From: Ailin Nemui Date: Thu, 22 Oct 2020 14:55:25 +0000 (+0200) Subject: add partial script X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=2d2703a8a333552258a97bcf69392bd90347170f;p=irssi-scripts.irssi.org.git add partial script a script for partial tab completion in Irssi --- diff --git a/scripts/partial.pl b/scripts/partial.pl new file mode 100644 index 0000000..8f5508d --- /dev/null +++ b/scripts/partial.pl @@ -0,0 +1,222 @@ +use strict; +use warnings; +use experimental 'signatures'; + +our $VERSION = '0.3'; # 90d307aaaf70a32 +our %IRSSI = ( + authors => 'Nei', + contact => 'Nei @ anti@conference.jabber.teamidiot.de', + url => "http://anti.teamidiot.de/", + name => 'partial', + description => 'partial tab completion for Irssi', + license => 'ISC', + ); + +# Usage +# ===== +# Complete only as many characters as uniquely possible while using +# tab completion. +# + +# If you disable completion_default_partial, you can bind another key +# to invoke partial completion: +# +# /bind meta-/ /script exec Irssi::Script::partial::partial_word_completion +# +# If you want to have another key to do regular completion, while +# completion_default_partial is enabled: +# +# /bind meta-/ /script exec Irssi::Script::partial::word_completion +# +# Note: you cannot change completion mode in the middle of an ongoing +# completion! Your completion key will continue to operate in the way +# that it was initiated with. + +# Options +# ======= +# /set completion_default_partial +# * If the default tab completion should use partial +# +# /set completion_suggest_partial +# * If partial completions should be suggested when you continue to +# press the completion key +# +# /set completion_partial_display +# * If partial completions should be printed to the window +# +# /set completion_partial_display_max +# * Maximum number of partial completions allowed inside one display +# item + +# For another implementation of the same idea, check +# https://github.com/aquanight/codejunk/blob/master/perl/irssi/bash_tab.pl + +use Tree::Trie; +use List::Util qw(min pairvalues); + +use Irssi; + +my $completing = 0; +my $suggest_partial; +my $partial_display; +my $partial_threshold; + +our $partial_complete; + +sub complete_to ($trie, $word) { + my @next = map { + if ($partial_threshold < 0 || $trie->lookup("$word$_") < $partial_threshold) { + [ $_, 1 ] + } else { + my $x = $_; + map { [ "$x$_", 2 ] } $trie->lookup("$word$_", 1) + } + } $trie->lookup($word, 1); + + for my $n (@next) { + my @nn = $trie->lookup("$word$n->[0]", 1); + if (@nn == 1 && length $nn[0]) { + $n->[0] .= $nn[0]; + redo; + } + } + sort { (min pairvalues $trie->lookup_data("$word$a->[0]") ) <=> (min pairvalues $trie->lookup_data("$word$b->[0]") ) } + @next +} + +sub clear_partial_sug ($win, $view) { + my $line = $view->get_bookmark('partial'); + if (defined $line) { + my $bottom = $view->{bottom}; + $view->remove_line($line); + $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; + $view->redraw; + } +} + +sub _show ($trie, $pre, $post) { + return $pre unless length $post->[0]; + + my $w1 = "$pre\cB" . (substr $post->[0], 0, $post->[1]) . "\cB" . substr $post->[0], $post->[1]; + my $c = $trie->lookup("$pre$post->[0]"); + if ($c > 1) { + $w1 .= "…($c)"; + } + $w1 +} + +sub print_next ($trie, $word, @next) { + my $win = Irssi::active_win; + my $view = $win->view; + + unless (@next) { + clear_partial_sug($win, $view); + return; + } + + my $sug = join ' ', map { _show($trie, $word, $_) } + @next; + $win->print($sug); + clear_partial_sug($win, $view); + $view->set_bookmark_bottom('partial'); +} + +sub key_partial_clear { + my $win = Irssi::active_win; + clear_partial_sug($win, $win->view); + $completing = 0; +} + +sub key_partial_complete_stop { + $completing = 0; +} + +sub key_clear_completions { + return if $completing; + local our $clear_completions = 1; + Irssi::signal_emit('key word_completion', '', $_[1], $_[2]) +} + +sub partial_complete ($list, $window, $word, $linestart, $want_space) { + $completing = 1; + + if (our $clear_completions) { + @$list = (); + Irssi::signal_stop; + return; + } + + if (!our $partial_complete) { + return; + } + + &Irssi::signal_continue; + + if (@$list > 1) { + my $trie = Tree::Trie->new; + $trie->deepsearch('count'); + my $idx = 1; + $trie->add_data(map { ( $_, $idx++ ) } @$list); + my @next = complete_to($trie, $word); + if (@next == 1) { + $word = "$word$next[0][0]"; + @$list = $word; + @next = complete_to($trie, $word); + $$want_space = 0 + if @next; + } + else { + if ($suggest_partial) { + @$list = ($word, map { "$word$_->[0]" } @next); + $$want_space = 0; + } + else { + @$list = (); + } + } + print_next($trie, $word, @next) + if $partial_display; + } +} + +sub partial_word_completion { + local our $partial_complete = 1; + Irssi::signal_emit('key word_completion', '', 0, undef); +} + +sub partial_word_completion_backward { + local our $partial_complete = 1; + Irssi::signal_emit('key word_completion_backward', '', 0, undef); +} + +sub word_completion { + local our $partial_complete = 0; + Irssi::signal_emit('key word_completion', '', 0, undef); +} + +sub word_completion_backward { + local our $partial_complete = 0; + Irssi::signal_emit('key word_completion_backward', '', 0, undef); +} + +sub init_partial { + $partial_complete = Irssi::settings_get_bool('completion_default_partial'); + $suggest_partial = Irssi::settings_get_bool('completion_suggest_partial'); + $partial_display = Irssi::settings_get_bool('completion_partial_display'); + $partial_threshold = Irssi::settings_get_int('completion_partial_display_max'); +} + +Irssi::settings_add_bool('completion', 'completion_suggest_partial', 1); +Irssi::settings_add_bool('completion', 'completion_default_partial', 1); +Irssi::settings_add_bool('completion', 'completion_partial_display', 1); +Irssi::settings_add_int('completion', 'completion_partial_display_max', 40); + +Irssi::signal_register({ "key " => [qw[string ulongptr Irssi::UI::Keyinfo]] }); + +Irssi::signal_add_first('complete word', 'partial_complete'); +Irssi::signal_add_first('key backspace', 'key_clear_completions'); +Irssi::signal_add('key check_replaces', 'key_partial_complete_stop'); +Irssi::signal_add('key send_line', 'key_partial_clear'); +Irssi::signal_add('setup changed', 'init_partial'); + +init_partial();