Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a command to delete history item at point #3574

Merged
merged 5 commits into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## master (unreleased)

### New features
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to rebase, as we cut a new CIDER release recently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about the slow responses here - I had a couple of busy weeks, but I'll use the holidays to catch up with oss work and finally merge your PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries

- CIDER [History](https://docs.cider.mx/cider/repl/history.html): Add a command to delete history item at point.

### Changes

- [#3574](https://github.com/clojure-emacs/cider/issues/3574): New value `per-project` for `cider-repl-history-file` to save the history on a per-project basis.

### Bugs fixed

- [#3763](https://github.com/clojure-emacs/cider/issues/3763): Fix `cider-docview-render` completion popup error when symbol being completed does not have a docstring.
Expand Down
23 changes: 17 additions & 6 deletions cider-repl-history.el
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ call `cider-repl-history' again.")
(defvar cider-repl-history-previous-overlay nil
"Previous overlay within *cider-repl-history* buffer.")


(defun cider-repl-history-get-history ()
"Function to retrieve history from the REPL buffer."
(if cider-repl-history-repl-buffer
Expand Down Expand Up @@ -576,6 +575,16 @@ text from the *cider-repl-history* buffer."
(with-current-buffer cider-repl-history-repl-buffer
(undo)))

(defun cider-repl-history-delete-entry-at-point ()
"Delete history entry (at point)."
(interactive)
(let* ((orig (point))
(str (cider-repl-history-current-string orig)))
(with-current-buffer cider-repl-history-repl-buffer
(delete str cider-repl-input-history))
(cider-repl-history-update)
(goto-char orig)))

(defun cider-repl-history-setup (repl-win repl-buf history-buf &optional regexp)
"Setup.
REPL-WIN and REPL-BUF are where to insert commands;
Expand Down Expand Up @@ -637,16 +646,17 @@ HISTORY-BUF is the history, and optional arg REGEXP is a filter."
#'cider-repl-history-update-highlighted-entry
nil t))
(message
(let ((entry (if (= 1 (length cider-command-history))
"entry"
"entries")))
(let* ((history-length (length cider-command-history))
(entry (if (= 1 history-length)
"entry"
"entries")))
(concat
(if (and (not regexp)
cider-repl-history-display-duplicates)
(format "%s %s in the command history."
(length cider-command-history) entry)
history-length entry)
(format "%s (of %s) %s in the command history shown."
(length items) (length cider-command-history) entry))
(length items) history-length entry))
(substitute-command-keys
(concat " Type \\[cider-repl-history-quit] to quit. "
"\\[describe-mode] for help.")))))
Expand Down Expand Up @@ -693,6 +703,7 @@ HISTORY-BUF is the history, and optional arg REGEXP is a filter."
(define-key map (kbd "g") #'cider-repl-history-update)
(define-key map (kbd "q") #'cider-repl-history-quit)
(define-key map (kbd "U") #'cider-repl-history-undo-other-window)
(define-key map (kbd "D") #'cider-repl-history-delete-entry-at-point)
(define-key map (kbd "?") #'describe-mode)
(define-key map (kbd "h") #'describe-mode)
map))
Expand Down
81 changes: 45 additions & 36 deletions cider-repl.el
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,6 @@ CIDER 1.7."
This property value must be unique to avoid having adjacent inputs be
joined together.")

(defvar-local cider-repl-input-history '()
"History list of strings read from the REPL buffer.")

(defvar-local cider-repl-input-history-items-added 0
"Variable counting the items added in the current session.")

(defvar-local cider-repl-output-start nil
"Marker for the start of output.
Currently its only purpose is to facilitate `cider-repl-clear-buffer'.")
Expand Down Expand Up @@ -1468,13 +1462,15 @@ WIN, BUFFER and POS are the window, buffer and point under mouse position."
(defvar cider-repl-history-pattern nil
"The regexp most recently used for finding input history.")

(defvar cider-repl-input-history '()
"History list of strings read from the REPL buffer.")

(defun cider-repl--add-to-input-history (string)
"Add STRING to the input history.
Empty strings and duplicates are ignored."
(unless (or (equal string "")
(equal string (car cider-repl-input-history)))
(push string cider-repl-input-history)
(cl-incf cider-repl-input-history-items-added)))
(push string cider-repl-input-history)))

(defun cider-repl-delete-current-input ()
"Delete all text after the prompt."
Expand Down Expand Up @@ -1593,9 +1589,11 @@ If USE-CURRENT-INPUT is non-nil, use the current input."
:safe #'integerp)

(defcustom cider-repl-history-file nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't just delete this - you'll have to add a deprecation warning for it, so people would know it's no longer being used. If we want to avoid breaking changes we'd probably want to keep the old behavior if this variable is set.

"File to save the persistent REPL history to."
:type 'string
:safe #'stringp)
"File to save the persistent REPL history to.
If this is set to a path the history will be global to all projects. If this is
set to `per-project', the history will be stored in a file (.cider-history) at
the root of each project."
:type '(choice string symbol))

(defun cider-repl--history-read-filename ()
"Ask the user which file to use, defaulting `cider-repl-history-file'."
Expand All @@ -1612,28 +1610,48 @@ It does not yet set the input history."
(read (current-buffer))))
'()))

(defun cider-repl--find-dir-for-history ()
"Find the first suitable directory to store the project's history."
(seq-find
(lambda (dir) (and (not (null dir)) (not (tramp-tramp-file-p dir))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue with storing the history on a remote filesystem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't know and I don't have access to a remote machine on which I can start CIDER on to try. I followed @vemv advice:

It may be better to pick the first, non-nil, non-tramp value of (list nrepl-project-dir clojure-project-dir default-directory)

This way we don't write files to remote TRAMP targets, which may surprise most people - or bring unforeseen issues.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

(list nrepl-project-dir (clojure-project-dir) default-directory)))

(defun cider-repl-history-load (&optional filename)
"Load history from FILENAME into current session.
FILENAME defaults to the value of `cider-repl-history-file' but user
defined filenames can be used to read special history files.

The value of `cider-repl-input-history' is set by this function."
(interactive (list (cider-repl--history-read-filename)))
(let ((f (or filename cider-repl-history-file)))
;; TODO: probably need to set cider-repl-input-history-position as well.
;; in a fresh connection the newest item in the list is currently
;; not available. After sending one input, everything seems to work.
(setq cider-repl-input-history (cider-repl--history-read f))))
(cond
(filename (setq cider-repl-history-file filename))
((equal 'per-project cider-repl-history-file)
(make-local-variable 'cider-repl-input-history)
(when-let ((dir (cider-repl--find-dir-for-history)))
(setq-local
cider-repl-history-file (expand-file-name ".cider-history" dir)))))
(when cider-repl-history-file
(condition-case nil
;; TODO: probably need to set cider-repl-input-history-position as
;; well. In a fresh connection the newest item in the list is
;; currently not available. After sending one input, everything
;; seems to work.
(setq
cider-repl-input-history
(cider-repl--history-read cider-repl-history-file))
(error
(message
"Malformed cider-repl-history-file: %s" cider-repl-history-file)))
(add-hook 'kill-buffer-hook #'cider-repl-history-just-save t t)
(add-hook 'kill-emacs-hook #'cider-repl-history-save-all)))

(defun cider-repl--history-write (filename)
"Write history to FILENAME.
Currently coding system for writing the contents is hardwired to
utf-8-unix."
(let* ((mhist (cider-repl--histories-merge cider-repl-input-history
cider-repl-input-history-items-added
(cider-repl--history-read filename)))
(let* ((end (min (length cider-repl-input-history) cider-repl-history-size))
;; newest items are at the beginning of the list, thus 0
(hist (cl-subseq mhist 0 (min (length mhist) cider-repl-history-size))))
(hist (cl-subseq cider-repl-input-history 0 end)))
(unless (file-writable-p filename)
(error (format "History file not writable: %s" filename)))
(let ((print-length nil) (print-level nil))
Expand All @@ -1658,15 +1676,12 @@ This function is meant to be used in hooks to avoid lambda
constructs."
(cider-repl-history-save cider-repl-history-file))

;; SLIME has different semantics and will not save any duplicates.
;; we keep track of how many items were added to the history in the
;; current session in `cider-repl--add-to-input-history' and merge only the
;; new items with the current history found in the file, which may
;; have been changed in the meantime by another session.
(defun cider-repl--histories-merge (session-hist n-added-items file-hist)
"Merge histories from SESSION-HIST adding N-ADDED-ITEMS into FILE-HIST."
(append (cl-subseq session-hist 0 n-added-items)
file-hist))
(defun cider-repl-history-save-all ()
"Save all histories."
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (equal major-mode 'cider-repl-mode)
(cider-repl-history-just-save)))))


;;; REPL shortcuts
Expand Down Expand Up @@ -2051,13 +2066,7 @@ in an unexpected place."
(setq-local prettify-symbols-alist clojure--prettify-symbols-alist)
;; apply dir-local variables to REPL buffers
(hack-dir-local-variables-non-file-buffer)
(when cider-repl-history-file
(condition-case nil
(cider-repl-history-load cider-repl-history-file)
(error
(message "Malformed cider-repl-history-file: %s" cider-repl-history-file)))
(add-hook 'kill-buffer-hook #'cider-repl-history-just-save t t)
(add-hook 'kill-emacs-hook #'cider-repl-history-just-save))
(cider-repl-history-load)
(add-hook 'completion-at-point-functions #'cider-complete-at-point nil t)
(add-hook 'paredit-mode-hook (lambda () (clojure-paredit-setup cider-repl-mode-map)))
(cider-repl-setup-paredit))
Expand Down
15 changes: 12 additions & 3 deletions doc/modules/ROOT/pages/repl/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,21 @@ reset automatically by the `track-state` middleware.
(setq cider-repl-history-size 1000) ; the default is 500
----

* To store the REPL history in a file:
* To store the REPL history of all projects in a single file:

[source,lisp]
----
(setq cider-repl-history-file "path/to/file")
----

Note that CIDER writes the history to the file when you kill the REPL
buffer, which includes invoking `cider-quit`, or when you quit Emacs.
* To store the REPL history per project (by creating a
`.cider-history` file at the root of each):

[source,lisp]
----
(setq cider-repl-history-file 'per-project)
----

Note that CIDER writes the history to the file(s) when you kill the
REPL buffer, which includes invoking `cider-quit`, or when you quit
Emacs.
3 changes: 3 additions & 0 deletions doc/modules/ROOT/pages/repl/history.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,7 @@ There are a number of important keybindings in history buffers.

| kbd:[U]
| Undo in the REPL buffer.

| kbd:[D]
| Delete history item (at point).
|===
Loading