st-0.8.5-autocomplete-20220327-230120.diff - sites - public wiki contents of su… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
st-0.8.5-autocomplete-20220327-230120.diff (20937B) | |
--- | |
1 diff -uraN st-0.8.5/autocomplete.h st-autocomplete/autocomplete.h | |
2 --- st-0.8.5/autocomplete.h 1970-01-01 04:00:00.000000000 +0400 | |
3 +++ st-autocomplete/autocomplete.h 2022-03-13 02:45:34.586842452 … | |
4 @@ -0,0 +1,16 @@ | |
5 +# ifndef __ST_AUTOCOMPLETE_H | |
6 +# define __ST_AUTOCOMPLETE_H | |
7 + | |
8 +enum { | |
9 + ACMPL_DEACTIVATE, | |
10 + ACMPL_WORD, | |
11 + ACMPL_WWORD, | |
12 + ACMPL_FUZZY_WORD, | |
13 + ACMPL_FUZZY_WWORD, | |
14 + ACMPL_FUZZY, | |
15 + ACMPL_SUFFIX, | |
16 + ACMPL_SURROUND, | |
17 + ACMPL_UNDO, | |
18 +}; | |
19 + | |
20 +# endif // __ST_AUTOCOMPLETE_H | |
21 diff -uraN st-0.8.5/config.def.h st-autocomplete/config.def.h | |
22 --- st-0.8.5/config.def.h 2022-03-13 02:45:34.586842452 +0400 | |
23 +++ st-autocomplete/config.def.h 2022-03-13 02:45:34.586842452 +0… | |
24 @@ -170,6 +170,8 @@ | |
25 */ | |
26 static uint forcemousemod = ShiftMask; | |
27 | |
28 +#include "autocomplete.h" | |
29 + | |
30 /* | |
31 * Internal mouse shortcuts. | |
32 * Beware that overloading Button1 will disable the selection. | |
33 @@ -187,6 +189,8 @@ | |
34 #define MODKEY Mod1Mask | |
35 #define TERMMOD (ControlMask|ShiftMask) | |
36 | |
37 +#define ACMPL_MOD ControlMask|Mod1Mask | |
38 + | |
39 static Shortcut shortcuts[] = { | |
40 /* mask keysym function argumen… | |
41 { XK_ANY_MOD, XK_Break, sendbreak, {.i = … | |
42 @@ -201,6 +205,14 @@ | |
43 { TERMMOD, XK_Y, selpaste, {.i = … | |
44 { ShiftMask, XK_Insert, selpaste, {.i = … | |
45 { TERMMOD, XK_Num_Lock, numlock, {.i = … | |
46 + { ACMPL_MOD, XK_slash, autocomplete, { .i = … | |
47 + { ACMPL_MOD, XK_period, autocomplete, { .i = … | |
48 + { ACMPL_MOD, XK_comma, autocomplete, { .i = … | |
49 + { ACMPL_MOD, XK_apostrophe, autocomplete, { .i = … | |
50 + { ACMPL_MOD, XK_semicolon, autocomplete, { .i = … | |
51 + { ACMPL_MOD, XK_bracketright,autocomplete, { .i = … | |
52 + { ACMPL_MOD, XK_bracketleft, autocomplete, { .i = … | |
53 + { ACMPL_MOD, XK_equal, autocomplete, { .i = … | |
54 }; | |
55 | |
56 /* | |
57 diff -uraN st-0.8.5/Makefile st-autocomplete/Makefile | |
58 --- st-0.8.5/Makefile 2022-03-13 02:45:34.586842452 +0400 | |
59 +++ st-autocomplete/Makefile 2022-03-13 02:45:34.586842452 +0400 | |
60 @@ -44,6 +44,8 @@ | |
61 mkdir -p $(DESTDIR)$(PREFIX)/bin | |
62 cp -f st $(DESTDIR)$(PREFIX)/bin | |
63 chmod 755 $(DESTDIR)$(PREFIX)/bin/st | |
64 + cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin | |
65 + chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete | |
66 mkdir -p $(DESTDIR)$(MANPREFIX)/man1 | |
67 sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/ma… | |
68 chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 | |
69 @@ -52,6 +54,7 @@ | |
70 | |
71 uninstall: | |
72 rm -f $(DESTDIR)$(PREFIX)/bin/st | |
73 + rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete | |
74 rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 | |
75 | |
76 .PHONY: all options clean dist install uninstall | |
77 diff -uraN st-0.8.5/st-autocomplete st-autocomplete/st-autocomplete | |
78 --- st-0.8.5/st-autocomplete 1970-01-01 04:00:00.000000000 +0400 | |
79 +++ st-autocomplete/st-autocomplete 2022-03-27 22:57:29.018288223… | |
80 @@ -0,0 +1,310 @@ | |
81 +#!/usr/bin/perl | |
82 +#######################################################################… | |
83 +# Copyright (C) 2012-2017 Wojciech Siewierski … | |
84 +# … | |
85 +# This program is free software: you can redistribute it and/or modify … | |
86 +# it under the terms of the GNU General Public License as published by … | |
87 +# the Free Software Foundation, either version 3 of the License, or … | |
88 +# (at your option) any later version. … | |
89 +# … | |
90 +# This program is distributed in the hope that it will be useful, … | |
91 +# but WITHOUT ANY WARRANTY; without even the implied warranty of … | |
92 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the … | |
93 +# GNU General Public License for more details. … | |
94 +# … | |
95 +# You should have received a copy of the GNU General Public License … | |
96 +# along with this program. If not, see <http://www.gnu.org/licenses/>.… | |
97 +#######################################################################… | |
98 + | |
99 +my ($cmd, $cursor_row, $cursor_column) = @ARGV; | |
100 + | |
101 +my $lines = []; | |
102 +my $lines1 = []; | |
103 + | |
104 +my $last_line = -1; | |
105 +my $lines_before_cursor = 0; | |
106 + | |
107 +while (<stdin>) | |
108 +{ | |
109 + $last_line++; | |
110 + | |
111 + s/[^[:print:]]/?/g; | |
112 + | |
113 + if ($last_line < $cursor_row) | |
114 + { | |
115 + unshift @{$lines1}, $_; | |
116 + $lines_before_cursor++; | |
117 + } | |
118 + else | |
119 + { | |
120 + unshift @{$lines}, $_; | |
121 + } | |
122 +} | |
123 + | |
124 +foreach (@{$lines1}) | |
125 +{ | |
126 + unshift @{$lines}, $_; | |
127 +} | |
128 + | |
129 +my $cursor_row_in = $cursor_row; | |
130 + | |
131 +$cursor_row = $last_line; | |
132 + | |
133 + | |
134 +$self = {}; | |
135 + | |
136 +# A reference to a function that transforms the completed word | |
137 +# into a regex matching the completions. Usually generated by | |
138 +# generate_matcher(). | |
139 +# | |
140 +# For example | |
141 +# $fun = generate_matcher(".*"); | |
142 +# $fun->("foo"); | |
143 +# would return "f.*o.*o" | |
144 +# | |
145 +# In other words, indirectly decides which characters can | |
146 +# appear in the completion. | |
147 +my $matcher; | |
148 + | |
149 +# A regular expression matching a character before each match. | |
150 +# For example, it you want to match the text after a | |
151 +# whitespace, set it to "\s". | |
152 +my $char_class_before; | |
153 + | |
154 +# A regular expression matching every character in the entered | |
155 +# text that will be used to find matching completions. Usually | |
156 +# "\w" or similar. | |
157 +my $char_class_to_complete; | |
158 + | |
159 +# A regular expression matching every allowed last character | |
160 +# of the completion (uses greedy matching). | |
161 +my $char_class_at_end; | |
162 + | |
163 +if ($cmd eq 'word-complete') { | |
164 + # Basic word completion. Completes the current word | |
165 + # without any special matching. | |
166 + $char_class_before = '[^-\w]'; | |
167 + $matcher = sub { quotemeta shift }; # identity | |
168 + $char_class_at_end = '[-\w]'; | |
169 + $char_class_to_complete = '[-\w]'; | |
170 +} elsif ($cmd eq 'WORD-complete') { | |
171 + # The same as above but in the Vim meaning of a "WORD" -- | |
172 + # whitespace delimited. | |
173 + $char_class_before = '\s'; | |
174 + $matcher = sub { quotemeta shift }; | |
175 + $char_class_at_end = '\S'; | |
176 + $char_class_to_complete = '\S'; | |
177 +} elsif ($cmd eq 'fuzzy-word-complete' || | |
178 + $cmd eq 'skeleton-word-complete') { | |
179 + # Fuzzy completion of the current word. | |
180 + $char_class_before = '[^-\w]'; | |
181 + $matcher = generate_matcher('[-\w]*'); | |
182 + $char_class_at_end = '[-\w]'; | |
183 + $char_class_to_complete = '[-\w]'; | |
184 +} elsif ($cmd eq 'fuzzy-WORD-complete') { | |
185 + # Fuzzy completion of the current WORD. | |
186 + $char_class_before = '\s'; | |
187 + $matcher = generate_matcher('\S*'); | |
188 + $char_class_at_end = '\S'; | |
189 + $char_class_to_complete = '\S'; | |
190 +} elsif ($cmd eq 'fuzzy-complete' || | |
191 + $cmd eq 'skeleton-complete') { | |
192 + # Fuzzy completion of an arbitrary text. | |
193 + $char_class_before = '\W'; | |
194 + $matcher = generate_matcher('.*?'); | |
195 + $char_class_at_end = '\w'; | |
196 + $char_class_to_complete = '\S'; | |
197 +} elsif ($cmd eq 'suffix-complete') { | |
198 + # Fuzzy completion of an completing suffixes, like | |
199 + # completing test=hello from /blah/hello. | |
200 + $char_class_before = '\S'; | |
201 + $matcher = generate_matcher('\S*'); | |
202 + $char_class_at_end = '\S'; | |
203 + $char_class_to_complete = '\S'; | |
204 +} elsif ($cmd eq 'surround-complete') { | |
205 + # Completing contents of quotes and braces. | |
206 + | |
207 + # Here we are using three named groups: s, b, p for quotes, bra… | |
208 + # and parenthesis. | |
209 + $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())'; | |
210 + | |
211 + $matcher = generate_matcher('.*?'); | |
212 + | |
213 + # Here we match text till enclosing pair, using perl conditiona… | |
214 + # regexps (?(condition)yes-expression|no-expression). | |
215 + # \0 is used to hack concatenation with '*' later in the code. | |
216 + $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q}))… | |
217 + $char_class_to_complete = '\S'; | |
218 +} | |
219 + | |
220 + | |
221 +# use the last used word or read the word behind the cursor | |
222 +my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_c… | |
223 + … | |
224 + | |
225 +print stdout "$word_to_complete\n"; | |
226 + | |
227 +if ($word_to_complete) { | |
228 + while (1) { | |
229 + # ignore the completed word itself | |
230 + $self->{already_completed}{$word_to_complete} = 1; | |
231 + | |
232 + # continue the last search or start from the current row | |
233 + my $completion = find_match($self, | |
234 + … | |
235 + … | |
236 + … | |
237 + … | |
238 + … | |
239 + if ($completion) { | |
240 + print stdout $completion."\n".join ("\n", @{$se… | |
241 + } | |
242 + else { | |
243 + last; | |
244 + } | |
245 + } | |
246 +} | |
247 + | |
248 +###################################################################### | |
249 + | |
250 +sub highlight_match { | |
251 + my ($self, $linenum, $completion) = @_; | |
252 + | |
253 + # clear_highlight($self); | |
254 + | |
255 + my $line = @{$lines}[$linenum]; | |
256 + my $re = quotemeta $completion; | |
257 + | |
258 + $line =~ /$re/; | |
259 + | |
260 + my $beg = $-[0]; | |
261 + my $end = $+[0]; | |
262 + | |
263 + if ($linenum >= $lines_before_cursor) | |
264 + { | |
265 + $lline = $last_line - $lines_before_cursor; | |
266 + $linenum -= $lines_before_cursor; | |
267 + $linenum = $lline - $linenum; | |
268 + $linenum += $lines_before_cursor; | |
269 + } | |
270 + | |
271 + | |
272 + $self->{highlight} = [$linenum, $beg, $end]; | |
273 +} | |
274 + | |
275 +###################################################################### | |
276 + | |
277 +sub read_word_at_coord { | |
278 + my ($self, $row, $col, $char_class) = @_; | |
279 + | |
280 + $_ = substr(@{$lines} [$row], 0, $col); # get the current line up t… | |
281 + s/.*?($char_class*)$/$1/; # ...and read the last word… | |
282 + return $_; | |
283 +} | |
284 + | |
285 +###################################################################### | |
286 + | |
287 +# Returns a function that takes a string and returns that string with | |
288 +# this function's argument inserted between its every two characters. | |
289 +# The resulting string is used as a regular expression matching the | |
290 +# completion candidates. | |
291 +sub generate_matcher { | |
292 + my $regex_between = shift; | |
293 + | |
294 + sub { | |
295 + $_ = shift; | |
296 + | |
297 + # sorry for this lispy code, I couldn't resist ;) | |
298 + (join "$regex_between", | |
299 + (map quotemeta, | |
300 + (split //))) | |
301 + } | |
302 +} | |
303 + | |
304 +###################################################################### | |
305 + | |
306 +# Checks whether the completion found by find_match() was already | |
307 +# found and if it was, calls find_match() again to find the next | |
308 +# completion. | |
309 +# | |
310 +# Takes all the arguments that find_match() would take, to make a | |
311 +# mutually recursive call. | |
312 +sub skip_duplicates { | |
313 + my ($self, $word_to_match, $current_row, $regexp, $char_class_befor… | |
314 + my $completion; | |
315 + | |
316 + if ($current_row <= $lines_before_cursor) | |
317 + { | |
318 + $completion = shift @{$self->{matches_in_row}}; # get t… | |
319 + } | |
320 + else | |
321 + { | |
322 + $completion = pop @{$self->{matches_in_row}}; # get the… | |
323 + } | |
324 + | |
325 + # check for duplicates | |
326 + if (exists $self->{already_completed}{$completion}) { | |
327 + # skip this completion | |
328 + return find_match(@_); | |
329 + } else { | |
330 + $self->{already_completed}{$completion} = 1; | |
331 + | |
332 + highlight_match($self, | |
333 + $self->{next_row}+1, | |
334 + $completion); | |
335 + | |
336 + return $completion; | |
337 + } | |
338 +} | |
339 + | |
340 +###################################################################### | |
341 + | |
342 +# Finds the next matching completion in the row current row or above | |
343 +# while skipping duplicates using skip_duplicates(). | |
344 +sub find_match { | |
345 + my ($self, $word_to_match, $current_row, $regexp, $char_class_befor… | |
346 + $self->{matches_in_row} //= []; | |
347 + | |
348 + # cycle through all the matches in the current row if not starting … | |
349 + if (@{$self->{matches_in_row}}) { | |
350 + return skip_duplicates($self, $word_to_match, $current_row, $re… | |
351 + } | |
352 + | |
353 + | |
354 + my $i; | |
355 + # search through all the rows starting with current one or one abov… | |
356 + for ($i = $current_row; $i >= 0; --$i) { | |
357 + my $line = @{$lines}[$i]; # get the line of text from the row | |
358 + | |
359 + # if ($i == $cursor_row) { | |
360 + # $line = substr $line, 0, $cursor_column; | |
361 + # } | |
362 + | |
363 + $_ = $line; | |
364 + | |
365 + # find all the matches in the current line | |
366 + my $match; | |
367 + push @{$self->{matches_in_row}}, $+{match} while ($_, $match) =… | |
368 + … | |
369 + … | |
370 + … | |
371 + … | |
372 + … | |
373 + /i… | |
374 + # corner case: match at the very beginning of line | |
375 + push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${cha… | |
376 + | |
377 + if (@{$self->{matches_in_row}}) { | |
378 + # remember which row should be searched next | |
379 + $self->{next_row} = --$i; | |
380 + | |
381 + # arguments needed for find_match() mutual recursion | |
382 + return skip_duplicates($self, $word_to_match, $i, $regexp, … | |
383 + } | |
384 + } | |
385 + | |
386 + # # no more possible completions, revert to the original word | |
387 + # undo_completion($self) if $i < 0; | |
388 + | |
389 + return undef; | |
390 +} | |
391 diff -uraN st-0.8.5/st.c st-autocomplete/st.c | |
392 --- st-0.8.5/st.c 2022-03-13 02:45:34.586842452 +0400 | |
393 +++ st-autocomplete/st.c 2022-03-27 22:28:39.041693478 +0400 | |
394 @@ -17,6 +17,7 @@ | |
395 #include <unistd.h> | |
396 #include <wchar.h> | |
397 | |
398 +#include "autocomplete.h" | |
399 #include "st.h" | |
400 #include "win.h" | |
401 | |
402 @@ -2569,6 +2570,8 @@ | |
403 return; | |
404 } | |
405 | |
406 + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); | |
407 + | |
408 /* | |
409 * slide screen to keep cursor where we expect it - | |
410 * tscrollup would work here, but we can optimize to | |
411 @@ -2688,3 +2691,256 @@ | |
412 tfulldirt(); | |
413 draw(); | |
414 } | |
415 + | |
416 +void autocomplete (const Arg * arg) | |
417 +{ | |
418 + static _Bool active = 0; | |
419 + | |
420 + int acmpl_cmdindex = arg -> i; | |
421 + | |
422 + static int acmpl_cmdindex_prev; | |
423 + | |
424 + if (active == 0) | |
425 + acmpl_cmdindex_prev = acmpl_cmdindex; | |
426 + | |
427 + static const char * const (acmpl_cmd []) = { | |
428 + [ACMPL_DEACTIVATE] = "__DEACTIVATE__", | |
429 + [ACMPL_WORD] = "word-complete", | |
430 + [ACMPL_WWORD] = "WORD-complete", | |
431 + [ACMPL_FUZZY_WORD] = "fuzzy-word-complete", | |
432 + [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete", | |
433 + [ACMPL_FUZZY] = "fuzzy-complete", | |
434 + [ACMPL_SUFFIX] = "suffix-complete", | |
435 + [ACMPL_SURROUND] = "surround-complete", | |
436 + [ACMPL_UNDO] = "__UNDO__", | |
437 + }; | |
438 + | |
439 + static char acmpl [1000]; // ACMPL_ISSUE: why 10… | |
440 + | |
441 + static FILE * acmpl_exec = NULL; | |
442 + static int acmpl_status; | |
443 + | |
444 + static const char * stbuffile; | |
445 + static char target [1000]; // ACMPL_ISSUE: why 1… | |
446 + static size_t targetlen; | |
447 + | |
448 + static char completion [1000] = {0}; // ACMPL_IS… | |
449 + static size_t complen_prev = 0; // NOTE: always … | |
450 + | |
451 + static int cx, cy; | |
452 + | |
453 + // ACMPL_ISSUE: crashes when term.row is too small | |
454 + | |
455 +// Check for deactivation | |
456 + | |
457 + if (acmpl_cmdindex == ACMPL_DEACTIVATE) | |
458 + { | |
459 + | |
460 +// Deactivate autocomplete mode keeping current completion | |
461 + | |
462 + if (active) | |
463 + { | |
464 + active = 0; | |
465 + pclose (acmpl_exec); | |
466 + remove (stbuffile); | |
467 + | |
468 + if (complen_prev) | |
469 + { | |
470 + selclear (); | |
471 + complen_prev = 0; | |
472 + } | |
473 + } | |
474 + | |
475 + return; | |
476 + } | |
477 + | |
478 +// Check for undo | |
479 + | |
480 + if (acmpl_cmdindex == ACMPL_UNDO) | |
481 + { | |
482 + | |
483 +// Deactivate autocomplete mode recovering target | |
484 + | |
485 + if (active) | |
486 + { | |
487 + active = 0; | |
488 + pclose (acmpl_exec); | |
489 + remove (stbuffile); | |
490 + | |
491 + if (complen_prev) | |
492 + { | |
493 + selclear (); | |
494 + for (size_t i = 0; i < complen_prev; i+… | |
495 + ttywrite ((char []) { '\b' }, 1… | |
496 + complen_prev = 0; | |
497 + ttywrite (target, targetlen, 0); … | |
498 + } | |
499 + } | |
500 + | |
501 + return; | |
502 + } | |
503 + | |
504 +// Check for command change | |
505 + | |
506 + if (acmpl_cmdindex != acmpl_cmdindex_prev) | |
507 + { | |
508 + | |
509 +// If command is changed, goto acmpl_begin avoiding rewriting st bu… | |
510 + | |
511 + if (active) | |
512 + { | |
513 + acmpl_cmdindex_prev = acmpl_cmdindex; | |
514 + | |
515 + goto acmpl_begin; | |
516 + } | |
517 + } | |
518 + | |
519 +// If not active | |
520 + | |
521 + if (active == 0) | |
522 + { | |
523 + acmpl_cmdindex_prev = acmpl_cmdindex; | |
524 + cx = term.c.x; | |
525 + cy = term.c.y; | |
526 + | |
527 +// Write st buffer to a temp file | |
528 + | |
529 + stbuffile = tmpnam (NULL); // ACMPL_ISSU… | |
530 + … | |
531 + | |
532 + FILE * stbuf = fopen (stbuffile, "w"); // ACMPL_ISSUE: … | |
533 + char * stbufline = malloc (term.col + 2); // ACMPL_ISSU… | |
534 + | |
535 + int cxp = 0; | |
536 + | |
537 + for (size_t y = 0; y < term.row; y++) | |
538 + { | |
539 + if (y == term.c.y) cx += cxp * term.col; | |
540 + | |
541 + size_t x = 0; | |
542 + for (; x < term.col; x++) | |
543 + utf8encode (term.line [y] [x].u, stbufl… | |
544 + if (term.line [y] [x - 1].mode & ATTR_WRAP) | |
545 + { | |
546 + x--; | |
547 + if (y <= term.c.y) cy--; | |
548 + cxp++; | |
549 + } | |
550 + else | |
551 + { | |
552 + stbufline [x] = '\n'; | |
553 + cxp = 0; | |
554 + } | |
555 + stbufline [x + 1] = 0; | |
556 + fputs (stbufline, stbuf); | |
557 + } | |
558 + | |
559 + free (stbufline); | |
560 + fclose (stbuf); | |
561 + | |
562 +acmpl_begin: | |
563 + | |
564 +// Run st-autocomplete | |
565 + | |
566 + sprintf ( | |
567 + acmpl, | |
568 + "cat %100s | st-autocomplete %500s %d %d", … | |
569 + stbuffile, | |
570 + acmpl_cmd [acmpl_cmdindex], | |
571 + cy, | |
572 + cx | |
573 + ); | |
574 + | |
575 + acmpl_exec = popen (acmpl, "r"); // ACMP… | |
576 + … | |
577 + | |
578 +// Read the target, targetlen | |
579 + | |
580 + fscanf (acmpl_exec, "%500s\n", target); // ACMPL_ISSUE:… | |
581 + targetlen = strlen (target); | |
582 + } | |
583 + | |
584 +// Read a completion if exists (acmpl_status) | |
585 + | |
586 + unsigned line, beg, end; | |
587 + | |
588 + acmpl_status = fscanf (acmpl_exec, "%500[^\n]\n%u\n%u\n%u\n", c… | |
589 + … | |
590 + | |
591 +// Exit if no completions found | |
592 + | |
593 + if (active == 0 && acmpl_status == EOF) | |
594 + { | |
595 + | |
596 +// Close st-autocomplete and exit without activating the autocomplet… | |
597 + | |
598 + pclose (acmpl_exec); | |
599 + remove (stbuffile); | |
600 + return; | |
601 + } | |
602 + | |
603 +// If completions found, enable autocomplete mode and autocomplete the … | |
604 + | |
605 + active = 1; | |
606 + | |
607 +// Clear target before first completion | |
608 + | |
609 + if (complen_prev == 0) | |
610 + { | |
611 + for (size_t i = 0; i < targetlen; i++) | |
612 + ttywrite ((char []) { '\b' }, 1, 1); // … | |
613 + } | |
614 + | |
615 +// Clear previuos completion if this is not the first | |
616 + | |
617 + else | |
618 + { | |
619 + selclear (); | |
620 + for (size_t i = 0; i < complen_prev; i++) | |
621 + ttywrite ((char []) { '\b' }, 1, 1); // … | |
622 + complen_prev = 0; | |
623 + } | |
624 + | |
625 +// If no more completions found, reset and restart | |
626 + | |
627 + if (acmpl_status == EOF) | |
628 + { | |
629 + active = 0; | |
630 + pclose (acmpl_exec); | |
631 + ttywrite (target, targetlen, 0); | |
632 + goto acmpl_begin; | |
633 + } | |
634 + | |
635 +// Count wrapped lines before the current line | |
636 + | |
637 + int wl = 0; | |
638 + | |
639 + int tl = line; | |
640 + | |
641 + for (int l = 0; l < tl; l++) | |
642 + if (term.line [l] [term.col - 1].mode & ATTR_WRAP) | |
643 + { | |
644 + wl++; | |
645 + tl++; | |
646 + } | |
647 + | |
648 +// Autcomplete | |
649 + | |
650 + complen_prev = strlen (completion); | |
651 + ttywrite (completion, complen_prev, 0); | |
652 + | |
653 + if (line == cy && beg > cx) | |
654 + { | |
655 + beg += complen_prev - targetlen; | |
656 + end += complen_prev - targetlen; | |
657 + | |
658 + // ACMPL_ISSUE: highlignthing doesn't work when "line =… | |
659 + // but coordinates are c… | |
660 + } | |
661 + | |
662 + end--; | |
663 + | |
664 + selstart (beg % term.col, line + wl + beg / term.col, 0); | |
665 + selextend (end % term.col, line + wl + end / term.col, 1, 0); | |
666 + xsetsel (getsel ()); | |
667 +} | |
668 diff -uraN st-0.8.5/st.h st-autocomplete/st.h | |
669 --- st-0.8.5/st.h 2022-03-13 02:45:34.586842452 +0400 | |
670 +++ st-autocomplete/st.h 2022-03-13 02:45:34.586842452 +0400 | |
671 @@ -77,6 +77,8 @@ | |
672 const char *s; | |
673 } Arg; | |
674 | |
675 +void autocomplete (const Arg *); | |
676 + | |
677 void die(const char *, ...); | |
678 void redraw(void); | |
679 void draw(void); | |
680 diff -uraN st-0.8.5/x.c st-autocomplete/x.c | |
681 --- st-0.8.5/x.c 2022-03-13 02:45:34.586842452 +0400 | |
682 +++ st-autocomplete/x.c 2022-03-13 02:45:34.590175835 +0400 | |
683 @@ -1834,11 +1834,20 @@ | |
684 /* 1. shortcuts */ | |
685 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { | |
686 if (ksym == bp->keysym && match(bp->mod, e->state)) { | |
687 + if (bp -> func != autocomplete) | |
688 + autocomplete ((const Arg []) { ACMPL_DE… | |
689 bp->func(&(bp->arg)); | |
690 return; | |
691 } | |
692 } | |
693 | |
694 + if (!( | |
695 + len == 0 && | |
696 + e -> state & ~ignoremod // ACMPL_ISSUE: … | |
697 + | ACMPL_MOD == ACMPL_MOD | |
698 + )) | |
699 + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); | |
700 + | |
701 /* 2. custom keys from config.h */ | |
702 if ((customkey = kmap(ksym, e->state))) { | |
703 ttywrite(customkey, strlen(customkey), 1); |