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.
This commit is contained in:
Akib Azmain Turja 2022-11-28 19:37:17 +06:00
parent 6a94082eff
commit 9d14bbeaa5
No known key found for this signature in database
GPG key ID: 5535FCF54D88616B

43
eat.el
View file

@ -2438,28 +2438,12 @@ character to actually show.")
(gethash (aref str i) eat--t-dec-line-drawing-chars))) (gethash (aref str i) eat--t-dec-line-drawing-chars)))
(when replacement (when replacement
(aset str i replacement)))))) (aset str i replacement))))))
;; Find all the multi-column wide characters in STR, using a ;; Find all the multi-column wide characters in ST; hopefully it
;; binary search like algorithm; hopefully it won't slow down ;; won't slow down showing plain ASCII.
;; showing ASCII. (setq multi-col-char-indices
(named-let find ((string str) (cl-loop for i from 0 to (1- (length str))
(beg 0) when (/= (char-width (aref str i)) 1)
(end (length str))) collect (cons i (char-width (aref str i)))))
;; 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)))))
;; TODO: Comment. ;; TODO: Comment.
;; REVIEW: This probably needs to be updated. ;; REVIEW: This probably needs to be updated.
(let* ((disp (eat--t-term-display eat--t-term)) (let* ((disp (eat--t-term-display eat--t-term))
@ -2473,9 +2457,12 @@ character to actually show.")
;; successfully. ;; successfully.
(let ((ins-count (let ((ins-count
(named-let write (named-let write
((max (min (- (eat--t-disp-width disp) ((max
(1- (eat--t-cur-x cursor))) (min (- (eat--t-disp-width disp)
(string-width str inserted-till))) (1- (eat--t-cur-x cursor)))
(apply #'+ (- (length str) inserted-till)
(mapcar (lambda (p) (1- (cdr p)))
multi-col-char-indices))))
(written 0)) (written 0))
(let* ((next-multi-col (car multi-col-char-indices)) (let* ((next-multi-col (car multi-col-char-indices))
(end (+ inserted-till max)) (end (+ inserted-till max))
@ -2484,9 +2471,7 @@ character to actually show.")
(min (car next-multi-col) end) (min (car next-multi-col) end)
end)) end))
(wrote (- e inserted-till))) (wrote (- e inserted-till)))
(cl-assert (cl-assert (>= wrote 0))
(= (string-width str inserted-till e)
(- e inserted-till)))
(insert (substring str inserted-till e)) (insert (substring str inserted-till e))
(setq inserted-till e) (setq inserted-till e)
(if (or (null next-multi-col) (if (or (null next-multi-col)
@ -2495,7 +2480,7 @@ character to actually show.")
;; the limit. ;; the limit.
(+ written wrote) (+ written wrote)
;; There are many characters which are too narrow ;; 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. ;; and St seems to ignore them, so we too.
(if (zerop (cdr next-multi-col)) (if (zerop (cdr next-multi-col))
(cl-incf inserted-till) (cl-incf inserted-till)