From 7b7732fe4f62edbaf2e81a019a3f0e3a286a111d Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sun, 31 May 2015 08:30:49 -0700 Subject: [PATCH] [split] Move vi-mode plugin to oh-my-fish/plugin-vi-mode https://github.com/oh-my-fish/plugin-vi-mode --- plugins/vi-mode/README.md | 62 ------- plugins/vi-mode/vi-mode-impl.py | 198 -------------------- plugins/vi-mode/vi-mode.load | 308 -------------------------------- 3 files changed, 568 deletions(-) delete mode 100644 plugins/vi-mode/README.md delete mode 100644 plugins/vi-mode/vi-mode-impl.py delete mode 100644 plugins/vi-mode/vi-mode.load diff --git a/plugins/vi-mode/README.md b/plugins/vi-mode/README.md deleted file mode 100644 index 7450cb7..0000000 --- a/plugins/vi-mode/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# vi-mode -Basic vi key bindings emulation for fish. - -## Install -Add `vi-mode` to your list of fish plugins in your `config.fish`. - -Example: - - set fish_plugins autojump vi-mode - -## Configuration -### Default mode -The default vi mode can be set by defining the variable `vi_mode_default` in -your `config.fish`. -If used, this variable must be set before loading `oh-my-fish`. -Its default value is `vi_mode_insert`. - -To set normal mode as default: - - set vi_mode_default vi_mode_normal - -### Mode indicator -The mode indicator is stored in the variable `vi_mode`. - -See the oh-my-fish theme `simplevi` for an example of integration of the -indicator into the prompt. - -### User key bindings -User additional key bindings can be defined with the function -`vi_mode_user_key_bindings`. If used, this function must be defined before -loading `oh-my-fish`. - -Example: - - function vi_mode_user_key_bindings - bind \el suppress-autosuggestion - end - -## Not implemented -- bind 2 vi-arg-digit -- bind y yank-direction -- bind g magic :-P -- bind ^a increment next number -- bind ^x decrement next number -- bind /?nN search (jk kind of does this) -- registers (maybe try to make sensible integration into X, like an - explicit yank with y goes to an X selection, while an implicit - delete with x etc. doesn't. "\* and "+ should natually go to the - appropriate X selection if possible) -- etc. - -## Author -This mode has been created by [Ian Munsie][ian_github], the original file can -be found [here][original]. -It has been adapted for oh-my-fish by [Sylvain Benner][syl_github]. - -[ian_github]: https://github.com/DarkStarSword -[original]: https://github.com/DarkStarSword/junk/blob/master/vi-mode.fish -[syl_github]: https://github.com/syl20bnr - - - diff --git a/plugins/vi-mode/vi-mode-impl.py b/plugins/vi-mode/vi-mode-impl.py deleted file mode 100644 index ae22eb9..0000000 --- a/plugins/vi-mode/vi-mode-impl.py +++ /dev/null @@ -1,198 +0,0 @@ -# This script is part of the vi-mode plugin for fish -# author: Ian Munsie -# Adapted for oh-my-fish by Sylvain Benner - -import sys -from functools import reduce - -command = sys.argv[1] -direction = sys.argv[2] -new_pos = pos = int(sys.argv[3]) -lineno = int(sys.argv[4]) - 1 -cmdline_list = sys.argv[5:] -cmdline = '\n'.join(cmdline_list) - -def start(): - return (0, 0) -def end(): - return (len(cmdline), -1) -class not_found(Exception): pass - -def dir_0(): - return (reduce(lambda a,b: a + len(b) + 1, cmdline_list[:lineno], 0), 0) - -def dir_eol(): # end of line - before_len = reduce(lambda a,b: a + len(b) + 1, cmdline_list[:lineno], 0) - line_len = len(cmdline_list[lineno]) or 1 - return (before_len + line_len, -1) - -# These routines are all similar, they can probably be combined into one, but -# I'll make sure I get all working and understand the differences first -def dir_fnw(): # First Non-Whitespace - import re - len_before = reduce(lambda a,b: a + len(b) + 1, cmdline_list[:lineno], 0) - match = re.search('^\s*[^\s]', cmdline_list[lineno]) - if not match: - return start() - return (len_before + match.end()-1, 0) -dir__ = dir_fnw # XXX: I always used _ as this, but turns out that might not be quite right - -def _dir_w(regexp): - import re - - searchpart = cmdline[pos:] - match = re.search(regexp, searchpart) - if not match: - return end() - return (pos + match.end()-1, 0) - -def _dir_e(regexp): - import re - - searchpart = cmdline[pos+1:] - match = re.search(regexp, searchpart) - if not match: - return end() - return (pos+2 + match.start(), -1) - -def _dir_b(regexp): - import re - - if pos == 0: - return start() - - # Reverse the string instead of matching to right: - searchpart = cmdline[pos-1::-1] - match = re.search(regexp, searchpart) - if not match: - return start() - return (len(searchpart) - (match.start()+1), 0) - -def _dir_ge(regexp): - import re - - if pos == 0: - return start() - - # Reverse the string instead of matching to right: - searchpart = cmdline[pos::-1] - match = re.search(regexp, searchpart) - if not match: - return start() - return (len(searchpart) - (match.end()), 0) - -# Simple, but not inclusive enough: -# def dir_w(): return _dir_w(r'[^\w]\w') -# def dir_e(): return _dir_e(r'\w[^\w]') - -# Slightly too inclusive, e.g. fi--sh matches both '-' characters, but should only match one: -_dir_w_regexp = r'[^\w][^\s]|\w[^\w\s]' -_dir_e_regexp = r'[^\s][^\w]|[^\w\s]\w' -_dir_W_regexp = r'\s[^\s]' -_dir_E_regexp = r'[^\s]\s' - -def dir_w(): return _dir_w(_dir_w_regexp) -def dir_W(): return _dir_w(_dir_W_regexp) -def dir_e(): return _dir_e(_dir_e_regexp) -def dir_E(): return _dir_e(_dir_E_regexp) -def dir_b(): return _dir_b(_dir_e_regexp) -def dir_B(): return _dir_b(_dir_E_regexp) -def dir_ge(): return _dir_ge(_dir_w_regexp) -def dir_gE(): return _dir_ge(_dir_W_regexp) -def dir_cw(): return _dir_w(_dir_e_regexp) -def dir_cW(): return _dir_w(_dir_E_regexp) - -def dir_h(): - if pos: return (pos-1, 0) - return start() - -def dir_l(): - return (pos+1, 0) - -def dir_t(char): - new_pos = cmdline.find(char, pos+1) - if new_pos < 0: - raise not_found - return (new_pos, -1) - -def dir_T(char): - new_pos = cmdline.rfind(char, 0, pos) - if new_pos < 0: - raise not_found - return (new_pos+1, 0) - -def dir_f(char): return (dir_t(char)[0]+1, -1) -def dir_F(char): return (dir_T(char)[0]-1, 0) - -def cmd_delete(): - dst_pos = dir(direction) - if dst_pos >= pos: - new_cmdline = cmdline[:pos] + cmdline[dst_pos:] - return (new_cmdline, pos) - new_cmdline = cmdline[:dst_pos] + cmdline[pos:] - return (new_cmdline, dst_pos) - -def cmd_change(): - # 'Special case: 'cw' and 'cW' are treated like 'ce' and 'cE' if the cursor - # is on a non-blank. This is because 'cw' is interpreted as change-word, - # and a word does not include the following white space.' - # - # Note: Even with this special case the behaviour does not quite match what - # vim actually does in practice - try with the cursor on punctuation, or on - # the last character in a word. Specifically, the behaviour of cw differs - # from ce when the cursor is already on the last character of a 'word', for - # vim's definition of word. - # - # Because of this, we use a special direction to handle this case. - global direction - if direction in 'wW' and not cmdline[pos].isspace(): - direction = direction.replace('w', 'cw').replace('W', 'cW') - return cmd_delete() - -def cmd_o(): - above = '\n'.join(cmdline_list[:lineno + 1]) - below = '\n'.join(cmdline_list[lineno + 1:]) - return (above + '\n\n' + below, len(above)+1) - -def cmd_O(): - above = '\n'.join(cmdline_list[:lineno]) - below = '\n'.join(cmdline_list[lineno:]) - return (above + '\n\n' + below, len(above)+1) - -def _dir_cmd_func(func): - (pos1, pos2) = (pos, dir(direction)) - if pos2 < pos: - (pos1, pos2) = (pos2, pos1) - new_cmdline = cmdline[:pos1] + func(cmdline[pos1:pos2]) + cmdline[pos2:] - return (new_cmdline, pos1) - -# XXX: automagic completion sometimes hides the results of changing the case in these commands: -def cmd_upper(): return _dir_cmd_func(str.upper) -def cmd_lower(): return _dir_cmd_func(str.lower) -def cmd_swapcase(): return _dir_cmd_func(str.swapcase) - -def dir(d, cursor = False): - def validate(pos): - if pos < 0: return 0 - if pos > len(cmdline): return len(cmdline) - return pos - a = () - if ':' in d: - (d, a) = d.split(':', 1) - (new_pos, cursor_off) = globals()['dir_%s' % d](*a) - if cursor: - return validate(new_pos + cursor_off) - return validate(new_pos) - -def cmd(c): return globals()['cmd_%s' % c]() - -def cmd_normal(): - return (None, dir(direction, True)) - -try: - (cmdline, new_pos) = cmd(command) - if cmdline is not None: - print ( cmdline ) -except not_found: - new_pos = pos -print ( new_pos ) diff --git a/plugins/vi-mode/vi-mode.load b/plugins/vi-mode/vi-mode.load deleted file mode 100644 index 134fbc7..0000000 --- a/plugins/vi-mode/vi-mode.load +++ /dev/null @@ -1,308 +0,0 @@ -set_color normal - -# vi:noexpandtab:sw=4:ts=4 -# -# vi-mode for fish -# author: Ian Munsie -# Adapted for oh-my-fish by Sylvain Benner -# -# Requirements: fish 2.0+ - -# I'm thinking about changing these to separate out the colours from the text. -# I'm undecided on this though - when I support count arguments there may be -# some benefit from displaying the count here, but that would also make the -# size of these strings vary, which I'd rather not do... -set -l cn (set_color normal 2>/dev/null) -set -g vi_mode_normal (set_color blue 2>/dev/null)'n'$cn -set -g vi_mode_replace (set_color red 2>/dev/null)'r'$cn -set -g vi_mode_REPLACE (set_color --background=red 2>/dev/null)'R'$cn -set -g vi_mode_insert (set_color green 2>/dev/null)'i'$cn -set -g vi_mode_delete (set_color red 2>/dev/null)'d'$cn -set -g vi_mode_change (set_color yellow 2>/dev/null)'c'$cn -set -g vi_mode_g (set_color blue 2>/dev/null)'g'$cn -set -g vi_mode_lower (set_color blue 2>/dev/null)'u'$cn -set -g vi_mode_upper (set_color blue 2>/dev/null)'U'$cn -set -g vi_mode_swapcase (set_color blue 2>/dev/null)'~'$cn - -set -g __vi_mode_undo_cmdline '' -set -g __vi_mode_undo_cmdline_pos 0 - -# default vi mode -if test -z $vi_mode_default - set -g vi_mode_default vi_mode_insert -end - -# additional user key bindings go in vi_mode_user_key_bindings -function __vi_mode_user_key_bindings - if functions | grep "vi_mode_user_key_bindings" > /dev/null - vi_mode_user_key_bindings - end -end - -function __vi_mode_direction_command - # commandline should always be last - set ret (python (dirname (status -f))/vi-mode-impl.py $argv[1] $argv[2] (commandline -C) (commandline -L) (commandline)) - set new_pos $ret[-1] - set -e ret[-1] # Guessing that deleting last element is likely to be faster than deleting first - if test (count $ret) -gt 0 - commandline -- $ret - end - commandline -C $new_pos -end - -function __vi_mode_common_emacs -d "common key bindings for all vi-like modes that are identical to the emacs mode" - # Feel free to expand this list for anything that makes sense, this is just - # a couple of hand-picked ones that seemed useful and/or I use :) - - bind \e\[A up-or-search - bind \e\[B down-or-search - bind -k down down-or-search - bind -k up up-or-search - - bind \e\[C forward-char - bind \e\[D backward-char - bind -k right forward-char - bind -k left backward-char - - bind \e\[H beginning-of-line - bind \e\[F end-of-line - # OS X SnowLeopard doesn't have these keys. Don't show an annoying error message. - bind -k home beginning-of-line 2> /dev/null - bind -k end end-of-line 2> /dev/null - - bind \cl 'clear; commandline -f repaint' - bind \cd delete-or-exit -end - -function __vi_mode_common -d "common key bindings for all vi-like modes" - __vi_mode_common_emacs - - bind \e vi_mode_normal - - # Can we put commandline into history when pressing ^C? - bind \cc '__vi_mode_save_cmdline; for i in (seq (count (commandline))); echo; end; commandline ""; vi_mode_insert' - - bind \n "commandline -f execute; "$vi_mode_default - __vi_mode_user_key_bindings -end - -function __vi_mode_common_insert -d "common key bindings for all insert vi-like modes" - __vi_mode_common - bind \e 'commandline -f backward-char; vi_mode_normal' - if functions -q vi_mode_user - vi_mode_user insert - end -end - -function __vi_mode_bind_directions - __vi_mode $argv[1] - - for direction in W w E e B b 0 _ h l - bind $direction "$argv[3]; __vi_mode_direction_command '$argv[1]' $direction; $argv[2]" - end - bind \$ "$argv[3]; __vi_mode_direction_command '$argv[1]' eol; $argv[2]" - bind \^ "$argv[3]; __vi_mode_direction_command '$argv[1]' fnw; $argv[2]" - for direction in f F t T - bind $direction "__vi_mode_bind_all '$argv[3]; __vi_mode_direction_command %q$argv[1]%q {$direction}:%k; $argv[2]'" - end - - bind g "__vi_mode_bind_directions_g $argv" -end - -function __vi_mode_bind_directions_g - for direction in e E - bind $direction "$argv[3]; __vi_mode_direction_command '$argv[1]' g$direction; $argv[2]" - end -end - -function __vi_mode_bind_all - # There seems to be some magic that doesn't work properly without this: - bind '' self-insert - - python -c " -command = '''$argv''' -for c in map(chr, range(0x20, 0x7f)): - q = '\"' # Enclose command in these - Q = '\'' # Other quote - for quotes inside command - if c == '\"': - l = r = r'\\%s' % c - (q, Q) = (Q, q) # Swap quotes - elif c in ['(', ')', '<', '>', ';', '|', '\'']: - l = r = r'\%s' % c - elif c == '\\\\': - l = r'\\\\' - r = r'\\\\\\\\' - elif c == '\$': - l = '\%s' % c - r = r\"'\%s'\" % c - else: - l = r = \"'%s'\" % c - print ( 'bind %s %s%s%s' % (l, q, command.replace('%k', r).replace('%q', Q), q)) - " | . -end - -function __vi_mode - # Is there a way to do this without eval? - # We really want something like a dictionary... - eval set -g vi_mode \$vi_mode_{$argv} - commandline -f repaint -end - -function __vi_mode_replace - __vi_mode replace - bind --erase --all - __vi_mode_common - - # backward-char should happen last, but only works if specified first - # (guess I should dig through the C code and figure out what is going - # on): - # __vi_mode_bind_all "commandline -f delete-char; commandline -i %k; commandline -f backward-char; vi_mode_normal" - __vi_mode_bind_all "__vi_mode_save_cmdline; commandline -f backward-char delete-char; commandline -i %k; vi_mode_normal" - - if functions -q vi_mode_user - vi_mode_user replace - end -end - -function __vi_mode_overwrite - __vi_mode REPLACE - bind --erase --all - __vi_mode_common_insert - __vi_mode_save_cmdline - - __vi_mode_bind_all "commandline -f delete-char; commandline -i %k" - if functions -q vi_mode_user - vi_mode_user overwrite - end -end - -function __vi_mode_save_cmdline - # Only vi style single level for now, patch to suppport vim style - # multi-level undo history welcome - set -g __vi_mode_undo_cmdline (commandline) - set -g __vi_mode_undo_cmdline_pos (commandline -C) -end - -function __vi_mode_undo - set -l cmdline (commandline) - set -l pos (commandline -C) - commandline $__vi_mode_undo_cmdline - commandline -C $__vi_mode_undo_cmdline_pos - set -g __vi_mode_undo_cmdline $cmdline - set -g __vi_mode_undo_cmdline_pos $pos -end - -function __vi_mode_g -d "vi-like key bindings for fish (commands starting with g)" - __vi_mode g - bind --erase --all - __vi_mode_bind_all 'vi_mode_normal' - __vi_mode_common - - bind I '__vi_mode_save_cmdline; commandline -f beginning-of-line; vi_mode_insert' - # XXX: automagic completion sometimes hides the results of changing the case in these commands: - bind u '__vi_mode_bind_directions lower vi_mode_normal __vi_mode_save_cmdline' - bind U '__vi_mode_bind_directions upper vi_mode_normal __vi_mode_save_cmdline' - bind \~ '__vi_mode_bind_directions swapcase vi_mode_normal __vi_mode_save_cmdline' - # TODO: The rest of the g commands + directions. - - __vi_mode_bind_directions_g normal vi_mode_normal '' - - if functions -q vi_mode_user - vi_mode_user g - end -end - -function vi_mode_normal -d "WIP vi-like key bindings for fish (normal mode)" - __vi_mode normal - - bind --erase --all - - # NOTE: bind '' self-insert seems to be required to allow the - # prompt to change, but we don't want unbound keys to be able to - # self-insert, so set the default binding, but bind everything to - # do nothing (which is wasteful, but seems to work): - __vi_mode_bind_all '' - - __vi_mode_common - - # Fish recently gained support for this, redirect to /dev/null so it - # doesn't fall over if running an old version of fish: - commandline -f suppress-autosuggestion 2>/dev/null - - bind i '__vi_mode_save_cmdline; vi_mode_insert' - bind I '__vi_mode_save_cmdline; __vi_mode_direction_command normal fnw; vi_mode_insert' - bind a '__vi_mode_save_cmdline; commandline -f forward-char; vi_mode_insert' - bind A '__vi_mode_save_cmdline; commandline -f end-of-line; vi_mode_insert' - bind o '__vi_mode_save_cmdline; __vi_mode_direction_command o ""; vi_mode_insert' - bind O '__vi_mode_save_cmdline; __vi_mode_direction_command O ""; vi_mode_insert' - - # Cool, these functions are pretty close to what I wanted: - # FIXME: Cursor not placed in correct position, but moving it prevents further searching - bind j down-or-search - bind k up-or-search - - bind x '__vi_mode_save_cmdline; commandline -f delete-char' - bind D '__vi_mode_save_cmdline; commandline -f kill-line' - # bind Y 'commandline -f kill-whole-line yank' - bind P '__vi_mode_save_cmdline; commandline -f yank' - bind p '__vi_mode_save_cmdline; commandline -f yank forward-char' # Yes, this is reversed. Otherwise it does the wrong thing. Go figure. - bind C '__vi_mode_save_cmdline; commandline -f kill-line; vi_mode_insert' - bind S '__vi_mode_save_cmdline; commandline -f kill-whole-line; vi_mode_insert' - bind s '__vi_mode_save_cmdline; commandline -f delete-char; vi_mode_insert' - bind r __vi_mode_replace - bind R __vi_mode_overwrite - - # XXX: The automagic completion sometimes displays the case from the - # command it wants to complete instead of the case actually on the - # commandline, so even though this works, it may not always appear to work. - # I'm not sure if I can do anything about that, I'll need to look at the - # code. Ideally I would turn off automagic completion whenever I'm not in - # insert mode. - bind \~ '__vi_mode_save_cmdline; commandline -f forward-char; __vi_mode_direction_command swapcase l' - - __vi_mode_bind_directions normal vi_mode_normal '' - bind d '__vi_mode_bind_directions delete vi_mode_normal __vi_mode_save_cmdline' - bind c '__vi_mode_bind_directions change vi_mode_insert __vi_mode_save_cmdline' - - # Override generic direction code for simple things that have a close - # match in fish's builtin commands, which should be faster: - bind h backward-char - bind l forward-char - bind 0 beginning-of-line - # bind \$ end-of-line #FIXME: Cursor position - # bind b backward-word # Note: built-in implementation only recently fixed. Also, before enabling this override, determine if this matches on the right characters - - bind g __vi_mode_g # MUST BE AFTER BIND_DIRECTIONS... I'm thinking about changing it so that this is all handled by bind_directions - bind u __vi_mode_undo - - # NOT IMPLEMENTED: - # bind 2 vi-arg-digit - # bind y yank-direction - # bind g magic :-P - # bind ^a increment next number - # bind ^x decrement next number - # bind /?nN search (jk kind of does this) - # registers (maybe try to make sensible integration into X, like an - # explicit yank with y goes to an X selection, while an implicit - # delete with x etc. doesn't. "* and "+ should natually go to the - # appropriate X selection if possible) - # etc. - - if functions -q vi_mode_user - vi_mode_user normal - end -end - -function vi_mode_insert -d "vi-like key bindings for fish (insert mode)" - __vi_mode insert - - fish_default_key_bindings - - __vi_mode_common_insert -end - -function fish_user_key_bindings - eval $vi_mode_default -end - -# vi:noexpandtab:sw=4:ts=4