Overhaul the code to let Eglot work with Org Babel source blocks
This commit is contained in:
parent
0f1be8c4a2
commit
a43104c2eb
223
README.org
223
README.org
@ -4750,11 +4750,14 @@ out of your way. [[info:eglot#Top][Eglot (info)]] is a builtin since Emacs-29.1
|
|||||||
listings contribute to a programming language mode independent [[https://github.com/joaotavora/eglot][Eglot]]
|
listings contribute to a programming language mode independent [[https://github.com/joaotavora/eglot][Eglot]]
|
||||||
configuration:
|
configuration:
|
||||||
1. Listing [[lst:minimal-eglot-setup][minimal Eglot setup]] adds key bindings to =eglot-mode-keymap=.
|
1. Listing [[lst:minimal-eglot-setup][minimal Eglot setup]] adds key bindings to =eglot-mode-keymap=.
|
||||||
2. Listing [[lst:help-setup-org-src-mode-for-eglot]] and
|
2. Listing [[lst:help-setup-org-src-mode-for-eglot-1]],
|
||||||
|
[[lst:help-setup-org-src-mode-for-eglot-2]],
|
||||||
|
[[lst:help-setup-org-src-mode-for-eglot-3]], and
|
||||||
[[lst:setup-python-org-src-mode-for-eglot]] try to prepare any =org-src-mode=
|
[[lst:setup-python-org-src-mode-for-eglot]] try to prepare any =org-src-mode=
|
||||||
buffers for use with [[https://github.com/joaotavora/eglot][Eglot]]. They are a refactored implementation of the post
|
buffers for use with [[https://github.com/joaotavora/eglot][Eglot]]. They are a refactored implementation of the post
|
||||||
[[https://www.reddit.com/r/emacs/comments/w4f4u3/using_rustic_eglot_and_orgbabel_for_literate/][Using rustic, eglot, and org-babel with LSP support in Emacs]] for my use with
|
[[https://www.reddit.com/r/emacs/comments/w4f4u3/using_rustic_eglot_and_orgbabel_for_literate/][Using rustic, eglot, and org-babel with LSP support in Emacs]] for my use with
|
||||||
Python.
|
Python. Listing [[lst:help-setup-org-src-mode-for-eglot-1]] is bad practice,
|
||||||
|
because it signals ~user-errors~.
|
||||||
3. Listing [[lst:eglot-maybe-ensure]] starts [[https://github.com/joaotavora/eglot][Eglot]] in case of proper programming
|
3. 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
|
modes and proper directory local variables (meaning in presence of a proper
|
||||||
file [[info:emacs#Directory Variables][.dir-locals.el]] in the root directory of any project using proper
|
file [[info:emacs#Directory Variables][.dir-locals.el]] in the root directory of any project using proper
|
||||||
@ -4772,94 +4775,196 @@ configuration:
|
|||||||
(keymap-set eglot-mode-map "C-c r" 'eglot-rename))
|
(keymap-set eglot-mode-map "C-c r" 'eglot-rename))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+caption[Help to setup any =org-src-mode= buffers for =eglot=]:
|
#+caption[1st help to setup any =org-src-mode= buffers for =eglot=]:
|
||||||
#+caption: Help to setup any =org-src-mode= buffers for =eglot=.
|
#+caption: 1st help to setup any =org-src-mode= buffers for =eglot=.
|
||||||
#+name: lst:help-setup-org-src-mode-for-eglot
|
#+caption: Bad practice.
|
||||||
|
#+name: lst:help-setup-org-src-mode-for-eglot-1
|
||||||
#+begin_src emacs-lisp -n :results silent
|
#+begin_src emacs-lisp -n :results silent
|
||||||
(with-eval-after-load 'emacs
|
;;; Begin: Eglot and Org Babel source blocks
|
||||||
(defcustom eglot-maybe-ensure-modes '(python-mode)
|
|
||||||
"Modes where maybe `eglot-ensure' should be or has been called.
|
|
||||||
This may be in the case of proper directory local variables or in
|
|
||||||
the case of proper `org-src-mode' buffers.")
|
|
||||||
|
|
||||||
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
||||||
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
||||||
(defun eglot-org-babel-edit-prep (info)
|
;;
|
||||||
"Try to setup an `org-mode-src' buffer to make `eglot-ensure' succeed.
|
;; One should not signal `user-error's in `org-babel-edit-prep:LANG'
|
||||||
|
;; functions.
|
||||||
|
(defun eglot-org-babel-edit-prep-user-error (info)
|
||||||
|
"Try to setup an `org-mode-src' buffer to make `eglot-ensure' succeed.
|
||||||
INFO has a form similar to the return value of
|
INFO has a form similar to the return value of
|
||||||
`org-babel-get-src-block-info'. Try to load the tangled file
|
`org-babel-get-src-block-info'. Try to load the tangled file
|
||||||
into the `org-src-mode' buffer as well as to narrow the region to
|
into the `org-src-mode' buffer as well as to narrow the region to
|
||||||
the Org-mode source block code before calling `eglot-ensure'."
|
the Org-mode source block code before calling `eglot-ensure'."
|
||||||
(unless (bound-and-true-p org-src-mode)
|
(unless (bound-and-true-p org-src-mode)
|
||||||
(user-error "Buffer %s is no `org-src-mode' buffer" (buffer-name)))
|
(user-error "Buffer %s is no `org-src-mode' buffer" (buffer-name)))
|
||||||
(let ((mark (point))
|
(let ((point (point))
|
||||||
(body (nth 1 info))
|
(body (nth 1 info))
|
||||||
(filename (cdr (assq :tangle (nth 2 info)))))
|
(filename (cdr (assq :tangle (nth 2 info)))))
|
||||||
(when (string= filename "no")
|
(when (string= filename "no")
|
||||||
(user-error "Org source block has no tangled file"))
|
(user-error "Org source block has no tangled file"))
|
||||||
|
(setq filename (expand-file-name filename))
|
||||||
|
(unless (file-readable-p filename)
|
||||||
|
(user-error "Tangled file %s is not readable" filename))
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
|
(unless (search-forward body nil 'noerror)
|
||||||
|
(user-error "Org source block does not occur in tangled file %s"
|
||||||
|
filename))
|
||||||
|
(when (search-forward body nil 'noerror)
|
||||||
|
(user-error "Org source block occurs twice or more in tangled file %s"
|
||||||
|
filename)))
|
||||||
|
(goto-char (point-min))
|
||||||
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
|
(search-forward body)
|
||||||
|
;; The next line preserves point in the `org-src-mode' buffer.
|
||||||
|
(goto-char (+ (match-beginning 0) point -1))
|
||||||
|
(narrow-to-region (match-beginning 0) (match-end 0))
|
||||||
|
(eglot-ensure)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+caption[2nd help to setup any =org-src-mode= buffers for =eglot=]:
|
||||||
|
#+caption: 2nd help to setup any =org-src-mode= buffers for =eglot=.
|
||||||
|
#+caption: Best practice.
|
||||||
|
#+name: lst:help-setup-org-src-mode-for-eglot-2
|
||||||
|
#+begin_src emacs-lisp -n :results silent
|
||||||
|
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
||||||
|
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
||||||
|
(defun eglot-org-babel-edit-prep (info)
|
||||||
|
"Try to setup an `org-mode-src' buffer to make `eglot-ensure' succeed.
|
||||||
|
INFO has a form similar to the return value of
|
||||||
|
`org-babel-get-src-block-info'. Try to load the tangled file
|
||||||
|
into the `org-src-mode' buffer as well as to narrow the region to
|
||||||
|
the Org-mode source block code before calling `eglot-ensure'."
|
||||||
|
(when-let ((ok (bound-and-true-p org-src-mode))
|
||||||
|
(point (point))
|
||||||
|
(body (nth 1 info))
|
||||||
|
(filename (cdr (assq :tangle (nth 2 info)))))
|
||||||
|
(when (string= filename "no")
|
||||||
|
(setq ok nil)
|
||||||
|
(message "Org source block has no tangled file"))
|
||||||
|
(when ok
|
||||||
(setq filename (expand-file-name filename))
|
(setq filename (expand-file-name filename))
|
||||||
(unless (file-readable-p filename)
|
(unless (file-readable-p filename)
|
||||||
(user-error "Tangled file %s is not readable" filename))
|
(setq ok nil)
|
||||||
|
(message "Tangled file %s is not readable" filename)))
|
||||||
|
(when ok
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert-file-contents filename 'visit nil nil 'replace)
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
(unless (search-forward body nil 'noerror)
|
(unless (search-forward body nil 'noerror)
|
||||||
(user-error "Org source block does not occur in tangled file %s"
|
(setq ok nil)
|
||||||
filename))
|
(message "Org source block does not occur in tangled file %s"
|
||||||
|
filename))
|
||||||
(when (search-forward body nil 'noerror)
|
(when (search-forward body nil 'noerror)
|
||||||
(user-error "Org source block occurs twice or more in tangled file %s"
|
(setq ok nil)
|
||||||
filename)))
|
(message
|
||||||
|
"Org source block occurs twice or more in tangled file %s"
|
||||||
|
filename))))
|
||||||
|
(when ok
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(insert-file-contents filename 'visit nil nil 'replace)
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
(search-forward body)
|
(search-forward body)
|
||||||
|
;; The next line preserves point in the `org-src-mode' buffer.
|
||||||
|
(goto-char (+ (match-beginning 0) point -1))
|
||||||
(narrow-to-region (match-beginning 0) (match-end 0))
|
(narrow-to-region (match-beginning 0) (match-end 0))
|
||||||
(goto-char mark)
|
(eglot-ensure))))
|
||||||
(eglot-ensure)))
|
#+end_src
|
||||||
|
|
||||||
(defun org-babel-edit-prep:python (info)
|
#+caption[3rd help to setup any =org-src-mode= buffers for =eglot=]:
|
||||||
(eglot-org-babel-edit-prep info)))
|
#+caption: 3rd help to setup any =org-src-mode= buffers for =eglot=.
|
||||||
|
#+caption: Good practice.
|
||||||
|
#+name: lst:help-setup-org-src-mode-for-eglot-3
|
||||||
|
#+begin_src emacs-lisp -n :results silent
|
||||||
|
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
||||||
|
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
||||||
|
(defun eglot-org-babel-edit-prep-if-let (info)
|
||||||
|
"Try to setup an `org-mode-src' buffer to make `eglot-ensure' succeed.
|
||||||
|
INFO has a form similar to the return value of
|
||||||
|
`org-babel-get-src-block-info'. Try to load the tangled file
|
||||||
|
into the `org-src-mode' buffer as well as to narrow the region to
|
||||||
|
the Org-mode source block code before calling `eglot-ensure'."
|
||||||
|
(if-let ((ok (bound-and-true-p org-src-mode))
|
||||||
|
(point (point))
|
||||||
|
(body (nth 1 info))
|
||||||
|
(filename (cdr (assq :tangle (nth 2 info)))))
|
||||||
|
(progn
|
||||||
|
(when (string= filename "no")
|
||||||
|
(setq ok nil)
|
||||||
|
(message "Org source block has no tangled file"))
|
||||||
|
(when ok
|
||||||
|
(setq filename (expand-file-name filename))
|
||||||
|
(unless (file-readable-p filename)
|
||||||
|
(setq ok nil)
|
||||||
|
(message "Tangled file %s is not readable" filename)))
|
||||||
|
(when ok
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
|
(unless (search-forward body nil 'noerror)
|
||||||
|
(setq ok nil)
|
||||||
|
(message "Org source block does not occur in tangled file %s"
|
||||||
|
filename))
|
||||||
|
(when (search-forward body nil 'noerror)
|
||||||
|
(setq ok nil)
|
||||||
|
(message
|
||||||
|
"Org source block occurs twice or more in tangled file %s"
|
||||||
|
filename))))
|
||||||
|
(when ok
|
||||||
|
(goto-char (point-min))
|
||||||
|
(insert-file-contents filename 'visit nil nil 'replace)
|
||||||
|
(search-forward body)
|
||||||
|
;; The next line preserves point in the `org-src-mode' buffer.
|
||||||
|
(goto-char (+ (match-beginning 0) point -1))
|
||||||
|
(narrow-to-region (match-beginning 0) (match-end 0))
|
||||||
|
(eglot-ensure)))
|
||||||
|
(message "Buffer %s is not `eglot' ready" (buffer-name))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+caption[Setup Python =org-src-mode= buffers for =eglot=]:
|
#+caption[Setup Python =org-src-mode= buffers for =eglot=]:
|
||||||
#+caption: Setup Python =org-src-mode= buffers for =eglot=.
|
#+caption: Setup Python =org-src-mode= buffers for =eglot=.
|
||||||
#+name: lst:setup-python-org-src-mode-for-eglot
|
#+name: lst:setup-python-org-src-mode-for-eglot
|
||||||
#+begin_src emacs-lisp -n :results silent
|
#+begin_src emacs-lisp -n :results silent
|
||||||
(with-eval-after-load 'emacs
|
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
||||||
;; https://www.reddit.com/r/emacs/comments/w4f4u3
|
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
||||||
;; /using_rustic_eglot_and_orgbabel_for_literate/
|
(defun org-babel-edit-prep:python (info)
|
||||||
(defun undo-eglot-org-babel-edit-prep()
|
(eglot-org-babel-edit-prep info))
|
||||||
"Undo the `eglot' setup by deleting the text hidden by narrowing.
|
|
||||||
This is to advice `org-edit-src-exit' and `org-edit-src-save'."
|
|
||||||
(when (and (bound-and-true-p org-src-mode)
|
|
||||||
(buffer-file-name)
|
|
||||||
(apply #'derived-mode-p eglot-maybe-ensure-modes))
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(save-restriction
|
|
||||||
(widen)
|
|
||||||
(delete-region (point-min) (point)))
|
|
||||||
(goto-char (point-max))
|
|
||||||
(save-restriction
|
|
||||||
(widen)
|
|
||||||
(delete-region (point) (point-max))))))
|
|
||||||
|
|
||||||
(advice-add 'org-edit-src-exit :before #'undo-eglot-org-babel-edit-prep)
|
(defcustom eglot-maybe-ensure-modes '(python-mode)
|
||||||
(advice-add 'org-edit-src-save :before #'undo-eglot-org-babel-edit-prep))
|
"Modes where calling `eglot-ensure' may have occurred.
|
||||||
|
This may be in the case of proper directory local variables or in
|
||||||
|
the case of proper `org-src-mode' buffers.")
|
||||||
|
|
||||||
|
(defun undo-eglot-org-babel-edit-prep()
|
||||||
|
"Undo the `eglot' setup by deleting the text hidden by narrowing.
|
||||||
|
This is to advice `org-edit-src-exit' and `org-edit-src-save'."
|
||||||
|
(when (and (bound-and-true-p org-src-mode)
|
||||||
|
(buffer-file-name)
|
||||||
|
(apply #'derived-mode-p eglot-maybe-ensure-modes))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(delete-region (point-min) (point)))
|
||||||
|
(goto-char (point-max))
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(delete-region (point) (point-max))))))
|
||||||
|
|
||||||
|
(advice-add 'org-edit-src-exit :before #'undo-eglot-org-babel-edit-prep)
|
||||||
|
(advice-add 'org-edit-src-save :before #'undo-eglot-org-babel-edit-prep)
|
||||||
#+end_src
|
#+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=]:
|
||||||
#+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
|
#+name: lst:eglot-maybe-ensure
|
||||||
#+begin_src emacs-lisp -n :results silent
|
#+begin_src emacs-lisp -n :results silent
|
||||||
(with-eval-after-load 'emacs
|
(defun eglot-maybe-ensure ()
|
||||||
(defun eglot-maybe-ensure ()
|
(when (and (apply #'derived-mode-p eglot-maybe-ensure-modes)
|
||||||
(when (and (apply #'derived-mode-p eglot-maybe-ensure-modes)
|
(assoc 'eglot-workspace-configuration dir-local-variables-alist))
|
||||||
(assoc 'eglot-workspace-configuration dir-local-variables-alist))
|
(eglot-ensure)))
|
||||||
(eglot-ensure)))
|
|
||||||
|
|
||||||
;; The two hooks `after-change-major-mode-hook' and
|
;; The two hooks `after-change-major-mode-hook' and
|
||||||
;; `hack-local-variables-hook' are OK, but language mode hooks like
|
;; `hack-local-variables-hook' are OK, but language mode hooks like
|
||||||
;; `python-mode-hook' are not.
|
;; `python-mode-hook' are not.
|
||||||
(add-hook 'after-change-major-mode-hook #'eglot-maybe-ensure))
|
(add-hook 'after-change-major-mode-hook #'eglot-maybe-ensure)
|
||||||
|
|
||||||
|
;;; End: Eglot and Org Babel source blocks
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+caption[Whiten Black]:
|
#+caption[Whiten Black]:
|
||||||
|
Loading…
Reference in New Issue
Block a user