Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/bsd/nvi/dist/vi - Fix cursor position when a multiw...



details:   https://anonhg.NetBSD.org/src/rev/044fa0983ee8
branches:  trunk
changeset: 827731:044fa0983ee8
user:      rin <rin%NetBSD.org@localhost>
date:      Fri Nov 10 14:44:13 2017 +0000

description:
- 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.

diffstat:

 external/bsd/nvi/dist/vi/vs_line.c     |  108 ++++++++++++++++++++-------
 external/bsd/nvi/dist/vi/vs_refresh.c  |  126 ++++++++++++++++++++++-----------
 external/bsd/nvi/dist/vi/vs_relative.c |  121 ++++++++++++++++++++++++++++--
 3 files changed, 274 insertions(+), 81 deletions(-)

diffs (truncated from 540 to 300 lines):

diff -r f79b61f07f3e -r 044fa0983ee8 external/bsd/nvi/dist/vi/vs_line.c
--- a/external/bsd/nvi/dist/vi/vs_line.c        Fri Nov 10 14:35:25 2017 +0000
+++ b/external/bsd/nvi/dist/vi/vs_line.c        Fri Nov 10 14:44:13 2017 +0000
@@ -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 @@
 
        /* 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 @@
                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 @@
         * 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 @@
                }
 
                /*
+                * 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 @@
                                        *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 @@
                        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 @@
 
        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;
 
                /*
diff -r f79b61f07f3e -r 044fa0983ee8 external/bsd/nvi/dist/vi/vs_refresh.c
--- a/external/bsd/nvi/dist/vi/vs_refresh.c     Fri Nov 10 14:35:25 2017 +0000
+++ b/external/bsd/nvi/dist/vi/vs_refresh.c     Fri Nov 10 14:44:13 2017 +0000
@@ -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 @@
        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,15 +467,31 @@
                /*
                 * 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.
+                */
+               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;
-               cnt = (OCNO - CNO) + 1;
-               if (OCNO >= len)
-                       goto slow;
+               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
@@ -488,63 +504,87 @@
 
                /*
                 * 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;
-
-               /*
-                * Decrement the screen cursor by the total width of the
-                * characters minus 1.
-                */
-               cwtotal -= 1;
+                       cwtotal -= chlen;
+               }
 
                /*
-                * 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.



Home | Main Index | Thread Index | Old Index