mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-05 22:20:24 -08:00
Add auto-margin enable/disable to term
* 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
This commit is contained in:
parent
83e2e5e24b
commit
13b1436d97
7 changed files with 115 additions and 38 deletions
13
etc/NEWS
13
etc/NEWS
|
|
@ -488,6 +488,19 @@ content.
|
||||||
When non-nil, buffer sizes are shown in human readable format. The
|
When non-nil, buffer sizes are shown in human readable format. The
|
||||||
default is nil, which retains the old format.
|
default is nil, which retains the old format.
|
||||||
|
|
||||||
|
** Term
|
||||||
|
|
||||||
|
*** The terminal emulator now supports auto-margins control.
|
||||||
|
Term mode now handles DECAWM escape sequences that control whether text
|
||||||
|
automatically wraps at the right margin:
|
||||||
|
- \e[?7h enables auto-margins (default)
|
||||||
|
- \e[?7l disables auto-margins
|
||||||
|
|
||||||
|
When auto-margins is disabled, characters that would go beyond the right margin
|
||||||
|
are discarded, which matches the behavior of physical terminals and other
|
||||||
|
terminal emulators. Control sequences and escape sequences are still processed
|
||||||
|
correctly regardless of margin position.
|
||||||
|
|
||||||
** Smerge
|
** Smerge
|
||||||
|
|
||||||
*** New command 'smerge-extend' extends a conflict over surrounding lines.
|
*** New command 'smerge-extend' extends a conflict over surrounding lines.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ version. If it is necessary, use:
|
||||||
|
|
||||||
tic -o ../ ./eterm-color.ti
|
tic -o ../ ./eterm-color.ti
|
||||||
|
|
||||||
|
(Sometimes tic puts output in etc/65 instead of etc/e. Move it to etc/e
|
||||||
|
yourself if it does that.)
|
||||||
|
|
||||||
The compiled files are used by lisp/term.el, so if they are moved,
|
The compiled files are used by lisp/term.el, so if they are moved,
|
||||||
term.el needs to be changed. terminfo requires them to be stored in
|
term.el needs to be changed. terminfo requires them to be stored in
|
||||||
an 'e' subdirectory (the first character of the file name).
|
an 'e' subdirectory (the first character of the file name).
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -5,7 +5,7 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96,
|
||||||
# in this format.
|
# in this format.
|
||||||
#
|
#
|
||||||
# When updating this file, etc/e/eterm-color should be regenerated by
|
# When updating this file, etc/e/eterm-color should be regenerated by
|
||||||
# running "make e/eterm-color" in the etc directory.
|
# following the instructions in etc/e/README.
|
||||||
# Any change to this file should be done at the same time with a
|
# Any change to this file should be done at the same time with a
|
||||||
# corresponding change to the TERMCAP environment variable in term.el.
|
# corresponding change to the TERMCAP environment variable in term.el.
|
||||||
# Comments in term.el specify where each of these capabilities is implemented.
|
# 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,
|
||||||
u7=\E[6n,
|
u7=\E[6n,
|
||||||
smcup=\E[47h,
|
smcup=\E[47h,
|
||||||
rmcup=\E[47l,
|
rmcup=\E[47l,
|
||||||
|
smam=\E[?7h,
|
||||||
|
rmam=\E[?7l,
|
||||||
# rs2 may need to be added
|
# rs2 may need to be added
|
||||||
|
|
||||||
eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 0.96,
|
eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 0.96,
|
||||||
|
|
|
||||||
Binary file not shown.
107
lisp/term.el
107
lisp/term.el
|
|
@ -349,6 +349,10 @@ contains saved `term-home-marker' from original sub-buffer.")
|
||||||
"Current vertical row (relative to home-marker) or nil if unknown.")
|
"Current vertical row (relative to home-marker) or nil if unknown.")
|
||||||
(defvar term-insert-mode nil)
|
(defvar term-insert-mode nil)
|
||||||
(defvar term-vertical-motion)
|
(defvar term-vertical-motion)
|
||||||
|
(defvar term-auto-margins t
|
||||||
|
"When non-nil, terminal will automatically wrap lines at the right margin.
|
||||||
|
This can be toggled by the application using DECAWM escape sequences.")
|
||||||
|
|
||||||
(defvar term-do-line-wrapping nil
|
(defvar term-do-line-wrapping nil
|
||||||
"Last character was a graphic in the last column.
|
"Last character was a graphic in the last column.
|
||||||
If next char is graphic, first move one column right
|
If next char is graphic, first move one column right
|
||||||
|
|
@ -1148,6 +1152,7 @@ Entry to this mode runs the hooks on `term-mode-hook'."
|
||||||
(setq-local term-last-input-start (make-marker))
|
(setq-local term-last-input-start (make-marker))
|
||||||
(setq-local term-last-input-end (make-marker))
|
(setq-local term-last-input-end (make-marker))
|
||||||
(setq-local term-last-input-match "")
|
(setq-local term-last-input-match "")
|
||||||
|
(setq-local term-auto-margins t)
|
||||||
|
|
||||||
;; Always display the onscreen keyboard.
|
;; Always display the onscreen keyboard.
|
||||||
(setq-local touch-screen-display-keyboard t)
|
(setq-local touch-screen-display-keyboard t)
|
||||||
|
|
@ -1682,7 +1687,7 @@ Using \"emacs\" loses, because bash disables editing if $TERM == emacs.")
|
||||||
:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\
|
:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\
|
||||||
:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\
|
:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\
|
||||||
:bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\
|
:bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\
|
||||||
:kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:"
|
:kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:RA=\\E[?7l:SA=\\E[?7h:"
|
||||||
;; : -undefine ic
|
;; : -undefine ic
|
||||||
;; don't define :te=\\E[2J\\E[?47l\\E8:ti=\\E7\\E[?47h\
|
;; don't define :te=\\E[2J\\E[?47l\\E8:ti=\\E7\\E[?47h\
|
||||||
"Termcap capabilities supported.")
|
"Termcap capabilities supported.")
|
||||||
|
|
@ -3128,19 +3133,24 @@ See `term-prompt-regexp'."
|
||||||
(unless term-suppress-hard-newline
|
(unless term-suppress-hard-newline
|
||||||
(while (> (+ (length decoded-substring) old-column)
|
(while (> (+ (length decoded-substring) old-column)
|
||||||
term-width)
|
term-width)
|
||||||
(insert (substring decoded-substring 0
|
(let* ((here-length (- term-width old-column))
|
||||||
(- term-width old-column)))
|
(to-insert (substring decoded-substring 0 here-length)))
|
||||||
;; Since we've enough text to fill the whole line,
|
(setf decoded-substring (substring decoded-substring here-length))
|
||||||
;; delete previous text regardless of
|
(insert to-insert)
|
||||||
;; `term-insert-mode's value.
|
(setf term-current-column nil)
|
||||||
(delete-region (point) (line-end-position))
|
;; Since we've enough text to fill the whole line,
|
||||||
(term-down 1 t)
|
;; delete previous text regardless of
|
||||||
(term-move-columns (- (term-current-column)))
|
;; `term-insert-mode's value.
|
||||||
(add-text-properties (1- (point)) (point)
|
(delete-region (point) (line-end-position))
|
||||||
'(term-line-wrap t rear-nonsticky t))
|
(if term-auto-margins
|
||||||
(setq decoded-substring
|
(progn
|
||||||
(substring decoded-substring (- term-width old-column)))
|
(term-move-to-column 0)
|
||||||
(setq old-column 0)))
|
(term-down 1 t)
|
||||||
|
(add-text-properties (1- (point)) (point)
|
||||||
|
'(term-line-wrap t rear-nonsticky t))
|
||||||
|
(setq old-column 0))
|
||||||
|
(term-move-columns -1)
|
||||||
|
(setf old-column (term-current-column))))))
|
||||||
(insert decoded-substring)
|
(insert decoded-substring)
|
||||||
(setq term-current-column (current-column)
|
(setq term-current-column (current-column)
|
||||||
columns (- term-current-column old-column))
|
columns (- term-current-column old-column))
|
||||||
|
|
@ -3162,14 +3172,18 @@ See `term-prompt-regexp'."
|
||||||
|
|
||||||
(put-text-property old-point (point)
|
(put-text-property old-point (point)
|
||||||
'font-lock-face term-current-face))
|
'font-lock-face term-current-face))
|
||||||
;; If the last char was written in last column,
|
;; If the last char was written in last column and auto-margins is enabled,
|
||||||
;; back up one column, but remember we did so.
|
;; back up one column, but remember we did so.
|
||||||
;; Thus we emulate xterm/vt100-style line-wrapping.
|
;; Thus we emulate xterm/vt100-style line-wrapping.
|
||||||
|
;; If auto-margins is disabled, the cursor stays at the last column
|
||||||
|
;; and further output is discarded until a cursor movement occurs.
|
||||||
(when (eq (term-current-column) term-width)
|
(when (eq (term-current-column) term-width)
|
||||||
(term-move-columns -1)
|
(term-move-columns -1)
|
||||||
;; We check after ctrl sequence handling if point
|
;; Only set line-wrapping if auto-margins is enabled
|
||||||
;; was moved (and leave line-wrapping state if so).
|
(when term-auto-margins
|
||||||
(setq term-do-line-wrapping (point)))
|
;; We check after ctrl sequence handling if point
|
||||||
|
;; was moved (and leave line-wrapping state if so).
|
||||||
|
(setq term-do-line-wrapping (point))))
|
||||||
(setq term-current-column nil)
|
(setq term-current-column nil)
|
||||||
(setq i funny))
|
(setq i funny))
|
||||||
(pcase-exhaustive (and (<= ctl-end str-length) (aref str i))
|
(pcase-exhaustive (and (<= ctl-end str-length) (aref str i))
|
||||||
|
|
@ -3205,15 +3219,19 @@ See `term-prompt-regexp'."
|
||||||
;; We only handle control sequences with a single
|
;; We only handle control sequences with a single
|
||||||
;; "Final" byte (see [ECMA-48] section 5.4).
|
;; "Final" byte (see [ECMA-48] section 5.4).
|
||||||
(when (eq ctl-params-end (1- ctl-end))
|
(when (eq ctl-params-end (1- ctl-end))
|
||||||
(term-handle-ansi-escape
|
(let* ((private (string-prefix-p "?" ctl-params))
|
||||||
proc
|
(ctl-params
|
||||||
(mapcar ;; We don't distinguish empty params
|
(if private (substring ctl-params 1) ctl-params)))
|
||||||
;; from 0 (according to [ECMA-48] we
|
(term-handle-ansi-escape
|
||||||
;; should, but all commands we support
|
proc
|
||||||
;; default to 0 values anyway).
|
(mapcar ;; We don't distinguish empty params
|
||||||
#'string-to-number
|
;; from 0 (according to [ECMA-48] we
|
||||||
(split-string ctl-params ";"))
|
;; should, but all commands we support
|
||||||
(aref str (1- ctl-end)))))
|
;; default to 0 values anyway).
|
||||||
|
#'string-to-number
|
||||||
|
(split-string ctl-params ";"))
|
||||||
|
(aref str (1- ctl-end))
|
||||||
|
private))))
|
||||||
(?D ;; Scroll forward (apparently not documented in
|
(?D ;; Scroll forward (apparently not documented in
|
||||||
;; [ECMA-48], [ctlseqs] mentions it as C1
|
;; [ECMA-48], [ctlseqs] mentions it as C1
|
||||||
;; character "Index" though).
|
;; character "Index" though).
|
||||||
|
|
@ -3426,7 +3444,8 @@ option is enabled. See `term-set-goto-process-mark'."
|
||||||
(setq term-current-row 0)
|
(setq term-current-row 0)
|
||||||
(setq term-current-column 1)
|
(setq term-current-column 1)
|
||||||
(term--reset-scroll-region)
|
(term--reset-scroll-region)
|
||||||
(setq term-insert-mode nil))
|
(setq term-insert-mode nil)
|
||||||
|
(setq term-auto-margins t))
|
||||||
|
|
||||||
(defun term--color-as-hex (for-foreground)
|
(defun term--color-as-hex (for-foreground)
|
||||||
"Return the current ANSI color as a hexadecimal color string.
|
"Return the current ANSI color as a hexadecimal color string.
|
||||||
|
|
@ -3569,8 +3588,11 @@ color is unset in the terminal state."
|
||||||
;; Handle a character assuming (eq terminal-state 2) -
|
;; Handle a character assuming (eq terminal-state 2) -
|
||||||
;; i.e. we have previously seen Escape followed by ?[.
|
;; i.e. we have previously seen Escape followed by ?[.
|
||||||
|
|
||||||
(defun term-handle-ansi-escape (proc params char)
|
(defun term-handle-ansi-escape (proc params char &optional private)
|
||||||
(cond
|
(cond
|
||||||
|
((and private (not (memq char '(?h ?l))))
|
||||||
|
;; Recognize private capabilities only for mode entry and exit
|
||||||
|
nil)
|
||||||
((or (eq char ?H) ;; cursor motion (terminfo: cup,home)
|
((or (eq char ?H) ;; cursor motion (terminfo: cup,home)
|
||||||
;; (eq char ?f) ;; xterm seems to handle this sequence too, not
|
;; (eq char ?f) ;; xterm seems to handle this sequence too, not
|
||||||
;; needed for now
|
;; needed for now
|
||||||
|
|
@ -3633,17 +3655,30 @@ color is unset in the terminal state."
|
||||||
((eq char ?@)
|
((eq char ?@)
|
||||||
(term-insert-spaces (max 1 (car params))))
|
(term-insert-spaces (max 1 (car params))))
|
||||||
;; \E[?h - DEC Private Mode Set
|
;; \E[?h - DEC Private Mode Set
|
||||||
|
|
||||||
|
;; N.B. we previously had a bug in which we'd decode \e[?<NR>h or
|
||||||
|
;; \e[?<NR>l as a command with zero in the params field and so
|
||||||
|
;; didn't recognize DEC private escape sequences. However, the
|
||||||
|
;; termcap and terminfo files had the non-? (question mark means DEC
|
||||||
|
;; private) versions, so things kind of worked anyway. To preserve
|
||||||
|
;; compatibility, we recognize both private- and non-private
|
||||||
|
;; messages for capabilities we added before we fixed the bug but
|
||||||
|
;; require the private flag for capabilities we added after.
|
||||||
((eq char ?h)
|
((eq char ?h)
|
||||||
(cond ((eq (car params) 4) ;; (terminfo: smir)
|
(cond ((eq (car params) 4) ;; (terminfo: smir)
|
||||||
(setq term-insert-mode t))
|
(setq term-insert-mode t))
|
||||||
((eq (car params) 47) ;; (terminfo: smcup)
|
((and private (eq (car params) 7)) ;; (terminfo: smam)
|
||||||
(term-switch-to-alternate-sub-buffer t))))
|
(setq term-auto-margins t))
|
||||||
|
((eq (car params) 47) ;; (terminfo: smcup)
|
||||||
|
(term-switch-to-alternate-sub-buffer t))))
|
||||||
;; \E[?l - DEC Private Mode Reset
|
;; \E[?l - DEC Private Mode Reset
|
||||||
((eq char ?l)
|
((eq char ?l)
|
||||||
(cond ((eq (car params) 4) ;; (terminfo: rmir)
|
(cond ((eq (car params) 4) ;; (terminfo: rmir)
|
||||||
(setq term-insert-mode nil))
|
(setq term-insert-mode nil))
|
||||||
|
((and private (eq (car params) 7)) ;; (terminfo: rmam)
|
||||||
|
(setq term-auto-margins nil))
|
||||||
((eq (car params) 47) ;; (terminfo: rmcup)
|
((eq (car params) 47) ;; (terminfo: rmcup)
|
||||||
(term-switch-to-alternate-sub-buffer nil))))
|
(term-switch-to-alternate-sub-buffer nil))))
|
||||||
|
|
||||||
;; Modified to allow ansi coloring -mm
|
;; Modified to allow ansi coloring -mm
|
||||||
;; \E[m - Set/reset modes, set bg/fg
|
;; \E[m - Set/reset modes, set bg/fg
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,30 @@ first line\r_next line\r\n"))
|
||||||
(term-test-screen-from-input 40 12 (let ((str (make-string 30 ?a)))
|
(term-test-screen-from-input 40 12 (let ((str (make-string 30 ?a)))
|
||||||
(list str str))))))
|
(list str str))))))
|
||||||
|
|
||||||
|
(ert-deftest term-line-wrap-no-auto-margins ()
|
||||||
|
(skip-when (memq system-type '(windows-nt ms-dos)))
|
||||||
|
(let* ((width 40)
|
||||||
|
(line (cl-loop for i upfrom 0 to 60
|
||||||
|
collect (+ ?a (% i 26)) into chars
|
||||||
|
finally return (apply #'string chars)))
|
||||||
|
(expected (concat (substring line 0 (1- width))
|
||||||
|
(substring line (1- (length line)))))
|
||||||
|
(rmam "\e[?7l"))
|
||||||
|
(should
|
||||||
|
(equal (term-test-screen-from-input width 12 (concat rmam line))
|
||||||
|
expected))
|
||||||
|
;; Again, but split input into chunks.
|
||||||
|
(should (equal
|
||||||
|
(term-test-screen-from-input
|
||||||
|
width 12
|
||||||
|
(cl-loop
|
||||||
|
with step = 3
|
||||||
|
with n = (length line)
|
||||||
|
for i upfrom 0 below n by step
|
||||||
|
collect (substring line i (min n (+ i step))) into parts
|
||||||
|
finally return (cons rmam parts)))
|
||||||
|
expected))))
|
||||||
|
|
||||||
(ert-deftest term-colors ()
|
(ert-deftest term-colors ()
|
||||||
(skip-when (memq system-type '(windows-nt ms-dos)))
|
(skip-when (memq system-type '(windows-nt ms-dos)))
|
||||||
(pcase-dolist (`(,str ,expected) ansi-test-strings)
|
(pcase-dolist (`(,str ,expected) ansi-test-strings)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue