Introduction
Introduction Statistics Contact Development Disclaimer Help
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);
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.