Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions flymake-ruff.el
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@

(defvar flymake-ruff--output-regex "\\(.*\\):\\([0-9]+\\):\\([0-9]+\\): \\([A-Za-z0-9-]+\\):? \\(.*\\)")

(defvar flymake-ruff--no-config-tramp-dirs
nil
"List of TRAMP directories that ruff checked for config in but found none. This prevents repeatedly looking for config files that do not exist.")

(defconst flymake-ruff--default-configs
'(".ruff.toml" "ruff.toml" "pyproject.toml")
"Default configuration files supported by Ruff.")
Expand All @@ -57,6 +61,46 @@
("PERF" . :warning)) ; Performance issues
"Mapping of Ruff diagnostic code prefixes to Flymake severities.")

(defun flymake-ruff--get-config ()
"Look for configuration files supported by Ruff in project root.
When project is on remote host, cache config using `default-directory' as key."
(if (tramp-handle-file-remote-p (or buffer-file-name
default-directory))
(when (not (seq-contains-p flymake-ruff--no-config-tramp-dirs default-directory #'string-equal))
(let ((cache-dir (expand-file-name
(concat "ruff-config-" (sha1 default-directory))
"/tmp")))
(if (file-directory-p cache-dir)
;; Return cached config if exists
(seq-find #'file-readable-p
(mapcar (lambda (f)
(expand-file-name f cache-dir))
flymake-ruff--default-configs))
;; Create cache and return config path
(if-let* ((project-current (project-current))
(config (seq-find
#'tramp-handle-file-readable-p
(mapcar (lambda (f)
(tramp-handle-expand-file-name f (project-root project-current)))
flymake-ruff--default-configs)))
(temp-file (tramp-handle-expand-file-name (tramp-handle-file-name-nondirectory config) cache-dir))
(temp-copy (tramp-handle-file-local-copy config)))
(progn
(make-directory cache-dir)
(copy-file temp-copy temp-file t)
(delete-file temp-copy)
temp-file)
(progn
(push default-directory flymake-ruff--no-config-tramp-dirs)
nil)))))

;; Local project path
(when-let ((project-current (project-current)))
(seq-find #'file-readable-p
(mapcar (lambda (f)
(expand-file-name f (project-root project-current)))
flymake-ruff--default-configs)))))

(defun flymake-ruff--severity-for-code (code)
"Return Flymake severity for Ruff CODE."
(let ((matched-prefix (seq-find (lambda (pfx)
Expand All @@ -82,14 +126,8 @@
;; check if the current buffer belongs to a project before
;; trying to build a path using `project-current' otherwise it
;; will fail silently
(let* ((config (and (project-current)
(seq-find
#'file-readable-p
(mapcar
(lambda (f)
(expand-file-name f (project-root (project-current))))
flymake-ruff--default-configs))))
(args (if config
(let* ((config (flymake-ruff--get-config))
(args (if config
;; for version > 0.5 the work "check" is
;; included so we need to extract it and put it
;; before --config argument
Expand Down Expand Up @@ -130,6 +168,14 @@
"Load hook for the current buffer to tell flymake to run checker."
(interactive)
(when (derived-mode-p 'python-mode 'python-ts-mode)
;; If cached TRAMP config file exists for current buffer, remove it so that cache can be refreshed on reverting buffer.
(when-let* ((_remote (file-remote-p default-directory))
(cache-dir (expand-file-name
(concat "ruff-config-" (sha1 default-directory))
"/tmp"))
(_cache_exist (file-directory-p cache-dir)))
(delete-directory cache-dir t))

(add-hook 'flymake-diagnostic-functions #'flymake-ruff--run-checker nil t)))

(defun flymake-ruff--run-checker (report-fn &rest _args)
Expand Down