diff options
-rw-r--r-- | vim-mode/vim_mode.pl | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl new file mode 100644 index 0000000..47ae262 --- /dev/null +++ b/vim-mode/vim_mode.pl @@ -0,0 +1,181 @@ +use strict; +use warnings; + +use Irssi; +use Irssi::TextUI; # for sbar_items_redraw + +# /statusbar window add vim_mode to get the status. + +use vars qw($VERSION %IRSSI); +$VERSION = "1.0.1"; +%IRSSI = + ( + authors => "shabble", + contact => 'shabble+irssi@metavore.org, shabble@#irssi/Freenode', + name => "vim_mode", + description => "Give Irssi Vim-like commands for editing the inputline", + license => "Public Domain", + changed => "20/9/2010" + ); + +#sub DEBUG () { 1 } +sub DEBUG () { 0 } + +# circular buffer to keep track of the last N keystrokes. +my @key_buf; + +my $mode = 0; # 0 is insert, 1 is command. no Ex for now. + +my $commands + = { + 'i' => { command => 'insert at cur', + func => \&cmd_insert, + params => {pos => sub { _input_pos() }}, + }, + + 'I' => { command => 'insert at end', + func => \&cmd_insert, + params => {pos => sub { _input_len() }}, + }, + + 'A' => { command => 'insert at start', + func => \&cmd_insert, + params => { pos => sub { 0 } }, + }, + + 'h' => { command => 'move left', + func => \&cmd_move, + params => { 'dir' => 'left' }, + }, + 'l' => { command => 'move right', + func => \&cmd_move, + params => { 'dir' => 'right' }, + }, + + }; + +sub cmd_jump_word { + my ($params) = @_; + +} + +sub cmd_insert { + my ($params) = @_; + my $pos = $params->{pos}->(); + + _input_pos($pos); + + $mode = 0; + + _update_mode(); + _stop(); +} + +sub cmd_move { + my ($params) = @_; + my $dir = $params->{dir}; + my $current_pos = _input_pos(); + + if ($dir eq 'left') { + _input_pos($current_pos -1) if $current_pos; + } elsif ($dir eq 'right') { + my $current_len = _input_len(); + _input_pos($current_pos +1) unless $current_pos == $current_len; + } else { + print "Unknown direction: $dir"; + } + + _stop(); +} + +sub vim_mode_cb { + my ($sb_item, $get_size_only) = @_; + my $mode_str = ''; + if ($mode == 0) { + $mode_str = 'Insert'; + } else { + $mode_str = '%_Command%_'; + } + $sb_item->default_handler($get_size_only, "{sb $mode_str}", '', 0); +} + + +sub got_key { + my ($key) = @_; + _key_buf_add($key); + if ($mode == 0) { + # we're in insert mode. + if ($key == 27) { # esc + + $mode = 1; + _update_mode(); + Irssi::signal_stop(); + return; + } + + return; + } else { + # command mode + handle_command($key); + } + print "Keys: ", join ', ', @key_buf; +} + + +sub handle_command { + my ($key) = @_; + my $char = chr($key); + if (exists $commands->{$char}) { + my $cmd = $commands->{$char}; + print "Going to execute command: ", $cmd->{command}; + $cmd->{func}->( $cmd->{params} ); + } else { + # some error handling. + } +} + + + + +Irssi::signal_add_first 'gui key pressed' => \&got_key; +Irssi::statusbar_item_register ('vim_mode', 0, 'vim_mode_cb'); + +sub _key_buf_add { + my ($key) = @_; + push @key_buf, $key; + if (@key_buf > 5) { + shift @key_buf; + } +} + +sub _input { + my ($data) = @_; + if (defined $data) { + Irssi::gui_input_set($data); + } else { + $data = Irssi::parse_special('$L', 0, 0) + } + return $data; +} + +sub _input_len { + return length (Irssi::parse_special('$L', 0, 0)); +} + +sub _input_pos { + my ($pos) = @_; + if (defined $pos) { + Irssi::gui_input_set_pos($pos); + } else { + $pos = Irssi::gui_input_get_pos(); + } + return $pos; +} + +sub _stop() { + Irssi::signal_stop(); +} + +sub _update_mode() { + Irssi::statusbar_items_redraw("vim_mode"); +} |