-
-
Notifications
You must be signed in to change notification settings - Fork 247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add refactoring command for converting #() shorthand #601
Conversation
079757a
to
394e6ba
Compare
394e6ba
to
eebb353
Compare
Sorry for forgetting about this PR! The code looks great and we only need to decide on a keybinding (where I'm fine with your suggestions) and add this to the menu, so it's easier to discover. I agree that a conversion in the other direction doesn't make as much sense, although we can add it for the sake of uniformity (this will also allow us to have some "toggle" command that alternates between the two). That's totally optional, though. |
We have this feature already tho, it's |
Oh! That's embarrassing... I should familiarize myself more with the cljr refactorings, unfortunately the ones requiring full project AST analysis don't work on our codebase. I guess one advantage of this PR's command is that it's entirely textual and doesn't require a Cider REPL, whereas the https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-promote-function It also doesn't appear to support There was a push to move all non-repl commands in clj-refactor to the clojure-mode repo, perhaps we could rename my code to |
I like this idea. I guess
Please, report those issues to the clj-refactor repo. We'll have to address them at some point. |
Ok, I've renamed the functions ("promote" does convey the intention better than "convert") and bound it to "C-c C-r P" ("p" was taken by clojure-cycle-privacy). Will submit a PR to clj-refactor repo if this gets merged :) |
553f786
to
0821b45
Compare
No, not at all. https://github.com/clojure-emacs/clj-refactor.el/wiki marks with Accordingly I'd try to move this impl to clj-refactor entirely - sounds simpler to only maintain one impl.
would appreciate a report, we keep improving things in this front (the only thing that hasn't seen an immediate fix is performance - scales linearly with codebase size. Think 8m for 100KLOC) Cheers - V |
btw, now that rewrite-clj is so advanced (and cross-platform) it would make sense to eventually implement this feature server-side. Else it's pretty plausible that the impl will always have bugs - who really wants to implement a full-blown Clojure refactoring engine in elisp? 😀 The good thing is that rewrite-clj is embedded in both refactor-nrepl and clj-kondo/lsp so this approach accomodates all kinds of preferences. |
The point is that many people don't want to install several packages, so it's a good idea to have some simple commands that mostly get the job done in |
I'd be comfortable with moving the impl from clj-refactor to clojure-mode + merging impls / discarding older bits. Maintaining two impls (presumably each with its own set of small bugs) seems a bit disproportionate. |
That'd be fine by me. I agree that having 2 implementations that don't rely on any server-side code is an overkill. |
Perhaps the wiki is outdated? The function body is clearly wrapped in a Although I got around it by invoking the private There's surely lots of buggy regex-based clojure parsing and code duplication going on in both codebases, but as @bbatsov pointed out, it's good enough for a lot of usecases. Another case in point - clj-refactor's use of multiple-cursors and interactive overlays often interact in unpredictable ways with Evil and/or undo-fu, corrupting the undo history. I ran into this many times while testing out That's not necessarily the fault of either package, but just one of my reasons to favour less "sophisticated" impls. I agree that delegating all refactoring ops to rewrite-clj would be the most elegant solution but that would itself be quite a significant refactoring(heh). |
Updated, thanks! I see, it's because it calls
So I'd expect a sub-second (but real) latency associated to tools.analyzer. Of course, one is trading it for something, namely accuracy.
There's I think it would add objectivity to the discussion that you tried to use clj-refactor's impl and created an issue for every observed nuance. My thinking is that simply:
I think this still leaves the room open for #601 (comment) . The 'locals' could be an argument. It would default to nothing when using bare clojure-mode, and to something when wrapping it via clj-refactor.el. That way we still have a single impl, while accomodating different approaches/tradeoffs. |
btw the 'locals' could also be provided by even more impls, e.g. clj-kondo. So one has 3 approaches for the price of one |
Perhaps there is some misunderstanding here - cljr-promote-function is in fact two different refactorings, dispatched on context
This PR only implements the first case, "promote-fn-literal" and does not consider the second case. It's only the latter which requires locals analysis and runtime powered smarts, while the former case even in clj-refactor impl is a purely textual transformation (being after all a read-time macro). My proposal was something like (pseudocode): ;; replace current impl
- (defun cljr--promote-function-literal
- ... )
(defun cljr-promote-function ()
(if (looking-at "#(")
+ (clojure-promote-fn-literal) ; <- this PR's impl, not REPL gated
(cljr--ensure-op-supported "find-used-locals")
(when (cljr--asts-y-or-n-p)
(cljr--promote-function))) ; <- retain the fn->defn runtime supported logic I'm sorry if this PR comes across as NIH, I was unaware of the existing impl and wrote one from scratch. After the fact I found several edge cases with the cljr impl as reported in clojure-emacs/clj-refactor.el#505, which are correctly handled by my code. |
Don't worry at all! We can really be talking about NIH, as for me all the projects here are just different parts of one project. :-) In light of everything so far, I still feel it's a good idea to include this in In this case it also seems that cljr benefits from the proposal as well, so it's a win-win in my book. We just have to document this well for posterity's sake. |
@@ -261,6 +261,8 @@ The prefixes are used to generate the correct namespace." | |||
(define-key map (kbd "C--") #'clojure-toggle-ignore) | |||
(define-key map (kbd "_") #'clojure-toggle-ignore-surrounding-form) | |||
(define-key map (kbd "C-_") #'clojure-toggle-ignore-surrounding-form) | |||
(define-key map (kbd "P") #'clojure-promote-fn-literal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to add a menu entry as well.
We also need a changelog entry. |
0821b45
to
c1cc7a5
Compare
Rebased on master and added changes |
Thanks! |
Released as 5.14.0 |
M-x clojure-convert-shorthand-fn
turns the closest #() before point into a regular (fn ...) form. If there are any%
arguments it prompts interactively for the arg names.Useful for fixing nested #() forms and general refactoring for readability. (I believe the reverse refactoring is much less necessary in practice)
Keybindings:
Not implemented yet, but I think "convert function" ( prefix +
cf
/fc
) makes sense in theclj-refactor
package, as well as here in the defaultclojure-refactor-map
as the single key bindings#
f
andc
are all taken.Before submitting a PR mark the checkboxes for the items you've done (if you
think a checkbox does not apply, then leave it unchecked):
M-x checkdoc
and fixed any warnings in the code you've written.Thanks!