Giter VIP home page Giter VIP logo

compliment's Introduction

Compliment

Compliment is a fast and smart completion library for Clojure. It can complete vars, namespaces, classes, class members, keywords, locals. Users and library authors can also extend Compliment with custom completion sources.

Compliment is used as a completion backend in the following editors/IDEs:

Most importantly, I am very glad you came here. You look gorgeous today.

Rationale

I wrote Compliment specifically for you because you are amazing and I believe you deserve a matching completion lib. Here are the features it boasts:

  • Speed. Your time is too precious to wait for completion to happen. Compliment is designed to be fast and is carefully benchmarked to make sure no sudden performance drops appear.
  • Smart completion. Such a smart person like you is entitled to completion being smart as well. Default Compliment sources use various techniques to give more meaningful completion depending on the context, and allow some fuzziness in prefix.
  • Extensibility. Your insatiable passion for exploration won't be satisfied by a set in stone completion list. For this reason Compliment allows every library developer to write custom sources, so later other users of the library will have better experience utilizing it.

Installation

In most Clojure IDEs that use Compliment, you don't have to install anything at all — it will already be there for you. In case you are a CIDER user you'll also need to install company-mode and company-quickhelp for optimal results. This guide will help you configure it.

To embed Compliment directly into your program add this to the :dependencies:

If you don't want to pull a dependency, check Compliment-lite.

For users

Here are the examples of different completion scenarios Compliment supports.

You can advise Compliment to provide special treatment for certain Vars by attaching metadata to them. See the Metadata page for details.

For developers

Compliment's primary public function is completions:

=> (require 'compliment.core)
=> (compliment.core/completions "compl")
({:candidate "complement", :type :function, :ns "clojure.core"}
 {:candidate "completing", :type :function, :ns "clojure.core"}
 {:candidate "compliment.core", :type :namespace, :file "compliment/core.clj"}
 {:candidate "compliment.utils", :type :namespace, :file "compliment/utils.clj"}
 ...)

completions can accept a map of options as a second argument. The supported options are:

  • :ns — complete within the provided namespace
  • :context — enable richer completions, see Context.
  • :sort-order — how to sort resulting candidates, either :by-length (default) or :by-name.
  • :extra-metadata — a list of keywords for extra metadata to attach to each candidate. Only used for completing vars. The values can be :doc, :arglists, :deprecated, :private.
  • :sources — a list of sources names that should be used when generating candidates. The name of the source is a keyword passed to defsource in each source namespace. If not provided, all sources will be used.

The second public function is documentation. It can be used for generating tooltip messages when the completion candidate is highlighted in the UI:

=> (println (compliment.core/documentation ".substring"))

java.lang.StringBuilder.substring
  (int int) -> String (public volatile)
  (int) -> String (public volatile)

java.lang.StringBuffer.substring
  (int int) -> String (public synchronized)
  (int) -> String (public synchronized)

java.lang.String.substring
  (int int) -> String (public)
  (int) -> String (public)

See tests for more examples and details.

Writing your own sources is explained in Custom sources.

License

Copyright © 2013-2024 Oleksandr Yakushev. Distributed under the Eclipse Public License. See LICENSE.

compliment's People

Contributors

aamedina avatar abo-abo avatar alexander-yakushev avatar arichiardi avatar bbatsov avatar brunobonacci avatar danielcompton avatar deraen avatar eval avatar jj-atkinson avatar junegunn avatar olical avatar peterwang avatar pfeodrippe avatar plexus avatar raxod502 avatar seancorfield avatar skrat avatar vemv avatar vmfhrmfoaj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

compliment's Issues

->/->> not handled

The problem

The two following pieces of code should get the same completions, but they don't:

(defn x [^String arg]
  (__prefix__ arg)) ;; for a prefix value of ".", String completions will be offered

(defn x [^String arg]
  (-> arg __prefix__)) ;; for a prefix value of ".", Object completions will be offered

Possible solution

Perform certain macroexpansions as an early step in compliment.context/parse-context.

The following POC worked fine for me:

(ns compliment.sources.poc
  (:require
   [compliment.sources.class-members :as src]
   [compliment.context :as ctx]
   [compliment.t-helpers :refer :all]
   [clojure.walk :as walk]))

(defn macroexpanded-context [form]
  (->> form
       (walk/postwalk (fn [x]
                        (if (and (list? x)
                                 (-> x first #{'-> '->>}))
                          (macroexpand-1 x)
                          x)))
       ctx/parse-context))

(strip-tags (src/members-candidates "." *ns* (macroexpanded-context '(defn x [^String arg]
                                                                       (-> arg __prefix__)))))

WDYT?

Cheers - Victor

Completion for local variables

As discussed here.

Suggestion is that the following forms be handled by compliment and the rest by auto-complete/company by drawing on words in the same buffer:

  • defn
  • defn-
  • let
  • if-let
  • when-let

Include boolean literals "true" and "false" in completion results

Hi,
I've been using compliment via company-mode in cider, and I keep running into an issue where typing a boolean literal autocompletes to the associated predicate function (true? instead of true / false? instead of false). If you add the strings "true" and "false" to the special-forms set in compliment.sources.special-forms, then this problem goes away.

Thanks for the great package!
Sanjay

Process specially import

It'd be nice if you got completion candidates when you did something like (import java.net. TAB - all the classes in the package, even the unimported ones.

Leverage type hints?

Hi!

For the following example:

(defn thing [^String s]
  (. s|))

| being the cursor, ideally compliment would infer that s is a String, offering accurate completions accordingly.

(bonus points: also accurately complete at (-> s .|))

My thinking is that type hinting could be a more extended practice if it resulted in accurate completions. Which would yield faster code and a more pleasant dev UX, so why not? :)

I assume the feature isn't there because I that's not the behavior I can observe (or find in https://github.com/alexander-yakushev/compliment/wiki/Examples).

Is this something you have attempted in the past? Or willing to give a shot someday?

I could try it myself. Would appreciate any info that might aid an implementation.

Cheers - Victor

Clojurescript support

Hi, I extended compliment to support clojurescript completion as part of replique. Is that something you would be interested in ?

Class candidates are always tagged with an :ns of *ns*

e.g.

user> (compliment.core/completions "Thre" {:tag-candidates true})

returns

({:ns "user", :type :class, :candidate "Thread"}
 {:ns "user", :type :class, :candidate "ThreadDeath"}
 {:ns "user", :type :class, :candidate "ThreadGroup"}
 {:ns "user", :type :class, :candidate "ThreadLocal"}
 {:ns "user", :type :class, :candidate "Thread$State"}
 {:ns "user", :type :class, :candidate "Thread$UncaughtExceptionHandler"})

core.typed integration?

Is there any interest in using core.typed to drive completion? Particularly interesting would be to complete java interop forms:

(.. "Hello World" toLow<tab>)
 ==> (.. "Hello World" toLowerCase)

The cf macro or something similar in core.typed could do a lot of the work here. It would seem you could go a long way with that and a bit of reflection. Of course, this would be jvm clojure only.

Documentation improvements

It'd be nice if the documentation function returned the complete javadoc for a class/member. That way we'll be able to create a documentation middleware that we'll behave similarly for Clojure vars and Java classes/members. It would also be good if we could reduce the ambiguity and return just a single documentation entry (that way the short documentation could used to implement eldoc-like functionality for Java stuff). That would require us to know the type of the receiver, but we'll know that most of the time (at least for already evaluated code).

Special forms have no :ns tag

user> (->> (compliment.core/completions "" {:tag-candidates true})
           (filter #(= (:type %) :special-form)))
({:type :special-form, :candidate "do"}
 {:type :special-form, :candidate "if"}
 {:type :special-form, :candidate "def"}
 {:type :special-form, :candidate "new"}
 {:type :special-form, :candidate "try"}
 {:type :special-form, :candidate "var"}
 {:type :special-form, :candidate "set!"}
 {:type :special-form, :candidate "catch"}
 {:type :special-form, :candidate "quote"}
 {:type :special-form, :candidate "recur"}
 {:type :special-form, :candidate "throw"}
 {:type :special-form, :candidate "monitor-exit"}
 {:type :special-form, :candidate "monitor-enter"})
user> 

Should these have an :ns of clojure.core? Technically, you can't invoke any of them with a namespace prefix (i.e. (clojure.core/try 1) does not work), but I think they're generally considered to belong to that namespace.

Just pointing it out, in case you consider it an omission. I have no opinion either way :-).

Completing "/" results in NPE

Trying to complete "/" with (co/completions "/" nil) generates a NPE:

java.lang.NullPointerException
    at clojure.lang.Symbol.intern(Symbol.java:60)
    at clojure.core$symbol.invoke(core.clj:546)
    at compliment.sources.class_members$static_members_candidates.invoke(class_members.clj:213)
    at clojure.lang.Var.invoke(Var.java:388)
    at compliment.core$completions$iter__3762__3766$fn__3767.invoke(core.clj:51)
...

in the class-members source. I don't think there's anything sensible to offer as a completion for "/", so it might be best just to guard against it in the class-members source.

Similarly, "/a" generates an exception, this time a StringIndexOutOfBoundsException.

I'm happy to send a PR if you think checking explicitly for strings starting with "/" is the right way to go.

Methods are tagged with a :type of :field when :ns is passed

e.g.

user> (compliment.core/completions ".getDe" {:tag-candidates true})

returns

({:type :method, :candidate ".getDeclaredField"}
 {:type :method, :candidate ".getDeclaredFields"}
 {:type :method, :candidate ".getDeclaredMethod"}
 {:type :method, :candidate ".getDeclaringClass"}
 {:type :method, :candidate ".getDeclaredClasses"}
 {:type :method, :candidate ".getDeclaredMethods"}
 {:type :method, :candidate ".getDeclaredAnnotation"}
 {:type :method, :candidate ".getDeclaredAnnotations"}
 {:type :method, :candidate ".getDeclaredConstructor"}
 {:type :method, :candidate ".getDeclaredConstructors"}
 {:type :method, :candidate ".getDeclaredAnnotationsByType"})

but

user> (compliment.core/completions ".getDe" {:ns 'user :tag-candidates true})

returns

({:type :field, :candidate ".getDeclaredField"}
 {:type :field, :candidate ".getDeclaredFields"}
 {:type :field, :candidate ".getDeclaredMethod"}
 {:type :field, :candidate ".getDeclaringClass"}
 {:type :field, :candidate ".getDeclaredClasses"}
 {:type :field, :candidate ".getDeclaredMethods"}
 {:type :field, :candidate ".getDeclaredAnnotation"}
 {:type :field, :candidate ".getDeclaredAnnotations"}
 {:type :field, :candidate ".getDeclaredConstructor"}
 {:type :field, :candidate ".getDeclaredConstructors"}
 {:type :field, :candidate ".getDeclaredAnnotationsByType"})

NPE while getting candidates

java.lang.NullPointerException: null
 at java.util.concurrent.ConcurrentHashMap.get (ConcurrentHashMap.java:936)
    clojure.lang.Namespace.find (Namespace.java:188)
    clojure.core$find_ns.invoke (core.clj:3976)
    clojure.core$the_ns.invoke (core.clj:4008)
    clojure.core$ns_map.invoke (core.clj:4022)
    cider.inlined_deps.compliment.v0v2v7.compliment.sources.ns_mappings$candidates.invoke (ns_mappings.clj:53)
    clojure.lang.Var.invoke (Var.java:388)
    cider.inlined_deps.compliment.v0v2v7.compliment.core$eval52698$completions__52701$iter__52703__52707$fn__52708.invoke (core.clj:95)
    clojure.lang.LazySeq.sval (LazySeq.java:40)
    clojure.lang.LazySeq.seq (LazySeq.java:49)
    clojure.lang.RT.seq (RT.java:507)
    clojure.core/seq (core.clj:137)
    clojure.core$tree_seq$walk__5045$fn__5046.invoke (core.clj:4739)
    clojure.lang.LazySeq.sval (LazySeq.java:40)
    clojure.lang.LazySeq.seq (LazySeq.java:49)
    clojure.lang.LazySeq.more (LazySeq.java:85)
    clojure.lang.RT.more (RT.java:683)
    clojure.core/rest (core.clj:73)
    clojure.core$flatten.invoke (core.clj:6851)
    cider.inlined_deps.compliment.v0v2v7.compliment.core$eval52698$completions__52701.invoke (core.clj:91)
    cider.nrepl.middleware.complete$complete.invoke (complete.clj:19)
    cider.nrepl.middleware.complete$complete_reply.invoke (complete.clj:34)
    cider.nrepl.middleware.complete$wrap_complete$fn__53008.invoke (complete.clj:55)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.ns$wrap_ns$fn__51752.invoke (ns.clj:110)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.trace$wrap_trace$fn__59014.invoke (trace.clj:65)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.macroexpand$wrap_macroexpand$fn__58340.invoke (macroexpand.clj:220)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.apropos$wrap_apropos$fn__51782.invoke (apropos.clj:100)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    refactor_nrepl.middleware$wrap_refactor$fn__68899.invoke (middleware.clj:135)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.classpath$wrap_classpath$fn__51806.invoke (classpath.clj:30)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__40547.invoke (interruptible_eval.clj:247)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.inspect$wrap_inspect$fn__53217.invoke (inspect.clj:108)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.debug$wrap_debug$fn__54863.invoke (debug.clj:461)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.middleware.load_file$wrap_load_file$fn__40667.invoke (load_file.clj:79)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    user$eval72797$fn__72798$fn__72800.invoke (form-init6400695034319109191.clj:1)
    cider.nrepl.middleware.enlighten$wrap_enlighten$fn__54905.invoke (enlighten.clj:86)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.middleware.session$add_stdin$fn__40626.invoke (session.clj:238)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.pprint$wrap_pprint$fn__54554.invoke (pprint.clj:106)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.track_state$wrap_tracker$fn__59277.invoke (track_state.clj:200)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.middleware.pr_values$pr_values$fn__40465.invoke (pr_values.clj:22)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.test$wrap_test$fn__58741.invoke (test.clj:286)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.resource$wrap_resource$fn__58596.invoke (resource.clj:49)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.stacktrace$wrap_stacktrace$fn__54632.invoke (stacktrace.clj:175)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.pprint$wrap_pprint_fn$fn__54528.invoke (pprint.clj:53)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.info$wrap_info$fn__58225.invoke (info.clj:304)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.undef$wrap_undef$fn__59304.invoke (undef.clj:30)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    cider.nrepl.middleware.out$wrap_out$fn__58426.invoke (out.clj:96)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.middleware.session$session$fn__40611.invoke (session.clj:192)
    clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__40282.invoke (middleware.clj:22)
    clojure.tools.nrepl.server$handle_STAR_.invoke (server.clj:19)
    clojure.tools.nrepl.server$handle$fn__40682.invoke (server.clj:28)
    clojure.core$binding_conveyor_fn$fn__4444.invoke (core.clj:1916)
    clojure.lang.AFn.call (AFn.java:18)
    java.util.concurrent.FutureTask.run (FutureTask.java:266)
    java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142)
    java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617)
    java.lang.Thread.run (Thread.java:745)

clojure-emacs/cider-nrepl#313

completion of non static members does not work unless the class is imported to the name space

In this scenario, we get no candidates,

  • start new repl
(use 'compliment.sources.class-members)
(def blob (javax.sql.rowset.serial.SerialBlob. (byte-array 1)))
(map :candidate (members-candidates "." (find-ns 'user) (ctx/parse-context '(__prefix__ blob)) ))

()

so no candidates are found.
expected behavior: all and only members of class SerialBlob are returned
found behavior: no members are returned

It does work, when class is imported first:

(require '[compliment.context :as ctx])
 (use 'compliment.sources.class-members)
 (import javax.sql.rowset.serial.SerialBlob)
(def blob (SerialBlob. (byte-array 1)))
(map :candidate (members-candidates "." (find-ns 'user) (ctx/parse-context '(__prefix__ blob)) ))


(".getBinaryStream" ".setBytes" ".free" ".setBinaryStream" ".getBytes" ".position" ".length" ".truncate" ".clone" ".hashCode" ".equals")

documentation shouldn't err or ""

cider.nrepl.middleware.complete> (jvm-complete/documentation "")
StringIndexOutOfBoundsException String index out of range: 0  java.lang.String.charAt (String.java:646)

Ideally this should return "" (what happens with unknown symbols).

"Unmunge" deftype field names

When you have a Clojure type like

(deftype Foo [x-y] ...)

then (.x completes to (.x_y instead of (.x-y. That's because for a deftype a class is generated, and the field names of the class are the "munged" names of the deftype's fields, i.e., hypens are replaced with underscores.

In Clojure on the JVM, (.x_y foo) actually works but it relies on this very implementation detail and is not portable to the CLR or ClojureScript. Thus, it's better to use (.x-y foo) as this is the documented way to access fields of a deftype.

So it would be nice if CIDER could directly suggest the correct version when completing. The fact that can be exploited is that all classes (and only those) generated for a deftype implement clojure.lang.IType (see https://github.com/clojure/clojure/blob/master/src/clj/clojure/core_deftype.clj#L396). Therefore, I suggest to "unmunge" field names of classes implementing IType.

Add support for letfn

Functions bound using letfn are currently not provided as completion candidates, but it would be nice if they were :)

compliment is unable to find completions for a namespace that is aliased as `user`

Had a bug report in #cider on clojure slack.

If you have a namespace that you require with an alias as user there will be no completions found. The bug is from


(defn resolve-namespace
  "Tries to resolve a namespace from the given symbol, either from a
  fully qualified name or an alias in the given namespace."
  [sym ns]
  (or (find-ns sym) ((ns-aliases ns) sym)))

as the prefix 'user comes in and this resolves to the single segment namespace user.

Note this happens on the special single-segment ns user but could happen on anything that is single segment ns and has the same name as an alias.

The fix seems easy in that the aliases should be consulted first and then single segment namespaces after. This works because if the person has imported something as user, this is what they would prefer. And would seem to make referring to the single segment namespace impossible so the completions should mimic.

Extra-metadata is confusing for :refer completion

For many results in :refer completion the var is not yet required and metadata can be retrieved. This makes the results a bit confusing as some results might show arglists while others don't.

Perhaps when :refer completion is used no extra-metadata should be added to any candidates?

image

Variables with colons aren't always completed

I've written a failing test for you. This issue was raised on CIDER

But vars with semicolons colons in them can be completed when the text doesn't include them. for instance,

(fact "handles vars with semicolons in them"
    (def foo:bar 1)
    (def foo:baz 2)
    (src/candidates "foo" *ns* nil)
    => (contains #{"foo:bar" "foo:baz"} :gaps-ok) ;; passes

    (src/candidates "foo:" *ns* nil)
    => (contains #{"foo:bar" "foo:baz"} :gaps-ok) ;; fails

    (src/candidates "foo:b" *ns* nil)
    => (contains #{"foo:bar" "foo:baz"} :gaps-ok)) ;; fails

prevent throwing null pointer exception

Got an issue popping up in CIDER with compliment throwing a null pointer exception by just typing ::/ and the autocomplete functionality throwing:

clojure-emacs/cider#1972

I've created the following test that "tests" it to demonstrate the error programatically and I'm starting to look into the codebase but i'm not too familiar with it.

(fact "keyword reading does not throw an error"
        (do (src/candidates "::/" *ns* nil)
            => (strip-tags (just #{""}))))

Tests

I recently started using compliment in CIDER as a replacement for clojure-complete. While it works great I noticed there are neither tests nor integration documentation. Sure, the public API is two functions, but I think you'll make developer lives easier if they had a formal specification in the form of tests.

stackoverflow completing import

ERROR: Unhandled REPL handler exception processing message {:op complete, :session 5eefc359-1330-474e-bd86-9df453b135af, :ns refactor-nrepl.rename-file-or-dir, :symbol jav, :context :same, :id 503}

java.lang.StackOverflowError

    at clojure.lang.LazySeq.sval(LazySeq.java:42)

    at clojure.lang.LazySeq.seq(LazySeq.java:60)

    at clojure.lang.RT.seq(RT.java:484)

    at clojure.core$seq.invoke(core.clj:133)

    at clojure.core$concat$fn__3923.invoke(core.clj:678)

    at clojure.lang.LazySeq.sval(LazySeq.java:42)

    at clojure.lang.LazySeq.seq(LazySeq.java:60)

    at clojure.lang.RT.seq(RT.java:484)

    at clojure.core$seq.invoke(core.clj:133)

    at clojure.core$concat$fn__3923.invoke(core.clj:678)

Reminded me of this blog post

Hopefully this is enough to go on, the stacktrace is entirely without reference to any of your code :/

Non-required namespaces have a :type of :class returned

Hi, thanks for the work on :tag-candidates - it's looking great! Here's a small issue:

user> (compliment.core/completions "clojure.core.async.la" {:tag-candidates true})
({:type :class, :candidate "clojure.core.async.lab"})
user> (require 'clojure.core.async.lab)
nil
user> (compliment.core/completions "clojure.core.async.la" {:tag-candidates true})
({:type :namespace, :candidate "clojure.core.async.lab"})

Note that the candidate has a :type of :class until the namespace has been required - then :namespace is correctly returned.

Pass additional parameters to :candidates function

Hi @alexander-yakushev I hope my #62 PR is not super scary but I have a new requirement for the :candidates function that plugs in defsource: basically ClojureScript completions require the compiler map to be passed through all the functions, because that's where the information we need lives.

I was wondering how to manage that, because it could potentially be breaking.

What do you think? What should we do?

What is the context

completions accepts context as a param, but I cannot understand from the docstring what exactly this context is supposed to be. Maybe you can extend the documentation about this or even add a few tests showcasing its work.

Licensing

Hi,
I'm currently writing an emacs mode for clojure development. I would love to embed compliment in order to provide auto completion, though I can't because of GPL/EPL license incompatibility. Would you consider dual licensing with a GPL compatible license?

Combine completion candidates with metadata regarding them

Emacs has a feature that allows you to annotate a completion candidate with addition information - e.g. the type of the candidate (function, macro, interface, etc). You can see the feature in action for Emacs Lisp completions. For this to effectively used, however, it'd be beneficial if one could retrieve a completion candidate together with some metadata regarding it (perhaps the type and the ns/package of the candidate, maybe others make sense as well), so avoid having to do one of two things:

  • retrieve the metadata for each candidate individually (which is slow)
  • retrieve all candidates and then do a second function call to retrieve the metadata for all of them

Obviously this is not a must-have feature, but it'd be nice to have something like this in tools like CIDER. I'm also not quite sure if packages like compliment should handle this or their clients, but I wanted to start a discussion on the subject.

Complete unimported classes by simple name

Very often I'm rewriting something from Java or going through a tutorial, and I have to use a Java class I don't know full package name of. So I have either to Google it, or search somewhere else, then type in its full name into :import clause.

Solution: Context-check if we are inside :import and then allow completing full classnames by a simple name.

Candidates sorting

I noticed that by default candidates don't seem to be sorted alphatebically, which is a bit odd:

user> (compliment.core/completions "map" nil)
("mapv" "map" "mapcat" "map?" "map-indexed")
user> (complete.core/completions "map")
("map" "map-indexed" "map?" "mapcat" "mapv")

Any particular reason about this? The current ordering seems confusing to me.

Completion doesn't work for aliased ns of lenght 1

Hi,

while playing around with compliment (0.0.3) I discovered the following:

(require 'compliment.core)
(require '[clojure.string :as s])
(compliment.core/completions "s/cap" nil) => ()

;; fresh repl
(require '[clojure.string :as str])
(compliment.core/completions "str/cap" nil) => ("str/capitalize")

Not sure if this is an issue of compliment or that of the underlying data source.

Resource completion

It'd be nice if there was a source for resource completions. Those completions should be contextual - e.g. triggered only in functions known to accept resource paths.

We can also reuse this functionality to implement find resource functionality in CIDER.

Related ticket clojure-emacs/cider#1062

Special forms are missing from the candidates list

;; set! is missing
user> (compliment.core/completions "set" nil)
("set" "set?" "set-validator!" "set-error-mode!" "set-error-handler!" "set-agent-send-executor!" "set-agent-send-off-executor!")
;; var is missing
user> (compliment.core/completions "va" nil)
("val" "vals" "var?" "var-get" "var-set" "vary-meta")

Pretty sure all special forms are missing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.