unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Visuwesh <visuweshm@gmail.com>
To: Tassilo Horn <tsdh@gnu.org>
Cc: Eli Zaretskii <eliz@gnu.org>, "Jose A. Ortega Ruiz" <jao@gnu.org>,
	73530@debbugs.gnu.org
Subject: bug#73530: [PATCH] Add imenu index function for Djvu files in doc-view
Date: Thu, 03 Oct 2024 20:21:46 +0530	[thread overview]
Message-ID: <87ldz5ck8t.fsf@gmail.com> (raw)
In-Reply-To: <87bk01obpf.fsf@gnu.org> (Tassilo Horn's message of "Thu, 03 Oct 2024 10:03:08 +0200")

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

[வியாழன் அக்டோபர் 03, 2024] Tassilo Horn wrote:

>>>> For DjVu, my sample size is 1, and that's a presentation, so at least
>>>> here I'm not sure if there should be an index available...
>>>
>>> I will send the link to the DjVu file that I wrote the feature for
>>> off-list.  I will send a link to a PDF file too.
>>
>> Thanks, will try with those two files.
>
> I did so now and it is blazingly fast for those 80+mb PDF/DjVu files
> even on my almost 10 years old laptop, so I'd say your simpler approach
> is the right choice.
>
>>> On this note, should we use doc-view-pdfdraw-program in place of
>>> mutool in doc-view--pdf-outline?
>>
>> Yes, but only if the older names pdfdraw and mudraw already had the
>> "show <file> outline" feature.
>
> I revert the "but only if" part.  If mupdf is old and comes with, e.g.,
> the pdfdraw executable, chances are almost zero that mutool is
> installed, too.  And if it is, then we should prefer it anywhere.  So I
> think the way to go is to (executable-find "mutool") in
> doc-view-pdfdraw-program first so that it takes precedence and use
> doc-view-pdfdraw-program in doc-view--pdf-outline.
>
>>>> Well, I actually have no strong opinion here.  Technically, I like
>>>> your approach better because of its simplicity.  I would like to test
>>>> with some larger documents to see how long index building takes,
>>>> though.
>>>
>>> I tried the function with a large PDF file:
>>
>> Will try with the large two you've linked later.
>
> As said above, it's more than fast enough, so let's take your approach.

I have now attached a patch with the above change.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-imenu-index-function-for-DjVu-files-in-doc-view.patch --]
[-- Type: text/x-diff, Size: 10574 bytes --]

From 441f0e9339a853ac011d08c8754fc5c9217d146f Mon Sep 17 00:00:00 2001
From: Visuwesh <visuweshm@gmail.com>
Date: Wed, 2 Oct 2024 13:48:25 +0530
Subject: [PATCH] Add imenu index function for DjVu files in doc-view

* lisp/doc-view.el (doc-view-pdfdraw-program): Prefer mutool
over other names.
(doc-view-imenu-enabled): Tweak the default value to check for
'djvused', and make it obsolete.
(doc-view--djvu-outline, doc-view--parse-djvu-outline): Add new
functions to return imenu index for a Djvu file.
(doc-view--outline): Add new function to create the imenu index
depending on the file type.
(doc-view--outline): Document new possible variable value.
(doc-view-imenu-index): Use the above function instead.
(doc-view-imenu-setup): Try to create the imenu index
unconditionally.
* doc/emacs/misc.texi (DocView Navigation): Mention index
creation using 'djvused' too.
* etc/NEWS: Announce the change.  (Bug#73530)
---
 doc/emacs/misc.texi |  18 ++++----
 etc/NEWS            |   7 +++
 lisp/doc-view.el    | 108 ++++++++++++++++++++++++++++++++++++--------
 3 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index b074eb034b2..7b11a829b0b 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -581,17 +581,17 @@ DocView Navigation
 default size for DocView, customize the variable
 @code{doc-view-resolution}.
 
-@vindex doc-view-imenu-enabled
 @vindex doc-view-imenu-flatten
 @vindex doc-view-imenu-format
-  When the @command{mutool} program is available, DocView will use it
-to generate entries for an outline menu, making it accessible via the
-@code{imenu} facility (@pxref{Imenu}).  To disable this functionality
-even when @command{mutool} can be found on your system, customize the
-variable @code{doc-view-imenu-enabled} to the @code{nil} value.  You
-can further customize how @code{imenu} items are formatted and
-displayed using the variables @code{doc-view-imenu-format} and
-@code{doc-view-imenu-flatten}.
+@vindex doc-view-djvused-program
+  DocView can generate an outline menu for PDF and DjVu documents using
+the @command{mutool} and the @command{djvused} programs respectively
+when they are available.  This is made accessible via the @code{imenu}
+facility (@pxref{Imenu}).  You can customize how @code{imenu} items are
+formatted and displayed using the variables @code{doc-view-imenu-format}
+and @code{doc-view-imenu-flatten}.  The filename of the
+@command{djvused} program can be customized by changing the
+@code{doc-view-djvused-program} user option.
 
 @cindex registers, in DocView mode
 @findex doc-view-page-to-register
diff --git a/etc/NEWS b/etc/NEWS
index abe316547aa..bbcef80b762 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -351,6 +351,13 @@ Docview can store current page to buffer-local registers with the new
 command 'doc-view-page-to-register' (bound to 'm'), and later the stored
 page can be restored with 'doc-view-jump-to-register' (bound to ''').
 
++++
+*** Docview can generate imenu index for DjVu files.
+When the 'djvused' program is available, Docview can now generate imenu
+index for DjVu files from its outline.
+The name of the 'djvused' program can be customized by changing the user
+option 'doc-view-djvused-program'.
+
 ** Tramp
 
 +++
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index e79295a8b01..3683f1f60d4 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -27,8 +27,10 @@
 ;; `pdftotext', which comes with xpdf (https://www.foolabs.com/xpdf/)
 ;; or poppler (https://poppler.freedesktop.org/). EPUB, CBZ, FB2, XPS
 ;; and OXPS documents require `mutool' which comes with mupdf
-;; (https://mupdf.com/index.html). Djvu documents require `ddjvu'
+;; (https://mupdf.com/index.html). DjVu documents require `ddjvu'
 ;; (from DjVuLibre).  ODF files require `soffice' (from LibreOffice).
+;; `djvused' (from DjVuLibre) can be optionally used to generate imenu
+;; outline for DjVu documents when available.
 
 ;;; Commentary:
 
@@ -185,13 +187,13 @@ doc-view-ghostscript-program
 
 (defcustom doc-view-pdfdraw-program
   (cond
+   ((executable-find "mutool") "mutool")
    ((executable-find "pdfdraw") "pdfdraw")
    ((executable-find "mudraw") "mudraw")
-   ((executable-find "mutool") "mutool")
    (t "mudraw"))
   "Name of MuPDF's program to convert PDF files to PNG."
   :type 'file
-  :version "24.4")
+  :version "31.1")
 
 (defcustom doc-view-pdftotext-program-args '("-raw")
   "Parameters to give to the pdftotext command."
@@ -216,10 +218,23 @@ doc-view-mupdf-use-svg
   :type 'boolean
   :version "30.1")
 
-(defcustom doc-view-imenu-enabled (and (executable-find "mutool") t)
-  "Whether to generate an imenu outline when \"mutool\" is available."
+(defcustom doc-view-djvused-program (and (executable-find "djvused")
+                                         "djvused")
+  "Name of \"djvused\" program to generate imenu outline for DjVu files.
+This is part of DjVuLibre."
+  :type 'file
+  :version "31.1")
+
+(defcustom doc-view-imenu-enabled (and (or (executable-find "mutool")
+                                           (executable-find "djvused"))
+                                       t)
+  "Whether to generate imenu outline for PDF and DjVu files.
+This uses \"mutool\" for PDF files and \"djvused\" for DjVu files."
   :type 'boolean
-  :version "29.1")
+  :version "31.1")
+(make-obsolete-variable 'doc-view-imenu-enabled
+   "Imenu index is generated unconditionally when available."
+   "31.1")
 
 (defcustom doc-view-imenu-title-format "%t (%p)"
   "Format spec for imenu's display of section titles from docview documents.
@@ -1958,7 +1973,9 @@ doc-view--outline-rx
   "[^\t]+\\(\t+\\)\"\\(.+\\)\"\t#\\(?:page=\\)?\\([0-9]+\\)")
 
 (defvar-local doc-view--outline nil
-  "Cached PDF outline, so that it is only computed once per document.")
+  "Cached PDF outline, so that it is only computed once per document.
+It can be the symbol `unavailable' to indicate that outline is
+unavailable for the document.")
 
 (defun doc-view--pdf-outline (&optional file-name)
   "Return a list describing the outline of FILE-NAME.
@@ -1972,7 +1989,9 @@ doc-view--pdf-outline
       (let ((outline nil)
             (fn (expand-file-name fn)))
         (with-temp-buffer
-          (unless (eql 0 (call-process "mutool" nil (current-buffer) nil "show" fn "outline"))
+          (unless (eql 0 (call-process doc-view-pdfdraw-program nil
+                                       (current-buffer) nil "show" fn "outline"))
+            (setq doc-view--outline 'unavailable)
             (imenu-unavailable-error "Unable to create imenu index using `mutool'"))
           (goto-char (point-min))
           (while (re-search-forward doc-view--outline-rx nil t)
@@ -1983,6 +2002,42 @@ doc-view--pdf-outline
                   outline)))
         (nreverse outline)))))
 
+(defun doc-view--djvu-outline (&optional file-name)
+  "Return a list describing the outline of FILE-NAME.
+If FILE-NAME is nil or omitted, it defaults to the current buffer's file
+name.
+
+For the format, see `doc-view--pdf-outline'."
+  (unless file-name (setq file-name (buffer-file-name)))
+  (with-temp-buffer
+    (call-process doc-view-djvused-program nil (current-buffer) nil
+                  "-e" "print-outline" file-name)
+    (goto-char (point-min))
+    (when (eobp)
+      (setq doc-view--outline 'unavailable)
+      (imenu-unavailable-error "Unable to create imenu index using `djvused'"))
+    (nreverse (doc-view--parse-djvu-outline (read (current-buffer))))))
+
+(defun doc-view--parse-djvu-outline (bookmark &optional level)
+  "Return a list describing the djvu outline from BOOKMARK.
+Optional argument LEVEL is the current heading level, which defaults to 1."
+  (unless level (setq level 1))
+  (let ((res))
+    (unless (eq (car bookmark) 'bookmarks)
+      (user-error "Unknown outline type: %S" (car bookmark)))
+    (pcase-dolist (`(,title ,page . ,rest) (cdr bookmark))
+      (push `((level . ,level)
+              (title . ,title)
+              (page . ,(string-to-number (string-remove-prefix "#" page))))
+            res)
+      (when (and rest (listp (car rest)))
+        (setq res (append
+                   (doc-view--parse-djvu-outline
+                    (cons 'bookmarks rest)
+                    (+ level 1))
+                   res))))
+    res))
+
 (defun doc-view--imenu-subtree (outline act)
   "Construct a tree of imenu items for the given outline list and action.
 
@@ -2015,19 +2070,36 @@ doc-view-imenu-index
 For extensibility, callers can specify a FILE-NAME to indicate
 the buffer other than the current buffer, and a jumping function
 GOTO-PAGE-FN other than `doc-view-goto-page'."
-  (let* ((goto (or goto-page-fn 'doc-view-goto-page))
-         (act (lambda (_name _pos page) (funcall goto page)))
-         (outline (or doc-view--outline (doc-view--pdf-outline file-name))))
-    (car (doc-view--imenu-subtree outline act))))
+  (unless doc-view--outline
+    (setq doc-view--outline (doc-view--outline file-name)))
+  (unless (eq doc-view--outline 'unavailable)
+    (let* ((goto (or goto-page-fn #'doc-view-goto-page))
+           (act (lambda (_name _pos page) (funcall goto page)))
+           (outline doc-view--outline))
+      (car (doc-view--imenu-subtree outline act)))))
+
+(defun doc-view--outline (&optional file-name)
+  "Return the outline for the file FILE-NAME.
+If FILE-NAME is nil, use the current file instead."
+  (unless file-name (setq file-name (buffer-file-name)))
+  (let ((outline
+         (pcase doc-view-doc-type
+           ('djvu
+            (when doc-view-djvused-program
+              (doc-view--djvu-outline file-name)))
+           (_
+            (doc-view--pdf-outline file-name)))))
+    (when outline (imenu-add-to-menubar "Outline"))
+    ;; When the outline could not be made due to unavailability of the
+    ;; required program, or its absency from the document, return
+    ;; 'unavailable'.
+    (or outline 'unavailable)))
 
 (defun doc-view-imenu-setup ()
   "Set up local state in the current buffer for imenu, if needed."
-  (when doc-view-imenu-enabled
-    (setq-local imenu-create-index-function #'doc-view-imenu-index
-                imenu-submenus-on-top nil
-                imenu-sort-function nil
-                doc-view--outline (doc-view--pdf-outline))
-    (when doc-view--outline (imenu-add-to-menubar "Outline"))))
+  (setq-local imenu-create-index-function #'doc-view-imenu-index
+              imenu-submenus-on-top nil
+              imenu-sort-function nil))
 
 ;;;; User interface commands and the mode
 
-- 
2.45.2


  parent reply	other threads:[~2024-10-03 14:51 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-28 15:10 bug#73530: [PATCH] Add imenu index function for Djvu files in doc-view Visuwesh
2024-09-28 15:42 ` Eli Zaretskii
2024-09-28 17:02   ` Tassilo Horn
2024-09-28 17:35     ` Visuwesh
2024-09-28 17:53       ` Eli Zaretskii
2024-09-28 18:11       ` Tassilo Horn
2024-09-28 19:03         ` jao
2024-09-28 19:15           ` Tassilo Horn
2024-09-28 19:50             ` Jose A. Ortega Ruiz
2024-09-29 14:03               ` Tassilo Horn
2024-09-29 14:34                 ` Visuwesh
2024-09-29 16:20                   ` Tassilo Horn
2024-09-29 16:38                     ` Visuwesh
2024-09-29 17:15                       ` Tassilo Horn
2024-09-30 17:29                         ` Visuwesh
2024-10-02  6:42                           ` Tassilo Horn
2024-10-02  8:19                             ` Visuwesh
2024-10-02 14:53                               ` Tassilo Horn
2024-10-03  8:03                                 ` Tassilo Horn
2024-10-03 11:10                                   ` Visuwesh
2024-10-03 12:11                                     ` Tassilo Horn
2024-10-03 14:51                                   ` Visuwesh [this message]
2024-10-04  5:31                                     ` Tassilo Horn
2024-10-04  7:31                                       ` Visuwesh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ldz5ck8t.fsf@gmail.com \
    --to=visuweshm@gmail.com \
    --cc=73530@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=jao@gnu.org \
    --cc=tsdh@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).