|
|
- ;;; cider-repl-history.el --- REPL input history browser
-
- ;; Copyright (c) 2017 John Valente and browse-kill-ring authors
-
- ;; This program is free software: you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, either version 3 of the License, or
- ;; (at your option) any later version.
-
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
-
- ;; You should have received a copy of the GNU General Public License
- ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- ;; This file is not part of GNU Emacs.
-
- ;; Based heavily on browse-kill-ring
- ;; https://github.com/browse-kill-ring/browse-kill-ring
-
- ;;; Commentary:
-
- ;; REPL input history browser for CIDER.
-
- ;; Allows you to browse the full input history for your REPL buffer, and
- ;; insert previous commands at the prompt.
-
- ;;; Code:
-
- (require 'cl-lib)
- (require 'cider-compat)
- (require 'cider-popup)
- (require 'clojure-mode)
- (require 'derived)
- (require 'pulse)
-
- (defconst cider-repl-history-buffer "*cider-repl-history*")
-
- (defgroup cider-repl-history nil
- "A package for browsing and inserting the items in the CIDER command history."
- :prefix "cider-repl-history-"
- :group 'cider)
-
- (defvar cider-repl-history-display-styles
- '((separated . cider-repl-history-insert-as-separated)
- (one-line . cider-repl-history-insert-as-one-line)))
-
- (defcustom cider-repl-history-display-style 'separated
- "How to display the CIDER command history items.
-
- If `one-line', then replace newlines with \"\\n\" for display.
-
- If `separated', then display `cider-repl-history-separator' between
- entries."
- :type '(choice (const :tag "One line" one-line)
- (const :tag "Separated" separated))
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-quit-action 'quit-window
- "What action to take when `cider-repl-history-quit' is called.
-
- If `bury-buffer', then simply bury the *cider-repl-history* buffer, but keep
- the window.
-
- If `bury-and-delete-window', then bury the buffer, and (if there is
- more than one window) delete the window.
-
- If `delete-and-restore', then restore the window configuration to what it was
- before `cider-repl-history' was called, and kill the *cider-repl-history*
- buffer.
-
- If `quit-window', then restore the window configuration to what
- it was before `cider-repl-history' was called, and bury *cider-repl-history*.
- This is the default.
-
- If `kill-and-delete-window', then kill the *cider-repl-history* buffer, and
- delete the window on close.
-
- Otherwise, it should be a function to call."
- ;; Note, if you use one of the non-"delete" options, after you "quit",
- ;; the *cider-repl-history* buffer is still available. If you are using
- ;; `cider-repl-history-show-preview', and you switch to *cider-repl-history* (i.e.,
- ;; with C-x b), it will not give the preview unless and until you "update"
- ;; the *cider-repl-history* buffer.
- ;;
- ;; This really should not be an issue, because there's no reason to "switch"
- ;; back to the buffer. If you want to get it back, you can just do C-c M-p
- ;; from the REPL buffer.
-
- ;; If you get in this situation and find it annoying, you can either disable
- ;; the preview, or set `cider-repl-history-quit-action' to 'delete-and-restore.
- ;; Then you will simply not have the *cider-repl-history* buffer after you quit,
- ;; and it won't be an issue.
-
- :type '(choice (const :tag "Bury buffer"
- :value bury-buffer)
- (const :tag "Bury buffer and delete window"
- :value bury-and-delete-window)
- (const :tag "Delete window"
- :value delete-and-restore)
- (const :tag "Save and restore"
- :value quit-window)
- (const :tag "Kill buffer and delete window"
- :value kill-and-delete-window)
- function)
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-resize-window nil
- "Whether to resize the `cider-repl-history' window to fit its contents.
- Value is either t, meaning yes, or a cons pair of integers,
- (MAXIMUM . MINIMUM) for the size of the window. MAXIMUM defaults to
- the window size chosen by `pop-to-buffer'; MINIMUM defaults to
- `window-min-height'."
- :type '(choice (const :tag "No" nil)
- (const :tag "Yes" t)
- (cons (integer :tag "Maximum") (integer :tag "Minimum")))
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-separator ";;;;;;;;;;"
- "The string separating entries in the `separated' style.
- See `cider-repl-history-display-style'."
- ;; The (default) separator is a Clojure comment, to preserve fontification
- ;; in the buffer.
- :type 'string
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-recenter nil
- "If non-nil, then always keep the current entry at the top of the window."
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-highlight-current-entry nil
- "If non-nil, highlight the currently selected command history entry."
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-highlight-inserted-item nil
- "If non-nil, then temporarily highlight the inserted command history entry.
- The value selected controls how the inserted item is highlighted,
- possible values are `solid' (highlight the inserted text for a
- fixed period of time), or `pulse' (fade out the highlighting gradually).
- Setting this variable to the value t will select the default
- highlighting style, which currently `pulse'.
-
- The variable `cider-repl-history-inserted-item-face' contains the
- face used for highlighting."
- :type '(choice (const nil) (const t) (const solid) (const pulse))
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-separator-face 'bold
- "The face in which to highlight the `cider-repl-history-separator'."
- :type 'face
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-current-entry-face 'highlight
- "The face in which to highlight the command history current entry."
- :type 'face
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-inserted-item-face 'highlight
- "The face in which to highlight the inserted item."
- :type 'face
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-maximum-display-length nil
- "Whether or not to limit the length of displayed items.
-
- If this variable is an integer, the display of the command history will be
- limited to that many characters.
- Setting this variable to nil means no limit."
- :type '(choice (const :tag "None" nil)
- integer)
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-display-duplicates t
- "If non-nil, then display duplicate items in the command history."
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-display-duplicate-highest t
- "When `cider-repl-history-display-duplicates' is nil, then display highest (most recent) duplicate items in the command history."
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-text-properties nil
- "If non-nil, maintain text properties of the command history items."
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-hook nil
- "A list of functions to call after `cider-repl-history'."
- :type 'hook
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defcustom cider-repl-history-show-preview nil
- "If non-nil, show a preview of the inserted text in the REPL buffer.
-
- The REPL buffer would show a preview of what the buffer would look like
- if the item under point were inserted."
-
- :type 'boolean
- :group 'cider-repl-history
- :package-version '(cider . "0.15.0"))
-
- (defvar cider-repl-history-repl-window nil
- "The window in which chosen command history data will be inserted.
- It is probably not a good idea to set this variable directly; simply
- call `cider-repl-history' again.")
-
- (defvar cider-repl-history-repl-buffer nil
- "The buffer in which chosen command history data will be inserted.
- It is probably not a good idea to set this variable directly; simply
- call `cider-repl-history' again.")
-
- (defvar cider-repl-history-preview-overlay nil
- "The overlay used to preview what would happen if the user inserted the given text.")
-
- (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
- (buffer-local-value
- 'cider-repl-input-history
- cider-repl-history-repl-buffer)
- (error "Variable `cider-repl-history-repl-buffer' not bound to a buffer")))
-
- (defun cider-repl-history-resize-window ()
- "If variable `cider-repl-history-resize-window' is non-nil, resize the *cider-repl-history* window."
- (when cider-repl-history-resize-window
- (apply #'fit-window-to-buffer (selected-window)
- (if (consp cider-repl-history-resize-window)
- (list (car cider-repl-history-resize-window)
- (or (cdr cider-repl-history-resize-window)
- window-min-height))
- (list nil window-min-height)))))
-
- (defun cider-repl-history-read-regexp (msg use-default-p)
- "Get a regular expression from the user, prompting with MSG; previous entry is default if USE-DEFAULT-P."
- (let* ((default (car regexp-history))
- (prompt (if (and default use-default-p)
- (format "%s for regexp (default `%s'): "
- msg
- default)
- (format "%s (regexp): " msg)))
- (input
- (read-from-minibuffer prompt nil nil nil 'regexp-history
- (if use-default-p nil default))))
- (if (equal input "")
- (if use-default-p default nil)
- input)))
-
- (defun cider-repl-history-clear-preview ()
- "Clear the preview, if one is present."
- (interactive)
- (when cider-repl-history-preview-overlay
- (cl-assert (overlayp cider-repl-history-preview-overlay))
- (delete-overlay cider-repl-history-preview-overlay)))
-
- (defun cider-repl-history-cleanup-on-exit ()
- "Function called when the user is finished with `cider-repl-history'.
- This function performs any cleanup that is required when the user
- has finished interacting with the *cider-repl-history* buffer. For now
- the only cleanup performed is to remove the preview overlay, if
- it's turned on."
- (cider-repl-history-clear-preview))
-
- (defun cider-repl-history-quit ()
- "Take the action specified by `cider-repl-history-quit-action'."
- (interactive)
- (cider-repl-history-cleanup-on-exit)
- (pcase cider-repl-history-quit-action
- (`delete-and-restore
- (quit-restore-window (selected-window) 'kill))
- (`quit-window
- (quit-window))
- (`kill-and-delete-window
- (kill-buffer (current-buffer))
- (unless (= (count-windows) 1)
- (delete-window)))
- (`bury-and-delete-window
- (bury-buffer)
- (unless (= (count-windows) 1)
- (delete-window)))
- (_
- (funcall cider-repl-history-quit-action))))
-
- (defun cider-repl-history-preview-overlay-setup (orig-buf)
- "Setup the preview overlay in ORIG-BUF."
- (when cider-repl-history-show-preview
- (with-current-buffer orig-buf
- (let* ((will-replace (region-active-p))
- (start (if will-replace
- (min (point) (mark))
- (point)))
- (end (if will-replace
- (max (point) (mark))
- (point))))
- (cider-repl-history-clear-preview)
- (setq cider-repl-history-preview-overlay
- (make-overlay start end orig-buf))
- (overlay-put cider-repl-history-preview-overlay
- 'invisible t)))))
-
- (defun cider-repl-history-highlight-inserted (start end)
- "Insert the text between START and END."
- (pcase cider-repl-history-highlight-inserted-item
- ((or `pulse `t)
- (let ((pulse-delay .05) (pulse-iterations 10))
- (with-no-warnings
- (pulse-momentary-highlight-region
- start end cider-repl-history-inserted-item-face))))
- (`solid
- (let ((o (make-overlay start end)))
- (overlay-put o 'face cider-repl-history-inserted-item-face)
- (sit-for 0.5)
- (delete-overlay o)))))
-
- (defun cider-repl-history-insert-and-highlight (str)
- "Helper function to insert STR at point, highlighting it if appropriate."
- (let ((before-insert (point)))
- (let (deactivate-mark)
- (insert-for-yank str))
- (cider-repl-history-highlight-inserted
- before-insert
- (point))))
-
- (defun cider-repl-history-target-overlay-at (position &optional no-error)
- "Return overlay at POSITION that has property `cider-repl-history-target'.
- If no such overlay, raise an error unless NO-ERROR is true, in which
- case retun nil."
- (let ((ovs (overlays-at (point))))
- (catch 'cider-repl-history-target-overlay-at
- (dolist (ov ovs)
- (when (overlay-get ov 'cider-repl-history-target)
- (throw 'cider-repl-history-target-overlay-at ov)))
- (unless no-error
- (error "No CIDER history item here")))))
-
- (defun cider-repl-history-current-string (pt &optional no-error)
- "Find the string to insert into the REPL by looking for the overlay at PT; might error unless NO-ERROR set."
- (let ((o (cider-repl-history-target-overlay-at pt t)))
- (if o
- (overlay-get o 'cider-repl-history-target)
- (unless no-error
- (error "No CIDER history item in this buffer")))))
-
- (defun cider-repl-history-do-insert (buf pt)
- "Helper function to insert text from BUF at PT into the REPL buffer and kill *cider-repl-history*."
- ;; Note: as mentioned at the top, this file is based on browse-kill-ring,
- ;; which has numerous insertion options. The functionality of
- ;; browse-kill-ring allows users to insert at point, and move point to the end
- ;; of the inserted text; or insert at the beginning or end of the buffer,
- ;; while leaving point alone. And each of these had the option of leaving the
- ;; history buffer in place, or getting rid of it. That was appropriate for a
- ;; generic paste tool, but for inserting a previous command into an
- ;; interpreter, I felt the only useful option would be inserting it at the end
- ;; and quitting the history buffer, so that is all that's provided.
- (let ((str (cider-repl-history-current-string pt)))
- (cider-repl-history-quit)
- (with-selected-window cider-repl-history-repl-window
- (with-current-buffer cider-repl-history-repl-buffer
- (let ((max (point-max)))
- (if (= max (point))
- (cider-repl-history-insert-and-highlight str)
- (save-excursion
- (goto-char max)
- (cider-repl-history-insert-and-highlight str))))))))
-
- (defun cider-repl-history-insert-and-quit ()
- "Insert the item into the REPL buffer, and close *cider-repl-history*.
-
- The text is always inserted at the very bottom of the REPL buffer. If your
- cursor is already at the bottom, it is advanced to the end of the inserted
- text. If your cursor is somewhere else, the cursor is not moved, but the
- text is still inserted at the end."
- (interactive)
- (cider-repl-history-do-insert (current-buffer) (point)))
-
- (defun cider-repl-history-mouse-insert (e)
- "Insert the item at E into the REPL buffer, and close *cider-repl-history*.
-
- The text is always inserted at the very bottom of the REPL buffer. If your
- cursor is already at the bottom, it is advanced to the end of the inserted
- text. If your cursor is somewhere else, the cursor is not moved, but the
- text is still inserted at the end."
- (interactive "e")
- (let* ((data (save-excursion
- (mouse-set-point e)
- (cons (current-buffer) (point))))
- (buf (car data))
- (pt (cdr data)))
- (cider-repl-history-do-insert buf pt)))
-
- (defun cider-repl-history-clear-highlighted-entry ()
- "Clear the highlighted entry, when one exists."
- (when cider-repl-history-previous-overlay
- (cl-assert (overlayp cider-repl-history-previous-overlay)
- nil "not an overlay")
- (overlay-put cider-repl-history-previous-overlay 'face nil)))
-
- (defun cider-repl-history-update-highlighted-entry ()
- "Update highlighted entry, when feature is turned on."
- (when cider-repl-history-highlight-current-entry
- (if-let* ((current-overlay (cider-repl-history-target-overlay-at (point) t)))
- (unless (equal cider-repl-history-previous-overlay current-overlay)
- ;; We've changed overlay. Clear current highlighting,
- ;; and highlight the new overlay.
- (cl-assert (overlay-get current-overlay 'cider-repl-history-target) t)
- (cider-repl-history-clear-highlighted-entry)
- (setq cider-repl-history-previous-overlay current-overlay)
- (overlay-put current-overlay 'face
- cider-repl-history-current-entry-face))
- ;; No overlay at point. Just clear all current highlighting.
- (cider-repl-history-clear-highlighted-entry))))
-
- (defun cider-repl-history-forward (&optional arg)
- "Move forward by ARG command history entries."
- (interactive "p")
- (beginning-of-line)
- (while (not (zerop arg))
- (let ((o (cider-repl-history-target-overlay-at (point) t)))
- (cond
- ((>= arg 0)
- (setq arg (1- arg))
- ;; We're on a cider-repl-history overlay, skip to the end of it.
- (when o
- (goto-char (overlay-end o))
- (setq o nil))
- (while (not (or o (eobp)))
- (goto-char (next-overlay-change (point)))
- (setq o (cider-repl-history-target-overlay-at (point) t))))
- (t
- (setq arg (1+ arg))
- (when o
- (goto-char (overlay-start o))
- (setq o nil))
- (while (not (or o (bobp)))
- (goto-char (previous-overlay-change (point)))
- (setq o (cider-repl-history-target-overlay-at (point) t)))))))
- (when cider-repl-history-recenter
- (recenter 1)))
-
- (defun cider-repl-history-previous (&optional arg)
- "Move backward by ARG command history entries."
- (interactive "p")
- (cider-repl-history-forward (- arg)))
-
- (defun cider-repl-history-search-forward (regexp &optional backwards)
- "Move to the next command history entry matching REGEXP from point.
- If optional arg BACKWARDS is non-nil, move to the previous matching
- entry."
- (interactive
- (list (cider-repl-history-read-regexp "Search forward" t)
- current-prefix-arg))
- (let ((orig (point)))
- (cider-repl-history-forward (if backwards -1 1))
- (let ((over (cider-repl-history-target-overlay-at (point) t)))
- (while (and over
- (not (if backwards (bobp) (eobp)))
- (not (string-match regexp
- (overlay-get over
- 'cider-repl-history-target))))
- (cider-repl-history-forward (if backwards -1 1))
- (setq over (cider-repl-history-target-overlay-at (point) t)))
- (unless (and over
- (string-match regexp
- (overlay-get over
- 'cider-repl-history-target)))
- (goto-char orig)
- (message "No more command history entries matching %s" regexp)))))
-
- (defun cider-repl-history-search-backward (regexp)
- "Move to the previous command history entry matching REGEXP from point."
- (interactive
- (list (cider-repl-history-read-regexp "Search backward" t)))
- (cider-repl-history-search-forward regexp t))
-
- (defun cider-repl-history-elide (str)
- "If STR is too long, abbreviate it with an ellipsis; otherwise, return it unchanged."
- (if (and cider-repl-history-maximum-display-length
- (> (length str)
- cider-repl-history-maximum-display-length))
- (concat (substring str 0 (- cider-repl-history-maximum-display-length 3))
- (propertize "..." 'cider-repl-history-extra t))
- str))
-
- (defmacro cider-repl-history-add-overlays-for (item &rest body)
- "Add overlays for ITEM, and execute BODY."
- (let ((beg (cl-gensym "cider-repl-history-add-overlays-"))
- (end (cl-gensym "cider-repl-history-add-overlays-")))
- `(let ((,beg (point))
- (,end
- (progn
- ,@body
- (point))))
- (let ((o (make-overlay ,beg ,end)))
- (overlay-put o 'cider-repl-history-target ,item)
- (overlay-put o 'mouse-face 'highlight)))))
-
- (defun cider-repl-history-insert-as-separated (items)
- "Insert ITEMS into the current buffer, with separators between items."
- (while items
- (let* ((origitem (car items))
- (item (cider-repl-history-elide origitem))
- (len (length item)))
- (cider-repl-history-add-overlays-for origitem (insert item))
- ;; When the command history has items with read-only text property at
- ;; **the end of** string, cider-repl-history-setup fails with error
- ;; `Text is read-only'. So inhibit-read-only here.
- ;; See http://bugs.debian.org/225082
- (let ((inhibit-read-only t))
- (insert "\n")
- (when (cdr items)
- (insert (propertize cider-repl-history-separator
- 'cider-repl-history-extra t
- 'cider-repl-history-separator t))
- (insert "\n"))))
- (setq items (cdr items))))
-
- (defun cider-repl-history-insert-as-one-line (items)
- "Insert ITEMS into the current buffer, formatting each item as a single line.
-
- An explicit newline character will replace newlines so that the text retains its
- spacing when it's actually inserted into the REPL buffer."
- (dolist (item items)
- (cider-repl-history-add-overlays-for
- item
- (let* ((item (cider-repl-history-elide item))
- (len (length item))
- (start 0)
- (newl (propertize "\\n" 'cider-repl-history-extra t)))
- (while (and (< start len)
- (string-match "\n" item start))
- (insert (substring item start (match-beginning 0))
- newl)
- (setq start (match-end 0)))
- (insert (substring item start len))))
- (insert "\n")))
-
- (defun cider-repl-history-preview-update-text (preview-text)
- "Update `cider-repl-history-preview-overlay' to show `PREVIEW-TEXT`."
- ;; If preview-text is nil, replacement should be nil too.
- (cl-assert (overlayp cider-repl-history-preview-overlay))
- (let ((replacement (when preview-text
- (propertize preview-text 'face 'highlight))))
- (overlay-put cider-repl-history-preview-overlay
- 'before-string replacement)))
-
- (defun cider-repl-history-preview-update-by-position (&optional pt)
- "Update `cider-repl-history-preview-overlay' to match item at PT.
-
- This function is called whenever the selection in the *cider-repl-history*
- buffer is adjusted, the `cider-repl-history-preview-overlay'
- is updated to preview the text of the selection at PT (or the
- current point if not specified)."
- (let ((new-text (cider-repl-history-current-string
- (or pt (point)) t)))
- (cider-repl-history-preview-update-text new-text)))
-
- (defun cider-repl-history-undo-other-window ()
- "Undo the most recent change in the other window's buffer.
- You most likely want to use this command for undoing an insertion of
- text from the *cider-repl-history* buffer."
- (interactive)
- (with-current-buffer cider-repl-history-repl-buffer
- (undo)))
-
- (defun cider-repl-history-setup (repl-win repl-buf history-buf &optional regexp)
- "Setup: REPL-WIN and REPL-BUF are where to insert commands, HISTORY-BUF is the history, and optional arg REGEXP is a filter."
- (cider-repl-history-preview-overlay-setup repl-buf)
- (with-current-buffer history-buf
- (unwind-protect
- (progn
- (cider-repl-history-mode)
- (setq buffer-read-only nil)
- (when (eq 'one-line cider-repl-history-display-style)
- (setq truncate-lines t))
- (let ((inhibit-read-only t))
- (erase-buffer))
- (setq cider-repl-history-repl-buffer repl-buf)
- (setq cider-repl-history-repl-window repl-win)
- (let* ((cider-repl-history-maximum-display-length
- (if (and cider-repl-history-maximum-display-length
- (<= cider-repl-history-maximum-display-length 3))
- 4
- cider-repl-history-maximum-display-length))
- (cider-command-history (cider-repl-history-get-history))
- (items (mapcar
- (if cider-repl-history-text-properties
- #'copy-sequence
- #'substring-no-properties)
- cider-command-history)))
- (unless cider-repl-history-display-duplicates
- ;; display highest or lowest duplicate.
- ;; if `cider-repl-history-display-duplicate-highest' is t,
- ;; display highest (most recent) duplicate.
- (cl-delete-duplicates
- items
- :test #'equal
- :from-end cider-repl-history-display-duplicate-highest))
- (when (stringp regexp)
- (setq items (delq nil
- (mapcar
- #'(lambda (item)
- (when (string-match regexp item)
- item))
- items))))
- (funcall (or (cdr (assq cider-repl-history-display-style
- cider-repl-history-display-styles))
- (error "Invalid `cider-repl-history-display-style': %s"
- cider-repl-history-display-style))
- items)
- (when cider-repl-history-show-preview
- (cider-repl-history-preview-update-by-position (point-min))
- ;; Local post-command-hook, only happens in *cider-repl-history*
- (add-hook 'post-command-hook
- 'cider-repl-history-preview-update-by-position
- nil t)
- (add-hook 'kill-buffer-hook
- 'cider-repl-history-cleanup-on-exit
- nil t))
- (when cider-repl-history-highlight-current-entry
- (add-hook 'post-command-hook
- 'cider-repl-history-update-highlighted-entry
- nil t))
- (message
- (let ((entry (if (= 1 (length cider-command-history))
- "entry"
- "entries")))
- (concat
- (if (and (not regexp)
- cider-repl-history-display-duplicates)
- (format "%s %s in the command history."
- (length cider-command-history) entry)
- (format "%s (of %s) %s in the command history shown."
- (length items) (length cider-command-history) entry))
- (substitute-command-keys
- (concat " Type \\[cider-repl-history-quit] to quit. "
- "\\[describe-mode] for help.")))))
- (set-buffer-modified-p nil)
- (goto-char (point-min))
- (cider-repl-history-forward 0)
- (setq mode-name (if regexp
- (concat "History [" regexp "]")
- "History"))
- (run-hooks 'cider-repl-history-hook)))
- (setq buffer-read-only t))))
-
- (defun cider-repl-history-update ()
- "Update the history buffer to reflect the latest state of the command history."
- (interactive)
- (cl-assert (eq major-mode 'cider-repl-history-mode))
- (cider-repl-history-setup cider-repl-history-repl-window
- cider-repl-history-repl-buffer
- (current-buffer))
- (cider-repl-history-resize-window))
-
- (defun cider-repl-history-occur (regexp)
- "Display all command history entries matching REGEXP."
- (interactive
- (list (cider-repl-history-read-regexp
- "Display command history entries matching" nil)))
- (cl-assert (eq major-mode 'cider-repl-history-mode))
- (cider-repl-history-setup cider-repl-history-repl-window
- cider-repl-history-repl-buffer
- (current-buffer)
- regexp)
- (cider-repl-history-resize-window))
-
- (put 'cider-repl-history-mode 'mode-class 'special)
- (define-derived-mode cider-repl-history-mode clojure-mode "History"
- "Major mode for browsing the entries in the command input history.
-
- \\{cider-repl-history-mode-map}"
- (setq-local sesman-system 'CIDER)
- (define-key cider-repl-history-mode-map (kbd "n") 'cider-repl-history-forward)
- (define-key cider-repl-history-mode-map (kbd "p") 'cider-repl-history-previous)
- (define-key cider-repl-history-mode-map (kbd "SPC") 'cider-repl-history-insert-and-quit)
- (define-key cider-repl-history-mode-map (kbd "RET") 'cider-repl-history-insert-and-quit)
- (define-key cider-repl-history-mode-map [(mouse-2)] 'cider-repl-history-mouse-insert)
- (define-key cider-repl-history-mode-map (kbd "l") 'cider-repl-history-occur)
- (define-key cider-repl-history-mode-map (kbd "s") 'cider-repl-history-search-forward)
- (define-key cider-repl-history-mode-map (kbd "r") 'cider-repl-history-search-backward)
- (define-key cider-repl-history-mode-map (kbd "g") 'cider-repl-history-update)
- (define-key cider-repl-history-mode-map (kbd "q") 'cider-repl-history-quit)
- (define-key cider-repl-history-mode-map (kbd "U") 'cider-repl-history-undo-other-window)
- (define-key cider-repl-history-mode-map (kbd "?") 'describe-mode)
- (define-key cider-repl-history-mode-map (kbd "h") 'describe-mode))
-
- ;;;###autoload
- (defun cider-repl-history ()
- "Display items in the CIDER command history in another buffer."
- (interactive)
- (when (eq major-mode 'cider-repl-history-mode)
- (user-error "Already viewing the CIDER command history"))
-
- (let* ((repl-win (selected-window))
- (repl-buf (window-buffer repl-win))
- (buf (get-buffer-create cider-repl-history-buffer)))
- (cider-repl-history-setup repl-win repl-buf buf)
- (pop-to-buffer buf)
- (cider-repl-history-resize-window)))
-
- (provide 'cider-repl-history)
-
- ;;; cider-repl-history.el ends here
|