| @@ -963,6 +963,9 @@ found, otherwise returns nil." | |||||
| ) | ) | ||||
| (set-variable 'flycheck-python-pycompile-executable "python3") | (set-variable 'flycheck-python-pycompile-executable "python3") | ||||
| (set-variable 'python-indent-guess-indent-offset nil) | (set-variable 'python-indent-guess-indent-offset nil) | ||||
| (with-eval-after-load 'blacken | |||||
| (with-venv-advice-add 'blacken-call-bin)) | |||||
| ;; http://fukuyama.co/foreign-regexp | ;; http://fukuyama.co/foreign-regexp | ||||
| '(and (safe-require-or-eval 'foreign-regexp) | '(and (safe-require-or-eval 'foreign-regexp) | ||||
| @@ -2012,134 +2015,6 @@ initializing." | |||||
| (tabulated-list-init-header) | (tabulated-list-init-header) | ||||
| (tabulated-list-print nil nil)) | (tabulated-list-print nil nil)) | ||||
| ;;;;;;;;;;;;;;;;;;;;;;; | |||||
| ;; with-venv | |||||
| (defvar-local with-venv-venv-dir | |||||
| nil | |||||
| "Venv directory path. | |||||
| This variable is intended to be explicitly set by user. | |||||
| When nil, `with-venv' tries to find suitable venv dir. | |||||
| When this variable is set , use this value without checking if it is a valid | |||||
| python environment.") | |||||
| (defmacro with-venv-dir (dir &rest body) | |||||
| "Set python environment to DIR and execute BODY. | |||||
| This macro does not check if DIR is a valid python environemnt. | |||||
| If dir is nil, execute BODY as usual." | |||||
| `(let ((--with-venv-process-environment-orig (cl-copy-list process-environment)) | |||||
| (--with-venv-exec-path-orig (cl-copy-list exec-path))) | |||||
| (unwind-protect | |||||
| (progn | |||||
| (when ,dir | |||||
| (let* ((dir (file-name-as-directory ,dir)) | |||||
| (bin (expand-file-name "bin" dir))) | |||||
| ;; Do the same thing that bin/activate does | |||||
| (setq exec-path | |||||
| (cons bin | |||||
| exec-path)) | |||||
| (setenv "VIRTUAL_ENV" dir) | |||||
| (setenv "PATH" (concat bin ":" (or (getenv "PATH") ""))) | |||||
| (setenv "PYTHONHOME"))) | |||||
| ,@body) | |||||
| (setq process-environment | |||||
| --with-venv-process-environment-orig) | |||||
| (setq exec-path | |||||
| --with-venv-exec-path-orig)))) | |||||
| (defvar-local with-venv-previously-used nil | |||||
| "Previously used venv dir path.") | |||||
| (defmacro with-venv (&rest body) | |||||
| "Execute BODY with venv enabled. | |||||
| This function tries to find suitable venv dir, or run BODY as usual when no | |||||
| suitable environment was found." | |||||
| `(with-venv-dir | |||||
| ;; If set explicitly use it | |||||
| (or with-venv-venv-dir | |||||
| ;; Check previously used directory | |||||
| (with-venv-check-exists with-venv-previously-used) | |||||
| (setq with-venv-previously-used (with-venv-find-venv-dir))) | |||||
| ,@body)) | |||||
| (defun with-venv-find-venv-dir (&optional dir) | |||||
| "Try to find venv dir for DIR. | |||||
| If none found return nil." | |||||
| (with-temp-buffer | |||||
| (when dir | |||||
| (cd dir)) | |||||
| (or | |||||
| ;; Check pipenv | |||||
| (with-venv-check-exists (with-venv--find-venv-dir-pipenv)) | |||||
| ;; Check poetry | |||||
| (with-venv-check-exists (with-venv--find-venv-dir-poetry)) | |||||
| ;; Search for .venv dir | |||||
| (with-venv-check-exists (with-venv--find-venv-dir-by-name))))) | |||||
| (defun with-venv--find-venv-dir-pipenv () | |||||
| "Try to find venv dir via pipenv." | |||||
| (with-temp-buffer | |||||
| (let ((status (call-process "pipenv" nil t nil "--venv"))) | |||||
| (when (eq status 0) | |||||
| (goto-char (point-min)) | |||||
| (buffer-substring-no-properties (point-at-bol) | |||||
| (point-at-eol)))))) | |||||
| (defun with-venv--find-venv-dir-poetry () | |||||
| "Try to find venv dir via poetry." | |||||
| (with-temp-buffer | |||||
| ;; TODO: Use poetry env info --path | |||||
| (let ((status (call-process "poetry" nil t nil "debug:info"))) | |||||
| (when (eq status 0) | |||||
| (goto-char (point-min)) | |||||
| (save-match-data | |||||
| (when (re-search-forward "^ \\* Path: *\\(.*\\)$") | |||||
| (match-string 1))))))) | |||||
| (defun with-venv--find-venv-dir-by-name () | |||||
| "Try to find venv dir by its name." | |||||
| (let ((dir (locate-dominating-file default-directory | |||||
| ".venv"))) | |||||
| (when dir | |||||
| ;; TODO: check with -check-exists | |||||
| (expand-file-name ".venv" | |||||
| dir)))) | |||||
| (defun with-venv-check-exists (dir) | |||||
| "Return DIR as is if \"bin\" directory was found under DIR." | |||||
| (and dir | |||||
| (file-directory-p (expand-file-name "bin" | |||||
| dir)) | |||||
| dir)) | |||||
| (defun with-venv-advice-add (func) | |||||
| "Setup advice so that FUNC uses `with-env' macro when executing." | |||||
| (advice-add func | |||||
| :around | |||||
| 'with-venv--advice-around)) | |||||
| (defun with-venv-advice-remove (func) | |||||
| "Remove advice added by `with-venv-advice-add'." | |||||
| (advice-remove func | |||||
| 'with-venv--advice-around)) | |||||
| (defun with-venv--advice-around (orig-func &rest args) | |||||
| "Function to be used to advice functions with `with-venv-advice-add'. | |||||
| When a function is adviced with this function, it is wrapped with `with-venv'." | |||||
| (with-venv | |||||
| (apply orig-func args))) | |||||
| (with-eval-after-load 'blacken | |||||
| (with-venv-advice-add 'blacken-call-bin)) | |||||
| ;; (with-venv (:dir default-directory) (message "a")) | |||||
| ;; (with-venv () (message "a")) | |||||
| ;; Local Variables: | ;; Local Variables: | ||||
| ;; flycheck-disabled-checkers: (emacs-lisp-checkdoc) | ;; flycheck-disabled-checkers: (emacs-lisp-checkdoc) | ||||
| ;; flycheck-checker: emacs-lisp | ;; flycheck-checker: emacs-lisp | ||||