aboutsummaryrefslogblamecommitdiffstats
path: root/vim-mode/vim_mode.pl
blob: 47ae2622182390a8912218fd1b590cca27e0e4e2 (plain) (tree)




















































































































































































                                                                               
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");
}