diff options
author | Bozhidar Batsov <bozhidar@tradeo.com> | 2013-10-16 19:28:06 +0300 |
---|---|---|
committer | Bozhidar Batsov <bozhidar@batsov.com> | 2013-10-17 13:02:23 +0300 |
commit | c3b0c093b46759abb776e61b5d66d590c6cffb17 (patch) | |
tree | afd65949f531c29f37b5a88e03297a23bdeabe1f /nrepl-repl.el | |
parent | e2894f975156c8ed8898014bc67bf2082670a4b8 (diff) |
Rename project to CIDER
Diffstat (limited to 'nrepl-repl.el')
-rw-r--r-- | nrepl-repl.el | 864 |
1 files changed, 0 insertions, 864 deletions
diff --git a/nrepl-repl.el b/nrepl-repl.el deleted file mode 100644 index 9657f3bd..00000000 --- a/nrepl-repl.el +++ /dev/null @@ -1,864 +0,0 @@ -;;; nrepl-repl-mode.el --- REPL interactions - -;; Copyright © 2012-2013 Tim King, Phil Hagelberg -;; Copyright © 2013 Bozhidar Batsov, Hugo Duncan, Steve Purcell -;; -;; Author: Tim King <kingtim@gmail.com> -;; Phil Hagelberg <technomancy@gmail.com> -;; Bozhidar Batsov <bozhidar@batsov.com> -;; Hugo Duncan <hugo@hugoduncan.org> -;; Steve Purcell <steve@sanityinc.com> - -;; 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. - -;;; Commentary: - -;; REPL interactions. - -;;; Code: - -(require 'nrepl-client) -(require 'nrepl-interaction) -(require 'nrepl-version) - -(defgroup nrepl-repl nil - "Interaction with the REPL." - :prefix "nrepl-repl-" - :group 'nrepl) - -(defface nrepl-repl-prompt-face - '((t (:inherit font-lock-keyword-face))) - "Face for the prompt in the REPL buffer." - :group 'nrepl-repl) - -(defface nrepl-repl-output-face - '((t (:inherit font-lock-string-face))) - "Face for output in the REPL buffer." - :group 'nrepl-repl) - -(defface nrepl-repl-input-face - '((t (:bold t))) - "Face for previous input in the REPL buffer." - :group 'nrepl-repl) - -(defface nrepl-repl-result-face - '((t ())) - "Face for the result of an evaluation in the REPL buffer." - :group 'nrepl-repl) - -(defcustom nrepl-repl-popup-stacktraces nil - "Non-nil means pop-up error stacktraces in the REPL buffer. -Nil means show only an error message in the minibuffer. This variable -overrides `nrepl-popup-stacktraces' in REPL buffers." - :type 'boolean - :group 'nrepl-repl) - -(defcustom nrepl-repl-pop-to-buffer-on-connect t - "Controls whether to pop to the REPL buffer on connect. - -When set to nil the buffer will only be created." - :type 'boolean - :group 'nrepl-repl) - -(defcustom nrepl-repl-use-pretty-printing nil - "Control whether the results in REPL are pretty-printed or not. -The `nrepl-toggle-pretty-printing' command can be used to interactively -change the setting's value." - :type 'boolean - :group 'nrepl-repl) - -(defcustom nrepl-repl-tab-command 'nrepl-indent-and-complete-symbol - "Select the command to be invoked by the TAB key. -The default option is `nrepl-indent-and-complete-symbol'. If -you'd like to use the default Emacs behavior use -`indent-for-tab-command'." - :type 'symbol - :group 'nrepl-repl) - -;;;; REPL buffer local variables -(defvar nrepl-input-start-mark) - -(defvar nrepl-prompt-start-mark) - -(defvar nrepl-old-input-counter 0 - "Counter used to generate unique `nrepl-old-input' properties. -This property value must be unique to avoid having adjacent inputs be -joined together.") - -(defvar nrepl-input-history '() - "History list of strings read from the nREPL buffer.") - -(defvar nrepl-input-history-items-added 0 - "Variable counting the items added in the current session.") - -(defvar nrepl-output-start nil - "Marker for the start of output.") - -(defvar nrepl-output-end nil - "Marker for the end of output.") - -(nrepl-make-variables-buffer-local - 'nrepl-input-start-mark - 'nrepl-prompt-start-mark - 'nrepl-old-input-counter - 'nrepl-input-history - 'nrepl-input-history-items-added - 'nrepl-output-start - 'nrepl-output-end) - -(defun nrepl-tab () - "Invoked on TAB keystrokes in `nrepl-repl-mode' buffers." - (interactive) - (funcall nrepl-repl-tab-command)) - -(defun nrepl-reset-markers () - "Reset all REPL markers." - (dolist (markname '(nrepl-output-start - nrepl-output-end - nrepl-prompt-start-mark - nrepl-input-start-mark)) - (set markname (make-marker)) - (set-marker (symbol-value markname) (point)))) - -(defmacro nrepl-propertize-region (props &rest body) - "Add PROPS to all text inserted by executing BODY. -More precisely, PROPS are added to the region between the point's -positions before and after executing BODY." - (let ((start (make-symbol "start-pos"))) - `(let ((,start (point))) - (prog1 (progn ,@body) - (add-text-properties ,start (point) ,props))))) - -(put 'nrepl-propertize-region 'lisp-indent-function 1) - -;;; REPL init -(defun nrepl-repl-buffer-name () - "Generate a REPL buffer name based on current connection buffer." - (with-current-buffer (get-buffer (nrepl-current-connection-buffer)) - (nrepl-buffer-name nrepl-repl-buffer-name-template))) - -(defun nrepl-create-repl-buffer (process) - "Create a REPL buffer for PROCESS." - (nrepl-init-repl-buffer - process - (let ((buffer-name (nrepl-repl-buffer-name))) - (if nrepl-repl-pop-to-buffer-on-connect - (pop-to-buffer buffer-name) - (generate-new-buffer buffer-name)) - buffer-name))) - -(defun nrepl-make-repl (process) - "Make a REPL for the connection PROCESS." - (let ((connection-buffer (process-buffer process)) - (repl-buffer (nrepl-create-repl-buffer process))) - (with-current-buffer repl-buffer - (setq nrepl-connection-buffer (buffer-name connection-buffer))) - (with-current-buffer connection-buffer - (setq nrepl-repl-buffer (buffer-name repl-buffer))))) - -;;; Words of inspiration -(defun nrepl-user-first-name () - "Find the current user's first name." - (let ((name (if (string= (user-full-name) "") - (user-login-name) - (user-full-name)))) - (string-match "^[^ ]*" name) - (capitalize (match-string 0 name)))) - -(defvar nrepl-words-of-inspiration - `("The best way to predict the future is to invent it. -Alan Kay" - "A point of view is worth 80 IQ points. -Alan Kay" - "Lisp isn't a language, it's a building material. -Alan Kay" - "Simple things should be simple, complex things should be possible. -Alan Kay" - "Measuring programming progress by lines of code is like measuring aircraft building progress by weight. -Bill Gates" - "Controlling complexity is the essence of computer programming. -Brian Kernighan" - "The unavoidable price of reliability is simplicity. -C.A.R. Hoare" - "You're bound to be unhappy if you optimize everything. -Donald Knuth" - "Simplicity is prerequisite for reliability. -Edsger W. Dijkstra" - "Deleted code is debugged code. -Jeff Sickel" - "The key to performance is elegance, not battalions of special cases. -Jon Bentley and Doug McIlroy" - "First, solve the problem. Then, write the code. -John Johnson" - "Simplicity is the ultimate sophistication. -Leonardo da Vinci" - "Programming is not about typing... it's about thinking. -Rich Hickey" - "Design is about pulling things apart. -Rich Hickey" - "Programmers know the benefits of everything and the tradeoffs of nothing. -Rich Hickey" - "Code never lies, comments sometimes do. -Ron Jeffries" - "Take this nREPL, brother, and may it serve you well." - "Let the hacking commence!" - "Hacks and glory await!" - "Hack and be merry!" - "Your hacking starts... NOW!" - "May the Source be with you!" - "May the Source shine upon thy nREPL!" - "Code long and prosper!" - "Happy hacking!" - ,(format "%s, this could be the start of a beautiful program." - (nrepl-user-first-name))) - "Scientifically-proven optimal words of hackerish encouragement.") - -(defun nrepl-random-words-of-inspiration () - "Select a random entry from `nrepl-words-of-inspiration'." - (eval (nth (random (length nrepl-words-of-inspiration)) - nrepl-words-of-inspiration))) - -(defun nrepl--banner () - "Generate the welcome REPL buffer banner." - (format "; nrepl.el %s (Clojure %s, nREPL %s)" - (nrepl-version) - (nrepl--clojure-version) - (nrepl--backend-version))) - -(defun nrepl-insert-banner-and-prompt (ns) - "Insert REPL banner and REPL prompt, taking into account NS." - (when (zerop (buffer-size)) - (insert (propertize (nrepl--banner) 'face 'font-lock-comment-face))) - (goto-char (point-max)) - (nrepl-mark-output-start) - (nrepl-mark-input-start) - (nrepl-insert-prompt ns)) - - -(defun nrepl-init-repl-buffer (connection buffer &optional noprompt) - "Initialize the REPL for CONNECTION in BUFFER. -Insert a banner, unless NOPROMPT is non-nil." - (with-current-buffer buffer - (unless (eq major-mode 'nrepl-repl-mode) - (nrepl-repl-mode)) - ;; use the same requires by default as clojure.main does - (nrepl-send-string-sync nrepl-repl-requires-sexp) - (nrepl-reset-markers) - (unless noprompt - (nrepl-insert-banner-and-prompt nrepl-buffer-ns)) - (nrepl-remember-clojure-buffer nrepl-current-clojure-buffer) - (current-buffer))) - -(defun nrepl-find-or-create-repl-buffer () - "Return the REPL buffer, create it if necessary." - (let ((buffer (nrepl-current-repl-buffer))) - (if (null buffer) - (error "No active nREPL connection") - (let ((buffer (get-buffer buffer))) - (or (when (buffer-live-p buffer) buffer) - (let ((buffer (nrepl-current-connection-buffer))) - (if (null buffer) - (error "No active nREPL connection") - (nrepl-init-repl-buffer - (get-process buffer) - (get-buffer-create - (nrepl-repl-buffer-name)))))))))) - - -;;; REPL interaction -(defun nrepl-property-bounds (prop) - "Return the the positions of the previous and next change to PROP. -PROP is the name of a text property." - (assert (get-text-property (point) prop)) - (let ((end (next-single-char-property-change (point) prop))) - (list (previous-single-char-property-change end prop) end))) - -(defun nrepl-in-input-area-p () - "Return t if in input area." - (<= nrepl-input-start-mark (point))) - -(defun nrepl-current-input (&optional until-point-p) - "Return the current input as string. -The input is the region from after the last prompt to the end of -buffer. If UNTIL-POINT-P is non-nil, the input is until the current -point." - (buffer-substring-no-properties nrepl-input-start-mark - (if until-point-p - (point) - (point-max)))) - -(defun nrepl-previous-prompt () - "Move backward to the previous prompt." - (interactive) - (nrepl-find-prompt t)) - -(defun nrepl-next-prompt () - "Move forward to the next prompt." - (interactive) - (nrepl-find-prompt)) - -(defun nrepl-find-prompt (&optional backward) - "Find the next prompt. -If BACKWARD is non-nil look backward." - (let ((origin (point)) - (prop 'nrepl-prompt)) - (while (progn - (nrepl-search-property-change prop backward) - (not (or (nrepl-end-of-proprange-p prop) (bobp) (eobp))))) - (unless (nrepl-end-of-proprange-p prop) - (goto-char origin)))) - -(defun nrepl-search-property-change (prop &optional backward) - "Search forward for a property change to PROP. -If BACKWARD is non-nil search backward." - (cond (backward - (goto-char (previous-single-char-property-change (point) prop))) - (t - (goto-char (next-single-char-property-change (point) prop))))) - -(defun nrepl-end-of-proprange-p (property) - "Return t if at the the end of a property range for PROPERTY." - (and (get-char-property (max 1 (1- (point))) property) - (not (get-char-property (point) property)))) - -(defun nrepl-mark-input-start () - "Mark the input start." - (set-marker nrepl-input-start-mark (point) (current-buffer))) - -(defun nrepl-mark-output-start () - "Mark the output start." - (set-marker nrepl-output-start (point)) - (set-marker nrepl-output-end (point))) - -(defun nrepl-mark-output-end () - "Marke the output end." - (add-text-properties nrepl-output-start nrepl-output-end - '(face nrepl-repl-output-face - rear-nonsticky (face)))) - -;;;;; History - -(defcustom nrepl-wrap-history nil - "T to wrap history around when the end is reached." - :type 'boolean - :group 'nrepl) - -;; These two vars contain the state of the last history search. We -;; only use them if `last-command' was 'nrepl-history-replace, -;; otherwise we reinitialize them. - -(defvar nrepl-input-history-position -1 - "Newer items have smaller indices.") - -(defvar nrepl-history-pattern nil - "The regexp most recently used for finding input 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) - (incf nrepl-input-history-items-added))) - -(defun nrepl-delete-current-input () - "Delete all text after the prompt." - (interactive) - (goto-char (point-max)) - (delete-region nrepl-input-start-mark (point-max))) - -(defun nrepl-replace-input (string) - "Replace the current REPL input with STRING." - (nrepl-delete-current-input) - (insert-and-inherit string)) - -(defun nrepl-position-in-history (start-pos direction regexp) - "Return the position of the history item starting at START-POS. -Search in DIRECTION for REGEXP. -Return -1 resp the length of the history if no item matches." - ;; Loop through the history list looking for a matching line - (let* ((step (ecase direction - (forward -1) - (backward 1))) - (history nrepl-input-history) - (len (length history))) - (loop for pos = (+ start-pos step) then (+ pos step) - if (< pos 0) return -1 - if (<= len pos) return len - if (string-match regexp (nth pos history)) return pos))) - -(defun nrepl-history-replace (direction &optional regexp) - "Replace the current input with the next line in DIRECTION. -DIRECTION is 'forward' or 'backward' (in the history list). -If REGEXP is non-nil, only lines matching REGEXP are considered." - (setq nrepl-history-pattern regexp) - (let* ((min-pos -1) - (max-pos (length nrepl-input-history)) - (pos0 (cond ((nrepl-history-search-in-progress-p) - nrepl-input-history-position) - (t min-pos))) - (pos (nrepl-position-in-history pos0 direction (or regexp ""))) - (msg nil)) - (cond ((and (< min-pos pos) (< pos max-pos)) - (nrepl-replace-input (nth pos nrepl-input-history)) - (setq msg (format "History item: %d" pos))) - ((not nrepl-wrap-history) - (setq msg (cond ((= pos min-pos) "End of history") - ((= pos max-pos) "Beginning of history")))) - (nrepl-wrap-history - (setq pos (if (= pos min-pos) max-pos min-pos)) - (setq msg "Wrapped history"))) - (when (or (<= pos min-pos) (<= max-pos pos)) - (when regexp - (setq msg (concat msg "; no matching item")))) - (message "%s%s" msg (cond ((not regexp) "") - (t (format "; current regexp: %s" regexp)))) - (setq nrepl-input-history-position pos) - (setq this-command 'nrepl-history-replace))) - -(defun nrepl-history-search-in-progress-p () - "Return t if a current history search is in progress." - (eq last-command 'nrepl-history-replace)) - -(defun nrepl-terminate-history-search () - "Terminate the current history search." - (setq last-command this-command)) - -(defun nrepl-previous-input () - "Cycle backwards through input history. -If the `last-command' was a history navigation command use the -same search pattern for this command. -Otherwise use the current input as search pattern." - (interactive) - (nrepl-history-replace 'backward (nrepl-history-pattern t))) - -(defun nrepl-next-input () - "Cycle forwards through input history. -See `nrepl-previous-input'." - (interactive) - (nrepl-history-replace 'forward (nrepl-history-pattern t))) - -(defun nrepl-forward-input () - "Cycle forwards through input history." - (interactive) - (nrepl-history-replace 'forward (nrepl-history-pattern))) - -(defun nrepl-backward-input () - "Cycle backwards through input history." - (interactive) - (nrepl-history-replace 'backward (nrepl-history-pattern))) - -(defun nrepl-previous-matching-input (regexp) - "Find the previous input matching REGEXP." - (interactive "sPrevious element matching (regexp): ") - (nrepl-terminate-history-search) - (nrepl-history-replace 'backward regexp)) - -(defun nrepl-next-matching-input (regexp) - "Find then next input matching REGEXP." - (interactive "sNext element matching (regexp): ") - (nrepl-terminate-history-search) - (nrepl-history-replace 'forward regexp)) - -(defun nrepl-history-pattern (&optional use-current-input) - "Return the regexp for the navigation commands. -If USE-CURRENT-INPUT is non-nil, use the current input." - (cond ((nrepl-history-search-in-progress-p) - nrepl-history-pattern) - (use-current-input - (assert (<= nrepl-input-start-mark (point))) - (let ((str (nrepl-current-input t))) - (cond ((string-match "^[ \n]*$" str) nil) - (t (concat "^" (regexp-quote str)))))) - (t nil))) - -;;; persistent history -(defcustom nrepl-history-size 500 - "The maximum number of items to keep in the REPL history." - :type 'integer - :safe 'integerp - :group 'nrepl-repl-mode) - -(defcustom nrepl-history-file nil - "File to save the persistent REPL history to." - :type 'string - :safe 'stringp - :group 'nrepl-repl-mode) - -(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 FILENAME and return it. -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-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 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 - nrepl-input-history-items-added - (nrepl-history-read filename))) - ;; newest items are at the beginning of the list, thus 0 - (hist (cl-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. -;; we keep track of how many items were added to the history in the -;; current session in nrepl-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 nrepl-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 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)) - (<= (max pos1 pos2) (line-end-position)))) - -(defun nrepl-bol-internal () - "Go to the beginning of line or the prompt." - (cond ((and (>= (point) nrepl-input-start-mark) - (nrepl-same-line-p (point) nrepl-input-start-mark)) - (goto-char nrepl-input-start-mark)) - (t (beginning-of-line 1)))) - -(defun nrepl-bol () - "Go to the beginning of line or the prompt." - (interactive) - (deactivate-mark) - (nrepl-bol-internal)) - -(defun nrepl-bol-mark () - "Set the mark and go to the beginning of line or the prompt." - (interactive) - (unless mark-active - (set-mark (point))) - (nrepl-bol-internal)) - -(defun nrepl-at-prompt-start-p () - "Return t if point is at the start of prompt. -This will not work on non-current prompts." - (= (point) nrepl-input-start-mark)) - -(defun nrepl-show-maximum-output () - "Put the end of the buffer at the bottom of the window." - (when (eobp) - (let ((win (get-buffer-window (current-buffer)))) - (when win - (with-selected-window win - (set-window-point win (point-max)) - (recenter -1)))))) - -(defmacro nrepl-save-marker (marker &rest body) - "Save MARKER and execute BODY." - (let ((pos (make-symbol "pos"))) - `(let ((,pos (marker-position ,marker))) - (prog1 (progn . ,body) - (set-marker ,marker ,pos))))) - -(put 'nrepl-save-marker 'lisp-indent-function 1) - -(defun nrepl-insert-prompt (namespace) - "Insert the prompt (before markers!), taking into account NAMESPACE. -Set point after the prompt. -Return the position of the prompt beginning." - (goto-char nrepl-input-start-mark) - (nrepl-save-marker nrepl-output-start - (nrepl-save-marker nrepl-output-end - (unless (bolp) (insert-before-markers "\n")) - (let ((prompt-start (point)) - (prompt (format "%s> " namespace))) - (nrepl-propertize-region - '(face nrepl-repl-prompt-face read-only t intangible t - nrepl-prompt t - rear-nonsticky (nrepl-prompt read-only face intangible)) - (insert-before-markers prompt)) - (set-marker nrepl-prompt-start-mark prompt-start) - prompt-start)))) - -(defun nrepl-emit-output-at-pos (buffer string position &optional bol) - "Using BUFFER, insert STRING at POSITION and mark it as output. -If BOL is non-nil insert at the beginning of line." - (with-current-buffer buffer - (save-excursion - (nrepl-save-marker nrepl-output-start - (nrepl-save-marker nrepl-output-end - (goto-char position) - (when (and bol (not (bolp))) (insert-before-markers "\n")) - (nrepl-propertize-region `(face nrepl-repl-output-face - rear-nonsticky (face)) - (insert-before-markers string) - (when (and (= (point) nrepl-prompt-start-mark) - (not (bolp))) - (insert-before-markers "\n") - (set-marker nrepl-output-end (1- (point)))))))) - (nrepl-show-maximum-output))) - -(defun nrepl-emit-interactive-output (string) - "Emit STRING as interactive output." - (with-current-buffer (nrepl-current-repl-buffer) - (let ((pos (1- (nrepl-input-line-beginning-position)))) - (nrepl-emit-output-at-pos (current-buffer) string pos t) - (ansi-color-apply-on-region pos (point-max)) - ))) - -(defun nrepl-emit-output (buffer string &optional bol) - "Using BUFFER, emit STRING. -If BOL is non-nil, emit at the beginning of the line." - (with-current-buffer buffer - (nrepl-emit-output-at-pos buffer string nrepl-input-start-mark bol))) - -(defun nrepl-emit-prompt (buffer) - "Emit the REPL prompt into BUFFER." - (with-current-buffer buffer - (save-excursion - (nrepl-save-marker nrepl-output-start - (nrepl-save-marker nrepl-output-end - (nrepl-insert-prompt nrepl-buffer-ns)))) - (nrepl-show-maximum-output))) - -(defun nrepl-emit-result (buffer string &optional bol) - "Emit into BUFFER the result STRING and mark it as an evaluation result. -If BOL is non-nil insert at the beginning of the line." - (with-current-buffer buffer - (save-excursion - (nrepl-save-marker nrepl-output-start - (nrepl-save-marker nrepl-output-end - (goto-char nrepl-input-start-mark) - (when (and bol (not (bolp))) (insert-before-markers "\n")) - (nrepl-propertize-region `(face nrepl-repl-result-face - rear-nonsticky (face)) - (insert-before-markers string))))) - (nrepl-show-maximum-output))) - - -(defun nrepl-newline-and-indent () - "Insert a newline, then indent the next line. -Restrict the buffer from the prompt for indentation, to avoid being -confused by strange characters (like unmatched quotes) appearing -earlier in the buffer." - (interactive) - (save-restriction - (narrow-to-region nrepl-prompt-start-mark (point-max)) - (insert "\n") - (lisp-indent-line))) - -(defun nrepl-indent-and-complete-symbol () - "Indent the current line and perform symbol completion. -First indent the line. If indenting doesn't move point, complete -the symbol." - (interactive) - (let ((pos (point))) - (lisp-indent-line) - (when (= pos (point)) - (if (save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t)) - (completion-at-point))))) - -(defun nrepl-kill-input () - "Kill all text from the prompt to point." - (interactive) - (cond ((< (marker-position nrepl-input-start-mark) (point)) - (kill-region nrepl-input-start-mark (point))) - ((= (point) (marker-position nrepl-input-start-mark)) - (nrepl-delete-current-input)))) - -(defun nrepl-input-complete-p (start end) - "Return t if the region from START to END is a complete sexp." - (save-excursion - (goto-char start) - (cond ((looking-at "\\s *[@'`#]?[(\"]") - (ignore-errors - (save-restriction - (narrow-to-region start end) - ;; Keep stepping over blanks and sexps until the end of - ;; buffer is reached or an error occurs. Tolerate extra - ;; close parens. - (loop do (skip-chars-forward " \t\r\n)") - until (eobp) - do (forward-sexp)) - t))) - (t t)))) - -(defun nrepl-send-input (&optional newline) - "Go to the end of the input and send the current input. -If NEWLINE is true then add a newline at the end of the input." - (unless (nrepl-in-input-area-p) - (error "No input at point")) - (goto-char (point-max)) - (let ((end (point))) ; end of input, without the newline - (nrepl-add-to-input-history (buffer-substring nrepl-input-start-mark end)) - (when newline - (insert "\n") - (nrepl-show-maximum-output)) - (let ((inhibit-modification-hooks t)) - (add-text-properties nrepl-input-start-mark - (point) - `(nrepl-old-input - ,(incf nrepl-old-input-counter)))) - (let ((overlay (make-overlay nrepl-input-start-mark end))) - ;; These properties are on an overlay so that they won't be taken - ;; by kill/yank. - (overlay-put overlay 'read-only t) - (overlay-put overlay 'face 'nrepl-repl-input-face))) - (let* ((input (nrepl-current-input)) - (form (if (and (not (string-match "\\`[ \t\r\n]*\\'" input)) nrepl-repl-use-pretty-printing) - (format "(clojure.pprint/pprint %s)" input) input))) - (goto-char (point-max)) - (nrepl-mark-input-start) - (nrepl-mark-output-start) - (nrepl-send-string form (nrepl-handler (current-buffer)) nrepl-buffer-ns))) - -(defun nrepl-return (&optional end-of-input) - "Evaluate the current input string, or insert a newline. -Send the current input ony if a whole expression has been entered, -i.e. the parenthesis are matched. -When END-OF-INPUT is non-nil, send the input even if the parentheses -are not balanced." - (interactive "P") - (cond - (end-of-input - (nrepl-send-input)) - ((and (get-text-property (point) 'nrepl-old-input) - (< (point) nrepl-input-start-mark)) - (nrepl-grab-old-input end-of-input) - (nrepl-recenter-if-needed)) - ((nrepl-input-complete-p nrepl-input-start-mark (point-max)) - (nrepl-send-input t)) - (t - (nrepl-newline-and-indent) - (message "[input not complete]")))) - -(defun nrepl-recenter-if-needed () - "Make sure that the point is visible." - (unless (pos-visible-in-window-p (point-max)) - (save-excursion - (goto-char (point-max)) - (recenter -1)))) - -(defun nrepl-grab-old-input (replace) - "Resend the old REPL input at point. -If REPLACE is non-nil the current input is replaced with the old -input; otherwise the new input is appended. The old input has the -text property `nrepl-old-input'." - (multiple-value-bind (beg end) (nrepl-property-bounds 'nrepl-old-input) - (let ((old-input (buffer-substring beg end)) ;;preserve - ;;properties, they will be removed later - (offset (- (point) beg))) - ;; Append the old input or replace the current input - (cond (replace (goto-char nrepl-input-start-mark)) - (t (goto-char (point-max)) - (unless (eq (char-before) ?\ ) - (insert " ")))) - (delete-region (point) (point-max)) - (save-excursion - (insert old-input) - (when (equal (char-before) ?\n) - (delete-char -1))) - (forward-char offset)))) - -(defun nrepl-closing-return () - "Evaluate the current input string after closing all open lists." - (interactive) - (goto-char (point-max)) - (save-restriction - (narrow-to-region nrepl-input-start-mark (point)) - (while (ignore-errors (save-excursion (backward-up-list 1)) t) - (insert ")"))) - (nrepl-return)) - -(defun nrepl-toggle-pretty-printing () - "Toggle pretty-printing in the REPL." - (interactive) - (setq nrepl-repl-use-pretty-printing (not nrepl-repl-use-pretty-printing)) - (message "Pretty printing in nREPL %s." - (if nrepl-repl-use-pretty-printing "enabled" "disabled"))) - -(defvar nrepl-clear-buffer-hook) - -(defun nrepl-clear-buffer () - "Delete the output generated by the Clojure process." - (interactive) - (let ((inhibit-read-only t)) - (delete-region (point-min) nrepl-prompt-start-mark) - (delete-region nrepl-output-start nrepl-output-end) - (when (< (point) nrepl-input-start-mark) - (goto-char nrepl-input-start-mark)) - (recenter t)) - (run-hooks 'nrepl-clear-buffer-hook)) - -(defun nrepl-find-and-clear-repl-buffer () - "Find the current REPL buffer and clear it. -Returns to the buffer in which the command was invoked." - (interactive) - (let ((origin-buffer (current-buffer))) - (switch-to-buffer (nrepl-current-repl-buffer)) - (nrepl-clear-buffer) - (switch-to-buffer origin-buffer))) - -(defun nrepl-input-line-beginning-position () - "Return the position of the beginning of input." - (save-excursion - (goto-char nrepl-input-start-mark) - (line-beginning-position))) - -(defun nrepl-clear-output () - "Delete the output inserted since the last input." - (interactive) - (let ((start (save-excursion - (nrepl-previous-prompt) - (ignore-errors (forward-sexp)) - (forward-line) - (point))) - (end (1- (nrepl-input-line-beginning-position)))) - (when (< start end) - (let ((inhibit-read-only t)) - (delete-region start end) - (save-excursion - (goto-char start) - (insert - (propertize ";;; output cleared" 'face 'font-lock-comment-face))))))) - -(provide 'nrepl-repl) -;;; nrepl-repl.el ends here |