From 8b514733fa3dbfdd0fad2a8e38061a499fca5c7b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 03:45:36 +0200 Subject: vim_mode: Fix . to only ignore movements, and not more. --- vim-mode/vim_mode.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 38c1aa9..8fa2fee 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -901,7 +901,10 @@ sub handle_command { } # Store command, necessary for . But ignore movements only. - if ($operator) { + if ($operator 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 '~') { $last->{char} = $char; $last->{numeric_prefix} = $numeric_prefix; $last->{operator} = $operator; -- cgit v1.2.3 From d88628c7735ab3e9132c0fe30cc46ca433e49494 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 04:16:52 +0200 Subject: vim_mode: Implement registers. --- vim-mode/vim_mode.pl | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 8fa2fee..26577a8 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -106,13 +106,17 @@ my $last 'char' => undef, 'numeric_prefix' => undef, 'operator' => undef, - 'movement' => undef + 'movement' => undef, + 'register' => undef, }; # what Vi mode we're in. We start in insert mode. my $mode = M_INS; -# vi registers, at the moment only the default yank register (") is used +# current active register +my $register = '"'; + +# vi registers, " is the default register my $registers = { '"' => '' @@ -202,6 +206,7 @@ my $movements # misc '~' => { func => \&cmd_movement_tilde }, '.' => {}, + '"' => { func => \&cmd_movement_register }, # undo 'u' => { func => \&cmd_undo }, "\x12" => { func => \&cmd_redo }, @@ -216,6 +221,7 @@ my $movements_multiple = 'F' => undef, 'T' => undef, 'r' => undef, + '"' => undef, }; @@ -240,9 +246,9 @@ sub cmd_operator_d { # Remove the selected string from the input. my $input = _input(); - $registers->{'"'} = substr $input, $pos, $length, ''; + $registers->{$register} = substr $input, $pos, $length, ''; _input($input); - print "Deleted: " . $registers->{'"'} if DEBUG; + print "Deleted into $register: " . $registers->{$register} if DEBUG; # Move the cursor at the right position. _input_pos($pos); @@ -254,8 +260,8 @@ sub cmd_operator_y { # Extract the selected string and put it in the " register. my $input = _input(); - $registers->{'"'} = substr $input, $pos, $length; - print "Yanked: " . $registers->{'"'} if DEBUG; + $registers->{$register} = substr $input, $pos, $length; + print "Yanked into $register: " . $registers->{$register} if DEBUG; _input_pos($old_pos); } @@ -583,9 +589,9 @@ sub cmd_movement_P { sub _paste_at_position { my ($count, $pos) = @_; - return if not $registers->{'"'}; + return if not $registers->{$register}; - my $string = $registers->{'"'} x $count; + 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 @@ -626,6 +632,13 @@ sub cmd_movement_tilde { _input_pos($pos + $count); } +sub cmd_movement_register { + my ($count, $pos, $char) = @_; + + $register = $char; + print "Changing register to $register" if DEBUG; +} + sub cmd_ex_command { my $arg_str = join '', @ex_buf; if ($arg_str =~ m|s/(.+)/(.*)/([ig]*)|) { @@ -669,8 +682,11 @@ sub vim_mode_cb { $mode_str = '%_Ex%_'; } else { $mode_str = '%_Command%_'; - if ($numeric_prefix or $operator or $movement) { + if ($register ne '"' or $numeric_prefix or $operator or $movement) { $mode_str .= ' ('; + if ($register ne '"') { + $mode_str .= '"' . $register; + } if ($numeric_prefix) { $mode_str .= $numeric_prefix; } @@ -858,6 +874,7 @@ sub handle_command { } $operator = $last->{operator}; $movement = $last->{movement}; + $register = $last->{register}; } elsif ($char eq '.') { $skip = 1; } @@ -900,15 +917,17 @@ sub handle_command { $operators->{$operator}->{func}->($cur_pos, $new_pos, $char); } - # Store command, necessary for . But ignore movements only. + # Store command, necessary for . But ignore movements and + # registers. if ($operator 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 '~') { + $char eq '~' or $char eq '"') { $last->{char} = $char; $last->{numeric_prefix} = $numeric_prefix; $last->{operator} = $operator; $last->{movement} = $movement; + $last->{register} = $register; } } @@ -916,6 +935,11 @@ sub handle_command { $operator = undef; $movement = undef; + if ($char ne '"' and $register ne '"') { + print 'Changing register to "' if DEBUG; + $register = '"'; + } + # Start Ex mode. } elsif ($char eq ':') { _update_mode(M_EX); @@ -1005,6 +1029,7 @@ sub _update_mode { $mode = $new_mode; if ($mode == M_INS) { $history_index = undef; + $register = '"'; } Irssi::statusbar_items_redraw("vim_mode"); } -- cgit v1.2.3 From e5228912060c5b8a82a2c4c1c73d8ba06fb1975b Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 04:32:28 +0200 Subject: vim_mode: esc also resets all command mode related settings. --- vim-mode/vim_mode.pl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 26577a8..45acf79 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -755,6 +755,13 @@ sub handle_esc_buffer { print "Enter Command Mode" if DEBUG; _update_mode(M_CMD); + # Reset every command mode related setting as a fallback in case + # something goes wrong. + $numeric_prefix = undef; + $operator = undef; + $movement = undef; + $register = '"'; + } else { # we need to identify what we got, and either replay it # or pass it off to the command handler. -- cgit v1.2.3 From a3f5bd31279816942282daef30038290b350880c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 04:34:15 +0200 Subject: vim_mode: Remove fixed todo. --- vim-mode/vim_mode.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 45acf79..54f3de3 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -23,7 +23,6 @@ # * /,?,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 movement should keep track of the 'active' input line and restore it # Known bugs: # * count with insert mode: 3iabc doesn't work -- cgit v1.2.3 From eb7d47524b3d025f0a3e5cd04e6d3ba51362740d Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 04:56:59 +0200 Subject: vim_mode: Fix b and e not working between two words. --- vim-mode/vim_mode.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 54f3de3..f2ea5fc 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -455,6 +455,10 @@ sub _end_of_word { $pos += $+[0] + 1; $skipped = 1; } + elsif (substr($input, $pos) =~ /^\s+/) { + $pos += $+[0]; + $skipped = 1; + } # We are inside a word/non-word, skip to the end of it. if (substr($input, $pos) =~ /^$word{2,}/ or substr($input, $pos) =~ /^$non_word{2,}/) { -- cgit v1.2.3 From 27d7acd387ebb1f36cb6756c1a5dc2e88c1ce903 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 05:08:29 +0200 Subject: vim_mode: Add X. --- vim-mode/vim_mode.pl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index f2ea5fc..742e7b8 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -187,6 +187,7 @@ my $movements '$' => { 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 }, @@ -274,10 +275,10 @@ sub _get_pos_and_length { $length *= -1; } - # w, x, h, l are the only movements which move one character after the + # 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 'h' and $move ne 'l') { + if ($move ne 'w' and $move ne 'x' and $move ne 'X' and $move ne 'h' and $move ne 'l') { $length += 1; } @@ -555,6 +556,15 @@ sub cmd_movement_x { cmd_operator_d($pos, $pos + $count, 'x'); } +sub cmd_movement_X { + my ($count, $pos) = @_; + + return if $pos == 0; + + my $new = $pos - $count; + $new = 0 if $new < 0; + cmd_operator_d($pos, $new, 'X'); +} sub cmd_movement_i { _update_mode(M_INS); @@ -929,8 +939,8 @@ sub handle_command { # Store command, necessary for . But ignore movements and # registers. - if ($operator or $char eq 'x' or $char eq 'r' or - $char eq 'p' or $char eq 'P' or + 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; -- cgit v1.2.3 From a5f44bd441281345c44e7f13b0c317e366117711 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 17:26:00 +0200 Subject: vim_mode: Rename esc_buf to input_buf. --- vim-mode/vim_mode.pl | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 742e7b8..0be39b9 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -83,9 +83,9 @@ my $non_word = '[^a-zA-Z0-9_\s]'; # GLOBAL VARIABLES # buffer to keep track of the last N keystrokes following an Esc character. -my @esc_buf; -my $esc_buf_timer; -my $esc_buf_enabled = 0; +my @input_buf; +my $input_buf_timer; +my $input_buf_enabled = 0; # flag to allow us to emulate keystrokes without re-intercepting them my $should_ignore = 0; @@ -724,13 +724,13 @@ sub got_key { # Esc key if ($key == 27) { print "Esc seen, starting buffer" if DEBUG; - $esc_buf_enabled = 1; + $input_buf_enabled = 1; # NOTE: this timeout might be too low on laggy systems, but # it comes at the cost of keystroke latency for things that # contain escape sequences (arrow keys, etc) - $esc_buf_timer - = Irssi::timeout_add_once(10, \&handle_esc_buffer, undef); + $input_buf_timer + = Irssi::timeout_add_once(10, \&handle_input_buffer, undef); } elsif ($mode == M_INS) { if ($key == 3) { # Ctrl-C enter command mode @@ -745,8 +745,8 @@ sub got_key { } } - if ($esc_buf_enabled) { - push @esc_buf, $key; + if ($input_buf_enabled) { + push @input_buf, $key; _stop(); return; } @@ -756,14 +756,14 @@ sub got_key { } } -sub handle_esc_buffer { +sub handle_input_buffer { - Irssi::timeout_remove($esc_buf_timer); - $esc_buf_timer = undef; + Irssi::timeout_remove($input_buf_timer); + $input_buf_timer = undef; # see what we've collected. - print "Esc buffer contains: ", join(", ", @esc_buf) if DEBUG; + print "Input buffer contains: ", join(", ", @input_buf) if DEBUG; - if (@esc_buf == 1 && $esc_buf[0] == 27) { + if (@input_buf == 1 && $input_buf[0] == 27) { print "Enter Command Mode" if DEBUG; _update_mode(M_CMD); @@ -780,19 +780,19 @@ sub handle_esc_buffer { # or pass it off to the command handler. if ($mode == M_CMD) { # command - my $key_str = join '', map { chr } @esc_buf; + 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(@esc_buf); + _emulate_keystrokes(@input_buf); } } - @esc_buf = (); - $esc_buf_enabled = 0; + @input_buf = (); + $input_buf_enabled = 0; } sub handle_numeric_prefix { -- cgit v1.2.3 From e164f45dbfeeeb91c795caddd57fadb44bfffec1 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 27 Sep 2010 18:01:44 +0200 Subject: vim_mode: Add jj to enter command mode. It's configured by the vim_mode_jj setting. --- vim-mode/vim_mode.pl | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 0be39b9..b0dfe6a 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -82,7 +82,8 @@ my $non_word = '[^a-zA-Z0-9_\s]'; # GLOBAL VARIABLES -# buffer to keep track of the last N keystrokes following an Esc character. +# buffer to keep track of the last N keystrokes, used for Esc detection and +# insert mode mappings my @input_buf; my $input_buf_timer; my $input_buf_enabled = 0; @@ -121,6 +122,12 @@ my $registers '"' => '' }; +# current imap still pending (first character entered) +my $imap = undef; + +# maps for insert mode +my $imaps = {}; + # index into the history list (for j,k) my $history_index = undef; # current line, necessary for j,k or the current input line gets destroyed @@ -742,6 +749,33 @@ sub got_key { @undo_buffer = (); $undo_index = undef; _stop(); + } elsif ($input_buf_enabled and $imap) { + print "Imap $imap active" if DEBUG; + my $map = $imaps->{$imap}; + if (chr($key) eq $map->{map}) { + $map->{func}(); + # Clear the buffer so the imap is not printed. + @input_buf = (); + } else { + push @input_buf, $key; + } + flush_input_buffer(); + _stop(); + $imap = undef; + return; + } elsif (exists $imaps->{chr($key)}) { + print "Imap " . chr($key) . " seen, starting buffer" if DEBUG; + + # start imap pending mode + $imap = chr($key); + + $input_buf_enabled = 1; + push @input_buf, $key; + $input_buf_timer + = Irssi::timeout_add_once(500, \&flush_input_buffer, undef); + + _stop(); + return; } } @@ -795,6 +829,20 @@ sub handle_input_buffer { $input_buf_enabled = 0; } +sub flush_input_buffer { + Irssi::timeout_remove($input_buf_timer); + $input_buf_timer = undef; + # see what we've collected. + print "Input buffer flushed" if DEBUG; + + _emulate_keystrokes(@input_buf); + + @input_buf = (); + $input_buf_enabled = 0; + + $imap = undef; +} + sub handle_numeric_prefix { my ($char) = @_; my $num = 0+$char; @@ -978,7 +1026,22 @@ sub handle_command { 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::settings_add_bool('vim_mode', 'vim_mode_jj', 0); + + setup_changed(); +} + +sub setup_changed { + if (Irssi::settings_get_bool('vim_mode_jj')) { + $imaps->{j} = { 'map' => 'j', + 'func' => sub { _update_mode(M_CMD) } + }; + } else { + delete $imaps->{j}; + } } sub _commit_line { -- cgit v1.2.3