diff --git a/elisp/latex-help.el b/elisp/latex-help.el index 2583fc0..c2935a4 100644 --- a/elisp/latex-help.el +++ b/elisp/latex-help.el @@ -8,6 +8,18 @@ ;; Elisp. For example, the original package still assumes that you may not have ;; `add-hook' or `buffer-substring-no-properties'. Only very old versions of ;; Emacs are missing these, so almost everyone has them nowadays. +;; +;; This file is mostly internal functions. People looking to use this are +;; probably only interested in the following commands: +;; - `latex-help-command' +;; - `latex-help-environment' +;; - `latex-help-package' +;; - `latex-help-class' +;; - `latex-help-texdoc' +;; - `latex-help-at-point' +;; - `latex-help' +;; The configuration options controlling these can be found by running +;; M-x customize-group RET latex-help RET ;;; Code: (require 'info) @@ -37,6 +49,11 @@ :group 'latex-help :type '(string :tag "Executable name")) +(defcustom latex-help-max-texdoc-entries 10 + "Maximum number of texdoc entries to show when prompting." + :group 'latex-help + :type 'interger) + (defcustom latex-help-pdf-view-program '(emacs "evince") "The program to use to view PDF documentation files." :group 'latex-help @@ -52,7 +69,7 @@ (function :tag "Use a custom function as a backup"))))) (defcustom latex-help-html-view-program 'emacs - "The program to use to view PDF documentation files." + "The program to use to view HTML documentation files." :group 'latex-help :type '(choice (string :tag "External program") @@ -259,10 +276,7 @@ A marker file is a file that signifies that its parent is a texdoc entry." (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) + (push (file-name-nondirectory dir) found) ;; search all subdirs (setq to-search (nconc to-search @@ -274,19 +288,59 @@ A marker file is a file that signifies that its parent is a texdoc entry." files))))) finally return found)) +(defun latex-help--texdoc-config-files () + "Return a list of texdoc config files." + (with-temp-buffer + (call-process latex-help-texdoc-program nil t nil "--files") + ;; goto line 3 + (goto-char (point-min)) + (forward-line 2) + (cl-loop while (re-search-forward (rx bol (+ " ") "active" "\t" + (group (+ any)) eol) nil t) + collect (match-string 1)))) + +(defun latex-help--texdoc-config-file-entries (file) + "Parse the texdoc config file FILE to find entries. +This attempts to find entries that might have been missed during the initial +scan. The return value is a list of cahce entries with the second element being +nil (signifying that we don't know the directory they below to)." + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (let ((found)) + (while (re-search-forward (rx bol "adjscore(" + (group (+ (not ")"))) ")") + nil t) + (push (match-string 1) found)) + (while (re-search-forward + (rx bol "alias" (? "(" (+ (any (?0 . ?9) ".")) ")") + " " (group (+ (not " "))) + " = " (group (* (not (any "#" "\n" " "))))) + nil t) + (push (match-string 1) found) + (let ((m2 (match-string 2))) + (unless (or (zerop (length m2)) + (seq-contains-p m2 ?/)) + (push m2 found)))) + 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))) + (let ((output)) + (dolist (root latex-help-documentation-roots) + (setq output (nconc output (latex-help--search-texdoc-root root)))) + (dolist (file (latex-help--texdoc-config-files)) + (setq output (nconc output (latex-help--texdoc-config-file-entries file)))) + (seq-uniq output))) (defun latex-help--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. The first item the the returned -list is the default value when prompting with `completing-read'." +This returns a list of conses of the display name of the entry and the file it +belongs to. The first item the the returned list is the default value when +prompting with `completing-read'." (with-temp-buffer (when-let ((exit-code (call-process latex-help-texdoc-program nil t - nil "-Ml" (car entry))) + nil "-Ml" entry)) ((not (zerop exit-code)))) ;; try to get the programs output without the normal Emacs process ;; sentinel message @@ -301,25 +355,21 @@ list is the default value when prompting with `completing-read'." "")))) ;; 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)) - (relname (file-relative-name (match-string 1) - (cdr entry))) - (desc (match-string 2)) - (prompt (if (zerop (length desc)) - relname - (format "%s (%s)" desc relname)))) - ;; check if the file is actually belongs to this entry - (when (string-prefix-p (cdr entry) file) - (push (cons prompt file) found)))) - (nreverse found)))) + (cl-loop repeat latex-help-max-texdoc-entries + while (re-search-forward (rx (and bol (= 2 (+ (not "\t")) "\t") + (group (+ (not "\t"))) + "\t" + (? (+ (not "\t"))) + "\t" + (group (* any)))) + nil t) + for file = (match-string 1) + for desc = (match-string 2) + unless (zerop (length desc)) + collect (cons (format "%s (%s)" desc file) file) + else + collect (cons (format "%s (%s)" (file-name-nondirectory file) file) + file)))) (defun latex-help--texdoc-prompt-for-entry-file (entry) "Prompt the user to open a texdoc file from ENTRY. @@ -337,22 +387,20 @@ This will return nil if the user does not want to open the file." "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." + "Ask the user for a texdoc entry." (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))) + (member (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 + latex-help--texdoc-cache + nil nil nil 'latex-help--texdoc-history (and has-default-p (car tap))))) (unless (zerop (length ans)) - (assoc ans latex-help--texdoc-cache)))) + ans))) (defun latex-help--run-index-search (regexp) "Search the LaTeX info pages index for REGEXP. @@ -479,6 +527,7 @@ This returns the name of the thing that was prompted." nil t nil 'latex-help--info-history default))) +;;;###autoload (defun latex-help-command (name &optional node) "Lookup the LaTeX command NAME. Unless NODE is non-nil, if NAME is in more than one node, prompt the user for @@ -487,6 +536,7 @@ which to use. If NODE is non-nil, use that instead." (when-let (entry (latex-help--maybe-prompt-entry name 'command node)) (latex-help--info-goto-entry entry))) +;;;###autoload (defun latex-help-environment (name &optional node) "Lookup the LaTeX environment NAME. Unless NODE is non-nil, if NAME is in more than one node, prompt the user for @@ -495,6 +545,7 @@ which to use. If NODE is non-nil, use that instead." (when-let (entry (latex-help--maybe-prompt-entry name 'environment node)) (latex-help--info-goto-entry entry))) +;;;###autoload (defun latex-help-package (name &optional node) "Lookup the LaTeX package NAME. Unless NODE is non-nil, if NAME is in more than one node, prompt the user for @@ -503,6 +554,7 @@ which to use. If NODE is non-nil, use that instead." (when-let (entry (latex-help--maybe-prompt-entry name 'package node)) (latex-help--info-goto-entry entry))) +;;;###autoload (defun latex-help-class (name &optional node) "Lookup the LaTeX document class NAME. Unless NODE is non-nil, if NAME is in more than one node, prompt the user for @@ -511,17 +563,14 @@ which to use. If NODE is non-nil, use that instead." (when-let (entry (latex-help--maybe-prompt-entry name 'class node)) (latex-help--info-goto-entry entry))) -(defun latex-help-texdoc (name &optional dir) +;;;###autoload +(defun latex-help-texdoc (name) "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)))) + (interactive (list (latex-help--prompt-texdoc-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))) + (when-let ((file (latex-help--texdoc-prompt-for-entry-file name))) (latex-help--texdoc-open-file file))) (defun latex-help--prompt-info-and-texdoc (info-entry texdoc-entry) @@ -550,6 +599,7 @@ from the texdoc cache." (cons (cdr (assoc (match-string 2 selected) texdoc-files)) 'texdoc))))))) +;;;###autoload (defun latex-help-at-point () "Try to lookup the LaTeX thing at point, whatever it may be. This will try to look up the command, package, document class, or environment at @@ -561,7 +611,8 @@ documentation for that thing." (let ((info-entry (assoc (car thing) (latex-help--get-cache-for-type (cdr thing)))) (texdoc-entry (and (member (cdr thing) '(class package environment)) - (assoc (car thing) latex-help--texdoc-cache)))) + (cl-find (car thing) latex-help--texdoc-cache + :test 'equal)))) (unless (or info-entry texdoc-entry) (user-error "Unknown %s: \"%s\"" (symbol-name (cdr thing)) @@ -580,6 +631,7 @@ documentation for that thing." (defvar latex-help--general-history nil "History for `latex-help'.") +;;;###autoload (defun latex-help () "Get help with LaTeX. Prompt the user for an info topic or texdoc file, then open that thing." @@ -597,7 +649,7 @@ Prompt the user for an info topic or texdoc file, then open that thing." (add-cache-for-type 'class) (add-cache-for-type 'environment) (dolist (entry latex-help--texdoc-cache) - (push (format "(Texdoc) %s" (car entry)) prompts)) + (push (format "(Texdoc) %s" entry) prompts)) (when-let ((ans (completing-read "LaTeX Help: " prompts nil t nil 'latex-help--general-history)) ((not (zerop (length ans))))) @@ -606,7 +658,6 @@ Prompt the user for an info topic or texdoc file, then open that thing." (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))) diff --git a/init.el b/init.el index 80838f5..49db404 100644 --- a/init.el +++ b/init.el @@ -24,6 +24,7 @@ package-user-dir "~/.emacs.d/var/elpa") (require 'use-package)) + ;; no-littering (use-package no-littering :autoload (no-littering-theme-backups @@ -141,6 +142,7 @@ fill-column 80 comment-multi-line t comment-empty-lines 'eol) + (add-to-list 'auto-mode-alist '("\\.[cC][nN][fF]\\'" . conf-mode)) ;; Tree sitter download locations (setq treesit-language-source-alist @@ -444,7 +446,8 @@ directory. Otherwise, run `find-file' on that file." :config (define-key evil-cleverparens-mode-map (kbd " M-o") nil t) (defun my/-enable-evil-cleverparens () - (if (member major-mode '(lisp-mode emacs-lisp-mode)) + (if (member major-mode '(lisp-mode emacs-lisp-mode + lisp-interaction-mode)) (evil-cleverparens-mode 1) (electric-pair-local-mode 1))))