summaryrefslogtreecommitdiffstats
path: root/scripts/typofix.pl
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/typofix.pl')
-rw-r--r--scripts/typofix.pl165
1 files changed, 165 insertions, 0 deletions
diff --git a/scripts/typofix.pl b/scripts/typofix.pl
new file mode 100644
index 0000000..49b312a
--- /dev/null
+++ b/scripts/typofix.pl
@@ -0,0 +1,165 @@
+# typofix.pl - when someone uses s/foo/bar typofixing, this script really
+# goes and modifies the original text on screen.
+
+use strict;
+use warnings;
+use Irssi qw(
+ settings_get_str settings_get_bool
+ settings_add_str settings_add_bool
+ signal_add signal_stop
+);
+use Irssi 20140701;
+use Irssi::TextUI;
+use Algorithm::Diff 'sdiff';
+
+our $VERSION = '1.12'; # 4be3787e5717715
+our %IRSSI = (
+ authors => 'Juerd (first version: Timo Sirainen, additions by: Qrczak)',
+ contact => 'tss@iki.fi, juerd@juerd.nl, qrczak@knm.org.pl',
+ name => 'Typofix',
+ description => 'When someone uses s/foo/bar/, this really modifies the text',
+ license => 'Same as Irssi',
+ url => 'http://juerd.nl/irssi/',
+ changed => 'Sat Jun 28 16:24:26 CEST 2014',
+ upgrade_info => '/set typofix_modify_string %wold%gnew%n',
+ NOTE1 => 'you need irssi 0.8.17'
+);
+
+# /SET typofix_modify_string [fixed] - append string after replaced text
+# /SET typofix_hide_replace NO - hide the s/foo/bar/ line
+# (J) /SET typofix_format - format with "old" and "new" in it
+
+
+my $chars = '/|;:\'"_=+*&^%$#@!~,.?-';
+my $regex = qq{(?x-sm: # "s/foo/bar/i # oops"
+ \\s* # Optional whitespace
+ s # Substitution operator s
+ ([$chars]) # Delimiter /
+ ( (?: \\\\. | (?!\\1). )* ) # Pattern foo
+ # Backslash plus any char, or a single non-delimiter char
+ \\1 # Delimiter /
+ ( (?: \\\\. | (?!\\1). )* ) # Replacementstring bar
+ \\1? # Optional delimiter /
+ ([a-z]*) # Modifiers i
+ \\s* # Optional whitespace
+ (.?) # Don't hide if there's more # oops
+)};
+my $irssi_mumbo = qr/\cD[`-i]|\cD[&-@\xff]./;
+my $irssi_mumbo_no_partial = qr/(?<!\cD)(?<!\cD[&-@\xff])/;
+
+sub replace {
+ my ($window, $nick, $from, $to, $opt, $screen) = @_;
+
+ my $view = $window->view();
+ my $line = $screen ? $view->{bottom_startline} : $view->{startline};
+
+ my $last_line;
+ (my $copy = $from) =~ s/\^|^/^.*\\b$nick\\b.*?\\s.*?/;
+ while ($line) {
+ my $text = $line->get_text(0);
+ eval {
+ $last_line = $line
+ if ($line->{info}{level} & (MSGLEVEL_PUBLIC | MSGLEVEL_MSGS)) &&
+ $text !~ /$regex/o && $text =~ /$copy/;
+ 1
+ } or return;
+ $line = $line->next();
+ }
+ return 0 if (!$last_line);
+ my $text = $last_line->get_text(1);
+
+ # variables and case insensitivity
+ $from = "(?i:$from)" if $opt =~ /i/;
+ $to = quotemeta $to;
+ $to =~ s{\\\\\\(.)|\\(.)([1-9])?}{
+ if (defined $1) {
+ "\\$1"
+ } elsif (defined $3 && ($2 eq "\\" || $2 eq "\$")) {
+ "\$$3"
+ } else {
+ "\\$2".($3//"")
+ } }ge;
+
+ # text replacing
+ $text =~ s/(.*(?:\b|$irssi_mumbo)$irssi_mumbo_no_partial$nick(?:\b|$irssi_mumbo).*?\s)//;
+ my $pre = $1;
+ $text =~ s/$irssi_mumbo//g;
+ my $format = settings_get_str('typofix_format');
+ $format =~ s/old/\0\cA/;
+ $format =~ s/new/\0\cB/;
+ $format =~ s/%/\0\cC/g;
+
+ my $old = $text;
+ eval " \$text =~ s/\$from/$to/".($opt =~ /g/ ? "g" : "")." ; 1 "
+ or Irssi::print "Typofix warning: $@", return 0;
+ my $new = '';
+ my $diff = Algorithm::Diff->new([split//,$old],[split//,$text]);
+ while ($diff->Next()) {
+ local $" = '';
+ if (my @it = $diff->Same()) {
+ $new .= "@it";
+ }
+ else {
+ my %r = ("\cA" => [ $diff->Items(1) ],
+ "\cB" => [ $diff->Items(2) ]);
+ my $format_st = $format;
+ $format_st =~ s/\0([\cA\cB])/@{$r{$1}}/g;
+ $new .= $format_st;
+ }
+ }
+ s/%/%%/g for $pre, $new;
+ s/\0\cC/%/g for $new;
+ $text = $pre . $new . settings_get_str('typofix_modify_string');
+
+ my $bottom = $view->{bottom};
+ my $info = $last_line->{info};
+ $window->print_after($last_line, $info->{level}, $text, $info->{time});
+ $view->remove_line($last_line);
+ $window->command('^scrollback end') if $bottom && !$window->view->{bottom};
+ $view->redraw();
+
+ return 1;
+}
+
+sub event_privmsg {
+ my ($server, $data, $nick, $address) = @_;
+ my ($target, $text) = $data =~ /^(\S*)\s:(.*)/ or return;
+
+ return unless $text =~ /^$regex/o;
+ my ($from, $to, $opt, $extra) = ($2, $3, $4, $5);
+
+ my $hide = settings_get_bool('typofix_hide_replace') && !$extra;
+
+ my $ischannel = $server->ischannel($target);
+ my $level = $ischannel ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS;
+
+ $target = $nick unless $ischannel;
+ my $window = $server->window_find_closest($target, $level);
+
+ signal_stop() if (replace($window, $nick, $from, $to, $opt, 0) && $hide);
+}
+
+sub event_own_public {
+ my ($server, $text, $target) = @_;
+
+ return unless $text =~ /^$regex/o;
+ my ($from, $to, $opt, $extra) = ($2, $3, $4, $5);
+
+ my $hide = settings_get_bool('typofix_hide_replace') && !$extra;
+ $hide = 0 if settings_get_bool('typofix_own_no_hide');
+
+ my $level = $server->ischannel($target) ? MSGLEVEL_MSGS : MSGLEVEL_PUBLIC;
+ my $window = $server->window_find_closest($target, $level);
+
+ signal_stop() if (replace($window, $server->{nick}, $from, $to, $opt, 0) && $hide);
+}
+
+settings_add_str ('typofix', 'typofix_modify_string', ' [fixed]');
+settings_add_str ('typofix', 'typofix_format', '%rold%gnew%n');
+settings_add_bool('typofix', 'typofix_hide_replace', 0);
+settings_add_bool('typofix', 'typofix_own_no_hide', 0);
+
+signal_add {
+ 'event privmsg' => \&event_privmsg,
+ 'message own_public' => \&event_own_public
+};