aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vim-mode/vim_mode.pl416
1 files changed, 253 insertions, 163 deletions
diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl
index 65dba09..e1bc14e 100644
--- a/vim-mode/vim_mode.pl
+++ b/vim-mode/vim_mode.pl
@@ -611,7 +611,9 @@ our %IRSSI =
);
-# CONSTANTS
+################################################################
+# CONSTANTS #
+################################################################
# command mode
sub M_CMD () { 1 }
@@ -646,7 +648,10 @@ sub S_STR () { 2 }
my $word = qr/[\w_]/o;
my $non_word = qr/[^\w_\s]/o;
-# COMMANDS
+
+################################################################
+# COMMANDS #
+################################################################
# All available commands in command mode, they are stored with a char as key,
# but this is not necessarily the key the command is currently mapped to.
@@ -856,15 +861,18 @@ my $commands_ex
};
-# MAPPINGS
+################################################################
+# USER COMMAND MAPPINGS #
+################################################################
+
+# command mode mappings
+my $cmap = undef; # cmap still pending (contains first character entered)
+my $cmaps = {};
-# default command mode mappings
-my $maps = {};
-# current imap still pending (first character entered)
-my $imap = undef;
+# insert-mode mappings
-# maps for insert mode
+my $imap = undef; # imap still pending (contains first character entered)
my $imaps
= {
# CTRL-R, insert register
@@ -872,7 +880,10 @@ my $imaps
};
-# GLOBAL VARIABLES
+
+################################################################
+# CONFIGURABLE SETTINGS #
+################################################################
# all vim_mode settings, must be enabled in vim_mode_init() before usage
my $settings
@@ -900,6 +911,11 @@ my $settings
sub DEBUG { $settings->{debug}->{value} }
+
+################################################################
+# INTERNAL GLOBALS #
+################################################################
+
# buffer to keep track of the last N keystrokes, used for Esc detection and
# insert mode mappings
my @input_buf;
@@ -914,7 +930,6 @@ my $should_ignore = 0;
# ex mode buffer
my @ex_buf;
-
# ex mode history storage.
my @ex_history;
my $ex_history_index = 0;
@@ -930,6 +945,7 @@ my $operator = undef;
# vi movements, only used when a movement needs more than one key (like f t).
my $movement = undef;
# last vi command, used by .
+
my $last
= {
'cmd' => $commands->{i}, # = i to support . when loading the script
@@ -979,14 +995,19 @@ my @tab_candidates;
my $completion_active = 0;
my $completion_string = '';
+
+################################################################
+# START OF CODE #
+################################################################
+
sub script_is_loaded {
return exists($Irssi::Script::{shift(@_) . '::'});
}
-
-
-# INSERT MODE COMMANDS
+################################################################
+# INSERT MODE COMMANDS #
+################################################################
sub insert_ctrl_r {
my ($key) = @_;
@@ -1001,7 +1022,9 @@ sub insert_ctrl_r {
}
-# COMMAND MODE OPERATORS
+################################################################
+# COMMAND MODE OPERATORS #
+################################################################
sub cmd_operator_c {
my ($old_pos, $new_pos, $move_cmd, $repeat) = @_;
@@ -1099,7 +1122,9 @@ sub _get_pos_and_length {
return ($old_pos, $length);
}
-# COMMAND MODE COMMANDS
+################################################################
+# COMMAND MODE COMMANDS #
+################################################################
sub cmd_h {
my ($count, $pos, $repeat) = @_;
@@ -1985,7 +2010,9 @@ sub _fix_input_pos {
}
-# EX MODE COMMANDS
+################################################################
+# EX MODE COMMANDS #
+################################################################
sub cmd_ex_command {
my $arg_str = join '', @ex_buf;
@@ -2292,6 +2319,11 @@ sub ex_undolist {
_print_undo_buffer();
}
+
+################################################################
+# MAPPINGS MANIPULATION #
+################################################################
+
sub ex_map {
my ($arg_str, $count) = @_;
@@ -2350,8 +2382,8 @@ sub ex_map {
$search = _parse_mapping_reverse(_parse_mapping($search));
my $active_window = Irssi::active_win();
- foreach my $key (sort keys %$maps) {
- my $map = $maps->{$key};
+ foreach my $key (sort keys %$cmaps) {
+ my $map = $cmaps->{$key};
my $cmd = $map->{cmd};
if (defined $cmd) {
next if $map->{char} eq $cmd->{char}; # skip default mappings
@@ -2378,8 +2410,8 @@ sub ex_unmap {
if (not defined $lhs) {
return _warn_ex('unmap', 'invalid {lhs}');
# Prevent unmapping of unknown or default mappings.
- } elsif (not exists $maps->{$lhs} or not defined $maps->{$lhs}->{cmd} or
- ($commands->{$lhs} and $maps->{$lhs}->{cmd} == $commands->{$lhs})) {
+ } elsif (not exists $cmaps->{$lhs} or not defined $cmaps->{$lhs}->{cmd} or
+ ($commands->{$lhs} and $cmaps->{$lhs}->{cmd} == $commands->{$lhs})) {
return _warn_ex('unmap', "$1 not found");
}
@@ -2459,6 +2491,10 @@ sub _parse_partial_command_reverse {
return $string;
}
+################################################################
+# CONFIG COMMANDS #
+################################################################
+
sub ex_source {
my ($arg_str, $count) = @_;
@@ -2492,8 +2528,8 @@ sub ex_mkvimrc {
open my $file, '>', $vim_moderc or return;
# copied from ex_map()
- foreach my $key (sort keys %$maps) {
- my $map = $maps->{$key};
+ foreach my $key (sort keys %$cmaps) {
+ my $map = $cmaps->{$key};
my $cmd = $map->{cmd};
if (defined $cmd) {
next if $map->{char} eq $cmd->{char}; # skip default mappings
@@ -2547,8 +2583,80 @@ sub ex_set {
}
}
+################################################################
+# UTILITY FUNCTIONS #
+################################################################
+
+# input line bits and pieces
+
+sub _input {
+ my ($data) = @_;
+
+ my $current_data = Irssi::parse_special('$L', 0, 0);
+
+ if ($settings->{utf8}->{value}) {
+ $current_data = decode_utf8($current_data);
+ }
+
+ if (defined $data) {
+ if ($settings->{utf8}->{value}) {
+ Irssi::gui_input_set(encode_utf8($data));
+ } else {
+ Irssi::gui_input_set($data);
+ }
+ } else {
+ $data = $current_data;
+ }
+
+ return $data;
+}
+
+sub _input_len {
+ return length _input();
+}
+
+sub _input_pos {
+ my ($pos) = @_;
+ my $cur_pos = Irssi::gui_input_get_pos();
+ # my $dpos = defined $pos?$pos:'undef';
+ # my @call = caller(1);
+ # my $cfunc = $call[3];
+ # $cfunc =~ s/^.*?::([^:]+)$/$1/;
+ # print "pos called from line: $call[2] sub: $cfunc pos: $dpos, cur_pos: $cur_pos"
+ # if DEBUG;
+
+ if (defined $pos) {
+ #print "Input pos being set from $cur_pos to $pos" if DEBUG;
+ Irssi::gui_input_set_pos($pos) if $pos != $cur_pos;
+ } else {
+ $pos = $cur_pos;
+ #print "Input pos retrieved as $pos" if DEBUG;
+ }
+
+ return $pos;
+}
+
+sub _commit_line {
+ _update_mode(M_INS);
+
+ # 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};
+
+ _reset_undo_buffer('', 0);
+}
+
+# Error and warning messages
+
+sub _warn {
+ my ($format, @args) = @_;
+ my $str = sprintf($format, @args);
+ print '%_vim_mode: ', $str, '%_';
+}
+
sub _warn_ex {
my ($command, $description) = @_;
+
my $message = "Error in ex-mode command $command";
if (defined $description) {
$message .= ": $description";
@@ -2556,6 +2664,81 @@ sub _warn_ex {
_warn($message);
}
+sub _debug {
+ return unless DEBUG;
+
+ my ($format, @args) = @_;
+ my $str = sprintf($format, @args);
+ print $str;
+}
+
+sub _fatal {
+ my ($format, @args) = @_;
+ my $str = sprintf($format, @args);
+ die $str;
+
+}
+
+# uberprompt output.
+
+sub _set_prompt {
+ my $msg = shift;
+
+ # add a leading space unless we're trying to clear it entirely.
+ if (length($msg) and $settings->{prompt_leading_space}->{value}) {
+ $msg = ' ' . $msg;
+ }
+
+ # escape % symbols. This prevents any _set_prompt calls from using
+ # colouring sequences.
+ $msg =~ s/%/%%/g;
+
+ Irssi::signal_emit('change prompt', $msg, 'UP_INNER');
+}
+
+# signal handling
+
+sub _stop() {
+ Irssi::signal_stop_by_name('gui key pressed');
+}
+
+sub _emulate_keystrokes {
+ my @keys = @_;
+ $should_ignore = 1;
+ for my $key (@keys) {
+ Irssi::signal_emit('gui key pressed', $key);
+ }
+ $should_ignore = 0;
+}
+
+sub _command_with_context {
+ my ($command) = @_;
+ my $context;
+ my $window = Irssi::active_win;
+ if (defined $window) {
+ my $witem = $window->{active};
+ if (defined $witem and ref($witem) eq 'Irssi::Windowitem') {
+ $context = $witem;
+ } else {
+ $context = $window;
+ }
+ } else {
+ my $server = Irssi::active_server;
+ if (defined $server) {
+ $context = $server;
+ }
+ }
+ if (defined $context) {
+ print "Command $command Using context: " . ref($context) if DEBUG;
+ $context->command($command);
+ } else {
+ print "Command $command has no context" if DEBUG;
+ Irssi::command($command);
+ }
+}
+
+# buffer selection stuff
+
sub _matching_windows {
my ($buffer) = @_;
@@ -2606,9 +2789,10 @@ sub _matching_windows {
}
-# STATUS ITEMS
+################################################################
+# STATUSBAR ITEMS AND EXPANDOS #
+################################################################
-#TODO: give these things better names.
sub vim_mode_status_string {
my $mode_str = '';
@@ -2707,6 +2891,10 @@ sub _tab_complete {
return sort { $a cmp $b } @out;
}
+################################################################
+# INITIALISATION #
+################################################################
+
sub vim_mode_init {
Irssi::signal_add_first 'gui key pressed' => \&sig_gui_keypress;
@@ -2806,6 +2994,10 @@ sub UNLOAD {
Irssi::statusbar_item_unregister ('vim_windows');
}
+################################################################
+# UNDO MODEL #
+################################################################
+
sub _add_undo_entry {
my ($line, $pos) = @_;
@@ -2873,6 +3065,10 @@ sub _reset_undo_buffer {
$undo_index = 0;
}
+################################################################
+# MAPPING MODEL #
+################################################################
+
sub add_map {
my ($keys, $command) = @_;
@@ -2883,55 +3079,55 @@ sub add_map {
my $tmp = $keys;
while (length $tmp > 1) {
my $map = substr $tmp, -1, 1, '';
- if (not exists $maps->{$tmp}) {
- $maps->{$tmp} = { char => _parse_mapping_reverse($tmp),
+ if (not exists $cmaps->{$tmp}) {
+ $cmaps->{$tmp} = { char => _parse_mapping_reverse($tmp),
cmd => undef,
maps => {}
};
}
- if (not exists $maps->{$tmp}->{maps}->{$tmp . $map}) {
- $maps->{$tmp}->{maps}->{$tmp . $map} = undef;
+ if (not exists $cmaps->{$tmp}->{maps}->{$tmp . $map}) {
+ $cmaps->{$tmp}->{maps}->{$tmp . $map} = undef;
}
}
- if (not exists $maps->{$keys}) {
- $maps->{$keys} = { char => undef,
+ if (not exists $cmaps->{$keys}) {
+ $cmaps->{$keys} = { char => undef,
cmd => undef,
maps => {}
};
}
- $maps->{$keys}->{char} = _parse_mapping_reverse($keys);
- $maps->{$keys}->{cmd} = $command;
+ $cmaps->{$keys}->{char} = _parse_mapping_reverse($keys);
+ $cmaps->{$keys}->{cmd} = $command;
}
sub delete_map {
my ($keys) = @_;
# Abort for non-existent mappings or placeholder mappings.
- return if not exists $maps->{$keys} or not defined $maps->{$keys}->{cmd};
+ return if not exists $cmaps->{$keys} or not defined $cmaps->{$keys}->{cmd};
my @add = ();
# If no maps need the current key, then remove it and all other
# unnecessary keys in the "tree".
- if (keys %{$maps->{$keys}->{maps}} == 0) {
+ if (keys %{$cmaps->{$keys}->{maps}} == 0) {
my $tmp = $keys;
while (length $tmp > 1) {
my $map = substr $tmp, -1, 1, '';
- delete $maps->{$tmp}->{maps}->{$tmp . $map};
- if (not $maps->{$tmp}->{cmd} and keys %{$maps->{$tmp}->{maps}} == 0) {
+ delete $cmaps->{$tmp}->{maps}->{$tmp . $map};
+ if (not $cmaps->{$tmp}->{cmd} and keys %{$cmaps->{$tmp}->{maps}} == 0) {
push @add, $tmp;
- delete $maps->{$tmp};
+ delete $cmaps->{$tmp};
} else {
last;
}
}
}
- if (keys %{$maps->{$keys}->{maps}} > 0) {
- $maps->{$keys}->{cmd} = undef;
+ if (keys %{$cmaps->{$keys}->{maps}} > 0) {
+ $cmaps->{$keys}->{cmd} = undef;
} else {
- delete $maps->{$keys};
+ delete $cmaps->{$keys};
}
push @add, $keys;
@@ -2944,76 +3140,10 @@ sub delete_map {
}
}
+################################################################
+# MODE MODEL #
+################################################################
-sub _commit_line {
- _update_mode(M_INS);
-
- # 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};
-
- _reset_undo_buffer('', 0);
-}
-
-sub _input {
- my ($data) = @_;
-
- my $current_data = Irssi::parse_special('$L', 0, 0);
-
- if ($settings->{utf8}->{value}) {
- $current_data = decode_utf8($current_data);
- }
-
- if (defined $data) {
- if ($settings->{utf8}->{value}) {
- Irssi::gui_input_set(encode_utf8($data));
- } else {
- Irssi::gui_input_set($data);
- }
- } else {
- $data = $current_data;
- }
-
- return $data;
-}
-
-sub _input_len {
- return length _input();
-}
-
-sub _input_pos {
- my ($pos) = @_;
- my $cur_pos = Irssi::gui_input_get_pos();
- # my $dpos = defined $pos?$pos:'undef';
- # my @call = caller(1);
- # my $cfunc = $call[3];
- # $cfunc =~ s/^.*?::([^:]+)$/$1/;
- # print "pos called from line: $call[2] sub: $cfunc pos: $dpos, cur_pos: $cur_pos"
- # if DEBUG;
-
- if (defined $pos) {
- #print "Input pos being set from $cur_pos to $pos" if DEBUG;
- Irssi::gui_input_set_pos($pos) if $pos != $cur_pos;
- } else {
- $pos = $cur_pos;
- #print "Input pos retrieved as $pos" if DEBUG;
- }
-
- return $pos;
-}
-
-sub _emulate_keystrokes {
- my @keys = @_;
- $should_ignore = 1;
- for my $key (@keys) {
- Irssi::signal_emit('gui key pressed', $key);
- }
- $should_ignore = 0;
-}
-
-sub _stop() {
- Irssi::signal_stop_by_name('gui key pressed');
-}
sub _update_mode {
my ($new_mode) = @_;
@@ -3073,20 +3203,9 @@ sub _update_mode {
}
-sub _set_prompt {
- my $msg = shift;
-
- # add a leading space unless we're trying to clear it entirely.
- if (length($msg) and $settings->{prompt_leading_space}->{value}) {
- $msg = ' ' . $msg;
- }
-
- # escape % symbols. This prevents any _set_prompt calls from using
- # colouring sequences.
- $msg =~ s/%/%%/g;
-
- Irssi::signal_emit('change prompt', $msg, 'UP_INNER');
-}
+################################################################
+# SETTINGS MODEL #
+################################################################
sub _setting_get {
my ($name) = @_;
@@ -3143,45 +3262,7 @@ sub _setting_register {
}
}
-sub _warn {
- my ($warning) = @_;
- print '%_vim_mode: ', $warning, '%_';
-}
-
-sub _debug {
- return unless DEBUG;
-
- my ($format, @args) = @_;
- my $str = sprintf($format, @args);
- print $str;
-}
-
-sub _command_with_context {
- my ($command) = @_;
- my $context;
- my $window = Irssi::active_win;
- if (defined $window) {
- my $witem = $window->{active};
- if (defined $witem and ref($witem) eq 'Irssi::Windowitem') {
- $context = $witem;
- } else {
- $context = $window;
- }
- } else {
- my $server = Irssi::active_server;
- if (defined $server) {
- $context = $server;
- }
- }
- if (defined $context) {
- print "Command $command Using context: " . ref($context) if DEBUG;
- $context->command($command);
- } else {
- print "Command $command has no context" if DEBUG;
- Irssi::command($command);
- }
-}
sub ex_history_add {
my ($line) = @_;
@@ -3203,6 +3284,10 @@ sub ex_history_add {
}
}
+################################################################
+# EX HISTORY MODEL #
+################################################################
+
sub ex_history_fwd {
my $hist_max = $#ex_history;
@@ -3479,8 +3564,8 @@ sub handle_command_cmd {
maps => {},
};
- } elsif (exists $maps->{$char}) {
- $map = $maps->{$char};
+ } elsif (exists $cmaps->{$char}) {
+ $map = $cmaps->{$char};
# We have multiple mappings starting with this key sequence.
if (!$pending_map_flushed and scalar keys %{$map->{maps}} > 0) {
@@ -3770,6 +3855,11 @@ sub handle_command_ex {
_stop();
}
+################################################################
+# STARTUP #
+################################################################
vim_mode_init();
+
+__END__