diff options
Diffstat (limited to 'vim/bundle/slimv/swank-clojure/swank/commands/contrib')
4 files changed, 631 insertions, 0 deletions
diff --git a/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_arglists.clj b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_arglists.clj new file mode 100644 index 0000000..232a116 --- /dev/null +++ b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_arglists.clj @@ -0,0 +1,123 @@ +(ns swank.commands.contrib.swank-arglists + (:use (swank util core commands))) + +((slime-fn 'swank-require) :swank-c-p-c) + +;;; pos starts at 1 bc 0 is function name +(defn position-in-arglist? [arglist pos] + (or (some #(= '& %) arglist) + (<= pos (count arglist)))) + +;; (position-in-arglist? '[x y] 2) +;; => true + +(defn highlight-position [arglist pos] + (if (zero? pos) + arglist + ;; i.e. not rest args + (let [num-normal-args (count (take-while #(not= % '&) arglist))] + (if (<= pos num-normal-args) + (into [] (concat (take (dec pos) arglist) + '(===>) + (list (nth arglist (dec pos))) + '(<===) + (drop pos arglist))) + (let [rest-arg? (some #(= % '&) arglist)] + (if rest-arg? + (into [] (concat (take-while #(not= % '&) arglist) + '(===>) + '(&) + (list (last arglist)) + '(<===))))))))) + +;; (highlight-position '[x y] 0) +;; => [===> x <=== y] + +(defn highlight-arglists [arglists pos] + (let [arglists (read-string arglists)] + (loop [checked [] + current (first arglists) + remaining (rest arglists)] + (if (position-in-arglist? current pos) + (apply list (concat checked + [(highlight-position current pos)] + remaining)) + (when (seq remaining) + (recur (conj checked current) + (first remaining) + (rest remaining))))))) + +;; (highlight-arglists "([x] [x & more])" 1) +;; => ([===> x <===] [x & more]) + +;;(defmacro dbg[x] `(let [x# ~x] (println '~x "->" x#) x#)) + +(defn defnk-arglists? [arglists] + (and (not (nil? arglists )) + (not (vector? (first (read-string arglists)))))) + +(defn fix-defnk-arglists [arglists] + (str (list (into [] (read-string arglists))))) + +(defn arglists-for-fname-lookup [fname] + ((slime-fn 'operator-arglist) fname *current-package*)) + +(defn arglists-for-fname [fname] + (let [arglists (arglists-for-fname-lookup fname)] + ;; defnk's arglists format is (a b) instead of ([a b]) + (if (defnk-arglists? arglists) + (fix-defnk-arglists arglists) + arglists))) + +(defn message-format [cmd arglists pos] + (str (when cmd (str cmd ": ")) + (when arglists + (if pos + (highlight-arglists arglists pos) + arglists)))) + +(defn handle-apply [raw-specs pos] + (let [fname (second (first raw-specs))] + (message-format fname (arglists-for-fname fname) (dec pos)))) + +(defslimefn arglist-for-echo-area [raw-specs & options] + (let [{:keys [arg-indices + print-right-margin + print-lines]} (apply hash-map options)] + (if-not (and raw-specs + (seq? raw-specs) + (seq? (first raw-specs))) + nil ;; problem? + (let [pos (first (second options)) + top-level? (= 1 (count raw-specs)) + parent-pos (when-not top-level? + (second (second options))) + fname (ffirst raw-specs) + parent-fname (when-not top-level? + (first (second raw-specs))) + arglists (arglists-for-fname fname) + inside-binding? (and (not top-level?) + (#{"let" "binding" "doseq" "for" "loop"} + parent-fname) + (= 1 parent-pos))] +;; (dbg raw-specs) +;; (dbg options) + (cond + ;; display arglists for function being applied unless on top of apply + (and (= fname "apply") (not= pos 0)) (handle-apply raw-specs pos) + ;; highlight binding inside binding forms unless >1 level deep + inside-binding? (message-format parent-fname + (arglists-for-fname parent-fname) + 1) + :else (message-format fname arglists pos)))))) + +(defslimefn variable-desc-for-echo-area [variable-name] + (with-emacs-package + (or + (try + (when-let [sym (read-string variable-name)] + (when-let [var (resolve sym)] + (when (.isBound #^clojure.lang.Var var) + (str variable-name " => " (var-get var))))) + (catch Exception e nil)) + ""))) diff --git a/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c.clj b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c.clj new file mode 100644 index 0000000..40ca3fd --- /dev/null +++ b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c.clj @@ -0,0 +1,21 @@ +(ns swank.commands.contrib.swank-c-p-c + (:use (swank util core commands) + (swank.commands completion) + (swank.util string clojure) + (swank.commands.contrib.swank-c-p-c internal))) + +(defslimefn completions [symbol-string package] + (try + (let [[sym-ns sym-name] (symbol-name-parts symbol-string) + potential (concat + (potential-completions + (when sym-ns (symbol sym-ns)) + (ns-name (maybe-ns package))) + (potential-classes-on-path symbol-string)) + matches (seq (sort (filter #(split-compound-prefix-match? symbol-string %) potential)))] + (list matches + (if matches + (reduce largest-common-prefix matches) + symbol-string))) + (catch java.lang.Throwable t + (list nil symbol-string)))) diff --git a/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c/internal.clj b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c/internal.clj new file mode 100644 index 0000000..89701dd --- /dev/null +++ b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_c_p_c/internal.clj @@ -0,0 +1,59 @@ +(ns swank.commands.contrib.swank-c-p-c.internal + (:use (swank util core commands) + (swank.commands completion) + (swank.util string clojure))) + +(defn compound-prefix-match? + "Takes a `prefix' and a `target' string and returns whether `prefix' + is a compound-prefix of `target'. + + Viewing each of `prefix' and `target' as a series of substrings + split by `split', if each substring of `prefix' is a prefix of the + corresponding substring in `target' then we call `prefix' a + compound-prefix of `target'." + ([split #^String prefix #^String target] + (let [prefixes (split prefix) + targets (split target)] + (when (<= (count prefixes) (count targets)) + (every? true? (map #(.startsWith #^String %1 %2) targets prefixes)))))) + +(defn unacronym + "Interposes delimiter between each character of string." + ([delimiter #^String string] + (apply str (interpose delimiter string))) + {:tag String}) + +(defn delimited-compound-prefix-match? + "Uses a delimiter as the `split' for a compound prefix match check. + See also: `compound-prefix-match?'" + ([delimiter prefix target] + (compound-prefix-match? #(.split #^String % (str "[" (java.util.regex.Pattern/quote delimiter) "]") -1) + prefix + target))) + + +(defn delimited-compound-prefix-match-acronym? + ([delimiter prefix target] + (or (delimited-compound-prefix-match? delimiter prefix target) + (delimited-compound-prefix-match? delimiter (unacronym (first delimiter) prefix) target)))) + +(defn camel-compound-prefix-match? + "Uses camel case as a delimiter for a compound prefix match check. + + See also: `compound-prefix-match?'" + ([#^String prefix #^String target] + (compound-prefix-match? #(re-seq #"(?:^.|[A-Z])[^A-Z]*" %) + prefix + target))) + +(defn split-compound-prefix-match? [#^String symbol-string #^String potential] + (if (.startsWith symbol-string ".") + (and (.startsWith potential ".") + (camel-compound-prefix-match? symbol-string potential)) + (let [[sym-ns sym-name] (symbol-name-parts symbol-string) + [pot-ns pot-name] (symbol-name-parts potential)] + (and (or (= sym-ns pot-ns) + (and sym-ns pot-ns + (delimited-compound-prefix-match-acronym? "." sym-ns pot-ns))) + (or (delimited-compound-prefix-match-acronym? "-." sym-name pot-name) + (camel-compound-prefix-match? sym-name pot-name)))))) diff --git a/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_fuzzy.clj b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_fuzzy.clj new file mode 100644 index 0000000..5aebb55 --- /dev/null +++ b/vim/bundle/slimv/swank-clojure/swank/commands/contrib/swank_fuzzy.clj @@ -0,0 +1,428 @@ +;;; swank_fuzzy.clj --- fuzzy symbol completion, Clojure implementation. + +;; Original CL implementation authors (from swank-fuzzy.lisp) below, +;; Authors: Brian Downing <bdowning@lavos.net> +;; Tobias C. Rittweiler <tcr@freebits.de> +;; and others + +;; This progam is based on the swank-fuzzy.lisp. +;; Thanks the CL implementation authors for that useful software. + +(ns swank.commands.contrib.swank-fuzzy + (:use (swank util core commands)) + (:use (swank.util clojure))) + +(def #^{:dynamic true} *fuzzy-recursion-soft-limit* 30) +(defn- compute-most-completions [short full] + (let [collect-chunk (fn [[pcur [[pa va] ys]] [pb vb]] + (let [xs (if (= (dec pb) pcur) + [[pa (str va vb)]] + [[pb vb] [pa va]])] + [pb (if ys (conj xs ys) xs)])) + step (fn step [short full pos chunk seed limit?] + (cond + (and (empty? full) (not (empty? short))) + nil + (or (empty? short) limit?) + (if chunk + (conj seed + (second (reduce collect-chunk + [(ffirst chunk) [(first chunk)]] + (rest chunk)))) + seed) + (= (first short) (first full)) + (let [seed2 + (step short (rest full) (inc pos) chunk seed + (< *fuzzy-recursion-soft-limit* (count seed)))] + (recur (rest short) (rest full) (inc pos) + (conj chunk [pos (str (first short))]) + (if (and seed2 (not (empty? seed2))) + seed2 + seed) + false)) + :else + (recur short (rest full) (inc pos) chunk seed false)))] + (map reverse (step short full 0 [] () false)))) + +(def fuzzy-completion-symbol-prefixes "*+-%&?<") +(def fuzzy-completion-word-separators "-/.") +(def fuzzy-completion-symbol-suffixes "*+->?!") +(defn- score-completion [completion short full] + (let [find1 + (fn [c s] + (re-find (re-pattern (java.util.regex.Pattern/quote (str c))) s)) + at-beginning? zero? + after-prefix? + (fn [pos] + (and (= pos 1) + (find1 (nth full 0) fuzzy-completion-symbol-prefixes))) + word-separator? + (fn [pos] + (find1 (nth full pos) fuzzy-completion-word-separators)) + after-word-separator? + (fn [pos] + (find1 (nth full (dec pos)) fuzzy-completion-word-separators)) + at-end? + (fn [pos] + (= pos (dec (count full)))) + before-suffix? + (fn [pos] + (and (= pos (- (count full) 2)) + (find1 (nth full (dec (count full))) + fuzzy-completion-symbol-suffixes)))] + (letfn [(score-or-percentage-of-previous + [base-score pos chunk-pos] + (if (zero? chunk-pos) + base-score + (max base-score + (+ (* (score-char (dec pos) (dec chunk-pos)) 0.85) + (Math/pow 1.2 chunk-pos))))) + (score-char + [pos chunk-pos] + (score-or-percentage-of-previous + (cond (at-beginning? pos) 10 + (after-prefix? pos) 10 + (word-separator? pos) 1 + (after-word-separator? pos) 8 + (at-end? pos) 6 + (before-suffix? pos) 6 + :else 1) + pos chunk-pos)) + (score-chunk + [chunk] + (let [chunk-len (count (second chunk))] + (apply + + (map score-char + (take chunk-len (iterate inc (first chunk))) + (reverse (take chunk-len + (iterate dec (dec chunk-len))))))))] + (let [chunk-scores (map score-chunk completion) + length-score (/ 10.0 (inc (- (count full) (count short))))] + [(+ (apply + chunk-scores) length-score) + (list (map list chunk-scores completion) length-score)])))) + +(defn- compute-highest-scoring-completion [short full] + (let [scored-results + (map (fn [result] + [(first (score-completion result short full)) + result]) + (compute-most-completions short full)) + winner (first (sort (fn [[av _] [bv _]] (> av bv)) + scored-results))] + [(second winner) (first winner)])) + +(defn- call-with-timeout [time-limit-in-msec proc] + "Create a thunk that returns true if given time-limit-in-msec has been + elapsed and calls proc with the thunk as an argument. Returns a 3 elements + vec: A proc result, given time-limit-in-msec has been elapsed or not, + elapsed time in millisecond." + (let [timed-out (atom false) + start! (fn [] + (future (do + (Thread/sleep time-limit-in-msec) + (swap! timed-out (constantly true))))) + timed-out? (fn [] @timed-out) + started-at (System/nanoTime)] + (start!) + [(proc timed-out?) + @timed-out + (/ (double (- (System/nanoTime) started-at)) 1000000.0)])) + +(defmacro with-timeout + "Create a thunk that returns true if given time-limit-in-msec has been + elapsed and bind it to timed-out?. Then execute body." + #^{:private true} + [[timed-out? time-limit-in-msec] & body] + `(call-with-timeout ~time-limit-in-msec (fn [~timed-out?] ~@body))) + +(defstruct fuzzy-matching + :var :ns :symbol :ns-name :score :ns-chunks :var-chunks) + +(defn- fuzzy-extract-matching-info [matching string] + (let [[user-ns-name _] (symbol-name-parts string)] + (cond + (:var matching) + [(str (:symbol matching)) + (cond (nil? user-ns-name) nil + :else (:ns-name matching))] + :else + ["" + (str (:symbol matching))]))) + +(defn- fuzzy-find-matching-vars + [string ns var-filter external-only?] + (let [compute (partial compute-highest-scoring-completion string) + ns-maps (cond + external-only? ns-publics + (= ns *ns*) ns-map + :else ns-interns)] + (map (fn [[match-result score var sym]] + (if (var? var) + (struct fuzzy-matching + var nil (or (:name (meta var)) + (symbol (pr-str var))) + nil + score nil match-result) + (struct fuzzy-matching + nil nil sym + nil + score nil match-result))) + (filter (fn [[match-result & _]] + (or (= string "") + (not-empty match-result))) + (map (fn [[k v]] + (if (= string "") + (conj [nil 0.0] v k) + (conj (compute (.toLowerCase (str k))) v k))) + (filter var-filter (seq (ns-maps ns)))))))) +(defn- fuzzy-find-matching-nss + [string] + (let [compute (partial compute-highest-scoring-completion string)] + (map (fn [[match-result score ns ns-sym]] + (struct fuzzy-matching nil ns ns-sym (str ns-sym) + score match-result nil)) + (filter (fn [[match-result & _]] (not-empty match-result)) + (map (fn [[ns-sym ns]] + (conj (compute (str ns-sym)) ns ns-sym)) + (concat + (map (fn [ns] [(symbol (str ns)) ns]) (all-ns)) + (ns-aliases *ns*))))))) + +(defn- fuzzy-generate-matchings + [string default-ns timed-out?] + (let [take* (partial take-while (fn [_] (not (timed-out?)))) + [parsed-ns-name parsed-symbol-name] (symbol-name-parts string) + find-vars + (fn find-vars + ([designator ns] + (find-vars designator ns identity)) + ([designator ns var-filter] + (find-vars designator ns var-filter nil)) + ([designator ns var-filter external-only?] + (take* (fuzzy-find-matching-vars designator + ns + var-filter + external-only?)))) + find-nss (comp take* fuzzy-find-matching-nss) + make-duplicate-var-filter + (fn [fuzzy-ns-matchings] + (let [nss (set (map :ns-name fuzzy-ns-matchings))] + (comp not nss str :ns meta second))) + matching-greater + (fn [a b] + (cond + (> (:score a) (:score b)) -1 + (< (:score a) (:score b)) 1 + :else (compare (:symbol a) (:symbol b)))) + fix-up + (fn [matchings parent-package-matching] + (map (fn [m] + (assoc m + :ns-name (:ns-name parent-package-matching) + :ns-chunks (:ns-chunks parent-package-matching) + :score (if (= parsed-ns-name "") + (/ (:score parent-package-matching) 100) + (+ (:score parent-package-matching) + (:score m))))) + matchings))] + (sort matching-greater + (cond + (nil? parsed-ns-name) + (concat + (find-vars parsed-symbol-name (maybe-ns default-ns)) + (find-nss parsed-symbol-name)) + ;; (apply concat + ;; (let [ns *ns*] + ;; (pcalls #(binding [*ns* ns] + ;; (find-vars parsed-symbol-name + ;; (maybe-ns default-ns))) + ;; #(binding [*ns* ns] + ;; (find-nss parsed-symbol-name))))) + (= "" parsed-ns-name) + (find-vars parsed-symbol-name (maybe-ns default-ns)) + :else + (let [found-nss (find-nss parsed-ns-name) + find-vars1 (fn [ns-matching] + (fix-up + (find-vars parsed-symbol-name + (:ns ns-matching) + (make-duplicate-var-filter + (filter (partial = ns-matching) + found-nss)) + true) + ns-matching))] + (concat + (apply concat + (map find-vars1 (sort matching-greater found-nss))) + found-nss)))))) + +(defn- fuzzy-format-matching [string matching] + (let [[symbol package] (fuzzy-extract-matching-info matching string) + result (str package (when package "/") symbol)] + [result (.indexOf #^String result #^String symbol)])) + +(defn- classify-matching [m] + (let [make-var-meta (fn [m] + (fn [key] + (when-let [var (:var m)] + (when-let [var-meta (meta var)] + (get var-meta key))))) + vm (make-var-meta m)] + (set + (filter + identity + [(when-not (or (vm :macro) (vm :arglists)) + :boundp) + (when (vm :arglists) :fboundp) + ;; (:typespec) + ;; (:class) + (when (vm :macro) :macro) + (when (special-symbol? (:symbol m)) :special-operator) + (when (:ns-name m) :package) + (when (= clojure.lang.MultiFn (vm :tag)) + :generic-function)])))) +(defn- classification->string [flags] + (format (apply str (replicate 8 "%s")) + (if (or (:boundp flags) + (:constant flags)) "b" "-") + (if (:fboundp flags) "f" "-") + (if (:generic-function flags) "g" "-") + (if (:class flags) "c" "-") + (if (:typespec flags) "t" "-") + (if (:macro flags) "m" "-") + (if (:special-operator flags) "s" "-") + (if (:package flags) "p" "-"))) + +(defn- fuzzy-convert-matching-for-emacs [string matching] + (let [[name added-length] (fuzzy-format-matching string matching)] + [name + (format "%.2f" (:score matching)) + (concat (:ns-chunks matching) + (map (fn [[offset string]] [(+ added-length offset) string]) + (:var-chunks matching))) + (classification->string (classify-matching matching)) + ])) + +(defn- fuzzy-completion-set + [string default-ns limit time-limit-in-msec] + (let [[matchings interrupted? _] + (with-timeout [timed-out? time-limit-in-msec] + (vec (fuzzy-generate-matchings string default-ns timed-out?))) + subvec1 (if (and limit + (> limit 0) + (< limit (count matchings))) + (fn [v] (subvec v 0 limit)) + identity)] + [(subvec1 (vec (map (partial fuzzy-convert-matching-for-emacs string) + matchings))) + interrupted?])) + +(defslimefn fuzzy-completions + [string default-package-name + _limit limit _time-limit-in-msec time-limit-in-msec] + (let [[xs x] (fuzzy-completion-set string default-package-name + limit time-limit-in-msec)] + (list + (map (fn [[symbol score chunks class]] + (list symbol score (map (partial apply list) chunks) class)) + xs) + (when x 't)))) + +(defslimefn fuzzy-completion-selected [_ _] nil) + +(comment + (do + (use '[clojure.test]) + + (is (= '(([0 "m"] [9 "v"] [15 "b"])) + (compute-most-completions "mvb" "multiple-value-bind"))) + (is (= '(([0 "zz"]) ([0 "z"] [2 "z"]) ([1 "zz"])) + (compute-most-completions "zz" "zzz"))) + (is (= 103 + (binding [*fuzzy-recursion-soft-limit* 2] + (count + (compute-most-completions "ZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZ"))))) + + (are [x p s] (= x (score-completion [[p s]] s "*multiple-value+")) + '[10.625 (((10 [0 "*"])) 0.625)] 0 "*" ;; at-beginning + '[10.625 (((10 [1 "m"])) 0.625)] 1 "m" ;; after-prefix + '[1.625 (((1 [9 "-"])) 0.625)] 9 "-" ;; word-sep + '[8.625 (((8 [10 "v"])) 0.625)] 10 "v" ;; after-word-sep + '[6.625 (((6 [15 "+"])) 0.625)] 15 "+" ;; at-end + '[6.625 (((6 [14 "e"])) 0.625)] 14 "e" ;; before-suffix + '[1.625 (((1 [2 "u"])) 0.625)] 2 "u" ;; other + ) + (is (= (+ 10 ;; m's score + (+ (* 10 0.85) (Math/pow 1.2 1))) ;; u's score + (let [[_ x] + (score-completion [[1 "mu"]] "mu" "*multiple-value+")] + ((comp first ffirst) x))) + "`m''s score + `u''s score (percentage of previous which is 'm''s)") + + (is (= '[([0 "zz"]) 24.7] + (compute-highest-scoring-completion "zz" "zzz"))) + + (are [to? ret to proc] (= [ret to?] + (let [[x y _] (call-with-timeout to proc)] + [x y])) + false "r" 10 (fn [_] "r") + true nil 1 (fn [_] (Thread/sleep 10) nil)) + + (are [symbol package input] (= [symbol package] + (fuzzy-extract-matching-info + (struct fuzzy-matching + true nil + "symbol" "ns-name" + nil nil nil) + input)) + "symbol" "ns-name" "p/*" + "symbol" nil "*") + (is (= ["" "ns-name"] + (fuzzy-extract-matching-info + (struct fuzzy-matching + nil nil + "ns-name" "" + nil nil nil) + ""))) + + (defmacro try! #^{:private true} + [& body] + `(do + ~@(map (fn [x] `(try ~x (catch Throwable ~'_ nil))) + body))) + + (try + (def testing-testing0 't) + (def #^{:private true} testing-testing1 't) + (are [x external-only?] (= x + (vec + (sort + (map (comp str :symbol) + (fuzzy-find-matching-vars + "testing" *ns* + (fn [[k v]] + (and (= ((comp :ns meta) v) *ns*) + (re-find #"^testing-" + (str k)))) + external-only?))))) + ["testing-testing0" "testing-testing1"] nil + ["testing-testing0"] true) + (finally + (try! + (ns-unmap *ns* 'testing-testing0) + (ns-unmap *ns* 'testing-testing1)))) + + (try + (create-ns 'testing-testing0) + (create-ns 'testing-testing1) + (is (= '["testing-testing0" "testing-testing1"] + (vec + (sort + (map (comp str :symbol) + (fuzzy-find-matching-nss "testing-")))))) + (finally + (try! + (remove-ns 'testing-testing0) + (remove-ns 'testing-testing1)))) + ) + ) |