emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/denote 2fc82bd292 1/4: Add Org dynamic block to insert


From: ELPA Syncer
Subject: [elpa] externals/denote 2fc82bd292 1/4: Add Org dynamic block to insert files as headings
Date: Fri, 2 Aug 2024 04:01:58 -0400 (EDT)

branch: externals/denote
commit 2fc82bd292e3a5f5677cdf961fa94d65dc03984a
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>

    Add Org dynamic block to insert files as headings
---
 README.org           |  88 +++++++++++++++++++++++++++++++++++++++++
 denote-org-extras.el | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 197 insertions(+)

diff --git a/README.org b/README.org
index 25169aed1c..10a05ae9e7 100644
--- a/README.org
+++ b/README.org
@@ -3399,6 +3399,94 @@ parameters, which are described further below:
   processing using Org facilities (a feature that is outside Denote's
   purview).
 
+** Org dynamic block to insert Org files as headings
+:PROPERTIES:
+:CUSTOM_ID: h:d6254a12-b762-4096-a5de-66a0d423e204
+:END:
+
+[ Part of {{{development-version}}}. ]
+
+[ IMPORTANT NOTE: This dynamic block only works with Org files,
+  because it has to assume the Org notation in order to insert each
+  file's contents as its own heading. ]
+
+#+findex: denote-org-extras-dblock-insert-files-as-headings
+As a variation of the previously covered block that inserts file
+contents, we have the ~denote-org-extras-dblock-insert-files-as-headings~
+command ([[#h:f15fa143-5036-416f-9bff-1bcabbb03456][Org dynamic block to 
insert file contents]]). It Turn the
+=#+title= of each file into a top-level heading. Then it increments
+all original headings in the file by one, so that they become
+subheadings of what once was the =#+title=. Similarly, the
+=#+filetags= of each file as tags for the top-level heading
+(what was the =#+title=).
+
+Because of how it is meant to work, this dynamic block only works with
+Org files.
+
+In its simplest form, this dynamic block looks like this:
+
+: #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE"
+:
+: #+END:
+
+Though when you use the command 
~denote-org-extras-dblock-insert-files-as-headings~
+you get all the parameters included:
+
+: #+BEGIN: denote-files-as-headings :regexp "YOUR REGEXP HERE" 
:excluded-dirs-regexp nil :sort-by-component title :reverse-sort nil :add-links 
t
+:
+: #+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 ([[#h:50160fae-6515-4d7d-9737-995ad925e64b][Org 
dynamic blocks to insert links or backlinks]]).
+  Note that you do not need to write an actual regular expression to
+  get meaningful results: even something like =_journal= will work to
+  include all files that have a =journal= keyword.
+
+- The =:excluded-dirs-regexp= is a string that contains a word or
+  regular expression that matches against directory files names
+  to-be-excluded from the results. This has the same meaning as
+  setting the ~denote-excluded-punctuation-regexp~ user option
+  ([[#h:8458f716-f9c2-4888-824b-2bf01cc5850a][Exclude certain directories from 
all operations]]). The user option
+  has a global effect, which is overridden locally in the dynamic
+  block. When the value of =:excluded-dirs-regexp= is nil (the
+  default), the value of ~denote-excluded-punctuation-regexp~ is used
+  (which is also nil by default, meaning that all directories are
+  included). When the value of =excluded-dirs-regexp= is ~t~ or some
+  other symbol, then the ~denote-excluded-punctuation-regexp~ is
+  ignored altogether. This is useful in the scenario where the user
+  option is set to exclude some directories but the dynamic blocks
+  wants to lift that restriction.
+
+- The =:sort-by-component= parameter is optional. It sorts the files
+  by the given Denote file name component. The value it accepts is an
+  unquoted symbol among =title=, =keywords=, =signature=, =identifier=.
+  When using the command ~denote-org-extras-dblock-insert-files~, this
+  parameter is automatically inserted together with the (=:regexp=
+  parameter) and the user is prompted for a file name component.
+
+- The =:reverse-sort= parameter is optional. It reverses the order in
+  which files appear in. This is meaningful even without the presence
+  of the parameter =:sort-by-component=, though it also combines with
+  it.
+
+- 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.
+
+- An optional =:block-name= parameter can be specified with a string
+  value to add a =#+name= to the results. This is useful for further
+  processing using Org facilities (a feature that is outside Denote's
+  purview).
+
 * Sort files by component
 :PROPERTIES:
 :CUSTOM_ID: h:9fe01e63-f34f-4479-8713-f162a5ca865e
diff --git a/denote-org-extras.el b/denote-org-extras.el
index 005df3b6d8..cc4cf5b1dd 100644
--- a/denote-org-extras.el
+++ b/denote-org-extras.el
@@ -601,6 +601,115 @@ Used by `org-dblock-update' with PARAMS provided by the 
dynamic block."
     (when rx (denote-org-extras-dblock-add-files rx separator no-f-m add-links 
sort reverse excluded-dirs)))
   (join-line)) ; remove trailing empty line
 
+;;;; Insert files as headings
+
+(defun denote-org-extras-dblock--extract-regexp (regexp)
+  "Extract REGEXP from the buffer and trim it of surrounding spaces."
+  (string-trim
+   (save-excursion
+     (re-search-forward regexp nil :no-error)
+     (buffer-substring-no-properties (match-end 0) (line-end-position)))))
+
+(defun denote-org-extras-dblock--get-file-contents-as-heading (file add-links)
+  "Insert the contents of Org FILE, formatting the #+title as a heading.
+With optional ADD-LINKS, make the title link to the original file."
+  (when-let ((_ (denote-file-is-note-p file))
+             (identifier (denote-retrieve-filename-identifier file))
+             (file-type (denote-filetype-heuristics file))
+             (_ (eq file-type 'org)))
+    (with-temp-buffer
+      (let ((beginning-of-contents (point))
+            title
+            tags)
+        (insert-file-contents file)
+        (setq title (denote-org-extras-dblock--extract-regexp 
(denote--title-key-regexp file-type)))
+        (setq tags (denote-org-extras-dblock--extract-regexp 
(denote--keywords-key-regexp file-type)))
+        (delete-region (1+ (re-search-forward "^$" nil :no-error 1)) 
beginning-of-contents)
+        (goto-char beginning-of-contents)
+        (when (and title tags)
+          (if add-links
+              (insert (format "* [[denote:%s][%s]] %s\n\n" identifier title 
tags))
+            (insert (format "* %s %s\n\n" title tags)))
+          (org-align-tags :all))
+        (while (re-search-forward "^\\(*+?\\) " nil :no-error)
+          (replace-match (format "*%s " "\\1"))))
+      (buffer-string))))
+
+(defun denote-org-extras-dblock-add-files-as-headings (regexp &optional 
add-links sort-by-component reverse excluded-dirs-regexp)
+  "Insert files matching REGEXP.
+
+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.
+
+If optional SORT-BY-COMPONENT is a symbol among `denote-sort-components',
+sort files matching REGEXP by the corresponding Denote file name
+component.  If the symbol is not among `denote-sort-components',
+fall back to the default identifier-based sorting.
+
+If optional REVERSE is non-nil reverse the sort order.
+
+Optional EXCLUDED-DIRS-REGEXP is the `let' bound value of
+`denote-excluded-directories-regexp'.  When nil, the original value of
+that user option is used."
+  (let* ((denote-excluded-directories-regexp (or excluded-dirs-regexp 
denote-excluded-directories-regexp))
+         (files (denote-org-extras-dblock--files regexp sort-by-component 
reverse))
+         (files-contents (mapcar
+                          (lambda (file)
+                            
(denote-org-extras-dblock--get-file-contents-as-heading file add-links))
+                          files)))
+    (insert (string-join files-contents))))
+
+;;;###autoload
+(defun denote-org-extras-dblock-insert-files-as-headings (regexp 
sort-by-component)
+  "Create Org dynamic block to insert Denote Org files matching REGEXP.
+
+Turn the #+title of each file into a top-level heading.  Then increment
+all original headings in the file by one, so that they become
+subheadings of what once was the #+title.
+
+Use the #+filetags of each file as tags for the top-level heading (what
+was the #+title).
+
+Sort the files according to SORT-BY-COMPONENT, which is a symbol
+among `denote-sort-components'.
+
+IMPORTANT NOTE: This dynamic block only works with Org files, because it
+has to assume the Org notation in order to insert each file's contents
+as its own heading."
+  (interactive
+   (list
+    (denote-files-matching-regexp-prompt)
+    (denote-sort-component-prompt))
+   org-mode)
+  (org-create-dblock (list :name "denote-files-as-headings"
+                           :regexp regexp
+                           :excluded-dirs-regexp nil
+                           :sort-by-component sort-by-component
+                           :reverse-sort nil
+                           :add-links nil))
+  (org-update-dblock))
+
+;; NOTE 2024-03-30: This is how the autoload is done in org.el.
+;;;###autoload
+(eval-after-load 'org
+  '(progn
+     (org-dynamic-block-define "denote-files-as-headings" 
'denote-org-extras-dblock-insert-files-as-headings)))
+
+;;;###autoload
+(defun org-dblock-write:denote-files-as-headings (params)
+  "Function to update `denote-files' Org Dynamic blocks.
+Used by `org-dblock-update' with PARAMS provided by the dynamic block."
+  (let* ((regexp (plist-get params :regexp))
+         (rx (if (listp regexp) (macroexpand `(rx ,regexp)) regexp))
+         (sort (plist-get params :sort-by-component))
+         (reverse (plist-get params :reverse-sort))
+         (block-name (plist-get params :block-name))
+         (add-links (plist-get params :add-links))
+         (excluded-dirs (plist-get params :excluded-dirs-regexp)))
+    (when block-name (insert "#+name: " block-name "\n"))
+    (when rx (denote-org-extras-dblock-add-files-as-headings rx add-links sort 
reverse excluded-dirs)))
+  (join-line)) ; remove trailing empty line
 
 (provide 'denote-org-extras)
 ;;; denote-org-extras.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]