(defconst term-protocol-version "0.96")
(eval-when-compile
(require 'ange-ftp))
(require 'ring)
(require 'ehelp)
(defgroup term nil
"General command interpreter in a window."
:group 'processes
:group 'unix)
(defvar term-input-ring-size 32 "Size of input history ring.")
(defvar term-height) (defvar term-width) (defvar term-home-marker) (defvar term-saved-home-marker nil) (defvar term-start-line-column 0) (defvar term-current-column 0) (defvar term-current-row 0) (defvar term-insert-mode nil)
(defvar term-vertical-motion)
(defvar term-terminal-state 0) (defvar term-kill-echo-list nil) (defvar term-terminal-parameter)
(defvar term-terminal-previous-parameter)
(defvar term-current-face 'default)
(defvar term-scroll-start 0) (defvar term-scroll-end) (defvar term-pager-count nil) (defvar term-saved-cursor nil)
(defvar term-command-hook)
(defvar term-log-buffer nil)
(defvar term-scroll-with-delete nil) (defvar term-pending-delete-marker) (defvar term-old-mode-map nil) (defvar term-old-mode-line-format) (defvar term-pager-old-local-map nil) (defvar term-pager-old-filter)
(defcustom explicit-shell-file-name nil
"*If non-nil, is file name to use for explicitly requested inferior shell."
:type '(choice (const nil) file)
:group 'term)
(defvar term-prompt-regexp "^"
"Regexp to recognize prompts in the inferior process.
Defaults to \"^\", the null string at BOL.
Good choices:
Canonical Lisp: \"^[^> \\n]*>+:? *\" (Lucid, franz, kcl, T, cscheme, oaklisp)
Lucid Common Lisp: \"^\\\\(>\\\\|\\\\(->\\\\)+\\\\) *\"
franz: \"^\\\\(->\\\\|<[0-9]*>:\\\\) *\"
kcl: \"^>+ *\"
shell: \"^[^#$%>\\n]*[#$%>] *\"
T: \"^>+ *\"
This is a good thing to set in mode hooks.")
(defvar term-delimiter-argument-list ()
"List of characters to recognize as separate arguments in input.
Strings comprising a character in this list will separate the arguments
surrounding them, and also be regarded as arguments in their own right (unlike
whitespace). See `term-arguments'.
Defaults to the empty list.
For shells, a good value is (?\\| ?& ?< ?> ?\\( ?\\) ?\\;).
This is a good thing to set in mode hooks.")
(defcustom term-input-autoexpand nil
"*If non-nil, expand input command history references on completion.
This mirrors the optional behavior of tcsh (its autoexpand and histlit).
If the value is `input', then the expansion is seen on input.
If the value is `history', then the expansion is only when inserting
into the buffer's input ring. See also `term-magic-space' and
`term-dynamic-complete'.
This variable is buffer-local."
:type '(choice (const nil) (const t) (const input) (const history))
:group 'term)
(defcustom term-input-ignoredups nil
"*If non-nil, don't add input matching the last on the input ring.
This mirrors the optional behavior of bash.
This variable is buffer-local."
:type 'boolean
:group 'term)
(defcustom term-input-ring-file-name nil
"*If non-nil, name of the file to read/write input history.
See also `term-read-input-ring' and `term-write-input-ring'.
This variable is buffer-local, and is a good thing to set in mode hooks."
:type 'boolean
:group 'term)
(defcustom term-scroll-to-bottom-on-output nil
"*Controls whether interpreter output causes window to scroll.
If nil, then do not scroll. If t or `all', scroll all windows showing buffer.
If `this', scroll only the selected window.
If `others', scroll only those that are not the selected window.
The default is nil.
See variable `term-scroll-show-maximum-output'.
This variable is buffer-local."
:type 'boolean
:group 'term)
(defcustom term-scroll-show-maximum-output nil
"*Controls how interpreter output causes window to scroll.
If non-nil, then show the maximum output when the window is scrolled.
See variable `term-scroll-to-bottom-on-output'.
This variable is buffer-local."
:type 'boolean
:group 'term)
(defvar term-pending-frame nil)
(defvar term-get-old-input (function term-get-old-input-default)
"Function that submits old text in term mode.
This function is called when return is typed while the point is in old text.
It returns the text to be submitted as process input. The default is
`term-get-old-input-default', which grabs the current line, and strips off
leading text matching `term-prompt-regexp'.")
(defvar term-dynamic-complete-functions
'(term-replace-by-expanded-history term-dynamic-complete-filename)
"List of functions called to perform completion.
Functions should return non-nil if completion was performed.
See also `term-dynamic-complete'.
This is a good thing to set in mode hooks.")
(defvar term-input-filter
(function (lambda (str) (not (string-match "\\`\\s *\\'" str))))
"Predicate for filtering additions to input history.
Only inputs answering true to this function are saved on the input
history list. Default is to save anything that isn't all whitespace.")
(defvar term-input-filter-functions '()
"Functions to call before input is sent to the process.
These functions get one argument, a string containing the text to send.
This variable is buffer-local.")
(defvar term-input-sender (function term-simple-send)
"Function to actually send to PROCESS the STRING submitted by user.
Usually this is just `term-simple-send', but if your mode needs to
massage the input string, this is your hook. This is called from
the user command `term-send-input'. `term-simple-send' just sends
the string plus a newline.")
(defcustom term-eol-on-send t
"*Non-nil means go to the end of the line before sending input.
See `term-send-input'."
:type 'boolean
:group 'term)
(defcustom term-mode-hook '()
"Called upon entry into term mode.
This is run before the process is cranked up."
:type 'hook
:group 'term)
(defcustom term-exec-hook '()
"Called each time a process is exec'd by `term-exec'.
This is called after the process is cranked up. It is useful for things that
must be done each time a process is executed in a term mode buffer (e.g.,
`process-kill-without-query'). In contrast, `term-mode-hook' is only
executed once when the buffer is created."
:type 'hook
:group 'term)
(defvar term-mode-map nil)
(defvar term-raw-map nil
"Keyboard map for sending characters directly to the inferior process.")
(defvar term-escape-char nil
"Escape character for char sub-mode of term mode.
Do not change it directly; use `term-set-escape-char' instead.")
(defvar term-raw-escape-map nil)
(defvar term-pager-break-map nil)
(defvar term-ptyp t
"True if communications via pty; false if by pipe. Buffer local.
This is to work around a bug in Emacs process signaling.")
(defvar term-last-input-match ""
"Last string searched for by term input history search, for defaulting.
Buffer local variable.")
(defvar term-input-ring nil)
(defvar term-last-input-start)
(defvar term-last-input-end)
(defvar term-input-ring-index nil
"Index of last matched history element.")
(defvar term-matching-input-from-input-string ""
"Input previously used to match input history.")
(defvar term-pager-filter t)
(put 'term-replace-by-expanded-history 'menu-enable 'term-input-autoexpand)
(put 'term-input-ring 'permanent-local t)
(put 'term-input-ring-index 'permanent-local t)
(put 'term-input-autoexpand 'permanent-local t)
(put 'term-input-filter-functions 'permanent-local t)
(put 'term-scroll-to-bottom-on-output 'permanent-local t)
(put 'term-scroll-show-maximum-output 'permanent-local t)
(put 'term-ptyp 'permanent-local t)
(defmacro term-in-char-mode () '(eq (current-local-map) term-raw-map))
(defmacro term-in-line-mode () '(not (term-in-char-mode)))
(defmacro term-pager-enabled () 'term-pager-count)
(defmacro term-handling-pager () 'term-pager-old-local-map)
(defmacro term-using-alternate-sub-buffer () 'term-saved-home-marker)
(defvar term-signals-menu)
(defvar term-terminal-menu)
(defvar term-ansi-at-host nil)
(defvar term-ansi-at-dir nil)
(defvar term-ansi-at-user nil)
(defvar term-ansi-at-message nil)
(defvar term-ansi-at-save-user nil)
(defvar term-ansi-at-save-pwd nil)
(defvar term-ansi-at-save-anon nil)
(defvar term-ansi-current-bold nil)
(defvar term-ansi-current-color 0)
(defvar term-ansi-face-already-done nil)
(defvar term-ansi-current-bg-color 0)
(defvar term-ansi-current-underline nil)
(defvar term-ansi-current-reverse nil)
(defvar term-ansi-current-invisible nil)
(defvar term-terminal-more-parameters 0)
(defvar term-terminal-previous-parameter-2 -1)
(defvar term-terminal-previous-parameter-3 -1)
(defvar term-terminal-previous-parameter-4 -1)
(defcustom term-default-fg-color 'unspecified
"Default color for foreground in `term'."
:group 'term
:type 'string)
(defcustom term-default-bg-color 'unspecified
"Default color for background in `term'."
:group 'term
:type 'string)
(defvar ansi-term-color-vector
[unspecified "black" "red3" "green3" "yellow3" "blue2"
"magenta3" "cyan3" "white"])
(defvar term-buffer-maximum-size 2048
"*The maximum size in lines for term buffers.
Term buffers are truncated from the top to be no greater than this number.
Notice that a setting of 0 means \"don't truncate anything\". This variable
is buffer-local.")
(when (featurep 'xemacs)
(defvar term-terminal-menu
'("Terminal"
[ "Character mode" term-char-mode (term-in-line-mode)]
[ "Line mode" term-line-mode (term-in-char-mode)]
[ "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)
)
(unless (featurep 'xemacs)
(let (newmap)
(setq newmap (make-sparse-keymap "Terminal"))
(define-key newmap [terminal-pager-enable]
'("Enable paging" . term-fake-pager-enable))
(define-key newmap [terminal-pager-disable]
'("Disable paging" . term-fake-pager-disable))
(define-key newmap [terminal-char-mode]
'("Character mode" . term-char-mode))
(define-key newmap [terminal-line-mode]
'("Line mode" . term-line-mode))
(setq term-terminal-menu (cons "Terminal" newmap))
(defvar term-completion-menu (make-sparse-keymap "Complete"))
(define-key term-mode-map [menu-bar completion]
(cons "Complete" term-completion-menu))
(define-key term-completion-menu [complete-expand]
'("Expand File Name" . term-replace-by-expanded-filename))
(define-key term-completion-menu [complete-listing]
'("File Completion Listing" . term-dynamic-list-filename-completions))
(define-key term-completion-menu [menu-bar completion complete-file]
'("Complete File Name" . term-dynamic-complete-filename))
(define-key term-completion-menu [menu-bar completion complete]
'("Complete Before Point" . term-dynamic-complete))
(defvar term-inout-menu (make-sparse-keymap "In/Out"))
(define-key term-mode-map [menu-bar inout]
(cons "In/Out" term-inout-menu))
(define-key term-inout-menu [kill-output]
'("Kill Current Output Group" . term-kill-output))
(define-key term-inout-menu [next-prompt]
'("Forward Output Group" . term-next-prompt))
(define-key term-inout-menu [previous-prompt]
'("Backward Output Group" . term-previous-prompt))
(define-key term-inout-menu [show-maximum-output]
'("Show Maximum Output" . term-show-maximum-output))
(define-key term-inout-menu [show-output]
'("Show Current Output Group" . term-show-output))
(define-key term-inout-menu [kill-input]
'("Kill Current Input" . term-kill-input))
(define-key term-inout-menu [copy-input]
'("Copy Old Input" . term-copy-old-input))
(define-key term-inout-menu [forward-matching-history]
'("Forward Matching Input..." . term-forward-matching-input))
(define-key term-inout-menu [backward-matching-history]
'("Backward Matching Input..." . term-backward-matching-input))
(define-key term-inout-menu [next-matching-history]
'("Next Matching Input..." . term-next-matching-input))
(define-key term-inout-menu [previous-matching-history]
'("Previous Matching Input..." . term-previous-matching-input))
(define-key term-inout-menu [next-matching-history-from-input]
'("Next Matching Current Input" . term-next-matching-input-from-input))
(define-key term-inout-menu [previous-matching-history-from-input]
'("Previous Matching Current Input" .
term-previous-matching-input-from-input))
(define-key term-inout-menu [next-history]
'("Next Input" . term-next-input))
(define-key term-inout-menu [previous-history]
'("Previous Input" . term-previous-input))
(define-key term-inout-menu [list-history]
'("List Input History" . term-dynamic-list-input-ring))
(define-key term-inout-menu [expand-history]
'("Expand History Before Point" . term-replace-by-expanded-history))
(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)))
))
(defun term-set-escape-char (c)
"Change `term-escape-char' and keymaps that depend on it."
(when term-escape-char
(define-key term-raw-map term-escape-char 'term-send-raw))
(setq c (make-string 1 c))
(define-key term-raw-map c term-raw-escape-map)
(define-key term-raw-escape-map "\C-v"
(lookup-key (current-global-map) "\C-v"))
(define-key term-raw-escape-map "\C-u"
(lookup-key (current-global-map) "\C-u"))
(define-key term-raw-escape-map c 'term-send-raw)
(define-key term-raw-escape-map "\C-q" 'term-pager-toggle)
(define-key term-raw-escape-map "\C-k" 'term-char-mode)
(define-key term-raw-escape-map "\C-j" 'term-line-mode)
(define-key term-raw-escape-map [?\M-x] 'execute-extended-command))
(let* ((map (make-keymap))
(esc-map (make-keymap))
(i 0))
(while (< i 128)
(define-key map (make-string 1 i) 'term-send-raw)
(unless (or (eq i ?O) (eq i 91))
(define-key esc-map (make-string 1 i) 'term-send-raw-meta))
(setq i (1+ i)))
(dolist (elm (generic-character-list))
(define-key map (vector elm) 'term-send-raw))
(define-key map "\e" esc-map)
(setq term-raw-map map)
(setq term-raw-escape-map
(copy-keymap (lookup-key (current-global-map) "\C-x")))
(if (featurep 'xemacs)
(define-key term-raw-map [button2] 'term-mouse-paste)
(define-key term-raw-map [mouse-2] 'term-mouse-paste)
(define-key term-raw-map [menu-bar terminal] term-terminal-menu)
(define-key term-raw-map [menu-bar signals] term-signals-menu))
(define-key term-raw-map [up] 'term-send-up)
(define-key term-raw-map [down] 'term-send-down)
(define-key term-raw-map [right] 'term-send-right)
(define-key term-raw-map [left] 'term-send-left)
(define-key term-raw-map [delete] 'term-send-del)
(define-key term-raw-map [deletechar] 'term-send-del)
(define-key term-raw-map [backspace] 'term-send-backspace)
(define-key term-raw-map [home] 'term-send-home)
(define-key term-raw-map [end] 'term-send-end)
(define-key term-raw-map [insert] 'term-send-insert)
(define-key term-raw-map [S-prior] 'scroll-down)
(define-key term-raw-map [S-next] 'scroll-up)
(define-key term-raw-map [S-insert] 'term-paste)
(define-key term-raw-map [prior] 'term-send-prior)
(define-key term-raw-map [next] 'term-send-next))
(term-set-escape-char ?\C-c)
(defun term-window-width ()
(if (featurep 'xemacs)
(1- (window-width))
(if (and window-system overflow-newline-into-fringe)
(window-width)
(1- (window-width)))))
(put 'term-mode 'mode-class 'special)
(defvar term-display-table
(let ((dt (or (copy-sequence standard-display-table)
(make-display-table)))
i)
(setq i 0)
(while (< i 10)
(aset dt i (vector i))
(setq i (1+ i)))
(setq i 11)
(while (< i 32)
(aset dt i (vector i))
(setq i (1+ i)))
(setq i 128)
(while (< i 256)
(aset dt i (vector i))
(setq i (1+ i)))
dt))
(defun term-mode ()
"Major mode for interacting with an inferior interpreter.
The interpreter name is same as buffer name, sans the asterisks.
There are two submodes: line mode and char mode. By default, you are
in char mode. In char sub-mode, each character (except
`term-escape-char') is sent immediately to the subprocess.
The escape character is equivalent to the usual meaning of C-x.
In line mode, you send a line of input at a time; use
\\[term-send-input] to send.
In line mode, this maintains an input history of size
`term-input-ring-size', and you can access it with the commands
\\[term-next-input], \\[term-previous-input], and
\\[term-dynamic-list-input-ring]. Input ring history expansion can be
achieved with the commands \\[term-replace-by-expanded-history] or
\\[term-magic-space]. Input ring expansion is controlled by the
variable `term-input-autoexpand', and addition is controlled by the
variable `term-input-ignoredups'.
Input to, and output from, the subprocess can cause the window to scroll to
the end of the buffer. See variables `term-scroll-to-bottom-on-input',
and `term-scroll-to-bottom-on-output'.
If you accidentally suspend your process, use \\[term-continue-subjob]
to continue it.
This mode can be customized to create specific modes for running
particular subprocesses. This can be done by setting the hooks
`term-input-filter-functions', `term-input-filter',
`term-input-sender' and `term-get-old-input' to appropriate functions,
and the variable `term-prompt-regexp' to the appropriate regular
expression.
Commands in raw mode:
\\{term-raw-map}
Commands in line mode:
\\{term-mode-map}
Entry to this mode runs the hooks on `term-mode-hook'."
(interactive)
(kill-all-local-variables)
(setq major-mode 'term-mode)
(setq mode-name "Term")
(use-local-map term-mode-map)
(setq indent-tabs-mode nil)
(setq buffer-display-table term-display-table)
(make-local-variable 'term-home-marker)
(setq term-home-marker (copy-marker 0))
(make-local-variable 'term-saved-home-marker)
(make-local-variable 'term-height)
(make-local-variable 'term-width)
(setq term-width (term-window-width))
(setq term-height (1- (window-height)))
(make-local-variable 'term-terminal-parameter)
(make-local-variable 'term-saved-cursor)
(make-local-variable 'term-last-input-start)
(setq term-last-input-start (make-marker))
(make-local-variable 'term-last-input-end)
(setq term-last-input-end (make-marker))
(make-local-variable 'term-last-input-match)
(setq term-last-input-match "")
(make-local-variable 'term-prompt-regexp) (make-local-variable 'term-input-ring-size) (make-local-variable 'term-input-ring)
(make-local-variable 'term-input-ring-file-name)
(or (and (boundp 'term-input-ring) term-input-ring)
(setq term-input-ring (make-ring term-input-ring-size)))
(make-local-variable 'term-input-ring-index)
(or (and (boundp 'term-input-ring-index) term-input-ring-index)
(setq term-input-ring-index nil))
(make-local-variable 'term-command-hook)
(setq term-command-hook (symbol-function 'term-command-hook))
(make-local-variable 'term-ansi-at-host)
(setq term-ansi-at-host (system-name))
(make-local-variable 'term-ansi-at-dir)
(setq term-ansi-at-dir default-directory)
(make-local-variable 'term-ansi-at-message)
(setq term-ansi-at-message nil)
(make-local-variable 'ange-ftp-default-user)
(make-local-variable 'ange-ftp-default-password)
(make-local-variable 'ange-ftp-generate-anonymous-password)
(make-local-variable 'term-buffer-maximum-size)
(make-local-variable 'term-ansi-current-bold)
(make-local-variable 'term-ansi-current-color)
(make-local-variable 'term-ansi-face-already-done)
(make-local-variable 'term-ansi-current-bg-color)
(make-local-variable 'term-ansi-current-underline)
(make-local-variable 'term-ansi-current-reverse)
(make-local-variable 'term-ansi-current-invisible)
(make-local-variable 'term-terminal-parameter)
(make-local-variable 'term-terminal-previous-parameter)
(make-local-variable 'term-terminal-previous-parameter-2)
(make-local-variable 'term-terminal-previous-parameter-3)
(make-local-variable 'term-terminal-previous-parameter-4)
(make-local-variable 'term-terminal-more-parameters)
(make-local-variable 'term-terminal-state)
(make-local-variable 'term-kill-echo-list)
(make-local-variable 'term-start-line-column)
(make-local-variable 'term-current-column)
(make-local-variable 'term-current-row)
(make-local-variable 'term-log-buffer)
(make-local-variable 'term-scroll-start)
(make-local-variable 'term-scroll-end)
(setq term-scroll-end term-height)
(make-local-variable 'term-scroll-with-delete)
(make-local-variable 'term-pager-count)
(make-local-variable 'term-pager-old-local-map)
(make-local-variable 'term-old-mode-map)
(make-local-variable 'term-insert-mode)
(make-local-variable 'term-dynamic-complete-functions)
(make-local-variable 'term-completion-fignore)
(make-local-variable 'term-get-old-input)
(make-local-variable 'term-matching-input-from-input-string)
(make-local-variable 'term-input-autoexpand)
(make-local-variable 'term-input-ignoredups)
(make-local-variable 'term-delimiter-argument-list)
(make-local-variable 'term-input-filter-functions)
(make-local-variable 'term-input-filter)
(make-local-variable 'term-input-sender)
(make-local-variable 'term-eol-on-send)
(make-local-variable 'term-scroll-to-bottom-on-output)
(make-local-variable 'term-scroll-show-maximum-output)
(make-local-variable 'term-ptyp)
(make-local-variable 'term-exec-hook)
(make-local-variable 'term-vertical-motion)
(make-local-variable 'term-pending-delete-marker)
(setq term-pending-delete-marker (make-marker))
(make-local-variable 'term-current-face)
(make-local-variable 'term-pending-frame)
(setq term-pending-frame nil)
(set (make-local-variable 'cua-mode) nil)
(run-mode-hooks 'term-mode-hook)
(when (featurep 'xemacs)
(set-buffer-menubar
(append current-menubar (list term-terminal-menu))))
(or term-input-ring
(setq term-input-ring (make-ring term-input-ring-size)))
(term-update-mode-line))
(defun term-reset-size (height width)
(setq term-height height)
(setq term-width width)
(setq term-start-line-column nil)
(setq term-current-row nil)
(setq term-current-column nil)
(term-set-scroll-region 0 height))
(defun term-check-kill-echo-list ()
(let ((cur term-kill-echo-list) (found nil) (save-point (point)))
(unwind-protect
(progn
(end-of-line)
(while cur
(let* ((str (car cur)) (len (length str)) (start (- (point) len)))
(if (and (>= start (point-min))
(string= str (buffer-substring start (point))))
(progn (delete-backward-char len)
(setq term-kill-echo-list (cdr cur))
(setq term-current-column nil)
(setq term-current-row nil)
(setq term-start-line-column nil)
(setq cur nil found t))
(setq cur (cdr cur))))))
(when (not found)
(goto-char save-point)))
found))
(defun term-check-size (process)
(when (or (/= term-height (1- (window-height)))
(/= term-width (term-window-width)))
(term-reset-size (1- (window-height)) (term-window-width))
(set-process-window-size process term-height term-width)))
(defun term-send-raw-string (chars)
(let ((proc (get-buffer-process (current-buffer))))
(if (not proc)
(error "Current buffer has no process")
(goto-char (process-mark proc))
(when (term-pager-enabled)
(setq term-pager-count (term-current-row)))
(process-send-string proc chars))))
(defun term-send-raw ()
"Send the last character typed through the terminal-emulator
without any interpretation."
(interactive)
(when (and (symbolp last-input-char)
(get last-input-char 'ascii-character))
(setq last-input-char (get last-input-char 'ascii-character)))
(term-send-raw-string (make-string 1 last-input-char)))
(defun term-send-raw-meta ()
(interactive)
(let ((char last-input-char))
(when (symbolp last-input-char)
(let ((tmp (get char 'event-symbol-elements)))
(when tmp
(setq char (car tmp)))
(when (symbolp char)
(setq tmp (get char 'ascii-character))
(when tmp
(setq char tmp)))))
(setq char (event-basic-type char))
(term-send-raw-string (if (and (numberp char)
(> char 127)
(< char 256))
(make-string 1 char)
(format "\e%c" char)))))
(defun term-mouse-paste (click arg)
"Insert the last stretch of killed text at the position clicked on."
(interactive "e\nP")
(if (featurep 'xemacs)
(term-send-raw-string
(or (condition-case () (x-get-selection) (error ()))
(x-get-cutbuffer)
(error "No selection or cut buffer available")))
(run-hooks 'mouse-leave-buffer-hook)
(setq this-command 'yank)
(mouse-set-point click)
(term-send-raw-string (current-kill (cond
((listp arg) 0)
((eq arg '-) -1)
(t (1- arg)))))))
(defun term-paste ()
"Insert the last stretch of killed text at point."
(interactive)
(term-send-raw-string (current-kill 0)))
(defun term-send-up () (interactive) (term-send-raw-string "\eOA"))
(defun term-send-down () (interactive) (term-send-raw-string "\eOB"))
(defun term-send-right () (interactive) (term-send-raw-string "\eOC"))
(defun term-send-left () (interactive) (term-send-raw-string "\eOD"))
(defun term-send-home () (interactive) (term-send-raw-string "\e[1~"))
(defun term-send-insert() (interactive) (term-send-raw-string "\e[2~"))
(defun term-send-end () (interactive) (term-send-raw-string "\e[4~"))
(defun term-send-prior () (interactive) (term-send-raw-string "\e[5~"))
(defun term-send-next () (interactive) (term-send-raw-string "\e[6~"))
(defun term-send-del () (interactive) (term-send-raw-string "\e[3~"))
(defun term-send-backspace () (interactive) (term-send-raw-string "\C-?"))
(defun term-char-mode ()
"Switch to char (\"raw\") sub-mode of term mode.
Each character you type is sent directly to the inferior without
intervention from Emacs, except for the escape character (usually C-c)."
(interactive)
(when (term-in-line-mode)
(setq term-old-mode-map (current-local-map))
(use-local-map term-raw-map)
(let ((pmark (process-mark (get-buffer-process (current-buffer))))
(save-input-sender term-input-sender))
(when (> (point) pmark)
(unwind-protect
(progn
(setq term-input-sender
(symbol-function 'term-send-string))
(end-of-line)
(term-send-input))
(setq term-input-sender save-input-sender))))
(term-update-mode-line)))
(defun term-line-mode ()
"Switch to line (\"cooked\") sub-mode of term mode.
This means that Emacs editing commands work as normally, until
you type \\[term-send-input] which sends the current line to the inferior."
(interactive)
(when (term-in-char-mode)
(use-local-map term-old-mode-map)
(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"))))
(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."
(let ((proc (get-buffer-process buffer)))
(and proc (memq (process-status proc) '(run stop)))))
(defun make-term (name program &optional startfile &rest switches)
"Make a term process NAME in a buffer, running PROGRAM.
The name of the buffer is made by surrounding NAME with `*'s.
If there is already a running process in that buffer, it is not restarted.
Optional third arg STARTFILE is the name of a file to send the contents of to
the process. Any more args are arguments to PROGRAM."
(let ((buffer (get-buffer-create (concat "*" name "*"))))
(cond ((not (term-check-proc buffer))
(save-excursion
(set-buffer buffer)
(term-mode)) (term-exec buffer name program startfile switches)))
buffer))
(defun term (program)
"Start a terminal-emulator in a new buffer.
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 (read-from-minibuffer "Run program: "
(or explicit-shell-file-name
(getenv "ESHELL")
(getenv "SHELL")
"/bin/sh"))))
(set-buffer (make-term "terminal" program))
(term-mode)
(term-char-mode)
(switch-to-buffer "*terminal*"))
(defun term-exec (buffer name command startfile switches)
"Start up a process in buffer for term modes.
Blasts any old process running in the buffer. Doesn't set the buffer mode.
You can use this to cheaply run a series of processes in the same term
buffer. The hook `term-exec-hook' is run after each exec."
(save-excursion
(set-buffer buffer)
(let ((proc (get-buffer-process buffer))) (when proc (delete-process proc)))
(let ((proc (term-exec-1 name buffer command switches)))
(make-local-variable 'term-ptyp)
(setq term-ptyp process-connection-type) (goto-char (point-max))
(set-marker (process-mark proc) (point))
(set-process-filter proc 'term-emulate-terminal)
(set-process-sentinel proc 'term-sentinel)
(cond (startfile
(sleep-for 1)
(goto-char (point-max))
(insert-file-contents startfile)
(setq startfile (buffer-substring (point) (point-max)))
(delete-region (point) (point-max))
(term-send-string proc startfile)))
(run-hooks 'term-exec-hook)
buffer)))
(defun term-sentinel (proc msg)
"Sentinel for term buffers.
The main purpose is to get rid of the local keymap."
(let ((buffer (process-buffer proc)))
(when (memq (process-status proc) '(signal exit))
(if (null (buffer-name buffer))
(set-process-buffer proc nil)
(let ((obuf (current-buffer)))
(unwind-protect
(progn
(set-buffer buffer)
(use-local-map nil)
(term-handle-exit (process-name proc)
msg)
(delete-process proc))
(set-buffer obuf)))
))))
(defun term-handle-exit (process-name msg)
"Write process exit (or other change) message MSG in the current buffer."
(let ((buffer-read-only nil)
(omax (point-max))
(opoint (point)))
(goto-char omax)
(insert ?\n "Process " process-name " " msg)
(force-mode-line-update)
(when (and opoint (< opoint omax))
(goto-char opoint))))
(defvar term-term-name "eterm-color")
(defvar term-termcap-format
"%s%s:li#%d:co#%d:cl=\\E[H\\E[J:cd=\\E[J:bs:am:xn:cm=\\E[%%i%%d;%%dH\
:nd=\\E[C:up=\\E[A:ce=\\E[K:ho=\\E[H:pt\
:al=\\E[L:dl=\\E[M:DL=\\E[%%dM:AL=\\E[%%dL:cs=\\E[%%i%%d;%%dr:sf=^J\
:dc=\\E[P:DC=\\E[%%dP:IC=\\E[%%d@:im=\\E[4h:ei=\\E[4l:mi:\
:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:md=\\E[1m:mr=\\E[7m:me=\\E[m\
:UP=\\E[%%dA:DO=\\E[%%dB:LE=\\E[%%dD:RI=\\E[%%dC\
:kl=\\EOD:kd=\\EOB:kr=\\EOC:ku=\\EOA:kN=\\E[6~:kP=\\E[5~:@7=\\E[4~:kh=\\E[1~\
:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#8:pa#64:AB=\\E[4%%dm:AF=\\E[3%%dm:cr=^M\
:bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E24m\
:kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:"
"Termcap capabilities supported.")
(defun term-exec-1 (name buffer command switches)
(let ((process-environment
(nconc
(list
(format "TERM=%s" term-term-name)
(format "TERMINFO=%s" data-directory)
(format term-termcap-format "TERMCAP="
term-term-name term-height term-width)
(format "EMACS=%s (term:%s)" emacs-version term-protocol-version)
(format "INSIDE_EMACS=%s,term:%s" emacs-version term-protocol-version)
(format "LINES=%d" term-height)
(format "COLUMNS=%d" term-width))
process-environment))
(process-connection-type t)
(inhibit-eol-conversion t)
(coding-system-for-read 'binary))
(apply 'start-process name buffer
"/bin/sh" "-c"
(format "stty -nl echo rows %d columns %d sane 2>/dev/null;\
if [ $1 = .. ]; then shift; fi; exec \"$@\""
term-height term-width)
".."
command switches)))
(defun term-read-input-ring (&optional silent)
"Sets the buffer's `term-input-ring' from a history file.
The name of the file is given by the variable `term-input-ring-file-name'.
The history ring is of size `term-input-ring-size', regardless of file size.
If `term-input-ring-file-name' is nil this function does nothing.
If the optional argument SILENT is non-nil, we say nothing about a
failure to read the history file.
This function is useful for major mode commands and mode hooks.
The structure of the history file should be one input command per line,
with the most recent command last.
See also `term-input-ignoredups' and `term-write-input-ring'."
(cond ((or (null term-input-ring-file-name)
(equal term-input-ring-file-name ""))
nil)
((not (file-readable-p term-input-ring-file-name))
(or silent
(message "Cannot read history file %s"
term-input-ring-file-name)))
(t
(let ((history-buf (get-buffer-create " *temp*"))
(file term-input-ring-file-name)
(count 0)
(ring (make-ring term-input-ring-size)))
(unwind-protect
(save-excursion
(set-buffer history-buf)
(widen)
(erase-buffer)
(insert-file-contents file)
(goto-char (point-max))
(while (and (< count term-input-ring-size)
(re-search-backward "^[ \t]*\\([^#\n].*\\)[ \t]*$"
nil t))
(let ((history (buffer-substring (match-beginning 1)
(match-end 1))))
(when (or (null term-input-ignoredups)
(ring-empty-p ring)
(not (string-equal (ring-ref ring 0) history)))
(ring-insert-at-beginning ring history)))
(setq count (1+ count))))
(kill-buffer history-buf))
(setq term-input-ring ring
term-input-ring-index nil)))))
(defun term-write-input-ring ()
"Writes the buffer's `term-input-ring' to a history file.
The name of the file is given by the variable `term-input-ring-file-name'.
The original contents of the file are lost if `term-input-ring' is not empty.
If `term-input-ring-file-name' is nil this function does nothing.
Useful within process sentinels.
See also `term-read-input-ring'."
(cond ((or (null term-input-ring-file-name)
(equal term-input-ring-file-name "")
(null term-input-ring) (ring-empty-p term-input-ring))
nil)
((not (file-writable-p term-input-ring-file-name))
(message "Cannot write history file %s" term-input-ring-file-name))
(t
(let* ((history-buf (get-buffer-create " *Temp Input History*"))
(ring term-input-ring)
(file term-input-ring-file-name)
(index (ring-length ring)))
(save-excursion
(set-buffer history-buf)
(erase-buffer)
(while (> index 0)
(setq index (1- index))
(insert (ring-ref ring index) ?\n))
(write-region (buffer-string) nil file nil 'no-message)
(kill-buffer nil))))))
(defun term-dynamic-list-input-ring ()
"List in help buffer the buffer's input history."
(interactive)
(if (or (not (ring-p term-input-ring))
(ring-empty-p term-input-ring))
(message "No history")
(let ((history nil)
(history-buffer " *Input History*")
(index (1- (ring-length term-input-ring)))
(conf (current-window-configuration)))
(while (>= index 0)
(setq history (cons (ring-ref term-input-ring index) history)
index (1- index)))
(with-output-to-temp-buffer history-buffer
(display-completion-list history)
(set-buffer history-buffer)
(forward-line 3)
(while (search-backward "completion" nil 'move)
(replace-match "history reference")))
(sit-for 0)
(message "Hit space to flush")
(let ((ch (read-event)))
(if (eq ch ?\s)
(set-window-configuration conf)
(setq unread-command-events (list ch)))))))
(defun term-regexp-arg (prompt)
(let* ( (last-command last-command)
(regexp (read-from-minibuffer prompt nil nil nil
'minibuffer-history-search-history)))
(list (if (string-equal regexp "")
(setcar minibuffer-history-search-history
(nth 1 minibuffer-history-search-history))
regexp)
(prefix-numeric-value current-prefix-arg))))
(defun term-search-arg (arg)
(cond ((not (term-after-pmark-p))
(error "Not at command line"))
((or (null term-input-ring)
(ring-empty-p term-input-ring))
(error "Empty input ring"))
((zerop arg)
(setq term-input-ring-index nil)
1)
(t
arg)))
(defun term-search-start (arg)
(if term-input-ring-index
(mod (+ term-input-ring-index (if (> arg 0) 1 -1))
(ring-length term-input-ring))
(if (>= arg 0)
0 (1- (ring-length term-input-ring)))))
(defun term-previous-input-string (arg)
"Return the string ARG places along the input ring.
Moves relative to `term-input-ring-index'."
(ring-ref term-input-ring (if term-input-ring-index
(mod (+ arg term-input-ring-index)
(ring-length term-input-ring))
arg)))
(defun term-previous-input (arg)
"Cycle backwards through input history."
(interactive "*p")
(term-previous-matching-input "." arg))
(defun term-next-input (arg)
"Cycle forwards through input history."
(interactive "*p")
(term-previous-input (- arg)))
(defun term-previous-matching-input-string (regexp arg)
"Return the string matching REGEXP ARG places along the input ring.
Moves relative to `term-input-ring-index'."
(let* ((pos (term-previous-matching-input-string-position regexp arg)))
(when pos (ring-ref term-input-ring pos))))
(defun term-previous-matching-input-string-position
(regexp arg &optional start)
"Return the index matching REGEXP ARG places along the input ring.
Moves relative to START, or `term-input-ring-index'."
(when (or (not (ring-p term-input-ring))
(ring-empty-p term-input-ring))
(error "No history"))
(let* ((len (ring-length term-input-ring))
(motion (if (> arg 0) 1 -1))
(n (mod (- (or start (term-search-start arg)) motion) len))
(tried-each-ring-item nil)
(prev nil))
(while (and (/= arg 0) (not tried-each-ring-item))
(setq prev n
n (mod (+ n motion) len))
(while (and (< n len) (not tried-each-ring-item)
(not (string-match regexp (ring-ref term-input-ring n))))
(setq n (mod (+ n motion) len)
tried-each-ring-item (= n prev)))
(setq arg (if (> arg 0) (1- arg) (1+ arg))))
(when (string-match regexp (ring-ref term-input-ring n))
n)))
(defun term-previous-matching-input (regexp arg)
"Search backwards through input history for match for REGEXP.
\(Previous history elements are earlier commands.)
With prefix argument N, search for Nth previous match.
If N is negative, find the next or Nth next match."
(interactive (term-regexp-arg "Previous input matching (regexp): "))
(setq arg (term-search-arg arg))
(let ((pos (term-previous-matching-input-string-position regexp arg)))
(if (null pos)
(error "Not found")
(setq term-input-ring-index pos)
(message "History item: %d" (1+ pos))
(delete-region
(process-mark (get-buffer-process (current-buffer))) (point))
(insert (ring-ref term-input-ring pos)))))
(defun term-next-matching-input (regexp arg)
"Search forwards through input history for match for REGEXP.
\(Later history elements are more recent commands.)
With prefix argument N, search for Nth following match.
If N is negative, find the previous or Nth previous match."
(interactive (term-regexp-arg "Next input matching (regexp): "))
(term-previous-matching-input regexp (- arg)))
(defun term-previous-matching-input-from-input (arg)
"Search backwards through input history for match for current input.
\(Previous history elements are earlier commands.)
With prefix argument N, search for Nth previous match.
If N is negative, search forwards for the -Nth following match."
(interactive "p")
(when (not (memq last-command '(term-previous-matching-input-from-input
term-next-matching-input-from-input)))
(setq term-matching-input-from-input-string
(buffer-substring
(process-mark (get-buffer-process (current-buffer)))
(point))
term-input-ring-index nil))
(term-previous-matching-input
(concat "^" (regexp-quote term-matching-input-from-input-string))
arg))
(defun term-next-matching-input-from-input (arg)
"Search forwards through input history for match for current input.
\(Following history elements are more recent commands.)
With prefix argument N, search for Nth following match.
If N is negative, search backwards for the -Nth previous match."
(interactive "p")
(term-previous-matching-input-from-input (- arg)))
(defun term-replace-by-expanded-history (&optional silent)
"Expand input command history references before point.
Expansion is dependent on the value of `term-input-autoexpand'.
This function depends on the buffer's idea of the input history, which may not
match the command interpreter's idea, assuming it has one.
Assumes history syntax is like typical Un*x shells'. However, since Emacs
cannot know the interpreter's idea of input line numbers, assuming it has one,
it cannot expand absolute input line number references.
If the optional argument SILENT is non-nil, never complain
even if history reference seems erroneous.
See `term-magic-space' and `term-replace-by-expanded-history-before-point'.
Returns t if successful."
(interactive)
(when (and term-input-autoexpand
(string-match "[!^]" (funcall term-get-old-input))
(save-excursion (beginning-of-line)
(looking-at term-prompt-regexp)))
(let ((previous-modified-tick (buffer-modified-tick)))
(message "Expanding history references...")
(term-replace-by-expanded-history-before-point silent)
(/= previous-modified-tick (buffer-modified-tick)))))
(defun term-replace-by-expanded-history-before-point (silent)
"Expand directory stack reference before point.
See `term-replace-by-expanded-history'. Returns t if successful."
(save-excursion
(let ((toend (- (save-excursion (end-of-line nil) (point)) (point)))
(start (progn (term-bol nil) (point))))
(while (progn
(skip-chars-forward "^!^"
(save-excursion
(end-of-line nil) (- (point) toend)))
(< (point)
(save-excursion
(end-of-line nil) (- (point) toend))))
(setq term-input-ring-index nil)
(cond ((or (= (preceding-char) ?\\)
(term-within-quotes start (point)))
(goto-char (1+ (point))))
((looking-at "![0-9]+\\($\\|[^-]\\)")
(goto-char (match-end 0))
(message "Absolute reference cannot be expanded"))
((looking-at "!-\\([0-9]+\\)\\(:?[0-9^$*-]+\\)?")
(let ((number (1- (string-to-number
(buffer-substring (match-beginning 1)
(match-end 1))))))
(if (<= number (ring-length term-input-ring))
(progn
(replace-match
(term-args (term-previous-input-string number)
(match-beginning 2) (match-end 2))
t t)
(setq term-input-ring-index number)
(message "History item: %d" (1+ number)))
(goto-char (match-end 0))
(message "Relative reference exceeds input history size"))))
((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!"))
(replace-match
(term-args (term-previous-input-string 0)
(match-beginning 1) (match-end 1))
t t)
(message "History item: previous"))
((looking-at
"!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?")
(let* ((mb1 (match-beginning 1)) (me1 (match-end 1))
(mb2 (match-beginning 2)) (me2 (match-end 2))
(exp (buffer-substring (or mb2 mb1) (or me2 me1)))
(pref (if (save-match-data (looking-at "!\\?")) "" "^"))
(pos (save-match-data
(term-previous-matching-input-string-position
(concat pref (regexp-quote exp)) 1))))
(if (null pos)
(progn
(goto-char (match-end 0))
(or silent
(progn (message "Not found")
(ding))))
(setq term-input-ring-index pos)
(replace-match
(term-args (ring-ref term-input-ring pos)
(match-beginning 4) (match-end 4))
t t)
(message "History item: %d" (1+ pos)))))
((looking-at "\\^\\([^^]+\\)\\^?\\([^^]*\\)\\^?")
(let ((old (buffer-substring (match-beginning 1) (match-end 1)))
(new (buffer-substring (match-beginning 2) (match-end 2)))
(pos nil))
(replace-match (term-previous-input-string 0) t t)
(setq pos (point))
(goto-char (match-beginning 0))
(if (not (search-forward old pos t))
(or silent
(error "Not found"))
(replace-match new t t)
(message "History item: substituted"))))
(t
(goto-char (match-end 0))))))))
(defun term-magic-space (arg)
"Expand input history references before point and insert ARG spaces.
A useful command to bind to SPC. See `term-replace-by-expanded-history'."
(interactive "p")
(term-replace-by-expanded-history)
(self-insert-command arg))
(defun term-within-quotes (beg end)
"Return t if the number of quotes between BEG and END is odd.
Quotes are single and double."
(let ((countsq (term-how-many-region "\\(^\\|[^\\\\]\\)\'" beg end))
(countdq (term-how-many-region "\\(^\\|[^\\\\]\\)\"" beg end)))
(or (= (mod countsq 2) 1) (= (mod countdq 2) 1))))
(defun term-how-many-region (regexp beg end)
"Return number of matches for REGEXP from BEG to END."
(let ((count 0))
(save-excursion
(save-match-data
(goto-char beg)
(while (re-search-forward regexp end t)
(setq count (1+ count)))))
count))
(defun term-args (string begin end)
(save-match-data
(if (null begin)
(term-arguments string 0 nil)
(let* ((range (buffer-substring
(if (eq (char-after begin) ?:) (1+ begin) begin) end))
(nth (cond ((string-match "^[*^]" range) 1)
((string-match "^-" range) 0)
((string-equal range "$") nil)
(t (string-to-number range))))
(mth (cond ((string-match "[-*$]$" range) nil)
((string-match "-" range)
(string-to-number (substring range (match-end 0))))
(t nth))))
(term-arguments string nth mth)))))
(defun term-delim-arg (arg)
(if (null term-delimiter-argument-list)
(list arg)
(let ((args nil)
(pos 0)
(len (length arg)))
(while (< pos len)
(let ((char (aref arg pos))
(start pos))
(if (memq char term-delimiter-argument-list)
(while (and (< pos len) (eq (aref arg pos) char))
(setq pos (1+ pos)))
(while (and (< pos len)
(not (memq (aref arg pos)
term-delimiter-argument-list)))
(setq pos (1+ pos))))
(setq args (cons (substring arg start pos) args))))
args)))
(defun term-arguments (string nth mth)
"Return from STRING the NTH to MTH arguments.
NTH and/or MTH can be nil, which means the last argument.
Returned arguments are separated by single spaces.
We assume whitespace separates arguments, except within quotes.
Also, a run of one or more of a single character
in `term-delimiter-argument-list' is a separate argument.
Argument 0 is the command name."
(let ((argpart "[^ \n\t\"'`]+\\|\\(\"[^\"]*\"\\|'[^']*'\\|`[^`]*`\\)")
(args ()) (pos 0)
(count 0)
beg str quotes)
(while (and (or (null mth) (<= count mth))
(string-match argpart string pos))
(if (and beg (= pos (match-beginning 0)))
(setq pos (match-end 0)
quotes (or quotes (match-beginning 1)))
(if beg
(setq str (substring string beg pos)
args (if quotes (cons str args)
(nconc (term-delim-arg str) args))
count (1+ count)))
(setq quotes (match-beginning 1))
(setq beg (match-beginning 0))
(setq pos (match-end 0))))
(if beg
(setq str (substring string beg pos)
args (if quotes (cons str args)
(nconc (term-delim-arg str) args))
count (1+ count)))
(let ((n (or nth (1- count)))
(m (if mth (1- (- count mth)) 0)))
(mapconcat
(function (lambda (a) a)) (nthcdr n (nreverse (nthcdr m args))) " "))))
(defun term-send-input ()
"Send input to process.
After the process output mark, sends all text from the process mark to
point as input to the process. Before the process output mark, calls value
of variable term-get-old-input to retrieve old input, copies it to the
process mark, and sends it. A terminal newline is also inserted into the
buffer and sent to the process. The list of function names contained in the
value of `term-input-filter-functions' is called on the input before sending
it. The input is entered into the input history ring, if the value of variable
term-input-filter returns non-nil when called on the input.
Any history reference may be expanded depending on the value of the variable
`term-input-autoexpand'. The list of function names contained in the value
of `term-input-filter-functions' is called on the input before sending it.
The input is entered into the input history ring, if the value of variable
`term-input-filter' returns non-nil when called on the input.
If variable `term-eol-on-send' is non-nil, then point is moved to the
end of line before sending the input.
The values of `term-get-old-input', `term-input-filter-functions', and
`term-input-filter' are chosen according to the command interpreter running
in the buffer. E.g.,
If the interpreter is the csh,
term-get-old-input is the default: take the current line, discard any
initial string matching regexp term-prompt-regexp.
term-input-filter-functions monitors input for \"cd\", \"pushd\", and
\"popd\" commands. When it sees one, it cd's the buffer.
term-input-filter is the default: returns t if the input isn't all white
space.
If the term is Lucid Common Lisp,
term-get-old-input snarfs the sexp ending at point.
term-input-filter-functions does nothing.
term-input-filter returns nil if the input matches input-filter-regexp,
which matches (1) all whitespace (2) :a, :c, etc.
Similarly for Soar, Scheme, etc."
(interactive)
(let ((proc (get-buffer-process (current-buffer))))
(if (not proc) (error "Current buffer has no process")
(let* ((pmark (process-mark proc))
(pmark-val (marker-position pmark))
(input-is-new (>= (point) pmark-val))
(intxt (if input-is-new
(progn (if term-eol-on-send (end-of-line))
(buffer-substring pmark (point)))
(funcall term-get-old-input)))
(input (if (not (eq term-input-autoexpand 'input))
intxt
(term-replace-by-expanded-history t)
(buffer-substring pmark (point))))
(history (if (not (eq term-input-autoexpand 'history))
input
(term-replace-by-expanded-history t)
(let ((copy (buffer-substring pmark (point))))
(delete-region pmark (point))
(insert input)
copy))))
(when (term-pager-enabled)
(save-excursion
(goto-char (process-mark proc))
(setq term-pager-count (term-current-row))))
(when (and (funcall term-input-filter history)
(or (null term-input-ignoredups)
(not (ring-p term-input-ring))
(ring-empty-p term-input-ring)
(not (string-equal (ring-ref term-input-ring 0)
history))))
(ring-insert term-input-ring history))
(let ((functions term-input-filter-functions))
(while functions
(funcall (car functions) (concat input "\n"))
(setq functions (cdr functions))))
(setq term-input-ring-index nil)
(set-marker term-last-input-start pmark)
(set-marker term-last-input-end (point))
(when input-is-new
(when (marker-buffer term-pending-delete-marker)
(delete-region term-pending-delete-marker pmark))
(set-marker term-pending-delete-marker pmark-val)
(set-marker (process-mark proc) (point)))
(goto-char pmark)
(funcall term-input-sender proc input)))))
(defun term-get-old-input-default ()
"Default for `term-get-old-input'.
Take the current line, and discard any initial text matching
`term-prompt-regexp'."
(save-excursion
(beginning-of-line)
(term-skip-prompt)
(let ((beg (point)))
(end-of-line)
(buffer-substring beg (point)))))
(defun term-copy-old-input ()
"Insert after prompt old input at point as new input to be edited.
Calls `term-get-old-input' to get old input."
(interactive)
(let ((input (funcall term-get-old-input))
(process (get-buffer-process (current-buffer))))
(if (not process)
(error "Current buffer has no process")
(goto-char (process-mark process))
(insert input))))
(defun term-skip-prompt ()
"Skip past the text matching regexp `term-prompt-regexp'.
If this takes us past the end of the current line, don't skip at all."
(let ((eol (save-excursion (end-of-line) (point))))
(when (and (looking-at term-prompt-regexp)
(<= (match-end 0) eol))
(goto-char (match-end 0)))))
(defun term-after-pmark-p ()
"Is point after the process output marker?"
(let ((proc-pos (marker-position
(process-mark (get-buffer-process (current-buffer))))))
(<= proc-pos (point))))
(defun term-simple-send (proc string)
"Default function for sending to PROC input STRING.
This just sends STRING plus a newline. To override this,
set the hook `term-input-sender'."
(term-send-string proc string)
(term-send-string proc "\n"))
(defun term-bol (arg)
"Goes to the beginning of line, then skips past the prompt, if any.
If a prefix argument is given (\\[universal-argument]), then no prompt skip
-- go straight to column 0.
The prompt skip is done by skipping text matching the regular expression
`term-prompt-regexp', a buffer local variable."
(interactive "P")
(beginning-of-line)
(when (null arg) (term-skip-prompt)))
(defun term-read-noecho (prompt &optional stars)
"Read a single line of text from user without echoing, and return it.
Prompt with argument PROMPT, a string. Optional argument STARS causes
input to be echoed with '*' characters on the prompt line. Input ends with
RET, LFD, or ESC. DEL or C-h rubs out. C-u kills line. C-g aborts (if
`inhibit-quit' is set because e.g. this function was called from a process
filter and C-g is pressed, this function returns nil rather than a string).
Note that the keystrokes comprising the text can still be recovered
\(temporarily) with \\[view-lossage]. This may be a security bug for some
applications."
(let ((ans "")
(c 0)
(echo-keystrokes 0)
(cursor-in-echo-area t)
(done nil))
(while (not done)
(if stars
(message "%s%s" prompt (make-string (length ans) ?*))
(message "%s" prompt))
(setq c (read-char))
(cond ((= c ?\C-g)
(setq quit-flag t
done t))
((or (= c ?\r) (= c ?\n) (= c ?\e))
(setq done t))
((= c ?\C-u)
(setq ans ""))
((and (/= c ?\b) (/= c ?\177))
(setq ans (concat ans (char-to-string c))))
((> (length ans) 0)
(setq ans (substring ans 0 -1)))))
(if quit-flag
(prog1
(setq quit-flag nil)
(message "Quit")
(beep t))
(message "")
ans)))
(defun term-send-invisible (str &optional proc)
"Read a string without echoing.
Then send it to the process running in the current buffer. A new-line
is additionally sent. String is not saved on term input history list.
Security bug: your string can still be temporarily recovered with
\\[view-lossage]."
(interactive "P") (when (not (stringp str))
(setq str (term-read-noecho "Non-echoed text: " t)))
(when (not proc)
(setq proc (get-buffer-process (current-buffer))))
(if (not proc) (error "Current buffer has no process")
(setq term-kill-echo-list (nconc term-kill-echo-list
(cons str nil)))
(term-send-string proc str)
(term-send-string proc "\n")))
(defvar term-input-chunk-size 512
"*Long inputs send to term processes are broken up into chunks of this size.
If your process is choking on big inputs, try lowering the value.")
(defun term-send-string (proc str)
"Send to PROC the contents of STR as input.
This is equivalent to `process-send-string', except that long input strings
are broken up into chunks of size `term-input-chunk-size'. Processes
are given a chance to output between chunks. This can help prevent processes
from hanging when you send them long inputs on some OS's."
(let* ((len (length str))
(i (min len term-input-chunk-size)))
(process-send-string proc (substring str 0 i))
(while (< i len)
(let ((next-i (+ i term-input-chunk-size)))
(accept-process-output)
(process-send-string proc (substring str i (min len next-i)))
(setq i next-i)))))
(defun term-send-region (proc start end)
"Send to PROC the region delimited by START and END.
This is a replacement for `process-send-region' that tries to keep
your process from hanging on long inputs. See `term-send-string'."
(term-send-string proc (buffer-substring start end)))
(defun term-kill-output ()
"Kill all output from interpreter since last input."
(interactive)
(let ((pmark (process-mark (get-buffer-process (current-buffer)))))
(kill-region term-last-input-end pmark)
(goto-char pmark)
(insert "*** output flushed ***\n")
(set-marker pmark (point))))
(defun term-show-output ()
"Display start of this batch of interpreter output at top of window.
Sets mark to the value of point when this command is run."
(interactive)
(goto-char term-last-input-end)
(backward-char)
(beginning-of-line)
(set-window-start (selected-window) (point))
(end-of-line))
(defun term-interrupt-subjob ()
"Interrupt the current subjob."
(interactive)
(interrupt-process nil term-ptyp))
(defun term-kill-subjob ()
"Send kill signal to the current subjob."
(interactive)
(kill-process nil term-ptyp))
(defun term-quit-subjob ()
"Send quit signal to the current subjob."
(interactive)
(quit-process nil term-ptyp))
(defun term-stop-subjob ()
"Stop the current subjob.
WARNING: if there is no current subjob, you can end up suspending
the top-level process running in the buffer. If you accidentally do
this, use \\[term-continue-subjob] to resume the process. (This
is not a problem with most shells, since they ignore this signal.)"
(interactive)
(stop-process nil term-ptyp))
(defun term-continue-subjob ()
"Send CONT signal to process buffer's process group.
Useful if you accidentally suspend the top-level process."
(interactive)
(continue-process nil term-ptyp))
(defun term-kill-input ()
"Kill all text from last stuff output by interpreter to point."
(interactive)
(let* ((pmark (process-mark (get-buffer-process (current-buffer))))
(p-pos (marker-position pmark)))
(when (> (point) p-pos)
(kill-region pmark (point)))))
(defun term-delchar-or-maybe-eof (arg)
"Delete ARG characters forward, or send an EOF to process if at end of
buffer."
(interactive "p")
(if (eobp)
(process-send-eof)
(delete-char arg)))
(defun term-send-eof ()
"Send an EOF to the current buffer's process."
(interactive)
(process-send-eof))
(defun term-backward-matching-input (regexp arg)
"Search backward through buffer for match for REGEXP.
Matches are searched for on lines that match `term-prompt-regexp'.
With prefix argument N, search for Nth previous match.
If N is negative, find the next or Nth next match."
(interactive (term-regexp-arg "Backward input matching (regexp): "))
(let* ((re (concat term-prompt-regexp ".*" regexp))
(pos (save-excursion (end-of-line (if (> arg 0) 0 1))
(when (re-search-backward re nil t arg)
(point)))))
(if (null pos)
(progn (message "Not found")
(ding))
(goto-char pos)
(term-bol nil))))
(defun term-forward-matching-input (regexp arg)
"Search forward through buffer for match for REGEXP.
Matches are searched for on lines that match `term-prompt-regexp'.
With prefix argument N, search for Nth following match.
If N is negative, find the previous or Nth previous match."
(interactive (term-regexp-arg "Forward input matching (regexp): "))
(term-backward-matching-input regexp (- arg)))
(defun term-next-prompt (n)
"Move to end of Nth next prompt in the buffer.
See `term-prompt-regexp'."
(interactive "p")
(let ((paragraph-start term-prompt-regexp))
(end-of-line (if (> n 0) 1 0))
(forward-paragraph n)
(term-skip-prompt)))
(defun term-previous-prompt (n)
"Move to end of Nth previous prompt in the buffer.
See `term-prompt-regexp'."
(interactive "p")
(term-next-prompt (- n)))
(defun term-source-default (previous-dir/file source-modes)
(cond ((and buffer-file-name (memq major-mode source-modes))
(cons (file-name-directory buffer-file-name)
(file-name-nondirectory buffer-file-name)))
(previous-dir/file)
(t
(cons default-directory nil))))
(defun term-check-source (fname)
(let ((buff (get-file-buffer fname)))
(when (and buff
(buffer-modified-p buff)
(y-or-n-p (format "Save buffer %s first? "
(buffer-name buff))))
(let ((old-buffer (current-buffer)))
(set-buffer buff)
(save-buffer)
(set-buffer old-buffer)))))
(defun term-extract-string ()
"Return string around `point' that starts the current line or nil."
(save-excursion
(let* ((point (point))
(bol (progn (beginning-of-line) (point)))
(eol (progn (end-of-line) (point)))
(start (progn (goto-char point)
(and (search-backward "\"" bol t)
(1+ (point)))))
(end (progn (goto-char point)
(and (search-forward "\"" eol t)
(1- (point))))))
(and start end
(buffer-substring start end)))))
(defun term-get-source (prompt prev-dir/file source-modes mustmatch-p)
(let* ((def (term-source-default prev-dir/file source-modes))
(stringfile (term-extract-string))
(sfile-p (and stringfile
(condition-case ()
(file-exists-p stringfile)
(error nil))
(not (file-directory-p stringfile))))
(defdir (if sfile-p (file-name-directory stringfile)
(car def)))
(deffile (if sfile-p (file-name-nondirectory stringfile)
(cdr def)))
(ans (read-file-name (if deffile (format "%s(default %s) "
prompt deffile)
prompt)
defdir
(concat defdir deffile)
mustmatch-p)))
(list (expand-file-name (substitute-in-file-name ans)))))
(defun term-proc-query (proc str)
(let* ((proc-buf (process-buffer proc))
(proc-mark (process-mark proc)))
(display-buffer proc-buf)
(set-buffer proc-buf) (let ((proc-win (get-buffer-window proc-buf))
(proc-pt (marker-position proc-mark)))
(term-send-string proc str) (accept-process-output proc) (when (not (pos-visible-in-window-p proc-pt proc-win))
(let ((opoint (window-point proc-win)))
(set-window-point proc-win proc-mark) (sit-for 0)
(if (not (pos-visible-in-window-p opoint proc-win))
(push-mark opoint)
(set-window-point proc-win opoint)))))))
(defun term-horizontal-column ()
(- (term-current-column) (term-start-line-column)))
(defmacro term-vertical-motion (count)
(list 'funcall 'term-vertical-motion count))
(defun term-buffer-vertical-motion (count)
(cond ((= count 0)
(move-to-column (* term-width (/ (current-column) term-width)))
0)
((> count 0)
(let ((H)
(todo (+ count (/ (current-column) term-width))))
(end-of-line)
(while (and (<= (setq H (max (/ (+ (current-column) term-width -1)
term-width)
1))
todo)
(not (eobp)))
(setq todo (- todo H))
(forward-char) (end-of-line)) (if (and (>= todo H) (> todo 0))
(+ (- count todo) H -1) (move-to-column (* todo term-width))
count)))
(t (let ((H)
(todo (- count)))
(while (and (<= (setq H (max (/ (+ (current-column) term-width -1)
term-width)
1))
todo)
(progn (beginning-of-line)
(not (bobp))))
(setq todo (- todo H))
(backward-char)) (if (and (>= todo H) (> todo 0))
(+ count todo (- 1 H)) (move-to-column (* (- H todo 1) term-width))
count)))))
(defun term-start-line-column ()
(cond (term-start-line-column)
((let ((save-pos (point)))
(term-vertical-motion 0)
(setq term-start-line-column (current-column))
(goto-char save-pos)
term-start-line-column))))
(defun term-current-column ()
(cond (term-current-column)
((setq term-current-column (current-column)))))
(defun term-move-columns (delta)
(setq term-current-column (max 0 (+ (term-current-column) delta)))
(let (point-at-eol)
(save-excursion
(end-of-line)
(setq point-at-eol (point)))
(move-to-column term-current-column t)
(when (> (point) point-at-eol)
(put-text-property point-at-eol (point) 'face 'default))))
(defun term-insert-char (char count)
(let ((old-point (point)))
(insert-char char count)
(put-text-property old-point (point) 'face 'default)))
(defun term-current-row ()
(cond (term-current-row)
((setq term-current-row
(save-restriction
(save-excursion
(narrow-to-region term-home-marker (point-max))
(- (term-vertical-motion -9999))))))))
(defun term-adjust-current-row-cache (delta)
(when term-current-row
(setq term-current-row
(max 0 (+ term-current-row delta)))))
(defun term-terminal-pos ()
(save-excursion (let ((save-col (term-current-column))
x y)
(term-vertical-motion 0)
(setq x (- save-col (current-column)))
(setq y (term-vertical-motion term-height))
(cons x y))))
(defun term-handle-ansi-terminal-messages (message)
(while (string-match "\eAnSiT.+\n" message)
(let* ((start (match-beginning 0))
(end (match-end 0))
(command-code (aref message (+ start 6)))
(argument
(save-match-data
(substring message
(+ start 8)
(string-match "\r?\n" message
(+ start 8)))))
ignore)
(setq message (replace-match "" t t message))
(cond ((= command-code ?c)
(setq term-ansi-at-dir argument))
((= command-code ?h)
(setq term-ansi-at-host argument))
((= command-code ?u)
(setq term-ansi-at-user argument))
(t
(setq ignore t)))
(if ignore
nil
(setq default-directory
(file-name-as-directory
(if (and (string= term-ansi-at-host (system-name))
(string= term-ansi-at-user (user-real-login-name)))
(expand-file-name term-ansi-at-dir)
(if (string= term-ansi-at-user (user-real-login-name))
(concat "/" term-ansi-at-host ":" term-ansi-at-dir)
(concat "/" term-ansi-at-user "@" term-ansi-at-host ":"
term-ansi-at-dir)))))
(if (string= term-ansi-at-host (system-name))
(progn
(setq ange-ftp-default-user term-ansi-at-save-user)
(setq ange-ftp-default-password term-ansi-at-save-pwd)
(setq ange-ftp-generate-anonymous-password term-ansi-at-save-anon))
(setq term-ansi-at-save-user ange-ftp-default-user)
(setq term-ansi-at-save-pwd ange-ftp-default-password)
(setq term-ansi-at-save-anon ange-ftp-generate-anonymous-password)
(setq ange-ftp-default-user nil)
(setq ange-ftp-default-password nil)
(setq ange-ftp-generate-anonymous-password nil)))))
message)
(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
(buffer-undo-list t)
(selected (selected-window))
last-win
handled-ansi-message
(str-length (length str)))
(save-selected-window
(let* ((newstr (term-handle-ansi-terminal-messages str)))
(when (not (eq str newstr))
(setq handled-ansi-message t
str newstr)))
(setq str-length (length str))
(when (marker-buffer term-pending-delete-marker)
(delete-region term-pending-delete-marker (process-mark proc))
(set-marker term-pending-delete-marker nil))
(if (eq (window-buffer) (current-buffer))
(progn
(setq term-vertical-motion (symbol-function 'vertical-motion))
(term-check-size proc))
(setq term-vertical-motion
(symbol-function 'term-buffer-vertical-motion)))
(setq save-marker (copy-marker (process-mark proc)))
(when (/= (point) (process-mark proc))
(setq save-point (point-marker))
(goto-char (process-mark proc)))
(save-restriction
(when (and (> (point-max) (process-mark proc))
(term-in-line-mode))
(narrow-to-region (point-min) (process-mark proc)))
(when term-log-buffer
(princ str term-log-buffer))
(cond ((eq term-terminal-state 4) (setq str (concat term-terminal-parameter str))
(setq term-terminal-parameter nil)
(setq str-length (length str))
(setq term-terminal-state 0)))
(while (< i str-length)
(setq char (aref str i))
(cond ((< term-terminal-state 2)
(setq funny
(string-match "[\r\n\000\007\033\t\b\032\016\017]"
str i))
(when (not funny) (setq funny str-length))
(cond ((> funny i)
(cond ((eq term-terminal-state 1)
(term-down 1 t)
(term-move-columns (- (term-current-column)))
(setq term-terminal-state 0)))
(setq count (- funny i))
(setq temp (- (+ (term-horizontal-column) count)
term-width))
(cond ((<= temp 0)) ((> count temp) (setq count (- count temp))
(setq temp 0)
(setq funny (+ count 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 term-start-line-column
term-current-column))
(t (setq count 0 funny i)
(setq term-current-column nil)
(setq term-start-line-column nil)))
(setq old-point (point))
(let ((old-column (current-column))
columns pos)
(insert (decode-coding-string (substring str i funny) locale-coding-system))
(setq term-current-column (current-column)
columns (- term-current-column old-column))
(when (not (or (eobp) term-insert-mode))
(setq pos (point))
(term-move-columns columns)
(delete-region pos (point)))
(when term-insert-mode
(setq pos (point))
(end-of-line)
(when (> (current-column) term-width)
(delete-region (- (point) (- (current-column) term-width))
(point)))
(goto-char pos)))
(setq term-current-column nil)
(put-text-property old-point (point)
'face term-current-face)
(cond ((eq temp 0)
(term-move-columns -1)
(setq term-terminal-state 1)))
(setq i (1- funny)))
((and (setq term-terminal-state 0)
(eq char ?\^I)) (setq count (term-current-column))
(setq count (min term-width
(+ count 8 (- (mod count 8)))))
(if (> term-width count)
(progn
(term-move-columns
(- count (term-current-column)))
(setq term-current-column count))
(when (> term-width (term-current-column))
(term-move-columns
(1- (- term-width (term-current-column)))))
(when (= term-width (term-current-column))
(term-move-columns -1))))
((eq char ?\r) (term-vertical-motion 0)
(setq term-current-column term-start-line-column))
((eq char ?\n) (unless (and term-kill-echo-list
(term-check-kill-echo-list))
(term-down 1 t)))
((eq char ?\b) (term-move-columns -1))
((eq char ?\033) (setq term-terminal-state 2))
((eq char 0)) ((eq char ?\016)) ((eq char ?\017)) ((eq char ?\^G) (beep t))
((and (eq char ?\032)
(not handled-ansi-message))
(let ((end (string-match "\r?$" str i)))
(if end
(funcall term-command-hook
(prog1 (substring str (1+ i) end)
(setq i (match-end 0))))
(setq term-terminal-parameter (substring str i))
(setq term-terminal-state 4)
(setq i str-length))))
(t (term-move-columns 1)
(backward-delete-char 1)
(insert char))))
((eq term-terminal-state 2) (cond ((eq char ?\133)
(setq term-terminal-parameter 0)
(setq term-terminal-previous-parameter -1)
(setq term-terminal-previous-parameter-2 -1)
(setq term-terminal-previous-parameter-3 -1)
(setq term-terminal-previous-parameter-4 -1)
(setq term-terminal-more-parameters 0)
(setq term-terminal-state 3))
((eq char ?D) (term-handle-deferred-scroll)
(term-down 1 t)
(setq term-terminal-state 0))
((eq char ?M) (if (or (< (term-current-row) term-scroll-start)
(>= (1- (term-current-row))
term-scroll-start))
(term-down -1)
(term-down -1 t))
(setq term-terminal-state 0))
((eq char ?7) (term-handle-deferred-scroll)
(setq term-saved-cursor
(list (term-current-row)
(term-horizontal-column)
term-ansi-current-bg-color
term-ansi-current-bold
term-ansi-current-color
term-ansi-current-invisible
term-ansi-current-reverse
term-ansi-current-underline
term-current-face)
)
(setq term-terminal-state 0))
((eq char ?8) (when term-saved-cursor
(term-goto (nth 0 term-saved-cursor)
(nth 1 term-saved-cursor))
(setq term-ansi-current-bg-color
(nth 2 term-saved-cursor)
term-ansi-current-bold
(nth 3 term-saved-cursor)
term-ansi-current-color
(nth 4 term-saved-cursor)
term-ansi-current-invisible
(nth 5 term-saved-cursor)
term-ansi-current-reverse
(nth 6 term-saved-cursor)
term-ansi-current-underline
(nth 7 term-saved-cursor)
term-current-face
(nth 8 term-saved-cursor)))
(setq term-terminal-state 0))
((eq char ?c) (setq term-terminal-state 0)
(term-reset-terminal))
((setq term-terminal-state 0))))
((eq term-terminal-state 3) (cond ((and (>= char ?0) (<= char ?9))
(setq term-terminal-parameter
(+ (* 10 term-terminal-parameter) (- char ?0))))
((eq char ?\ (setq term-terminal-more-parameters 1)
(setq term-terminal-previous-parameter-4
term-terminal-previous-parameter-3)
(setq term-terminal-previous-parameter-3
term-terminal-previous-parameter-2)
(setq term-terminal-previous-parameter-2
term-terminal-previous-parameter)
(setq term-terminal-previous-parameter
term-terminal-parameter)
(setq term-terminal-parameter 0))
((eq char ??)) (t
(term-handle-ansi-escape proc char)
(setq term-terminal-more-parameters 0)
(setq term-terminal-previous-parameter-4 -1)
(setq term-terminal-previous-parameter-3 -1)
(setq term-terminal-previous-parameter-2 -1)
(setq term-terminal-previous-parameter -1)
(setq term-terminal-state 0)))))
(when (term-handling-pager)
(if (> (% (current-column) term-width) 0)
(setq term-terminal-parameter
(substring str i))
(if (zerop i)
(setq term-terminal-parameter
(concat "\r" (substring str i)))
(setq term-terminal-parameter (substring str (1- i)))
(aset term-terminal-parameter 0 ?\r))
(goto-char (point-max)))
(setq term-terminal-state 4)
(make-local-variable 'term-pager-old-filter)
(setq term-pager-old-filter (process-filter proc))
(set-process-filter proc term-pager-filter)
(setq i str-length))
(setq i (1+ i))))
(when (>= (term-current-row) term-height)
(term-handle-deferred-scroll))
(set-marker (process-mark proc) (point))
(when save-point
(goto-char save-point)
(set-marker save-point nil))
(when (and term-pending-frame
(eq (window-buffer selected) (current-buffer)))
(term-display-line (car term-pending-frame)
(cdr term-pending-frame))
(setq term-pending-frame nil)
(term-check-size proc))
(setq win selected)
(while (window-minibuffer-p win)
(setq win (next-window win nil t)))
(setq last-win win)
(while (progn
(setq win (next-window win nil t))
(when (eq (window-buffer win) (process-buffer proc))
(let ((scroll term-scroll-to-bottom-on-output))
(select-window win)
(when (or (= (point) save-marker)
(eq scroll t) (eq scroll 'all)
(and (eq selected win)
(or (eq scroll 'this) (not save-point)))
(and (eq scroll 'others)
(not (eq selected win))))
(goto-char term-home-marker)
(recenter 0)
(goto-char (process-mark proc))
(if (not (pos-visible-in-window-p (point) win))
(recenter -1)))
(when (and term-scroll-show-maximum-output
(>= (point) (process-mark proc)))
(save-excursion
(goto-char (point-max))
(recenter -1)))))
(not (eq win last-win))))
(when (> term-buffer-maximum-size 0)
(save-excursion
(goto-char (process-mark (get-buffer-process (current-buffer))))
(forward-line (- term-buffer-maximum-size))
(beginning-of-line)
(delete-region (point-min) (point))))
(set-marker save-marker nil)))))
(defun term-handle-deferred-scroll ()
(let ((count (- (term-current-row) term-height)))
(when (>= count 0)
(save-excursion
(goto-char term-home-marker)
(term-vertical-motion (1+ count))
(set-marker term-home-marker (point))
(setq term-current-row (1- term-height))))))
(defun term-reset-terminal ()
(erase-buffer)
(setq term-current-row 0)
(setq term-current-column 1)
(setq term-scroll-start 0)
(setq term-scroll-end term-height)
(setq term-insert-mode nil)
(setq term-current-face nil)
(setq term-ansi-current-underline nil)
(setq term-ansi-current-bold nil)
(setq term-ansi-current-reverse nil)
(setq term-ansi-current-color 0)
(setq term-ansi-current-invisible nil)
(setq term-ansi-face-already-done nil)
(setq term-ansi-current-bg-color 0))
(defun term-handle-colors-array (parameter)
(cond
((eq parameter 1)
(setq term-ansi-current-bold t))
((eq parameter 4)
(setq term-ansi-current-underline t))
((eq parameter 5)
(setq term-ansi-current-bold t))
((eq parameter 7)
(setq term-ansi-current-reverse t))
((eq parameter 8)
(setq term-ansi-current-invisible t))
((eq parameter 24)
(setq term-ansi-current-underline nil))
((eq parameter 27)
(setq term-ansi-current-reverse nil))
((and (>= parameter 30) (<= parameter 37))
(setq term-ansi-current-color (- parameter 29)))
((eq parameter 39)
(setq term-ansi-current-color 0))
((and (>= parameter 40) (<= parameter 47))
(setq term-ansi-current-bg-color (- parameter 39)))
((eq parameter 49)
(setq term-ansi-current-bg-color 0))
(t
(setq term-current-face nil)
(setq term-ansi-current-underline nil)
(setq term-ansi-current-bold nil)
(setq term-ansi-current-reverse nil)
(setq term-ansi-current-color 0)
(setq term-ansi-current-invisible nil)
(setq term-ansi-face-already-done t)
(setq term-ansi-current-bg-color 0)))
(unless term-ansi-face-already-done
(if term-ansi-current-reverse
(if term-ansi-current-invisible
(setq term-current-face
(if (= term-ansi-current-color 0)
(list :background
term-default-fg-color
:foreground
term-default-fg-color)
(list :background
(elt ansi-term-color-vector term-ansi-current-color)
:foreground
(elt ansi-term-color-vector term-ansi-current-color)))
)
(setq term-current-face
(list :background
(if (= term-ansi-current-color 0)
(face-foreground 'default)
(elt ansi-term-color-vector term-ansi-current-color))
:foreground
(if (= term-ansi-current-bg-color 0)
(face-background 'default)
(elt ansi-term-color-vector term-ansi-current-bg-color))))
(when term-ansi-current-bold
(setq term-current-face
(append '(:weight bold) term-current-face)))
(when term-ansi-current-underline
(setq term-current-face
(append '(:underline t) term-current-face))))
(if term-ansi-current-invisible
(setq term-current-face
(if (= term-ansi-current-bg-color 0)
(list :background
term-default-bg-color
:foreground
term-default-bg-color)
(list :foreground
(elt ansi-term-color-vector term-ansi-current-bg-color)
:background
(elt ansi-term-color-vector term-ansi-current-bg-color)))
)
(setq term-current-face
(list :foreground
(elt ansi-term-color-vector term-ansi-current-color)
:background
(elt ansi-term-color-vector term-ansi-current-bg-color)))
(when term-ansi-current-bold
(setq term-current-face
(append '(:weight bold) term-current-face)))
(when term-ansi-current-underline
(setq term-current-face
(append '(:underline t) term-current-face))))))
(setq term-ansi-face-already-done nil))
(defun term-handle-ansi-escape (proc char)
(cond
((or (eq char ?H) )
(when (<= term-terminal-parameter 0)
(setq term-terminal-parameter 1))
(when (<= term-terminal-previous-parameter 0)
(setq term-terminal-previous-parameter 1))
(when (> term-terminal-previous-parameter term-height)
(setq term-terminal-previous-parameter term-height))
(when (> term-terminal-parameter term-width)
(setq term-terminal-parameter term-width))
(term-goto
(1- term-terminal-previous-parameter)
(1- term-terminal-parameter)))
((eq char ?A)
(term-handle-deferred-scroll)
(let ((tcr (term-current-row)))
(term-down
(if (< (- tcr term-terminal-parameter) term-scroll-start)
(- term-scroll-start tcr)
(if (>= term-terminal-parameter tcr)
(- tcr)
(- (max 1 term-terminal-parameter)))) t)))
((eq char ?B)
(let ((tcr (term-current-row)))
(unless (= tcr (1- term-scroll-end))
(term-down
(if (> (+ tcr term-terminal-parameter) term-scroll-end)
(- term-scroll-end 1 tcr)
(max 1 term-terminal-parameter)) t))))
((eq char ?C)
(term-move-columns
(max 1
(if (>= (+ term-terminal-parameter (term-current-column)) term-width)
(- term-width (term-current-column) 1)
term-terminal-parameter))))
((eq char ?D)
(term-move-columns (- (max 1 term-terminal-parameter))))
((eq char ?J)
(term-erase-in-display term-terminal-parameter))
((eq char ?K)
(term-erase-in-line term-terminal-parameter))
((eq char ?L)
(term-insert-lines (max 1 term-terminal-parameter)))
((eq char ?M)
(term-delete-lines (max 1 term-terminal-parameter)))
((eq char ?P)
(term-delete-chars (max 1 term-terminal-parameter)))
((eq char ?@)
(term-insert-spaces (max 1 term-terminal-parameter)))
((eq char ?h)
(cond ((eq term-terminal-parameter 4) (setq term-insert-mode t))
))
((eq char ?l)
(cond ((eq term-terminal-parameter 4) (setq term-insert-mode nil))
))
((eq char ?m)
(when (= term-terminal-more-parameters 1)
(when (>= term-terminal-previous-parameter-4 0)
(term-handle-colors-array term-terminal-previous-parameter-4))
(when (>= term-terminal-previous-parameter-3 0)
(term-handle-colors-array term-terminal-previous-parameter-3))
(when (>= term-terminal-previous-parameter-2 0)
(term-handle-colors-array term-terminal-previous-parameter-2))
(term-handle-colors-array term-terminal-previous-parameter))
(term-handle-colors-array term-terminal-parameter))
((eq char ?n)
(term-handle-deferred-scroll)
(process-send-string proc
(format "\e[%s;%sR"
(1+ (term-current-row))
(1+ (term-horizontal-column)))))
((eq char ?r)
(term-set-scroll-region
(1- term-terminal-previous-parameter)
(1- term-terminal-parameter)))
(t)))
(defun term-set-scroll-region (top bottom)
"Set scrolling region.
TOP is the top-most line (inclusive) of the new scrolling region,
while BOTTOM is the line following the new scrolling region (e.g. exclusive).
The top-most line is line 0."
(setq term-scroll-start
(if (or (< top 0) (>= top term-height))
0
top))
(setq term-scroll-end
(if (or (<= bottom term-scroll-start) (> bottom term-height))
term-height
bottom))
(setq term-scroll-with-delete
(or (term-using-alternate-sub-buffer)
(not (and (= term-scroll-start 0)
(= term-scroll-end term-height)))))
(term-move-columns (- (term-current-column)))
(term-goto 0 0))
(defun term-command-hook (string)
(cond ((equal string "")
t)
((= (aref string 0) ?\032)
(let* ((first-colon (string-match ":" string 1))
(second-colon
(string-match ":" string (1+ first-colon)))
(filename (substring string 1 first-colon))
(fileline (string-to-number
(substring string (1+ first-colon) second-colon))))
(setq term-pending-frame (cons filename fileline))))
((= (aref string 0) ?/)
(cd (substring string 1)))
(t)))
(defun term-display-line (true-file line)
(term-display-buffer-line (find-file-noselect true-file) line))
(defun term-display-buffer-line (buffer line)
(let* ((window (display-buffer buffer t))
(pos))
(save-excursion
(set-buffer buffer)
(save-restriction
(widen)
(goto-line line)
(setq pos (point))
(setq overlay-arrow-string "=>")
(or overlay-arrow-position
(setq overlay-arrow-position (make-marker)))
(set-marker overlay-arrow-position (point) (current-buffer)))
(cond ((or (< pos (point-min)) (> pos (point-max)))
(widen)
(goto-char pos))))
(set-window-point window overlay-arrow-position)))
(defun term-goto-home ()
(term-handle-deferred-scroll)
(goto-char term-home-marker)
(setq term-current-row 0)
(setq term-current-column (current-column))
(setq term-start-line-column term-current-column))
(defun term-goto (row col)
(term-handle-deferred-scroll)
(cond ((and term-current-row (>= row term-current-row))
(term-vertical-motion 0)
(setq term-current-column term-start-line-column)
(setq row (- row term-current-row)))
(t
(term-goto-home)))
(term-down row)
(term-move-columns col))
(defun term-process-pager ()
(when (not term-pager-break-map)
(let* ((map (make-keymap))
(i 0) tmp)
(define-key map "\e"
(lookup-key (current-global-map) "\e"))
(define-key map "\C-x"
(lookup-key (current-global-map) "\C-x"))
(define-key map "\C-u"
(lookup-key (current-global-map) "\C-u"))
(define-key map " " 'term-pager-page)
(define-key map "\r" 'term-pager-line)
(define-key map "?" 'term-pager-help)
(define-key map "h" 'term-pager-help)
(define-key map "b" 'term-pager-back-page)
(define-key map "\177" 'term-pager-back-line)
(define-key map "q" 'term-pager-discard)
(define-key map "D" 'term-pager-disable)
(define-key map "<" 'term-pager-bob)
(define-key map ">" 'term-pager-eob)
(unless (featurep 'xemacs)
(define-key map [menu-bar terminal] term-terminal-menu)
(define-key map [menu-bar signals] term-signals-menu)
(setq tmp (make-sparse-keymap "More pages?"))
(define-key tmp [help] '("Help" . term-pager-help))
(define-key tmp [disable]
'("Disable paging" . term-fake-pager-disable))
(define-key tmp [discard]
'("Discard remaining output" . term-pager-discard))
(define-key tmp [eob] '("Goto to end" . term-pager-eob))
(define-key tmp [bob] '("Goto to beginning" . term-pager-bob))
(define-key tmp [line] '("1 line forwards" . term-pager-line))
(define-key tmp [bline] '("1 line backwards" . term-pager-back-line))
(define-key tmp [back] '("1 page backwards" . term-pager-back-page))
(define-key tmp [page] '("1 page forwards" . term-pager-page))
(define-key map [menu-bar page] (cons "More pages?" tmp))
)
(setq term-pager-break-map map)))
(setq term-pager-old-local-map (current-local-map))
(use-local-map term-pager-break-map)
(make-local-variable 'term-old-mode-line-format)
(setq term-old-mode-line-format mode-line-format)
(setq mode-line-format
(list "-- **MORE** "
mode-line-buffer-identification
" [Type ? for help] "
"%-"))
(force-mode-line-update))
(defun term-pager-line (lines)
(interactive "p")
(let* ((moved (vertical-motion (1+ lines)))
(deficit (- lines moved)))
(when (> moved lines)
(backward-char))
(cond ((<= deficit 0) (recenter (1- term-height)))
((term-pager-continue deficit)))))
(defun term-pager-page (arg)
"Proceed past the **MORE** break, allowing the next page of output to appear."
(interactive "p")
(term-pager-line (* arg term-height)))
(defun term-pager-bob ()
(interactive)
(goto-char (point-min))
(when (= (vertical-motion term-height) term-height)
(backward-char))
(recenter (1- term-height)))
(defun term-pager-eob ()
(interactive)
(goto-char term-home-marker)
(recenter 0)
(goto-char (process-mark (get-buffer-process (current-buffer)))))
(defun term-pager-back-line (lines)
(interactive "p")
(vertical-motion (- 1 lines))
(if (not (bobp))
(backward-char)
(beep)
(vertical-motion term-height)
(backward-char))
(recenter (1- term-height)))
(defun term-pager-back-page (arg)
(interactive "p")
(term-pager-back-line (* arg term-height)))
(defun term-pager-discard ()
(interactive)
(setq term-terminal-parameter "")
(interrupt-process nil t)
(term-pager-continue term-height))
(defun term-pager-disable ()
(interactive)
(if (term-handling-pager)
(term-pager-continue nil)
(setq term-pager-count nil))
(term-update-mode-line))
(defun term-pager-enable ()
(interactive)
(or (term-pager-enabled)
(setq term-pager-count 0)) (term-update-mode-line))
(defun term-pager-toggle ()
(interactive)
(if (term-pager-enabled) (term-pager-disable) (term-pager-enable)))
(unless (featurep 'xemacs)
(defalias 'term-fake-pager-enable 'term-pager-toggle)
(defalias 'term-fake-pager-disable 'term-pager-toggle)
(put 'term-char-mode 'menu-enable '(term-in-line-mode))
(put 'term-line-mode 'menu-enable '(term-in-char-mode))
(put 'term-fake-pager-enable 'menu-enable '(not term-pager-count))
(put 'term-fake-pager-disable 'menu-enable 'term-pager-count))
(defun term-pager-help ()
"Provide help on commands available in a terminal-emulator **MORE** break."
(interactive)
(message "Terminal-emulator pager break help...")
(sit-for 0)
(with-electric-help
(function (lambda ()
(princ (substitute-command-keys
"\\<term-pager-break-map>\
Terminal-emulator MORE break.\n\
Type one of the following keys:\n\n\
\\[term-pager-page]\t\tMove forward one page.\n\
\\[term-pager-line]\t\tMove forward one line.\n\
\\[universal-argument] N \\[term-pager-page]\tMove N pages forward.\n\
\\[universal-argument] N \\[term-pager-line]\tMove N lines forward.\n\
\\[universal-argument] N \\[term-pager-back-line]\tMove N lines back.\n\
\\[universal-argument] N \\[term-pager-back-page]\t\tMove N pages back.\n\
\\[term-pager-bob]\t\tMove to the beginning of the buffer.\n\
\\[term-pager-eob]\t\tMove to the end of the buffer.\n\
\\[term-pager-discard]\t\tKill pending output and kill process.\n\
\\[term-pager-disable]\t\tDisable PAGER handling.\n\n\
\\{term-pager-break-map}\n\
Any other key is passed through to the program
running under the terminal emulator and disables pager processing until
all pending output has been dealt with."))
nil))))
(defun term-pager-continue (new-count)
(let ((process (get-buffer-process (current-buffer))))
(use-local-map term-pager-old-local-map)
(setq term-pager-old-local-map nil)
(setq mode-line-format term-old-mode-line-format)
(force-mode-line-update)
(setq term-pager-count new-count)
(set-process-filter process term-pager-old-filter)
(funcall term-pager-old-filter process "")
(continue-process process)))
(defun term-handle-scroll (down)
(let ((scroll-needed
(- (+ (term-current-row) down)
(if (< down 0) term-scroll-start term-scroll-end))))
(when (or (and (< down 0) (< scroll-needed 0))
(and (> down 0) (> scroll-needed 0)))
(let ((save-point (copy-marker (point))) (save-top))
(goto-char term-home-marker)
(cond (term-scroll-with-delete
(if (< down 0)
(progn
(term-vertical-motion term-scroll-end)
(end-of-line)
(setq save-top (point))
(term-vertical-motion scroll-needed)
(end-of-line)
(delete-region save-top (point))
(goto-char save-point)
(setq down (- scroll-needed down))
(term-vertical-motion down))
(term-vertical-motion term-scroll-start)
(setq save-top (point))
(term-vertical-motion scroll-needed)
(delete-region save-top (point))
(goto-char save-point)
(term-vertical-motion down)
(term-adjust-current-row-cache (- scroll-needed)))
(setq term-current-column nil)
(term-insert-char ?\n (abs scroll-needed)))
((and (numberp term-pager-count)
(< (setq term-pager-count (- term-pager-count down))
0))
(setq down 0)
(term-process-pager))
(t
(term-adjust-current-row-cache (- scroll-needed))
(term-vertical-motion scroll-needed)
(set-marker term-home-marker (point))))
(goto-char save-point)
(set-marker save-point nil))))
down)
(defun term-down (down &optional check-for-scroll)
"Move down DOWN screen lines vertically."
(let ((start-column (term-horizontal-column)))
(when (and check-for-scroll (or term-scroll-with-delete term-pager-count))
(setq down (term-handle-scroll down)))
(unless (and (= term-current-row 0) (< down 0))
(term-adjust-current-row-cache down)
(when (or (/= (point) (point-max)) (< down 0))
(setq down (- down (term-vertical-motion down)))))
(cond ((>= down 0)
(term-insert-char ?\n down)
(setq term-current-column 0)
(setq term-start-line-column 0))
(t
(when (= term-current-row 0)
(save-excursion (term-insert-char ?\n (- down)))
(save-excursion
(let (p)
(forward-line term-height)
(setq p (point))
(forward-line (- down))
(delete-region p (point)))))
(setq term-current-column 0)
(setq term-start-line-column (current-column))))
(when start-column
(term-move-columns start-column))))
(defun term-unwrap-line ()
(when (not (bolp)) (insert-before-markers ?\n)))
(defun term-erase-in-line (kind)
(when (= kind 1) (let ((cols (term-horizontal-column)) (saved-point (point)))
(term-vertical-motion 0)
(delete-region (point) saved-point)
(term-insert-char ? cols)))
(when (not (eq kind 1)) (let ((saved-point (point))
(wrapped (and (zerop (term-horizontal-column))
(not (zerop (term-current-column))))))
(term-vertical-motion 1)
(delete-region saved-point (point))
(when wrapped
(insert ? ))
(insert ?\n)
(put-text-property saved-point (point) 'face 'default)
(goto-char saved-point))))
(defun term-erase-in-display (kind)
"Erases (that is blanks out) part of the window.
If KIND is 0, erase from (point) to (point-max);
if KIND is 1, erase from home to point; else erase from home to point-max.
Should only be called when point is at the start of a screen line."
(term-handle-deferred-scroll)
(cond ((eq term-terminal-parameter 0)
(delete-region (point) (point-max))
(term-unwrap-line))
((let ((row (term-current-row))
(col (term-horizontal-column))
(start-region term-home-marker)
(end-region (if (eq kind 1) (point) (point-max))))
(delete-region start-region end-region)
(term-unwrap-line)
(when (eq kind 1)
(term-insert-char ?\n row))
(setq term-current-column nil)
(setq term-current-row nil)
(term-goto row col)))))
(defun term-delete-chars (count)
(let ((save-point (point)))
(term-vertical-motion 1)
(term-unwrap-line)
(goto-char save-point)
(move-to-column (+ (term-current-column) count) t)
(delete-region save-point (point))))
(defun term-insert-spaces (count)
(let ((save-point (point)) (save-eol) (pnt-at-eol))
(term-vertical-motion 1)
(when (bolp)
(backward-char))
(setq save-eol (point))
(save-excursion
(end-of-line)
(setq pnt-at-eol (point)))
(move-to-column (+ (term-start-line-column) (- term-width count)) t)
(when (>= (point) pnt-at-eol)
(put-text-property pnt-at-eol (point) 'face 'default))
(when (> save-eol (point))
(delete-region (point) save-eol))
(goto-char save-point)
(term-insert-char ? count)
(goto-char save-point)))
(defun term-delete-lines (lines)
(let ((start (point))
(save-current-column term-current-column)
(save-start-line-column term-start-line-column)
(save-current-row (term-current-row)))
(when (> (+ save-current-row lines) (1+ term-scroll-end))
(setq lines (- lines (- (+ save-current-row lines) (1+ term-scroll-end)))))
(term-down lines)
(delete-region start (point))
(term-down (- (1+ term-scroll-end) save-current-row lines))
(term-insert-char ?\n lines)
(setq term-current-column save-current-column)
(setq term-start-line-column save-start-line-column)
(setq term-current-row save-current-row)
(goto-char start)))
(defun term-insert-lines (lines)
(let ((start (point))
(start-deleted)
(save-current-column term-current-column)
(save-start-line-column term-start-line-column)
(save-current-row (term-current-row)))
(if (< save-current-row term-scroll-start)
(progn
(setq lines (- lines (- term-scroll-start save-current-row)))
(term-down (- term-scroll-start save-current-row))
(setq start (point)))
(when (> (+ save-current-row lines) (1+ term-scroll-end))
(setq lines (- lines (- (+ save-current-row lines)(1+ term-scroll-end)))))
(term-down (- (1+ term-scroll-end) save-current-row lines)))
(setq start-deleted (point))
(term-down lines)
(delete-region start-deleted (point))
(goto-char start)
(setq term-current-column save-current-column)
(setq term-start-line-column save-start-line-column)
(setq term-current-row save-current-row)
(term-insert-char ?\n lines)
(goto-char start)))
(defun term-start-output-log (name)
"Record raw inferior process output in a buffer."
(interactive (list (if term-log-buffer
nil
(read-buffer "Record output in buffer: "
(format "%s output-log"
(buffer-name (current-buffer)))
nil))))
(if (or (null name) (equal name ""))
(progn (setq term-log-buffer nil)
(message "Output logging off."))
(if (get-buffer name)
nil
(save-excursion
(set-buffer (get-buffer-create name))
(fundamental-mode)
(buffer-disable-undo (current-buffer))
(erase-buffer)))
(setq term-log-buffer (get-buffer name))
(message "Recording terminal emulator output into buffer \"%s\""
(buffer-name term-log-buffer))))
(defun term-stop-output-log ()
"Discontinue raw inferior process logging."
(interactive)
(term-start-output-log nil))
(defun term-show-maximum-output ()
"Put the end of the buffer at the bottom of the window."
(interactive)
(goto-char (point-max))
(recenter -1))
(defvar term-load-hook nil
"This hook is run when term is loaded in.
This is a good place to put keybindings.")
(run-hooks 'term-load-hook)
(defvar term-completion-autolist nil
"*If non-nil, automatically list possibilities on partial completion.
This mirrors the optional behavior of tcsh.")
(defvar term-completion-addsuffix t
"*If non-nil, add a `/' to completed directories, ` ' to file names.
If a cons pair, it should be of the form (DIRSUFFIX . FILESUFFIX) where
DIRSUFFIX and FILESUFFIX are strings added on unambiguous or exact
completion. This mirrors the optional behavior of tcsh.")
(defvar term-completion-recexact nil
"*If non-nil, use shortest completion if characters cannot be added.
This mirrors the optional behavior of tcsh.
A non-nil value is useful if `term-completion-autolist' is non-nil too.")
(defvar term-completion-fignore nil
"*List of suffixes to be disregarded during file completion.
This mirrors the optional behavior of bash and tcsh.
Note that this applies to `term-dynamic-complete-filename' only.")
(defvar term-file-name-prefix ""
"Prefix prepended to absolute file names taken from process input.
This is used by term's and shell's completion functions, and by shell's
directory tracking functions.")
(defun term-directory (directory)
(expand-file-name (if (file-name-absolute-p directory)
(concat term-file-name-prefix directory)
directory)))
(defun term-word (word-chars)
"Return the word of WORD-CHARS at point, or nil if none is found.
Word constituents are considered to be those in WORD-CHARS, which is like the
inside of a \"[...]\" (see `skip-chars-forward')."
(save-excursion
(let ((limit (point))
(word (concat "[" word-chars "]"))
(non-word (concat "[^" word-chars "]")))
(when (re-search-backward non-word nil 'move)
(forward-char 1))
(if (or (eolp) (looking-at non-word))
nil
(re-search-forward (concat word "+") limit)
(buffer-substring (match-beginning 0) (match-end 0))))))
(defun term-match-partial-filename ()
"Return the filename at point, or nil if none is found.
Environment variables are substituted. See `term-word'."
(let ((filename (term-word "~/A-Za-z0-9+@:_.$#,={}-")))
(and filename (substitute-in-file-name filename))))
(defun term-dynamic-complete ()
"Dynamically perform completion at point.
Calls the functions in `term-dynamic-complete-functions' to perform
completion until a function returns non-nil, at which point completion is
assumed to have occurred."
(interactive)
(let ((functions term-dynamic-complete-functions))
(while (and functions (null (funcall (car functions))))
(setq functions (cdr functions)))))
(defun term-dynamic-complete-filename ()
"Dynamically complete the filename at point.
Completes if after a filename. See `term-match-partial-filename' and
`term-dynamic-complete-as-filename'.
This function is similar to `term-replace-by-expanded-filename', except that
it won't change parts of the filename already entered in the buffer; it just
adds completion characters to the end of the filename. A completions listing
may be shown in a help buffer if completion is ambiguous.
Completion is dependent on the value of `term-completion-addsuffix',
`term-completion-recexact' and `term-completion-fignore', and the timing of
completions listing is dependent on the value of `term-completion-autolist'.
Returns t if successful."
(interactive)
(when (term-match-partial-filename)
(prog2 (or (eq (selected-window) (minibuffer-window))
(message "Completing file name..."))
(term-dynamic-complete-as-filename))))
(defun term-dynamic-complete-as-filename ()
"Dynamically complete at point as a filename.
See `term-dynamic-complete-filename'. Returns t if successful."
(let* ((completion-ignore-case nil)
(completion-ignored-extensions term-completion-fignore)
(success t)
(dirsuffix (cond ((not term-completion-addsuffix) "")
((not (consp term-completion-addsuffix)) "/")
(t (car term-completion-addsuffix))))
(filesuffix (cond ((not term-completion-addsuffix) "")
((not (consp term-completion-addsuffix)) " ")
(t (cdr term-completion-addsuffix))))
(filename (or (term-match-partial-filename) ""))
(pathdir (file-name-directory filename))
(pathnondir (file-name-nondirectory filename))
(directory (if pathdir (term-directory pathdir) default-directory))
(completion (file-name-completion pathnondir directory))
(mini-flag (eq (selected-window) (minibuffer-window))))
(cond ((null completion)
(message "No completions of %s" filename)
(setq success nil))
((eq completion t) (when term-completion-addsuffix (insert " "))
(or mini-flag (message "Sole completion")))
((string-equal completion "") (term-dynamic-list-filename-completions))
(t (let ((file (concat (file-name-as-directory directory) completion)))
(insert (substring (directory-file-name completion)
(length pathnondir)))
(cond ((symbolp (file-name-completion completion directory))
(insert (if (file-directory-p file) dirsuffix filesuffix))
(or mini-flag (message "Completed")))
((and term-completion-recexact term-completion-addsuffix
(string-equal pathnondir completion)
(file-exists-p file))
(insert (if (file-directory-p file) dirsuffix filesuffix))
(or mini-flag (message "Completed shortest")))
((or term-completion-autolist
(string-equal pathnondir completion))
(term-dynamic-list-filename-completions))
(t
(or mini-flag (message "Partially completed")))))))
success))
(defun term-replace-by-expanded-filename ()
"Dynamically expand and complete the filename at point.
Replace the filename with an expanded, canonicalized and completed replacement.
\"Expanded\" means environment variables (e.g., $HOME) and `~'s are replaced
with the corresponding directories. \"Canonicalized\" means `..' and `.' are
removed, and the filename is made absolute instead of relative. For expansion
see `expand-file-name' and `substitute-in-file-name'. For completion see
`term-dynamic-complete-filename'."
(interactive)
(replace-match (expand-file-name (term-match-partial-filename)) t t)
(term-dynamic-complete-filename))
(defun term-dynamic-simple-complete (stub candidates)
"Dynamically complete STUB from CANDIDATES list.
This function inserts completion characters at point by completing STUB from
the strings in CANDIDATES. A completions listing may be shown in a help buffer
if completion is ambiguous.
Returns nil if no completion was inserted.
Returns `sole' if completed with the only completion match.
Returns `shortest' if completed with the shortest of the completion matches.
Returns `partial' if completed as far as possible with the completion matches.
Returns `listed' if a completion listing was shown.
See also `term-dynamic-complete-filename'."
(let* ((completion-ignore-case nil)
(candidates (mapcar (function (lambda (x) (list x))) candidates))
(completions (all-completions stub candidates)))
(cond ((null completions)
(message "No completions of %s" stub)
nil)
((= 1 (length completions)) (let ((completion (car completions)))
(if (string-equal completion stub)
(message "Sole completion")
(insert (substring completion (length stub)))
(message "Completed"))
(when term-completion-addsuffix (insert " "))
'sole))
(t (let ((completion (try-completion stub candidates)))
(insert (substring completion (length stub)))
(cond ((and term-completion-recexact term-completion-addsuffix
(string-equal stub completion)
(member completion completions))
(insert " ")
(message "Completed shortest")
'shortest)
((or term-completion-autolist
(string-equal stub completion))
(term-dynamic-list-completions completions)
'listed)
(t
(message "Partially completed")
'partial)))))))
(defun term-dynamic-list-filename-completions ()
"List in help buffer possible completions of the filename at point."
(interactive)
(let* ((completion-ignore-case nil)
(filename (or (term-match-partial-filename) ""))
(pathdir (file-name-directory filename))
(pathnondir (file-name-nondirectory filename))
(directory (if pathdir (term-directory pathdir) default-directory))
(completions (file-name-all-completions pathnondir directory)))
(if completions
(term-dynamic-list-completions completions)
(message "No completions of %s" filename))))
(defun term-dynamic-list-completions (completions)
"List in help buffer sorted COMPLETIONS.
Typing SPC flushes the help buffer."
(let ((conf (current-window-configuration)))
(with-output-to-temp-buffer "*Completions*"
(display-completion-list (sort completions 'string-lessp)))
(message "Hit space to flush")
(let (key first)
(if (save-excursion
(set-buffer (get-buffer "*Completions*"))
(setq key (read-key-sequence nil)
first (aref key 0))
(and (consp first)
(eq (window-buffer (posn-window (event-start first)))
(get-buffer "*Completions*"))
(eq (key-binding key) 'mouse-choose-completion)))
(progn
(mouse-choose-completion first)
(set-window-configuration conf))
(if (eq first ?\s)
(set-window-configuration conf)
(setq unread-command-events (listify-key-sequence key)))))))
(defun term-ansi-make-term (name program &optional startfile &rest switches)
"Make a term process NAME in a buffer, running PROGRAM.
The name of the buffer is NAME.
If there is already a running process in that buffer, it is not restarted.
Optional third arg STARTFILE is the name of a file to send the contents of to
the process. Any more args are arguments to PROGRAM."
(let ((buffer (get-buffer-create name )))
(cond ((not (term-check-proc buffer))
(save-excursion
(set-buffer buffer)
(term-mode)) (term-exec buffer name program startfile switches)))
buffer))
(defvar term-ansi-buffer-name nil)
(defvar term-ansi-default-program nil)
(defvar term-ansi-buffer-base-name nil)
(defun ansi-term (program &optional new-buffer-name)
"Start a terminal-emulator in a new buffer."
(interactive (list (read-from-minibuffer "Run program: "
(or explicit-shell-file-name
(getenv "ESHELL")
(getenv "SHELL")
"/bin/sh"))))
(setq term-ansi-buffer-name
(if new-buffer-name
new-buffer-name
(if term-ansi-buffer-base-name
(if (eq term-ansi-buffer-base-name t)
(file-name-nondirectory program)
term-ansi-buffer-base-name)
"ansi-term")))
(setq term-ansi-buffer-name (concat "*" term-ansi-buffer-name "*"))
(setq term-ansi-buffer-name (generate-new-buffer-name term-ansi-buffer-name))
(setq term-ansi-buffer-name (term-ansi-make-term term-ansi-buffer-name program))
(set-buffer term-ansi-buffer-name)
(term-mode)
(term-char-mode)
(term-set-escape-char ?\C-x)
(switch-to-buffer term-ansi-buffer-name))
(provide 'term)