commit 0549e25928e11882f868b285ff071fcaf798df65
Author: GasparVardanyan <[email protected]>
Date:   Mon Mar 14 03:26:22 2022 +0400

    [st][patch][autocomplete] first production release

diff --git a/st.suckless.org/patches/autocomplete/index.md 
b/st.suckless.org/patches/autocomplete/index.md
index 04ef9258..d98a3bfc 100644
--- a/st.suckless.org/patches/autocomplete/index.md
+++ b/st.suckless.org/patches/autocomplete/index.md
@@ -71,12 +71,7 @@ along with this program.  If not, see 
<http://www.gnu.org/licenses/>.
 
 Download
 --------
-This patch is under testing phase:
-* 
[st-autocomplete-20211215-181216-st-0.8.4-testrelease.diff](st-autocomplete-20211215-181216-st-0.8.4-testrelease.diff)
-* 
[st-autocomplete-20211216-221700-st-0.8.4-testrelease.diff](st-autocomplete-20211216-221700-st-0.8.4-testrelease.diff)
-* 
[st-autocomplete-20211218-131244-st-0.8.4-testrelease.diff](st-autocomplete-20211218-131244-st-0.8.4-testrelease.diff)
-* 
[st-autocomplete-20220110-234714-st-0.8.4-testrelease.diff](st-autocomplete-20220110-234714-st-0.8.4-testrelease.diff)
-* 
[st-0.8.5-autocomplete-20220313-024831-testrelease.diff](st-0.8.5-autocomplete-20220313-024831-testrelease.diff)
 (the freezing bug was fixed!)
+* 
[st-0.8.5-autocomplete-20220314-032311.diff](st-0.8.5-autocomplete-20220314-032311.diff)
 
 Contribution
 ------------
diff --git 
a/st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220313-024831-testrelease.diff
 
b/st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220314-032311.diff
similarity index 88%
rename from 
st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220313-024831-testrelease.diff
rename to 
st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220314-032311.diff
index e3105941..665b20ef 100644
--- 
a/st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220313-024831-testrelease.diff
+++ 
b/st.suckless.org/patches/autocomplete/st-0.8.5-autocomplete-20220314-032311.diff
@@ -76,11 +76,11 @@ diff -uraN st-0.8.5/Makefile st-autocomplete/Makefile
  .PHONY: all options clean dist install uninstall
 diff -uraN st-0.8.5/st-autocomplete st-autocomplete/st-autocomplete
 --- st-0.8.5/st-autocomplete   1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/st-autocomplete    2022-03-13 02:45:53.503785745 +0400
-@@ -0,0 +1,302 @@
++++ st-autocomplete/st-autocomplete    2022-03-14 03:23:02.995498786 +0400
+@@ -0,0 +1,292 @@
 +#!/usr/bin/perl
 +#########################################################################
-+# Copyright (C) 2012-2021  Wojciech Siewierski, Gaspar Vardanyan        #
++# Copyright (C) 2012-2017  Wojciech Siewierski                          #
 +#                                                                       #
 +# This program is free software: you can redistribute it and/or modify  #
 +# it under the terms of the GNU General Public License as published by  #
@@ -98,6 +98,31 @@ diff -uraN st-0.8.5/st-autocomplete 
st-autocomplete/st-autocomplete
 +
 +my ($cmd, $cursor_row, $cursor_column) = @ARGV;
 +
++my $lines = [];
++
++my $last_line = -1;
++my $lines_after_cursor = 0;
++
++while (<stdin>)
++{
++      $last_line++;
++
++      if ($last_line <= $cursor_row)
++      {
++              push @{$lines}, $_;
++      }
++      else
++      {
++              unshift @{$lines}, $_;
++              $lines_after_cursor++;
++      }
++}
++
++$cursor_row = $last_line;
++
++
++$self = {};
++
 +# A reference to a function that transforms the completed word
 +# into a regex matching the completions. Usually generated by
 +# generate_matcher().
@@ -182,58 +207,117 @@ diff -uraN st-0.8.5/st-autocomplete 
st-autocomplete/st-autocomplete
 +      $char_class_to_complete = '\S';
 +}
 +
-+my $lines = [];
 +
-+my $last_line = -1;
-+my $lines_after_cursor = 0;
++# use the last used word or read the word behind the cursor
++my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column,
++                                                                              
  $char_class_to_complete);
 +
-+while (<STDIN>)
-+{
-+      $last_line++;
++print stdout "$word_to_complete
";
 +
-+      if ($last_line <= $cursor_row)
++if ($word_to_complete) {
++      while (1) {
++              # ignore the completed word itself
++              $self->{already_completed}{$word_to_complete} = 1;
++
++              # continue the last search or start from the current row
++              my $completion = find_match($self,
++                                                                      
$word_to_complete,
++                                                                      
$self->{next_row} // $cursor_row,
++                                                                      
$matcher->($word_to_complete),
++                                                                      
$char_class_before,
++                                                                      
$char_class_at_end);
++              if ($completion) {
++                      # save the last completed word unless continuing the 
last search
++                      highlight_match($self,
++                                                      $self->{next_row}+1,
++                                                      $completion);
++
++                      print stdout $completion." ".join (" ", 
@{$self->{highlight}})."
";
++              }
++              else {
++                      last;
++              }
++      }
++}
++
++######################################################################
++
++sub highlight_match {
++    my ($self, $linenum, $completion) = @_;
++
++    # clear_highlight($self);
++
++    my $line = @{$lines}[$linenum];
++    my $re = quotemeta $completion;
++
++    $line =~ /$re/;
++
++    my $beg = $-[0];
++    my $end = $+[0];
++
++      if ($linenum >= $lines_after_cursor)
 +      {
-+              push @{$lines}, $_;
++              $linenum -= $lines_after_cursor;
 +      }
 +      else
 +      {
-+              unshift @{$lines}, $_;
-+              $lines_after_cursor++;
++              $linenum = $last_line - $linenum;
 +      }
++
++
++    $self->{highlight} = [$linenum, $beg, $end];
 +}
 +
-+$cursor_row = $last_line;
++######################################################################
 +
-+# read the word behind the cursor
-+$_ = substr(@{$lines} [$cursor_row], 0, $cursor_column); # get the current 
line up to the cursor...
-+s/.*?($char_class_to_complete*)$/$1/;                 # ...and read the last 
word from it
-+my $word_to_complete = $_;
++sub read_word_at_coord {
++    my ($self, $row, $col, $char_class) = @_;
 +
-+# ignore the completed word itself
-+$self->{already_completed}{$word_to_complete} = 1;
++    $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the 
cursor...
++    s/.*?($char_class*)$/$1/;               # ...and read the last word from 
it
++    return $_;
++}
 +
-+print stdout "$word_to_complete
";
++######################################################################
 +
-+# search for matches
-+if ($word_to_complete)
-+{
-+      while (my $completion = find_match($self,
-+                                        $word_to_complete,
-+                                        $self->{next_row} // $cursor_row,
-+                                        $matcher->($word_to_complete),
-+                                        $char_class_before,
-+                                        $char_class_at_end)
-+      ) {
-+              calc_match_coords($self,
-+                                              $self->{next_row}+1,
-+                                              $completion);
-+              print stdout "$completion @{$self->{highlight}}
";
-+      }
++# Returns a function that takes a string and returns that string with
++# this function's argument inserted between its every two characters.
++# The resulting string is used as a regular expression matching the
++# completion candidates.
++sub generate_matcher {
++    my $regex_between = shift;
 +
-+      leave($self);
++    sub {
++        $_ = shift;
++
++        # sorry for this lispy code, I couldn't resist ;)
++        (join "$regex_between",
++         (map quotemeta,
++          (split //)))
++    }
 +}
 +
++######################################################################
++
++# Checks whether the completion found by find_match() was already
++# found and if it was, calls find_match() again to find the next
++# completion.
++#
++# Takes all the arguments that find_match() would take, to make a
++# mutually recursive call.
++sub skip_duplicates {
++    my $self = $_[0];
++    my $completion = shift @{$self->{matches_in_row}}; # get the rightmost one
 +
++    # check for duplicates
++    if (exists $self->{already_completed}{$completion}) {
++        # skip this completion
++        return find_match(@_);
++    } else {
++        $self->{already_completed}{$completion} = 1;
++        return $completion;
++    }
++}
 +
 +######################################################################
 +
@@ -252,11 +336,11 @@ diff -uraN st-0.8.5/st-autocomplete 
st-autocomplete/st-autocomplete
 +    my $i;
 +    # search through all the rows starting with current one or one above the 
last checked
 +    for ($i = $current_row; $i >= 0; --$i) {
-+        my $line = @{$lines} [$i];   # get the line of text from the row
++        my $line = @{$lines}[$i];   # get the line of text from the row
 +
-+        if ($i == $cursor_row) {
-+            $line = substr $line, 0, $cursor_column;
-+        }
++        # if ($i == $cursor_row) {
++        #     $line = substr $line, 0, $cursor_column;
++        # }
 +
 +        $_ = $line;
 +
@@ -281,108 +365,14 @@ diff -uraN st-0.8.5/st-autocomplete 
st-autocomplete/st-autocomplete
 +        }
 +    }
 +
-+    # no more possible completions, revert to the original word
-+    $self->{next_row} = -1 if $i < 0;
++    # # no more possible completions, revert to the original word
++    # undo_completion($self) if $i < 0;
 +
 +    return undef;
 +}
-+
-+######################################################################
-+
-+# Checks whether the completion found by find_match() was already
-+# found and if it was, calls find_match() again to find the next
-+# completion.
-+#
-+# Takes all the arguments that find_match() would take, to make a
-+# mutually recursive call.
-+sub skip_duplicates {
-+    my $self = $_[0];
-+      my $current_row = $_[2];
-+      my $completion;
-+      if ($current_row >= $lines_after_cursor)
-+      {
-+              $completion = shift @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+      else
-+      {
-+              $completion = pop @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+
-+    # check for duplicates
-+    if (exists $self->{already_completed}{$completion}) {
-+        # skip this completion
-+        return find_match(@_);
-+    } else {
-+        $self->{already_completed}{$completion} = 1;
-+        return $completion;
-+    }
-+}
-+
-+######################################################################
-+
-+# Returns a function that takes a string and returns that string with
-+# this function's argument inserted between its every two characters.
-+# The resulting string is used as a regular expression matching the
-+# completion candidates.
-+sub generate_matcher {
-+    my $regex_between = shift;
-+
-+    sub {
-+        $_ = shift;
-+
-+        # sorry for this lispy code, I couldn't resist ;)
-+        (join "$regex_between",
-+         (map quotemeta,
-+          (split //)))
-+    }
-+}
-+
-+######################################################################
-+
-+sub calc_match_coords {
-+    my ($self, $linenum, $completion) = @_;
-+
-+    my $line = @{$lines} [$linenum];
-+    my $re = quotemeta $completion;
-+
-+    $line =~ /$re/;
-+
-+      #my ($beg_row, $beg_col) = $line->coord_of($-[0]);
-+      #my ($end_row, $end_col) = $line->coord_of($+[0]);
-+      my $beg = $-[0];
-+      my $end = $+[0];
-+
-+    if (exists $self->{highlight}) {
-+        delete $self->{highlight};
-+    }
-+    # () # TODO: what does () do in perl ????
-+
-+      if ($linenum >= $lines_after_cursor)
-+      {
-+              $linenum -= $lines_after_cursor;
-+      }
-+      else
-+      {
-+              $linenum = $last_line - $linenum;
-+      }
-+
-+    # $self->{highlight} = [$beg_row, $beg_col, $end_row, $end_col];
-+    $self->{highlight} = [$linenum, $beg, $end];
-+}
-+
-+######################################################################
-+
-+sub leave {
-+    my ($self) = @_;
-+
-+    delete $self->{next_row};
-+    delete $self->{matches_in_row};
-+    delete $self->{already_completed};
-+    delete $self->{highlight};
-+}
 diff -uraN st-0.8.5/st.c st-autocomplete/st.c
 --- st-0.8.5/st.c      2022-03-13 02:45:34.586842452 +0400
-+++ st-autocomplete/st.c       2022-03-13 02:45:34.586842452 +0400
++++ st-autocomplete/st.c       2022-03-14 03:23:02.995498786 +0400
 @@ -17,6 +17,7 @@
  #include <unistd.h>
  #include <wchar.h>
@@ -400,7 +390,7 @@ diff -uraN st-0.8.5/st.c st-autocomplete/st.c
        /*
         * slide screen to keep cursor where we expect it -
         * tscrollup would work here, but we can optimize to
-@@ -2688,3 +2691,241 @@
+@@ -2688,3 +2691,250 @@
        tfulldirt();
        draw();
  }
@@ -631,16 +621,25 @@ diff -uraN st-0.8.5/st.c st-autocomplete/st.c
 +                      tl++;
 +              }
 +
-+// Read the new completion and autcomplete
++// Autcomplete
++
++      complen_prev = strlen (completion);
++      ttywrite (completion, complen_prev, 0);
++
++      if (line == cy && beg > cx)
++      {
++              beg += complen_prev - targetlen;
++              end += complen_prev - targetlen;
++
++              // ACMPL_ISSUE: highlignthing doesn't work when "line == cy && 
beg > cx",
++              //                              but coordinates are correct...
++      }
 +
 +      end--;
 +
 +      selstart (beg, line + wl, 0);
 +      selextend (end % term.col, line + wl + end / term.col, 1, 0);
 +      xsetsel (getsel ());
-+
-+      complen_prev = strlen (completion);
-+      ttywrite (completion, complen_prev, 0);
 +}
 diff -uraN st-0.8.5/st.h st-autocomplete/st.h
 --- st-0.8.5/st.h      2022-03-13 02:45:34.586842452 +0400
diff --git 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211215-181216-st-0.8.4-testrelease.diff
 
b/st.suckless.org/patches/autocomplete/st-autocomplete-20211215-181216-st-0.8.4-testrelease.diff
deleted file mode 100644
index c41506f4..00000000
--- 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211215-181216-st-0.8.4-testrelease.diff
+++ /dev/null
@@ -1,601 +0,0 @@
-diff -uraN st-0.8.4/autocomplete.h st-autocomplete/autocomplete.h
---- st-0.8.4/autocomplete.h    1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/autocomplete.h     2021-12-14 20:20:03.322050025 +0400
-@@ -0,0 +1,16 @@
-+# ifndef __ST_AUTOCOMPLETE_H
-+# define __ST_AUTOCOMPLETE_H
-+
-+enum {
-+      ACMPL_DEACTIVATE,
-+      ACMPL_WORD,
-+      ACMPL_WWORD,
-+      ACMPL_FUZZY_WORD,
-+      ACMPL_FUZZY_WWORD,
-+      ACMPL_FUZZY,
-+      ACMPL_SUFFIX,
-+      ACMPL_SURROUND,
-+      ACMPL_UNDO,
-+};
-+
-+# endif // __ST_AUTOCOMPLETE_H
-diff -uraN st-0.8.4/config.def.h st-autocomplete/config.def.h
---- st-0.8.4/config.def.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/config.def.h       2021-12-14 20:22:30.088821478 +0400
-@@ -168,6 +168,8 @@
-  */
- static uint forcemousemod = ShiftMask;
- 
-+# include "autocomplete.h"
-+
- /*
-  * Internal mouse shortcuts.
-  * Beware that overloading Button1 will disable the selection.
-@@ -199,6 +201,14 @@
-       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
-       { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
-       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
-+      { ControlMask|Mod1Mask, XK_slash,       autocomplete,   { .i = 
ACMPL_WORD        } },
-+      { ControlMask|Mod1Mask, XK_period,      autocomplete,   { .i = 
ACMPL_FUZZY_WORD  } },
-+      { ControlMask|Mod1Mask, XK_comma,       autocomplete,   { .i = 
ACMPL_FUZZY       } },
-+      { ControlMask|Mod1Mask, XK_apostrophe,  autocomplete,   { .i = 
ACMPL_SUFFIX      } },
-+      { ControlMask|Mod1Mask, XK_semicolon,   autocomplete,   { .i = 
ACMPL_SURROUND    } },
-+      { ControlMask|Mod1Mask, XK_bracketright,autocomplete,   { .i = 
ACMPL_WWORD       } },
-+      { ControlMask|Mod1Mask, XK_bracketleft, autocomplete,   { .i = 
ACMPL_FUZZY_WWORD } },
-+      { ControlMask|Mod1Mask, XK_equal,       autocomplete,   { .i = 
ACMPL_UNDO        } },
- };
- 
- /*
-diff -uraN st-0.8.4/Makefile st-autocomplete/Makefile
---- st-0.8.4/Makefile  2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/Makefile   2021-12-15 07:12:40.291573671 +0400
-@@ -44,6 +44,8 @@
-       mkdir -p $(DESTDIR)$(PREFIX)/bin
-       cp -f st $(DESTDIR)$(PREFIX)/bin
-       chmod 755 $(DESTDIR)$(PREFIX)/bin/st
-+      cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
-+      chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       mkdir -p $(DESTDIR)$(MANPREFIX)/man1
-       sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
-       chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
-@@ -52,6 +54,7 @@
- 
- uninstall:
-       rm -f $(DESTDIR)$(PREFIX)/bin/st
-+      rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
- 
- .PHONY: all options clean dist install uninstall
-diff -uraN st-0.8.4/st-autocomplete st-autocomplete/st-autocomplete
---- st-0.8.4/st-autocomplete   1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/st-autocomplete    2021-12-14 20:18:13.171971360 +0400
-@@ -0,0 +1,266 @@
-+#!/usr/bin/perl
-+#########################################################################
-+# Copyright (C) 2012-2021  Wojciech Siewierski, Gaspar Vardanyan        #
-+#                                                                       #
-+# This program is free software: you can redistribute it and/or modify  #
-+# it under the terms of the GNU General Public License as published by  #
-+# the Free Software Foundation, either version 3 of the License, or     #
-+# (at your option) any later version.                                   #
-+#                                                                       #
-+# This program is distributed in the hope that it will be useful,       #
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of        #
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
-+# GNU General Public License for more details.                          #
-+#                                                                       #
-+# You should have received a copy of the GNU General Public License     #
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>. #
-+#########################################################################
-+
-+my ($cmd, $cursor_row, $cursor_column) = @ARGV;
-+
-+# A reference to a function that transforms the completed word
-+# into a regex matching the completions. Usually generated by
-+# generate_matcher().
-+#
-+# For example
-+#   $fun = generate_matcher(".*");
-+#   $fun->("foo");
-+# would return "f.*o.*o"
-+#
-+# In other words, indirectly decides which characters can
-+# appear in the completion.
-+my $matcher;
-+
-+# A regular expression matching a character before each match.
-+# For example, it you want to match the text after a
-+# whitespace, set it to "\s".
-+my $char_class_before;
-+
-+# A regular expression matching every character in the entered
-+# text that will be used to find matching completions. Usually
-+# "\w" or similar.
-+my $char_class_to_complete;
-+
-+# A regular expression matching every allowed last character
-+# of the completion (uses greedy matching).
-+my $char_class_at_end;
-+
-+if ($cmd eq 'word-complete') {
-+      # Basic word completion. Completes the current word
-+      # without any special matching.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = sub { quotemeta shift }; # identity
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'WORD-complete') {
-+      # The same as above but in the Vim meaning of a "WORD" --
-+      # whitespace delimited.
-+      $char_class_before      = '\s';
-+      $matcher                = sub { quotemeta shift };
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-word-complete' ||
-+               $cmd eq 'skeleton-word-complete') {
-+      # Fuzzy completion of the current word.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = generate_matcher('[-\w]*');
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'fuzzy-WORD-complete') {
-+      # Fuzzy completion of the current WORD.
-+      $char_class_before      = '\s';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-complete' ||
-+               $cmd eq 'skeleton-complete') {
-+      # Fuzzy completion of an arbitrary text.
-+      $char_class_before      = '\W';
-+      $matcher                = generate_matcher('.*?');
-+      $char_class_at_end      = '\w';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'suffix-complete') {
-+      # Fuzzy completion of an completing suffixes, like
-+      # completing test=hello from /blah/hello.
-+      $char_class_before      = '\S';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'surround-complete') {
-+      # Completing contents of quotes and braces.
-+
-+      # Here we are using three named groups: s, b, p for quotes, braces
-+      # and parenthesis.
-+      $char_class_before      = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
-+
-+      $matcher                = generate_matcher('.*?');
-+
-+      # Here we match text till enclosing pair, using perl conditionals in
-+      # regexps (?(condition)yes-expression|no-expression).
-+      # -+    $char_class_at_end      = 
'.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))-+    $char_class_to_complete = '\S';
-+}
-+
-+my $lines = [];
-+
-+while (<STDIN>)
-+{
-+      push @{$lines}, $_;
-+}
-+
-+# read the word behind the cursor
-+$_ = substr(@{$lines} [$cursor_row], 0, $cursor_column); # get the current 
line up to the cursor...
-+s/.*?($char_class_to_complete*)$/$1/;                 # ...and read the last 
word from it
-+my $word_to_complete = $_;
-+
-+# ignore the completed word itself
-+$self->{already_completed}{$word_to_complete} = 1;
-+
-+print stdout "$word_to_complete
";
-+
-+# search for matches
-+while (my $completion = find_match($self,
-+                                        $word_to_complete,
-+                                        $self->{next_row} // $cursor_row,
-+                                        $matcher->($word_to_complete),
-+                                        $char_class_before,
-+                                        $char_class_at_end)
-+) {
-+      calc_match_coords($self,
-+                                      $self->{next_row}+1,
-+                                      $completion);
-+      print stdout "$completion @{$self->{highlight}}
";
-+}
-+
-+leave($self);
-+
-+
-+
-+######################################################################
-+
-+# Finds the next matching completion in the row current row or above
-+# while skipping duplicates using skip_duplicates().
-+sub find_match {
-+    my ($self, $word_to_match, $current_row, $regexp, $char_class_before, 
$char_class_at_end) = @_;
-+    $self->{matches_in_row} //= [];
-+
-+    # cycle through all the matches in the current row if not starting a new 
search
-+    if (@{$self->{matches_in_row}}) {
-+        return skip_duplicates($self, $word_to_match, $current_row, $regexp, 
$char_class_before, $char_class_at_end);
-+    }
-+
-+
-+    my $i;
-+    # search through all the rows starting with current one or one above the 
last checked
-+    for ($i = $current_row; $i >= 0; --$i) {
-+        my $line = @{$lines} [$i];   # get the line of text from the row
-+
-+        if ($i == $cursor_row) {
-+            $line = substr $line, 0, $cursor_column;
-+        }
-+
-+        $_ = $line;
-+
-+        # find all the matches in the current line
-+        my $match;
-+        push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
-+                                                                         
(.*${char_class_before})
-+                                                                         
(?<match>
-+                                                                             
${regexp}
-+                                                                             
${char_class_at_end}*
-+                                                                         )
-+                                                                     /ix;
-+        # corner case: match at the very beginning of line
-+        push @{$self->{matches_in_row}}, $+{match} if $line =~ 
/^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
-+
-+        if (@{$self->{matches_in_row}}) {
-+            # remember which row should be searched next
-+            $self->{next_row} = --$i;
-+
-+            # arguments needed for find_match() mutual recursion
-+            return skip_duplicates($self, $word_to_match, $i, $regexp, 
$char_class_before, $char_class_at_end);
-+        }
-+    }
-+
-+    # no more possible completions, revert to the original word
-+    $self->{next_row} = -1 if $i < 0;
-+
-+    return undef;
-+}
-+
-+######################################################################
-+
-+# Checks whether the completion found by find_match() was already
-+# found and if it was, calls find_match() again to find the next
-+# completion.
-+#
-+# Takes all the arguments that find_match() would take, to make a
-+# mutually recursive call.
-+sub skip_duplicates {
-+    my $self = $_[0];
-+    my $completion = shift @{$self->{matches_in_row}}; # get the rightmost one
-+
-+    # check for duplicates
-+    if (exists $self->{already_completed}{$completion}) {
-+        # skip this completion
-+        return find_match(@_);
-+    } else {
-+        $self->{already_completed}{$completion} = 1;
-+        return $completion;
-+    }
-+}
-+
-+######################################################################
-+
-+# Returns a function that takes a string and returns that string with
-+# this function's argument inserted between its every two characters.
-+# The resulting string is used as a regular expression matching the
-+# completion candidates.
-+sub generate_matcher {
-+    my $regex_between = shift;
-+
-+    sub {
-+        $_ = shift;
-+
-+        # sorry for this lispy code, I couldn't resist ;)
-+        (join "$regex_between",
-+         (map quotemeta,
-+          (split //)))
-+    }
-+}
-+
-+######################################################################
-+
-+sub calc_match_coords {
-+    my ($self, $linenum, $completion) = @_;
-+
-+    my $line = @{$lines} [$linenum];
-+    my $re = quotemeta $completion;
-+
-+    $line =~ /$re/;
-+
-+      #my ($beg_row, $beg_col) = $line->coord_of($-[0]);
-+      #my ($end_row, $end_col) = $line->coord_of($+[0]);
-+      my $beg = $-[0];
-+      my $end = $+[0];
-+
-+    if (exists $self->{highlight}) {
-+        delete $self->{highlight};
-+    }
-+    # () # TODO: what does () do in perl ????
-+
-+    # $self->{highlight} = [$beg_row, $beg_col, $end_row, $end_col];
-+    $self->{highlight} = [$linenum, $beg, $end];
-+}
-+
-+######################################################################
-+
-+sub leave {
-+    my ($self) = @_;
-+
-+    delete $self->{next_row};
-+    delete $self->{matches_in_row};
-+    delete $self->{already_completed};
-+    delete $self->{highlight};
-+}
-diff -uraN st-0.8.4/st.c st-autocomplete/st.c
---- st-0.8.4/st.c      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.c       2021-12-15 07:44:05.609586643 +0400
-@@ -17,6 +17,7 @@
- #include <unistd.h>
- #include <wchar.h>
- 
-+#include "autocomplete.h"
- #include "st.h"
- #include "win.h"
- 
-@@ -2476,6 +2477,9 @@
-               return;
-       }
- 
-+      if ( row < term.row  || col < term.col )
-+              autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /*
-        * slide screen to keep cursor where we expect it -
-        * tscrollup would work here, but we can optimize to
-@@ -2595,3 +2599,211 @@
-       tfulldirt();
-       draw();
- }
-+
-+void autocomplete (const Arg * arg)
-+{
-+      static _Bool active = 0;
-+
-+      int acmpl_cmdindex = arg -> i;
-+
-+      static int acmpl_cmdindex_prev;
-+
-+      if (active == 0)
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+      static const char * const (acmpl_cmd []) = {
-+              [ACMPL_DEACTIVATE]      = "__DEACTIVATE__",
-+              [ACMPL_WORD]            = "word-complete",
-+              [ACMPL_WWORD]           = "WORD-complete",
-+              [ACMPL_FUZZY_WORD]      = "fuzzy-word-complete",
-+              [ACMPL_FUZZY_WWORD]     = "fuzzy-WORD-complete",
-+              [ACMPL_FUZZY]           = "fuzzy-complete",
-+              [ACMPL_SUFFIX]          = "suffix-complete",
-+              [ACMPL_SURROUND]        = "surround-complete",
-+              [ACMPL_UNDO]            = "__UNDO__",
-+      };
-+
-+      static char acmpl [1000];               // ACMPL_ISSUE: why 1000?
-+
-+      static FILE * acmpl_exec = NULL;
-+      static int acmpl_status;
-+
-+      static const char * stbuffile;
-+      static char target [1000];              // ACMPL_ISSUE: why 1000? 
dynamically allocate char array of size term.col
-+      static size_t targetlen;
-+
-+      static char completion [1000] = {0};            // ACMPL_ISSUE: why 
1000? dynamically allocate char array of size term.col
-+      static size_t complen_prev = 0;         // NOTE: always clear this 
variable after clearing completion
-+
-+// Check for deactivation
-+
-+      if (acmpl_cmdindex == ACMPL_DEACTIVATE)
-+      {
-+
-+//     Deactivate autocomplete mode keeping current completion
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              complen_prev = 0;
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for undo
-+
-+      if (acmpl_cmdindex == ACMPL_UNDO)
-+      {
-+
-+//     Deactivate autocomplete mode recovering target
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              for (size_t i = 0; i < complen_prev; i++)
-+                                      ttywrite ((char []) { '' }, 1, 1);     
// ACMPL_ISSUE: I'm not sure that this is the right way
-+                              complen_prev = 0;
-+                              ttywrite (target, targetlen, 0);                
// ACMPL_ISSUE: I'm not sure that this is a right solution
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for command change
-+
-+      if (acmpl_cmdindex != acmpl_cmdindex_prev)
-+      {
-+
-+//     If command is changed, goto acmpl_begin avoiding rewriting st buffer
-+
-+              if (active)
-+              {
-+                      acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+                      goto acmpl_begin;
-+              }
-+      }
-+
-+// If not active
-+
-+      if (active == 0)
-+      {
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+//     Write st buffer to a temp file
-+
-+              stbuffile = tmpnam (NULL);              // check for return 
value ...
-+                                                                              
// ACMPL_ISSUE: use coprocesses instead of temp files
-+              sprintf (
-+                      acmpl,
-+                      "cat %100s | st-autocomplete %500s %d %d",      // 
ACMPL_ISSUE: why 100 and 500?
-+                      stbuffile,
-+                      acmpl_cmd [acmpl_cmdindex],
-+                      term.c.y,
-+                      term.c.x
-+              );
-+
-+              FILE * stbuf = fopen (stbuffile, "w"); // check for opening 
error ...
-+              char * stbufline = malloc (term.col + 2); // check for 
allocating error ...
-+
-+              for (size_t y = 0; y < term.row; y++)
-+              {
-+                      size_t x = 0;
-+                      for (; x < term.col; x++)
-+                              utf8encode (term.line [y] [x].u, stbufline + x);
-+                      stbufline [x] = '
';
-+                      stbufline [x + 1] = 0;
-+                      fputs (stbufline, stbuf);
-+              }
-+
-+              free (stbufline);
-+              fclose (stbuf);
-+
-+acmpl_begin:
-+
-+//     Run st-autocomplete
-+
-+              acmpl_exec = popen (acmpl, "r");                // ACMPL_ISSUE: 
popen isn't defined by The Standard. Does it work in BSDs for example?
-+                                                                              
                // check for popen error ...
-+
-+//     Read the target, targetlen
-+
-+              fscanf (acmpl_exec, "%500s
", target); // check for scanning error ...
-+              targetlen = strlen (target);
-+      }
-+
-+// Read a completion if exists (acmpl_status)
-+
-+      unsigned line, beg, end;
-+
-+      acmpl_status = fscanf (acmpl_exec, "%500s %u %u %u
", completion, & line, & beg, & end);
-+                                                                              
                // ACMPL_ISSUE: why 500? use term.col instead
-+
-+// Exit if no completions found
-+
-+      if (active == 0 && acmpl_status == EOF)
-+      {
-+
-+//    Close st-autocomplete and exit without activating the autocomplete mode
-+
-+              pclose (acmpl_exec);
-+              remove (stbuffile);
-+              return;
-+      }
-+
-+// If completions found, enable autocomplete mode and autocomplete the target
-+
-+      active = 1;
-+
-+// Clear target before first completion
-+
-+      if (complen_prev == 0)
-+      {
-+              for (size_t i = 0; i < targetlen; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+      }
-+
-+// Clear previuos completion if this is not the first
-+
-+      else
-+      {
-+              selclear ();
-+              for (size_t i = 0; i < complen_prev; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+              complen_prev = 0;
-+      }
-+
-+// If no more completions found, reset and restart
-+
-+      if (acmpl_status == EOF)
-+      {
-+              active = 0;
-+              pclose (acmpl_exec);
-+              ttywrite (target, targetlen, 0);
-+              goto acmpl_begin;
-+      }
-+
-+// Read the new completion and autcomplete
-+
-+      selstart (beg, line, 0);
-+      selextend (end - 1, line, 1, 0);
-+      xsetsel (getsel ());
-+
-+      complen_prev = strlen (completion);
-+      ttywrite (completion, complen_prev, 0);
-+}
-diff -uraN st-0.8.4/st.h st-autocomplete/st.h
---- st-0.8.4/st.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.h       2021-12-14 20:28:59.272432749 +0400
-@@ -77,6 +77,8 @@
-       const char *s;
- } Arg;
- 
-+void autocomplete (const Arg *);
-+
- void die(const char *, ...);
- void redraw(void);
- void draw(void);
-diff -uraN st-0.8.4/x.c st-autocomplete/x.c
---- st-0.8.4/x.c       2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/x.c        2021-12-14 20:30:30.045830893 +0400
-@@ -1803,11 +1803,15 @@
-       /* 1. shortcuts */
-       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-               if (ksym == bp->keysym && match(bp->mod, e->state)) {
-+                      if (bp -> func != autocomplete)
-+                              autocomplete ((const Arg []) { ACMPL_DEACTIVATE 
});
-                       bp->func(&(bp->arg));
-                       return;
-               }
-       }
- 
-+      autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /* 2. custom keys from config.h */
-       if ((customkey = kmap(ksym, e->state))) {
-               ttywrite(customkey, strlen(customkey), 1);
diff --git 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211216-221700-st-0.8.4-testrelease.diff
 
b/st.suckless.org/patches/autocomplete/st-autocomplete-20211216-221700-st-0.8.4-testrelease.diff
deleted file mode 100644
index cb945c3c..00000000
--- 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211216-221700-st-0.8.4-testrelease.diff
+++ /dev/null
@@ -1,636 +0,0 @@
-diff -uraN st-0.8.4/autocomplete.h st-autocomplete/autocomplete.h
---- st-0.8.4/autocomplete.h    1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/autocomplete.h     2021-12-14 20:20:03.322050025 +0400
-@@ -0,0 +1,16 @@
-+# ifndef __ST_AUTOCOMPLETE_H
-+# define __ST_AUTOCOMPLETE_H
-+
-+enum {
-+      ACMPL_DEACTIVATE,
-+      ACMPL_WORD,
-+      ACMPL_WWORD,
-+      ACMPL_FUZZY_WORD,
-+      ACMPL_FUZZY_WWORD,
-+      ACMPL_FUZZY,
-+      ACMPL_SUFFIX,
-+      ACMPL_SURROUND,
-+      ACMPL_UNDO,
-+};
-+
-+# endif // __ST_AUTOCOMPLETE_H
-diff -uraN st-0.8.4/config.def.h st-autocomplete/config.def.h
---- st-0.8.4/config.def.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/config.def.h       2021-12-14 20:22:30.088821478 +0400
-@@ -168,6 +168,8 @@
-  */
- static uint forcemousemod = ShiftMask;
- 
-+# include "autocomplete.h"
-+
- /*
-  * Internal mouse shortcuts.
-  * Beware that overloading Button1 will disable the selection.
-@@ -199,6 +201,14 @@
-       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
-       { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
-       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
-+      { ControlMask|Mod1Mask, XK_slash,       autocomplete,   { .i = 
ACMPL_WORD        } },
-+      { ControlMask|Mod1Mask, XK_period,      autocomplete,   { .i = 
ACMPL_FUZZY_WORD  } },
-+      { ControlMask|Mod1Mask, XK_comma,       autocomplete,   { .i = 
ACMPL_FUZZY       } },
-+      { ControlMask|Mod1Mask, XK_apostrophe,  autocomplete,   { .i = 
ACMPL_SUFFIX      } },
-+      { ControlMask|Mod1Mask, XK_semicolon,   autocomplete,   { .i = 
ACMPL_SURROUND    } },
-+      { ControlMask|Mod1Mask, XK_bracketright,autocomplete,   { .i = 
ACMPL_WWORD       } },
-+      { ControlMask|Mod1Mask, XK_bracketleft, autocomplete,   { .i = 
ACMPL_FUZZY_WWORD } },
-+      { ControlMask|Mod1Mask, XK_equal,       autocomplete,   { .i = 
ACMPL_UNDO        } },
- };
- 
- /*
-diff -uraN st-0.8.4/Makefile st-autocomplete/Makefile
---- st-0.8.4/Makefile  2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/Makefile   2021-12-15 07:12:40.291573671 +0400
-@@ -44,6 +44,8 @@
-       mkdir -p $(DESTDIR)$(PREFIX)/bin
-       cp -f st $(DESTDIR)$(PREFIX)/bin
-       chmod 755 $(DESTDIR)$(PREFIX)/bin/st
-+      cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
-+      chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       mkdir -p $(DESTDIR)$(MANPREFIX)/man1
-       sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
-       chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
-@@ -52,6 +54,7 @@
- 
- uninstall:
-       rm -f $(DESTDIR)$(PREFIX)/bin/st
-+      rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
- 
- .PHONY: all options clean dist install uninstall
-diff -uraN st-0.8.4/st-autocomplete st-autocomplete/st-autocomplete
---- st-0.8.4/st-autocomplete   1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/st-autocomplete    2021-12-16 22:13:54.590807654 +0400
-@@ -0,0 +1,301 @@
-+#!/usr/bin/perl
-+#########################################################################
-+# Copyright (C) 2012-2021  Wojciech Siewierski, Gaspar Vardanyan        #
-+#                                                                       #
-+# This program is free software: you can redistribute it and/or modify  #
-+# it under the terms of the GNU General Public License as published by  #
-+# the Free Software Foundation, either version 3 of the License, or     #
-+# (at your option) any later version.                                   #
-+#                                                                       #
-+# This program is distributed in the hope that it will be useful,       #
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of        #
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
-+# GNU General Public License for more details.                          #
-+#                                                                       #
-+# You should have received a copy of the GNU General Public License     #
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>. #
-+#########################################################################
-+
-+my ($cmd, $cursor_row, $cursor_column) = @ARGV;
-+
-+# A reference to a function that transforms the completed word
-+# into a regex matching the completions. Usually generated by
-+# generate_matcher().
-+#
-+# For example
-+#   $fun = generate_matcher(".*");
-+#   $fun->("foo");
-+# would return "f.*o.*o"
-+#
-+# In other words, indirectly decides which characters can
-+# appear in the completion.
-+my $matcher;
-+
-+# A regular expression matching a character before each match.
-+# For example, it you want to match the text after a
-+# whitespace, set it to "\s".
-+my $char_class_before;
-+
-+# A regular expression matching every character in the entered
-+# text that will be used to find matching completions. Usually
-+# "\w" or similar.
-+my $char_class_to_complete;
-+
-+# A regular expression matching every allowed last character
-+# of the completion (uses greedy matching).
-+my $char_class_at_end;
-+
-+if ($cmd eq 'word-complete') {
-+      # Basic word completion. Completes the current word
-+      # without any special matching.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = sub { quotemeta shift }; # identity
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'WORD-complete') {
-+      # The same as above but in the Vim meaning of a "WORD" --
-+      # whitespace delimited.
-+      $char_class_before      = '\s';
-+      $matcher                = sub { quotemeta shift };
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-word-complete' ||
-+               $cmd eq 'skeleton-word-complete') {
-+      # Fuzzy completion of the current word.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = generate_matcher('[-\w]*');
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'fuzzy-WORD-complete') {
-+      # Fuzzy completion of the current WORD.
-+      $char_class_before      = '\s';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-complete' ||
-+               $cmd eq 'skeleton-complete') {
-+      # Fuzzy completion of an arbitrary text.
-+      $char_class_before      = '\W';
-+      $matcher                = generate_matcher('.*?');
-+      $char_class_at_end      = '\w';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'suffix-complete') {
-+      # Fuzzy completion of an completing suffixes, like
-+      # completing test=hello from /blah/hello.
-+      $char_class_before      = '\S';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'surround-complete') {
-+      # Completing contents of quotes and braces.
-+
-+      # Here we are using three named groups: s, b, p for quotes, braces
-+      # and parenthesis.
-+      $char_class_before      = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
-+
-+      $matcher                = generate_matcher('.*?');
-+
-+      # Here we match text till enclosing pair, using perl conditionals in
-+      # regexps (?(condition)yes-expression|no-expression).
-+      # -+    $char_class_at_end      = 
'.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))-+    $char_class_to_complete = '\S';
-+}
-+
-+my $lines = [];
-+
-+my $last_line = -1;
-+my $lines_after_cursor = 0;
-+
-+while (<STDIN>)
-+{
-+      $last_line++;
-+
-+      if ($last_line <= $cursor_row)
-+      {
-+              push @{$lines}, $_;
-+      }
-+      else
-+      {
-+              unshift @{$lines}, $_;
-+              $cursor_row++;
-+              $lines_after_cursor++;
-+      }
-+}
-+
-+$cursor_row = $last_line;
-+
-+# read the word behind the cursor
-+$_ = substr(@{$lines} [$cursor_row], 0, $cursor_column); # get the current 
line up to the cursor...
-+s/.*?($char_class_to_complete*)$/$1/;                 # ...and read the last 
word from it
-+my $word_to_complete = quotemeta;
-+
-+# ignore the completed word itself
-+$self->{already_completed}{$word_to_complete} = 1;
-+
-+print stdout "$word_to_complete
";
-+
-+# search for matches
-+while (my $completion = find_match($self,
-+                                        $word_to_complete,
-+                                        $self->{next_row} // $cursor_row,
-+                                        $matcher->($word_to_complete),
-+                                        $char_class_before,
-+                                        $char_class_at_end)
-+) {
-+      calc_match_coords($self,
-+                                      $self->{next_row}+1,
-+                                      $completion);
-+      print stdout "$completion @{$self->{highlight}}
";
-+}
-+
-+leave($self);
-+
-+
-+
-+######################################################################
-+
-+# Finds the next matching completion in the row current row or above
-+# while skipping duplicates using skip_duplicates().
-+sub find_match {
-+    my ($self, $word_to_match, $current_row, $regexp, $char_class_before, 
$char_class_at_end) = @_;
-+    $self->{matches_in_row} //= [];
-+
-+    # cycle through all the matches in the current row if not starting a new 
search
-+    if (@{$self->{matches_in_row}}) {
-+        return skip_duplicates($self, $word_to_match, $current_row, $regexp, 
$char_class_before, $char_class_at_end);
-+    }
-+
-+
-+    my $i;
-+    # search through all the rows starting with current one or one above the 
last checked
-+    for ($i = $current_row; $i >= 0; --$i) {
-+        my $line = @{$lines} [$i];   # get the line of text from the row
-+
-+        if ($i == $cursor_row) {
-+            $line = substr $line, 0, $cursor_column;
-+        }
-+
-+        $_ = $line;
-+
-+        # find all the matches in the current line
-+        my $match;
-+        push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
-+                                                                         
(.*${char_class_before})
-+                                                                         
(?<match>
-+                                                                             
${regexp}
-+                                                                             
${char_class_at_end}*
-+                                                                         )
-+                                                                     /ix;
-+        # corner case: match at the very beginning of line
-+        push @{$self->{matches_in_row}}, $+{match} if $line =~ 
/^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
-+
-+        if (@{$self->{matches_in_row}}) {
-+            # remember which row should be searched next
-+            $self->{next_row} = --$i;
-+
-+            # arguments needed for find_match() mutual recursion
-+            return skip_duplicates($self, $word_to_match, $i, $regexp, 
$char_class_before, $char_class_at_end);
-+        }
-+    }
-+
-+    # no more possible completions, revert to the original word
-+    $self->{next_row} = -1 if $i < 0;
-+
-+    return undef;
-+}
-+
-+######################################################################
-+
-+# Checks whether the completion found by find_match() was already
-+# found and if it was, calls find_match() again to find the next
-+# completion.
-+#
-+# Takes all the arguments that find_match() would take, to make a
-+# mutually recursive call.
-+sub skip_duplicates {
-+    my $self = $_[0];
-+      my $current_row = $_[2];
-+      my $completion;
-+      if ($current_row >= $lines_after_cursor)
-+      {
-+              $completion = shift @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+      else
-+      {
-+              $completion = pop @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+
-+    # check for duplicates
-+    if (exists $self->{already_completed}{$completion}) {
-+        # skip this completion
-+        return find_match(@_);
-+    } else {
-+        $self->{already_completed}{$completion} = 1;
-+        return $completion;
-+    }
-+}
-+
-+######################################################################
-+
-+# Returns a function that takes a string and returns that string with
-+# this function's argument inserted between its every two characters.
-+# The resulting string is used as a regular expression matching the
-+# completion candidates.
-+sub generate_matcher {
-+    my $regex_between = shift;
-+
-+    sub {
-+        $_ = shift;
-+
-+        # sorry for this lispy code, I couldn't resist ;)
-+        (join "$regex_between",
-+         (map quotemeta,
-+          (split //)))
-+    }
-+}
-+
-+######################################################################
-+
-+sub calc_match_coords {
-+    my ($self, $linenum, $completion) = @_;
-+
-+    my $line = @{$lines} [$linenum];
-+    my $re = quotemeta $completion;
-+
-+    $line =~ /$re/;
-+
-+      #my ($beg_row, $beg_col) = $line->coord_of($-[0]);
-+      #my ($end_row, $end_col) = $line->coord_of($+[0]);
-+      my $beg = $-[0];
-+      my $end = $+[0];
-+
-+    if (exists $self->{highlight}) {
-+        delete $self->{highlight};
-+    }
-+    # () # TODO: what does () do in perl ????
-+
-+      if ($linenum >= $lines_after_cursor)
-+      {
-+              $linenum -= $lines_after_cursor;
-+      }
-+      else
-+      {
-+              $linenum = $last_line - $linenum;
-+      }
-+
-+      # ACMPL_ISSUE: multi-line completions don't work
-+    # $self->{highlight} = [$beg_row, $beg_col, $end_row, $end_col];
-+    $self->{highlight} = [$linenum, $beg, $end];
-+}
-+
-+######################################################################
-+
-+sub leave {
-+    my ($self) = @_;
-+
-+    delete $self->{next_row};
-+    delete $self->{matches_in_row};
-+    delete $self->{already_completed};
-+    delete $self->{highlight};
-+}
-diff -uraN st-0.8.4/st.c st-autocomplete/st.c
---- st-0.8.4/st.c      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.c       2021-12-16 20:25:18.984039549 +0400
-@@ -17,6 +17,7 @@
- #include <unistd.h>
- #include <wchar.h>
- 
-+#include "autocomplete.h"
- #include "st.h"
- #include "win.h"
- 
-@@ -2476,6 +2477,9 @@
-               return;
-       }
- 
-+      if ( row < term.row  || col < term.col )
-+              autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /*
-        * slide screen to keep cursor where we expect it -
-        * tscrollup would work here, but we can optimize to
-@@ -2595,3 +2599,211 @@
-       tfulldirt();
-       draw();
- }
-+
-+void autocomplete (const Arg * arg)
-+{
-+      static _Bool active = 0;
-+
-+      int acmpl_cmdindex = arg -> i;
-+
-+      static int acmpl_cmdindex_prev;
-+
-+      if (active == 0)
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+      static const char * const (acmpl_cmd []) = {
-+              [ACMPL_DEACTIVATE]      = "__DEACTIVATE__",
-+              [ACMPL_WORD]            = "word-complete",
-+              [ACMPL_WWORD]           = "WORD-complete",
-+              [ACMPL_FUZZY_WORD]      = "fuzzy-word-complete",
-+              [ACMPL_FUZZY_WWORD]     = "fuzzy-WORD-complete",
-+              [ACMPL_FUZZY]           = "fuzzy-complete",
-+              [ACMPL_SUFFIX]          = "suffix-complete",
-+              [ACMPL_SURROUND]        = "surround-complete",
-+              [ACMPL_UNDO]            = "__UNDO__",
-+      };
-+
-+      static char acmpl [1000];               // ACMPL_ISSUE: why 1000?
-+
-+      static FILE * acmpl_exec = NULL;
-+      static int acmpl_status;
-+
-+      static const char * stbuffile;
-+      static char target [1000];              // ACMPL_ISSUE: why 1000? 
dynamically allocate char array of size term.col
-+      static size_t targetlen;
-+
-+      static char completion [1000] = {0};            // ACMPL_ISSUE: why 
1000? dynamically allocate char array of size term.col
-+      static size_t complen_prev = 0;         // NOTE: always clear this 
variable after clearing completion
-+
-+// Check for deactivation
-+
-+      if (acmpl_cmdindex == ACMPL_DEACTIVATE)
-+      {
-+
-+//     Deactivate autocomplete mode keeping current completion
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              complen_prev = 0;
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for undo
-+
-+      if (acmpl_cmdindex == ACMPL_UNDO)
-+      {
-+
-+//     Deactivate autocomplete mode recovering target
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              for (size_t i = 0; i < complen_prev; i++)
-+                                      ttywrite ((char []) { '' }, 1, 1);     
// ACMPL_ISSUE: I'm not sure that this is the right way
-+                              complen_prev = 0;
-+                              ttywrite (target, targetlen, 0);                
// ACMPL_ISSUE: I'm not sure that this is a right solution
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for command change
-+
-+      if (acmpl_cmdindex != acmpl_cmdindex_prev)
-+      {
-+
-+//     If command is changed, goto acmpl_begin avoiding rewriting st buffer
-+
-+              if (active)
-+              {
-+                      acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+                      goto acmpl_begin;
-+              }
-+      }
-+
-+// If not active
-+
-+      if (active == 0)
-+      {
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+//     Write st buffer to a temp file
-+
-+              stbuffile = tmpnam (NULL);              // check for return 
value ...
-+                                                                              
// ACMPL_ISSUE: use coprocesses instead of temp files
-+              sprintf (
-+                      acmpl,
-+                      "cat %100s | st-autocomplete %500s %d %d",      // 
ACMPL_ISSUE: why 100 and 500?
-+                      stbuffile,
-+                      acmpl_cmd [acmpl_cmdindex],
-+                      term.c.y,
-+                      term.c.x
-+              );
-+
-+              FILE * stbuf = fopen (stbuffile, "w"); // check for opening 
error ...
-+              char * stbufline = malloc (term.col + 2); // check for 
allocating error ...
-+
-+              for (size_t y = 0; y < term.row; y++)
-+              {
-+                      size_t x = 0;
-+                      for (; x < term.col; x++)
-+                              utf8encode (term.line [y] [x].u, stbufline + x);
-+                      stbufline [x] = '
';
-+                      stbufline [x + 1] = 0;
-+                      fputs (stbufline, stbuf);
-+              }
-+
-+              free (stbufline);
-+              fclose (stbuf);
-+
-+acmpl_begin:
-+
-+//     Run st-autocomplete
-+
-+              acmpl_exec = popen (acmpl, "r");                // ACMPL_ISSUE: 
popen isn't defined by The Standard. Does it work in BSDs for example?
-+                                                                              
                // check for popen error ...
-+
-+//     Read the target, targetlen
-+
-+              fscanf (acmpl_exec, "%500s
", target); // check for scanning error ...
-+              targetlen = strlen (target);
-+      }
-+
-+// Read a completion if exists (acmpl_status)
-+
-+      unsigned line, beg, end;
-+
-+      acmpl_status = fscanf (acmpl_exec, "%500s %u %u %u
", completion, & line, & beg, & end);
-+                                                                              
                // ACMPL_ISSUE: why 500? use term.col instead
-+
-+// Exit if no completions found
-+
-+      if (active == 0 && acmpl_status == EOF)
-+      {
-+
-+//    Close st-autocomplete and exit without activating the autocomplete mode
-+
-+              pclose (acmpl_exec);
-+              remove (stbuffile);
-+              return;
-+      }
-+
-+// If completions found, enable autocomplete mode and autocomplete the target
-+
-+      active = 1;
-+
-+// Clear target before first completion
-+
-+      if (complen_prev == 0)
-+      {
-+              for (size_t i = 0; i < targetlen; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+      }
-+
-+// Clear previuos completion if this is not the first
-+
-+      else
-+      {
-+              selclear ();
-+              for (size_t i = 0; i < complen_prev; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+              complen_prev = 0;
-+      }
-+
-+// If no more completions found, reset and restart
-+
-+      if (acmpl_status == EOF)
-+      {
-+              active = 0;
-+              pclose (acmpl_exec);
-+              ttywrite (target, targetlen, 0);
-+              goto acmpl_begin;
-+      }
-+
-+// Read the new completion and autcomplete
-+
-+      selstart (beg, line, 0);
-+      selextend (end - 1, line, 1, 0);
-+      xsetsel (getsel ());
-+
-+      complen_prev = strlen (completion);
-+      ttywrite (completion, complen_prev, 0);
-+}
-diff -uraN st-0.8.4/st.h st-autocomplete/st.h
---- st-0.8.4/st.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.h       2021-12-14 20:28:59.272432749 +0400
-@@ -77,6 +77,8 @@
-       const char *s;
- } Arg;
- 
-+void autocomplete (const Arg *);
-+
- void die(const char *, ...);
- void redraw(void);
- void draw(void);
-diff -uraN st-0.8.4/x.c st-autocomplete/x.c
---- st-0.8.4/x.c       2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/x.c        2021-12-14 20:30:30.045830893 +0400
-@@ -1803,11 +1803,15 @@
-       /* 1. shortcuts */
-       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-               if (ksym == bp->keysym && match(bp->mod, e->state)) {
-+                      if (bp -> func != autocomplete)
-+                              autocomplete ((const Arg []) { ACMPL_DEACTIVATE 
});
-                       bp->func(&(bp->arg));
-                       return;
-               }
-       }
- 
-+      autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /* 2. custom keys from config.h */
-       if ((customkey = kmap(ksym, e->state))) {
-               ttywrite(customkey, strlen(customkey), 1);
diff --git 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211218-131244-st-0.8.4-testrelease.diff
 
b/st.suckless.org/patches/autocomplete/st-autocomplete-20211218-131244-st-0.8.4-testrelease.diff
deleted file mode 100644
index c1059347..00000000
--- 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20211218-131244-st-0.8.4-testrelease.diff
+++ /dev/null
@@ -1,640 +0,0 @@
-diff -uraN st-0.8.4/autocomplete.h st-autocomplete/autocomplete.h
---- st-0.8.4/autocomplete.h    1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/autocomplete.h     2021-12-18 10:56:10.545143280 +0400
-@@ -0,0 +1,16 @@
-+# ifndef __ST_AUTOCOMPLETE_H
-+# define __ST_AUTOCOMPLETE_H
-+
-+enum {
-+      ACMPL_DEACTIVATE,
-+      ACMPL_WORD,
-+      ACMPL_WWORD,
-+      ACMPL_FUZZY_WORD,
-+      ACMPL_FUZZY_WWORD,
-+      ACMPL_FUZZY,
-+      ACMPL_SUFFIX,
-+      ACMPL_SURROUND,
-+      ACMPL_UNDO,
-+};
-+
-+# endif // __ST_AUTOCOMPLETE_H
-diff -uraN st-0.8.4/config.def.h st-autocomplete/config.def.h
---- st-0.8.4/config.def.h      2021-12-18 10:56:10.545143280 +0400
-+++ st-autocomplete/config.def.h       2021-12-18 10:56:10.545143280 +0400
-@@ -168,6 +168,8 @@
-  */
- static uint forcemousemod = ShiftMask;
- 
-+# include "autocomplete.h"
-+
- /*
-  * Internal mouse shortcuts.
-  * Beware that overloading Button1 will disable the selection.
-@@ -199,6 +201,14 @@
-       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
-       { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
-       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
-+      { ControlMask|Mod1Mask, XK_slash,       autocomplete,   { .i = 
ACMPL_WORD        } },
-+      { ControlMask|Mod1Mask, XK_period,      autocomplete,   { .i = 
ACMPL_FUZZY_WORD  } },
-+      { ControlMask|Mod1Mask, XK_comma,       autocomplete,   { .i = 
ACMPL_FUZZY       } },
-+      { ControlMask|Mod1Mask, XK_apostrophe,  autocomplete,   { .i = 
ACMPL_SUFFIX      } },
-+      { ControlMask|Mod1Mask, XK_semicolon,   autocomplete,   { .i = 
ACMPL_SURROUND    } },
-+      { ControlMask|Mod1Mask, XK_bracketright,autocomplete,   { .i = 
ACMPL_WWORD       } },
-+      { ControlMask|Mod1Mask, XK_bracketleft, autocomplete,   { .i = 
ACMPL_FUZZY_WWORD } },
-+      { ControlMask|Mod1Mask, XK_equal,       autocomplete,   { .i = 
ACMPL_UNDO        } },
- };
- 
- /*
-diff -uraN st-0.8.4/Makefile st-autocomplete/Makefile
---- st-0.8.4/Makefile  2021-12-18 10:56:10.545143280 +0400
-+++ st-autocomplete/Makefile   2021-12-18 10:56:10.545143280 +0400
-@@ -44,6 +44,8 @@
-       mkdir -p $(DESTDIR)$(PREFIX)/bin
-       cp -f st $(DESTDIR)$(PREFIX)/bin
-       chmod 755 $(DESTDIR)$(PREFIX)/bin/st
-+      cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
-+      chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       mkdir -p $(DESTDIR)$(MANPREFIX)/man1
-       sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
-       chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
-@@ -52,6 +54,7 @@
- 
- uninstall:
-       rm -f $(DESTDIR)$(PREFIX)/bin/st
-+      rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
- 
- .PHONY: all options clean dist install uninstall
-diff -uraN st-0.8.4/st-autocomplete st-autocomplete/st-autocomplete
---- st-0.8.4/st-autocomplete   1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/st-autocomplete    2021-12-18 12:42:16.841949553 +0400
-@@ -0,0 +1,300 @@
-+#!/usr/bin/perl
-+#########################################################################
-+# Copyright (C) 2012-2021  Wojciech Siewierski, Gaspar Vardanyan        #
-+#                                                                       #
-+# This program is free software: you can redistribute it and/or modify  #
-+# it under the terms of the GNU General Public License as published by  #
-+# the Free Software Foundation, either version 3 of the License, or     #
-+# (at your option) any later version.                                   #
-+#                                                                       #
-+# This program is distributed in the hope that it will be useful,       #
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of        #
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
-+# GNU General Public License for more details.                          #
-+#                                                                       #
-+# You should have received a copy of the GNU General Public License     #
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>. #
-+#########################################################################
-+
-+my ($cmd, $cursor_row, $cursor_column) = @ARGV;
-+
-+# A reference to a function that transforms the completed word
-+# into a regex matching the completions. Usually generated by
-+# generate_matcher().
-+#
-+# For example
-+#   $fun = generate_matcher(".*");
-+#   $fun->("foo");
-+# would return "f.*o.*o"
-+#
-+# In other words, indirectly decides which characters can
-+# appear in the completion.
-+my $matcher;
-+
-+# A regular expression matching a character before each match.
-+# For example, it you want to match the text after a
-+# whitespace, set it to "\s".
-+my $char_class_before;
-+
-+# A regular expression matching every character in the entered
-+# text that will be used to find matching completions. Usually
-+# "\w" or similar.
-+my $char_class_to_complete;
-+
-+# A regular expression matching every allowed last character
-+# of the completion (uses greedy matching).
-+my $char_class_at_end;
-+
-+if ($cmd eq 'word-complete') {
-+      # Basic word completion. Completes the current word
-+      # without any special matching.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = sub { quotemeta shift }; # identity
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'WORD-complete') {
-+      # The same as above but in the Vim meaning of a "WORD" --
-+      # whitespace delimited.
-+      $char_class_before      = '\s';
-+      $matcher                = sub { quotemeta shift };
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-word-complete' ||
-+               $cmd eq 'skeleton-word-complete') {
-+      # Fuzzy completion of the current word.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = generate_matcher('[-\w]*');
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'fuzzy-WORD-complete') {
-+      # Fuzzy completion of the current WORD.
-+      $char_class_before      = '\s';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-complete' ||
-+               $cmd eq 'skeleton-complete') {
-+      # Fuzzy completion of an arbitrary text.
-+      $char_class_before      = '\W';
-+      $matcher                = generate_matcher('.*?');
-+      $char_class_at_end      = '\w';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'suffix-complete') {
-+      # Fuzzy completion of an completing suffixes, like
-+      # completing test=hello from /blah/hello.
-+      $char_class_before      = '\S';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'surround-complete') {
-+      # Completing contents of quotes and braces.
-+
-+      # Here we are using three named groups: s, b, p for quotes, braces
-+      # and parenthesis.
-+      $char_class_before      = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
-+
-+      $matcher                = generate_matcher('.*?');
-+
-+      # Here we match text till enclosing pair, using perl conditionals in
-+      # regexps (?(condition)yes-expression|no-expression).
-+      # -+    $char_class_at_end      = 
'.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))-+    $char_class_to_complete = '\S';
-+}
-+
-+my $lines = [];
-+
-+my $last_line = -1;
-+my $lines_after_cursor = 0;
-+
-+while (<STDIN>)
-+{
-+      $last_line++;
-+
-+      if ($last_line <= $cursor_row)
-+      {
-+              push @{$lines}, $_;
-+      }
-+      else
-+      {
-+              unshift @{$lines}, $_;
-+              $lines_after_cursor++;
-+      }
-+}
-+
-+$cursor_row = $last_line;
-+
-+# read the word behind the cursor
-+$_ = substr(@{$lines} [$cursor_row], 0, $cursor_column); # get the current 
line up to the cursor...
-+s/.*?($char_class_to_complete*)$/$1/;                 # ...and read the last 
word from it
-+my $word_to_complete = quotemeta;
-+
-+# ignore the completed word itself
-+$self->{already_completed}{$word_to_complete} = 1;
-+
-+print stdout "$word_to_complete
";
-+
-+# search for matches
-+while (my $completion = find_match($self,
-+                                        $word_to_complete,
-+                                        $self->{next_row} // $cursor_row,
-+                                        $matcher->($word_to_complete),
-+                                        $char_class_before,
-+                                        $char_class_at_end)
-+) {
-+      calc_match_coords($self,
-+                                      $self->{next_row}+1,
-+                                      $completion);
-+      print stdout "$completion @{$self->{highlight}}
";
-+}
-+
-+leave($self);
-+
-+
-+
-+######################################################################
-+
-+# Finds the next matching completion in the row current row or above
-+# while skipping duplicates using skip_duplicates().
-+sub find_match {
-+    my ($self, $word_to_match, $current_row, $regexp, $char_class_before, 
$char_class_at_end) = @_;
-+    $self->{matches_in_row} //= [];
-+
-+    # cycle through all the matches in the current row if not starting a new 
search
-+    if (@{$self->{matches_in_row}}) {
-+        return skip_duplicates($self, $word_to_match, $current_row, $regexp, 
$char_class_before, $char_class_at_end);
-+    }
-+
-+
-+    my $i;
-+    # search through all the rows starting with current one or one above the 
last checked
-+    for ($i = $current_row; $i >= 0; --$i) {
-+        my $line = @{$lines} [$i];   # get the line of text from the row
-+
-+        if ($i == $cursor_row) {
-+            $line = substr $line, 0, $cursor_column;
-+        }
-+
-+        $_ = $line;
-+
-+        # find all the matches in the current line
-+        my $match;
-+        push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
-+                                                                         
(.*${char_class_before})
-+                                                                         
(?<match>
-+                                                                             
${regexp}
-+                                                                             
${char_class_at_end}*
-+                                                                         )
-+                                                                     /ix;
-+        # corner case: match at the very beginning of line
-+        push @{$self->{matches_in_row}}, $+{match} if $line =~ 
/^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
-+
-+        if (@{$self->{matches_in_row}}) {
-+            # remember which row should be searched next
-+            $self->{next_row} = --$i;
-+
-+            # arguments needed for find_match() mutual recursion
-+            return skip_duplicates($self, $word_to_match, $i, $regexp, 
$char_class_before, $char_class_at_end);
-+        }
-+    }
-+
-+    # no more possible completions, revert to the original word
-+    $self->{next_row} = -1 if $i < 0;
-+
-+    return undef;
-+}
-+
-+######################################################################
-+
-+# Checks whether the completion found by find_match() was already
-+# found and if it was, calls find_match() again to find the next
-+# completion.
-+#
-+# Takes all the arguments that find_match() would take, to make a
-+# mutually recursive call.
-+sub skip_duplicates {
-+    my $self = $_[0];
-+      my $current_row = $_[2];
-+      my $completion;
-+      if ($current_row >= $lines_after_cursor)
-+      {
-+              $completion = shift @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+      else
-+      {
-+              $completion = pop @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+
-+    # check for duplicates
-+    if (exists $self->{already_completed}{$completion}) {
-+        # skip this completion
-+        return find_match(@_);
-+    } else {
-+        $self->{already_completed}{$completion} = 1;
-+        return $completion;
-+    }
-+}
-+
-+######################################################################
-+
-+# Returns a function that takes a string and returns that string with
-+# this function's argument inserted between its every two characters.
-+# The resulting string is used as a regular expression matching the
-+# completion candidates.
-+sub generate_matcher {
-+    my $regex_between = shift;
-+
-+    sub {
-+        $_ = shift;
-+
-+        # sorry for this lispy code, I couldn't resist ;)
-+        (join "$regex_between",
-+         (map quotemeta,
-+          (split //)))
-+    }
-+}
-+
-+######################################################################
-+
-+sub calc_match_coords {
-+    my ($self, $linenum, $completion) = @_;
-+
-+    my $line = @{$lines} [$linenum];
-+    my $re = quotemeta $completion;
-+
-+    $line =~ /$re/;
-+
-+      #my ($beg_row, $beg_col) = $line->coord_of($-[0]);
-+      #my ($end_row, $end_col) = $line->coord_of($+[0]);
-+      my $beg = $-[0];
-+      my $end = $+[0];
-+
-+    if (exists $self->{highlight}) {
-+        delete $self->{highlight};
-+    }
-+    # () # TODO: what does () do in perl ????
-+
-+      if ($linenum >= $lines_after_cursor)
-+      {
-+              $linenum -= $lines_after_cursor;
-+      }
-+      else
-+      {
-+              $linenum = $last_line - $linenum;
-+      }
-+
-+      # ACMPL_ISSUE: multi-line completions don't work
-+    # $self->{highlight} = [$beg_row, $beg_col, $end_row, $end_col];
-+    $self->{highlight} = [$linenum, $beg, $end];
-+}
-+
-+######################################################################
-+
-+sub leave {
-+    my ($self) = @_;
-+
-+    delete $self->{next_row};
-+    delete $self->{matches_in_row};
-+    delete $self->{already_completed};
-+    delete $self->{highlight};
-+}
-diff -uraN st-0.8.4/st.c st-autocomplete/st.c
---- st-0.8.4/st.c      2021-12-18 10:56:10.545143280 +0400
-+++ st-autocomplete/st.c       2021-12-18 13:02:28.898642717 +0400
-@@ -17,6 +17,7 @@
- #include <unistd.h>
- #include <wchar.h>
- 
-+#include "autocomplete.h"
- #include "st.h"
- #include "win.h"
- 
-@@ -2476,6 +2477,9 @@
-               return;
-       }
- 
-+      if ( row < term.row  || col < term.col )
-+              autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /*
-        * slide screen to keep cursor where we expect it -
-        * tscrollup would work here, but we can optimize to
-@@ -2595,3 +2599,216 @@
-       tfulldirt();
-       draw();
- }
-+
-+void autocomplete (const Arg * arg)
-+{
-+      static _Bool active = 0;
-+
-+      int acmpl_cmdindex = arg -> i;
-+
-+      static int acmpl_cmdindex_prev;
-+
-+      if (active == 0)
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+      static const char * const (acmpl_cmd []) = {
-+              [ACMPL_DEACTIVATE]      = "__DEACTIVATE__",
-+              [ACMPL_WORD]            = "word-complete",
-+              [ACMPL_WWORD]           = "WORD-complete",
-+              [ACMPL_FUZZY_WORD]      = "fuzzy-word-complete",
-+              [ACMPL_FUZZY_WWORD]     = "fuzzy-WORD-complete",
-+              [ACMPL_FUZZY]           = "fuzzy-complete",
-+              [ACMPL_SUFFIX]          = "suffix-complete",
-+              [ACMPL_SURROUND]        = "surround-complete",
-+              [ACMPL_UNDO]            = "__UNDO__",
-+      };
-+
-+      static char acmpl [1000];               // ACMPL_ISSUE: why 1000?
-+
-+      static FILE * acmpl_exec = NULL;
-+      static int acmpl_status;
-+
-+      static const char * stbuffile;
-+      static char target [1000];              // ACMPL_ISSUE: why 1000? 
dynamically allocate char array of size term.col
-+      static size_t targetlen;
-+
-+      static char completion [1000] = {0};            // ACMPL_ISSUE: why 
1000? dynamically allocate char array of size term.col
-+      static size_t complen_prev = 0;         // NOTE: always clear this 
variable after clearing completion
-+
-+      static int cx, cy;
-+
-+// Check for deactivation
-+
-+      if (acmpl_cmdindex == ACMPL_DEACTIVATE)
-+      {
-+
-+//     Deactivate autocomplete mode keeping current completion
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              complen_prev = 0;
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for undo
-+
-+      if (acmpl_cmdindex == ACMPL_UNDO)
-+      {
-+
-+//     Deactivate autocomplete mode recovering target
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              for (size_t i = 0; i < complen_prev; i++)
-+                                      ttywrite ((char []) { '' }, 1, 1);     
// ACMPL_ISSUE: I'm not sure that this is the right way
-+                              complen_prev = 0;
-+                              ttywrite (target, targetlen, 0);                
// ACMPL_ISSUE: I'm not sure that this is a right solution
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for command change
-+
-+      if (acmpl_cmdindex != acmpl_cmdindex_prev)
-+      {
-+
-+//     If command is changed, goto acmpl_begin avoiding rewriting st buffer
-+
-+              if (active)
-+              {
-+                      acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+                      goto acmpl_begin;
-+              }
-+      }
-+
-+// If not active
-+
-+      if (active == 0)
-+      {
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+              cx = term.c.x;
-+              cy = term.c.y;
-+
-+//     Write st buffer to a temp file
-+
-+              stbuffile = tmpnam (NULL);              // check for return 
value ...
-+                                                                              
// ACMPL_ISSUE: use coprocesses instead of temp files
-+
-+              FILE * stbuf = fopen (stbuffile, "w"); // check for opening 
error ...
-+              char * stbufline = malloc (term.col + 2); // check for 
allocating error ...
-+
-+              for (size_t y = 0; y < term.row; y++)
-+              {
-+                      size_t x = 0;
-+                      for (; x < term.col; x++)
-+                              utf8encode (term.line [y] [x].u, stbufline + x);
-+                      stbufline [x] = '
';
-+                      stbufline [x + 1] = 0;
-+                      fputs (stbufline, stbuf);
-+              }
-+
-+              free (stbufline);
-+              fclose (stbuf);
-+
-+acmpl_begin:
-+
-+//     Run st-autocomplete
-+
-+              sprintf (
-+                      acmpl,
-+                      "cat %100s | st-autocomplete %500s %d %d",      // 
ACMPL_ISSUE: why 100 and 500?
-+                      stbuffile,
-+                      acmpl_cmd [acmpl_cmdindex],
-+                      cy,
-+                      cx
-+              );
-+
-+              acmpl_exec = popen (acmpl, "r");                // ACMPL_ISSUE: 
popen isn't defined by The Standard. Does it work in BSDs for example?
-+                                                                              
                // check for popen error ...
-+
-+//     Read the target, targetlen
-+
-+              fscanf (acmpl_exec, "%500s
", target); // check for scanning error ...
-+              targetlen = strlen (target);
-+      }
-+
-+// Read a completion if exists (acmpl_status)
-+
-+      unsigned line, beg, end;
-+
-+      acmpl_status = fscanf (acmpl_exec, "%500s %u %u %u
", completion, & line, & beg, & end);
-+                                                                              
                // ACMPL_ISSUE: why 500? use term.col instead
-+
-+// Exit if no completions found
-+
-+      if (active == 0 && acmpl_status == EOF)
-+      {
-+
-+//    Close st-autocomplete and exit without activating the autocomplete mode
-+
-+              pclose (acmpl_exec);
-+              remove (stbuffile);
-+              return;
-+      }
-+
-+// If completions found, enable autocomplete mode and autocomplete the target
-+
-+      active = 1;
-+
-+// Clear target before first completion
-+
-+      if (complen_prev == 0)
-+      {
-+              for (size_t i = 0; i < targetlen; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+      }
-+
-+// Clear previuos completion if this is not the first
-+
-+      else
-+      {
-+              selclear ();
-+              for (size_t i = 0; i < complen_prev; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+              complen_prev = 0;
-+      }
-+
-+// If no more completions found, reset and restart
-+
-+      if (acmpl_status == EOF)
-+      {
-+              active = 0;
-+              pclose (acmpl_exec);
-+              ttywrite (target, targetlen, 0);
-+              goto acmpl_begin;
-+      }
-+
-+// Read the new completion and autcomplete
-+
-+      selstart (beg, line, 0);
-+      selextend (end - 1, line, 1, 0);
-+      xsetsel (getsel ());
-+
-+      complen_prev = strlen (completion);
-+      ttywrite (completion, complen_prev, 0);
-+}
-diff -uraN st-0.8.4/st.h st-autocomplete/st.h
---- st-0.8.4/st.h      2021-12-18 10:56:10.545143280 +0400
-+++ st-autocomplete/st.h       2021-12-18 10:56:10.545143280 +0400
-@@ -77,6 +77,8 @@
-       const char *s;
- } Arg;
- 
-+void autocomplete (const Arg *);
-+
- void die(const char *, ...);
- void redraw(void);
- void draw(void);
-diff -uraN st-0.8.4/x.c st-autocomplete/x.c
---- st-0.8.4/x.c       2021-12-18 10:56:10.545143280 +0400
-+++ st-autocomplete/x.c        2021-12-18 10:56:10.545143280 +0400
-@@ -1803,11 +1803,15 @@
-       /* 1. shortcuts */
-       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-               if (ksym == bp->keysym && match(bp->mod, e->state)) {
-+                      if (bp -> func != autocomplete)
-+                              autocomplete ((const Arg []) { ACMPL_DEACTIVATE 
});
-                       bp->func(&(bp->arg));
-                       return;
-               }
-       }
- 
-+      autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /* 2. custom keys from config.h */
-       if ((customkey = kmap(ksym, e->state))) {
-               ttywrite(customkey, strlen(customkey), 1);
diff --git 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20220110-234714-st-0.8.4-testrelease.diff
 
b/st.suckless.org/patches/autocomplete/st-autocomplete-20220110-234714-st-0.8.4-testrelease.diff
deleted file mode 100644
index fc42bd7a..00000000
--- 
a/st.suckless.org/patches/autocomplete/st-autocomplete-20220110-234714-st-0.8.4-testrelease.diff
+++ /dev/null
@@ -1,664 +0,0 @@
-diff -uraN st-0.8.4/autocomplete.h st-autocomplete/autocomplete.h
---- st-0.8.4/autocomplete.h    1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/autocomplete.h     2021-12-14 20:20:03.322050025 +0400
-@@ -0,0 +1,16 @@
-+# ifndef __ST_AUTOCOMPLETE_H
-+# define __ST_AUTOCOMPLETE_H
-+
-+enum {
-+      ACMPL_DEACTIVATE,
-+      ACMPL_WORD,
-+      ACMPL_WWORD,
-+      ACMPL_FUZZY_WORD,
-+      ACMPL_FUZZY_WWORD,
-+      ACMPL_FUZZY,
-+      ACMPL_SUFFIX,
-+      ACMPL_SURROUND,
-+      ACMPL_UNDO,
-+};
-+
-+# endif // __ST_AUTOCOMPLETE_H
-diff -uraN st-0.8.4/config.def.h st-autocomplete/config.def.h
---- st-0.8.4/config.def.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/config.def.h       2021-12-14 20:22:30.088821478 +0400
-@@ -168,6 +168,8 @@
-  */
- static uint forcemousemod = ShiftMask;
- 
-+# include "autocomplete.h"
-+
- /*
-  * Internal mouse shortcuts.
-  * Beware that overloading Button1 will disable the selection.
-@@ -199,6 +201,14 @@
-       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
-       { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
-       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
-+      { ControlMask|Mod1Mask, XK_slash,       autocomplete,   { .i = 
ACMPL_WORD        } },
-+      { ControlMask|Mod1Mask, XK_period,      autocomplete,   { .i = 
ACMPL_FUZZY_WORD  } },
-+      { ControlMask|Mod1Mask, XK_comma,       autocomplete,   { .i = 
ACMPL_FUZZY       } },
-+      { ControlMask|Mod1Mask, XK_apostrophe,  autocomplete,   { .i = 
ACMPL_SUFFIX      } },
-+      { ControlMask|Mod1Mask, XK_semicolon,   autocomplete,   { .i = 
ACMPL_SURROUND    } },
-+      { ControlMask|Mod1Mask, XK_bracketright,autocomplete,   { .i = 
ACMPL_WWORD       } },
-+      { ControlMask|Mod1Mask, XK_bracketleft, autocomplete,   { .i = 
ACMPL_FUZZY_WWORD } },
-+      { ControlMask|Mod1Mask, XK_equal,       autocomplete,   { .i = 
ACMPL_UNDO        } },
- };
- 
- /*
-diff -uraN st-0.8.4/Makefile st-autocomplete/Makefile
---- st-0.8.4/Makefile  2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/Makefile   2022-01-10 23:42:52.724563917 +0400
-@@ -44,6 +44,8 @@
-       mkdir -p $(DESTDIR)$(PREFIX)/bin
-       cp -f st $(DESTDIR)$(PREFIX)/bin
-       chmod 755 $(DESTDIR)$(PREFIX)/bin/st
-+      cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
-+      chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       mkdir -p $(DESTDIR)$(MANPREFIX)/man1
-       sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
-       chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
-@@ -52,6 +54,7 @@
- 
- uninstall:
-       rm -f $(DESTDIR)$(PREFIX)/bin/st
-+      rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
-       rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
- 
- .PHONY: all options clean dist install uninstall
-diff -uraN st-0.8.4/st-autocomplete st-autocomplete/st-autocomplete
---- st-0.8.4/st-autocomplete   1970-01-01 04:00:00.000000000 +0400
-+++ st-autocomplete/st-autocomplete    2022-01-10 23:44:42.377991545 +0400
-@@ -0,0 +1,299 @@
-+#!/usr/bin/perl
-+#########################################################################
-+# Copyright (C) 2012-2021  Wojciech Siewierski, Gaspar Vardanyan        #
-+#                                                                       #
-+# This program is free software: you can redistribute it and/or modify  #
-+# it under the terms of the GNU General Public License as published by  #
-+# the Free Software Foundation, either version 3 of the License, or     #
-+# (at your option) any later version.                                   #
-+#                                                                       #
-+# This program is distributed in the hope that it will be useful,       #
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of        #
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
-+# GNU General Public License for more details.                          #
-+#                                                                       #
-+# You should have received a copy of the GNU General Public License     #
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>. #
-+#########################################################################
-+
-+my ($cmd, $cursor_row, $cursor_column) = @ARGV;
-+
-+# A reference to a function that transforms the completed word
-+# into a regex matching the completions. Usually generated by
-+# generate_matcher().
-+#
-+# For example
-+#   $fun = generate_matcher(".*");
-+#   $fun->("foo");
-+# would return "f.*o.*o"
-+#
-+# In other words, indirectly decides which characters can
-+# appear in the completion.
-+my $matcher;
-+
-+# A regular expression matching a character before each match.
-+# For example, it you want to match the text after a
-+# whitespace, set it to "\s".
-+my $char_class_before;
-+
-+# A regular expression matching every character in the entered
-+# text that will be used to find matching completions. Usually
-+# "\w" or similar.
-+my $char_class_to_complete;
-+
-+# A regular expression matching every allowed last character
-+# of the completion (uses greedy matching).
-+my $char_class_at_end;
-+
-+if ($cmd eq 'word-complete') {
-+      # Basic word completion. Completes the current word
-+      # without any special matching.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = sub { quotemeta shift }; # identity
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'WORD-complete') {
-+      # The same as above but in the Vim meaning of a "WORD" --
-+      # whitespace delimited.
-+      $char_class_before      = '\s';
-+      $matcher                = sub { quotemeta shift };
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-word-complete' ||
-+               $cmd eq 'skeleton-word-complete') {
-+      # Fuzzy completion of the current word.
-+      $char_class_before      = '[^-\w]';
-+      $matcher                = generate_matcher('[-\w]*');
-+      $char_class_at_end      = '[-\w]';
-+      $char_class_to_complete = '[-\w]';
-+} elsif ($cmd eq 'fuzzy-WORD-complete') {
-+      # Fuzzy completion of the current WORD.
-+      $char_class_before      = '\s';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'fuzzy-complete' ||
-+               $cmd eq 'skeleton-complete') {
-+      # Fuzzy completion of an arbitrary text.
-+      $char_class_before      = '\W';
-+      $matcher                = generate_matcher('.*?');
-+      $char_class_at_end      = '\w';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'suffix-complete') {
-+      # Fuzzy completion of an completing suffixes, like
-+      # completing test=hello from /blah/hello.
-+      $char_class_before      = '\S';
-+      $matcher                = generate_matcher('\S*');
-+      $char_class_at_end      = '\S';
-+      $char_class_to_complete = '\S';
-+} elsif ($cmd eq 'surround-complete') {
-+      # Completing contents of quotes and braces.
-+
-+      # Here we are using three named groups: s, b, p for quotes, braces
-+      # and parenthesis.
-+      $char_class_before      = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
-+
-+      $matcher                = generate_matcher('.*?');
-+
-+      # Here we match text till enclosing pair, using perl conditionals in
-+      # regexps (?(condition)yes-expression|no-expression).
-+      # -+    $char_class_at_end      = 
'.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))-+    $char_class_to_complete = '\S';
-+}
-+
-+my $lines = [];
-+
-+my $last_line = -1;
-+my $lines_after_cursor = 0;
-+
-+while (<STDIN>)
-+{
-+      $last_line++;
-+
-+      if ($last_line <= $cursor_row)
-+      {
-+              push @{$lines}, $_;
-+      }
-+      else
-+      {
-+              unshift @{$lines}, $_;
-+              $lines_after_cursor++;
-+      }
-+}
-+
-+$cursor_row = $last_line;
-+
-+# read the word behind the cursor
-+$_ = substr(@{$lines} [$cursor_row], 0, $cursor_column); # get the current 
line up to the cursor...
-+s/.*?($char_class_to_complete*)$/$1/;                 # ...and read the last 
word from it
-+my $word_to_complete = $_;
-+
-+# ignore the completed word itself
-+$self->{already_completed}{$word_to_complete} = 1;
-+
-+print stdout "$word_to_complete
";
-+
-+# search for matches
-+while (my $completion = find_match($self,
-+                                        $word_to_complete,
-+                                        $self->{next_row} // $cursor_row,
-+                                        $matcher->($word_to_complete),
-+                                        $char_class_before,
-+                                        $char_class_at_end)
-+) {
-+      calc_match_coords($self,
-+                                      $self->{next_row}+1,
-+                                      $completion);
-+      print stdout "$completion @{$self->{highlight}}
";
-+}
-+
-+leave($self);
-+
-+
-+
-+######################################################################
-+
-+# Finds the next matching completion in the row current row or above
-+# while skipping duplicates using skip_duplicates().
-+sub find_match {
-+    my ($self, $word_to_match, $current_row, $regexp, $char_class_before, 
$char_class_at_end) = @_;
-+    $self->{matches_in_row} //= [];
-+
-+    # cycle through all the matches in the current row if not starting a new 
search
-+    if (@{$self->{matches_in_row}}) {
-+        return skip_duplicates($self, $word_to_match, $current_row, $regexp, 
$char_class_before, $char_class_at_end);
-+    }
-+
-+
-+    my $i;
-+    # search through all the rows starting with current one or one above the 
last checked
-+    for ($i = $current_row; $i >= 0; --$i) {
-+        my $line = @{$lines} [$i];   # get the line of text from the row
-+
-+        if ($i == $cursor_row) {
-+            $line = substr $line, 0, $cursor_column;
-+        }
-+
-+        $_ = $line;
-+
-+        # find all the matches in the current line
-+        my $match;
-+        push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
-+                                                                         
(.*${char_class_before})
-+                                                                         
(?<match>
-+                                                                             
${regexp}
-+                                                                             
${char_class_at_end}*
-+                                                                         )
-+                                                                     /ix;
-+        # corner case: match at the very beginning of line
-+        push @{$self->{matches_in_row}}, $+{match} if $line =~ 
/^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
-+
-+        if (@{$self->{matches_in_row}}) {
-+            # remember which row should be searched next
-+            $self->{next_row} = --$i;
-+
-+            # arguments needed for find_match() mutual recursion
-+            return skip_duplicates($self, $word_to_match, $i, $regexp, 
$char_class_before, $char_class_at_end);
-+        }
-+    }
-+
-+    # no more possible completions, revert to the original word
-+    $self->{next_row} = -1 if $i < 0;
-+
-+    return undef;
-+}
-+
-+######################################################################
-+
-+# Checks whether the completion found by find_match() was already
-+# found and if it was, calls find_match() again to find the next
-+# completion.
-+#
-+# Takes all the arguments that find_match() would take, to make a
-+# mutually recursive call.
-+sub skip_duplicates {
-+    my $self = $_[0];
-+      my $current_row = $_[2];
-+      my $completion;
-+      if ($current_row >= $lines_after_cursor)
-+      {
-+              $completion = shift @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+      else
-+      {
-+              $completion = pop @{$self->{matches_in_row}}; # get the 
rightmost one
-+      }
-+
-+    # check for duplicates
-+    if (exists $self->{already_completed}{$completion}) {
-+        # skip this completion
-+        return find_match(@_);
-+    } else {
-+        $self->{already_completed}{$completion} = 1;
-+        return $completion;
-+    }
-+}
-+
-+######################################################################
-+
-+# Returns a function that takes a string and returns that string with
-+# this function's argument inserted between its every two characters.
-+# The resulting string is used as a regular expression matching the
-+# completion candidates.
-+sub generate_matcher {
-+    my $regex_between = shift;
-+
-+    sub {
-+        $_ = shift;
-+
-+        # sorry for this lispy code, I couldn't resist ;)
-+        (join "$regex_between",
-+         (map quotemeta,
-+          (split //)))
-+    }
-+}
-+
-+######################################################################
-+
-+sub calc_match_coords {
-+    my ($self, $linenum, $completion) = @_;
-+
-+    my $line = @{$lines} [$linenum];
-+    my $re = quotemeta $completion;
-+
-+    $line =~ /$re/;
-+
-+      #my ($beg_row, $beg_col) = $line->coord_of($-[0]);
-+      #my ($end_row, $end_col) = $line->coord_of($+[0]);
-+      my $beg = $-[0];
-+      my $end = $+[0];
-+
-+    if (exists $self->{highlight}) {
-+        delete $self->{highlight};
-+    }
-+    # () # TODO: what does () do in perl ????
-+
-+      if ($linenum >= $lines_after_cursor)
-+      {
-+              $linenum -= $lines_after_cursor;
-+      }
-+      else
-+      {
-+              $linenum = $last_line - $linenum;
-+      }
-+
-+    # $self->{highlight} = [$beg_row, $beg_col, $end_row, $end_col];
-+    $self->{highlight} = [$linenum, $beg, $end];
-+}
-+
-+######################################################################
-+
-+sub leave {
-+    my ($self) = @_;
-+
-+    delete $self->{next_row};
-+    delete $self->{matches_in_row};
-+    delete $self->{already_completed};
-+    delete $self->{highlight};
-+}
-diff -uraN st-0.8.4/st.c st-autocomplete/st.c
---- st-0.8.4/st.c      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.c       2022-01-10 23:43:52.199387990 +0400
-@@ -17,6 +17,7 @@
- #include <unistd.h>
- #include <wchar.h>
- 
-+#include "autocomplete.h"
- #include "st.h"
- #include "win.h"
- 
-@@ -2476,6 +2477,9 @@
-               return;
-       }
- 
-+      if ( row < term.row  || col < term.col )
-+              autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /*
-        * slide screen to keep cursor where we expect it -
-        * tscrollup would work here, but we can optimize to
-@@ -2595,3 +2599,241 @@
-       tfulldirt();
-       draw();
- }
-+
-+void autocomplete (const Arg * arg)
-+{
-+      static _Bool active = 0;
-+
-+      int acmpl_cmdindex = arg -> i;
-+
-+      static int acmpl_cmdindex_prev;
-+
-+      if (active == 0)
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+      static const char * const (acmpl_cmd []) = {
-+              [ACMPL_DEACTIVATE]      = "__DEACTIVATE__",
-+              [ACMPL_WORD]            = "word-complete",
-+              [ACMPL_WWORD]           = "WORD-complete",
-+              [ACMPL_FUZZY_WORD]      = "fuzzy-word-complete",
-+              [ACMPL_FUZZY_WWORD]     = "fuzzy-WORD-complete",
-+              [ACMPL_FUZZY]           = "fuzzy-complete",
-+              [ACMPL_SUFFIX]          = "suffix-complete",
-+              [ACMPL_SURROUND]        = "surround-complete",
-+              [ACMPL_UNDO]            = "__UNDO__",
-+      };
-+
-+      static char acmpl [1000];               // ACMPL_ISSUE: why 1000?
-+
-+      static FILE * acmpl_exec = NULL;
-+      static int acmpl_status;
-+
-+      static const char * stbuffile;
-+      static char target [1000];              // ACMPL_ISSUE: why 1000? 
dynamically allocate char array of size term.col
-+      static size_t targetlen;
-+
-+      static char completion [1000] = {0};            // ACMPL_ISSUE: why 
1000? dynamically allocate char array of size term.col
-+      static size_t complen_prev = 0;         // NOTE: always clear this 
variable after clearing completion
-+
-+      static int cx, cy;
-+
-+      // ACMPL_ISSUE: crashes when term.row is too small
-+
-+// Check for deactivation
-+
-+      if (acmpl_cmdindex == ACMPL_DEACTIVATE)
-+      {
-+
-+//     Deactivate autocomplete mode keeping current completion
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              complen_prev = 0;
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for undo
-+
-+      if (acmpl_cmdindex == ACMPL_UNDO)
-+      {
-+
-+//     Deactivate autocomplete mode recovering target
-+
-+              if (active)
-+              {
-+                      active = 0;
-+                      pclose (acmpl_exec);
-+                      remove (stbuffile);
-+
-+                      if (complen_prev)
-+                      {
-+                              selclear ();
-+                              for (size_t i = 0; i < complen_prev; i++)
-+                                      ttywrite ((char []) { '' }, 1, 1);     
// ACMPL_ISSUE: I'm not sure that this is the right way
-+                              complen_prev = 0;
-+                              ttywrite (target, targetlen, 0);                
// ACMPL_ISSUE: I'm not sure that this is a right solution
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-+// Check for command change
-+
-+      if (acmpl_cmdindex != acmpl_cmdindex_prev)
-+      {
-+
-+//     If command is changed, goto acmpl_begin avoiding rewriting st buffer
-+
-+              if (active)
-+              {
-+                      acmpl_cmdindex_prev = acmpl_cmdindex;
-+
-+                      goto acmpl_begin;
-+              }
-+      }
-+
-+// If not active
-+
-+      if (active == 0)
-+      {
-+              acmpl_cmdindex_prev = acmpl_cmdindex;
-+              cx = term.c.x;
-+              cy = term.c.y;
-+
-+//     Write st buffer to a temp file
-+
-+              stbuffile = tmpnam (NULL);              // check for return 
value ...
-+                                                                              
// ACMPL_ISSUE: use coprocesses instead of temp files
-+
-+              FILE * stbuf = fopen (stbuffile, "w"); // check for opening 
error ...
-+              char * stbufline = malloc (term.col + 2); // check for 
allocating error ...
-+
-+              for (size_t y = 0; y < term.row; y++)
-+              {
-+                      size_t x = 0;
-+                      for (; x < term.col; x++)
-+                              utf8encode (term.line [y] [x].u, stbufline + x);
-+                      if (term.line [y] [x - 1].mode & ATTR_WRAP)
-+                      {
-+                              x--;
-+                              if (y <= cy) cy--;
-+                      }
-+                      else
-+                      {
-+                              stbufline [x] = '
';
-+                      }
-+                      stbufline [x + 1] = 0;
-+                      fputs (stbufline, stbuf);
-+              }
-+
-+              free (stbufline);
-+              fclose (stbuf);
-+
-+acmpl_begin:
-+
-+//     Run st-autocomplete
-+
-+              sprintf (
-+                      acmpl,
-+                      "cat %100s | st-autocomplete %500s %d %d",      // 
ACMPL_ISSUE: why 100 and 500?
-+                      stbuffile,
-+                      acmpl_cmd [acmpl_cmdindex],
-+                      cy,
-+                      cx
-+              );
-+
-+              acmpl_exec = popen (acmpl, "r");                // ACMPL_ISSUE: 
popen isn't defined by The Standard. Does it work in BSDs for example?
-+                                                                              
                // check for popen error ...
-+
-+//     Read the target, targetlen
-+
-+              fscanf (acmpl_exec, "%500s
", target); // check for scanning error ...
-+              targetlen = strlen (target);
-+      }
-+
-+// Read a completion if exists (acmpl_status)
-+
-+      unsigned line, beg, end;
-+
-+      acmpl_status = fscanf (acmpl_exec, "%500s %u %u %u
", completion, & line, & beg, & end);
-+                                                                              
                // ACMPL_ISSUE: why 500? use term.col instead
-+
-+// Exit if no completions found
-+
-+      if (active == 0 && acmpl_status == EOF)
-+      {
-+
-+//    Close st-autocomplete and exit without activating the autocomplete mode
-+
-+              pclose (acmpl_exec);
-+              remove (stbuffile);
-+              return;
-+      }
-+
-+// If completions found, enable autocomplete mode and autocomplete the target
-+
-+      active = 1;
-+
-+// Clear target before first completion
-+
-+      if (complen_prev == 0)
-+      {
-+              for (size_t i = 0; i < targetlen; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+      }
-+
-+// Clear previuos completion if this is not the first
-+
-+      else
-+      {
-+              selclear ();
-+              for (size_t i = 0; i < complen_prev; i++)
-+                      ttywrite ((char []) { '' }, 1, 1);     // ACMPL_ISSUE: 
I'm not sure that this is a right solution
-+              complen_prev = 0;
-+      }
-+
-+// If no more completions found, reset and restart
-+
-+      if (acmpl_status == EOF)
-+      {
-+              active = 0;
-+              pclose (acmpl_exec);
-+              ttywrite (target, targetlen, 0);
-+              goto acmpl_begin;
-+      }
-+
-+// Count wrapped lines before the current line
-+
-+      int wl = 0;
-+
-+      int tl = line;
-+
-+      for (int l = 0; l < tl; l++)
-+              if (term.line [l] [term.col - 1].mode & ATTR_WRAP)
-+              {
-+                      wl++;
-+                      tl++;
-+              }
-+
-+// Read the new completion and autcomplete
-+
-+      end--;
-+
-+      selstart (beg, line + wl, 0);
-+      selextend (end % term.col, line + wl + end / term.col, 1, 0);
-+      xsetsel (getsel ());
-+
-+      complen_prev = strlen (completion);
-+      ttywrite (completion, complen_prev, 0);
-+}
-diff -uraN st-0.8.4/st.h st-autocomplete/st.h
---- st-0.8.4/st.h      2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/st.h       2021-12-14 20:28:59.272432749 +0400
-@@ -77,6 +77,8 @@
-       const char *s;
- } Arg;
- 
-+void autocomplete (const Arg *);
-+
- void die(const char *, ...);
- void redraw(void);
- void draw(void);
-diff -uraN st-0.8.4/x.c st-autocomplete/x.c
---- st-0.8.4/x.c       2021-12-14 20:03:03.981322164 +0400
-+++ st-autocomplete/x.c        2021-12-14 20:30:30.045830893 +0400
-@@ -1803,11 +1803,15 @@
-       /* 1. shortcuts */
-       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-               if (ksym == bp->keysym && match(bp->mod, e->state)) {
-+                      if (bp -> func != autocomplete)
-+                              autocomplete ((const Arg []) { ACMPL_DEACTIVATE 
});
-                       bp->func(&(bp->arg));
-                       return;
-               }
-       }
- 
-+      autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
-+
-       /* 2. custom keys from config.h */
-       if ((customkey = kmap(ksym, e->state))) {
-               ttywrite(customkey, strlen(customkey), 1);


Reply via email to