diff --git a/powerline/bindings/zsh/__init__.py b/powerline/bindings/zsh/__init__.py index ad3fa90b..9fa82794 100644 --- a/powerline/bindings/zsh/__init__.py +++ b/powerline/bindings/zsh/__init__.py @@ -135,6 +135,7 @@ class Prompt(object): 'client_id': 1, 'local_theme': self.theme, 'parser_state': zsh.getvalue('_POWERLINE_PARSER_STATE'), + 'shortened_path': zsh.getvalue('_POWERLINE_SHORTENED_PATH'), } r = '' if self.above: diff --git a/powerline/bindings/zsh/powerline.zsh b/powerline/bindings/zsh/powerline.zsh index 42eafe45..0c097b66 100644 --- a/powerline/bindings/zsh/powerline.zsh +++ b/powerline/bindings/zsh/powerline.zsh @@ -103,6 +103,10 @@ _powerline_set_jobnum() { _POWERLINE_JOBNUM=${(%):-%j} } +_powerline_set_shortened_path() { + _POWERLINE_SHORTENED_PATH="${(%):-%~}" +} + _powerline_update_counter() { zpython '_powerline.precmd()' } @@ -116,6 +120,8 @@ _powerline_setup_prompt() { fi done precmd_functions+=( _powerline_set_jobnum ) + chpwd_functions+=( _powerline_set_shortened_path ) + _powerline_set_shortened_path VIRTUAL_ENV_DISABLE_PROMPT=1 @@ -138,6 +144,7 @@ _powerline_setup_prompt() { add_args+=' --last_exit_code=$?' add_args+=' --last_pipe_status="$pipestatus"' add_args+=' --renderer_arg="client_id=$$"' + add_args+=' --renderer_arg="shortened_path=$_POWERLINE_SHORTENED_PATH"' add_args+=' --jobnum=$_POWERLINE_JOBNUM' local new_args_2=' --renderer_arg="parser_state=${(%%):-%_}"' new_args_2+=' --renderer_arg="local_theme=continuation"' diff --git a/powerline/config_files/themes/ascii.json b/powerline/config_files/themes/ascii.json index ff7c6d76..adacfbfb 100644 --- a/powerline/config_files/themes/ascii.json +++ b/powerline/config_files/themes/ascii.json @@ -14,16 +14,16 @@ "branch": { "before": "BR " }, + "cwd": { + "args": { + "ellipsis": "..." + } + }, "line_current_symbol": { "contents": "LN " }, - "powerline.segments.common.cwd": { - "args": { - "ellipsis": "..." - } - }, "powerline.segments.common.network_load": { "args": { "recv_format": "DL {value:>8}", diff --git a/powerline/config_files/themes/powerline.json b/powerline/config_files/themes/powerline.json index 6fa43e81..e076f770 100644 --- a/powerline/config_files/themes/powerline.json +++ b/powerline/config_files/themes/powerline.json @@ -14,16 +14,16 @@ "branch": { "before": " " }, + "cwd": { + "args": { + "ellipsis": "⋯" + } + }, "line_current_symbol": { "contents": " " }, - "powerline.segments.common.cwd": { - "args": { - "ellipsis": "⋯" - } - }, "powerline.segments.common.network_load": { "args": { "recv_format": "⬇ {value:>8}", diff --git a/powerline/config_files/themes/shell/__main__.json b/powerline/config_files/themes/shell/__main__.json index 2b37f8b6..13ae942b 100644 --- a/powerline/config_files/themes/shell/__main__.json +++ b/powerline/config_files/themes/shell/__main__.json @@ -5,7 +5,7 @@ "only_if_ssh": true } }, - "powerline.segments.common.cwd": { + "cwd": { "args": { "dir_limit_depth": 3 } diff --git a/powerline/config_files/themes/shell/default.json b/powerline/config_files/themes/shell/default.json index 56e3ce70..e4f486a3 100644 --- a/powerline/config_files/themes/shell/default.json +++ b/powerline/config_files/themes/shell/default.json @@ -19,6 +19,7 @@ "priority": 50 }, { + "module": "powerline.segments.shell", "name": "cwd", "priority": 10 }, diff --git a/powerline/config_files/themes/shell/default_leftonly.json b/powerline/config_files/themes/shell/default_leftonly.json index ca7dd15d..350fb026 100644 --- a/powerline/config_files/themes/shell/default_leftonly.json +++ b/powerline/config_files/themes/shell/default_leftonly.json @@ -19,6 +19,7 @@ "priority": 40 }, { + "module": "powerline.segments.shell", "name": "cwd", "priority": 10 }, diff --git a/powerline/config_files/themes/unicode.json b/powerline/config_files/themes/unicode.json index 484ac5c2..9a3faf7a 100644 --- a/powerline/config_files/themes/unicode.json +++ b/powerline/config_files/themes/unicode.json @@ -14,16 +14,16 @@ "branch": { "before": "⎇ " }, + "cwd": { + "args": { + "ellipsis": "⋯" + } + }, "line_current_symbol": { "contents": "␤ " }, - "powerline.segments.common.cwd": { - "args": { - "ellipsis": "⋯" - } - }, "powerline.segments.common.network_load": { "args": { "recv_format": "⬇ {value:>8}", diff --git a/powerline/config_files/themes/unicode_terminus.json b/powerline/config_files/themes/unicode_terminus.json index aa9c679d..01b981f2 100644 --- a/powerline/config_files/themes/unicode_terminus.json +++ b/powerline/config_files/themes/unicode_terminus.json @@ -14,16 +14,16 @@ "branch": { "before": "BR " }, + "cwd": { + "args": { + "ellipsis": "…" + } + }, "line_current_symbol": { "contents": "␤ " }, - "powerline.segments.common.cwd": { - "args": { - "ellipsis": "…" - } - }, "powerline.segments.common.network_load": { "args": { "recv_format": "⇓ {value:>8}", diff --git a/powerline/config_files/themes/unicode_terminus_condensed.json b/powerline/config_files/themes/unicode_terminus_condensed.json index ee759316..15f37a1a 100644 --- a/powerline/config_files/themes/unicode_terminus_condensed.json +++ b/powerline/config_files/themes/unicode_terminus_condensed.json @@ -14,17 +14,17 @@ "branch": { "before": "B " }, - - "line_current_symbol": { - "contents": "␤" - }, - - "powerline.segments.common.cwd": { + "cwd": { "args": { "use_path_separator": true, "ellipsis": "…" } }, + + "line_current_symbol": { + "contents": "␤" + }, + "powerline.segments.common.network_load": { "args": { "recv_format": "⇓{value:>8}", diff --git a/powerline/segments/shell.py b/powerline/segments/shell.py index a13fa09f..bfd7c9a3 100644 --- a/powerline/segments/shell.py +++ b/powerline/segments/shell.py @@ -1,6 +1,8 @@ # vim:fileencoding=utf-8:noet from powerline.theme import requires_segment_info +from powerline.segments import with_docstring +from powerline.segments.common import CwdSegment @requires_segment_info @@ -120,3 +122,42 @@ def continuation(pl, segment_info, omit_cmdsubst=True, right_align=False, rename ret[-1].update(width='auto', align='l', highlight_group=['continuation:current', 'continuation']) return ret + + +@requires_segment_info +class ShellCwdSegment(CwdSegment): + def get_shortened_path(self, pl, segment_info, use_shortened_path=True, **kwargs): + if use_shortened_path: + try: + return segment_info['shortened_path'] + except KeyError: + pass + return super(ShellCwdSegment, self).get_shortened_path(pl, segment_info, **kwargs) + + +cwd = with_docstring(ShellCwdSegment(), +'''Return the current working directory. + +Returns a segment list to create a breadcrumb-like effect. + +:param int dir_shorten_len: + shorten parent directory names to this length (e.g. + :file:`/long/path/to/powerline` → :file:`/l/p/t/powerline`) +:param int dir_limit_depth: + limit directory depth to this number (e.g. + :file:`/long/path/to/powerline` → :file:`⋯/to/powerline`) +:param bool use_path_separator: + Use path separator in place of soft divider. +:param bool use_shortened_path: + Use path from shortened_path ``--renderer_arg`` argument. If this argument + is present ``shorten_home`` argument is ignored. +:param bool shorten_home: + Shorten home directory to ``~``. +:param str ellipsis: + Specifies what to use in place of omitted directories. Use None to not + show this subsegment at all. + +Divider highlight group used: ``cwd:divider``. + +Highlight groups used: ``cwd:current_folder`` or ``cwd``. It is recommended to define all highlight groups. +''') diff --git a/tests/test_segments.py b/tests/test_segments.py index 59c6040a..c46b9216 100644 --- a/tests/test_segments.py +++ b/tests/test_segments.py @@ -162,6 +162,122 @@ class TestShell(TestCase): }, ]) + def test_cwd(self): + new_os = new_module('os', path=os.path, sep='/') + pl = Pl() + cwd = [None] + + def getcwd(): + wd = cwd[0] + if isinstance(wd, Exception): + raise wd + else: + return wd + + segment_info = {'getcwd': getcwd, 'home': None} + with replace_attr(shell, 'os', new_os): + cwd[0] = '/abc/def/ghi/foo/bar' + self.assertEqual(common.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'abc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'def', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + segment_info['home'] = '/abc/def/ghi' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + segment_info.update(shortened_path='~foo/ghi') + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '~foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_shortened_path=False), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + segment_info.pop('shortened_path') + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3, shorten_home=False), [ + {'contents': '⋯', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1), [ + {'contents': '⋯', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis='...'), [ + {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True), [ + {'contents': '⋯/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis='...'), [ + {'contents': '.../', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'fo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2, use_path_separator=True), [ + {'contents': '~/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'fo/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']} + ]) + cwd[0] = '/etc' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + cwd[0] = '/' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_group': ['cwd:current_folder', 'cwd']}, + ]) + ose = OSError() + ose.errno = 2 + cwd[0] = ose + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '[not found]', 'divider_highlight_group': 'cwd:divider', 'highlight_group': ['cwd:current_folder', 'cwd'], 'draw_inner_divider': True} + ]) + cwd[0] = OSError() + self.assertRaises(OSError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + cwd[0] = ValueError() + self.assertRaises(ValueError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + + def test_date(self): + pl = Pl() + with replace_attr(common, 'datetime', Args(now=lambda: Args(strftime=lambda fmt: fmt))): + self.assertEqual(common.date(pl=pl), [{'contents': '%Y-%m-%d', 'highlight_group': ['date'], 'divider_highlight_group': None}]) + self.assertEqual(common.date(pl=pl, format='%H:%M', istime=True), [{'contents': '%H:%M', 'highlight_group': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]) + class TestCommon(TestCase): def test_hostname(self): diff --git a/tests/test_shells/input.zsh b/tests/test_shells/input.zsh index 228a9ca9..f31af608 100644 --- a/tests/test_shells/input.zsh +++ b/tests/test_shells/input.zsh @@ -39,5 +39,7 @@ do break done 1 +hash -d foo=$PWD:h ; cd . +true true is the last line exit diff --git a/tests/test_shells/zsh.daemon.ok b/tests/test_shells/zsh.daemon.ok index d57f2182..7151fc4f 100644 Binary files a/tests/test_shells/zsh.daemon.ok and b/tests/test_shells/zsh.daemon.ok differ diff --git a/tests/test_shells/zsh.nodaemon.ok b/tests/test_shells/zsh.nodaemon.ok index c4b4f6d2..9853d9b6 100644 --- a/tests/test_shells/zsh.nodaemon.ok +++ b/tests/test_shells/zsh.nodaemon.ok @@ -33,3 +33,5 @@ abc 1) def 2) ghi 3) jkl  Select variant  1 def + INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd . + INSERT  ~foo  3rd  true