diff --git a/.gitignore b/.gitignore index 3784151..de9df85 100644 --- a/.gitignore +++ b/.gitignore @@ -12,11 +12,11 @@ *.lot *.out *.pdf -*.py *.run.xml *.tex *.toc +example.py latexmkrc org-store-link setup-include.org diff --git a/README.org b/README.org index 7ef9ad4..455a4fd 100644 --- a/README.org +++ b/README.org @@ -1695,31 +1695,52 @@ Listing [[lst:enable-pyenv-mode]] configures and enables =pyenv-mode=. :CUSTOM_ID: sec:eglot :END: -Listing [[lst:configure-eglot-for-python]] configures [[https://github.com/joaotavora/eglot][eglot]] with [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] -for [[https://www.python.org][Python]]. It defines a hook function to launch [[https://github.com/joaotavora/eglot][eglot]] when it sees a proper -[[info:emacs#Directory - Variables][.dir-locals.el]] file in the root directory of any [[https://www.python.org][Python]] project. Listing -[[lst:eglot-directory-variables-for-python]] shows such a proper [[info:emacs#Directory Variables][.dir-locals.el]] -file. +Listing [[lst:configure-eglot+python-lsp-server-for-python]] (tangles to +=user-init-file=) and [[lst:configure-eglot+jedi-language-server-for-python]] (does +not tangle to =user-init-file=) configure [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] using either the +[[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] or experimentally the [[https://github.com/pappasam/jedi-language-server][jedi-language-server]]. Listing +[[lst:on-hack-local-variables-hook-eglot-maybe]] defines a hook function to launch +[[https://github.com/joaotavora/eglot][eglot]] in presence of a proper [[info:emacs#Directory Variables][.dir-locals.el]] file in the root directory of any +[[https://www.python.org][Python]] project. Listing [[lst:eglot-directory-variables-for-python]] shows such a +proper [[info:emacs#Directory Variables][.dir-locals.el]] file. -#+caption[Configure =eglot= for Python]: -#+caption: Configure =eglot= for Python. -#+name: lst:configure-eglot-for-python +#+caption[Configure =eglot= with =python-lsp-server= for Python]: +#+caption: Configure =eglot= with =python-lsp-server= for Python. +#+name: lst:configure-eglot+python-lsp-server-for-python #+begin_src emacs-lisp (with-eval-after-load 'eglot + ;; (setq eglot-server-programs '((python-mode "pylsp"))) (add-to-list 'eglot-server-programs '(python-mode "pylsp")) (setq-default eglot-workspace-configuration - '((:pylsp . (:plugins (:jedi - (:auto_import_modules ["numpy" "scipy"])))) - (:pylsp . (:plugins (:jedi_completion - (:cache_for ["astropy"])))) - (:pylsp . (:plugins (:jedi_completion (:eager t))))))) + '((:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))) + (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"])))) + (:pylsp . (:configurationSources ["flake8"]))))) +#+end_src +#+caption[Configure =eglot= with =jedi-language-server= for Python]: +#+caption: Configure =eglot= with =jedi-langage-server= for Python. +#+name: lst:configure-eglot+jedi-language-server-for-python +#+begin_src emacs-lisp :tangle no + (with-eval-after-load 'eglot + ;; (setq eglot-server-programs '((python-mode "jedi-language-server"))) + (add-to-list 'eglot-server-programs '(python-mode "jedi-language-server")) + + (setq-default + eglot-workspace-configuration + '((:jedi-language-server + . (:plugins (:jedi (:jediSettings (:autoImportModules ["numpy"])))))))) +#+end_src + +#+caption[Start =eglot= in case of a proper =dir-local-variables-alist=]: +#+caption: Start =eglot= in case of a proper =dir-local-variables-alist=. +#+name: lst:on-hack-local-variables-hook-eglot-maybe +#+begin_src emacs-lisp (when (fboundp 'eglot-ensure) ;; The two hooks `after-change-major-mode-hook' and - ;; `hack-local-variables-hook' are OK, but `-mode-hook' is not. + ;; `hack-local-variables-hook' are OK, but language mode hooks like + ;; `python-mode-hook' are not. (add-hook 'hack-local-variables-hook (defun on-hack-local-variables-hook-eglot-maybe () (when (and (derived-mode-p 'python-mode) @@ -1736,17 +1757,24 @@ file. ;; Proposal for a .dir-locals.el file in the root of any Python project. ((python-mode . ((eglot-workspace-configuration - . ((:pylsp . (:plugins (:jedi - (:auto_import_modules ["numpy" "scipy"])))) - (:pylsp . (:plugins (:jedi_completion - (:cache_for ["astropy"])))) - (:pylsp . (:plugins (:jedi_completion (:eager nil))))))))) + . ((:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"])))) + (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))) + (:pylsp . (:configurationSources ["flake8"]))))))) #+end_src +Here are a few links covering how to integrate Emacs, Python and a Python LSP +server: +1. [[https://taingram.org/blog/emacs-lsp-ide.html][Building Your Own Emacs IDE with LSP]] +2. [[https://rgoswami.me/posts/emacs-lang-servers/][Doom Emacs and Language Servers]] +3. [[https://ddavis.io/posts/eglot-python-ide/][Eglot based Emacs Python IDE]] +4. [[https://www.mattduck.com/lsp-python-getting-started.html][Getting started with lsp-mode for Python]] +5. [[https://ddavis.io/posts/python-emacs-3/][Python & Emacs, Take 3]] +6. [[https://ddavis.io/posts/emacs-python-lsp/][Python with Emacs: py(v)env and lsp-mode]] + [[https://jedi.readthedocs.io/en/latest/][Jedi]] provides grammar checking and completion candidates to [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. -Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.21.5]] in the sense that it +Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.22.0]] in the sense that it handles builtins and universal functions provided that [[https://jedi.readthedocs.io/en/latest/][jedi]] does not parse but -imports [[https://numpy.org/][numpy-1.21.5]] (see [[https://github.com/davidhalter/jedi/issues/1744][jedi issue #1744]], [[https://github.com/davidhalter/jedi/issues/1745][#1745]], and [[https://github.com/davidhalter/jedi/issues/1746][#1746]]). +imports [[https://numpy.org/][numpy-1.22.0]] (see [[https://github.com/davidhalter/jedi/issues/1744][jedi issue #1744]], [[https://github.com/davidhalter/jedi/issues/1745][#1745]], and [[https://github.com/davidhalter/jedi/issues/1746][#1746]]). #+header: :wrap "src diff :exports code :tangle pylsp-auto-import-modules.patch" #+begin_src shell :exports both :results org @@ -1756,7 +1784,7 @@ imports [[https://numpy.org/][numpy-1.21.5]] (see [[https://github.com/davidhalt #+RESULTS: #+begin_src diff :exports code :tangle pylsp-auto-import-modules.patch diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json -index c29d78b..f54b67a 100644 +index c29d78b..4f30101 100644 --- a/pylsp/config/schema.json +++ b/pylsp/config/schema.json @@ -69,6 +69,14 @@ @@ -1765,7 +1793,7 @@ index c29d78b..f54b67a 100644 }, + "pylsp.plugins.jedi.auto_import_modules": { + "type": "array", -+ "default": ["numpy", "scipy", "gi"], ++ "default": ["numpy", "gi"], + "items": { + "type": "string" + }, @@ -1775,14 +1803,14 @@ index c29d78b..f54b67a 100644 "type": "array", "default": [], diff --git a/pylsp/workspace.py b/pylsp/workspace.py -index bf312f6..49e967a 100644 +index bf312f6..4758b53 100644 --- a/pylsp/workspace.py +++ b/pylsp/workspace.py @@ -14,6 +14,8 @@ from . import lsp, uris, _utils log = logging.getLogger(__name__) -+DEFAULT_AUTO_IMPORT_MODULES = ["numpy", "scipy", "gi"] ++DEFAULT_AUTO_IMPORT_MODULES = ["numpy", "gi"] + # TODO: this is not the best e.g. we capture numbers RE_START_WORD = re.compile('[A-Za-z_0-9]*$') @@ -1803,13 +1831,16 @@ index bf312f6..49e967a 100644 :CUSTOM_ID: sec:anaconda :END: -Listing [[lst:configure-anaconda-for-python]] configures [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]]. See -[[https://github.com/jorgenschaefer/elpy/blob/8d0de310d41ebf06b22321a8534546447456870c/elpy.el#L2775][elpy-module-company]] for how to handle ~company-backends~ as a local variable and -the call to [[info:elisp#Advising Functions][advice-add]] opens Python org-mode edit-buffers in ~anaconda-mode~. +Listing [[lst:configure-anaconda+company-for-python]] and +[[lst:define-my-toggle-anaconda-mode]] configure [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]]. See [[https://github.com/jorgenschaefer/elpy/blob/8d0de310d41ebf06b22321a8534546447456870c/elpy.el#L2775][elpy-module-company]] +for how to handle ~company-backends~ as a local variable in listing +[[lst:configure-anaconda+company-for-python]]. The call to [[info:elisp#Advising Functions][advice-add]] in listing +[[lst:define-my-toggle-anaconda-mode]] opens Python =org-edit-src-code= buffers in +~anaconda-mode~. -#+caption[Configure =anaconda= for Python]: -#+caption: Configure =anaconda= for Python. -#+name: lst:configure-anaconda-for-python +#+caption[Configure =anaconda= with =company= for Python]: +#+caption: Configure =anaconda= with =company= for Python. +#+name: lst:configure-anaconda+company-for-python #+begin_src emacs-lisp (with-eval-after-load 'python (with-eval-after-load 'company @@ -1833,8 +1864,14 @@ the call to [[info:elisp#Advising Functions][advice-add]] opens Python org-mode (delq 'company-capf (mapcar #'identity company-backends))))) (anaconda-eldoc-mode - (if (file-remote-p default-directory) -1 1)))))) + (if (file-remote-p default-directory) -1 1))))))) +#+end_src +#+caption[Define =my-toggle-anaconda-mode= for Python]: +#+caption: Define =my-toggle-anaconda-mode= for Python. +#+name: lst:define-my-toggle-anaconda-mode +#+begin_src emacs-lisp + (with-eval-after-load 'python (unless (and (fboundp 'my-disable-anaconda-mode) (fboundp 'my-enable-anaconda-mode)) (when (fboundp 'anaconda-mode) diff --git a/pylsp-auto-import-modules.patch b/pylsp-auto-import-modules.patch index 8978682..e9c1cee 100644 --- a/pylsp-auto-import-modules.patch +++ b/pylsp-auto-import-modules.patch @@ -1,5 +1,5 @@ diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json -index c29d78b..f54b67a 100644 +index c29d78b..4f30101 100644 --- a/pylsp/config/schema.json +++ b/pylsp/config/schema.json @@ -69,6 +69,14 @@ @@ -8,7 +8,7 @@ index c29d78b..f54b67a 100644 }, + "pylsp.plugins.jedi.auto_import_modules": { + "type": "array", -+ "default": ["numpy", "scipy", "gi"], ++ "default": ["numpy", "gi"], + "items": { + "type": "string" + }, @@ -18,14 +18,14 @@ index c29d78b..f54b67a 100644 "type": "array", "default": [], diff --git a/pylsp/workspace.py b/pylsp/workspace.py -index bf312f6..49e967a 100644 +index bf312f6..4758b53 100644 --- a/pylsp/workspace.py +++ b/pylsp/workspace.py @@ -14,6 +14,8 @@ from . import lsp, uris, _utils log = logging.getLogger(__name__) -+DEFAULT_AUTO_IMPORT_MODULES = ["numpy", "scipy", "gi"] ++DEFAULT_AUTO_IMPORT_MODULES = ["numpy", "gi"] + # TODO: this is not the best e.g. we capture numbers RE_START_WORD = re.compile('[A-Za-z_0-9]*$')