branch: externals/denote
commit b00a8230cdb9750c05722914cc8ab8ea94383eb1
Author: Protesilaos Stavrou <[email protected]>
Commit: Protesilaos Stavrou <[email protected]>

    Greatly expand the capabilities of the 'denote-files' Org dynamic block
    
    1. The :no-front-matter parameter can now read a number value to
       omit that many lines from the top of the file.
    
    2. A new :add-links parameter formats the inserted files as a
       typographic list and creates a link to each file.
---
 README.org           | 70 +++++++++++++++++++++++++++++++++-------------------
 denote-org-dblock.el | 60 ++++++++++++++++++++++++++++++++------------
 2 files changed, 89 insertions(+), 41 deletions(-)

diff --git a/README.org b/README.org
index 5046329e4d..4990b7c4c1 100644
--- a/README.org
+++ b/README.org
@@ -2461,7 +2461,7 @@ reflect on the status of earlier notes 
([[#h:6060a7e6-f179-4d42-a9de-a9968aaebec
 Denote can optionally use Org's dynamic blocks facility to produce a
 section that lists entire file contents 
([[#h:8b542c50-dcc9-4bca-8037-a36599b22779][Use Org dynamic blocks]]).
 This works by instrucing Org to match a regular expression of Denote
-files, the same way we do with Denote links 
([[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links matching a regexp]]). 
+files, the same way we do with Denote links 
([[#h:9bec2c83-36ca-4951-aefc-7187c5463f90][Insert links matching a regexp]]).
 
 This is useful to, for example, compile a dynamically concatenated
 list of scattered thoughts on a given topic, like =^2023.*_emacs= for
@@ -2472,35 +2472,55 @@ To produce such a block, use the following syntax in an 
Org file and
 type =C-c C-x C-u= (~org-dblock-update~) on the =#+BEGIN= line (type
 =C-c C-x C-u= again to recalculate the block):
 
-: #+BEGIN: denote-files :regexp "YOUR-REGEXP-HERE"
+: #+BEGIN: denote-files :regexp "^2023.*_journal"
 :
 : #+END:
 
-The =:regexp= parameter is mandatory. Its value is a string,
-representing a regular expression to match Denote file names. Its
-value may also be an ~rx~ expression instead of a string, as noted in
-the previous section about Org dynamic blocks.
+Or to fully control the output, include these parameters, which are
+described further below:
+
+: #+BEGIN: denote-files :regexp "^2023.*_journal" :no-front-matter nil 
:file-separator t :add-links nil
+:
+: #+END:
+
+- The =:regexp= parameter is mandatory. Its value is a string,
+  representing a regular expression to match Denote file names. Its
+  value may also be an ~rx~ expression instead of a string, as noted
+  in the previous section about Org dynamic blocks.
 
 #+vindex: denote-org-dblock-file-contents-separator
-File contents are inserted verbatim. They are separated by the
-~denote-org-dblock-file-contents-separator~, which introduces some
-empty lines and a horizontal rule between them to visually distinguish
-individual files. Though the block accepts an optional parameter of
-=:file-separator=, which takes a string as a value. It is recommended
-to include newline characters (=\n=) in the string for better results.
-The value of =:file-separator= may also be =none=, in which case no
-separator is used.
-
-An optional =:block-name= parameter adds a =#+name= to the results for
-further processing using Org facilities (this is outside Denote's
-purview).
-
-The optional =:no-front-matter= parameter with a ~t~ value instructs
-Denote to try to remove front matter from the files it is inserting in
-the dynamic block. The technique used to perform this operation is by
-removing all lines from the top of the file until the first empty
-line. This works with the default front matter that Denote adds, but
-is not 100% reliable with all sorts of user-level modifications.
+- The =:file-separator= parameter is optional. If it is omitted, then
+  Denote will use the ~denote-org-dblock-file-contents-separator~: it
+  introduces some empty lines and a horizontal rule between them to
+  visually distinguish individual files. If the =:file-separator=
+  value is a string, it is used as the file separator (e.g. use ="\n"=
+  to insert just one empty new line). If the =:file-separator= value
+  is set to =none=, no separator is used.
+
+- The =:no-front-matter= parameter is optional. When set to a ~t~
+  value Denote tries to remove front matter from the files it is
+  inserting in the dynamic block. The technique used to perform this
+  operation is by removing all lines from the top of the file until
+  the first empty line. This works with the default front matter that
+  Denote adds, but is not 100% reliable with all sorts of user-level
+  modifications and edits to the file. When the =:no-front-matter= is
+  set to a natural number, Denote will omit that many lines from the
+  top of the file.
+
+- The =:add-links= parameter is optional. When it is set to a ~t~
+  value, all files are inserted as a typographic list and are indented
+  accordingly. The first line in each list item is a link to the file
+  whose contents are inserted in the following lines. When the value
+  is =id-only=, then links are inserted without a description text but
+  only with the identifier of the given file. This has the same
+  meaning as with the ~denote-link~ command and related facilities
+  ([[#h:fc913d54-26c8-4c41-be86-999839e8ad31][Linking notes]]). Remember that 
Org can fold the items in a
+  typographic list the same way it does with headings. So even long
+  files can be presented in this format without much trouble.
+
+- The =:block-name= parameter is optional. It adds a =#+name= to the
+  results for further processing using Org facilities (this is outside
+  Denote's purview).
 
 * Minibuffer histories
 :PROPERTIES:
diff --git a/denote-org-dblock.el b/denote-org-dblock.el
index 981f88e9f1..d16f667987 100644
--- a/denote-org-dblock.el
+++ b/denote-org-dblock.el
@@ -151,18 +151,38 @@ Used by `org-dblock-update' with PARAMS provided by the 
dynamic block."
 
 ;;;; Dynamic block with entire file contents
 
-(defun denote-org-dblock--get-file-contents (file &optional no-front-matter)
+(defun denote-org-dblock--get-file-contents (file &optional no-front-matter 
add-links)
   "Insert the contents of FILE.
 With optional NO-FRONT-MATTER as non-nil, try to remove the front
-matter from the top of the file.  Do it by finding the first
-blank line, starting from the top of the buffer."
+matter from the top of the file.  If NO-FRONT-MATTER is a number,
+remove that many lines starting from the top.  If it is any other
+non-nil value, delete from the top until the first blank line.
+
+With optional ADD-LINKS as non-nil, first insert a link to the
+file and then insert its contents.  In this case, format the
+contents as a typographic list.  If ADD-LINKS is `id-only', then
+insert links as `denote-link' does when supplied with an ID-ONLY
+argument."
   (with-temp-buffer
-    (insert-file-contents file)
-    (when no-front-matter
-      (let ((min (point-min)))
-        (goto-char min)
-        (re-search-forward "^$" nil :no-error 1)
-      (delete-region (1+ (point)) min)))
+    (when add-links
+      (insert
+       (format "- %s\n\n"
+               (denote-format-link
+                file
+                (if (eq add-links 'id-only)
+                    denote-id-only-link-format
+                  denote-org-link-format)
+                nil))))
+    (let ((beginning-of-contents (point)))
+      (insert-file-contents file)
+      (when no-front-matter
+        (delete-region
+         (if (natnump no-front-matter)
+             (progn (forward-line no-front-matter) (line-beginning-position))
+           (1+ (re-search-forward "^$" nil :no-error 1)))
+         beginning-of-contents))
+      (when add-links
+        (indent-region beginning-of-contents (point-max) 2)))
     (buffer-string)))
 
 (defvar denote-org-dblock-file-contents-separator
@@ -173,17 +193,21 @@ blank line, starting from the top of the buffer."
   "Return appropriate value of SEPARATOR for `denote-org-dblock-add-files'."
   (cond
    ((eq separator 'none) "")
-   (separator separator)
+   ((stringp separator) separator)
    (t denote-org-dblock-file-contents-separator)))
 
-(defun denote-org-dblock-add-files (regexp &optional separator no-front-matter)
+(defun denote-org-dblock-add-files (regexp &optional separator no-front-matter 
add-links)
   "Insert files matching REGEXP.
 Seaprate them with the optional SEPARATOR.  If SEPARATOR is nil,
 use the `denote-org-dblock-file-contents-separator'.
 
 If optional NO-FRONT-MATTER is non-nil try to remove the front
 matter from the top of the file.  Do it by finding the first
-blank line, starting from the top of the buffer."
+blank line, starting from the top of the buffer.
+
+If optional ADD-LINKS is non-nil, first insert a link to the file
+and then insert its contents.  In this case, format the contents
+as a typographic list."
   (let ((files (denote-directory-files-matching-regexp regexp)))
     ;; FIXME 2023-11-23: Do not use a separator for the last file.
     ;; Not a big issue, but is worth checking.
@@ -192,7 +216,7 @@ blank line, starting from the top of the buffer."
        ;; NOTE 2023-11-23: I tried to just do `insert-file-contents'
        ;; without the temporary buffer, but it seems that the point is
        ;; not moved, so the SEPARATOR does not follow the contents.
-       (let ((contents (denote-org-dblock--get-file-contents file 
no-front-matter)))
+       (let ((contents (denote-org-dblock--get-file-contents file 
no-front-matter add-links)))
          (insert (concat contents (denote-org-dblock--separator separator)))))
      files)))
 
@@ -203,7 +227,10 @@ blank line, starting from the top of the buffer."
     (list
      (read-regexp "Search for notes matching REGEX: " nil 
'denote--file-history)))
   (org-create-dblock (list :name "denote-files"
-                           :regexp regexp))
+                           :regexp regexp
+                           :no-front-matter nil
+                           :file-separator t
+                           :add-links nil))
   (org-update-dblock))
 
 (defun org-dblock-write:denote-files (params)
@@ -213,10 +240,11 @@ Used by `org-dblock-update' with PARAMS provided by the 
dynamic block."
          (rx (if (listp regexp) (macroexpand `(rx ,regexp)) regexp))
          (block-name (plist-get params :block-name))
          (separator (plist-get params :file-separator))
-         (no-front-matter (plist-get params :no-front-matter)))
+         (no-front-matter (plist-get params :no-front-matter))
+         (add-links (plist-get params :add-links)))
     (when block-name
       (insert "#+name: " block-name "\n"))
-    (when rx (denote-org-dblock-add-files rx separator no-front-matter))))
+    (when rx (denote-org-dblock-add-files rx separator no-front-matter 
add-links))))
 
 (provide 'denote-org-dblock)
 ;;; denote-org-dblock.el ends here

Reply via email to