Merge pull request #2 from powerline/develop

Upstream merge
This commit is contained in:
pachi-belero 2022-05-26 19:50:49 +02:00 committed by GitHub
commit 60366d023b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 541 additions and 286 deletions

View File

@ -528,10 +528,10 @@ i3wm
in lemonbar bindings.
``workspace``
dictionary containing the workspace name under the key ``"name"`` and
boolean values for the ``"visible"``, ``"urgent"`` and ``"focused"``
keys, indicating the state of the workspace. Currently only provided by
the :py:func:`powerline.listers.i3wm.workspace_lister` lister.
the `i3-ipc` workspace object corresponding to this workspace.
Contains string attributes ``name`` and ``output``, as well as boolean
attributes for ``visible``, ``urgent`` and ``focused``. Currently only
provided by the :py:func:`powerline.listers.i3wm.workspace_lister` lister.
Segment class
=============

View File

@ -54,7 +54,7 @@ Generic requirements
Pip installation
================
Due to a naming conflict with an unrelated project powerline is available on
Due to a naming conflict with an unrelated project, powerline is available on
PyPI under the ``powerline-status`` name:
.. code-block:: sh
@ -66,7 +66,7 @@ development version
.. code-block:: sh
pip install --user git+git://github.com/powerline/powerline
pip install --user git+https://github.com/powerline/powerline
may be used. If powerline was already checked out into some directory
@ -85,10 +85,9 @@ will have to be done (:file:`~/.local/bin` should be replaced with some path
present in ``$PATH``).
.. note::
If ISP blocks git protocol for some reason github also provides ``ssh``
(``git+ssh://git@github.com/powerline/powerline``) and ``https``
(``git+https://github.com/powerline/powerline``) protocols. ``git`` protocol
should be the fastest, but least secure one though.
We can use either ``https``(``git+ssh://git@github.com/powerline/powerline``)
or ``https``(``git+https://github.com/powerline/powerline``) protocols.
``git`` protocol is deprecated by Github.
Fonts installation
==================

View File

@ -29,7 +29,7 @@ should be followed:
.. code-block:: sh
pip install --user git+git://github.com/powerline/powerline
pip install --user git+https://github.com/powerline/powerline
will get the latest development version.

View File

@ -16,9 +16,13 @@ Python package
brew install python
.. note::
In case :file:`powerline.sh` as a client ``socat`` and ``coreutils`` need
to be installed. ``coreutils`` may be installed using ``brew install
coreutils``.
There are three variants of the powerline client. The fastest is
written in C and will be compiled if the compiler and libraries are
detected during installation. The second fastest option is
:file:`powerline.sh` which requires ``socat`` and ``coreutils``.
``coreutils`` may be installed using ``brew install
coreutils``. If neither of these are viable, then Powerline will
utilize a fallback client written in Python.
2. Install Powerline using one of the following commands:
@ -30,7 +34,7 @@ Python package
.. code-block:: sh
pip install --user git+git://github.com/powerline/powerline
pip install --user git+https://github.com/powerline/powerline
will get latest development version.

View File

@ -193,8 +193,12 @@ I am suffering bad lags before displaying shell prompt
To get rid of these lags there currently are two options:
* Run ``powerline-daemon``. Powerline does not automatically start it for you.
See installation instructions for more details.
* Compile and install ``libzpython`` module that lives in
https://bitbucket.org/ZyX_I/zpython. This variant is zsh-specific.
* If you are a python package manager, be sure to set ``POWERLINE_COMMAND``
to your Powerline command. See installation instructions for details.
Prompt is spoiled after completing files in ksh
-----------------------------------------------

View File

@ -5,8 +5,9 @@ Shell prompts
*************
.. note::
Powerline daemon is not run automatically by any of my bindings. It is
advised to add
Powerline can operate without a background daemon, but the shell performance
can be very slow. The Powerline daemon improves this performance
significantly, but must be started separately. It is advised to add
.. code-block:: bash
@ -142,3 +143,19 @@ following in ``~/.profile``:
.. warning::
Busybox has two shells: ``ash`` and ``hush``. Second is known to segfault in
busybox 1.22.1 when using :file:`powerline.sh` script.
Python Virtual Environments (conda, pyenv)
==========================================
If your system uses virtual environments to manage different Python versions,
such as pyenv or anaconda, these tools will add a performance delay to every
shell prompt. This delay can be bypassed by explicitly specifying your command
path.
.. code-block:: bash
export POWERLINE_COMMAND={path_to_powerline}
where ``{path_to_powerline}`` is the full filepath for powerline. If you
installed Powerline within an environment, you can find this path for pyenv
with ``pyenv which powerline`` or for conda with ``which powerline``.

View File

@ -77,8 +77,7 @@ to run with i3, simply ``exec`` this in the i3 config file and set the ``--i3``
exec python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --i3
Running the binding in i3-mode will require `i3ipc <https://github.com/acrisci/i3ipc-python>`_
(or the outdated `i3-py <https://github.com/ziberna/i3-py>`_).
Running the binding in i3-mode will require `i3ipc <https://github.com/acrisci/i3ipc-python>`_.
See the `lemonbar documentation <https://github.com/LemonBoy/bar>`_ for more
information and options.

View File

@ -1,14 +1,13 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
from weakref import ref
from atexit import register as atexit
from IPython.terminal.prompts import Prompts
from pygments.token import Token # NOQA
from powerline.ipython import IPythonPowerline
from powerline.renderers.ipython.since_7 import PowerlinePromptStyle
from powerline.bindings.ipython.post_0_11 import PowerlineMagics, ShutdownHook
from powerline.bindings.ipython.post_0_11 import PowerlineMagics
class ConfigurableIPythonPowerline(IPythonPowerline):
@ -20,7 +19,7 @@ class ConfigurableIPythonPowerline(IPythonPowerline):
super(ConfigurableIPythonPowerline, self).init(
renderer_module='.since_7')
def do_setup(self, ip, prompts, shutdown_hook):
def do_setup(self, ip, prompts):
prompts.powerline = self
msfn_missing = ()
@ -50,18 +49,16 @@ class ConfigurableIPythonPowerline(IPythonPowerline):
magics = PowerlineMagics(ip, self)
ip.register_magics(magics)
if shutdown_hook:
shutdown_hook.powerline = ref(self)
atexit(self.shutdown)
class PowerlinePrompts(Prompts):
'''Class that returns powerline prompts
'''
def __init__(self, shell):
shutdown_hook = ShutdownHook(shell)
powerline = ConfigurableIPythonPowerline(shell)
self.shell = shell
powerline.do_setup(shell, self, shutdown_hook)
powerline.do_setup(shell, self)
self.last_output_count = None
self.last_output = {}

View File

@ -24,15 +24,6 @@ def i3_subscribe(conn, event, callback):
:param func callback:
Function to run on event.
'''
try:
import i3ipc
except ImportError:
import i3
conn.Subscription(callback, event)
return
else:
pass
conn.on(event, callback)
from threading import Thread
@ -57,12 +48,8 @@ def get_i3_connection():
'''
global conn
if not conn:
try:
import i3ipc
except ImportError:
import i3 as conn
else:
conn = i3ipc.Connection()
import i3ipc
conn = i3ipc.Connection()
return conn

View File

@ -197,7 +197,7 @@ _powerline_add_widget() {
}
if test -z "${POWERLINE_CONFIG_COMMAND}" ; then
if which powerline-config >/dev/null ; then
if which powerline-config >/dev/null 2>/dev/null ; then
typeset -g POWERLINE_CONFIG_COMMAND=powerline-config
else
typeset -g POWERLINE_CONFIG_COMMAND="${_POWERLINE_SOURCED:h:h:h:h}/scripts/powerline-config"

View File

@ -51,6 +51,7 @@
"cwd:current_folder": "information:regular",
"cwd:divider": { "fg": "gray7", "bg": "gray4", "attrs": [] },
"virtualenv": { "fg": "white", "bg": "darkcyan", "attrs": [] },
"attached_clients": { "fg": "gray8", "bg": "gray0", "attrs": [] }
"attached_clients": { "fg": "gray8", "bg": "gray0", "attrs": [] },
"workspace": "information:regular"
}
}

View File

@ -1,10 +1,6 @@
{
"segments": {
"right": [
{
"function": "powerline.segments.common.wthr.weather",
"priority": 50
},
{
"function": "powerline.segments.common.time.date"
},
@ -15,14 +11,6 @@
"format": "%H:%M",
"istime": true
}
},
{
"function": "powerline.segments.common.mail.email_imap_alert",
"priority": 10,
"args": {
"username": "",
"password": ""
}
}
]
}

View File

@ -122,7 +122,7 @@ class BaseConstructor:
mapping = {}
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
if not isinstance(key, collections.Hashable):
if not isinstance(key, collections.abc.Hashable):
self.echoerr(
'While constructing a mapping', node.start_mark,
'found unhashable key', key_node.start_mark

View File

@ -163,7 +163,7 @@ class Spec(object):
'''Define message which will be used when unknown key was found
Unknown is a key that was not provided at the initialization and via
:py:meth:`Spec.update` and did not match any ``keyfunc`` proided via
:py:meth:`Spec.update` and did not match any ``keyfunc`` provided via
:py:meth:`Spec.unknown_spec`.
:param msgfunc:

View File

@ -50,19 +50,14 @@ def workspace_lister(pl, segment_info, only_show=None, output=None):
(
updated(
segment_info,
output=w['output'],
workspace={
'name': w['name'],
'visible': w['visible'],
'urgent': w['urgent'],
'focused': w['focused'],
},
output=w.output,
workspace=w,
),
{
'draw_inner_divider': None
}
)
for w in get_i3_connection().get_workspaces()
if (((not only_show or any(w[typ] for typ in only_show))
and (not output or w['output'] == output)))
if (((not only_show or any(getattr(w, typ) for typ in only_show))
and (not output or w.output == output)))
)

View File

@ -251,7 +251,7 @@ class Renderer(object):
for line in range(theme.get_line_number() - 1, 0, -1):
yield self.render(side=None, line=line, **kwargs)
def render(self, mode=None, width=None, side=None, line=0, output_raw=False, output_width=False, segment_info=None, matcher_info=None):
def render(self, mode=None, width=None, side=None, line=0, output_raw=False, output_width=False, segment_info=None, matcher_info=None, hl_args=None):
'''Render all segments.
When a width is provided, low-priority segments are dropped one at
@ -286,6 +286,11 @@ class Renderer(object):
:param matcher_info:
Matcher information. Is processed in :py:meth:`get_segment_info`
method.
:param dict hl_args:
Additional arguments to pass on the :py:meth:`hl` and
:py:meth`hlstyle` methods. They are ignored in the default
implementation, but renderer-specific overrides can make use of
them as run-time "configuration" information.
'''
theme = self.get_theme(matcher_info)
return self.do_render(
@ -297,6 +302,7 @@ class Renderer(object):
output_width=output_width,
segment_info=self.get_segment_info(segment_info, mode),
theme=theme,
hl_args=hl_args
)
def compute_divider_widths(self, theme):
@ -324,7 +330,7 @@ class Renderer(object):
:return: Results of joining these segments.
'''
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme):
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme, hl_args):
'''Like Renderer.render(), but accept theme in place of matcher_info
'''
segments = list(theme.get_segments(side, line, segment_info, mode))
@ -333,14 +339,16 @@ class Renderer(object):
self._prepare_segments(segments, output_width or width)
hl_args = hl_args or dict()
if not width:
# No width specified, so we dont need to crop or pad anything
if output_width:
current_width = self._render_length(theme, segments, self.compute_divider_widths(theme))
return construct_returned_value(self.hl_join([
segment['_rendered_hl']
for segment in self._render_segments(theme, segments)
]) + self.hlstyle(), segments, current_width, output_raw, output_width)
for segment in self._render_segments(theme, segments, hl_args)
]) + self.hlstyle(**hl_args), segments, current_width, output_raw, output_width)
divider_widths = self.compute_divider_widths(theme)
@ -394,10 +402,10 @@ class Renderer(object):
rendered_highlighted = self.hl_join([
segment['_rendered_hl']
for segment in self._render_segments(theme, segments)
for segment in self._render_segments(theme, segments, hl_args)
])
if rendered_highlighted:
rendered_highlighted += self.hlstyle()
rendered_highlighted += self.hlstyle(**hl_args)
return construct_returned_value(rendered_highlighted, segments, current_width, output_raw, output_width)
@ -470,7 +478,7 @@ class Renderer(object):
ret += segment_len
return ret
def _render_segments(self, theme, segments, render_highlighted=True):
def _render_segments(self, theme, segments, hl_args, render_highlighted=True):
'''Internal segment rendering method.
This method loops through the segment array and compares the
@ -527,6 +535,10 @@ class Renderer(object):
contents_highlighted = ''
draw_divider = segment['draw_' + divider_type + '_divider']
segment_hl_args = {}
segment_hl_args.update(segment['highlight'])
segment_hl_args.update(hl_args)
# XXX Make sure self.hl() calls are called in the same order
# segments are displayed. This is needed for Vim renderer to work.
if draw_divider:
@ -546,14 +558,14 @@ class Renderer(object):
if side == 'left':
if render_highlighted:
contents_highlighted = self.hl(self.escape(contents_raw), **segment['highlight'])
divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False)
contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args)
divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False, **hl_args)
segment['_rendered_raw'] = contents_raw + divider_raw
segment['_rendered_hl'] = contents_highlighted + divider_highlighted
else:
if render_highlighted:
divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False)
contents_highlighted = self.hl(self.escape(contents_raw), **segment['highlight'])
divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False, **hl_args)
contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args)
segment['_rendered_raw'] = divider_raw + contents_raw
segment['_rendered_hl'] = divider_highlighted + contents_highlighted
else:
@ -562,7 +574,7 @@ class Renderer(object):
else:
contents_raw = contents_raw + outer_padding
contents_highlighted = self.hl(self.escape(contents_raw), **segment['highlight'])
contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args)
segment['_rendered_raw'] = contents_raw
segment['_rendered_hl'] = contents_highlighted
prev_segment = segment
@ -576,7 +588,7 @@ class Renderer(object):
'''
return string.translate(self.character_translations)
def hlstyle(fg=None, bg=None, attrs=None):
def hlstyle(fg=None, bg=None, attrs=None, **kwargs):
'''Output highlight style string.
Assuming highlighted string looks like ``{style}{contents}`` this method
@ -585,10 +597,10 @@ class Renderer(object):
'''
raise NotImplementedError
def hl(self, contents, fg=None, bg=None, attrs=None):
def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
'''Output highlighted chunk.
This implementation just outputs :py:meth:`hlstyle` joined with
``contents``.
'''
return self.hlstyle(fg, bg, attrs) + (contents or '')
return self.hlstyle(fg, bg, attrs, **kwargs) + (contents or '')

View File

@ -17,7 +17,7 @@ class I3barRenderer(Renderer):
# We dont need to explicitly reset attributes, so skip those calls
return ''
def hl(self, contents, fg=None, bg=None, attrs=None):
def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
segment = {
'full_text': contents,
'separator': False,

View File

@ -90,7 +90,7 @@ class IPythonPygmentsRenderer(IPythonRenderer):
def hl_join(segments):
return reduce(operator.iadd, segments, [])
def hl(self, contents, fg=None, bg=None, attrs=None):
def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
'''Output highlighted chunk.
This implementation outputs a list containing a single pair

View File

@ -21,7 +21,7 @@ class LemonbarRenderer(Renderer):
# We dont need to explicitly reset attributes, so skip those calls
return ''
def hl(self, contents, fg=None, bg=None, attrs=None):
def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
text = ''
if fg is not None:

View File

@ -15,7 +15,7 @@ class PangoMarkupRenderer(Renderer):
# We dont need to explicitly reset attributes, so skip those calls
return ''
def hl(self, contents, fg=None, bg=None, attrs=None):
def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
'''Highlight a segment.'''
awesome_attr = []
if fg is not None:

View File

@ -105,7 +105,7 @@ class ShellRenderer(PromptRenderer):
self.used_term_escape_style = self.term_escape_style
return super(ShellRenderer, self).do_render(segment_info=segment_info, **kwargs)
def hlstyle(self, fg=None, bg=None, attrs=None):
def hlstyle(self, fg=None, bg=None, attrs=None, escape=True, **kwargs):
'''Highlight a segment.
If an argument is None, the argument is ignored. If an argument is
@ -162,7 +162,7 @@ class ShellRenderer(PromptRenderer):
r = '\033Ptmux;' + r.replace('\033', '\033\033') + '\033\\'
elif self.screen_escape:
r = '\033P' + r.replace('\033', '\033\033') + '\033\\'
return self.escape_hl_start + r + self.escape_hl_end
return self.escape_hl_start + r + self.escape_hl_end if escape else r
def get_theme(self, matcher_info):
if not matcher_info:

View File

@ -6,13 +6,91 @@ from powerline.renderers.shell import ShellRenderer
class BashPromptRenderer(ShellRenderer):
'''Powerline bash prompt segment renderer.'''
escape_hl_start = '\['
escape_hl_end = '\]'
escape_hl_start = '\\['
escape_hl_end = '\\]'
character_translations = ShellRenderer.character_translations.copy()
character_translations[ord('$')] = '\\$'
character_translations[ord('`')] = '\\`'
character_translations[ord('\\')] = '\\\\'
def do_render(self, side, line, width, output_width, output_raw, hl_args, **kwargs):
# we are rendering the normal left prompt
if side == 'left' and line == 0 and width is not None:
# we need left prompt's width to render the raw spacer
output_width = output_width or output_raw
left = super(BashPromptRenderer, self).do_render(
side=side,
line=line,
output_width=output_width,
width=width,
output_raw=output_raw,
hl_args=hl_args,
**kwargs
)
left_rendered = left[0] if output_width else left
# we don't escape color sequences in the right prompt so we can do escaping as a whole
if hl_args:
hl_args = hl_args.copy()
hl_args.update({'escape': False})
else:
hl_args = {'escape': False}
right = super(BashPromptRenderer, self).do_render(
side='right',
line=line,
output_width=True,
width=width,
output_raw=output_raw,
hl_args=hl_args,
**kwargs
)
ret = []
if right[-1] > 0:
# if the right prompt is not empty we embed it in the left prompt
# it must be escaped as a whole so readline doesn't see it
ret.append(''.join((
left_rendered,
self.escape_hl_start,
'\033[s', # save the cursor position
'\033[{0}C'.format(width), # move to the right edge of the terminal
'\033[{0}D'.format(right[-1] - 1), # move back to the right prompt position
right[0],
'\033[u', # restore the cursor position
self.escape_hl_end
)))
if output_raw:
ret.append(''.join((
left[1],
' ' * (width - left[-1] - right[-1]),
right[1]
)))
else:
ret.append(left_rendered)
if output_raw:
ret.append(left[1])
if output_width:
ret.append(left[-1])
if len(ret) == 1:
return ret[0]
else:
return ret
else:
return super(BashPromptRenderer, self).do_render(
side=side,
line=line,
width=width,
output_width=output_width,
output_raw=output_raw,
hl_args=hl_args,
**kwargs
)
renderer = BashPromptRenderer

View File

@ -38,7 +38,7 @@ class TmuxRenderer(Renderer):
width = 10
return super(TmuxRenderer, self).render(width=width, segment_info=segment_info, **kwargs)
def hlstyle(self, fg=None, bg=None, attrs=None):
def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs):
'''Highlight a segment.'''
# We dont need to explicitly reset attributes, so skip those calls
if not attrs and not bg and not fg:

View File

@ -123,7 +123,7 @@ class VimRenderer(Renderer):
def reset_highlight(self):
self.hl_groups.clear()
def hlstyle(self, fg=None, bg=None, attrs=None):
def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs):
'''Highlight a segment.
If an argument is None, the argument is ignored. If an argument is

View File

@ -6,17 +6,18 @@ import re
from powerline.theme import requires_segment_info
from powerline.bindings.wm import get_i3_connection
WORKSPACE_REGEX = re.compile(r'^[0-9]+: ?')
def workspace_groups(w):
group = []
if w['focused']:
if w.focused:
group.append('workspace:focused')
group.append('w_focused')
if w['urgent']:
if w.urgent:
group.append('workspace:urgent')
group.append('w_urgent')
if w['visible']:
if w.visible:
group.append('workspace:visible')
group.append('w_visible')
group.append('workspace')
return group
@ -28,41 +29,152 @@ def format_name(name, strip=False):
return name
def is_empty_workspace(workspace, containers):
if workspace.focused or workspace.visible:
return False
wins = [win for win in containers[workspace.name].leaves()]
return False if len(wins) > 0 else True
WS_ICONS = {"multiple": "M"}
def get_icon(workspace, separator, icons, show_multiple_icons, ws_containers):
icons_tmp = WS_ICONS
icons_tmp.update(icons)
icons = icons_tmp
wins = [win for win in ws_containers[workspace.name].leaves() \
if win.parent.scratchpad_state == 'none']
if len(wins) == 0:
return ''
result = ''
cnt = 0
for key in icons:
if not icons[key] or len(icons[key]) < 1:
continue
if any(key in win.window_class for win in wins if win.window_class):
result += (separator if cnt > 0 else '') + icons[key]
cnt += 1
if not show_multiple_icons and cnt > 1:
if 'multiple' in icons:
return icons['multiple']
else:
return ''
return result
@requires_segment_info
def workspaces(pl, segment_info, only_show=None, output=None, strip=0):
def workspaces(pl, segment_info, only_show=None, output=None, strip=0, format='{name}',
icons=WS_ICONS, sort_workspaces=False, show_output=False, priority_workspaces=[],
hide_empty_workspaces=False):
'''Return list of used workspaces
:param list only_show:
Specifies which workspaces to show. Valid entries are ``"visible"``,
``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces
are shown.
:param str output:
May be set to the name of an X output. If specified, only workspaces
on that output are shown. Overrides automatic output detection by
the lemonbar renderer and bindings.
Use "__all__" to show workspaces on all outputs.
:param int strip:
Specifies how many characters from the front of each workspace name
should be stripped (e.g. to remove workspace numbers). Defaults to zero.
:param str format:
Specifies the format used to display workspaces; defaults to ``{name}``.
Valid fields are: ``name`` (workspace name), ``number`` (workspace number
if present), `stipped_name`` (workspace name stripped of leading number),
``icon`` (if available, icon for application running in the workspace,
uses the ``multiple`` icon instead of multiple different icons), ``multi_icon``
(similar to ``icon``, but does not use ``multiple``, instead joins all icons
with a single space)
:param dict icons:
A dictionary mapping a substring of window classes to strings to be used as an
icon for that window class.
Further, there is a ``multiple`` icon for workspaces containing more than one
window.
:param bool sort_workspaces:
Sort the workspaces displayed by their name according to the natural ordering.
:param bool show_output:
Shows the name of the output if more than one output is connected.
:param list priority_workspaces:
A list of workspace names to be sorted before any other workspaces in the given
order.
:param bool hide_empty_workspaces:
Hides all workspaces without any open window.
Also hides non-focussed workspaces containing only an open scratchpad.
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace`` or ``w_focused``, ``workspace`` or ``w_urgent``.
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace`` or ``output``.
'''
output = output or segment_info.get('output')
conn = get_i3_connection()
return [
{
'contents': w['name'][strip:],
if not output == "__all__":
output = output or segment_info.get('output')
else:
output = None
if output:
output = [output]
else:
output = [o.name for o in conn.get_outputs() if o.active]
def sort_ws(ws):
if sort_workspaces:
def natural_key(ws):
str = ws.name
return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', str)]
ws = sorted(ws, key=natural_key)
result = []
for n in priority_workspaces:
result += [w for w in ws if w.name == n]
return result + [w for w in ws if not w.name in priority_workspaces]
ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()}
if len(output) <= 1:
res = []
if show_output:
res += [{
'contents': output[0],
'highlight_groups': ['output']
}]
res += [{
'contents': format.format(name = w.name[min(len(w.name), strip):],
stripped_name = format_name(w.name, strip=True),
number = w.num,
icon = get_icon(w, '', icons, False, ws_containers),
multi_icon = get_icon(w, ' ', icons, True, ws_containers)),
'highlight_groups': workspace_groups(w)
}
for w in get_i3_connection().get_workspaces()
if ((not only_show or any(w[typ] for typ in only_show))
and (not output or w['output'] == output))
]
} for w in sort_ws(conn.get_workspaces()) \
if (not only_show or any(getattr(w, tp) for tp in only_show)) \
if w.output == output[0] \
if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))]
return res
else:
res = []
for n in output:
if show_output:
res += [{
'contents': n,
'highlight_groups': ['output']
}]
res += [{
'contents': format.format(name = w.name[min(len(w.name), strip):],
stripped_name = format_name(w.name, strip=True),
number = w.num,
icon = get_icon(w, '', icons, False, ws_containers),
multi_icon = get_icon(w, ' ', icons, True, ws_containers)),
'highlight_groups': workspace_groups(w)
} for w in sort_ws(conn.get_workspaces()) \
if (not only_show or any(getattr(w, tp) for tp in only_show)) \
if w.output == n \
if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))]
return res
@requires_segment_info
def workspace(pl, segment_info, workspace=None, strip=False):
def workspace(pl, segment_info, workspace=None, strip=False, format=None, icons=WS_ICONS):
'''Return the specified workspace name
:param str workspace:
@ -73,14 +185,36 @@ def workspace(pl, segment_info, workspace=None, strip=False):
:param bool strip:
Specifies whether workspace numbers (in the ``1: name`` format) should
be stripped from workspace names before being displayed. Defaults to false.
Deprecated: Use {name} or {stripped_name} of format instead.
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace`` or ``w_focused``, ``workspace`` or ``w_urgent``.
:param str format:
Specifies the format used to display workspaces; defaults to ``{name}``.
Valid fields are: ``name`` (workspace name), ``number`` (workspace number
if present), `stipped_name`` (workspace name stripped of leading number),
``icon`` (if available, icon for application running in the workspace,
uses the ``multiple`` icon instead of multiple different icons), ``multi_icon``
(similar to ``icon``, but does not use ``multiple``, instead joins all icons
with a single space)
:param dict icons:
A dictionary mapping a substring of window classes to strings to be used as an
icon for that window class.
Further, there is a ``multiple`` icon for workspaces containing more than one
window.
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace``.
'''
if format == None:
format = '{stripped_name}' if strip else '{name}'
conn = get_i3_connection()
ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()}
if workspace:
try:
w = next((
w for w in get_i3_connection().get_workspaces()
if w['name'] == workspace
w for w in conn.get_workspaces()
if w.name == workspace
))
except StopIteration:
return None
@ -89,16 +223,20 @@ def workspace(pl, segment_info, workspace=None, strip=False):
else:
try:
w = next((
w for w in get_i3_connection().get_workspaces()
if w['focused']
w for w in conn.get_workspaces()
if w.focused
))
except StopIteration:
return None
return [{
'contents': format_name(w['name'], strip=strip),
'contents': format.format(name = w.name,
stripped_name = format_name(w.name, strip=True),
number = w.num,
icon = get_icon(w, '', icons, False, ws_containers),
multi_icon = get_icon(w, ' ', icons, True, ws_containers)),
'highlight_groups': workspace_groups(w)
}]
}]
@requires_segment_info
@ -150,6 +288,22 @@ def scratchpad(pl, icons=SCRATCHPAD_ICONS):
'contents': icons.get(w.scratchpad_state, icons['changed']),
'highlight_groups': scratchpad_groups(w)
}
for w in get_i3_connection().get_tree().descendents()
for w in get_i3_connection().get_tree().descendants()
if w.scratchpad_state != 'none'
]
def active_window(pl, cutoff=100):
'''Returns the title of the currently active window.
:param int cutoff:
Maximum title length. If the title is longer, the window_class is used instead.
Highlight groups used: ``active_window_title``.
'''
focused = get_i3_connection().get_tree().find_focused()
cont = focused.name
if len(cont) > cutoff:
cont = focused.window_class
return [{'contents': cont, 'highlight_groups': ['active_window_title']}] if focused.name != focused.workspace().name else []

View File

@ -4,11 +4,11 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import subprocess
from traceback import print_exc
__version__ = "2.8.1"
__version__ = "2.8.3"
def get_version():
try:
return __version__ + '.dev9999+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip())
return __version__ + 'b' + subprocess.check_output(['git', 'rev-list', '--count', __version__ + '..HEAD']).strip().decode()
except Exception:
print_exc()
return __version__

View File

@ -70,10 +70,10 @@ setup(
'Natural Language :: English',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],

View File

@ -33,6 +33,7 @@ class PowerlineDummyTest(object):
class PowerlineTestSuite(object):
def __init__(self, name):
self.name = name
self.suite = ''
def __enter__(self):
self.saved_current_suite = os.environ['POWERLINE_CURRENT_SUITE']

View File

@ -8,14 +8,16 @@ from tests.modules import TestCase
class TestI3WM(TestCase):
workspaces = [
Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False),
Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True),
Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True),
Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True),
]
@staticmethod
def get_workspaces():
return iter([
{'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False},
{'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True},
{'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True},
{'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True},
])
return iter(TestI3WM.workspaces)
@staticmethod
def get_outputs(pl):
@ -46,42 +48,22 @@ class TestI3WM(TestCase):
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '1: w1',
'focused': False,
'urgent': False,
'visible': False
}
'workspace': self.workspaces[0],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '2: w2',
'focused': False,
'urgent': False,
'visible': True
}
'workspace': self.workspaces[1],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'HDMI1',
'workspace': {
'name': '3: w3',
'focused': False,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[2],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'DVI01',
'workspace': {
'name': '4: w4',
'focused': True,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[3],
}, {'draw_inner_divider': None}),
]
)
@ -92,22 +74,12 @@ class TestI3WM(TestCase):
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '1: w1',
'focused': False,
'urgent': False,
'visible': False
}
'workspace': self.workspaces[0],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '2: w2',
'focused': False,
'urgent': False,
'visible': True
}
'workspace': self.workspaces[1],
}, {'draw_inner_divider': None}),
]
)
@ -121,22 +93,12 @@ class TestI3WM(TestCase):
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '1: w1',
'focused': False,
'urgent': False,
'visible': False
}
'workspace': self.workspaces[0],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '2: w2',
'focused': False,
'urgent': False,
'visible': True
}
'workspace': self.workspaces[1],
}, {'draw_inner_divider': None}),
]
)
@ -151,42 +113,22 @@ class TestI3WM(TestCase):
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '1: w1',
'focused': False,
'urgent': False,
'visible': False
}
'workspace': self.workspaces[0],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'LVDS1',
'workspace': {
'name': '2: w2',
'focused': False,
'urgent': False,
'visible': True
}
'workspace': self.workspaces[1],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'HDMI1',
'workspace': {
'name': '3: w3',
'focused': False,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[2],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'DVI01',
'workspace': {
'name': '4: w4',
'focused': True,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[3],
}, {'draw_inner_divider': None}),
]
)
@ -201,22 +143,12 @@ class TestI3WM(TestCase):
({
'a': 1,
'output': 'HDMI1',
'workspace': {
'name': '3: w3',
'focused': False,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[2],
}, {'draw_inner_divider': None}),
({
'a': 1,
'output': 'DVI01',
'workspace': {
'name': '4: w4',
'focused': True,
'urgent': True,
'visible': True
}
'workspace': self.workspaces[3],
}, {'draw_inner_divider': None}),
]
)

View File

@ -1001,81 +1001,158 @@ class TestWthr(TestCommon):
class TestI3WM(TestCase):
@staticmethod
def get_workspaces():
return iter([
{'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False},
{'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True},
{'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True},
{'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True},
])
def test_workspaces(self):
class Conn(object):
def get_tree(self):
return self
def descendents(self):
nodes_unfocused = [Args(focused = False)]
nodes_focused = [Args(focused = True)]
workspace_scratch = lambda: Args(name='__i3_scratch')
workspace_noscratch = lambda: Args(name='2: w2')
return [
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused),
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused),
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused),
Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused),
]
def workspaces(self):
return iter([
Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []),
Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []),
Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []),
Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: [])
])
def get_workspaces(self):
return iter([
Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []),
Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []),
Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []),
Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: [])
])
def get_outputs(self):
return iter([
Args(name='LVDS1', active=True),
Args(name='HDMI1', active=True),
Args(name='DVI01', active=True),
Args(name='HDMI2', active=False),
])
pl = Pl()
with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)):
with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()):
segment_info = {}
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info), [
{'contents': '1: w1', 'highlight_groups': ['workspace']},
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=None), [
{'contents': '1: w1', 'highlight_groups': ['workspace']},
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent']), [
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible']), [
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
{'contents': 'w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
{'contents': 'w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent'], output='DVI01'), [
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3, output='LVDS1'), [
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
])
segment_info['output'] = 'LVDS1'
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
{'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']},
])
def test_workspace(self):
class Conn(object):
def get_tree(self):
return self
def descendents(self):
nodes_unfocused = [Args(focused = False)]
nodes_focused = [Args(focused = True)]
workspace_scratch = lambda: Args(name='__i3_scratch')
workspace_noscratch = lambda: Args(name='2: w2')
return [
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused),
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused),
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused),
Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused),
]
def workspaces(self):
return iter([
Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []),
Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []),
Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []),
Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: [])
])
def get_workspaces(self):
return iter([
Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []),
Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []),
Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []),
Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: [])
])
def get_outputs(self):
return iter([
Args(name='LVDS1', active=True),
Args(name='HDMI1', active=True),
Args(name='DVI01', active=True),
Args(name='HDMI2', active=False),
])
pl = Pl()
with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)):
with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()):
segment_info = {}
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='1: w1'), [
{'contents': '1: w1', 'highlight_groups': ['workspace']},
])
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='3: w3', strip=True), [
{'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': 'w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='9: w9'), None)
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info), [
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
segment_info['workspace'] = next(self.get_workspaces())
segment_info['workspace'] = next(Conn().get_workspaces())
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='4: w4'), [
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
{'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, strip=True), [
{'contents': 'w1', 'highlight_groups': ['workspace']},
@ -1093,7 +1170,7 @@ class TestI3WM(TestCase):
def get_tree(self):
return self
def descendents(self):
def descendants(self):
nodes_unfocused = [Args(focused = False)]
nodes_focused = [Args(focused = True)]

View File

@ -4,6 +4,7 @@ set_theme_option() {
set_theme() {
export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
}
set_theme_option default.segment_data.hostname.args.only_if_ssh false
set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
ABOVE_LEFT='[{
"left": [
@ -40,7 +41,9 @@ VIRTUAL_ENV=
bgscript.sh & waitpid.sh
false
kill `cat pid` ; sleep 1s
set_theme_option default.segment_data.hostname.display false
set_theme_option default_leftonly.segment_data.hostname.display false
set_theme_option default.segment_data.user.display false
set_theme_option default_leftonly.segment_data.user.display false
echo '
abc
@ -56,14 +59,15 @@ cd ../'$(echo)'
cd ../'`echo`'
cd ../'«Unicode!»'
(exit 42)|(exit 43)
set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
set_theme default
set_theme_option default.segments.above "$ABOVE_LEFT"
export DISPLAYED_ENV_VAR=foo
unset DISPLAYED_ENV_VAR
set_theme_option default_leftonly.segments.above "$ABOVE_FULL"
set_theme_option default.segments.above "$ABOVE_FULL"
export DISPLAYED_ENV_VAR=foo
unset DISPLAYED_ENV_VAR
set_theme_option default_leftonly.segments.above
set_theme_option default_leftonly.dividers.left.hard \$ABC
set_theme_option default.segments.above
set_theme_option default.dividers.left.hard \$ABC
false
true is the last line
exit

View File

@ -7,7 +7,9 @@
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
[1]+ Terminated bgscript.sh
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
 USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
 USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
  BRANCH  …  tmp  shell  3rd  echo '
                                   abc
@ -27,16 +29,17 @@ def
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"
   shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
 foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_FULL"
   shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                            
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
   shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                       foo 
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR
   shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                            
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC
 …  shell  3rd  «Unicode!» $ABC   BRANCH false

View File

@ -7,7 +7,9 @@
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
[1]+ Terminated bgscript.sh
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
 USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
 USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
  BRANCH  …  tmp  shell  3rd  echo '
   abc
@ -27,16 +29,17 @@ def
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"
   shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
 foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_FULL"
   shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                            
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
   shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                       foo 
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR
   shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                            
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above
   shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC
 …  shell  3rd  «Unicode!» $ABC   BRANCH false