Module Name: src Committed By: rin Date: Fri Nov 10 14:44:13 UTC 2017
Modified Files: src/external/bsd/nvi/dist/vi: vs_line.c vs_refresh.c vs_relative.c Log Message: - Fix cursor position when a multiwidth char does not fit within a line. - Put cursor on the leftmost column of a multiwidth char, instead of the rightmost one. Otherwise, some terminal emulators do not focus on the entire of the char. Logic taken from nvi-m17n by itojun. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/external/bsd/nvi/dist/vi/vs_line.c \ src/external/bsd/nvi/dist/vi/vs_relative.c cvs rdiff -u -r1.6 -r1.7 src/external/bsd/nvi/dist/vi/vs_refresh.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/nvi/dist/vi/vs_line.c diff -u src/external/bsd/nvi/dist/vi/vs_line.c:1.3 src/external/bsd/nvi/dist/vi/vs_line.c:1.4 --- src/external/bsd/nvi/dist/vi/vs_line.c:1.3 Sun Jan 26 21:43:45 2014 +++ src/external/bsd/nvi/dist/vi/vs_line.c Fri Nov 10 14:44:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vs_line.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */ +/* $NetBSD: vs_line.c,v 1.4 2017/11/10 14:44:13 rin Exp $ */ /*- * Copyright (c) 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -16,7 +16,7 @@ static const char sccsid[] = "Id: vs_line.c,v 10.38 2002/01/19 21:59:07 skimo Exp (Berkeley) Date: 2002/01/19 21:59:07 "; #endif /* not lint */ #else -__RCSID("$NetBSD: vs_line.c,v 1.3 2014/01/26 21:43:45 christos Exp $"); +__RCSID("$NetBSD: vs_line.c,v 1.4 2017/11/10 14:44:13 rin Exp $"); #endif #include <sys/types.h> @@ -271,38 +271,64 @@ empty: (void)gp->scr_addstr(sp, /* Do it the hard way, for leftright scrolling screens. */ if (O_ISSET(sp, O_LEFTRIGHT)) { - for (; offset_in_line < len; ++offset_in_line) { - chlen = (ch = (UCHAR_T)*p++) == L('\t') && !list_tab ? + while (offset_in_line < len) { + ch = (UCHAR_T)*p; + chlen = (ch == '\t' && !list_tab) ? TAB_OFF(scno) : KEY_COL(sp, ch); - if ((scno += chlen) >= skip_cols) - break; + + /* easy cases first. */ + if (scno + chlen < skip_cols) { + scno += chlen; + p++; + offset_in_line++; + continue; + } + + if (scno + chlen == skip_cols) { + scno += chlen; + p++; + offset_in_line++; + } + + break; } /* Set cols_per_screen to 2nd and later line length. */ cols_per_screen = sp->cols; /* Put starting info for this line in the cache. */ - if (offset_in_line >= len) { - smp->c_sboff = offset_in_line; - smp->c_scoff = 255; - } else if (scno != skip_cols) { - smp->c_sboff = offset_in_line; - smp->c_scoff = - offset_in_char = chlen - (scno - skip_cols); - --p; - } else { - smp->c_sboff = ++offset_in_line; - smp->c_scoff = 0; - } + smp->c_sboff = offset_in_line; + smp->c_scoff = offset_in_char = scno + chlen - skip_cols; } /* Do it the hard way, for historic line-folding screens. */ else { - for (; offset_in_line < len; ++offset_in_line) { - chlen = (ch = (UCHAR_T)*p++) == L('\t') && !list_tab ? + while (offset_in_line < len) { + ch = (UCHAR_T)*p; + chlen = (ch == '\t' && !list_tab) ? TAB_OFF(scno) : KEY_COL(sp, ch); - if ((scno += chlen) < cols_per_screen) + + /* Easy case first. */ + if (scno + chlen < cols_per_screen) { + scno += chlen; + p++; + offset_in_line++; continue; + } + + /* + * Since we can't generally cross the rightmost column + * by displaying multi-width char, we must check it. + * In that case, we fake the scno so that you'll see + * that the line was already filled up completely. + */ + if (!INTISWIDE(ch) || scno + chlen == cols_per_screen) { + scno += chlen; + p++; + offset_in_line++; + } else + scno = cols_per_screen; + scno -= cols_per_screen; /* Set cols_per_screen to 2nd and later line length. */ @@ -320,9 +346,10 @@ empty: (void)gp->scr_addstr(sp, if (scno != 0) { smp->c_sboff = offset_in_line; smp->c_scoff = offset_in_char = chlen - scno; - --p; + offset_in_line--; + p--; } else { - smp->c_sboff = ++offset_in_line; + smp->c_sboff = offset_in_line; smp->c_scoff = 0; } } @@ -334,10 +361,16 @@ display: * called repeatedly with a valid pointer to a cursor position. * Don't fill anything in unless it's the right line and the right * character, and the right part of the character... + * + * It is not true that every wide chars occupy at least single column. + * - It is safe to compare sp->cno and offset_in_line since they are + * both offset in unit of CHAR_T. + * - We can't simply compare offset_in_line + cols_per_screen against + * sp->cno, since cols_per_screen is screen column, not offset in + * CHAR_T. Do it slowly. */ if (yp == NULL || - smp->lno != sp->lno || sp->cno < offset_in_line || - offset_in_line + cols_per_screen < sp->cno) { + smp->lno != sp->lno || sp->cno < offset_in_line) { cno_cnt = 0; /* If the line is on the screen, quit. */ if (is_cached || no_draw) @@ -358,6 +391,23 @@ display: } /* + * Since we can't generally cross the rightmost column + * by displaying multi-width char, we must check it. + * In that case, we fake the scno so that you'll see + * that the line was already filled up completely. + */ + if (INTISWIDE(ch) && scno > cols_per_screen) { + smp->c_ecsize = chlen; + smp->c_eclen = 0; + + is_partial = 1; + + smp->c_eboff = offset_in_line; + + /* Terminate the loop. */ + offset_in_line = len; + } else + /* * Only display up to the right-hand column. Set a flag if * the entire character wasn't displayed for use in setting * the cursor. If reached the end of the line, set the cache @@ -400,6 +450,8 @@ display: *xp = scno - smp->c_ecsize; else *xp = scno - chlen; + else if (INTISWIDE(ch)) + *xp = scno - chlen; else *xp = scno - 1; if (O_ISSET(sp, O_NUMBER) && @@ -437,8 +489,8 @@ display: if (cbp + chlen >= ecbp) FLUSH; - /* don't display half a wide character */ - if (is_partial && CHAR_WIDTH(sp, ch) > 1) { + /* Don't display half a multi-width character */ + if (is_partial && INTISWIDE(ch)) { *cbp++ = ' '; break; } @@ -458,7 +510,7 @@ display: if (scno < cols_per_screen) { /* If didn't paint the whole line, update the cache. */ - smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch); + smp->c_ecsize = smp->c_eclen = KEY_COL(sp, ch); smp->c_eboff = len - 1; /* Index: src/external/bsd/nvi/dist/vi/vs_relative.c diff -u src/external/bsd/nvi/dist/vi/vs_relative.c:1.3 src/external/bsd/nvi/dist/vi/vs_relative.c:1.4 --- src/external/bsd/nvi/dist/vi/vs_relative.c:1.3 Sun Jan 26 21:43:45 2014 +++ src/external/bsd/nvi/dist/vi/vs_relative.c Fri Nov 10 14:44:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vs_relative.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */ +/* $NetBSD: vs_relative.c,v 1.4 2017/11/10 14:44:13 rin Exp $ */ /*- * Copyright (c) 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -16,7 +16,7 @@ static const char sccsid[] = "Id: vs_relative.c,v 10.18 2001/07/08 13:02:48 skimo Exp (Berkeley) Date: 2001/07/08 13:02:48 "; #endif /* not lint */ #else -__RCSID("$NetBSD: vs_relative.c,v 1.3 2014/01/26 21:43:45 christos Exp $"); +__RCSID("$NetBSD: vs_relative.c,v 1.4 2017/11/10 14:44:13 rin Exp $"); #endif #include <sys/types.h> @@ -162,22 +162,84 @@ done: if (diffp != NULL) /* XXX */ curoff -= sp->cols; \ } \ } - if (cnop == NULL) - while (len--) { - chlen = CHLEN(curoff); + if (cnop == NULL) { + while (len > 0) { + ch = (UCHAR_T)*p; + + /* singlebyte case */ + if (!INTISWIDE(ch)) { + chlen = CHLEN(curoff); + last = scno; + scno += chlen; + len--; + /* p will be modified in CHLEN() */ + TAB_RESET; + continue; + } + + /* multibyte case */ + chlen = CHAR_WIDTH(sp, ch); last = scno; scno += chlen; - TAB_RESET; + len--; + p++; + + /* + * If multi-width char crosses the end-of-screen, + * put it on the next line. + */ + curoff += chlen; + if (!leftright && curoff >= sp->cols) { + if (curoff == sp->cols) + curoff = 0; + else { + scno -= scno % sp->cols; + scno += chlen; + curoff = chlen; + } + } } - else + } else { for (cno = *cnop;; --cno) { - chlen = CHLEN(curoff); + ch = (UCHAR_T)*p; + + /* singlebyte case */ + if (!INTISWIDE(ch)) { + chlen = CHLEN(curoff); + last = scno; + scno += chlen; + /* p will be modified in CHLEN() */ + TAB_RESET; + if (cno == 0) + break; + continue; + } + + /* multibyte case */ + chlen = CHAR_WIDTH(sp, ch); last = scno; scno += chlen; - TAB_RESET; + p++; + + /* + * If multi-width char crosses the end-of-screen, + * put it on the next line. + */ + curoff += chlen; + if (!leftright && curoff >= sp->cols) { + if (curoff == sp->cols) + curoff = 0; + else { + scno -= scno % sp->cols; + scno += chlen; + curoff = chlen; + } + } + if (cno == 0) break; } + } /* Add the trailing '$' if the O_LIST option set. */ if (listset && cnop == NULL) @@ -249,8 +311,45 @@ vs_colpos(SCR *sp, db_recno_t lno, size_ off = cno / sp->cols; cno %= sp->cols; for (scno = 0, p = lp, len = llen; off--;) { - for (; len && scno < sp->cols; --len) - scno += CHLEN(scno); + while (len && scno < sp->cols) { + ch = (UCHAR_T)*p; + if (ch == '\t' && !listset) { + scno += TAB_OFF(scno); + len--; + p++; + continue; + } + + chlen = KEY_COL(sp, ch); + if (!INTISWIDE(ch) || scno + chlen < sp->cols) { + /* + * Singlebyte char can be displayed across + * the end-of-screen. + * If a multi-width char fits into this line, + * put it here. + */ + scno += chlen; + len--; + p++; + } else if (leftright) { + /* + * Side-scrolling screen is similar to + * singlebyte case. + */ + scno += chlen; + len--; + p++; + } else { + /* + * If multi-width char crosses the + * end-of-screen, put it on the next line. + * + * We must adjust ch to the last char of the + * line. + */ + scno = sp->cols; + } + } /* * If reached the end of the physical line, return the last Index: src/external/bsd/nvi/dist/vi/vs_refresh.c diff -u src/external/bsd/nvi/dist/vi/vs_refresh.c:1.6 src/external/bsd/nvi/dist/vi/vs_refresh.c:1.7 --- src/external/bsd/nvi/dist/vi/vs_refresh.c:1.6 Sun Jan 26 21:43:45 2014 +++ src/external/bsd/nvi/dist/vi/vs_refresh.c Fri Nov 10 14:44:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vs_refresh.c,v 1.6 2014/01/26 21:43:45 christos Exp $ */ +/* $NetBSD: vs_refresh.c,v 1.7 2017/11/10 14:44:13 rin Exp $ */ /*- * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -16,7 +16,7 @@ static const char sccsid[] = "Id: vs_refresh.c,v 10.50 2001/06/25 15:19:37 skimo Exp (Berkeley) Date: 2001/06/25 15:19:37 "; #endif /* not lint */ #else -__RCSID("$NetBSD: vs_refresh.c,v 1.6 2014/01/26 21:43:45 christos Exp $"); +__RCSID("$NetBSD: vs_refresh.c,v 1.7 2017/11/10 14:44:13 rin Exp $"); #endif #include <sys/types.h> @@ -148,7 +148,7 @@ vs_paint(SCR *sp, u_int flags) SMAP *smp, tmp; VI_PRIVATE *vip; db_recno_t lastline, lcnt; - size_t cwtotal, cnt, len, notused, off, y; + size_t cwtotal, cnt, len, notused, off, y, chlen; int ch = 0, didpaint, isempty, leftright_warp; CHAR_T *p; @@ -467,17 +467,33 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) && /* * 7a: Cursor moved left. * - * Point to the old character. The old cursor position can - * be past EOL if, for example, we just deleted the rest of - * the line. In this case, since we don't know the width of - * the characters we traversed, we have to do it slowly. + * The old cursor position can be past EOL if, for example, + * we just deleted the rest of the line. In this case, since + * we don't know the width of the characters we traversed, we + * have to do it slowly. */ - p += OCNO; - cnt = (OCNO - CNO) + 1; if (OCNO >= len) goto slow; /* + * cwtotal acts as new value for SCNO. Set cwtotal to the + * first char for content on CNO byte, for ease handling of + * wide characters. + * + * If the character we're stepping on lies across a screen + * boundary, we have no hope to speed it up. Do it slowly. + */ + p += OCNO; + if (INTISWIDE(ch = (UCHAR_T)*p)) + cwtotal = SCNO; + else { + if (ch == '\t' || (chlen = KEY_LEN(sp, ch)) > SCNO + 1) + goto slow; + cwtotal = SCNO + 1 - chlen; + } + cnt = OCNO - CNO; + + /* * Quick sanity check -- it's hard to figure out exactly when * we cross a screen boundary as we do in the cursor right * movement. If cnt is so large that we're going to cross the @@ -488,63 +504,87 @@ adjust: if (!O_ISSET(sp, O_LEFTRIGHT) && /* * Count up the widths of the characters. If it's a tab - * character, go do it the the slow way. + * character, go do it the slow way. */ - for (cwtotal = 0; cnt--; cwtotal += KEY_COL(sp, ch)) - if ((ch = *(UCHAR_T *)p--) == '\t') + while (cnt--) { + if ((ch = (UCHAR_T)*--p) == '\t' + || (chlen = KEY_COL(sp, ch)) > cwtotal) goto slow; + cwtotal -= chlen; + } /* - * Decrement the screen cursor by the total width of the - * characters minus 1. - */ - cwtotal -= 1; - - /* - * If we're moving left, and there's a wide character in the + * If we're moving left, and there's a multi-width char in the * current position, go to the end of the character. */ - if (KEY_COL(sp, ch) > 1) - cwtotal -= KEY_COL(sp, ch) - 1; + if (!INTISWIDE(ch) && (chlen = KEY_LEN(sp, ch)) > 1) + cwtotal += chlen - 1; /* - * If the new column moved us off of the current logical line, - * calculate a new one. If doing leftright scrolling, we've - * moved off of the current screen, as well. + * At last, update the screen cursor. */ - if (SCNO < cwtotal) - goto slow; - SCNO -= cwtotal; + SCNO = cwtotal; } else { /* * 7b: Cursor moved right. - * - * Point to the first character to the right. */ - p += OCNO + 1; + if (OCNO >= len) + goto slow; + + /* + * cwtotal acts as new value for SCNO. Set cwtotal to the + * first char for content on CNO byte, for ease handling + * of wide characters. + */ + p += OCNO; + if (INTISWIDE(ch = (UCHAR_T)*p)) + cwtotal = SCNO; + else + cwtotal = SCNO + 1 - KEY_LEN(sp, ch); cnt = CNO - OCNO; /* * Count up the widths of the characters. If it's a tab - * character, go do it the the slow way. If we cross a - * screen boundary, we can quit. + * character, go do it the the slow way. + * + * If a multi-width char seems to occupy the screen boundary, + * that will be pushed to the next line. Adjust the cursor + * in that case. + * + * If we cross a screen boundary, we can quit. */ - for (cwtotal = SCNO; cnt--;) { - if ((ch = *(UCHAR_T *)p++) == '\t') + while (cnt) { + if (ch == '\t') goto slow; - if ((cwtotal += KEY_COL(sp, ch)) >= SCREEN_COLS(sp)) + cwtotal += KEY_COL(sp, ch); + cnt--; + if (INTISWIDE(ch = (UCHAR_T)*++p) + && (chlen = CHAR_WIDTH(sp, ch)) > 1 + && cwtotal + chlen >= SCREEN_COLS(sp)) + cwtotal = SCREEN_COLS(sp); + if (cwtotal >= SCREEN_COLS(sp)) break; } /* - * Increment the screen cursor by the total width of the - * characters. + * If we are on the tab character, we must do it slowly. + * + * If we're on a multi-width character in the current position, + * go to the end of the character. */ - SCNO = cwtotal; + if (ch == '\t') + goto slow; + if (!INTISWIDE(ch) && (chlen = KEY_LEN(sp, ch)) > 1) + cwtotal += chlen - 1; /* See screen change comment in section 6a. */ - if (SCNO >= SCREEN_COLS(sp)) + if (cwtotal >= SCREEN_COLS(sp)) goto slow; + + /* + * At last, update the screen cursor. + */ + SCNO = cwtotal; } /* @@ -678,6 +718,8 @@ done_cursor: } #else if (vip->sc_smap == NULL) { + if (F_ISSET(sp, SC_SCR_REFORMAT)) + abort(); /* XXX */ F_SET(sp, SC_SCR_REFORMAT); return (vs_paint(sp, flags)); }