This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-10
Channels
- # beginners (15)
- # boot (15)
- # cider (6)
- # cljs-dev (231)
- # cljsjs (1)
- # cljsrn (26)
- # clojure (147)
- # clojure-argentina (1)
- # clojure-dev (8)
- # clojure-germany (1)
- # clojure-italy (26)
- # clojure-russia (2)
- # clojure-spec (83)
- # clojure-uk (154)
- # clojurescript (123)
- # conf-proposals (3)
- # core-async (5)
- # cursive (26)
- # datascript (21)
- # datomic (120)
- # emacs (2)
- # graphql (9)
- # hoplon (195)
- # instaparse (16)
- # jobs-discuss (1)
- # leiningen (8)
- # luminus (8)
- # lumo (7)
- # off-topic (17)
- # om (7)
- # om-next (3)
- # parinfer (121)
- # pedestal (5)
- # planck (13)
- # re-frame (11)
- # reagent (21)
- # ring-swagger (2)
- # spacemacs (28)
- # uncomplicate (3)
- # unrepl (7)
- # untangled (34)
- # vim (5)
my feeling is that this cursorDx solution is a partial one, but still useful enough for an early version, since it is not introducing more problems to Indent Mode, but reducing them
and the smart mode can be a complete solution that takes an array of changes, but will require some work
If you wrap the whole (if some-condition ... )
, then the print
and println
should be indented by 1, and the map by 2.
nice case
do you control the wrap operation?
could it replaced with a single change like atom does?
(not paredit I mean)
makes sense
I think the changes
option is doable for handling renames like this
I track both input and output coordinates as I parse the text
i’ll have to think more about it, but it feels doable
Really, the cursorDx at the moment is “from some point in the file (the new end offset of a change), indents must be changed by dx until a close paren”
So it seems like you could accept a list of those in result-document-order, and essentially keep a stack of them - they’re scoped by the parens, really.
When you encounter a new one, it gets pushed on the stack, and when you reach the corresponding close paren, you pop it.
“result-document-order”?
Really, a cursorDx is the dx value and the offset in the doc after which to apply it.
Whoever gives them to you will have to take care that they’re in the correct order, and also that they’re updated to use the co-ordinates in the resulting document.
sounds good
what would you call this option? it should replace cursorDx
maybe I should just take the changes and compute the [offset dx] internally
I suspect there are hairy edge cases here if the changes are not balanced, thinking about it.
and then we can use that option for other things later
Imagine that a user selects some text including an open paren, and then replaces it with text containing no parens.
what problem would that cause?
Because these will be applied using the parens for scoping. Let me see if I can think of a case.
I guess that would work, actually, since the closing }
will be removed during processing anyway
yeah, I couldn’t think of a problem with it actually, other than causing extra character insertion that could throw off the other change coordinates if I’m doing it incorrectly
will look at this after dinner, thanks so much guys. couldn’t have done this myself
As you’re processing, you record more or less the same data you’re doing now, but don’t make any modifications.
When you encounter a change, you know when the previous open paren was. You then process, making modifications, until that paren is balanced again.
In fact, it’s possible you could have two modes - scanning and only checking that parens are balanced, and then a mode where you’re processing, basically exactly as you do now. You just need to set up the correct data at the start of the open paren previous to the change.
ha, not following yet
But I think this might be the change which achieves everything I wanted from parinfer 🙂
streaming some work tonight: https://www.twitch.tv/shaunlebron
@shaunlebron So I basically wanted to change two things from parinfer, which I was planning to investigate. One was removing the indent/paren mode difference. The other was only processing the parts of the file (sexps, probably) affected by a particular change. This would mean that people wouldn’t have to pre-format their files on file open, and it would not be a requirement that the whole file complied with the indent rules - just the parts that they’re editing. My idea was to detect while processing the affected part of the file if that particular section didn’t comply with the indent rules, and to show an error at that point. So if the user tried an action in a part of the file which couldn’t support indent mode, parinfer just wouldn’t get run, they would be notified and they would have to fix it by hand, reformat it or something similar.
This change you’re making fixes the first, and I believe it can also be made to do the second.
I think the best way to do this would be to start scanning the file in a non-modifying mode. This would scan the file contents much like parinfer does at the moment, but it would not actually modify the file, it would just record the paren stack, the current horizontal position and the position of the last open paren (that might be implicitly stored in the paren stack).
Then, when you encounter one of these changes, you switch to processing exactly like parinfer does now, or at least like your new modified version does. You record the last open paren you saw. You update the file, but critically you stop processing as soon as the last open paren you recorded earlier is balanced. This means that the paren trail handling is a little trickier since you don’t just delete all close parens wholesale, you only do it until they’re balanced. Once your original open paren is balanced again, you switch back to your non-modifying scanning mode again until you hit another change.
If you ever get to a stage where the parens can’t balance, you barf with an error - this is like your new v2 warning mode. Similarly, you barf with an error if the sections you’re actually processing don’t obey the indent mode rules - I’m not sure if this requires more information to be tracked than is currently, but I suspect it’s a relatively simple change.
The only bit that I don’t have quite clear in my head (been too long since I looked at all the details) is that the close paren tracking & matching will work correctly - I’d need to try it.
Actually, thinking about this, I’m not sure it will work - I don’t know if parinfer can work out when processing should stop, since normally it relies on removing all close parens and putting them back where it infers them.
I think it will probably need the original range of the sexp from the original document, which gets back to the complexity around tracking ranges across all the changes.
just thinking through an example:
(defn foo
([a]
(foo a 123)) ;; <--- what happens when adjusting indentation of this line?
([a b]
(+ a b)))
having a hard time piecing together expected behavior here, maybe we can work from this example to see what would be partially processed
some questions: 1. should dedenting this line by one space cause it to enter the parent form? 2. should dedenting all the way cause it to adopt everything below it?
@rgdelato: I published 2.5.2
you can either run with that, or wait for a cursorDx
to be replaced with a changes
array option
i’m leaving for a road trip tomorrow, and I may not finish the changes
thing today
@shaunlebron > maybe I should just take the changes and compute the [offset dx] internally I think this would be a good idea BTW, then you have more context if you want it later. It means explaining the concept of the different co-ordinate spaces and specifying which you want though.
thanks colin!
streaming here for the changes
option: http://twitch.tv/shaunlebron
@shaunlebron So that’s a tricky case to start with 🙂
One thing I’m not clear on is if when you encounter a change, if you need to reprocess from the last opening paren. I’m not sure how much data you would need to collect to begin processing immediately when encountering a change.
So I think assuming that either you reprocess from the opening paren, or you do have enough data from the initial scanning, when adjusting the indentation of that line the last opening paren will be the ([a]...
But as soon as we start processing it, we’ll find that it’s not indented according to the indent mode rules, and fail with an error stating that.
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(when (or (= :all refer) ; <-- replace this when with an if
(contains? refer name))
name))
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (or (= :all refer) ; <-- change is right after if, dx = -2
(contains? refer name))
name))
Now, when you run parinfer, you’ll scan the file, not modifying anything but just checking parens are balanced, until you hit the change.
So your last open paren is right before the if
, and you start processing. I’m assuming that at that point you’re processing in paren mode, because you have an active dx.
I haven’t seen that code, so I don’t know exactly how that works, but I’m assuming that dx is in scope for the following block, i.e. the (or ...)
sexp, so that all gets indented correctly:
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (or (= :all refer)
(contains? refer name)) ; <- this gets indented by dx
name))
then you continue processing until the end of name)
. At that point you realise that your original open paren (if...
is now balanced, so you go back to scanning. Since there are no more changes, you’re done.
So you only made edits inside the if
sexp, and the forms in the let
binding vector could have been incorrectly indented (according to indent mode rules), and that wouldn’t have been a problem as long as the parens are correctly balanced.
If something inside the if
block were incorrectly indented, you’d fail with an error.
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (or (= :all refer) ; <- caret is now right before (or…, and I type or paste (and
(contains? refer name))
name))
So now we have:
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (and (or (= :all refer) ; <- and is currently unbalanced, following code is not indented
(contains? refer name))
name))
Again, assuming that dx is in scope for the or
block, you process that in paren mode:
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (and (or (= :all refer) ; <- and is still unbalanced
(contains? refer name))
name))
Then at the end of the (or...)
block, you’re processing in indent mode again as normal, and add the closing paren for the (and...
(let [{:keys [refer rename]} filters
name (get rename place-name place-name)]
(if (and (or (= :all refer)
(contains? refer name)))
name))
Then as before, you keep processing until the end of name)
, switch to scanning and run to the end.
The tricky part here (and in the previous case) is how to handle the paren trail for name))
Actually, looking back at the existing paren trail rules, I’m not sure they need to be any different.
The one tricky bit might be: IIRC at the end of a file, if there are any remaining outstanding close parens they’re inserted at the end to ensure everything is balanced.
Should that happen here when the open paren before the change is balanced? I guess by definition there can be no outstanding close parens at that point.
2.6.0 pushed with changes
option that replaces cursorDx
@rgdelato @chrisoakman we can start integrating the changes
option into atom-parinfer now
I’ll try to update the site demo tonight if I have time 🙂