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)) (global-set-key (kbd "C-c g") #'writegood-mode))
#+end_src #+end_src
* Programming * Programming Tools
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:programming :CUSTOM_ID: sec:programming-tools
:END: :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]] ** [[https://github.com/lassik/emacs-format-all-the-code#readme][Format-all]]
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:format-all :CUSTOM_ID: sec:format-all
@ -2937,6 +2981,19 @@ Listing [[lst:configure-format-all]]:
(message "Saved reformatted tangled buffer `%s'" (buffer-file-name))))))) (message "Saved reformatted tangled buffer `%s'" (buffer-file-name)))))))
#+end_src #+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]] ** [[https://dept-info.labri.fr/~strandh/Teaching/PFS/Common/Strandh-Tutorial/Dir-symbolic.html][Common Lisp programming]]
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:common-lisp-programming :CUSTOM_ID: sec:common-lisp-programming
@ -3145,8 +3202,8 @@ server, before plunging into the configuring steps:
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:python-mode :CUSTOM_ID: sec:python-mode
:END: :END:
Listing [[lst:configure-python]] tells the Python shell to disregard its environment 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
variables (in particular =PYTHONSTARTUPFILE=). The [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]] and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages 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]] 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]]) 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 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 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 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:manage-pyenv]] to manage [[https://github.com/pyenv/pyenv#readme][pyenv]] from within Emacs and listing
[[lst:setting-python-shell-virtualenv-root]] to set [[lst:setting-python-shell-virtualenv-root]] to set =python-shell-virtualenv-root=.
=python-shell-virtualenv-root=.
#+caption[Configure =python=]: #+caption[Configure =python=]:
#+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 (with-eval-after-load 'python
(custom-set-variables (custom-set-variables
`(python-check-command ,(executable-find "flake8")) `(python-check-command ,(executable-find "flake8"))
`(python-flymake-command '(,(executable-find "flake8") "-"))
'(python-indent-guess-indent-offset nil) '(python-indent-guess-indent-offset nil)
'(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy")) '(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy"))
'(python-shell-interpreter "ipython3") '(python-shell-interpreter "ipython3")
@ -3257,85 +3314,51 @@ of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, thi
python-shell-virtualenv-root))))) python-shell-virtualenv-root)))))
#+end_src #+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: :PROPERTIES:
:CUSTOM_ID: sec:eglot :CUSTOM_ID: sec:eglot-python
:END: :END:
Listing [[lst:configure-eglot+python-lsp-server-for-python]] tangles to Listing [[lst:configure-eglot+python-lsp-server-for-python]] configures [[https://github.com/joaotavora/eglot][eglot]] for
=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]]. [[https://www.python.org][Python]] using the [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. In order to enable all builtin
In order to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation of the Python packages
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]], [[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
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]] 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]].
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 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
[[https://github.com/PyCQA/flake8][flake8]] as in [[lst:broken-configure-eglot+python-lsp-server-for-python]], but it [[lst:broken-configure-eglot+python-lsp-server-for-python]], but it does not work.
does not work.
Listing [[lst:on-hack-local-variables-hook-eglot-maybe]] defines a hook function to Listing [[lst:eglot-directory-variables-for-python]] shows a proper [[info:emacs#Directory Variables][.dir-locals.el]]
launch [[https://github.com/joaotavora/eglot][eglot]] in presence of a proper [[info:emacs#Directory Variables][.dir-locals.el]] file in the root directory file in the root directory of any [[https://www.python.org][Python]] project to start [[https://github.com/joaotavora/eglot][eglot]] automatically
of any [[https://www.python.org][Python]] project. Listing [[lst:eglot-directory-variables-for-python]] shows according to the configuration in listing [[lst:eglot-maybe-ensure]].
such a proper [[info:emacs#Directory Variables][.dir-locals.el]] file.
#+caption[Configure =eglot= with =python-lsp-server= for Python]: #+caption[Configure =eglot= with =python-lsp-server= 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 #+name: lst:configure-eglot+python-lsp-server-for-python
#+begin_src emacs-lisp #+begin_src emacs-lisp
(when (ensure-package-installation 'eglot) (with-eval-after-load 'eglot
(defvar eglot-server-programs (setq-default
`((python-mode . ("pylsp"))) eglot-workspace-configuration
"Shadow the definition of `eglot-server-programs' in `eglot'.") '(;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle.
(with-eval-after-load 'eglot (:pylsp . (:plugins (:pyls_flake8 (:enabled t))))
(setq-default (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
eglot-workspace-configuration (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
'(;; 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)))
#+end_src #+end_src
#+caption[Broken configure =eglot= with =python-lsp-server= for Python]: #+caption[Broken configure =eglot= with =python-lsp-server= for Python]:
#+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 #+name: lst:broken-configure-eglot+python-lsp-server-for-python
#+begin_src emacs-lisp :tangle no #+begin_src emacs-lisp :tangle no
(when (ensure-package-installation 'eglot) (with-eval-after-load 'eglot
(defvar eglot-server-programs (setq-default
`((python-mode . ("pylsp" "-vvv"))) eglot-workspace-configuration
"Shadow the definition of `eglot-server-programs' in `eglot'.") '(;; To use flake8 instead of pycodestyle, see:
(with-eval-after-load 'eglot ;; https://github.com/python-lsp/python-lsp-server#configuration
(setq-default (:pylsp . (:configurationSources ["flake8"]))
eglot-workspace-configuration (:pylsp . (:plugins (:pycodestyle (:enabled :json-false))))
'(;; To use flake8 instead of pycodestyle, see: (:pylsp . (:plugins (:mccabe (:enabled :json-false))))
;; https://github.com/python-lsp/python-lsp-server#configuration (:pylsp . (:plugins (:pyflakes (:enabled :json-false))))
(:pylsp . (:configurationSources ["flake8"])) (:pylsp . (:plugins (:flake8 (:enabled t))))
(:pylsp . (:plugins (:pycodestyle (:enabled :json-false)))) (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:mccabe (:enabled :json-false)))) (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
(: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)))))
#+end_src #+end_src
#+caption[Propose =directory-variables= to launch =eglot=]: #+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 #+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]]. [[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 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 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 instances", the [[https://docs.python.org/3/library/inspect.html][Python inspect]] module also fails to handle the universal
functions properly. functions properly.