Update latex-help and some other stuff

This commit is contained in:
Alexander Rosenberg 2024-10-10 06:42:08 -07:00
parent a6ba5e74a3
commit 9ae0d7a93f
Signed by: Zander671
GPG Key ID: 5FD0394ADBD72730
2 changed files with 463 additions and 123 deletions

View File

@ -11,6 +11,8 @@
;;; Code: ;;; Code:
(require 'info) (require 'info)
(require 'cl-lib)
(require 'shr)
(defcustom latex-help-info-manual "latex2e" (defcustom latex-help-info-manual "latex2e"
"The name of the info manual to use when looking up latex commands." "The name of the info manual to use when looking up latex commands."
@ -25,139 +27,163 @@
:group 'latex-help :group 'latex-help
:type 'string) :type 'string)
(defun latex-help--run-index-search (regexp) (defcustom latex-help-texdoc-buffer-name "*latex-help-texdoc*"
"Search the LaTeX info pages index for REGEXP. "The name of the buffer to use when showing texdoc files."
This returns a list of cache entries suitable for use in :group 'latex-help
`latex-help--commands-cache'." :type 'string)
(with-temp-buffer
(Info-mode)
(Info-find-node latex-help-info-manual "Index" nil t)
(let ((found))
(while (re-search-forward regexp nil t)
(let ((match (match-string-no-properties 1))
(node (match-string-no-properties 2)))
(if (equal (caar found) match)
(push (cons node (pos-bol)) (cdar found))
(push (list match (cons node (pos-bol))) found))))
found)))
(defvar latex-help--commands-cache nil (defcustom latex-help-texdoc-program "texdoc"
"Cahce of discovered of LaTeX commands. "The program to use when looking things up with texdoc."
These do NOT have a leading '\\'.") :group 'latex-help
:type '(string :tag "Executable name"))
(defun latex-help--discover-commands () (defcustom latex-help-pdf-view-program '(emacs "evince")
"Discover LaTeX commands. "The program to use to view PDF documentation files."
This is done by parsing the index for `latex-help-info-manual'." :group 'latex-help
(let ((found (latex-help--run-index-search :type '(choice
(rx (and bol "* \\" (string :tag "External program")
(group (or (const :tag "Texdoc default" texdoc)
"," (function :tag "Custom function")
(+ (not (any " " "{" ","))))) (list :tag "Emacs Doc-View mode"
(*? any) ":" (+ " ") (const :tag "Emacs will be used as the default" emacs)
(group (+? any)) "."))))) (choice :tag "Backup"
(push (list "(SPACE)" "\\(SPACE)") found) (string :tag "Use external program as a backup")
(when-let (entry (assoc "(...\\)" found)) (const :tag "Use texdoc default as a backup" texdoc)
(setq found (assoc-delete-all "(...\\)" found)) (function :tag "Use a custom function as a backup")))))
(push (cons "(" (cdr entry)) found)
(push (cons ")" (cdr entry)) found))
(when-let (entry (assoc "[...\\]" found))
(setq found (assoc-delete-all "[...\\]" found))
(push (cons "[" (cdr entry)) found)
(push (cons "]" (cdr entry)) found))
found))
(defvar latex-help--package-cache nil (defcustom latex-help-html-view-program 'emacs
"Cache of discovered LaTeX packages.") "The program to use to view PDF documentation files."
:group 'latex-help
:type '(choice
(string :tag "External program")
(const :tag "Texdoc default" texdoc)
(const :tag "Emacs internal HTML engine" emacs)
(function :tag "Custom function")))
(defun latex-help--discover-packages () (defcustom latex-help-documentation-roots '("/usr/share/texmf-dist/doc/")
"Discover LaTeX packages. "The directories to search to discover texdoc entries."
This is done by parsing the index for `latex-help-info-manual'." :group 'latex-help
(latex-help--run-index-search (rx (and bol "* package, " :type '(repeat directory))
(group (+? any))
(any " " ":")
(+? any) (+ " ")
(group (+? any))
"."))))
(defvar latex-help--environment-cache nil
"Cache of discovered LaTeX environments.")
(defun latex-help--discover-environments ()
"Discover LaTeX environments.
This is done by parsing the index for `latex-help-info-manual'."
(latex-help--run-index-search (rx (and bol "* environment, "
(group (+? any))
(any " " ":" "-")
(+? any) (+ " ")
(group (+? any))
"."))))
(defvar latex-help--class-cache nil (defvar latex-help--class-cache nil
"Cache of discovered LaTeX document classes.") "Cache of discovered LaTeX document classes.")
(defun latex-help--discover-classes () (defvar latex-help--environment-cache nil
"Discover LaTeX document classes. "Cache of discovered LaTeX environments.")
This is done by parsing the index for `latex-help-info-manual'."
(latex-help--run-index-search (rx (and bol "* "
(group (+ (not (any "," " "))))
" class:" (+ " ")
(group (+ (not ".")))))))
(defun latex-help--goto-entry (entry) (defvar latex-help--package-cache nil
"Open the info page for ENTRY, a cache entry." "Cache of discovered LaTeX packages.")
(let ((buffer (get-buffer-create latex-help-buffer-name)))
(with-current-buffer buffer (defvar latex-help--commands-cache nil
(unless (derived-mode-p 'Info-mode) "Cache of discovered of LaTeX commands.
(Info-mode)) These do NOT have a leading '\\'.")
(Info-find-node latex-help-info-manual "Index" nil t)
(goto-char (cdr entry)) (defvar latex-help--texdoc-cache nil
(Info-follow-nearest-node)) "Cache of texdoc entries.")
(pop-to-buffer buffer)))
(defvar latex-help--caches-initialized-p nil (defvar latex-help--caches-initialized-p nil
"Non-nil if the latex-help caches have been initialized.") "Non-nil if the latex-help caches have been initialized.")
(defun latex-help--get-cache-for-type (type) (defun latex-help--maybe-init-caches ()
"Lookup the cache for TYPE. "Init the latex-help caches if they ware empty."
If the caches are not yet initialized, do that first."
(unless latex-help--caches-initialized-p (unless latex-help--caches-initialized-p
(setq latex-help--commands-cache (latex-help--discover-commands) (setq latex-help--commands-cache (latex-help--discover-commands)
latex-help--package-cache (latex-help--discover-packages) latex-help--package-cache (latex-help--discover-packages)
latex-help--environment-cache (latex-help--discover-environments) latex-help--environment-cache (latex-help--discover-environments)
latex-help--class-cache (latex-help--discover-classes) latex-help--class-cache (latex-help--discover-classes)
latex-help--caches-initialized-p t)) latex-help--texdoc-cache (latex-help--discover-texdoc-entries)
latex-help--caches-initialized-p t)))
(defun latex-help--open-file-with (cmd file)
"Open FILE with shell command CMD."
(call-process-shell-command (format "%s %s" cmd
(shell-quote-argument file))
nil 0))
(defun latex-help--open-file-with-texdoc (file)
"Open FILE with texdoc."
(call-process latex-help-texdoc-program nil 0 nil "--just-view" file))
(defun latex-help--texdoc-open-pdf-file (file)
"Open the PDF file FILE."
(cond (cond
((eq type 'command) ((and (listp latex-help-pdf-view-program)
latex-help--commands-cache) (eq (car latex-help-pdf-view-program) 'emacs))
((eq type 'package) (let ((backup (cadr latex-help-pdf-view-program)))
latex-help--package-cache)
((eq type 'environment)
latex-help--environment-cache)
((eq type 'class)
latex-help--class-cache)))
(defun latex-help--history nil
"History list for `latex-help--maybe-prompt-entry'.")
(defun latex-help--maybe-prompt-entry (name type &optional default)
"Lookup and prompt the user for the node of NAME.
The lookup is performed in the correct cache for TYPE. If there is only one
node associated with NAME, return its entry. Otherwise, ask the user which node
they want to use.
If DEFAULT is non-nil, use that instead of prompting. If it does not exist,
return nil."
(when-let (entries (alist-get name (latex-help--get-cache-for-type type)
nil nil 'equal))
(cond (cond
(default ((display-graphic-p)
(assoc default entries)) (find-file-other-window file))
((length= entries 1) ((eq backup 'texdoc)
(car entries)) (latex-help--open-file-with-texdoc file))
(t ((functionp backup)
(let ((resp (completing-read "Select Node: " (mapcar 'car entries) (funcall backup file))
nil t nil))) ((stringp backup)
(assoc resp entries)))))) (latex-help--open-file-with backup file)))))
((eq latex-help-pdf-view-program 'texdoc)
(latex-help--open-file-with-texdoc file))
((functionp latex-help-pdf-view-program)
(funcall latex-help-pdf-view-program file))
((stringp latex-help-pdf-view-program)
(latex-help--open-file-with latex-help-pdf-view-program file))))
(defun latex-help--pop-to-texdoc-buffer ()
"Pop to (and possibly create) the texdoc buffer.
The buffer's name is from `latex-help-texdoc-buffer-name'."
(pop-to-buffer (get-buffer-create latex-help-texdoc-buffer-name))
(setq buffer-read-only t)
(special-mode))
(defun latex-help--texdoc-open-html-file (file)
"Open the HTML file FILE."
(cond
((eq latex-help-html-view-program 'emacs)
(latex-help--pop-to-texdoc-buffer)
(let ((buffer-read-only nil))
(erase-buffer)
(insert-file-contents file nil)
(shr-render-region (point-min) (point-max))
(goto-char (point-min))))
((eq latex-help-html-view-program 'texdoc)
(latex-help--open-file-with-texdoc file))
((functionp latex-help-html-view-program)
(funcall latex-help-html-view-program file))
((stringp latex-help-html-view-program)
(latex-help--open-file-with latex-help-html-view-program file))))
(defun latex-help--texdoc-maybe-text-file (file)
"Try to open FILE as a text file.
Read FILE into a buffer. If it is a text file, show the user that buffer, and
return t. Otherwise, kill the buffer and return nil."
(with-current-buffer (generate-new-buffer "*latex-help-texdoc-temp*")
(setq buffer-read-only t)
(special-mode)
(let ((buffer-read-only nil))
(erase-buffer)
(insert-file-contents file nil)
(if (eq buffer-file-coding-system 'no-conversion)
;; the file was a binary file
(progn
(let ((kill-buffer-query-functions nil))
(set-buffer-modified-p nil)
(kill-buffer (current-buffer))
(user-error "File \"%s\" is binary" file)))
;; we are good to go
(when-let (old-buffer (get-buffer latex-help-texdoc-buffer-name))
(kill-buffer old-buffer))
(rename-buffer latex-help-texdoc-buffer-name)
(pop-to-buffer (current-buffer))))))
(defun latex-help--texdoc-open-file (file)
"Open the texdoc file FILE.
This will attempt to detect the file's type and open it with the correct
program."
(let ((ext (or (file-name-extension file) "")))
(cond
((string-equal-ignore-case ext "pdf")
(latex-help--texdoc-open-pdf-file file))
((string-equal-ignore-case ext "html")
(latex-help--texdoc-open-html-file file))
(t (latex-help--texdoc-maybe-text-file file)))))
(defun latex-help--get-thing-at-point () (defun latex-help--get-thing-at-point ()
"Return a cons of the LaTeX thing at point and its type (as a symbol). "Return a cons of the LaTeX thing at point and its type (as a symbol).
@ -203,6 +229,235 @@ The following are some examples:
;; just return nil ;; just return nil
((or user-error scan-error))))))))) ((or user-error scan-error)))))))))
(defun latex-help--is-marker-file (file root)
"Return non-nil if FILE is a texdoc marker file under ROOT.
A marker file is a file that signifies that its parent is a texdoc entry."
(let ((name (file-name-nondirectory file))
(dirname (file-name-nondirectory
(directory-file-name (file-name-parent-directory file))))
(case-fold-search t))
(and
(not (length= (file-name-split (file-relative-name file root)) 2))
(or (string-match (rx bos "readme" (* "." (+ (any (?a . ?z))))) name)
(string-match (rx bos "doc" eos) name)
(string-match (rx bos "base" eos) name)
;; check if file is just its parent directories name with an .tex or
;; .pdf
(string-match (format "^%s[-0-9]*\\.\\(?:tex\\|pdf\\)$"
(regexp-quote dirname))
name)))))
(defun latex-help--search-texdoc-root (root)
"Search the texdoc root directory ROOT and discover package names."
(cl-loop with found = nil
with to-search = nil
for dir = root then (pop to-search)
while dir
when (file-directory-p dir) do
(let ((files (directory-files dir t)))
(if (cl-member-if (lambda (file)
(latex-help--is-marker-file file root))
files)
;; dir is an entry
(push (cons (directory-file-name
(file-name-nondirectory dir))
(file-name-as-directory dir))
found)
;; search all subdirs
(setq to-search
(nconc to-search
(seq-filter
(lambda (file)
(let ((name (file-name-nondirectory file)))
(and (not (equal name "."))
(not (equal name "..")))))
files)))))
finally return found))
(defun latex-help--discover-texdoc-entries ()
"Discover texdoc entries in each of `latex-help-documentation-roots'."
(cl-loop for root in latex-help-documentation-roots
append (latex-help--search-texdoc-root root)))
(defun latex-help--list-texdoc-files-for-entry (entry)
"List the texdoc files for ENTRY.
ENTRY is of the form (name . dir). This returns a list of conses of the display
name of the entry and the file it belongs to."
(with-temp-buffer
(when-let ((exit-code (call-process latex-help-texdoc-program nil t
nil "-Ml" (car entry)))
((not (zerop exit-code))))
;; try to get the programs output without the normal Emacs process
;; sentinel message
(goto-char (point-max))
(forward-line -2)
(end-of-line)
(let ((msg (buffer-substring-no-properties (point-min)
(point))))
(user-error "Texdoc exited with a non-zero code: %d%s"
exit-code (if (not (zerop (length msg)))
(concat "\n\n" msg)
""))))
;; the process succeeded, try to extract the files it found
(goto-char (point-min))
(let ((found))
(while (re-search-forward (rx (and bol (= 2 (+ (not "\t")) "\t")
(group (+ (not "\t")))
"\t"
(? (+ (not "\t")))
"\t"
(group (* any))))
nil t)
(let* ((file (match-string 1))
(desc (match-string 2))
(prompt (if (zerop (length desc))
file
(format "%s - %s" desc file))))
;; check if the file is actually belongs to this entry
(when (string-prefix-p (cdr entry) file)
(push (cons prompt file) found))))
(nreverse found))))
(defun latex-help--texdoc-prompt-for-entry-file (entry)
"Prompt the user to open a texdoc file from ENTRY.
This will return nil if the user does not want to open the file."
(let ((entries (latex-help--list-texdoc-files-for-entry entry)))
(if (length= entries 1)
(and (y-or-n-p (format "Open texdoc \"%s\"?" (caar entry)))
(cdar entry))
(let ((ans (completing-read "Texdoc File: " (mapcar 'car entries) nil t)))
(unless (zerop (length ans))
(cdr (assoc ans entries)))))))
(defvar latex-help--texdoc-history nil
"History for `latex-heklp--list-texdoc-files'.")
(defun latex-help--prompt-texdoc-entry ()
"Ask the user for a texdoc entry.
This returns the actual entry from `latex-help--texdoc-cache'. Therefore, the
result is a cons."
(latex-help--maybe-init-caches)
(let* ((tap (latex-help--get-thing-at-point))
(has-default-p (and (member (cdr tap) '(package class))
(assoc (car tap) latex-help--texdoc-cache)))
(ans (completing-read (format "Texdoc Entry%s: "
(if has-default-p
(format " (default %s)" (car tap))
""))
(mapcar 'car latex-help--texdoc-cache)
nil t nil 'latex-help--texdoc-history
(and has-default-p (car tap)))))
(unless (zerop (length ans))
(assoc ans latex-help--texdoc-cache))))
(defun latex-help--run-index-search (regexp)
"Search the LaTeX info pages index for REGEXP.
This returns a list of cache entries suitable for use in
`latex-help--commands-cache'."
(with-temp-buffer
(Info-mode)
(Info-find-node latex-help-info-manual "Index" nil t)
(let ((found))
(while (re-search-forward regexp nil t)
(let ((match (match-string-no-properties 1))
(node (match-string-no-properties 2)))
(if (equal (caar found) match)
(push (cons node (pos-bol)) (cdar found))
(push (list match (cons node (pos-bol))) found))))
found)))
(defun latex-help--discover-commands ()
"Discover LaTeX commands.
This is done by parsing the index for `latex-help-info-manual'."
(let ((found (latex-help--run-index-search
(rx (and bol "* \\"
(group (or
","
(+ (not (any " " "{" ",")))))
(*? any) ":" (+ " ")
(group (+? any)) ".")))))
(push (list "(SPACE)" "\\(SPACE)") found)
(when-let (entry (assoc "(...\\)" found))
(setq found (assoc-delete-all "(...\\)" found))
(push (cons "(" (cdr entry)) found)
(push (cons ")" (cdr entry)) found))
(when-let (entry (assoc "[...\\]" found))
(setq found (assoc-delete-all "[...\\]" found))
(push (cons "[" (cdr entry)) found)
(push (cons "]" (cdr entry)) found))
found))
(defun latex-help--discover-packages ()
"Discover LaTeX packages.
This is done by parsing the index for `latex-help-info-manual'."
(latex-help--run-index-search (rx (and bol "* package, "
(group (+? any))
(any " " ":")
(+? any) (+ " ")
(group (+? any))
"."))))
(defun latex-help--discover-environments ()
"Discover LaTeX environments.
This is done by parsing the index for `latex-help-info-manual'."
(latex-help--run-index-search (rx (and bol "* environment, "
(group (+? any))
(any " " ":" "-")
(+? any) (+ " ")
(group (+? any))
"."))))
(defun latex-help--discover-classes ()
"Discover LaTeX document classes.
This is done by parsing the index for `latex-help-info-manual'."
(latex-help--run-index-search (rx (and bol "* "
(group (+ (not (any "," " "))))
" class:" (+ " ")
(group (+ (not ".")))))))
(defun latex-help--info-goto-entry (entry)
"Open the info page for ENTRY, a cache entry."
(let ((buffer (get-buffer-create latex-help-buffer-name)))
(with-current-buffer buffer
(unless (derived-mode-p 'Info-mode)
(Info-mode))
(Info-find-node latex-help-info-manual "Index" nil t)
(goto-char (cdr entry))
(Info-follow-nearest-node))
(pop-to-buffer buffer)))
(defun latex-help--get-cache-for-type (type)
"Lookup the cache for TYPE.
If the caches are not yet initialized, do that first."
(latex-help--maybe-init-caches)
(cl-case type
(command latex-help--commands-cache)
(package latex-help--package-cache)
(environment latex-help--environment-cache)
(class latex-help--class-cache)))
(defvar latex-help--info-history nil
"History list for `latex-help--prompt-for'.")
(defun latex-help--maybe-prompt-entry (name type &optional default)
"Lookup and prompt the user for the node of NAME.
The lookup is performed in the correct cache for TYPE. If there is only one
node associated with NAME, return its entry. Otherwise, ask the user which node
they want to use.
If DEFAULT is non-nil, use that instead of prompting. If it does not exist,
return nil."
(when-let (entries (cdr (assoc name (latex-help--get-cache-for-type type))))
(cond
(default
(assoc default entries))
((length= entries 1)
(car entries))
(t
(let ((resp (completing-read "Select Node: " (mapcar 'car entries)
nil t nil)))
(assoc resp entries))))))
(defun latex-help--prompt-for (type) (defun latex-help--prompt-for (type)
"Prompt for a command, environment, etc. from TYPE. "Prompt for a command, environment, etc. from TYPE.
This returns the name of the thing that was prompted." This returns the name of the thing that was prompted."
@ -217,7 +472,7 @@ This returns the name of the thing that was prompted."
(format " (default %s)" default) (format " (default %s)" default)
"")) ""))
(latex-help--get-cache-for-type type) (latex-help--get-cache-for-type type)
nil t nil 'latex-help--history nil t nil 'latex-help--info-history
default))) default)))
(defun latex-help-command (name &optional node) (defun latex-help-command (name &optional node)
@ -226,7 +481,7 @@ Unless NODE is non-nil, if NAME is in more than one node, prompt the user for
which to use. If NODE is non-nil, use that instead." which to use. If NODE is non-nil, use that instead."
(interactive (list (latex-help--prompt-for 'command))) (interactive (list (latex-help--prompt-for 'command)))
(when-let (entry (latex-help--maybe-prompt-entry name 'command node)) (when-let (entry (latex-help--maybe-prompt-entry name 'command node))
(latex-help--goto-entry entry))) (latex-help--info-goto-entry entry)))
(defun latex-help-environment (name &optional node) (defun latex-help-environment (name &optional node)
"Lookup the LaTeX environment NAME. "Lookup the LaTeX environment NAME.
@ -234,7 +489,7 @@ Unless NODE is non-nil, if NAME is in more than one node, prompt the user for
which to use. If NODE is non-nil, use that instead." which to use. If NODE is non-nil, use that instead."
(interactive (list (latex-help--prompt-for 'environment))) (interactive (list (latex-help--prompt-for 'environment)))
(when-let (entry (latex-help--maybe-prompt-entry name 'environment node)) (when-let (entry (latex-help--maybe-prompt-entry name 'environment node))
(latex-help--goto-entry entry))) (latex-help--info-goto-entry entry)))
(defun latex-help-package (name &optional node) (defun latex-help-package (name &optional node)
"Lookup the LaTeX package NAME. "Lookup the LaTeX package NAME.
@ -242,7 +497,7 @@ Unless NODE is non-nil, if NAME is in more than one node, prompt the user for
which to use. If NODE is non-nil, use that instead." which to use. If NODE is non-nil, use that instead."
(interactive (list (latex-help--prompt-for 'package))) (interactive (list (latex-help--prompt-for 'package)))
(when-let (entry (latex-help--maybe-prompt-entry name 'package node)) (when-let (entry (latex-help--maybe-prompt-entry name 'package node))
(latex-help--goto-entry entry))) (latex-help--info-goto-entry entry)))
(defun latex-help-class (name &optional node) (defun latex-help-class (name &optional node)
"Lookup the LaTeX document class NAME. "Lookup the LaTeX document class NAME.
@ -250,7 +505,44 @@ Unless NODE is non-nil, if NAME is in more than one node, prompt the user for
which to use. If NODE is non-nil, use that instead." which to use. If NODE is non-nil, use that instead."
(interactive (list (latex-help--prompt-for 'class))) (interactive (list (latex-help--prompt-for 'class)))
(when-let (entry (latex-help--maybe-prompt-entry name 'class node)) (when-let (entry (latex-help--maybe-prompt-entry name 'class node))
(latex-help--goto-entry entry))) (latex-help--info-goto-entry entry)))
(defun latex-help-texdoc (name &optional dir)
"Lookup NAME in the texdoc cache.
When used interactively, prompt for NAME. If DIR is nil, it will be looked up
in the texdoc cache."
(interactive (let ((entry (latex-help--prompt-texdoc-entry)))
(list (car entry) (cdr entry))))
(latex-help--maybe-init-caches)
(when-let ((entry (if dir
(cons name dir)
(assoc name latex-help--texdoc-cache)))
(file (latex-help--texdoc-prompt-for-entry-file entry)))
(latex-help--texdoc-open-file file)))
(defun latex-help--prompt-info-and-texdoc (info-entry texdoc-entry)
"Prompt the user for both info and texdoc entries.
INFO-ENTRY is an entry from one of the info caches. TEXDOC-ENTRY is an entry
from the texdoc cache."
(let* ((texdoc-files (and texdoc-entry
(latex-help--list-texdoc-files-for-entry
texdoc-entry)))
(prompts (nconc (mapcar (lambda (node)
(concat "(Info) " (car node)))
(cdr info-entry))
(mapcar (lambda (file)
(concat "(Texdoc) " (car file)))
texdoc-files))))
(when prompts
(let ((selected (completing-read "LaTeX Help: " prompts nil t)))
(when (string-match (rx bos "(" (group (+ (any (?a . ?z))
(any (?A . ?Z))))
") " (group (* any)))
selected)
(if (equal (match-string 1 selected) "Info")
(cons (assoc (match-string 2 selected) (cdr info-entry)) 'info)
(cons (cdr (assoc (match-string 2 selected) texdoc-files))
'texdoc)))))))
(defun latex-help-at-point () (defun latex-help-at-point ()
"Try to lookup the LaTeX thing at point, whatever it may be. "Try to lookup the LaTeX thing at point, whatever it may be.
@ -258,16 +550,61 @@ This will try to look up the command, package, document class, or environment at
point. If that thing at point is valid, it will open an info buffer to the point. If that thing at point is valid, it will open an info buffer to the
documentation for that thing." documentation for that thing."
(interactive) (interactive)
(latex-help--maybe-init-caches)
(if-let (thing (latex-help--get-thing-at-point)) (if-let (thing (latex-help--get-thing-at-point))
(if-let (entry (latex-help--maybe-prompt-entry (car thing) (let ((info-entry (assoc (car thing) (latex-help--get-cache-for-type
(cdr thing))) (cdr thing))))
(latex-help--goto-entry entry) (texdoc-entry (and (member (cdr thing) '(class package environment))
(assoc (car thing) latex-help--texdoc-cache))))
(unless (or info-entry texdoc-entry)
(user-error "Unknown %s: \"%s\"" (user-error "Unknown %s: \"%s\""
(symbol-name (cdr thing)) (symbol-name (cdr thing))
(if (eq (cdr thing) 'command) (if (eq (cdr thing) 'command)
(concat "\\" (car thing)) (concat "\\" (car thing))
(car thing)))) (car thing))))
(cl-destructuring-bind (thing . type)
(latex-help--prompt-info-and-texdoc info-entry texdoc-entry)
(cl-case type
(texdoc
(latex-help--texdoc-open-file thing))
(info
(latex-help--info-goto-entry thing)))))
(user-error "Nothing at point to look up"))) (user-error "Nothing at point to look up")))
(defvar latex-help--general-history nil
"History for `latex-help'.")
(defun latex-help ()
"Get help with LaTeX.
Prompt the user for an info topic or texdoc file, then open that thing."
(interactive)
(let ((prompts))
(latex-help--maybe-init-caches)
(cl-flet ((add-cache-for-type (type)
(dolist (entry (latex-help--get-cache-for-type type))
(push (format "(Info) %s - %s"
(capitalize (symbol-name type))
(car entry))
prompts))))
(add-cache-for-type 'command)
(add-cache-for-type 'package)
(add-cache-for-type 'class)
(add-cache-for-type 'environment)
(dolist (entry latex-help--texdoc-cache)
(push (format "(Texdoc) %s" (car entry)) prompts))
(when-let ((ans (completing-read "LaTeX Help: " prompts
nil t nil 'latex-help--general-history))
((not (zerop (length ans)))))
(if (string-prefix-p "(Texdoc) " ans)
(latex-help-texdoc (seq-subseq ans (length "(Texdoc) ")))
(string-match (rx "(Info) " (group (+ (not " ")))
" - " (group (+ any)))
ans)
(message "%s %s" (match-string 1 ans) (match-string 2 ans))
(when-let ((thing (match-string 2 ans))
(type (intern (downcase (match-string 1 ans))))
(entry (latex-help--maybe-prompt-entry thing type)))
(latex-help--info-goto-entry entry)))))))
(provide 'latex-help) (provide 'latex-help)
;;; latex-help.el ends here ;;; latex-help.el ends here

View File

@ -764,6 +764,7 @@ to `posframe-show' if the display is graphical."
(my/floating-tooltip " *flycheck-error-posframe*" (my/floating-tooltip " *flycheck-error-posframe*"
(substring message 0 (1- (length message))))))) (substring message 0 (1- (length message)))))))
(use-package consult-flycheck (use-package consult-flycheck
:defer nil
:bind (:map flycheck-mode-map :bind (:map flycheck-mode-map
("C-c C-e" . consult-flycheck))) ("C-c C-e" . consult-flycheck)))
@ -1105,6 +1106,8 @@ otherwise, call `bibtex-find-text'."
:hook ((LaTeX-mode . turn-on-reftex) :hook ((LaTeX-mode . turn-on-reftex)
(LaTeX-mode . LaTeX-math-mode) (LaTeX-mode . LaTeX-math-mode)
(LaTeX-mode . my/-setup-LaTeX-mode)) (LaTeX-mode . my/-setup-LaTeX-mode))
:bind (:map TeX-mode-map
("C-c ?" . latex-help-texdoc))
:init :init
(add-to-list 'major-mode-remap-alist '(plain-tex-mode . plain-TeX-mode)) (add-to-list 'major-mode-remap-alist '(plain-tex-mode . plain-TeX-mode))
(add-to-list 'major-mode-remap-alist '(latex-mode . LaTeX-mode)) (add-to-list 'major-mode-remap-alist '(latex-mode . LaTeX-mode))