Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 164 additions & 52 deletions equake.el
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@
(expand-file-name "equake-persistent-display" user-emacs-directory)
"A file to store memorized DISPLAY in.")

(defvar equake-saved-layout-file
(expand-file-name "equake-saved-layout" user-emacs-directory)
"A file to store saved layout file in.")

(defgroup equake ()
"Equake, a drop-down console for eshell and terminal emulation."
:group 'shell)
Expand Down Expand Up @@ -337,6 +341,11 @@
:type 'symbol
:group 'equake)

(defcustom equake-append-shell-type-to-tab-name 'nil
"If true, append shell type to autogenerated tab name."
:type 'boolean
:group 'equake)

(defcustom equake-default-sh-command ""
"Default shell command used by `(ansi-)term' in Equake tab.
If set to empty string, Equake will fall back to system's default SHELL
Expand Down Expand Up @@ -413,7 +422,7 @@ background colour."

(defun equake-kill-emacs-advice (&rest _)
"Ask whether a user wants to kill an Equake frame.

s
Intended as `:before-while' advice for
`save-buffers-kill-terminal'"
(or (not (frame-parameter nil 'equakep))
Expand Down Expand Up @@ -442,12 +451,12 @@ Intended as `:before-while' advice for
(equake-ask-before-closing-equake)
(save-buffers-kill-terminal)))

(defun equake-invoke ()
(defun equake-invoke (&optional monitor)
"Toggle Equake frames.
Run with \"emacsclient -n -e '(equake-invoke)'\"."
(interactive)
(equake--select-some-graphic-frame)
(let* ((monitor (equake--get-monitor))
(let* ((monitor (or monitor (equake--get-monitor)))
(current-equake-frame (alist-get monitor equake--frame)))
(if (frame-live-p current-equake-frame)
(if (frame-visible-p current-equake-frame)
Expand All @@ -460,6 +469,9 @@ Run with \"emacsclient -n -e '(equake-invoke)'\"."
(defvar equake--tab-list ()
"A monitor to tab list mapping.")

(defvar equake--tab-to-shell-mapping ()
"A Equake buffer to shell-type mapping.")

(defvar equake--max-tab-no ()
"A monitor to maximum tab number mapping.

Expand All @@ -474,27 +486,41 @@ Needed to assign a new name for a new tab (e.g. its number)")
(ido-completing-read "Choose shell:"
equake-available-shells 'nil 't 'nil 'nil)))))

(defun equake-new-tab (&optional override)
"Open a new shell tab on monitor, optionally OVERRIDE default shell."
(defun equake-new-tab (&optional specified-shell saved-monitor saved-tab-name targbuff)
"Open a new shell tab on monitor, optionally override default shell with SPECIFIED-SHELL;
optionally used a specified SAVED-MONITOR and SAVED-TAB-NAME."
(interactive)
(let ((launchshell (or override equake-default-shell)))
(if (not (equake--launch-shell launchshell))
(let ((launchshell (or specified-shell equake-default-shell)))
(if (not (equake--launch-shell launchshell targbuff))
(let ((inhibit-message t))
(message "No such shell or relevant shell not installed."))
(buffer-face-set 'equake-buffer-face)
(let* ((monitor (equake--get-monitor))
(new-tab (current-buffer))
(tab-no (1+ (alist-get monitor equake--max-tab-no -1)))
(tab-name (number-to-string tab-no)))
(setf (alist-get monitor equake--max-tab-no) tab-no)
(cl-callf -snoc (alist-get monitor equake--tab-list) new-tab)
(when rash-mode
(comint-send-string nil "racket -l rash/repl --\n"))
(puthash new-tab `((monitor . ,monitor)
(tab-name . ,tab-name))
equake--tab-properties)
(equake--rename-tab tab-name)
(equake-mode))))) ; set Equake minor mode for buffer
(let* ((monitor (or saved-monitor (equake--get-monitor)))
(new-tab (or targbuff (current-buffer)))
(tab-no (1+ (alist-get monitor equake--max-tab-no -1)))
(tab-name (or saved-tab-name
(if equake-append-shell-type-to-tab-name
(concat (number-to-string tab-no)
"-"
(symbol-name launchshell))
(number-to-string tab-no)))))

(setf (alist-get monitor equake--max-tab-no) tab-no)
(cl-callf -snoc (alist-get monitor equake--tab-list) new-tab)
(when rash-mode
(set-buffer new-tab)
(comint-send-string nil "racket -l rash/repl --\n"))
(puthash new-tab `((monitor . ,monitor)
(tab-name . ,tab-name)
(shell-type . ,launchshell))
equake--tab-properties)
(if targbuff
(with-current-buffer new-tab
(buffer-face-set 'equake-buffer-face)
(equake--rename-tab tab-name monitor)
(equake-mode))
(buffer-face-set 'equake-buffer-face)
(equake--rename-tab tab-name monitor)
(equake-mode))))))

(defun equake-move-tab-right ()
"Move current tab one position to the right."
Expand Down Expand Up @@ -553,6 +579,10 @@ Needed to assign a new name for a new tab (e.g. its number)")
(kill-buffer (current-buffer)))
(message "Not an Equake tab.")))

(defun equake--destroy-equake-frame (monitor)
"Destroy an Equake frame."
(delete-frame (select-frame-by-name (concat "*EQUAKE*[" monitor "]"))))

(defun equake--on-kill-buffer ()
"Things to do when an Equake buffer is killed." ; TODO: prevent last equake tab from being killed?
(when equake-mode
Expand All @@ -566,7 +596,7 @@ Needed to assign a new name for a new tab (e.g. its number)")
(null (cdr (assoc monitor equake--tab-list)))) ;; if no more etabs,
(setf (alist-get monitor equake--max-tab-no) -1) ;; reset the "highest tab number" and
;; destroy the corresponding equake frame:
(delete-frame (select-frame-by-name (concat "*EQUAKE*[" (symbol-name monitor) "]")))))))
(equake--destroy-equake-frame (symbol-name monitor))))))

(defun equake--tab-p (&optional buffer)
"Return t if BUFFER is an Equake tab."
Expand Down Expand Up @@ -609,12 +639,12 @@ OFFSET might be negative."
(next-index (mod (+ offset current-index) (length etab-list))))
(elt etab-list next-index)))

(defun equake--rename-tab (base-name)
(defun equake--rename-tab (base-name &optional mon)
"Rename the current buffer (presumed Equake tab) to BASE-NAME.
The actual buffer name is changed to some unique name that
includes BASE-NAME."
(setf (equake--get-tab-property 'tab-name) base-name)
(let ((monitor (equake--get-tab-property 'monitor)))
(let ((monitor (or mon (equake--get-tab-property 'monitor))))
(rename-buffer (format "*Equake[%s]*<%s>" monitor base-name) t)))

;;; Mode line
Expand Down Expand Up @@ -849,15 +879,27 @@ reason remains to be determined."
(progn (x-open-connection display) (x-close-connection display) t)
(error nil)))

(defun equake--write-saved-layout-to-file (layout)
"Saved the current layout to a file."
(with-temp-file equake-saved-layout-file
(prin1 layout (current-buffer))))

(defun equake--read-saved-layout-from-file (layout)
"Read in the saved layout from the `equake-saved-layed-file`."
(with-temp-buffer
(insert-file-contents layout)
(cl-assert (eq (point) (point-min)))
(read (current-buffer))))

;;; Rest

(defun equake--hide-from-taskbar ()
"Hide Equake from the taskbar."
(let ((frame (alist-get (equake--get-monitor) equake--frame)))
(when (executable-find "xprop")
(shell-command (concat "xprop -name "
(frame-parameter frame 'name)
" -f _NET_WM_STATE 32a -set _NET_WM_STATE _NET_WM_STATE_SKIP_TASKBAR")))))
(frame-parameter frame 'name)
" -f _NET_WM_STATE 32a -set _NET_WM_STATE _NET_WM_STATE_SKIP_TASKBAR")))))

(defun equake--select-some-graphic-frame ()
"Try to select some graphic frame.
Expand Down Expand Up @@ -901,37 +943,107 @@ HISTORY is of format given by `window-prev-buffers'."
(equake--update-mode-line monitor)
(modify-frame-parameters nil '((vertical-scroll-bars . nil)
(horizontal-scroll-bars . nil)))))

(defun equake--launch-shell (launchshell)
"Launch a new shell session, LAUNCHSHELL will set non-default shell."
(defun equake-save-layout ()
"Save the current Equake tab layout."
(interactive)
(let ((current-layout equake--tab-list)
(to-be-saved-layout '()))
(cl-loop for mon in current-layout
do (let ((monname (cons (car mon) '())))
(cl-loop for buf in (cdr mon)
do (setf monname
(cons (equake--get-tab-properties buf)
monname)))
(setf to-be-saved-layout (cons (nreverse monname) to-be-saved-layout))))
(equake--write-saved-layout-to-file
(nreverse to-be-saved-layout))))

(defun equake-load-layout ()
"Load a saved Equake tab layout."
(interactive)
(let ((sh-command equake-default-sh-command)
(success 't))
(when (equal sh-command "")
(setq sh-command shell-file-name))
(cond ((equal launchshell 'eshell)
(eshell 'N))
((equal launchshell 'vterm)
(if (require 'vterm nil 'noerror)
(vterm)
(setq success 'nil)))
((equal launchshell 'rash)
(if (not equake-rash-installed)
(setq success 'nil)
(let ((saved-layout
(equake--read-saved-layout-from-file
equake-saved-layout-file))
(current-tab-list equake--tab-list)
(current-property-list equake--tab-properties))
;; (setf equake--tab-list '())
;; (setf equake--tab-properties (make-hash-table :test #'eq :weakness 'key)
(cl-loop for mon in saved-layout
do (let ((monname (car mon)))
;; (select-frame-by-name
;; (concat "*EQUAKE*[" (symbol-name (car monname)) "]"))
;; (equake--destroy-equake-frame (symbol-name (car monname)))
;; (equake-invoke monname)
(cl-loop for buf in (cdr mon)
do (let ((shell-type (cdr (assoc 'shell-type buf)))
(tab-name (cdr (assoc 'tab-name buf))))
(setf newbuf (generate-new-buffer "tmp-equake-tab"))
;; (with-current-buffer newbuf
(equake-new-tab shell-type monname tab-name newbuf)
;; )
))))))

(defun equake--launch-shell (launchshell &optional targbuf)
"Launch a new shell session, LAUNCHSHELL will set non-default shell."
;; (interactive)
(if targbuf
(with-current-buffer targ
(let ((sh-command equake-default-sh-command)
(success 't))
(when (equal sh-command "")
(setq sh-command shell-file-name))
(cond ((equal launchshell 'eshell)
(eshell 'N))
((equal launchshell 'vterm)
(if (require 'vterm nil 'noerror)
(vterm)
(setq success 'nil)))
((equal launchshell 'rash)
(if (not equake-rash-installed)
(setq success 'nil)
(if (require 'vterm nil 'noerror)
(vterm)
(shell)
(delete-other-windows))
(rash-mode)))
((equal launchshell 'ansi-term)
(ansi-term sh-command))
((equal launchshell 'term)
(term sh-command))
((equal launchshell 'shell)
(shell)
(delete-other-windows))
('t (setq success 'nil)))
success))
(let ((sh-command equake-default-sh-command)
(success 't))
(when (equal sh-command "")
(setq sh-command shell-file-name))
(cond ((equal launchshell 'eshell)
(eshell 'N))
((equal launchshell 'vterm)
(if (require 'vterm nil 'noerror)
(vterm)
(setq success 'nil)))
((equal launchshell 'rash)
(if (not equake-rash-installed)
(setq success 'nil)
(if (require 'vterm nil 'noerror)
(vterm)
(shell)
(delete-other-windows))
(rash-mode)))
((equal launchshell 'ansi-term)
(ansi-term sh-command))
((equal launchshell 'term)
(term sh-command))
((equal launchshell 'shell)
(shell)
(delete-other-windows))
('t (setq success 'nil)))
success))
(rash-mode)))
((equal launchshell 'ansi-term)
(ansi-term sh-command))
((equal launchshell 'term)
(term sh-command))
((equal launchshell 'shell)
(shell)
(delete-other-windows))
('t (setq success 'nil)))
success)))



;;; Configuration

Expand Down