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  {