mirror of
https://github.com/fscotto/infra.git
synced 2026-07-29 16:20:01 +00:00
110 lines
4.3 KiB
EmacsLisp
110 lines
4.3 KiB
EmacsLisp
;;; python.el -*- lexical-binding: t; -*-
|
|
|
|
(require 'reformatter)
|
|
|
|
(with-eval-after-load 'project
|
|
(add-to-list 'project-vc-extra-root-markers "pyproject.toml")
|
|
(add-to-list 'project-vc-extra-root-markers "uv.lock")
|
|
(add-to-list 'project-vc-extra-root-markers ".venv"))
|
|
|
|
(defun fscotto/python-project-root ()
|
|
"Return project root for Python projects, nil otherwise."
|
|
(when (and (featurep 'project)
|
|
(project-current))
|
|
(let ((root (project-root (project-current))))
|
|
(when (or (file-exists-p (expand-file-name "pyproject.toml" root))
|
|
(file-exists-p (expand-file-name "uv.lock" root)))
|
|
root))))
|
|
|
|
(defun fscotto/python-project-has-uv-p ()
|
|
"Return t if current project uses uv (pyproject.toml or uv.lock)."
|
|
(when-let ((root (fscotto/python-project-root)))
|
|
(or (file-exists-p (expand-file-name "uv.lock" root))
|
|
(file-exists-p (expand-file-name "pyproject.toml" root)))))
|
|
|
|
(defun fscotto/python-project-bin (tool)
|
|
"Return path to TOOL in .venv/bin if it exists, else nil."
|
|
(when-let ((root (fscotto/python-project-root)))
|
|
(let ((venv-bin (expand-file-name (concat ".venv/bin/" tool) root)))
|
|
(when (and (file-exists-p venv-bin)
|
|
(file-executable-p venv-bin))
|
|
venv-bin))))
|
|
|
|
(defun fscotto/python-activate-project-tools ()
|
|
"Prefer tools from the project virtualenv when available."
|
|
(when-let* ((root (fscotto/python-project-root))
|
|
(venv-bin (expand-file-name ".venv/bin" root))
|
|
((file-directory-p venv-bin)))
|
|
(make-local-variable 'exec-path)
|
|
(add-to-list 'exec-path venv-bin)
|
|
(setq-local process-environment (copy-sequence process-environment))
|
|
(setenv "PATH" (concat venv-bin path-separator (getenv "PATH")))))
|
|
|
|
(defun fscotto/resolve-pylsp ()
|
|
"Return the pylsp binary path if found, else nil.
|
|
Checks: project .venv, uv tool install path, and PATH."
|
|
(or (fscotto/python-project-bin "pylsp")
|
|
(let ((uv-pylsp (expand-file-name "pylsp"
|
|
(concat (getenv "HOME")
|
|
"/.local/share/uv/tools/python-lsp-server/bin"))))
|
|
(when (and (file-exists-p uv-pylsp)
|
|
(file-executable-p uv-pylsp))
|
|
uv-pylsp))
|
|
(executable-find "pylsp")))
|
|
|
|
(defun fscotto/python-lsp-server-available-p ()
|
|
"Return non-nil when a supported Python LSP server is available."
|
|
(fscotto/resolve-pylsp))
|
|
|
|
(defun fscotto/python-ensure-lsp-server ()
|
|
"Start Python LSP when its Ansible-managed pylsp executable is available."
|
|
(cond
|
|
((not (fboundp 'lsp-deferred))
|
|
(message "python: lsp-mode not available"))
|
|
((fscotto/python-lsp-server-available-p)
|
|
(setq lsp-pylsp-server-command (fscotto/resolve-pylsp))
|
|
(lsp-deferred))
|
|
(t
|
|
(message "python: pylsp not found; run the desktop Ansible profile"))))
|
|
|
|
(defun fscotto/python-maybe-start-lsp ()
|
|
"Start Python LSP when pylsp is available."
|
|
(fscotto/python-ensure-lsp-server))
|
|
|
|
(defun fscotto/python-setup-check-command ()
|
|
"Use Ruff for the built-in Python check command."
|
|
(setq-local python-check-command "ruff check"))
|
|
|
|
(reformatter-define fscotto/ruff-format
|
|
:program (or (fscotto/python-project-bin "ruff") (executable-find "ruff"))
|
|
:args '("format" "-")
|
|
:lighter " ruff")
|
|
|
|
(with-eval-after-load 'python
|
|
(add-hook 'python-mode-hook #'fscotto/python-activate-project-tools)
|
|
(add-hook 'python-mode-hook #'fscotto/python-setup-check-command)
|
|
(add-hook 'python-mode-hook #'fscotto/ruff-format-on-save-mode)
|
|
(add-hook 'python-mode-hook #'fscotto/python-maybe-start-lsp))
|
|
|
|
(with-eval-after-load 'python-ts-mode
|
|
(add-hook 'python-ts-mode-hook #'fscotto/python-activate-project-tools)
|
|
(add-hook 'python-ts-mode-hook #'fscotto/python-setup-check-command)
|
|
(add-hook 'python-ts-mode-hook #'fscotto/ruff-format-on-save-mode)
|
|
(add-hook 'python-ts-mode-hook #'fscotto/python-maybe-start-lsp))
|
|
|
|
(with-eval-after-load 'lsp-mode
|
|
(add-to-list 'lsp-language-id-configuration '(python-mode . "python"))
|
|
(add-to-list 'lsp-language-id-configuration '(python-ts-mode . "python"))
|
|
(setq lsp-pylsp-server-command (fscotto/resolve-pylsp))
|
|
(setq lsp-pylsp-plugins
|
|
'((pycodestyle nil)
|
|
(pyflakes nil)
|
|
(mccabe nil)
|
|
(autopep8 nil)
|
|
(yapf nil)))
|
|
(add-to-list 'lsp-disabled-clients 'pyls))
|
|
|
|
(provide 'lang/python)
|
|
|
|
;;; python.el ends here
|