unrepl 2018-03-29

unrepl lives now in vimpire's shading scheme. Nice. šŸ˜Ž

Unrepl is now shaded as: vv-8zmXciM-6qVYjA3apmzDNEzIgiRFW7EXcizIgAqgAAU.un repl.repl.

This also gets rid of the unshaded unrepl.core since I can make it available to the other shading units in its unshaded form.

However we went from

=> (let [a] 2)
IllegalArgumentException let requires an even number of forms in binding vector in hwlc5.core:1  clojure.core/let (core.clj:4333)

to

=> (let [a] 2)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
In: [0] val: () fails spec: :clojure.core.specs.alpha/bindings at: [:args :bindings :init-expr] predicate: any?,  Insufficient input
 #:clojure.spec.alpha{:problems [{:path [:args :bindings :init-expr], :reason ā€œInsufficient inputā€, :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x64ba3208 ā€œclojure.spec.alpha$regex_spec_impl$reify__2436@64ba3208"], :value ([a] 2), :args ([a] 2)}, compiling:(NO_SOURCE_PATH:1:1)

With expound:

=> (let [a] 2)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
-- Syntax error -------------------

  ([a] ...)
   ^^^

should have additional elements. The next element ā€œ:argsā€ should satisfy

  any?

-- Relevant specs -------

:clojure.core.specs.alpha/bindings:
  (clojure.spec.alpha/and
   clojure.core/vector?
   (clojure.spec.alpha/* :clojure.core.specs.alpha/binding))

-------------------------
Detected 1 error
 #:clojure.spec.alpha{:problems [{:path [:args :bindings :init-expr], :reason ā€œInsufficient inputā€, :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x5aa360ea ā€œclojure.spec.alpha$regex_spec_impl$reify__2436@5aa360eaā€], :value ([a] 2), :args ([a] 2)}, compiling:(NO_SOURCE_PATH:3:1)

Much better for sure

I wonder if it should say "The vector should have additional elements." — That's what I would say in conversation

And the formatting around

The next element ":args" should satisfy

  any?
is weird

I'll bring this up to Ben, he's my coworker

I’m not even sure to what it refers

really? that’s awesome!

Yup šŸ™‚ Happy coincidence

@bbrinck has joined the channel

So given the state of 1.9 exceptions, I believe shipping expound with unrepl is a necessity

I wouldn't say it's necessary but it would be awesome

s/necessity/would be a strong differentiator/

is looking up if differentiator is an actual word

Hello šŸ‘‹ !

Feedback on expound messages is always welcome. I may also be able to provide a little context on why things are the way they are šŸ™‚

the "next element" in (let [a 1]) would be the 1 right?

that’s correct, but I agree that’s not easy to see

Generally speaking, the errors around arg lists are the worst part of expound, but something I’m very interested in improving

(well, around any regex spec, but the most common case is around arglists)

:args is the name of the spec?

Yes, that’s correct … when you call fdef for a function or macro, you can provide 3 parts: :args, :ret and :fn. Later, you do something like (:args (s/get-spec `let))`

hm, my backtick escaping is failing in slack

trying this: ā€œ(s/form (:args (s/get-spec `let)))ā€

eh, you get the idea

the whole spec for :args is (clojure.spec.alpha/cat :bindings :clojure.core.specs.alpha/bindings :body (clojure.spec.alpha/* clojure.core/any?))

user=> (s/get-spec 'clojure.core/let)
#object[clojure.spec.alpha$fspec_impl$reify__2451 0x732f29af "clojure.spec.alpha$fspec_impl$reify__2451@732f29af"]

I'm a spec-newb šŸ˜ž

so I was tempted to interpret

The next element ":args" should satisfy

  any?
as ā€œthe next element of :args out of :bindings

Using the -m friendly option from the expound README. Fun!

@cgrand Agreed, this looks like a bug in expound.

And yeah s/form shows the right spec

I suspect I failed to account for some extra data spec puts in the explain-data in this case

I’ve created an issue, thanks for pointing this out!

In general, the problem with the core macros is that there is a lot of branching

but it’s something I’m working on

thanks to you! I’m looking at the code, problems is the ns where most magic happens?

if by ā€œmagicā€, you mean ā€œchaosā€, then yes šŸ™‚

generally speaking the complexity of expound comes from a design constraint

the message after the announcement of spec was that anyone could print the explain-data however they wanted, so I really wanted to follow that to the logical conclusion

(as opposed to say, pinpointer, which analyzes the actual spec forms itself. really cool idea! but I wanted to flush out bugs w/ spec that would prevent others from building things like expound)

however, the trick with using explain-data is that the :in path is often ambiguous and, in any case, you can’t use the path to trivially find the bad value

i.e. you can’t just use the path in get-in or update-in. As a result, there’s a ton of code to a) disambiguate paths and b) highlight bad values.

this code is kind of a mess but I haven’t yet had time to rework it šŸ˜ž

anyway, a few things to point out: 1. If you don’t like the fact that expound adds ... for irrelevant values, that can be controlled 2. you can also omit the ā€œrelevant specsā€ section 3. I’ve got a branch right now that includes colorization

for the record, here is with pinpoint

=> (let [a] 2)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
Detected 1 spec error:
----------------------------------------------------------------------
(1/1)

    Cause: ([a ...] 2)
               ^^^
 Expected: any?
 Failure
   Reason: Insufficient input

----------------------------------------------------------------------
 #:clojure.spec.alpha{:problems [{:path [:args :bindings :init-expr], :reason ā€œInsufficient inputā€, :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x1d6d1d42 ā€œclojure.spec.alpha$regex_spec_impl$reify__2436@1d6d1d42"], :value ([a] 2), :args ([a] 2)}, compiling:(NO_SOURCE_PATH:3:1)

@bbrink well I would be interested in a more data-ish/less formated output

like the colors

the ... is a nice touch

@cgrand Do you mean you’d like to get something like explain-data so that unrepl can format it accordingly?

yeah somewhere between you annotated explain-data and your printer

[warning: thinking out loud]

the idea for unrepl integration would be to not bing *explain-out* but in the exception handler of the repl to sniff spec exceptions and pimp them

Also thinking out loud here …

it’s possible that expound could provide an option to just print a more parseable thing with the data, although IIRC, the result of the normal explain-data is not readable in some cases due to the actual specs included

(this may change with new version of spec that is supposed more data focused, but i don’t know what that will look like)

you could potentially bind *explain-out* and just capture the explain-data that is passed in, then pass it to expound to annotate it with more data

(that inner API is not stable right now, but eventually it could be)

also, in general, i’ll be curious to see how unrepl catches exceptions and improves them. there’s quite a lot of interest in trying to do that generally for any project, so I

I’m keeping my eye on efforts on this front - related to stuff in maria.cloud, pyro, a discussion in #clojure yesterday about heuristics for better errors, https://github.com/always-be-clojuring/issues/issues/7 … lots of interesting discussions around this

but AFAICT, spec doesn’t let a printer like expound really control the actual exception data, so I can’t attach more data to the exception.

(at least, that’s my memory of the situation, I haven’t actually tried it)

so unrepl installs its own read eval print loop and there are two places where exceptions can be intercepted

* when the exception is caught by the loop * when any exception is printed (including as part of a result value)

so it would be quite possible to detect when ex-data contains ::s/problems and enrich the map before printing

I see, that’s cool

I’m biased of course, but I’d be happy to see expound used in some way within unrepl. Bug reports are always welcome and I’m open to expanding the API to make unrepl integration easier. Let me know how I can help!

what I like about expound is that it has no deps (unlike pinpointer)

Why is that a preference?

I know sideloader, shading etc.

Are you implying they don't work transitively? I don't understand sorry.

No I just imply that it’s a matter of taste and that I tend to consider any dep as a liability

@volrath @pesterhazy @kotarak you all use your own actions (or even no actions at all) for completion, right?

yeah unravel doesn't use an action currently

I use my own

IIRC the proposed general contract for a standardize completion actions was: • in: code (string) • in: offset (int) • in: ns-name (sym) • out: coll of candidates (strings)

do you use any extra information (in or out)?

I may imagine more output: • candidate (string) • relative offset (relative to the input offset) and length to specify what to replace by the candidate

=> (complete "(let [x (mapc" 13 'user) ; 13 is the end of the string
({:candidate "mapcat", :roffset -4, :len 4})

Now for something a bit more controversial:

=> (complete "(let [x (mapc" 12 'user)
({:candidate "map", :roffset -3, :len 3}
 {:candidate "map?", :roffset -3, :len 3}
 {:candidate "mapv", :roffset -3, :len 3}
 {:candidate "mapcat", :roffset -3, :len 3}
 {:candidate "map-entry?", :roffset -3, :len 3}
 {:candidate "map-indexed", :roffset -3, :len 3})

so here the completion is asked as if the caret ws between p and c

with compliment I'm getting the type and ns of each candidate

type as in: function, keyword, namespace, blah blah

do you use this info?

map|c so how would you substitue the candidate map?? and mapcat?

<f> as in function...

I can't upload files to the channel

I see your screenshot just fine

oh ok... I got a message saying that the workspace doesn't have any storage space left

the screenshot comes from cider (I'm doing cljs right now), but I'm using the same underlying lib to display the candidates in spiral

and do you pass the context or only the prefix to compliment?

Vim has an option to show doc string while completing options. It would be good to support that.

@dominicm can’t it be done in two steps? or does vim show all docstrings at once?

@cgrand it can't, but not for that reason. It's not possible to show it in response to a callback.

I also pass the context

also = in addition to the prefix?

if I remember correctly, I pass the context as a string with a __prefix__

yes I double checked, I pass context with a __prefix__ substring

@cgrand I use my own action which uses compliment under the hood and then transforms/enriches things for vim to digest.

Trying to make screenshot.

From compliment I get the candidate and it's type. I look up the various information based on the type. Compliment accepts the prefix and the namespace. The action looks like this:

`#:vimpire {:complete (vimpire.complete/completions #unrepl/param :prefix #unrepl/param :nspace)}`