Skip to content

Commit

Permalink
[Fix clojure-emacs#111] Introduce inf-clojure-compliment completions
Browse files Browse the repository at this point in the history
Given compliment on the classpath, the inf-clojure-compliment can be required
in order to customize the right defcustoms that are necessary for it.
Completions are only annotated and in order to customize this process an
inf-clojure hacker can use inf-clojure-completions-annotation-fn.
  • Loading branch information
arichiardi committed Jan 5, 2018
1 parent 247ca70 commit c4aa6d2
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 8 deletions.
117 changes: 117 additions & 0 deletions inf-clojure-compliment.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
;;; inf-clojure-compliment.el --- Completion file for Inf-Clojure -*- lexical-binding: t; -*-
;;
;; Copyright © 2014-2018 Bozhidar Batsov

;; Authors: Bozhidar Batsov <bozhidar@batsov.com>
;; Andrea Richiardi <a.richiardi.work@gmail.com>
;; URL: http://github.com/clojure-emacs/inf-clojure
;; Keywords: processes, clojure
;; Version: 2.1.0
;; Package-Requires: ((emacs "24.4") (edn "1.1.2"))

;; This file is part of GNU Emacs.

;; GNU Emacs 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.

;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.

;; Authors: Andrea Richiardi
;;
;; URL: http://github.com/clojure-emacs/inf-clojure
;; Keywords: processes, clojure

;;; Commentary:
;;
;; Code completion using alexander-yakushev/compliment.

;;; Code:

(require 'edn)

(defconst inf-clojure-compliment--annotations-alist
'((:class "c")
(:field "fi")
(:function "f")
(:import "i")
(:keyword "k")
(:local "l")
(:macro "m")
(:method "me")
(:namespace "n")
(:protocol "p")
(:protocol-function "pf")
(:record "r")
(:special-form "s")
(:static-field "sf")
(:static-method "sm")
(:type "t")
(:var "v"))
"Controls the abbreviations used when annotating completion candidates.
Must be a list of elements with the form (TYPE . ABBREVIATION), where TYPE
is a possible value of the candidate's type returned from the completion
backend, and ABBREVIATION is a short form of that type.")

(defun inf-clojure-compliment--get-candidate-type (symbol)
"Get candidate type for SYMBOL."
(let ((type (get-text-property 0 'type symbol)))
(or (cadr (assoc type inf-clojure-compliment--annotations-alist))
type)))

(defun inf-clojure-compliment--get-candidate-ns (symbol)
"Get candidate ns for SYMBOL."
(get-text-property 0 'ns symbol))

(defun inf-clojure-compliment--annotate-symbol (symbol)
"Return a string suitable for annotating SYMBOL.
If SYMBOL has a text property `type` whose value is recognised, its
abbreviation according to `cider-completion-annotations-alist' will be
used. If `type` is present but not recognised, its value will be used
unaltered."
(let* ((type (inf-clojure-compliment--get-candidate-type symbol))
(ns (inf-clojure-compliment--get-candidate-ns symbol)))
(concat (when ns (format " (%s)" ns))
(when type (format " <%s>" type)))))

(defun inf-clojure-compliment--parse-candidate (candidate)
"Get \"candidate\" from CANDIDATE.
Put type and ns properties on the candidate"
(let ((entry (gethash :candidate candidate))
(type (gethash :type candidate))
(ns (gethash :ns candidate)))
(put-text-property 0 1 'type type entry)
(put-text-property 0 1 'ns ns entry)
entry))

(defun inf-clojure-compliment--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."
(mapcar #'inf-clojure-compliment--parse-candidate
(thread-first
response-str
(inf-clojure--some)
(edn-read))))

(setq inf-clojure-completions-fn #'inf-clojure-compliment--completions)
(setq inf-clojure-completions-annotation-fn #'inf-clojure-compliment--annotate-symbol)
(setq inf-clojure-completion-form "(do (require '[compliment.core :as comp]) (compliment.core/completions \"%s\"))")

(provide 'inf-clojure-compliment)

;; Local variables:
;; coding: utf-8
;; indent-tabs-mode: nil
;; End:

;;; inf-clojure-compliment.el ends here
35 changes: 27 additions & 8 deletions inf-clojure.el
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ 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)
(defun inf-clojure--list-completions (response-str)
"Parse completions from RESPONSE-STR.
Its only ability is to parse a Lisp list of candidate strings,
Expand All @@ -1265,7 +1265,7 @@ every other EXPR will be discarded and nil will be returned."
(inf-clojure--read-or-nil)
(inf-clojure--list-or-nil)))

(defun inf-clojure-completions (expr)
(defun inf-clojure--completions (expr)
"Return completions for the Clojure expression starting with EXPR.
Under the hood it calls the function
Expand All @@ -1277,7 +1277,7 @@ evaluating \\[inf-clojure-completion-form] at the REPL."
(funcall inf-clojure-completions-fn
(inf-clojure--process-response completion-form proc "(" ")")))))

(defcustom inf-clojure-completions-fn 'inf-clojure-list-completions
(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
Expand All @@ -1294,14 +1294,31 @@ 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,
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"))

(defcustom inf-clojure-completions-annotation-fn nil
"The function that annotates completion results.
It is a single-arity function that will receive a a completion
candidate from \\[inf-clojure-completions-fn] and returns the
string that some completion backends (like `company-mode' use for
augmenting the results.
The candidate may or may not contain text properties. The
`inf-clojure-completions-fn' is responsible for passing back
these text properties. You can retrieve any of these properties
with `get-text-property', such as \(get-text-property 0
'type candidate)."
:type 'function
:safe #'functionp
:package-version '(inf-clojure . "2.2.0"))

(defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{()[]")

(defun inf-clojure-completion-bounds-of-expr-at-point ()
Expand All @@ -1325,10 +1342,12 @@ you might want to use in your customization."
Returns the selected completion or nil."
(let ((bounds (inf-clojure-completion-bounds-of-expr-at-point)))
(when bounds
(list (car bounds) (cdr bounds)
(if (fboundp 'completion-table-with-cache)
(completion-table-with-cache #'inf-clojure-completions)
(completion-table-dynamic #'inf-clojure-completions))))))
(nconc (list (car bounds) (cdr bounds)
(if (fboundp 'completion-table-with-cache)
(completion-table-with-cache #'inf-clojure--completions)
(completion-table-dynamic #'inf-clojure--completions)))
(when inf-clojure-completions-annotation-fn
(list :annotation-function inf-clojure-completions-annotation-fn))))))

;;;; ElDoc
;;;; =====
Expand Down

0 comments on commit c4aa6d2

Please sign in to comment.