sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 45691fc2ba333f578d2ee3c9186809368bb33ddc
parent 3919de58931e6efc09f0fe336f19cdacf239e9d8
Author: elbachir-one <bachiralfa@gmail.com>
Date:   Thu,  4 Jul 2024 00:00:46 +0100

Fixed a warrnig message (the use of mkstemp')

Diffstat:
Mst.suckless.org/patches/autocomplete/index.md | 4++++
Ast.suckless.org/patches/autocomplete/st-autocomplete-20240703-6508693.diff | 703+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 707 insertions(+), 0 deletions(-)

diff --git a/st.suckless.org/patches/autocomplete/index.md b/st.suckless.org/patches/autocomplete/index.md @@ -72,6 +72,9 @@ Download -------- * [st-0.8.5-autocomplete-20220327-230120.diff](st-0.8.5-autocomplete-20220327-230120.diff) +The use of `tmpnam' is dangerous, better use `mkstemp' +* [st-autocomplete-20240703-6508693.diff](st-autocomplete-20240703-6508693.diff) + Contribution ------------ You can create issues and do pull requests on [this gitlab repo](https://gitlab.com/GasparVardanyan/st-autocomplete). @@ -80,3 +83,4 @@ Authors ------- * [Wojciech Siewierski](https://github.com/vifon) * [Gaspar Vardanyan](https://gitlab.com/GasparVardanyan) +* [El Bachir](https://github.com/elbachir-one) diff --git a/st.suckless.org/patches/autocomplete/st-autocomplete-20240703-6508693.diff b/st.suckless.org/patches/autocomplete/st-autocomplete-20240703-6508693.diff @@ -0,0 +1,703 @@ +From 650869359d3568dd2a000d474054e835a9c7ac74 Mon Sep 17 00:00:00 2001 +From: elbachir-one <bachiralfa@gmail.com> +Date: Wed, 3 Jul 2024 22:44:40 +0100 +Subject: [PATCH] The use of mkstemp' + +--- + Makefile | 3 + + autocomplete.h | 16 +++ + config.def.h | 12 ++ + st-autocomplete | 310 ++++++++++++++++++++++++++++++++++++++++++++++++ + st.c | 227 +++++++++++++++++++++++++++++++++++ + st.h | 2 + + x.c | 9 ++ + 7 files changed, 579 insertions(+) + create mode 100644 autocomplete.h + create mode 100644 st-autocomplete + +diff --git a/Makefile b/Makefile +index 93fed02..9aff9e0 100644 +--- a/Makefile ++++ b/Makefile +@@ -38,6 +38,8 @@ install: st + 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 +@@ -46,6 +48,7 @@ install: st + + uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/st ++ rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 + + .PHONY: all clean dist install uninstall +diff --git a/autocomplete.h b/autocomplete.h +new file mode 100644 +index 0000000..fc88447 +--- /dev/null ++++ b/autocomplete.h +@@ -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 --git a/config.def.h b/config.def.h +index 2cd740a..b74e03e 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -170,6 +170,8 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++#include "autocomplete.h" ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +@@ -187,6 +189,8 @@ static MouseShortcut mshortcuts[] = { + #define MODKEY Mod1Mask + #define TERMMOD (ControlMask|ShiftMask) + ++#define ACMPL_MOD ControlMask|Mod1Mask ++ + static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, +@@ -201,6 +205,14 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { ACMPL_MOD, XK_slash, autocomplete, { .i = ACMPL_WORD } }, ++ { ACMPL_MOD, XK_period, autocomplete, { .i = ACMPL_FUZZY_WORD } }, ++ { ACMPL_MOD, XK_comma, autocomplete, { .i = ACMPL_FUZZY } }, ++ { ACMPL_MOD, XK_apostrophe, autocomplete, { .i = ACMPL_SUFFIX } }, ++ { ACMPL_MOD, XK_semicolon, autocomplete, { .i = ACMPL_SURROUND } }, ++ { ACMPL_MOD, XK_bracketright,autocomplete, { .i = ACMPL_WWORD } }, ++ { ACMPL_MOD, XK_bracketleft, autocomplete, { .i = ACMPL_FUZZY_WWORD } }, ++ { ACMPL_MOD, XK_equal, autocomplete, { .i = ACMPL_UNDO } }, + }; + + /* +diff --git a/st-autocomplete b/st-autocomplete +new file mode 100644 +index 0000000..0fad536 +--- /dev/null ++++ b/st-autocomplete +@@ -0,0 +1,310 @@ ++#!/usr/bin/perl ++######################################################################### ++# 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 # ++# 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; ++ ++my $lines = []; ++my $lines1 = []; ++ ++my $last_line = -1; ++my $lines_before_cursor = 0; ++ ++while (<stdin>) ++{ ++ $last_line++; ++ ++ s/[^[:print:]]/?/g; ++ ++ if ($last_line < $cursor_row) ++ { ++ unshift @{$lines1}, $_; ++ $lines_before_cursor++; ++ } ++ else ++ { ++ unshift @{$lines}, $_; ++ } ++} ++ ++foreach (@{$lines1}) ++{ ++ unshift @{$lines}, $_; ++} ++ ++my $cursor_row_in = $cursor_row; ++ ++$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(). ++# ++# 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). ++ # \0 is used to hack concatenation with '*' later in the code. ++ $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0'; ++ $char_class_to_complete = '\S'; ++} ++ ++ ++# 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); ++ ++print stdout "$word_to_complete\n"; ++ ++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) { ++ print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n"; ++ } ++ 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_before_cursor) ++ { ++ $lline = $last_line - $lines_before_cursor; ++ $linenum -= $lines_before_cursor; ++ $linenum = $lline - $linenum; ++ $linenum += $lines_before_cursor; ++ } ++ ++ ++ $self->{highlight} = [$linenum, $beg, $end]; ++} ++ ++###################################################################### ++ ++sub read_word_at_coord { ++ my ($self, $row, $col, $char_class) = @_; ++ ++ $_ = 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 $_; ++} ++ ++###################################################################### ++ ++# 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 //))) ++ } ++} ++ ++###################################################################### ++ ++# 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, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; ++ my $completion; ++ ++ if ($current_row <= $lines_before_cursor) ++ { ++ $completion = shift @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ else ++ { ++ $completion = pop @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ ++ # check for duplicates ++ if (exists $self->{already_completed}{$completion}) { ++ # skip this completion ++ return find_match(@_); ++ } else { ++ $self->{already_completed}{$completion} = 1; ++ ++ highlight_match($self, ++ $self->{next_row}+1, ++ $completion); ++ ++ return $completion; ++ } ++} ++ ++###################################################################### ++ ++# 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 ++ # undo_completion($self) if $i < 0; ++ ++ return undef; ++} +diff --git a/st.c b/st.c +index 57c6e96..9ff8d00 100644 +--- a/st.c ++++ b/st.c +@@ -17,6 +17,7 @@ + #include <unistd.h> + #include <wchar.h> + ++#include "autocomplete.h" + #include "st.h" + #include "win.h" + +@@ -2557,6 +2558,8 @@ tresize(int col, int row) + return; + } + ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to +@@ -2676,3 +2679,227 @@ redraw(void) + 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 FILE *acmpl_exec = NULL; ++ static int acmpl_status; ++ static char *stbuffile; ++ static char *target = NULL; ++ static size_t targetlen; ++ static char *completion = NULL; ++ static size_t complen_prev = 0; ++ static int cx, cy; ++ ++ if (acmpl_cmdindex == ACMPL_DEACTIVATE) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ complen_prev = 0; ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex == ACMPL_UNDO) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ ttywrite(target, targetlen, 0); ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex != acmpl_cmdindex_prev) { ++ if (active) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ goto acmpl_begin; ++ } ++ } ++ ++ if (active == 0) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ cx = term.c.x; ++ cy = term.c.y; ++ ++ char filename[] = "/tmp/st-autocomplete-XXXXXX"; ++ int fd = mkstemp(filename); ++ ++ if (fd == -1) { ++ perror("mkstemp"); ++ return; ++ } ++ ++ stbuffile = strdup(filename); ++ ++ FILE *stbuf = fdopen(fd, "w"); ++ if (!stbuf) { ++ perror("fdopen"); ++ close(fd); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char *stbufline = malloc(term.col + 2); ++ if (!stbufline) { ++ perror("malloc"); ++ fclose(stbuf); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ int cxp = 0; ++ for (size_t y = 0; y < term.row; y++) { ++ if (y == term.c.y) cx += cxp * term.col; ++ ++ 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 <= term.c.y) cy--; ++ cxp++; ++ } else { ++ stbufline[x] = '\n'; ++ cxp = 0; ++ } ++ stbufline[x + 1] = 0; ++ fputs(stbufline, stbuf); ++ } ++ ++ free(stbufline); ++ fclose(stbuf); ++ ++acmpl_begin: ++ target = malloc(term.col + 1); ++ completion = malloc(term.col + 1); ++ if (!target || !completion) { ++ perror("malloc"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char acmpl[1500]; ++ snprintf(acmpl, sizeof(acmpl), ++ "cat %s | st-autocomplete %s %d %d", ++ stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx); ++ ++ acmpl_exec = popen(acmpl, "r"); ++ if (!acmpl_exec) { ++ perror("popen"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ if (fscanf(acmpl_exec, "%s\n", target) != 1) { ++ perror("fscanf"); ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ targetlen = strlen(target); ++ } ++ ++ unsigned line, beg, end; ++ ++ acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end); ++ if (acmpl_status == EOF) { ++ if (active == 0) { ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ active = 0; ++ pclose(acmpl_exec); ++ ttywrite(target, targetlen, 0); ++ goto acmpl_begin; ++ } ++ ++ active = 1; ++ ++ if (complen_prev == 0) { ++ for (size_t i = 0; i < targetlen; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ } else { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ } ++ ++ complen_prev = strlen(completion); ++ ttywrite(completion, complen_prev, 0); ++ ++ if (line == cy && beg > cx) { ++ beg += complen_prev - targetlen; ++ end += complen_prev - targetlen; ++ } ++ ++ end--; ++ ++ 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++; ++ } ++ ++ selstart(beg % term.col, line + wl + beg / term.col, 0); ++ selextend(end % term.col, line + wl + end / term.col, 1, 0); ++ xsetsel(getsel()); ++} +diff --git a/st.h b/st.h +index fd3b0d8..113ebad 100644 +--- a/st.h ++++ b/st.h +@@ -77,6 +77,8 @@ typedef union { + const char *s; + } Arg; + ++void autocomplete (const Arg *); ++ + void die(const char *, ...); + void redraw(void); + void draw(void); +diff --git a/x.c b/x.c +index bd23686..c647721 100644 +--- a/x.c ++++ b/x.c +@@ -1859,11 +1859,20 @@ kpress(XEvent *ev) + /* 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; + } + } + ++ if (!( ++ len == 0 && ++ e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way ++ | ACMPL_MOD == ACMPL_MOD ++ )) ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); +-- +2.45.2 +