Improve sections on Org and Python
* Add patch for python-lsp-server. * Swap order of sections on programming and editing.
This commit is contained in:
parent
ae2c0fd48e
commit
8ba219f045
482
README.org
482
README.org
@ -956,6 +956,7 @@ The code in listing [[lst:customize-org-babel]], [[lst:customize-org]], and
|
|||||||
'(org-latex-listings 'minted)
|
'(org-latex-listings 'minted)
|
||||||
'(org-latex-minted-langs '((cc "c++")
|
'(org-latex-minted-langs '((cc "c++")
|
||||||
(cperl "perl")
|
(cperl "perl")
|
||||||
|
(diff "diff")
|
||||||
(shell-script "bash")
|
(shell-script "bash")
|
||||||
(caml "ocaml")
|
(caml "ocaml")
|
||||||
(org "latex")))
|
(org "latex")))
|
||||||
@ -1273,25 +1274,45 @@ blocks) do not work in [[info:org#Export Settings][#+SETUPFILE: <FILE>]], but on
|
|||||||
:CUSTOM_ID: sec:setupfile+include-usage
|
:CUSTOM_ID: sec:setupfile+include-usage
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
Listing [[lst:source-file-export-keyword-settings]] shows a copie of the first six
|
Evaluation of the source block in listing
|
||||||
lines of this [[file:README.org]] file. The last two lines shows that the file
|
[[lst:make-source-block-with-export-keyword-settings]] produces the source block
|
||||||
[[file:setup-include]] serves as a [[info:org#Export Settings][#+SETUPFILE:FILE]] file and as a [[info:org#Export Settings][#+INCLUDE: FILE]].
|
that exports to listing [[lst:source-file-export-keyword-settings]] which shows the
|
||||||
|
first six lines of this [[file:README.org]] file. The last two lines show that
|
||||||
|
[[file:setup-include.org][setup-include.org]] is argument for [[info:org#Export Settings][#+SETUPFILE:]] *and* [[info:org#Export Settings][#+INCLUDE:]].
|
||||||
|
|
||||||
|
#+caption[Make setup and include file export keyword settings source block]:
|
||||||
|
#+caption: The shell script to make the source block containing the export
|
||||||
|
#+caption: keyword settings.
|
||||||
|
#+name: lst:make-source-block-with-export-keyword-settings
|
||||||
|
#+begin_src shell :exports both :results drawer
|
||||||
|
echo "#+caption[Source file export keyword settings]:"
|
||||||
|
echo "#+caption: The first six lines of README.org containing the export"
|
||||||
|
echo "#+caption: keyword settings."
|
||||||
|
echo "#+name: lst:source-file-export-keyword-settings"
|
||||||
|
echo "#+begin_src org :tangle no"
|
||||||
|
head -n 6 README.org
|
||||||
|
echo -n "#+end_src"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: lst:make-source-block-with-export-keyword-settings
|
||||||
|
:results:
|
||||||
#+caption[Source file export keyword settings]:
|
#+caption[Source file export keyword settings]:
|
||||||
#+caption: Source file export keyword settings.
|
#+caption: The first six lines of README.org containing the export
|
||||||
|
#+caption: keyword settings.
|
||||||
#+name: lst:source-file-export-keyword-settings
|
#+name: lst:source-file-export-keyword-settings
|
||||||
#+begin_src org :tangle no
|
#+begin_src org :tangle no
|
||||||
,#+title: Emacs setup for use with LaTeX, Org, and Python
|
#+title: Emacs setup for use with LaTeX, Org, and Python
|
||||||
,#+author: Gerard Vermeulen
|
#+author: Gerard Vermeulen
|
||||||
,#+latex_class: article
|
#+latex_class: article
|
||||||
,#+latex_class_options: [11pt,a4paper,english,svgnames,tables]
|
#+latex_class_options: [11pt,a4paper,english,svgnames,tables]
|
||||||
,#+setupfile: "setup-include.org"
|
#+setupfile: "setup-include.org"
|
||||||
,#+include: "setup-include.org"
|
#+include: "setup-include.org"
|
||||||
#+end_src
|
#+end_src
|
||||||
|
:end:
|
||||||
|
|
||||||
Listing [[lst:setup-include-export-keyword-settings]], [[lst:use-latex-header-1]],
|
Listing [[lst:setup-include-export-keyword-settings]], [[lst:use-latex-header-1]],
|
||||||
[[lst:use-latex-header-2]], [[lst:use-latex-header-3]], and [[lst:use-latex-header-4]]
|
[[lst:use-latex-header-2]], [[lst:use-latex-header-3]], and [[lst:use-latex-header-4]]
|
||||||
tangle into the [[file:setup-include]] file.
|
tangle into the [[file:setup-include.org][setup-include.org]] file.
|
||||||
|
|
||||||
#+caption[Setup and include file export keyword settings]:
|
#+caption[Setup and include file export keyword settings]:
|
||||||
#+caption: Setup and include file export keyword settings.
|
#+caption: Setup and include file export keyword settings.
|
||||||
@ -1523,6 +1544,260 @@ Listing [[lst:emacs-lisp-setup-call]] initializes the buffer local variables
|
|||||||
\end{titlepage}
|
\end{titlepage}
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
* Programming
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: sec:programming
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** Emacs-lisp programming
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: sec:emacs-lisp-programming
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** [[https://www.seas.upenn.edu/~chaoliu/2017/09/01/python-programming-in-emacs/][Python programming]]
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: sec:python-coding
|
||||||
|
:END:
|
||||||
|
|
||||||
|
The [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python Programming in Emacs]] wiki page lists options to enhance Emacs's
|
||||||
|
built-in ~python-mode~. Here, the focus is on two packages:
|
||||||
|
1. [[https://github.com/joaotavora/eglot][Eglot - Emacs polyGLOT: an Emacs LSP client that stays out of your way]]. The
|
||||||
|
maintainer also contributes to Emacs itself and has a deep understanding of
|
||||||
|
[[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]]. He refuses to add new features without seeing how they fit
|
||||||
|
into [[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]] as this discussion on [[https://github.com/joaotavora/eglot/issues/523][org-mode source code blocks]]
|
||||||
|
shows.
|
||||||
|
2. [[https://github.com/pythonic-emacs/anaconda-mode][Anaconda - code navigation, documentation lookup, and completion for Python]].
|
||||||
|
In my opinion, [[https://github.com/joaotavora/eglot][eglot]] has more potential than [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]], but [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] is
|
||||||
|
compatible with [[info:org#Editing Source Code][source code block editing]] while [[https://github.com/joaotavora/eglot][eglot]] is not. Listing
|
||||||
|
[[lst:configure-python]] configures [[https://www.python.org][Python]].
|
||||||
|
|
||||||
|
*** [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][Python-mode]]
|
||||||
|
|
||||||
|
#+caption[Configure =python=]:
|
||||||
|
#+caption: Configure =python=.
|
||||||
|
#+name: lst:configure-python
|
||||||
|
#+begin_src elisp
|
||||||
|
(with-eval-after-load 'python
|
||||||
|
(custom-set-variables
|
||||||
|
'(python-indent-guess-indent-offset nil)
|
||||||
|
'(python-shell-interpreter-args "-i -E")))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** [[https://github.com/joaotavora/eglot][Eglot]]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
#+caption[Configure =eglot= for Python]:
|
||||||
|
#+caption: Configure =eglot= for Python.
|
||||||
|
#+name: lst:configure-eglot-for-python
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(with-eval-after-load 'eglot
|
||||||
|
(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)))))))
|
||||||
|
|
||||||
|
(when (fboundp 'eglot-ensure)
|
||||||
|
;; The two hooks `after-change-major-mode-hook' and
|
||||||
|
;; `hack-local-variables-hook' are OK, but `<ANY>-mode-hook' is not.
|
||||||
|
(add-hook 'hack-local-variables-hook
|
||||||
|
(defun on-hack-local-variables-hook-eglot-maybe ()
|
||||||
|
(when (and (derived-mode-p 'python-mode)
|
||||||
|
(assoc 'eglot-workspace-configuration
|
||||||
|
dir-local-variables-alist))
|
||||||
|
(eglot-ensure)))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+caption[Propose =directory-variables= to launch =eglot=]:
|
||||||
|
#+caption: Propose =directory-variables= in the root of any Python project to
|
||||||
|
#+caption: launch =eglot=.
|
||||||
|
#+name: lst:eglot-directory-variables-for-python
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
;; 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)))))))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
[[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
|
||||||
|
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]]).
|
||||||
|
|
||||||
|
#+header: :wrap "src diff :exports code :tangle pylsp-auto-import-modules.patch"
|
||||||
|
#+begin_src shell :exports both :results org
|
||||||
|
git -C $HOME/VCS/python-lsp-server diff
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+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
|
||||||
|
--- a/pylsp/config/schema.json
|
||||||
|
+++ b/pylsp/config/schema.json
|
||||||
|
@@ -69,6 +69,14 @@
|
||||||
|
"default": null,
|
||||||
|
"description": "List of errors and warnings to enable."
|
||||||
|
},
|
||||||
|
+ "pylsp.plugins.jedi.auto_import_modules": {
|
||||||
|
+ "type": "array",
|
||||||
|
+ "default": ["numpy", "scipy", "gi"],
|
||||||
|
+ "items": {
|
||||||
|
+ "type": "string"
|
||||||
|
+ },
|
||||||
|
+ "description": "List of module names for jedi to import (jedi.settings.auto_import_modules)."
|
||||||
|
+ },
|
||||||
|
"pylsp.plugins.jedi.extra_paths": {
|
||||||
|
"type": "array",
|
||||||
|
"default": [],
|
||||||
|
diff --git a/pylsp/workspace.py b/pylsp/workspace.py
|
||||||
|
index bf312f6..49e967a 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"]
|
||||||
|
+
|
||||||
|
# TODO: this is not the best e.g. we capture numbers
|
||||||
|
RE_START_WORD = re.compile('[A-Za-z_0-9]*$')
|
||||||
|
RE_END_WORD = re.compile('^[A-Za-z_0-9]*')
|
||||||
|
@@ -252,6 +254,8 @@ class Document:
|
||||||
|
|
||||||
|
if self._config:
|
||||||
|
jedi_settings = self._config.plugin_settings('jedi', document_path=self.path)
|
||||||
|
+ jedi.settings.auto_import_modules = jedi_settings.get('auto_import_modules',
|
||||||
|
+ DEFAULT_AUTO_IMPORT_MODULES)
|
||||||
|
environment_path = jedi_settings.get('environment')
|
||||||
|
extra_paths = jedi_settings.get('extra_paths') or []
|
||||||
|
env_vars = jedi_settings.get('env_vars')
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** [[https://github.com/pythonic-emacs/anaconda-mode][Anaconda]]
|
||||||
|
|
||||||
|
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~.
|
||||||
|
|
||||||
|
#+caption[Configure =anaconda= for Python]:
|
||||||
|
#+caption: Configure =anaconda= for Python.
|
||||||
|
#+name: lst:configure-anaconda-for-python
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(with-eval-after-load 'python
|
||||||
|
(with-eval-after-load 'company
|
||||||
|
(when (and (fboundp 'anaconda-mode)
|
||||||
|
(fboundp 'company-anaconda))
|
||||||
|
(defun my-disable-anaconda-mode ()
|
||||||
|
(when (derived-mode-p 'python-mode)
|
||||||
|
(anaconda-mode -1)
|
||||||
|
(make-variable-buffer-local 'company-backends)
|
||||||
|
(setq company-backends
|
||||||
|
(delq 'company-anaconda
|
||||||
|
(mapcar #'identity company-backends)))
|
||||||
|
(anaconda-eldoc-mode -1)))
|
||||||
|
(defun my-enable-anaconda-mode ()
|
||||||
|
(when (derived-mode-p 'python-mode)
|
||||||
|
(anaconda-mode +1)
|
||||||
|
(make-variable-buffer-local 'company-backends)
|
||||||
|
(setq company-backends
|
||||||
|
(cons 'company-anaconda
|
||||||
|
(delq 'company-semantic
|
||||||
|
(delq 'company-capf
|
||||||
|
(mapcar #'identity company-backends)))))
|
||||||
|
(anaconda-eldoc-mode
|
||||||
|
(if (file-remote-p default-directory) -1 1))))))
|
||||||
|
|
||||||
|
(unless (and (fboundp 'my-disable-anaconda-mode)
|
||||||
|
(fboundp 'my-enable-anaconda-mode))
|
||||||
|
(when (fboundp 'anaconda-mode)
|
||||||
|
(defun my-disable-anaconda-mode ()
|
||||||
|
(when (derived-mode-p 'python-mode)
|
||||||
|
(anaconda-mode -1)
|
||||||
|
(anaconda-eldoc-mode -1)))
|
||||||
|
(defun my-enable-anaconda-mode ()
|
||||||
|
(when (derived-mode-p 'python-mode)
|
||||||
|
(anaconda-mode +1)
|
||||||
|
(anaconda-eldoc-mode
|
||||||
|
(if (file-remote-p default-directory) -1 1))))))
|
||||||
|
|
||||||
|
(when (fboundp 'my-enable-anaconda-mode)
|
||||||
|
(advice-add 'org-edit-src-code :after #'my-enable-anaconda-mode))
|
||||||
|
(when (and (fboundp 'my-disable-anaconda-mode)
|
||||||
|
(fboundp 'my-enable-anaconda-mode))
|
||||||
|
(defun my-toggle-anaconda-mode ()
|
||||||
|
"Toggle anaconda-mode with bells and whistles."
|
||||||
|
(interactive)
|
||||||
|
(if (bound-and-true-p anaconda-mode)
|
||||||
|
(my-disable-anaconda-mode)
|
||||||
|
(my-enable-anaconda-mode)))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** [[https://jedi.readthedocs.io/en/latest/][Jedi]]
|
||||||
|
|
||||||
|
Listing [[lst:example-py]] is a [[https://www.python.org][Python]] example to test whether [[https://jedi.readthedocs.io/en/latest/][jedi]] in combination
|
||||||
|
with and either [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] or [[https://github.com/joaotavora/eglot][eglot]] works when coding certain functions of for
|
||||||
|
instance [[https://numpy.org/][numpy]] and [[https://scipy.org/][scipy]].
|
||||||
|
|
||||||
|
#+caption[Tangle the =example.py= file]:
|
||||||
|
#+caption: Tangle the =example.py= file.
|
||||||
|
#+name: lst:example-py
|
||||||
|
#+begin_src python :tangle example.py
|
||||||
|
import numpy
|
||||||
|
import astropy.units as apu
|
||||||
|
|
||||||
|
a = numpy.arange(0, 11)
|
||||||
|
a = numpy.linspace(0, 10, num=11)
|
||||||
|
a = numpy.arccos(a)
|
||||||
|
q = apu.Quantity(a, apu.meter)
|
||||||
|
print(q)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** [[https://github.com/pyenv/pyenv][Pyenv]]
|
||||||
|
|
||||||
|
Listing [[lst:enable-pyenv-mode]] configures and enables =pyenv-mode=.
|
||||||
|
|
||||||
|
#+caption[Enable =pyenv-mode=]:
|
||||||
|
#+caption: Enable =pyenv-mode=.
|
||||||
|
#+name: lst:enable-pyenv-mode
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(when (and (executable-find "pyenv")
|
||||||
|
(require 'pyenv-mode nil 'noerror))
|
||||||
|
(pyenv-mode +1)
|
||||||
|
(pyenv-mode-set "3.9.9/envs/python-3.9.9"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Info
|
||||||
|
|
||||||
|
Listing [[lst:configure-info]] adds a path in my home directory to the places where
|
||||||
|
=info= looks for files.
|
||||||
|
|
||||||
|
#+caption[Configure =info=]:
|
||||||
|
#+caption: Configure =info=.
|
||||||
|
#+name: lst:configure-info
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(with-eval-after-load 'info
|
||||||
|
(add-to-list 'Info-directory-list
|
||||||
|
(expand-file-name "~/.local/share/info")))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** TODO Look into: editing facilities
|
||||||
|
1. [[https://github.com/douglasdavis/numpydoc.el/blob/main/numpydoc.el][Emacs extension to insert numpy style docstrings in function definitions]]
|
||||||
|
|
||||||
* Editing
|
* Editing
|
||||||
|
|
||||||
** [[https://www.emacswiki.org/emacs/DisabledCommands][Enable disabled commands and inform]]
|
** [[https://www.emacswiki.org/emacs/DisabledCommands][Enable disabled commands and inform]]
|
||||||
@ -1624,7 +1899,7 @@ on tables by means of =org-narrow-to-table=.
|
|||||||
(add-hook 'text-mode-hook #'ws-butler-mode)))
|
(add-hook 'text-mode-hook #'ws-butler-mode)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Structural editing
|
** [[https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/][Structural editing]]
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: sec:structural-editing
|
:CUSTOM_ID: sec:structural-editing
|
||||||
:END:
|
:END:
|
||||||
@ -1737,189 +2012,6 @@ code formatter for Python]].
|
|||||||
(yas-global-mode +1))
|
(yas-global-mode +1))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
* Coding
|
|
||||||
:PROPERTIES:
|
|
||||||
:CUSTOM_ID: sec:coding
|
|
||||||
:END:
|
|
||||||
|
|
||||||
** Emacs-lisp coding
|
|
||||||
:PROPERTIES:
|
|
||||||
:CUSTOM_ID: sec:emacs-lisp-coding
|
|
||||||
:END:
|
|
||||||
|
|
||||||
** Python coding
|
|
||||||
:PROPERTIES:
|
|
||||||
:CUSTOM_ID: sec:python-coding
|
|
||||||
:END:
|
|
||||||
|
|
||||||
The [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python Programming in Emacs]] wiki page lists options to enhance Emacs's
|
|
||||||
built-in ~python-mode~. Here, the focus is on two packages:
|
|
||||||
1. [[https://github.com/joaotavora/eglot][Eglot - Emacs polyGLOT: an Emacs LSP client that stays out of your way]]. The
|
|
||||||
maintainer also contributes to Emacs itself and has a deep understanding of
|
|
||||||
[[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]]. He refuses to add new features without seeing how they fit
|
|
||||||
into [[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]] as this discussion on [[https://github.com/joaotavora/eglot/issues/523][org-mode source code blocks]]
|
|
||||||
shows.
|
|
||||||
2. [[https://github.com/pythonic-emacs/anaconda-mode][Anaconda - code navigation, documentation lookup, and completion for Python]].
|
|
||||||
In my opinion, [[https://github.com/joaotavora/eglot][eglot]] has more potential than [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]], but [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] is
|
|
||||||
compatible with [[info:org#Editing Source Code][source code block editing]] while [[https://github.com/joaotavora/eglot][eglot]] is not. Listing
|
|
||||||
[[lst:configure-python]] configures [[https://www.python.org][Python]].
|
|
||||||
|
|
||||||
#+caption[Configure =python=]:
|
|
||||||
#+caption: Configure =python=.
|
|
||||||
#+name: lst:configure-python
|
|
||||||
#+begin_src elisp
|
|
||||||
(with-eval-after-load 'python
|
|
||||||
(custom-set-variables
|
|
||||||
'(python-indent-guess-indent-offset nil)
|
|
||||||
'(python-shell-interpreter-args "-i -E")))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Listing [[lst:configure-eglot-for-python]] configures [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]]. It defines
|
|
||||||
a hook function to launch [[https://github.com/joaotavora/eglot][eglot]] by means of a proper [[info:emacs#Directory Variables][directory variables]] file in
|
|
||||||
the root directory of any [[https://www.python.org][Python]] project. Listing
|
|
||||||
[[lst:eglot-directory-variables-for-python]] does shows such a proper [[info:emacs#Directory Variables][directory
|
|
||||||
variables]] file.
|
|
||||||
|
|
||||||
#+caption[Configure =eglot= for Python]:
|
|
||||||
#+caption: Configure =eglot= for Python.
|
|
||||||
#+name: lst:configure-eglot-for-python
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(with-eval-after-load 'eglot
|
|
||||||
(add-to-list 'eglot-server-programs '(python-mode "pylsp"))
|
|
||||||
(setq-default
|
|
||||||
eglot-workspace-configuration
|
|
||||||
'((:pylsp . (:plugins (:jedi_completion
|
|
||||||
(:cache_for ["astropy" "numpy" "scipy"]))))
|
|
||||||
(:pylsp . (:plugins (:jedi_completion (:eager nil)))))))
|
|
||||||
|
|
||||||
(when (fboundp 'eglot-ensure)
|
|
||||||
;; The two hooks `after-change-major-mode-hook' and
|
|
||||||
;; `hack-local-variables-hook' are OK, but `<ANY>-mode-hook' is not.
|
|
||||||
(add-hook 'hack-local-variables-hook
|
|
||||||
(defun on-hack-local-variables-hook-eglot-maybe ()
|
|
||||||
(when (and (derived-mode-p 'python-mode)
|
|
||||||
(assoc 'eglot-workspace-configuration
|
|
||||||
dir-local-variables-alist))
|
|
||||||
(eglot-ensure)))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+caption[Propose =directory-variables= to launch =eglot=]:
|
|
||||||
#+caption: Propose =directory-variables= in the root of any Python project to
|
|
||||||
#+caption: launch =eglot=.
|
|
||||||
#+name: lst:eglot-directory-variables-for-python
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
|
||||||
;; Proposal for a .dir-locals.el file in the root of any Python project.
|
|
||||||
((python-mode
|
|
||||||
. ((eglot-workspace-configuration
|
|
||||||
. ((:pylsp . (:plugins (:jedi_completion
|
|
||||||
(:cache_for ["astropy" "numpy" "scipy"]))))
|
|
||||||
(:pylsp . (:plugins (:jedi_completion (:eager nil)))))))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
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~.
|
|
||||||
|
|
||||||
#+caption[Configure =anaconda= for Python]:
|
|
||||||
#+caption: Configure =anaconda= for Python.
|
|
||||||
#+name: lst:configure-anaconda-for-python
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(with-eval-after-load 'python
|
|
||||||
(with-eval-after-load 'company
|
|
||||||
(when (and (fboundp 'anaconda-mode)
|
|
||||||
(fboundp 'company-anaconda))
|
|
||||||
(defun my-disable-anaconda-mode ()
|
|
||||||
(when (derived-mode-p 'python-mode)
|
|
||||||
(anaconda-mode -1)
|
|
||||||
(make-variable-buffer-local 'company-backends)
|
|
||||||
(setq company-backends
|
|
||||||
(delq 'company-anaconda
|
|
||||||
(mapcar #'identity company-backends)))
|
|
||||||
(anaconda-eldoc-mode -1)))
|
|
||||||
(defun my-enable-anaconda-mode ()
|
|
||||||
(when (derived-mode-p 'python-mode)
|
|
||||||
(anaconda-mode +1)
|
|
||||||
(make-variable-buffer-local 'company-backends)
|
|
||||||
(setq company-backends
|
|
||||||
(cons 'company-anaconda
|
|
||||||
(delq 'company-semantic
|
|
||||||
(delq 'company-capf
|
|
||||||
(mapcar #'identity company-backends)))))
|
|
||||||
(anaconda-eldoc-mode
|
|
||||||
(if (file-remote-p default-directory) -1 1))))))
|
|
||||||
|
|
||||||
(unless (and (fboundp 'my-disable-anaconda-mode)
|
|
||||||
(fboundp 'my-enable-anaconda-mode))
|
|
||||||
(when (fboundp 'anaconda-mode)
|
|
||||||
(defun my-disable-anaconda-mode ()
|
|
||||||
(when (derived-mode-p 'python-mode)
|
|
||||||
(anaconda-mode -1)
|
|
||||||
(anaconda-eldoc-mode -1)))
|
|
||||||
(defun my-enable-anaconda-mode ()
|
|
||||||
(when (derived-mode-p 'python-mode)
|
|
||||||
(anaconda-mode +1)
|
|
||||||
(anaconda-eldoc-mode
|
|
||||||
(if (file-remote-p default-directory) -1 1))))))
|
|
||||||
|
|
||||||
(when (fboundp 'my-enable-anaconda-mode)
|
|
||||||
(advice-add 'org-edit-src-code :after #'my-enable-anaconda-mode))
|
|
||||||
(when (and (fboundp 'my-disable-anaconda-mode)
|
|
||||||
(fboundp 'my-enable-anaconda-mode))
|
|
||||||
(defun my-toggle-anaconda-mode ()
|
|
||||||
"Toggle anaconda-mode with bells and whistles."
|
|
||||||
(interactive)
|
|
||||||
(if (bound-and-true-p anaconda-mode)
|
|
||||||
(my-disable-anaconda-mode)
|
|
||||||
(my-enable-anaconda-mode)))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Listing [[lst:example-py]] is a [[https://www.python.org][Python]] example showing differences in the handling
|
|
||||||
of compiled foreign language modules and pure [[https://www.python.org][Python]] modules. The underlying
|
|
||||||
[[https://jedi.readthedocs.io/en/latest/][jedi]] library parses modules (instead of imports) in order to handle completion
|
|
||||||
and documentation request. Therefore, [[https://jedi.readthedocs.io/en/latest/][jedi]] and consequently [[https://github.com/joaotavora/eglot][eglot]] as well as
|
|
||||||
[[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] treat compiled foreign language modules as second zone citizens. This
|
|
||||||
is noticible when coding certain functions of for instance [[https://numpy.org/][numpy]] and [[https://scipy.org/][scipy]].
|
|
||||||
|
|
||||||
#+caption[Tangle the =example.py= file]:
|
|
||||||
#+caption: Tangle the =example.py= file.
|
|
||||||
#+name: lst:example-py
|
|
||||||
#+begin_src python :tangle example.py :comments link
|
|
||||||
import numpy
|
|
||||||
import astropy.units as apu
|
|
||||||
|
|
||||||
a = numpy.arange(0, 11)
|
|
||||||
a = numpy.linspace(0, 10, num=11)
|
|
||||||
q = apu.Quantity(a, apu.meter)
|
|
||||||
print(q)
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Listing [[lst:enable-pyenv-mode]] configures and enables =pyenv-mode=.
|
|
||||||
|
|
||||||
#+caption[Enable =pyenv-mode=]:
|
|
||||||
#+caption: Enable =pyenv-mode=.
|
|
||||||
#+name: lst:enable-pyenv-mode
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(when (and (executable-find "pyenv")
|
|
||||||
(require 'pyenv-mode nil 'noerror))
|
|
||||||
(pyenv-mode +1)
|
|
||||||
(pyenv-mode-set "3.9.9/envs/python-3.9.9"))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Listing [[lst:configure-info]] adds a path in my home directory to the places where
|
|
||||||
=info= looks for files.
|
|
||||||
|
|
||||||
#+caption[Configure =info=]:
|
|
||||||
#+caption: Configure =info=.
|
|
||||||
#+name: lst:configure-info
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(with-eval-after-load 'info
|
|
||||||
(add-to-list 'Info-directory-list
|
|
||||||
(expand-file-name "~/.local/share/info")))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Look into:
|
|
||||||
1. [[https://github.com/douglasdavis/numpydoc.el/blob/main/numpydoc.el][Emacs extension to insert numpy style docstrings in function definitions]]
|
|
||||||
|
|
||||||
* [[https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg00775.html][Appearance]]
|
* [[https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg00775.html][Appearance]]
|
||||||
|
|
||||||
** [[info:emacs#Faces][Text faces (or styles)]]
|
** [[info:emacs#Faces][Text faces (or styles)]]
|
||||||
|
41
pylsp-auto-import-modules.patch
Normal file
41
pylsp-auto-import-modules.patch
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json
|
||||||
|
index c29d78b..f54b67a 100644
|
||||||
|
--- a/pylsp/config/schema.json
|
||||||
|
+++ b/pylsp/config/schema.json
|
||||||
|
@@ -69,6 +69,14 @@
|
||||||
|
"default": null,
|
||||||
|
"description": "List of errors and warnings to enable."
|
||||||
|
},
|
||||||
|
+ "pylsp.plugins.jedi.auto_import_modules": {
|
||||||
|
+ "type": "array",
|
||||||
|
+ "default": ["numpy", "scipy", "gi"],
|
||||||
|
+ "items": {
|
||||||
|
+ "type": "string"
|
||||||
|
+ },
|
||||||
|
+ "description": "List of module names for jedi to import (jedi.settings.auto_import_modules)."
|
||||||
|
+ },
|
||||||
|
"pylsp.plugins.jedi.extra_paths": {
|
||||||
|
"type": "array",
|
||||||
|
"default": [],
|
||||||
|
diff --git a/pylsp/workspace.py b/pylsp/workspace.py
|
||||||
|
index bf312f6..49e967a 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"]
|
||||||
|
+
|
||||||
|
# TODO: this is not the best e.g. we capture numbers
|
||||||
|
RE_START_WORD = re.compile('[A-Za-z_0-9]*$')
|
||||||
|
RE_END_WORD = re.compile('^[A-Za-z_0-9]*')
|
||||||
|
@@ -252,6 +254,8 @@ class Document:
|
||||||
|
|
||||||
|
if self._config:
|
||||||
|
jedi_settings = self._config.plugin_settings('jedi', document_path=self.path)
|
||||||
|
+ jedi.settings.auto_import_modules = jedi_settings.get('auto_import_modules',
|
||||||
|
+ DEFAULT_AUTO_IMPORT_MODULES)
|
||||||
|
environment_path = jedi_settings.get('environment')
|
||||||
|
extra_paths = jedi_settings.get('extra_paths') or []
|
||||||
|
env_vars = jedi_settings.get('env_vars')
|
Loading…
Reference in New Issue
Block a user