display org-tag-eldoc explanation in "sideline"
[org-tag-eldoc.git] / org-tag-eldoc.el
blob5bc936c27f50a9d92984d3079cf8c68782562e3b
1 ;;; org-tag-eldoc.el --- Display tag explanation in Eldoc -*- lexical-binding: t; -*-
2 ;; -*- coding: utf-8 -*-
4 ;; Authors: stardiviner <numbchild@gmail.com>
5 ;; Package-Requires: ((emacs "28.1") (request "0.3.3"))
6 ;; Version: 0.1.0
7 ;; Keywords: text org
8 ;; Homepage: https://repo.or.cz/org-tag-eldoc.git
10 ;; Copyright (C) 2024-2025 Christopher M. Miles, all rights reserved.
12 ;; org-tag-eldoc is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; any later version.
17 ;; org-tag-eldoc is distributed in the hope that it will be useful, but WITHOUT
18 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20 ;; License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
25 ;;; Commentary:
27 ;;; Display tag explanation in Eldoc when point on tag.
29 ;;; Usage:
30 ;;;
31 ;;; (add-hook 'org-mode-hook #'org-tag-eldoc-setup)
33 ;;; Code:
35 (require 'org)
36 (require 'org-tag-eldoc-common)
37 (require 'org-tag-eldoc-database)
38 (require 'org-tag-eldoc-wikipedia)
39 (require 'org-tag-eldoc-baidu-baike)
40 (require 'org-tag-eldoc-urban-dictionary)
41 (require 'org-tag-eldoc-pixiv-encyclopedia)
42 (require 'org-tag-eldoc-moegirl)
43 (require 'subr-x)
46 (defgroup org-tag-eldoc nil
47 "Customize group of `org-tag-eldoc-mode'."
48 :prefix "org-tag-eldoc-"
49 :group 'org-tags)
51 (defcustom org-tag-eldoc-tag-explanation-functions
52 '(org-tag-eldoc-database-query
53 org-tag-eldoc-wikipedia-query
54 org-tag-eldoc-urban-dictionary-query
55 org-tag-eldoc-baidu-baike-query
56 org-tag-eldoc-moegirl-query
57 org-tag-eldoc-pixiv-encyclopedia-query)
58 "A list of functions to be executed for query tag explanation."
59 :type 'list
60 :safe #'listp
61 :group 'org-tag-eldoc)
63 (defcustom org-tag-eldoc-request-proxy
64 (or url-proxy-services
65 '(("http" . "127.0.0.1:7890")
66 ("https" . "127.0.0.1:7890")))
67 "The proxy services inherited from `url-proxy-services'."
68 :type 'alist
69 :group 'org-tag-eldoc)
71 (defcustom org-tag-eldoc-display-backend 'sideline
72 "The backend for displaying org-tag-eldoc explanation."
73 :type 'symbol
74 :safe #'symbolp
75 :group 'org-tag-eldoc)
77 (defcustom org-tag-eldoc-tag-explanations-alist
78 '(("Linux" . "Linux (/ˈlɪnʊks/ LIN-uuks) is a family of open-source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds.")
79 ("Emacs" . "Emacs /ˈiːmæks/ ⓘ, originally named EMACS (an acronym for \"Editor Macros\"), is a family of text editors that are characterized by their extensibility. The manual for the most widely used variant, GNU Emacs, describes it as \"the extensible, customizable, self-documenting, real-time display editor\". Development of the first Emacs began in the mid-1970s, and work on GNU Emacs, directly descended from the original, is ongoing; its latest version is 29.2, released January 2024.")
80 ("GNU" . "GNU (/ɡnuː/ ⓘ) is an extensive collection of free software (385 packages as of September 2023), which can be used as an operating system or can be used in parts with other operating systems. The use of the completed GNU tools led to the family of operating systems popularly known as Linux. Most of GNU is licensed under the GNU Project's own General Public License (GPL)."))
81 "Alist of cons cell with tag and explanation."
82 :type 'alist
83 :safe #'listp
84 :group 'org-tag-eldoc)
86 (defcustom org-tag-eldoc-translation nil
87 "Boolean value to toggle translation for explanation."
88 :type 'boolean
89 :safe #'booleanp)
92 (defun org-tag-eldoc-translate (explanation)
93 "Translate EXPLANATION."
94 ;; TODO:
95 (when org-tag-eldoc-translation
97 explanation)
99 (defun org-tag-eldoc--format-explanation (explanation)
100 "Format the EXPLANATION string."
101 ;; prettify display explanation long string.
102 (if explanation
103 (org-tag-eldoc-translate
104 (string-fill
105 (if (string-match-p "\n" explanation) ; if explanation is a large block of paragraphs.
106 explanation
107 ;; if only have single long line with several paragraphs, then break paragraphs into lines.
108 (string-replace ". " ". \n\n" explanation))
109 fill-column))
110 (message "[org-tag-eldoc] `org-tag-eldoc--format-explanation' argument `explanation' is `nil'")))
112 (defun org-tag-eldoc-tag-explanation (&optional tag)
113 "Display tag explanation in Eldoc when point on TAG."
114 (let ((tag (or tag (substring-no-properties (thing-at-point 'symbol)))))
115 (if-let ((explanation (cdr (assoc tag org-tag-eldoc-tag-explanations-alist))))
116 (org-tag-eldoc--format-explanation explanation)
117 (let ((explanation (seq-some
118 (lambda (f)
119 ;; reset `org-tag-eldoc--explanation' to avoid bellowing `seq-some' chaos.
120 (setq org-tag-eldoc--explanation nil)
121 (apply f (list tag))
122 (unless (string-equal org-tag-eldoc--explanation "nil")
123 org-tag-eldoc--explanation))
124 org-tag-eldoc-tag-explanation-functions)))
125 ;; cache already queried result explanation into `org-tag-eldoc-tag-explanations-alist'.
126 (if explanation
127 (progn
128 (add-to-list 'org-tag-eldoc-tag-explanations-alist (cons tag explanation))
129 (org-tag-eldoc--format-explanation explanation))
130 (error "[org-tag-eldoc] Still no `explanation' after backends from `org-tag-eldoc-tag-explanation-functions'"))))))
133 (defun org-tag-eldoc-tag-explanation-at-point ()
134 "Get tag explanation at point."
135 ;; NOTE: `org-element-at-point' return `headline' instead of `tags.' Need Org mode to implement it.
136 ;; Use `thing-at-point' to workaround the missing `tags' syntax element node in `org-element-at-point' / `org-context'.
137 (when-let* ((symbol (thing-at-point 'symbol))
138 (tag (substring-no-properties symbol))
139 (tags (org-get-tags nil 'local)))
140 (when (member tag tags)
141 (org-tag-eldoc-tag-explanation tag))))
143 (defun org-tag-eldoc-function (&rest args)
144 "The eldoc function to be added into `eldoc-documentation-functions' with ARGS."
145 ;; NOTE: `org-element-at-point' return `headline' instead of `tags.' Need Org mode to implement it.
146 ;; Use `thing-at-point' to workaround the missing `tags' syntax element node in `org-element-at-point' / `org-context'.
147 (let ((explanation (org-tag-eldoc-tag-explanation-at-point)))
148 (cl-case org-tag-eldoc-display-backend
149 (sideline explanation)
150 (quick-peek (quick-peek-show explanation (point) 1)))))
152 (defun org-tag-eldoc-sideline (command)
153 "Display org-tag-eldoc explanation based on COMMAND in sideline.
154 Backend for sideline.
155 Argument COMMAND is required in sideline backend."
156 (cl-case command
157 (`candidates (list (org-tag-eldoc-tag-explanation-at-point)))
158 (`action 'org-tag-eldoc-database-update-row)
159 (`face 'org-tag)
160 (`name "org-tag-eldoc")))
162 (defun org-tag-eldoc-sideline-async (command)
163 "Display org-tag-eldoc explanation based on COMMAND in sideline in async.
164 Backend for sideline.
165 Argument COMMAND is required in sideline backend."
166 (cl-case command
167 (`candidates (cons :async (list (org-tag-eldoc-tag-explanation-at-point))))
168 (`action 'org-tag-eldoc-database-update-row)
169 (`face 'org-tag)
170 (`name "org-tag-eldoc")))
172 ;;; `eldoc-documentation-function', `eldoc-documentation-functions'
173 ;;;###autoload
174 (defun org-tag-eldoc-setup ()
175 "Setup `eldoc-documentation-functions'."
176 (eldoc-mode t)
177 (cl-case org-tag-eldoc-display-backend
178 (sideline
179 (add-to-list 'sideline-backends-right 'org-tag-eldoc-sideline 'append) ; `org-tag-eldoc-sideline-async'
180 (sideline-mode 1)))
181 (add-hook 'eldoc-documentation-functions #'org-tag-eldoc-function -10 t))
183 ;;;###autoload
184 (defun org-tag-eldoc-enable ()
185 "Enable `org-tag-eldoc-mode'."
186 (add-hook 'org-mode-hook #'org-tag-eldoc-setup 100))
188 ;;;###autoload
189 (defun org-tag-eldoc-disable ()
190 "Disable `org-tag-eldoc-mode'."
191 (remove-hook 'org-mode-hook #'org-tag-eldoc-setup))
193 ;;;###autoload
194 (define-minor-mode org-tag-eldoc-mode
195 "A minor mode that display Org tag explanation through Eldoc."
196 :init-value nil
197 :lighter nil
198 :group 'org-tag-eldoc
199 :global t
200 (if org-tag-eldoc-mode
201 (org-tag-eldoc-enable)
202 (org-tag-eldoc-disable)))
204 ;;; TODO: Add mouse hover popup info support.
209 (provide 'org-tag-eldoc)
211 ;;; org-tag-eldoc.el ends here