From 394692188f43224cddb1775de748af458af0b852 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Sat, 15 Oct 2016 17:18:42 -0400 Subject: [PATCH] Fixed display and selection of multi-column unicode characters. Also cleaned up tab handling logic in screen.c --- edit.h | 5 +---- screen.c | 64 ++++++++++++++++++++++++++------------------------------ xedit.c | 22 ++++++++++--------- 3 files changed, 43 insertions(+), 48 deletions(-) diff --git a/edit.h b/edit.h index d964836..fe48303 100644 --- a/edit.h +++ b/edit.h @@ -192,18 +192,15 @@ typedef struct { UGlyph cols[]; /* row data */ } Row; -void screen_reflow(Buf* buf); void screen_update(Buf* buf, unsigned crsr, unsigned* csrx, unsigned* csry); unsigned screen_getoff(Buf* buf, unsigned pos, unsigned row, unsigned col); void screen_setsize(Buf* buf, unsigned nrows, unsigned ncols); void screen_getsize(unsigned* nrows, unsigned* ncols); -void screen_clear(void); Row* screen_getrow(unsigned row); void screen_clearrow(unsigned row); -void screen_setrowoff(unsigned row, unsigned off); unsigned screen_setcell(unsigned row, unsigned col, Rune r); -UGlyph* screen_getcell(unsigned row, unsigned col); void screen_status(char* fmt, ...); +UGlyph* screen_getglyph(unsigned row, unsigned col, unsigned* scrwidth); /* Color Scheme Handling *****************************************************************************/ diff --git a/screen.c b/screen.c index 326a54e..b9952e2 100644 --- a/screen.c +++ b/screen.c @@ -1,14 +1,15 @@ #include "edit.h" +#include static unsigned NumRows = 0; static unsigned NumCols = 0; static Row** Rows; -void screen_reflow(Buf* buf) { +static void screen_reflow(Buf* buf) { unsigned pos = Rows[1]->off; for (unsigned y = 1; y < NumRows; y++) { screen_clearrow(y); - screen_setrowoff(y, pos); + screen_getrow(y)->off = pos; for (unsigned x = 0; x < NumCols;) { Rune r = buf_get(buf, pos++); x += screen_setcell(y,x,r); @@ -42,15 +43,13 @@ unsigned screen_getoff(Buf* buf, unsigned pos, unsigned row, unsigned col) { if (col > scrrow->len) { pos = (scrrow->off + scrrow->rlen - 1); } else { - for (unsigned x = 0; x < col;) { - Rune r = buf_get(buf,pos++); - if (r == '\n') - break; - else if (r == '\t') - x += (TabWidth - (x % TabWidth)); - else - x += 1; - } + /* multi column runes are followed by \0 slots so if we clicked on a \0 + slot, slide backwards to the real rune. */ + for (; !scrrow->cols[col].rune && col > 0; col--); + /* now lets count the number of runes up to the one we clicked on */ + for (unsigned i = 0; i < col; i++) + if (scrrow->cols[i].rune) + pos++; } if (pos >= buf_end(buf)) return buf_end(buf)-1; @@ -61,11 +60,6 @@ void screen_getsize(unsigned* nrows, unsigned* ncols) { *nrows = NumRows, *ncols = NumCols; } -void screen_clear(void) { - for (unsigned i = 0; i < NumRows; i++) - screen_clearrow(i); -} - Row* screen_getrow(unsigned row) { return (row < NumRows ? Rows[row] : NULL); } @@ -79,32 +73,39 @@ void screen_clearrow(unsigned row) { scrrow->len = 0; } -void screen_setrowoff(unsigned row, unsigned off) { - screen_getrow(row)->off = off; +static int runewidth(unsigned col, Rune r) { + if (r == '\t') return (TabWidth - (col % TabWidth)); + int width = wcwidth(r); + if (width < 0) width = 1; + return width; } unsigned screen_setcell(unsigned row, unsigned col, Rune r) { if (row >= NumRows || col >= NumCols) return 0; Row* scrrow = screen_getrow(row); + int ncols = runewidth(col, r); /* write the rune to the screen buf */ - unsigned ncols = 1; - if (r == '\t') { + if (r == '\t' || r == '\n' || r == '\r') scrrow->cols[col].rune = ' '; - ncols = (TabWidth - (col % TabWidth)); - } else if (r != '\n') { + else scrrow->cols[col].rune = r; - } /* Update lengths */ scrrow->rlen += 1; + for (int i = 1; i < ncols; i++) + scrrow->cols[col+i].rune = '\0'; if ((col + ncols) > scrrow->len) scrrow->len = col + ncols; return ncols; } -UGlyph* screen_getcell(unsigned row, unsigned col) { +UGlyph* screen_getglyph(unsigned row, unsigned col, unsigned* scrwidth) { if (row >= NumRows || col >= NumCols) return 0; Row* scrrow = screen_getrow(row); - return &(scrrow->cols[col]); + UGlyph* glyph = &(scrrow->cols[col]); + *scrwidth = 1; + for (col++; !scrrow->cols[col].rune; col++) + *scrwidth += 1; + return glyph; } static void fill_row(Buf* buf, unsigned row, unsigned pos) { @@ -119,11 +120,9 @@ static void fill_row(Buf* buf, unsigned row, unsigned pos) { static unsigned prev_screen_line(Buf* buf, unsigned bol, unsigned off) { unsigned pos = bol; while (true) { - unsigned x = 0; - for (; x < NumCols && (pos + x) < off; x++) { - Rune r = buf_get(buf, pos+x); - x += (r == '\t' ? (TabWidth - (x % TabWidth)) : 1); - } + unsigned x; + for (x = 0; x < NumCols && (pos + x) < off; x++) + x += runewidth(x, buf_get(buf, pos+x)); if ((pos + x) >= off) break; pos += x; } @@ -185,10 +184,7 @@ void screen_update(Buf* buf, unsigned csr, unsigned* csrx, unsigned* csry) { *csry = y, *csrx = x; break; } - if (buf_get(buf,pos++) == '\t') - x += (TabWidth - (x % TabWidth)); - else - x += 1; + x += runewidth(x, buf_get(buf,pos++)); } break; } diff --git a/xedit.c b/xedit.c index 04bd59b..d83c28c 100644 --- a/xedit.c +++ b/xedit.c @@ -127,14 +127,16 @@ void font_find(XftGlyphFontSpec* spec, Rune rune) { int font_makespecs(XftGlyphFontSpec* specs, const UGlyph* glyphs, int len, int x, int y) { int winx = x * Fonts.base.width, winy = y * Fonts.base.height; int numspecs = 0; - for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len; ++i) { - if (!glyphs[i].rune) continue; + for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len;) { font_find(&(specs[numspecs]), glyphs[i].rune); - int runewidth = wcwidth(glyphs[i].rune) * Fonts.base.width; specs[numspecs].x = xp; specs[numspecs].y = yp; - xp += runewidth; + xp += Fonts.base.width; numspecs++; + i++; + /* skip over null chars which mark multi column runes */ + for (; i < len && !glyphs[i].rune; i++) + xp += Fonts.base.width; } return numspecs; } @@ -144,9 +146,9 @@ int font_makespecs(XftGlyphFontSpec* specs, const UGlyph* glyphs, int len, int x static XftColor xftcolor(enum ColorId cid) { Color c = Palette[cid][ColorBase]; XftColor xc; - xc.color.red = ((c & 0x00FF0000) >> 8); - xc.color.green = ((c & 0x0000FF00)); - xc.color.blue = ((c & 0x000000FF) << 8); + xc.color.red = 0xFF | ((c & 0x00FF0000) >> 8); + xc.color.green = 0xFF | ((c & 0x0000FF00)); + xc.color.blue = 0xFF | ((c & 0x000000FF) << 8); xc.color.alpha = UINT16_MAX; XftColorAllocValue(X.display, X.visual, X.colormap, &xc.color, &xc); return xc; @@ -338,12 +340,12 @@ static void redraw(void) { } /* Place cursor on screen */ - UGlyph* csrrune = screen_getcell(csry,csrx); + unsigned rwidth; + UGlyph* csrrune = screen_getglyph(csry, csrx, &rwidth); if (Buffer.insert_mode) { XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, 2, Fonts.base.height); } else { - unsigned width = ('\t' == buf_get(&Buffer, CursorPos) ? (TabWidth - (csrx % TabWidth)) : 1); - XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, width * Fonts.base.width, Fonts.base.height); + XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, rwidth * Fonts.base.width, Fonts.base.height); draw_runes(csrx, csry, &bkgclr, NULL, csrrune, 1); } -- 2.49.0