Make a programming tools section and a programming modes section

This commit is contained in:
Gerard Vermeulen 2022-07-17 20:10:17 +02:00
parent 1069693680
commit ea4d1f6521
1 changed files with 96 additions and 73 deletions

View File

@ -2899,11 +2899,55 @@ Listing [[lst:configure-writegood-mode]] configures [[https://github.com/bnbeckw
(global-set-key (kbd "C-c g") #'writegood-mode))
#+end_src
* Programming
* Programming Tools
:PROPERTIES:
:CUSTOM_ID: sec:programming
:CUSTOM_ID: sec:programming-tools
:END:
*** [[https://github.com/joaotavora/eglot][Eglot]]
:PROPERTIES:
:CUSTOM_ID: sec:eglot
:END:
[[https://github.com/joaotavora/eglot#readme][Emacs polyGLOT (eglot)]] is an Emacs language-server-protocol client that stays
out of the way. Listing [[lst:ensure-eglot-installation]] ensures installation of
[[https://github.com/joaotavora/eglot][eglot]] with minimal configuration and listing [[lst:eglot-maybe-ensure]] starts [[https://github.com/joaotavora/eglot][eglot]]
in case of proper programming modes and proper directory local variables
(meaning in presence of a proper [[info:emacs#Directory Variables][.dir-locals.el]] file in the root directory of
any project using proper programming modes).
#+caption[Ensure =eglot= installation]:
#+caption: Ensure =eglot= installation.
#+name: lst:ensure-eglot-installation
#+begin_src emacs-lisp
(when (ensure-package-installation 'eglot)
;; (defvar eglot-server-programs
;; `((python-mode . ("pylsp" "-vvv")))
;; "Shadow the definition of `eglot-server-programs' in `eglot'.")
(with-eval-after-load 'eglot
(define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error)
(define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error)
(define-key eglot-mode-map (kbd "C-c r") 'eglot-rename)))
#+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:eglot-maybe-ensure
#+begin_src emacs-lisp
(when (fboundp 'eglot-ensure)
(defcustom eglot-maybe-derived-modes '(python-mode)
"Modes to call `eglot-ensure' in case of proper directory local variables.")
;; The two hooks `after-change-major-mode-hook' and
;; `hack-local-variables-hook' are OK, but language mode hooks like
;; `python-mode-hook' are not.
(add-hook 'after-change-major-mode-hook
(defun eglot-maybe-ensure ()
(when (and (apply #'derived-mode-p eglot-maybe-derived-modes)
(assoc 'eglot-workspace-configuration
dir-local-variables-alist))
(eglot-ensure)))))
#+end_src
** [[https://github.com/lassik/emacs-format-all-the-code#readme][Format-all]]
:PROPERTIES:
:CUSTOM_ID: sec:format-all
@ -2937,6 +2981,19 @@ Listing [[lst:configure-format-all]]:
(message "Saved reformatted tangled buffer `%s'" (buffer-file-name)))))))
#+end_src
** [[info:flymake#Top][Flymake (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:flymake
:END:
Flymake is an universal on-the-fly syntax checker for Emacs. It is a requirement
of [[https://github.com/joaotavora/eglot][eglot]], but you can use it without [[https://github.com/joaotavora/eglot][eglot]] for instance in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] buffers
that do not visit a file.
* Programming Modes
:PROPERTIES:
:CUSTOM_ID: sec:programming-languages
:END:
** [[https://dept-info.labri.fr/~strandh/Teaching/PFS/Common/Strandh-Tutorial/Dir-symbolic.html][Common Lisp programming]]
:PROPERTIES:
:CUSTOM_ID: sec:common-lisp-programming
@ -3145,8 +3202,8 @@ server, before plunging into the configuring steps:
:PROPERTIES:
:CUSTOM_ID: sec:python-mode
:END:
Listing [[lst:configure-python]] tells the Python shell to disregard its environment
variables (in particular =PYTHONSTARTUPFILE=). The [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]] and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages
Listing [[lst:configure-python]] configures [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] to use [[https://flake8.pycqa.org/en/latest/][flake8]] as style
checker and [[https://ipython.org/][IPython]] as shell interpreter. The [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]] and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages
provide support to handle Python virtual environments within Emacs. The [[https://github.com/pyenv/pyenv][pyenv]]
package provides support to work with [[https://github.com/pyenv/pyenv#readme][pyenv]] (eventually with [[https://github.com/pyenv/pyenv-virtualenv#readme][pyenv-virtualenv]])
to select between different python versions (eventually each with different
@ -3155,8 +3212,7 @@ environments). In the end, all those packages do is to set
environment variables and restart the relevant Python child processes (in case
of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, this setup replaces those packages with listing
[[lst:manage-pyenv]] to manage [[https://github.com/pyenv/pyenv#readme][pyenv]] from within Emacs and listing
[[lst:setting-python-shell-virtualenv-root]] to set
=python-shell-virtualenv-root=.
[[lst:setting-python-shell-virtualenv-root]] to set =python-shell-virtualenv-root=.
#+caption[Configure =python=]:
#+caption: Configure =python=.
@ -3165,6 +3221,7 @@ of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, thi
(with-eval-after-load 'python
(custom-set-variables
`(python-check-command ,(executable-find "flake8"))
`(python-flymake-command '(,(executable-find "flake8") "-"))
'(python-indent-guess-indent-offset nil)
'(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy"))
'(python-shell-interpreter "ipython3")
@ -3257,85 +3314,51 @@ of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, thi
python-shell-virtualenv-root)))))
#+end_src
*** [[https://github.com/joaotavora/eglot][Eglot]]
*** [[https://github.com/joaotavora/eglot][Eglot]] for [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]]
:PROPERTIES:
:CUSTOM_ID: sec:eglot
:CUSTOM_ID: sec:eglot-python
:END:
Listing [[lst:configure-eglot+python-lsp-server-for-python]] tangles to
=user-init-file= and configures [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] using the [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]].
In order to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure
installation of the Python packages [[https://github.com/hhatto/autopep8#readme][autopep8]], [[https://github.com/PyCQA/flake8][flake8]], [[https://github.com/PyCQA/pydocstyle#readme][pydocstyle]], [[https://github.com/PyCQA/pylint#readme][pylint]], [[https://github.com/python-rope/rope#readme][rope]],
and [[https://github.com/google/yapf#readme][yapf]]. In addition, install the [[https://github.com/emanspeaks/pyls-flake8#readme][pyls-flake8]] plugin to let [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]
use [[https://github.com/PyCQA/flake8][flake8]]. The latest [[https://github.com/python-lsp/python-lsp-server#readme][python-lsp-server]] documentation tells to let it use
[[https://github.com/PyCQA/flake8][flake8]] as in [[lst:broken-configure-eglot+python-lsp-server-for-python]], but it
does not work.
Listing [[lst:configure-eglot+python-lsp-server-for-python]] configures [[https://github.com/joaotavora/eglot][eglot]] for
[[https://www.python.org][Python]] using the [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. In order to enable all builtin
[[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation of the Python packages
[[https://github.com/hhatto/autopep8#readme][autopep8]], [[https://github.com/PyCQA/flake8][flake8]], [[https://github.com/PyCQA/pydocstyle#readme][pydocstyle]], [[https://github.com/PyCQA/pylint#readme][pylint]], [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]], [[https://github.com/python-rope/rope#readme][rope]], and [[https://github.com/google/yapf#readme][yapf]]. In
addition, install the [[https://github.com/emanspeaks/pyls-flake8#readme][pyls-flake8]] plugin to let [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] use [[https://github.com/PyCQA/flake8][flake8]].
The latest [[https://github.com/python-lsp/python-lsp-server#readme][python-lsp-server]] documentation tells to let it use [[https://github.com/PyCQA/flake8][flake8]] as in
[[lst:broken-configure-eglot+python-lsp-server-for-python]], but it does not work.
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.
Listing [[lst:eglot-directory-variables-for-python]] shows a proper [[info:emacs#Directory Variables][.dir-locals.el]]
file in the root directory of any [[https://www.python.org][Python]] project to start [[https://github.com/joaotavora/eglot][eglot]] automatically
according to the configuration in listing [[lst:eglot-maybe-ensure]].
#+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
(when (ensure-package-installation 'eglot)
(defvar eglot-server-programs
`((python-mode . ("pylsp")))
"Shadow the definition of `eglot-server-programs' in `eglot'.")
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle.
(:pylsp . (:plugins (:pyls_flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"]))))))
(define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error)
(define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error)
(define-key eglot-mode-map (kbd "C-c r") 'eglot-rename)))
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle.
(:pylsp . (:plugins (:pyls_flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
#+end_src
#+caption[Broken configure =eglot= with =python-lsp-server= for Python]:
#+caption: Broken configure =eglot= with =python-lsp-server= for Python.
#+name: lst:broken-configure-eglot+python-lsp-server-for-python
#+begin_src emacs-lisp :tangle no
(when (ensure-package-installation 'eglot)
(defvar eglot-server-programs
`((python-mode . ("pylsp" "-vvv")))
"Shadow the definition of `eglot-server-programs' in `eglot'.")
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; To use flake8 instead of pycodestyle, see:
;; https://github.com/python-lsp/python-lsp-server#configuration
(:pylsp . (:configurationSources ["flake8"]))
(:pylsp . (:plugins (:pycodestyle (:enabled :json-false))))
(:pylsp . (:plugins (:mccabe (:enabled :json-false))))
(:pylsp . (:plugins (:pyflakes (:enabled :json-false))))
(:pylsp . (:plugins (:flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"]))))))
(define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error)
(define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error)
(define-key eglot-mode-map (kbd "C-c r") 'eglot-rename)))
#+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 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)
(assoc 'eglot-workspace-configuration
dir-local-variables-alist))
(eglot-ensure)))))
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; To use flake8 instead of pycodestyle, see:
;; https://github.com/python-lsp/python-lsp-server#configuration
(:pylsp . (:configurationSources ["flake8"]))
(:pylsp . (:plugins (:pycodestyle (:enabled :json-false))))
(:pylsp . (:plugins (:mccabe (:enabled :json-false))))
(:pylsp . (:plugins (:pyflakes (:enabled :json-false))))
(:pylsp . (:plugins (:flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
#+end_src
#+caption[Propose =directory-variables= to launch =eglot=]:
@ -3397,9 +3420,9 @@ agree with [[https://black.readthedocs.io/en/stable/index.html][black's uncompro
#+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.22.0]] in the sense that it does
Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.23.0]] in the sense that it does
not choke on universal functions provided that [[https://jedi.readthedocs.io/en/latest/][jedi]] does not parse but 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]]). Since the universal
[[https://numpy.org/][numpy-1.23.1]] (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]]). Since the universal
functions are neither builtin methods nor data instances but a kind of "callable
instances", the [[https://docs.python.org/3/library/inspect.html][Python inspect]] module also fails to handle the universal
functions properly.