Introduction
Introduction Statistics Contact Development Disclaimer Help
st-vimBrowse-20191203-2b8333f.diff - sites - public wiki contents of suckless.o…
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-vimBrowse-20191203-2b8333f.diff (45812B)
---
1 From de020f0c06440fd19a36e1b001ef9e0058f73369 Mon Sep 17 00:00:00 2001
2 From: Julius Huelsmann <[email protected]>
3 Date: Thu, 7 Nov 2019 09:08:49 +0100
4 Subject: [PATCH 1/2] [PATCH:VIM]: first version
5
6 ---
7 Makefile | 6 +-
8 config.def.h | 27 ++
9 dynamicArray.h | 90 ++++++
10 st.c | 794 +++++++++++++++++++++++++++++++++++++++++++++----
11 st.h | 31 +-
12 win.h | 2 +
13 x.c | 51 +++-
14 7 files changed, 936 insertions(+), 65 deletions(-)
15 create mode 100644 dynamicArray.h
16
17 diff --git a/Makefile b/Makefile
18 index 470ac86..7d93347 100644
19 --- a/Makefile
20 +++ b/Makefile
21 @@ -21,8 +21,8 @@ config.h:
22 .c.o:
23 $(CC) $(STCFLAGS) -c $<
24
25 -st.o: config.h st.h win.h
26 -x.o: arg.h config.h st.h win.h
27 +st.o: config.h st.h win.h dynamicArray.h
28 +x.o: arg.h config.h st.h win.h dynamicArray.h
29
30 $(OBJ): config.h config.mk
31
32 @@ -35,7 +35,7 @@ clean:
33 dist: clean
34 mkdir -p st-$(VERSION)
35 cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\
36 - config.def.h st.info st.1 arg.h st.h win.h $(SRC)\
37 + config.def.h st.info st.1 arg.h st.h win.h dynamicArray…
38 st-$(VERSION)
39 tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
40 rm -rf st-$(VERSION)
41 diff --git a/config.def.h b/config.def.h
42 index 6ebea98..1b0e501 100644
43 --- a/config.def.h
44 +++ b/config.def.h
45 @@ -149,6 +149,12 @@ static unsigned int mousebg = 0;
46 * doesn't match the ones requested.
47 */
48 static unsigned int defaultattr = 11;
49 +/// Colors for the entities that are highlighted in normal mode.
50 +static unsigned int highlightBg = 160;
51 +static unsigned int highlightFg = 15;
52 +/// Colors for the line and column that is marked 'current' in normal m…
53 +static unsigned int currentBg = 0;
54 +static unsigned int currentFg = 15;
55
56 /*
57 * Internal mouse shortcuts.
58 @@ -162,10 +168,12 @@ static MouseShortcut mshortcuts[] = {
59
60 /* Internal keyboard shortcuts. */
61 #define MODKEY Mod1Mask
62 +#define AltMask Mod1Mask
63 #define TERMMOD (ControlMask|ShiftMask)
64
65 static Shortcut shortcuts[] = {
66 /* mask keysym function argumen…
67 + { AltMask, XK_c, normalMode, {.i = …
68 { XK_ANY_MOD, XK_Break, sendbreak, {.i = …
69 { ControlMask, XK_Print, toggleprinter, {.i = …
70 { ShiftMask, XK_Print, printscreen, {.i = …
71 @@ -178,6 +186,8 @@ static Shortcut shortcuts[] = {
72 { TERMMOD, XK_Y, selpaste, {.i = …
73 { ShiftMask, XK_Insert, selpaste, {.i = …
74 { TERMMOD, XK_Num_Lock, numlock, {.i = …
75 + { ShiftMask, XK_Page_Up, kscrollup, {.i = -…
76 + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -…
77 };
78
79 /*
80 @@ -456,3 +466,20 @@ static char ascii_printable[] =
81 " !\"#$%&'()*+,-./0123456789:;<=>?"
82 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
83 "`abcdefghijklmnopqrstuvwxyz{|}~";
84 +
85 +
86 +/// word sepearors normal mode
87 +char wordDelimSmall[] = " \t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
88 +char wordDelimLarge[] = " \t"; /// <Word sepearors normal mode (capital…
89 +
90 +/// Shortcusts executed in normal mode (which should not already be in …
91 +struct NormalModeShortcuts normalModeShortcuts [] = {
92 + { 'C', "?Building\n" },
93 + { 'c', "/Building\n" },
94 + { 'F', "?: error:\n" },
95 + { 'f', "/: error:\n" },
96 + { 'X', "?juli@machine\n" },
97 + { 'x', "/juli@machine\n" },
98 +};
99 +
100 +size_t const amountNormalModeShortcuts = sizeof(normalModeShortcuts) / …
101 diff --git a/dynamicArray.h b/dynamicArray.h
102 new file mode 100644
103 index 0000000..c65fbef
104 --- /dev/null
105 +++ b/dynamicArray.h
106 @@ -0,0 +1,90 @@
107 +#include <stdint.h>
108 +#include <assert.h>
109 +#include <stdlib.h>
110 +#include <string.h>
111 +#include <stdbool.h>
112 +
113 +/// Struct for which this file offers functionality in order to expand …
114 +/// and set / get its content.
115 +typedef struct DynamicArray {
116 + uint8_t itemSize;
117 + uint32_t index;
118 + uint32_t allocated;
119 + char* content;
120 +} DynamicArray;
121 +
122 +#define EXPAND_STEP 15
123 +
124 +/// Default initializers for the dynamic array.
125 +#define CHAR_ARRAY {1, 0, 0, NULL}
126 +#define WORD_ARRAY {2, 0, 0, NULL}
127 +#define DWORD_ARRAY {4, 0, 0, NULL}
128 +#define QWORD_ARRAY {8, 0, 0, NULL}
129 +/// (Wasteful) utf-8 array, that always used 4 bytes in order to displa…
130 +/// even if the space is not required.
131 +#define UTF8_ARRAY DWORD_ARRAY
132 +
133 +
134 +inline char*
135 +gnext(DynamicArray *s) { return &s->content[s->index+=s->itemSize]; }
136 +
137 +inline char*
138 +get(DynamicArray const * s) { return &s->content[s->index]; }
139 +
140 +inline char*
141 +view(DynamicArray const * s, uint32_t i) {
142 + return s->content + i*s->itemSize;
143 +}
144 +
145 +inline char *
146 +viewEnd(DynamicArray const *s, uint32_t i) {
147 + return s->content + s->index - (i + 1) * s->itemSize;
148 +}
149 +
150 +inline void
151 +set(DynamicArray* s, char const *vals, uint8_t amount) {
152 + assert(amount <= s->itemSize);
153 + memcpy(s->content + s->index, vals, amount);
154 +}
155 +
156 +inline void
157 +snext(DynamicArray* s, char const *vals, uint8_t amount) {
158 + set(s, vals, amount);
159 + s->index+=s->itemSize;
160 +}
161 +
162 +inline void
163 +empty(DynamicArray* s) { s->index = 0; }
164 +
165 +inline bool
166 +isEmpty(DynamicArray* s) { return s->index == 0; }
167 +
168 +inline uint32_t
169 +size(DynamicArray const * s) { return s->index / s->itemSize; }
170 +
171 +inline void
172 +pop(DynamicArray* s) { s->index -= s->itemSize; }
173 +
174 +inline void checkSetNext(DynamicArray *s, char const *c, uint8_t amount…
175 + if (s->index + s->itemSize >= s->allocated) {
176 + if ((s->content = (char *)realloc(
177 + s->content, s->allocate…
178 + exit(1);
179 + };
180 + }
181 + if (amount) { snext(s, c, amount); }
182 +}
183 +
184 +char *checkGetNext(DynamicArray *s) {
185 + if (s->index + s->itemSize >= s->allocated) {
186 + if ((s->content = (char *)realloc(
187 + s->content, s->allocate…
188 + exit(1);
189 + };
190 + }
191 + s->index+=s->itemSize;
192 + return viewEnd(s, 0);
193 +}
194 +
195 +#define append(s, c) checkSetNext((s), (char const *) (c), (s)->itemSiz…
196 +#define appendPartial(s, c, i) checkSetNext((s), (char const *) (c), (i…
197 diff --git a/st.c b/st.c
198 index ede7ae6..27bfca8 100644
199 --- a/st.c
200 +++ b/st.c
201 @@ -1,8 +1,10 @@
202 /* See LICENSE for license details. */
203 +#include <assert.h>
204 #include <ctype.h>
205 #include <errno.h>
206 #include <fcntl.h>
207 #include <limits.h>
208 +#include <math.h>
209 #include <pwd.h>
210 #include <stdarg.h>
211 #include <stdio.h>
212 @@ -17,8 +19,10 @@
213 #include <unistd.h>
214 #include <wchar.h>
215
216 +
217 #include "st.h"
218 #include "win.h"
219 +#include "dynamicArray.h"
220
221 #if defined(__linux)
222 #include <pty.h>
223 @@ -35,6 +39,8 @@
224 #define ESC_ARG_SIZ 16
225 #define STR_BUF_SIZ ESC_BUF_SIZ
226 #define STR_ARG_SIZ ESC_ARG_SIZ
227 +//#define HISTSIZE 100
228 +#define HISTSIZE 2000
229
230 /* macros */
231 #define IS_SET(flag) ((term.mode & (flag)) != 0)
232 @@ -42,6 +48,9 @@
233 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
234 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
235 #define ISDELIM(u) (u && wcschr(worddelimiters, u))
236 +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term…
237 + term.scr + HISTSIZE + 1) % HISTSIZE] : \
238 + term.line[(y) - term.scr])
239
240 enum term_mode {
241 MODE_WRAP = 1 << 0,
242 @@ -97,16 +106,18 @@ typedef struct {
243 int mode;
244 int type;
245 int snap;
246 - /*
247 - * Selection variables:
248 - * nb – normalized coordinates of the beginning of the select…
249 - * ne – normalized coordinates of the end of the selection
250 - * ob – original coordinates of the beginning of the selection
251 - * oe – original coordinates of the end of the selection
252 - */
253 + /// Selection variables:
254 + /// ob – original coordinates of the beginning of the selecti…
255 + /// oe – original coordinates of the end of the selection
256 + struct {
257 + int x, y, scroll;
258 + } ob, oe;
259 + /// Selection variables; currently displayed chunk.
260 + /// nb – normalized coordinates of the beginning of the selec…
261 + /// ne – normalized coordinates of the end of the selection
262 struct {
263 int x, y;
264 - } nb, ne, ob, oe;
265 + } nb, ne;
266
267 int alt;
268 } Selection;
269 @@ -117,6 +128,9 @@ typedef struct {
270 int col; /* nb col */
271 Line *line; /* screen */
272 Line *alt; /* alternate screen */
273 + Line hist[HISTSIZE]; /* history buffer */
274 + int histi; /* history index */
275 + int scr; /* scroll back */
276 int *dirty; /* dirtyness of lines */
277 TCursor c; /* cursor */
278 int ocx; /* old cursor col */
279 @@ -152,6 +166,50 @@ typedef struct {
280 int narg; /* nb of args */
281 } STREscape;
282
283 +/// Position (x, y , and current scroll in the y dimension).
284 +typedef struct Position {
285 + uint32_t x;
286 + uint32_t y;
287 + uint32_t yScr;
288 +} Position;
289 +
290 +/// The entire normal mode state, consisting of an operation
291 +/// and a motion.
292 +struct NormalModeState {
293 + Position initialPosition;
294 + // Operation:
295 + struct OperationState {
296 + enum Operation {
297 + noop,
298 + visual,
299 + visualLine,
300 + yank
301 + } op;
302 + Position startPosition;
303 + } command;
304 + // Motions:
305 + struct MotionState {
306 + uint32_t amount;
307 + enum Search {
308 + none,
309 + forward,
310 + backward,
311 + } search;
312 + Position searchPosition;
313 + bool finished;
314 + } motion;
315 +} stateNormalMode;
316 +
317 +
318 +DynamicArray searchString = UTF8_ARRAY;
319 +DynamicArray commandHist0 = UTF8_ARRAY;
320 +DynamicArray commandHist1 = UTF8_ARRAY;
321 +DynamicArray highlights = QWORD_ARRAY;
322 +/// History command toggle
323 +bool toggle = false;
324 +#define currentCommand toggle ? &commandHist0 : &commandHist1
325 +#define lastCommand toggle ? &commandHist1 : &commandHist0
326 +
327 static void execsh(char *, char **);
328 static void stty(char **);
329 static void sigchld(int);
330 @@ -184,8 +242,8 @@ static void tnewline(int);
331 static void tputtab(int);
332 static void tputc(Rune);
333 static void treset(void);
334 -static void tscrollup(int, int);
335 -static void tscrolldown(int, int);
336 +static void tscrollup(int, int, int);
337 +static void tscrolldown(int, int, int);
338 static void tsetattr(int *, int);
339 static void tsetchar(Rune, Glyph *, int, int);
340 static void tsetdirt(int, int);
341 @@ -231,6 +289,12 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0x…
342 static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10…
343 static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10F…
344
345 +void applyPosition(Position const *pos) {
346 + term.c.x = pos->x;
347 + term.c.y = pos->y;
348 + term.scr = pos->yScr;
349 +}
350 +
351 ssize_t
352 xwrite(int fd, const char *s, size_t len)
353 {
354 @@ -409,17 +473,22 @@ tlinelen(int y)
355 {
356 int i = term.col;
357
358 - if (term.line[y][i - 1].mode & ATTR_WRAP)
359 + if (TLINE(y)[i - 1].mode & ATTR_WRAP)
360 return i;
361
362 - while (i > 0 && term.line[y][i - 1].u == ' ')
363 + while (i > 0 && TLINE(y)[i - 1].u == ' ')
364 --i;
365
366 return i;
367 }
368
369 void
370 -selstart(int col, int row, int snap)
371 +xselstart(int col, int row, int snap) {
372 + selstart(col, row, term.scr, snap);
373 +}
374 +
375 +void
376 +selstart(int col, int row, int scroll, int snap)
377 {
378 selclear();
379 sel.mode = SEL_EMPTY;
380 @@ -428,6 +497,7 @@ selstart(int col, int row, int snap)
381 sel.snap = snap;
382 sel.oe.x = sel.ob.x = col;
383 sel.oe.y = sel.ob.y = row;
384 + sel.oe.scroll = sel.ob.scroll = scroll;
385 selnormalize();
386
387 if (sel.snap != 0)
388 @@ -436,10 +506,13 @@ selstart(int col, int row, int snap)
389 }
390
391 void
392 -selextend(int col, int row, int type, int done)
393 -{
394 - int oldey, oldex, oldsby, oldsey, oldtype;
395 +xselextend(int col, int row, int type, int done) {
396 + selextend(col, row, term.scr, type, done);
397 +}
398
399 +void
400 +selextend(int col, int row, int scroll, int type, int done)
401 +{
402 if (sel.mode == SEL_IDLE)
403 return;
404 if (done && sel.mode == SEL_EMPTY) {
405 @@ -447,18 +520,22 @@ selextend(int col, int row, int type, int done)
406 return;
407 }
408
409 - oldey = sel.oe.y;
410 - oldex = sel.oe.x;
411 - oldsby = sel.nb.y;
412 - oldsey = sel.ne.y;
413 - oldtype = sel.type;
414 + int const oldey = sel.oe.y;
415 + int const oldex = sel.oe.x;
416 + int const oldscroll = sel.oe.scroll;
417 + int const oldsby = sel.nb.y;
418 + int const oldsey = sel.ne.y;
419 + int const oldtype = sel.type;
420
421 sel.oe.x = col;
422 sel.oe.y = row;
423 + sel.oe.scroll = scroll;
424 +
425 selnormalize();
426 sel.type = type;
427
428 - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.ty…
429 + if (oldey != sel.oe.y || oldex != sel.oe.x || oldscroll != sel.…
430 + || oldtype != sel.type || sel.mode == SEL_EMPTY)
431 tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
432
433 sel.mode = done ? SEL_IDLE : SEL_READY;
434 @@ -467,17 +544,21 @@ selextend(int col, int row, int type, int done)
435 void
436 selnormalize(void)
437 {
438 - int i;
439 -
440 - if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
441 - sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
442 - sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
443 + sel.nb.y = INTERVAL(sel.ob.y + term.scr - sel.ob.scroll, 0, ter…
444 + sel.ne.y = INTERVAL(sel.oe.y + term.scr - sel.oe.scroll, 0, ter…
445 + if (sel.type == SEL_REGULAR && sel.nb.y != sel.ne.y) {
446 + sel.nb.x = sel.nb.y < sel.ne.y ? sel.ob.x : sel.oe.x;
447 + sel.ne.x = sel.nb.y < sel.ne.y ? sel.oe.x : sel.ob.x;
448 } else {
449 sel.nb.x = MIN(sel.ob.x, sel.oe.x);
450 sel.ne.x = MAX(sel.ob.x, sel.oe.x);
451 }
452 - sel.nb.y = MIN(sel.ob.y, sel.oe.y);
453 - sel.ne.y = MAX(sel.ob.y, sel.oe.y);
454 +
455 + if (sel.nb.y > sel.ne.y) {
456 + int32_t const tmp = sel.nb.y;
457 + sel.nb.y = sel.ne.y;
458 + sel.ne.y = tmp;
459 + }
460
461 selsnap(&sel.nb.x, &sel.nb.y, -1);
462 selsnap(&sel.ne.x, &sel.ne.y, +1);
463 @@ -485,7 +566,7 @@ selnormalize(void)
464 /* expand selection over line breaks */
465 if (sel.type == SEL_RECTANGULAR)
466 return;
467 - i = tlinelen(sel.nb.y);
468 + int i = tlinelen(sel.nb.y);
469 if (i < sel.nb.x)
470 sel.nb.x = i;
471 if (tlinelen(sel.ne.y) <= sel.ne.x)
472 @@ -521,7 +602,7 @@ selsnap(int *x, int *y, int direction)
473 * Snap around if the word wraps around at the end or
474 * beginning of a line.
475 */
476 - prevgp = &term.line[*y][*x];
477 + prevgp = &TLINE(*y)[*x];
478 prevdelim = ISDELIM(prevgp->u);
479 for (;;) {
480 newx = *x + direction;
481 @@ -536,14 +617,14 @@ selsnap(int *x, int *y, int direction)
482 yt = *y, xt = *x;
483 else
484 yt = newy, xt = newx;
485 - if (!(term.line[yt][xt].mode & ATTR_WRA…
486 + if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
487 break;
488 }
489
490 if (newx >= tlinelen(newy))
491 break;
492
493 - gp = &term.line[newy][newx];
494 + gp = &TLINE(newy)[newx];
495 delim = ISDELIM(gp->u);
496 if (!(gp->mode & ATTR_WDUMMY) && (delim != prev…
497 || (delim && gp->u != prevgp->u…
498 @@ -564,14 +645,14 @@ selsnap(int *x, int *y, int direction)
499 *x = (direction < 0) ? 0 : term.col - 1;
500 if (direction < 0) {
501 for (; *y > 0; *y += direction) {
502 - if (!(term.line[*y-1][term.col-1].mode
503 + if (!(TLINE(*y-1)[term.col-1].mode
504 & ATTR_WRAP)) {
505 break;
506 }
507 }
508 } else if (direction > 0) {
509 for (; *y < term.row-1; *y += direction) {
510 - if (!(term.line[*y][term.col-1].mode
511 + if (!(TLINE(*y)[term.col-1].mode
512 & ATTR_WRAP)) {
513 break;
514 }
515 @@ -591,24 +672,32 @@ getsel(void)
516 if (sel.ob.x == -1)
517 return NULL;
518
519 - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
520 + int32_t syb = sel.ob.y - sel.ob.scroll + term.scr;
521 + int32_t sye = sel.oe.y - sel.oe.scroll + term.scr;
522 + if (syb > sye) {
523 + int32_t tmp = sye;
524 + sye = syb;
525 + syb = tmp;
526 + }
527 +
528 + bufsize = (term.col+1) * (sye - syb + 1) * UTF_SIZ;
529 ptr = str = xmalloc(bufsize);
530
531 /* append every set & selected glyph to the selection */
532 - for (y = sel.nb.y; y <= sel.ne.y; y++) {
533 + for (y = syb; y <= sye; y++) {
534 if ((linelen = tlinelen(y)) == 0) {
535 *ptr++ = '\n';
536 continue;
537 }
538
539 if (sel.type == SEL_RECTANGULAR) {
540 - gp = &term.line[y][sel.nb.x];
541 + gp = &TLINE(y)[sel.nb.x];
542 lastx = sel.ne.x;
543 } else {
544 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0…
545 - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
546 + gp = &TLINE(y)[syb == y ? sel.nb.x : 0];
547 + lastx = (sye == y) ? sel.ne.x : term.col-1;
548 }
549 - last = &term.line[y][MIN(lastx, linelen-1)];
550 + last = &TLINE(y)[MIN(lastx, linelen-1)];
551 while (last >= gp && last->u == ' ')
552 --last;
553
554 @@ -831,6 +920,9 @@ void
555 ttywrite(const char *s, size_t n, int may_echo)
556 {
557 const char *next;
558 + Arg arg = (Arg) { .i = term.scr };
559 +
560 + kscrolldown(&arg);
561
562 if (may_echo && IS_SET(MODE_ECHO))
563 twrite(s, n, 1);
564 @@ -1042,13 +1134,53 @@ tswapscreen(void)
565 }
566
567 void
568 -tscrolldown(int orig, int n)
569 +kscrolldown(const Arg* a)
570 +{
571 + int n = a->i;
572 +
573 + if (n < 0)
574 + n = term.row + n;
575 +
576 + if (n > term.scr)
577 + n = term.scr;
578 +
579 + if (term.scr > 0) {
580 + term.scr -= n;
581 + selscroll(0, -n);
582 + tfulldirt();
583 + }
584 +}
585 +
586 +void
587 +kscrollup(const Arg* a)
588 +{
589 + int n = a->i;
590 +
591 + if (n < 0)
592 + n = term.row + n;
593 +
594 + if (term.scr <= HISTSIZE-n) {
595 + term.scr += n;
596 + selscroll(0, n);
597 + tfulldirt();
598 + }
599 +}
600 +
601 +void
602 +tscrolldown(int orig, int n, int copyhist)
603 {
604 int i;
605 Line temp;
606
607 LIMIT(n, 0, term.bot-orig+1);
608
609 + if (copyhist) {
610 + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
611 + temp = term.hist[term.histi];
612 + term.hist[term.histi] = term.line[term.bot];
613 + term.line[term.bot] = temp;
614 + }
615 +
616 tsetdirt(orig, term.bot-n);
617 tclearregion(0, term.bot-n+1, term.col-1, term.bot);
618
619 @@ -1062,13 +1194,23 @@ tscrolldown(int orig, int n)
620 }
621
622 void
623 -tscrollup(int orig, int n)
624 +tscrollup(int orig, int n, int copyhist)
625 {
626 int i;
627 Line temp;
628
629 LIMIT(n, 0, term.bot-orig+1);
630
631 + if (copyhist) {
632 + term.histi = (term.histi + 1) % HISTSIZE;
633 + temp = term.hist[term.histi];
634 + term.hist[term.histi] = term.line[orig];
635 + term.line[orig] = temp;
636 + }
637 +
638 + if (term.scr > 0 && term.scr < HISTSIZE)
639 + term.scr = MIN(term.scr + n, HISTSIZE-1);
640 +
641 tclearregion(0, orig, term.col-1, orig+n-1);
642 tsetdirt(orig+n, term.bot);
643
644 @@ -1088,6 +1230,7 @@ selscroll(int orig, int n)
645 return;
646
647 if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig…
648 + sel.oe.scroll = sel.ob.scroll = term.scr;
649 if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < ter…
650 selclear();
651 return;
652 @@ -1117,13 +1260,544 @@ tnewline(int first_col)
653 int y = term.c.y;
654
655 if (y == term.bot) {
656 - tscrollup(term.top, 1);
657 + tscrollup(term.top, 1, 1);
658 } else {
659 y++;
660 }
661 tmoveto(first_col ? 0 : term.c.x, y);
662 }
663
664 +int
665 +currentLine(int x, int y)
666 +{
667 + return (x == term.c.x || y == term.c.y);
668 +}
669 +
670 +int
671 +highlighted(int x, int y)
672 +{
673 + // Compute the legal bounds for a hit:
674 + int32_t const stringSize = size(&searchString);
675 + int32_t xMin = x - stringSize;
676 + int32_t yMin = y;
677 + while (xMin < 0 && yMin > 0) { //< I think this temds to be mor…
678 + xMin += term.col; // division + modulo.
679 + --yMin;
680 + }
681 + if (xMin < 0) { xMin = 0; }
682 +
683 + uint32_t highSize = size(&highlights);
684 + uint32_t *ptr = (uint32_t*) highlights.content;
685 + for (uint32_t i = 0; i < highSize; ++i) {
686 + int32_t const sx = *(ptr++);
687 + int32_t const sy = *(ptr++);
688 + if (BETWEEN(sy, yMin, y) && (sy != yMin || sx > xMin) &…
689 + return true;
690 + }
691 + }
692 + return false;
693 +}
694 +
695 +int mod(int a, int b) {
696 + while (a < 0) {
697 + a+= b;
698 + }
699 + return a % b;
700 +}
701 +
702 +void displayString(DynamicArray const *str, Glyph *g, int yPos) {
703 + // Threshold: if there is nothing or no space to print, do not …
704 + if (term.col == 0 || str->index == 0) {
705 + term.dirty[yPos] = 1; //< mark this line as 'dirty', be…
706 + // marked dirty when scrolling due to string display.
707 + return;
708 + }
709 +
710 + uint32_t lineSize = MIN(size(str), term.col / 3);
711 + uint32_t xEnd = term.col - 1;
712 + assert(lineSize <= 1 + xEnd); //< as lineSize <= term.col/3 <= …
713 + uint32_t xStart = 1 + xEnd - lineSize;
714 +
715 + Line line = malloc(sizeof(Glyph) * lineSize);
716 + assert(str->index - 1 >= lineSize - 1); //< lineSize <= str->i…
717 +
718 + for (uint32_t lineIdx = 0; lineIdx < lineSize; lineIdx++) {
719 + line[lineIdx] = *g;
720 + char* end = viewEnd(str, lineSize - lineIdx - 1);
721 + memcpy(&line[lineIdx].u, end, str->itemSize);
722 + }
723 + xdrawline(TLINE(yPos), 0, yPos, xStart);
724 + xdrawline(line -xStart, xStart, yPos, xEnd+1);
725 + free(line); // that sucks.
726 +}
727 +
728 +/// Print either the current command or the last comman din case the cu…
729 +void printCommandString() {
730 + Glyph g = {'c', ATTR_ITALIC | ATTR_FAINT , defaultfg, defaultbg…
731 + if (term.c.y == term.row-1) { g.mode ^= ATTR_CURRENT; } //< don…
732 + DynamicArray * cc = currentCommand;
733 + displayString(isEmpty(cc) ? lastCommand : cc, &g, term.row - 1);
734 + //displayString(lastCommand, &g, term.row - 2);
735 +}
736 +
737 +void printSearchString() {
738 + Glyph g = {'c', ATTR_ITALIC | ATTR_BOLD_FAINT, defaultfg, defau…
739 + if (term.c.y == term.row-2) { g.mode ^= ATTR_CURRENT; } //< don…
740 + displayString(&searchString, &g, term.row - 2);
741 +}
742 +
743 +/// Default state if no operation is performed.
744 +struct NormalModeState defaultNormalMode = {{0,0,0}, {noop, {0, 0, 0}},…
745 +
746 +void enableMode(enum Operation o) {
747 + stateNormalMode.command.op = o;
748 + stateNormalMode.command.startPosition.x = term.c.x;
749 + stateNormalMode.command.startPosition.y = term.c.y;
750 + stateNormalMode.command.startPosition.yScr = term.scr;
751 +}
752 +
753 +bool normalModeEnabled = false;
754 +
755 +void onNormalModeStart() {
756 + normalModeEnabled = true;
757 +}
758 +
759 +void onNormalModeStop() { //XXX breaks if resized
760 + normalModeEnabled = false;
761 + applyPosition(&stateNormalMode.initialPosition);
762 +}
763 +
764 +void moveLine(int8_t sign) {
765 + if (sign == -1) {
766 + if (term.c.y-- == 0) {
767 + if (++term.scr == HISTSIZE) {
768 + term.c.y = term.row - 1;
769 + term.scr = 0;
770 + } else {
771 + term.c.y = 0;
772 + }
773 + }
774 + } else {
775 + term.c.x = 0;
776 + if (++term.c.y == term.row) {
777 + if (term.scr-- == 0) {
778 + term.c.y = 0;
779 + term.scr = HISTSIZE - 1;
780 + } else {
781 + term.c.y = term.row - 1;
782 + }
783 + }
784 + }
785 +}
786 +
787 +void moveLetter(int8_t sign) {
788 + term.c.x += sign;
789 + if (!BETWEEN(term.c.x, 0, term.col-1)) {
790 + if (term.c.x < 0) {
791 + term.c.x = term.col - 1;
792 + moveLine(sign);
793 + } else {
794 + term.c.x = 0;
795 + moveLine(sign);
796 + }
797 + }
798 +}
799 +
800 +bool contains (char ksym, char const * values, uint32_t amount) {
801 + for (uint32_t i = 0; i < amount; i++) { if (ksym == values[i]) …
802 + return false;
803 +}
804 +
805 +
806 +void terminateCommand(bool abort) {
807 + stateNormalMode.command = defaultNormalMode.command; //< clear …
808 + stateNormalMode.motion = defaultNormalMode.motion;
809 + selclear(); //< clear …
810 +
811 + if (!abort) { toggle = !toggle; }
812 + empty(currentCommand);
813 +
814 + printCommandString();
815 + printSearchString();
816 + //tsetdirt(0, term.row-3);
817 +}
818 +inline void exitCommand() { terminateCommand(false); }
819 +inline void abortCommand() { terminateCommand(true); }
820 +
821 +/// Go to next occurrence of string relative to the current location
822 +/// conduct search, starting at start pos
823 +bool
824 +gotoString(int8_t sign) {
825 + uint32_t findIndex = 0;
826 + uint32_t searchStringSize = size(&searchString);
827 + uint32_t const maxIteration = (HISTSIZE + term.row) * term.col …
828 + for (uint32_t cIteration = 0; findIndex < searchStringSize
829 + && cIteration ++ < maxIteration; moveLetter(sig…
830 + uint32_t const searchChar = *((uint32_t*)(sign == 1 ? v…
831 + : viewEnd(&searchString, findIn…
832 +
833 + uint32_t const fu = TLINE(term.c.y)[term.c.x].u;
834 +
835 + if (fu == searchChar) findIndex++;
836 + else findIndex = 0;
837 + }
838 + bool const found = findIndex == searchStringSize;
839 + if (found) { for (uint32_t i = 0; i < searchStringSize; i++) { …
840 + return found;
841 +}
842 +
843 +/// Find the next occurrence of a word
844 +bool
845 +gotoNextString(int8_t sign) {
846 + moveLetter(sign);
847 + return gotoString(sign);
848 +}
849 +
850 +/// Highlight all found strings on the current screen.
851 +void
852 +highlightStringOnScreen() {
853 + if (isEmpty(&searchString)) { return; }
854 + uint32_t const searchStringSize = size(&searchString);
855 + uint32_t findIndex = 0;
856 + uint32_t xStart, yStart;
857 + for (uint32_t y = 0; y < term.row; y++) {
858 + for (uint32_t x = 0; x < term.col; x++) {
859 + if (TLINE(y)[x].u == *((uint32_t*)(view(&search…
860 + if (findIndex++ == 0) {
861 + xStart = x;
862 + yStart = y;
863 + }
864 + if (findIndex == searchStringSize) {
865 + // mark selected
866 + append(&highlights, &xStart);
867 + append(&highlights, &yStart);
868 +
869 + findIndex = 0;
870 + term.dirty[yStart] = 1;
871 + }
872 + } else {
873 + findIndex = 0;
874 + }
875 + }
876 + }
877 +}
878 +
879 +void gotoStringAndHighlight(int8_t sign) {
880 + bool const found = gotoString(sign); //< find the next string …
881 + empty(&highlights); //< remove previous highlights
882 + if (found) { //< apply new highlights …
883 + //if (sign == -1) { moveLetter(-1); }
884 + highlightStringOnScreen(sign);
885 + } else { //< go to the position wh…
886 + applyPosition(&stateNormalMode.motion.searchPosition);
887 + }
888 + tsetdirt(0, term.row-3); //< repaint everything ex…
889 + // is painted separately.
890 +}
891 +
892 +void pressKeys(char const* nullTerminatedString) {
893 + size_t end;
894 + for (size_t i = 0, end=strlen(nullTerminatedString); i < end; +…
895 + if (nullTerminatedString[i] == '\n') {
896 + kpressNormalMode(&nullTerminatedString[i], 0, f…
897 + } else {
898 + kpressNormalMode(&nullTerminatedString[i], 1, f…
899 + }
900 + }
901 +}
902 +
903 +void executeCommand(DynamicArray const *command) {
904 + size_t end;
905 + char decoded [32];
906 + for (size_t i = 0, end=size(command); i < end; ++i) {
907 + size_t len = utf8encode(*((Rune*)view(command, i)) , de…
908 + kpressNormalMode(decoded, len, false, false, false);
909 + }
910 + //kpressNormalMode(NULL, 0, false, true, false);
911 +}
912 +
913 +void kpressNormalMode(char const * ksym, uint32_t len, bool esc, bool e…
914 + // [ESC] or [ENTER] abort resp. finish the current operation or
915 + // the Normal Mode if no operation is currently executed.
916 + if (esc || enter) {
917 + if (stateNormalMode.command.op == noop
918 + && stateNormalMode.motion.search == none
919 + && stateNormalMode.motion.amount == 0) {
920 + terminateCommand(!enter);
921 + empty(&highlights);
922 + tfulldirt(); // < this also removes the search …
923 + normalMode(NULL);
924 + } else {
925 + if (enter && stateNormalMode.motion.search != n…
926 + exitCommand(); //stateNormalMode.motion…
927 + return;
928 + } else {
929 + abortCommand();
930 + }
931 + }
932 + return;
933 + } //< ! (esc || enter)
934 + // Search: append to search string & conduct search for best hi…
935 + // highlighting all other occurrences on the current pa…
936 + if (stateNormalMode.motion.search != none && !stateNormalMode.m…
937 + int8_t const sign = stateNormalMode.motion.search == fo…
938 + // Apply start position.
939 + if (backspace) { // XXX: if a quantifier is subject to …
940 + // from the command string.
941 + if (!isEmpty(currentCommand) && !isEmpty(&searc…
942 + pop(currentCommand);
943 + pop(&searchString);
944 + } else if (isEmpty(currentCommand) || isEmpty(&…
945 + empty(&highlights);
946 + stateNormalMode.motion = defaultNormalM…
947 + selclear(); …
948 + return; …
949 + }
950 + applyPosition(&stateNormalMode.motion.searchPos…
951 + } else {
952 + if (len > 0) {
953 + char* kSearch = checkGetNext(&searchStr…
954 + utf8decode(ksym, (Rune*)(kSearch), len);
955 +
956 + char* kCommand = checkGetNext(currentCo…
957 + utf8decode(ksym, (Rune*)(kCommand), len…
958 + }
959 + }
960 + if (sign == -1) { moveLetter(1); }
961 + gotoStringAndHighlight(sign); //< go to the next occurr…
962 + // all occurrences curre…
963 +
964 + if (stateNormalMode.command.op == visual) {
965 + selextend(term.c.x, term.c.y, term.scr, sel.typ…
966 + } else if (stateNormalMode.command.op == visualLine) {
967 + selextend(term.col-1, term.c.y, term.scr, sel.t…
968 + }
969 + printCommandString();
970 + printSearchString();
971 + return;
972 + }
973 +
974 + if (len == 0) { return; }
975 + // V / v or y take precedence over movement commands.
976 + switch(ksym[0]) {
977 + case '.':
978 + {
979 +
980 + if (!isEmpty(currentCommand)) { toggle …
981 + executeCommand(lastCommand);
982 + }
983 + return;
984 + case 'y': //< Yank mode
985 + {
986 + char* kCommand = checkGetNext(currentCo…
987 + utf8decode(ksym, (Rune*)(kCommand), len…
988 + switch(stateNormalMode.command.op) {
989 + case noop: //< Start …
990 + enableMode(yank);
991 + selstart(term.c.x, term…
992 + empty(currentCommand);
993 + break;
994 + case visualLine: //< Comple…
995 + case visual:
996 + xsetsel(getsel()); …
997 + xclipcopy();
998 + exitCommand(); …
999 + break;
1000 + case yank: //< Comple…
1001 + selstart(0, term.c.y, t…
1002 + uint32_t const origY = …
1003 + for (int32_t i = 0; i <…
1004 + selextend(term.col-1, t…
1005 + xsetsel(getsel());
1006 + xclipcopy();
1007 + term.c.y = origY;
1008 + exitCommand();
1009 + }
1010 + }
1011 + printCommandString();
1012 + printSearchString();
1013 + return;
1014 + case 'v': //< Visual Mode: Toggle mode.
1015 + case 'V':
1016 + {
1017 + enum Operation mode = ksym[0] == 'v' ? …
1018 + bool assign = stateNormalMode.command.o…
1019 + abortCommand();
1020 + if (assign) {
1021 + enableMode(mode);
1022 + char* kCommand = checkGetNext(c…
1023 + utf8decode(ksym, (Rune*)(kComma…
1024 + if (mode == visualLine) {
1025 + selstart(0, term.c.y, t…
1026 + selextend(term.col-1, t…
1027 + } else {
1028 + selstart(term.c.x, term…
1029 + }
1030 + }
1031 + }
1032 + return;
1033 + }
1034 + // Perform the movement.
1035 + int32_t sign = -1; //< whehter a command goes 'forward' (1) …
1036 + bool discard = false; //< discard input, as it does not have a …
1037 + switch(ksym[0]) {
1038 + case 'j': sign = 1;
1039 + case 'k':
1040 + term.c.y += sig…
1041 + break;
1042 + case 'H': term.c.y = 0; break; //< [numer]H …
1043 + case 'M': term.c.y = term.bot / 2; break;
1044 + case 'L': term.c.y = term.bot; break; //< [numer]L …
1045 + case 'G': //< a little different from vim, but in this…
1046 + applyPosition(&…
1047 + case 'l': sign = 1;
1048 + case 'h':
1049 + {
1050 + int32_t…
1051 + term.c.…
1052 + while (…
1053 + term.c.…
1054 + break;
1055 + }
1056 + case '0':
1057 + if (stateNormal…
1058 + else { discard …
1059 + break;
1060 + case '$': term.c.x = term.col-1; break;
1061 + case 'w':
1062 + case 'W':
1063 + case 'e':
1064 + case 'E': sign = 1;
1065 + case 'B':
1066 + case 'b':
1067 + {
1068 + bool co…
1069 + bool co…
1070 + char co…
1071 + uint32_…
1072 + bool co…
1073 + uint32_…
1074 +
1075 + // does…
1076 + // Line…
1077 + stateNo…
1078 + for (; …
1079 + …
1080 + …
1081 + …
1082 + …
1083 + …
1084 + …
1085 + …
1086 + …
1087 + …
1088 + …
1089 + }
1090 + break;
1091 + }
1092 + case '/': sign = 1;
1093 + case '?':
1094 + empty(&searchSt…
1095 + stateNormalMode…
1096 + stateNormalMode…
1097 + stateNormalMode…
1098 + stateNormalMode…
1099 + stateNormalMode…
1100 + break;
1101 + case 'n': sign = 1;
1102 + case 'N':
1103 + toggle = !toggl…
1104 + empty(currentCo…
1105 + if (stateNormal…
1106 + stateNo…
1107 + stateNo…
1108 + }
1109 + for (int32_t am…
1110 + if (sta…
1111 + moveLet…
1112 + gotoStr…
1113 + }
1114 + break;
1115 + case 't':
1116 + if (sel.type ==…
1117 + sel.typ…
1118 + } else {
1119 + sel.typ…
1120 + }
1121 + tsetdirt(sel.nb…
1122 + discard = true;
1123 + default:
1124 + discard = true;
1125 + }
1126 + bool const isNumber = len == 1 && BETWEEN(ksym[0], 48, 57);
1127 + if (isNumber) { //< record numbers
1128 + discard = false;
1129 + stateNormalMode.motion.amount =
1130 + MIN(SHRT_MAX, stateNormalMode.motion.amount * 1…
1131 + } else if (!discard) {
1132 + stateNormalMode.motion.amount = 0;
1133 + }
1134 +
1135 + if (discard) {
1136 + for (size_t i = 0; i < amountNormalModeShortcuts; ++i) {
1137 + if (ksym[0] == normalModeShortcuts[i].key) {
1138 + pressKeys(normalModeShortcuts[i].value);
1139 + }
1140 + }
1141 + } else {
1142 + char* kCommand = checkGetNext(currentCommand);
1143 + utf8decode(ksym, (Rune*)(kCommand), len);
1144 +
1145 + int diff = 0;
1146 + if (term.c.y > 0) {
1147 + if (term.c.y > term.bot) {
1148 + diff = term.bot - term.c.y;
1149 + term.c.y = term.bot;
1150 + }
1151 + } else {
1152 + if (term.c.y < 0) {
1153 + diff = -term.c.y;
1154 + term.c.y = 0;
1155 + }
1156 + }
1157 +
1158 + int const _newScr = term.scr + diff;
1159 + term.c.y = _newScr < 0 ? 0 : (_newScr >= HISTSIZE ? ter…
1160 + term.scr = mod(_newScr, HISTSIZE);
1161 +
1162 + if (!isEmpty(&highlights)) {
1163 + empty(&highlights);
1164 + highlightStringOnScreen();
1165 + }
1166 +
1167 + tsetdirt(0, term.row-3);
1168 + printCommandString();
1169 + printSearchString();
1170 +
1171 + if (stateNormalMode.command.op == visual) {
1172 + selextend(term.c.x, term.c.y, term.scr, sel.typ…
1173 + } else if (stateNormalMode.command.op == visualLine) {
1174 + selextend(term.col-1, term.c.y, term.scr, sel.t…
1175 + } else {
1176 + if (!isNumber && (stateNormalMode.motion.search…
1177 + || stateNormalMode.motion.finis…
1178 + toggle = !toggle;
1179 + empty(currentCommand);
1180 + }
1181 + if (stateNormalMode.command.op == yank) {
1182 + if (!isNumber && !discard) {
1183 + // copy
1184 + selextend(term.c.x, term.c.y, t…
1185 + xsetsel(getsel());
1186 + xclipcopy();
1187 + applyPosition(&stateNormalMode.…
1188 + exitCommand();
1189 + }
1190 + }
1191 + }
1192 + }
1193 +}
1194 +
1195 void
1196 csiparse(void)
1197 {
1198 @@ -1176,6 +1850,10 @@ tmoveto(int x, int y)
1199 term.c.state &= ~CURSOR_WRAPNEXT;
1200 term.c.x = LIMIT(x, 0, term.col-1);
1201 term.c.y = LIMIT(y, miny, maxy);
1202 + // Set the last position in order to restore after normal mode …
1203 + stateNormalMode.initialPosition.x = term.c.x;
1204 + stateNormalMode.initialPosition.y = term.c.y;
1205 + stateNormalMode.initialPosition.yScr = term.scr;
1206 }
1207
1208 void
1209 @@ -1282,14 +1960,14 @@ void
1210 tinsertblankline(int n)
1211 {
1212 if (BETWEEN(term.c.y, term.top, term.bot))
1213 - tscrolldown(term.c.y, n);
1214 + tscrolldown(term.c.y, n, 0);
1215 }
1216
1217 void
1218 tdeleteline(int n)
1219 {
1220 if (BETWEEN(term.c.y, term.top, term.bot))
1221 - tscrollup(term.c.y, n);
1222 + tscrollup(term.c.y, n, 0);
1223 }
1224
1225 int32_t
1226 @@ -1720,11 +2398,11 @@ csihandle(void)
1227 break;
1228 case 'S': /* SU -- Scroll <n> line up */
1229 DEFAULT(csiescseq.arg[0], 1);
1230 - tscrollup(term.top, csiescseq.arg[0]);
1231 + tscrollup(term.top, csiescseq.arg[0], 0);
1232 break;
1233 case 'T': /* SD -- Scroll <n> line down */
1234 DEFAULT(csiescseq.arg[0], 1);
1235 - tscrolldown(term.top, csiescseq.arg[0]);
1236 + tscrolldown(term.top, csiescseq.arg[0], 0);
1237 break;
1238 case 'L': /* IL -- Insert <n> blank lines */
1239 DEFAULT(csiescseq.arg[0], 1);
1240 @@ -2227,7 +2905,7 @@ eschandle(uchar ascii)
1241 return 0;
1242 case 'D': /* IND -- Linefeed */
1243 if (term.c.y == term.bot) {
1244 - tscrollup(term.top, 1);
1245 + tscrollup(term.top, 1, 1);
1246 } else {
1247 tmoveto(term.c.x, term.c.y+1);
1248 }
1249 @@ -2240,7 +2918,7 @@ eschandle(uchar ascii)
1250 break;
1251 case 'M': /* RI -- Reverse index */
1252 if (term.c.y == term.top) {
1253 - tscrolldown(term.top, 1);
1254 + tscrolldown(term.top, 1, 1);
1255 } else {
1256 tmoveto(term.c.x, term.c.y-1);
1257 }
1258 @@ -2458,7 +3136,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
1259 void
1260 tresize(int col, int row)
1261 {
1262 - int i;
1263 + int i, j;
1264 int minrow = MIN(row, term.row);
1265 int mincol = MIN(col, term.col);
1266 int *bp;
1267 @@ -2495,6 +3173,14 @@ tresize(int col, int row)
1268 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
1269 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
1270
1271 + for (i = 0; i < HISTSIZE; i++) {
1272 + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyp…
1273 + for (j = mincol; j < col; j++) {
1274 + term.hist[i][j] = term.c.attr;
1275 + term.hist[i][j].u = ' ';
1276 + }
1277 + }
1278 +
1279 /* resize each row to new width, zero-pad if needed */
1280 for (i = 0; i < minrow; i++) {
1281 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyp…
1282 @@ -2552,7 +3238,7 @@ drawregion(int x1, int y1, int x2, int y2)
1283 continue;
1284
1285 term.dirty[y] = 0;
1286 - xdrawline(term.line[y], x1, y, x2);
1287 + xdrawline(TLINE(y), x1, y, x2);
1288 }
1289 }
1290
1291 @@ -2573,8 +3259,8 @@ draw(void)
1292 cx--;
1293
1294 drawregion(0, 0, term.col, term.row);
1295 - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
1296 - term.ocx, term.ocy, term.line[term.ocy][term.oc…
1297 + xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
1298 + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
1299 term.ocx = cx, term.ocy = term.c.y;
1300 xfinishdraw();
1301 xximspot(term.ocx, term.ocy);
1302 diff --git a/st.h b/st.h
1303 index 4da3051..7bd8bba 100644
1304 --- a/st.h
1305 +++ b/st.h
1306 @@ -1,5 +1,6 @@
1307 /* See LICENSE for license details. */
1308
1309 +#include <stdbool.h>
1310 #include <stdint.h>
1311 #include <sys/types.h>
1312
1313 @@ -10,6 +11,8 @@
1314 #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
1315 #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
1316 #define DEFAULT(a, b) (a) = (a) ? (a) : (b)
1317 +#define INTERVAL(x, a, b) (x) < (a) ? (a) : (x) > (b) ? …
1318 +#define INTERVAL_DIFF(x, a, b) (x) < (a) ? (x) - (a) : (…
1319 #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b)…
1320 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg !=…
1321 (a).bg != (b).bg)
1322 @@ -33,6 +36,8 @@ enum glyph_attribute {
1323 ATTR_WRAP = 1 << 8,
1324 ATTR_WIDE = 1 << 9,
1325 ATTR_WDUMMY = 1 << 10,
1326 + ATTR_HIGHLIGHT = 1 << 11 | ATTR_UNDERLINE,
1327 + ATTR_CURRENT = 1 << 12,
1328 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
1329 };
1330
1331 @@ -80,6 +85,14 @@ void die(const char *, ...);
1332 void redraw(void);
1333 void draw(void);
1334
1335 +int highlighted(int, int);
1336 +int currentLine(int, int);
1337 +void kscrolldown(const Arg *);
1338 +void kscrollup(const Arg *);
1339 +void kpressNormalMode(char const * ksym, uint32_t len, bool esc, bool e…
1340 +void normalMode(Arg const *);
1341 +void onNormalModeStart();
1342 +void onNormalModeStop();
1343 void printscreen(const Arg *);
1344 void printsel(const Arg *);
1345 void sendbreak(const Arg *);
1346 @@ -99,8 +112,10 @@ void resettitle(void);
1347
1348 void selclear(void);
1349 void selinit(void);
1350 -void selstart(int, int, int);
1351 -void selextend(int, int, int, int);
1352 +void selstart(int, int, int, int);
1353 +void xselstart(int, int, int);
1354 +void selextend(int, int, int, int, int);
1355 +void xselextend(int, int, int, int);
1356 int selected(int, int);
1357 char *getsel(void);
1358
1359 @@ -110,6 +125,8 @@ void *xmalloc(size_t);
1360 void *xrealloc(void *, size_t);
1361 char *xstrdup(char *);
1362
1363 +
1364 +
1365 /* config.h globals */
1366 extern char *utmp;
1367 extern char *stty_args;
1368 @@ -120,3 +137,13 @@ extern char *termname;
1369 extern unsigned int tabspaces;
1370 extern unsigned int defaultfg;
1371 extern unsigned int defaultbg;
1372 +extern char wordDelimSmall[];
1373 +extern char wordDelimLarge[];
1374 +
1375 +typedef struct NormalModeShortcuts {
1376 + char key;
1377 + char *value;
1378 +} NormalModeShortcuts;
1379 +
1380 +extern NormalModeShortcuts normalModeShortcuts[];
1381 +extern size_t const amountNormalModeShortcuts;
1382 diff --git a/win.h b/win.h
1383 index a6ef1b9..1a6fefe 100644
1384 --- a/win.h
1385 +++ b/win.h
1386 @@ -19,6 +19,7 @@ enum win_mode {
1387 MODE_MOUSEMANY = 1 << 15,
1388 MODE_BRCKTPASTE = 1 << 16,
1389 MODE_NUMLOCK = 1 << 17,
1390 + MODE_NORMAL = 1 << 18,
1391 MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
1392 |MODE_MOUSEMANY,
1393 };
1394 @@ -27,6 +28,7 @@ void xbell(void);
1395 void xclipcopy(void);
1396 void xdrawcursor(int, int, Glyph, int, int, Glyph);
1397 void xdrawline(Line, int, int, int);
1398 +void xdrawglyph(Glyph, int, int);
1399 void xfinishdraw(void);
1400 void xloadcols(void);
1401 int xsetcolorname(int, const char *);
1402 diff --git a/x.c b/x.c
1403 index 5828a3b..ccf1751 100644
1404 --- a/x.c
1405 +++ b/x.c
1406 @@ -136,7 +136,6 @@ typedef struct {
1407 static inline ushort sixd_to_16bit(int);
1408 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, …
1409 static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i…
1410 -static void xdrawglyph(Glyph, int, int);
1411 static void xclear(int, int, int, int);
1412 static int xgeommasktogravity(int);
1413 static void ximopen(Display *);
1414 @@ -340,7 +339,7 @@ mousesel(XEvent *e, int done)
1415 break;
1416 }
1417 }
1418 - selextend(evcol(e), evrow(e), seltype, done);
1419 + xselextend(evcol(e), evrow(e), seltype, done);
1420 if (done)
1421 setsel(getsel(), e->xbutton.time);
1422 }
1423 @@ -444,7 +443,7 @@ bpress(XEvent *e)
1424 xsel.tclick2 = xsel.tclick1;
1425 xsel.tclick1 = now;
1426
1427 - selstart(evcol(e), evrow(e), snap);
1428 + xselstart(evcol(e), evrow(e), snap);
1429 }
1430 }
1431
1432 @@ -730,6 +729,19 @@ xloadcolor(int i, const char *name, Color *ncolor)
1433 return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
1434 }
1435
1436 +void
1437 +normalMode(Arg const *_) //< the argument is just for the sake of
1438 + // adhering to the function format.
1439 +{
1440 + win.mode ^= MODE_NORMAL; //< toggle normal mode via exclusive o…
1441 + if (win.mode & MODE_NORMAL) {
1442 + onNormalModeStart();
1443 + } else {
1444 + onNormalModeStop();
1445 + }
1446 +}
1447 +
1448 +
1449 void
1450 xloadcols(void)
1451 {
1452 @@ -1296,6 +1308,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs…
1453 base.fg = defaultattr;
1454 }
1455
1456 + if (base.mode & ATTR_HIGHLIGHT) {
1457 + base.bg = highlightBg;
1458 + base.fg = highlightFg;
1459 + } else if ((base.mode & ATTR_CURRENT) && (win.mode & MODE_NORMA…
1460 + base.bg = currentBg;
1461 + base.fg = currentFg;
1462 + }
1463 +
1464 if (IS_TRUECOL(base.fg)) {
1465 colfg.alpha = 0xffff;
1466 colfg.red = TRUERED(base.fg);
1467 @@ -1428,8 +1448,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int o…
1468 Color drawcol;
1469
1470 /* remove the old cursor */
1471 - if (selected(ox, oy))
1472 - og.mode ^= ATTR_REVERSE;
1473 + if (selected(ox, oy)) og.mode ^= ATTR_REVERSE;
1474 + if (highlighted(ox, oy)) { og.mode ^= ATTR_HIGHLIGHT; }
1475 + if (currentLine(ox, oy)) { og.mode ^= ATTR_CURRENT; }
1476 xdrawglyph(og, ox, oy);
1477
1478 if (IS_SET(MODE_HIDE))
1479 @@ -1461,6 +1482,11 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int …
1480 drawcol = dc.col[g.bg];
1481 }
1482
1483 + if ((g.mode & ATTR_CURRENT) && (win.mode & MODE_NORMAL)) {
1484 + g.bg = currentBg;
1485 + g.fg = currentFg;
1486 + }
1487 +
1488 /* draw the new one */
1489 if (IS_SET(MODE_FOCUSED)) {
1490 switch (win.cursor) {
1491 @@ -1550,6 +1576,12 @@ xdrawline(Line line, int x1, int y1, int x2)
1492 continue;
1493 if (selected(x, y1))
1494 new.mode ^= ATTR_REVERSE;
1495 + if (highlighted(x, y1)) {
1496 + new.mode ^= ATTR_HIGHLIGHT;
1497 + }
1498 + if (currentLine(x, y1)) {
1499 + new.mode ^= ATTR_CURRENT;
1500 + }
1501 if (i > 0 && ATTRCMP(base, new)) {
1502 xdrawglyphfontspecs(specs, base, i, ox, y1);
1503 specs += i;
1504 @@ -1731,6 +1763,12 @@ kpress(XEvent *ev)
1505 return;
1506
1507 len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &statu…
1508 + if (IS_SET(MODE_NORMAL)) {
1509 + kpressNormalMode(buf, strlen(buf),
1510 + ksym == XK_Escape, ksym == XK_Return, k…
1511 + return;
1512 + }
1513 +
1514 /* 1. shortcuts */
1515 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
1516 if (ksym == bp->keysym && match(bp->mod, e->state)) {
1517 @@ -1870,8 +1908,9 @@ run(void)
1518 XNextEvent(xw.dpy, &ev);
1519 if (XFilterEvent(&ev, None))
1520 continue;
1521 - if (handler[ev.type])
1522 + if (handler[ev.type]) {
1523 (handler[ev.type])(&ev);
1524 + }
1525 }
1526
1527 draw();
1528 --
1529 2.24.0
1530
1531
1532 From aae3d1c2e5437a3bd2c79ae0cb2ad6380b10adce Mon Sep 17 00:00:00 2001
1533 From: Kevin Velghe <[email protected]>
1534 Date: Mon, 2 Dec 2019 23:25:52 +0100
1535 Subject: [PATCH 2/2] Merge contribution of paretje: fix underlined text
1536
1537 https://github.com/juliusHuelsmann/st/issues/13
1538 ---
1539 st.h | 4 ++--
1540 1 file changed, 2 insertions(+), 2 deletions(-)
1541
1542 diff --git a/st.h b/st.h
1543 index 7bd8bba..4a78440 100644
1544 --- a/st.h
1545 +++ b/st.h
1546 @@ -36,8 +36,8 @@ enum glyph_attribute {
1547 ATTR_WRAP = 1 << 8,
1548 ATTR_WIDE = 1 << 9,
1549 ATTR_WDUMMY = 1 << 10,
1550 - ATTR_HIGHLIGHT = 1 << 11 | ATTR_UNDERLINE,
1551 - ATTR_CURRENT = 1 << 12,
1552 + ATTR_HIGHLIGHT = 1 << 12,
1553 + ATTR_CURRENT = 1 << 13,
1554 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
1555 };
1556
1557 --
1558 2.24.0
1559
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.