diff --git a/.emacs.d/init.el b/.emacs.d/init.el index e35636c..4e5f1a8 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -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 ( . ) 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 ( . ) 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 ( . ) 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 ( . ) or nil." ("~" . "\\sim") ("|" . "\\mid") ("_|" . "\\perp"))) - + (setq my/latex-math-prefix ";") - + (yas-define-snippets 'latex-mode (mapcar @@ -1904,7 +1904,7 @@ Returns ( . ) or nil." ("ssec" . "\\subsection{$1}") ("sssec" . "\\subsubsection{$1}") ("par" . "\\paragraph{$1}}"))) - + (setq my/latex-section-snippets (mapcar (lambda (elem) @@ -1914,7 +1914,7 @@ Returns ( . ) 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 ( . ) 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 ( . ) 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 diff --git a/Emacs.org b/Emacs.org index 8ed58a8..3023871 100644 --- a/Emacs.org +++ b/Emacs.org @@ -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 , +#+end_example + +And I have a note called =#Personalities=, which looks like that: +#+begin_example +Philosophers: +- +- +- +... +#+end_example + +So I'm curious to see how many notes do I have linked to each: +#+begin_example +Philosophers: +- [30] +- [40] +- [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.