Fix some bugs based in eshell and vterm
After making my presentation on eshell, I encountered some bugs that needed addressing.
This commit is contained in:
parent
4df8279e20
commit
6a74607b85
2 changed files with 98 additions and 57 deletions
|
@ -413,35 +413,35 @@ I’m calling the ability to get a buffer contents, /flow/ (Fetch contents as Li
|
|||
- /as a string/ :: no conversion
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun eshell/flow (&rest args)
|
||||
"Output the contents of one or more buffers as a string.
|
||||
Usage: flow [OPTION] [BUFFER ...]
|
||||
-h, --help show this usage screen
|
||||
-l, --lines output contents as a list of lines
|
||||
-w, --words output contents as a list of space-separated elements "
|
||||
(let* ((options (eshell-getopts '((:name words :short "w" :long "words")
|
||||
(:name lines :short "l" :long "lines")
|
||||
(:name string :short "s" :long "string")
|
||||
(:name help :short "h" :long "help"
|
||||
:help eshell/flow))
|
||||
args))
|
||||
(buffers (gethash 'parameters options))
|
||||
(content (thread-last parameters
|
||||
(-map 'eshell-flow-buffer-contents)
|
||||
(s-join "\n"))))
|
||||
(if (gethash 'help options)
|
||||
(error (documentation 'eshell/flow))
|
||||
(defun eshell/flow (&rest args)
|
||||
"Output the contents of one or more buffers as a string.
|
||||
Usage: flow [OPTION] [BUFFER ...]
|
||||
-h, --help show this usage screen
|
||||
-l, --lines output contents as a list of lines
|
||||
-w, --words output contents as a list of space-separated elements "
|
||||
(let* ((options (eshell-getopts '((:name words :short "w" :long "words")
|
||||
(:name lines :short "l" :long "lines")
|
||||
(:name string :short "s" :long "string")
|
||||
(:name help :short "h" :long "help"
|
||||
:help eshell/flow))
|
||||
args))
|
||||
(buffers (gethash 'parameters options))
|
||||
(content (thread-last buffers
|
||||
(-map 'eshell-flow-buffer-contents)
|
||||
(s-join "\n"))))
|
||||
(if (gethash 'help options)
|
||||
(error (documentation 'eshell/flow))
|
||||
|
||||
;; No buffer specified? Use the default buffer's contents:
|
||||
(unless buffers
|
||||
(setq content
|
||||
(eshell-flow-buffer-contents ha-eshell-ebbflow-buffername)))
|
||||
;; No buffer specified? Use the default buffer's contents:
|
||||
(unless buffers
|
||||
(setq content
|
||||
(eshell-flow-buffer-contents ha-eshell-ebbflow-buffername)))
|
||||
|
||||
;; Do we need to convert the output to lines or split on words?
|
||||
(cond
|
||||
((gethash 'words options) (split-string content))
|
||||
((gethash 'lines options) (split-string content "\n"))
|
||||
(t content)))))
|
||||
;; Do we need to convert the output to lines or split on words?
|
||||
(cond
|
||||
((gethash 'words options) (split-string content))
|
||||
((gethash 'lines options) (split-string content "\n"))
|
||||
(t content)))))
|
||||
#+end_src
|
||||
|
||||
Straight-forward to acquire the contents of a buffer :
|
||||
|
@ -699,6 +699,7 @@ The [[https://github.com/joddie/pcre2el][pcre2el]] project can convert from a Li
|
|||
(regexp "[0-9]\\{1,2\\}")))
|
||||
(ipaddr (seq b256 "." b256 "." b256 "." b256))
|
||||
(time (seq digit (optional digit) ":" (= 2 digit) (optional ":" (= 2 digit))))
|
||||
(email (seq (1+ (regexp "[^,< ]")) "@" (1+ (seq (1+ (any alnum "-"))) ".") (1+ alnum)))
|
||||
(date (seq (= 2 digit) (or "/" "-") (= 2 digit) (or "/" "-") (= 4 digit)))
|
||||
(ymd (seq (= 4 digit) (or "/" "-") (= 2 digit) (or "/" "-") (= 2 digit)))
|
||||
(uuid (seq (= 8 hex) "-" (= 3 (seq (= 4 hex) "-")) (= 12 hex)))
|
||||
|
@ -1028,8 +1029,8 @@ This requires capture templates that don’t do any formatting. I will reused =c
|
|||
(defun ha-eshell-engineering-capture (capture-template comment cmd out)
|
||||
"Capture formatted string in CAPTURE-TEMPLATE.
|
||||
Base the string created on COMMENT, CMD, and OUT. Return OUTPUT."
|
||||
(let* ((command (s-trim cmd))
|
||||
(output (s-trim out))
|
||||
(let* ((command (when cmd (s-trim cmd)))
|
||||
(output (when out (s-trim out)))
|
||||
(results (concat
|
||||
(when comment (format "%s\n\n" comment))
|
||||
(when command (format "#+begin_src shell\n %s\n#+end_src\n\n" command))
|
||||
|
@ -1061,6 +1062,21 @@ This function simply calls [[help-org-capture][org-capture]] with [[info:org#Tem
|
|||
"Call `org-capture' with the `ee' template to enter text into the engineering notebook."
|
||||
(org-capture nil "ee"))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-eshell-target-engineering-notebook (output)
|
||||
"Write OUTPUT into the engineering notebook via `org-capture'."
|
||||
(ha-eshell-engineering-capture "ef" nil nil output))
|
||||
|
||||
(defun ha-eshell-target-clocked-in-task (output)
|
||||
"Write OUTPUT into the current clocked in task via `org-capture'."
|
||||
(ha-eshell-engineering-capture "cc" nil nil output))
|
||||
#+end_src
|
||||
And finally, add our new functions to [[elisp(describe-variable 'eshell-virtual-targets)][eshell-virtual-targets]]:
|
||||
#+begin_src emacs-lisp
|
||||
(add-to-list 'eshell-virtual-targets '("/dev/e" ha-eshell-target-engineering-notebook nil))
|
||||
(add-to-list 'eshell-virtual-targets '("/dev/c" ha-eshell-target-engineering-notebook nil))
|
||||
#+end_src
|
||||
* Special Prompt
|
||||
Following [[http://blog.liangzan.net/blog/2012/12/12/customizing-your-emacs-eshell-prompt/][these instructions]], we build a better prompt with the Git branch in it (Of course, it matches my Bash prompt). First, we need a function that returns a string with the Git branch in it, e.g. ":master"
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
|
|
|
@ -241,19 +241,16 @@ This is used in calls to =interactive= to select a host."
|
|||
Simply calling =vterm= fails to load my full environment, so this allows me to start the terminal in a particular directory (defaulting to the root of the current project):
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-shell (&optional directory)
|
||||
"Creates and tidies up a =vterm= terminal shell in side window."
|
||||
(interactive (list (read-directory-name "Starting Directory: " (projectile-project-root))))
|
||||
(let* ((win-name "Terminal")
|
||||
(buf-name (format "*%s*" win-name))
|
||||
(default-directory (or directory default-directory)))
|
||||
(setq ha-latest-ssh-window-name buf-name)
|
||||
(if (not (fboundp 'vterm))
|
||||
(make-term win-name ha-ssh-shell)
|
||||
(vterm buf-name)
|
||||
;; (ha-ssh-send "source ~/.bash_profile" buf-name)
|
||||
;; (ha-ssh-send "clear" buf-name)
|
||||
)))
|
||||
(defun ha-shell (&optional directory)
|
||||
"Creates and tidies up a =vterm= terminal shell in side window."
|
||||
(interactive (list (read-directory-name "Starting Directory: " (projectile-project-root))))
|
||||
(let* ((win-name (ha--terminal-name-from-dir directory))
|
||||
(buf-name (format "*%s*" win-name))
|
||||
(default-directory (or directory default-directory)))
|
||||
(setq ha-latest-ssh-window-name buf-name)
|
||||
(if (not (fboundp 'vterm))
|
||||
(make-term win-name ha-ssh-shell)
|
||||
(vterm buf-name))))
|
||||
#+end_src
|
||||
|
||||
Before we leave this section, I realize that I would like a way to /add/ to my list of hosts:
|
||||
|
@ -264,26 +261,54 @@ Before we leave this section, I realize that I would like a way to /add/ to my l
|
|||
(add-to-list 'ha-ssh-favorite-hostnames (cons hostname ip-address)))
|
||||
#+end_src
|
||||
** Programmatic Interface
|
||||
Let’s send stuff to it:
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-shell-send (command &optional directory)
|
||||
"Send COMMAND to existing shell based on DIRECTORY.
|
||||
If the shell doesn't already exist, start on up by calling
|
||||
the `ha-shell' function."
|
||||
(let* ((win-name (ha--terminal-name-from-dir directory))
|
||||
(win-rx (rx "*" (literal win-name) "*"))
|
||||
(bufs (seq-filter (lambda (b) (when (string-match win-rx (buffer-name b)) b))
|
||||
(buffer-list)))
|
||||
(buf (first bufs)))
|
||||
(unless buf
|
||||
(setq buf (ha-shell directory)))
|
||||
(ha-ssh-send command buf)))
|
||||
|
||||
(defun ha--terminal-name-from-dir (&optional directory)
|
||||
"Return an appropriate title for a terminal based on DIRECTORY.
|
||||
If DIRECTORY is nil, use the `projectile-project-name'."
|
||||
(unless directory
|
||||
(setq directory (projectile-project-name)))
|
||||
(format "Terminal: %s" (file-name-base (directory-file-name directory))))
|
||||
|
||||
(ert-deftest ha--terminal-name-from-dir-test ()
|
||||
(should
|
||||
(string= (ha--terminal-name-from-dir "~/other/hamacs/") "Terminal: hamacs"))
|
||||
(should
|
||||
(string= (ha--terminal-name-from-dir) "Terminal: hamacs")))
|
||||
#+end_src
|
||||
|
||||
The previous functions (as well as my own end of sprint demonstrations) often need to issue some commands to a running terminal session, which is a simple wrapper around a /send text/ and /send return/ sequence:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-ssh-send (phrase &optional window-name)
|
||||
"Send command PHRASE to the currently running SSH instance.
|
||||
If you want to refer to another session, specify the correct WINDOW-NAME.
|
||||
This is really useful for scripts and demonstrations."
|
||||
(unless window-name
|
||||
(setq window-name ha-latest-ssh-window-name))
|
||||
(defun ha-ssh-send (phrase &optional window-name)
|
||||
"Send command PHRASE to the currently running SSH instance.
|
||||
If you want to refer to another session, specify the correct WINDOW-NAME.
|
||||
This is really useful for scripts and demonstrations."
|
||||
(unless window-name
|
||||
(setq window-name ha-latest-ssh-window-name))
|
||||
(save-window-excursion
|
||||
(pop-to-buffer window-name)
|
||||
|
||||
(pop-to-buffer window-name)
|
||||
|
||||
(if (fboundp 'vterm)
|
||||
(progn
|
||||
(vterm-send-string phrase)
|
||||
(vterm-send-return))
|
||||
(progn
|
||||
(term-send-raw-string phrase)
|
||||
(term-send-input))))
|
||||
(if (fboundp 'vterm)
|
||||
(progn
|
||||
(vterm-send-string phrase)
|
||||
(vterm-send-return))
|
||||
(progn
|
||||
(term-send-raw-string phrase)
|
||||
(term-send-input)))))
|
||||
#+end_src
|
||||
|
||||
On the rare occasion that I write a shell script, or at least, need to execute some one-line shell commands from some document, I have a function that combines a /read line from buffer/ and then send it to the currently running terminal:
|
||||
|
|
Loading…
Reference in a new issue