diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a03e33eb..fb12dbdd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - New `cider-repl-history-doctor` command: walks `cider-repl-input-history` looking for entries whose parens don't balance under Clojure syntax, shows each in a side buffer, and asks whether to delete it. When done, rewrites `cider-repl-history-file` if one is configured. Useful for cleaning up history after a typo got committed that breaks `cider-repl-history` rendering (see [#3915](https://github.com/clojure-emacs/cider/issues/3915)). - Recognize [let-go](https://github.com/nooga/let-go) (a Clojure dialect implemented in Go) as a known nREPL runtime. `cider-runtime` returns `let-go` for these connections and the connection info line shows the runtime version, e.g. `CLJ project@localhost:2137 (let-go 1.0)`. - Decouple the nREPL transport layer from CIDER's UI layer (closes [#1099](https://github.com/clojure-emacs/cider/issues/1099)). `nrepl-make-eval-handler` is now CIDER-agnostic: it no longer references `nrepl-namespace-handler-function`, `nrepl-err-handler-function`, `nrepl-need-input-handler-function`, or any hardcoded UI strings. New `:on-ns` and `:on-status` keyword slots let any consumer wire up their own namespace tracking and status handling. The editor-level `cider-make-eval-handler` wraps it with CIDER's UI behavior (ns tracking, default error handler, need-input prompt, "Evaluation interrupted." / "Namespace not found." messages); in-tree callers all use it. +- New nREPL message log commands: `nrepl-show-messages` pops up the messages buffer (prompting when there are multiple connections), and `c` in `nrepl-messages-mode` runs the new `nrepl-clear-messages` to wipe the buffer. Auto-follow on new entries now leaves windows alone if you've scrolled back to read history; only windows already at end-of-buffer get scrolled to the latest message. ### Bugs fixed diff --git a/lisp/nrepl-client.el b/lisp/nrepl-client.el index 352f5ffdd..308a957d5 100644 --- a/lisp/nrepl-client.el +++ b/lisp/nrepl-client.el @@ -1233,6 +1233,7 @@ operations.") (let ((map (make-sparse-keymap))) (define-key map (kbd "n") #'next-line) (define-key map (kbd "p") #'previous-line) + (define-key map (kbd "c") #'nrepl-clear-messages) (define-key map (kbd "TAB") #'forward-button) (define-key map (kbd "RET") #'nrepl-log-expand-button) (define-key map (kbd "e") #'nrepl-log-expand-button) @@ -1267,19 +1268,26 @@ described by `nrepl-message-buffer-name-template'." (setq msg (cons (car msg) (nrepl-plist-put (cdr msg) "time-stamp" (format-time-string "%Y-%m-%0d %H:%M:%S.%N")))) - (with-current-buffer (nrepl-messages-buffer (current-buffer)) - (setq buffer-read-only nil) - (when (> (buffer-size) nrepl-message-buffer-max-size) - (goto-char (/ (buffer-size) nrepl-message-buffer-reduce-denominator)) - (re-search-forward "^(" nil t) - (delete-region (point-min) (- (point) 1))) - (goto-char (point-max)) - (nrepl-log-pp-object (nrepl-decorate-msg msg type) - (nrepl-log--message-color (nrepl-plist-get (cdr msg) "id")) - t) - (when-let* ((win (get-buffer-window))) - (set-window-point win (point-max))) - (setq buffer-read-only t)))) + (let ((log-buffer (nrepl-messages-buffer (current-buffer)))) + (with-current-buffer log-buffer + (setq buffer-read-only nil) + ;; Snapshot which windows were already at end-of-buffer before we + ;; insert, so we only auto-follow those. Windows the user has + ;; scrolled back to read history are left where they are. + (let ((following (seq-filter + (lambda (w) (= (window-point w) (point-max))) + (get-buffer-window-list log-buffer nil t)))) + (when (> (buffer-size) nrepl-message-buffer-max-size) + (goto-char (/ (buffer-size) nrepl-message-buffer-reduce-denominator)) + (re-search-forward "^(" nil t) + (delete-region (point-min) (- (point) 1))) + (goto-char (point-max)) + (nrepl-log-pp-object (nrepl-decorate-msg msg type) + (nrepl-log--message-color (nrepl-plist-get (cdr msg) "id")) + t) + (dolist (w following) + (set-window-point w (point-max)))) + (setq buffer-read-only t))))) (defun nrepl-toggle-message-logging () "Toggle the value of `nrepl-log-messages' between nil and t. @@ -1291,6 +1299,33 @@ This in effect enables or disables the logging of nREPL messages." (message "nREPL message logging enabled") (message "nREPL message logging disabled"))) +(defun nrepl-clear-messages () + "Wipe the current nREPL messages buffer." + (interactive) + (unless (derived-mode-p 'nrepl-messages-mode) + (user-error "Not in an `nrepl-messages-mode' buffer")) + (let ((inhibit-read-only t)) + (erase-buffer))) + +(defun nrepl-show-messages () + "Pop up an nREPL messages buffer. +With more than one active connection, prompt for which one to show. +If `nrepl-log-messages' is nil no buffer exists yet, so signal an +error pointing at `nrepl-toggle-message-logging'." + (interactive) + (let ((buffers (seq-filter (lambda (b) + (with-current-buffer b + (derived-mode-p 'nrepl-messages-mode))) + (buffer-list)))) + (pcase (length buffers) + (0 (user-error "No nREPL messages buffer exists; enable logging with `nrepl-toggle-message-logging'")) + (1 (pop-to-buffer (car buffers))) + (_ (pop-to-buffer + (get-buffer + (completing-read "nREPL messages buffer: " + (mapcar #'buffer-name buffers) + nil t))))))) + (defcustom nrepl-message-colors '("red" "brown" "coral" "orange" "green" "deep sky blue" "blue" "dark violet") "Colors used in the messages buffer."