From 7a4a8f611cb80493ad5630a9477ab82dde1b7318 Mon Sep 17 00:00:00 2001 From: Alexander Yakushev Date: Sat, 18 Jul 2015 23:18:09 +0300 Subject: [PATCH] [c.s.keywords] Improved support for ns-qualified keywords See clojure-emacs/cider-nrepl#224. --- src/compliment/sources/keywords.clj | 38 ++++++++++++++++++++++---- test/compliment/sources/t_keywords.clj | 13 ++++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/compliment/sources/keywords.clj b/src/compliment/sources/keywords.clj index fb66dad..9b1547d 100644 --- a/src/compliment/sources/keywords.clj +++ b/src/compliment/sources/keywords.clj @@ -1,7 +1,7 @@ (ns compliment.sources.keywords "Completion for keywords interned globally across the application" (:require [compliment.sources :refer [defsource]] - [compliment.utils :refer [defmemoized]]) + [compliment.utils :refer [defmemoized resolve-namespace]]) (:import java.lang.reflect.Field)) (defmemoized ^:private keywords-table @@ -10,12 +10,38 @@ (.setAccessible field true) (.get field nil))) -(defn candidates - [prefix _ _] - (when (= (first prefix) \:) +(defn qualified-candidates + "Returns a list of namespace-qualified double-colon keywords (like ::foo) + resolved for the given namespace." + [prefix ns] + (let [prefix (subs prefix 2) + ns-name (str ns)] + (for [[kw _] (keywords-table) + :when (= (namespace kw) ns-name) + :when (.startsWith (name kw) prefix)] + (str "::" (name kw))))) + +(defn aliased-candidates + "Returns a list of alias-qualified double-colon keywords (like ::str/foo), + where alias has to be registered in the given namespace." + [prefix ns] + (let [[_ alias prefix] (re-matches #"::([^/]+)/(.*)" prefix) + alias-ns-name (str (resolve-namespace (symbol alias) ns))] (for [[kw _] (keywords-table) - :when (.startsWith (str kw) (subs prefix 1))] - (str ":" kw)))) + :when (= (namespace kw) alias-ns-name) + :when (.startsWith (name kw) prefix)] + (str "::" alias "/" (name kw))))) + +(defn candidates + [^String prefix, ns _] + (let [single-colon? (.startsWith prefix ":") + double-colon? (.startsWith prefix "::") + has-slash? (> (.indexOf prefix "/") -1)] + (cond (and double-colon? has-slash?) (aliased-candidates prefix ns) + double-colon? (qualified-candidates prefix ns) + single-colon? (for [[kw _] (keywords-table) + :when (.startsWith (str kw) (subs prefix 1))] + (str ":" kw))))) (defsource ::keywords :candidates #'candidates diff --git a/test/compliment/sources/t_keywords.clj b/test/compliment/sources/t_keywords.clj index 76fa389..72fbcf7 100644 --- a/test/compliment/sources/t_keywords.clj +++ b/test/compliment/sources/t_keywords.clj @@ -14,4 +14,15 @@ => (contains #{":compliment.sources.t-keywords/bar" ":compliment.sources.t-keywords/baz" ":compliment.sources.t-keywords/foo"} - :gaps-ok))) + :gaps-ok)) + + (fact "namespace-qualified keywords can be completed in the same namespace" + (do (str ::foo ::bar ::baz) + (src/candidates "::ba" *ns* nil)) + => (contains #{"::bar" "::baz"} :gaps-ok)) + + (fact "namespace-qualified keywords can be completed with an ns alias" + (do (str :compliment.core/aliased-one :compliment.core/aliased-two) + (require '[compliment.core :as core]) + (src/candidates "::core/ali" *ns* nil)) + => (contains #{"::core/aliased-two" "::core/aliased-one"} :gaps-ok)))