;;; term.el --- general command interpreter in a window stuff
;; Copyright (C) 1988, 1990, 1992, 1994, 1995, 2001, 2002, 2003,
-;; 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Per Bothner <per@bothner.com>
;; Maintainer: Dan Nicolaescu <dann@ics.uci.edu>, Per Bothner <per@bothner.com>
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Marck 13 2001
;;; Fixes for CJK support by Yong Lu <lyongu@yahoo.com>.
:type 'hook
:group 'term)
-(defvar term-mode-map nil)
+(defvar term-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\ep" 'term-previous-input)
+ (define-key map "\en" 'term-next-input)
+ (define-key map "\er" 'term-previous-matching-input)
+ (define-key map "\es" 'term-next-matching-input)
+ (unless (featurep 'xemacs)
+ (define-key map [?\A-\M-r]
+ 'term-previous-matching-input-from-input)
+ (define-key map [?\A-\M-s] 'term-next-matching-input-from-input))
+ (define-key map "\e\C-l" 'term-show-output)
+ (define-key map "\C-m" 'term-send-input)
+ (define-key map "\C-d" 'term-delchar-or-maybe-eof)
+ (define-key map "\C-c\C-a" 'term-bol)
+ (define-key map "\C-c\C-u" 'term-kill-input)
+ (define-key map "\C-c\C-w" 'backward-kill-word)
+ (define-key map "\C-c\C-c" 'term-interrupt-subjob)
+ (define-key map "\C-c\C-z" 'term-stop-subjob)
+ (define-key map "\C-c\C-\\" 'term-quit-subjob)
+ (define-key map "\C-c\C-m" 'term-copy-old-input)
+ (define-key map "\C-c\C-o" 'term-kill-output)
+ (define-key map "\C-c\C-r" 'term-show-output)
+ (define-key map "\C-c\C-e" 'term-show-maximum-output)
+ (define-key map "\C-c\C-l" 'term-dynamic-list-input-ring)
+ (define-key map "\C-c\C-n" 'term-next-prompt)
+ (define-key map "\C-c\C-p" 'term-previous-prompt)
+ (define-key map "\C-c\C-d" 'term-send-eof)
+ (define-key map "\C-c\C-k" 'term-char-mode)
+ (define-key map "\C-c\C-j" 'term-line-mode)
+ (define-key map "\C-c\C-q" 'term-pager-toggle)
+
+ ;; ;; completion:
+ ;; (define-key map [menu-bar completion]
+ ;; (cons "Complete" (make-sparse-keymap "Complete")))
+ ;; (define-key map [menu-bar completion complete-expand]
+ ;; '("Expand File Name" . term-replace-by-expanded-filename))
+ ;; (define-key map [menu-bar completion complete-listing]
+ ;; '("File Completion Listing" . term-dynamic-list-filename-completions))
+ ;; (define-key map [menu-bar completion complete-file]
+ ;; '("Complete File Name" . term-dynamic-complete-filename))
+ ;; (define-key map [menu-bar completion complete]
+ ;; '("Complete Before Point" . term-dynamic-complete))
+ ;; ;; Put them in the menu bar:
+ ;; (setq menu-bar-final-items (append '(terminal completion inout signals)
+ ;; menu-bar-final-items))
+ map))
+
(defvar term-raw-map nil
"Keyboard map for sending characters directly to the inferior process.")
(defvar term-escape-char nil
[ "Enable paging" term-pager-toggle (not term-pager-count)]
[ "Disable paging" term-pager-toggle term-pager-count])))
-(unless term-mode-map
- (setq term-mode-map (make-sparse-keymap))
- (define-key term-mode-map "\ep" 'term-previous-input)
- (define-key term-mode-map "\en" 'term-next-input)
- (define-key term-mode-map "\er" 'term-previous-matching-input)
- (define-key term-mode-map "\es" 'term-next-matching-input)
- (unless (featurep 'xemacs)
- (define-key term-mode-map [?\A-\M-r]
- 'term-previous-matching-input-from-input)
- (define-key term-mode-map [?\A-\M-s] 'term-next-matching-input-from-input))
- (define-key term-mode-map "\e\C-l" 'term-show-output)
- (define-key term-mode-map "\C-m" 'term-send-input)
- (define-key term-mode-map "\C-d" 'term-delchar-or-maybe-eof)
- (define-key term-mode-map "\C-c\C-a" 'term-bol)
- (define-key term-mode-map "\C-c\C-u" 'term-kill-input)
- (define-key term-mode-map "\C-c\C-w" 'backward-kill-word)
- (define-key term-mode-map "\C-c\C-c" 'term-interrupt-subjob)
- (define-key term-mode-map "\C-c\C-z" 'term-stop-subjob)
- (define-key term-mode-map "\C-c\C-\\" 'term-quit-subjob)
- (define-key term-mode-map "\C-c\C-m" 'term-copy-old-input)
- (define-key term-mode-map "\C-c\C-o" 'term-kill-output)
- (define-key term-mode-map "\C-c\C-r" 'term-show-output)
- (define-key term-mode-map "\C-c\C-e" 'term-show-maximum-output)
- (define-key term-mode-map "\C-c\C-l" 'term-dynamic-list-input-ring)
- (define-key term-mode-map "\C-c\C-n" 'term-next-prompt)
- (define-key term-mode-map "\C-c\C-p" 'term-previous-prompt)
- (define-key term-mode-map "\C-c\C-d" 'term-send-eof)
- (define-key term-mode-map "\C-c\C-k" 'term-char-mode)
- (define-key term-mode-map "\C-c\C-j" 'term-line-mode)
- (define-key term-mode-map "\C-c\C-q" 'term-pager-toggle)
-
-; ;; completion:
-; (define-key term-mode-map [menu-bar completion]
-; (cons "Complete" (make-sparse-keymap "Complete")))
-; (define-key term-mode-map [menu-bar completion complete-expand]
-; '("Expand File Name" . term-replace-by-expanded-filename))
-; (define-key term-mode-map [menu-bar completion complete-listing]
-; '("File Completion Listing" . term-dynamic-list-filename-completions))
-; (define-key term-mode-map [menu-bar completion complete-file]
-; '("Complete File Name" . term-dynamic-complete-filename))
-; (define-key term-mode-map [menu-bar completion complete]
-; '("Complete Before Point" . term-dynamic-complete))
-; ;; Put them in the menu bar:
-; (setq menu-bar-final-items (append '(terminal completion inout signals)
-; menu-bar-final-items))
- )
-
;; Menu bars:
(unless (featurep 'xemacs)
;; terminal:
(let (newmap)
(setq newmap (make-sparse-keymap "Terminal"))
(define-key newmap [terminal-pager-enable]
- '("Enable paging" . term-fake-pager-enable))
+ '(menu-item "Enable paging" term-fake-pager-enable
+ :help "Enable paging feature"))
(define-key newmap [terminal-pager-disable]
- '("Disable paging" . term-fake-pager-disable))
+ '(menu-item "Disable paging" term-fake-pager-disable
+ :help "Disable paging feature"))
(define-key newmap [terminal-char-mode]
- '("Character mode" . term-char-mode))
+ '(menu-item "Character mode" term-char-mode
+ :help "Switch to char (raw) sub-mode of term mode"))
(define-key newmap [terminal-line-mode]
- '("Line mode" . term-line-mode))
+ '(menu-item "Line mode" term-line-mode
+ :help "Switch to line (cooked) sub-mode of term mode"))
(setq term-terminal-menu (cons "Terminal" newmap))
;; completion: (line mode only)
;; Signals
(setq newmap (make-sparse-keymap "Signals"))
- (define-key newmap [eof] '("EOF" . term-send-eof))
- (define-key newmap [kill] '("KILL" . term-kill-subjob))
- (define-key newmap [quit] '("QUIT" . term-quit-subjob))
- (define-key newmap [cont] '("CONT" . term-continue-subjob))
- (define-key newmap [stop] '("STOP" . term-stop-subjob))
- (define-key newmap [] '("BREAK" . term-interrupt-subjob))
(define-key term-mode-map [menu-bar signals]
(setq term-signals-menu (cons "Signals" newmap)))
+ (define-key newmap [eof]
+ '(menu-item "EOF" term-send-eof
+ :help "Send an EOF to the current buffer's process"))
+ (define-key newmap [kill]
+ '(menu-item "KILL" term-kill-subjob
+ :help "Send kill signal to the current subjob"))
+ (define-key newmap [quit]
+ '(menu-item "QUIT" term-quit-subjob
+ :help "Send quit signal to the current subjob."))
+ (define-key newmap [cont]
+ '(menu-item "CONT" term-continue-subjob
+ :help "Send CONT signal to process buffer's process group"))
+ (define-key newmap [stop]
+ '(menu-item "STOP" term-stop-subjob
+ :help "Stop the current subjob"))
+ (define-key newmap [brk]
+ '(menu-item "BREAK" term-interrupt-subjob
+ :help "Interrupt the current subjob"))
))
\f
;; Set up term-raw-map, etc.
(term-set-escape-char ?\C-c)
+(defvar overflow-newline-into-fringe)
+
(defun term-window-width ()
(if (featurep 'xemacs)
(1- (window-width))
(term-update-mode-line)))
(defun term-update-mode-line ()
- (setq mode-line-process
- (if (term-in-char-mode)
- (if (term-pager-enabled) '(": char page %s") '(": char %s"))
- (if (term-pager-enabled) '(": line page %s") '(": line %s"))))
+ (let ((term-mode (if (term-in-char-mode) "char" "line"))
+ (term-page (when (term-pager-enabled) " page"))
+ (serial-item-speed)
+ (serial-item-config)
+ (temp)
+ (proc (get-buffer-process (current-buffer))))
+ (when (and (term-check-proc (current-buffer))
+ (equal (process-type nil) 'serial))
+ (let ((temp (serial-speed)))
+ (setq serial-item-speed
+ `(:propertize
+ ,(or (and temp (format " %d" temp)) "")
+ help-echo "mouse-1: Change the speed of the serial port"
+ mouse-face mode-line-highlight
+ local-map (keymap (mode-line keymap
+ (down-mouse-1 . serial-mode-line-speed-menu-1))))))
+ (let ((temp (process-contact proc :summary)))
+ (setq serial-item-config
+ `(:propertize
+ ,(or (and temp (format " %s" temp)) "")
+ help-echo "mouse-1: Change the configuration of the serial port"
+ mouse-face mode-line-highlight
+ local-map (keymap (mode-line keymap
+ (down-mouse-1 . serial-mode-line-config-menu-1)))))))
+ (setq mode-line-process
+ (list ": " term-mode term-page
+ serial-item-speed
+ serial-item-config
+ " %s")))
(force-mode-line-update))
(defun term-check-proc (buffer)
- "True if there is a process associated w/buffer BUFFER, and
-it is alive (status RUN or STOP). BUFFER can be either a buffer or the
-name of one."
+ "True if there is a process associated w/buffer BUFFER, and it
+is alive. BUFFER can be either a buffer or the name of one."
(let ((proc (get-buffer-process buffer)))
- (and proc (memq (process-status proc) '(run stop)))))
+ (and proc (memq (process-status proc) '(run stop open listen connect)))))
;;;###autoload
(defun make-term (name program &optional startfile &rest switches)
(defun term-emulate-terminal (proc str)
(with-current-buffer (process-buffer proc)
- (let* ((i 0) char funny count save-point save-marker old-point temp win
+ (let* ((i 0) char funny
+ count ; number of decoded chars in substring
+ count-bytes ; number of bytes
+ decoded-substring
+ save-point save-marker old-point temp win
(buffer-undo-list t)
(selected (selected-window))
last-win
str i))
(when (not funny) (setq funny str-length))
(cond ((> funny i)
+ ;; Decode the string before counting
+ ;; characters, to avoid garbling of certain
+ ;; multibyte characters (bug#1006).
+ (setq decoded-substring
+ (decode-coding-string
+ (substring str i funny)
+ locale-coding-system))
(cond ((eq term-terminal-state 1)
;; We are in state 1, we need to wrap
;; around. Go to the beginning of
(term-down 1 t)
(term-move-columns (- (term-current-column)))
(setq term-terminal-state 0)))
- (setq count (- funny i))
+ (setq count (length decoded-substring))
(setq temp (- (+ (term-horizontal-column) count)
term-width))
(cond ((<= temp 0)) ;; All count chars fit in line.
((> count temp) ;; Some chars fit.
;; This iteration, handle only what fits.
(setq count (- count temp))
+ (setq count-bytes
+ (length
+ (encode-coding-string
+ (substring decoded-substring 0 count)
+ 'binary)))
(setq temp 0)
- (setq funny (+ count i)))
+ (setq funny (+ count-bytes i)))
((or (not (or term-pager-count
term-scroll-with-delete))
(> (term-handle-scroll 1) 0))
(term-adjust-current-row-cache 1)
(setq count (min count term-width))
- (setq funny (+ count i))
+ (setq count-bytes
+ (length
+ (encode-coding-string
+ (substring decoded-substring 0 count)
+ 'binary)))
+ (setq funny (+ count-bytes i))
(setq term-start-line-column
term-current-column))
(t ;; Doing PAGER processing.
;; following point if not eob nor insert-mode.
(let ((old-column (current-column))
columns pos)
- (insert (decode-coding-string (substring str i funny) locale-coding-system))
+ (insert decoded-substring)
(setq term-current-column (current-column)
columns (- term-current-column old-column))
(when (not (or (eobp) term-insert-mode))
(forward-line (- term-buffer-maximum-size))
(beginning-of-line)
(delete-region (point-min) (point))))
- (set-marker save-marker nil)))))
+ (set-marker save-marker nil)))
+ ;; This might be expensive, but we need it to handle something
+ ;; like `sleep 5 | less -c' in more-or-less real time.
+ (when (get-buffer-window (current-buffer))
+ (redisplay))))
(defun term-handle-deferred-scroll ()
(let ((count (- (term-current-row) term-height)))
(switch-to-buffer term-ansi-buffer-name))
\f
+;;; Serial terminals
+;;; ===========================================================================
+(defun serial-port-is-file-p ()
+ "Guess whether serial ports are files on this system.
+Return t if this is a Unix-based system, where serial ports are
+files, such as /dev/ttyS0.
+Return nil if this is Windows or DOS, where serial ports have
+special identifiers such as COM1."
+ (not (member system-type (list 'windows-nt 'cygwin 'ms-dos))))
+
+(defvar serial-name-history
+ (if (serial-port-is-file-p)
+ (or (when (file-exists-p "/dev/ttys0") (list "/dev/ttys0"))
+ (when (file-exists-p "/dev/ttyS0") (list "/dev/ttyS0")))
+ (list "COM1"))
+ "History of serial ports used by `serial-read-name'.")
+
+(defvar serial-speed-history
+ ;; Initialised with reasonable values for newbies.
+ (list "9600" ;; Given twice because 9600 b/s is the most common speed
+ "1200" "2400" "4800" "9600" "14400" "19200"
+ "28800" "38400" "57600" "115200")
+ "History of serial port speeds used by `serial-read-speed'.")
+
+(defun serial-nice-speed-history ()
+ "Return `serial-speed-history' cleaned up for a mouse-menu."
+ (let ((x) (y))
+ (setq x
+ (sort
+ (copy-sequence serial-speed-history)
+ '(lambda (a b) (when (and (stringp a) (stringp b))
+ (> (string-to-number a) (string-to-number b))))))
+ (dolist (i x) (when (not (equal i (car y))) (push i y)))
+ y))
+
+(defconst serial-no-speed "nil"
+ "String for `serial-read-speed' for special serial ports.
+If `serial-read-speed' reads this string from the user, it
+returns nil, which is recognized by `serial-process-configure'
+for special serial ports that cannot be configured.")
+
+(defun serial-supported-or-barf ()
+ "Signal an error if serial processes are not supported"
+ (unless (fboundp 'make-serial-process)
+ (error "Serial processes are not supported on this system")))
+
+(defun serial-read-name ()
+ "Read a serial port name from the user.
+Try to be nice by providing useful defaults and history.
+On Windows, prepend \\.\ to the port name unless it already
+contains a backslash. This handles the legacy ports COM1-COM9 as
+well as the newer ports COM10 and higher."
+ (serial-supported-or-barf)
+ (let* ((file-name-history serial-name-history)
+ (h (car file-name-history))
+ (x (if (serial-port-is-file-p)
+ (read-file-name
+ ;; `prompt': The most recently used port is provided as
+ ;; the default value, which is used when the user
+ ;; simply presses return.
+ (if (stringp h) (format "Serial port (default %s): " h)
+ "Serial port: ")
+ ;; `directory': Most systems have their serial ports
+ ;; in the same directory, so start in the directory
+ ;; of the most recently used port, or in a reasonable
+ ;; default directory.
+ (or (and h (file-name-directory h))
+ (and (file-exists-p "/dev/") "/dev/")
+ (and (file-exists-p "/") "/"))
+ ;; `default': This causes (read-file-name) to return
+ ;; the empty string if he user simply presses return.
+ ;; Using nil here may result in a default directory
+ ;; of the current buffer, which is not useful for
+ ;; serial port.
+ "")
+ (read-from-minibuffer
+ (if (stringp h) (format "Serial port (default %s): " h)
+ "Serial port: ")
+ nil nil nil '(file-name-history . 1) nil nil))))
+ (if (or (null x) (and (stringp x) (zerop (length x))))
+ (setq x h)
+ (setq serial-name-history file-name-history))
+ (when (or (null x) (and (stringp x) (zerop (length x))))
+ (error "No serial port selected"))
+ (when (and (not (serial-port-is-file-p))
+ (not (string-match "\\\\" x)))
+ (set 'x (concat "\\\\.\\" x)))
+ x))
+
+(defun serial-read-speed ()
+ "Read a serial port speed (in bits per second) from the user.
+Try to be nice by providing useful defaults and history."
+ (serial-supported-or-barf)
+ (let* ((history serial-speed-history)
+ (h (car history))
+ (x (read-from-minibuffer
+ (cond ((string= h serial-no-speed)
+ "Speed (default nil = set by port): ")
+ (h
+ (format "Speed (default %s b/s): " h))
+ (t
+ (format "Speed (b/s): ")))
+ nil nil nil '(history . 1) nil nil)))
+ (when (or (null x) (and (stringp x) (zerop (length x))))
+ (setq x h))
+ (when (or (null x) (not (stringp x)) (zerop (length x)))
+ (error "Invalid speed"))
+ (if (string= x serial-no-speed)
+ (setq x nil)
+ (setq x (string-to-number x))
+ (when (or (null x) (not (integerp x)) (<= x 0))
+ (error "Invalid speed")))
+ (setq serial-speed-history history)
+ x))
+
+;;;###autoload
+(defun serial-term (port speed)
+ "Start a terminal-emulator for a serial port in a new buffer.
+PORT is the path or name of the serial port. For example, this
+could be \"/dev/ttyS0\" on Unix. On Windows, this could be
+\"COM1\" or \"\\\\.\\COM10\".
+SPEED is the speed of the serial port in bits per second. 9600
+is a common value. SPEED can be nil, see
+`serial-process-configure' for details.
+The buffer is in Term mode; see `term-mode' for the commands to
+use in that buffer.
+\\<term-raw-map>Type \\[switch-to-buffer] to switch to another buffer."
+ (interactive (list (serial-read-name) (serial-read-speed)))
+ (serial-supported-or-barf)
+ (let* ((process (make-serial-process
+ :port port
+ :speed speed
+ :coding 'no-conversion
+ :noquery t))
+ (buffer (process-buffer process)))
+ (save-excursion
+ (set-buffer buffer)
+ (term-mode)
+ (term-char-mode)
+ (goto-char (point-max))
+ (set-marker (process-mark process) (point))
+ (set-process-filter process 'term-emulate-terminal)
+ (set-process-sentinel process 'term-sentinel))
+ (switch-to-buffer buffer)
+ buffer))
+
+(defvar serial-mode-line-speed-menu nil)
+(defvar serial-mode-line-config-menu nil)
+
+(defun serial-speed ()
+ "Return the speed of the serial port of the current buffer's process.
+The return value may be nil for a special serial port."
+ (process-contact (get-buffer-process (current-buffer)) :speed))
+
+(defun serial-mode-line-speed-menu-1 (event)
+ (interactive "e")
+ (save-selected-window
+ (select-window (posn-window (event-start event)))
+ (serial-update-speed-menu)
+ (let* ((selection (serial-mode-line-speed-menu event))
+ (binding (and selection (lookup-key serial-mode-line-speed-menu
+ (vector (car selection))))))
+ (when binding (call-interactively binding)))))
+
+(defun serial-mode-line-speed-menu (event)
+ (x-popup-menu event serial-mode-line-speed-menu))
+
+(defun serial-update-speed-menu ()
+ (setq serial-mode-line-speed-menu (make-sparse-keymap "Speed (b/s)"))
+ (define-key serial-mode-line-speed-menu [serial-mode-line-speed-menu-other]
+ '(menu-item "Other..."
+ (lambda (event) (interactive "e")
+ (let ((speed (serial-read-speed)))
+ (serial-process-configure :speed speed)
+ (term-update-mode-line)
+ (message "Speed set to %d b/s" speed)))))
+ (dolist (str (serial-nice-speed-history))
+ (let ((num (or (and (stringp str) (string-to-number str)) 0)))
+ (define-key
+ serial-mode-line-speed-menu
+ (vector (make-symbol (format "serial-mode-line-speed-menu-%s" str)))
+ `(menu-item
+ ,str
+ (lambda (event) (interactive "e")
+ (serial-process-configure :speed ,num)
+ (term-update-mode-line)
+ (message "Speed set to %d b/s" ,num))
+ :button (:toggle . (= (serial-speed) ,num)))))))
+
+(defun serial-mode-line-config-menu-1 (event)
+ (interactive "e")
+ (save-selected-window
+ (select-window (posn-window (event-start event)))
+ (serial-update-config-menu)
+ (let* ((selection (serial-mode-line-config-menu event))
+ (binding (and selection (lookup-key serial-mode-line-config-menu
+ (vector (car selection))))))
+ (when binding (call-interactively binding)))))
+
+(defun serial-mode-line-config-menu (event)
+ (x-popup-menu event serial-mode-line-config-menu))
+
+(defun serial-update-config-menu ()
+ (setq serial-mode-line-config-menu (make-sparse-keymap "Configuration"))
+ (let ((config (process-contact
+ (get-buffer-process (current-buffer)) t))
+ (y)
+ (str))
+ (dolist (y '((:flowcontrol hw "Hardware flowcontrol (RTS/CTS)")
+ (:flowcontrol sw "Software flowcontrol (XON/XOFF)")
+ (:flowcontrol nil "No flowcontrol")
+ (:stopbits 2 "2 stopbits")
+ (:stopbits 1 "1 stopbit")
+ (:parity odd "Odd parity")
+ (:parity even "Even parity")
+ (:parity nil "No parity")
+ (:bytesize 7 "7 bits per byte")
+ (:bytesize 8 "8 bits per byte")))
+ (define-key serial-mode-line-config-menu
+ (vector (make-symbol (format "%s-%s" (nth 0 y) (nth 1 y))))
+ `(menu-item
+ ,(nth 2 y)
+ (lambda (event) (interactive "e")
+ (serial-process-configure ,(nth 0 y) ',(nth 1 y))
+ (term-update-mode-line)
+ (message "%s" ,(nth 2 y)))
+ ;; Use :toggle instead of :radio because a non-standard port
+ ;; configuration may not match any menu items.
+ :button (:toggle . ,(equal (plist-get config (nth 0 y))
+ (nth 1 y))))))))
+
+\f
;;; Converting process modes to use term mode
;;; ===========================================================================
;;; Renaming variables
\f
(provide 'term)
-;;; arch-tag: eee16bc8-2cd7-4147-9534-a5694752f716
+;; arch-tag: eee16bc8-2cd7-4147-9534-a5694752f716
;;; term.el ends here