1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

docview: imenu access to table of contents

* lisp/doc-view.el (doc-view-imenu-enabled): user option to disable
imenu generation.
* lisp/doc-view.el (doc-view--outline-rx):
(doc-view--pdf-outline, doc-view--imenu-subtree, doc-view-imenu-index):
functions implementing the imenu index generation via mutool.
* lisp/doc-view.el (doc-view-imenu-setup, doc-view-mode): setup of the
new functionality in doc-view mode.
* lisp/imenu.el (imenu-submenus-on-top):
(imenu--split-menu): new local variable to optionally inhibit
grouping of entries with children at the top of imenu menus.
* doc/emacs/misc.texi: documentation for the new functionality
(bug#58103).
This commit is contained in:
Jose A. Ortega Ruiz 2022-09-27 13:53:24 +02:00 committed by Lars Ingebrigtsen
parent fd653f5208
commit b1c1ff9ee1
3 changed files with 89 additions and 5 deletions

View file

@ -584,6 +584,13 @@ you instead want the image to be re-rendered at the new size, set
default size for DocView, customize the variable default size for DocView, customize the variable
@code{doc-view-resolution}. @code{doc-view-resolution}.
@vindex doc-view-imenu-enabled
When the @command{mutool} executable is available, DocView will use
to generate entries for an outline menu, making it accessible via the
imenu facility (@pxref{Imenu}). To disable this functionality even
when @command{mutool} can be found in your @code{exec-path}, customize
the variable @code{doc-view-imenu-enabled}.
@node DocView Searching @node DocView Searching
@subsection DocView Searching @subsection DocView Searching

View file

@ -214,6 +214,11 @@ are available (see Info node `(emacs)Document View')."
:type 'boolean :type 'boolean
:version "29.1") :version "29.1")
(defcustom doc-view-imenu-enabled (and (executable-find "mutool") t)
"Whether to generate an imenu outline when mutool is available."
:type 'boolean
:version "29.1")
(defcustom doc-view-svg-background "white" (defcustom doc-view-svg-background "white"
"Background color for svg images. "Background color for svg images.
See `doc-view-mupdf-use-svg'." See `doc-view-mupdf-use-svg'."
@ -1874,6 +1879,69 @@ If BACKWARD is non-nil, jump to the previous match."
(y-or-n-p "No more matches before current page. Wrap to last match? ")) (y-or-n-p "No more matches before current page. Wrap to last match? "))
(doc-view-goto-page (caar (last doc-view--current-search-matches))))))) (doc-view-goto-page (caar (last doc-view--current-search-matches)))))))
;;;; Imenu support
(defconst doc-view--outline-rx
"[^\t]+\\(\t+\\)\"\\(.+\\)\"\t#\\(?:page=\\)?\\([0-9]+\\)")
(defun doc-view--pdf-outline (&optional file-name)
"Return a describing the outline of FILE-NAME (or current if nil).
Each element in the list contains information about a section's
title, nesting level and page number. The list is flat: its tree
structure is extracted by `doc-view--imenu-subtree'."
(let* ((outline nil)
(fn (or file-name (buffer-file-name)))
(fn (shell-quote-argument (expand-file-name fn))))
(with-temp-buffer
(insert (shell-command-to-string (format "mutool show %s outline" fn)))
(goto-char (point-min))
(while (re-search-forward doc-view--outline-rx nil t)
(push `((level . ,(length (match-string 1)))
(title . ,(match-string 2))
(page . ,(string-to-number (match-string 3))))
outline)))
(nreverse outline)))
(defun doc-view--imenu-subtree (outline act)
"Construct a tree of imenu items for the given outline list and action.
This auxliary function constructs recursively all the items for
the first node in the outline and all its siblings at the same
level. Returns that imenu alist together with any other pending outline
entries at an upper level."
(let ((level (alist-get 'level (car outline)))
(index nil))
(while (and (car outline) (<= level (alist-get 'level (car outline))))
(let-alist (car outline)
(let ((title (format "%s (%s)" .title .page)))
(if (> .level level)
(let ((sub (doc-view--imenu-subtree outline act))
(fst (car index)))
(setq index (cdr index))
(push (cons (car fst) (cons fst (car sub))) index)
(setq outline (cdr sub)))
(push `(,title 0 ,act ,.page) index)
(setq outline (cdr outline))))))
(cons (nreverse index) outline)))
(defun doc-view-imenu-index (&optional file-name goto-page-fn)
"Create an imenu index using mutool to extract its outline.
For extensibility, a FILE-NAME other than the current buffer and
a jumping function, GOTO-PAGE-FN other than `doc-view-goto-page'
can be specified."
(let* ((goto (or goto-page-fn 'doc-view-goto-page))
(act (lambda (_name _pos page) (funcall goto page))))
(car (doc-view--imenu-subtree (doc-view--pdf-outline file-name) act))))
(defun doc-view-imenu-setup ()
"Set up local state in the current buffer for imenu, if needed."
(when (and doc-view-imenu-enabled (executable-find "mutool"))
(setq-local imenu-create-index-function #'doc-view-imenu-index
imenu-submenus-on-top nil
imenu-sort-function nil)
(imenu-add-to-menubar "Outline")))
;;;; User interface commands and the mode ;;;; User interface commands and the mode
(put 'doc-view-mode 'mode-class 'special) (put 'doc-view-mode 'mode-class 'special)
@ -2047,7 +2115,7 @@ If BACKWARD is non-nil, jump to the previous match."
"Major mode in DocView buffers. "Major mode in DocView buffers.
DocView Mode is an Emacs document viewer. It displays PDF, PS DocView Mode is an Emacs document viewer. It displays PDF, PS
and DVI files (as PNG images) in Emacs buffers. and DVI files (as PNG or SVG images) in Emacs buffers.
You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to
toggle between displaying the document or editing it as text. toggle between displaying the document or editing it as text.
@ -2142,6 +2210,7 @@ toggle between displaying the document or editing it as text.
(setq mode-name "DocView" (setq mode-name "DocView"
buffer-read-only t buffer-read-only t
major-mode 'doc-view-mode) major-mode 'doc-view-mode)
(doc-view-imenu-setup)
(doc-view-initiate-display) (doc-view-initiate-display)
;; Switch off view-mode explicitly, because doc-view-mode is the ;; Switch off view-mode explicitly, because doc-view-mode is the
;; canonical view mode for PDF/PS/DVI files. This could be ;; canonical view mode for PDF/PS/DVI files. This could be

View file

@ -208,6 +208,13 @@ called within a `save-excursion'.
See `imenu--index-alist' for the format of the buffer index alist.") See `imenu--index-alist' for the format of the buffer index alist.")
;;;###autoload
(defvar-local imenu-submenus-on-top t
"Flag specifiying whether items with sublists should be kept at top.
For some indexes, such as those describing sections in a document, it
makes sense to keep their original order even in the menubar.")
;;;###autoload ;;;###autoload
(defvar-local imenu-prev-index-position-function 'beginning-of-defun (defvar-local imenu-prev-index-position-function 'beginning-of-defun
"Function for finding the next index position. "Function for finding the next index position.
@ -373,10 +380,11 @@ The returned alist DOES NOT share structure with MENULIST."
(if (memq imenu--rescan-item menulist) (if (memq imenu--rescan-item menulist)
(setq keep-at-top (list imenu--rescan-item) (setq keep-at-top (list imenu--rescan-item)
menulist (delq imenu--rescan-item menulist))) menulist (delq imenu--rescan-item menulist)))
(dolist (item menulist) (if imenu-submenus-on-top
(when (imenu--subalist-p item) (dolist (item menulist)
(push item keep-at-top) (when (imenu--subalist-p item)
(setq menulist (delq item menulist)))) (push item keep-at-top)
(setq menulist (delq item menulist)))))
(if imenu-sort-function (if imenu-sort-function
(setq menulist (sort menulist imenu-sort-function))) (setq menulist (sort menulist imenu-sort-function)))
(if (> (length menulist) imenu-max-items) (if (> (length menulist) imenu-max-items)