3

I have a project where I want to disable format-all-mode for all my python files. I can do this manually by running M-x format-all-mode every time I open up a python file for that project.

I tried automating this by setting my .dir-locals.el to this:

((python-mode
  (eval . (progn
          (make-local-variable 'format-all-mode)
          (setq format-all-mode nil)))
))

I've also tried:

((python-mode
  (eval . (progn
         (format-all-mode nil)))
))

but format-all-mode continues to be t every time I open a python file. I've confirmed that my .dir-locals.el settings are otherwise working, because when I add something like (setq blah "asdf") inside the progn function, I see that variable in my buffer.

What am I missing in order to configure the buffer-local format-all-mode variable?

Here are the docs when I describe this format-all-mode variable:

format-all-mode is a buffer-local variable defined in format-all.el.

Value in #<buffer my-file.py>
t

Buffer values Global value Toggle Set

Documentation
Non-nil if Format-All mode is enabled.

Use the command format-all-mode to change this variable.

Key Bindings
This command is not in any keymaps.

References
References in format-all.el:
(define-minor-mode format-all-mode ...) 2 references

Find all references

Update

I should've mentioned that I'm using Doom emacs, which has modified the format-all-mode so that it cannot be disabled with the usual (format-all-mode -1).

I followed these instructions: https://docs.doomemacs.org/latest/modules/editor/format/

and got it working with the following value in my .dir-locals.el:

((python-mode
  (eval . (progn
        ;; this doesn't work, because we're using doom emacs:
        ;; (format-all-mode -1)
        ;;
        ;; https://docs.doomemacs.org/latest/modules/editor/format/
        ;; TODO: add python-mode to the list, instead of overwriting the whole list
        (setq +format-on-save-enabled-modes
          '(not python-mode sql-mode org-mode emacs-lisp-mode))
  ))
))

It's a hack though, since +format-on-save-enabled-modes isn't buffer local. I'm not sure if there's a better way - any help is appreciated!

modulitos
  • 2,432
  • 1
  • 18
  • 36
  • 1
    To disable a minor mode, you call it with a negative argument, so try `((python-mode (eval . (format-all-mode -1))))`. I didn't check the syntax though. – NickD May 11 '23 at 18:20
  • Hmm I tried that, but it's still not working... Note that the docs mention `Non-nil if Format-All mode is enabled.` (I referenced the output above) – modulitos May 11 '23 at 18:35
  • 4
    You need to call the *function* `format-all-mode` with a negative argument. If the mode is disabled, then the *variable* `format-all-mode` should automatically be set to `nil`. Setting the variable does *not* disable the mode in general. So try this: open a python file, check the variable (which should be `t` if the mode is automatically enabled); then do `M-: (format-all-mode -1)` to disable the mode and check the variable again: it should now be `nil`. If that's all as it should be, then you have to make sure that the syntax of your entry in the `.dir-locals.el` file is correct. – NickD May 11 '23 at 18:49
  • @NickD Thanks for the tips! You are correct. This helped me narrow down the issue, which I detailed at the bottom of my updated post. Looks like there's some complications due to me using Doom emacs, and while I have a workaround as described, it's pretty hacky. – modulitos May 11 '23 at 23:57
  • Just to update this thread, philz answer below provides an elegant solution to make this work with Doom emacs! – modulitos May 12 '23 at 07:27

1 Answers1

2

The real question is about disabling a minor mode, but just to answer the stated question of setting a buffer-local variable, it's as simple as this:

((python-mode . ((format-all-mode . nil))))

I.e. giving variables buffer-local values is what the most basic syntax of .dir-locals.el is for. There is no need to complicate anything with eval.

Note that if you ever use (eval . (setq VAR VALUE)) in a .dir-locals.el file and VAR is not already/automatically buffer-local, then you are setting the global value. I would suggest using setq-local as standard in that situation.

In your case, and per the quoted docs, you need to:

Use the command format-all-mode to change this variable.

Where the command is the function itself, which is interactively callable via M-x.

(Because changing the variable is not the real goal; the variable is merely intended to be a reflection of whether or not certain other functionality is active, and the function controls that functionality.)

So you would use eval if you needed this to be a buffer-local thing, but you'd do that to call the function:

((python-mode . ((eval . (format-all-mode 0)))))

n.b. I'm also assuming that format-all-mode is a buffer-local minor mode. If it's a global mode, then the above would disable its behaviour globally as soon as you visited a python file under that directory. (Global modes need to be handled on a case-by-case basis, as how they operate can be highly variable.)


Edit: From the comments, this particular case needed something different again, but a working solution turns out to be:

((python-mode . ((+format-on-save-enabled-modes . nil))))

I.e. in python-mode buffers, for files under the dir-locals directory, we give +format-on-save-enabled-modes the buffer-local value of nil. Testing has confirmed that this has the desired effect of preventing the format-on-save behaviour for those files.

phils
  • 48,657
  • 3
  • 76
  • 115
  • Unfortunately neither of these solutions disables the format-all minor mode for me, I think because Doom emacs has its own hooks which prevents that. I posted an update to my question above which explores some workarounds, but it still feels very hacky. I appreciate this answer though - it's helped me understand these fundamentals a bit more. Happy to mark this as an accepted answer if it helps others. – modulitos May 12 '23 at 00:44
  • 1
    I don't use doom or this mode, but looking at your update, you might try `((python-mode . ((+format-on-save-enabled-modes . (not python-mode)))))` -- whether that works would very much depend on the manner in which `+format-on-save-enabled-modes` is used, but it seems worth a try. – phils May 12 '23 at 01:33
  • 1
    Or maybe `((python-mode . ((+format-on-save-enabled-modes . nil))))` is a slightly cleaner option. I don't know anything about this variable though, so that's purely a guess. – phils May 12 '23 at 03:28
  • 1
    Amazing! Your suggestion above works perfectly: `((python-mode . ((+format-on-save-enabled-modes . nil))))` I'm still wrapping my head around buffer-local variables, but it seems like setting +format-on-save-enabled-modes in this manner is specific to `python-mode` and correctly uses the default for all other modes. This is exactly what I needed. I should probably read up on how this actually works, but for now, I'm thrilled to have this working as expected :D – modulitos May 12 '23 at 07:26
  • 1
    I'm glad that worked. My guess is that the format-on-save functionality is triggered in `before-save-hook` for the specific buffer being saved, checks the value of `+format-on-save-enabled-modes` at that point in time, sees the buffer-local value, and therefore does nothing. – phils May 12 '23 at 09:06
  • 1
    You've correctly understood the .dir-locals.el behaviour -- the buffer-local value is being set *only* for file buffers which are in `python-mode`; other buffers are unaffected. – phils May 12 '23 at 09:12