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:
parent
fd653f5208
commit
b1c1ff9ee1
3 changed files with 89 additions and 5 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue