From a6da43a24966d8378e8c4821183b820a4e8bb19e Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Fri, 12 Jan 2018 09:56:59 -0800 Subject: [PATCH] Avoid throwing an error for frequent operations like completion This patch introduces an argument to inf-clojure-proc so that client code can decide when to error out return the processs. This is necessary because while it is good to communicate an error on "eval" operations, it is not good to have it on "under the hood" and very frequent ones like completion and get arglists. --- CHANGELOG.md | 1 + inf-clojure.el | 141 ++++++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c384c..9f63d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * [#117](https://github.com/clojure-emacs/inf-clojure/pull/117): Introduce `tools.deps` project type and `inf-clojure-tools-deps-cmd`. * [#122](https://github.com/clojure-emacs/inf-clojure/pull/122): Introduce `inf-clojure-completions-fn` defcustom. * [#128](https://github.com/clojure-emacs/inf-clojure/pull/128): Expose `inf-clojure-apropos` as `C-c C-S-a` in `inf-clojure-mode` (the REPL). +* [#125](https://github.com/clojure-emacs/inf-clojure/pull/125): Avoid throwing an error for frequent operations like completion. ### Bugs Fixed diff --git a/inf-clojure.el b/inf-clojure.el index ee0eae8..2854761 100644 --- a/inf-clojure.el +++ b/inf-clojure.el @@ -363,11 +363,11 @@ Clojure to load that file." :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-load-form () - "Return the form to query inferior Clojure for a var's documentation. +(defun inf-clojure-load-form (proc) + "Return the form to query the Inf-Clojure PROC for var's documentation. If you are using REPL types, it will pickup the most appropriate `inf-clojure-var-doc-form` variant." - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-load-form-lumo) (`planck inf-clojure-load-form-planck) (_ inf-clojure-load-form))) @@ -689,15 +689,15 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the file is loaded or not. If the argument FILE-NAME is present it will be used instead of the current file." (interactive "P") - (let ((file-name (or file-name + (let ((proc (inf-clojure-proc)) + (file-name (or file-name (car (comint-get-source "Load Clojure file: " inf-clojure-prev-l/c-dir/file ;; nil because doesn't need an exact name inf-clojure-source-modes nil))))) (comint-check-source file-name) ; Check to see if buffer needs saved. (setq inf-clojure-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) - (inf-clojure--send-string (inf-clojure-proc) - (format (inf-clojure-load-form) file-name)) + (inf-clojure--send-string proc (format (inf-clojure-load-form proc) file-name)) (when switch-to-repl (inf-clojure-switch-to-repl t)))) @@ -736,12 +736,12 @@ is present it will be used instead of the current file." :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-var-doc-form () - "Return the form to query inferior Clojure for a var's documentation. +(defun inf-clojure-var-doc-form (proc) + "Return the form to query the Inf-Clojure PROC for a var's documentation. If you are using REPL types, it will pickup the most approapriate `inf-clojure-var-doc-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-var-doc-form-lumo) (`planck inf-clojure-var-doc-form-planck) (_ inf-clojure-var-doc-form)))) @@ -767,12 +767,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-var-source-form () - "Return the form to query inferior Clojure for a var's source. +(defun inf-clojure-var-source-form (proc) + "Return the form to query the Inf-Clojure PROC for a var's source. If you are using REPL types, it will pickup the most approapriate `inf-clojure-var-source-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-var-source-form-lumo) (`planck inf-clojure-var-source-form-planck) (_ inf-clojure-var-source-form)))) @@ -810,12 +810,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.1.0")) -(defun inf-clojure-arglists-form () - "Return the form to query inferior Clojure for arglists of a var. +(defun inf-clojure-arglists-form (proc) + "Return the form to query the Inf-Clojure PROC for arglists of a var. If you are using REPL types, it will pickup the most approapriate `inf-clojure-arglists-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-arglists-form-lumo) (`planck inf-clojure-arglists-form-planck) (_ inf-clojure-arglists-form)))) @@ -846,12 +846,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-completion-form () - "Return the form to query inferior Clojure for a var's documentation. +(defun inf-clojure-completion-form (proc) + "Return the form to query the Inf-Clojure PROC for completions. If you are using REPL types, it will pickup the most approapriate `inf-clojure-completion-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-completion-form-lumo) (`planck inf-clojure-completion-form-planck) (_ inf-clojure-completion-form)))) @@ -877,12 +877,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-ns-vars-form () - "Return the form to query inferior Clojure for public vars in a namespace. +(defun inf-clojure-ns-vars-form (proc) + "Return the form to query the Inf-Clojure PROC for public vars in a namespace. If you are using REPL types, it will pickup the most approapriate `inf-clojure-ns-vars-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-ns-vars-form-lumo) (`planck inf-clojure-ns-vars-form-planck) (_ inf-clojure-ns-vars-form)))) @@ -910,11 +910,11 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-set-ns-form () - "Return the form to set the ns of the inferior Clojure process. +(defun inf-clojure-set-ns-form (proc) + "Return the form to set the namespace of the Inf-Clojure PROC. If you are using REPL types, it will pickup the most approapriate `inf-clojure-set-ns-form` variant." - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`planck inf-clojure-set-ns-form-planck) (`lumo inf-clojure-set-ns-form-lumo) (_ inf-clojure-set-ns-form))) @@ -944,12 +944,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-apropos-form () - "Return the form to query inferior Clojure for public vars in a namespace. +(defun inf-clojure-apropos-form (proc) + "Return the form to query the Inf-Clojure PROC for a var's apropos. If you are using REPL types, it will pickup the most approapriate -`inf-clojure-ns-vars-form` variant." +`inf-clojure-apropos-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`lumo inf-clojure-apropos-form-lumo) (`planck inf-clojure-apropos-form-planck) (_ inf-clojure-apropos-form)))) @@ -970,12 +970,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-macroexpand-form () - "Return the form for macroexpansion in the inferior Clojure process. +(defun inf-clojure-macroexpand-form (proc) + "Return the form for macroexpansion in the Inf-Clojure PROC. If you are using REPL types, it will pickup the most approapriate `inf-clojure-macroexpand-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`planck inf-clojure-macroexpand-form-planck) (_ inf-clojure-macroexpand-form)))) @@ -995,12 +995,12 @@ If you are using REPL types, it will pickup the most approapriate :safe #'stringp :package-version '(inf-clojure . "2.0.0")) -(defun inf-clojure-macroexpand-1-form () - "Return the form for macroexpand-1 in the inferior Clojure process. +(defun inf-clojure-macroexpand-1-form (proc) + "Return the form for macroexpand-1 in the Inf-Clojure PROC. If you are using REPL types, it will pickup the most approapriate `inf-clojure-macroexpand-1-form` variant." (inf-clojure--sanitize-command - (pcase (inf-clojure--set-repl-type (inf-clojure-proc)) + (pcase (inf-clojure--set-repl-type proc) (`planck inf-clojure-macroexpand-1-form-planck) (_ inf-clojure-macroexpand-1-form)))) @@ -1047,20 +1047,22 @@ The value is nil if it can't find one." See function `inf-clojure-var-doc-form'. When invoked with a prefix argument PROMPT-FOR-SYMBOL, it prompts for a symbol name." (interactive "P") - (let ((var (if prompt-for-symbol - (car (inf-clojure-symprompt "Var doc" (inf-clojure-symbol-at-point))) - (inf-clojure-symbol-at-point)))) - (inf-clojure--send-string (inf-clojure-proc) (format (inf-clojure-var-doc-form) var)))) + (let ((proc (inf-clojure-proc)) + (var (if prompt-for-symbol + (car (inf-clojure-symprompt "Var doc" (inf-clojure-symbol-at-point))) + (inf-clojure-symbol-at-point)))) + (inf-clojure--send-string proc (format (inf-clojure-var-doc-form proc) var)))) (defun inf-clojure-show-var-source (prompt-for-symbol) "Send a command to the inferior Clojure to give source for VAR. See variable `inf-clojure-var-source-form'. When invoked with a prefix argument PROMPT-FOR-SYMBOL, it prompts for a symbol name." (interactive "P") - (let ((var (if prompt-for-symbol + (let ((proc (inf-clojure-proc)) + (var (if prompt-for-symbol (car (inf-clojure-symprompt "Var source" (inf-clojure-symbol-at-point))) (inf-clojure-symbol-at-point)))) - (inf-clojure--send-string (inf-clojure-proc) (format (inf-clojure-var-source-form) var)))) + (inf-clojure--send-string proc (format (inf-clojure-var-source-form proc) var)))) ;;;; Response parsing ;;;; ================ @@ -1190,10 +1192,11 @@ for evaluation, therefore FORM should not include it." (defun inf-clojure-arglists (fn) "Send a query to the inferior Clojure for the arglists for function FN. See variable `inf-clojure-arglists-form'." - (thread-first - (format (inf-clojure-arglists-form) fn) - (inf-clojure--process-response (inf-clojure-proc) "(" ")") - (inf-clojure--some))) + (when-let ((proc (inf-clojure-proc 'no-error))) + (thread-first + (format (inf-clojure-arglists-form proc) fn) + (inf-clojure--process-response proc "(" ")") + (inf-clojure--some)))) (defun inf-clojure-show-arglists (prompt-for-symbol) "Show the arglists for function FN in the mini-buffer. @@ -1212,10 +1215,11 @@ prefix argument PROMPT-FOR-SYMBOL, it prompts for a symbol name." See variable `inf-clojure-ns-vars-form'. When invoked with a prefix argument PROMPT-FOR-NS, it prompts for a namespace name." (interactive "P") - (let ((ns (if prompt-for-ns - (car (inf-clojure-symprompt "Ns vars" (clojure-find-ns))) - (clojure-find-ns)))) - (inf-clojure--send-string (inf-clojure-proc) (format (inf-clojure-ns-vars-form) ns)))) + (let ((proc (inf-clojure-proc)) + (ns (if prompt-for-ns + (car (inf-clojure-symprompt "Ns vars" (clojure-find-ns))) + (clojure-find-ns)))) + (inf-clojure--send-string proc (format (inf-clojure-ns-vars-form proc) ns)))) (defun inf-clojure-set-ns (prompt-for-ns) "Set the ns of the inferior Clojure process to NS. @@ -1223,41 +1227,44 @@ See variable `inf-clojure-set-ns-form'. It defaults to the ns of the current buffer. When invoked with a prefix argument PROMPT-FOR-NS, it prompts for a namespace name." (interactive "P") - (let ((ns (if prompt-for-ns + (let ((proc (inf-clojure-proc)) + (ns (if prompt-for-ns (car (inf-clojure-symprompt "Set ns to" (clojure-find-ns))) (clojure-find-ns)))) (when (or (not ns) (equal ns "")) (user-error "No namespace selected")) - (inf-clojure--send-string (inf-clojure-proc) (format (inf-clojure-set-ns-form) ns)))) + (inf-clojure--send-string proc (format (inf-clojure-set-ns-form proc) ns)))) (defun inf-clojure-apropos (expr) "Send an expression to the inferior Clojure for apropos. EXPR can be either a regular expression or a stringable thing. See variable `inf-clojure-apropos-form'." (interactive (inf-clojure-symprompt "Var apropos" (inf-clojure-symbol-at-point))) - (inf-clojure--send-string (inf-clojure-proc) (format (inf-clojure-apropos-form) expr))) + (let ((proc (inf-clojure-proc))) + (inf-clojure--send-string proc (format (inf-clojure-apropos-form proc) expr)))) (defun inf-clojure-macroexpand (&optional macro-1) "Send a form to the inferior Clojure for macro expansion. See variable `inf-clojure-macroexpand-form'. With a prefix arg MACRO-1 uses function `inf-clojure-macroexpand-1-form'." (interactive "P") - (let ((last-sexp (buffer-substring-no-properties (save-excursion (backward-sexp) (point)) (point)))) + (let ((proc (inf-clojure-proc)) + (last-sexp (buffer-substring-no-properties (save-excursion (backward-sexp) (point)) (point)))) (inf-clojure--send-string - (inf-clojure-proc) + proc (format (if macro-1 - (inf-clojure-macroexpand-1-form) - (inf-clojure-macroexpand-form)) + (inf-clojure-macroexpand-1-form proc) + (inf-clojure-macroexpand-form proc)) last-sexp)))) - -(defun inf-clojure-proc () +(defun inf-clojure-proc (&optional no-error) "Return the current inferior Clojure process. -See variable `inf-clojure-buffer'." - (let ((proc (get-buffer-process (if (derived-mode-p 'inf-clojure-mode) - (current-buffer) - inf-clojure-buffer)))) - (or proc +When NO-ERROR is non-nil, don't throw an error when no connection +has been found. See also variable `inf-clojure-buffer'." + (or (get-buffer-process (if (derived-mode-p 'inf-clojure-mode) + (current-buffer) + inf-clojure-buffer)) + (unless no-error (error "No Clojure subprocess; see variable `inf-clojure-buffer'")))) (defun inf-clojure--list-or-nil (data) @@ -1280,11 +1287,11 @@ every other EXPR will be discarded and nil will be returned." Under the hood it calls the function \\[inf-clojure-completions-fn] passing in the result of evaluating \\[inf-clojure-completion-form] at the REPL." - (when (not (string-blank-p expr)) - (let ((proc (inf-clojure-proc)) - (completion-form (format (inf-clojure-completion-form) (substring-no-properties expr)))) - (funcall inf-clojure-completions-fn - (inf-clojure--process-response completion-form proc "(" ")"))))) + (let ((proc (inf-clojure-proc 'no-error))) + (when (and proc (not (string-blank-p expr))) + (let ((completion-form (format (inf-clojure-completion-form proc) (substring-no-properties expr)))) + (funcall inf-clojure-completions-fn + (inf-clojure--process-response completion-form proc "(" ")")))))) (defcustom inf-clojure-completions-fn 'inf-clojure-list-completions "The function that parses completion results.