This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-25
Channels
- # announcements (1)
- # asami (3)
- # aws (2)
- # babashka (8)
- # beginners (60)
- # biff (3)
- # calva (45)
- # clj-http (3)
- # clj-kondo (19)
- # clojure (50)
- # clojure-europe (23)
- # clojure-nl (8)
- # clojure-spec (4)
- # clojure-uk (3)
- # clojurescript (32)
- # conjure (3)
- # datomic (7)
- # events (2)
- # fulcro (24)
- # graalvm (3)
- # inf-clojure (3)
- # jackdaw (1)
- # lsp (3)
- # malli (8)
- # missionary (14)
- # off-topic (1)
- # polylith (3)
- # portal (11)
- # rewrite-clj (63)
- # shadow-cljs (21)
- # spacemacs (7)
- # tools-build (6)
- # xtdb (4)
You might also have to think about formatting. Does sorting also reformat? Like if you have:
{:b 2 :c 3
:a 1}
What result would you expect?I would expect to keep the same sort, follow the same formatting before applying the function
> I think I'd use rewrite-clj if I were to do this, but... maybe I am biased? hahah, I think rewrite-clj makes sense for that, but It doesn't seems easy at least to me
The preserving formatting might be more complicated. I would encourage you to work out exactly what you'd like to see for various inputs. For example, exactly what should this look like after sorted?:
{:x 2 :c 2 :d 4
:a 12345678 :y 1}
If you are not careful, you might end up scoping in some sort of vertical alignment feature.But if you get too restrictive and only allow sorting on maps that look like:
{:z 2
:a 1
:x 2
:c 3}
Maybe a sort map feature is only marginally better than an editor/IDE's sort lines feature?yeah, the idea is to add a code action on clojure-lsp that sort map keys, so I'd like to avoid changing formatting and things like that, only sort/swap the key-value pair with other key-value pair
not sure it'd be a big issue if the result map become not correctly formatted, I think for now would be ok
later then we could use cljfmt format after sorting when the vertical alignment is implemented :) (if user opt-in to that)
I have the same issue with rewrite-edn. it doesn't always do nice formatting, but at least all the original whitespace and comments are there
https://github.com/clojure-lsp/clojure-lsp/issues/651 I do think it's something cool to have as a command, not priority tho
I already saw that feature request on other libs like clj-refactor, and other editors
Well, I'm happy to fiddle up a little simplistic/naive example sometime later today for you.
I’ve started to fiddle a bit late in the day… will continue tomorrow… Interesting… but… well.. we’ll see…
So, the tricky part is not find the keys and values in the map.
The tricky part, I think, is deciding what to do with spacing, comments and discards.
Let’s start with basics, just in case there are lurkers who are interested.
If we go all naive, and ignore the possibility of #_
, here’s an example of finding all keys in a map:
(->> "{:a 1
:b 2
:c 3}"
z/of-string
z/down
(iterate #(-> % z/right z/right))
(take-while identity)
(map z/string))
;; => (":a" ":b" ":c")
As you can see, rewrite-clj stores child nodes of a map in a simple sequence. It does not distinguish the key from the value.
Here’s the same, but for values:
(->> "{:a 1
:b 2
:c 3}"
z/of-string
z/down
z/right
(iterate #(-> % z/right z/right))
(take-while identity)
(map z/string))
;; => ("1" "2" "3")
So it is not too terribly difficult to find keys and values, and one found, sort by the stringified key. But what what to do about: • spacing • comments • #_
For spacing, given kv-seq <k><spacing>+<v>, I am currently experimenting with moving kv-seq and leaving any surrounding whitespace where it is. This seems to work fine for simple cases:
{:c 3
:b 2
:a 1}
becomes, as you would expect:
{:a 1
:b 2
:c 3}
And with this strategy
{ :d 4
:c 3
:b 2
:a 1 }
Becomes:
{ :a 1
:b 2
:c 3
:d 4 }
But this currently can break down a bit if a kv-seq includes newlines. For example:
{:z 1 :b {:x 4
:c 7}
:a [1 2
3 7]}
Becomes (you’ll notice that :c
is no longer aligned under :x
, and you will notice that nested maps are not automatically sorted):
{:a [1 2
3 7] :b {:x 4
:c 7}
:z 1}
I suppose though, we could add in specific compensations for these cases.
But first, I’d like your feedback on this general approach.I’ve not looked a comments yet, but let’s explore a scenario:
{;; c1 is this a comment for the map or for the first kv?
:z 1 ;; c2 this is most probably a comment for this kv and should move with it.
;; c3 is this a comment for a group of kvs or only the next kv, or is it a continuation of the comment for the last kv?
:a 2
:x 3}
I think if a comment trails a value on the same line, it is pretty clear it should be moved with the kv-seq.
For the rest… well… not sure what we should do. Maybe just leave them where they are and let the user move them after the sort?
Also notice that a trailing comment, if moved to the last element in the map, will mean moving the closing }
, the above might become:
{;; c1 is this a comment for the map or for the first kv?
:a 2
;; c3 is this a comment for a group of kvs or only the next kv, or is it a continuation of the comment for the last kv?
:x 3
:z 1 ;; c2 this is most probably a comment for this kv and should move with it.
}
For maps containing #_
and unbalanced maps, I think maybe our original idea of not sorting is good.
Thank you for the help @UE21H2HHD!
> Becomes (you’ll notice that `:c` is no longer aligned under `:x`, and you will notice that nested maps are not automatically sorted):
I'm pretty ok on this minor alignment for now, users could just call clojure-lsp format
after the sort or even clojure-lsp could do that automatically for that map when user triggers the sort :)
> Maybe just leave them where they are and let the user move them after the sort?
The same, I'm pretty ok on leaving comments not on the same line of a k-v not sorted
I think most formatting cases we could fix with calling format for that map right after the sort.
Cool, I’ll explore moving the same-line comment, do a little cleanup and share what I’ve come up with.
@ericdallo, the code was getting a bit long so I instead of a gist, http://nextjournal.com/lread/sorting-maps-by-key-with-rewrite-clj. Pretty cool! Lemme know watcha think and if this gets you on your way. If not, we can chat more.
wow, what a detailed explanation @UE21H2HHD, that's awesome!
thank you very much for the effort, also explaining it on nextjournal was very cool
Glad you are enjoying it! I'm not crazy about my excessive use of loop
but not a bad first crack at it.
I understood the concepts of the function and I will even need to use the sortable-map?
as well 😛
I'll try to use on clojure-lsp and let you know if I find any issues, but it looks really good as a first iteration
Go ahead and tweet it if you like. I think I've only tweeted like 4 times. Don't want to get into the habit!
@UE21H2HHD it works like a charm 🚀
@ericdallo btw, Eric, I managed to do without making a change in rewrite-clj with regards to adding an id to the keyword nodes
Just adding a :context
with an id to the node in the hook is sufficient.
https://github.com/clj-kondo/clj-kondo/pull/1469/files#diff-78dfd2ff457fbf1d75e85a7e3949bbf31bc199636bb192e2e79d759a03d4a4c6R24