Table of Contents
Lazy-ruff
is an Emacs integration of the blazingly fast ruff
formatter/linter simply using shell
commands. lazy-ruff
offers an (hopefully) easy approach to formatting and
linting your Python code with ruff
, whether it's within org-babel
code
blocks, specific marked regions or on entire Python major mode buffers.
From my experience lazy-ruff
operates MUCH faster than any other formatter or
linter that I've used so far (all credits to ruff
of course), but that is a
purely subjective experience, since I have not run any benchmarks what-so-ever.
I hope this package will help your workflow.
The ruff
command-line tool must be installed and be available in your
system's PATH, for more information see:
https://docs.astral.sh/ruff/installation/
If you have pip
or uv
on your system, a simple call on the shell should
suffice:
uv pip install ruff
Add the following to your init.el (or other personalization file):
(use-package lazy-ruff
:ensure t
:bind (("C-c f" . lazy-ruff-lint-format-dwim)) ;; keybinding
:config
(lazy-ruff-global-mode t)) ;; Enable the lazy-ruff minor mode globally
If you don't want to use the ruff
linter and only use the ruff
formatter, go to this
section.
If you have MELPA added to your Emacs config and
use-package
installed, you can
install lazy-ruff
with use-package
and its :ensure t
directive:
(use-package lazy-ruff
:ensure t) ;; Ensure the package is fetched from MELPA
I recommend directly enabling the lazy-ruff
minor mode globally and adding
the handy keybinding C-c f
for the dwim method during the use-package
call:
(use-package lazy-ruff
:ensure t
:bind (("C-c f" . lazy-ruff-lint-format-dwim)) ;; keybinding
:config
(lazy-ruff-global-mode t)) ;; Enable the lazy-ruff minor mode globally
Simply install lazy-ruff
with M-x package-install RET lazy-ruff RET
or
You can download the lazy-ruff.el
elisp file, put it in a place in your
.emacs.d
directory and load the package by adding the following to your
init.el
or a personalization file of your choice.
(add-to-list 'load-path "/path/to/lazy-ruff-directory") ;; Only needed if the directory for lazy-ruff.el isn't yet on the load-path
(require 'lazy-ruff)
Use the lazy-ruff-lint-format-dwim
method for your keybinding, this function
will help automatically detect the context your cursor/pointer is in and apply
the best fitting lazy-ruff
method. Here is an example:
(global-set-key (kbd "C-c f") 'lazy-ruff-lint-format-dwim)
Or during the use-package
call:
(use-package lazy-ruff
:ensure t
:bind (("C-c f" . lazy-ruff-lint-format-dwim)))
You can also set up keybindings for each individual method depending on your
use-case, but if you use the lazy-ruff-lint-format-dwim
method then
lazy-ruff
will automatically know which method to call depending on the
context your cursor/pointer is in (an org-babel
code block, a
marked/highlighted region, a Python major mode buffer).
Lazy-ruff
provides a minor mode lazy-ruff-mode
for automatically using the
formatter/linter on save for Python buffers/files. To use this minor mode
globally, add the following line to your Emacs config:
(lazy-ruff-global-mode t)
You can also toggle it on/off in a buffer by calling M-x lazy-ruff-mode
or do
it globally by calling M-x lazy-ruff-global-mode
Defaults have been provided in the package for the ruff
shell command, but
you can dynamically change these to fit your own use-case. The defaults are:
;; Default settings
(defvar lazy-ruff-check-command "ruff check --fix -s"
"Defines the ruff check call for all methods.")
(defvar lazy-ruff-format-command "ruff format -s"
"Defines the ruff format call for all methods.")
(defvar lazy-ruff-only-format-block nil
"When non-nil (e.g. t), only format the code in a block without linting fixes.")
(defvar lazy-ruff-only-format-buffer nil
"When non-nil (e.g. t), only format the code in a buffer without linting fixes.")
(defvar lazy-ruff-only-format-region nil
"When non-nil (e.g. t), only format the code in a region without linting fixes.")
Observe that the lazy-ruff-check-command
defines the linter call
to ruff
on the CLI and the lazy-ruff-format-command
defines the
formatter call. You should modify them to something that suits your
project. For the rules that you can select (and ignore) have a look at the
Ruff tutorial and available linting
rules.
If you do not add rules directly to lazy-ruff-check-command
and
lazy-ruff-format-command
then ruff
will automatically look for a
pyproject.toml
or ruff.toml
in the parent directories of your project,
have a look
here to read
an explanation of how that works.
Here is an example of how you could change the call to ruff check
(the
linter, specifically) using a much more radical
config
including unsafe fixes, a max line length of 79 and preview rules enabled. This
will overrule whatever you have in your ruff.toml
or pyproject.toml
file:
;; More radical settings
(setq lazy-ruff-check-command
(concat "ruff check --fix --unsafe-fixes -s "
"--preview "
"--line-length=79 "
"--select ALL "
"--ignore E266,E402,E731,F403,F405,D100,D104,D401,T203,T201"))
If you don't want to include the ruff
linter when using lazy-ruff
on
code and you're only interested in using the formatter, then you can simply
update the following variables:
(setq lazy-ruff-only-format-block t) ;; Don't lint in code blocks
(setq lazy-ruff-only-format-region t) ;; Don't lint in marked regions
(setq lazy-ruff-only-format-buffer t) ;; Don't lint in Python major mode buffers
We can also add these changes immediately when calling use-package
with the
:config
directive:
(use-package lazy-ruff
:config
(setq lazy-ruff-only-format-block t) ;; Don't lint in code blocks
(setq lazy-ruff-only-format-region t) ;; Don't lint in marked regions
(setq lazy-ruff-only-format-buffer t)) ;; Don't lint in Python major mode buffers