From 9d14bbeaa5c7f5499dcde485ef3a539f8590088e Mon Sep 17 00:00:00 2001 From: Akib Azmain Turja Date: Mon, 28 Nov 2022 19:37:17 +0600 Subject: [PATCH] Support multi-column characters properly * eat.el (eat--t-write): Use 'char-width' instead of the unpredictable 'string-width' to support multi-column characters properly. --- eat.el | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/eat.el b/eat.el index e07081b..36b42ba 100644 --- a/eat.el +++ b/eat.el @@ -2438,28 +2438,12 @@ character to actually show.") (gethash (aref str i) eat--t-dec-line-drawing-chars))) (when replacement (aset str i replacement)))))) - ;; Find all the multi-column wide characters in STR, using a - ;; binary search like algorithm; hopefully it won't slow down - ;; showing ASCII. - (named-let find ((string str) - (beg 0) - (end (length str))) - ;; NOTE: `string-width' doesn't work correctly given a range of - ;; characters in a string. This workarounds the bug partially. - ;; FIXME: This sometimes doesn't work. To reproduce, do C-h h - ;; in emacs -nw in Eat. - (unless (= (- end beg) (string-width string)) - (if (= (- end beg) 1) - ;; Record the character width here. We only use - ;; `string-width', (= `string-width' `char-width') isn't - ;; always t. - (push (cons beg (string-width string)) - multi-col-char-indices) - (let ((mid (/ (+ beg end) 2))) - ;; Processing the latter half first in important, - ;; otherwise the order of indices will be reversed. - (find (substring str mid end) mid end) - (find (substring str beg mid) beg mid))))) + ;; Find all the multi-column wide characters in ST; hopefully it + ;; won't slow down showing plain ASCII. + (setq multi-col-char-indices + (cl-loop for i from 0 to (1- (length str)) + when (/= (char-width (aref str i)) 1) + collect (cons i (char-width (aref str i))))) ;; TODO: Comment. ;; REVIEW: This probably needs to be updated. (let* ((disp (eat--t-term-display eat--t-term)) @@ -2473,9 +2457,12 @@ character to actually show.") ;; successfully. (let ((ins-count (named-let write - ((max (min (- (eat--t-disp-width disp) - (1- (eat--t-cur-x cursor))) - (string-width str inserted-till))) + ((max + (min (- (eat--t-disp-width disp) + (1- (eat--t-cur-x cursor))) + (apply #'+ (- (length str) inserted-till) + (mapcar (lambda (p) (1- (cdr p))) + multi-col-char-indices)))) (written 0)) (let* ((next-multi-col (car multi-col-char-indices)) (end (+ inserted-till max)) @@ -2484,9 +2471,7 @@ character to actually show.") (min (car next-multi-col) end) end)) (wrote (- e inserted-till))) - (cl-assert - (= (string-width str inserted-till e) - (- e inserted-till))) + (cl-assert (>= wrote 0)) (insert (substring str inserted-till e)) (setq inserted-till e) (if (or (null next-multi-col) @@ -2495,7 +2480,7 @@ character to actually show.") ;; the limit. (+ written wrote) ;; There are many characters which are too narrow - ;; for `string-width' to return 1. XTerm, Kitty + ;; for `char-width' to return 1. XTerm, Kitty ;; and St seems to ignore them, so we too. (if (zerop (cdr next-multi-col)) (cl-incf inserted-till)