diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eca521..80c5dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * [#114](https://github.com/clojure-emacs/inf-clojure/pull/114): Introduce `inf-clojure-project-type` defcustom. * [#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. ## 2.0.1 (2017-05-18) diff --git a/README.md b/README.md index f528b1c..eebb9d1 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,18 @@ following to you Emacs config: ElDoc currently doesn't work with ClojureScript buffers and REPL's. You can leave it enabled, it just won't show anything in the echo area. +#### Code Completion + +Code completion is particularly open to customization. Not only you can `setq` +the customary `inf-clojure-completion-form`, `inf-clojure-completion-form-lumo` +and `inf-clojure-completion-form-planck` - the form to send to the REPL - but +you can also use `inf-clojure-completions-fn` for specifying a function that +given the REPL response should return elisp data compatible with +[`completion-at-point-functions`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html). +For more info run `M-x describe-variable RET inf-clojure-completions-fn`. +Another option is to have a look at +[how cider does it](https://github.com/clojure-emacs/cider/blob/3e9ed12e8cfbad04d7618e649322765dc9bff5d6/cider-interaction.el#L595). + #### Lumo Setup For an optimal Lumo experience the `-d` needs to be passed to Lumo diff --git a/inf-clojure.el b/inf-clojure.el index ed6058e..3106d8a 100644 --- a/inf-clojure.el +++ b/inf-clojure.el @@ -1210,7 +1210,7 @@ prefix argument PROMPT-FOR-NS, it prompts for a namespace name." (defun inf-clojure-set-ns (prompt-for-ns) "Set the ns of the inferior Clojure process to NS. -See variable `inf-clojure-set-ns-form`. It defaults to the ns of +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") @@ -1254,14 +1254,52 @@ See variable `inf-clojure-buffer'." "Return DATA if and only if it is a list." (when (listp data) data)) +(defun inf-clojure-list-completions (response-str) + "Parse completions from RESPONSE-STR. + +Its only ability is to parse a Lisp list of candidate strings, +every other EXPR will be discarded and nil will be returned." + (thread-first + response-str + (inf-clojure--read-or-nil) + (inf-clojure--list-or-nil))) + (defun inf-clojure-completions (expr) - "Return a list of completions for the Clojure expression starting with EXPR." + "Return completions for the Clojure expression starting with EXPR. + +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)) - (thread-first - (format (inf-clojure-completion-form) (substring-no-properties expr)) - (inf-clojure--process-response (inf-clojure-proc) "(" ")") - (inf-clojure--read-or-nil) - (inf-clojure--list-or-nil)))) + (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 "(" ")"))))) + +(defcustom inf-clojure-completions-fn 'inf-clojure-list-completions + "The function that parses completion results. + +It is a single-arity function that will receive the REPL +evaluation result of \\[inf-clojure-completion-form] as string and +should return elisp data compatible with your completion mode. + +The easiest possible data passed in input is a list of +candidates (e.g.: (\"def\" \"defn\")) but more complex libraries +like `alexander-yakushev/compliment' can return other things like +edn. + +The expected return depends on the mode that you use for +completion: usually it is something compatible with +\\[completion-at-point-functions] but other modes like +`company-mode' allow an even higher level of sophistication. + +The default value is the `inf-clojure-list-completions' function, +which is able to parse results in list form only. You can peek +at its implementation for getting to know some utility functions +you might want to use in your customization." + :type 'function + :safe #'functionp + :package-version '(inf-clojure . "2.1.0")) (defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{()[]")