83 lines
3.8 KiB
EmacsLisp
83 lines
3.8 KiB
EmacsLisp
|
;;; Term
|
||
|
|
||
|
;;; TODO: Report `term-char-mode' fix upstream.
|
||
|
;;;
|
||
|
;;; Originally, `term-char-mode' check if point is after `pmark' and if it is,
|
||
|
;;; it cuts the characters between pmark and point and sends them to the
|
||
|
;;; terminal. The idea is that when you write a commandline in char mode, then
|
||
|
;;; switch to line mode and keep on writing _without moving the point_, you can
|
||
|
;;; go back to char mode and keep the modifications.
|
||
|
;;;
|
||
|
;;; I'd say this is rather useless as the point of line mode is to _move
|
||
|
;;; around_, not to do the same thing you can do in char mode.
|
||
|
;;;
|
||
|
;;; The more sensical thing to do: replace char-mode's commandline with
|
||
|
;;; line-mode's commandline and move char-mode point to where line-mode point
|
||
|
;;; is.
|
||
|
(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)
|
||
|
;; FIXME: Emit message? Cf. elisp-raw-message
|
||
|
(when (term-in-line-mode)
|
||
|
(setq term-old-mode-map (current-local-map))
|
||
|
(use-local-map term-raw-map)
|
||
|
(easy-menu-add term-terminal-menu)
|
||
|
(easy-menu-add term-signals-menu)
|
||
|
(let* (last-prompt
|
||
|
commandline
|
||
|
commandline-end-position
|
||
|
(line-mode-point (point))
|
||
|
(proc (get-buffer-process (current-buffer)))
|
||
|
(pmark (process-mark proc)))
|
||
|
(save-excursion
|
||
|
(goto-char (point-max))
|
||
|
(when (= (line-beginning-position) (line-end-position))
|
||
|
;; Sometimes a spurious newline gets inserted.
|
||
|
;; Work around it by skipping back past it.
|
||
|
(ignore-errors (backward-char)))
|
||
|
(setq
|
||
|
;; If the prompt regexp is wrong or if we are on a multiline prompt, get the line-beginning-position.
|
||
|
last-prompt (max (term-bol nil) (line-beginning-position))
|
||
|
;; Yank last commandline. If prompt is not properly recognized, it yanks the whole line.
|
||
|
commandline (buffer-substring-no-properties last-prompt (line-end-position))
|
||
|
;; We store the end-position here so that we don't have to wait for the
|
||
|
;; process when we send the commandline.
|
||
|
commandline-end-position (line-end-position)))
|
||
|
|
||
|
(when (and (>= (point) last-prompt)
|
||
|
;; commandline can be empty (e.g. term is still initializing),
|
||
|
;; then no need to continue.
|
||
|
(not (string-empty-p commandline)))
|
||
|
;; Clear line.
|
||
|
(dotimes (_ (abs (- last-prompt pmark)))
|
||
|
(term-send-backspace))
|
||
|
;; Point could be before line-end-position, so we need to delete the trailing characters.
|
||
|
(dotimes (_ (abs (- (point-max) pmark)))
|
||
|
(term-send-del))
|
||
|
;; Get prompt position with `process-mark'.
|
||
|
;; TODO: We need to wait a bit to make sure the previously-sent deletions have been processed.
|
||
|
;; This is brittle and it makes the prompt flicker once.
|
||
|
;; It is possible to work-around this: either use `term-prompt-regexp'
|
||
|
;; or send `term-left' enough times, wait and get it. That latter
|
||
|
;; solution has the advantage that it does not flickers, but it won't
|
||
|
;; work on dash.
|
||
|
(sleep-for 0 100)
|
||
|
(setq pmark (process-mark proc))
|
||
|
;; Remove actual prompt length from the commandline.
|
||
|
(setq commandline (substring commandline (- pmark last-prompt)))
|
||
|
;; Send commandline to term.
|
||
|
(term-send-raw-string commandline)
|
||
|
|
||
|
;; Move char-mode point to line-mode point. TODO: Don't do this if shell does not support cursor moves.
|
||
|
;; Underlying shell can be retrieved with:
|
||
|
;; (car (last (process-command (get-buffer-process (current-buffer)))))
|
||
|
(dotimes (_ (abs (- line-mode-point commandline-end-position)))
|
||
|
(term-send-left)))
|
||
|
|
||
|
;; Finish up.
|
||
|
(term-update-mode-line))))
|
||
|
|
||
|
(provide 'init-term)
|