aboutsummaryrefslogtreecommitdiffstats
path: root/vim-mode/vim_mode.pl
diff options
context:
space:
mode:
authorSimon Ruderich <simon@ruderich.org>2010-10-08 00:23:43 +0000
committerSimon Ruderich <simon@ruderich.org>2010-10-08 00:23:43 +0000
commit8f84f6e57c31085dcf5cc5a987d44debc11860d5 (patch)
tree4fa96e9ef06a50538cdc29fb54b204446e849970 /vim-mode/vim_mode.pl
parentvim_mode: Add char to $commands_ex hash. (diff)
downloadirssi-scripts-8f84f6e57c31085dcf5cc5a987d44debc11860d5.tar.gz
irssi-scripts-8f84f6e57c31085dcf5cc5a987d44debc11860d5.zip
vim_mode: Add :map to allow custom mappings.
Diffstat (limited to 'vim-mode/vim_mode.pl')
-rw-r--r--vim-mode/vim_mode.pl123
1 files changed, 121 insertions, 2 deletions
diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl
index 042fc34..e941d07 100644
--- a/vim-mode/vim_mode.pl
+++ b/vim-mode/vim_mode.pl
@@ -69,6 +69,20 @@
# * Display windows: :ls :buffers
# * Display registers: :reg[isters] :di[splay] {args}
# * Display undolist: :undol[ist] (mostly used for debugging)
+# * Mappings: :map - display custom mappings
+# :map {lhs} {rhs} - add mapping
+#
+# Mappings:
+#
+# {lhs} is the key combination to be mapped, {rhs} the target. The <> notation
+# is used (e.g. <C-F> is Ctrl-F), case is ignored. Supported <> keys:
+# <C-A>-<C-Z>, <C-^>, <C-6>, <Space>, <CR>. Mapping ex-mode command is
+# supported. Only default mappings can be used in {rhs}.
+# Examples:
+# :map gb :bnext # to map gb to call :bnext
+# :map gB :bprev
+# :map w W # to remap w to work like W
+#
#
# The following irssi settings are available:
#
@@ -330,6 +344,7 @@ my $commands_ex
ls => { char => 'ls', func => \&ex_buffers, type => C_EX },
undolist => { char => 'undolist', func => \&ex_undolist, type => C_EX },
undol => { char => 'undol', func => \&ex_undolist, type => C_EX },
+ map => { char => 'map', func => \&ex_map, type => C_EX },
};
# MAPPINGS
@@ -1526,9 +1541,113 @@ sub ex_undolist {
_print_undo_buffer();
}
+sub ex_map {
+ my ($arg_str) = @_;
+
+ # :map {lhs} {rhs}
+ if ($arg_str =~ /^map (\S+) (\S+)$/) {
+ my $lhs = _parse_mapping($1);
+ my $rhs = $2;
+
+ if (not defined $lhs) {
+ return _warn_ex('map', 'invalid {lhs}');
+ }
+
+ # Add new mapping.
+ my $command;
+ if (index($rhs, ':') == 0) {
+ $rhs = substr $rhs, 1;
+ if (not exists $commands_ex->{$rhs}) {
+ return _warn_ex('map', "$2 not found");
+ } else {
+ $command = $commands_ex->{$rhs};
+ }
+ } else {
+ $rhs = _parse_mapping($2);
+ if (not defined $rhs) {
+ return _warn_ex('map', 'invalid {rhs}');
+ } elsif (not exists $commands->{$rhs}) {
+ return _warn_ex('map', "$2 not found");
+ } else {
+ $command = $commands->{$rhs};
+ }
+ }
+ add_map($lhs, $command);
+
+ # :map
+ } elsif ($arg_str eq 'map') {
+ my $active_window = Irssi::active_win();
+ foreach my $key (sort keys %$maps) {
+ my $map = $maps->{$key};
+ my $cmd = $map->{cmd};
+ if (defined $map->{char}) {
+ my $char = _parse_mapping_reverse($map->{char});
+ next if $char eq $cmd->{char}; # skip default mappings
+
+ my $cmdc = _parse_mapping_reverse($cmd->{char});
+ if ($cmd->{type} == C_EX) {
+ $cmdc = ":$cmdc";
+ }
+ $active_window->print(sprintf "%-15s %s", $char, $cmdc);
+ }
+ }
+ } else {
+ _warn_ex('map');
+ }
+}
+sub _parse_mapping {
+ my ($string) = @_;
+
+ $string =~ s/<([^>]+)>/_parse_mapping_bracket($1)/ge;
+ if (index($string, '<invalid>') != -1) {
+ return undef;
+ }
+ return $string;
+}
+sub _parse_mapping_bracket {
+ my ($string) = @_;
+
+ $string = lc $string;
+
+ # <C-X>, get corresponding CTRL char.
+ if ($string =~ /^c-([a-z])$/i) {
+ $string = chr(ord($1) - 96);
+ # <C-6> and <C-^>
+ } elsif ($string =~ /^c-[6^]$/i) {
+ $string = chr(30);
+ # <Space>
+ } elsif ($string eq 'space') {
+ $string = ' ';
+ # <CR>
+ } elsif ($string eq 'cr') {
+ $string = "\n";
+ # Invalid char, return special string to recognize the error.
+ } else {
+ $string = '<invalid>';
+ }
+ return $string;
+}
+sub _parse_mapping_reverse {
+ my ($string) = @_;
+
+ # Convert char to <char-name>.
+ $string =~ s/ /<Space>/g;
+ $string =~ s/\n/<CR>/g;
+ # Convert Ctrl-X to <C-X>.
+ $string =~ s/([\x01-\x1A])/"<C-" . chr(ord($1) + 64) . ">"/ge;
+ # Convert Ctrl-6 and Ctrl-^ to <C-^>.
+ $string =~ s/\x1E/<C-^>/g;
+
+ return $string;
+}
+
sub _warn_ex {
- my ($command) = @_;
- _warn("Error in ex-mode command $command");
+ my ($command, $description) = @_;
+ my $message = "Error in ex-mode command $command";
+ if (defined $description) {
+ $message .= ": $description";
+ }
+ _warn($message);
}
sub _matching_windows {