aboutsummaryrefslogtreecommitdiffstats
path: root/vim-mode
diff options
context:
space:
mode:
authorTom Feist <shabble@metavore.org>2010-10-15 19:45:53 +0000
committerTom Feist <shabble@metavore.org>2010-10-15 19:45:53 +0000
commitd01eee2a5d0c8735512e2cb92e95fa422584280b (patch)
tree5fe3e1b5479ba102c9af1aba56c4e4007314b08a /vim-mode
parentuberprompt: fix to allow { and } characters in input. (diff)
parentvim_mode: escaped % in _set_prompt so uberprompt displays them correctly. (diff)
downloadirssi-scripts-d01eee2a5d0c8735512e2cb92e95fa422584280b.tar.gz
irssi-scripts-d01eee2a5d0c8735512e2cb92e95fa422584280b.zip
Merge remote branch 'origin/dev'
Diffstat (limited to 'vim-mode')
-rw-r--r--vim-mode/vim_mode.pl162
1 files changed, 130 insertions, 32 deletions
diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl
index 6ff8c78..cce0700 100644
--- a/vim-mode/vim_mode.pl
+++ b/vim-mode/vim_mode.pl
@@ -114,9 +114,15 @@
# * utf8: support UTF-8 characters, boolean, default on
# * debug: enable debug output, boolean, default off
# * cmd_seq: char that when double-pressed simulates <esc>, string, default ''
+# * start_cmd: start every line in command mode, boolean, default off
#
# In contrast to irssi's settings, :set accepts 0 and 1 as values for boolean
# settings, but only vim_mode's settings can be set/displayed.
+# Examples:
+# :set cmd_seq=j # set cmd_seq to j
+# :set cmd_seq= # disable cmd_seq
+# :set debug=on # enable debug
+# :set debug=off # disable debug
#
#
# The following statusbar items are available:
@@ -193,6 +199,11 @@
# WONTFIX - things we're not ever likely to do
# * Macros
#
+# THANKS:
+#
+# * estragib: a lot of testing and many bug reports and feature requests
+# * iaj: testing
+#
# LICENCE:
#
# Copyright (c) 2010 Tom Feist & Simon Ruderich
@@ -392,7 +403,7 @@ my $commands
'~' => { char => '~', func => \&cmd_tilde, type => C_NORMAL,
repeatable => 1, no_operator => 1 },
'"' => { char => '"', func => \&cmd_register, type => C_NEEDSKEY,
- no_operator => 1 },
+ no_operator => 1, dont_clear_partial_keys => 1 },
'.' => { char => '.', type => C_NORMAL, repeatable => 1,
no_operator => 1 },
':' => { char => ':', type => C_NORMAL },
@@ -483,6 +494,8 @@ my $settings
utf8 => { type => S_BOOL, value => 1 },
# esc-shortcut in insert mode
cmd_seq => { type => S_STR, value => '' },
+ # start every line in command mode
+ start_cmd => { type => S_BOOL, value => 0 },
# not used yet
max_undo_lines => { type => S_INT, value => 50 },
};
@@ -514,6 +527,10 @@ my $numeric_prefix = undef;
my $operator = undef;
# vi movements, only used when a movement needs more than one key (like f t).
my $movement = undef;
+
+# current partial command = all pending keys currently entered
+my $partial_command = '';
+
# last vi command, used by .
my $last
= {
@@ -1459,6 +1476,8 @@ sub cmd_register {
return (undef, undef);
}
+ $partial_command .= $char;
+
# make sure black hole register is always empty
if ($char eq '_') {
$registers->{_} = '';
@@ -1902,7 +1921,7 @@ sub ex_set {
my ($arg_str, $count) = @_;
# :se[t] [option] [value]
- if ($arg_str =~ /^se(?:t)?(?:\s(\S+)(?:\s(.+)$)?)?/) {
+ if ($arg_str =~ /^se(?:t)?(?:\s([^=]+)(?:=(.*)$)?)?/) {
# :se[t] {option} {value}
if (defined $1 and defined $2) {
if (not exists $settings->{$1}) {
@@ -1911,11 +1930,15 @@ sub ex_set {
my $name = $1;
my $value = $2;
# Also accept numeric values for boolean options.
- if ($settings->{$name}->{type} == S_BOOL and
- $value !~ /^(on|off)$/) {
- $value = $value ? 'on' : 'off';
+ if ($settings->{$name}->{type} == S_BOOL) {
+ if ($value =~ /^(on|off)$/i) {
+ $value = lc $value eq 'on' ? 1 : 0;
+ } elsif ($value eq '') {
+ $value = 0;
+ }
}
- Irssi::command("set vim_mode_$name $value");
+ _setting_set($name, $value);
+ setup_changed();
# :se[t] [option]
} else {
@@ -2008,21 +2031,10 @@ sub vim_mode_cb {
$mode_str = '%_Ex%_';
} else {
$mode_str = '%_Command%_';
- 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;
- }
- if ($operator) {
- $mode_str .= $operator->{char};
- }
- if ($movement) {
- $mode_str .= $movement->{char};
- }
- $mode_str .= ')';
+ if ($partial_command) {
+ my $p_copy = $partial_command;
+ $p_copy =~ s/\\/\\\\\\\\/g;
+ $mode_str .= " ($p_copy)";
}
}
$sb_item->default_handler($get_size_only, "{sb $mode_str}", '', 0);
@@ -2238,6 +2250,7 @@ sub handle_command_cmd {
($char =~ m/[1-9]/ or ($numeric_prefix && $char =~ m/[0-9]/))) {
print "Processing numeric prefix: $char" if DEBUG;
handle_numeric_prefix($char);
+ $partial_command .= $char;
return 1; # call _stop()
}
@@ -2256,6 +2269,8 @@ sub handle_command_cmd {
} elsif (exists $maps->{$char}) {
$map = $maps->{$char};
+ $partial_command .= $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) {
@@ -2274,6 +2289,8 @@ sub handle_command_cmd {
} else {
print "No mapping found for $char" if DEBUG;
$pending_map = undef;
+ $numeric_prefix = undef;
+ $partial_command = '';
return 1; # call _stop()
}
@@ -2284,6 +2301,7 @@ sub handle_command_cmd {
# Make sure we have a valid $cmd.
if (not defined $cmd) {
print "Bug in pending_map_flushed() $map->{char}" if DEBUG;
+ $partial_command = '';
return 1; # call _stop()
}
@@ -2294,6 +2312,7 @@ sub handle_command_cmd {
$cmd->{func}->(substr($cmd->{char}, 1), $numeric_prefix);
$numeric_prefix = undef;
+ $partial_command = '';
return 1; # call _stop()
# As can irssi commands.
} elsif ($cmd->{type} == C_IRSSI) {
@@ -2301,12 +2320,14 @@ sub handle_command_cmd {
Irssi::command($cmd->{func});
$numeric_prefix = undef;
+ $partial_command = '';
return 1; # call _stop();
# <Nop> does nothing.
} elsif ($cmd->{type} == C_NOP) {
print "Processing <Nop>: $map->{char}" if DEBUG;
$numeric_prefix = undef;
+ $partial_command = '';
return 1; # call _stop();
}
@@ -2347,6 +2368,7 @@ sub handle_command_cmd {
$numeric_prefix = undef;
$operator = undef;
$movement = undef;
+ $partial_command = '';
# Set new operator.
} else {
$operator = $cmd;
@@ -2470,6 +2492,10 @@ sub handle_command_cmd {
$last->{movement} = $movement;
$last->{register} = $register;
}
+
+ if (!$cmd->{dont_clear_partial_keys}) {
+ $partial_command = '';
+ }
}
# Reset the count unless we go into insert mode, _update_mode() needs
@@ -2533,16 +2559,20 @@ sub vim_mode_init {
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);
- Irssi::settings_add_bool('vim_mode', 'vim_mode_utf8', 1);
- Irssi::settings_add_int('vim_mode', 'vim_mode_max_undo_lines', 50);
+ # Register all available settings.
+ foreach my $name (keys %$settings) {
+ _setting_register($name);
+ }
# Load the vim_moderc file if it exists.
ex_source('source');
setup_changed();
_reset_undo_buffer();
+
+ if ($settings->{start_cmd}->{value}) {
+ _update_mode(M_CMD);
+ }
}
sub setup_changed {
@@ -2551,7 +2581,7 @@ sub setup_changed {
if ($settings->{cmd_seq}->{value} ne '') {
delete $imaps->{$settings->{cmd_seq}->{value}};
}
- $value = Irssi::settings_get_str('vim_mode_cmd_seq');
+ $value = _setting_get('cmd_seq');
if ($value eq '') {
$settings->{cmd_seq}->{value} = $value;
} else {
@@ -2562,12 +2592,13 @@ sub setup_changed {
$settings->{cmd_seq}->{value} = $value;
} else {
_warn("Error: vim_mode_cmd_seq must be a single character");
+ # Restore the value so $settings and irssi settings are
+ # consistent.
+ _setting_set('cmd_seq', $settings->{cmd_seq}->{value});
}
}
- $settings->{debug}->{value} = Irssi::settings_get_bool('vim_mode_debug');
-
- my $new_utf8 = Irssi::settings_get_bool('vim_mode_utf8');
+ my $new_utf8 = _setting_get('utf8');
if ($new_utf8 != $settings->{utf8}->{value}) {
# recompile the patterns when switching to/from utf-8
$word = qr/[\w_]/o;
@@ -2580,15 +2611,20 @@ sub setup_changed {
"Please disable the vim_mode_utf8 setting.");
}
- $settings->{max_undo_lines}->{value}
- = Irssi::settings_get_int('vim_mode_max_undo_lines');
+ # Sync $settings with current irssi values.
+ foreach my $name (keys %$settings) {
+ # These were already handled above.
+ next if $name eq 'cmd_seq' or $name eq 'cmd_seq';
+
+ $settings->{$name}->{value} = _setting_get($name);
+ }
}
sub UNLOAD {
Irssi::signal_remove('gui key pressed' => \&got_key);
+ Irssi::signal_remove('setup changed' => \&setup_changed);
Irssi::statusbar_item_unregister ('vim_mode');
Irssi::statusbar_item_unregister ('vim_windows');
-
}
sub _add_undo_entry {
@@ -2733,6 +2769,9 @@ sub delete_map {
sub _commit_line {
_update_mode(M_INS);
_reset_undo_buffer('', 0);
+ # separate from call above as _update_mode() does additional internal work
+ # and we need to make sure it gets correctly called.
+ _update_mode(M_CMD) if $settings->{start_cmd}->{value};
}
sub _input {
@@ -2824,6 +2863,8 @@ sub _update_mode {
# 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};
+
+ $partial_command = '';
# Make sure prompt is cleared when leaving ex mode.
} elsif ($mode == M_EX and $new_mode != M_EX) {
_set_prompt('');
@@ -2843,6 +2884,7 @@ sub _update_mode {
$register = '"';
$pending_map = undef;
+ $partial_command = '';
# Also clear ex-mode buffer.
@ex_buf = ();
@@ -2855,9 +2897,65 @@ sub _set_prompt {
my $msg = shift;
# add a leading space unless we're trying to clear it entirely.
$msg = ' ' . $msg if length $msg;
+
+ # escape % symbols. This prevents any _set_prompt calls from using
+ # colouring sequences.
+ $msg =~ s/%/%%/g;
+
Irssi::signal_emit('change prompt', $msg, 'UP_INNER');
}
+sub _setting_get {
+ my ($name) = @_;
+
+ my $type = $settings->{$name}->{type};
+ $name = "vim_mode_$name";
+
+ if ($type == S_BOOL) {
+ return Irssi::settings_get_bool($name);
+ } elsif ($type == S_INT) {
+ return Irssi::settings_get_int($name);
+ } elsif ($type == S_STR) {
+ return Irssi::settings_get_str($name);
+ } else {
+ _warn("Unknown setting type '$type', please report.");
+ }
+ return undef;
+}
+sub _setting_set {
+ my ($name, $value) = @_;
+
+ my $type = $settings->{$name}->{type};
+ $name = "vim_mode_$name";
+
+ if ($type == S_BOOL) {
+ Irssi::settings_set_bool($name, $value);
+ } elsif ($type == S_INT) {
+ Irssi::settings_set_int($name, $value);
+ } elsif ($type == S_STR) {
+ Irssi::settings_set_str($name, $value);
+ } else {
+ _warn("Unknown setting type '$type', please report.");
+ }
+}
+sub _setting_register {
+ my ($name) = @_;
+
+ my $value = $settings->{$name}->{value};
+ my $type = $settings->{$name}->{type};
+ $name = "vim_mode_$name";
+
+ if ($type == S_BOOL) {
+ Irssi::settings_add_bool('vim_mode', $name, $value);
+ } elsif ($type == S_INT) {
+ Irssi::settings_add_int('vim_mode', $name, $value);
+ } elsif ($type == S_STR) {
+ Irssi::settings_add_str('vim_mode', $name, $value);
+ } else {
+ _warn("Unknown setting type '$type', please report.");
+ }
+}
+
sub _warn {
my ($warning) = @_;