st-preedit-0.9.2.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) 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 *str)
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.ocx]);
164 + xdrawpreedit(&preedit.pline, term.line[term.c.y], term.c.y, term.col);
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 = ximdestroy };
234 XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
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.ime.spot,
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 | XIMStatusNothing,
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, &pestart,
278 + XNPreeditDoneCallback, &pedone,
279 + XNPreeditDrawCallback, &pedraw,
280 + XNPreeditCaretCallback, &pecaret,
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 context.\n");
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 *call)
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 : ATTR_NULL;
330 + *m |= fb & XIMUnderline ? ATTR_UNDERLINE : ATTR_NULL;
331 + *m |= fb & XIMHighlight ? ATTR_BOLD : ATTR_NULL;
332 + *m |= fb & XIMPrimary ? ATTR_ITALIC : ATTR_NULL;
333 + *m |= fb & XIMSecondary ? ATTR_FAINT : ATTR_NULL;
334 + *m |= fb & XIMTertiary ? ATTR_BOLD_FAINT : ATTR_NULL;
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 *call)
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 {