Support directory tracking with OSC 7
* eat.el: Require 'url'. * eat.el (eat-enable-directory-tracking): New user option. * eat.el (eat--t-term): New slots: 'cwd' and 'set-cwd-fn'. * eat.el (eat--t-set-cwd, eat-term-cwd): New function. * eat.el (eat-term-set-cwd-function): New function and generalized variable. * eat.el (eat--t-handle-output): Handle OSC 7. * eat.el (eat--set-cwd): New function. * eat.el (eat-exec): Use 'eat--set-cwd' to change current working directory. * eat.el (eat--eshell-invocation-directory): New variable, local in Eshell buffers when 'eat-eshell-mode' is enabled. * eat.el (eat--eshell-setup-proc-and-term): Save the invocation directory of process. * eat.el (eat--eshell-cleanup): Revert working directory to invocation directory. * eat.el (eat--eshell-local-mode): When enabling, make 'eat--eshell-invocation-directory' local variable and kill when disabling. * eat-tests.el (eat-test-set-cwd): New test. * eat.texi (Directory Tracking): New chapter.
This commit is contained in:
parent
29a6ab9141
commit
eac1165a1a
3 changed files with 136 additions and 6 deletions
24
eat-tests.el
24
eat-tests.el
|
@ -5748,6 +5748,30 @@ Write plain text and newline to move cursor."
|
|||
"frob")
|
||||
:cursor '(1 . 4))))
|
||||
|
||||
(ert-deftest eat-test-set-cwd ()
|
||||
"Test setting current working directory."
|
||||
(eat--tests-with-term '()
|
||||
(let ((cwd default-directory))
|
||||
(should (string= (eat-term-cwd (terminal)) default-directory))
|
||||
(setf (eat-term-set-cwd-function (terminal))
|
||||
(lambda (term dir)
|
||||
(should (eq term (terminal)))
|
||||
(setq cwd dir)))
|
||||
;; file://HOST/PATH/.
|
||||
(output (format "\e]7;file://%s/foo/bar/\e\\" (system-name)))
|
||||
(should (string= cwd "/foo/bar/"))
|
||||
(should (string= (eat-term-cwd (terminal)) "/foo/bar/"))
|
||||
;; file://HOST/PATH (note the missing trailing slash).
|
||||
(output (format "\e]7;file://%s/bar/baz\a" (system-name)))
|
||||
(should (string= cwd "/bar/baz/"))
|
||||
(should (string= (eat-term-cwd (terminal)) "/bar/baz/"))
|
||||
;; file://SOME-OTHER-HOST/PATH/
|
||||
(output (format "\e]7;file://%s/baz/foo/\e\\"
|
||||
(if (string= (system-name) "foo") "bar" "foo")))
|
||||
(should (string= cwd "/bar/baz/"))
|
||||
(should (string= (eat-term-cwd (terminal)) "/bar/baz/"))
|
||||
(should-term :cursor '(1 . 1)))))
|
||||
|
||||
|
||||
;;;;; Input Event Tests.
|
||||
|
||||
|
|
85
eat.el
85
eat.el
|
@ -81,6 +81,7 @@
|
|||
(require 'cl-lib)
|
||||
(require 'ansi-color)
|
||||
(require 'shell)
|
||||
(require 'url)
|
||||
|
||||
|
||||
;;;; User Options.
|
||||
|
@ -139,6 +140,16 @@ This is left disabled for security reasons."
|
|||
:group 'eat-ui
|
||||
:group 'eat-eshell)
|
||||
|
||||
(defcustom eat-enable-directory-tracking t
|
||||
"Non-nil means do directory tracking.
|
||||
|
||||
When non-nil, Eat will track the working directory of program. You
|
||||
need to configure the program to send current working directory
|
||||
information."
|
||||
:type 'boolean
|
||||
:group 'eat-ui
|
||||
:group 'eat-eshell)
|
||||
|
||||
(defconst eat--cursor-type-value-type
|
||||
(let ((cur-type
|
||||
'(choice
|
||||
|
@ -647,6 +658,9 @@ For example: when THRESHOLD is 3, \"*foobarbaz\" is converted to
|
|||
(begin nil :documentation "Beginning of terminal.")
|
||||
(end nil :documentation "End of terminal area.")
|
||||
(title "" :documentation "The title of the terminal.")
|
||||
(cwd
|
||||
default-directory
|
||||
:documentation "The working directory of the terminal.")
|
||||
(bell-fn
|
||||
(1value #'ignore)
|
||||
:documentation "Function to ring the bell.")
|
||||
|
@ -662,6 +676,9 @@ For example: when THRESHOLD is 3, \"*foobarbaz\" is converted to
|
|||
(set-title-fn
|
||||
(1value #'ignore)
|
||||
:documentation "Function to set title.")
|
||||
(set-cwd-fn
|
||||
(1value #'ignore)
|
||||
:documentation "Function to set the current working directory.")
|
||||
(grab-mouse-fn
|
||||
(1value #'ignore)
|
||||
:documentation "Function to grab mouse.")
|
||||
|
@ -2189,6 +2206,25 @@ MODE should be one of nil and `x10', `normal', `button-event',
|
|||
;; Inform the UI.
|
||||
(funcall (eat--t-term-set-title-fn eat--t-term) eat--t-term title))
|
||||
|
||||
(defun eat--t-set-cwd (url)
|
||||
"Set the working directory of terminal to URL.
|
||||
|
||||
URL should be a URL in the format \"file://HOST/CWD/\"; HOST can be
|
||||
empty."
|
||||
(message "%S" url)
|
||||
(let ((obj (url-generic-parse-url url)))
|
||||
(when (and (string= (url-type obj) "file")
|
||||
(or (null (url-host obj))
|
||||
(string= (url-host obj) (system-name))))
|
||||
(let ((dir (expand-file-name
|
||||
(file-name-as-directory
|
||||
(url-unhex-string (url-filename obj))))))
|
||||
;; Update working directory.
|
||||
(setf (eat--t-term-cwd eat--t-term) dir)
|
||||
;; Inform the UI.
|
||||
(funcall (eat--t-term-set-cwd-fn eat--t-term)
|
||||
eat--t-term dir)))))
|
||||
|
||||
(defun eat--t-send-device-attrs (params format)
|
||||
"Return device attributes.
|
||||
|
||||
|
@ -2701,6 +2737,11 @@ DATA is the selection data encoded in base64."
|
|||
(let title (zero-or-more anything))
|
||||
string-end)
|
||||
(eat--t-set-title title))
|
||||
;; OSC 7 ; <t> ST.
|
||||
((rx string-start ?7 ?\;
|
||||
(let url (zero-or-more anything))
|
||||
string-end)
|
||||
(eat--t-set-cwd url))
|
||||
;; OSC 10 ; ? ST.
|
||||
("10;?"
|
||||
(eat--t-report-foreground-color))
|
||||
|
@ -2971,6 +3012,24 @@ FUNCTION), where FUNCTION is the function to set title."
|
|||
(gv-define-setter eat-term-set-title-function (function terminal)
|
||||
`(setf (eat--t-term-set-title-fn ,terminal) ,function))
|
||||
|
||||
(defun eat-term-cwd (terminal)
|
||||
"Return the current working directory of TERMINAL."
|
||||
(eat--t-term-cwd terminal))
|
||||
|
||||
(defun eat-term-set-cwd-function (terminal)
|
||||
"Return the function used to set the working directory of TERMINAL.
|
||||
|
||||
The function is called with two arguments, TERMINAL and the new
|
||||
\(current) working directory of TERMINAL. The function should not
|
||||
change point and buffer restriction.
|
||||
|
||||
To set it, use (`setf' (`eat-term-set-cwd-function' TERMINAL)
|
||||
FUNCTION), where FUNCTION is the function to set title."
|
||||
(eat--t-term-set-cwd-fn terminal))
|
||||
|
||||
(gv-define-setter eat-term-set-cwd-function (function terminal)
|
||||
`(setf (eat--t-term-set-cwd-fn ,terminal) ,function))
|
||||
|
||||
(defun eat-term-grab-mouse-function (terminal)
|
||||
"Return the function used to grab the mouse.
|
||||
|
||||
|
@ -4185,6 +4244,12 @@ selection, or nil if none."
|
|||
"Ring the bell."
|
||||
(ding t))
|
||||
|
||||
(defun eat--set-cwd (_ cwd)
|
||||
"Set CWD as the current working directory (`default-directory')."
|
||||
(when eat-enable-directory-tracking
|
||||
(ignore-errors
|
||||
(cd-absolute cwd))))
|
||||
|
||||
|
||||
;;;;; Major Mode.
|
||||
|
||||
|
@ -4488,7 +4553,8 @@ same Eat buffer. The hook `eat-exec-hook' is run after each exec."
|
|||
#'eat--grab-mouse
|
||||
(eat-term-manipulate-selection-function eat--terminal)
|
||||
#'eat--manipulate-kill-ring
|
||||
(eat-term-ring-bell-function eat--terminal) #'eat--bell)
|
||||
(eat-term-ring-bell-function eat--terminal) #'eat--bell
|
||||
(eat-term-set-cwd-function eat--terminal) #'eat--set-cwd)
|
||||
;; Crank up a new process.
|
||||
(let* ((size (eat-term-size eat--terminal))
|
||||
(process-environment
|
||||
|
@ -4702,6 +4768,9 @@ PROGRAM can be a shell command."
|
|||
|
||||
;;;;; Process Handling.
|
||||
|
||||
(defvar eat--eshell-invocation-directory nil
|
||||
"The directory from where the current process was started.")
|
||||
|
||||
(defvar eshell-last-output-start) ; In `esh-mode'.
|
||||
(defvar eshell-last-output-end) ; In `esh-mode'.
|
||||
|
||||
|
@ -4732,7 +4801,8 @@ PROGRAM can be a shell command."
|
|||
(defun eat--eshell-setup-proc-and-term (proc)
|
||||
"Setup process PROC and a new terminal for it."
|
||||
(unless (or eat--terminal eat--process)
|
||||
(setq eat--process proc)
|
||||
(setq eat--process proc
|
||||
eat--eshell-invocation-directory default-directory)
|
||||
(process-put proc 'adjust-window-size-function
|
||||
#'eat--adjust-process-window-size)
|
||||
(setq eat--terminal (eat-term-make (current-buffer)
|
||||
|
@ -4745,20 +4815,22 @@ PROGRAM can be a shell command."
|
|||
#'eat--grab-mouse
|
||||
(eat-term-manipulate-selection-function eat--terminal)
|
||||
#'eat--manipulate-kill-ring
|
||||
(eat-term-ring-bell-function eat--terminal) #'eat--bell)
|
||||
(eat-term-ring-bell-function eat--terminal) #'eat--bell
|
||||
(eat-term-set-cwd-function eat--terminal) #'eat--set-cwd)
|
||||
(when-let* ((window (get-buffer-window nil t)))
|
||||
(with-selected-window window
|
||||
(eat-term-resize eat--terminal (window-max-chars-per-line)
|
||||
(window-text-height))))
|
||||
(eat-term-redisplay eat--terminal)
|
||||
(make-local-variable 'eshell-output-filter-functions)
|
||||
(setq eshell-output-filter-functions '(eat--eshell-output-filter))
|
||||
(setq-local eshell-output-filter-functions
|
||||
'(eat--eshell-output-filter))
|
||||
(eat-eshell-semi-char-mode)))
|
||||
|
||||
(defun eat--eshell-cleanup ()
|
||||
"Cleanup everything."
|
||||
(when eat--terminal
|
||||
(let ((inhibit-read-only t))
|
||||
(cd-absolute eat--eshell-invocation-directory)
|
||||
(goto-char (eat-term-end eat--terminal))
|
||||
(unless (or (= (point) (point-min))
|
||||
(= (char-before) ?\n))
|
||||
|
@ -4923,7 +4995,8 @@ sane 2>%s ; if [ $1 = .. ]; then shift; fi; exec \"$@\""
|
|||
eat--mouse-grabbing-type
|
||||
eat--pending-output-chunks
|
||||
eat--output-queue-first-chunk-time
|
||||
eat--process-output-queue-timer)))
|
||||
eat--process-output-queue-timer
|
||||
eat--eshell-invocation-directory)))
|
||||
(cond
|
||||
(eat--eshell-local-mode
|
||||
(mapc #'make-local-variable locals)
|
||||
|
|
33
eat.texi
33
eat.texi
|
@ -70,6 +70,7 @@ Advanced Customizations
|
|||
* Cursor Types:: Cursor can displayed in many forms.
|
||||
* Mouse Tracking:: Eat tracks mouse, but this can be changed.
|
||||
* Clipboard:: Integrating kill ring with terminal.
|
||||
* Directory Tracking:: Tracking the working directory of program.
|
||||
* Colors:: Eat can show more than sixteen million colors.
|
||||
* Fonts:: Eat can show up to sixty font different fonts.
|
||||
* Blinking Text:: Annoying blinking texts.
|
||||
|
@ -470,6 +471,38 @@ non-@code{nil}, programs can receive the kill ring contents. This is
|
|||
disabled by default for security reasons.
|
||||
@end defopt
|
||||
|
||||
@node Directory Tracking
|
||||
@cindex directory tracking
|
||||
@cindex tracking directory
|
||||
@cindex working directory tracking
|
||||
@cindex tracking working directory
|
||||
@cindex cwd tracking
|
||||
@cindex tracking cwd
|
||||
@chapter Directory Tracking
|
||||
|
||||
Eat can track the current working directory of the program. This also
|
||||
works in Eshell, but after the program exits, the current working
|
||||
directory is changed back to the directory from where the program was
|
||||
invoked.
|
||||
|
||||
To track, Eat needs the program to send this information. So, to
|
||||
enable directory tracking, you'll need to setup your shell. You'll
|
||||
need to arrange that your shell sends appropriate escape sequence at
|
||||
each prompt, for example with the command:
|
||||
|
||||
@example
|
||||
printf "\\e]7;file://%s%s\\e\\\\" "$HOSTNAME" "$PWD"
|
||||
@end example
|
||||
|
||||
If you don't want Eat to track your program's working directory, you
|
||||
can set the following to nil:
|
||||
|
||||
@vindex eat-enable-directory-tracking
|
||||
@defopt eat-enable-directory-tracking
|
||||
This controls directory tracking. When set to non-@code{nil}, Eat
|
||||
tracks the current working directory of programs.
|
||||
@end defopt
|
||||
|
||||
@node Colors
|
||||
@cindex colors
|
||||
@cindex customizing colors
|
||||
|
|
Loading…
Add table
Reference in a new issue