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 |