From 550b84c3ddf77b86b4d7182fa0eea73eeeb73ae2 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 20 Jan 2011 21:20:05 +0100 Subject: [PATCH 1/5] vim-mode: Support ^H as BS key. Reported by peth. At the moment it's not working for custom mappings though! --- vim-mode/vim_mode.pl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 7d898ab..a0be248 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -312,6 +312,7 @@ # arrow like movement h => { char => 'h', func => \&cmd_h, type => C_NORMAL }, l => { char => 'l', func => \&cmd_l, type => C_NORMAL }, + "\x08" => { char => '', func => \&cmd_h, type => C_NORMAL }, "\x7F" => { char => '', func => \&cmd_h, type => C_NORMAL }, ' ' => { char => '', func => \&cmd_l, type => C_NORMAL }, # history movement @@ -2347,9 +2348,9 @@ sub got_key { _stop(); return; - # Pressing delete resets insert mode repetition. + # Pressing delete resets insert mode repetition (8 = BS, 127 = DEL). # TODO: maybe allow it - } elsif ($key == 127) { + } elsif ($key == 8 || $key == 127) { @insert_buf = (); # All other entered characters need to be stored to allow repeat of # insert mode. Ignore delete and control characters. @@ -2743,8 +2744,8 @@ sub handle_command_cmd { sub handle_command_ex { my ($key) = @_; - # DEL key - remove last character - if ($key == 127) { + # BS key (8) or DEL key (127) - remove last character. + if ($key == 8 || $key == 127) { print "Delete" if DEBUG; if (scalar @ex_buf > 0) { pop @ex_buf; From ab0e95cfa1d1f72c2df4e6debe687d6a9e94f839 Mon Sep 17 00:00:00 2001 From: Sascha Friedmann Date: Fri, 28 Jan 2011 23:58:25 +0100 Subject: [PATCH 2/5] vim-mode: use a mapping table for extended mode. Build and maintain a mapping table for extended mode the same way it's already done for command mode ("normal mode"). --- vim-mode/vim_mode.pl | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a0be248..9b7c421 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -503,7 +503,15 @@ # Add all default mappings. foreach my $char (keys %$commands) { next if $char =~ /^_/; # skip private commands (text-objects for now) - add_map($char, $commands->{$char}); + add_map($maps, $char, $commands->{$char}); +} + +# default extended mode mappings +my $ex_maps = {}; + +# Add all default mappings. +foreach my $char (keys %$commands_ex) { + add_map($ex_maps, $char, $commands_ex->{$char}); } # GLOBAL VARIABLES @@ -1634,10 +1642,14 @@ sub cmd_ex_command { return _warn("Invalid Ex-mode command!"); } - # Abort if command doesn't exist or used with count for unsupported - # commands. - if (not exists $commands_ex->{$2} or - ($1 ne '' and not $commands_ex->{$2}->{uses_count})) { + # Abort if command doesn't exist + if (not exists $ex_maps->{$2}) { + return _warn("Ex-mode $1$2 doesn't exist!"); + } + + my $cmd = $ex_maps->{$2}->{cmd}; + # Abort if used with count for unsupported commands. + if ($1 ne '' and not $cmd->{uses_count}) { return _warn("Ex-mode $1$2 doesn't exist!"); } @@ -1645,7 +1657,8 @@ sub cmd_ex_command { if ($count eq '') { $count = undef; } - $commands_ex->{$2}->{func}($arg_str, $count); + + $cmd->{func}($arg_str, $count); } sub ex_substitute { @@ -1976,7 +1989,7 @@ sub ex_map { $command = $commands->{$rhs}; } } - add_map($lhs, $command); + add_map($maps, $lhs, $command); # :map [lhs] } elsif ($arg_str =~ m/^map\s*$/ or $arg_str =~ m/^map (\S+)$/) { @@ -2017,7 +2030,7 @@ sub ex_unmap { return _warn_ex('unmap', "$1 not found"); } - delete_map($lhs); + delete_map($maps, $lhs); } sub _parse_mapping { my ($string) = @_; @@ -2935,7 +2948,7 @@ sub _reset_undo_buffer { } sub add_map { - my ($keys, $command) = @_; + my ($maps, $keys, $command) = @_; # To allow multiple mappings starting with the same key (like gg, ge, gE) # also create maps for the keys "leading" to this key (g in this case, but @@ -2966,7 +2979,7 @@ sub add_map { } sub delete_map { - my ($keys) = @_; + my ($maps, $keys) = @_; # Abort for non-existent mappings or placeholder mappings. return if not exists $maps->{$keys} or not defined $maps->{$keys}->{cmd}; @@ -3000,7 +3013,7 @@ sub delete_map { # key. foreach my $key (@add) { if (exists $commands->{$key}) { - add_map($key, $commands->{$key}); + add_map($maps, $key, $commands->{$key}); } } } From eeeb1812d2e4a802dec73f6ddecf219b06f3bc0b Mon Sep 17 00:00:00 2001 From: Sascha Friedmann Date: Sun, 30 Jan 2011 22:02:20 +0100 Subject: [PATCH 3/5] vim-mode: add :cmap. --- vim-mode/vim_mode.pl | 50 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 9b7c421..cd2f2a9 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -76,6 +76,8 @@ # * Mappings: :map - display custom mappings # :map {lhs} - display mappings starting with {lhs} # :map {lhs} {rhs} - add mapping +# :cmap - same as :map but for ex-mode, e.g. +# use :cmap LS :ls and not :cmap LS ls! # :unm[ap] {lhs} - remove custom mapping # * Save mappings: :mkv[imrc][!] - like in Vim, but [file] not supported # * Substitute: :s/// - i and g are supported as flags, only /// can be @@ -464,6 +466,8 @@ type => C_EX }, unm => { char => ':unm', func => \&ex_unmap, type => C_EX }, + cmap => { char => ':cmap', func => \&ex_cmap, + type => C_EX }, source => { char => ':source', func => \&ex_source, type => C_EX }, so => { char => ':so', func => \&ex_source, @@ -1658,7 +1662,25 @@ sub cmd_ex_command { $count = undef; } - $cmd->{func}($arg_str, $count); + # Ex-mode commands are either bound to ex commands or... + if ($cmd->{type} == C_EX) { + print "Processing ex-command: $2 ($cmd->{char})" if DEBUG; + + $cmd->{func}($arg_str, $count); + # ...irssi commands. + } elsif ($cmd->{type} == C_IRSSI) { + print "Processing irssi-command: $2 ($cmd->{char})" if DEBUG; + + # TODO: fix me more better (general server/win/none context?) + my $server = Irssi::active_server; + if (defined $server) { + $server->command($cmd->{func}); + } else { + Irssi::command($cmd->{func}); + } + } else { + return _warn("Ex-mode command of unknown type $cmd->{type} bound to :$2!"); + } } sub ex_substitute { @@ -1941,16 +1963,16 @@ sub ex_undolist { _print_undo_buffer(); } -sub ex_map { - my ($arg_str, $count) = @_; +sub _ex_map { + my ($cmd_name, $maps, $arg_str, $count) = @_; # :map {lhs} {rhs} - if ($arg_str =~ /^map (\S+) (\S.*)$/) { + if ($arg_str =~ /^$cmd_name (\S+) (\S.*)$/) { my $lhs = _parse_mapping($1); my $rhs = $2; if (not defined $lhs) { - return _warn_ex('map', 'invalid {lhs}'); + return _warn_ex($cmd_name, 'invalid {lhs}'); } # Add new mapping. @@ -1959,7 +1981,7 @@ sub ex_map { if (index($rhs, ':') == 0) { $rhs =~ /^:(\S+)(\s.+)?$/; if (not exists $commands_ex->{$1}) { - return _warn_ex('map', "$rhs not found"); + return _warn_ex($cmd_name, "$rhs not found"); } else { $command = { char => $rhs, func => $commands_ex->{$1}->{func}, @@ -1982,9 +2004,9 @@ sub ex_map { } else { $rhs = _parse_mapping($2); if (not defined $rhs) { - return _warn_ex('map', 'invalid {rhs}'); + return _warn_ex($cmd_name, 'invalid {rhs}'); } elsif (not exists $commands->{$rhs}) { - return _warn_ex('map', "$2 not found"); + return _warn_ex($cmd_name, "$2 not found"); } else { $command = $commands->{$rhs}; } @@ -1992,7 +2014,7 @@ sub ex_map { add_map($maps, $lhs, $command); # :map [lhs] - } elsif ($arg_str =~ m/^map\s*$/ or $arg_str =~ m/^map (\S+)$/) { + } elsif ($arg_str =~ m/^$cmd_name\s*$/ or $arg_str =~ m/^$cmd_name (\S+)$/) { # Necessary for case insensitive matchings. lc alone won't work. my $search = $1; $search = '' if not defined $search; @@ -2010,9 +2032,13 @@ sub ex_map { } } } else { - _warn_ex('map'); + _warn_ex($cmd_name); } } +sub ex_map { + my ($arg_str, $count) = @_; + return _ex_map('map', $maps, $arg_str, $count); +} sub ex_unmap { my ($arg_str, $count) = @_; @@ -2032,6 +2058,10 @@ sub ex_unmap { delete_map($maps, $lhs); } +sub ex_cmap { + my ($arg_str, $count) = @_; + return _ex_map('cmap', $ex_maps, $arg_str, $count); +} sub _parse_mapping { my ($string) = @_; From b979f53810d6a89648481a643f58262b721e3faf Mon Sep 17 00:00:00 2001 From: Sascha Friedmann Date: Sun, 30 Jan 2011 22:41:40 +0100 Subject: [PATCH 4/5] vim-mode: add :cunmap. --- vim-mode/vim_mode.pl | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cd2f2a9..e0a3984 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -79,6 +79,7 @@ # :cmap - same as :map but for ex-mode, e.g. # use :cmap LS :ls and not :cmap LS ls! # :unm[ap] {lhs} - remove custom mapping +# :cunm[ap] {lhs} - remove custom mapping in ex-mode # * Save mappings: :mkv[imrc][!] - like in Vim, but [file] not supported # * Substitute: :s/// - i and g are supported as flags, only /// can be # used as separator, uses Perl regex instead of @@ -468,6 +469,10 @@ type => C_EX }, cmap => { char => ':cmap', func => \&ex_cmap, type => C_EX }, + cunmap => { char => ':cunmap', func => \&ex_cunmap, + type => C_EX }, + cunm => { char => ':cunm', func => \&ex_cunmap, + type => C_EX }, source => { char => ':source', func => \&ex_source, type => C_EX }, so => { char => ':so', func => \&ex_source, @@ -1679,7 +1684,7 @@ sub cmd_ex_command { Irssi::command($cmd->{func}); } } else { - return _warn("Ex-mode command of unknown type $cmd->{type} bound to :$2!"); + return _warn("Ex-mode command of unsupported type $cmd->{type} bound to :$2!"); } } @@ -2062,6 +2067,25 @@ sub ex_cmap { my ($arg_str, $count) = @_; return _ex_map('cmap', $ex_maps, $arg_str, $count); } +sub ex_cunmap { + my ($arg_str, $count) = @_; + + # :cunm[ap] {lhs} + if ($arg_str !~ /^cunm(?:ap)? (\S+)$/) { + return _warn_ex('cunmap'); + } + + my $lhs = _parse_mapping($1); + if (not defined $lhs) { + return _warn_ex('cunmap', 'invalid {lhs}'); + # Prevent unmapping of unknown or default mappings. + } elsif (not exists $ex_maps->{$lhs} or not defined $ex_maps->{$lhs}->{cmd} or + ($commands_ex->{$lhs} and $ex_maps->{$lhs}->{cmd} == $commands_ex->{$lhs})) { + return _warn_ex('cunmap', "$1 not found"); + } + + delete_map($ex_maps, $lhs); +} sub _parse_mapping { my ($string) = @_; From cdec8db46adf5c2d3ef154274103a1d3bbc3b6cf Mon Sep 17 00:00:00 2001 From: Sascha Friedmann Date: Sun, 30 Jan 2011 23:00:10 +0100 Subject: [PATCH 5/5] vim-mode: add mkview/source support for cmap. --- vim-mode/vim_mode.pl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e0a3984..753539d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -2160,6 +2160,9 @@ sub ex_source { # :map {lhs} {rhs}, keep in sync with ex_map() if ($line =~ /^\s*map (\S+) (\S.*)$/) { ex_map($line); + # :cmap {lhs} {rhs}, keep in sync with ex_cmap() + } elsif ($line =~ /^\s*cmap (\S+) (\S.*)$/) { + ex_cmap($line); } else { _warn_ex('source', "command not supported: $line"); } @@ -2178,7 +2181,7 @@ sub ex_mkvimrc { open my $file, '>', $vim_moderc or return; - # copied from ex_map() + # copied from _ex_map() foreach my $key (sort keys %$maps) { my $map = $maps->{$key}; my $cmd = $map->{cmd}; @@ -2188,6 +2191,17 @@ sub ex_mkvimrc { } } + # copied from _ex_map() + foreach my $key (sort keys %$ex_maps) { + my $map = $ex_maps->{$key}; + my $cmd = $map->{cmd}; + if (defined $cmd) { + # Remember $cmd->{char} starts with a colon (:)! + next if ":$map->{char}" eq $cmd->{char}; # skip default mappings + print $file "cmap $map->{char} $cmd->{char}\n"; + } + } + close $file; }