st-preedit-0.9.2.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
st-preedit-0.9.2.diff (10180B) | |
--- | |
1 diff --git a/st.c b/st.c | |
2 index b9f66e7..ede6d6b 100644 | |
3 --- a/st.c | |
4 +++ b/st.c | |
5 @@ -109,6 +109,12 @@ typedef struct { | |
6 int alt; | |
7 } Selection; | |
8 | |
9 +typedef struct { | |
10 + Glyph *text; /* preedit text */ | |
11 + int len; /* text length */ | |
12 + PLine pline; | |
13 +} Preedit; | |
14 + | |
15 /* Internal representation of the screen */ | |
16 typedef struct { | |
17 int row; /* nb row */ | |
18 @@ -202,6 +208,7 @@ static int32_t tdefcolor(const int *, int *, int); | |
19 static void tdeftran(char); | |
20 static void tstrsequence(uchar); | |
21 | |
22 +static void pelineupdate(void); | |
23 static void drawregion(int, int, int, int); | |
24 | |
25 static void selnormalize(void); | |
26 @@ -221,6 +228,7 @@ static ssize_t xwrite(int, const char *, size_t); | |
27 /* Globals */ | |
28 static Term term; | |
29 static Selection sel; | |
30 +static Preedit preedit; | |
31 static CSIEscape csiescseq; | |
32 static STREscape strescseq; | |
33 static int iofd = 1; | |
34 @@ -1179,6 +1187,9 @@ tmoveto(int x, int y) | |
35 term.c.state &= ~CURSOR_WRAPNEXT; | |
36 term.c.x = LIMIT(x, 0, term.col-1); | |
37 term.c.y = LIMIT(y, miny, maxy); | |
38 + | |
39 + if (preedit.len > 0) | |
40 + pelineupdate(); | |
41 } | |
42 | |
43 void | |
44 @@ -2627,6 +2638,115 @@ resettitle(void) | |
45 xsettitle(NULL); | |
46 } | |
47 | |
48 +void | |
49 +pereset(void) | |
50 +{ | |
51 + preedit.len = 0; | |
52 + preedit.pline.width = 0; | |
53 + pelineupdate(); | |
54 +} | |
55 + | |
56 +void | |
57 +peupdate(int caret, int chg_fst, int chg_len, | |
58 + unsigned short str_len, const ushort *modes, const char… | |
59 +{ | |
60 + int i; | |
61 + int defmode; | |
62 + Glyph *text, *g; | |
63 + int chg_last, len; | |
64 + | |
65 + chg_fst = MIN(chg_fst, preedit.len); | |
66 + chg_len = MIN(chg_len, preedit.len - chg_fst); | |
67 + chg_last = chg_fst + chg_len; | |
68 + len = preedit.len - chg_len + (str ? str_len : 0); | |
69 + | |
70 + /* default glyph mode */ | |
71 + defmode = ATTR_NULL; | |
72 + if (preedit.len > 0) | |
73 + defmode = (chg_fst < preedit.len) ? | |
74 + preedit.text[chg_fst].mode : | |
75 + preedit.text[chg_fst - 1].mode; | |
76 + defmode &= ~ATTR_WIDE; | |
77 + | |
78 + /* create new text and copy old glyphs */ | |
79 + text = xmalloc(len * sizeof(Glyph)); | |
80 + if (preedit.len > 0) { | |
81 + memcpy(text, preedit.text, chg_fst * sizeof(Glyph)); | |
82 + memcpy(text + chg_fst + (str ? str_len : 0), | |
83 + preedit.text + chg_last, | |
84 + (preedit.len - chg_last) * sizeof(Glyph… | |
85 + free(preedit.text); | |
86 + } | |
87 + preedit.text = text; | |
88 + preedit.len = len; | |
89 + | |
90 + /* new glyphs */ | |
91 + if (str) { | |
92 + for (i = 0; i < str_len; i++) { | |
93 + g = text + chg_fst + i; | |
94 + *g = (Glyph){ 0, defmode, defaultfg, defaultbg … | |
95 + str += utf8decode(str, &g->u, UTF_SIZ); | |
96 + if (wcwidth(g->u) > 1) | |
97 + g->mode |= ATTR_WIDE; | |
98 + } | |
99 + } | |
100 + | |
101 + /* glyph mode */ | |
102 + if (modes) { | |
103 + for (i = 0; i < str_len; i++) { | |
104 + g = text + chg_fst + i; | |
105 + g->mode = modes[i] | (g->mode & ATTR_WIDE); | |
106 + } | |
107 + } | |
108 + | |
109 + /* visual width and caret position */ | |
110 + preedit.pline.width = 0; | |
111 + preedit.pline.caret = 0; | |
112 + for (i = 0; i < len; i++) { | |
113 + preedit.pline.width += MAX(wcwidth(text[i].u), 1); | |
114 + if (i + 1 == caret) | |
115 + preedit.pline.caret = preedit.pline.width; | |
116 + } | |
117 + | |
118 + pelineupdate(); | |
119 +} | |
120 + | |
121 +void | |
122 +pelineupdate() | |
123 +{ | |
124 + int i, x; | |
125 + | |
126 + free(preedit.pline.line); | |
127 + preedit.pline.line = xmalloc((term.col + 1) * sizeof(Glyph)); | |
128 + for (i = 0; i < term.col + 1; i++) | |
129 + preedit.pline.line[i] = (Glyph){ ' ', ATTR_WDUMMY }; | |
130 + | |
131 + x = term.col / 2 - preedit.pline.caret; | |
132 + x = MIN(x, 0); | |
133 + x = MAX(x, term.col - preedit.pline.width); | |
134 + x = MIN(x, term.c.x); | |
135 + preedit.pline.offset = x; | |
136 + | |
137 + for (i = 0; i < preedit.len; i++) { | |
138 + if (term.col < x) | |
139 + break; | |
140 + if (0 <= x) | |
141 + preedit.pline.line[x] = preedit.text[i]; | |
142 + x += MAX(wcwidth(preedit.text[i].u), 1); | |
143 + } | |
144 + | |
145 + if (preedit.len == 0) | |
146 + term.dirty[term.c.y] = 1; | |
147 + | |
148 + if (preedit.pline.l.u == 0) { | |
149 + preedit.pline.l = preedit.pline.r = (Glyph){ | |
150 + 0, ATTR_REVERSE, defaultfg, defaultbg | |
151 + }; | |
152 + utf8decode("<", &preedit.pline.l.u, UTF_SIZ); | |
153 + utf8decode(">", &preedit.pline.r.u, UTF_SIZ); | |
154 + } | |
155 +} | |
156 + | |
157 void | |
158 drawregion(int x1, int y1, int x2, int y2) | |
159 { | |
160 @@ -2660,6 +2780,7 @@ draw(void) | |
161 drawregion(0, 0, term.col, term.row); | |
162 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], | |
163 term.ocx, term.ocy, term.line[term.ocy][term.oc… | |
164 + xdrawpreedit(&preedit.pline, term.line[term.c.y], term.c.y, ter… | |
165 term.ocx = cx; | |
166 term.ocy = term.c.y; | |
167 xfinishdraw(); | |
168 diff --git a/st.h b/st.h | |
169 index fd3b0d8..97e1491 100644 | |
170 --- a/st.h | |
171 +++ b/st.h | |
172 @@ -69,6 +69,14 @@ typedef struct { | |
173 | |
174 typedef Glyph *Line; | |
175 | |
176 +typedef struct { | |
177 + Line line; | |
178 + int offset; | |
179 + int width; | |
180 + int caret; | |
181 + Glyph l,r; | |
182 +} PLine; | |
183 + | |
184 typedef union { | |
185 int i; | |
186 uint ui; | |
187 @@ -95,6 +103,8 @@ int ttynew(const char *, char *, const char *, char *… | |
188 size_t ttyread(void); | |
189 void ttyresize(int, int); | |
190 void ttywrite(const char *, size_t, int); | |
191 +void pereset(void); | |
192 +void peupdate(int, int, int, unsigned short, const ushort *, const char… | |
193 | |
194 void resettitle(void); | |
195 | |
196 diff --git a/win.h b/win.h | |
197 index 6de960d..fb5a1d5 100644 | |
198 --- a/win.h | |
199 +++ b/win.h | |
200 @@ -27,6 +27,7 @@ void xbell(void); | |
201 void xclipcopy(void); | |
202 void xdrawcursor(int, int, Glyph, int, int, Glyph); | |
203 void xdrawline(Line, int, int, int); | |
204 +void xdrawpreedit(PLine *, Line, int, int); | |
205 void xfinishdraw(void); | |
206 void xloadcols(void); | |
207 int xsetcolorname(int, const char *); | |
208 diff --git a/x.c b/x.c | |
209 index bd23686..fd6308e 100644 | |
210 --- a/x.c | |
211 +++ b/x.c | |
212 @@ -99,6 +99,7 @@ typedef struct { | |
213 XIC xic; | |
214 XPoint spot; | |
215 XVaNestedList spotlist; | |
216 + XVaNestedList preeditattrs; | |
217 } ime; | |
218 Draw draw; | |
219 Visual *vis; | |
220 @@ -150,6 +151,10 @@ static int ximopen(Display *); | |
221 static void ximinstantiate(Display *, XPointer, XPointer); | |
222 static void ximdestroy(XIM, XPointer, XPointer); | |
223 static int xicdestroy(XIC, XPointer, XPointer); | |
224 +static void xpreeditstart(XIM , XPointer, XPointer); | |
225 +static void xpreeditdone(XIM, XPointer, XPointer); | |
226 +static void xpreeditdraw(XIM, XPointer, XIMPreeditDrawCallbackStruct *); | |
227 +static void xpreeditcaret(XIM, XPointer, XIMPreeditCaretCallbackStruct … | |
228 static void xinit(int, int); | |
229 static void cresize(int, int); | |
230 static void xresize(int, int); | |
231 @@ -1077,6 +1082,16 @@ ximopen(Display *dpy) | |
232 { | |
233 XIMCallback imdestroy = { .client_data = NULL, .callback = ximd… | |
234 XICCallback icdestroy = { .client_data = NULL, .callback = xicd… | |
235 + static XIMCallback pestart = { NULL, xpreeditstart }; | |
236 + static XIMCallback pedone = { NULL, xpreeditdone }; | |
237 + static XIMCallback pedraw = { NULL, (XIMProc)xpreeditdraw }; | |
238 + static XIMCallback pecaret = { NULL, (XIMProc)xpreeditcaret }; | |
239 + XIMStyles *styles; | |
240 + XIMStyle candidates[] = { | |
241 + XIMPreeditCallbacks | XIMStatusNothing, | |
242 + XIMPreeditNothing | XIMStatusNothing | |
243 + }; | |
244 + int i, j; | |
245 | |
246 xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); | |
247 if (xw.ime.xim == NULL) | |
248 @@ -1089,12 +1104,38 @@ ximopen(Display *dpy) | |
249 xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.im… | |
250 NULL); | |
251 | |
252 + if (XGetIMValues(xw.ime.xim, XNQueryInputStyle, &styles, NULL))… | |
253 + fprintf(stderr, "XGetIMValues:" | |
254 + "Could not get XNQueryInputStyle.\n"); | |
255 + return 1; | |
256 + } | |
257 + for (i = 0; i < LEN(candidates); i++) | |
258 + for (j = 0; j < styles->count_styles; j++) | |
259 + if (candidates[i] == styles->supported_styles[j… | |
260 + goto match; | |
261 + fprintf(stderr, "XGetIMValues: " | |
262 + "None of the candidates styles matched.\n"); | |
263 + XFree(styles); | |
264 + return 1; | |
265 +match: | |
266 + XFree(styles); | |
267 + | |
268 if (xw.ime.xic == NULL) { | |
269 xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, | |
270 - XIMPreeditNothing | XIMStatusNot… | |
271 + candidates[i], | |
272 XNClientWindow, xw.win, | |
273 XNDestroyCallback, &icdestroy, | |
274 NULL); | |
275 + if (xw.ime.xic && candidates[i] & XIMPreeditCallbacks) { | |
276 + xw.ime.preeditattrs = XVaCreateNestedList(0, | |
277 + XNPreeditStartCallback, &pestar… | |
278 + XNPreeditDoneCallback, &pedone, | |
279 + XNPreeditDrawCallback, &pedraw, | |
280 + XNPreeditCaretCallback, &pecare… | |
281 + NULL); | |
282 + XSetICValues(xw.ime.xic, XNPreeditAttributes, | |
283 + xw.ime.preeditattrs, NULL); | |
284 + } | |
285 } | |
286 if (xw.ime.xic == NULL) | |
287 fprintf(stderr, "XCreateIC: Could not create input cont… | |
288 @@ -1123,9 +1164,64 @@ int | |
289 xicdestroy(XIC xim, XPointer client, XPointer call) | |
290 { | |
291 xw.ime.xic = NULL; | |
292 + XFree(xw.ime.preeditattrs); | |
293 + xw.ime.preeditattrs = NULL; | |
294 return 1; | |
295 } | |
296 | |
297 +void | |
298 +xpreeditstart(XIM xim, XPointer client, XPointer call) | |
299 +{ | |
300 + pereset(); | |
301 +} | |
302 + | |
303 +void | |
304 +xpreeditdone(XIM xim, XPointer client, XPointer call) | |
305 +{ | |
306 + pereset(); | |
307 +} | |
308 + | |
309 +void | |
310 +xpreeditdraw(XIM xim, XPointer client, XIMPreeditDrawCallbackStruct *ca… | |
311 +{ | |
312 + const XIMText *text = call->text; | |
313 + ushort *m, *modes = NULL; | |
314 + int i; | |
315 + XIMFeedback fb; | |
316 + | |
317 + if (!text) { | |
318 + peupdate(call->caret, call->chg_first, call->chg_length, | |
319 + 0, NULL, NULL); | |
320 + return; | |
321 + } | |
322 + | |
323 + if (text->feedback) { | |
324 + modes = xmalloc(text->length * sizeof(ushort)); | |
325 + for (i = 0; i < text->length; i++) { | |
326 + m = modes + i; | |
327 + fb = text->feedback[i]; | |
328 + *m = ATTR_NULL; | |
329 + *m |= fb & XIMReverse ? ATTR_REVERSE : ATT… | |
330 + *m |= fb & XIMUnderline ? ATTR_UNDERLINE : ATT… | |
331 + *m |= fb & XIMHighlight ? ATTR_BOLD : ATT… | |
332 + *m |= fb & XIMPrimary ? ATTR_ITALIC : ATT… | |
333 + *m |= fb & XIMSecondary ? ATTR_FAINT : ATT… | |
334 + *m |= fb & XIMTertiary ? ATTR_BOLD_FAINT : ATT… | |
335 + } | |
336 + } | |
337 + | |
338 + peupdate(call->caret, call->chg_first, call->chg_length, | |
339 + text->length, modes, text->string.multi_byte); | |
340 + | |
341 + free(modes); | |
342 +} | |
343 + | |
344 +void | |
345 +xpreeditcaret(XIM xim, XPointer client, XIMPreeditCaretCallbackStruct *… | |
346 +{ | |
347 + peupdate(call->position, 0, 0, 0, NULL, NULL); | |
348 +} | |
349 + | |
350 void | |
351 xinit(int cols, int rows) | |
352 { | |
353 @@ -1682,6 +1778,35 @@ xdrawline(Line line, int x1, int y1, int x2) | |
354 xdrawglyphfontspecs(specs, base, i, ox, y1); | |
355 } | |
356 | |
357 +void | |
358 +xdrawpreedit(PLine *pl, Line base, int y, int col) | |
359 +{ | |
360 + int head, tail; | |
361 + int tcur; | |
362 + const int offc = pl->offset + pl->caret; | |
363 + | |
364 + if (pl->width == 0 || !(win.mode & MODE_FOCUSED)) | |
365 + return; | |
366 + | |
367 + xdrawline(base, 0, y, col); | |
368 + | |
369 + head = MAX(pl->offset, 0); | |
370 + tail = MIN(pl->offset + pl->width, col); | |
371 + if (pl->line[head].mode & ATTR_WDUMMY) | |
372 + head++; | |
373 + xdrawline(pl->line, head, y, tail); | |
374 + | |
375 + tcur = win.cursor; | |
376 + win.cursor = 6; | |
377 + xdrawcursor(offc, y, pl->line[offc], head, y, pl->line[head]); | |
378 + win.cursor = tcur; | |
379 + | |
380 + if (pl->offset < 0) | |
381 + xdrawline(&pl->l, 0, y, 1); | |
382 + if (col < pl->offset + pl->width) | |
383 + xdrawline(&pl->r - (col - 1), col - 1, y, col); | |
384 +} | |
385 + | |
386 void | |
387 xfinishdraw(void) | |
388 { |