How can I run Ruff in Emacs? I need to enable 2 commands on the current buffer:
ruff check --select ALL current_buffer
→ bind to M-x ruff-check
ruff check --select ALL --fix current_buffer
→ bind to M-x ruff-fix
I can run each of these commands with a file argument on the command line, and ruff
is in my $PATH
.
I tried the solutions from here: Setup | Ruff, and have the following lines in ~/.emacs
, but they are not running ruff
on save as expected. Besides, I really want to enable the two distinct commands above, rather than running ruff
on save.
(add-hook 'python-mode-hook 'eglot-ensure)
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs
'(python-mode . ("ruff" "server")))
(add-hook 'after-save-hook 'eglot-format))
(require 'ruff-format)
(add-hook 'python-mode-hook 'ruff-format-on-save-mode)
I also tried out the proposal from Emacs to utilize the language server and failed. My reason was that I don't have ruff-format
available. This can be checked by simply trying out M-xshell-command
and then ruff-format
. This can be easily fixed by installing it (e.g. via MELPA) or using a different command instead. But your requirements are different nevertheless, meaning that ruff should not be triggered automatically, but on certain user interactions.
Therefore, I would simply recommend to not follow the setup instructions from Emacs page and define your own functions for both mentioned commands:
For the M-xruff-check
requirement you can define something like this:
(defun ruff-check ()
(interactive)
(let ((current-file (buffer-file-name)))
(if current-file
(async-shell-command
(format "ruff check --select ALL %s" (shell-quote-argument current-file))
)
)
)
)
And for the M-xruff-fix
requirement you can define something like this:
(defun ruff-fix ()
(interactive)
(let ((current-file (buffer-file-name)))
(if current-file
(progn
(shell-command
(format "ruff check --select ALL --fix %s" (shell-quote-argument current-file))
)
(revert-buffer t t t)
)
)
)
)
The interactive command can bind your command. In the example above, it is simply available as a command via M-x.
This special form declares that a function is a command, and that it may therefore be called interactively (via M-x or by entering a key sequence bound to it).
In the above function (ruff-check), I think we can use an async-command (minor improvement) since we are only reading. But in the ruff-fix it is easier to use a blocking command. Otherwise the buffer will not be refreshed correctly.
I have a slightly different setup and using an .emacs.d
folder (see here for the advantages) with an init.el
inside, where I put the two functions above in. You can also create an extra file, e.g. ruff.el
, but then you should not forget to load it in the init.el
file: (load-file "~/.emacs.d/ruff.el)"
.
Test setup:
def foo() -> int:
"""docstring for foo."""
return 42
After M-xruff-check
:
After M-xruff-fix
: