From c900166eb6d83ab5f7b50691ac66a2b909f82648 Mon Sep 17 00:00:00 2001 From: Stefan Kamphausen Date: Mon, 30 Jul 2012 00:28:35 +0200 Subject: [PATCH] Persistent history Added basic functions to save and load the input history in a REPL session. Added local variables kill-buffer-hook and kill-emacs-hook --- nrepl.el | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/nrepl.el b/nrepl.el index 08cd4e72c..41bd0f23d 100644 --- a/nrepl.el +++ b/nrepl.el @@ -148,13 +148,6 @@ joined together.") 'nrepl-output-start 'nrepl-output-end) -(defun nrepl-add-to-input-history (string) - "Add STRING to the input history. -Empty strings and duplicates are ignored." - (unless (or (equal string "") - (equal string (car nrepl-input-history))) - (push string nrepl-input-history))) - (defun nrepl-reset-markers () (dolist (markname '(nrepl-output-start nrepl-output-end @@ -683,6 +676,13 @@ in a macroexpansion buffer. Prefix argument forces pretty-printed output." (nrepl-interactive-eval (nrepl-last-expression)))) ;;;;; History +(defun nrepl-add-to-input-history (string) + "Add STRING to the input history. +Empty strings and duplicates are ignored." + (unless (or (equal string "") + (equal string (car nrepl-input-history))) + (push string nrepl-input-history))) + (defun nrepl-delete-current-input () "Delete all text after the prompt." (interactive) @@ -726,6 +726,75 @@ DIRECTION is 'forward' or 'backward' (in the history list)." (interactive) (nrepl-history-replace 'forward)) +;;;;;;;;;;;;;;;;;;;;;;;; +;; working on persistent hist +;; make sure to move things around later +(defvar nrepl-history-size 500) +(defvar nrepl-history-file "~/.nrepl-history.eld") + +(defun nrepl-history-read-filename () + "Ask the user which file to use, defaulting `nrepl-history-file`." + (read-file-name "Use nREPL history file: " + nrepl-history-file)) + +(defun nrepl-history-read (filename) + "Read history from FILE and return it. +Does not yet set the input history." + (if (file-readable-p filename) + (with-temp-buffer + (insert-file-contents filename) + (read (current-buffer))) + '())) + +(defun nrepl-history-load (&optional filename) + "Load history from FILENAME into current session. +FILENAME defaults to the value of `nrepl-history-file` but user +defined filenames can be used to read special history files. + +The value of `nrepl-input-history` is set by this function." + (interactive (list (nrepl-history-read-filename))) + (let ((f (or filename nrepl-history-file))) + ;; TODO: probably need to set nrepl-input-history-index 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 nrepl-input-history (nrepl-history-read f)))) + +(defun nrepl-history-write (filename) + "Write history to FILENAME. +Currently coding system for writing the contents is hardwired to +utf-8-unix." + (let* ((mhist (nrepl-histories-merge nrepl-input-history nil)) + ;; newest items are at the beginning of the list, thus 0 + (hist (subseq mhist 0 (min (length mhist) nrepl-history-size)))) + (unless (file-writable-p filename) + (error (format "History file not writable: %s" filename))) + (let ((print-length nil) (print-level nil)) + (with-temp-file filename + ;; TODO: really set cs for output + ;; TODO: does cs need to be customizable? + (insert ";; -*- coding: utf-8-unix -*-\n") + (insert ";; Automatically written history of nREPL session\n") + (insert ";; Edit at your own risk\n\n") + (prin1 (mapcar #'substring-no-properties hist) (current-buffer)))))) + +(defun nrepl-history-save (&optional filename) + "Save the current nREPL input history to FILENAME. +FILENAME defaults to the value of `nrepl-history-file`." + (interactive (list (nrepl-history-read-filename))) + (let* ((file (or filename nrepl-history-file))) + (nrepl-history-write file))) + +(defun nrepl-history-just-save () + "Just save the history to `nrepl-history-file`. +This function is meant to be used in hooks to avoid lambda + constructs." + (nrepl-history-save nrepl-history-file)) + +;; SLIME has different semantics and will not save any duplicates. +(defun nrepl-histories-merge (session-hist file-hist) + (append session-hist)) + +;;; (defun nrepl-same-line-p (pos1 pos2) "Return t if buffer positions POS1 and POS2 are on the same line." (save-excursion (goto-char (min pos1 pos2)) @@ -810,6 +879,11 @@ DIRECTION is 'forward' or 'backward' (in the history list)." major-mode 'nrepl-mode) (set-syntax-table nrepl-mode-syntax-table) (nrepl-eldoc-enable-in-current-buffer) + (when nrepl-history-file + (nrepl-history-load nrepl-history-file) + (make-local-variable 'kill-buffer-hook) + (add-hook 'kill-buffer-hook 'nrepl-history-just-save) + (add-hook 'kill-emacs-hook 'nrepl-history-just-save)) (run-mode-hooks 'nrepl-mode-hook)) ;;; communication