Introduction
Introduction Statistics Contact Development Disclaimer Help
st-vimBrowse-20200604-295a43f.diff - sites - public wiki contents of suckless.o…
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-vimBrowse-20200604-295a43f.diff (64935B)
---
1 diff -ruN st-default/config.def.h st1/config.def.h
2 --- st-default/config.def.h 2020-06-04 11:15:55.164135902 +0200
3 +++ st1/config.def.h 2020-06-04 11:15:28.476134951 +0200
4 @@ -56,6 +56,10 @@
5 static double minlatency = 8;
6 static double maxlatency = 33;
7
8 +/* frames per second st should at maximum draw to the screen */
9 +static unsigned int xfps = 120;
10 +static unsigned int actionfps = 30;
11 +
12 /*
13 * blinking timeout (set to 0 to disable blinking) for the terminal bli…
14 * attribute.
15 @@ -160,6 +164,14 @@
16 * doesn't match the ones requested.
17 */
18 static unsigned int defaultattr = 11;
19 +/// Colors for the entities that are 'highlighted' in normal mode (sear…
20 +/// results currently on screen) [Vim Browse].
21 +static unsigned int highlightBg = 160;
22 +static unsigned int highlightFg = 15;
23 +/// Colors for highlighting the current cursor position (row + col) in …
24 +/// mode [Vim Browse].
25 +static unsigned int currentBg = 8;
26 +static unsigned int currentFg = 15;
27
28 /*
29 * Force mouse select/shortcuts while mask is active (when MODE_MOUSE i…
30 @@ -175,18 +187,18 @@
31 static MouseShortcut mshortcuts[] = {
32 /* mask button function argument …
33 { XK_ANY_MOD, Button2, selpaste, {.i = 0}, …
34 - { ShiftMask, Button4, ttysend, {.s = "\033[5;…
35 { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} …
36 - { ShiftMask, Button5, ttysend, {.s = "\033[6;…
37 { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} …
38 };
39
40 /* Internal keyboard shortcuts. */
41 #define MODKEY Mod1Mask
42 +#define AltMask Mod1Mask
43 #define TERMMOD (ControlMask|ShiftMask)
44
45 static Shortcut shortcuts[] = {
46 /* mask keysym function argumen…
47 + { AltMask, XK_c, normalMode, {.i = …
48 { XK_ANY_MOD, XK_Break, sendbreak, {.i = …
49 { ControlMask, XK_Print, toggleprinter, {.i = …
50 { ShiftMask, XK_Print, printscreen, {.i = …
51 @@ -199,6 +211,8 @@
52 { TERMMOD, XK_Y, selpaste, {.i = …
53 { ShiftMask, XK_Insert, selpaste, {.i = …
54 { TERMMOD, XK_Num_Lock, numlock, {.i = …
55 + { ShiftMask, XK_Page_Up, kscrollup, {.i = -…
56 + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -…
57 };
58
59 /*
60 @@ -470,3 +484,45 @@
61 " !\"#$%&'()*+,-./0123456789:;<=>?"
62 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
63 "`abcdefghijklmnopqrstuvwxyz{|}~";
64 +
65 +
66 +/// word sepearors normal mode
67 +/// [Vim Browse].
68 +char wordDelimSmall[] = " \t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
69 +char wordDelimLarge[] = " \t"; /// <Word sepearors normal mode (capital…
70 +
71 +/// Shortcusts executed in normal mode (which should not already be in …
72 +/// [Vim Browse].
73 +struct NormalModeShortcuts normalModeShortcuts [] = {
74 + { 'R', "?Building\n" },
75 + { 'r', "/Building\n" },
76 + { 'F', "?: error:\n" },
77 + { 'f', "/: error:\n" },
78 + { 'Q', "?[Leaving vim, starting execution]\n" },
79 + { 'S', "Qf" },
80 + { 'X', "?juli@machine\n" },
81 + { 'x', "/juli@machine\n" },
82 +};
83 +
84 +size_t const amountNormalModeShortcuts = sizeof(normalModeShortcuts) / …
85 +
86 +/// Style of the command string visualized in normal mode in the right …
87 +/// [Vim Browse].
88 +Glyph const styleCommand = {' ', ATTR_ITALIC | ATTR_FAINT, 7, 16};
89 +/// Style of the search string visualized in normal mode in the right c…
90 +/// [Vim Browse].
91 +Glyph const styleSearch = {' ', ATTR_ITALIC | ATTR_BOLD_FAINT, 7, 16};
92 +
93 +/// Colors used in normal mode in order to highlight different operatio…
94 +/// empathise the current position on screen in the status area [Vim …
95 +unsigned int bgCommandYank = 11;
96 +unsigned int bgCommandVisual = 4;
97 +unsigned int bgCommandVisualLine = 12;
98 +
99 +unsigned int fgCommandYank = 232;
100 +unsigned int fgCommandVisual = 232;
101 +unsigned int fgCommandVisualLine = 232;
102 +
103 +unsigned int bgPos = 15;
104 +unsigned int fgPos = 16;
105 +
106 diff -ruN st-default/dynamicArray.h st1/dynamicArray.h
107 --- st-default/dynamicArray.h 1970-01-01 01:00:00.000000000 +0100
108 +++ st1/dynamicArray.h 2020-06-04 11:04:30.227111509 +0200
109 @@ -0,0 +1,175 @@
110 +#ifndef DYNAMIC_ARRAY_H
111 +#define DYNAMIC_ARRAY_H
112 +
113 +#include "error.h"
114 +
115 +#include <stdint.h>
116 +#include <stdlib.h>
117 +#include <string.h>
118 +#include <stdbool.h>
119 +
120 +/// Struct for which this file offers functionality in order to expand …
121 +/// and set / get its content.
122 +typedef struct DynamicArray {
123 + /// Size of the datatype contained in the array.
124 + uint8_t itemSize;
125 + /// Amount of bytes currently initialized
126 + uint32_t index;
127 + /// Amount of bytes currently reserved (not necessarily initial…
128 + uint32_t allocated;
129 + /// Actual content.
130 + char* content;
131 +} DynamicArray;
132 +
133 +#define EXPAND_STEP 15
134 +
135 +/// Default initializers for the dynamic array.
136 +#define CHAR_ARRAY {1, 0, 0, NULL}
137 +#define WORD_ARRAY {2, 0, 0, NULL}
138 +#define DWORD_ARRAY {4, 0, 0, NULL}
139 +#define QWORD_ARRAY {8, 0, 0, NULL}
140 +/// (Wasteful) utf-8 array, that always used 4 bytes in order to displa…
141 +/// character, even if the space is not required.
142 +#define UTF8_ARRAY DWORD_ARRAY
143 +
144 +/// Check that at least \p bytes are allocated, if true implying that
145 +/// \p s->content[\bytes - 1] is allocated.
146 +static inline bool
147 +isAllocated(DynamicArray const *s, uint32_t bytes) {
148 + return s != NULL && s->allocated >= bytes;
149 +}
150 +
151 +/// @see #isAllocated
152 +static inline bool
153 +isInitialized(DynamicArray const *s, uint32_t bytes) {
154 + return s != NULL && s->index >= bytes;
155 +}
156 +
157 +/// Return the next element in \p s and increment index without checkin…
158 +static inline char*
159 +gnext(DynamicArray *s) {
160 + ENSURE(s!=NULL, return NULL);
161 + ENSURE(s->index % s->itemSize == 0 && "(index not aligned)",
162 + s->index += s->itemSize - (s->index % s->itemSi…
163 + ENSURE(isAllocated(s, s->index + 2 * s->itemSize), return NULL);
164 + return s->content + (s->index += s->itemSize);
165 +}
166 +
167 +/// View element \p i in \p s.
168 +static inline char*
169 +view(DynamicArray const * s, uint32_t i) {
170 + ENSURE((s != NULL) && isAllocated(s, (i+1) * s->itemSize), retu…
171 + return s->content + i*s->itemSize;
172 +}
173 +
174 +/// Inspect element content[size() - 1 - i].
175 +static inline char *
176 +viewEnd(DynamicArray const *s, uint32_t i) {
177 + ENSURE((s != NULL) && isInitialized(s, i * s->itemSize), return…
178 + ENSURE(s->index%s->itemSize == 0 && "(index not aligned)", retu…
179 + return s->content + s->index - (i + 1) * s->itemSize;
180 +}
181 +
182 +/// Set conent without applying
183 +static inline bool
184 +setValues(DynamicArray* s, char const *vals, uint32_t amount) {
185 + ENSURE(vals != NULL, return false);
186 + ENSURE((s != NULL) && isAllocated(s, s->index + amount), return…
187 + memcpy(s->content + s->index, vals, amount);
188 + return true;
189 +}
190 +
191 +static inline bool
192 +snext(DynamicArray* s, char const *vals, uint32_t amount) {
193 + bool const success = setValues(s, vals, amount);
194 + ENSURE(success, return false);
195 + uint8_t const rest = amount % s->itemSize;
196 + uint32_t const newSize = s->index + amount + (rest ? s->itemSiz…
197 + ENSURE(isAllocated(s, newSize), return false);
198 + s->index = newSize;
199 + return true;
200 +}
201 +
202 +/// Empty \p s.
203 +static inline void
204 +empty(DynamicArray* s) {
205 + ENSURE((s != NULL), return);
206 + s->index = 0;
207 +}
208 +
209 +/// Check if \p s has initialized content (which can be the case even i…
210 +/// is allocated).
211 +static inline bool
212 +isEmpty(DynamicArray const * s) {
213 + ENSURE((s != NULL), return true);
214 + return s->index == 0;
215 +}
216 +
217 +static inline int
218 +size(DynamicArray const * s) {
219 + ENSURE(s != NULL, return 0);
220 + ENSURE(s->itemSize != 0, return 0);
221 + return s->index / s->itemSize;
222 +}
223 +
224 +static inline void
225 +pop(DynamicArray* s) {
226 + ENSURE((s != NULL), return);
227 + ENSURE(s->index % s->itemSize == 0 && "(index not aligned)",
228 + s->index += s->itemSize - (s->index % s->itemSi…
229 + ENSURE(isInitialized(s, s->itemSize), return);
230 + s->index -= s->itemSize;
231 +}
232 +
233 +static inline bool
234 +checkSetNext(DynamicArray *s, char const *c, uint32_t amount) {
235 + ENSURE(s != NULL && c != NULL, return false);
236 + if (s->allocated < s->index + s->itemSize * amount) {
237 + uint32_t const diff = s->index+s->itemSize*amount-s->al…
238 + uint32_t const newAlloSize = s->allocated + (diff > EXP…
239 + ? diff : EXPAND_STEP) * s->itemSize;
240 + char* tmp = realloc(s->content, newAlloSize);
241 + if (tmp == NULL) { return false; }
242 + s->allocated = newAlloSize;
243 + s->content = tmp;
244 + assert(s->allocated >= s->index + s->itemSize * amount);
245 + }
246 + if (amount) { snext(s, c, amount); }
247 + return true;
248 +}
249 +
250 +static inline bool
251 +checkSetNextV(DynamicArray *s, char const c) {
252 + return checkSetNext(s, &c, 1);
253 +}
254 +
255 +static inline bool
256 +checkSetNextP(DynamicArray *s, char const *c) {
257 + ENSURE(c != NULL, return false);
258 + return checkSetNext(s, c, strlen(c));
259 +}
260 +
261 +/// Expand the currently initialized content in \p s and the allocated …
262 +/// memory if required.
263 +static char *
264 +expand(DynamicArray *s) {
265 + ENSURE(s != NULL, return NULL);
266 + if (s->allocated < s->index + s->itemSize) {
267 + uint32_t const diff = s->index + s->itemSize - s->alloc…
268 + uint32_t const newAlloSize = s->allocated + (diff > EXP…
269 + ? diff : EXPAND_STEP) * s->itemSize;
270 + char* tmp = realloc(s->content, newAlloSize);
271 + if (tmp == NULL) { return NULL; }
272 + s->allocated = newAlloSize;
273 + s->content = tmp;
274 + assert(s->allocated >= s->index + s->itemSize);
275 + }
276 + s->index+=s->itemSize;
277 + return viewEnd(s, 0);
278 +}
279 +
280 +#define append(s, c) checkSetNext((s), (char const *) (c), (s)->itemSiz…
281 +#define appendPartial(s, c, i) checkSetNext((s), (char const *) (c), (i…
282 +
283 +
284 +#endif // DYNAMIC_ARRAY_H
285 diff -ruN st-default/error.h st1/error.h
286 --- st-default/error.h 1970-01-01 01:00:00.000000000 +0100
287 +++ st1/error.h 2020-06-04 11:04:30.227111509 +0200
288 @@ -0,0 +1,47 @@
289 +#ifndef ERROR_H
290 +#define ERROR_H
291 +
292 +#include <assert.h>
293 +
294 +// Flag which determines whether to fail if a required condition is not…
295 +// to adapt the condition in order to work properly.
296 +// Attention: Be sure to perform a clean build after you alter preproce…
297 +// directives / definitions.
298 +//#define FAIL_ON_ERROR
299 +
300 +#include <stdio.h>
301 +
302 +///
303 +/// Function used in case the fail-on-error mode is disabled (via defin…
304 +/// to report errors. In debug production mode, alias st to st 2> error…
305 +static void reportError(char const * cond, char const * stt, char const…
306 + unsigned int line ) {
307 + unsigned int const maxErrorCount = 100;
308 + static unsigned int errorCount = 0;
309 + if (++errorCount == 1) {
310 + printf("Report the following bug to "
311 + "https://github.com/juliusHuelsmann/st.…
312 + }
313 + if (errorCount < maxErrorCount) {
314 + printf("Bug:\tCondition '%s' evaluates to false.\n\tPer…
315 + " '%s' to counteract.\n\tFile:%s:%u\n",
316 + cond, stt, file, line);
317 + } else if (errorCount == maxErrorCount) {
318 + printf("Max amount of reported errors %u is reached. Fr…
319 + "on, no additional errors will be repor…
320 + maxErrorCount);
321 + }
322 +}
323 +
324 +/// Note that everyting condition checked / endforced with #ENSURE is
325 +/// considered an error, and behaves like an error depending on the fla…
326 +#ifdef FAIL_ON_ERROR
327 +#define ENSURE(cond, stt) assert(cond);
328 +#else // FAIL_ON_ERROR
329 +#define ENSURE(cond, stt) if (!(cond)) { …
330 + reportError(#cond, #stt, __FILE__, __…
331 + stt; …
332 + }
333 +#endif // FAIL_ON_ERROR
334 +
335 +#endif // ERROR_H
336 diff -ruN st-default/glyph.h st1/glyph.h
337 --- st-default/glyph.h 1970-01-01 01:00:00.000000000 +0100
338 +++ st1/glyph.h 2020-06-04 11:04:30.228111510 +0200
339 @@ -0,0 +1,30 @@
340 +#ifndef LINE_H
341 +#define LINE_H
342 +
343 +//
344 +// Contains the representation of the entities in the buffer (Line, Gyl…
345 +// is used by every part of the software implmeneting terminal logic.
346 +//
347 +
348 +#include <stdint.h>
349 +
350 +enum selection_type {
351 + SEL_REGULAR = 1,
352 + SEL_RECTANGULAR = 2
353 +};
354 +
355 +typedef uint_least32_t Rune;
356 +
357 +#define Glyph Glyph_
358 +
359 +typedef struct {
360 + Rune u; /* character code */
361 + unsigned short mode; /* attribute flags */
362 + uint32_t fg; /* foreground */
363 + uint32_t bg; /* background */
364 +} Glyph;
365 +
366 +
367 +typedef Glyph *Line;
368 +
369 +#endif // LINE_H
370 diff -ruN st-default/Makefile st1/Makefile
371 --- st-default/Makefile 2020-06-04 11:15:55.164135902 +0200
372 +++ st1/Makefile 2020-06-04 11:04:30.228111510 +0200
373 @@ -4,7 +4,7 @@
374
375 include config.mk
376
377 -SRC = st.c x.c
378 +SRC = st.c x.c normalMode.c
379 OBJ = $(SRC:.c=.o)
380
381 all: options st
382 @@ -21,8 +21,8 @@
383 .c.o:
384 $(CC) $(STCFLAGS) -c $<
385
386 -st.o: config.h st.h win.h
387 -x.o: arg.h config.h st.h win.h
388 +st.o: config.h st.h win.h dynamicArray.h normalMode.h term.h glyph.h er…
389 +x.o: arg.h config.h st.h win.h dynamicArray.h normalMode.h term.h glyph…
390
391 $(OBJ): config.h config.mk
392
393 @@ -35,7 +35,8 @@
394 dist: clean
395 mkdir -p st-$(VERSION)
396 cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\
397 - config.def.h st.info st.1 arg.h st.h win.h $(SRC)\
398 + config.def.h st.info st.1 arg.h st.h win.h dynamicArray…
399 + normalMode.h term.h error.h $(SRC)\
400 st-$(VERSION)
401 tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
402 rm -rf st-$(VERSION)
403 diff -ruN st-default/normalMode.c st1/normalMode.c
404 --- st-default/normalMode.c 1970-01-01 01:00:00.000000000 +0100
405 +++ st1/normalMode.c 2020-06-04 11:04:30.229111510 +0200
406 @@ -0,0 +1,752 @@
407 +/* See LICENSE for license details. */
408 +#include "normalMode.h"
409 +#include "dynamicArray.h"
410 +#include "term.h"
411 +#include "win.h"
412 +#include "error.h"
413 +
414 +#include <X11/keysym.h>
415 +#include <X11/XKBlib.h>
416 +
417 +#include <ctype.h>
418 +#include <stdio.h>
419 +#include <limits.h>
420 +#include <math.h>
421 +
422 +#define LEN(a) (sizeof(a) / sizeof(a)[0])
423 +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
424 +//#define FALLTHROUGH __attribute__((fallthrough));
425 +#define FALLTHROUGH
426 +#define SEC(var,ini,h,r) var = ini; if (!var) { h; return r; }
427 +#define EXPAND(v1,v2,r) char *SEC(v1, expand(v2), empty(v2), tru…
428 +#define currentCommand (toggle ? &commandHist0 : &commandHist1)
429 +#define lastCommand (toggle ? &commandHist1 : &commandHist0)
430 +
431 +//
432 +// Interface to the terminal
433 +extern Glyph const styleCommand, styleSearch;
434 +extern NormalModeShortcuts normalModeShortcuts[];
435 +extern size_t const amountNormalModeShortcuts;
436 +extern char wordDelimSmall[];
437 +extern char wordDelimLarge[];
438 +extern unsigned int fgCommandYank, fgCommandVisual, fgCommandVisualLine,
439 + bgCommandYank, bgCommandVisual, bgCommandVisualLine, bgPos, fgPo…
440 +
441 +extern void selclear(void);
442 +extern void tsetdirt(int, int);
443 +extern size_t utf8encode(Rune, char *);
444 +extern size_t utf8decode(const char *, Rune *, size_t);
445 +extern size_t utf8decodebyte(char c, size_t *i);
446 +
447 +extern void selextend(int, int, int, int, int);
448 +extern void selstart(int, int, int, int);
449 +extern char *getsel(void);
450 +extern void tfulldirt(void);
451 +
452 +//
453 +// `Private` structs
454 +typedef struct { uint32_t x; uint32_t y; uint32_t yScr; } Position;
455 +
456 +/// Entire normal mode state, consisting of an operation and a motion.
457 +typedef struct {
458 + Position initialPosition;
459 + struct OperationState {
460 + enum Operation {
461 + noop = ' ', visual='v', visualLine='V', yank = …
462 + Position startPosition;
463 + enum Infix { infix_none = 0, infix_i = 1, infix_a = 2, …
464 + } command;
465 + struct MotionState {
466 + uint32_t amount;
467 + enum Search {none, forward, backward} search;
468 + Position searchPosition;
469 + bool finished;
470 + } motion;
471 +} NormalModeState;
472 +
473 +/// Default state if no operation is performed.
474 +NormalModeState defaultNormalMode = {
475 + {0,0,0}, {noop, {0, 0, 0}, false}, {0, none, {0, 0, 0}, tr…
476 +};
477 +NormalModeState stateVB = {
478 + {0,0,0}, {noop, {0, 0, 0}, false}, {0, none, {0, 0, 0}, tr…
479 +};
480 +
481 +DynamicArray searchString = UTF8_ARRAY;
482 +DynamicArray commandHist0 = UTF8_ARRAY;
483 +DynamicArray commandHist1 = UTF8_ARRAY;
484 +DynamicArray highlights = DWORD_ARRAY;
485 +
486 +/// History command toggle
487 +static bool toggle = false;
488 +
489 +//
490 +// Utility functions
491 +static inline int intervalDiff(int v, int a, int b) {
492 + return (v < a) ? (v - a) : ((v > b) ? (v - b) : 0);
493 +}
494 +static inline void swap(DynamicArray *const a, DynamicArray *const b) {
495 + DynamicArray tmp = *a; *a = *b; *b = tmp;
496 +}
497 +static inline int max(int a, int b) { return a > b ? a : b; }
498 +static inline int min(int a, int b) { return a < b ? a : b; }
499 +static inline int mod(int a, int b) { for (; a < 0; a += b); return a %…
500 +static inline bool contains (char c, char const * values, uint32_t memS…
501 + ENSURE(values != NULL, return false);
502 + for (uint32_t i = 0; i < memSize; ++i) if (c == values[i]) retu…
503 + return false;
504 +}
505 +static inline void applyPosition(Position const *pos) {
506 + ENSURE(pos != NULL, return);
507 + term.c.x = pos->x;
508 + term.c.y = pos->y;
509 + term.scr = pos->yScr;
510 +}
511 +static inline int getSearchDirection(void) {
512 + return stateVB.motion.search == forward ? 1 : -1;
513 +}
514 +
515 +// Utilities for working with the current version of the scrollback pa…
516 +static bool moveLine(int32_t const amount) {
517 + int32_t const reqShift = intervalDiff(term.c.y+=amount, 0, term…
518 + term.c.y -= reqShift;
519 + int32_t const sDiff = intervalDiff(term.scr-=reqShift, 0, HISTS…
520 + term.scr -= sDiff;
521 + return sDiff == 0;
522 +}
523 +
524 +static void moveLetter(int32_t const amount) {
525 + int32_t value = (term.c.x += amount) / term.col;
526 + if (value -= (term.c.x < 0)) {
527 + term.c.x = moveLine(value) ? mod(term.c.x, term.col)
528 + : max(min(term.c.x,term.col - 1), 0);
529 + }
530 + assert(BETWEEN(term.c.x,0,term.col-1)&&BETWEEN(term.c.y,0,term.…
531 +}
532 +
533 +//
534 +// `Private` functions:
535 +
536 +// Functions: Temporarily display string on screen.
537 +
538 +/// Display string at end of a specified line without writing it into t…
539 +/// @param str string that is to be displayed
540 +/// @param g glyph
541 +/// @param yPos
542 +static void
543 +displayString(DynamicArray const *str, Glyph const *g, int yPos, bool p…
544 + ENSURE((str != NULL) && (g != NULL) && (term.row > 0), return);
545 + ENSURE(yPos >= 0, yPos = 0);
546 + ENSURE(yPos < term.row, yPos = term.row - 1);
547 + // Arbritary limit to avoid withhelding too much info from user.
548 + int const maxFractionOverridden = 3;
549 + // Threshold: if there is no space to print, do not print, but …
550 + // repsonsibility for printing back to [st].
551 + if (term.col < maxFractionOverridden) { …
552 + term.dirty[yPos] = 1;
553 + return;
554 + }
555 + int32_t const botSz = prePos * 6; //< sz for position indication
556 + // Determine the dimensions of used chunk of screen.
557 + int32_t const overrideSize = min(size(str) + botSz,
558 + term.col / maxFractionOverridden); …
559 + int32_t const overrideEnd = term.col - 2;
560 + // Has to follow trivially hence th assert:
561 + // overrideSize <(1)= term.col/3 <(0)= term.col = overrideEnd …
562 + assert(overrideSize <= overrideEnd + 1);
563 + int32_t const overrideStart = 1 + overrideEnd - overrideSize;
564 + // display history[history.size() - (overrideSize - botSz)::-1]
565 + Glyph *SEC(line, malloc(sizeof(Glyph) * (overrideSize)),,)
566 + int32_t offset = (size(str) - overrideSize - 1 + botSz) * str->…
567 + for (uint32_t chr = 0; chr < overrideSize - botSz; ++chr) {
568 + line[chr] = *g;
569 + line[chr].u = *((Rune*) (str->content+(offset+=str->ite…
570 + }
571 + if (prePos) {
572 + ENSURE(term.scr < HISTSIZE, term.scr = HISTSIZE - 1);
573 + int const p=(int)(0.5+(HISTSIZE-1-term.scr)*100./(HISTS…
574 + int const v = min(max(p, 0), 100);
575 + char prc [10];
576 + switch (term.scr) {
577 + case HISTSIZE - 1: strcpy(prc, " [TOP]"); break;
578 + case 0: strcpy(prc, " [BOT]"); break;
579 + default: sprintf(prc, " % 3d%c ", v,…
580 + }
581 + for (uint32_t chr = 0; chr < botSz; ++chr) {
582 + line[chr + overrideSize - botSz] =*g;
583 + line[chr + overrideSize - botSz].fg = fgPos;
584 + line[chr + overrideSize - botSz].bg = bgPos;
585 + utf8decode(&prc[chr],&line[chr+overrideSize-bot…
586 + }
587 + line[overrideSize - botSz] =*g;
588 + }
589 + xdrawline(TLINE(yPos), 0, yPos, overrideStart);
590 + term.c.y -= term.row; term.c.x -= term.col; // not highlight ha…
591 + xdrawline(line-overrideStart, overrideStart, yPos, overrideEnd …
592 + term.c.y += term.row; term.c.x += term.col;
593 + free(line);
594 +}
595 +
596 +static inline void printCommandString(void) {
597 + Glyph g = styleCommand;
598 + switch(stateVB.command.op) {
599 + case yank: g.fg = fgCommandYank; g.bg = bgCommandYank; …
600 + case visual: g.fg=fgCommandVisual; g.bg=bgCommandVisual…
601 + case visualLine: g.fg=fgCommandVisualLine;
602 + g.bg=bgCommandVisualLine;
603 + }
604 + displayString(isEmpty(currentCommand) ? lastCommand : currentCo…
605 + &g, term.row - 1, true);
606 +}
607 +
608 +static inline void printSearchString(void) {
609 + displayString(&searchString, &styleSearch, term.row - 2, false);
610 +}
611 +
612 +// NormalMode Operation / Motion utilies.
613 +
614 +static inline bool isMotionFinished(void) { return stateVB.motion.finis…
615 +
616 +static inline void finishMotion(void) { stateVB.motion.finished = true;…
617 +
618 +static inline bool isOperationFinished(void) {
619 + return stateVB.command.op==noop && stateVB.command.infix==infix…
620 +}
621 +
622 +/// Register that the current comamnd is finished and a new command is …
623 +static inline void startNewCommand(bool abort) {
624 + if (!abort) { toggle = !toggle; }
625 + empty(currentCommand);
626 +}
627 +
628 +static inline void finishOperation(void) {
629 + stateVB.command = defaultNormalMode.command;
630 + assert(isOperationFinished());
631 + // After an operation is finished, the selection has to be rele…
632 + // no highlights are to be released.
633 + selclear();
634 + empty(&highlights);
635 + // THe command string is reset for a new command.
636 + startNewCommand(true);
637 +}
638 +
639 +static inline void enableOperation(enum Operation o) {
640 + finishOperation();
641 + stateVB.command.op = o;
642 + stateVB.command.infix = infix_none;
643 + stateVB.command.startPosition.x = term.c.x;
644 + stateVB.command.startPosition.y = term.c.y;
645 + stateVB.command.startPosition.yScr = term.scr;
646 +}
647 +
648 +/// @param abort: If enabled, the command exits without registering
649 +/// @return Whether the the application is ready to yield control…
650 +//the normal command flow
651 +static bool terminateCommand(bool abort) {
652 + bool const exitOperation = isMotionFinished();
653 + bool exitNormalMode = false;
654 + finishMotion();
655 +
656 + if (exitOperation) {
657 + exitNormalMode = isOperationFinished();
658 + finishOperation();
659 + }
660 + printCommandString();
661 + printSearchString();
662 + return exitNormalMode;
663 +}
664 +
665 +static inline void exitCommand(void) { terminateCommand(false); }
666 +
667 +static inline void abortCommand(void) { terminateCommand(true); }
668 +
669 +/// Go to next occurrence of string relative to the current location
670 +/// conduct search, starting at start pos
671 +static bool gotoString(int8_t sign) {
672 + moveLetter(sign);
673 + uint32_t const searchStrSize = size(&searchString);
674 + uint32_t const maxIter = (HISTSIZE+term.row) * term.col + searc…
675 + uint32_t findIdx = 0;
676 + for (uint32_t cIteration = 0; findIdx < searchStrSize
677 + && ++cIteration <= maxIter; moveLetter(sign)) {
678 + char const * const SEC(next, sign==1
679 + ? view(&searchString, findIdx)
680 + : viewEnd(&searchString, findIdx), , fa…
681 + uint32_t const searchChar = *((uint32_t*) next);
682 +
683 + if (TLINE(term.c.y)[term.c.x].u == searchChar) { ++find…
684 + else { findIdx = 0; }
685 + }
686 + bool const found = findIdx == searchStrSize;
687 + for (uint32_t i = 0; found && i < searchStrSize; ++i) moveLette…
688 + return found;
689 +}
690 +
691 +/// Highlight all found strings on the current screen.
692 +static void highlightStringOnScreen(void) {
693 + if (isEmpty(&searchString)) { return; }
694 + empty(&highlights);
695 + uint32_t const searchStringSize = size(&searchString);
696 + uint32_t findIdx = 0;
697 + uint32_t xStart, yStart;
698 + bool success = true;
699 + for (int y = 0; y < term.row && success; y++) {
700 + for (int x = 0; x < term.col && success; x++) {
701 + char const* const SEC(next,
702 + view(&searchString,findIdx),,)
703 + if (TLINE(y)[x].u == (Rune) *((uint32_t*)(next)…
704 + if (++findIdx == 1) {
705 + xStart = x;
706 + yStart = y;
707 + }
708 + if (findIdx == searchStringSize) {
709 + success = success
710 + && append(&highlights, …
711 + && append(&highlights, …
712 + findIdx = 0; //term.dirty[yStar…
713 + }
714 + } else { findIdx = 0; }
715 + }
716 + }
717 + if (!success) { empty(&highlights); }
718 +}
719 +
720 +static bool gotoStringAndHighlight(int8_t sign) {
721 + // Find hte next occurrence of the #searchString in direc…
722 + bool const found = gotoString(sign);
723 + if (!found) { applyPosition(&stateVB.motion.searchPosition); }
724 + highlightStringOnScreen();
725 + //tsetdirt(0, term.row-3); //< everything except for the 'statu…
726 + return found;
727 +}
728 +
729 +static bool pressKeys(char const* nullTerminatedString, size_t end) {
730 + bool sc = true;
731 + for (size_t i = 0; i < end && sc; ++i) {
732 + sc = kpressNormalMode(&nullTerminatedString[i], 1, fals…
733 + }
734 + return sc;
735 +}
736 +
737 +static bool executeCommand(DynamicArray const *command) {
738 + size_t end=size(command);
739 + char decoded [32];
740 + bool succ = true;
741 + size_t len;
742 + for (size_t i = 0; i < end && succ; ++i) {
743 + char const *const SEC(nextRune, view(command, i),,false)
744 + len = utf8encode(*((Rune *) nextRune), decoded);
745 + succ = kpressNormalMode(decoded, len, false, NULL);
746 + }
747 + return succ;
748 +}
749 +
750 +struct { char const first; char const second; } const Brackets [] =
751 +{ {'(', ')'}, {'<', '>'}, {'{', '}'}, {'[', ']'}, };
752 +
753 +
754 +/// Emits Command prefix and suffix when i motion is performed (e.g. yi…
755 +///
756 +/// @param c: motion character
757 +/// @param expandMode: 1 for 'i', 2 for 'a'
758 +/// @param first, second: Dynamic arrays in which the prefix and postfix
759 +/// commands will be returned
760 +/// @return whether the command could be extracted succes…
761 +static bool expandExpression(char const c, enum Infix expandMode,
762 + char operation, DynamicArray *cmd) {
763 + empty(cmd);
764 + bool s = true; //< used in order to detect memory allocation er…
765 + char const lower = tolower(c);
766 + // Motions
767 + if (lower == 'w') {
768 + // translated into wb[command]e resp. WB[command]E, whi…
769 + // file even when at the fist letter. Does not work for…
770 + // letter words though.
771 + int const diff = c - lower;
772 + s = s && checkSetNextV(cmd, c);
773 + s = s && checkSetNextV(cmd, (signed char)(((int)'b') + …
774 + s = s && checkSetNextV(cmd, operation);
775 + s = s && checkSetNextV(cmd, (signed char)(((int)'e')+ d…
776 + return s;
777 + }
778 + // Symmetrical brackets (quotation marks)
779 + if (c == '\'' || c == '"') {
780 + // Local ambiguity -> do nothing. It cannot be determin…
781 + // the current char is the 1st or last char of the sele…
782 + // <---- search here? -- ['] -- or search here? --->
783 + if (TLINE(term.c.y)[term.c.x].u == c) {
784 + return false;
785 + }
786 + // Prefix
787 + char res [] = {'?', c, '\n'};
788 + s = s && checkSetNextP(cmd, res);
789 + // infix
790 + bool const iffy = expandMode == infix_i;
791 + if (iffy) { s = s && checkSetNextV(cmd, 'l'); }
792 + s = s && checkSetNextV(cmd, operation);
793 + if (!iffy) { s = s && checkSetNextV(cmd, 'l'); }
794 + // suffix
795 + res[0] = '/';
796 + s = s && checkSetNextP(cmd, res);
797 + if (iffy) { s = s && checkSetNextV(cmd, 'h'); }
798 + return s;
799 + }
800 + // Brackets: Does not if in range / if the brackets belong toge…
801 + for (size_t pid = 0; pid < sizeof(Brackets); ++pid) {
802 + if(Brackets[pid].first == c || Brackets[pid].second == …
803 + if (TLINE(term.c.y)[term.c.x].u!=Brackets[pid].…
804 + s = s && checkSetNextV(cmd, '?');
805 + s = s && checkSetNextV(cmd, Brackets[pi…
806 + s = s && checkSetNextV(cmd, '\n');
807 + }
808 + bool const iffy = expandMode == infix_i;
809 + if (iffy) { s = s && checkSetNextV(cmd, 'l'); }
810 + s = s && checkSetNextV(cmd, operation);
811 + if (!iffy) { s = s && checkSetNextV(cmd, 'l'); }
812 + s = s && checkSetNextV(cmd, '/');
813 + s = s && checkSetNextV(cmd, Brackets[pid].secon…
814 + s = s && checkSetNextV(cmd, '\n');
815 + if (iffy) { s = s && checkSetNextV(cmd, 'h'); }
816 + return s;
817 + }
818 + }
819 + /**/
820 + // search string
821 + // complicated search operation: <tag>
822 + if (c == 't') {
823 + // XXX: (Bug in vim: @vit )
824 + // <tag_name attr="hier" a2="\<sch\>"> [current pos] </…
825 +
826 + // 1. Copy history ( tag := hist[?<\n:/ \n] )
827 + // 2. Copy history ( first_find := hist[?<\n: next plac…
828 + // history where count '>' > count '<'
829 + // (can be behind current pos) )
830 + // 3. first := [?first_find][#first_ind]l
831 + // second:= [/tag">"]h
832 + //return true; // XXX: not implmented yet.
833 + }
834 + return false;
835 +}
836 +
837 +//
838 +// Public API
839 +//
840 +
841 +void onMove(void) {
842 + stateVB.initialPosition.x = term.c.x;
843 + stateVB.initialPosition.y = term.c.y;
844 + stateVB.initialPosition.yScr = term.scr;
845 +}
846 +
847 +int highlighted(int x, int y) {
848 + // Compute the legal bounds for a hit:
849 + int32_t const stringSize = size(&searchString);
850 + int32_t xMin = x - stringSize;
851 + int32_t yMin = y;
852 + while (xMin < 0 && yMin > 0) {
853 + xMin += term.col;
854 + --yMin;
855 + }
856 + if (xMin < 0) { xMin = 0; }
857 +
858 + uint32_t highSize = size(&highlights);
859 + ENSURE(highSize % 2 == 0, empty(&highlights); return false;);
860 + highSize /= 2;
861 + uint32_t *ptr = (uint32_t*) highlights.content;
862 + for (uint32_t i = 0; i < highSize; ++i) {
863 + int32_t const sx = (int32_t) *(ptr++);
864 + int32_t const sy = (int32_t) *(ptr++);
865 + if (BETWEEN(sy, yMin, y) && (sy != yMin || sx > xMin)
866 + && (sy != y || sx <= x)) {
867 + return true;
868 + }
869 + }
870 + return false;
871 +}
872 +
873 +ExitState kpressNormalMode(char const * cs, int len, bool ctrl, void co…
874 + KeySym const * const ksym = (KeySym*) v;
875 + bool const esc = ksym && *ksym == XK_Escape;
876 + bool const enter = (ksym && *ksym==XK_Return) || (len==1 &&cs[0…
877 + bool const quantifier = len == 1 && (BETWEEN(cs[0], 49, 57)
878 + || (cs[0] == 48 && stateVB.motion.amount));
879 + int const previousScroll = term.scr;
880 + // [ESC] or [ENTER] abort resp. finish the current level of ope…
881 + // Typing 'i' if no operation is currently performed behaves li…
882 + if (esc || enter || (len == 1 && cs[0] == 'i' && isMotionFinish…
883 + && isOperationFinished())) {
884 + if (terminateCommand(!enter)) {
885 + applyPosition(&stateVB.initialPosition);
886 + Position const pc = stateVB.initialPosition;
887 + stateVB = defaultNormalMode;
888 + stateVB.initialPosition = pc;
889 + tfulldirt();
890 + return finished;
891 + }
892 + len = 0;
893 + goto motionFinish;
894 + }
895 + // Backspace
896 + if (ksym && *ksym == XK_BackSpace) {
897 + bool s = stateVB.motion.search!=none&&!stateVB.motion.f…
898 + bool q = stateVB.motion.amount != 0;
899 + if (!(s || q)) { return failed; }
900 + len = 0;
901 +
902 + if (!isEmpty(currentCommand)) { pop(currentCommand); }
903 + if (s) {
904 + if (!isEmpty(&searchString)) { pop(&searchStrin…
905 + else if (isEmpty(&searchString)) {
906 + exitCommand();
907 + return success;
908 + }
909 + } else if (q) {
910 + stateVB.motion.amount /= 10;
911 + goto finishNoAppend;
912 + }
913 + }
914 +
915 + // Search: append to search string, then search & highlight
916 + if (stateVB.motion.search != none && !stateVB.motion.finished) {
917 + if (len >= 1) {
918 + EXPAND(kSearch, &searchString, true)
919 + utf8decode(cs, (Rune*)(kSearch), len);
920 + }
921 + applyPosition(&stateVB.motion.searchPosition);
922 + gotoStringAndHighlight(getSearchDirection());
923 + goto finish;
924 + }
925 + if (len == 0) { return failed; }
926 + // Quantifiers
927 + if (quantifier) {
928 + stateVB.motion.amount = min(SHRT_MAX,
929 + stateVB.motion.amount * 10 + cs[0] - 48…
930 + goto finish;
931 + }
932 + // 'i' mode enabled, hence the expression is to be expanded:
933 + // [start_expression(cs[0])] [operation] [stop_expression(cs[0]…
934 + if (stateVB.command.infix != infix_none && stateVB.command.op !…
935 + DynamicArray cmd = CHAR_ARRAY;
936 + char const operation = stateVB.command.op;
937 + bool succ = expandExpression(cs[0],
938 + stateVB.command.infix, visual, &cmd);
939 + if (operation == yank) {
940 + succ = succ && checkSetNextV(&cmd, operation);
941 + }
942 + NormalModeState const st = stateVB;
943 + TCursor const tc = term.c;
944 + stateVB.command.infix = infix_none;
945 + if (succ) {
946 + stateVB.command.op = noop;
947 + for (int i = 0; i < size(&cmd) && succ; ++i) {
948 + succ = pressKeys(&cmd.content[i], 1);
949 + }
950 + if (!succ) { // go back to the old position, ap…
951 + stateVB = st;
952 + term.c = tc;
953 + }
954 + empty(currentCommand);
955 + for (uint32_t i = 0; i < size(&cmd); ++i) {
956 + EXPAND(kCommand, currentCommand, true)
957 + utf8decode(cmd.content+i, (Rune*)(kComm…
958 + }
959 + }
960 + free(cmd.content);
961 + goto finishNoAppend;
962 + }
963 + // Commands (V / v or y)
964 + switch(cs[0]) {
965 + case '.':
966 + {
967 + if (isEmpty(currentCommand)) { toggle = !toggle…
968 + DynamicArray cmd = UTF8_ARRAY;
969 + swap(&cmd, currentCommand);
970 + executeCommand(&cmd) ? success : failed;
971 + swap(&cmd, currentCommand);
972 + free(cmd.content);
973 + goto finishNoAppend;
974 + }
975 + case 'i': stateVB.command.infix = infix_i; goto finish;
976 + case 'a': stateVB.command.infix = infix_a; goto finish;
977 + case 'y':
978 + switch(stateVB.command.op) {
979 + case noop: //< Start yank mode & set #op
980 + enableOperation(yank);
981 + selstart(term.c.x, term.c.y,ter…
982 + goto finish;
983 + case yank: //< Complete yank [y#amount …
984 + selstart(0, term.c.y, term.scr,…
985 + int const origY = term.c.y;
986 + moveLine(max(stateVB.motion.amo…
987 + selextend(term.col-1,term.c.y,t…
988 + SEL_RECTANGULAR…
989 + term.c.y = origY;
990 + FALLTHROUGH
991 + case visualLine: // Yank visual selecti…
992 + case visual:
993 + xsetsel(getsel());
994 + xclipcopy();
995 + exitCommand();
996 + goto finish;
997 + default:
998 + return failed;
999 + }
1000 + case visual:
1001 + case visualLine:
1002 + if (stateVB.command.op == cs[0]) {
1003 + finishOperation();
1004 + return true;
1005 + } else {
1006 + enableOperation(cs[0]);
1007 + selstart(cs[0] == visualLine ? 0 : term…
1008 + term.c.y, term.scr, 0);
1009 + goto finish;
1010 + }
1011 + }
1012 + // CTRL Motions
1013 + int32_t sign = -1; //< if command goes 'forward'(1) or 'back…
1014 + if (ctrl) {
1015 + if (ksym == NULL) { return false; }
1016 + switch(*ksym) {
1017 + case XK_f:
1018 + term.scr = max(term.scr - max(term.row-…
1019 + term.c.y = 0;
1020 + goto finish;
1021 + case XK_b:
1022 + term.scr = min(term.scr + max(term.row …
1023 + HISTSIZE - 1);
1024 + term.c.y = term.bot;
1025 + goto finish;
1026 + case XK_u:
1027 + term.scr = min(term.scr+term.row/2, HIS…
1028 + goto finish;
1029 + case XK_d:
1030 + term.scr = max(term.scr - term.row / 2,…
1031 + goto finish;
1032 + default: return false;
1033 + }
1034 + }
1035 + // Motions
1036 + switch(cs[0]) {
1037 + case 'c': empty(&commandHist0); empty(&commandHist1);
1038 + goto finishNoAppend;
1039 + case 'j': sign = 1; FALLTHROUGH
1040 + case 'k': moveLine(max(stateVB.motion.amount,1) * sign);
1041 + goto motionFinish;
1042 + case 'H': term.c.y = 0;
1043 + goto motionFinish;
1044 + case 'M': term.c.y = term.bot / 2;
1045 + goto motionFinish;
1046 + case 'L': term.c.y = term.bot;
1047 + goto motionFinish;
1048 + case 'G': applyPosition(&stateVB.initialPosition);
1049 + goto motionFinish;
1050 + case 'l': sign = 1; FALLTHROUGH
1051 + case 'h': moveLetter(sign * max(stateVB.motion.amount,1…
1052 + goto motionFinish;
1053 + case '0': term.c.x = 0;
1054 + goto motionFinish;
1055 + case '$': term.c.x = term.col-1;
1056 + goto motionFinish;
1057 + case 'w': FALLTHROUGH
1058 + case 'W': FALLTHROUGH
1059 + case 'e': FALLTHROUGH
1060 + case 'E': sign = 1; FALLTHROUGH
1061 + case 'B': FALLTHROUGH
1062 + case 'b': {
1063 + char const * const wDelim =
1064 + cs[0] <= 90 ? wordDelimLarge : wordDeli…
1065 + uint32_t const wDelimLen = strlen(wDelim);
1066 +
1067 + bool const startSpaceIsSeparator =
1068 + !(cs[0] == 'w' || cs[0] == 'W');
1069 + // Whether to start & end with offset:
1070 + bool const performOffset = startSpaceIsSeparato…
1071 + // Max iteration := One complete hist traversal.
1072 + uint32_t const maxIter = (HISTSIZE+term.row) * …
1073 + // Doesn't work exactly as in vim: Linebreak is
1074 + // counted as 'normal' separator, hence a jump …
1075 + // span multiple lines here.
1076 + stateVB.motion.amount = max(stateVB.motion.amou…
1077 + for (;stateVB.motion.amount>0;--stateVB.motion.…
1078 + uint8_t state = 0;
1079 + if (performOffset) { moveLetter(sign); }
1080 + for (uint32_t cIt = 0; cIt ++ < maxIter…
1081 + if (startSpaceIsSeparator == co…
1082 + if (state == 1) {
1083 + if (performOffs…
1084 + moveLet…
1085 + }
1086 + break;
1087 + }
1088 + } else if (state == 0) { state …
1089 + }
1090 + }
1091 + goto motionFinish;
1092 + }
1093 + case '/': sign = 1; FALLTHROUGH
1094 + case '?':
1095 + empty(&searchString);
1096 + stateVB.motion.search = sign == 1 ? forward :…
1097 + stateVB.motion.searchPosition.x = term.c.x;
1098 + stateVB.motion.searchPosition.y = term.c.y;
1099 + stateVB.motion.searchPosition.yScr = term.scr;
1100 + stateVB.motion.finished = false;
1101 + goto finish;
1102 + case 'n': sign = 1; FALLTHROUGH
1103 + case 'N': {
1104 + if (stateVB.motion.search == none) return faile…
1105 + if (stateVB.motion.search == backward) { sign *…
1106 + bool b = true; int ox = term.c.x;
1107 + int oy = term.c.y ; int scr = term.scr;
1108 + int32_t i = max(stateVB.motion.amount, 1);
1109 + for (;i>0 && (b=gotoString(sign)); --i) {
1110 + oy = term.c.y; scr = term.scr;
1111 + }
1112 + if (!b) { term.c.x = ox; term.c.y = oy; term.sc…
1113 + goto motionFinish;
1114 + }
1115 + case 't': // Toggle selection mode and set dirt.
1116 + sel.type = sel.type == SEL_REGULAR
1117 + ? SEL_RECTANGULAR : SEL_REGULAR;
1118 + //tsetdirt(sel.nb.y, sel.ne.y);
1119 + goto motionFinish;
1120 + }
1121 + // Custom commands
1122 + for (size_t i = 0; i < amountNormalModeShortcuts; ++i) {
1123 + if (cs[0] == normalModeShortcuts[i].key) {
1124 + return pressKeys(normalModeShortcuts[i].value,
1125 + strlen(normalModeShortcuts[i].v…
1126 + ? success : failed;
1127 + }
1128 + }
1129 + return failed;
1130 +motionFinish:
1131 + stateVB.motion.amount = 0;
1132 + //if (isMotionFinished() && stateVB.command.op == yank) {
1133 + if (stateVB.command.op == yank) {
1134 + selextend(term.c.x, term.c.y, term.scr, sel.type, 0);
1135 + xsetsel(getsel());
1136 + xclipcopy();
1137 + exitCommand();
1138 + }
1139 +finish:
1140 + if (len == 1 && !ctrl) { // XXX: for now.
1141 + EXPAND(kCommand, currentCommand, true)
1142 + utf8decode(cs, (Rune*)(kCommand), len);
1143 + }
1144 +finishNoAppend:
1145 + if (stateVB.command.op == visual) {
1146 + selextend(term.c.x, term.c.y, term.scr, sel.type, 0);
1147 + } else if (stateVB.command.op == visualLine) {
1148 + selextend(term.col-1, term.c.y, term.scr, sel.type, 0);
1149 + }
1150 +
1151 + if (previousScroll != term.scr && !isEmpty(&searchString)) {
1152 + highlightStringOnScreen();
1153 + }
1154 + tsetdirt(0, term.row-3); //< Required because of the cursor cro…
1155 + printCommandString();
1156 + printSearchString();
1157 + return success;
1158 +}
1159 diff -ruN st-default/normalMode.h st1/normalMode.h
1160 --- st-default/normalMode.h 1970-01-01 01:00:00.000000000 +0100
1161 +++ st1/normalMode.h 2020-06-04 11:04:30.229111510 +0200
1162 @@ -0,0 +1,36 @@
1163 +/* See LICENSE for license details. */
1164 +#ifndef NORMAL_MODE_H
1165 +#define NORMAL_MODE_H
1166 +
1167 +#include <stdbool.h>
1168 +#include <stddef.h>
1169 +#include <stdint.h>
1170 +
1171 +/// Used in the configuration file to define custom shortcuts.
1172 +typedef struct NormalModeShortcuts {
1173 + char key;
1174 + char *value;
1175 +} NormalModeShortcuts;
1176 +
1177 +/// Holds the exit status of the #kpressNormalMode function, which info…
1178 +/// caller when to exit normal mode.
1179 +typedef enum ExitState {
1180 + failed = 0,
1181 + success = 1,
1182 + finished = 2,
1183 +} ExitState;
1184 +
1185 +/// Called when curr position is altered.
1186 +void onMove(void);
1187 +
1188 +/// Function which returns whether the value at position provided as ar…
1189 +/// is to be highlighted.
1190 +int highlighted(int, int);
1191 +
1192 +/// Handles keys in normal mode.
1193 +ExitState kpressNormalMode(char const * decoded, int len, bool ctrlPres…
1194 + void const * ksym);
1195 + //bool esc, bool enter, bool backspace, void* keysym);
1196 +
1197 +
1198 +#endif // NORMAL_MODE_H
1199 Binary files st-default/normalMode.o and st1/normalMode.o differ
1200 Binary files st-default/st and st1/st differ
1201 diff -ruN st-default/st.c st1/st.c
1202 --- st-default/st.c 2020-06-04 11:15:55.165135902 +0200
1203 +++ st1/st.c 2020-06-04 11:04:30.231111510 +0200
1204 @@ -1,8 +1,10 @@
1205 /* See LICENSE for license details. */
1206 +#include <assert.h>
1207 #include <ctype.h>
1208 #include <errno.h>
1209 #include <fcntl.h>
1210 #include <limits.h>
1211 +#include <math.h>
1212 #include <pwd.h>
1213 #include <stdarg.h>
1214 #include <stdio.h>
1215 @@ -17,6 +19,8 @@
1216 #include <unistd.h>
1217 #include <wchar.h>
1218
1219 +
1220 +#include "term.h"
1221 #include "st.h"
1222 #include "win.h"
1223
1224 @@ -42,6 +46,7 @@
1225 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
1226 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
1227 #define ISDELIM(u) (u && wcschr(worddelimiters, u))
1228 +#define INTERVAL(x, a, b) (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
1229
1230 enum term_mode {
1231 MODE_WRAP = 1 << 0,
1232 @@ -86,17 +91,17 @@
1233 ESC_DCS =128,
1234 };
1235
1236 -typedef struct {
1237 - Glyph attr; /* current char attributes */
1238 - int x;
1239 - int y;
1240 - char state;
1241 -} TCursor;
1242 -
1243 -typedef struct {
1244 - int mode;
1245 - int type;
1246 - int snap;
1247 +/*typedef struct {*/
1248 + /*Glyph attr; [> current char attributes <]*/
1249 + /*int x;*/
1250 + /*int y;*/
1251 + /*char state;*/
1252 +/*} TCursor;*/
1253 +
1254 +/*typedef struct {*/
1255 + /*int mode;*/
1256 + /*int type;*/
1257 + /*int snap;*/
1258 /*
1259 * Selection variables:
1260 * nb – normalized coordinates of the beginning of the select…
1261 @@ -104,33 +109,33 @@
1262 * ob – original coordinates of the beginning of the selection
1263 * oe – original coordinates of the end of the selection
1264 */
1265 - struct {
1266 - int x, y;
1267 - } nb, ne, ob, oe;
1268 -
1269 - int alt;
1270 -} Selection;
1271 -
1272 -/* Internal representation of the screen */
1273 -typedef struct {
1274 - int row; /* nb row */
1275 - int col; /* nb col */
1276 - Line *line; /* screen */
1277 - Line *alt; /* alternate screen */
1278 - int *dirty; /* dirtyness of lines */
1279 - TCursor c; /* cursor */
1280 - int ocx; /* old cursor col */
1281 - int ocy; /* old cursor row */
1282 - int top; /* top scroll limit */
1283 - int bot; /* bottom scroll limit */
1284 - int mode; /* terminal mode flags */
1285 - int esc; /* escape state flags */
1286 - char trantbl[4]; /* charset table translation */
1287 - int charset; /* current charset */
1288 - int icharset; /* selected charset for sequence */
1289 - int *tabs;
1290 - Rune lastc; /* last printed char outside of sequence, 0 if co…
1291 -} Term;
1292 + /*struct {*/
1293 + /*int x, y;*/
1294 + /*} nb, ne, ob, oe;*/
1295 +
1296 + /*int alt;*/
1297 +/*} Selection;*/
1298 +
1299 +/*[> Internal representation of the screen <]*/
1300 +/*typedef struct {*/
1301 + /*int row; [> nb row <]*/
1302 + /*int col; [> nb col <]*/
1303 + /*Line *line; [> screen <]*/
1304 + /*Line *alt; [> alternate screen <]*/
1305 + /*int *dirty; [> dirtyness of lines <]*/
1306 + /*TCursor c; [> cursor <]*/
1307 + /*int ocx; [> old cursor col <]*/
1308 + /*int ocy; [> old cursor row <]*/
1309 + /*int top; [> top scroll limit <]*/
1310 + /*int bot; [> bottom scroll limit <]*/
1311 + /*int mode; [> terminal mode flags <]*/
1312 + /*int esc; [> escape state flags <]*/
1313 + /*char trantbl[4]; [> charset table translation <]*/
1314 + /*int charset; [> current charset <]*/
1315 + /*int icharset; [> selected charset for sequence <]*/
1316 + /*int *tabs;*/
1317 + /*Rune lastc; [> last printed char outside of sequence, 0 if …
1318 +/*} Term;*/
1319
1320 /* CSI Escape sequence structs */
1321 /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
1322 @@ -154,6 +159,8 @@
1323 int narg; /* nb of args */
1324 } STREscape;
1325
1326 +void tfulldirt(void);
1327 +
1328 static void execsh(char *, char **);
1329 static void stty(char **);
1330 static void sigchld(int);
1331 @@ -186,16 +193,14 @@
1332 static void tputtab(int);
1333 static void tputc(Rune);
1334 static void treset(void);
1335 -static void tscrollup(int, int);
1336 -static void tscrolldown(int, int);
1337 +static void tscrollup(int, int, int);
1338 +static void tscrolldown(int, int, int);
1339 static void tsetattr(int *, int);
1340 static void tsetchar(Rune, Glyph *, int, int);
1341 -static void tsetdirt(int, int);
1342 static void tsetscroll(int, int);
1343 static void tswapscreen(void);
1344 static void tsetmode(int, int, int *, int);
1345 static int twrite(const char *, int, int);
1346 -static void tfulldirt(void);
1347 static void tcontrolcode(uchar );
1348 static void tdectest(char );
1349 static void tdefutf8(char);
1350 @@ -209,8 +214,6 @@
1351 static void selscroll(int, int);
1352 static void selsnap(int *, int *, int);
1353
1354 -static size_t utf8decode(const char *, Rune *, size_t);
1355 -static Rune utf8decodebyte(char, size_t *);
1356 static char utf8encodebyte(Rune, size_t);
1357 static size_t utf8validate(Rune *, size_t);
1358
1359 @@ -220,8 +223,8 @@
1360 static ssize_t xwrite(int, const char *, size_t);
1361
1362 /* Globals */
1363 -static Term term;
1364 -static Selection sel;
1365 +Term term;
1366 +Selection sel;
1367 static CSIEscape csiescseq;
1368 static STREscape strescseq;
1369 static int iofd = 1;
1370 @@ -416,17 +419,22 @@
1371 {
1372 int i = term.col;
1373
1374 - if (term.line[y][i - 1].mode & ATTR_WRAP)
1375 + if (TLINE(y)[i - 1].mode & ATTR_WRAP)
1376 return i;
1377
1378 - while (i > 0 && term.line[y][i - 1].u == ' ')
1379 + while (i > 0 && TLINE(y)[i - 1].u == ' ')
1380 --i;
1381
1382 return i;
1383 }
1384
1385 void
1386 -selstart(int col, int row, int snap)
1387 +xselstart(int col, int row, int snap) {
1388 + selstart(col, row, term.scr, snap);
1389 +}
1390 +
1391 +void
1392 +selstart(int col, int row, int scroll, int snap)
1393 {
1394 selclear();
1395 sel.mode = SEL_EMPTY;
1396 @@ -435,6 +443,7 @@
1397 sel.snap = snap;
1398 sel.oe.x = sel.ob.x = col;
1399 sel.oe.y = sel.ob.y = row;
1400 + sel.oe.scroll = sel.ob.scroll = scroll;
1401 selnormalize();
1402
1403 if (sel.snap != 0)
1404 @@ -443,10 +452,13 @@
1405 }
1406
1407 void
1408 -selextend(int col, int row, int type, int done)
1409 -{
1410 - int oldey, oldex, oldsby, oldsey, oldtype;
1411 +xselextend(int col, int row, int type, int done) {
1412 + selextend(col, row, term.scr, type, done);
1413 +}
1414
1415 +void
1416 +selextend(int col, int row, int scroll, int type, int done)
1417 +{
1418 if (sel.mode == SEL_IDLE)
1419 return;
1420 if (done && sel.mode == SEL_EMPTY) {
1421 @@ -454,18 +466,22 @@
1422 return;
1423 }
1424
1425 - oldey = sel.oe.y;
1426 - oldex = sel.oe.x;
1427 - oldsby = sel.nb.y;
1428 - oldsey = sel.ne.y;
1429 - oldtype = sel.type;
1430 + int const oldey = sel.oe.y;
1431 + int const oldex = sel.oe.x;
1432 + int const oldscroll = sel.oe.scroll;
1433 + int const oldsby = sel.nb.y;
1434 + int const oldsey = sel.ne.y;
1435 + int const oldtype = sel.type;
1436
1437 sel.oe.x = col;
1438 sel.oe.y = row;
1439 + sel.oe.scroll = scroll;
1440 +
1441 selnormalize();
1442 sel.type = type;
1443
1444 - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.ty…
1445 + if (oldey != sel.oe.y || oldex != sel.oe.x || oldscroll != sel.…
1446 + || oldtype != sel.type || sel.mode == SEL_EMPTY)
1447 tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
1448
1449 sel.mode = done ? SEL_IDLE : SEL_READY;
1450 @@ -474,17 +490,21 @@
1451 void
1452 selnormalize(void)
1453 {
1454 - int i;
1455 -
1456 - if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
1457 - sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
1458 - sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
1459 + sel.nb.y = INTERVAL(sel.ob.y + term.scr - sel.ob.scroll, 0, ter…
1460 + sel.ne.y = INTERVAL(sel.oe.y + term.scr - sel.oe.scroll, 0, ter…
1461 + if (sel.type == SEL_REGULAR && sel.nb.y != sel.ne.y) {
1462 + sel.nb.x = sel.nb.y < sel.ne.y ? sel.ob.x : sel.oe.x;
1463 + sel.ne.x = sel.nb.y < sel.ne.y ? sel.oe.x : sel.ob.x;
1464 } else {
1465 sel.nb.x = MIN(sel.ob.x, sel.oe.x);
1466 sel.ne.x = MAX(sel.ob.x, sel.oe.x);
1467 }
1468 - sel.nb.y = MIN(sel.ob.y, sel.oe.y);
1469 - sel.ne.y = MAX(sel.ob.y, sel.oe.y);
1470 +
1471 + if (sel.nb.y > sel.ne.y) {
1472 + int32_t const tmp = sel.nb.y;
1473 + sel.nb.y = sel.ne.y;
1474 + sel.ne.y = tmp;
1475 + }
1476
1477 selsnap(&sel.nb.x, &sel.nb.y, -1);
1478 selsnap(&sel.ne.x, &sel.ne.y, +1);
1479 @@ -492,7 +512,7 @@
1480 /* expand selection over line breaks */
1481 if (sel.type == SEL_RECTANGULAR)
1482 return;
1483 - i = tlinelen(sel.nb.y);
1484 + int i = tlinelen(sel.nb.y);
1485 if (i < sel.nb.x)
1486 sel.nb.x = i;
1487 if (tlinelen(sel.ne.y) <= sel.ne.x)
1488 @@ -528,7 +548,7 @@
1489 * Snap around if the word wraps around at the end or
1490 * beginning of a line.
1491 */
1492 - prevgp = &term.line[*y][*x];
1493 + prevgp = &TLINE(*y)[*x];
1494 prevdelim = ISDELIM(prevgp->u);
1495 for (;;) {
1496 newx = *x + direction;
1497 @@ -543,14 +563,14 @@
1498 yt = *y, xt = *x;
1499 else
1500 yt = newy, xt = newx;
1501 - if (!(term.line[yt][xt].mode & ATTR_WRA…
1502 + if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
1503 break;
1504 }
1505
1506 if (newx >= tlinelen(newy))
1507 break;
1508
1509 - gp = &term.line[newy][newx];
1510 + gp = &TLINE(newy)[newx];
1511 delim = ISDELIM(gp->u);
1512 if (!(gp->mode & ATTR_WDUMMY) && (delim != prev…
1513 || (delim && gp->u != prevgp->u…
1514 @@ -571,14 +591,14 @@
1515 *x = (direction < 0) ? 0 : term.col - 1;
1516 if (direction < 0) {
1517 for (; *y > 0; *y += direction) {
1518 - if (!(term.line[*y-1][term.col-1].mode
1519 + if (!(TLINE(*y-1)[term.col-1].mode
1520 & ATTR_WRAP)) {
1521 break;
1522 }
1523 }
1524 } else if (direction > 0) {
1525 for (; *y < term.row-1; *y += direction) {
1526 - if (!(term.line[*y][term.col-1].mode
1527 + if (!(TLINE(*y)[term.col-1].mode
1528 & ATTR_WRAP)) {
1529 break;
1530 }
1531 @@ -598,24 +618,32 @@
1532 if (sel.ob.x == -1)
1533 return NULL;
1534
1535 - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
1536 + int32_t syb = sel.ob.y - sel.ob.scroll + term.scr;
1537 + int32_t sye = sel.oe.y - sel.oe.scroll + term.scr;
1538 + if (syb > sye) {
1539 + int32_t tmp = sye;
1540 + sye = syb;
1541 + syb = tmp;
1542 + }
1543 +
1544 + bufsize = (term.col+1) * (sye - syb + 1) * UTF_SIZ;
1545 ptr = str = xmalloc(bufsize);
1546
1547 /* append every set & selected glyph to the selection */
1548 - for (y = sel.nb.y; y <= sel.ne.y; y++) {
1549 + for (y = syb; y <= sye; y++) {
1550 if ((linelen = tlinelen(y)) == 0) {
1551 *ptr++ = '\n';
1552 continue;
1553 }
1554
1555 if (sel.type == SEL_RECTANGULAR) {
1556 - gp = &term.line[y][sel.nb.x];
1557 + gp = &TLINE(y)[sel.nb.x];
1558 lastx = sel.ne.x;
1559 } else {
1560 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0…
1561 - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
1562 + gp = &TLINE(y)[syb == y ? sel.nb.x : 0];
1563 + lastx = (sye == y) ? sel.ne.x : term.col-1;
1564 }
1565 - last = &term.line[y][MIN(lastx, linelen-1)];
1566 + last = &TLINE(y)[MIN(lastx, linelen-1)];
1567 while (last >= gp && last->u == ' ')
1568 --last;
1569
1570 @@ -850,6 +878,9 @@
1571 ttywrite(const char *s, size_t n, int may_echo)
1572 {
1573 const char *next;
1574 + Arg arg = (Arg) { .i = term.scr };
1575 +
1576 + kscrolldown(&arg);
1577
1578 if (may_echo && IS_SET(MODE_ECHO))
1579 twrite(s, n, 1);
1580 @@ -1061,13 +1092,53 @@
1581 }
1582
1583 void
1584 -tscrolldown(int orig, int n)
1585 +kscrolldown(const Arg* a)
1586 +{
1587 + int n = a->i;
1588 +
1589 + if (n < 0)
1590 + n = term.row + n;
1591 +
1592 + if (n > term.scr)
1593 + n = term.scr;
1594 +
1595 + if (term.scr > 0) {
1596 + term.scr -= n;
1597 + selscroll(0, -n);
1598 + tfulldirt();
1599 + }
1600 +}
1601 +
1602 +void
1603 +kscrollup(const Arg* a)
1604 +{
1605 + int n = a->i;
1606 +
1607 + if (n < 0)
1608 + n = term.row + n;
1609 +
1610 + if (term.scr <= HISTSIZE-n) {
1611 + term.scr += n;
1612 + selscroll(0, n);
1613 + tfulldirt();
1614 + }
1615 +}
1616 +
1617 +void
1618 +tscrolldown(int orig, int n, int copyhist)
1619 {
1620 int i;
1621 Line temp;
1622
1623 LIMIT(n, 0, term.bot-orig+1);
1624
1625 + if (copyhist) {
1626 + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
1627 + temp = term.hist[term.histi];
1628 + term.hist[term.histi] = term.line[term.bot];
1629 + term.line[term.bot] = temp;
1630 + }
1631 +
1632 tsetdirt(orig, term.bot-n);
1633 tclearregion(0, term.bot-n+1, term.col-1, term.bot);
1634
1635 @@ -1081,13 +1152,23 @@
1636 }
1637
1638 void
1639 -tscrollup(int orig, int n)
1640 +tscrollup(int orig, int n, int copyhist)
1641 {
1642 int i;
1643 Line temp;
1644
1645 LIMIT(n, 0, term.bot-orig+1);
1646
1647 + if (copyhist) {
1648 + term.histi = (term.histi + 1) % HISTSIZE;
1649 + temp = term.hist[term.histi];
1650 + term.hist[term.histi] = term.line[orig];
1651 + term.line[orig] = temp;
1652 + }
1653 +
1654 + if (term.scr > 0 && term.scr < HISTSIZE)
1655 + term.scr = MIN(term.scr + n, HISTSIZE-1);
1656 +
1657 tclearregion(0, orig, term.col-1, orig+n-1);
1658 tsetdirt(orig+n, term.bot);
1659
1660 @@ -1109,6 +1190,7 @@
1661 if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig…
1662 selclear();
1663 } else if (BETWEEN(sel.nb.y, orig, term.bot)) {
1664 + sel.oe.scroll = sel.ob.scroll = term.scr;
1665 sel.ob.y += n;
1666 sel.oe.y += n;
1667 if (sel.ob.y < term.top || sel.ob.y > term.bot ||
1668 @@ -1126,13 +1208,19 @@
1669 int y = term.c.y;
1670
1671 if (y == term.bot) {
1672 - tscrollup(term.top, 1);
1673 + tscrollup(term.top, 1, 1);
1674 } else {
1675 y++;
1676 }
1677 tmoveto(first_col ? 0 : term.c.x, y);
1678 }
1679
1680 +int
1681 +currentLine(int x, int y)
1682 +{
1683 + return (x == term.c.x || y == term.c.y);
1684 +}
1685 +
1686 void
1687 csiparse(void)
1688 {
1689 @@ -1185,6 +1273,8 @@
1690 term.c.state &= ~CURSOR_WRAPNEXT;
1691 term.c.x = LIMIT(x, 0, term.col-1);
1692 term.c.y = LIMIT(y, miny, maxy);
1693 + // Set the last position in order to restore after normal mode …
1694 + onMove();
1695 }
1696
1697 void
1698 @@ -1291,14 +1381,14 @@
1699 tinsertblankline(int n)
1700 {
1701 if (BETWEEN(term.c.y, term.top, term.bot))
1702 - tscrolldown(term.c.y, n);
1703 + tscrolldown(term.c.y, n, 0);
1704 }
1705
1706 void
1707 tdeleteline(int n)
1708 {
1709 if (BETWEEN(term.c.y, term.top, term.bot))
1710 - tscrollup(term.c.y, n);
1711 + tscrollup(term.c.y, n, 0);
1712 }
1713
1714 int32_t
1715 @@ -1735,11 +1825,11 @@
1716 break;
1717 case 'S': /* SU -- Scroll <n> line up */
1718 DEFAULT(csiescseq.arg[0], 1);
1719 - tscrollup(term.top, csiescseq.arg[0]);
1720 + tscrollup(term.top, csiescseq.arg[0], 0);
1721 break;
1722 case 'T': /* SD -- Scroll <n> line down */
1723 DEFAULT(csiescseq.arg[0], 1);
1724 - tscrolldown(term.top, csiescseq.arg[0]);
1725 + tscrolldown(term.top, csiescseq.arg[0], 0);
1726 break;
1727 case 'L': /* IL -- Insert <n> blank lines */
1728 DEFAULT(csiescseq.arg[0], 1);
1729 @@ -2246,7 +2336,7 @@
1730 return 0;
1731 case 'D': /* IND -- Linefeed */
1732 if (term.c.y == term.bot) {
1733 - tscrollup(term.top, 1);
1734 + tscrollup(term.top, 1, 1);
1735 } else {
1736 tmoveto(term.c.x, term.c.y+1);
1737 }
1738 @@ -2259,7 +2349,7 @@
1739 break;
1740 case 'M': /* RI -- Reverse index */
1741 if (term.c.y == term.top) {
1742 - tscrolldown(term.top, 1);
1743 + tscrolldown(term.top, 1, 1);
1744 } else {
1745 tmoveto(term.c.x, term.c.y-1);
1746 }
1747 @@ -2301,7 +2391,7 @@
1748 {
1749 char c[UTF_SIZ];
1750 int control;
1751 - int width, len;
1752 + int width = 0, len;
1753 Glyph *gp;
1754
1755 control = ISCONTROL(u);
1756 @@ -2481,7 +2571,7 @@
1757 void
1758 tresize(int col, int row)
1759 {
1760 - int i;
1761 + int i, j;
1762 int minrow = MIN(row, term.row);
1763 int mincol = MIN(col, term.col);
1764 int *bp;
1765 @@ -2518,6 +2608,14 @@
1766 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
1767 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
1768
1769 + for (i = 0; i < HISTSIZE; i++) {
1770 + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyp…
1771 + for (j = mincol; j < col; j++) {
1772 + term.hist[i][j] = term.c.attr;
1773 + term.hist[i][j].u = ' ';
1774 + }
1775 + }
1776 +
1777 /* resize each row to new width, zero-pad if needed */
1778 for (i = 0; i < minrow; i++) {
1779 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyp…
1780 @@ -2576,7 +2674,7 @@
1781 continue;
1782
1783 term.dirty[y] = 0;
1784 - xdrawline(term.line[y], x1, y, x2);
1785 + xdrawline(TLINE(y), x1, y, x2);
1786 }
1787 }
1788
1789 @@ -2597,8 +2695,8 @@
1790 cx--;
1791
1792 drawregion(0, 0, term.col, term.row);
1793 - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
1794 - term.ocx, term.ocy, term.line[term.ocy][term.oc…
1795 + xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
1796 + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
1797 term.ocx = cx;
1798 term.ocy = term.c.y;
1799 xfinishdraw();
1800 diff -ruN st-default/st.c.rej st1/st.c.rej
1801 --- st-default/st.c.rej 1970-01-01 01:00:00.000000000 +0100
1802 +++ st1/st.c.rej 2020-06-04 11:04:30.231111510 +0200
1803 @@ -0,0 +1,73 @@
1804 +--- st.c
1805 ++++ st.c
1806 +@@ -91,51 +96,6 @@ enum escape_state {
1807 + ESC_DCS =128,
1808 + };
1809 +
1810 +-typedef struct {
1811 +- Glyph attr; /* current char attributes */
1812 +- int x;
1813 +- int y;
1814 +- char state;
1815 +-} TCursor;
1816 +-
1817 +-typedef struct {
1818 +- int mode;
1819 +- int type;
1820 +- int snap;
1821 +- /*
1822 +- * Selection variables:
1823 +- * nb – normalized coordinates of the beginning of the selec…
1824 +- * ne – normalized coordinates of the end of the selection
1825 +- * ob – original coordinates of the beginning of the selecti…
1826 +- * oe – original coordinates of the end of the selection
1827 +- */
1828 +- struct {
1829 +- int x, y;
1830 +- } nb, ne, ob, oe;
1831 +-
1832 +- int alt;
1833 +-} Selection;
1834 +-
1835 +-/* Internal representation of the screen */
1836 +-typedef struct {
1837 +- int row; /* nb row */
1838 +- int col; /* nb col */
1839 +- Line *line; /* screen */
1840 +- Line *alt; /* alternate screen */
1841 +- int *dirty; /* dirtyness of lines */
1842 +- TCursor c; /* cursor */
1843 +- int ocx; /* old cursor col */
1844 +- int ocy; /* old cursor row */
1845 +- int top; /* top scroll limit */
1846 +- int bot; /* bottom scroll limit */
1847 +- int mode; /* terminal mode flags */
1848 +- int esc; /* escape state flags */
1849 +- char trantbl[4]; /* charset table translation */
1850 +- int charset; /* current charset */
1851 +- int icharset; /* selected charset for sequence */
1852 +- int *tabs;
1853 +-} Term;
1854 +-
1855 + /* CSI Escape sequence structs */
1856 + /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
1857 + typedef struct {
1858 +@@ -1174,6 +1210,7 @@ selscroll(int orig, int n)
1859 + return;
1860 +
1861 + if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, ori…
1862 ++ sel.oe.scroll = sel.ob.scroll = term.scr;
1863 + if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < te…
1864 + selclear();
1865 + return;
1866 +@@ -2681,8 +2734,8 @@ draw(void)
1867 + cx--;
1868 +
1869 + drawregion(0, 0, term.col, term.row);
1870 +- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
1871 +- term.ocx, term.ocy, term.line[term.ocy][term.o…
1872 ++ xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
1873 ++ term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
1874 + term.ocx = cx, term.ocy = term.c.y;
1875 + xfinishdraw();
1876 + xximspot(term.ocx, term.ocy);
1877 diff -ruN st-default/st.h st1/st.h
1878 --- st-default/st.h 2020-06-04 11:15:55.165135902 +0200
1879 +++ st1/st.h 2020-06-04 11:04:30.232111510 +0200
1880 @@ -1,5 +1,8 @@
1881 /* See LICENSE for license details. */
1882
1883 +#include "glyph.h"
1884 +#include "normalMode.h"
1885 +
1886 #include <stdint.h>
1887 #include <sys/types.h>
1888
1889 @@ -33,6 +36,8 @@
1890 ATTR_WRAP = 1 << 8,
1891 ATTR_WIDE = 1 << 9,
1892 ATTR_WDUMMY = 1 << 10,
1893 + ATTR_HIGHLIGHT = 1 << 12,
1894 + ATTR_CURRENT = 1 << 13,
1895 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
1896 };
1897
1898 @@ -42,11 +47,6 @@
1899 SEL_READY = 2
1900 };
1901
1902 -enum selection_type {
1903 - SEL_REGULAR = 1,
1904 - SEL_RECTANGULAR = 2
1905 -};
1906 -
1907 enum selection_snap {
1908 SNAP_WORD = 1,
1909 SNAP_LINE = 2
1910 @@ -57,18 +57,6 @@
1911 typedef unsigned long ulong;
1912 typedef unsigned short ushort;
1913
1914 -typedef uint_least32_t Rune;
1915 -
1916 -#define Glyph Glyph_
1917 -typedef struct {
1918 - Rune u; /* character code */
1919 - ushort mode; /* attribute flags */
1920 - uint32_t fg; /* foreground */
1921 - uint32_t bg; /* background */
1922 -} Glyph;
1923 -
1924 -typedef Glyph *Line;
1925 -
1926 typedef union {
1927 int i;
1928 uint ui;
1929 @@ -81,6 +69,11 @@
1930 void redraw(void);
1931 void draw(void);
1932
1933 +int currentLine(int, int);
1934 +void kscrolldown(const Arg *);
1935 +void kscrollup(const Arg *);
1936 +void normalMode(Arg const *);
1937 +
1938 void printscreen(const Arg *);
1939 void printsel(const Arg *);
1940 void sendbreak(const Arg *);
1941 @@ -90,6 +83,9 @@
1942 void tnew(int, int);
1943 void tresize(int, int);
1944 void tsetdirtattr(int);
1945 +size_t utf8decode(const char *, Rune *, size_t);
1946 +Rune utf8decodebyte(char, size_t *);
1947 +void tsetdirt(int, int);
1948 void ttyhangup(void);
1949 int ttynew(char *, char *, char *, char **);
1950 size_t ttyread(void);
1951 @@ -100,8 +96,10 @@
1952
1953 void selclear(void);
1954 void selinit(void);
1955 -void selstart(int, int, int);
1956 -void selextend(int, int, int, int);
1957 +void selstart(int, int, int, int);
1958 +void xselstart(int, int, int);
1959 +void selextend(int, int, int, int, int);
1960 +void xselextend(int, int, int, int);
1961 int selected(int, int);
1962 char *getsel(void);
1963
1964 Binary files st-default/st.o and st1/st.o differ
1965 diff -ruN st-default/term.h st1/term.h
1966 --- st-default/term.h 1970-01-01 01:00:00.000000000 +0100
1967 +++ st1/term.h 2020-06-04 11:04:30.232111510 +0200
1968 @@ -0,0 +1,74 @@
1969 +#ifndef TERM_H
1970 +#define TERM_H
1971 +
1972 +//
1973 +// Internal terminal structs.
1974 +//
1975 +
1976 +#include "glyph.h"
1977 +
1978 +#include <stdint.h>
1979 +
1980 +#define HISTSIZE 2500
1981 +
1982 +typedef struct {
1983 + Glyph attr; /* current char attributes */
1984 + int x;
1985 + int y;
1986 + char state;
1987 +} TCursor;
1988 +
1989 +typedef struct {
1990 + int mode;
1991 + int type;
1992 + int snap;
1993 + /// Selection variables:
1994 + /// ob – original coordinates of the beginning of the selecti…
1995 + /// oe – original coordinates of the end of the selection
1996 + struct {
1997 + int x, y, scroll;
1998 + } ob, oe;
1999 + /// Selection variables; currently displayed chunk.
2000 + /// nb – normalized coordinates of the beginning of the selec…
2001 + /// ne – normalized coordinates of the end of the selection
2002 + struct {
2003 + int x, y;
2004 + } nb, ne;
2005 +
2006 + int alt;
2007 +} Selection;
2008 +
2009 +/* Internal representation of the screen */
2010 +typedef struct {
2011 + int row; /* nb row */
2012 + int col; /* nb col */
2013 + Line *line; /* screen */
2014 + Line *alt; /* alternate screen */
2015 + Line hist[HISTSIZE]; /* history buffer */
2016 + int histi; /* history index */
2017 + int scr; /* scroll back */
2018 + int *dirty; /* dirtyness of lines */
2019 + TCursor c; /* cursor */
2020 + int ocx; /* old cursor col */
2021 + int ocy; /* old cursor row */
2022 + int top; /* top scroll limit */
2023 + int bot; /* bottom scroll limit */
2024 + int mode; /* terminal mode flags */
2025 + int esc; /* escape state flags */
2026 + char trantbl[4]; /* charset table translation */
2027 + int charset; /* current charset */
2028 + int icharset; /* selected charset for sequence */
2029 + int *tabs;
2030 + Rune lastc;
2031 +} Term;
2032 +
2033 +extern Term term;
2034 +
2035 +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
2036 + term.scr + HISTSIZE + 1) % HISTSIZE] : \
2037 + term.line[(y) - term.scr])
2038 +
2039 +extern Selection sel;
2040 +
2041 +
2042 +#endif // TERM_H
2043 diff -ruN st-default/win.h st1/win.h
2044 --- st-default/win.h 2020-06-04 11:15:55.166135902 +0200
2045 +++ st1/win.h 2020-06-04 11:04:30.232111510 +0200
2046 @@ -19,6 +19,7 @@
2047 MODE_MOUSEMANY = 1 << 15,
2048 MODE_BRCKTPASTE = 1 << 16,
2049 MODE_NUMLOCK = 1 << 17,
2050 + MODE_NORMAL = 1 << 18,
2051 MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
2052 |MODE_MOUSEMANY,
2053 };
2054 @@ -27,6 +28,7 @@
2055 void xclipcopy(void);
2056 void xdrawcursor(int, int, Glyph, int, int, Glyph);
2057 void xdrawline(Line, int, int, int);
2058 +void xdrawglyph(Glyph, int, int);
2059 void xfinishdraw(void);
2060 void xloadcols(void);
2061 int xsetcolorname(int, const char *);
2062 diff -ruN st-default/x.c st1/x.c
2063 --- st-default/x.c 2020-06-04 11:15:55.166135902 +0200
2064 +++ st1/x.c 2020-06-04 11:04:30.232111510 +0200
2065 @@ -143,7 +143,6 @@
2066 static inline ushort sixd_to_16bit(int);
2067 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, …
2068 static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i…
2069 -static void xdrawglyph(Glyph, int, int);
2070 static void xclear(int, int, int, int);
2071 static int xgeommasktogravity(int);
2072 static int ximopen(Display *);
2073 @@ -356,7 +355,7 @@
2074 break;
2075 }
2076 }
2077 - selextend(evcol(e), evrow(e), seltype, done);
2078 + xselextend(evcol(e), evrow(e), seltype, done);
2079 if (done)
2080 setsel(getsel(), e->xbutton.time);
2081 }
2082 @@ -486,7 +485,7 @@
2083 xsel.tclick2 = xsel.tclick1;
2084 xsel.tclick1 = now;
2085
2086 - selstart(evcol(e), evrow(e), snap);
2087 + xselstart(evcol(e), evrow(e), snap);
2088 }
2089 }
2090
2091 @@ -773,6 +772,13 @@
2092 }
2093
2094 void
2095 +normalMode(Arg const *_) {
2096 + (void) _;
2097 + win.mode ^= MODE_NORMAL;
2098 +}
2099 +
2100 +
2101 +void
2102 xloadcols(void)
2103 {
2104 int i;
2105 @@ -1358,6 +1364,14 @@
2106 base.fg = defaultattr;
2107 }
2108
2109 + if (base.mode & ATTR_HIGHLIGHT) {
2110 + base.bg = highlightBg;
2111 + base.fg = highlightFg;
2112 + } else if ((base.mode & ATTR_CURRENT) && (win.mode & MODE_NORMA…
2113 + base.bg = currentBg;
2114 + base.fg = currentFg;
2115 + }
2116 +
2117 if (IS_TRUECOL(base.fg)) {
2118 colfg.alpha = 0xffff;
2119 colfg.red = TRUERED(base.fg);
2120 @@ -1447,7 +1461,7 @@
2121 xclear(winx, winy + win.ch, winx + width, win.h);
2122
2123 /* Clean up the region we want to draw to. */
2124 - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
2125 + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
2126
2127 /* Set the clip region because Xft is sometimes dirty. */
2128 r.x = 0;
2129 @@ -1490,8 +1504,9 @@
2130 Color drawcol;
2131
2132 /* remove the old cursor */
2133 - if (selected(ox, oy))
2134 - og.mode ^= ATTR_REVERSE;
2135 + if (selected(ox, oy)) og.mode ^= ATTR_REVERSE;
2136 + if (highlighted(ox, oy)) { og.mode ^= ATTR_HIGHLIGHT; }
2137 + if (currentLine(ox, oy)) { og.mode ^= ATTR_CURRENT; }
2138 xdrawglyph(og, ox, oy);
2139
2140 if (IS_SET(MODE_HIDE))
2141 @@ -1523,6 +1538,11 @@
2142 drawcol = dc.col[g.bg];
2143 }
2144
2145 + if ((g.mode & ATTR_CURRENT) && (win.mode & MODE_NORMAL)) {
2146 + g.bg = currentBg;
2147 + g.fg = currentFg;
2148 + }
2149 +
2150 /* draw the new one */
2151 if (IS_SET(MODE_FOCUSED)) {
2152 switch (win.cursor) {
2153 @@ -1607,12 +1627,18 @@
2154
2155 numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y…
2156 i = ox = 0;
2157 - for (x = x1; x < x2 && i < numspecs; x++) {
2158 + for (x = x1; x < x2 && i < numspecs; ++x) {
2159 new = line[x];
2160 if (new.mode == ATTR_WDUMMY)
2161 continue;
2162 if (selected(x, y1))
2163 new.mode ^= ATTR_REVERSE;
2164 + if (highlighted(x, y1)) {
2165 + new.mode ^= ATTR_HIGHLIGHT;
2166 + }
2167 + if (currentLine(x, y1)) {
2168 + new.mode ^= ATTR_CURRENT;
2169 + }
2170 if (i > 0 && ATTRCMP(base, new)) {
2171 xdrawglyphfontspecs(specs, base, i, ox, y1);
2172 specs += i;
2173 @@ -1800,6 +1826,14 @@
2174 len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &…
2175 else
2176 len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
2177 +
2178 + if (IS_SET(MODE_NORMAL)) {
2179 + ExitState const es = kpressNormalMode(buf, len, // strl…
2180 + match(ControlMask, e->state),
2181 + &ksym);
2182 + if (es == finished) { normalMode(NULL); }
2183 + return;
2184 + }
2185 /* 1. shortcuts */
2186 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
2187 if (ksym == bp->keysym && match(bp->mod, e->state)) {
2188 Binary files st-default/x.o and st1/x.o differ
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.