Introduction
Introduction Statistics Contact Development Disclaimer Help
st-vimBrowse-20200607-0.8.3.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-vimBrowse-20200607-0.8.3.diff (36879B)
---
1 From 8e4543ce29ca528e19fcb2db8964247a4e0597bc Mon Sep 17 00:00:00 2001
2 From: Julius Huelsmann <[email protected]>
3 Date: Sun, 7 Jun 2020 17:26:17 +0200
4 Subject: [PATCH] meta-patch: vim-browse
5
6 ---
7 Makefile | 2 +-
8 config.def.h | 14 +++
9 normalMode.c | 279 +++++++++++++++++++++++++++++++++++++++++
10 normalMode.h | 7 ++
11 st.c | 348 +++++++++++++++++++++++++++------------------------
12 st.h | 1 +
13 utils.h | 23 ++++
14 win.h | 1 +
15 x.c | 16 ++-
16 9 files changed, 521 insertions(+), 170 deletions(-)
17 create mode 100644 normalMode.c
18 create mode 100644 normalMode.h
19 create mode 100644 utils.h
20
21 diff --git a/Makefile b/Makefile
22 index 470ac86..6688a58 100644
23 --- a/Makefile
24 +++ b/Makefile
25 @@ -21,7 +21,7 @@ config.h:
26 .c.o:
27 $(CC) $(STCFLAGS) -c $<
28
29 -st.o: config.h st.h win.h
30 +st.o: config.h st.h win.h normalMode.h normalMode.c utils.h
31 x.o: arg.h config.h st.h win.h
32
33 $(OBJ): config.h config.mk
34 diff --git a/config.def.h b/config.def.h
35 index 0895a1f..daa092b 100644
36 --- a/config.def.h
37 +++ b/config.def.h
38 @@ -122,6 +122,19 @@ unsigned int defaultfg = 7;
39 unsigned int defaultbg = 0;
40 static unsigned int defaultcs = 256;
41 static unsigned int defaultrcs = 257;
42 +unsigned int const currentBg = 6, buffSize = 2048;
43 +/// [Vim Browse] Colors for search results currently on screen.
44 +unsigned int const highlightBg = 160, highlightFg = 15;
45 +char const wDelS[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", wDelL[] = " \…
46 +char *nmKeys [] = { ///< Shortcusts executed in normal mode
47 + "R/Building\nN", "r/Building\n", "X/juli@machine\nN", "x/juli@machine…
48 + "Q?[Leaving vim, starting execution]\n","F/: error:\nN", "f/: error:\…
49 +};
50 +unsigned int const amountNmKeys = sizeof(nmKeys) / sizeof(*nmKeys);
51 +/// Style of the {command, search} string shown in the right corner (y,…
52 +Glyph styleSearch = {' ', ATTR_ITALIC | ATTR_BOLD_FAINT, 7, 16};
53 +Glyph style[] = {{' ',ATTR_ITALIC|ATTR_FAINT,15,16}, {' ',ATTR_ITALIC,2…
54 + {' ', ATTR_ITALIC, 232, 4}, {' ', ATTR_ITALIC, 232, 12…
55
56 /*
57 * Default shape of cursor
58 @@ -188,6 +201,7 @@ static Shortcut shortcuts[] = {
59 { TERMMOD, XK_Y, selpaste, {.i = …
60 { ShiftMask, XK_Insert, selpaste, {.i = …
61 { TERMMOD, XK_Num_Lock, numlock, {.i = …
62 + { MODKEY, XK_c, normalMode, {.i = …
63 };
64
65 /*
66 diff --git a/normalMode.c b/normalMode.c
67 new file mode 100644
68 index 0000000..24a3fb2
69 --- /dev/null
70 +++ b/normalMode.c
71 @@ -0,0 +1,279 @@
72 +#include <X11/keysym.h>
73 +#include <X11/XKBlib.h>
74 +
75 +#include "normalMode.h"
76 +#include "utils.h"
77 +
78 +extern Glyph const styleSearch, style[];
79 +extern char const wDelS[], wDelL[], *nmKeys[];
80 +extern unsigned int bg[], fg, currentBg, highlightBg, highlightFg, amou…
81 +
82 +typedef struct { int p[3]; } Pos;
83 +struct NormalModeState {
84 + struct OperationState {
85 + enum Op {noop=0, visual='v', visualLine='V', yank = 'y'…
86 + enum Infix {infix_none=0, infix_i='i', infix_a='a'} inf…
87 + } cmd;
88 + struct MotionState {
89 + uint32_t c; int active; Pos searchPos;
90 + enum Search {none=0, fw='/', bw='?'} search;
91 + } m;
92 +} defaultNormalMode, state;
93 +DynamicArray searchStr=UTF8_ARRAY, cCmd=UTF8_ARRAY, lCmd=UTF8_ARRAY;
94 +Glyph styleCmd;
95 +char posBuffer[10], brack[6][2] = { {"()"}, {"<>"}, {"{}"}, {"[]"}, {"\…
96 +int exited=1, overlay=1;
97 +static inline uint32_t cchar() { return term.line[term.c.y][term.c.x].u…
98 +static inline int pos(int p, int h) {return IS_SET(MODE_ALTSCREEN)?p:ra…
99 +static inline int contains(char c, char const * values, uint32_t memSiz…
100 + for (uint32_t i = 0; i < memSize; ++i) if (c == values[i]) retu…
101 + return 0;
102 +}
103 +static inline void decodeTo(char const *cs, int len, DynamicArray *darr…
104 + char *var = expand(darr);
105 + if (!var) empty(darr); else utf8decode(cs, (Rune*)(var), len);
106 +}
107 +static inline void applyPos(Pos p) {
108 + term.c.x = p.p[0], term.c.y = p.p[1];
109 + if (!IS_SET(MODE_ALTSCREEN) && histOp) term.line = &buf[histOff…
110 +}
111 +/// Find string in history buffer, and provide string-match-lookup for …
112 +static int highlighted(int x, int y) {
113 + int const s=term.row*term.col, i=y*term.col+x, sz=size(&searchS…
114 + return sz && i<s && mark[i]!=sz && i+mark[i]<s && !mark[i+mark[…
115 +}
116 +static void markSearchMatches(int all) {
117 + int sz = size(&searchStr), ox = 0, oy = 0, oi=0;
118 + for (int y=0; sz && all && y<term.row; ++y)
119 + for (int x=0; x<term.col; ++x) term.dirty[y] |= highlig…
120 + for (int y = 0, wi=0, owi=0, i=0; sz && y < term.row; ++y)
121 + for (int x=0; x<term.col; ++x, wi%=sz, ++i, owi=wi)
122 + if (all || term.dirty[y]) {
123 + mark[i]=sz-(wi=(getU32(&searchStr,wi,1)…
124 + if (wi==1) ox=x, oy=y, oi=i; else if (!…
125 + }
126 + for (int y=0; sz &&all &&y<term.row; ++y)
127 + for (int x=0; x<term.col; ++x) term.dirty[y] |= highlig…
128 +}
129 +static int findString(int8_t s, int all) {
130 + Pos p = (Pos) {.p={term.c.x, term.c.y, IS_SET(MODE_ALTSCREEN) ?…
131 + historyMove(s, 0, 0);
132 + uint32_t strSz=size(&searchStr), maxIter=rows()*term.col+strSz,…
133 + for (uint32_t i=0, wi = 0; widx<strSz && ++i<=maxIter; historyM…
134 + widx = (getU32(&searchStr, widx, s>0)==cchar())?widx+1:…
135 + if (wi && !widx) historyMove(-s*wi, 0, 0);
136 + }
137 + if (widx == strSz && widx) historyMove(-s * strSz, 0, 0);
138 + else applyPos(p);
139 + markSearchMatches(all);
140 + return widx == strSz;
141 +}
142 +/// Execute series of normal-mode commands from char array / decoded fr…
143 +static ExitState pressKeys(char const* s, size_t e) {
144 + ExitState x=succ;
145 + for (size_t i=0; i<e && (x=(!s[i] ? x : kpressHist(&s[i], 1, 0,…
146 + return x;
147 +}
148 +static ExitState executeCommand(uint32_t *c, size_t z) {
149 + ExitState x=succ;
150 + char dc [32];
151 + for (size_t i=0; i<z && (x=kpressHist(dc,utf8encode(c[i],dc),0,…
152 + return x;
153 +}
154 +/// Get character for overlay, if the overlay (st) has something to sho…
155 +static void getChar(DynamicArray *st, Glyph *glyphChange, int y, int xE…
156 + if (x < xEnd - min(width=min(width,xEnd), size(st))) *glyphChan…
157 + else if (x<xEnd) glyphChange->u = *((Rune*)(st->content + (size…
158 +}
159 +/// Expand "infix" expression: for instance (w =>) l b | …
160 +static ExitState expandExpression(char c) { // ({ =>) l ? { …
161 + int a=state.cmd.infix==infix_a, yank=state.cmd.op=='y', lc=tolo…
162 + state.cmd.infix = infix_none;
163 + if(!yank && state.cmd.op!=visual && state.cmd.op!=visualLine) r…
164 + char mot[11] = {'l', 0, 'b', 0, 0, 'v', 0, 'e', 0, 0, yank ? 'y…
165 + if (lc == 'w') mot[2] = 'b' - lc + c, mot[7] = (a ? 'w' : 'e') …
166 + else {
167 + mot[1]='?', mot[3]=mot[8]='\n', mot[6]='/', mot[4]=a?0:…
168 + for (int i=found=0; !found && i < 6; ++i)
169 + if ((found=contains(c,brack[i],2))) mot[2]=brac…
170 + }
171 + if (!found) return failed;
172 + assign(&lCmd, &cCmd);
173 + empty(&cCmd);
174 + state.cmd = defaultNormalMode.cmd;
175 + return pressKeys(mot, 11);
176 +}
177 +
178 +int executeMotion(char const cs, int len, KeySym const *const ks) {
179 + state.m.c = max(state.m.c, 1);
180 + if (ks && *ks == XK_d) historyMove(0, 0, term.row / 2);
181 + else if (ks && *ks == XK_u) historyMove(0, 0, -term.row / 2);
182 + else if (ks && *ks == XK_f) historyMove(0, 0, term.row-1+(term.…
183 + else if (ks && *ks == XK_b) historyMove(0, 0, -(term.c.y=term.r…
184 + else if (ks && *ks == XK_h) overlay = !overlay;
185 + else if (!len) return failed;
186 + else if (cs == 'K') historyMove(0, 0, -state.m.c);
187 + else if (cs == 'J') historyMove(0, 0, state.m.c);
188 + else if (cs == 'k') historyMove(0, -state.m.c, 0);
189 + else if (cs == 'j') historyMove(0, state.m.c, 0);
190 + else if (cs == 'h') historyMove(-state.m.c, 0, 0);
191 + else if (cs == 'l') historyMove( state.m.c, 0, 0);
192 + else if (cs == 'H') term.c.y = 0;
193 + else if (cs == 'M') term.c.y = term.bot / 2;
194 + else if (cs == 'L') term.c.y = term.bot;
195 + else if (cs == 's' || cs == 'S') altToggle = cs == 's' ? !altTo…
196 + else if (cs == 'G' || cs == 'g') {
197 + if (cs == 'G') term.c = c[0] = c[IS_SET(MODE_ALTSCREEN)…
198 + if (!IS_SET(MODE_ALTSCREEN)) term.line = &buf[histOff=i…
199 + } else if (cs == '0') term.c.x = 0;
200 + else if (cs == '$') term.c.x = term.col-1;
201 + else if (cs == 't') sel.type = sel.type==SEL_REGULAR ? SEL_RECT…
202 + else if (cs == 'n' || cs == 'N') {
203 + int const d = ((cs=='N')!=(state.m.search==bw))?-1:1;
204 + for (int i = state.m.c; i && findString(d, 0); --i);
205 + } else if (contains(cs, "wWeEbB", 6)) {
206 + int const low=cs<=90, off=tolower(cs)!='w', sgn=(tolowe…
207 + l=strlen(wDelL), s=strlen(wDelS), mit=rows()*…
208 + for (int it=0, on=0; state.m.c > 0; ++it) {
209 + if (off || it) if (!historyMove(sgn, 0, 0)) it …
210 + int n = 1<<(contains(cchar(),wDelS,s) ?(2-low) …
211 + found = (on|=n)^n && ((off ?on^n :n)!=1); /…
212 + if (found && off) historyMove(-sgn, 0, 0); …
213 + if (found || it>mit) it=-1, on=0, --state.m.c; …
214 + }
215 + } else return failed;
216 + state.m.c = 0;
217 + return state.cmd.op == yank ? exitMotion : succ;
218 +}
219 +
220 +ExitState kpressHist(char const *cs, int len, int ctrl, KeySym const *k…
221 + historyOpToggle(1, 1);
222 + int const prevYOff=IS_SET(MODE_ALTSCREEN)?0:histOff, search=sta…
223 + prevAltToggle=altToggle, prevOverlay=overlay;
224 + int const noOp=!state.cmd.op&&!state.cmd.infix, num=len==1&&BET…
225 + esc=ksym&&*ksym==XK_Escape, ret=(ksym&&*ksym==XK_Retu…
226 + quantifier=num&&(cs[0]!='0'||state.m.c), ins=!search …
227 + exited = 0;
228 + ExitState result = succ;
229 + if (esc || ret || ins) { result = exitMotion, len = 0;
230 + } else if (ksym && *ksym == XK_BackSpace) {
231 + if ((search || state.m.c) && size(&cCmd)) pop(&cCmd);
232 + if (search) {
233 + if (size(&searchStr)) pop(&searchStr);
234 + else result = exitMotion;
235 + if (!size(&searchStr)) tfulldirt();
236 + applyPos(state.m.searchPos);
237 + findString(state.m.search==fw ? 1 : -1, 1);
238 + } else if (state.m.c) state.m.c /= 10;
239 + len = 0;
240 + } else if (search) {
241 + if (len >= 1) decodeTo(cs, len, &searchStr);
242 + applyPos(state.m.searchPos);
243 + findString(state.m.search==fw ? 1 : -1, 1);
244 + } else if (len == 0) { result = failed;
245 + } else if (quantifier) { state.m.c = min(SHRT_MAX, state.m.c*10…
246 + } else if (state.cmd.infix && state.cmd.op && (result = expandE…
247 + } else if (cs[0] == '.') {
248 + if (size(&cCmd)) assign(&lCmd, &cCmd);
249 + empty(&cCmd);
250 + executeCommand((uint32_t*) lCmd.content, size(&lCmd));
251 + empty(&cCmd);
252 + len = 0;
253 + } else if (cs[0] == 'r') { tfulldirt();
254 + } else if (cs[0] == 'c') {
255 + empty(&lCmd);
256 + empty(&cCmd);
257 + empty(&searchStr);
258 + tfulldirt();
259 + len = 0;
260 + } else if (cs[0] == fw || cs[0] == bw) {
261 + empty(&searchStr);
262 + state.m.search = cs[0];
263 + state.m.searchPos = (Pos){.p={term.c.x, term.c.y, prevY…
264 + state.m.active = 1;
265 + } else if (cs[0]==infix_i || cs[0]==infix_a) { state.cmd.infix=…
266 + } else if (cs[0] == 'y') {
267 + if (state.cmd.op) {
268 + result = (state.cmd.op == yank) ? exitOp : exit…
269 + if (state.cmd.op == yank) selstart(0, term.c.y,…
270 + } else selstart(term.c.x, term.c.y, 0);
271 + state.cmd.op = yank;
272 + } else if (cs[0] == visual || cs[0] == visualLine) {
273 + if (state.cmd.op != (unsigned char) cs[0]) {
274 + state.cmd = defaultNormalMode.cmd;
275 + state.cmd.op = cs[0];
276 + selstart(cs[0] == visualLine ?0 :term.c.x, term…
277 + } else result = exitOp;
278 + } else if (!(result =executeMotion(len?cs[0]:0, len, ctrl?ksym:…
279 + result=failed;
280 + for (size_t i = 0; !ctrl && i < amountNmKeys; ++i)
281 + if (cs[0]==nmKeys[i][0] &&
282 + failed!=(result=pressKeys(&nmKeys[i][1], str…
283 + } // Operation/Motion finished if valid: update cmd string, ext…
284 + if (result != failed) {
285 + if (len == 1 && !ctrl) decodeTo(cs, len, &cCmd);
286 + if ((state.cmd.op == visualLine) || ((state.cmd.op == y…
287 + int const off = pos(term.c.y, 1) < pos(sel.ob.y…
288 + sel.ob.x = off ? term.col - 1 : 0;
289 + selextend(off ? 0 : term.col-1, term.c.y, sel.t…
290 + } else if (sel.oe.x != -1) selextend(term.c.x, term.c.y…
291 + } // Set repaint for motion or status bar
292 + if (!IS_SET(MODE_ALTSCREEN) && prevYOff != histOff) tfulldirt();
293 + // Terminate Motion / operation if thus indicated
294 + if (result == exitMotion) {
295 + if (!state.m.active) result = (exited=noOp) ? finished …
296 + state.m.active = state.m.c = 0;
297 + }
298 + if (result == exitOp || result == finished) {
299 + if (state.cmd.op == yank) {
300 + xsetsel(getsel());
301 + xclipcopy();
302 + }
303 + state = defaultNormalMode;
304 + selclear();
305 + if (!esc) assign(&lCmd, &cCmd);
306 + empty(&cCmd);
307 + } // Update the content displayed in the history overlay
308 + styleCmd = style[state.cmd.op==yank ? 1 : (state.cmd.op==visual…
309 + (state.cmd.op==visualLine ? 3 :0))];
310 + int const posLin = !IS_SET(MODE_ALTSCREEN) ? rangeY(insertOff-h…
311 + if (!posLin || posLin==h || !h) strcpy(posBuffer, posLin ? " [B…
312 + else sprintf(posBuffer, " % 3d%c ", min(100, max(0, .5 + posLi…
313 + if ((overlay || overlay!=prevOverlay) && term.col>9 && term.row…
314 + if (!term.dirty[term.row-1]) xdrawline(term.line[term.r…
315 + if (!term.dirty[term.row-2]) xdrawline(term.line[term.r…
316 + }
317 + if (result==finished) altToggle = 0;
318 + if (altToggle != prevAltToggle) tswapscreen();
319 +end:
320 + historyOpToggle(-1, 1);
321 + return result;
322 +}
323 +
324 +void historyOverlay(int x, int y, Glyph* g) {
325 + if (!histMode) return;
326 + TCursor const *cHist = histOp ? &term.c : &c[0];
327 + if(overlay && term.col > 9 && term.row > 4 && (x > (2*term.col/…
328 + *g = (y == term.row - 2) ? styleSearch : styleCmd;
329 + if (y == term.row-2) getChar(&searchStr, g, term.row-2,…
330 + else if (x > term.col - 7) g->u = posBuffer[x - term.co…
331 + else getChar(size(&cCmd) ?&cCmd :&lCmd, g, term.row-1, …
332 + } else if (highlighted(x, y)) g->bg = highlightBg, g->fg = high…
333 + else if ((x==cHist->x) ^ (y==cHist->y)) g->bg = currentBg;
334 + else if (x==cHist->x) g->mode^=ATTR_REVERSE;
335 +}
336 +void historyPreDraw() {
337 + static Pos op = {.p={0, 0, 0}};
338 + historyOpToggle(1, 0);
339 + // Draw the cursor cross if changed
340 + if (term.c.y >= term.row || op.p[1] >= term.row) tfulldirt();
341 + else if (exited || (op.p[1] != term.c.y)) term.dirty[term.c.y] …
342 + for (int i=0; (exited || term.c.x != op.p[0]) && i<term.row; ++…
343 + xdrawline(term.line[i], term.c.x, i, term.c.x + 1);
344 + xdrawline(term.line[i], op.p[0], i, op.p[0] + 1);
345 + }
346 + // Update search results either only for lines with new content…
347 + markSearchMatches(exited);
348 + op = (Pos){.p = {term.c.x, term.c.y, 0}};
349 + historyOpToggle(-1, 0);
350 +}
351 diff --git a/normalMode.h b/normalMode.h
352 new file mode 100644
353 index 0000000..f520c61
354 --- /dev/null
355 +++ b/normalMode.h
356 @@ -0,0 +1,7 @@
357 +void normalMode();
358 +void historyPreDraw();
359 +void historyOverlay(int x, int y, Glyph* g);
360 +void historyModeToggle(int start);
361 +/// Handles keys in normal mode.
362 +typedef enum {failed=0, succ=1, exitMotion=2, exitOp=3, finished=4} Exi…
363 +ExitState kpressHist(char const *txt, int len, int ctrl, KeySym const *…
364 diff --git a/st.c b/st.c
365 index 0ce6ac2..14dfe64 100644
366 --- a/st.c
367 +++ b/st.c
368 @@ -1,4 +1,5 @@
369 /* See LICENSE for license details. */
370 +#include <assert.h>
371 #include <ctype.h>
372 #include <errno.h>
373 #include <fcntl.h>
374 @@ -42,6 +43,8 @@
375 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
376 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
377 #define ISDELIM(u) (u && wcschr(worddelimiters, u))
378 +static inline int max(int a, int b) { return a > b ? a : b; }
379 +static inline int min(int a, int b) { return a < b ? a : b; }
380
381 enum term_mode {
382 MODE_WRAP = 1 << 0,
383 @@ -97,6 +100,7 @@ typedef struct {
384 int mode;
385 int type;
386 int snap;
387 + int swap;
388 /*
389 * Selection variables:
390 * nb – normalized coordinates of the beginning of the select…
391 @@ -204,9 +208,8 @@ static void tstrsequence(uchar);
392
393 static void drawregion(int, int, int, int);
394
395 -static void selnormalize(void);
396 static void selscroll(int, int);
397 -static void selsnap(int *, int *, int);
398 +static void selnormalize(void);
399
400 static size_t utf8decode(const char *, Rune *, size_t);
401 static Rune utf8decodebyte(char, size_t *);
402 @@ -232,6 +235,14 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0x…
403 static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10…
404 static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10F…
405
406 +int buffCols;
407 +extern int const buffSize;
408 +int histOp, histMode, histOff, histOffX, insertOff, altToggle, *mark;
409 +Line *buf = NULL;
410 +static TCursor c[3];
411 +static inline int rows() { return IS_SET(MODE_ALTSCREEN) ? term.row : b…
412 +static inline int rangeY(int i) { while (i < 0) i += rows(); return i %…
413 +
414 ssize_t
415 xwrite(int fd, const char *s, size_t len)
416 {
417 @@ -424,6 +435,114 @@ tlinelen(int y)
418 return i;
419 }
420
421 +void historyOpToggle(int start, int paint) {
422 + if (!histOp == !(histOp + start)) if ((histOp += start) || 1) r…
423 + if (histMode && paint && (!IS_SET(MODE_ALTSCREEN) || altToggle)…
424 + tcursor(CURSOR_SAVE);
425 + histOp += start;
426 + if (histMode && altToggle) {
427 + tswapscreen();
428 + memset(term.dirty,0,sizeof(*term.dirty)*term.row);
429 + }
430 + tcursor(CURSOR_LOAD);
431 + *(!IS_SET(MODE_ALTSCREEN)?&term.line:&term.alt)=&buf[histOp?his…
432 +}
433 +
434 +void historyModeToggle(int start) {
435 + if (!(histMode = (histOp = !!start))) {
436 + selnormalize();
437 + tfulldirt();
438 + } else {
439 + tcursor(CURSOR_SAVE);
440 + histOp = 0;
441 + histOff = insertOff;
442 + }
443 +}
444 +
445 +int historyBufferScroll(int n) {
446 + if (IS_SET(MODE_ALTSCREEN) || !n) return histOp;
447 + int p=abs(n=(n<0) ? max(n,-term.row) : min(n,term.row)), r=term…
448 + s=sizeof(*term.dirty), *ptr=histOp?&histOff:&insertOf…
449 + if (!histMode || histOp) tfulldirt(); else {
450 + memmove(&term.dirty[-min(n,0)], &term.dirty[max(n,0)], …
451 + memset(&term.dirty[n>0 ? r : 0], 0, s * p);
452 + }
453 + int const prevOffBuf = sel.alt ? 0 : insertOff + term.row;
454 + term.line = &buf[*ptr = (buffSize+*ptr+n) % buffSize];
455 + // Cut part of selection removed from buffer, and update sel.ne…
456 + if (sel.ob.x != -1 && !histOp && n) {
457 + int const offBuf = sel.alt ? 0 : insertOff + term.row,
458 + pb = rangeY(sel.ob.y - prevOffBuf),
459 + pe = rangeY(sel.oe.y - prevOffBuf);
460 + int const b = rangeY(sel.ob.y - offBuf), nln = n < 0,
461 + e = rangeY(sel.oe.y - offBuf), last = offBuf …
462 + if (pb != b && ((pb < b) != nln)) sel.ob.y = last;
463 + if (pe != e && ((pe < e) != nln)) sel.oe.y = last;
464 + if (sel.oe.y == last && sel.ob.y == last) selclear();
465 + }
466 + selnormalize();
467 + // Clear the new region exposed by the shift.
468 + if (!histOp) tclearregion(0, n>0?r+1:0, buffCols-1, n>0?term.ro…
469 + return 1;
470 +}
471 +
472 +int historyMove(int x, int y, int ly) {
473 + historyOpToggle(1, 1);
474 + y += ((term.c.x += x) < 0 ?term.c.x-term.col :term.c.x) / term.…
475 + if ((term.c.x %= term.col) < 0) term.c.x += term.col;
476 + if ((term.c.y += y) >= term.row) ly += term.c.y - term.row + 1;…
477 + else if (term.c.y < 0) ly += term.c.y;
478 + term.c.y = MIN(MAX(term.c.y, 0), term.row - 1);
479 + int off=insertOff-histOff, bot=rangeY(off), top=-rangeY(-term.r…
480 + pTop = (-ly>-top), pBot = (ly > bot), fin=histMode&&(pTop||…
481 + if (fin && (x||y)) term.c.x = pBot ? term.col-1 : 0;
482 + historyBufferScroll(fin ? (pBot ? bot : top) : ly);
483 + historyOpToggle(-1, 1);
484 + return fin;
485 +}
486 +
487 +#include "normalMode.c"
488 +
489 +void selnormalize(void) {
490 + historyOpToggle(1, 1);
491 +
492 + int const oldb = sel.nb.y, olde = sel.ne.y;
493 + if (sel.ob.x == -1) {
494 + sel.ne.y = sel.nb.y = -1;
495 + } else {
496 + int const offsetBuffer = sel.alt ? 0 : insertOff + term…
497 + int const off = sel.alt ? 0 : (histMode ? histOff : ins…
498 + int const nby = rangeY(sel.ob.y - off),
499 + ney = rangeY(sel.oe.y - off);
500 + sel.swap = rangeY(sel.ob.y - offsetBuffer)
501 + > rangeY(sel.oe.y - offsetBuffer);
502 + sel.nb.y = sel.swap ? ney : nby;
503 + sel.ne.y = !sel.swap ? ney : nby;
504 + int const cnb = sel.nb.y < term.row, cne = sel.ne.y < t…
505 + if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
506 + if (cnb) sel.nb.x = (!sel.swap) ? sel.ob.x : se…
507 + if (cne) sel.ne.x = (!sel.swap) ? sel.oe.x : se…
508 + } else {
509 + if (cnb) sel.nb.x = MIN(sel.ob.x, sel.oe.x);
510 + if (cne) sel.ne.x = MAX(sel.ob.x, sel.oe.x);
511 + }
512 + }
513 + int const nBet=sel.nb.y<=sel.ne.y, oBet=oldb<=olde;
514 + for (int i = 0; i < term.row; ++i) {
515 + int const n = nBet ? BETWEEN(i, sel.nb.y, sel.ne.y)
516 + : OUT(i, sel.nb.y, sel.ne.y);
517 + term.dirty[i] |= (sel.type == SEL_RECTANGULAR && n) ||
518 + (n != (oBet ? BETWEEN(i,oldb,olde) : OUT(i,oldb…
519 +
520 + }
521 + if (BETWEEN(oldb, 0, term.row - 1)) term.dirty[oldb] = 1;
522 + if (BETWEEN(olde, 0, term.row - 1)) term.dirty[olde] = 1;
523 + if (BETWEEN(sel.nb.y, 0, term.row - 1)) term.dirty[sel.nb.y] = …
524 + if (BETWEEN(sel.ne.y, 0, term.row - 1)) term.dirty[sel.ne.y] = …
525 +
526 + historyOpToggle(-1, 1);
527 +}
528 +
529 void
530 selstart(int col, int row, int snap)
531 {
532 @@ -433,19 +552,14 @@ selstart(int col, int row, int snap)
533 sel.alt = IS_SET(MODE_ALTSCREEN);
534 sel.snap = snap;
535 sel.oe.x = sel.ob.x = col;
536 - sel.oe.y = sel.ob.y = row;
537 + sel.oe.y = sel.ob.y = row + !sel.alt * (histMode ? histOff : in…
538 + if (sel.snap != 0) sel.mode = SEL_READY;
539 selnormalize();
540 -
541 - if (sel.snap != 0)
542 - sel.mode = SEL_READY;
543 - tsetdirt(sel.nb.y, sel.ne.y);
544 }
545
546 void
547 selextend(int col, int row, int type, int done)
548 {
549 - int oldey, oldex, oldsby, oldsey, oldtype;
550 -
551 if (sel.mode == SEL_IDLE)
552 return;
553 if (done && sel.mode == SEL_EMPTY) {
554 @@ -453,51 +567,13 @@ selextend(int col, int row, int type, int done)
555 return;
556 }
557
558 - oldey = sel.oe.y;
559 - oldex = sel.oe.x;
560 - oldsby = sel.nb.y;
561 - oldsey = sel.ne.y;
562 - oldtype = sel.type;
563 -
564 sel.oe.x = col;
565 - sel.oe.y = row;
566 + sel.oe.y = row + (sel.alt ? 0 : (histMode ? histOff : insertOff…
567 selnormalize();
568 sel.type = type;
569 -
570 - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.ty…
571 - tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
572 -
573 sel.mode = done ? SEL_IDLE : SEL_READY;
574 }
575
576 -void
577 -selnormalize(void)
578 -{
579 - int i;
580 -
581 - if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
582 - sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
583 - sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
584 - } else {
585 - sel.nb.x = MIN(sel.ob.x, sel.oe.x);
586 - sel.ne.x = MAX(sel.ob.x, sel.oe.x);
587 - }
588 - sel.nb.y = MIN(sel.ob.y, sel.oe.y);
589 - sel.ne.y = MAX(sel.ob.y, sel.oe.y);
590 -
591 - selsnap(&sel.nb.x, &sel.nb.y, -1);
592 - selsnap(&sel.ne.x, &sel.ne.y, +1);
593 -
594 - /* expand selection over line breaks */
595 - if (sel.type == SEL_RECTANGULAR)
596 - return;
597 - i = tlinelen(sel.nb.y);
598 - if (i < sel.nb.x)
599 - sel.nb.x = i;
600 - if (tlinelen(sel.ne.y) <= sel.ne.x)
601 - sel.ne.x = term.col - 1;
602 -}
603 -
604 int
605 selected(int x, int y)
606 {
607 @@ -509,119 +585,47 @@ selected(int x, int y)
608 return BETWEEN(y, sel.nb.y, sel.ne.y)
609 && BETWEEN(x, sel.nb.x, sel.ne.x);
610
611 - return BETWEEN(y, sel.nb.y, sel.ne.y)
612 - && (y != sel.nb.y || x >= sel.nb.x)
613 - && (y != sel.ne.y || x <= sel.ne.x);
614 -}
615 -
616 -void
617 -selsnap(int *x, int *y, int direction)
618 -{
619 - int newx, newy, xt, yt;
620 - int delim, prevdelim;
621 - Glyph *gp, *prevgp;
622 -
623 - switch (sel.snap) {
624 - case SNAP_WORD:
625 - /*
626 - * Snap around if the word wraps around at the end or
627 - * beginning of a line.
628 - */
629 - prevgp = &term.line[*y][*x];
630 - prevdelim = ISDELIM(prevgp->u);
631 - for (;;) {
632 - newx = *x + direction;
633 - newy = *y;
634 - if (!BETWEEN(newx, 0, term.col - 1)) {
635 - newy += direction;
636 - newx = (newx + term.col) % term.col;
637 - if (!BETWEEN(newy, 0, term.row - 1))
638 - break;
639 -
640 - if (direction > 0)
641 - yt = *y, xt = *x;
642 - else
643 - yt = newy, xt = newx;
644 - if (!(term.line[yt][xt].mode & ATTR_WRA…
645 - break;
646 - }
647 -
648 - if (newx >= tlinelen(newy))
649 - break;
650 -
651 - gp = &term.line[newy][newx];
652 - delim = ISDELIM(gp->u);
653 - if (!(gp->mode & ATTR_WDUMMY) && (delim != prev…
654 - || (delim && gp->u != prevgp->u…
655 - break;
656 -
657 - *x = newx;
658 - *y = newy;
659 - prevgp = gp;
660 - prevdelim = delim;
661 - }
662 - break;
663 - case SNAP_LINE:
664 - /*
665 - * Snap around if the the previous line or the current …
666 - * has set ATTR_WRAP at its end. Then the whole next or
667 - * previous line will be selected.
668 - */
669 - *x = (direction < 0) ? 0 : term.col - 1;
670 - if (direction < 0) {
671 - for (; *y > 0; *y += direction) {
672 - if (!(term.line[*y-1][term.col-1].mode
673 - & ATTR_WRAP)) {
674 - break;
675 - }
676 - }
677 - } else if (direction > 0) {
678 - for (; *y < term.row-1; *y += direction) {
679 - if (!(term.line[*y][term.col-1].mode
680 - & ATTR_WRAP)) {
681 - break;
682 - }
683 - }
684 - }
685 - break;
686 - }
687 + return ((sel.nb.y > sel.ne.y) ? OUT(y, sel.nb.y, sel.ne.y)
688 + : BETWEEN(y, sel.nb.y, sel.ne.y))…
689 + (y != sel.nb.y || x >= sel.nb.x) &&
690 + (y != sel.ne.y || x <= sel.ne.x);
691 }
692
693 char *
694 getsel(void)
695 {
696 char *str, *ptr;
697 - int y, bufsize, lastx, linelen;
698 + int y, yy, bufsize, lastx;
699 Glyph *gp, *last;
700
701 if (sel.ob.x == -1)
702 return NULL;
703
704 - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
705 + int const start = sel.swap ? sel.oe.y : sel.ob.y, h = rows();
706 + int endy = (sel.swap ? sel.ob.y : sel.oe.y);
707 + for (; endy < start; endy += h);
708 + Line * const cbuf = IS_SET(MODE_ALTSCREEN) ? term.line : buf;
709 + bufsize = (term.col+1) * (endy-start+1 ) * UTF_SIZ;
710 + assert(bufsize > 0);
711 ptr = str = xmalloc(bufsize);
712
713 /* append every set & selected glyph to the selection */
714 - for (y = sel.nb.y; y <= sel.ne.y; y++) {
715 - if ((linelen = tlinelen(y)) == 0) {
716 - *ptr++ = '\n';
717 - continue;
718 - }
719 + for (y = start; y <= endy; y++) {
720 + yy = y % h;
721
722 if (sel.type == SEL_RECTANGULAR) {
723 - gp = &term.line[y][sel.nb.x];
724 + gp = &cbuf[yy][sel.nb.x];
725 lastx = sel.ne.x;
726 } else {
727 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0…
728 - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
729 + gp = &cbuf[yy][start == y ? sel.nb.x : 0];
730 + lastx = (endy == y) ? sel.ne.x : term.col-1;
731 }
732 - last = &term.line[y][MIN(lastx, linelen-1)];
733 - while (last >= gp && last->u == ' ')
734 - --last;
735 + last = &cbuf[yy][lastx];
736 + if (!(cbuf[yy][term.col - 1].mode & ATTR_WRAP))
737 + while (last > gp && last->u == ' ') --last;
738
739 for ( ; gp <= last; ++gp) {
740 - if (gp->mode & ATTR_WDUMMY)
741 - continue;
742 -
743 + if (gp->mode & ATTR_WDUMMY) continue;
744 ptr += utf8encode(gp->u, ptr);
745 }
746
747 @@ -634,7 +638,7 @@ getsel(void)
748 * st.
749 * FIXME: Fix the computer world.
750 */
751 - if ((y < sel.ne.y || lastx >= linelen) && !(last->mode …
752 + if ((y < endy || lastx == term.col - 1) && !(last->mode…
753 *ptr++ = '\n';
754 }
755 *ptr = 0;
756 @@ -648,7 +652,7 @@ selclear(void)
757 return;
758 sel.mode = SEL_IDLE;
759 sel.ob.x = -1;
760 - tsetdirt(sel.nb.y, sel.ne.y);
761 + selnormalize();
762 }
763
764 void
765 @@ -1001,8 +1005,7 @@ tfulldirt(void)
766 void
767 tcursor(int mode)
768 {
769 - static TCursor c[2];
770 - int alt = IS_SET(MODE_ALTSCREEN);
771 + int alt = (histOp) ? 0 : (IS_SET(MODE_ALTSCREEN) + 1);
772
773 if (mode == CURSOR_SAVE) {
774 c[alt] = term.c;
775 @@ -1062,6 +1065,7 @@ tswapscreen(void)
776 void
777 tscrolldown(int orig, int n)
778 {
779 + if (historyBufferScroll(-n)) return;
780 int i;
781 Line temp;
782
783 @@ -1082,6 +1086,7 @@ tscrolldown(int orig, int n)
784 void
785 tscrollup(int orig, int n)
786 {
787 + if (historyBufferScroll(n)) return;
788 int i;
789 Line temp;
790
791 @@ -1243,8 +1248,8 @@ tclearregion(int x1, int y1, int x2, int y2)
792 if (y1 > y2)
793 temp = y1, y1 = y2, y2 = temp;
794
795 - LIMIT(x1, 0, term.col-1);
796 - LIMIT(x2, 0, term.col-1);
797 + LIMIT(x1, 0, buffCols-1);
798 + LIMIT(x2, 0, buffCols-1);
799 LIMIT(y1, 0, term.row-1);
800 LIMIT(y2, 0, term.row-1);
801
802 @@ -1252,8 +1257,6 @@ tclearregion(int x1, int y1, int x2, int y2)
803 term.dirty[y] = 1;
804 for (x = x1; x <= x2; x++) {
805 gp = &term.line[y][x];
806 - if (selected(x, y))
807 - selclear();
808 gp->fg = term.c.attr.fg;
809 gp->bg = term.c.attr.bg;
810 gp->mode = 0;
811 @@ -2413,8 +2416,6 @@ check_control_code:
812 */
813 return;
814 }
815 - if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
816 - selclear();
817
818 gp = &term.line[term.c.y][term.c.x];
819 if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
820 @@ -2483,8 +2484,10 @@ void
821 tresize(int col, int row)
822 {
823 int i;
824 - int minrow = MIN(row, term.row);
825 - int mincol = MIN(col, term.col);
826 + int const colSet = col, alt = IS_SET(MODE_ALTSCREEN), ini = buf…
827 + col = MAX(col, buffCols);
828 + row = MIN(row, buffSize);
829 + int const minrow = MIN(row, term.row), mincol = MIN(col, buffCo…
830 int *bp;
831 TCursor c;
832
833 @@ -2493,6 +2496,7 @@ tresize(int col, int row)
834 "tresize: error resizing to %dx%d\n", col, row);
835 return;
836 }
837 + if (alt) tswapscreen();
838
839 /*
840 * slide screen to keep cursor where we expect it -
841 @@ -2500,48 +2504,54 @@ tresize(int col, int row)
842 * memmove because we're freeing the earlier lines
843 */
844 for (i = 0; i <= term.c.y - row; i++) {
845 - free(term.line[i]);
846 free(term.alt[i]);
847 }
848 /* ensure that both src and dst are not NULL */
849 if (i > 0) {
850 - memmove(term.line, term.line + i, row * sizeof(Line));
851 memmove(term.alt, term.alt + i, row * sizeof(Line));
852 }
853 for (i += row; i < term.row; i++) {
854 - free(term.line[i]);
855 free(term.alt[i]);
856 }
857
858 /* resize to new height */
859 - term.line = xrealloc(term.line, row * sizeof(Line));
860 + buf = xrealloc(buf, (buffSize + row) * sizeof(Line));
861 term.alt = xrealloc(term.alt, row * sizeof(Line));
862 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
863 + mark = xrealloc(mark, col * row * sizeof(*mark));
864 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
865
866 /* resize each row to new width, zero-pad if needed */
867 for (i = 0; i < minrow; i++) {
868 - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyp…
869 term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyp…
870 }
871
872 /* allocate any new rows */
873 for (/* i = minrow */; i < row; i++) {
874 - term.line[i] = xmalloc(col * sizeof(Glyph));
875 term.alt[i] = xmalloc(col * sizeof(Glyph));
876 }
877 - if (col > term.col) {
878 - bp = term.tabs + term.col;
879 + if (col > buffCols) {
880 + bp = term.tabs + buffCols;
881
882 - memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
883 + memset(bp, 0, sizeof(*term.tabs) * (col - buffCols));
884 while (--bp > term.tabs && !*bp)
885 /* nothing */ ;
886 for (bp += tabspaces; bp < term.tabs + col; bp += tabsp…
887 *bp = 1;
888 }
889 + Glyph g=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ',…
890 + for (i = 0; i < buffSize; ++i) {
891 + buf[i] = xrealloc(ini ? NULL : buf[i], col*sizeof(Glyph…
892 + for (int j = ini ? 0 : buffCols; j < col; ++j) buf[i][j…
893 + }
894 + for (i = 0; i < row; ++i) buf[buffSize + i] = buf[i];
895 + term.line = &buf[*(histOp?&histOff:&insertOff) +=MAX(term.c.y-r…
896 + memset(mark, 0, col * row * sizeof(*mark));
897 /* update terminal size */
898 - term.col = col;
899 + term.col = colSet;
900 + buffCols = col;
901 term.row = row;
902 + if (alt) tswapscreen();
903 /* reset scrolling region */
904 tsetscroll(0, row-1);
905 /* make use of the LIMIT in tmoveto */
906 @@ -2570,15 +2580,17 @@ resettitle(void)
907 void
908 drawregion(int x1, int y1, int x2, int y2)
909 {
910 + if (altToggle && histMode && !histOp)
911 + memset(term.dirty, 0, sizeof(*term.dirty) * term.row);
912 + int const o = !IS_SET(MODE_ALTSCREEN) && histMode && !histOp, h…
913 int y;
914
915 for (y = y1; y < y2; y++) {
916 - if (!term.dirty[y])
917 - continue;
918 -
919 - term.dirty[y] = 0;
920 - xdrawline(term.line[y], x1, y, x2);
921 + int const oy = o ? (y + insertOff - histOff + h) % h : …
922 + if (!BETWEEN(oy, 0, term.row-1) || !term.dirty[y]) cont…
923 + xdrawline(term.line[y], x1, oy, x2);
924 }
925 + memset(&term.dirty[y1], 0, sizeof(*term.dirty) * (y2 - y1));
926 }
927
928 void
929 @@ -2597,7 +2609,9 @@ draw(void)
930 if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
931 cx--;
932
933 + if (histMode) historyPreDraw();
934 drawregion(0, 0, term.col, term.row);
935 + if (!histMode)
936 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
937 term.ocx, term.ocy, term.line[term.ocy][term.oc…
938 term.ocx = cx;
939 diff --git a/st.h b/st.h
940 index d978458..f537392 100644
941 --- a/st.h
942 +++ b/st.h
943 @@ -8,6 +8,7 @@
944 #define MAX(a, b) ((a) < (b) ? (b) : (a))
945 #define LEN(a) (sizeof(a) / sizeof(a)[0])
946 #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
947 +#define OUT(x, a, b) ((a) <= (x) || (x) <= (b))
948 #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
949 #define DEFAULT(a, b) (a) = (a) ? (a) : (b)
950 #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b)…
951 diff --git a/utils.h b/utils.h
952 new file mode 100644
953 index 0000000..ca435e6
954 --- /dev/null
955 +++ b/utils.h
956 @@ -0,0 +1,23 @@
957 +/// Dynamic memory-chunk, with (1) datatype size, (2/3) initialized / a…
958 +typedef struct { uint8_t const elSize; uint32_t init, alloc; char* cont…
959 +#define UTF8_ARRAY {4, 0, 0, NULL}
960 +
961 +static inline int p_alloc(DynamicArray *s, uint32_t amount) {
962 + uint32_t const diff=s->init+s->elSize*amount-s->alloc, nas=s->a…
963 + if (s->alloc < s->init + s->elSize * amount) {
964 + char* tmp = realloc(s->content, nas);
965 + if (!tmp) return 0;
966 + s->alloc = nas, s->content = tmp;
967 + }
968 + return 1;
969 +}
970 +static inline char *view(DynamicArray * s, uint32_t i) { return s->cont…
971 +static inline char *end(DynamicArray *s, uint32_t i) { return s->conten…
972 +static inline uint32_t getU32(DynamicArray* s, uint32_t i, int b) { ret…
973 +static char *expand(DynamicArray *s) { if (!p_alloc(s, 1)) return NULL;…
974 +static inline void pop(DynamicArray* s) { s->init -= s->elSize; }
975 +static inline void empty(DynamicArray* s) { s->init = 0; }
976 +static inline int size(DynamicArray const * s) { return s->init / s->el…
977 +static inline void assign(DynamicArray* s, DynamicArray const *o) {
978 + if (p_alloc(s, size(o))) memcpy(s->content, o->content, (s->ini…
979 +}
980 diff --git a/win.h b/win.h
981 index a6ef1b9..cea19f3 100644
982 --- a/win.h
983 +++ b/win.h
984 @@ -19,6 +19,7 @@ enum win_mode {
985 MODE_MOUSEMANY = 1 << 15,
986 MODE_BRCKTPASTE = 1 << 16,
987 MODE_NUMLOCK = 1 << 17,
988 + MODE_NORMAL = 1 << 18,
989 MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
990 |MODE_MOUSEMANY,
991 };
992 diff --git a/x.c b/x.c
993 index e5f1737..6f675e9 100644
994 --- a/x.c
995 +++ b/x.c
996 @@ -19,6 +19,7 @@ char *argv0;
997 #include "arg.h"
998 #include "st.h"
999 #include "win.h"
1000 +#include "normalMode.h"
1001
1002 /* types used in config.h */
1003 typedef struct {
1004 @@ -261,6 +262,7 @@ clipcopy(const Arg *dummy)
1005
1006 free(xsel.clipboard);
1007 xsel.clipboard = NULL;
1008 + xsetsel(getsel());
1009
1010 if (xsel.primary != NULL) {
1011 xsel.clipboard = xstrdup(xsel.primary);
1012 @@ -772,6 +774,8 @@ xloadcolor(int i, const char *name, Color *ncolor)
1013 return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
1014 }
1015
1016 +void normalMode() { historyModeToggle((win.mode ^=MODE_NORMAL) & MODE_N…
1017 +
1018 void
1019 xloadcols(void)
1020 {
1021 @@ -1225,8 +1229,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, cons…
1022
1023 for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
1024 /* Fetch rune and mode for current glyph. */
1025 - rune = glyphs[i].u;
1026 - mode = glyphs[i].mode;
1027 + Glyph g = glyphs[i];
1028 + historyOverlay(x+i, y, &g);
1029 + rune = g.u;
1030 + mode = g.mode;
1031
1032 /* Skip dummy wide-character spacing. */
1033 if (mode == ATTR_WDUMMY)
1034 @@ -1608,6 +1614,7 @@ xdrawline(Line line, int x1, int y1, int x2)
1035 i = ox = 0;
1036 for (x = x1; x < x2 && i < numspecs; x++) {
1037 new = line[x];
1038 + historyOverlay(x, y1, &new);
1039 if (new.mode == ATTR_WDUMMY)
1040 continue;
1041 if (selected(x, y1))
1042 @@ -1800,6 +1807,11 @@ kpress(XEvent *ev)
1043 len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &…
1044 else
1045 len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
1046 + if (IS_SET(MODE_NORMAL)) {
1047 + if (kpressHist(buf, len, match(ControlMask, e->state), …
1048 + == finished) norm…
1049 + return;
1050 + }
1051 /* 1. shortcuts */
1052 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
1053 if (ksym == bp->keysym && match(bp->mod, e->state)) {
1054 --
1055 2.27.0
1056
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.