unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#58103: [PATCH] docview: imenu access to table of contents
@ 2022-09-27  5:41 Jose A Ortega Ruiz
  2022-09-27 11:53 ` Lars Ingebrigtsen
  2022-09-28 22:00 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 6+ messages in thread
From: Jose A Ortega Ruiz @ 2022-09-27  5:41 UTC (permalink / raw)
  To: 58103

[-- Attachment #1: Type: text/plain, Size: 1107 bytes --]

Tags: patch


Hi,

The patch below provides a quite simple implemetation of an imenu for
doc-view, using mutool.  That means of course that is limited to systems
where it's installed, and doesn't try to be too smart, but it's been
working quite well for me.  It needs a slight tweak to imenu.el to add a
knob inhibiting it to push all entries with submenus to the top, which
doesn't make sense when those entries represent sections of a TOC.

If this is acceptable (with any needed modification, of course), i guess
we could also add a bit of further customization, like perhaps a "flat
mode", or whether or not the section titles include page numbers, but
i'm not sure if that's desired (in my usage, i never want either).

Cheers,
jao


In GNU Emacs 29.0.50 (build 8, x86_64-pc-linux-gnu, GTK+ Version
 3.24.34, cairo version 1.16.0) of 2022-09-26 built on rivendell
Repository revision: adcdea5d159540aa09892f410bd3a5163eebecf2
Repository branch: master
System Description: Debian GNU/Linux bookworm/sid

Configured using:
 'configure -C --prefix=/usr/local/stow/pemacs --with-pgtk
 --with-imagemagick'


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-docview-imenu-access-to-table-of-contents.patch --]
[-- Type: text/patch, Size: 7419 bytes --]

From 37d46e61a194c87293a2e4ed54495a9436bd5422 Mon Sep 17 00:00:00 2001
From: Jose A Ortega Ruiz <jao@gnu.org>
Date: Tue, 27 Sep 2022 05:45:00 +0100
Subject: [PATCH] docview: imenu access to table of contents

When mutool is available, use it to extract a table of contents of
supported documents and make it available via imenu.
* 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.
---
 doc/emacs/misc.texi |  7 +++++
 lisp/doc-view.el    | 71 ++++++++++++++++++++++++++++++++++++++++++++-
 lisp/imenu.el       | 16 +++++++---
 3 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 10b44028bb..f3a6e6c33b 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -584,6 +584,13 @@ DocView Navigation
 default size for DocView, customize the variable
 @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
 @subsection DocView Searching
 
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index fbd1427946..fe772efcfc 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -214,6 +214,11 @@ doc-view-mupdf-use-svg
   :type 'boolean
   :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"
   "Background color for svg images.
 See `doc-view-mupdf-use-svg'."
@@ -1874,6 +1879,69 @@ doc-view-search-previous-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)))))))
 
+;;;; 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
 
 (put 'doc-view-mode 'mode-class 'special)
@@ -2047,7 +2115,7 @@ doc-view-mode
   "Major mode in DocView buffers.
 
 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
 toggle between displaying the document or editing it as text.
@@ -2142,6 +2210,7 @@ doc-view-mode
     (setq mode-name "DocView"
 	  buffer-read-only t
 	  major-mode 'doc-view-mode)
+    (doc-view-imenu-setup)
     (doc-view-initiate-display)
     ;; Switch off view-mode explicitly, because doc-view-mode is the
     ;; canonical view mode for PDF/PS/DVI files.  This could be
diff --git a/lisp/imenu.el b/lisp/imenu.el
index c407f501d6..bfc2429100 100644
--- a/lisp/imenu.el
+++ b/lisp/imenu.el
@@ -208,6 +208,13 @@ imenu-create-index-function
 
 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
 (defvar-local imenu-prev-index-position-function 'beginning-of-defun
   "Function for finding the next index position.
@@ -373,10 +380,11 @@ imenu--split-menu
     (if (memq imenu--rescan-item menulist)
 	(setq keep-at-top (list imenu--rescan-item)
 	      menulist (delq imenu--rescan-item menulist)))
-    (dolist (item menulist)
-      (when (imenu--subalist-p item)
-	(push item keep-at-top)
-	(setq menulist (delq item menulist))))
+    (if imenu-submenus-on-top
+        (dolist (item menulist)
+          (when (imenu--subalist-p item)
+	    (push item keep-at-top)
+	    (setq menulist (delq item menulist)))))
     (if imenu-sort-function
 	(setq menulist (sort menulist imenu-sort-function)))
     (if (> (length menulist) imenu-max-items)
-- 
2.37.2


[-- Attachment #3: Type: text/plain, Size: 132 bytes --]


-- 
Give a man a fish and you feed him for a day. Write a program to fish for him
and you maintain it for a lifetime. - Tim Hopper

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#58103: [PATCH] docview: imenu access to table of contents
  2022-09-27  5:41 bug#58103: [PATCH] docview: imenu access to table of contents Jose A Ortega Ruiz
@ 2022-09-27 11:53 ` Lars Ingebrigtsen
  2022-09-27 16:18   ` Jose A Ortega Ruiz
  2022-09-28 22:00 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 6+ messages in thread
From: Lars Ingebrigtsen @ 2022-09-27 11:53 UTC (permalink / raw)
  To: Jose A Ortega Ruiz; +Cc: 58103

Jose A Ortega Ruiz <jao@gnu.org> writes:

> The patch below provides a quite simple implemetation of an imenu for
> doc-view, using mutool.  That means of course that is limited to systems
> where it's installed, and doesn't try to be too smart, but it's been
> working quite well for me. 

Looks good to me; pushed to Emacs 29.

(Using `let-alist' is pretty unusual, but I guess it's nice that
somebody does -- there only seems to be two other usages in-tree in
Emacs since this was added in 2014.  🙃)





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#58103: [PATCH] docview: imenu access to table of contents
  2022-09-27 11:53 ` Lars Ingebrigtsen
@ 2022-09-27 16:18   ` Jose A Ortega Ruiz
  0 siblings, 0 replies; 6+ messages in thread
From: Jose A Ortega Ruiz @ 2022-09-27 16:18 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58103

On Tue, Sep 27 2022, Lars Ingebrigtsen wrote:

> Jose A Ortega Ruiz <jao@gnu.org> writes:
>
>> The patch below provides a quite simple implemetation of an imenu for
>> doc-view, using mutool.  That means of course that is limited to systems
>> where it's installed, and doesn't try to be too smart, but it's been
>> working quite well for me. 
>
> Looks good to me; pushed to Emacs 29.

excellent, thanks a lot!

> (Using `let-alist' is pretty unusual, but I guess it's nice that
> somebody does -- there only seems to be two other usages in-tree in
> Emacs since this was added in 2014.  🙃)

i find it handy when the let body is small, otherwise it can make things
harder to read.  but i'm not specially attached to it if we prefer more
idiomatic ways.

cheers,
jao





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#58103: [PATCH] docview: imenu access to table of contents
  2022-09-27  5:41 bug#58103: [PATCH] docview: imenu access to table of contents Jose A Ortega Ruiz
  2022-09-27 11:53 ` Lars Ingebrigtsen
@ 2022-09-28 22:00 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-28 22:53   ` Jose A Ortega Ruiz
  1 sibling, 1 reply; 6+ messages in thread
From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-28 22:00 UTC (permalink / raw)
  To: Jose A Ortega Ruiz; +Cc: 58103

Jose A Ortega Ruiz <jao@gnu.org> writes:

> Tags: patch
>
>
> Hi,
>
> The patch below provides a quite simple implemetation of an imenu for
> doc-view, using mutool.  That means of course that is limited to systems
> where it's installed, and doesn't try to be too smart, but it's been
> working quite well for me.  It needs a slight tweak to imenu.el to add a
> knob inhibiting it to push all entries with submenus to the top, which
> doesn't make sense when those entries represent sections of a TOC.
>
> If this is acceptable (with any needed modification, of course), i guess
> we could also add a bit of further customization, like perhaps a "flat
> mode", or whether or not the section titles include page numbers, but
> i'm not sure if that's desired (in my usage, i never want either).

Thanks for working on this! I've given it a try, and I get the following
error when the PDF does not have an outline (starting from emacs -Q):

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  string-match("\\`%PDF-1\\'" nil)
  imenu-find-default("%PDF-1" (("*Rescan*" . -99) (nil)))
  imenu--completion-buffer((("*Rescan*" . -99) nil) nil)
  imenu-choose-buffer-index()
  byte-code("\300 C\207" [imenu-choose-buffer-index] 1)
  call-interactively(imenu record nil)
  command-execute(imenu record)
  execute-extended-command(nil "imenu" "imenu")
  funcall-interactively(execute-extended-command nil "imenu" "imenu")
  call-interactively(execute-extended-command nil nil)
  command-execute(execute-extended-command)

Can you reproduce the same issue as well?  I'm using mutool version
1.19.0.

In GNU Emacs 29.0.50 (build 8, aarch64-apple-darwin21.6.0, NS
 appkit-2113.60 Version 12.6 (Build 21G115)) of 2022-09-28 built on
 Daniels-MacBook-Pro.local
Repository revision: b6a163ba7cdf57eff5542b4cb6956780ebb2880f
Repository branch: master
Windowing system distributor 'Apple', version 10.3.2113
System Description:  macOS 12.6

Configured using:
 'configure CPPFLAGS=-I/opt/homebrew/opt/openjdk@11/include'

Configured features:
ACL DBUS GLIB GNUTLS JSON LCMS2 LIBXML2 MODULES NOTIFY KQUEUE NS PDUMPER
PNG RSVG SQLITE3 THREADS TOOLKIT_SCROLL_BARS WEBP XIM ZLIB





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#58103: [PATCH] docview: imenu access to table of contents
  2022-09-28 22:00 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-09-28 22:53   ` Jose A Ortega Ruiz
  2022-09-29 12:48     ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 6+ messages in thread
From: Jose A Ortega Ruiz @ 2022-09-28 22:53 UTC (permalink / raw)
  To: Daniel Martín; +Cc: 58103


Hi Daniel,

[...]

> Thanks for working on this! I've given it a try, and I get the following
> error when the PDF does not have an outline (starting from emacs -Q):

Hmm, i cannot reproduce it. When i try for instance M-g i for a PDF
without outline i just get back an error message telling me that there
is no imenu.

I have mutool 1.20, so maybe that's the difference.  What's the output
of this command in a terminal for you:

     mutool show file.pdf outline    

with file.pdf one of those without an outline?  Do you have any
imenu-related variable customized to a non-default value?

Thanks for your help,
jao
-- 
The mind commands the body and the body obeys. The mind commands itself and
finds resistance.
 -St. Augustine (354-430)





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#58103: [PATCH] docview: imenu access to table of contents
  2022-09-28 22:53   ` Jose A Ortega Ruiz
@ 2022-09-29 12:48     ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-29 12:48 UTC (permalink / raw)
  To: Jose A Ortega Ruiz; +Cc: 58103

Jose A Ortega Ruiz <jao@gnu.org> writes:

> I have mutool 1.20, so maybe that's the difference.  What's the output
> of this command in a terminal for you:
>
>      mutool show file.pdf outline    
>
> with file.pdf one of those without an outline?  Do you have any
> imenu-related variable customized to a non-default value?

The above command does not print any output if the PDF does not have an
outline.  And I haven't configured any imenu variable, I tested with
plain emacs -Q.

Thanks.





^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-09-29 12:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27  5:41 bug#58103: [PATCH] docview: imenu access to table of contents Jose A Ortega Ruiz
2022-09-27 11:53 ` Lars Ingebrigtsen
2022-09-27 16:18   ` Jose A Ortega Ruiz
2022-09-28 22:00 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-28 22:53   ` Jose A Ortega Ruiz
2022-09-29 12:48     ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).