aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Colascione2025-03-02 15:53:17 -0500
committerDaniel Colascione2025-03-02 16:01:13 -0500
commit13b1436d975b270cb1001cf475fa65cc854ec462 (patch)
treee0597cd099c066b59e33fb5d1182b35b45749bbc
parent83e2e5e24b72f7a271c04a0ce9cad1399fb2a0f9 (diff)
downloademacs-dancol/term-am.tar.gz
emacs-dancol/term-am.zip
Add auto-margin enable/disable to termdancol/term-am
* test/lisp/term-tests.el (term-line-wrap-no-auto-margins): add test * lisp/term.el (term-auto-margins): new variable (term-mode): documentation (term-termcap-format): mention auto-margins flag (term-emulate-terminal): support it (term-reset-terminal): reset it (term-handle-ansi-escape): notice it * etc/e/eterm-color.ti: add auto margin capability * etc/e/README: fix build documentation * etc/NEWS: mention auto-margins
-rw-r--r--etc/NEWS13
-rw-r--r--etc/e/README3
-rw-r--r--etc/e/eterm-colorbin1318 -> 1330 bytes
-rw-r--r--etc/e/eterm-color.ti6
-rw-r--r--etc/e/eterm-directbin1397 -> 1409 bytes
-rw-r--r--lisp/term.el107
-rw-r--r--test/lisp/term-tests.el24
7 files changed, 115 insertions, 38 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 8d8fbbf38b9..6ae648ab8cf 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -488,6 +488,19 @@ content.
488When non-nil, buffer sizes are shown in human readable format. The 488When non-nil, buffer sizes are shown in human readable format. The
489default is nil, which retains the old format. 489default is nil, which retains the old format.
490 490
491** Term
492
493*** The terminal emulator now supports auto-margins control.
494Term mode now handles DECAWM escape sequences that control whether text
495automatically wraps at the right margin:
496- \e[?7h enables auto-margins (default)
497- \e[?7l disables auto-margins
498
499When auto-margins is disabled, characters that would go beyond the right margin
500are discarded, which matches the behavior of physical terminals and other
501terminal emulators. Control sequences and escape sequences are still processed
502correctly regardless of margin position.
503
491** Smerge 504** Smerge
492 505
493*** New command 'smerge-extend' extends a conflict over surrounding lines. 506*** New command 'smerge-extend' extends a conflict over surrounding lines.
diff --git a/etc/e/README b/etc/e/README
index 1293292a878..7a1a6406c7d 100644
--- a/etc/e/README
+++ b/etc/e/README
@@ -7,6 +7,9 @@ version. If it is necessary, use:
7 7
8tic -o ../ ./eterm-color.ti 8tic -o ../ ./eterm-color.ti
9 9
10(Sometimes tic puts output in etc/65 instead of etc/e. Move it to etc/e
11yourself if it does that.)
12
10The compiled files are used by lisp/term.el, so if they are moved, 13The compiled files are used by lisp/term.el, so if they are moved,
11term.el needs to be changed. terminfo requires them to be stored in 14term.el needs to be changed. terminfo requires them to be stored in
12an 'e' subdirectory (the first character of the file name). 15an 'e' subdirectory (the first character of the file name).
diff --git a/etc/e/eterm-color b/etc/e/eterm-color
index fadac25ffcb..fb497ecca8c 100644
--- a/etc/e/eterm-color
+++ b/etc/e/eterm-color
Binary files differ
diff --git a/etc/e/eterm-color.ti b/etc/e/eterm-color.ti
index 84b27aef5d9..fb9e59c97cf 100644
--- a/etc/e/eterm-color.ti
+++ b/etc/e/eterm-color.ti
@@ -4,8 +4,8 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96,
4# copyright, constituting the only possible expression of the algorithm 4# copyright, constituting the only possible expression of the algorithm
5# in this format. 5# in this format.
6# 6#
7# When updating this file, etc/e/eterm-color should be regenerated by 7# When updating this file, etc/e/eterm-color should be regenerated by
8# running "make e/eterm-color" in the etc directory. 8# following the instructions in etc/e/README.
9# Any change to this file should be done at the same time with a 9# Any change to this file should be done at the same time with a
10# corresponding change to the TERMCAP environment variable in term.el. 10# corresponding change to the TERMCAP environment variable in term.el.
11# Comments in term.el specify where each of these capabilities is implemented. 11# Comments in term.el specify where each of these capabilities is implemented.
@@ -80,6 +80,8 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96,
80 u7=\E[6n, 80 u7=\E[6n,
81 smcup=\E[47h, 81 smcup=\E[47h,
82 rmcup=\E[47l, 82 rmcup=\E[47l,
83 smam=\E[?7h,
84 rmam=\E[?7l,
83# rs2 may need to be added 85# rs2 may need to be added
84 86
85eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 0.96, 87eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 0.96,
diff --git a/etc/e/eterm-direct b/etc/e/eterm-direct
index f4c16621eb1..945707fa6c4 100644
--- a/etc/e/eterm-direct
+++ b/etc/e/eterm-direct
Binary files differ
diff --git a/lisp/term.el b/lisp/term.el
index 3f6b5c8f123..a74216f00c5 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -349,6 +349,10 @@ contains saved `term-home-marker' from original sub-buffer.")
349 "Current vertical row (relative to home-marker) or nil if unknown.") 349 "Current vertical row (relative to home-marker) or nil if unknown.")
350(defvar term-insert-mode nil) 350(defvar term-insert-mode nil)
351(defvar term-vertical-motion) 351(defvar term-vertical-motion)
352(defvar term-auto-margins t
353 "When non-nil, terminal will automatically wrap lines at the right margin.
354This can be toggled by the application using DECAWM escape sequences.")
355
352(defvar term-do-line-wrapping nil 356(defvar term-do-line-wrapping nil
353 "Last character was a graphic in the last column. 357 "Last character was a graphic in the last column.
354If next char is graphic, first move one column right 358If next char is graphic, first move one column right
@@ -1148,6 +1152,7 @@ Entry to this mode runs the hooks on `term-mode-hook'."
1148 (setq-local term-last-input-start (make-marker)) 1152 (setq-local term-last-input-start (make-marker))
1149 (setq-local term-last-input-end (make-marker)) 1153 (setq-local term-last-input-end (make-marker))
1150 (setq-local term-last-input-match "") 1154 (setq-local term-last-input-match "")
1155 (setq-local term-auto-margins t)
1151 1156
1152 ;; Always display the onscreen keyboard. 1157 ;; Always display the onscreen keyboard.
1153 (setq-local touch-screen-display-keyboard t) 1158 (setq-local touch-screen-display-keyboard t)
@@ -1682,7 +1687,7 @@ Using \"emacs\" loses, because bash disables editing if $TERM == emacs.")
1682:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\ 1687:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\
1683:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\ 1688:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\
1684:bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\ 1689:bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\
1685:kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:" 1690:kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:RA=\\E[?7l:SA=\\E[?7h:"
1686 ;; : -undefine ic 1691 ;; : -undefine ic
1687 ;; don't define :te=\\E[2J\\E[?47l\\E8:ti=\\E7\\E[?47h\ 1692 ;; don't define :te=\\E[2J\\E[?47l\\E8:ti=\\E7\\E[?47h\
1688 "Termcap capabilities supported.") 1693 "Termcap capabilities supported.")
@@ -3128,19 +3133,24 @@ See `term-prompt-regexp'."
3128 (unless term-suppress-hard-newline 3133 (unless term-suppress-hard-newline
3129 (while (> (+ (length decoded-substring) old-column) 3134 (while (> (+ (length decoded-substring) old-column)
3130 term-width) 3135 term-width)
3131 (insert (substring decoded-substring 0 3136 (let* ((here-length (- term-width old-column))
3132 (- term-width old-column))) 3137 (to-insert (substring decoded-substring 0 here-length)))
3133 ;; Since we've enough text to fill the whole line, 3138 (setf decoded-substring (substring decoded-substring here-length))
3134 ;; delete previous text regardless of 3139 (insert to-insert)
3135 ;; `term-insert-mode's value. 3140 (setf term-current-column nil)
3136 (delete-region (point) (line-end-position)) 3141 ;; Since we've enough text to fill the whole line,
3137 (term-down 1 t) 3142 ;; delete previous text regardless of
3138 (term-move-columns (- (term-current-column))) 3143 ;; `term-insert-mode's value.
3139 (add-text-properties (1- (point)) (point) 3144 (delete-region (point) (line-end-position))
3140 '(term-line-wrap t rear-nonsticky t)) 3145 (if term-auto-margins
3141 (setq decoded-substring 3146 (progn
3142 (substring decoded-substring (- term-width old-column))) 3147 (term-move-to-column 0)
3143 (setq old-column 0))) 3148 (term-down 1 t)
3149 (add-text-properties (1- (point)) (point)
3150 '(term-line-wrap t rear-nonsticky t))
3151 (setq old-column 0))
3152 (term-move-columns -1)
3153 (setf old-column (term-current-column))))))
3144 (insert decoded-substring) 3154 (insert decoded-substring)
3145 (setq term-current-column (current-column) 3155 (setq term-current-column (current-column)
3146 columns (- term-current-column old-column)) 3156 columns (- term-current-column old-column))
@@ -3162,14 +3172,18 @@ See `term-prompt-regexp'."
3162 3172
3163 (put-text-property old-point (point) 3173 (put-text-property old-point (point)
3164 'font-lock-face term-current-face)) 3174 'font-lock-face term-current-face))
3165 ;; If the last char was written in last column, 3175 ;; If the last char was written in last column and auto-margins is enabled,
3166 ;; back up one column, but remember we did so. 3176 ;; back up one column, but remember we did so.
3167 ;; Thus we emulate xterm/vt100-style line-wrapping. 3177 ;; Thus we emulate xterm/vt100-style line-wrapping.
3178 ;; If auto-margins is disabled, the cursor stays at the last column
3179 ;; and further output is discarded until a cursor movement occurs.
3168 (when (eq (term-current-column) term-width) 3180 (when (eq (term-current-column) term-width)
3169 (term-move-columns -1) 3181 (term-move-columns -1)
3170 ;; We check after ctrl sequence handling if point 3182 ;; Only set line-wrapping if auto-margins is enabled
3171 ;; was moved (and leave line-wrapping state if so). 3183 (when term-auto-margins
3172 (setq term-do-line-wrapping (point))) 3184 ;; We check after ctrl sequence handling if point
3185 ;; was moved (and leave line-wrapping state if so).
3186 (setq term-do-line-wrapping (point))))
3173 (setq term-current-column nil) 3187 (setq term-current-column nil)
3174 (setq i funny)) 3188 (setq i funny))
3175 (pcase-exhaustive (and (<= ctl-end str-length) (aref str i)) 3189 (pcase-exhaustive (and (<= ctl-end str-length) (aref str i))
@@ -3205,15 +3219,19 @@ See `term-prompt-regexp'."
3205 ;; We only handle control sequences with a single 3219 ;; We only handle control sequences with a single
3206 ;; "Final" byte (see [ECMA-48] section 5.4). 3220 ;; "Final" byte (see [ECMA-48] section 5.4).
3207 (when (eq ctl-params-end (1- ctl-end)) 3221 (when (eq ctl-params-end (1- ctl-end))
3208 (term-handle-ansi-escape 3222 (let* ((private (string-prefix-p "?" ctl-params))
3209 proc 3223 (ctl-params
3210 (mapcar ;; We don't distinguish empty params 3224 (if private (substring ctl-params 1) ctl-params)))
3211 ;; from 0 (according to [ECMA-48] we 3225 (term-handle-ansi-escape
3212 ;; should, but all commands we support 3226 proc
3213 ;; default to 0 values anyway). 3227 (mapcar ;; We don't distinguish empty params
3214 #'string-to-number 3228 ;; from 0 (according to [ECMA-48] we
3215 (split-string ctl-params ";")) 3229 ;; should, but all commands we support
3216 (aref str (1- ctl-end))))) 3230 ;; default to 0 values anyway).
3231 #'string-to-number
3232 (split-string ctl-params ";"))
3233 (aref str (1- ctl-end))
3234 private))))
3217 (?D ;; Scroll forward (apparently not documented in 3235 (?D ;; Scroll forward (apparently not documented in
3218 ;; [ECMA-48], [ctlseqs] mentions it as C1 3236 ;; [ECMA-48], [ctlseqs] mentions it as C1
3219 ;; character "Index" though). 3237 ;; character "Index" though).
@@ -3426,7 +3444,8 @@ option is enabled. See `term-set-goto-process-mark'."
3426 (setq term-current-row 0) 3444 (setq term-current-row 0)
3427 (setq term-current-column 1) 3445 (setq term-current-column 1)
3428 (term--reset-scroll-region) 3446 (term--reset-scroll-region)
3429 (setq term-insert-mode nil)) 3447 (setq term-insert-mode nil)
3448 (setq term-auto-margins t))
3430 3449
3431(defun term--color-as-hex (for-foreground) 3450(defun term--color-as-hex (for-foreground)
3432 "Return the current ANSI color as a hexadecimal color string. 3451 "Return the current ANSI color as a hexadecimal color string.
@@ -3569,8 +3588,11 @@ color is unset in the terminal state."
3569;; Handle a character assuming (eq terminal-state 2) - 3588;; Handle a character assuming (eq terminal-state 2) -
3570;; i.e. we have previously seen Escape followed by ?[. 3589;; i.e. we have previously seen Escape followed by ?[.
3571 3590
3572(defun term-handle-ansi-escape (proc params char) 3591(defun term-handle-ansi-escape (proc params char &optional private)
3573 (cond 3592 (cond
3593 ((and private (not (memq char '(?h ?l))))
3594 ;; Recognize private capabilities only for mode entry and exit
3595 nil)
3574 ((or (eq char ?H) ;; cursor motion (terminfo: cup,home) 3596 ((or (eq char ?H) ;; cursor motion (terminfo: cup,home)
3575 ;; (eq char ?f) ;; xterm seems to handle this sequence too, not 3597 ;; (eq char ?f) ;; xterm seems to handle this sequence too, not
3576 ;; needed for now 3598 ;; needed for now
@@ -3633,17 +3655,30 @@ color is unset in the terminal state."
3633 ((eq char ?@) 3655 ((eq char ?@)
3634 (term-insert-spaces (max 1 (car params)))) 3656 (term-insert-spaces (max 1 (car params))))
3635 ;; \E[?h - DEC Private Mode Set 3657 ;; \E[?h - DEC Private Mode Set
3658
3659 ;; N.B. we previously had a bug in which we'd decode \e[?<NR>h or
3660 ;; \e[?<NR>l as a command with zero in the params field and so
3661 ;; didn't recognize DEC private escape sequences. However, the
3662 ;; termcap and terminfo files had the non-? (question mark means DEC
3663 ;; private) versions, so things kind of worked anyway. To preserve
3664 ;; compatibility, we recognize both private- and non-private
3665 ;; messages for capabilities we added before we fixed the bug but
3666 ;; require the private flag for capabilities we added after.
3636 ((eq char ?h) 3667 ((eq char ?h)
3637 (cond ((eq (car params) 4) ;; (terminfo: smir) 3668 (cond ((eq (car params) 4) ;; (terminfo: smir)
3638 (setq term-insert-mode t)) 3669 (setq term-insert-mode t))
3639 ((eq (car params) 47) ;; (terminfo: smcup) 3670 ((and private (eq (car params) 7)) ;; (terminfo: smam)
3640 (term-switch-to-alternate-sub-buffer t)))) 3671 (setq term-auto-margins t))
3672 ((eq (car params) 47) ;; (terminfo: smcup)
3673 (term-switch-to-alternate-sub-buffer t))))
3641 ;; \E[?l - DEC Private Mode Reset 3674 ;; \E[?l - DEC Private Mode Reset
3642 ((eq char ?l) 3675 ((eq char ?l)
3643 (cond ((eq (car params) 4) ;; (terminfo: rmir) 3676 (cond ((eq (car params) 4) ;; (terminfo: rmir)
3644 (setq term-insert-mode nil)) 3677 (setq term-insert-mode nil))
3678 ((and private (eq (car params) 7)) ;; (terminfo: rmam)
3679 (setq term-auto-margins nil))
3645 ((eq (car params) 47) ;; (terminfo: rmcup) 3680 ((eq (car params) 47) ;; (terminfo: rmcup)
3646 (term-switch-to-alternate-sub-buffer nil)))) 3681 (term-switch-to-alternate-sub-buffer nil))))
3647 3682
3648 ;; Modified to allow ansi coloring -mm 3683 ;; Modified to allow ansi coloring -mm
3649 ;; \E[m - Set/reset modes, set bg/fg 3684 ;; \E[m - Set/reset modes, set bg/fg
diff --git a/test/lisp/term-tests.el b/test/lisp/term-tests.el
index 65531b66d09..5ef8c1174df 100644
--- a/test/lisp/term-tests.el
+++ b/test/lisp/term-tests.el
@@ -129,6 +129,30 @@ first line\r_next line\r\n"))
129 (term-test-screen-from-input 40 12 (let ((str (make-string 30 ?a))) 129 (term-test-screen-from-input 40 12 (let ((str (make-string 30 ?a)))
130 (list str str)))))) 130 (list str str))))))
131 131
132(ert-deftest term-line-wrap-no-auto-margins ()
133 (skip-when (memq system-type '(windows-nt ms-dos)))
134 (let* ((width 40)
135 (line (cl-loop for i upfrom 0 to 60
136 collect (+ ?a (% i 26)) into chars
137 finally return (apply #'string chars)))
138 (expected (concat (substring line 0 (1- width))
139 (substring line (1- (length line)))))
140 (rmam "\e[?7l"))
141 (should
142 (equal (term-test-screen-from-input width 12 (concat rmam line))
143 expected))
144 ;; Again, but split input into chunks.
145 (should (equal
146 (term-test-screen-from-input
147 width 12
148 (cl-loop
149 with step = 3
150 with n = (length line)
151 for i upfrom 0 below n by step
152 collect (substring line i (min n (+ i step))) into parts
153 finally return (cons rmam parts)))
154 expected))))
155
132(ert-deftest term-colors () 156(ert-deftest term-colors ()
133 (skip-when (memq system-type '(windows-nt ms-dos))) 157 (skip-when (memq system-type '(windows-nt ms-dos)))
134 (pcase-dolist (`(,str ,expected) ansi-test-strings) 158 (pcase-dolist (`(,str ,expected) ansi-test-strings)