i3 segments rework (#2159)

rework i3wm segments
This commit is contained in:
Philip Wellnitz 2021-03-15 03:45:17 +09:00 committed by GitHub
parent a1309cc116
commit 7310d53ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 305 additions and 84 deletions

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

@ -26,20 +26,20 @@ def output_lister(pl, segment_info):
def workspace_lister(pl, segment_info, only_show=None, output=None):
'''List all workspaces in segment_info format
Sets the segment info values of ``workspace`` and ``output`` to the name of
Sets the segment info values of ``workspace`` and ``output`` to the name of
the i3 workspace and the ``xrandr`` output respectively and the keys
``"visible"``, ``"urgent"`` and ``"focused"`` to a boolean indicating these
states.
:param list only_show:
Specifies which workspaces to list. Valid entries are ``"visible"``,
``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces
Specifies which workspaces to list. Valid entries are ``"visible"``,
``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces
are listed.
:param str output:
May be set to the name of an X output. If specified, only workspaces
on that output are listed. Overrides automatic output detection by
the lemonbar renderer and bindings. Set to ``false`` to force
May be set to the name of an X output. If specified, only workspaces
on that output are listed. Overrides automatic output detection by
the lemonbar renderer and bindings. Set to ``false`` to force
all workspaces to be shown.
'''

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:
group.append('workspace:focused')
group.append('w_focused')
if w.urgent:
group.append('workspace:urgent')
group.append('w_urgent')
if w.visible:
group.append('workspace:visible')
group.append('w_visible')
group.append('workspace')
return group
@ -28,58 +29,191 @@ 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
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
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
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(getattr(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:
Specifies which workspace to show. If unspecified, may be set by the
``list_workspaces`` lister if used, otherwise falls back to
Specifies which workspace to show. If unspecified, may be set by the
``list_workspaces`` lister if used, otherwise falls back to
currently focused workspace.
:param bool strip:
Specifies whether workspace numbers (in the ``1: name`` format) should
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()
w for w in conn.get_workspaces()
if w.name == workspace
))
except StopIteration:
@ -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()
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
@ -139,7 +277,7 @@ def scratchpad(pl, icons=SCRATCHPAD_ICONS):
'''Returns the windows currently on the scratchpad
:param dict icons:
Specifies the strings to show for the different scratchpad window states. Must
Specifies the strings to show for the different scratchpad window states. Must
contain the keys ``fresh`` and ``changed``.
Highlight groups used: ``scratchpad`` or ``scratchpad:visible``, ``scratchpad`` or ``scratchpad:focused``, ``scratchpad`` or ``scratchpad:urgent``.
@ -153,3 +291,19 @@ def scratchpad(pl, icons=SCRATCHPAD_ICONS):
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

@ -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

@ -1001,81 +1001,158 @@ class TestWthr(TestCommon):
class TestI3WM(TestCase):
@staticmethod
def get_workspaces():
return iter([
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),
])
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']},