Skip to content

Instantly share code, notes, and snippets.

@jdtsmith
Last active May 4, 2019 16:14
Show Gist options
  • Select an option

  • Save jdtsmith/b50b14ba4baa321ed200a3c35fa2b880 to your computer and use it in GitHub Desktop.

Select an option

Save jdtsmith/b50b14ba4baa321ed200a3c35fa2b880 to your computer and use it in GitHub Desktop.
Simple Emacs shell for Hammerspoon, using the /usr/local/bin/hs -C shell process
;;===> hammerspoon-shell
;; Quick and dirty shell with interactive history search and persistence
;; Just drop into your ~/.emacs file.
;;
;; A hammerspoon buffer is any lua buffer visiting a pathname like
;; **/*hammerspoon**/*.lua
;; Usage: M-x hammerspoon-shell, or Hyper-s in a hammerspoon buffer.
;; In any hammerspoon buffer, Hyper-c runs dofile(file) on the visited file.
;;
;; Tip: to reload a Spoon "MySpoon" without hs.reload:
;; package.loaded.MySpoon=false hs.spoons.use("MySpoon",{config={debug=true})
(add-hook 'lua-mode-hook
(lambda ()
(when (string-match "hammerspoon" buffer-file-name)
(local-set-key (kbd "H-s") #'hammerspoon-shell)
(local-set-key
(kbd "H-c")
(lambda ()
(interactive)
(save-buffer)
(let ((name buffer-file-name))
(unless (and (boundp 'hammerspoon-buffer)
(buffer-live-p hammerspoon-buffer))
(hammerspoon-shell))
(with-current-buffer hammerspoon-buffer
(goto-char (point-max))
(insert (concat "dofile(\"" name "\")"))
(comint-send-input))))))))
(defvar hammerspoon-buffer nil)
(defun hammerspoon-shell ()
(interactive)
(if (and hammerspoon-buffer (comint-check-proc hammerspoon-buffer))
(pop-to-buffer hammerspoon-buffer)
(setq hammerspoon-buffer (make-comint "hammerspoon"
"/usr/local/bin/hs" nil "-C"))
(let* ((process (get-buffer-process hammerspoon-buffer))
(history-file "~/.hammerspoon/.hs-history"))
(pop-to-buffer hammerspoon-buffer)
(turn-on-comint-history history-file)
(local-set-key (kbd "<down>") (lambda() (interactive)
(comint-move-or-history nil)))
(local-set-key (kbd "<up>") (lambda() (interactive)
(comint-move-or-history 'up))))))
;; Comint configs and extensions
(setq comint-input-ring-size 1024
comint-history-isearch 'dwim)
(defun comint-move-or-history (up &optional arg)
"History if at process mark, move otherwise"
(interactive)
(let* ((proc (get-buffer-process (current-buffer)))
(proc-pos (if proc (marker-position (process-mark proc))))
(arg (or arg 1))
(arg (if up arg (- arg))))
(if (and proc
(if up
(= (line-number-at-pos) (line-number-at-pos proc-pos))
(= (line-number-at-pos) (line-number-at-pos (point-max)))))
(comint-previous-input arg)
(forward-line (- arg)))))
(defun comint-write-history-on-exit (process event)
(comint-write-input-ring)
(let ((buf (process-buffer process)))
(when (buffer-live-p buf)
(with-current-buffer buf
(insert (format "\nProcess %s %s" process event))))))
(defun turn-on-comint-history (&optional file)
(let ((process (get-buffer-process (current-buffer))))
(when process
(setq comint-input-ring-file-name
(or file
(format "~/.emacs.d/inferior-%s-history"
(process-name process))))
(comint-read-input-ring)
;; Ensure input ring gets written
(add-hook 'kill-buffer-hook 'comint-write-input-ring nil t)
(set-process-sentinel process
#'comint-write-history-on-exit))))
;; Ensure all input rings get written on exit
(defun comint-write-input-ring-all-buffers ()
(mapc (lambda (buffer)
(with-current-buffer buffer
(comint-write-input-ring)))
(buffer-list)))
(add-hook 'kill-emacs-hook 'comint-write-input-ring-all-buffers)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment