From 31939d43bce286f4b13a2e4ceeab68e5d88ed986 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 23:28:52 +0200 Subject: vim_mode: Use new _warn() to display warnings. --- vim-mode/vim_mode.pl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0aa6b61..944db53 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1017,8 +1017,8 @@ sub handle_command { # Start Ex mode. } elsif ($char eq ':') { if (not script_is_loaded('prompt_info')) { - print "This script requires the 'prompt_info' script to " - . "support Ex mode. Please load it and try again."; + _warn("Warning: Ex mode requires the 'prompt_info' script. " . + "Please load it and try again."); } else { _update_mode(M_EX); _set_prompt(':'); @@ -1061,7 +1061,7 @@ sub setup_changed { 'func' => sub { _update_mode(M_CMD) } }; } else { - print "Error: vim_mode_cmd_seq must be a single character"; + _warn("Error: vim_mode_cmd_seq must be a single character"); } } @@ -1210,5 +1210,11 @@ sub _set_prompt { Irssi::signal_emit('change prompt', $msg); } +sub _warn { + my ($warning) = @_; + + print "vim_mode: ", $warning; +} + # TODO: # 10gg -> go to window 10 (prefix.gg -> win ) -- cgit v1.2.3 From 6c7074b5f641f73e92b6b906f632cc5f97357408 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 23:30:01 +0200 Subject: vim_mode: Print a warning for UTF-8 mode if Perl < 5.8.1. --- vim-mode/vim_mode.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 944db53..dbe953c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1075,6 +1075,11 @@ sub setup_changed { $non_word = qr/[^\w_\s]/o; } + if ($new_utf8 and (!$^V or $^V lt v5.8.1)) { + _warn("Warning: UTF-8 isn't supported very well in perl < 5.8.1! " . + "Please disable vim_mode_utf8."); + } + $utf8 = $new_utf8; } -- cgit v1.2.3 From 9867e437c480c962100fa1ea0ca335102ce43b97 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Mon, 27 Sep 2010 22:41:06 +0100 Subject: boldified message in _warn() --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index dbe953c..f33b6c3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1218,7 +1218,7 @@ sub _set_prompt { sub _warn { my ($warning) = @_; - print "vim_mode: ", $warning; + print '%_vim_mode: ', $warning, '%_'; } # TODO: -- cgit v1.2.3 From 3577405263c97302298d91c9c4a8e051d62e5b45 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Mon, 27 Sep 2010 23:17:46 +0100 Subject: changed commit_line to only do internal housekeeping - enter now submits the line to irssi for default handling (signal is not stopped) --- vim-mode/vim_mode.pl | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f33b6c3..31b8d88 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -756,11 +756,9 @@ sub got_key { _update_mode(M_CMD); _stop(); return; + } elsif ($key == 10) { # enter. - _stop(); - _commit_line(_input()); - @undo_buffer = (); - $undo_index = undef; + _commit_line(); } elsif ($input_buf_enabled and $imap) { print "Imap $imap active" if DEBUG; @@ -776,6 +774,7 @@ sub got_key { _stop(); $imap = undef; return; + } elsif (exists $imaps->{chr($key)}) { print "Imap " . chr($key) . " seen, starting buffer" if DEBUG; @@ -1026,8 +1025,7 @@ sub handle_command { # Enter key sends the current input line in command mode as well. } elsif ($key == 10) { - _stop(); - _commit_line(_input()); + _commit_line(); } Irssi::statusbar_items_redraw("vim_mode"); @@ -1111,29 +1109,8 @@ sub _clear_undo_buffer { sub _commit_line { - my ($line) = @_; - - my $cmdchars = Irssi::settings_get_str('cmdchars'); - - _input(''); _update_mode(M_INS); _clear_undo_buffer(); - - return unless length $line; # ignore empty lines - - my $server = Irssi::active_server(); - my $win = Irssi::active_win(); - my $witem = ref $win ? $win->{active} : undef; - - my @context; - push @context, $server if defined $server; - push @context, $witem if defined $witem; - - if ($line =~ /^[\Q$cmdchars\E]/) { - Irssi::signal_emit 'send command', $line, @context; - } else { - Irssi::signal_emit 'send text', $line, @context; - } } sub _input { -- cgit v1.2.3 From 98b1b6bac606f3a2d52080a4d9490351860cec51 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 28 Sep 2010 00:08:45 +0100 Subject: fixed enter key not working in cmd mode, also added pass-thru for meta-keys in cmd mode --- vim-mode/vim_mode.pl | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 31b8d88..44abc99 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -817,17 +817,18 @@ sub handle_input_buffer { } else { # we need to identify what we got, and either replay it # or pass it off to the command handler. - if ($mode == M_CMD) { - # command - my $key_str = join '', map { chr } @input_buf; - if ($key_str =~ m/^\e\[([ABCD])/) { - print "Arrow key: $1" if DEBUG; - } else { - print "Dunno what that is." if DEBUG; - } - } else { - _emulate_keystrokes(@input_buf); - } + # if ($mode == M_CMD) { + # # command + # my $key_str = join '', map { chr } @input_buf; + # if ($key_str =~ m/^\e\[([ABCD])/) { + # print "Arrow key: $1" if DEBUG; + # } else { + # print "Dunno what that is." if DEBUG; + # } + # } else { + # _emulate_keystrokes(@input_buf); + # } + _emulate_keystrokes(@input_buf); } @input_buf = (); @@ -863,6 +864,8 @@ sub handle_numeric_prefix { sub handle_command { my ($key) = @_; + my $should_stop = 1; + if ($mode == M_EX) { # DEL key - remove last character if ($key == 127) { @@ -1025,13 +1028,14 @@ sub handle_command { # Enter key sends the current input line in command mode as well. } elsif ($key == 10) { + $should_stop = 0; _commit_line(); } Irssi::statusbar_items_redraw("vim_mode"); } - _stop(); + _stop() if $should_stop; } sub vim_mode_init { -- cgit v1.2.3 From f1d3e2e9ba4fffb7a8d5fae66000e771f6898418 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 00:16:44 +0200 Subject: vim_mode: Remove G, instead use Ex-mode :b (:buffer) to switch windows. --- vim-mode/vim_mode.pl | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 44abc99..26f950b 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -17,7 +17,6 @@ # * repeat change: . # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx -# * goto window: 5G # # TODO: # * /,?,n to search through history (like history_search.pl) @@ -208,8 +207,6 @@ my $movements # to end of line 'C' => { func => \&cmd_movement_dollar }, 'D' => { func => \&cmd_movement_dollar }, - # change window - 'G' => { func => \&cmd_movement_G }, # misc '~' => { func => \&cmd_movement_tilde }, '.' => {}, @@ -638,20 +635,6 @@ sub _paste_at_position { _input_pos($pos - 1 + length $string); } -sub cmd_movement_G { - my ($count, $pos) = @_; - - # If no count is given go to the last window (= highest refnum). - if (not $count) { - $count = List::Util::max(map { $_->{refnum} } Irssi::windows()); - } - - my $window = Irssi::window_find_refnum($count); - if ($window) { - $window->set_active(); - } -} - sub cmd_movement_tilde { my ($count, $pos) = @_; @@ -700,6 +683,18 @@ sub cmd_ex_command { print "New line is: $line" if DEBUG; _input($line); + + } elsif ($arg_str =~ m|b(?:uffer)?\s*(.+)$|) { + my $window; + my $buffer = $1; + + if ($buffer =~ /^[0-9]+$/) { + $window = Irssi::window_find_refnum($buffer); + } + + if ($window) { + $window->set_active(); + } } } @@ -965,9 +960,8 @@ sub handle_command { if ($skip) { print "Skipping movement and operator." if DEBUG; } else { - # Make sure count is at least 1, except for G which needs to - # handle undef specially. - if (not $numeric_prefix and $char ne 'G') { + # Make sure count is at least 1. + if (not $numeric_prefix) { $numeric_prefix = 1; } -- cgit v1.2.3 From 288da6a76b7d55684f93db3a2e49b54462f32513 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 02:28:30 +0200 Subject: vim_mode: Implement :b# and :b window-name. --- vim-mode/vim_mode.pl | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 26f950b..46ae7cc 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -686,14 +686,53 @@ sub cmd_ex_command { } elsif ($arg_str =~ m|b(?:uffer)?\s*(.+)$|) { my $window; + my $item; my $buffer = $1; + # Go to window number. if ($buffer =~ /^[0-9]+$/) { $window = Irssi::window_find_refnum($buffer); + # Go to previous window. + } elsif ($buffer eq '#') { + Irssi::command('window last'); + # Go to best regex matching window. + } else { + my $regex = qr/\Q$buffer\E/; + + my @matches; + foreach my $window (Irssi::windows()) { + # Matching window names. + if ($window->{name} =~ /$regex/) { + my $ratio = ($+[0] - $-[0]) / length($window->{name}); + push @matches, { window => $window, + item => undef, + ratio => $ratio }; + } + # Matching Window item names (= channels). + foreach my $item ($window->items()) { + if ($item->{name} =~ /$regex/) { + my $length = length($item->{name}); + $length-- if index($item->{name}, '#') == 0; + push @matches, { window => $window, + item => $item, + ratio => ($+[0] - $-[0]) / $length }; + } + } + } + + if (scalar @matches > 0) { + @matches = sort {$b->{ratio} <=> $a->{ratio}} @matches; + + $window = $matches[0]->{window}; + $item = $matches[0]->{item}; + } } if ($window) { $window->set_active(); + if ($item) { + $item->set_active(); + } } } } -- cgit v1.2.3 From 4ad7cde52a924d87af026c2dc2af8033e62edc4d Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 02:36:14 +0200 Subject: vim_mode: Add debug output for :b window. --- vim-mode/vim_mode.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 46ae7cc..eadcce2 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -707,15 +707,19 @@ sub cmd_ex_command { push @matches, { window => $window, item => undef, ratio => $ratio }; + print ":b $window->{name}: $ratio" if DEBUG; } # Matching Window item names (= channels). foreach my $item ($window->items()) { if ($item->{name} =~ /$regex/) { my $length = length($item->{name}); $length-- if index($item->{name}, '#') == 0; + my $ratio = ($+[0] - $-[0]) / $length; push @matches, { window => $window, item => $item, - ratio => ($+[0] - $-[0]) / $length }; + ratio => $ratio }; + print ":b $window->{name} $item->{name}: $ratio" + if DEBUG; } } } -- cgit v1.2.3 From 8ac757333bd0175590e5beaa7c90c00d934ec69b Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 28 Sep 2010 01:53:37 +0100 Subject: cleaned up the todo list and some of the header comments, including mentioning the dep for :ex on prompt_info. --- vim-mode/vim_mode.pl | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 46ae7cc..9bcf436 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -17,27 +17,56 @@ # * repeat change: . # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx -# +# * window selection: :b, :b#, :b + # TODO: -# * /,?,n to search through history (like history_search.pl) -# * u = undo (how many levels, branching?!) redo? -# * use irssi settings for some of the features (esp. debug) +# * History: +# * /,?,n,N to search through history (like history_search.pl) +# * Undo: +# * u = undo (how many levels, branching?!) +# * C-r = redo +# * Window switching (:b) +# * Tab completion of window(-item) names +# * non-sequential matches(?) +# * additional statusbar-item for showing matches + +# * use irssi settings for some of the features +# * Done: +# * vim_mode_utf8 (use utf-8 toggle) +# * vim_mode_debug (debug prints) +# * vim_mode_cmd_seq (char that when double-pressed enters cmd mode from ins) +# * Pending: +# * ??? + +# WONTFIX - things we're not ever likely to do +# * Macros # Known bugs: # * count with insert mode: 3iabc doesn't work # * repeat insert mode: iabc. only enters insert mode +# * multi-line pastes # Installation: # -# The usual, stick in scripts dir, /script load vim_mode.pl ... +# Dependencies: +# +# For proper :ex mode support, requires the installation of prompt_info.pl +# http://github.com/shabble/shab-irssi-scripts/raw/master/prompt_info/prompt_info.pl +# +# and follow the instructions in the top of that file for installation instructions. + +# Then, copy into scripts dir, /script load vim_mode.pl ... # # Use the following command to get a statusbar item that shows which mode you're -# in. Annoying vi bleeping not yet supported :) +# in. # /statusbar window add vim_mode to get the status. -# NOTE: This is still under extreme development, and there's a whole bunch of -# debugging output. Edit the DEBUG constant to remove it if it bothers you. +# NOTE: This script is still under heavy development, and there may be bugs. +# Please submit reproducible sequences to the bug-tracker at: +# http://github.com/shabble/shab-irssi-scripts/issues +# +# or contact rudi_s or shabble on irc.freenode.net (#irssi) # Have fun! -- cgit v1.2.3 From 2096ac515f05cf524a441299d86493502b6f6397 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 03:26:18 +0200 Subject: vim_mode: :b Ignore case. --- vim-mode/vim_mode.pl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5ae2467..f61ce95 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -726,12 +726,11 @@ sub cmd_ex_command { Irssi::command('window last'); # Go to best regex matching window. } else { - my $regex = qr/\Q$buffer\E/; my @matches; foreach my $window (Irssi::windows()) { # Matching window names. - if ($window->{name} =~ /$regex/) { + if ($window->{name} =~ /$buffer/i) { my $ratio = ($+[0] - $-[0]) / length($window->{name}); push @matches, { window => $window, item => undef, @@ -740,7 +739,7 @@ sub cmd_ex_command { } # Matching Window item names (= channels). foreach my $item ($window->items()) { - if ($item->{name} =~ /$regex/) { + if ($item->{name} =~ /$buffer/i) { my $length = length($item->{name}); $length-- if index($item->{name}, '#') == 0; my $ratio = ($+[0] - $-[0]) / $length; -- cgit v1.2.3 From a18dc0ebc72e2aba67506cdb5b57db3f7f5d50c0 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 03:27:13 +0200 Subject: vim_mode: Add support for :b s/c Where s is the server (lowercase) and c is the channel (lowercase). --- vim-mode/vim_mode.pl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f61ce95..e5cf904 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -726,6 +726,15 @@ sub cmd_ex_command { Irssi::command('window last'); # Go to best regex matching window. } else { + my $server; + + if ($buffer =~ m{^(.+)/(.+)}) { + $server = $1; + $buffer = $2; + } + + print ":b searching for channel $buffer" if DEBUG; + print ":b on server $server" if $server and DEBUG; my @matches; foreach my $window (Irssi::windows()) { @@ -739,6 +748,11 @@ sub cmd_ex_command { } # Matching Window item names (= channels). foreach my $item ($window->items()) { + # Wrong server. + if ($server and (!$item->{server} or + $item->{server}->{chatnet} !~ /^$server/i)) { + next; + } if ($item->{name} =~ /$buffer/i) { my $length = length($item->{name}); $length-- if index($item->{name}, '#') == 0; -- cgit v1.2.3 From 5a67a6b83a96a44a350bd291dc84e15fa2e45d7f Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 03:38:14 +0200 Subject: vim_mode: Move :b name code to own function. --- vim-mode/vim_mode.pl | 96 ++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 45 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e5cf904..56982bb 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -726,51 +726,10 @@ sub cmd_ex_command { Irssi::command('window last'); # Go to best regex matching window. } else { - my $server; - - if ($buffer =~ m{^(.+)/(.+)}) { - $server = $1; - $buffer = $2; - } - - print ":b searching for channel $buffer" if DEBUG; - print ":b on server $server" if $server and DEBUG; - - my @matches; - foreach my $window (Irssi::windows()) { - # Matching window names. - if ($window->{name} =~ /$buffer/i) { - my $ratio = ($+[0] - $-[0]) / length($window->{name}); - push @matches, { window => $window, - item => undef, - ratio => $ratio }; - print ":b $window->{name}: $ratio" if DEBUG; - } - # Matching Window item names (= channels). - foreach my $item ($window->items()) { - # Wrong server. - if ($server and (!$item->{server} or - $item->{server}->{chatnet} !~ /^$server/i)) { - next; - } - if ($item->{name} =~ /$buffer/i) { - my $length = length($item->{name}); - $length-- if index($item->{name}, '#') == 0; - my $ratio = ($+[0] - $-[0]) / $length; - push @matches, { window => $window, - item => $item, - ratio => $ratio }; - print ":b $window->{name} $item->{name}: $ratio" - if DEBUG; - } - } - } - - if (scalar @matches > 0) { - @matches = sort {$b->{ratio} <=> $a->{ratio}} @matches; - - $window = $matches[0]->{window}; - $item = $matches[0]->{item}; + my $matches = _matching_windows($buffer); + if (scalar @$matches > 0) { + $window = @$matches[0]->{window}; + $item = @$matches[0]->{item}; } } @@ -783,6 +742,53 @@ sub cmd_ex_command { } } +sub _matching_windows { + my ($buffer) = @_; + + my $server; + + if ($buffer =~ m{^(.+)/(.+)}) { + $server = $1; + $buffer = $2; + } + + print ":b searching for channel $buffer" if DEBUG; + print ":b on server $server" if $server and DEBUG; + + my @matches; + foreach my $window (Irssi::windows()) { + # Matching window names. + if ($window->{name} =~ /$buffer/i) { + my $ratio = ($+[0] - $-[0]) / length($window->{name}); + push @matches, { window => $window, + item => undef, + ratio => $ratio }; + print ":b $window->{name}: $ratio" if DEBUG; + } + # Matching Window item names (= channels). + foreach my $item ($window->items()) { + # Wrong server. + if ($server and (!$item->{server} or + $item->{server}->{chatnet} !~ /^$server/i)) { + next; + } + if ($item->{name} =~ /$buffer/i) { + my $length = length($item->{name}); + $length-- if index($item->{name}, '#') == 0; + my $ratio = ($+[0] - $-[0]) / $length; + push @matches, { window => $window, + item => $item, + ratio => $ratio }; + print ":b $window->{name} $item->{name}: $ratio" if DEBUG; + } + } + } + + @matches = sort {$b->{ratio} <=> $a->{ratio}} @matches; + + return \@matches; +} + # vi mode status item. sub vim_mode_cb { -- cgit v1.2.3 From 650b21755ced7d538fa4e846b6e100fd2f3c7135 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 03:56:14 +0200 Subject: vim_mode: :b has vim_windows statusbar displaying matching channels. --- vim-mode/vim_mode.pl | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 56982bb..c34db2d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -62,6 +62,10 @@ # /statusbar window add vim_mode to get the status. +# And the following to let :b name display a list of matching channels + +# /statusbar window add vim_windows + # NOTE: This script is still under heavy development, and there may be bugs. # Please submit reproducible sequences to the bug-tracker at: # http://github.com/shabble/shab-irssi-scripts/issues @@ -762,7 +766,8 @@ sub _matching_windows { my $ratio = ($+[0] - $-[0]) / length($window->{name}); push @matches, { window => $window, item => undef, - ratio => $ratio }; + ratio => $ratio, + text => $window->{name} }; print ":b $window->{name}: $ratio" if DEBUG; } # Matching Window item names (= channels). @@ -778,7 +783,8 @@ sub _matching_windows { my $ratio = ($+[0] - $-[0]) / $length; push @matches, { window => $window, item => $item, - ratio => $ratio }; + ratio => $ratio, + text => $item->{name} }; print ":b $window->{name} $item->{name}: $ratio" if DEBUG; } } @@ -820,6 +826,26 @@ sub vim_mode_cb { $sb_item->default_handler($get_size_only, "{sb $mode_str}", '', 0); } +# :b window list item. +sub b_windows_cb { + my ($sb_item, $get_size_only) = @_; + + my $windows = ''; + + # A little code duplication of cmd_ex_command()! + my $arg_str = join '', @ex_buf; + if ($arg_str =~ m|b(?:uffer)?\s*(.+)$|) { + my $buffer = $1; + if ($buffer !~ /^[0-9]$/ and $buffer ne '#') { + # Display matching windows. + my $matches = _matching_windows($buffer); + $windows = join ',', map { $_->{text} } @$matches; + } + } + + $sb_item->default_handler($get_size_only, "{sb $windows}", '', 0); +} + sub got_key { my ($key) = @_; @@ -973,6 +999,8 @@ sub handle_command { _set_prompt(':' . join '', @ex_buf); } + Irssi::statusbar_items_redraw("vim_windows"); + } else { my $char = chr($key); @@ -1127,6 +1155,7 @@ sub vim_mode_init { Irssi::signal_add_first 'gui key pressed' => \&got_key; Irssi::signal_add 'setup changed' => \&setup_changed; Irssi::statusbar_item_register ('vim_mode', 0, 'vim_mode_cb'); + Irssi::statusbar_item_register ('vim_windows', 0, 'b_windows_cb'); Irssi::settings_add_str('vim_mode', 'vim_mode_cmd_seq', ''); Irssi::settings_add_bool('vim_mode', 'vim_mode_debug', 0); -- cgit v1.2.3 From 89a1e94b7f12bd29d91649dd9dd6952712701081 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 04:20:05 +0200 Subject: vim_mode: Add special registers "* and "+ for irssi's cut buffer. --- vim-mode/vim_mode.pl | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c34db2d..e40d15f 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -18,6 +18,8 @@ # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx # * window selection: :b, :b#, :b +# +# * special registers: "* "+ (contain irssi's cut-buffer) # TODO: # * History: @@ -683,6 +685,12 @@ sub cmd_movement_tilde { sub cmd_movement_register { my ($count, $pos, $char) = @_; + # + and * contain both irssi's cut-buffer + if ($char eq '+' or $char eq '*') { + $registers->{'+'} = Irssi::parse_special('$U'); + $registers->{'*'} = $registers->{'+'}; + } + $register = $char; print "Changing register to $register" if DEBUG; } -- cgit v1.2.3 From eafc06da4f8120ab167d93193d0856efd157ce86 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 28 Sep 2010 03:29:50 +0100 Subject: slightly better undo mode. Still gets position wrong sometimes --- vim-mode/vim_mode.pl | 62 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 15 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5ae2467..85965c5 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -243,6 +243,7 @@ my $movements # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, + "\x04" => { func => \&_print_undo_buffer }, }; @@ -260,16 +261,16 @@ my $movements_multiple = sub cmd_undo { print "Undo!" if DEBUG; - if ($undo_index > $#undo_buffer) { - $undo_index = $#undo_buffer; - print "No further undo." if DEBUG; - } elsif ($undo_index != $#undo_buffer) { - $undo_index++; - } - print "Undoing entry $undo_index of " . $#undo_buffer if DEBUG; + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; _restore_undo_entry($undo_index); + + if ($undo_index != $#undo_buffer) { + $undo_index++; + } else { + print "No further undo." if DEBUG; + } } sub cmd_redo { @@ -1114,6 +1115,7 @@ sub vim_mode_init { Irssi::settings_add_bool('vim_mode', 'vim_mode_utf8', 1); setup_changed(); + _reset_undo_buffer(); } sub setup_changed { @@ -1145,7 +1147,7 @@ sub setup_changed { if ($new_utf8 and (!$^V or $^V lt v5.8.1)) { _warn("Warning: UTF-8 isn't supported very well in perl < 5.8.1! " . - "Please disable vim_mode_utf8."); + "Please disable the vim_mode_utf8 setting."); } $utf8 = $new_utf8; @@ -1171,29 +1173,59 @@ sub _restore_undo_entry { _input_pos($entry->[1]); } -sub _clear_undo_buffer { +sub _print_undo_buffer { + + my $i = 0; + my @buf; + foreach my $entry (@undo_buffer) { + my $str = ''; + if ($i == $undo_index) { + $str .= '* '; + } else { + $str .= ' '; + } + $str .= sprintf('%02d %s [%d]', $i, $entry->[0], $entry->[1]); + push @buf, $str; + $i++; + } + print "------ undo buffer ------"; + print join("\n", @buf); + print "------------------ ------"; + +} + +sub _reset_undo_buffer { + my ($line, $pos) = @_; + $line = _input() unless defined $line; + $pos = _input_pos() unless defined $pos; + print "Clearing undo buffer" if DEBUG; - @undo_buffer = (['', 0]); - $undo_index = 0; + @undo_buffer = ([$line, $pos]); + $undo_index = 0; } sub _commit_line { _update_mode(M_INS); - _clear_undo_buffer(); + _reset_undo_buffer('', 0); } sub _input { - my ($data, $ignore) = @_; + my ($data, $ignore_undo) = @_; my $current_data = Irssi::parse_special('$L', 0, 0); + if ($utf8) { $current_data = decode_utf8($current_data); } if (defined $data) { - if (!$ignore && ($data ne $current_data)) { - _add_undo_entry($current_data, _input_pos()); + if (!$ignore_undo && ($data ne $current_data)) { + if ($undo_index != 0) { # ??? + _reset_undo_buffer($current_data, _input_pos()); + } else { + _add_undo_entry($current_data, _input_pos()); + } } if ($utf8) { Irssi::gui_input_set(encode_utf8($data)); -- cgit v1.2.3 From 27018ca2b1f0ae4322ce3648b81b76adfe385c7d Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 23:01:13 +0200 Subject: vim_mode: Add UTF-8 support for ~. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 085ea78..d44452c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -676,7 +676,7 @@ sub cmd_movement_tilde { my $input = _input(); my $string = substr $input, $pos, $count; - $string =~ tr/a-zA-Z/A-Za-z/; + $string =~ s/(.)/(uc($1) eq $1) ? lc($1) : uc($1)/ge; substr $input, $pos, $count, $string; _input($input); -- cgit v1.2.3 From d06c0bda422c6c26679c913eeee4f61a651ce3e7 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 28 Sep 2010 22:52:54 +0100 Subject: changed licence to MIT --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index d44452c..74ccd18 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -96,8 +96,8 @@ $VERSION = "1.0.1"; . 'rudi_s@#irssi/Freenode', name => "vim_mode", description => "Give Irssi Vim-like commands for editing the inputline", - license => "Public Domain", - changed => "20/9/2010" + license => "MIT", + changed => "28/9/2010" ); -- cgit v1.2.3 From e77c897c5a01a14a6f0f1cf24a6924fb61b50994 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 28 Sep 2010 23:59:50 +0200 Subject: vim_mode: Move cmd and ex-mode handling to separate functions. --- vim-mode/vim_mode.pl | 306 ++++++++++++++++++++++++++------------------------- 1 file changed, 155 insertions(+), 151 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 74ccd18..3ba679d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -918,8 +918,10 @@ sub got_key { return; } - if ($mode == M_CMD || $mode == M_EX) { - handle_command($key); + if ($mode == M_CMD) { + handle_command_cmd($key); + } elsif ($mode == M_EX) { + handle_command_ex($key); } } @@ -982,184 +984,186 @@ sub handle_numeric_prefix { } } -sub handle_command { +sub handle_command_cmd { my ($key) = @_; my $should_stop = 1; - if ($mode == M_EX) { - # DEL key - remove last character - if ($key == 127) { - print "Delete" if DEBUG; - pop @ex_buf; - _set_prompt(':' . join '', @ex_buf); - - # Return key - execute command - } elsif ($key == 10) { - print "Run ex-mode command" if DEBUG; - cmd_ex_command(); - _set_prompt(''); - @ex_buf = (); - _update_mode(M_CMD); - - # Append entered key - } else { - push @ex_buf, chr $key; - _set_prompt(':' . join '', @ex_buf); - } - - Irssi::statusbar_items_redraw("vim_windows"); + my $char = chr($key); - } else { - my $char = chr($key); + # We need to treat $movements_multiple specially as they need another + # argument. + if ($movement) { + $movement .= $char; + } - # We need to treat $movements_multiple specially as they need another - # argument. - if ($movement) { - $movement .= $char; - } + # S is an alias for cc. + if (!$movement and !$operator and $char eq 'S') { + print "Changing S to cc" if DEBUG; + $char = 'c'; + $operator = 'c'; + } - # S is an alias for cc. - if (!$movement and !$operator and $char eq 'S') { - print "Changing S to cc" if DEBUG; - $char = 'c'; - $operator = 'c'; + if (!$movement && ($char =~ m/[1-9]/ || + ($numeric_prefix && $char =~ m/[0-9]/))) { + print "Processing numeric prefix: $char" if DEBUG; + handle_numeric_prefix($char); + + } elsif (!$movement && exists $movements_multiple->{$char}) { + print "Processing movement: $char" if DEBUG; + $movement = $char; + + } elsif (!$movement && exists $operators->{$char}) { + print "Processing operator: $char" if DEBUG; + + # Abort operator if we already have one pending. + if ($operator) { + # But allow cc/dd/yy. + if ($operator eq $char) { + print "Processing operator: ", $operator, $char if DEBUG; + my $pos = _input_pos(); + $operators->{$operator}->{func}->(0, _input_len(), ''); + # Restore position for yy. + if ($char eq 'y') { + _input_pos($pos); + } + } + $numeric_prefix = undef; + $operator = undef; + $movement = undef; + # Set new operator. + } else { + $operator = $char; } - if (!$movement && ($char =~ m/[1-9]/ || - ($numeric_prefix && $char =~ m/[0-9]/))) { - print "Processing numeric prefix: $char" if DEBUG; - handle_numeric_prefix($char); - - } elsif (!$movement && exists $movements_multiple->{$char}) { - print "Processing movement: $char" if DEBUG; - $movement = $char; + } elsif ($movement || exists $movements->{$char}) { + print "Processing movement command: $char" if DEBUG; - } elsif (!$movement && exists $operators->{$char}) { - print "Processing operator: $char" if DEBUG; + my $skip = 0; - # Abort operator if we already have one pending. - if ($operator) { - # But allow cc/dd/yy. - if ($operator eq $char) { - print "Processing operator: ", $operator, $char if DEBUG; - my $pos = _input_pos(); - $operators->{$operator}->{func}->(0, _input_len(), ''); - # Restore position for yy. - if ($char eq 'y') { - _input_pos($pos); - } + if (!$movement) { + # . repeats the last command. + if ($char eq '.' and defined $last->{char}) { + $char = $last->{char}; + # If . is given a count then it replaces original count. + if (not defined $numeric_prefix) { + $numeric_prefix = $last->{numeric_prefix}; } - $numeric_prefix = undef; - $operator = undef; - $movement = undef; - # Set new operator. - } else { - $operator = $char; + $operator = $last->{operator}; + $movement = $last->{movement}; + $register = $last->{register}; + } elsif ($char eq '.') { + $skip = 1; } + # C and D force the matching operator + if ($char eq 'C') { + $operator = 'c'; + } elsif ($char eq 'D') { + $operator = 'd'; + } + } - } elsif ($movement || exists $movements->{$char}) { - print "Processing movement command: $char" if DEBUG; - - my $skip = 0; - - if (!$movement) { - # . repeats the last command. - if ($char eq '.' and defined $last->{char}) { - $char = $last->{char}; - # If . is given a count then it replaces original count. - if (not defined $numeric_prefix) { - $numeric_prefix = $last->{numeric_prefix}; - } - $operator = $last->{operator}; - $movement = $last->{movement}; - $register = $last->{register}; - } elsif ($char eq '.') { - $skip = 1; - } - # C and D force the matching operator - if ($char eq 'C') { - $operator = 'c'; - } elsif ($char eq 'D') { - $operator = 'd'; - } + if ($skip) { + print "Skipping movement and operator." if DEBUG; + } else { + # Make sure count is at least 1. + if (not $numeric_prefix) { + $numeric_prefix = 1; } - if ($skip) { - print "Skipping movement and operator." if DEBUG; + # Execute the movement (multiple times). + my $cur_pos = _input_pos(); + if (not $movement) { + $movements->{$char}->{func}->($numeric_prefix, $cur_pos); } else { - # Make sure count is at least 1. - if (not $numeric_prefix) { - $numeric_prefix = 1; - } - - # Execute the movement (multiple times). - my $cur_pos = _input_pos(); - if (not $movement) { - $movements->{$char}->{func}->($numeric_prefix, $cur_pos); - } else { - # Use the real movement command (like t or f) for operator - # below. - $char = substr $movement, 0, 1; - $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, substr $movement, 1); - } - my $new_pos = _input_pos(); - - # If we have an operator pending then run it on the handled - # text. But only if the movement changed the position (this - # prevents problems with e.g. f when the search string doesn't - # exist). - if ($operator and $cur_pos != $new_pos) { - print "Processing operator: ", $operator if DEBUG; - $operators->{$operator}->{func}->($cur_pos, $new_pos, $char); - } - - # Store command, necessary for . But ignore movements and - # registers. - if ($operator or $char eq 'x' or $char eq 'X' or $char eq 'r' - or $char eq 'p' or $char eq 'P' or - $char eq 'C' or $char eq 'D' or - $char eq '~' or $char eq '"') { - $last->{char} = $char; - $last->{numeric_prefix} = $numeric_prefix; - $last->{operator} = $operator; - $last->{movement} = $movement; - $last->{register} = $register; - } + # Use the real movement command (like t or f) for operator + # below. + $char = substr $movement, 0, 1; + $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, substr $movement, 1); } - - $numeric_prefix = undef; - $operator = undef; - $movement = undef; - - if ($char ne '"' and $register ne '"') { - print 'Changing register to "' if DEBUG; - $register = '"'; + my $new_pos = _input_pos(); + + # If we have an operator pending then run it on the handled text. + # But only if the movement changed the position (this prevents + # problems with e.g. f when the search string doesn't exist). + if ($operator and $cur_pos != $new_pos) { + print "Processing operator: ", $operator if DEBUG; + $operators->{$operator}->{func}->($cur_pos, $new_pos, $char); } - # Start Ex mode. - } elsif ($char eq ':') { - if (not script_is_loaded('prompt_info')) { - _warn("Warning: Ex mode requires the 'prompt_info' script. " . - "Please load it and try again."); - } else { - _update_mode(M_EX); - _set_prompt(':'); + # Store command, necessary for . But ignore movements and + # registers. + if ($operator or $char eq 'x' or $char eq 'X' or $char eq 'r' or + $char eq 'p' or $char eq 'P' or $char eq 'C' or + $char eq 'D' or $char eq '~' or $char eq '"') { + $last->{char} = $char; + $last->{numeric_prefix} = $numeric_prefix; + $last->{operator} = $operator; + $last->{movement} = $movement; + $last->{register} = $register; } + } - # Enter key sends the current input line in command mode as well. - } elsif ($key == 10) { - $should_stop = 0; - _commit_line(); + $numeric_prefix = undef; + $operator = undef; + $movement = undef; + + if ($char ne '"' and $register ne '"') { + print 'Changing register to "' if DEBUG; + $register = '"'; } - Irssi::statusbar_items_redraw("vim_mode"); + # Start Ex mode. + } elsif ($char eq ':') { + if (not script_is_loaded('prompt_info')) { + _warn("Warning: Ex mode requires the 'prompt_info' script. " . + "Please load it and try again."); + } else { + _update_mode(M_EX); + _set_prompt(':'); + } + + # Enter key sends the current input line in command mode as well. + } elsif ($key == 10) { + $should_stop = 0; + _commit_line(); } + Irssi::statusbar_items_redraw("vim_mode"); + _stop() if $should_stop; } +sub handle_command_ex { + my ($key) = @_; + + # DEL key - remove last character + if ($key == 127) { + print "Delete" if DEBUG; + pop @ex_buf; + _set_prompt(':' . join '', @ex_buf); + + # Return key - execute command + } elsif ($key == 10) { + print "Run ex-mode command" if DEBUG; + cmd_ex_command(); + _set_prompt(''); + @ex_buf = (); + _update_mode(M_CMD); + + # Append entered key + } else { + push @ex_buf, chr $key; + _set_prompt(':' . join '', @ex_buf); + } + + Irssi::statusbar_items_redraw("vim_windows"); + + _stop(); +} + + sub vim_mode_init { Irssi::signal_add_first 'gui key pressed' => \&got_key; Irssi::signal_add 'setup changed' => \&setup_changed; -- cgit v1.2.3 From c386391074e23fa92c9c2ac13a64e1c53f736b14 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 28 Sep 2010 23:19:25 +0100 Subject: added MIT licence boilerplate --- vim-mode/vim_mode.pl | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 74ccd18..b59b2af 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -20,7 +20,7 @@ # * window selection: :b, :b#, :b # # * special registers: "* "+ (contain irssi's cut-buffer) - +# # TODO: # * History: # * /,?,n,N to search through history (like history_search.pl) @@ -31,7 +31,7 @@ # * Tab completion of window(-item) names # * non-sequential matches(?) # * additional statusbar-item for showing matches - +# # * use irssi settings for some of the features # * Done: # * vim_mode_utf8 (use utf-8 toggle) @@ -39,15 +39,15 @@ # * vim_mode_cmd_seq (char that when double-pressed enters cmd mode from ins) # * Pending: # * ??? - +# # WONTFIX - things we're not ever likely to do # * Macros - +# # Known bugs: # * count with insert mode: 3iabc doesn't work # * repeat insert mode: iabc. only enters insert mode # * multi-line pastes - +# # Installation: # # Dependencies: @@ -56,24 +56,48 @@ # http://github.com/shabble/shab-irssi-scripts/raw/master/prompt_info/prompt_info.pl # # and follow the instructions in the top of that file for installation instructions. - +# # Then, copy into scripts dir, /script load vim_mode.pl ... # # Use the following command to get a statusbar item that shows which mode you're # in. - +# # /statusbar window add vim_mode to get the status. - +# # And the following to let :b name display a list of matching channels - +# # /statusbar window add vim_windows - +# # NOTE: This script is still under heavy development, and there may be bugs. # Please submit reproducible sequences to the bug-tracker at: # http://github.com/shabble/shab-irssi-scripts/issues # # or contact rudi_s or shabble on irc.freenode.net (#irssi) - +# +# LICENCE: +# +# Copyright (c) 2010 Tom Feist & Simon Ruderich +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# +# # Have fun! use strict; -- cgit v1.2.3 From 275ce1fd35a3ffffcbf49c24f4e28cd744c5ec9b Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Wed, 29 Sep 2010 02:53:22 +0100 Subject: additional debug prints in _input(_pos) to determine why undo positions are being set incorrectly --- vim-mode/vim_mode.pl | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index bd4d39f..8dfa35d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1245,9 +1245,15 @@ sub UNLOAD { sub _add_undo_entry { my ($line, $pos) = @_; - # add to the front of the buffer - print "adding $line to undo list" if DEBUG; - unshift @undo_buffer, [$line, $pos]; + # check it's not a dupe of the list head + my $head = $undo_buffer[0]; + if ($line eq $head->[0] && $pos == $head->[1]) { + print "Not adding duplicate to undo list"; + } else { + print "adding $line to undo list" if DEBUG; + # add to the front of the buffer + unshift @undo_buffer, [$line, $pos]; + } $undo_index = 0; } @@ -1268,7 +1274,11 @@ sub _print_undo_buffer { } else { $str .= ' '; } - $str .= sprintf('%02d %s [%d]', $i, $entry->[0], $entry->[1]); + my ($line, $pos) = @$entry; + substr($line, $pos, 0) = '*'; + # substr($line, $pos+3, 0) = '%_'; + + $str .= sprintf('%02d %s [%d]', $i, $line, $pos); push @buf, $str; $i++; } @@ -1306,9 +1316,12 @@ sub _input { if (defined $data) { if (!$ignore_undo && ($data ne $current_data)) { if ($undo_index != 0) { # ??? + print "Resetting undo buffer" if DEBUG; _reset_undo_buffer($current_data, _input_pos()); } else { - _add_undo_entry($current_data, _input_pos()); + my $pos = _input_pos(); + print "Adding debug entry: $current_data $pos" if DEBUG; + _add_undo_entry($current_data, $pos); } } if ($utf8) { @@ -1332,9 +1345,11 @@ sub _input_pos { my $cur_pos = Irssi::gui_input_get_pos(); if (defined $pos) { + print "Input pos being set from $cur_pos to $pos" if DEBUG; Irssi::gui_input_set_pos($pos) if $pos != $cur_pos; } else { $pos = $cur_pos; + print "Input pos retrieved as $pos" if DEBUG; } return $pos; -- cgit v1.2.3 From 5cbd1e07ee5a7d75019512150d34db98788056e7 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 03:47:08 +0200 Subject: vim_mode: Fix cursor position to work like Vim. --- vim-mode/vim_mode.pl | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8dfa35d..786921c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1370,6 +1370,17 @@ sub _stop() { sub _update_mode { my ($new_mode) = @_; + + # In insert mode we are "between" characters, in command mode "on top" of + # keys. When leaving insert mode we have to move on key left to accomplish + # that. + if ($mode == M_INS and $new_mode == M_CMD) { + my $pos = _input_pos(); + if ($pos != 0) { + _input_pos($pos - 1); + } + } + $mode = $new_mode; if ($mode == M_INS) { $history_index = undef; -- cgit v1.2.3 From 59e3fad3f0be37847336369319d964d6547a79f2 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 16:04:07 +0200 Subject: vim_mode: Add support for insert mode repetition and counts. --- vim-mode/vim_mode.pl | 180 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 126 insertions(+), 54 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 786921c..3a81b88 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -44,8 +44,6 @@ # * Macros # # Known bugs: -# * count with insert mode: 3iabc doesn't work -# * repeat insert mode: iabc. only enters insert mode # * multi-line pastes # # Installation: @@ -151,6 +149,9 @@ my @input_buf; my $input_buf_timer; my $input_buf_enabled = 0; +# insert mode repeat buffer, used to repeat (.) last insert +my @insert_buf; + # flag to allow us to emulate keystrokes without re-intercepting them my $should_ignore = 0; @@ -166,11 +167,11 @@ my $movement = undef; # last vi command, used by . my $last = { - 'char' => undef, + 'char' => 'i', # = i to support . when loading the script 'numeric_prefix' => undef, 'operator' => undef, 'movement' => undef, - 'register' => undef, + 'register' => '"', }; # what Vi mode we're in. We start in insert mode. @@ -361,14 +362,14 @@ sub _get_pos_and_length { sub cmd_movement_h { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; $pos -= $count; $pos = 0 if $pos < 0; _input_pos($pos); } sub cmd_movement_l { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $length = _input_len(); $pos += $count; @@ -376,13 +377,13 @@ sub cmd_movement_l { _input_pos($pos); } sub cmd_movement_space { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; cmd_movement_l($count, $pos); } # later history (down) sub cmd_movement_j { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { # simulate a down-arrow @@ -411,7 +412,7 @@ sub cmd_movement_j { } # earlier history (up) sub cmd_movement_k { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { # simulate an up-arrow @@ -437,7 +438,7 @@ sub cmd_movement_k { } sub cmd_movement_f { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); if ($pos != -1) { @@ -445,7 +446,7 @@ sub cmd_movement_f { } } sub cmd_movement_t { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); if ($pos != -1) { @@ -453,7 +454,7 @@ sub cmd_movement_t { } } sub cmd_movement_F { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); $pos = _next_occurrence($input, $char, $count, length($input) - $pos - 1); @@ -462,7 +463,7 @@ sub cmd_movement_F { } } sub cmd_movement_T { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); $pos = _next_occurrence($input, $char, $count, length($input) - $pos - 1); @@ -484,7 +485,7 @@ sub _next_occurrence { } sub cmd_movement_w { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $input = _input(); while ($count-- > 0) { @@ -503,7 +504,7 @@ sub cmd_movement_w { _input_pos($pos); } sub cmd_movement_b { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $input = reverse _input(); $pos = length($input) - $pos - 1; @@ -515,7 +516,7 @@ sub cmd_movement_b { _input_pos($pos); } sub cmd_movement_e { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; $pos = _end_of_word(_input(), $count, $pos); _input_pos($pos); @@ -552,7 +553,7 @@ sub _end_of_word { return $pos; } sub cmd_movement_W { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $input = _input(); while ($count-- > 0 and length($input) > $pos) { @@ -564,7 +565,7 @@ sub cmd_movement_W { _input_pos($pos); } sub cmd_movement_B { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $input = reverse _input(); $pos = _end_of_WORD($input, $count, length($input) - $pos - 1); @@ -575,7 +576,7 @@ sub cmd_movement_B { } } sub cmd_movement_E { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; $pos = _end_of_WORD(_input(), $count, $pos); if ($pos == -1) { @@ -628,12 +629,12 @@ sub cmd_movement_dollar { } sub cmd_movement_x { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; cmd_operator_d($pos, $pos + $count, 'x'); } sub cmd_movement_X { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; return if $pos == 0; @@ -643,23 +644,69 @@ sub cmd_movement_X { } sub cmd_movement_i { - _update_mode(M_INS); + my ($count, $pos, $repeat) = @_; + + if (!$repeat) { + _update_mode(M_INS); + } else { + _insert_buffer($count); + } } sub cmd_movement_I { + my ($count, $pos, $repeat) = @_; + cmd_movement_caret(); - _update_mode(M_INS); + if (!$repeat) { + _update_mode(M_INS); + } else { + _insert_buffer($count); + } } sub cmd_movement_a { + my ($count, $pos, $repeat) = @_; + cmd_movement_l(1, _input_pos()); - _update_mode(M_INS); + if (!$repeat) { + _update_mode(M_INS); + } else { + _insert_buffer($count); + } } sub cmd_movement_A { + my ($count, $pos, $repeat) = @_; + cmd_movement_dollar(); - _update_mode(M_INS); + if (!$repeat) { + _update_mode(M_INS); + } else { + _insert_buffer($count); + } +} +# Add @insert_buf to _input() at the current cursor position. +sub _insert_buffer { + my ($count) = @_; + _insert_at_position(join('', @insert_buf), $count, _input_pos()); +} +sub _insert_at_position { + my ($string, $count, $pos) = @_; + + $string = $string x $count; + + my $input = _input(); + # Check if we are not at the end of the line to prevent substr outside of + # string error. + if (length $input > $pos) { + substr($input, $pos, 0) = $string; + } else { + $input .= $string; + } + _input($input); + + _input_pos($pos - 1 + length $string); } sub cmd_movement_r { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; my $input = _input(); substr $input, $pos, 1, $char; @@ -668,35 +715,22 @@ sub cmd_movement_r { } sub cmd_movement_p { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; _paste_at_position($count, $pos + 1); } sub cmd_movement_P { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; _paste_at_position($count, $pos); } sub _paste_at_position { my ($count, $pos) = @_; return if not $registers->{$register}; - - my $string = $registers->{$register} x $count; - - my $input = _input(); - # Check if we are not at the end of the line to prevent substr outside of - # string error. - if (length $input > $pos) { - substr($input, $pos, 0) = $string; - } else { - $input .= $string; - } - _input($input); - - _input_pos($pos - 1 + length $string); + _insert_at_position($registers->{$register}, $count, $pos); } sub cmd_movement_tilde { - my ($count, $pos) = @_; + my ($count, $pos, $repeat) = @_; my $input = _input(); my $string = substr $input, $pos, $count; @@ -708,7 +742,7 @@ sub cmd_movement_tilde { } sub cmd_movement_register { - my ($count, $pos, $char) = @_; + my ($count, $pos, $repeat, $char) = @_; # + and * contain both irssi's cut-buffer if ($char eq '+' or $char eq '*') { @@ -933,6 +967,15 @@ sub got_key { _stop(); return; + + # Pressing delete resets insert mode repetition. + # TODO: maybe allow it + } elsif ($key == 127) { + @insert_buf = (); + # All other entered characters need to be stored to allow repeat of + # insert mode. Ignore delete and ctrl characters. + } elsif ($key > 31) { + push @insert_buf, chr($key); } } @@ -976,6 +1019,10 @@ sub handle_input_buffer { # _emulate_keystrokes(@input_buf); # } _emulate_keystrokes(@input_buf); + + # Clear insert buffer, pressing "special" keys (like arrow keys) + # resets it. + @insert_buf = (); } @input_buf = (); @@ -1064,6 +1111,7 @@ sub handle_command_cmd { print "Processing movement command: $char" if DEBUG; my $skip = 0; + my $repeat = 0; if (!$movement) { # . repeats the last command. @@ -1076,7 +1124,9 @@ sub handle_command_cmd { $operator = $last->{operator}; $movement = $last->{movement}; $register = $last->{register}; + $repeat = 1; } elsif ($char eq '.') { + print '. pressed but $last->{char} not set' if DEBUG; $skip = 1; } # C and D force the matching operator @@ -1098,13 +1148,15 @@ sub handle_command_cmd { # Execute the movement (multiple times). my $cur_pos = _input_pos(); if (not $movement) { - $movements->{$char}->{func}->($numeric_prefix, $cur_pos); + $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, $repeat); } else { # Use the real movement command (like t or f) for operator # below. $char = substr $movement, 0, 1; $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, substr $movement, 1); + ->($numeric_prefix, $cur_pos, $repeat, + substr $movement, 1); } my $new_pos = _input_pos(); @@ -1120,7 +1172,9 @@ sub handle_command_cmd { # registers. if ($operator or $char eq 'x' or $char eq 'X' or $char eq 'r' or $char eq 'p' or $char eq 'P' or $char eq 'C' or - $char eq 'D' or $char eq '~' or $char eq '"') { + $char eq 'D' or $char eq '~' or $char eq '"' or + $char eq 'i' or $char eq 'I' or $char eq 'a' or + $char eq 'A') { $last->{char} = $char; $last->{numeric_prefix} = $numeric_prefix; $last->{operator} = $operator; @@ -1129,7 +1183,12 @@ sub handle_command_cmd { } } - $numeric_prefix = undef; + # Reset the count unless we go into insert mode, _update_mode() needs + # to know it when leaving insert mode to support insert with counts + # (like 3i). + if ($repeat or ($char ne 'i' and $char ne 'I' and $char ne 'a' and $char ne 'A')) { + $numeric_prefix = undef; + } $operator = undef; $movement = undef; @@ -1371,20 +1430,33 @@ sub _stop() { sub _update_mode { my ($new_mode) = @_; - # In insert mode we are "between" characters, in command mode "on top" of - # keys. When leaving insert mode we have to move on key left to accomplish - # that. if ($mode == M_INS and $new_mode == M_CMD) { - my $pos = _input_pos(); - if ($pos != 0) { - _input_pos($pos - 1); + # Support counts with insert modes, like 3i. + if ($numeric_prefix and $numeric_prefix > 1) { + _insert_buffer($numeric_prefix - 1); + $numeric_prefix = undef; + + # In insert mode we are "between" characters, in command mode "on top" + # of keys. When leaving insert mode we have to move on key left to + # accomplish that. + } else { + my $pos = _input_pos(); + if ($pos != 0) { + _input_pos($pos - 1); + } } + # Change mode to i to support insert mode repetition. This doesn't affect + # commands like i/a/I/A because handle_command_cmd() sets $last->{char}. + # It's necessary when pressing enter. + } elsif ($mode == M_CMD and $new_mode == M_INS) { + $last->{char} = 'i'; } $mode = $new_mode; if ($mode == M_INS) { $history_index = undef; $register = '"'; + @insert_buf = (); # Reset every command mode related status as a fallback in case something # goes wrong. } elsif ($mode == M_CMD) { -- cgit v1.2.3 From a3349f29c86725c9cad89eff66152da2a057ae75 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 16:11:28 +0200 Subject: vim_mode: Add missing if DEBUG. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3a81b88..c55481c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1307,7 +1307,7 @@ sub _add_undo_entry { # check it's not a dupe of the list head my $head = $undo_buffer[0]; if ($line eq $head->[0] && $pos == $head->[1]) { - print "Not adding duplicate to undo list"; + print "Not adding duplicate to undo list" if DEBUG; } else { print "adding $line to undo list" if DEBUG; # add to the front of the buffer -- cgit v1.2.3 From 39dc92fe8cbdcffc5966a25aad29802e3f1aa44b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 16:33:54 +0200 Subject: vim_mode: Comment update. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c55481c..0b2bb37 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -130,7 +130,7 @@ sub M_CMD() { 1 } # command mode sub M_INS() { 0 } # insert mode sub M_EX () { 2 } # extended mode (after a :?) -# word and non-word regex +# word and non-word regex, when modifiying also update them in setup_changed() my $word = qr/[\w_]/o; my $non_word = qr/[^\w_\s]/o; -- cgit v1.2.3 From 9e11fd40f49ab53b50aedd9a874516af223e6b55 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 16:53:37 +0200 Subject: vim_mode: Make sure ex commands match from the beginning. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0b2bb37..c4719d7 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -756,7 +756,7 @@ sub cmd_movement_register { sub cmd_ex_command { my $arg_str = join '', @ex_buf; - if ($arg_str =~ m|s/(.+)/(.*)/([ig]*)|) { + if ($arg_str =~ m|^s/(.+)/(.*)/([ig]*)|) { my ($search, $replace, $flags) = ($1, $2, $3); print "Searching for $search, replace: $replace, flags; $flags" if DEBUG; @@ -784,7 +784,7 @@ sub cmd_ex_command { print "New line is: $line" if DEBUG; _input($line); - } elsif ($arg_str =~ m|b(?:uffer)?\s*(.+)$|) { + } elsif ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { my $window; my $item; my $buffer = $1; -- cgit v1.2.3 From 69a0ace326eb7050539980c6cbca340cdae9b741 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 17:00:52 +0200 Subject: vim_mode: Only allow access to registers a-z and " * +. --- vim-mode/vim_mode.pl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c4719d7..63d51ca 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -180,11 +180,16 @@ my $mode = M_INS; # current active register my $register = '"'; -# vi registers, " is the default register +# vi registers my $registers = { - '"' => '' + '"' => '', # default register + '+' => '', # contains irssi's cut buffer + '*' => '', # same }; +foreach my $char ('a' .. 'z') { + $registers->{$char} = ''; +} # current imap still pending (first character entered) my $imap = undef; @@ -744,6 +749,11 @@ sub cmd_movement_tilde { sub cmd_movement_register { my ($count, $pos, $repeat, $char) = @_; + if (not exists $registers->{$char}) { + print "Wrong register $char, ignoring." if DEBUG; + return; + } + # + and * contain both irssi's cut-buffer if ($char eq '+' or $char eq '*') { $registers->{'+'} = Irssi::parse_special('$U'); -- cgit v1.2.3 From 9fdaf81e05d7cb799bfc24a76b14134a51ce785d Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 17:01:39 +0200 Subject: vim_mode: Add :reg[isters] and :di[splay] ex commands. --- vim-mode/vim_mode.pl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 63d51ca..6f5a70a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -820,6 +820,21 @@ sub cmd_ex_command { $item->set_active(); } } + + # :reg[isters] {arg} and :di[splay] {arg} + } elsif ($arg_str =~ /^(?:reg(?:isters)?|di(?:splay)?)(?:\s+(.+)$)?/) { + my @regs; + if ($1) { + @regs = split //, $1 =~ s/\s+//g; + } else { + @regs = keys %$registers; + } + my $window = Irssi::active_win; + foreach my $key (sort @regs) { + if (defined $registers->{$key}) { + $window->print("register $key: $registers->{$key}"); + } + } } } -- cgit v1.2.3 From 2a78cf48f886f2ed69aa7e8a0771bd5be5256dbc Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 17:05:37 +0200 Subject: vim_mode: Fix :registers/:display with arguments. --- vim-mode/vim_mode.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 6f5a70a..f801761 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -825,7 +825,9 @@ sub cmd_ex_command { } elsif ($arg_str =~ /^(?:reg(?:isters)?|di(?:splay)?)(?:\s+(.+)$)?/) { my @regs; if ($1) { - @regs = split //, $1 =~ s/\s+//g; + my $regs = $1; + $regs =~ s/\s+//g; + @regs = split //, $regs; } else { @regs = keys %$registers; } -- cgit v1.2.3 From b51bb6d7bfb522b37656638835fa6f00a13d189b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 18:09:18 +0200 Subject: vim_mode: Add support to append to registers (A-Z). --- vim-mode/vim_mode.pl | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f801761..3cf1b7e 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -326,9 +326,15 @@ sub cmd_operator_d { # Remove the selected string from the input. my $input = _input(); - $registers->{$register} = substr $input, $pos, $length, ''; + my $string = substr $input, $pos, $length, ''; + if ($register =~ /[A-Z]/) { + $registers->{lc $register} .= $string; + print "Deleted into $register: ", $registers->{lc $register} if DEBUG; + } else { + $registers->{$register} = $string; + print "Deleted into $register: ", $registers->{$register} if DEBUG; + } _input($input); - print "Deleted into $register: " . $registers->{$register} if DEBUG; # Move the cursor at the right position. _input_pos($pos); @@ -340,8 +346,14 @@ sub cmd_operator_y { # Extract the selected string and put it in the " register. my $input = _input(); - $registers->{$register} = substr $input, $pos, $length; - print "Yanked into $register: " . $registers->{$register} if DEBUG; + my $string = substr $input, $pos, $length; + if ($register =~ /[A-Z]/) { + $registers->{lc $register} .= $string; + print "Yanked into $register: ", $registers->{lc $register} if DEBUG; + } else { + $registers->{$register} = $string; + print "Yanked into $register: ", $registers->{$register} if DEBUG; + } _input_pos($old_pos); } @@ -749,7 +761,7 @@ sub cmd_movement_tilde { sub cmd_movement_register { my ($count, $pos, $repeat, $char) = @_; - if (not exists $registers->{$char}) { + if (not exists $registers->{$char} and not exists $registers->{lc $char}) { print "Wrong register $char, ignoring." if DEBUG; return; } -- cgit v1.2.3 From 889b2b262800c17f462c62ddea2a290788c42087 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 18:16:15 +0200 Subject: vim_mode: Don't move after last character in command mode. --- vim-mode/vim_mode.pl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3cf1b7e..a42fc65 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -390,7 +390,7 @@ sub cmd_movement_l { my $length = _input_len(); $pos += $count; - $pos = $length if $pos > $length; + $pos = $length - 1 if $pos > $length - 1; _input_pos($pos); } sub cmd_movement_space { @@ -642,7 +642,7 @@ sub cmd_movement_caret { _input_pos($pos); } sub cmd_movement_dollar { - _input_pos(_input_len()); + _input_pos(_input_len() - 1); } sub cmd_movement_x { @@ -682,7 +682,13 @@ sub cmd_movement_I { sub cmd_movement_a { my ($count, $pos, $repeat) = @_; - cmd_movement_l(1, _input_pos()); + # Move after current character. Can't use cmd_movement_l() because we need + # to mover after last character at the end of the line. + my $length = _input_len(); + $pos += $count; + $pos = $length if $pos > $length; + _input_pos($pos); + if (!$repeat) { _update_mode(M_INS); } else { @@ -692,7 +698,8 @@ sub cmd_movement_a { sub cmd_movement_A { my ($count, $pos, $repeat) = @_; - cmd_movement_dollar(); + _input_pos(_input_len()); + if (!$repeat) { _update_mode(M_INS); } else { -- cgit v1.2.3 From 50f6b1c8ac8aa83ae252435b0e21401d816c7e75 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 18:54:51 +0200 Subject: vim_mode: Support repeat for c, like c3wxxx . --- vim-mode/vim_mode.pl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a42fc65..acc4f26 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -314,13 +314,17 @@ sub cmd_redo { } sub cmd_operator_c { - my ($old_pos, $new_pos, $move) = @_; + my ($old_pos, $new_pos, $move, $repeat) = @_; cmd_operator_d($old_pos, $new_pos, $move); - _update_mode(M_INS); + if (!$repeat) { + _update_mode(M_INS); + } else { + _insert_buffer(1); + } } sub cmd_operator_d { - my ($old_pos, $new_pos, $move) = @_; + my ($old_pos, $new_pos, $move, $repeat) = @_; my ($pos, $length) = _get_pos_and_length($old_pos, $new_pos, $move); @@ -340,7 +344,7 @@ sub cmd_operator_d { _input_pos($pos); } sub cmd_operator_y { - my ($old_pos, $new_pos, $move) = @_; + my ($old_pos, $new_pos, $move, $repeat) = @_; my ($pos, $length) = _get_pos_and_length($old_pos, $new_pos, $move); @@ -1139,7 +1143,7 @@ sub handle_command_cmd { if ($operator eq $char) { print "Processing operator: ", $operator, $char if DEBUG; my $pos = _input_pos(); - $operators->{$operator}->{func}->(0, _input_len(), ''); + $operators->{$operator}->{func}->(0, _input_len(), '', 0); # Restore position for yy. if ($char eq 'y') { _input_pos($pos); @@ -1211,7 +1215,8 @@ sub handle_command_cmd { # problems with e.g. f when the search string doesn't exist). if ($operator and $cur_pos != $new_pos) { print "Processing operator: ", $operator if DEBUG; - $operators->{$operator}->{func}->($cur_pos, $new_pos, $char); + $operators->{$operator}->{func}->($cur_pos, $new_pos, $char, + $repeat); } # Store command, necessary for . But ignore movements and -- cgit v1.2.3 From a2b9673ec108c5f66e6c2d8a8361aac5817f3a65 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 21:31:33 +0200 Subject: vim_mode: Fix d at the end of the line. --- vim-mode/vim_mode.pl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index acc4f26..847ce6e 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -340,6 +340,9 @@ sub cmd_operator_d { } _input($input); + # Prevent moving after the text when we delete the last character. + $pos-- if $pos == length($input); + # Move the cursor at the right position. _input_pos($pos); } -- cgit v1.2.3 From 37f477d0f42560b847916d8c2e678756746fd5c4 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 23:19:00 +0200 Subject: vim_mode: Fix deletion/yanking/changing with most movements. --- vim-mode/vim_mode.pl | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 847ce6e..cf04f35 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -397,7 +397,7 @@ sub cmd_movement_l { my $length = _input_len(); $pos += $count; - $pos = $length - 1 if $pos > $length - 1; + $pos = _fix_input_pos($pos, $length); _input_pos($pos); } sub cmd_movement_space { @@ -525,6 +525,7 @@ sub cmd_movement_w { } } + $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } sub cmd_movement_b { @@ -542,7 +543,9 @@ sub cmd_movement_b { sub cmd_movement_e { my ($count, $pos, $repeat) = @_; - $pos = _end_of_word(_input(), $count, $pos); + my $input = _input(); + $pos = _end_of_word($input, $count, $pos); + $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } # Go to the end of $count-th word, like vi's e. @@ -574,6 +577,11 @@ sub _end_of_word { } } + # Necessary for correct deletion at the end of the line. + if (length $input == $pos + 1) { + $pos++; + } + return $pos; } sub cmd_movement_W { @@ -586,6 +594,7 @@ sub cmd_movement_W { } $pos += $+[0] + 1; } + $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } sub cmd_movement_B { @@ -644,12 +653,14 @@ sub cmd_movement_caret { $pos = $-[0]; # Only whitespace, go to the end. } else { - $pos = _input_len(); + $pos = _fix_input_pos(_input_len(), length $input); } _input_pos($pos); } sub cmd_movement_dollar { - _input_pos(_input_len() - 1); + my $input = _input(); + my $length = length $input; + _input_pos(_fix_input_pos($length, $length)); } sub cmd_movement_x { @@ -790,6 +801,22 @@ sub cmd_movement_register { print "Changing register to $register" if DEBUG; } +# Adapt the input position depending if an operator is active or not. +sub _fix_input_pos { + my ($pos, $length) = @_; + + # Allow moving past the last character when an operator is active to allow + # correct handling of last character in line. + if ($operator) { + $pos = $length if $pos > $length; + # Otherwise forbid it. + } else { + $pos = $length - 1 if $pos > $length - 1; + } + + return $pos; +} + sub cmd_ex_command { my $arg_str = join '', @ex_buf; if ($arg_str =~ m|^s/(.+)/(.*)/([ig]*)|) { -- cgit v1.2.3 From e3d9f9c94d9f266999a22b387f857bdc8d4a5927 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 23:20:11 +0200 Subject: vim_mode: Fix W with operators. --- vim-mode/vim_mode.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cf04f35..99268a5 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -374,10 +374,11 @@ sub _get_pos_and_length { $length *= -1; } - # w, x, X, h, l are the only movements which move one character after the - # deletion area (which is what we need), all other commands need one + # w, W, x, X, h, l are the only movements which move one character after + # the deletion area (which is what we need), all other commands need one # character more for correct deletion. - if ($move ne 'w' and $move ne 'x' and $move ne 'X' and $move ne 'h' and $move ne 'l') { + if ($move ne 'w' and $move ne 'W' and $move ne 'x' and $move ne 'X' and + $move ne 'h' and $move ne 'l') { $length += 1; } -- cgit v1.2.3 From 20c5a2b31de167f4491e557b2ff3e10061ab61d1 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 23:37:35 +0200 Subject: vim_mode: Fix missing argument to cmd_operator_d(). --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 99268a5..8e05927 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -316,7 +316,7 @@ sub cmd_redo { sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; - cmd_operator_d($old_pos, $new_pos, $move); + cmd_operator_d($old_pos, $new_pos, $move, $repeat); if (!$repeat) { _update_mode(M_INS); } else { -- cgit v1.2.3 From 4a06ec71f736f4155b810087d30c1413c284eadc Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 23:37:53 +0200 Subject: vim_mode: Fix dB. --- vim-mode/vim_mode.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8e05927..eebe58b 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -374,11 +374,11 @@ sub _get_pos_and_length { $length *= -1; } - # w, W, x, X, h, l are the only movements which move one character after - # the deletion area (which is what we need), all other commands need one - # character more for correct deletion. + # Most movement commands don't move one character after the deletion area + # (which is what we need). For those increase length to support proper + # selection/deletion. if ($move ne 'w' and $move ne 'W' and $move ne 'x' and $move ne 'X' and - $move ne 'h' and $move ne 'l') { + $move ne 'B' and $move ne 'h' and $move ne 'l') { $length += 1; } -- cgit v1.2.3 From 4224a6ef673e337d7253043f9ade7f45785b1bcf Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 29 Sep 2010 23:42:52 +0200 Subject: vim_mode: Fix c to not delete the last space before a word. --- vim-mode/vim_mode.pl | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index eebe58b..bd15c2f 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -316,6 +316,14 @@ sub cmd_redo { sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; + # Changing a word or WORD doesn't delete the last space before a word. + if ($move eq 'w' or $move eq 'W') { + my $input = _input(); + if (substr($input, $new_pos - 1, 1) =~ /\s/) { + $new_pos--; + } + } + cmd_operator_d($old_pos, $new_pos, $move, $repeat); if (!$repeat) { _update_mode(M_INS); -- cgit v1.2.3 From ae73ff808df9356552f231934612412281dc45e9 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 30 Sep 2010 00:27:36 +0200 Subject: vim_mode: Fix C not to move one character to the left. --- vim-mode/vim_mode.pl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index bd15c2f..f7705ed 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -324,7 +324,8 @@ sub cmd_operator_c { } } - cmd_operator_d($old_pos, $new_pos, $move, $repeat); + cmd_operator_d($old_pos, $new_pos, $move, $repeat, 1); + if (!$repeat) { _update_mode(M_INS); } else { @@ -332,7 +333,7 @@ sub cmd_operator_c { } } sub cmd_operator_d { - my ($old_pos, $new_pos, $move, $repeat) = @_; + my ($old_pos, $new_pos, $move, $repeat, $change) = @_; my ($pos, $length) = _get_pos_and_length($old_pos, $new_pos, $move); @@ -348,8 +349,9 @@ sub cmd_operator_d { } _input($input); - # Prevent moving after the text when we delete the last character. - $pos-- if $pos == length($input); + # Prevent moving after the text when we delete the last character. But not + # when changing (C). + $pos-- if $pos == length($input) and !$change; # Move the cursor at the right position. _input_pos($pos); -- cgit v1.2.3 From aa51fbc616e960251606a36f35f41e0081d8ad99 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 20:55:00 +0100 Subject: removed // defined-or to allow 5.8 users to play. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f7705ed..0263876 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -838,7 +838,7 @@ sub cmd_ex_command { my $rep_fun = sub { $replace }; my $line = _input(); - my @re_flags = split '', $flags // ''; + my @re_flags = split '', defined $flags:$flags:''; if (scalar grep { $_ eq 'i' } @re_flags) { $search = '(?i)' . $search; -- cgit v1.2.3 From cfcea1939a82fb52ddfc8b7d6a493ed0d55627fb Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 21:01:15 +0100 Subject: fixed comment urls to point at irssi-scripts/ as they should --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0263876..e7c39d8 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -51,7 +51,7 @@ # Dependencies: # # For proper :ex mode support, requires the installation of prompt_info.pl -# http://github.com/shabble/shab-irssi-scripts/raw/master/prompt_info/prompt_info.pl +# http://github.com/shabble/irssi-scripts/raw/master/prompt_info/prompt_info.pl # # and follow the instructions in the top of that file for installation instructions. # @@ -68,7 +68,7 @@ # # NOTE: This script is still under heavy development, and there may be bugs. # Please submit reproducible sequences to the bug-tracker at: -# http://github.com/shabble/shab-irssi-scripts/issues +# http://github.com/shabble/irssi-scripts/issues # # or contact rudi_s or shabble on irc.freenode.net (#irssi) # -- cgit v1.2.3 From 08be16aead4f98217dd7a4191c98a79dac83b366 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 21:03:06 +0100 Subject: rename $window to avoid conflict in cmd_ex_command --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e7c39d8..c4c4740 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -895,10 +895,10 @@ sub cmd_ex_command { } else { @regs = keys %$registers; } - my $window = Irssi::active_win; + my $active_window = Irssi::active_win; foreach my $key (sort @regs) { if (defined $registers->{$key}) { - $window->print("register $key: $registers->{$key}"); + $active_window->print("register $key: $registers->{$key}"); } } } -- cgit v1.2.3 From 1d8e4518d0731e240b65b6010c1457522c0302da Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 21:05:20 +0100 Subject: thanks to rudi_s for pointing out what a ternary operator looks like. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c4c4740..1da40c0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -838,7 +838,7 @@ sub cmd_ex_command { my $rep_fun = sub { $replace }; my $line = _input(); - my @re_flags = split '', defined $flags:$flags:''; + my @re_flags = split '', defined $flags?$flags:''; if (scalar grep { $_ eq 'i' } @re_flags) { $search = '(?i)' . $search; -- cgit v1.2.3 From 8b72bce555be87822bd5ff37ead74931f4e046b2 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 21:08:04 +0100 Subject: renamed $ratio for some more 'my masks ... scope' weirdness in 5.8.9 --- vim-mode/vim_mode.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 1da40c0..40a5a14 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -921,10 +921,10 @@ sub _matching_windows { foreach my $window (Irssi::windows()) { # Matching window names. if ($window->{name} =~ /$buffer/i) { - my $ratio = ($+[0] - $-[0]) / length($window->{name}); + my $win_ratio = ($+[0] - $-[0]) / length($window->{name}); push @matches, { window => $window, item => undef, - ratio => $ratio, + ratio => $win_ratio, text => $window->{name} }; print ":b $window->{name}: $ratio" if DEBUG; } @@ -938,10 +938,10 @@ sub _matching_windows { if ($item->{name} =~ /$buffer/i) { my $length = length($item->{name}); $length-- if index($item->{name}, '#') == 0; - my $ratio = ($+[0] - $-[0]) / $length; + my $item_ratio = ($+[0] - $-[0]) / $length; push @matches, { window => $window, item => $item, - ratio => $ratio, + ratio => $item_ratio, text => $item->{name} }; print ":b $window->{name} $item->{name}: $ratio" if DEBUG; } -- cgit v1.2.3 From 5e644a649b3bf7ed93a8b355f88998ee50d4e634 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 21:13:39 +0100 Subject: missed some $ratios in teh debug prints when fixing last time --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 40a5a14..ab948c3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -926,7 +926,7 @@ sub _matching_windows { item => undef, ratio => $win_ratio, text => $window->{name} }; - print ":b $window->{name}: $ratio" if DEBUG; + print ":b $window->{name}: $win_ratio" if DEBUG; } # Matching Window item names (= channels). foreach my $item ($window->items()) { @@ -943,7 +943,7 @@ sub _matching_windows { item => $item, ratio => $item_ratio, text => $item->{name} }; - print ":b $window->{name} $item->{name}: $ratio" if DEBUG; + print ":b $window->{name} $item->{name}: $item_ratio" if DEBUG; } } } -- cgit v1.2.3 From c2c5b35a212409109b7ed9676427e8a420078c90 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 30 Sep 2010 22:13:42 +0200 Subject: vim_mode: Also unregister the vim_windows statusbar. --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ab948c3..ebed331 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1391,6 +1391,7 @@ sub setup_changed { sub UNLOAD { Irssi::signal_remove('gui key pressed' => \&got_key); Irssi::statusbar_item_unregister ('vim_mode'); + Irssi::statusbar_item_unregister ('vim_windows'); } -- cgit v1.2.3 From 61ebb39943e3ca8b32a724c14885399b55f51709 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 30 Sep 2010 22:55:41 +0200 Subject: vim_mode: Fix insert repeat forgetting flushed @input_buf chars. --- vim-mode/vim_mode.pl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ebed331..89b2dd0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1126,6 +1126,9 @@ sub flush_input_buffer { # see what we've collected. print "Input buffer flushed" if DEBUG; + # Add the characters to @insert_buf so they can be repeated. + push @insert_buf, map chr, @input_buf; + _emulate_keystrokes(@input_buf); @input_buf = (); -- cgit v1.2.3 From 800020720932c089a0997fe7aa1be241a15f2d80 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 30 Sep 2010 23:45:46 +0200 Subject: vim_mode: Implement black hole register. --- vim-mode/vim_mode.pl | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 89b2dd0..1de7a6d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -186,6 +186,7 @@ my $registers '"' => '', # default register '+' => '', # contains irssi's cut buffer '*' => '', # same + '_' => '', # black hole register, always empty }; foreach my $char ('a' .. 'z') { $registers->{$char} = ''; @@ -802,6 +803,11 @@ sub cmd_movement_register { return; } + # make sure black hole register is always empty + if ($char eq '_') { + $registers->{_} = ''; + } + # + and * contain both irssi's cut-buffer if ($char eq '+' or $char eq '*') { $registers->{'+'} = Irssi::parse_special('$U'); -- cgit v1.2.3 From 3013106f6c9ee7770ba493c7fc33249d047c298a Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 23:04:01 +0100 Subject: major changes to undo, no longer saving entries from inside _input, but using command handler instead. --- vim-mode/vim_mode.pl | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ab948c3..0189041 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -298,15 +298,15 @@ my $movements_multiple = sub cmd_undo { print "Undo!" if DEBUG; - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - - _restore_undo_entry($undo_index); - if ($undo_index != $#undo_buffer) { $undo_index++; } else { print "No further undo." if DEBUG; } + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; + + _restore_undo_entry($undo_index); + } sub cmd_redo { @@ -1236,8 +1236,12 @@ sub handle_command_cmd { $numeric_prefix = 1; } - # Execute the movement (multiple times). my $cur_pos = _input_pos(); + + _add_undo_entry(_input(), $cur_pos) unless $char eq 'u'; + + # Execute the movement (multiple times). + if (not $movement) { $movements->{$char}->{func} ->($numeric_prefix, $cur_pos, $repeat); @@ -1400,8 +1404,11 @@ sub _add_undo_entry { my $head = $undo_buffer[0]; if ($line eq $head->[0] && $pos == $head->[1]) { print "Not adding duplicate to undo list" if DEBUG; + } elsif ($line eq $head->[0]) { + print "Updating position of undo list head" if DEBUG; + $undo_buffer[0]->[1] = $pos; } else { - print "adding $line to undo list" if DEBUG; + print "adding $line ($pos) to undo list" if DEBUG; # add to the front of the buffer unshift @undo_buffer, [$line, $pos]; } @@ -1410,7 +1417,7 @@ sub _add_undo_entry { sub _restore_undo_entry { my $entry = $undo_buffer[$undo_index]; - _input($entry->[0], 1); + _input($entry->[0]); _input_pos($entry->[1]); } @@ -1456,7 +1463,7 @@ sub _commit_line { } sub _input { - my ($data, $ignore_undo) = @_; + my ($data) = @_; my $current_data = Irssi::parse_special('$L', 0, 0); @@ -1465,16 +1472,6 @@ sub _input { } if (defined $data) { - if (!$ignore_undo && ($data ne $current_data)) { - if ($undo_index != 0) { # ??? - print "Resetting undo buffer" if DEBUG; - _reset_undo_buffer($current_data, _input_pos()); - } else { - my $pos = _input_pos(); - print "Adding debug entry: $current_data $pos" if DEBUG; - _add_undo_entry($current_data, $pos); - } - } if ($utf8) { Irssi::gui_input_set(encode_utf8($data)); } else { @@ -1494,6 +1491,12 @@ sub _input_len { sub _input_pos { my ($pos) = @_; my $cur_pos = Irssi::gui_input_get_pos(); + my $dpos = defined $pos?$pos:'undef'; + my @call = caller(1); + my $cfunc = $call[3]; + $cfunc =~ s/^.*?::([^:]+)$/$1/; + print "pos called from line: $call[2] sub: $cfunc pos: $dpos, cur_pos: $cur_pos" + if DEBUG; if (defined $pos) { print "Input pos being set from $cur_pos to $pos" if DEBUG; -- cgit v1.2.3 From 6ed1c63beab95077112319f945c75c8c7ed928bc Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:26:36 +0200 Subject: vim_mode: Add missing use for irssi 0.8.14. --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 366bc3f..8751ac0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -106,6 +106,7 @@ use List::Util; use Irssi; use Irssi::TextUI; # for sbar_items_redraw +use Irssi::Irc; # necessary for 0.8.14 use vars qw($VERSION %IRSSI); -- cgit v1.2.3 From 2daf2ccbf49dbf4bb9bcc46790e77359a289381b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:37:36 +0200 Subject: vim_mode: Add ; and ,. --- vim-mode/vim_mode.pl | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8751ac0..40b8cc4 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -174,6 +174,12 @@ my $last 'movement' => undef, 'register' => '"', }; +# last ftFT movement, used by ; and , +my $last_ftFT + = { + type => undef, # f, t, F or T + char => undef, + }; # what Vi mode we're in. We start in insert mode. my $mode = M_INS; @@ -247,6 +253,8 @@ my $movements 't' => { func => \&cmd_movement_t }, 'F' => { func => \&cmd_movement_F }, 'T' => { func => \&cmd_movement_T }, + ';' => { func => \&cmd_movement_semicolon }, + ',' => { func => \&cmd_movement_comma }, # word movement 'w' => { func => \&cmd_movement_w }, 'b' => { func => \&cmd_movement_b }, @@ -481,6 +489,8 @@ sub cmd_movement_f { if ($pos != -1) { _input_pos($pos); } + + $last_ftFT = { type => 'f', char => $char }; } sub cmd_movement_t { my ($count, $pos, $repeat, $char) = @_; @@ -489,6 +499,8 @@ sub cmd_movement_t { if ($pos != -1) { _input_pos($pos - 1); } + + $last_ftFT = { type => 't', char => $char }; } sub cmd_movement_F { my ($count, $pos, $repeat, $char) = @_; @@ -498,6 +510,8 @@ sub cmd_movement_F { if ($pos != -1) { _input_pos(length($input) - $pos - 1); } + + $last_ftFT = { type => 'F', char => $char }; } sub cmd_movement_T { my ($count, $pos, $repeat, $char) = @_; @@ -507,6 +521,8 @@ sub cmd_movement_T { if ($pos != -1) { _input_pos(length($input) - $pos - 1 + 1); } + + $last_ftFT = { type => 'T', char => $char }; } # Find $count-th next occurrence of $char. sub _next_occurrence { @@ -796,6 +812,31 @@ sub cmd_movement_tilde { _input_pos($pos + $count); } +sub cmd_movement_semicolon { + my ($count, $pos, $repeat) = @_; + + return if not defined $last_ftFT; + + $movements->{$last_ftFT->{type}} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); +} +sub cmd_movement_comma { + my ($count, $pos, $repeat) = @_; + + return if not defined $last_ftFT; + + # Change direction. + my $save = $last_ftFT->{type}; + my $type = $save; + $type =~ tr/ftFT/FTft/; + + $movements->{$type} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + # Restore type as the move functions overwrites it. + $last_ftFT->{type} = $save; +} + + sub cmd_movement_register { my ($count, $pos, $repeat, $char) = @_; -- cgit v1.2.3 From 979d1835e7172f7aaeb6a4c0e15e78dda6c3ff26 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Thu, 30 Sep 2010 23:41:49 +0100 Subject: mostly working undo/redo support. Still adding history entries though, which we don't really want. --- vim-mode/vim_mode.pl | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 366bc3f..d0f1d46 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -312,6 +312,15 @@ sub cmd_undo { sub cmd_redo { print "Redo!" if DEBUG; + + if ($undo_index != 0) { + $undo_index--; + } else { + print "No further Redo." if DEBUG; + } + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; + + _restore_undo_entry($undo_index); } sub cmd_operator_c { @@ -1247,7 +1256,16 @@ sub handle_command_cmd { my $cur_pos = _input_pos(); - _add_undo_entry(_input(), $cur_pos) unless $char eq 'u'; + # save an undo checkpoint here. + + if ($char ne 'u' && $char ne "\x12" + && $char ne 'j' && $char ne 'k') { + + # TODO: why do histpry entries still show up in undo + # buffer? Is avoiding the commands here insufficient? + + _add_undo_entry(_input(), $cur_pos); + } # Execute the movement (multiple times). @@ -1411,18 +1429,18 @@ sub UNLOAD { sub _add_undo_entry { my ($line, $pos) = @_; # check it's not a dupe of the list head - my $head = $undo_buffer[0]; - if ($line eq $head->[0] && $pos == $head->[1]) { + my $current = $undo_buffer[$undo_index]; + if ($line eq $current->[0] && $pos == $current->[1]) { print "Not adding duplicate to undo list" if DEBUG; - } elsif ($line eq $head->[0]) { - print "Updating position of undo list head" if DEBUG; - $undo_buffer[0]->[1] = $pos; + } elsif ($line eq $current->[0]) { + print "Updating position of undo list at $undo_index" if DEBUG; + $undo_buffer[$undo_index]->[1] = $pos; } else { print "adding $line ($pos) to undo list" if DEBUG; # add to the front of the buffer unshift @undo_buffer, [$line, $pos]; + $undo_index = 0; } - $undo_index = 0; } sub _restore_undo_entry { @@ -1501,19 +1519,19 @@ sub _input_len { sub _input_pos { my ($pos) = @_; my $cur_pos = Irssi::gui_input_get_pos(); - my $dpos = defined $pos?$pos:'undef'; - my @call = caller(1); - my $cfunc = $call[3]; - $cfunc =~ s/^.*?::([^:]+)$/$1/; - print "pos called from line: $call[2] sub: $cfunc pos: $dpos, cur_pos: $cur_pos" - if DEBUG; + # my $dpos = defined $pos?$pos:'undef'; + # my @call = caller(1); + # my $cfunc = $call[3]; + # $cfunc =~ s/^.*?::([^:]+)$/$1/; + # print "pos called from line: $call[2] sub: $cfunc pos: $dpos, cur_pos: $cur_pos" + # if DEBUG; if (defined $pos) { - print "Input pos being set from $cur_pos to $pos" if DEBUG; + #print "Input pos being set from $cur_pos to $pos" if DEBUG; Irssi::gui_input_set_pos($pos) if $pos != $cur_pos; } else { $pos = $cur_pos; - print "Input pos retrieved as $pos" if DEBUG; + #print "Input pos retrieved as $pos" if DEBUG; } return $pos; -- cgit v1.2.3 From a916626f1db1d414bc73391ed5c332af8ff8e52e Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Fri, 1 Oct 2010 00:12:41 +0100 Subject: more fixing to undo, weird bug that C-d would make it work when it shouldn't. --- vim-mode/vim_mode.pl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5e5096d..28a6383 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -308,28 +308,28 @@ my $movements_multiple = sub cmd_undo { print "Undo!" if DEBUG; + _restore_undo_entry($undo_index); + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; if ($undo_index != $#undo_buffer) { $undo_index++; } else { print "No further undo." if DEBUG; } - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - _restore_undo_entry($undo_index); } sub cmd_redo { print "Redo!" if DEBUG; + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; + + _restore_undo_entry($undo_index); if ($undo_index != 0) { $undo_index--; } else { print "No further Redo." if DEBUG; } - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - - _restore_undo_entry($undo_index); } sub cmd_operator_c { @@ -1300,7 +1300,7 @@ sub handle_command_cmd { # save an undo checkpoint here. - if ($char ne 'u' && $char ne "\x12" + if ($char ne 'u' && $char ne "\x12" && $char ne "\x04" && $char ne 'j' && $char ne 'k') { # TODO: why do histpry entries still show up in undo -- cgit v1.2.3 From a41577d74462ae1cbcb086dd0241111ff1abe656 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:38:41 +0200 Subject: vim_mode: Remove implemented todo. --- vim-mode/vim_mode.pl | 1 - 1 file changed, 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 28a6383..b484b87 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -30,7 +30,6 @@ # * Window switching (:b) # * Tab completion of window(-item) names # * non-sequential matches(?) -# * additional statusbar-item for showing matches # # * use irssi settings for some of the features # * Done: -- cgit v1.2.3 From 64127c970fea1f7f8caa7986154aafa5cb36a064 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:48:56 +0200 Subject: vim_mode: Add s. --- vim-mode/vim_mode.pl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index b484b87..c0dee6a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -6,7 +6,7 @@ # * cursor motion with: h l 0 ^ $ # * history motion with j k # * cursor word motion with: w b e W B E -# * change/delete: c d C D +# * change/delete: c d C D s # * delete at cursor: x # * replace at cursor: r # * Insert mode at pos: i a @@ -1218,6 +1218,12 @@ sub handle_command_cmd { $movement .= $char; } + # s is an alias for cl. + if (!$movement and !$operator and $char eq 's') { + print "Changing s to cl" if DEBUG; + $char = 'l'; + $operator = 'c'; + } # S is an alias for cc. if (!$movement and !$operator and $char eq 'S') { print "Changing S to cc" if DEBUG; -- cgit v1.2.3 From 90c9b37ba4cef2b4aaa7fd47fe28a32ec7edc7c3 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:52:34 +0200 Subject: vim_mode: Document ; and . --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c0dee6a..4ce53f6 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -15,6 +15,7 @@ # * yank and paste: y p P # * switch case: ~ # * repeat change: . +# * repeat ftFT: ; , # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx # * window selection: :b, :b#, :b -- cgit v1.2.3 From 64ecf5ca769f74266d8c5a1bdf577cf4645a1985 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 00:59:33 +0200 Subject: vim_mode: Fix esc in ex mode leaving the prompt unchanged. --- vim-mode/vim_mode.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 4ce53f6..fe7fb58 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1402,7 +1402,6 @@ sub handle_command_ex { } elsif ($key == 10) { print "Run ex-mode command" if DEBUG; cmd_ex_command(); - _set_prompt(''); @ex_buf = (); _update_mode(M_CMD); @@ -1621,6 +1620,9 @@ sub _update_mode { # It's necessary when pressing enter. } elsif ($mode == M_CMD and $new_mode == M_INS) { $last->{char} = 'i'; + # Make sure prompt is cleared when leaving ex mode. + } elsif ($mode == M_EX and $new_mode != M_EX) { + _set_prompt(''); } $mode = $new_mode; -- cgit v1.2.3 From aaf88d8ffe11e65edc855676da135b49f34bd829 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 01:05:41 +0200 Subject: vim_mode: Add :ls and :buffers. --- vim-mode/vim_mode.pl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index fe7fb58..cb2a182 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -958,6 +958,9 @@ sub cmd_ex_command { $active_window->print("register $key: $registers->{$key}"); } } + # :ls and :buffers + } elsif ($arg_str eq 'ls' or $arg_str eq 'buffers') { + Irssi::command('window list'); } } -- cgit v1.2.3 From 353aa8969ed5677c057b2670bf7178a97665fbb5 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 01:27:42 +0200 Subject: vim_mode: Add :bn :bp. --- vim-mode/vim_mode.pl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cb2a182..f0ad409 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -18,7 +18,7 @@ # * repeat ftFT: ; , # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx -# * window selection: :b, :b#, :b +# * window selection: :b, :b#, :b :bn :bp # # * special registers: "* "+ (contain irssi's cut-buffer) # @@ -914,7 +914,13 @@ sub cmd_ex_command { print "New line is: $line" if DEBUG; _input($line); - + # :bn + } elsif ($arg_str eq 'bn') { + Irssi::command('window next'); + # :bp + } elsif ($arg_str eq 'bp') { + Irssi::command('window previous'); + # :b[buffer] {args} } elsif ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { my $window; my $item; -- cgit v1.2.3 From 55745779b3b3ae7b95e15a9835958e5301dc0354 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 01:37:48 +0200 Subject: vim_mode: Add Ctrl-6 in command mode, same like :b#. --- vim-mode/vim_mode.pl | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f0ad409..a9b7d0f 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -286,6 +286,7 @@ my $movements '~' => { func => \&cmd_movement_tilde }, '.' => {}, '"' => { func => \&cmd_movement_register }, + "\x1e" => { func => \&cmd_movement_ctrl_6 }, # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, @@ -869,6 +870,11 @@ sub cmd_movement_register { print "Changing register to $register" if DEBUG; } +sub cmd_movement_ctrl_6 { + # like :b# + Irssi::command('window last'); +} + # Adapt the input position depending if an operator is active or not. sub _fix_input_pos { my ($pos, $length) = @_; -- cgit v1.2.3 From 0baba895e6047e2a192c5b9cdc06aaebf5d4500c Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Fri, 1 Oct 2010 00:38:30 +0100 Subject: beginnings of configurable undo buffer size limit. --- vim-mode/vim_mode.pl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 28a6383..fcbe944 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1421,6 +1421,7 @@ sub vim_mode_init { Irssi::settings_add_str('vim_mode', 'vim_mode_cmd_seq', ''); Irssi::settings_add_bool('vim_mode', 'vim_mode_debug', 0); Irssi::settings_add_bool('vim_mode', 'vim_mode_utf8', 1); + Irssi::settings_add_int('vim_mode', 'vim_mode_max_undo_lines', 50); setup_changed(); _reset_undo_buffer(); @@ -1483,6 +1484,7 @@ sub _add_undo_entry { unshift @undo_buffer, [$line, $pos]; $undo_index = 0; } + my $max = Irssi::settings_get_int('vim_mode_max_undo_lines'); } sub _restore_undo_entry { -- cgit v1.2.3 From c1c1b33cb6210e689926d15fc466fdc129a736d7 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 02:00:04 +0200 Subject: vim_mode: Add :undol[ist], remove Ctrl-D. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a9b7d0f..8eef556 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -290,8 +290,6 @@ my $movements # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, - "\x04" => { func => \&_print_undo_buffer }, - }; # special movements which take an additional key @@ -973,6 +971,8 @@ sub cmd_ex_command { # :ls and :buffers } elsif ($arg_str eq 'ls' or $arg_str eq 'buffers') { Irssi::command('window list'); + } elsif ($arg_str eq 'undol' or $arg_str eq 'undolist') { + _print_undo_buffer(); } } -- cgit v1.2.3 From f4515f471290d38acbff699cc59239531c175918 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 02:01:01 +0200 Subject: vim_mode: Add Ctrl-D, Ctrl-U, Ctrl-F, Ctrl-B for scrolling. --- vim-mode/vim_mode.pl | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8eef556..0524be5 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -282,6 +282,11 @@ my $movements # to end of line 'C' => { func => \&cmd_movement_dollar }, 'D' => { func => \&cmd_movement_dollar }, + # scrolling + "\x04" => { func => \&cmd_movement_ctrl_d }, # half screen down + "\x15" => { func => \&cmd_movement_ctrl_u }, # half screen up + "\x06" => { func => \&cmd_movement_ctrl_f }, # screen down + "\x02" => { func => \&cmd_movement_ctrl_b }, # screen up # misc '~' => { func => \&cmd_movement_tilde }, '.' => {}, @@ -808,6 +813,38 @@ sub _paste_at_position { _insert_at_position($registers->{$register}, $count, $pos); } +sub cmd_movement_ctrl_d { + my ($count, $pos, $repeat) = @_; + + my $window = Irssi::active_win(); + # no count = half of screen + if (not defined $count) { + $count = $window->{height} / 2; + } + $window->view()->scroll($count); +} +sub cmd_movement_ctrl_u { + my ($count, $pos, $repeat) = @_; + + my $window = Irssi::active_win(); + # no count = half of screen + if (not defined $count) { + $count = $window->{height} / 2; + } + $window->view()->scroll($count * -1); +} +sub cmd_movement_ctrl_f { + my ($count, $pos, $repeat) = @_; + + my $window = Irssi::active_win(); + $window->view()->scroll($count * $window->{height}); +} +sub cmd_movement_ctrl_b { + my ($count, $pos, $repeat) = @_; + + cmd_movement_ctrl_f($count * -1, $pos, $repeat); +} + sub cmd_movement_tilde { my ($count, $pos, $repeat) = @_; @@ -1312,8 +1349,10 @@ sub handle_command_cmd { if ($skip) { print "Skipping movement and operator." if DEBUG; } else { - # Make sure count is at least 1. - if (not $numeric_prefix) { + # Make sure count is at least 1 except for functions which need to + # know if no count was used + if (not $numeric_prefix and $char ne "\x04" # ctrl-d + and $char ne "\x15") { # ctrl-u $numeric_prefix = 1; } -- cgit v1.2.3 From 71f90b647abaf0881823604adaa68618799f722a Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 02:09:06 +0200 Subject: vim_mode: Minor comment update. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 517b31c..5d918ef 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -294,7 +294,7 @@ my $movements "\x1e" => { func => \&cmd_movement_ctrl_6 }, # undo 'u' => { func => \&cmd_undo }, - "\x12" => { func => \&cmd_redo }, + "\x12" => { func => \&cmd_redo }, # ctrl-r }; # special movements which take an additional key -- cgit v1.2.3 From 15d5c53ccad7b09aaeda2029c9958d9853016a14 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 15:21:29 +0200 Subject: vim_mode: Add Ctrl-W j/k to switch to split windows. --- vim-mode/vim_mode.pl | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5d918ef..006f2b3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -18,7 +18,7 @@ # * repeat ftFT: ; , # * change/change/yank line: cc dd yy S # * Combinations like in Vi, e.g. d5fx -# * window selection: :b, :b#, :b :bn :bp +# * window selection: :b, :b#, :b :bn :bp Ctrl-W j/k # # * special registers: "* "+ (contain irssi's cut-buffer) # @@ -287,11 +287,13 @@ my $movements "\x15" => { func => \&cmd_movement_ctrl_u }, # half screen up "\x06" => { func => \&cmd_movement_ctrl_f }, # screen down "\x02" => { func => \&cmd_movement_ctrl_b }, # screen up + # window switching + "\x17" => { func => \&cmd_movement_ctrl_w }, + "\x1e" => { func => \&cmd_movement_ctrl_6 }, # misc '~' => { func => \&cmd_movement_tilde }, '.' => {}, '"' => { func => \&cmd_movement_register }, - "\x1e" => { func => \&cmd_movement_ctrl_6 }, # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, # ctrl-r @@ -306,6 +308,7 @@ my $movements_multiple = 'T' => undef, 'r' => undef, '"' => undef, + "\x17" => undef, # ctrl-w }; @@ -905,6 +908,19 @@ sub cmd_movement_register { print "Changing register to $register" if DEBUG; } +sub cmd_movement_ctrl_w { + my ($count, $pos, $repeat, $char) = @_; + + if ($char eq 'j') { + while ($count -- > 0) { + Irssi::command('window down'); + } + } elsif ($char eq 'k') { + while ($count -- > 0) { + Irssi::command('window up'); + } + } +} sub cmd_movement_ctrl_6 { # like :b# Irssi::command('window last'); -- cgit v1.2.3 From 8bc1587e11649fab126fbfd2cc840ffa3e8e570e Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 16:22:21 +0200 Subject: vim_mode: Update documentation. --- vim-mode/vim_mode.pl | 136 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 55 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 006f2b3..2b771b3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1,53 +1,84 @@ # A script to emulate some of the vi(m) features for the Irssi inputline. # -# Currently supported features: +# NOTE: This script is still under heavy development, and there may be bugs. +# Please submit reproducible sequences to the bug-tracker at: +# http://github.com/shabble/irssi-scripts/issues # -# * Insert/Command mode. Escape enters command mode. -# * cursor motion with: h l 0 ^ $ -# * history motion with j k -# * cursor word motion with: w b e W B E -# * change/delete: c d C D s -# * delete at cursor: x -# * replace at cursor: r -# * Insert mode at pos: i a -# * Insert mode at start: I -# * insert mode at end: A -# * yank and paste: y p P -# * switch case: ~ -# * repeat change: . -# * repeat ftFT: ; , -# * change/change/yank line: cc dd yy S -# * Combinations like in Vi, e.g. d5fx -# * window selection: :b, :b#, :b :bn :bp Ctrl-W j/k +# or contact rudi_s or shabble on irc.freenode.net (#irssi) # -# * special registers: "* "+ (contain irssi's cut-buffer) # -# TODO: -# * History: -# * /,?,n,N to search through history (like history_search.pl) -# * Undo: -# * u = undo (how many levels, branching?!) -# * C-r = redo -# * Window switching (:b) -# * Tab completion of window(-item) names -# * non-sequential matches(?) +# Features: # -# * use irssi settings for some of the features -# * Done: -# * vim_mode_utf8 (use utf-8 toggle) -# * vim_mode_debug (debug prints) -# * vim_mode_cmd_seq (char that when double-pressed enters cmd mode from ins) -# * Pending: -# * ??? +# It supports most commonly used command mode features: # -# WONTFIX - things we're not ever likely to do -# * Macros +# * Insert/Command mode. Escape and Ctrl-C enter command mode. +# /set vim_mode_cmd_seq j allows to use jj as Escape (any other character +# can be used as well). +# * Cursor motion: h l 0 ^ $ f t F T +# * History motion: j k +# * Cursor word motion: w b e W B E +# * Yank and paste: y p P +# * Change and delete: c d +# * Delete at cursor: x X +# * Replace at cursor: r +# * Insert mode: i a I A +# * Switch case: ~ +# * Repeat change: . +# * Repeat ftFT: ; , +# * Registers: "a-"z "" "* "+ "_ (black hole) +# Appending to register with "A-"Z +# "" is the default yank/delete register. +# The special registers "* "+ contain both irssi's cut-buffer. +# * Line-wise shortcuts: dd cc yy +# * Shortcuts: s S C D +# * Scroll the scrollback buffer: Ctrl-D Ctrl-U Ctrl-F Ctrl-B +# * Switch to last active window: Ctrl-6/Ctrl-^ +# * Switch split windows: Ctrl-W j Ctrl-W k +# * Undo/Redo: u Ctrl-R +# +# Counts and combinations work as well, e.g. d5fx or 3iabc +# Repeat also supports counts. +# +# Ex-mode supports (activated by : in command mode) the following commands: +# +# * Switching buffers: :b - switch to channel number +# :b# - switch to last channel +# :b +# :b / +# :buffer {args} (same as :b) +# :bn - switch to next window +# :bp - switch to previous window +# * Display windows: :ls :buffers +# * Display registers: :reg[isters] :di[splay] {args} +# * Display undolist: :undol[ist] (mostly used for debugging) +# +# The following irssi settings are available: +# +# * vim_mode_utf8: support UTF-8 characters, default on +# * vim_mode_debug: enable debug output, default off +# * vim_mode_cmd_seq: char that when double-pressed simulates +# +# The following statusbar items are available: +# +# * vim_mode: displays current mode +# * vim_windows: displays windows selected with :b # -# Known bugs: -# * multi-line pastes # # Installation: # +# As always copy the script into .irssi/scripts and load it with +# /script load # vim_mode.pl +# +# Use the following command to get a statusbar item that shows which mode +# you're in. +# +# /statusbar window add vim_mode +# +# And the following to let :b name display a list of matching channels +# +# /statusbar window add vim_windows +# +# # Dependencies: # # For proper :ex mode support, requires the installation of prompt_info.pl @@ -55,22 +86,19 @@ # # and follow the instructions in the top of that file for installation instructions. # -# Then, copy into scripts dir, /script load vim_mode.pl ... -# -# Use the following command to get a statusbar item that shows which mode you're -# in. +# If you don't need Ex-mode, you can run vim_mode.pl without the +# prompt_info.pl script. # -# /statusbar window add vim_mode to get the status. # -# And the following to let :b name display a list of matching channels -# -# /statusbar window add vim_windows -# -# NOTE: This script is still under heavy development, and there may be bugs. -# Please submit reproducible sequences to the bug-tracker at: -# http://github.com/shabble/irssi-scripts/issues +# TODO: +# * History: +# * /,?,n,N to search through history (like history_search.pl) +# * Window switching (:b) +# * Tab completion of window(-item) names +# * non-sequential matches(?) # -# or contact rudi_s or shabble on irc.freenode.net (#irssi) +# WONTFIX - things we're not ever likely to do +# * Macros # # LICENCE: # @@ -95,7 +123,6 @@ # THE SOFTWARE. # # -# # Have fun! use strict; @@ -126,12 +153,11 @@ $VERSION = "1.0.1"; # CONSTANTS - sub M_CMD() { 1 } # command mode sub M_INS() { 0 } # insert mode sub M_EX () { 2 } # extended mode (after a :?) -# word and non-word regex, when modifiying also update them in setup_changed() +# word and non-word regex, keep in sync with setup_changed()! my $word = qr/[\w_]/o; my $non_word = qr/[^\w_\s]/o; -- cgit v1.2.3 From 40ef612ce45e0c8acd6e6a2183e7d4241a4b48df Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 16:40:52 +0200 Subject: vim_mode: Store repeatable "movements" in hash. --- vim-mode/vim_mode.pl | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 2b771b3..487779d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -337,6 +337,24 @@ my $movements_multiple = "\x17" => undef, # ctrl-w }; +# "movements" which can be repeated (additional to operators of course). +my $movements_repeatable + = { + 'x' => undef, + 'X' => undef, + 'r' => undef, + 'p' => undef, + 'P' => undef, + 'C' => undef, + 'D' => undef, + '~' => undef, + '"' => undef, + 'i' => undef, + 'a' => undef, + 'I' => undef, + 'A' => undef, + }; + sub cmd_undo { print "Undo!" if DEBUG; @@ -1435,13 +1453,8 @@ sub handle_command_cmd { $repeat); } - # Store command, necessary for . But ignore movements and - # registers. - if ($operator or $char eq 'x' or $char eq 'X' or $char eq 'r' or - $char eq 'p' or $char eq 'P' or $char eq 'C' or - $char eq 'D' or $char eq '~' or $char eq '"' or - $char eq 'i' or $char eq 'I' or $char eq 'a' or - $char eq 'A') { + # Store command, necessary for . + if ($operator or exists $movements_repeatable->{$char}) { $last->{char} = $char; $last->{numeric_prefix} = $numeric_prefix; $last->{operator} = $operator; -- cgit v1.2.3 From 7d33687c838f138e7462016386410df8574fb67b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 16:42:47 +0200 Subject: vim_mode: " is not repeatable. --- vim-mode/vim_mode.pl | 1 - 1 file changed, 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 487779d..52129c0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -348,7 +348,6 @@ my $movements_repeatable 'C' => undef, 'D' => undef, '~' => undef, - '"' => undef, 'i' => undef, 'a' => undef, 'I' => undef, -- cgit v1.2.3 From 47b760256e13fbb6548e2aaeacfd152ed31b455b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 16:50:23 +0200 Subject: vim_mode: Move movement w to new function. --- vim-mode/vim_mode.pl | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 52129c0..5aa5274 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -600,19 +600,7 @@ sub cmd_movement_w { my ($count, $pos, $repeat) = @_; my $input = _input(); - while ($count-- > 0) { - # Go to end of next word/non-word. - if (substr($input, $pos) =~ /^$word+/ or - substr($input, $pos) =~ /^$non_word+/) { - $pos += $+[0]; - } - # And skip over any whitespace if necessary. This also happens when - # we're inside whitespace. - if (substr($input, $pos) =~ /^\s+/) { - $pos += $+[0]; - } - } - + $pos = _beginning_of_word($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } @@ -636,6 +624,25 @@ sub cmd_movement_e { $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } +# Go to the beginning of $count-th word, like vi's w. +sub _beginning_of_word { + my ($input, $count, $pos) = @_; + + while ($count-- > 0) { + # Go to end of next word/non-word. + if (substr($input, $pos) =~ /^$word+/ or + substr($input, $pos) =~ /^$non_word+/) { + $pos += $+[0]; + } + # And skip over any whitespace if necessary. This also happens when + # we're inside whitespace. + if (substr($input, $pos) =~ /^\s+/) { + $pos += $+[0]; + } + } + + return $pos; +} # Go to the end of $count-th word, like vi's e. sub _end_of_word { my ($input, $count, $pos) = @_; -- cgit v1.2.3 From 96eb03e9bd2b991f5c792f1fbd855a9ee189eeee Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 16:58:51 +0200 Subject: vim_mode: Move movement W to new function. --- vim-mode/vim_mode.pl | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5aa5274..44ebaae 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -683,12 +683,7 @@ sub cmd_movement_W { my ($count, $pos, $repeat) = @_; my $input = _input(); - while ($count-- > 0 and length($input) > $pos) { - if (substr($input, $pos + 1) !~ /\s+/) { - return cmd_movement_dollar(); - } - $pos += $+[0] + 1; - } + $pos = _beginning_of_WORD($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); _input_pos($pos); } @@ -713,7 +708,20 @@ sub cmd_movement_E { _input_pos($pos); } } -# Go to the end of $count-th WORD, like vi's e. +# Go to beginning of $count-th WORD, like vi's W. +sub _beginning_of_WORD { + my ($input, $count, $pos) = @_; + + while ($count-- > 0 and length($input) > $pos) { + if (substr($input, $pos + 1) !~ /\s+/) { + return cmd_movement_dollar(); + } + $pos += $+[0] + 1; + } + + return $pos; +} +# Go to end of $count-th WORD, like vi's E. sub _end_of_WORD { my ($input, $count, $pos) = @_; -- cgit v1.2.3 From ebfe036c1bc1217ca74af3b14d33ab4b6181a458 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 17:13:06 +0200 Subject: vim_mode: Add ge and gE. --- vim-mode/vim_mode.pl | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 44ebaae..ef7dd81 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -16,7 +16,7 @@ # can be used as well). # * Cursor motion: h l 0 ^ $ f t F T # * History motion: j k -# * Cursor word motion: w b e W B E +# * Cursor word motion: w b ge e W gE B E # * Yank and paste: y p P # * Change and delete: c d # * Delete at cursor: x X @@ -320,6 +320,7 @@ my $movements '~' => { func => \&cmd_movement_tilde }, '.' => {}, '"' => { func => \&cmd_movement_register }, + 'g' => { func => \&cmd_movement_g }, # g does many things # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, # ctrl-r @@ -334,6 +335,7 @@ my $movements_multiple = 'T' => undef, 'r' => undef, '"' => undef, + 'g' => undef, "\x17" => undef, # ctrl-w }; @@ -966,6 +968,32 @@ sub cmd_movement_register { print "Changing register to $register" if DEBUG; } +sub cmd_movement_g { + my ($count, $pos, $repeat, $char) = @_; + + my $input = _input(); + # ge + if ($char eq 'e') { + $input = reverse $input; + $pos = length($input) - $pos - 1; + $pos = 0 if ($pos < 0); + + $pos = _beginning_of_word($input, $count, $pos); + $pos = length($input) - $pos - 1; + $pos = 0 if ($pos < 0); + _input_pos($pos); + # gE + } elsif ($char eq 'E') { + $input = reverse $input; + $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); + if ($pos == -1) { + cmd_movement_0(); + } else { + _input_pos(length($input) - $pos - 1); + } + } +} + sub cmd_movement_ctrl_w { my ($count, $pos, $repeat, $char) = @_; -- cgit v1.2.3 From ac7ca81a37321cd89c2ed59b97984a6a31803ac6 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 17:50:48 +0200 Subject: vim_mode: Add known bugs. --- vim-mode/vim_mode.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ef7dd81..16e8ec0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -90,6 +90,11 @@ # prompt_info.pl script. # # +# Known bugs: +# +# * count before register doesn't work: e.g. 3"ap doesn't work, but "a3p does +# +# # TODO: # * History: # * /,?,n,N to search through history (like history_search.pl) -- cgit v1.2.3 From ffb7d66db4218abc93a408fc7981d51fe903c4eb Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 18:39:17 +0200 Subject: vim_mode: Fix _beginning_of_WORD() at end of the line. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 16e8ec0..4a01921 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -721,7 +721,7 @@ sub _beginning_of_WORD { while ($count-- > 0 and length($input) > $pos) { if (substr($input, $pos + 1) !~ /\s+/) { - return cmd_movement_dollar(); + return length($input); } $pos += $+[0] + 1; } -- cgit v1.2.3 From d1cc0dc0cfbf7a0b5220576fe1eeff1ea6c3d3e8 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 18:11:09 +0200 Subject: vim_mode: Allow movement functions to change $cur_pos. --- vim-mode/vim_mode.pl | 62 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 4a01921..4c91329 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -271,6 +271,10 @@ my $operators # vi-moves like w,b; they move the cursor and may get combined with an # operator; also things like i/I are listed here, not entirely correct but # they work in a similar way +# +# If a function returns a value it's interpreted as changing the $cur_pos (see +# handle_command_cmd()), to prevent that most functions should return; at the +# end. my $movements = { # arrow like movement @@ -372,8 +376,7 @@ sub cmd_undo { } else { print "No further undo." if DEBUG; } - - + return; } sub cmd_redo { @@ -387,6 +390,7 @@ sub cmd_redo { } else { print "No further Redo." if DEBUG; } + return; } sub cmd_operator_c { @@ -478,6 +482,7 @@ sub cmd_movement_h { $pos -= $count; $pos = 0 if $pos < 0; _input_pos($pos); + return; } sub cmd_movement_l { my ($count, $pos, $repeat) = @_; @@ -486,10 +491,12 @@ sub cmd_movement_l { $pos += $count; $pos = _fix_input_pos($pos, $length); _input_pos($pos); + return; } sub cmd_movement_space { my ($count, $pos, $repeat) = @_; cmd_movement_l($count, $pos); + return; } # later history (down) @@ -520,6 +527,7 @@ sub cmd_movement_j { _input($history[$history_index]); _input_pos(0); } + return; } # earlier history (up) sub cmd_movement_k { @@ -546,6 +554,7 @@ sub cmd_movement_k { _input($history[$history_index]); _input_pos(0); } + return; } sub cmd_movement_f { @@ -557,6 +566,7 @@ sub cmd_movement_f { } $last_ftFT = { type => 'f', char => $char }; + return; } sub cmd_movement_t { my ($count, $pos, $repeat, $char) = @_; @@ -567,6 +577,7 @@ sub cmd_movement_t { } $last_ftFT = { type => 't', char => $char }; + return; } sub cmd_movement_F { my ($count, $pos, $repeat, $char) = @_; @@ -578,6 +589,7 @@ sub cmd_movement_F { } $last_ftFT = { type => 'F', char => $char }; + return; } sub cmd_movement_T { my ($count, $pos, $repeat, $char) = @_; @@ -589,6 +601,7 @@ sub cmd_movement_T { } $last_ftFT = { type => 'T', char => $char }; + return; } # Find $count-th next occurrence of $char. sub _next_occurrence { @@ -610,6 +623,7 @@ sub cmd_movement_w { $pos = _beginning_of_word($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); _input_pos($pos); + return; } sub cmd_movement_b { my ($count, $pos, $repeat) = @_; @@ -622,6 +636,7 @@ sub cmd_movement_b { $pos = length($input) - $pos - 1; $pos = 0 if ($pos < 0); _input_pos($pos); + return; } sub cmd_movement_e { my ($count, $pos, $repeat) = @_; @@ -630,6 +645,7 @@ sub cmd_movement_e { $pos = _end_of_word($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); _input_pos($pos); + return; } # Go to the beginning of $count-th word, like vi's w. sub _beginning_of_word { @@ -693,6 +709,7 @@ sub cmd_movement_W { $pos = _beginning_of_WORD($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); _input_pos($pos); + return; } sub cmd_movement_B { my ($count, $pos, $repeat) = @_; @@ -704,6 +721,7 @@ sub cmd_movement_B { } else { _input_pos(length($input) - $pos - 1); } + return; } sub cmd_movement_E { my ($count, $pos, $repeat) = @_; @@ -714,6 +732,7 @@ sub cmd_movement_E { } else { _input_pos($pos); } + return; } # Go to beginning of $count-th WORD, like vi's W. sub _beginning_of_WORD { @@ -751,6 +770,7 @@ sub _end_of_WORD { sub cmd_movement_0 { _input_pos(0); + return; } sub cmd_movement_caret { my $input = _input(); @@ -766,17 +786,20 @@ sub cmd_movement_caret { $pos = _fix_input_pos(_input_len(), length $input); } _input_pos($pos); + return; } sub cmd_movement_dollar { my $input = _input(); my $length = length $input; _input_pos(_fix_input_pos($length, $length)); + return; } sub cmd_movement_x { my ($count, $pos, $repeat) = @_; cmd_operator_d($pos, $pos + $count, 'x'); + return; } sub cmd_movement_X { my ($count, $pos, $repeat) = @_; @@ -786,6 +809,7 @@ sub cmd_movement_X { my $new = $pos - $count; $new = 0 if $new < 0; cmd_operator_d($pos, $new, 'X'); + return; } sub cmd_movement_i { @@ -796,6 +820,7 @@ sub cmd_movement_i { } else { _insert_buffer($count); } + return; } sub cmd_movement_I { my ($count, $pos, $repeat) = @_; @@ -806,6 +831,7 @@ sub cmd_movement_I { } else { _insert_buffer($count); } + return; } sub cmd_movement_a { my ($count, $pos, $repeat) = @_; @@ -822,6 +848,7 @@ sub cmd_movement_a { } else { _insert_buffer($count); } + return; } sub cmd_movement_A { my ($count, $pos, $repeat) = @_; @@ -833,6 +860,7 @@ sub cmd_movement_A { } else { _insert_buffer($count); } + return; } # Add @insert_buf to _input() at the current cursor position. sub _insert_buffer { @@ -864,15 +892,18 @@ sub cmd_movement_r { substr $input, $pos, 1, $char; _input($input); _input_pos($pos); + return; } sub cmd_movement_p { my ($count, $pos, $repeat) = @_; _paste_at_position($count, $pos + 1); + return; } sub cmd_movement_P { my ($count, $pos, $repeat) = @_; _paste_at_position($count, $pos); + return; } sub _paste_at_position { my ($count, $pos) = @_; @@ -890,6 +921,7 @@ sub cmd_movement_ctrl_d { $count = $window->{height} / 2; } $window->view()->scroll($count); + return; } sub cmd_movement_ctrl_u { my ($count, $pos, $repeat) = @_; @@ -900,17 +932,20 @@ sub cmd_movement_ctrl_u { $count = $window->{height} / 2; } $window->view()->scroll($count * -1); + return; } sub cmd_movement_ctrl_f { my ($count, $pos, $repeat) = @_; my $window = Irssi::active_win(); $window->view()->scroll($count * $window->{height}); + return; } sub cmd_movement_ctrl_b { my ($count, $pos, $repeat) = @_; cmd_movement_ctrl_f($count * -1, $pos, $repeat); + return; } sub cmd_movement_tilde { @@ -923,6 +958,7 @@ sub cmd_movement_tilde { _input($input); _input_pos($pos + $count); + return; } sub cmd_movement_semicolon { @@ -932,6 +968,7 @@ sub cmd_movement_semicolon { $movements->{$last_ftFT->{type}} ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + return; } sub cmd_movement_comma { my ($count, $pos, $repeat) = @_; @@ -947,6 +984,7 @@ sub cmd_movement_comma { ->{func}($count, $pos, $repeat, $last_ftFT->{char}); # Restore type as the move functions overwrites it. $last_ftFT->{type} = $save; + return; } @@ -971,6 +1009,7 @@ sub cmd_movement_register { $register = $char; print "Changing register to $register" if DEBUG; + return; } sub cmd_movement_g { @@ -997,6 +1036,7 @@ sub cmd_movement_g { _input_pos(length($input) - $pos - 1); } } + return; } sub cmd_movement_ctrl_w { @@ -1011,10 +1051,12 @@ sub cmd_movement_ctrl_w { Irssi::command('window up'); } } + return; } sub cmd_movement_ctrl_6 { # like :b# Irssi::command('window last'); + return; } # Adapt the input position depending if an operator is active or not. @@ -1476,21 +1518,25 @@ sub handle_command_cmd { _add_undo_entry(_input(), $cur_pos); } + my $return; # Execute the movement (multiple times). - if (not $movement) { - $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat); + $return = $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, $repeat); } else { # Use the real movement command (like t or f) for operator # below. $char = substr $movement, 0, 1; - $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat, - substr $movement, 1); + $return = $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, $repeat, + substr $movement, 1); } my $new_pos = _input_pos(); + if (defined $return) { + $cur_pos = $return; + } + # If we have an operator pending then run it on the handled text. # But only if the movement changed the position (this prevents # problems with e.g. f when the search string doesn't exist). -- cgit v1.2.3 From cb830faff50530169eef1c932de56233b2f3c9c1 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 18:12:33 +0200 Subject: vim_mode: First work on text-objects. They do nothing at the moment, but get (correctly) called. --- vim-mode/vim_mode.pl | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 4c91329..e861c71 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -297,6 +297,9 @@ my $movements 'W' => { func => \&cmd_movement_W }, 'B' => { func => \&cmd_movement_B }, 'E' => { func => \&cmd_movement_E }, + # text-objects + 'i_' => { func => \&cmd_movement_i_ }, + 'a_' => { func => \&cmd_movement_a_ }, # line movement '0' => { func => \&cmd_movement_0 }, '^' => { func => \&cmd_movement_caret }, @@ -768,6 +771,19 @@ sub _end_of_WORD { return $pos; } +sub cmd_movement_i_ { + my ($count, $pos, $repeat, $char) = @_; + + _warn("i_ not implemented yet"); + return; +} +sub cmd_movement_a_ { + my ($count, $pos, $repeat, $char) = @_; + + _warn("a_ not implemented yet"); + return; +} + sub cmd_movement_0 { _input_pos(0); return; @@ -1438,7 +1454,9 @@ sub handle_command_cmd { print "Processing numeric prefix: $char" if DEBUG; handle_numeric_prefix($char); - } elsif (!$movement && exists $movements_multiple->{$char}) { + # text-objects (i a) are simulated with $movement + } elsif (!$movement && (exists $movements_multiple->{$char} + or $operator and ($char eq 'i' or $char eq 'a'))) { print "Processing movement: $char" if DEBUG; $movement = $char; @@ -1527,6 +1545,10 @@ sub handle_command_cmd { # Use the real movement command (like t or f) for operator # below. $char = substr $movement, 0, 1; + # i_ and a_ represent text-objects. + if ($char eq 'i' or $char eq 'a') { + $char .= '_'; + } $return = $movements->{$char}->{func} ->($numeric_prefix, $cur_pos, $repeat, substr $movement, 1); -- cgit v1.2.3 From f3b427631ba1d64ed304ed206c9e05ae0c441e0d Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 20:55:44 +0200 Subject: vim_mode: Fix W between words. --- vim-mode/vim_mode.pl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e861c71..9d3314d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -741,6 +741,13 @@ sub cmd_movement_E { sub _beginning_of_WORD { my ($input, $count, $pos) = @_; + # Necessary for correct movement between two words with only one + # whitespace. + if (substr($input, $pos) =~ /^\s\S/) { + $pos++; + $count--; + } + while ($count-- > 0 and length($input) > $pos) { if (substr($input, $pos + 1) !~ /\s+/) { return length($input); -- cgit v1.2.3 From 724b2059890adb72a940fdc6f7c02613da5dc0e8 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 20:56:05 +0200 Subject: vim_mode: Fix gE in first word on line. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 9d3314d..5c07030 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1053,7 +1053,7 @@ sub cmd_movement_g { } elsif ($char eq 'E') { $input = reverse $input; $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); - if ($pos == -1) { + if ($pos == -1 or length($input) - $pos - 1 == -1) { cmd_movement_0(); } else { _input_pos(length($input) - $pos - 1); -- cgit v1.2.3 From b332c6ab9c8b94a124b36880e42b4c2deef1e4f5 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Fri, 1 Oct 2010 22:38:40 +0200 Subject: vim_mode: Add :bd. --- vim-mode/vim_mode.pl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 5c07030..d013f11 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -48,6 +48,7 @@ # :buffer {args} (same as :b) # :bn - switch to next window # :bp - switch to previous window +# * Close window: :bd # * Display windows: :ls :buffers # * Display registers: :reg[isters] :di[splay] {args} # * Display undolist: :undol[ist] (mostly used for debugging) @@ -1133,6 +1134,9 @@ sub cmd_ex_command { # :bp } elsif ($arg_str eq 'bp') { Irssi::command('window previous'); + # :bd + } elsif ($arg_str eq 'bd') { + Irssi::command('window close'); # :b[buffer] {args} } elsif ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { my $window; -- cgit v1.2.3 From 3aade79d22d3ba9bb09f220245bffd52c57ea784 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 16:08:44 +0200 Subject: vim_mode: Add text-object aW. --- vim-mode/vim_mode.pl | 93 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index d013f11..2adcdc9 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -17,6 +17,7 @@ # * Cursor motion: h l 0 ^ $ f t F T # * History motion: j k # * Cursor word motion: w b ge e W gE B E +# * Word objects (only the following work yet): aW # * Yank and paste: y p P # * Change and delete: c d # * Delete at cursor: x X @@ -788,8 +789,86 @@ sub cmd_movement_i_ { sub cmd_movement_a_ { my ($count, $pos, $repeat, $char) = @_; - _warn("a_ not implemented yet"); - return; + my $cur_pos; + my $input = _input(); + + # aw and aW + if ($char eq 'w' or $char eq 'W') { + if ($char eq 'w') { + + } elsif ($char eq 'W') { + while ($count-- > 0 and length($input) > $pos) { + if (substr($input, $pos, 1) =~ /\s/) { + # Any whitespace before the WORD must be removed. + if (not defined $cur_pos) { + $cur_pos = _find_regex_before($input, '\S', $pos, 0); + if ($cur_pos < 0) { + $cur_pos = 0; + } else { + $cur_pos++; + } + } + # Move before the WORD. + if (substr($input, $pos + 1) =~ /^\s+/) { + $pos += $+[0]; + } + # And delete it. + if (substr($input, $pos + 1) =~ /\s/) { + $pos += $-[0] + 1; + } else { + $pos = length($input); + } + + } else { + # Start at the beginning of this WORD. + if (not defined $cur_pos and $pos > 0 and + substr($input, $pos - 1, 1) !~ /\s/) { + $cur_pos = _find_regex_before($input, '\s', $pos - 1, 0); + if ($cur_pos < 0) { + $cur_pos = 0; + } else { + $cur_pos++; + } + } + # Delete to the end of the word. + if (substr($input, $pos + 1) =~ /^\S*\s+\S/) { + $pos += $+[0]; + } else { + $pos = length($input); + # If we are at the end of the line, whitespace before + # the WORD is also deleted. + my $new_pos = _find_regex_before($input, '\s+', $pos, 1); + if (not defined $cur_pos or $cur_pos > $new_pos + 1) { + $cur_pos = $new_pos + 1; + } + } + } + } + _input_pos($pos); + } + } + + return $cur_pos; +} +# Find regex as close as possible before the current position. If $end is true +# the end of the match is returned, otherwise the beginning. +sub _find_regex_before { + my ($input, $regex, $pos, $end) = @_; + + $input = reverse $input; + $pos = length($input) - $pos - 1; + $pos = 0 if $pos < 0; + + if (substr($input, $pos) =~ /$regex/) { + if (!$end) { + $pos += $-[0]; + } else { + $pos += $+[0]; + } + return length($input) - $pos - 1; + } else { + return -1; + } } sub cmd_movement_0 { @@ -1575,8 +1654,14 @@ sub handle_command_cmd { # problems with e.g. f when the search string doesn't exist). if ($operator and $cur_pos != $new_pos) { print "Processing operator: ", $operator if DEBUG; - $operators->{$operator}->{func}->($cur_pos, $new_pos, $char, - $repeat); + # If text-objects are used the real move character must be + # passed to the operator. + my $tmp_char = $char; + if ($char eq 'i_' or $char eq 'a_') { + $tmp_char = substr $movement, 1; + } + $operators->{$operator}->{func}->($cur_pos, $new_pos, + $tmp_char, $repeat); } # Store command, necessary for . -- cgit v1.2.3 From 8f2bd0ac21b64271a2ac9eb934ca4cc5dfe956f7 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:27:57 +0200 Subject: vim_mode: Fix history with /set vim_mode_utf8 on. --- vim-mode/vim_mode.pl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 2adcdc9..117d639 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -529,7 +529,12 @@ sub cmd_movement_j { _input_pos($history_pos); $history_index = $#history + 1; } elsif ($history_index >= 0) { - _input($history[$history_index]); + my $history = $history[$history_index]; + # History is not in UTF-8! + if ($utf8) { + $history = decode_utf8($history); + } + _input($history); _input_pos(0); } return; @@ -556,7 +561,12 @@ sub cmd_movement_k { } print "History Index: $history_index" if DEBUG; if ($history_index >= 0) { - _input($history[$history_index]); + my $history = $history[$history_index]; + # History is not in UTF-8! + if ($utf8) { + $history = decode_utf8($history); + } + _input($history); _input_pos(0); } return; -- cgit v1.2.3 From 6182698fb900d7a6f17d2b03a7e29348e221b608 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:36:33 +0200 Subject: vim_mode: Movement commands return $cur_pos, $new_pos. They don't call _input_pos() anymore. --- vim-mode/vim_mode.pl | 213 +++++++++++++++++++++++++-------------------------- 1 file changed, 103 insertions(+), 110 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 117d639..0149844 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -274,9 +274,9 @@ my $operators # operator; also things like i/I are listed here, not entirely correct but # they work in a similar way # -# If a function returns a value it's interpreted as changing the $cur_pos (see -# handle_command_cmd()), to prevent that most functions should return; at the -# end. +# Each function returns two values, an updated $cur_pos (see +# handle_command_cmd()) and the new cursor position. If undef is returned in +# either place, the position isn't changed. my $movements = { # arrow like movement @@ -381,7 +381,7 @@ sub cmd_undo { } else { print "No further undo." if DEBUG; } - return; + return (undef, undef); } sub cmd_redo { @@ -395,7 +395,7 @@ sub cmd_redo { } else { print "No further Redo." if DEBUG; } - return; + return (undef, undef); } sub cmd_operator_c { @@ -414,7 +414,7 @@ sub cmd_operator_c { if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer(1); + _insert_buffer(1, $new_pos); } } sub cmd_operator_d { @@ -486,8 +486,7 @@ sub cmd_movement_h { $pos -= $count; $pos = 0 if $pos < 0; - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_l { my ($count, $pos, $repeat) = @_; @@ -495,13 +494,11 @@ sub cmd_movement_l { my $length = _input_len(); $pos += $count; $pos = _fix_input_pos($pos, $length); - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_space { my ($count, $pos, $repeat) = @_; - cmd_movement_l($count, $pos); - return; + return cmd_movement_l($count, $pos); } # later history (down) @@ -537,7 +534,7 @@ sub cmd_movement_j { _input($history); _input_pos(0); } - return; + return (undef, undef); } # earlier history (up) sub cmd_movement_k { @@ -569,54 +566,51 @@ sub cmd_movement_k { _input($history); _input_pos(0); } - return; + return (undef, undef); } sub cmd_movement_f { my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); - if ($pos != -1) { - _input_pos($pos); - } $last_ftFT = { type => 'f', char => $char }; - return; + return (undef, $pos); } sub cmd_movement_t { my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); - if ($pos != -1) { - _input_pos($pos - 1); + if (defined $pos) { + $pos--; } $last_ftFT = { type => 't', char => $char }; - return; + return (undef, $pos); } sub cmd_movement_F { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); $pos = _next_occurrence($input, $char, $count, length($input) - $pos - 1); - if ($pos != -1) { - _input_pos(length($input) - $pos - 1); + if (defined $pos) { + $pos = length($input) - $pos - 1; } $last_ftFT = { type => 'F', char => $char }; - return; + return (undef, $pos); } sub cmd_movement_T { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); $pos = _next_occurrence($input, $char, $count, length($input) - $pos - 1); - if ($pos != -1) { - _input_pos(length($input) - $pos - 1 + 1); + if (defined $pos) { + $pos = length($input) - $pos - 1 + 1; } $last_ftFT = { type => 'T', char => $char }; - return; + return (undef, $pos); } # Find $count-th next occurrence of $char. sub _next_occurrence { @@ -625,7 +619,7 @@ sub _next_occurrence { while ($count-- > 0) { $pos = index $input, $char, $pos + 1; if ($pos == -1) { - return -1; + return undef; } } return $pos; @@ -637,8 +631,7 @@ sub cmd_movement_w { my $input = _input(); $pos = _beginning_of_word($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_b { my ($count, $pos, $repeat) = @_; @@ -650,8 +643,7 @@ sub cmd_movement_b { $pos = _end_of_word($input, $count, $pos); $pos = length($input) - $pos - 1; $pos = 0 if ($pos < 0); - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_e { my ($count, $pos, $repeat) = @_; @@ -659,8 +651,7 @@ sub cmd_movement_e { my $input = _input(); $pos = _end_of_word($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); - _input_pos($pos); - return; + return (undef, $pos); } # Go to the beginning of $count-th word, like vi's w. sub _beginning_of_word { @@ -723,8 +714,7 @@ sub cmd_movement_W { my $input = _input(); $pos = _beginning_of_WORD($input, $count, $pos); $pos = _fix_input_pos($pos, length $input); - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_B { my ($count, $pos, $repeat) = @_; @@ -732,22 +722,20 @@ sub cmd_movement_B { my $input = reverse _input(); $pos = _end_of_WORD($input, $count, length($input) - $pos - 1); if ($pos == -1) { - cmd_movement_0(); + return cmd_movement_0(); } else { - _input_pos(length($input) - $pos - 1); + return (undef, length($input) - $pos - 1); } - return; } sub cmd_movement_E { my ($count, $pos, $repeat) = @_; $pos = _end_of_WORD(_input(), $count, $pos); if ($pos == -1) { - cmd_movement_dollar(); + return cmd_movement_dollar(); } else { - _input_pos($pos); + return (undef, $pos); } - return; } # Go to beginning of $count-th WORD, like vi's W. sub _beginning_of_WORD { @@ -794,7 +782,7 @@ sub cmd_movement_i_ { my ($count, $pos, $repeat, $char) = @_; _warn("i_ not implemented yet"); - return; + return (undef, undef); } sub cmd_movement_a_ { my ($count, $pos, $repeat, $char) = @_; @@ -854,11 +842,10 @@ sub cmd_movement_a_ { } } } - _input_pos($pos); } } - return $cur_pos; + return ($cur_pos, $pos); } # Find regex as close as possible before the current position. If $end is true # the end of the match is returned, otherwise the beginning. @@ -882,8 +869,7 @@ sub _find_regex_before { } sub cmd_movement_0 { - _input_pos(0); - return; + return (undef, 0); } sub cmd_movement_caret { my $input = _input(); @@ -898,31 +884,29 @@ sub cmd_movement_caret { } else { $pos = _fix_input_pos(_input_len(), length $input); } - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_dollar { my $input = _input(); my $length = length $input; - _input_pos(_fix_input_pos($length, $length)); - return; + return (undef, _fix_input_pos($length, $length)); } sub cmd_movement_x { my ($count, $pos, $repeat) = @_; cmd_operator_d($pos, $pos + $count, 'x'); - return; + return (undef, undef); } sub cmd_movement_X { my ($count, $pos, $repeat) = @_; - return if $pos == 0; + return (undef, undef) if $pos == 0; my $new = $pos - $count; $new = 0 if $new < 0; cmd_operator_d($pos, $new, 'X'); - return; + return (undef, undef); } sub cmd_movement_i { @@ -931,20 +915,20 @@ sub cmd_movement_i { if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer($count); + $pos = _insert_buffer($count, $pos); } - return; + return (undef, $pos); } sub cmd_movement_I { my ($count, $pos, $repeat) = @_; - cmd_movement_caret(); + $pos = cmd_movement_caret(); if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer($count); + $pos = _insert_buffer($count, $pos); } - return; + return (undef, $pos); } sub cmd_movement_a { my ($count, $pos, $repeat) = @_; @@ -954,31 +938,30 @@ sub cmd_movement_a { my $length = _input_len(); $pos += $count; $pos = $length if $pos > $length; - _input_pos($pos); if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer($count); + $pos = _insert_buffer($count, $pos); } - return; + return (undef, $pos); } sub cmd_movement_A { my ($count, $pos, $repeat) = @_; - _input_pos(_input_len()); + $pos = _input_len(); if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer($count); + $pos = _insert_buffer($count, $pos); } - return; + return (undef, $pos); } -# Add @insert_buf to _input() at the current cursor position. +# Add @insert_buf to _input() at the given position. sub _insert_buffer { - my ($count) = @_; - _insert_at_position(join('', @insert_buf), $count, _input_pos()); + my ($count, $pos) = @_; + return _insert_at_position(join('', @insert_buf), $count, $pos); } sub _insert_at_position { my ($string, $count, $pos) = @_; @@ -995,7 +978,7 @@ sub _insert_at_position { } _input($input); - _input_pos($pos - 1 + length $string); + return $pos - 1 + length $string; } sub cmd_movement_r { @@ -1004,25 +987,24 @@ sub cmd_movement_r { my $input = _input(); substr $input, $pos, 1, $char; _input($input); - _input_pos($pos); - return; + return (undef, $pos); } sub cmd_movement_p { my ($count, $pos, $repeat) = @_; - _paste_at_position($count, $pos + 1); - return; + $pos = _paste_at_position($count, $pos + 1); + return (undef, $pos); } sub cmd_movement_P { my ($count, $pos, $repeat) = @_; - _paste_at_position($count, $pos); - return; + $pos = _paste_at_position($count, $pos); + return (undef, $pos); } sub _paste_at_position { my ($count, $pos) = @_; return if not $registers->{$register}; - _insert_at_position($registers->{$register}, $count, $pos); + return _insert_at_position($registers->{$register}, $count, $pos); } sub cmd_movement_ctrl_d { @@ -1034,7 +1016,7 @@ sub cmd_movement_ctrl_d { $count = $window->{height} / 2; } $window->view()->scroll($count); - return; + return (undef, undef); } sub cmd_movement_ctrl_u { my ($count, $pos, $repeat) = @_; @@ -1045,20 +1027,20 @@ sub cmd_movement_ctrl_u { $count = $window->{height} / 2; } $window->view()->scroll($count * -1); - return; + return (undef, undef); } sub cmd_movement_ctrl_f { my ($count, $pos, $repeat) = @_; my $window = Irssi::active_win(); $window->view()->scroll($count * $window->{height}); - return; + return (undef, undef); } sub cmd_movement_ctrl_b { my ($count, $pos, $repeat) = @_; cmd_movement_ctrl_f($count * -1, $pos, $repeat); - return; + return (undef, undef); } sub cmd_movement_tilde { @@ -1070,34 +1052,35 @@ sub cmd_movement_tilde { substr $input, $pos, $count, $string; _input($input); - _input_pos($pos + $count); - return; + return (undef, $pos + $count); } sub cmd_movement_semicolon { my ($count, $pos, $repeat) = @_; - return if not defined $last_ftFT; + return (undef, undef) if not defined $last_ftFT; - $movements->{$last_ftFT->{type}} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); - return; + (undef, $pos) + = $movements->{$last_ftFT->{type}} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + return (undef, $pos); } sub cmd_movement_comma { my ($count, $pos, $repeat) = @_; - return if not defined $last_ftFT; + return (undef, undef) if not defined $last_ftFT; # Change direction. my $save = $last_ftFT->{type}; my $type = $save; $type =~ tr/ftFT/FTft/; - $movements->{$type} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + (undef, $pos) + = $movements->{$type} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); # Restore type as the move functions overwrites it. $last_ftFT->{type} = $save; - return; + return (undef, $pos); } @@ -1106,7 +1089,7 @@ sub cmd_movement_register { if (not exists $registers->{$char} and not exists $registers->{lc $char}) { print "Wrong register $char, ignoring." if DEBUG; - return; + return (undef, undef); } # make sure black hole register is always empty @@ -1122,7 +1105,7 @@ sub cmd_movement_register { $register = $char; print "Changing register to $register" if DEBUG; - return; + return (undef, undef); } sub cmd_movement_g { @@ -1138,18 +1121,17 @@ sub cmd_movement_g { $pos = _beginning_of_word($input, $count, $pos); $pos = length($input) - $pos - 1; $pos = 0 if ($pos < 0); - _input_pos($pos); # gE } elsif ($char eq 'E') { $input = reverse $input; $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); if ($pos == -1 or length($input) - $pos - 1 == -1) { - cmd_movement_0(); + return cmd_movement_0(); } else { - _input_pos(length($input) - $pos - 1); + $pos = length($input) - $pos - 1; } } - return; + return (undef, $pos); } sub cmd_movement_ctrl_w { @@ -1164,12 +1146,12 @@ sub cmd_movement_ctrl_w { Irssi::command('window up'); } } - return; + return (undef, undef); } sub cmd_movement_ctrl_6 { # like :b# Irssi::command('window last'); - return; + return (undef, undef); } # Adapt the input position depending if an operator is active or not. @@ -1636,11 +1618,15 @@ sub handle_command_cmd { _add_undo_entry(_input(), $cur_pos); } - my $return; + # If defined $cur_pos will be changed to this. + my $old_pos; + # Position after the move. + my $new_pos; # Execute the movement (multiple times). if (not $movement) { - $return = $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat); + ($old_pos, $new_pos) + = $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, $repeat); } else { # Use the real movement command (like t or f) for operator # below. @@ -1649,14 +1635,18 @@ sub handle_command_cmd { if ($char eq 'i' or $char eq 'a') { $char .= '_'; } - $return = $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat, - substr $movement, 1); + ($old_pos, $new_pos) + = $movements->{$char}->{func} + ->($numeric_prefix, $cur_pos, $repeat, + substr $movement, 1); } - my $new_pos = _input_pos(); - - if (defined $return) { - $cur_pos = $return; + if (defined $old_pos) { + $cur_pos = $old_pos; + } + if (defined $new_pos) { + _input_pos($new_pos); + } else { + $new_pos = _input_pos(); } # If we have an operator pending then run it on the handled text. @@ -1932,17 +1922,20 @@ sub _stop() { sub _update_mode { my ($new_mode) = @_; + my $pos; + if ($mode == M_INS and $new_mode == M_CMD) { # Support counts with insert modes, like 3i. if ($numeric_prefix and $numeric_prefix > 1) { - _insert_buffer($numeric_prefix - 1); + $pos = _insert_buffer($numeric_prefix - 1, _input_pos()); + _input_pos($pos); $numeric_prefix = undef; # In insert mode we are "between" characters, in command mode "on top" # of keys. When leaving insert mode we have to move on key left to # accomplish that. } else { - my $pos = _input_pos(); + $pos = _input_pos(); if ($pos != 0) { _input_pos($pos - 1); } -- cgit v1.2.3 From 0760d31f2eef9aa6a486851a2d8cf6d9c1307845 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:37:56 +0200 Subject: vim_mode: Fix a with count. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0149844..50792dd 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -936,7 +936,7 @@ sub cmd_movement_a { # Move after current character. Can't use cmd_movement_l() because we need # to mover after last character at the end of the line. my $length = _input_len(); - $pos += $count; + $pos += 1; $pos = $length if $pos > $length; if (!$repeat) { -- cgit v1.2.3 From e3e06d4e57388eac3f5ae78efd731095d0ba2dc3 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:44:00 +0200 Subject: vim_mode: Fix r with count. --- vim-mode/vim_mode.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 50792dd..d01c5dc 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -985,9 +985,13 @@ sub cmd_movement_r { my ($count, $pos, $repeat, $char) = @_; my $input = _input(); - substr $input, $pos, 1, $char; + + # Abort if at end of the line. + return (undef, undef) if length($input) < $pos + $count; + + substr $input, $pos, $count, $char x $count; _input($input); - return (undef, $pos); + return (undef, $pos + $count - 1); } sub cmd_movement_p { -- cgit v1.2.3 From 45796c4b3e7f60f9f7ec34b7379fcaf8165873f0 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:45:53 +0200 Subject: vim_mode: Fix ~ at end of the line. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index d01c5dc..e43b562 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1056,7 +1056,7 @@ sub cmd_movement_tilde { substr $input, $pos, $count, $string; _input($input); - return (undef, $pos + $count); + return (undef, _fix_input_pos($pos + $count, length $input)); } sub cmd_movement_semicolon { -- cgit v1.2.3 From a8384612d72826fd91dc77a7823bae38b8106ab4 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:49:41 +0200 Subject: vim_mode: Fix :reg not to display "_. --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e43b562..37982e4 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1252,6 +1252,7 @@ sub cmd_ex_command { } my $active_window = Irssi::active_win; foreach my $key (sort @regs) { + next if $key eq '_'; # skip black hole if (defined $registers->{$key}) { $active_window->print("register $key: $registers->{$key}"); } -- cgit v1.2.3 From ccec8886edc89fe0ec583c44082b8d211d2ddf21 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:50:34 +0200 Subject: vim_mode: Minor comment fixes. --- vim-mode/vim_mode.pl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 37982e4..33513a0 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -86,7 +86,8 @@ # For proper :ex mode support, requires the installation of prompt_info.pl # http://github.com/shabble/irssi-scripts/raw/master/prompt_info/prompt_info.pl # -# and follow the instructions in the top of that file for installation instructions. +# and follow the instructions in the top of that file for installation +# instructions. # # If you don't need Ex-mode, you can run vim_mode.pl without the # prompt_info.pl script. @@ -262,7 +263,7 @@ sub script_is_loaded { vim_mode_init(); -# vi-operators like d, c; they don't move the cursor +# vi-operators like d, c, y my $operators = { 'c' => { func => \&cmd_operator_c }, -- cgit v1.2.3 From 8b6d0abd1498b3b77c2ecf510d10a2f33bf5dde7 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:54:26 +0200 Subject: vim_mode: Minor cleanup. --- vim-mode/vim_mode.pl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 33513a0..ecada0d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -883,13 +883,12 @@ sub cmd_movement_caret { $pos = $-[0]; # Only whitespace, go to the end. } else { - $pos = _fix_input_pos(_input_len(), length $input); + $pos = _fix_input_pos(length $input, length $input); } return (undef, $pos); } sub cmd_movement_dollar { - my $input = _input(); - my $length = length $input; + my $length = _input_len(); return (undef, _fix_input_pos($length, $length)); } -- cgit v1.2.3 From 3c72f0d33348625b7a3e60031bfbbe53f030798f Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 17:55:47 +0200 Subject: vim_mode: Add debug output. --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ecada0d..f406592 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1646,6 +1646,7 @@ sub handle_command_cmd { substr $movement, 1); } if (defined $old_pos) { + print "Changing \$cur_pos from $cur_pos to $old_pos" if DEBUG; $cur_pos = $old_pos; } if (defined $new_pos) { -- cgit v1.2.3 From fd75583e7c9067df730f50f1a70981fc4707f8c2 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 18:06:44 +0200 Subject: vim_mode: Move some functions. No changes. --- vim-mode/vim_mode.pl | 137 +++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 69 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f406592..cd47878 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -372,33 +372,6 @@ my $movements_repeatable }; -sub cmd_undo { - print "Undo!" if DEBUG; - - _restore_undo_entry($undo_index); - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - if ($undo_index != $#undo_buffer) { - $undo_index++; - } else { - print "No further undo." if DEBUG; - } - return (undef, undef); -} - -sub cmd_redo { - print "Redo!" if DEBUG; - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - - _restore_undo_entry($undo_index); - - if ($undo_index != 0) { - $undo_index--; - } else { - print "No further Redo." if DEBUG; - } - return (undef, undef); -} - sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; @@ -626,6 +599,34 @@ sub _next_occurrence { return $pos; } +sub cmd_movement_semicolon { + my ($count, $pos, $repeat) = @_; + + return (undef, undef) if not defined $last_ftFT; + + (undef, $pos) + = $movements->{$last_ftFT->{type}} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + return (undef, $pos); +} +sub cmd_movement_comma { + my ($count, $pos, $repeat) = @_; + + return (undef, undef) if not defined $last_ftFT; + + # Change direction. + my $save = $last_ftFT->{type}; + my $type = $save; + $type =~ tr/ftFT/FTft/; + + (undef, $pos) + = $movements->{$type} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + # Restore type as the move functions overwrites it. + $last_ftFT->{type} = $save; + return (undef, $pos); +} + sub cmd_movement_w { my ($count, $pos, $repeat) = @_; @@ -1047,6 +1048,26 @@ sub cmd_movement_ctrl_b { return (undef, undef); } +sub cmd_movement_ctrl_w { + my ($count, $pos, $repeat, $char) = @_; + + if ($char eq 'j') { + while ($count -- > 0) { + Irssi::command('window down'); + } + } elsif ($char eq 'k') { + while ($count -- > 0) { + Irssi::command('window up'); + } + } + return (undef, undef); +} +sub cmd_movement_ctrl_6 { + # like :b# + Irssi::command('window last'); + return (undef, undef); +} + sub cmd_movement_tilde { my ($count, $pos, $repeat) = @_; @@ -1059,35 +1080,6 @@ sub cmd_movement_tilde { return (undef, _fix_input_pos($pos + $count, length $input)); } -sub cmd_movement_semicolon { - my ($count, $pos, $repeat) = @_; - - return (undef, undef) if not defined $last_ftFT; - - (undef, $pos) - = $movements->{$last_ftFT->{type}} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); - return (undef, $pos); -} -sub cmd_movement_comma { - my ($count, $pos, $repeat) = @_; - - return (undef, undef) if not defined $last_ftFT; - - # Change direction. - my $save = $last_ftFT->{type}; - my $type = $save; - $type =~ tr/ftFT/FTft/; - - (undef, $pos) - = $movements->{$type} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); - # Restore type as the move functions overwrites it. - $last_ftFT->{type} = $save; - return (undef, $pos); -} - - sub cmd_movement_register { my ($count, $pos, $repeat, $char) = @_; @@ -1138,23 +1130,29 @@ sub cmd_movement_g { return (undef, $pos); } -sub cmd_movement_ctrl_w { - my ($count, $pos, $repeat, $char) = @_; +sub cmd_undo { + print "Undo!" if DEBUG; - if ($char eq 'j') { - while ($count -- > 0) { - Irssi::command('window down'); - } - } elsif ($char eq 'k') { - while ($count -- > 0) { - Irssi::command('window up'); - } + _restore_undo_entry($undo_index); + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; + if ($undo_index != $#undo_buffer) { + $undo_index++; + } else { + print "No further undo." if DEBUG; } return (undef, undef); } -sub cmd_movement_ctrl_6 { - # like :b# - Irssi::command('window last'); +sub cmd_redo { + print "Redo!" if DEBUG; + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; + + _restore_undo_entry($undo_index); + + if ($undo_index != 0) { + $undo_index--; + } else { + print "No further Redo." if DEBUG; + } return (undef, undef); } @@ -1174,6 +1172,7 @@ sub _fix_input_pos { return $pos; } + sub cmd_ex_command { my $arg_str = join '', @ex_buf; if ($arg_str =~ m|^s/(.+)/(.*)/([ig]*)|) { -- cgit v1.2.3 From 87a8ed00f1b7fa9f9a4c5a38967b15b5fc269450 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 18:08:03 +0200 Subject: vim_mode: Add missing (undef, undef) for clarity. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cd47878..7bf6e28 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -482,7 +482,7 @@ sub cmd_movement_j { if (Irssi::version < 20090117) { # simulate a down-arrow _emulate_keystrokes(0x1b, 0x5b, 0x42); - return; + return (undef, undef); } my @history = Irssi::active_win->get_history_lines(); @@ -517,7 +517,7 @@ sub cmd_movement_k { if (Irssi::version < 20090117) { # simulate an up-arrow _emulate_keystrokes(0x1b, 0x5b, 0x41); - return; + return (undef, undef); } my @history = Irssi::active_win->get_history_lines(); -- cgit v1.2.3 From a18073ddb36993fdd63e4094113fe2c580efe5c3 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 18:20:33 +0200 Subject: vim_mode: Fix j from destroying the input line. --- vim-mode/vim_mode.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 7bf6e28..1c282ad 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -490,8 +490,12 @@ sub cmd_movement_j { if (defined $history_index) { $history_index += $count; print "History Index: $history_index" if DEBUG; + # Prevent destroying the current input when pressing j after entering + # command mode. Not exactly like in default irssi, but simplest solution + # (and S can be used to clear the input line fast, which is what + # does in plain irssi). } else { - $history_index = $#history; + return (undef, undef); } if ($history_index > $#history) { -- cgit v1.2.3 From 48828d5e44e3ec22176a6ffe1f3a91a606027316 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 19:06:42 +0200 Subject: vim_mode: Fix crash when pressing , or ; before f,t,F,T. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 1c282ad..42fa18c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -606,7 +606,7 @@ sub _next_occurrence { sub cmd_movement_semicolon { my ($count, $pos, $repeat) = @_; - return (undef, undef) if not defined $last_ftFT; + return (undef, undef) if not defined $last_ftFT->{type}; (undef, $pos) = $movements->{$last_ftFT->{type}} @@ -616,7 +616,7 @@ sub cmd_movement_semicolon { sub cmd_movement_comma { my ($count, $pos, $repeat) = @_; - return (undef, undef) if not defined $last_ftFT; + return (undef, undef) if not defined $last_ftFT->{type}; # Change direction. my $save = $last_ftFT->{type}; -- cgit v1.2.3 From 869d8cba84a2809e9e060cdc5d9e1384af614b3e Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sat, 2 Oct 2010 21:22:49 +0200 Subject: vim_mode: Add Ctrl-R in insert mode. --- vim-mode/vim_mode.pl | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 42fa18c..bc8df72 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -40,6 +40,10 @@ # Counts and combinations work as well, e.g. d5fx or 3iabc # Repeat also supports counts. # +# The following insert mode mappings are supported: +# +# * Insert register content: Ctrl-R x (where x is the register to insert) +# # Ex-mode supports (activated by : in command mode) the following commands: # # * Switching buffers: :b - switch to channel number @@ -237,7 +241,11 @@ foreach my $char ('a' .. 'z') { my $imap = undef; # maps for insert mode -my $imaps = {}; +my $imaps + = { + # ctrl-r, insert register + "\x12" => { map => undef, func => \&cmd_insert_ctrl_r }, + }; # index into the history list (for j,k) my $history_index = undef; @@ -372,6 +380,17 @@ my $movements_repeatable }; +sub cmd_insert_ctrl_r { + my ($key) = @_; + + my $char = chr($key); + return if not defined $registers->{$char} or not $registers->{$char}; + + my $pos = _insert_at_position($registers->{$char}, 1, _input_pos()); + _input_pos($pos + 1); +} + + sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; @@ -1397,8 +1416,8 @@ sub got_key { } elsif ($input_buf_enabled and $imap) { print "Imap $imap active" if DEBUG; my $map = $imaps->{$imap}; - if (chr($key) eq $map->{map}) { - $map->{func}(); + if (not defined $map->{map} or chr($key) eq $map->{map}) { + $map->{func}($key); # Clear the buffer so the imap is not printed. @input_buf = (); } else { @@ -1764,8 +1783,10 @@ sub vim_mode_init { sub setup_changed { my $value; - # TODO: okay for now, will cause problems when we have more imaps - $imaps = {}; + # Delete all possible imaps created by /set vim_mode_cmd_seq. + foreach my $char ('a' .. 'z') { + delete $imaps->{$char}; + } $value = Irssi::settings_get_str('vim_mode_cmd_seq'); if ($value) { -- cgit v1.2.3 From 26a407e4a35130929056614afdfdcb258738c305 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 00:32:46 +0200 Subject: vim_mode: Add aw (text-object). --- vim-mode/vim_mode.pl | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index bc8df72..a6244c1 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -17,7 +17,7 @@ # * Cursor motion: h l 0 ^ $ f t F T # * History motion: j k # * Cursor word motion: w b ge e W gE B E -# * Word objects (only the following work yet): aW +# * Word objects (only the following work yet): aw aW # * Yank and paste: y p P # * Change and delete: c d # * Delete at cursor: x X @@ -817,12 +817,9 @@ sub cmd_movement_a_ { # aw and aW if ($char eq 'w' or $char eq 'W') { - if ($char eq 'w') { - - } elsif ($char eq 'W') { while ($count-- > 0 and length($input) > $pos) { if (substr($input, $pos, 1) =~ /\s/) { - # Any whitespace before the WORD must be removed. + # Any whitespace before the word/WORD must be removed. if (not defined $cur_pos) { $cur_pos = _find_regex_before($input, '\S', $pos, 0); if ($cur_pos < 0) { @@ -831,17 +828,52 @@ sub cmd_movement_a_ { $cur_pos++; } } - # Move before the WORD. + # Move before the word/WORD. if (substr($input, $pos + 1) =~ /^\s+/) { $pos += $+[0]; } - # And delete it. - if (substr($input, $pos + 1) =~ /\s/) { - $pos += $-[0] + 1; + # And delete the word. + if ($char eq 'w') { + if (substr($input, $pos) =~ /^\s($word+|$non_word+)/) { + $pos += $+[0]; + } else { + $pos = length($input); + } + # WORD + } else { + if (substr($input, $pos + 1) =~ /\s/) { + $pos += $-[0] + 1; + } else { + $pos = length($input); + } + } + + # word + } elsif ($char eq 'w') { + # Start at the beginning of this WORD. + if (not defined $cur_pos and $pos > 0 and substr($input, $pos - 1, 2) !~ /(\s.|$word$non_word|$non_word$word)/) { + + $cur_pos = _find_regex_before($input, "^($word+$non_word|$non_word+$word|$word+\\s|$non_word+\\s)", $pos, 1); + if ($cur_pos < 0) { + $cur_pos = 0; + } else { + $cur_pos += 2; + } + } + # Delete to the end of the word. + if (substr($input, $pos) =~ /^($word+$non_word|$non_word+$word|$word+\s+\S|$non_word+\s+\S)/) { + $pos += $+[0] - 1; } else { $pos = length($input); + # If we are at the end of the line, whitespace before + # the word is also deleted. + my $new_pos = _find_regex_before($input, "^($word+\\s+|$non_word+\\s+)", $pos, 1); + if ($new_pos != -1 and (not defined $cur_pos or $cur_pos > $new_pos + 1)) { + $cur_pos = $new_pos + 1; + } } + # WORD } else { # Start at the beginning of this WORD. if (not defined $cur_pos and $pos > 0 and @@ -867,7 +899,6 @@ sub cmd_movement_a_ { } } } - } } return ($cur_pos, $pos); -- cgit v1.2.3 From ba0bdce0469e584a814e601c9f91a430486ea851 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 00:33:25 +0200 Subject: vim_mode: Fix indentation. No code change. --- vim-mode/vim_mode.pl | 136 +++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 68 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a6244c1..9d78677 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -817,88 +817,88 @@ sub cmd_movement_a_ { # aw and aW if ($char eq 'w' or $char eq 'W') { - while ($count-- > 0 and length($input) > $pos) { - if (substr($input, $pos, 1) =~ /\s/) { - # Any whitespace before the word/WORD must be removed. - if (not defined $cur_pos) { - $cur_pos = _find_regex_before($input, '\S', $pos, 0); - if ($cur_pos < 0) { - $cur_pos = 0; - } else { - $cur_pos++; - } + while ($count-- > 0 and length($input) > $pos) { + if (substr($input, $pos, 1) =~ /\s/) { + # Any whitespace before the word/WORD must be removed. + if (not defined $cur_pos) { + $cur_pos = _find_regex_before($input, '\S', $pos, 0); + if ($cur_pos < 0) { + $cur_pos = 0; + } else { + $cur_pos++; } - # Move before the word/WORD. - if (substr($input, $pos + 1) =~ /^\s+/) { + } + # Move before the word/WORD. + if (substr($input, $pos + 1) =~ /^\s+/) { + $pos += $+[0]; + } + # And delete the word. + if ($char eq 'w') { + if (substr($input, $pos) =~ /^\s($word+|$non_word+)/) { $pos += $+[0]; - } - # And delete the word. - if ($char eq 'w') { - if (substr($input, $pos) =~ /^\s($word+|$non_word+)/) { - $pos += $+[0]; - } else { - $pos = length($input); - } - # WORD } else { - if (substr($input, $pos + 1) =~ /\s/) { - $pos += $-[0] + 1; - } else { - $pos = length($input); - } - } - - # word - } elsif ($char eq 'w') { - # Start at the beginning of this WORD. - if (not defined $cur_pos and $pos > 0 and substr($input, $pos - 1, 2) !~ /(\s.|$word$non_word|$non_word$word)/) { - - $cur_pos = _find_regex_before($input, "^($word+$non_word|$non_word+$word|$word+\\s|$non_word+\\s)", $pos, 1); - if ($cur_pos < 0) { - $cur_pos = 0; - } else { - $cur_pos += 2; - } + $pos = length($input); } - # Delete to the end of the word. - if (substr($input, $pos) =~ /^($word+$non_word|$non_word+$word|$word+\s+\S|$non_word+\s+\S)/) { - $pos += $+[0] - 1; + # WORD + } else { + if (substr($input, $pos + 1) =~ /\s/) { + $pos += $-[0] + 1; } else { $pos = length($input); - # If we are at the end of the line, whitespace before - # the word is also deleted. - my $new_pos = _find_regex_before($input, "^($word+\\s+|$non_word+\\s+)", $pos, 1); - if ($new_pos != -1 and (not defined $cur_pos or $cur_pos > $new_pos + 1)) { - $cur_pos = $new_pos + 1; - } } + } - # WORD + # word + } elsif ($char eq 'w') { + # Start at the beginning of this WORD. + if (not defined $cur_pos and $pos > 0 and substr($input, $pos - 1, 2) !~ /(\s.|$word$non_word|$non_word$word)/) { + + $cur_pos = _find_regex_before($input, "^($word+$non_word|$non_word+$word|$word+\\s|$non_word+\\s)", $pos, 1); + if ($cur_pos < 0) { + $cur_pos = 0; + } else { + $cur_pos += 2; + } + } + # Delete to the end of the word. + if (substr($input, $pos) =~ /^($word+$non_word|$non_word+$word|$word+\s+\S|$non_word+\s+\S)/) { + $pos += $+[0] - 1; } else { - # Start at the beginning of this WORD. - if (not defined $cur_pos and $pos > 0 and - substr($input, $pos - 1, 1) !~ /\s/) { - $cur_pos = _find_regex_before($input, '\s', $pos - 1, 0); - if ($cur_pos < 0) { - $cur_pos = 0; - } else { - $cur_pos++; - } + $pos = length($input); + # If we are at the end of the line, whitespace before + # the word is also deleted. + my $new_pos = _find_regex_before($input, "^($word+\\s+|$non_word+\\s+)", $pos, 1); + if ($new_pos != -1 and (not defined $cur_pos or $cur_pos > $new_pos + 1)) { + $cur_pos = $new_pos + 1; } - # Delete to the end of the word. - if (substr($input, $pos + 1) =~ /^\S*\s+\S/) { - $pos += $+[0]; + } + + # WORD + } else { + # Start at the beginning of this WORD. + if (not defined $cur_pos and $pos > 0 and + substr($input, $pos - 1, 1) !~ /\s/) { + $cur_pos = _find_regex_before($input, '\s', $pos - 1, 0); + if ($cur_pos < 0) { + $cur_pos = 0; } else { - $pos = length($input); - # If we are at the end of the line, whitespace before - # the WORD is also deleted. - my $new_pos = _find_regex_before($input, '\s+', $pos, 1); - if (not defined $cur_pos or $cur_pos > $new_pos + 1) { - $cur_pos = $new_pos + 1; - } + $cur_pos++; + } + } + # Delete to the end of the word. + if (substr($input, $pos + 1) =~ /^\S*\s+\S/) { + $pos += $+[0]; + } else { + $pos = length($input); + # If we are at the end of the line, whitespace before + # the WORD is also deleted. + my $new_pos = _find_regex_before($input, '\s+', $pos, 1); + if (not defined $cur_pos or $cur_pos > $new_pos + 1) { + $cur_pos = $new_pos + 1; } } } + } } return ($cur_pos, $pos); -- cgit v1.2.3 From 0fc08ac1f4ce48d1b9529968428fb40550f9c87c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 01:57:10 +0200 Subject: vim_mode: Fix caw. In contrast to cw, caw does delete the space before a word. --- vim-mode/vim_mode.pl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 9d78677..8a6a2ab 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -462,6 +462,11 @@ sub _get_pos_and_length { $length *= -1; } + # Strip leading a_ or i_ if a text-object was used. + if ($move =~ /^[ai]_(.)/) { + $move = $1; + } + # Most movement commands don't move one character after the deletion area # (which is what we need). For those increase length to support proper # selection/deletion. @@ -1713,11 +1718,11 @@ sub handle_command_cmd { # problems with e.g. f when the search string doesn't exist). if ($operator and $cur_pos != $new_pos) { print "Processing operator: ", $operator if DEBUG; - # If text-objects are used the real move character must be - # passed to the operator. + # If text-objects are used the real move character must also + # be passed to the operator. my $tmp_char = $char; if ($char eq 'i_' or $char eq 'a_') { - $tmp_char = substr $movement, 1; + $tmp_char .= substr $movement, 1; } $operators->{$operator}->{func}->($cur_pos, $new_pos, $tmp_char, $repeat); -- cgit v1.2.3 From 0fce5db1b81aa23a18ce3596b42cbfdad42c88d6 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 02:14:04 +0200 Subject: vim_mode: Only undo operators, repeatable movements and repetitions. --- vim-mode/vim_mode.pl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8a6a2ab..3982c93 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1670,11 +1670,10 @@ sub handle_command_cmd { my $cur_pos = _input_pos(); - # save an undo checkpoint here. - - if ($char ne 'u' && $char ne "\x12" && $char ne "\x04" - && $char ne 'j' && $char ne 'k') { - + # Save an undo checkpoint here for operators, all repeatable + # movements, operators and repetition. + if (defined $operator or exists $movements_repeatable->{$char} or + $char eq '.') { # TODO: why do histpry entries still show up in undo # buffer? Is avoiding the commands here insufficient? -- cgit v1.2.3 From 26d93fa047f6d3f55e287268f52b415e050fe819 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 02:50:36 +0200 Subject: vim_mode: Hopefully fix undo/redo. --- vim-mode/vim_mode.pl | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3982c93..a0afc6c 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1192,10 +1192,11 @@ sub cmd_movement_g { sub cmd_undo { print "Undo!" if DEBUG; - _restore_undo_entry($undo_index); - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; if ($undo_index != $#undo_buffer) { $undo_index++; + _restore_undo_entry($undo_index); + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) + if DEBUG; } else { print "No further undo." if DEBUG; } @@ -1203,12 +1204,12 @@ sub cmd_undo { } sub cmd_redo { print "Redo!" if DEBUG; - print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) if DEBUG; - - _restore_undo_entry($undo_index); if ($undo_index != 0) { $undo_index--; + print "Undoing entry index: $undo_index of " . scalar(@undo_buffer) + if DEBUG; + _restore_undo_entry($undo_index); } else { print "No further Redo." if DEBUG; } @@ -1670,16 +1671,6 @@ sub handle_command_cmd { my $cur_pos = _input_pos(); - # Save an undo checkpoint here for operators, all repeatable - # movements, operators and repetition. - if (defined $operator or exists $movements_repeatable->{$char} or - $char eq '.') { - # TODO: why do histpry entries still show up in undo - # buffer? Is avoiding the commands here insufficient? - - _add_undo_entry(_input(), $cur_pos); - } - # If defined $cur_pos will be changed to this. my $old_pos; # Position after the move. @@ -1727,6 +1718,16 @@ sub handle_command_cmd { $tmp_char, $repeat); } + # Save an undo checkpoint here for operators, all repeatable + # movements, operators and repetition. + if (defined $operator or exists $movements_repeatable->{$char} or + $char eq '.') { + # TODO: why do histpry entries still show up in undo + # buffer? Is avoiding the commands here insufficient? + + _add_undo_entry(_input(), $cur_pos); + } + # Store command, necessary for . if ($operator or exists $movements_repeatable->{$char}) { $last->{char} = $char; @@ -2005,6 +2006,9 @@ sub _update_mode { _input_pos($pos - 1); } } + # Store current line to allow undo of i/a/I/A. + _add_undo_entry(_input(), _input_pos()); + # Change mode to i to support insert mode repetition. This doesn't affect # commands like i/a/I/A because handle_command_cmd() sets $last->{char}. # It's necessary when pressing enter. -- cgit v1.2.3 From 8949a4d0a231efd366fa272fad12c0ec9de882b2 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 03:27:18 +0200 Subject: vim_mode: Hopefully fix undo positions. --- vim-mode/vim_mode.pl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a0afc6c..0e665e6 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1671,6 +1671,16 @@ sub handle_command_cmd { my $cur_pos = _input_pos(); + # Update input position of last undo entry so that undo/redo + # restores correct position. + if (@undo_buffer and _input() eq $undo_buffer[0]->[0] and + (defined $operator or exists $movements_repeatable->{$char} or + $char eq '.')) { + print "Updating history position: $undo_buffer[0]->[0]" + if DEBUG; + $undo_buffer[0]->[1] = $cur_pos; + } + # If defined $cur_pos will be changed to this. my $old_pos; # Position after the move. @@ -1725,7 +1735,7 @@ sub handle_command_cmd { # TODO: why do histpry entries still show up in undo # buffer? Is avoiding the commands here insufficient? - _add_undo_entry(_input(), $cur_pos); + _add_undo_entry(_input(), _input_pos()); } # Store command, necessary for . -- cgit v1.2.3 From 55762316ddbed2986ac587e494c9189fe6051b14 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 03:42:28 +0200 Subject: vim_mode: Fix undo positions for text-objects. --- vim-mode/vim_mode.pl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0e665e6..51c4c0b 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1671,16 +1671,6 @@ sub handle_command_cmd { my $cur_pos = _input_pos(); - # Update input position of last undo entry so that undo/redo - # restores correct position. - if (@undo_buffer and _input() eq $undo_buffer[0]->[0] and - (defined $operator or exists $movements_repeatable->{$char} or - $char eq '.')) { - print "Updating history position: $undo_buffer[0]->[0]" - if DEBUG; - $undo_buffer[0]->[1] = $cur_pos; - } - # If defined $cur_pos will be changed to this. my $old_pos; # Position after the move. @@ -1713,6 +1703,16 @@ sub handle_command_cmd { $new_pos = _input_pos(); } + # Update input position of last undo entry so that undo/redo + # restores correct position. + if (@undo_buffer and _input() eq $undo_buffer[0]->[0] and + (defined $operator or exists $movements_repeatable->{$char} or + $char eq '.')) { + print "Updating history position: $undo_buffer[0]->[0]" + if DEBUG; + $undo_buffer[0]->[1] = $cur_pos; + } + # If we have an operator pending then run it on the handled text. # But only if the movement changed the position (this prevents # problems with e.g. f when the search string doesn't exist). -- cgit v1.2.3 From b76dfe17e70d7bbd65f98c5c59fe41ff10acaca5 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 04:18:19 +0200 Subject: vim_mode: Undo only tracks d operators. y is irrelevant for undo and c will get handled once leaving insert mode. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 51c4c0b..60746f2 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1730,8 +1730,8 @@ sub handle_command_cmd { # Save an undo checkpoint here for operators, all repeatable # movements, operators and repetition. - if (defined $operator or exists $movements_repeatable->{$char} or - $char eq '.') { + if ((defined $operator and $operator eq 'd') or + exists $movements_repeatable->{$char} or $char eq '.') { # TODO: why do histpry entries still show up in undo # buffer? Is avoiding the commands here insufficient? -- cgit v1.2.3 From bdf88c3d8a0ad522a1e2be73e08f4c4c81745787 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 04:19:58 +0200 Subject: vim_mode: Only track input positions for d operator. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 60746f2..512a281 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1706,8 +1706,8 @@ sub handle_command_cmd { # Update input position of last undo entry so that undo/redo # restores correct position. if (@undo_buffer and _input() eq $undo_buffer[0]->[0] and - (defined $operator or exists $movements_repeatable->{$char} or - $char eq '.')) { + ((defined $operator and $operator eq 'd') or + exists $movements_repeatable->{$char} or $char eq '.')) { print "Updating history position: $undo_buffer[0]->[0]" if DEBUG; $undo_buffer[0]->[1] = $cur_pos; -- cgit v1.2.3 From 0e08f7de0ff69c5b4c7bae34f29c79b16486ac99 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 04:41:51 +0200 Subject: vim_mode: Fix undo if some changes were already undid. --- vim-mode/vim_mode.pl | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 512a281..74d8403 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1872,6 +1872,14 @@ sub UNLOAD { sub _add_undo_entry { my ($line, $pos) = @_; + + # If we aren't at the top of the history stack, then drop newer entries as + # we can't branch (yet). + while ($undo_index > 0) { + shift @undo_buffer; + $undo_index--; + } + # check it's not a dupe of the list head my $current = $undo_buffer[$undo_index]; if ($line eq $current->[0] && $pos == $current->[1]) { -- cgit v1.2.3 From cf0e900643f010aad92349f7e2d4217e39a81857 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 23:28:34 +0200 Subject: vim_mode: Reorder $movements_repeatable. --- vim-mode/vim_mode.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 74d8403..45b2055 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -367,16 +367,16 @@ my $movements_repeatable = { 'x' => undef, 'X' => undef, + 'i' => undef, + 'a' => undef, + 'I' => undef, + 'A' => undef, 'r' => undef, 'p' => undef, 'P' => undef, 'C' => undef, 'D' => undef, '~' => undef, - 'i' => undef, - 'a' => undef, - 'I' => undef, - 'A' => undef, }; -- cgit v1.2.3 From 81463f53bf6f60e8c961c495bb89f9c71a6e1b9c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 23:28:56 +0200 Subject: vim_mode: Minor comment fix. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 45b2055..a8dd629 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -938,7 +938,7 @@ sub cmd_movement_caret { # No whitespace at all. if ($input !~ m/^\s/) { $pos = 0; - # Some non-whitesapece, go to first one. + # Some non-whitespace, go to first one. } elsif ($input =~ m/[^\s]/) { $pos = $-[0]; # Only whitespace, go to the end. -- cgit v1.2.3 From 808f6aa9610b1b3c8d8af6c5b7c92d90638f6b00 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 23:38:25 +0200 Subject: vim_mode: Fix c repetition. --- vim-mode/vim_mode.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index a8dd629..ba736a5 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -407,7 +407,9 @@ sub cmd_operator_c { if (!$repeat) { _update_mode(M_INS); } else { - _insert_buffer(1, $new_pos); + my $pos = _input_pos(); + $pos = _insert_buffer(1, $pos); + _input_pos($pos); } } sub cmd_operator_d { -- cgit v1.2.3 From cf9f774ef829bae12eb055e148cb04ec7799b1c0 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 3 Oct 2010 23:42:50 +0200 Subject: vim_mode: Fix cw/cW on whitespace directly in front of word. --- vim-mode/vim_mode.pl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ba736a5..588c1e1 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -394,10 +394,12 @@ sub cmd_insert_ctrl_r { sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; - # Changing a word or WORD doesn't delete the last space before a word. + # Changing a word or WORD doesn't delete the last space before a word, but + # not if we are on that whitespace before the word. if ($move eq 'w' or $move eq 'W') { my $input = _input(); - if (substr($input, $new_pos - 1, 1) =~ /\s/) { + if ($new_pos - $old_pos > 1 and + substr($input, $new_pos - 1, 1) =~ /\s/) { $new_pos--; } } -- cgit v1.2.3 From bf5df119cce145b6009e9a08cb4040e4aded2638 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 14:46:57 +0200 Subject: vim_mode: Fix "xdd and "xyy not resetting the register. --- vim-mode/vim_mode.pl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 588c1e1..dba18dd 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1624,6 +1624,10 @@ sub handle_command_cmd { if ($char eq 'y') { _input_pos($pos); } + if ($register ne '"') { + print 'Changing register to "' if DEBUG; + $register = '"'; + } } $numeric_prefix = undef; $operator = undef; -- cgit v1.2.3 From 5ec91faccd74dbba9ba55b87e7d3cbc427e2ad98 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 16:15:38 +0200 Subject: vim_mode: Add G, moves to count-th history line. --- vim-mode/vim_mode.pl | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index dba18dd..2a6edaa 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -15,7 +15,9 @@ # /set vim_mode_cmd_seq j allows to use jj as Escape (any other character # can be used as well). # * Cursor motion: h l 0 ^ $ f t F T -# * History motion: j k +# * History motion: j k G +# G without a count moves to the current input line, with a count it goes to +# the count-th history line (1 is the oldest). # * Cursor word motion: w b ge e W gE B E # * Word objects (only the following work yet): aw aW # * Yank and paste: y p P @@ -292,8 +294,10 @@ my $movements 'h' => { func => \&cmd_movement_h }, 'l' => { func => \&cmd_movement_l }, ' ' => { func => \&cmd_movement_space }, + # history movement 'j' => { func => \&cmd_movement_j }, 'k' => { func => \&cmd_movement_k }, + 'G' => { func => \&cmd_movement_G }, # char movement, take an additional parameter and use $movement 'f' => { func => \&cmd_movement_f }, 't' => { func => \&cmd_movement_t }, @@ -574,6 +578,42 @@ sub cmd_movement_k { } return (undef, undef); } +sub cmd_movement_G { + my ($count, $pos, $repeat) = @_; + + if (Irssi::version < 20090117) { + return; + } + + my @history = Irssi::active_win->get_history_lines(); + + # Go to the current input line if no count was given or it's too big. + if (not $count or $count - 1 >= scalar @history) { + if (defined $history_input and defined $history_pos) { + _input($history_input); + _input_pos($history_pos); + $history_index = undef; + } + return; + } else { + # Save input line so it doesn't get lost. + if (not defined $history_index) { + $history_input = _input(); + $history_pos = _input_pos(); + } + $history_index = $count - 1; + } + + my $history = $history[$history_index]; + # History is not in UTF-8! + if ($utf8) { + $history = decode_utf8($history); + } + _input($history); + _input_pos(0); + + return (undef, undef); +} sub cmd_movement_f { my ($count, $pos, $repeat, $char) = @_; @@ -1673,7 +1713,8 @@ sub handle_command_cmd { # Make sure count is at least 1 except for functions which need to # know if no count was used if (not $numeric_prefix and $char ne "\x04" # ctrl-d - and $char ne "\x15") { # ctrl-u + and $char ne "\x15" # ctrl-u + and $char ne 'G') { $numeric_prefix = 1; } -- cgit v1.2.3 From d2d067d274ebc9a20b40d55442f47d78b8aee2e7 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 16:31:01 +0200 Subject: vim_mode: Add gg, moves to oldest history line. --- vim-mode/vim_mode.pl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 2a6edaa..09710eb 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -15,7 +15,8 @@ # /set vim_mode_cmd_seq j allows to use jj as Escape (any other character # can be used as well). # * Cursor motion: h l 0 ^ $ f t F T -# * History motion: j k G +# * History motion: j k gg G +# gg moves to the oldest (first) history line. # G without a count moves to the current input line, with a count it goes to # the count-th history line (1 is the oldest). # * Cursor word motion: w b ge e W gE B E @@ -1229,7 +1230,12 @@ sub cmd_movement_g { } else { $pos = length($input) - $pos - 1; } + # gg + } elsif ($char eq 'g') { + cmd_movement_G(1, $pos, $repeat); + $pos = undef; } + return (undef, $pos); } -- cgit v1.2.3 From b63078f77a1ba3d1fcdb2cbfac492aa553e5a33c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 16:40:41 +0200 Subject: vim_mode: Prevent j and k with operator. --- vim-mode/vim_mode.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 09710eb..3d31b95 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1704,6 +1704,11 @@ sub handle_command_cmd { } elsif ($char eq '.') { print '. pressed but $last->{char} not set' if DEBUG; $skip = 1; + + # Ignore invalid operator/char combinations. + } elsif ($operator and ($char eq 'j' or $char eq 'k')) { + print "Invalid operator/char: $operator $char" if DEBUG; + $skip = 1; } # C and D force the matching operator if ($char eq 'C') { -- cgit v1.2.3 From e79619c5e880d06f16c16d08c3c4920abbb91a42 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 17:16:53 +0200 Subject: vim_mode: Describe irssi requirements. --- vim-mode/vim_mode.pl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3d31b95..bedf53a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1,5 +1,10 @@ # A script to emulate some of the vi(m) features for the Irssi inputline. # +# It should work fine with at least 0.8.12 and later versions. However some +# features are disabled in older versions (see below for details). Perl >= +# 5.8.1 is recommended for UTF-8 support (which can be disabled if necessary). +# Please report bugs in older versions as well, we'll try to fix them. +# # NOTE: This script is still under heavy development, and there may be bugs. # Please submit reproducible sequences to the bug-tracker at: # http://github.com/shabble/irssi-scripts/issues @@ -100,6 +105,15 @@ # prompt_info.pl script. # # +# Irssi requirements: +# +# 0.8.12 and above should work fine. However the following features are +# disabled in irssi < 0.8.13: +# +# * j k (only with count, they work fine without count in older versions) +# * gg G +# +# # Known bugs: # # * count before register doesn't work: e.g. 3"ap doesn't work, but "a3p does -- cgit v1.2.3 From 443ea86331c3ae1c712248717d403633fb5c27ff Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 20:49:59 +0200 Subject: vim_mode: Minor comment fixes. --- vim-mode/vim_mode.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index bedf53a..cc798f5 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -454,7 +454,6 @@ sub cmd_operator_d { # when changing (C). $pos-- if $pos == length($input) and !$change; - # Move the cursor at the right position. _input_pos($pos); } sub cmd_operator_y { @@ -1736,7 +1735,7 @@ sub handle_command_cmd { print "Skipping movement and operator." if DEBUG; } else { # Make sure count is at least 1 except for functions which need to - # know if no count was used + # know if no count was used. if (not $numeric_prefix and $char ne "\x04" # ctrl-d and $char ne "\x15" # ctrl-u and $char ne 'G') { -- cgit v1.2.3 From e9c166868f41344653b116f1cb596cc6a2598dbf Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 20:50:12 +0200 Subject: vim_mode: Use elsif where possible. --- vim-mode/vim_mode.pl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cc798f5..16247cf 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1650,9 +1650,8 @@ sub handle_command_cmd { print "Changing s to cl" if DEBUG; $char = 'l'; $operator = 'c'; - } # S is an alias for cc. - if (!$movement and !$operator and $char eq 'S') { + } elsif (!$movement and !$operator and $char eq 'S') { print "Changing S to cc" if DEBUG; $char = 'c'; $operator = 'c'; @@ -1722,9 +1721,8 @@ sub handle_command_cmd { } elsif ($operator and ($char eq 'j' or $char eq 'k')) { print "Invalid operator/char: $operator $char" if DEBUG; $skip = 1; - } # C and D force the matching operator - if ($char eq 'C') { + } elsif ($char eq 'C') { $operator = 'c'; } elsif ($char eq 'D') { $operator = 'd'; -- cgit v1.2.3 From e6d611a95aa10cf9f69f449d40a5015ae1161381 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 22:58:16 +0200 Subject: vim_mode: Also clear @ex_buf when pressing esc. --- vim-mode/vim_mode.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 16247cf..61672da 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1867,7 +1867,6 @@ sub handle_command_ex { } elsif ($key == 10) { print "Run ex-mode command" if DEBUG; cmd_ex_command(); - @ex_buf = (); _update_mode(M_CMD); # Append entered key @@ -2120,6 +2119,9 @@ sub _update_mode { $operator = undef; $movement = undef; $register = '"'; + + # Also clear ex-mode buffer. + @ex_buf = (); } Irssi::statusbar_items_redraw("vim_mode"); -- cgit v1.2.3 From d34f1785b5ce85c46ec74bcd095cba740049d5d4 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 23:04:39 +0200 Subject: vim_mode: Fix :abc from display all buffers matching c. Reported by estragib. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 61672da..47de3cf 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1475,7 +1475,7 @@ sub b_windows_cb { # A little code duplication of cmd_ex_command()! my $arg_str = join '', @ex_buf; - if ($arg_str =~ m|b(?:uffer)?\s*(.+)$|) { + if ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { my $buffer = $1; if ($buffer !~ /^[0-9]$/ and $buffer ne '#') { # Display matching windows. -- cgit v1.2.3 From 3a2dba6358cbe2fb2946081c06aa1865f8d0bbdf Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 23:20:18 +0200 Subject: vim_mode: Add #irssi_vim. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 47de3cf..1274e57 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -9,7 +9,7 @@ # Please submit reproducible sequences to the bug-tracker at: # http://github.com/shabble/irssi-scripts/issues # -# or contact rudi_s or shabble on irc.freenode.net (#irssi) +# or contact rudi_s or shabble on irc.freenode.net (#irssi and #irssi_vim) # # # Features: -- cgit v1.2.3 From 4cb98513c63476ee22650ea564fb89b778e1789d Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Tue, 5 Oct 2010 21:41:17 +0100 Subject: disabled removal of timeout waiting for esc input buffer, since it was a timeout_once anyway. --- vim-mode/vim_mode.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 1274e57..3631a1d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1503,7 +1503,7 @@ sub got_key { # contain escape sequences (arrow keys, etc) $input_buf_timer = Irssi::timeout_add_once(10, \&handle_input_buffer, undef); - + print "Buffer Timer tag: $input_buf_timer" if DEBUG; } elsif ($mode == M_INS) { if ($key == 3) { # Ctrl-C enter command mode _update_mode(M_CMD); @@ -1568,7 +1568,7 @@ sub got_key { sub handle_input_buffer { - Irssi::timeout_remove($input_buf_timer); + #Irssi::timeout_remove($input_buf_timer); $input_buf_timer = undef; # see what we've collected. print "Input buffer contains: ", join(", ", @input_buf) if DEBUG; -- cgit v1.2.3 From 5378fbcc55dc94c81f504a8033c9e262fbd16088 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Oct 2010 23:23:55 +0200 Subject: vim_mode: Remove outdated TODO. --- vim-mode/vim_mode.pl | 3 --- 1 file changed, 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3631a1d..c141114 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -2139,6 +2139,3 @@ sub _warn { print '%_vim_mode: ', $warning, '%_'; } - -# TODO: -# 10gg -> go to window 10 (prefix.gg -> win ) -- cgit v1.2.3 From bf636147a15e12383beaf60e1ec5d0f5013b6be1 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 6 Oct 2010 21:35:36 +0200 Subject: vim_mode: Simplify handle_command_cmd() a little. --- vim-mode/vim_mode.pl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index c141114..30bab6a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1560,7 +1560,10 @@ sub got_key { } if ($mode == M_CMD) { - handle_command_cmd($key); + my $should_stop = handle_command_cmd($key); + _stop() if $should_stop; + Irssi::statusbar_items_redraw("vim_mode"); + } elsif ($mode == M_EX) { handle_command_ex($key); } @@ -1635,8 +1638,6 @@ sub handle_numeric_prefix { sub handle_command_cmd { my ($key) = @_; - my $should_stop = 1; - my $char = chr($key); # We need to treat $movements_multiple specially as they need another @@ -1661,9 +1662,11 @@ sub handle_command_cmd { ($numeric_prefix && $char =~ m/[0-9]/))) { print "Processing numeric prefix: $char" if DEBUG; handle_numeric_prefix($char); + return 1; # call _stop() + } # text-objects (i a) are simulated with $movement - } elsif (!$movement && (exists $movements_multiple->{$char} + if (!$movement && (exists $movements_multiple->{$char} or $operator and ($char eq 'i' or $char eq 'a'))) { print "Processing movement: $char" if DEBUG; $movement = $char; @@ -1845,13 +1848,11 @@ sub handle_command_cmd { # Enter key sends the current input line in command mode as well. } elsif ($key == 10) { - $should_stop = 0; _commit_line(); + return 0; # don't call _stop() } - Irssi::statusbar_items_redraw("vim_mode"); - - _stop() if $should_stop; + return 1; # call _stop() } sub handle_command_ex { -- cgit v1.2.3 From a0896e03e25e716c1c3ef76df8feee603dd5d488 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Wed, 6 Oct 2010 21:37:33 +0200 Subject: vim_mode: More cleanup of handle_command_cmd(). --- vim-mode/vim_mode.pl | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 30bab6a..cf53735 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1644,6 +1644,12 @@ sub handle_command_cmd { # argument. if ($movement) { $movement .= $char; + + # Counts + } elsif ($char =~ m/[1-9]/ || ($numeric_prefix && $char =~ m/[0-9]/)) { + print "Processing numeric prefix: $char" if DEBUG; + handle_numeric_prefix($char); + return 1; # call _stop() } # s is an alias for cl. @@ -1658,13 +1664,6 @@ sub handle_command_cmd { $operator = 'c'; } - if (!$movement && ($char =~ m/[1-9]/ || - ($numeric_prefix && $char =~ m/[0-9]/))) { - print "Processing numeric prefix: $char" if DEBUG; - handle_numeric_prefix($char); - return 1; # call _stop() - } - # text-objects (i a) are simulated with $movement if (!$movement && (exists $movements_multiple->{$char} or $operator and ($char eq 'i' or $char eq 'a'))) { -- cgit v1.2.3 From 4ead077f1e58f486133a82dc09d18aa1323f4200 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 03:03:22 +0200 Subject: vim_mode: Add support for complex command mode mappings. Also some internal cleanup of handle_command_cmd(). --- vim-mode/vim_mode.pl | 617 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 367 insertions(+), 250 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index cf53735..051cfd3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -186,10 +186,135 @@ sub M_CMD() { 1 } # command mode sub M_INS() { 0 } # insert mode sub M_EX () { 2 } # extended mode (after a :?) +# operator command +sub C_OPERATOR () { 0 } +# normal commmand +sub C_NORMAL () { 1 } +# command taking another key as argument +sub C_NEEDSKEY () { 2 } +# text-object commmand (i a) +sub C_TEXTOBJECT () { 3 } +# commands entering insert mode +sub C_INSERT () { 4 } + # word and non-word regex, keep in sync with setup_changed()! my $word = qr/[\w_]/o; my $non_word = qr/[^\w_\s]/o; +# COMMANDS + +# All available commands in command mode, they are stored with a char as key, +# but this is not necessarily the key the command is currently mapped to. +my $commands + = { + # operators + c => { char => 'c', func => \&cmd_operator_c, type => C_OPERATOR, + repeatable => 1 }, + d => { char => 'd', func => \&cmd_operator_d, type => C_OPERATOR, + repeatable => 1 }, + y => { char => 'y', func => \&cmd_operator_y, type => C_OPERATOR, + repeatable => 1 }, + + # arrow like movement + h => { char => 'h', func => \&cmd_movement_h, type => C_NORMAL }, + l => { char => 'l', func => \&cmd_movement_l, type => C_NORMAL }, + ' ' => { char => '', func => \&cmd_movement_space, type => C_NORMAL }, + # history movement + j => { char => 'j', func => \&cmd_movement_j, type => C_NORMAL }, + k => { char => 'k', func => \&cmd_movement_k, type => C_NORMAL }, + gg => { char => 'gg', func => \&cmd_movement_gg, type => C_NORMAL }, + G => { char => 'G', func => \&cmd_movement_G, type => C_NORMAL, + needs_count => 1 }, + # char movement, take an additional parameter and use $movement + f => { char => 'f', func => \&cmd_movement_f, type => C_NEEDSKEY }, + t => { char => 't', func => \&cmd_movement_t, type => C_NEEDSKEY }, + F => { char => 'F', func => \&cmd_movement_F, type => C_NEEDSKEY }, + T => { char => 'T', func => \&cmd_movement_T, type => C_NEEDSKEY }, + ';' => { char => ';', func => \&cmd_movement_semicolon, type => C_NORMAL }, + ',' => { char => ',', func => \&cmd_movement_comma, type => C_NORMAL }, + # word movement + w => { char => 'w', func => \&cmd_movement_w, type => C_NORMAL }, + b => { char => 'b', func => \&cmd_movement_b, type => C_NORMAL }, + e => { char => 'e', func => \&cmd_movement_e, type => C_NORMAL }, + ge => { char => 'ge', func => \&cmd_movement_ge, type => C_NORMAL }, + W => { char => 'W', func => \&cmd_movement_W, type => C_NORMAL }, + B => { char => 'B', func => \&cmd_movement_B, type => C_NORMAL }, + E => { char => 'E', func => \&cmd_movement_E, type => C_NORMAL }, + gE => { char => 'gE', func => \&cmd_movement_gE, type => C_NORMAL }, + # text-objects, leading _ means can't be mapped! + _i => { char => '_i', func => \&cmd_movement__i, type => C_TEXTOBJECT }, + _a => { char => '_a', func => \&cmd_movement__a, type => C_TEXTOBJECT }, + # line movement + '0' => { char => '0', func => \&cmd_movement_0, type => C_NORMAL }, + '^' => { char => '^', func => \&cmd_movement_caret, type => C_NORMAL }, + '$' => { char => '$', func => \&cmd_movement_dollar, type => C_NORMAL }, + # delete chars + x => { char => 'x', func => \&cmd_movement_x, type => C_NORMAL, + repeatable => 1 }, + X => { char => 'X', func => \&cmd_movement_X, type => C_NORMAL, + repeatable => 1 }, + s => { char => 's', func => \&cmd_movement_s, type => C_NORMAL, + repeatable => 1 }, # operator c takes care of insert mode + S => { char => 'S', func => \&cmd_movement_S, type => C_NORMAL, + repeatable => 1 }, # operator c takes care of insert mode + # insert mode + i => { char => 'i', func => \&cmd_movement_i, type => C_INSERT }, + I => { char => 'I', func => \&cmd_movement_I, type => C_INSERT }, + a => { char => 'a', func => \&cmd_movement_a, type => C_INSERT }, + A => { char => 'A', func => \&cmd_movement_A, type => C_INSERT }, + # replace + r => { char => 'r', func => \&cmd_movement_r, type => C_NEEDSKEY, + repeatable => 1 }, + # paste + p => { char => 'p', func => \&cmd_movement_p, type => C_NORMAL, + repeatable => 1 }, + P => { char => 'P', func => \&cmd_movement_P, type => C_NORMAL, + repeatable => 1 }, + # to end of line + C => { char => 'C', func => \&cmd_movement_C, type => C_NORMAL, + repeatable => 1 }, + D => { char => 'D', func => \&cmd_movement_D, type => C_NORMAL, + repeatable => 1 }, + # scrolling + "\x04" => { char => '', func => \&cmd_movement_ctrl_d, type => C_NORMAL, + repeatable => 1 }, # half screen down + "\x15" => { char => '', func => \&cmd_movement_ctrl_u, type => C_NORMAL, + repeatable => 1 }, # half screen up + "\x06" => { char => '', func => \&cmd_movement_ctrl_f, type => C_NORMAL, + repeatable => 1 }, # screen down + "\x02" => { char => '', func => \&cmd_movement_ctrl_b, type => C_NORMAL, + repeatable => 1 }, # screen up + # window switching + "\x17j" => { char => 'j', func => \&cmd_movement_ctrl_wj, type => C_NORMAL, + needs_count => 1 }, + "\x17k" => { char => 'k', func => \&cmd_movement_ctrl_wk, type => C_NORMAL, + needs_count => 1 }, + "\x1e" => { char => '', func => \&cmd_movement_ctrl_6, type => C_NORMAL, + needs_count => 1 }, + # misc + '~' => { char => '~', func => \&cmd_movement_tilde, type => C_NORMAL, + repeatable => 1 }, + '"' => { char => '"', func => \&cmd_movement_register, type => C_NEEDSKEY }, + '.' => { char => '.', type => C_NORMAL, repeatable => 1 }, + ':' => { char => ':', type => C_NORMAL }, + "\n" => { char => '', type => C_NORMAL }, # return + # undo + 'u' => { char => 'u', func => \&cmd_undo, type => C_NORMAL }, + "\x12" => { char => '', func => \&cmd_redo, type => C_NORMAL }, + }; + + +# MAPPINGS + +# default command mode mappings +my $maps = {}; + +# Add all default mappings. +foreach my $char (keys %$commands) { + next if $char =~ /^_/; # skip private commands (text-objects for now) + add_map($char, $commands->{$char}); +} + # GLOBAL VARIABLES my $DEBUG_ENABLED = 0; @@ -214,16 +339,20 @@ my $should_ignore = 0; # ex mode buffer my @ex_buf; +# we are waiting for another mapped key (e.g. g pressed, but there are +# multiple mappings like gg gE etc.) +my $pending_map = undef; + # for commands like 10x my $numeric_prefix = undef; -# vi operators like d, c, .. +# current operator as $command hash my $operator = undef; # vi movements, only used when a movement needs more than one key (like f t). my $movement = undef; # last vi command, used by . my $last = { - 'char' => 'i', # = i to support . when loading the script + 'cmd' => $commands->{i}, # = i to support . when loading the script 'numeric_prefix' => undef, 'operator' => undef, 'movement' => undef, @@ -288,117 +417,6 @@ sub script_is_loaded { vim_mode_init(); -# vi-operators like d, c, y -my $operators - = { - 'c' => { func => \&cmd_operator_c }, - 'd' => { func => \&cmd_operator_d }, - 'y' => { func => \&cmd_operator_y }, - }; - -# vi-moves like w,b; they move the cursor and may get combined with an -# operator; also things like i/I are listed here, not entirely correct but -# they work in a similar way -# -# Each function returns two values, an updated $cur_pos (see -# handle_command_cmd()) and the new cursor position. If undef is returned in -# either place, the position isn't changed. -my $movements - = { - # arrow like movement - 'h' => { func => \&cmd_movement_h }, - 'l' => { func => \&cmd_movement_l }, - ' ' => { func => \&cmd_movement_space }, - # history movement - 'j' => { func => \&cmd_movement_j }, - 'k' => { func => \&cmd_movement_k }, - 'G' => { func => \&cmd_movement_G }, - # char movement, take an additional parameter and use $movement - 'f' => { func => \&cmd_movement_f }, - 't' => { func => \&cmd_movement_t }, - 'F' => { func => \&cmd_movement_F }, - 'T' => { func => \&cmd_movement_T }, - ';' => { func => \&cmd_movement_semicolon }, - ',' => { func => \&cmd_movement_comma }, - # word movement - 'w' => { func => \&cmd_movement_w }, - 'b' => { func => \&cmd_movement_b }, - 'e' => { func => \&cmd_movement_e }, - 'W' => { func => \&cmd_movement_W }, - 'B' => { func => \&cmd_movement_B }, - 'E' => { func => \&cmd_movement_E }, - # text-objects - 'i_' => { func => \&cmd_movement_i_ }, - 'a_' => { func => \&cmd_movement_a_ }, - # line movement - '0' => { func => \&cmd_movement_0 }, - '^' => { func => \&cmd_movement_caret }, - '$' => { func => \&cmd_movement_dollar }, - # delete chars - 'x' => { func => \&cmd_movement_x }, - 'X' => { func => \&cmd_movement_X }, - # insert mode - 'i' => { func => \&cmd_movement_i }, - 'I' => { func => \&cmd_movement_I }, - 'a' => { func => \&cmd_movement_a }, - 'A' => { func => \&cmd_movement_A }, - # replace mode - 'r' => { func => \&cmd_movement_r }, - # paste - 'p' => { func => \&cmd_movement_p }, - 'P' => { func => \&cmd_movement_P }, - # to end of line - 'C' => { func => \&cmd_movement_dollar }, - 'D' => { func => \&cmd_movement_dollar }, - # scrolling - "\x04" => { func => \&cmd_movement_ctrl_d }, # half screen down - "\x15" => { func => \&cmd_movement_ctrl_u }, # half screen up - "\x06" => { func => \&cmd_movement_ctrl_f }, # screen down - "\x02" => { func => \&cmd_movement_ctrl_b }, # screen up - # window switching - "\x17" => { func => \&cmd_movement_ctrl_w }, - "\x1e" => { func => \&cmd_movement_ctrl_6 }, - # misc - '~' => { func => \&cmd_movement_tilde }, - '.' => {}, - '"' => { func => \&cmd_movement_register }, - 'g' => { func => \&cmd_movement_g }, # g does many things - # undo - 'u' => { func => \&cmd_undo }, - "\x12" => { func => \&cmd_redo }, # ctrl-r - }; - -# special movements which take an additional key -my $movements_multiple = - { - 'f' => undef, - 't' => undef, - 'F' => undef, - 'T' => undef, - 'r' => undef, - '"' => undef, - 'g' => undef, - "\x17" => undef, # ctrl-w - }; - -# "movements" which can be repeated (additional to operators of course). -my $movements_repeatable - = { - 'x' => undef, - 'X' => undef, - 'i' => undef, - 'a' => undef, - 'I' => undef, - 'A' => undef, - 'r' => undef, - 'p' => undef, - 'P' => undef, - 'C' => undef, - 'D' => undef, - '~' => undef, - }; - - sub cmd_insert_ctrl_r { my ($key) = @_; @@ -484,8 +502,8 @@ sub _get_pos_and_length { $length *= -1; } - # Strip leading a_ or i_ if a text-object was used. - if ($move =~ /^[ai]_(.)/) { + # Strip leading _a or _i if a text-object was used. + if ($move =~ /^_[ai](.)/) { $move = $1; } @@ -628,6 +646,11 @@ sub cmd_movement_G { return (undef, undef); } +sub cmd_movement_gg { + my ($count, $pos, $repeat) = @_; + + return cmd_movement_G(1, $pos, $repeat); +} sub cmd_movement_f { my ($count, $pos, $repeat, $char) = @_; @@ -691,8 +714,8 @@ sub cmd_movement_semicolon { return (undef, undef) if not defined $last_ftFT->{type}; (undef, $pos) - = $movements->{$last_ftFT->{type}} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + = $commands->{$last_ftFT->{type}} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); return (undef, $pos); } sub cmd_movement_comma { @@ -706,8 +729,8 @@ sub cmd_movement_comma { $type =~ tr/ftFT/FTft/; (undef, $pos) - = $movements->{$type} - ->{func}($count, $pos, $repeat, $last_ftFT->{char}); + = $commands->{$type} + ->{func}($count, $pos, $repeat, $last_ftFT->{char}); # Restore type as the move functions overwrites it. $last_ftFT->{type} = $save; return (undef, $pos); @@ -741,6 +764,19 @@ sub cmd_movement_e { $pos = _fix_input_pos($pos, length $input); return (undef, $pos); } +sub cmd_movement_ge { + my ($count, $pos, $repeat, $char) = @_; + + my $input = reverse _input(); + $pos = length($input) - $pos - 1; + $pos = 0 if ($pos < 0); + + $pos = _beginning_of_word($input, $count, $pos); + $pos = length($input) - $pos - 1; + $pos = 0 if ($pos < 0); + + return (undef, $pos); +} # Go to the beginning of $count-th word, like vi's w. sub _beginning_of_word { my ($input, $count, $pos) = @_; @@ -825,6 +861,19 @@ sub cmd_movement_E { return (undef, $pos); } } +sub cmd_movement_gE { + my ($count, $pos, $repeat, $char) = @_; + + my $input = reverse _input(); + $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); + if ($pos == -1 or length($input) - $pos - 1 == -1) { + return cmd_movement_0(); + } else { + $pos = length($input) - $pos - 1; + } + + return (undef, $pos); +} # Go to beginning of $count-th WORD, like vi's W. sub _beginning_of_WORD { my ($input, $count, $pos) = @_; @@ -866,13 +915,13 @@ sub _end_of_WORD { return $pos; } -sub cmd_movement_i_ { +sub cmd_movement__i { my ($count, $pos, $repeat, $char) = @_; _warn("i_ not implemented yet"); return (undef, undef); } -sub cmd_movement_a_ { +sub cmd_movement__a { my ($count, $pos, $repeat, $char) = @_; my $cur_pos; @@ -1026,6 +1075,18 @@ sub cmd_movement_X { cmd_operator_d($pos, $new, 'X'); return (undef, undef); } +sub cmd_movement_s { + my ($count, $pos, $repeat) = @_; + + $operator = $commands->{c}; + return (undef, $pos + 1); +} +sub cmd_movement_S { + my ($count, $pos, $repeat) = @_; + + $operator = $commands->{c}; + return (0, _input_len()); +} sub cmd_movement_i { my ($count, $pos, $repeat) = @_; @@ -1129,6 +1190,19 @@ sub _paste_at_position { return _insert_at_position($registers->{$register}, $count, $pos); } +sub cmd_movement_C { + my ($count, $pos, $repeat) = @_; + + $operator = $commands->{c}; + return (undef, _input_len()); +} +sub cmd_movement_D { + my ($count, $pos, $repeat) = @_; + + $operator = $commands->{d}; + return (undef, _input_len()); +} + sub cmd_movement_ctrl_d { my ($count, $pos, $repeat) = @_; @@ -1165,18 +1239,22 @@ sub cmd_movement_ctrl_b { return (undef, undef); } -sub cmd_movement_ctrl_w { - my ($count, $pos, $repeat, $char) = @_; +sub cmd_movement_ctrl_wj { + my ($count, $pos, $repeat) = @_; - if ($char eq 'j') { - while ($count -- > 0) { - Irssi::command('window down'); - } - } elsif ($char eq 'k') { - while ($count -- > 0) { - Irssi::command('window up'); - } + while ($count -- > 0) { + Irssi::command('window down'); + } + + return (undef, undef); +} +sub cmd_movement_ctrl_wk { + my ($count, $pos, $repeat) = @_; + + while ($count -- > 0) { + Irssi::command('window up'); } + return (undef, undef); } sub cmd_movement_ctrl_6 { @@ -1221,37 +1299,6 @@ sub cmd_movement_register { return (undef, undef); } -sub cmd_movement_g { - my ($count, $pos, $repeat, $char) = @_; - - my $input = _input(); - # ge - if ($char eq 'e') { - $input = reverse $input; - $pos = length($input) - $pos - 1; - $pos = 0 if ($pos < 0); - - $pos = _beginning_of_word($input, $count, $pos); - $pos = length($input) - $pos - 1; - $pos = 0 if ($pos < 0); - # gE - } elsif ($char eq 'E') { - $input = reverse $input; - $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); - if ($pos == -1 or length($input) - $pos - 1 == -1) { - return cmd_movement_0(); - } else { - $pos = length($input) - $pos - 1; - } - # gg - } elsif ($char eq 'g') { - cmd_movement_G(1, $pos, $repeat); - $pos = undef; - } - - return (undef, $pos); -} - sub cmd_undo { print "Undo!" if DEBUG; @@ -1456,10 +1503,10 @@ sub vim_mode_cb { $mode_str .= $numeric_prefix; } if ($operator) { - $mode_str .= $operator; + $mode_str .= $operator->{char}; } if ($movement) { - $mode_str .= $movement; + $mode_str .= $movement->{char}; } $mode_str .= ')'; } @@ -1623,6 +1670,18 @@ sub flush_input_buffer { $imap = undef; } +sub flush_pending_map { + my ($old_pending_map) = @_; + + print "flush_pending_map(): ", $pending_map, ' ', $old_pending_map + if DEBUG; + + return if not defined $pending_map or + $pending_map ne $old_pending_map; + + handle_command_cmd(undef); +} + sub handle_numeric_prefix { my ($char) = @_; my $num = 0+$char; @@ -1638,50 +1697,96 @@ sub handle_numeric_prefix { sub handle_command_cmd { my ($key) = @_; - my $char = chr($key); + my $pending_map_flushed = 0; - # We need to treat $movements_multiple specially as they need another - # argument. - if ($movement) { - $movement .= $char; + my $char; + if (defined $key) { + $char = chr($key); + # We were called from flush_pending_map(). + } else { + $char = $pending_map; + $key = 0; + $pending_map_flushed = 1; + } # Counts - } elsif ($char =~ m/[1-9]/ || ($numeric_prefix && $char =~ m/[0-9]/)) { + if (!$movement and ($char =~ m/[1-9]/ or + ($numeric_prefix && $char =~ m/[0-9]/))) { print "Processing numeric prefix: $char" if DEBUG; handle_numeric_prefix($char); return 1; # call _stop() } - # s is an alias for cl. - if (!$movement and !$operator and $char eq 's') { - print "Changing s to cl" if DEBUG; - $char = 'l'; - $operator = 'c'; - # S is an alias for cc. - } elsif (!$movement and !$operator and $char eq 'S') { - print "Changing S to cc" if DEBUG; - $char = 'c'; - $operator = 'c'; + if (defined $pending_map and not $pending_map_flushed) { + $pending_map = $pending_map . $char; + $char = $pending_map; } - # text-objects (i a) are simulated with $movement - if (!$movement && (exists $movements_multiple->{$char} - or $operator and ($char eq 'i' or $char eq 'a'))) { - print "Processing movement: $char" if DEBUG; - $movement = $char; + my $map; + if ($movement) { + $map = { char => $movement->{char}, + cmd => $movement, + maps => {}, + }; + + } elsif (exists $maps->{$char}) { + $map = $maps->{$char}; + + # We have multiple mappings starting with this key sequence. + if (!$pending_map_flushed and scalar keys %{$map->{maps}} > 0) { + if (not defined $pending_map) { + $pending_map = $char; + } - } elsif (!$movement && exists $operators->{$char}) { - print "Processing operator: $char" if DEBUG; + # The current key sequence has a command mapped to it, run if + # after a timeout. + if (defined $map->{cmd}) { + Irssi::timeout_add_once(1000, \&flush_pending_map, + $pending_map); + } + return 1; # call _stop() + } + + } else { + print "No mapping found for $char" if DEBUG; + $pending_map = undef; + return 1; # call _stop() + } + + $pending_map = undef; + my $cmd = $map->{cmd}; + + # Make sure we have a valid $cmd. + if (not defined $cmd) { + print "Bug in pending_map_flushed() $map->{char}" if DEBUG; + return 1; # call _stop() + } + + # text-objects (i a) are simulated with $movement + if (!$movement and ($cmd->{type} == C_NEEDSKEY or + ($operator and ($char eq 'i' or $char eq 'a')))) { + print "Processing movement: $map->{char} ($cmd->{char})" if DEBUG; + if ($char eq 'i') { + $movement = $commands->{_i}; + } elsif ($char eq 'a') { + $movement = $commands->{_a}; + } else { + $movement = $cmd; + } + + } elsif (!$movement and $cmd->{type} == C_OPERATOR) { + print "Processing operator: $map->{char} ($cmd->{char})" if DEBUG; # Abort operator if we already have one pending. if ($operator) { # But allow cc/dd/yy. - if ($operator eq $char) { - print "Processing operator: ", $operator, $char if DEBUG; + if ($operator == $cmd) { + print "Processing line operator: $map->{char} ($cmd->{char})" + if DEBUG; my $pos = _input_pos(); - $operators->{$operator}->{func}->(0, _input_len(), '', 0); + $cmd->{func}->(0, _input_len(), '', 0); # Restore position for yy. - if ($char eq 'y') { + if ($cmd == $commands->{y}) { _input_pos($pos); } if ($register ne '"') { @@ -1694,18 +1799,34 @@ sub handle_command_cmd { $movement = undef; # Set new operator. } else { - $operator = $char; + $operator = $cmd; } - } elsif ($movement || exists $movements->{$char}) { - print "Processing movement command: $char" if DEBUG; + # Start Ex mode. + } elsif ($cmd == $commands->{':'}) { + if (not script_is_loaded('prompt_info')) { + _warn("Warning: Ex mode requires the 'prompt_info' script. " . + "Please load it and try again."); + } else { + _update_mode(M_EX); + _set_prompt(':'); + } + + # Enter key sends the current input line in command mode as well. + } elsif ($key == 10) { + _commit_line(); + return 0; # don't call _stop() + + } else { #if ($movement || exists $movements->{$char}) { + print "Processing command: $map->{char} ($cmd->{char})" if DEBUG; my $skip = 0; my $repeat = 0; if (!$movement) { # . repeats the last command. - if ($char eq '.' and defined $last->{char}) { + if ($cmd == $commands->{'.'} and defined $last->{cmd}) { + $cmd = $last->{cmd}; $char = $last->{char}; # If . is given a count then it replaces original count. if (not defined $numeric_prefix) { @@ -1715,19 +1836,9 @@ sub handle_command_cmd { $movement = $last->{movement}; $register = $last->{register}; $repeat = 1; - } elsif ($char eq '.') { + } elsif ($cmd == $commands->{'.'}) { print '. pressed but $last->{char} not set' if DEBUG; $skip = 1; - - # Ignore invalid operator/char combinations. - } elsif ($operator and ($char eq 'j' or $char eq 'k')) { - print "Invalid operator/char: $operator $char" if DEBUG; - $skip = 1; - # C and D force the matching operator - } elsif ($char eq 'C') { - $operator = 'c'; - } elsif ($char eq 'D') { - $operator = 'd'; } } @@ -1736,9 +1847,7 @@ sub handle_command_cmd { } else { # Make sure count is at least 1 except for functions which need to # know if no count was used. - if (not $numeric_prefix and $char ne "\x04" # ctrl-d - and $char ne "\x15" # ctrl-u - and $char ne 'G') { + if (not $numeric_prefix and not $cmd->{needs_count}) { $numeric_prefix = 1; } @@ -1751,20 +1860,11 @@ sub handle_command_cmd { # Execute the movement (multiple times). if (not $movement) { ($old_pos, $new_pos) - = $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat); + = $cmd->{func}->($numeric_prefix, $cur_pos, $repeat); } else { - # Use the real movement command (like t or f) for operator - # below. - $char = substr $movement, 0, 1; - # i_ and a_ represent text-objects. - if ($char eq 'i' or $char eq 'a') { - $char .= '_'; - } ($old_pos, $new_pos) - = $movements->{$char}->{func} - ->($numeric_prefix, $cur_pos, $repeat, - substr $movement, 1); + = $cmd->{func}->($numeric_prefix, $cur_pos, $repeat, + $char); } if (defined $old_pos) { print "Changing \$cur_pos from $cur_pos to $old_pos" if DEBUG; @@ -1779,8 +1879,8 @@ sub handle_command_cmd { # Update input position of last undo entry so that undo/redo # restores correct position. if (@undo_buffer and _input() eq $undo_buffer[0]->[0] and - ((defined $operator and $operator eq 'd') or - exists $movements_repeatable->{$char} or $char eq '.')) { + ((defined $operator and $operator == $commands->{d}) or + $cmd->{repeatable})) { print "Updating history position: $undo_buffer[0]->[0]" if DEBUG; $undo_buffer[0]->[1] = $cur_pos; @@ -1790,21 +1890,20 @@ sub handle_command_cmd { # But only if the movement changed the position (this prevents # problems with e.g. f when the search string doesn't exist). if ($operator and $cur_pos != $new_pos) { - print "Processing operator: ", $operator if DEBUG; + print "Processing operator: ", $operator->{char} if DEBUG; # If text-objects are used the real move character must also # be passed to the operator. - my $tmp_char = $char; - if ($char eq 'i_' or $char eq 'a_') { - $tmp_char .= substr $movement, 1; + my $tmp_char = $cmd->{char}; + if ($tmp_char eq '_i' or $tmp_char eq '_a') { + $tmp_char .= $char; } - $operators->{$operator}->{func}->($cur_pos, $new_pos, - $tmp_char, $repeat); + $operator->{func}->($cur_pos, $new_pos, $tmp_char, $repeat); } # Save an undo checkpoint here for operators, all repeatable # movements, operators and repetition. - if ((defined $operator and $operator eq 'd') or - exists $movements_repeatable->{$char} or $char eq '.') { + if ((defined $operator and $operator == $commands->{d}) or + $cmd->{repeatable}) { # TODO: why do histpry entries still show up in undo # buffer? Is avoiding the commands here insufficient? @@ -1812,7 +1911,8 @@ sub handle_command_cmd { } # Store command, necessary for . - if ($operator or exists $movements_repeatable->{$char}) { + if ($operator or $cmd->{repeatable}) { + $last->{cmd} = $cmd; $last->{char} = $char; $last->{numeric_prefix} = $numeric_prefix; $last->{operator} = $operator; @@ -1824,31 +1924,17 @@ sub handle_command_cmd { # Reset the count unless we go into insert mode, _update_mode() needs # to know it when leaving insert mode to support insert with counts # (like 3i). - if ($repeat or ($char ne 'i' and $char ne 'I' and $char ne 'a' and $char ne 'A')) { + if ($repeat or $cmd->{type} != C_INSERT) { $numeric_prefix = undef; } $operator = undef; $movement = undef; - if ($char ne '"' and $register ne '"') { + if ($cmd != $commands->{'"'} and $register ne '"') { print 'Changing register to "' if DEBUG; $register = '"'; } - # Start Ex mode. - } elsif ($char eq ':') { - if (not script_is_loaded('prompt_info')) { - _warn("Warning: Ex mode requires the 'prompt_info' script. " . - "Please load it and try again."); - } else { - _update_mode(M_EX); - _set_prompt(':'); - } - - # Enter key sends the current input line in command mode as well. - } elsif ($key == 10) { - _commit_line(); - return 0; # don't call _stop() } return 1; # call _stop() @@ -2008,6 +2094,35 @@ sub _reset_undo_buffer { } +sub add_map { + my ($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 + # can be longer for this like ,ls). When looking for the mapping these + # "leading" maps are followed. + my $tmp = $keys; + while (length $tmp > 1) { + my $map = substr $tmp, -1, 1, ''; + if (not exists $maps->{$tmp}) { + $maps->{$tmp} = { cmd => undef, maps => {} }; + } + if (not exists $maps->{$tmp}->{maps}->{$tmp . $map}) { + $maps->{$tmp}->{maps}->{$tmp . $map} = undef; + } + } + + if (not exists $maps->{$keys}) { + $maps->{$keys} = { char => $keys, + cmd => $command, + maps => {} + }; + } else { + $maps->{$keys}->{cmd} = $command; + } +} + + sub _commit_line { _update_mode(M_INS); _reset_undo_buffer('', 0); @@ -2098,10 +2213,10 @@ sub _update_mode { _add_undo_entry(_input(), _input_pos()); # Change mode to i to support insert mode repetition. This doesn't affect - # commands like i/a/I/A because handle_command_cmd() sets $last->{char}. + # commands like i/a/I/A because handle_command_cmd() sets $last->{cmd}. # It's necessary when pressing enter. } elsif ($mode == M_CMD and $new_mode == M_INS) { - $last->{char} = 'i'; + $last->{cmd} = $commands->{i}; # Make sure prompt is cleared when leaving ex mode. } elsif ($mode == M_EX and $new_mode != M_EX) { _set_prompt(''); @@ -2120,6 +2235,8 @@ sub _update_mode { $movement = undef; $register = '"'; + $pending_map = undef; + # Also clear ex-mode buffer. @ex_buf = (); } -- cgit v1.2.3 From 6f8e199be69122bb34767b0f996562d1f82efcd2 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 03:44:56 +0200 Subject: vim_mode: Fix function names. --- vim-mode/vim_mode.pl | 214 +++++++++++++++++++++++++-------------------------- 1 file changed, 107 insertions(+), 107 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 051cfd3..e1bfcca 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -216,85 +216,85 @@ my $commands repeatable => 1 }, # arrow like movement - h => { char => 'h', func => \&cmd_movement_h, type => C_NORMAL }, - l => { char => 'l', func => \&cmd_movement_l, type => C_NORMAL }, - ' ' => { char => '', func => \&cmd_movement_space, type => C_NORMAL }, + h => { char => 'h', func => \&cmd_h, type => C_NORMAL }, + l => { char => 'l', func => \&cmd_l, type => C_NORMAL }, + ' ' => { char => '', func => \&cmd_space, type => C_NORMAL }, # history movement - j => { char => 'j', func => \&cmd_movement_j, type => C_NORMAL }, - k => { char => 'k', func => \&cmd_movement_k, type => C_NORMAL }, - gg => { char => 'gg', func => \&cmd_movement_gg, type => C_NORMAL }, - G => { char => 'G', func => \&cmd_movement_G, type => C_NORMAL, + j => { char => 'j', func => \&cmd_j, type => C_NORMAL }, + k => { char => 'k', func => \&cmd_k, type => C_NORMAL }, + gg => { char => 'gg', func => \&cmd_gg, type => C_NORMAL }, + G => { char => 'G', func => \&cmd_G, type => C_NORMAL, needs_count => 1 }, # char movement, take an additional parameter and use $movement - f => { char => 'f', func => \&cmd_movement_f, type => C_NEEDSKEY }, - t => { char => 't', func => \&cmd_movement_t, type => C_NEEDSKEY }, - F => { char => 'F', func => \&cmd_movement_F, type => C_NEEDSKEY }, - T => { char => 'T', func => \&cmd_movement_T, type => C_NEEDSKEY }, - ';' => { char => ';', func => \&cmd_movement_semicolon, type => C_NORMAL }, - ',' => { char => ',', func => \&cmd_movement_comma, type => C_NORMAL }, + f => { char => 'f', func => \&cmd_f, type => C_NEEDSKEY }, + t => { char => 't', func => \&cmd_t, type => C_NEEDSKEY }, + F => { char => 'F', func => \&cmd_F, type => C_NEEDSKEY }, + T => { char => 'T', func => \&cmd_T, type => C_NEEDSKEY }, + ';' => { char => ';', func => \&cmd_semicolon, type => C_NORMAL }, + ',' => { char => ',', func => \&cmd_comma, type => C_NORMAL }, # word movement - w => { char => 'w', func => \&cmd_movement_w, type => C_NORMAL }, - b => { char => 'b', func => \&cmd_movement_b, type => C_NORMAL }, - e => { char => 'e', func => \&cmd_movement_e, type => C_NORMAL }, - ge => { char => 'ge', func => \&cmd_movement_ge, type => C_NORMAL }, - W => { char => 'W', func => \&cmd_movement_W, type => C_NORMAL }, - B => { char => 'B', func => \&cmd_movement_B, type => C_NORMAL }, - E => { char => 'E', func => \&cmd_movement_E, type => C_NORMAL }, - gE => { char => 'gE', func => \&cmd_movement_gE, type => C_NORMAL }, + w => { char => 'w', func => \&cmd_w, type => C_NORMAL }, + b => { char => 'b', func => \&cmd_b, type => C_NORMAL }, + e => { char => 'e', func => \&cmd_e, type => C_NORMAL }, + ge => { char => 'ge', func => \&cmd_ge, type => C_NORMAL }, + W => { char => 'W', func => \&cmd_W, type => C_NORMAL }, + B => { char => 'B', func => \&cmd_B, type => C_NORMAL }, + E => { char => 'E', func => \&cmd_E, type => C_NORMAL }, + gE => { char => 'gE', func => \&cmd_gE, type => C_NORMAL }, # text-objects, leading _ means can't be mapped! - _i => { char => '_i', func => \&cmd_movement__i, type => C_TEXTOBJECT }, - _a => { char => '_a', func => \&cmd_movement__a, type => C_TEXTOBJECT }, + _i => { char => '_i', func => \&cmd__i, type => C_TEXTOBJECT }, + _a => { char => '_a', func => \&cmd__a, type => C_TEXTOBJECT }, # line movement - '0' => { char => '0', func => \&cmd_movement_0, type => C_NORMAL }, - '^' => { char => '^', func => \&cmd_movement_caret, type => C_NORMAL }, - '$' => { char => '$', func => \&cmd_movement_dollar, type => C_NORMAL }, + '0' => { char => '0', func => \&cmd_0, type => C_NORMAL }, + '^' => { char => '^', func => \&cmd_caret, type => C_NORMAL }, + '$' => { char => '$', func => \&cmd_dollar, type => C_NORMAL }, # delete chars - x => { char => 'x', func => \&cmd_movement_x, type => C_NORMAL, + x => { char => 'x', func => \&cmd_x, type => C_NORMAL, repeatable => 1 }, - X => { char => 'X', func => \&cmd_movement_X, type => C_NORMAL, + X => { char => 'X', func => \&cmd_X, type => C_NORMAL, repeatable => 1 }, - s => { char => 's', func => \&cmd_movement_s, type => C_NORMAL, + s => { char => 's', func => \&cmd_s, type => C_NORMAL, repeatable => 1 }, # operator c takes care of insert mode - S => { char => 'S', func => \&cmd_movement_S, type => C_NORMAL, + S => { char => 'S', func => \&cmd_S, type => C_NORMAL, repeatable => 1 }, # operator c takes care of insert mode # insert mode - i => { char => 'i', func => \&cmd_movement_i, type => C_INSERT }, - I => { char => 'I', func => \&cmd_movement_I, type => C_INSERT }, - a => { char => 'a', func => \&cmd_movement_a, type => C_INSERT }, - A => { char => 'A', func => \&cmd_movement_A, type => C_INSERT }, + i => { char => 'i', func => \&cmd_i, type => C_INSERT }, + I => { char => 'I', func => \&cmd_I, type => C_INSERT }, + a => { char => 'a', func => \&cmd_a, type => C_INSERT }, + A => { char => 'A', func => \&cmd_A, type => C_INSERT }, # replace - r => { char => 'r', func => \&cmd_movement_r, type => C_NEEDSKEY, + r => { char => 'r', func => \&cmd_r, type => C_NEEDSKEY, repeatable => 1 }, # paste - p => { char => 'p', func => \&cmd_movement_p, type => C_NORMAL, + p => { char => 'p', func => \&cmd_p, type => C_NORMAL, repeatable => 1 }, - P => { char => 'P', func => \&cmd_movement_P, type => C_NORMAL, + P => { char => 'P', func => \&cmd_P, type => C_NORMAL, repeatable => 1 }, # to end of line - C => { char => 'C', func => \&cmd_movement_C, type => C_NORMAL, + C => { char => 'C', func => \&cmd_C, type => C_NORMAL, repeatable => 1 }, - D => { char => 'D', func => \&cmd_movement_D, type => C_NORMAL, + D => { char => 'D', func => \&cmd_D, type => C_NORMAL, repeatable => 1 }, # scrolling - "\x04" => { char => '', func => \&cmd_movement_ctrl_d, type => C_NORMAL, + "\x04" => { char => '', func => \&cmd_ctrl_d, type => C_NORMAL, repeatable => 1 }, # half screen down - "\x15" => { char => '', func => \&cmd_movement_ctrl_u, type => C_NORMAL, + "\x15" => { char => '', func => \&cmd_ctrl_u, type => C_NORMAL, repeatable => 1 }, # half screen up - "\x06" => { char => '', func => \&cmd_movement_ctrl_f, type => C_NORMAL, + "\x06" => { char => '', func => \&cmd_ctrl_f, type => C_NORMAL, repeatable => 1 }, # screen down - "\x02" => { char => '', func => \&cmd_movement_ctrl_b, type => C_NORMAL, + "\x02" => { char => '', func => \&cmd_ctrl_b, type => C_NORMAL, repeatable => 1 }, # screen up # window switching - "\x17j" => { char => 'j', func => \&cmd_movement_ctrl_wj, type => C_NORMAL, + "\x17j" => { char => 'j', func => \&cmd_ctrl_wj, type => C_NORMAL, needs_count => 1 }, - "\x17k" => { char => 'k', func => \&cmd_movement_ctrl_wk, type => C_NORMAL, + "\x17k" => { char => 'k', func => \&cmd_ctrl_wk, type => C_NORMAL, needs_count => 1 }, - "\x1e" => { char => '', func => \&cmd_movement_ctrl_6, type => C_NORMAL, + "\x1e" => { char => '', func => \&cmd_ctrl_6, type => C_NORMAL, needs_count => 1 }, # misc - '~' => { char => '~', func => \&cmd_movement_tilde, type => C_NORMAL, + '~' => { char => '~', func => \&cmd_tilde, type => C_NORMAL, repeatable => 1 }, - '"' => { char => '"', func => \&cmd_movement_register, type => C_NEEDSKEY }, + '"' => { char => '"', func => \&cmd_register, type => C_NEEDSKEY }, '.' => { char => '.', type => C_NORMAL, repeatable => 1 }, ':' => { char => ':', type => C_NORMAL }, "\n" => { char => '', type => C_NORMAL }, # return @@ -390,7 +390,7 @@ my $imap = undef; my $imaps = { # ctrl-r, insert register - "\x12" => { map => undef, func => \&cmd_insert_ctrl_r }, + "\x12" => { map => undef, func => \&insert_ctrl_r }, }; # index into the history list (for j,k) @@ -417,7 +417,7 @@ sub script_is_loaded { vim_mode_init(); -sub cmd_insert_ctrl_r { +sub insert_ctrl_r { my ($key) = @_; my $char = chr($key); @@ -519,14 +519,14 @@ sub _get_pos_and_length { } -sub cmd_movement_h { +sub cmd_h { my ($count, $pos, $repeat) = @_; $pos -= $count; $pos = 0 if $pos < 0; return (undef, $pos); } -sub cmd_movement_l { +sub cmd_l { my ($count, $pos, $repeat) = @_; my $length = _input_len(); @@ -534,13 +534,13 @@ sub cmd_movement_l { $pos = _fix_input_pos($pos, $length); return (undef, $pos); } -sub cmd_movement_space { +sub cmd_space { my ($count, $pos, $repeat) = @_; - return cmd_movement_l($count, $pos); + return cmd_l($count, $pos); } # later history (down) -sub cmd_movement_j { +sub cmd_j { my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { @@ -579,7 +579,7 @@ sub cmd_movement_j { return (undef, undef); } # earlier history (up) -sub cmd_movement_k { +sub cmd_k { my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { @@ -610,7 +610,7 @@ sub cmd_movement_k { } return (undef, undef); } -sub cmd_movement_G { +sub cmd_G { my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { @@ -646,13 +646,13 @@ sub cmd_movement_G { return (undef, undef); } -sub cmd_movement_gg { +sub cmd_gg { my ($count, $pos, $repeat) = @_; - return cmd_movement_G(1, $pos, $repeat); + return cmd_G(1, $pos, $repeat); } -sub cmd_movement_f { +sub cmd_f { my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); @@ -660,7 +660,7 @@ sub cmd_movement_f { $last_ftFT = { type => 'f', char => $char }; return (undef, $pos); } -sub cmd_movement_t { +sub cmd_t { my ($count, $pos, $repeat, $char) = @_; $pos = _next_occurrence(_input(), $char, $count, $pos); @@ -671,7 +671,7 @@ sub cmd_movement_t { $last_ftFT = { type => 't', char => $char }; return (undef, $pos); } -sub cmd_movement_F { +sub cmd_F { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); @@ -683,7 +683,7 @@ sub cmd_movement_F { $last_ftFT = { type => 'F', char => $char }; return (undef, $pos); } -sub cmd_movement_T { +sub cmd_T { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); @@ -708,7 +708,7 @@ sub _next_occurrence { return $pos; } -sub cmd_movement_semicolon { +sub cmd_semicolon { my ($count, $pos, $repeat) = @_; return (undef, undef) if not defined $last_ftFT->{type}; @@ -718,7 +718,7 @@ sub cmd_movement_semicolon { ->{func}($count, $pos, $repeat, $last_ftFT->{char}); return (undef, $pos); } -sub cmd_movement_comma { +sub cmd_comma { my ($count, $pos, $repeat) = @_; return (undef, undef) if not defined $last_ftFT->{type}; @@ -736,7 +736,7 @@ sub cmd_movement_comma { return (undef, $pos); } -sub cmd_movement_w { +sub cmd_w { my ($count, $pos, $repeat) = @_; my $input = _input(); @@ -744,7 +744,7 @@ sub cmd_movement_w { $pos = _fix_input_pos($pos, length $input); return (undef, $pos); } -sub cmd_movement_b { +sub cmd_b { my ($count, $pos, $repeat) = @_; my $input = reverse _input(); @@ -756,7 +756,7 @@ sub cmd_movement_b { $pos = 0 if ($pos < 0); return (undef, $pos); } -sub cmd_movement_e { +sub cmd_e { my ($count, $pos, $repeat) = @_; my $input = _input(); @@ -764,7 +764,7 @@ sub cmd_movement_e { $pos = _fix_input_pos($pos, length $input); return (undef, $pos); } -sub cmd_movement_ge { +sub cmd_ge { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); @@ -832,7 +832,7 @@ sub _end_of_word { return $pos; } -sub cmd_movement_W { +sub cmd_W { my ($count, $pos, $repeat) = @_; my $input = _input(); @@ -840,34 +840,34 @@ sub cmd_movement_W { $pos = _fix_input_pos($pos, length $input); return (undef, $pos); } -sub cmd_movement_B { +sub cmd_B { my ($count, $pos, $repeat) = @_; my $input = reverse _input(); $pos = _end_of_WORD($input, $count, length($input) - $pos - 1); if ($pos == -1) { - return cmd_movement_0(); + return cmd_0(); } else { return (undef, length($input) - $pos - 1); } } -sub cmd_movement_E { +sub cmd_E { my ($count, $pos, $repeat) = @_; $pos = _end_of_WORD(_input(), $count, $pos); if ($pos == -1) { - return cmd_movement_dollar(); + return cmd_dollar(); } else { return (undef, $pos); } } -sub cmd_movement_gE { +sub cmd_gE { my ($count, $pos, $repeat, $char) = @_; my $input = reverse _input(); $pos = _beginning_of_WORD($input, $count, length($input) - $pos - 1); if ($pos == -1 or length($input) - $pos - 1 == -1) { - return cmd_movement_0(); + return cmd_0(); } else { $pos = length($input) - $pos - 1; } @@ -915,13 +915,13 @@ sub _end_of_WORD { return $pos; } -sub cmd_movement__i { +sub cmd__i { my ($count, $pos, $repeat, $char) = @_; _warn("i_ not implemented yet"); return (undef, undef); } -sub cmd_movement__a { +sub cmd__a { my ($count, $pos, $repeat, $char) = @_; my $cur_pos; @@ -1036,10 +1036,10 @@ sub _find_regex_before { } } -sub cmd_movement_0 { +sub cmd_0 { return (undef, 0); } -sub cmd_movement_caret { +sub cmd_caret { my $input = _input(); my $pos; # No whitespace at all. @@ -1054,18 +1054,18 @@ sub cmd_movement_caret { } return (undef, $pos); } -sub cmd_movement_dollar { +sub cmd_dollar { my $length = _input_len(); return (undef, _fix_input_pos($length, $length)); } -sub cmd_movement_x { +sub cmd_x { my ($count, $pos, $repeat) = @_; cmd_operator_d($pos, $pos + $count, 'x'); return (undef, undef); } -sub cmd_movement_X { +sub cmd_X { my ($count, $pos, $repeat) = @_; return (undef, undef) if $pos == 0; @@ -1075,20 +1075,20 @@ sub cmd_movement_X { cmd_operator_d($pos, $new, 'X'); return (undef, undef); } -sub cmd_movement_s { +sub cmd_s { my ($count, $pos, $repeat) = @_; $operator = $commands->{c}; return (undef, $pos + 1); } -sub cmd_movement_S { +sub cmd_S { my ($count, $pos, $repeat) = @_; $operator = $commands->{c}; return (0, _input_len()); } -sub cmd_movement_i { +sub cmd_i { my ($count, $pos, $repeat) = @_; if (!$repeat) { @@ -1098,10 +1098,10 @@ sub cmd_movement_i { } return (undef, $pos); } -sub cmd_movement_I { +sub cmd_I { my ($count, $pos, $repeat) = @_; - $pos = cmd_movement_caret(); + $pos = cmd_caret(); if (!$repeat) { _update_mode(M_INS); } else { @@ -1109,11 +1109,11 @@ sub cmd_movement_I { } return (undef, $pos); } -sub cmd_movement_a { +sub cmd_a { my ($count, $pos, $repeat) = @_; - # Move after current character. Can't use cmd_movement_l() because we need - # to mover after last character at the end of the line. + # Move after current character. Can't use cmd_l() because we need to mover + # after last character at the end of the line. my $length = _input_len(); $pos += 1; $pos = $length if $pos > $length; @@ -1125,7 +1125,7 @@ sub cmd_movement_a { } return (undef, $pos); } -sub cmd_movement_A { +sub cmd_A { my ($count, $pos, $repeat) = @_; $pos = _input_len(); @@ -1160,7 +1160,7 @@ sub _insert_at_position { return $pos - 1 + length $string; } -sub cmd_movement_r { +sub cmd_r { my ($count, $pos, $repeat, $char) = @_; my $input = _input(); @@ -1173,12 +1173,12 @@ sub cmd_movement_r { return (undef, $pos + $count - 1); } -sub cmd_movement_p { +sub cmd_p { my ($count, $pos, $repeat) = @_; $pos = _paste_at_position($count, $pos + 1); return (undef, $pos); } -sub cmd_movement_P { +sub cmd_P { my ($count, $pos, $repeat) = @_; $pos = _paste_at_position($count, $pos); return (undef, $pos); @@ -1190,20 +1190,20 @@ sub _paste_at_position { return _insert_at_position($registers->{$register}, $count, $pos); } -sub cmd_movement_C { +sub cmd_C { my ($count, $pos, $repeat) = @_; $operator = $commands->{c}; return (undef, _input_len()); } -sub cmd_movement_D { +sub cmd_D { my ($count, $pos, $repeat) = @_; $operator = $commands->{d}; return (undef, _input_len()); } -sub cmd_movement_ctrl_d { +sub cmd_ctrl_d { my ($count, $pos, $repeat) = @_; my $window = Irssi::active_win(); @@ -1214,7 +1214,7 @@ sub cmd_movement_ctrl_d { $window->view()->scroll($count); return (undef, undef); } -sub cmd_movement_ctrl_u { +sub cmd_ctrl_u { my ($count, $pos, $repeat) = @_; my $window = Irssi::active_win(); @@ -1225,21 +1225,21 @@ sub cmd_movement_ctrl_u { $window->view()->scroll($count * -1); return (undef, undef); } -sub cmd_movement_ctrl_f { +sub cmd_ctrl_f { my ($count, $pos, $repeat) = @_; my $window = Irssi::active_win(); $window->view()->scroll($count * $window->{height}); return (undef, undef); } -sub cmd_movement_ctrl_b { +sub cmd_ctrl_b { my ($count, $pos, $repeat) = @_; - cmd_movement_ctrl_f($count * -1, $pos, $repeat); + cmd_ctrl_f($count * -1, $pos, $repeat); return (undef, undef); } -sub cmd_movement_ctrl_wj { +sub cmd_ctrl_wj { my ($count, $pos, $repeat) = @_; while ($count -- > 0) { @@ -1248,7 +1248,7 @@ sub cmd_movement_ctrl_wj { return (undef, undef); } -sub cmd_movement_ctrl_wk { +sub cmd_ctrl_wk { my ($count, $pos, $repeat) = @_; while ($count -- > 0) { @@ -1257,13 +1257,13 @@ sub cmd_movement_ctrl_wk { return (undef, undef); } -sub cmd_movement_ctrl_6 { +sub cmd_ctrl_6 { # like :b# Irssi::command('window last'); return (undef, undef); } -sub cmd_movement_tilde { +sub cmd_tilde { my ($count, $pos, $repeat) = @_; my $input = _input(); @@ -1275,7 +1275,7 @@ sub cmd_movement_tilde { return (undef, _fix_input_pos($pos + $count, length $input)); } -sub cmd_movement_register { +sub cmd_register { my ($count, $pos, $repeat, $char) = @_; if (not exists $registers->{$char} and not exists $registers->{lc $char}) { -- cgit v1.2.3 From ba13b09ac6112f9d6c69705b1783fd5ffdf9503b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 03:51:13 +0200 Subject: vim_mode: Add comments before each code section. --- vim-mode/vim_mode.pl | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index e1bfcca..fe155e2 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -417,6 +417,8 @@ sub script_is_loaded { vim_mode_init(); +# INSERT MODE COMMANDS + sub insert_ctrl_r { my ($key) = @_; @@ -428,6 +430,8 @@ sub insert_ctrl_r { } +# COMMAND MODE OPERATORS + sub cmd_operator_c { my ($old_pos, $new_pos, $move, $repeat) = @_; @@ -518,6 +522,7 @@ sub _get_pos_and_length { return ($old_pos, $length); } +# COMMAND MODE COMMANDS sub cmd_h { my ($count, $pos, $repeat) = @_; @@ -1343,6 +1348,8 @@ sub _fix_input_pos { } +# EX MODE COMMANDS + sub cmd_ex_command { my $arg_str = join '', @ex_buf; if ($arg_str =~ m|^s/(.+)/(.*)/([ig]*)|) { @@ -1484,6 +1491,8 @@ sub _matching_windows { } +# STATUS ITEMS + # vi mode status item. sub vim_mode_cb { my ($sb_item, $get_size_only) = @_; @@ -1535,6 +1544,8 @@ sub b_windows_cb { } +# INPUT HANDLING + sub got_key { my ($key) = @_; -- cgit v1.2.3 From 69fe95c5c37a4b68115a340e8292bb2d693d4e4b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 04:11:52 +0200 Subject: vim_mode: Separate Ex-mode commands. --- vim-mode/vim_mode.pl | 90 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 16 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index fe155e2..3cb141a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -303,6 +303,24 @@ my $commands "\x12" => { char => '', func => \&cmd_redo, type => C_NORMAL }, }; +# All available commands in Ex-Mode. +my $commands_ex + = { + s => \&ex_substitute, + bn => \&ex_bnext, + bp => \&ex_bprev, + bd => \&ex_bdelete, + buffer => \&ex_buffer, + b => \&ex_buffer, + registers => \&ex_registers, + reg => \&ex_registers, + display => \&ex_registers, + di => \&ex_registers, + buffers => \&ex_buffers, + ls => \&ex_buffers, + undolist => \&ex_undolist, + undol => \&ex_undolist, + }; # MAPPINGS @@ -1352,6 +1370,21 @@ sub _fix_input_pos { sub cmd_ex_command { my $arg_str = join '', @ex_buf; + + if ($arg_str !~ /^([a-z]+)/) { + return _warn("Invalid Ex-mode command!"); + } + + if (not exists $commands_ex->{$1}) { + return _warn("Ex-mode $1 doesn't exist!"); + } + + $commands_ex->{$1}($arg_str); +} + +sub ex_substitute { + my ($arg_str) = @_; + if ($arg_str =~ m|^s/(.+)/(.*)/([ig]*)|) { my ($search, $replace, $flags) = ($1, $2, $3); print "Searching for $search, replace: $replace, flags; $flags" @@ -1379,17 +1412,25 @@ sub cmd_ex_command { print "New line is: $line" if DEBUG; _input($line); - # :bn - } elsif ($arg_str eq 'bn') { - Irssi::command('window next'); - # :bp - } elsif ($arg_str eq 'bp') { - Irssi::command('window previous'); - # :bd - } elsif ($arg_str eq 'bd') { - Irssi::command('window close'); + } else { + _warn_ex('s'); + } +} + +sub ex_bnext { + Irssi::command('window next'); +} +sub ex_bprev { + Irssi::command('window previous'); +} +sub ex_bdelete { + Irssi::command('window close'); +} +sub ex_buffer { + my ($arg_str) = @_; + # :b[buffer] {args} - } elsif ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { + if ($arg_str =~ m|^b(?:uffer)?\s*(.+)$|) { my $window; my $item; my $buffer = $1; @@ -1415,9 +1456,16 @@ sub cmd_ex_command { $item->set_active(); } } + } else { + _warn_ex('buffer'); + } +} + +sub ex_registers { + my ($arg_str) = @_; # :reg[isters] {arg} and :di[splay] {arg} - } elsif ($arg_str =~ /^(?:reg(?:isters)?|di(?:splay)?)(?:\s+(.+)$)?/) { + if ($arg_str =~ /^(?:reg(?:isters)?|di(?:splay)?)(?:\s+(.+)$)?/) { my @regs; if ($1) { my $regs = $1; @@ -1433,14 +1481,24 @@ sub cmd_ex_command { $active_window->print("register $key: $registers->{$key}"); } } - # :ls and :buffers - } elsif ($arg_str eq 'ls' or $arg_str eq 'buffers') { - Irssi::command('window list'); - } elsif ($arg_str eq 'undol' or $arg_str eq 'undolist') { - _print_undo_buffer(); + } else { + _warn_ex(':reigsters'); } } +sub ex_buffers { + Irssi::command('window list'); +} + +sub ex_undolist { + _print_undo_buffer(); +} + +sub _warn_ex { + my ($command) = @_; + _warn("Error in ex-mode command $command"); +} + sub _matching_windows { my ($buffer) = @_; -- cgit v1.2.3 From 2ce2c7d227eeba6315259ab579f29f1570797e3f Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 04:13:45 +0200 Subject: vim_mode: Add :bnext, :bprev and :bdelete. --- vim-mode/vim_mode.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 3cb141a..28ceaf7 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -59,9 +59,9 @@ # :b # :b / # :buffer {args} (same as :b) -# :bn - switch to next window -# :bp - switch to previous window -# * Close window: :bd +# :bn[ext] - switch to next window +# :bp[rev] - switch to previous window +# * Close window: :bd[elete] # * Display windows: :ls :buffers # * Display registers: :reg[isters] :di[splay] {args} # * Display undolist: :undol[ist] (mostly used for debugging) @@ -307,8 +307,11 @@ my $commands my $commands_ex = { s => \&ex_substitute, + bnext => \&ex_bnext, bn => \&ex_bnext, + bprev => \&ex_bprev, bp => \&ex_bprev, + bdelete => \&ex_bdelete, bd => \&ex_bdelete, buffer => \&ex_buffer, b => \&ex_buffer, -- cgit v1.2.3 From 3e129bab4162fc6a00bcd0f0149b4dcca46504bd Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 04:19:01 +0200 Subject: vim_mode: Fix minor typo. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 28ceaf7..302100e 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1485,7 +1485,7 @@ sub ex_registers { } } } else { - _warn_ex(':reigsters'); + _warn_ex(':registers'); } } -- cgit v1.2.3 From b73959e84198b677dd81b42b63e0b54689ac761c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 04:27:09 +0200 Subject: vim_mode: Add internal support to bind ex-mode commands in command mode. --- vim-mode/vim_mode.pl | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 302100e..0daff6d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -196,6 +196,8 @@ sub C_NEEDSKEY () { 2 } sub C_TEXTOBJECT () { 3 } # commands entering insert mode sub C_INSERT () { 4 } +# ex-mode commands +sub C_EX () { 5 } # word and non-word regex, keep in sync with setup_changed()! my $word = qr/[\w_]/o; @@ -306,23 +308,23 @@ my $commands # All available commands in Ex-Mode. my $commands_ex = { - s => \&ex_substitute, - bnext => \&ex_bnext, - bn => \&ex_bnext, - bprev => \&ex_bprev, - bp => \&ex_bprev, - bdelete => \&ex_bdelete, - bd => \&ex_bdelete, - buffer => \&ex_buffer, - b => \&ex_buffer, - registers => \&ex_registers, - reg => \&ex_registers, - display => \&ex_registers, - di => \&ex_registers, - buffers => \&ex_buffers, - ls => \&ex_buffers, - undolist => \&ex_undolist, - undol => \&ex_undolist, + s => { func => \&ex_substitute => type => C_EX }, + bnext => { func => \&ex_bnext => type => C_EX }, + bn => { func => \&ex_bnext => type => C_EX }, + bprev => { func => \&ex_bprev => type => C_EX }, + bp => { func => \&ex_bprev => type => C_EX }, + bdelete => { func => \&ex_bdelete => type => C_EX }, + bd => { func => \&ex_bdelete => type => C_EX }, + buffer => { func => \&ex_buffer => type => C_EX }, + b => { func => \&ex_buffer => type => C_EX }, + registers => { func => \&ex_registers => type => C_EX }, + reg => { func => \&ex_registers => type => C_EX }, + display => { func => \&ex_registers => type => C_EX }, + di => { func => \&ex_registers => type => C_EX }, + buffers => { func => \&ex_buffers => type => C_EX }, + ls => { func => \&ex_buffers => type => C_EX }, + undolist => { func => \&ex_undolist => type => C_EX }, + undol => { func => \&ex_undolist => type => C_EX }, }; # MAPPINGS @@ -1835,6 +1837,13 @@ sub handle_command_cmd { return 1; # call _stop() } + # Ex-mode commands can also be bound in command mode. Works only if the + # ex-mode command doesn't take any arguments. + if ($cmd->{type} == C_EX) { + $cmd->{func}->(); + return 1; # call _stop() + } + # text-objects (i a) are simulated with $movement if (!$movement and ($cmd->{type} == C_NEEDSKEY or ($operator and ($char eq 'i' or $char eq 'a')))) { -- cgit v1.2.3 From 8b9fa9038758291517a1ced01ebbe45bbd957821 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 18:44:08 +0200 Subject: vim_mode: Fix ex-mode broken in last commit. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0daff6d..f6ba516 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1384,7 +1384,7 @@ sub cmd_ex_command { return _warn("Ex-mode $1 doesn't exist!"); } - $commands_ex->{$1}($arg_str); + $commands_ex->{$1}->{func}($arg_str); } sub ex_substitute { -- cgit v1.2.3 From dda9e7519366508cebaf08fd820937b636698dd6 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 18:49:52 +0200 Subject: vim_mode: Fix Ctrl-W j, Ctrl-W k. --- vim-mode/vim_mode.pl | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f6ba516..6f779bb 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -287,12 +287,9 @@ my $commands "\x02" => { char => '', func => \&cmd_ctrl_b, type => C_NORMAL, repeatable => 1 }, # screen up # window switching - "\x17j" => { char => 'j', func => \&cmd_ctrl_wj, type => C_NORMAL, - needs_count => 1 }, - "\x17k" => { char => 'k', func => \&cmd_ctrl_wk, type => C_NORMAL, - needs_count => 1 }, - "\x1e" => { char => '', func => \&cmd_ctrl_6, type => C_NORMAL, - needs_count => 1 }, + "\x17j" => { char => 'j', func => \&cmd_ctrl_wj, type => C_NORMAL }, + "\x17k" => { char => 'k', func => \&cmd_ctrl_wk, type => C_NORMAL }, + "\x1e" => { char => '', func => \&cmd_ctrl_6, type => C_NORMAL }, # misc '~' => { char => '~', func => \&cmd_tilde, type => C_NORMAL, repeatable => 1 }, @@ -1270,7 +1267,7 @@ sub cmd_ctrl_b { sub cmd_ctrl_wj { my ($count, $pos, $repeat) = @_; - while ($count -- > 0) { + while ($count-- > 0) { Irssi::command('window down'); } @@ -1279,7 +1276,7 @@ sub cmd_ctrl_wj { sub cmd_ctrl_wk { my ($count, $pos, $repeat) = @_; - while ($count -- > 0) { + while ($count-- > 0) { Irssi::command('window up'); } -- cgit v1.2.3 From 79141f0d78f0c9d3655e3b07c44b77d3e1658d7c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 21:14:46 +0200 Subject: vim_mode: Fix i/I/a/A repeat. --- vim-mode/vim_mode.pl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 6f779bb..17cbdad 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -260,10 +260,14 @@ my $commands S => { char => 'S', func => \&cmd_S, type => C_NORMAL, repeatable => 1 }, # operator c takes care of insert mode # insert mode - i => { char => 'i', func => \&cmd_i, type => C_INSERT }, - I => { char => 'I', func => \&cmd_I, type => C_INSERT }, - a => { char => 'a', func => \&cmd_a, type => C_INSERT }, - A => { char => 'A', func => \&cmd_A, type => C_INSERT }, + i => { char => 'i', func => \&cmd_i, type => C_INSERT, + repeatable => 1 }, + I => { char => 'I', func => \&cmd_I, type => C_INSERT, + repeatable => 1 }, + a => { char => 'a', func => \&cmd_a, type => C_INSERT, + repeatable => 1 }, + A => { char => 'A', func => \&cmd_A, type => C_INSERT, + repeatable => 1 }, # replace r => { char => 'r', func => \&cmd_r, type => C_NEEDSKEY, repeatable => 1 }, -- cgit v1.2.3 From 267eed1b9eebd91e6541a3a9d747fffbc28de339 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 21:15:22 +0200 Subject: vim_mode: Minor documentation updates. --- vim-mode/vim_mode.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 17cbdad..ea43169 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -5,6 +5,9 @@ # 5.8.1 is recommended for UTF-8 support (which can be disabled if necessary). # Please report bugs in older versions as well, we'll try to fix them. # +# Any behavior different from Vim (unless explicitly documented) should be +# considered a bug and reported. +# # NOTE: This script is still under heavy development, and there may be bugs. # Please submit reproducible sequences to the bug-tracker at: # http://github.com/shabble/irssi-scripts/issues @@ -2296,7 +2299,7 @@ sub _update_mode { # Change mode to i to support insert mode repetition. This doesn't affect # commands like i/a/I/A because handle_command_cmd() sets $last->{cmd}. - # It's necessary when pressing enter. + # It's necessary when pressing enter so the next line can be repeated. } elsif ($mode == M_CMD and $new_mode == M_INS) { $last->{cmd} = $commands->{i}; # Make sure prompt is cleared when leaving ex mode. -- cgit v1.2.3 From 30e704c5305844bd789e6a36d5103b379e96cc18 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 22:00:01 +0200 Subject: vim_mode: Fix yank movement and behavior. Reported by estragib. --- vim-mode/vim_mode.pl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ea43169..ce9dc2a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -510,6 +510,12 @@ sub cmd_operator_y { my ($pos, $length) = _get_pos_and_length($old_pos, $new_pos, $move); + # When yanking left of the current char, the current char is not included + # in the yank. + if ($old_pos > $new_pos) { + $length--; + } + # Extract the selected string and put it in the " register. my $input = _input(); my $string = substr $input, $pos, $length; @@ -521,7 +527,12 @@ sub cmd_operator_y { print "Yanked into $register: ", $registers->{$register} if DEBUG; } - _input_pos($old_pos); + # Always move to the lower position. + if ($old_pos > $new_pos) { + _input_pos($new_pos); + } else { + _input_pos($old_pos); + } } sub _get_pos_and_length { my ($old_pos, $new_pos, $move) = @_; -- cgit v1.2.3 From e1ac5729e88eb1841464b26ae29a580cbe032a0f Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 22:36:17 +0200 Subject: vim_mode: Add warning for irssi < 0.8.13 for g and GG. --- vim-mode/vim_mode.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index ce9dc2a..0be1f13 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -657,6 +657,7 @@ sub cmd_G { my ($count, $pos, $repeat) = @_; if (Irssi::version < 20090117) { + _warn("G and gg not supported in irssi < 0.8.13"); return; } -- cgit v1.2.3 From b7dbdbfa1685778c1b77a991ed37db7980b3d6c9 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 22:45:33 +0200 Subject: vim_mode: Increase insert mode timeout to one second. --- vim-mode/vim_mode.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0be1f13..0c64a91 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1674,7 +1674,7 @@ sub got_key { $input_buf_enabled = 1; push @input_buf, $key; $input_buf_timer - = Irssi::timeout_add_once(500, \&flush_input_buffer, undef); + = Irssi::timeout_add_once(1000, \&flush_input_buffer, undef); _stop(); return; -- cgit v1.2.3 From a35a8436a7cc8fe37db0bb5c8462e45e988c80af Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Thu, 7 Oct 2010 22:50:17 +0200 Subject: vim_mode: Fix :registers' display of "+ and "*. Reported by estragib. --- vim-mode/vim_mode.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0c64a91..134874d 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -1495,6 +1495,11 @@ sub ex_registers { } else { @regs = keys %$registers; } + + # Update "+ and "* registers so correct values are displayed. + $registers->{'+'} = Irssi::parse_special('$U'); + $registers->{'*'} = $registers->{'+'}; + my $active_window = Irssi::active_win; foreach my $key (sort @regs) { next if $key eq '_'; # skip black hole -- cgit v1.2.3