drym-org / symex.el

An intuitive way to edit Lisp symbolic expressions ("symexes") structurally in Emacs
Other
271 stars 22 forks source link

Applying symex-tidy after at each symex-delete can be annoying #105

Open pbaille opened 1 year ago

pbaille commented 1 year ago

I was wondering if applying symex-tidy automatically after each symex-delete was really a good thing. Most of the time I like this behavior, but when working with teams that has specific indentation practices it can be annoying. What do you think ?

countvajhula commented 1 year ago

Could you give an example of these indentation practices and how the result of tidying deviates from it? I'm also curious how your team keeps the code formatted according to the convention -- do you use any built-in formatting functions like indent-region, or anything else? Or is it done manually? Any insights into these practices or examples would help to design the right solution.

One idea is to make the tidying function user customizable (defcustom) so that it could be set to none, or it could be set to a custom function too.

Also, in the 2.0-integration branch there have been some tidying changes there and it's possible the behavior is improved from what's currently in master. So if you have time to try that out too (optional -- not required at all), that could be useful as well. If you want to try it, you can use config resembling this:

(use-package symex
  :straight
  (symex
   :type git
   :host github
   :repo "drym-org/symex.el")
   :branch "2.0-integration"
   :config (symex-initialize))
pbaille commented 1 year ago

Thank you for the quick feedback ! The indentation pattern I have to observe in the company I work for is this one

(a-function obj
  arg1
  arg2
  arg3)

But symex is tidying this as so

(a-function obj
            arg1
            arg2
            arg3)

here is a fragment of our coding-style document:

Thus we should try to not align values which are unrelated, or else otherwise distinguish semantically distinct groupings.

;; Sensible - these are all just arbitrary values
(def values [haggis
             :tatties
             "neeps"])

;; Un-semantic - a `let`'s bindings and body have distinct meanings
(let
  [something (foo)]
  (println something)

;; Also un-semantic - `cook` is an action, distinct from its ingredients
(let [food (cook
            haggis
            tatties
            neeps)])
tommy-mor commented 1 year ago

Most of the time I like this behavior

Same. I think it makes sense that would be a toggleable behavior, which can be done per-project in a .dir-locals.el .

I really like the notion of semantic alignment in a style guide manner. Is there a public version of this style guide anywhere? After seeing this I get the feeling my intuitive indenting is somewhat like this (whenever I go against the symex-tidy, which is rare)

pbaille commented 1 year ago

It is not yet published, but will be soon, I will remember to send a link to you !

countvajhula commented 1 year ago

Yeah, I like all these too, but it's worth noting that Symex mostly relies on Emacs / the relevant major mode to tell it how to indent. In the master branch it uses evil-indent which internally uses Emacs's built-in indent-according-to-mode, and in the 2.0-integration branch it uses indent-region which also defaults to indent-according-to-mode.

Some major modes allow you to customize the indenting behavior. For instance, with Racket Mode, you can modify the indent behavior by setting a property on the symbol to tell Emacs how to indent that form. I'm not too familiar with that way of doing it, but I use it in my config and it works well enough. According to the Racket Mode docs, this is also how lisp-mode (for Common Lisp) and scheme-mode (for Scheme) do it. Maybe there are similar options for Clojure and other languages that you could customize to achieve your conventions? In that case, symex-tidy would just work out of the box and respect these conventions.

If for some reason that's not possible, then another option could be to look at indentation packages for Emacs like Format All the Code -- I haven't tried it, but if this is usable and if it's customizable for what you need that would be good to know so we can define a proper integration with it and include it in the docs.

If that doesn't work either, you could try implementing an indenting function yourself, for which Emacs docs on indent-according-to-mode and indent-region seem like good starting points to understand how Emacs indents code and how it can be customized.

And of course, worst case, you would just disable the auto-indenting.

So to summarize, it seems like we could address this by adding a defcustom for whether to auto-indent after each operation or not, which can be set either globally in your .emacs.d or via major mode hook for each language, or in a dir-locals.el for specific projects. And if you need to customize the indenting to match your conventions (instead of disabling the indenting), that could be done at the major mode / Emacs level using one of these options above. Wdyt?

pbaille commented 1 year ago

Thank you a lot for this detailed answer ! I've looked a bit more carefully to the indenting customizations available for clojure and I've found that using this via .dir-locals I can get almost what I wanted. I've also implemented a bunch of elisp functions (on top of indent-region and evil-shift-*) that help me to handle edge cases and now it's near perfect :)