This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-02-16
Channels
- # admin-announcements (14)
- # announcements (1)
- # aws (1)
- # beginners (105)
- # boot (609)
- # braid-chat (4)
- # braveandtrue (3)
- # cider (24)
- # cljs-dev (13)
- # cljsrn (2)
- # clojure (142)
- # clojure-berlin (7)
- # clojure-ireland (7)
- # clojure-japan (10)
- # clojure-nl (4)
- # clojure-poland (76)
- # clojure-russia (198)
- # clojure-sg (4)
- # clojure-taiwan (1)
- # clojurebridge (1)
- # clojured (4)
- # clojurescript (73)
- # conf-proposals (11)
- # cursive (10)
- # datomic (32)
- # devcards (1)
- # dirac (22)
- # editors (5)
- # emacs (3)
- # events (4)
- # funcool (19)
- # hoplon (18)
- # job (1)
- # jobs (3)
- # jobs-rus (16)
- # keechma (25)
- # ldnclj (33)
- # lein-figwheel (10)
- # leiningen (4)
- # luminus (1)
- # off-topic (19)
- # om (255)
- # onyx (51)
- # overtone (1)
- # parinfer (206)
- # perun (5)
- # proton (2)
- # re-frame (3)
- # reagent (2)
- # remote-jobs (13)
- # ring-swagger (7)
- # slack-help (4)
- # yada (7)
"implies that indent mode should be run again on a caret movement where the caret leaves the line with the held paren" <-- this is correct and expected behavior while in Indent Mode
@cfleming: have you used atom-parinfer at all? it might be worth using it some to get a feel for how Parinfer works there
the code for applying Paren Mode when a file is opened can get tricky. For reference: https://github.com/oakmac/atom-parinfer/blob/master/src-cljs/atom_parinfer/core.cljs#L337-L383
@chrisoakman: I haven’t but I’ve been meaning to
might be helpful; atom-parinfer is the most mature and stable implementation of parinfer (to my knowledge)
> this is correct and expected behavior while in Indent Mode Doesn’t this mean that you can never actually manually enter a close paren though?
while in Indent mode, closing parens at the end of lines are always "under control" of the Parinfer algorithm
you can edit them, but then Parinfer will always just replace what you type
Right. The more I play around with it, the more I think a hybrid mode is what’s required.
give atom-parinfer a try
@chrisoakman: I can’t find the parinfer package for Atom
are you on the packages tab in the settings?
From the getting started page, I clicked “Install a package” and searched for “parinfer”, but it doesn’t find anything.
which platform are you on?
Cmd+,
then the "Install" tab
then type "parinfer" + Enter
There it is - I think the first time it presented me with a list of recommended plugins
or if you were on the "Packages" tab, that was a list of your existing packages
probably
I think it ships with the Clojure language already
nope - give that a try
pretend like you're a new Clojure user 😉
Are you aware of the Cmd + (
and Cmd + )
hotkeys?
Having used this more than me, what’s your feeling about the usefulness of paren mode?
as an editing mode? I basically never use it
I can't remember the last time I ever turned it on other than checking the extension
are you planning on having a toggle to turn Parinfer on / off?
then I would offer it
I mean - I'm not familiar with Cursive conventions
but I think if you copy the atom-parinfer conventions of Ctrl + (
and Ctrl + )
that would be good
after using Parinfer for a while, you don't even notice it's there
it automatically turns on for file extensions it recognizes
runs paren mode (which usually doesn't do anything to the file)
and drop you into indent mode
it's only when you first start using it that you hit the Paren Mode edge cases
also - none of the extensions are using cursorDx correctly right now
so that limits Paren Mode's usefulness
That’s what I’ve been thinking. I’m also thinking that I might start working towards the hybrid mode by special casing some things (like entering a closing paren)
correct
I would suggest the opposite, actually
re: entering closing parens
when using Indent Mode, indentation is the master and parens are the slave
you mean at the end of a line?
I mean - it just doesn't matter if they do or not
if they do, and it's the "correct" one, then parinfer runs and it looks like nothing happens
if they do, and it's the "wrong" one, parinfer runs and corrects it immediately
oh - yes
due to the cursor rules
If you close that paren, it doesn’t get corrected but the indentation is wrong on the (when true)
that's just how parinfer works
indent mode never touches indentation
I mean, I understand the theory but using it it would feel more natural if it did correct indentation.
I need to give it a think; it's hard for me to separate my thoughts on this since I have ported the thing 4 times and written two plugins for it
it feels very natural to me at this point
when in indent mode, my primary "control lever" is indentation, basically tab
and shift + tab
just like it would be in Python or if I were formatting JS code to common convention
Sure, but I don’t think that precludes other types of manipulations doing intuitive things.
and I practically never leave Indent Mode
I would have to use it with those modifications in order to see if they felt "natural"
of course "natural" is a function of what you're familiar with... but you know what I mean
would also be interested to hear what Shaun thinks about it
he's good at coming up with use cases that break or support intended behavior
But I’m leaning towards implementing a hybrid mode out of the gate and iterating based on feedback.
that might be quite tricky to implement; I'm not sure
something about the parinfer algorithm right now: it doesn't know what you just typed
it just has input text --> output text; the result is a pure function of the input text
(with optional cursor parameters, but still makes it a pure function)
so you would have to come up with "what the user just typed"
which you might know in some simple cases, like regular typing
but that becomes quite tricky once you start dealing with copy/paste and multiple cursors, etc
I think that what I would do is: the before or after text contain an unbalanced number of parens, I would adjust the indentation for the whole top-level form.
Basically, if the event is changing the nesting, then the indentation needs to be adjusted
I'm not sure what happens at the end of a line when you do that
yeah; interesting
having some test cases and discussing on Issue #86 is the way to go I think
being able to test it out would be helpful too
Yeah, I’ll try to modify the algorithm to test it out, and I can help you get a test build of Cursive installed to try when I do.
try some real-world editing in Atom for a day; see how it feels after a while
sure; I would be open to that
every onChange
and cursorMove
event
which is why the debounce is important, because those fire all the time
on a single keypress both of those events are fired
it's probably fine
parinfer is so fast
unless you're noticing any sluggishness
No, but in IntelliJ doc changes trigger a whole lot of stuff, it’s not just about the speed of parinfer
I'm not sure I know what you mean when you say "doc change"
oh - ok
@shaunlebron: Actually, re-reading the issue about caret movement I misunderstood what was written there - feel free to ignore me
trying to distill some of the points you made so I can address them simply
1. user should not be able to type a close-paren in Indent Mode (given the current rules)
2. the behavior of “holding parens” is confusing and breaks Indent Mode rules
3. Indentation can be wrong when inserting a close-paren
4. Inserting close-parens should trigger an indentation correction
For point 1, here’s an example of a simple close-paren insertion that doesn’t cause indentation problems, and it results in an inline paredit-barf
(def foo| bar)
=> (def foo|) bar
, after inserting a )
at the cursor
For point 2, let me sketch out a diagram...
The problem is that indent mode does not allow you to move between these states
because the moment you type the ]
, it would be displaced
the problem is that moving between valid states sometimes requires moving through an invalid one
I’m not saying this is the best way, this is just to paint a picture of the model that I currently use to solve it
You may be wondering why “State 2” is valid above. Obviously, the indentation is wonky. This brings us to Point 3. I’ll first address the example you gave for clarity, and then cover “State 2"
Cursor is |
(let| [x 10]
(when true))
when the user types a )
, we get
(let)| [x 10]
(when true)
Even when the cursor moves away, this indentation here will remain the same:
(let) [x 10]
(when true)
So we end up with code that has wonky indentation, just like “State 2” in the previous example
This is just a design decision that was made
even though the indentation is weird, it doesn’t violate the indentation thresholds
The right-bound of the threshold is this:
(let) [x 10]
(when true)
You can indent the expression to the right, but the structure won’t change until you hit this:
(let) [x 10
(when true)]
And since Parinfer respects the user’s chosen indentation within thresholds, we allow this:
(let) [x 10]
(when true)
I think my guiding design philosophy behind these examples is that I find it important to allow this motion between valid states
Alright, for Point 4, I think this will sum up my thoughts pretty well...
My suspicion is that Parinfer has become a set of primitives by which you can perform what you describe in Point 4
you can see this by how Mike Fikes has combined the modes to meet his own needs in Planck
For example, for point 4, we start with:
(let [x 1]|
(when true))
In indent mode, we insert a )
:
(let [x 1])|
(when true)
If you wish indentation to be corrected, you don’t have to rewrite Parinfer. Rather, you can treat Parinfer as the primitive operations which you can compose for your desired behavior.
To continue the example, you can have Cursive’s plugin apply Paren Mode when )
is typed:
(let [x 1])
(when true)
I’m really happy that you’re challenging the notions of what Parinfer should be doing in different cases
I would recommend thinking about your custom rules not as a new mode separate from Indent Mode and Paren Mode
but rather as a set of rules for determining when to apply each Mode
anyway, I’ve tried to get everything that I know about Parinfer into the website, design doc, and test cases for posterity.
but I still think the best way to explore an idea is to ask a person, so keep the questions coming if you have a question
Thanks for the thoughtful feedback @shaunlebron, this is very interesting.
I agree that this should be thought of as a combination of primitives. I think I’m proposing to modify paren mode to use IntelliJ/Cursive’s indentation, so it will use semantically-aware indentation. This will make it probably too slow to be as real-time as indent mode, but even with these modifications it won’t be run that often.
And then to work out when that should be applied based on the change to the document.
Hi, can I just say that I LOVE parinfer!!!! I am using it with Atom and it works perfect!!!
thanks @thomas
Hey all after seeing parinferlib in emacslisp I updated my attempt at the parinfer emacs plugin to use it: https://github.com/edpaget/parinfer-mode
I think it's working better than the node version did, but I'm not sure it's all the way correct yet, if someone wants to give it a try I'd appreciate it
unfortunately for me, today is a python day at work instead of a clojure one, so I'll have to try it more after work
@edpaget: great work
let me know if you need anything from the parinferlib side; I'm looking at MELPA right now
@chrisoakman: thanks for porting it over. I gave it a try about a month ago and got totally overwhelmed.
I think all you'll need to do to add it to melpa is add some metadata to the main parinferlib file and send a pull request here: https://github.com/melpa/melpa
right - I was reading about that
I was thinking it definitely makes sense for the editing mode to be available from a package manager like that; does the same logic apply for just the library though?
would your package just depend on the parinferlib package?
and people's Emacs installations would figure out that dependency chain?
I know nothing about Emacs
haha, yeah packages can declare dependencies and melpa (or package.el can't remember which bit handles it) will resolve them when they get installed
I could also see me just adding my little bit of code to your project and publishing that if you want
ok, so it's very similar to package.json and the npm world
let's treat them separately; I'd like to keep the library independent
in case someone else wants to make a different Emacs package (for whatever reason)
In the JVM parinfer, the PARENS map maps opening braces to closing ones, but it also maps closing ones to opening ones.
I think it uses both
but you could remove the closing -> opening map and see if all the tests still pass
I’m modifying it at the moment to use Cursive’s lexer, which makes a lot of things simpler