2020-02-08 17:00:31 +01:00
|
|
|
;;; vterm-mgt.el --- Help me manage my vterm instances -*- lexical-binding: t -*-
|
2020-08-31 15:40:34 +02:00
|
|
|
|
2020-02-08 17:00:31 +01:00
|
|
|
;; Author: William Carroll <wpcarro@gmail.com>
|
2020-08-31 15:40:34 +02:00
|
|
|
;; Version: 0.0.1
|
|
|
|
;; Package-Requires: ((emacs "25.1"))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
;; Supporting functions to instantiate vterm buffers, kill existing vterm
|
|
|
|
;; buffers, rename vterm buffers, cycle forwards and backwards through vterm
|
|
|
|
;; buffers.
|
|
|
|
;;
|
|
|
|
;; Many of the functions defined herein are intended to be bound to
|
|
|
|
;; `vterm-mode-map'. Some assertions are made to guard against calling
|
|
|
|
;; functions that are intended to be called from outside of a vterm buffer.
|
|
|
|
;; These assertions shouldn't error when the functions are bound to
|
|
|
|
;; `vterm-mode-map'. If for some reason, you'd like to bind these functions to
|
|
|
|
;; a separate keymap, caveat emptor.
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Dependencies
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(require 'dash)
|
|
|
|
(require 'cycle)
|
|
|
|
(require 'vterm)
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Configuration
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
2020-09-06 14:47:04 +02:00
|
|
|
(defgroup vterm-mgt nil
|
|
|
|
"Customization options for `vterm-mgt'.")
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defcustom vterm-mgt-scroll-on-focus nil
|
2020-09-06 14:47:04 +02:00
|
|
|
"When t, call `end-of-buffer' after focusing a vterm instance."
|
|
|
|
:type '(boolean)
|
|
|
|
:group 'vterm-mgt)
|
|
|
|
|
|
|
|
(defconst vterm-mgt--instances (cycle-new)
|
|
|
|
"A cycle tracking all of my vterm instances.")
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defun vterm-mgt--instance? (b)
|
|
|
|
"Return t if the buffer B is a vterm instance."
|
|
|
|
(equal 'vterm-mode (buffer-local-value 'major-mode b)))
|
|
|
|
|
|
|
|
(defmacro vterm-mgt--assert-vterm-buffer ()
|
|
|
|
"Error when the `current-buffer' is not a vterm buffer."
|
2020-08-31 18:05:31 +02:00
|
|
|
'(prelude-assert (vterm-mgt--instance? (current-buffer))))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defun vterm-mgt-next ()
|
|
|
|
"Replace the current buffer with the next item in `vterm-mgt--instances'.
|
|
|
|
This function should be called from a buffer running vterm."
|
|
|
|
(interactive)
|
|
|
|
(vterm-mgt--assert-vterm-buffer)
|
2021-12-24 17:47:16 +01:00
|
|
|
(vterm-mgt-reconcile-state)
|
2020-09-01 11:17:43 +02:00
|
|
|
(cycle-focus-item (current-buffer) vterm-mgt--instances)
|
|
|
|
(switch-to-buffer (cycle-next vterm-mgt--instances))
|
2020-02-08 17:00:31 +01:00
|
|
|
(when vterm-mgt-scroll-on-focus (end-of-buffer)))
|
|
|
|
|
|
|
|
(defun vterm-mgt-prev ()
|
|
|
|
"Replace the current buffer with the previous item in `vterm-mgt--instances'.
|
|
|
|
This function should be called from a buffer running vterm."
|
|
|
|
(interactive)
|
|
|
|
(vterm-mgt--assert-vterm-buffer)
|
2021-12-24 17:47:16 +01:00
|
|
|
(vterm-mgt-reconcile-state)
|
2020-09-01 11:17:43 +02:00
|
|
|
(cycle-focus-item (current-buffer) vterm-mgt--instances)
|
|
|
|
(switch-to-buffer (cycle-prev vterm-mgt--instances))
|
2020-02-08 17:00:31 +01:00
|
|
|
(when vterm-mgt-scroll-on-focus (end-of-buffer)))
|
|
|
|
|
|
|
|
(defun vterm-mgt-instantiate ()
|
|
|
|
"Create a new vterm instance.
|
|
|
|
|
|
|
|
Prefer calling this function instead of `vterm'. This function ensures that the
|
|
|
|
newly created instance is added to `vterm-mgt--instances'.
|
|
|
|
|
|
|
|
If however you must call `vterm', if you'd like to cycle through vterm
|
2021-12-24 17:47:16 +01:00
|
|
|
instances, make sure you call `vterm-mgt-reconcile-state' to allow vterm-mgt
|
|
|
|
to collect any untracked vterm instances."
|
2020-02-08 17:00:31 +01:00
|
|
|
(interactive)
|
2021-12-24 17:47:16 +01:00
|
|
|
(vterm-mgt-reconcile-state)
|
|
|
|
(let ((buffer (vterm t)))
|
2020-09-01 11:17:43 +02:00
|
|
|
(cycle-append buffer vterm-mgt--instances)
|
|
|
|
(cycle-focus-item buffer vterm-mgt--instances)))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defun vterm-mgt-kill ()
|
|
|
|
"Kill the current buffer and remove it from `vterm-mgt--instances'.
|
|
|
|
This function should be called from a buffer running vterm."
|
|
|
|
(interactive)
|
|
|
|
(vterm-mgt--assert-vterm-buffer)
|
2021-12-24 17:47:16 +01:00
|
|
|
(let* ((buffer (current-buffer)))
|
|
|
|
(when (kill-buffer buffer)
|
|
|
|
(vterm-mgt-reconcile-state))))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defun vterm-mgt-find-or-create ()
|
|
|
|
"Call `switch-to-buffer' on a focused vterm instance if there is one.
|
|
|
|
|
2020-09-01 11:17:43 +02:00
|
|
|
When `cycle-focused?' returns nil, focus the first item in the cycle. When
|
2020-02-08 17:00:31 +01:00
|
|
|
there are no items in the cycle, call `vterm-mgt-instantiate' to create a vterm
|
|
|
|
instance."
|
|
|
|
(interactive)
|
2021-12-24 17:47:16 +01:00
|
|
|
(vterm-mgt-reconcile-state)
|
2020-09-01 11:17:43 +02:00
|
|
|
(if (cycle-empty? vterm-mgt--instances)
|
2020-02-08 17:00:31 +01:00
|
|
|
(vterm-mgt-instantiate)
|
2020-09-01 11:17:43 +02:00
|
|
|
(if (cycle-focused? vterm-mgt--instances)
|
|
|
|
(switch-to-buffer (cycle-current vterm-mgt--instances))
|
2020-02-08 17:00:31 +01:00
|
|
|
(progn
|
2020-09-01 11:17:43 +02:00
|
|
|
(cycle-jump 0 vterm-mgt--instances)
|
|
|
|
(switch-to-buffer (cycle-current vterm-mgt--instances))))))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
|
|
|
(defun vterm-mgt-rename-buffer (name)
|
|
|
|
"Rename the current buffer ensuring that its NAME is wrapped in *vterm*<...>.
|
|
|
|
This function should be called from a buffer running vterm."
|
|
|
|
(interactive "SRename vterm buffer: ")
|
|
|
|
(vterm-mgt--assert-vterm-buffer)
|
2021-12-24 17:47:16 +01:00
|
|
|
(rename-buffer (format "*vterm*<%s>" name)))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
2021-12-24 17:47:16 +01:00
|
|
|
(defun vterm-mgt-reconcile-state ()
|
2020-02-08 17:00:31 +01:00
|
|
|
"Fill `vterm-mgt--instances' with the existing vterm buffers.
|
|
|
|
|
|
|
|
If for whatever reason, the state of `vterm-mgt--instances' is corrupted and
|
|
|
|
misaligns with the state of vterm buffers in Emacs, use this function to
|
2020-09-06 14:47:04 +02:00
|
|
|
restore the state."
|
2020-02-08 17:00:31 +01:00
|
|
|
(interactive)
|
|
|
|
(setq vterm-mgt--instances
|
|
|
|
(->> (buffer-list)
|
|
|
|
(-filter #'vterm-mgt--instance?)
|
2020-09-01 11:17:43 +02:00
|
|
|
cycle-from-list)))
|
2020-02-08 17:00:31 +01:00
|
|
|
|
2021-12-24 17:47:16 +01:00
|
|
|
(defun vterm-mgt-select ()
|
|
|
|
"Select a vterm instance by name from the list in `vterm-mgt--instances'."
|
|
|
|
(interactive)
|
|
|
|
(vterm-mgt-reconcile-state)
|
|
|
|
(switch-to-buffer
|
|
|
|
(buffer-find-or-create
|
|
|
|
(completing-read "Switch to vterm: "
|
|
|
|
(->> vterm-mgt--instances
|
|
|
|
cycle-to-list
|
|
|
|
(-map #'buffer-name))))))
|
|
|
|
|
2020-02-08 17:00:31 +01:00
|
|
|
(provide 'vterm-mgt)
|
|
|
|
;;; vterm-mgt.el ends here
|