From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Jose A Ortega Ruiz Newsgroups: gmane.emacs.bugs Subject: bug#58103: [PATCH] docview: imenu access to table of contents Date: Tue, 27 Sep 2022 06:41:14 +0100 Message-ID: <87r0zxz85h.fsf@mail.jao.io> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="9724"; mail-complaints-to="usenet@ciao.gmane.io" To: 58103@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Sep 27 07:43:02 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1od3N0-0002Ns-0j for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 27 Sep 2022 07:43:02 +0200 Original-Received: from localhost ([::1]:55472 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1od3My-0001as-QX for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 27 Sep 2022 01:43:00 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:35484) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1od3M2-0001ZB-Ap for bug-gnu-emacs@gnu.org; Tue, 27 Sep 2022 01:42:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:53096) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1od3M2-0002zh-1v for bug-gnu-emacs@gnu.org; Tue, 27 Sep 2022 01:42:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1od3M1-0006JN-Nn for bug-gnu-emacs@gnu.org; Tue, 27 Sep 2022 01:42:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Jose A Ortega Ruiz Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 27 Sep 2022 05:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 58103 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.166425729624227 (code B ref -1); Tue, 27 Sep 2022 05:42:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 27 Sep 2022 05:41:36 +0000 Original-Received: from localhost ([127.0.0.1]:52174 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1od3Lb-0006Ih-Lb for submit@debbugs.gnu.org; Tue, 27 Sep 2022 01:41:36 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:34914) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1od3LZ-0006IW-E0 for submit@debbugs.gnu.org; Tue, 27 Sep 2022 01:41:34 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55322) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1od3LP-0001Vo-9J for bug-gnu-emacs@gnu.org; Tue, 27 Sep 2022 01:41:29 -0400 Original-Received: from fencepost.gnu.org ([2001:470:142:3::e]:37752) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1od3LM-0002sb-Jy; Tue, 27 Sep 2022 01:41:21 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to: references; bh=9M1fX7BSgR6pAb0IjXxzwamiWtmzQpkpmjuwk4VtxHk=; b=dR0AdYK3O6rNI8 s3cuZC7tT7Q1KDL2s2Cx8yfw8Yc0MUY5sJwaIgL368PQTx5CfJJo7vNrQPleQNjGY02YySnndXzWw n3KkcDl5srEBSxZlbOjDXFyZ0CNSkzIUGxEyz41e6DhxtyBkanPPzanh6yR+2d5IKpq+nEKkODcPF UOXI+8JKktKGJPoN4YHjFWriZDMU+WAbOd32VHgQVxBY4uFrY5NSOSOGwEx2N7z4q0aZaKgfmq3oN OKqyPYI0XFMN7Ej2VZbeJudmtmGvIpkZbSMkZWg0sT4v/qdtr3zh7ew/JqEkbnptDk6IM5kD9V8u0 7LhgELiKN2MZ87Et9PAw==; Original-Received: from cpc103048-sgyl39-2-0-cust502.18-2.cable.virginm.net ([92.233.85.247]:50832 helo=rivendell.localdomain) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1od3LK-0004EL-Ju; Tue, 27 Sep 2022 01:41:20 -0400 Original-Received: from localhost (rivendell.localdomain [local]) by rivendell.localdomain (OpenSMTPD) with ESMTPA id 59a6c927; Tue, 27 Sep 2022 05:41:14 +0000 (UTC) X-Attribution: jao X-Clacks-Overhead: GNU Terry Pratchett X-URL: X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:243689 Archived-At: --=-=-= Content-Type: text/plain 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' --=-=-= Content-Type: text/patch Content-Disposition: attachment; filename=0001-docview-imenu-access-to-table-of-contents.patch >From 37d46e61a194c87293a2e4ed54495a9436bd5422 Mon Sep 17 00:00:00 2001 From: Jose A Ortega Ruiz 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-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 --=-=-= Content-Type: text/plain -- 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 --=-=-=--