77 lines
2.5 KiB
EmacsLisp
77 lines
2.5 KiB
EmacsLisp
;;; clj-watch.el --- A pinned, self-overwriting watch buffer -*- lexical-binding: t -*-
|
|
|
|
;;; Commentary:
|
|
|
|
;; Polls `watch/render' on a timer and replaces the buffer contents in
|
|
;; place. Unlike `cider-tap', nothing is appended -- the buffer always shows
|
|
;; the current frame's snapshot and nothing else.
|
|
;;
|
|
;; Usage: M-x clj-watch / M-x clj-watch-stop
|
|
;;
|
|
;; Load with: (load "/path/to/project/watch.el")
|
|
|
|
;;; Code:
|
|
|
|
(require 'cider-client)
|
|
|
|
(defvar clj-watch-buffer "*clj-watch*")
|
|
(defvar clj-watch-interval 0.2
|
|
"Seconds between polls. This is the watch rate, not the frame rate.")
|
|
|
|
(defvar clj-watch--timer nil)
|
|
|
|
(defun clj-watch--paint (text)
|
|
"Replace the watch buffer's contents with TEXT."
|
|
(when-let* ((buf (get-buffer clj-watch-buffer)))
|
|
(let ((tmp (get-buffer-create " *clj-watch-src*")))
|
|
(with-current-buffer tmp
|
|
(erase-buffer)
|
|
(insert text))
|
|
(with-current-buffer buf
|
|
(let ((inhibit-read-only t))
|
|
;; replace-buffer-contents diffs rather than erasing, so point and
|
|
;; scroll position survive every tick. erase-buffer + insert would
|
|
;; yank the cursor back to the top five times a second.
|
|
(replace-buffer-contents tmp))))))
|
|
|
|
(defun clj-watch--tick ()
|
|
"Poll the snapshot once, asynchronously."
|
|
(if (not (get-buffer clj-watch-buffer))
|
|
(clj-watch-stop)
|
|
;; Async, not `cider-nrepl-sync-request': a sync request on a timer blocks
|
|
;; Emacs's UI thread every tick.
|
|
(cider-nrepl-request:eval
|
|
"(watch/render)"
|
|
(lambda (response)
|
|
(nrepl-dbind-response response (value err)
|
|
(cond
|
|
(err (clj-watch--paint (format "error:\n%s" err)))
|
|
(value (clj-watch--paint (car (read-from-string value))))))))))
|
|
|
|
(define-derived-mode clj-watch-mode special-mode "clj-watch"
|
|
"Major mode for the pinned watch buffer."
|
|
(setq-local truncate-lines t))
|
|
|
|
;;;###autoload
|
|
(defun clj-watch ()
|
|
"Open the pinned watch buffer and start polling."
|
|
(interactive)
|
|
(cider-current-repl nil 'ensure)
|
|
(with-current-buffer (get-buffer-create clj-watch-buffer)
|
|
(unless (eq major-mode 'clj-watch-mode)
|
|
(clj-watch-mode)))
|
|
(when clj-watch--timer (cancel-timer clj-watch--timer))
|
|
(setq clj-watch--timer
|
|
(run-with-timer 0 clj-watch-interval #'clj-watch--tick))
|
|
(display-buffer clj-watch-buffer))
|
|
|
|
(defun clj-watch-stop ()
|
|
"Stop polling."
|
|
(interactive)
|
|
(when clj-watch--timer
|
|
(cancel-timer clj-watch--timer)
|
|
(setq clj-watch--timer nil)))
|
|
|
|
(provide 'clj-watch)
|
|
;;; clj-watch.el ends here
|