feat(emacs): ltex-ls & backlinks count display

This commit is contained in:
Pavel Korytov 2023-02-12 23:37:13 +03:00
parent a1b77e2330
commit d2620549b8
2 changed files with 191 additions and 18 deletions

View file

@ -1234,7 +1234,7 @@ influence of C1 on the result."
(haskell-literate-mode . lsp)
(java-mode . lsp)
;; (csharp-mode . lsp)
)
(text-mode . lsp))
:commands lsp
:init
(setq lsp-keymap-prefix nil)
@ -1833,9 +1833,9 @@ Returns (<buffer> . <workspace-index>) or nil."
("c" . "\\chi")
("v" . "\\psi")
("g" . "\\omega")))
(setq my/latex-greek-prefix "'")
;; The same for capitalized letters
(dolist (elem my/greek-alphabet)
(let ((key (car elem))
@ -1848,7 +1848,7 @@ Returns (<buffer> . <workspace-index>) or nil."
(substring value 0 1)
(capitalize (substring value 1 2))
(substring value 2)))))))
(yas-define-snippets
'latex-mode
(mapcar
@ -1857,13 +1857,13 @@ Returns (<buffer> . <workspace-index>) or nil."
my/greek-alphabet))
(setq my/english-alphabet
'("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))
(dolist (elem my/english-alphabet)
(when (string-equal elem (downcase elem))
(add-to-list 'my/english-alphabet (upcase elem))))
(setq my/latex-mathbb-prefix "`")
(yas-define-snippets
'latex-mode
(mapcar
@ -1887,9 +1887,9 @@ Returns (<buffer> . <workspace-index>) or nil."
("~" . "\\sim")
("|" . "\\mid")
("_|" . "\\perp")))
(setq my/latex-math-prefix ";")
(yas-define-snippets
'latex-mode
(mapcar
@ -1904,7 +1904,7 @@ Returns (<buffer> . <workspace-index>) or nil."
("ssec" . "\\subsection{$1}")
("sssec" . "\\subsubsection{$1}")
("par" . "\\paragraph{$1}}")))
(setq my/latex-section-snippets
(mapcar
(lambda (elem)
@ -1914,7 +1914,7 @@ Returns (<buffer> . <workspace-index>) or nil."
(string-match "[a-z]+" (cdr elem))
(match-string 0 (cdr elem)))))
my/latex-section-snippets))
(dolist (elem my/latex-section-snippets)
(let* ((key (nth 0 elem))
(value (nth 1 elem))
@ -1931,10 +1931,10 @@ Returns (<buffer> . <workspace-index>) or nil."
`(,(concat key "l")
,(concat value "%\n\\label{sec:$2}")
,(concat desc " with label")))))
(dolist (elem my/latex-section-snippets)
(setf (nth 1 elem) (concat (nth 1 elem) "\n$0")))
(yas-define-snippets
'latex-mode
my/latex-section-snippets))
@ -2167,6 +2167,20 @@ Returns (<buffer> . <workspace-index>) or nil."
:states '(normal)
"gp" #'subed-mpv-toggle-pause))
(use-package lsp-ltex
:straight t
:after (lsp)
:init
(setq lsp-ltex-version "15.2.0")
(setq lsp-ltex-check-frequency "save"))
(defun my/ltex-lang ()
(interactive)
(setq lsp-ltex-language (completing-read
"Language: "
'("en-US" "ru-RU" "de-DE")))
(lsp-workspace-restart (lsp--read-workspace)))
(use-package langtool
:straight t
:commands (langtool-check)
@ -3378,6 +3392,55 @@ skip exactly those headlines that do not match."
:keymap 'org-mode-map
"C-c i" 'org-roam-node-insert))
(defface my/org-roam-count-overlay-face
'((t :inherit tooltip))
"Face for Org Roam count overlay.")
(defun my/org-roam--count-overlay-make (pos count)
(let* ((overlay-value (concat
" "
(propertize
(format "%d" count)
'face 'my/org-roam-count-overlay-face)
" "))
(ov (make-overlay pos pos (current-buffer) nil t)))
(overlay-put ov 'roam-backlinks-count count)
(overlay-put ov 'priority 1)
(overlay-put ov 'after-string overlay-value)))
(defun my/org-roam--count-overlay-remove-all ()
(dolist (ov (overlays-in (point-min) (point-max)))
(when (overlay-get ov 'roam-backlinks-count)
(delete-overlay ov))))
(defun my/org-roam--count-overlay-make-all ()
(my/org-roam--count-overlay-remove-all)
(org-element-map (org-element-parse-buffer) 'link
(lambda (elem)
(when (string-equal (org-element-property :type elem) "id")
(let* ((id (org-element-property :path elem))
(count (caar
(org-roam-db-query
[:select (funcall count source)
:from links
:where (= dest $s1)
:and (= type "id")]
id))))
(when (< 0 count)
(my/org-roam--count-overlay-make
(org-element-property :end elem)
count)))))))
(define-minor-mode my/org-roam-count-overlay-mode
"Display backlink count for org-roam links."
:after-hook
(if my/org-roam-count-overlay-mode
(progn
(my/org-roam--count-overlay-make-all)
(add-hook 'after-save-hook #'my/org-roam--count-overlay-make-all nil t))
(my/org-roam--count-overlay-remove-all)
(remove-hook 'after-save-hook #'my/org-roam--count-overlay-remove-all t)))
(use-package org-roam-ui
:straight (:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
:if (not my/remote-server)
@ -5101,17 +5164,17 @@ ENTRY is an instance of `elfeed-entry'."
'("bestvideo[height<=720]+bestaudio/best[height<=720]"
"bestvideo[height<=480]+bestaudio/best[height<=480]"
"bestvideo[height<=1080]+bestaudio/best[height<=1080]"))
(setq my/default-emms-player-mpv-parameters
'("--quiet" "--really-quiet" "--no-audio-display"))
(defun my/set-emms-mpd-youtube-quality (quality)
(interactive "P")
(unless quality
(setq quality (completing-read "Quality: " my/youtube-dl-quality-list nil t)))
(setq emms-player-mpv-parameters
`(,@my/default-emms-player-mpv-parameters ,(format "--ytdl-format=%s" quality))))
(my/set-emms-mpd-youtube-quality (car my/youtube-dl-quality-list))
;; evil-lion and evil-commentary shadow some gX bindings
;; (add-hook 'emms-browser-mode-hook
@ -5145,7 +5208,7 @@ ENTRY is an instance of `elfeed-entry'."
(emms-track-set track name value)))))
(defun emms-player-mpd-get-alists (info)
"Turn the given parsed INFO from MusicPD into an list of alists.
The list will be in reverse order."
(when (and info
(null (car info)) ; no error has occurred

112
Emacs.org
View file

@ -1945,7 +1945,7 @@ References:
(haskell-literate-mode . lsp)
(java-mode . lsp)
;; (csharp-mode . lsp)
)
(text-mode . lsp))
:commands lsp
:init
(setq lsp-keymap-prefix nil)
@ -2940,6 +2940,30 @@ A major mode to work with subtitles.
:states '(normal)
"gp" #'subed-mpv-toggle-pause))
#+end_src
*** LTeX
[[https://github.com/valentjn/ltex-ls][ltex-ls]] is a tool that wraps LanguageTool into a language server.
It takes maybe 10 seconds to run on my Master's thesis file (=M-x count words=: 13453 words and 117566 characters), but it's totally worth it. And it's much faster on smaller files. The good thing is that it supports markup syntaxes like Org and Markdown, whereas LanguageTool by itself produces a lot of false positives on these files.
It shouldn't be too hard to package that for guix, but I've installed the nix version for now.
#+begin_src emacs-lisp
(use-package lsp-ltex
:straight t
:after (lsp)
:init
(setq lsp-ltex-version "15.2.0")
(setq lsp-ltex-check-frequency "save"))
#+end_src
A function to switch the current language.
#+begin_src emacs-lisp
(defun my/ltex-lang ()
(interactive)
(setq lsp-ltex-language (completing-read
"Language: "
'("en-US" "ru-RU" "de-DE")))
(lsp-workspace-restart (lsp--read-workspace)))
#+end_src
*** LanguageTool
LanguageTool is a great offline spell checker. For some reason, the download link is nowhere to be found on the home page, so it is listed in the references as well.
@ -4734,6 +4758,92 @@ A set of keybindings to quickly access things in Org Roam.
:keymap 'org-mode-map
"C-c i" 'org-roam-node-insert))
#+end_src
**** Backlinks count display
Occasionally I want to see how much backlinks does a particular page have.
This idea came to my mind because I occasionally write a note in the following form:
#+begin_example
According to <This Person>, <some opinion>
#+end_example
And I have a note called =#Personalities=, which looks like that:
#+begin_example
Philosophers:
- <This Person>
- <That Person>
- <Another Person>
...
#+end_example
So I'm curious to see how many notes do I have linked to each:
#+begin_example
Philosophers:
- <This Person> [30]
- <That Person> [40]
- <Another Person> [20]
...
#+end_example
The obvious way to implement that is via [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Overlays.html][overlays]]:
#+begin_src emacs-lisp
(defface my/org-roam-count-overlay-face
'((t :inherit tooltip))
"Face for Org Roam count overlay.")
(defun my/org-roam--count-overlay-make (pos count)
(let* ((overlay-value (concat
" "
(propertize
(format "%d" count)
'face 'my/org-roam-count-overlay-face)
" "))
(ov (make-overlay pos pos (current-buffer) nil t)))
(overlay-put ov 'roam-backlinks-count count)
(overlay-put ov 'priority 1)
(overlay-put ov 'after-string overlay-value)))
#+end_src
Also a function to remove them:
#+begin_src emacs-lisp
(defun my/org-roam--count-overlay-remove-all ()
(dolist (ov (overlays-in (point-min) (point-max)))
(when (overlay-get ov 'roam-backlinks-count)
(delete-overlay ov))))
#+end_src
Now we can iterate over all roam links in the buffer, count the number of backlinks via =org-roam-db-query= and invoke =my/org-roam--count-overlay-make= if that number is greater than zero:
#+begin_src emacs-lisp
(defun my/org-roam--count-overlay-make-all ()
(my/org-roam--count-overlay-remove-all)
(org-element-map (org-element-parse-buffer) 'link
(lambda (elem)
(when (string-equal (org-element-property :type elem) "id")
(let* ((id (org-element-property :path elem))
(count (caar
(org-roam-db-query
[:select (funcall count source)
:from links
:where (= dest $s1)
:and (= type "id")]
id))))
(when (< 0 count)
(my/org-roam--count-overlay-make
(org-element-property :end elem)
count)))))))
#+end_src
And a minor mode to toggle the display in a particular =org-roam= buffer.
#+begin_src emacs-lisp
(define-minor-mode my/org-roam-count-overlay-mode
"Display backlink count for org-roam links."
:after-hook
(if my/org-roam-count-overlay-mode
(progn
(my/org-roam--count-overlay-make-all)
(add-hook 'after-save-hook #'my/org-roam--count-overlay-make-all nil t))
(my/org-roam--count-overlay-remove-all)
(remove-hook 'after-save-hook #'my/org-roam--count-overlay-remove-all t)))
#+end_src
**** Org Roam UI
A browser frontend to visualize the Roam database as a graph.