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 *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  {