diff --git a/modules/lang/python/autoload/python.el b/modules/lang/python/autoload/python.el index ecca5a796..827bc9cbc 100644 --- a/modules/lang/python/autoload/python.el +++ b/modules/lang/python/autoload/python.el @@ -1,11 +1,18 @@ ;;; lang/python/autoload/python.el -*- lexical-binding: t; -*- +(defvar +python-version-cache (make-hash-table :test 'equal) + "TODO") + ;;;###autoload (defun +python/repl () "Open the Python REPL." (interactive) (process-buffer (run-python nil t t))) +(defun +python--extract-version (prefix str) + (when str + (format "%s%s" prefix (cadr (split-string str " "))))) + ;;;###autoload (defun +python-version () "Return the currently installed version of python on your system or active in @@ -14,18 +21,37 @@ the current pipenv. This is not necessarily aware of env management tools like virtualenv, pyenv or pipenv, unless those tools have modified the PATH that Emacs picked up when you started it." - (let* ((pipenv-dir (pipenv-project-p)) - (default-directory (or pipenv-dir default-directory)) - (command (if pipenv-dir - "pipenv run python --version" - "python --version")) - (bin (car (split-string command " ")))) - (unless (executable-find bin) - (user-error "Couldn't find %s executable in PATH" bin)) - (with-temp-buffer - (let ((p (apply #'call-process bin nil (current-buffer) nil - (cdr (split-string command " " t)))) - (output (string-trim (buffer-string)))) - (unless (zerop p) - (user-error "'%s' failed: %s" command output)) - (cadr (split-string output " " t)))))) + (condition-case _ + (if-let* ((proot (and (fboundp 'pipenv-project-p) + (pipenv-project-p)))) + (let* ((default-directory proot) + (v (car (process-lines "pipenv" "run" "python" "--version")))) + (puthash proot + (+python--extract-version "Pipenv " v) + +python-version-cache)) + (puthash (doom-project-root) + (+python--extract-version "Python " (car (process-lines "python" "--version"))) + +python-version-cache)) + (error "Python"))) + + +;; +;; Hooks + +;;;###autoload +(defun +python|update-version (&rest _) + "Update `+python--version' by consulting `+python-version' function." + (setq +python--version + (or (gethash (or (and (fboundp 'pipenv-project-p) + (pipenv-project-p)) + (doom-project-root)) + +python-version-cache) + (+python-version)))) + +;;;###autoload +(defun +python|update-version-in-all-buffers () + "Update `+python-version' in all buffers in `python-mode'." + (dolist (buffer (doom-buffers-in-mode 'python-mode)) + (setq +python-version-cache (clrhash +python-version-cache)) + (with-current-buffer buffer + (+python|update-version)))) diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 40bce909a..1dc367b46 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -1,10 +1,9 @@ ;;; lang/python/config.el -*- lexical-binding: t; -*- -(defvar +python-mode-line-indicator - '("Python" (+python-version (" " +python-version))) +(defconst +python-mode-line-indicator '("" +python--version) "Format for the python version/env indicator in the mode-line.") -(defvar-local +python-version nil +(defvar-local +python--version nil "The python version in the current buffer.") @@ -64,9 +63,6 @@ (setq mode-name +python-mode-line-indicator)) (add-hook 'python-mode-hook #'+python|adjust-mode-line) - (defun +python|update-version (&rest _) - (setq +python-version (+python-version))) - (+python|update-version) (add-hook 'python-mode-hook #'+python|update-version)) @@ -135,8 +131,8 @@ :hook (python-mode . pipenv-mode) :init (setq pipenv-with-projectile nil) :config - (advice-add #'pipenv-activate :after-while #'+python|update-version) - (advice-add #'pipenv-deactivate :after-while #'+python|update-version)) + (advice-add #'pipenv-activate :after-while #'+python|update-version-in-all-buffers) + (advice-add #'pipenv-deactivate :after-while #'+python|update-version-in-all-buffers)) (def-package! pyenv-mode @@ -144,11 +140,10 @@ :after python :config (pyenv-mode +1) - (advice-add #'pyenv-mode-set :after #'+python|update-version) - (advice-add #'pyenv-mode-unset :after #'+python|update-version) - (add-to-list '+python-mode-line-indicator - '(:eval (if (pyenv-mode-version) (concat " pyenv:" (pyenv-mode-version)))) - 'append)) + (when (executable-find "pyenv") + (add-to-list 'exec-path (expand-file-name "shims" (or (getenv "PYENV_ROOT") "~/.pyenv")))) + (advice-add #'pyenv-mode-set :after #'+python|update-version-in-all-buffers) + (advice-add #'pyenv-mode-unset :after #'+python|update-version-in-all-buffers)) (def-package! pyvenv @@ -156,8 +151,8 @@ :after python :config (defun +python-current-pyvenv () pyvenv-virtual-env-name) - (add-hook 'pyvenv-post-activate-hooks #'+python|update-version) - (add-hook 'pyvenv-post-deactivate-hooks #'+python|update-version) + (add-hook 'pyvenv-post-activate-hooks #'+python|update-version-in-all-buffers) + (add-hook 'pyvenv-post-deactivate-hooks #'+python|update-version-in-all-buffers) (add-to-list '+python-mode-line-indicator '(pyvenv-virtual-env-name (" venv:" pyvenv-virtual-env-name)) 'append)) @@ -192,8 +187,8 @@ (conda-env-initialize-interactive-shells) (after! eshell (conda-env-initialize-eshell)) - (add-hook 'conda-postactivate-hook #'+python|update-version) - (add-hook 'conda-postdeactivate-hook #'+python|update-version) + (add-hook 'conda-postactivate-hook #'+python|update-version-in-all-buffers) + (add-hook 'conda-postdeactivate-hook #'+python|update-version-in-all-buffers) (add-to-list '+python-mode-line-indicator '(conda-env-current-name (" conda:" conda-env-current-name)) 'append))