Merge pull request #709 from ZyX-I/zsh-vi-mode

Add support for modes to shell bindings
This commit is contained in:
ZyX-I 2014-01-26 10:38:19 -08:00
commit e18a2e62fa
13 changed files with 140 additions and 11 deletions

View File

@ -36,6 +36,7 @@ _powerline_precmd() {
# wrong number of jobs. You need to filter the lines first. Or not use
# jobs built-in at all.
_POWERLINE_JOBNUM=${(%):-%j}
_powerline_set_true_keymap_name "${${(Q)${${(z)${"$(bindkey -lL main)"}}[3]}}:-.safe}"
}
_powerline_setup_prompt() {
@ -47,6 +48,7 @@ _powerline_setup_prompt() {
done
precmd_functions+=( _powerline_precmd )
chpwd_functions+=( _powerline_tmux_set_pwd )
_powerline_set_true_keymap_name "${${(Q)${${(z)${"$(bindkey -lL main)"}}[3]}}:-.safe}"
if zmodload zsh/zpython &>/dev/null ; then
zpython 'from powerline.bindings.zsh import setup as powerline_setup'
zpython 'powerline_setup()'
@ -59,6 +61,48 @@ _powerline_setup_prompt() {
fi
}
_powerline_add_widget() {
local widget="$1"
local function="$2"
local old_widget_command="$(zle -l -L $widget)"
if [[ "$old_widget_command" = "zle -N $widget $function" ]] ; then
return 0
elif [[ -z "$old_widget_command" ]] ; then
zle -N $widget $function
else
local save_widget="powerline_save_$widget"
local -i i=0
while ! test -z "$(zle -l -L $save_widget)" ; do
save_widget="${save_widget}_$i"
(( i++ ))
done
eval "${old_widget_command/$widget/$save_widget}"
zle -N $widget $function
export POWERLINE_SAVE_WIDGET="$save_widget"
fi
}
_powerline_set_true_keymap_name() {
export POWERLINE_MODE="${1}"
local plm_bk="$(bindkey -lL ${POWERLINE_MODE})"
if [[ $plm_bk = 'bindkey -A'* ]] ; then
_powerline_set_true_keymap_name ${(Q)${${(z)plm_bk}[3]}}
fi
}
_powerline_zle_keymap_select() {
_powerline_set_true_keymap_name $KEYMAP
zle reset-prompt
test -z "$POWERLINE_SAVE_WIDGET" || zle $POWERLINE_SAVE_WIDGET
}
_powerline_add_widget zle-keymap-select _powerline_zle_keymap_select
_powerline_precmd
if [[ "$POWERLINE_MODE" != vi* ]] ; then
export POWERLINE_DEFAULT_MODE="$POWERLINE_MODE"
fi
trap "_powerline_tmux_set_columns" SIGWINCH
_powerline_tmux_set_columns
_powerline_tmux_set_pwd

View File

@ -14,6 +14,14 @@
"hostname": { "fg": "brightyellow", "bg": "mediumorange" },
"exit_fail": { "fg": "white", "bg": "darkestred" },
"exit_success": { "fg": "white", "bg": "darkestgreen" },
"environment": { "fg": "white", "bg": "darkestgreen" }
"environment": { "fg": "white", "bg": "darkestgreen" },
"mode": { "fg": "darkestgreen", "bg": "brightgreen", "attr": ["bold"] }
},
"mode_translations": {
"vicmd": {
"groups": {
"mode": {"fg": "darkestcyan", "bg": "white", "attr": ["bold"]}
}
}
}
}

View File

@ -14,6 +14,14 @@
"hostname": { "fg": "oldlace", "bg": "darkgreencopper" },
"exit_fail": { "fg": "oldlace", "bg": "red" },
"exit_success": { "fg": "oldlace", "bg": "green" },
"environment": { "fg": "oldlace", "bg": "green" }
"environment": { "fg": "oldlace", "bg": "green" },
"mode": { "fg": "oldlace", "bg": "green", "attr": ["bold"] }
},
"mode_translations": {
"vicmd": {
"groups": {
"mode": { "fg": "oldlace", "bg": "blue", "attr": ["bold"] }
}
}
}
}

View File

@ -16,6 +16,10 @@
},
"segments": {
"left": [
{
"module": "powerline.segments.shell",
"name": "mode"
},
{
"name": "hostname"
},

View File

@ -535,15 +535,15 @@ group_name_spec = Spec().re('^\w+(?::\w+)?$').copy
groups_spec = Spec().unknown_spec(
group_name_spec(),
group_spec(),
).copy
).context_message('Error while loading groups (key {key})').copy
colorscheme_spec = (Spec(
name=name_spec(),
groups=groups_spec().context_message('Error while loading groups (key {key})'),
groups=groups_spec(),
).context_message('Error while loading coloscheme'))
vim_mode_spec = Spec().oneof(set(list(vim_modes) + ['nc'])).copy
vim_colorscheme_spec = (Spec(
name=name_spec(),
groups=groups_spec().context_message('Error while loading groups (key {key})'),
groups=groups_spec(),
mode_translations=Spec().unknown_spec(
vim_mode_spec(),
Spec(
@ -558,6 +558,24 @@ vim_colorscheme_spec = (Spec(
),
).context_message('Error while loading mode translations (key {key})'),
).context_message('Error while loading vim colorscheme'))
shell_mode_spec = Spec().re('^(?:[\w\-]+|\.safe)$').copy
shell_colorscheme_spec = (Spec(
name=name_spec(),
groups=groups_spec(),
mode_translations=Spec().unknown_spec(
shell_mode_spec(),
Spec(
colors=Spec().unknown_spec(
color_spec(),
color_spec(),
).optional(),
groups=Spec().unknown_spec(
group_name_spec().func(check_translated_group_name),
group_spec(),
).optional(),
),
).context_message('Error while loading mode translations (key {key})'),
).context_message('Error while loading shell colorscheme'))
generic_keys = set(('exclude_modes', 'include_modes', 'width', 'align', 'name', 'draw_soft_divider', 'draw_hard_divider', 'priority', 'after', 'before'))
@ -1106,6 +1124,8 @@ def check(path=None, debug=False):
colorscheme_configs[ext][colorscheme] = config
if ext == 'vim':
spec = vim_colorscheme_spec
elif ext == 'shell':
spec = shell_colorscheme_spec
else:
spec = colorscheme_spec
if spec.match(config, context=(('', config),), data=data, echoerr=ee)[1]:

View File

@ -150,7 +150,7 @@ class Renderer(object):
segment['divider_highlight'] = None
return segment
def get_segment_info(self, segment_info):
def get_segment_info(self, segment_info, mode):
'''Get segment information.
Must return a dictionary containing at least ``home``, ``environ`` and
@ -167,6 +167,7 @@ class Renderer(object):
:return: dict with segment information.
'''
r = self.segment_info.copy()
r['mode'] = mode
if segment_info:
r.update(segment_info)
if 'PWD' in r['environ']:
@ -201,7 +202,7 @@ class Renderer(object):
Matcher information. Is processed in ``.get_theme()`` method.
'''
theme = self.get_theme(matcher_info)
segments = theme.get_segments(side, self.get_segment_info(segment_info))
segments = theme.get_segments(side, self.get_segment_info(segment_info, mode))
# Handle excluded/included segments for the current mode
segments = [self._get_highlighting(segment, mode) for segment in segments

View File

@ -9,7 +9,7 @@ class IpythonRenderer(ShellRenderer):
escape_hl_start = '\x01'
escape_hl_end = '\x02'
def get_segment_info(self, segment_info):
def get_segment_info(self, segment_info, mode):
r = self.segment_info.copy()
r['ipython'] = segment_info
return r

View File

@ -46,7 +46,7 @@ class TmuxRenderer(Renderer):
tmux_attr += ['nounderscore']
return '#[' + ','.join(tmux_attr) + ']'
def get_segment_info(self, segment_info):
def get_segment_info(self, segment_info, mode):
r = self.segment_info.copy()
if segment_info:
r.update(segment_info)
@ -54,6 +54,7 @@ class TmuxRenderer(Renderer):
varname = 'TMUX_PWD_' + r['pane_id'].lstrip('%')
if varname in r['environ']:
r['getcwd'] = lambda: r['environ'][varname]
r['mode'] = mode
return r

View File

@ -74,7 +74,7 @@ class VimRenderer(Renderer):
def strwidth(string):
return vim.strwidth(string)
def get_segment_info(self, segment_info):
def get_segment_info(self, segment_info, mode):
return segment_info or self.segment_info
def render(self, window, window_id, winnr):

View File

@ -41,3 +41,34 @@ def last_pipe_status(pl, segment_info):
for status in last_pipe_status]
else:
return None
@requires_segment_info
def mode(pl, segment_info, override={'vicmd': 'COMMND', 'viins': 'INSERT'}, default=None):
'''Return the current mode.
:param dict override:
dict for overriding mode strings.
:param str default:
If current mode is equal to this string then this segment will not get
displayed. If not specified the value is taken from
``$POWERLINE_DEFAULT_MODE`` variable. This variable is set by zsh
bindings for any mode that does not start from ``vi``.
'''
mode = segment_info['mode']
if not mode:
pl.warn('No or empty POWERLINE_MODE variable')
return None
default = default or segment_info['environ'].get('POWERLINE_DEFAULT_MODE')
if mode == default:
return None
try:
return override[mode]
except KeyError:
# Note: with zsh line editor you can emulate as much modes as you wish.
# Thus having unknown mode is not an error: maybe just some developer
# added support for his own zle widgets. As there is no built-in mode()
# function like in VimL and POWERLINE_MODE is likely be defined by our
# code or by somebody knowing what he is doing there is absolutely no
# need in keeping translations dictionary.
return mode.upper()

View File

@ -22,6 +22,7 @@ if __name__ == '__main__':
width=args.width,
side=args.side,
segment_info=segment_info,
mode=os.environ.get('POWERLINE_MODE'),
)
try:
sys.stdout.write(rendered)

View File

@ -19,6 +19,11 @@ cd ../'#[bold]'
cd ../'(echo)'
cd ../'$(echo)'
cd ../'`echo`'
cd ..
POWERLINE_COMMAND=( $POWERLINE_COMMAND[1,4] ${${POWERLINE_COMMAND[5]}/_leftonly} ) ; bindkey -v

echo abc
false
true is the last line
exit

View File

@ -16,4 +16,10 @@
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  #[bold]  cd ../'(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  (echo)  cd ../'$(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  $(echo)  cd ../'`echo`'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  false
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  cd ..
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  POWERLINE_COMMAND=( $POWERLINE_COMMAND[1,4] ${${POWERLINE_COMMAND[5]}/_leftonly} ) ; bindkey -v
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd   COMMND   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc
abc
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  false