[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/denote 3df88a05d0 096/355: Make linking aware of file t
From: |
ELPA Syncer |
Subject: |
[elpa] externals/denote 3df88a05d0 096/355: Make linking aware of file types (extends 299b897) |
Date: |
Sun, 26 Jun 2022 23:58:03 -0400 (EDT) |
branch: externals/denote
commit 3df88a05d0dea7590811b7468537df62ee564660
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>
Make linking aware of file types (extends 299b897)
I think this is a cool feature, especially the ability to read the
relevant file in order to use the correct link format.
---
README.org | 36 ++++++++++++----
denote-link.el | 129 +++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 127 insertions(+), 38 deletions(-)
diff --git a/README.org b/README.org
index 661e31dd46..f308b471ca 100644
--- a/README.org
+++ b/README.org
@@ -225,20 +225,40 @@ Denote has a basic linking facility to quickly establish
connections
between notes. The command ~denote-link~ prompts for a file name in the
~denote-directory~ (only regular files are considered, not directories).
It then retrieves the path of the given note, inserts it at point using
-the link notation of Org, and creates a backlink entry in the target
-file.
+the appropriate link notation, and creates a backlink entry in the
+target file (again using the appropriate notation).
+
+What constitutes "appropriate link notation" depends on the file type of
+the given entry per ~denote-file-type~
([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file naming scheme]]). For
+example when linking from an Org file to a Markdown file, the link in
+the former will follow Org syntax while the backlink in the latter will
+use that of Markdown. Org links use =[[file:TARGET][DESCRIPTION]]=,
+those of Markdown are =[DESCRIPTION](file:TARGET)=, while for plain text
+we implement our own scheme of =<TYPE: TARGET> [DESCRIPTION]=, where
+=TYPE= is either =LINK= or =BACKLINK= (capitalization in the latter two
+is literal, because plain text lacks other means of emphasis).
+
+Plain text links can benefit from Emacs' notion of "future history",
+else its ability to read the thing at point for relevant commands. With
+point over the =TARGET=, =M-x find-file= followed by =M-n= will fill the
+path to that file (this also works with point over just the identifier
+of a note).
Backlinks are recorded at the end of a note under the heading with the
-title =Denote backlinks=. Users should not edit this part manually: it
-is controlled by Denote, such as to delete duplicate links (in the
-future it might also handle stuff like alphabetic sorting).
+title =Denote backlinks=. Users should not edit the note below this
+part manually: it is controlled by Denote, such as to delete duplicate
+links (in the future it might also handle stuff like alphabetic
+sorting).
+
+The section with the backlinks is formatted according to the note's file
+type.
#+vindex: denote-link-insert-functions
#+findex: denote-link-backlink
The special hook ~denote-link-insert-functions~ is called after a link
-is created. It accepts two arguments for the target file and the origin
-of the current link. The function ~denote-link-backlink~ provides an
-example for advanced users.
+is created. It accepts two arguments for the target file and the
+formatted backlink to the original file. The function
+~denote-link-backlink~ provides an example for advanced users.
#+findex: denote-link-clear-stale-backlinks
Backlinks that no longer point to available notes can be removed from
diff --git a/denote-link.el b/denote-link.el
index e07d31e968..64619be262 100644
--- a/denote-link.el
+++ b/denote-link.el
@@ -24,7 +24,46 @@
;;; Commentary:
;;
-;; Links for denote.
+;; Denote has a basic linking facility to quickly establish connections
+;; between notes. The command `denote-link' prompts for a file name in the
+;; `denote-directory' (only regular files are considered, not directories).
+;; It then retrieves the path of the given note, inserts it at point using
+;; the appropriate link notation, and creates a backlink entry in the
+;; target file (again using the appropriate notation).
+;;
+;; What constitutes "appropriate link notation" depends on the file type
+;; of the given entry per `denote-file-type' (see "The file naming
+;; scheme" in the manual). For example when linking from an Org file to
+;; a Markdown file, the link in the former will follow Org syntax while
+;; the backlink in the latter will use that of Markdown. Org links use
+;; `[[file:TARGET][DESCRIPTION]]', those of Markdown are
+;; `[DESCRIPTION](file:TARGET)', while for plain text we implement our
+;; own scheme of `<TYPE: TARGET> [DESCRIPTION]', where `TYPE' is either
+;; `LINK' or `BACKLINK' (capitalization in the latter two is literal,
+;; because plain text lacks other means of emphasis).
+;;
+;; Plain text links can benefit from Emacs' notion of "future history",
+;; else its ability to read the thing at point for relevant commands. With
+;; point over the `TARGET', `M-x find-file' followed by `M-n' will fill the
+;; path to that file (this also works with point over just the identifier
+;; of a note).
+;;
+;; Backlinks are recorded at the end of a note under the heading with the
+;; title `Denote backlinks'. Users should not edit the note below this
+;; part manually: it is controlled by Denote, such as to delete duplicate
+;; links (in the future it might also handle stuff like alphabetic
+;; sorting).
+;;
+;; The section with the backlinks is formatted according to the note's file
+;; type.
+;;
+;; The special hook `denote-link-insert-functions' is called after a link
+;; is created. It accepts two arguments for the target file and the
+;; formatted backlink to the original file. The function
+;; `denote-link-backlink' provides an example for advanced users.
+;;
+;; Backlinks that no longer point to available notes can be removed from
+;; the current buffer with the command `denote-link-clear-stale-backlinks'.
;;; Code:
@@ -39,55 +78,75 @@
(defcustom denote-link-insert-functions
(list #'denote-link-backlink)
"Functions that run after `denote-link'.
-Each function accepts a TARGET-FILE and an ORIGIN-LINK argument.
-Both are supplied by `denote-link'."
+Each function accepts a TARGET file and a BACKLINK argument.
+Both are supplied by `denote-link'. Advanced users are
+encouraged to study `denote-link-backlink' for how those
+arguments are used."
:type 'hook
:group 'denote-link)
;;;; Link to note
-(defun denote-link--find-key-value-pair (regexp)
- "Produce a cons cell from REGEXP by searching the file."
+(defun denote-link--find-value (regexp)
+ "Return value from REGEXP by searching the file."
(goto-char (point-min))
(re-search-forward regexp)
- (cons (match-string-no-properties 1)
- (match-string-no-properties 2)))
+ (match-string-no-properties 3))
-(defconst denote-link--title-regexp "^\\(#\\+title:\\)[\s\t]+\\(.*\\)"
+(defconst denote-link--title-regexp "^\\(#\\+\\)?\\(title:\\)[\s\t]+\\(.*\\)"
"Regular expression for title key and value.")
-(defconst denote-link--identifier-regexp
"^\\(#\\+identifier:\\)[\s\t]+\\(.*\\)"
+(defconst denote-link--identifier-regexp
"^\\(#\\+\\)?\\(identifier:\\)[\s\t]+\\(.*\\)"
"Regular expression for filename key and value.")
-(defconst denote-link--link-format "[[file:%s][%s (%s)]]"
+(defconst denote-link--link-format-org "[[file:%s][%s (%s)]]"
"Format of Org link to note.")
-(defconst denote-link--backlink-format "[[file:%s][backlink: %s (%s)]]"
+(defconst denote-link--backlink-format-org "[[file:%s][backlink: %s (%s)]]"
"Format of Org backlink to note.")
+(defconst denote-link--link-format-md "[%2$s (%3$s)](file:%1$s)"
+ "Format of Markdown link to note.")
+
+(defconst denote-link--backlink-format-md "[backlink: %2$s (%3$s)](file:%1$s)"
+ "Format of Markdown backlink to note.")
+
+(defconst denote-link--link-format-txt "<LINK: %s> [NAME %s (%s)]"
+ "Format of plain text link to note.")
+
+(defconst denote-link--backlink-format-txt "BACKLINK: <%s> [NAME %s (%s)]"
+ "Format of plain text backlink to note.")
+
(defconst denote-link--backlink-regexp "\\[\\[file:\\(.*?\\)\\]\\[backlink:
\\(.*?\\) (\\(.*?\\))\\]\\]"
- "Regexp of `denote-link--backlink-format'.")
+ "Regexp of `denote-link--backlink-format-org'.")
(defun denote-link--retrieve-value (note regexp)
"Return REGEXP value from NOTE."
(let ((default-directory (denote-directory)))
(with-temp-buffer
(insert-file-contents-literally note)
- (denote-link--find-key-value-pair regexp))))
+ (denote-link--find-value regexp))))
(defun denote-link--read-file-prompt ()
"Prompt for regular file in variable `denote-directory'."
(read-file-name "Select note: " (denote-directory)
- nil t nil #'file-regular-p)) ; Includes backup files. Maybe
we can remove them?
-
-(defun denote-link--format-link (file &optional backlink)
- "Format link to FILE.
+ nil t nil #'file-regular-p))
+
+(defun denote-link--file-type-format (file &optional backlink)
+ "Return link pattern based on FILE format.
+With optional BACKLINK, return a backlink pattern"
+ (pcase (file-name-extension file)
+ ("md" (if backlink denote-link--backlink-format-md
denote-link--link-format-md))
+ ("txt" (if backlink denote-link--backlink-format-txt
denote-link--link-format-txt))
+ (_ (if backlink denote-link--backlink-format-org
denote-link--link-format-org)))) ; Includes backup files. Maybe we can remove
them?
+
+(defun denote-link--format-link (file pattern)
+ "Prepare link to FILE using PATTERN.
With optional BACKLINK, format it as a backlink."
(let* ((dir (denote-directory))
- (file-id (cdr (denote-link--retrieve-value file
denote-link--identifier-regexp)))
+ (file-id (denote-link--retrieve-value file
denote-link--identifier-regexp))
(file-path (file-name-completion file-id dir))
- (file-title (cdr (denote-link--retrieve-value file
denote-link--title-regexp)))
- (pattern (if backlink denote-link--backlink-format
denote-link--link-format)))
+ (file-title (denote-link--retrieve-value file
denote-link--title-regexp)))
(format pattern file-path file-title file-id)))
;;;###autoload
@@ -95,28 +154,38 @@ With optional BACKLINK, format it as a backlink."
"Create Org link to TARGET note in variable `denote-directory'.
Run `denote-link-insert-functions' afterwards."
(interactive (list (denote-link--read-file-prompt)))
- (let* ((target-link (denote-link--format-link target))
- (origin-link (denote-link--format-link (buffer-file-name) :backlink)))
- (insert target-link)
- (run-hook-with-args 'denote-link-insert-functions target origin-link)))
+ (let* ((origin (buffer-file-name))
+ (link (denote-link--format-link target (denote-link--file-type-format
origin)))
+ (backlink (denote-link--format-link origin
(denote-link--file-type-format target :backlink))))
+ (insert link)
+ (run-hook-with-args 'denote-link-insert-functions target backlink)))
(defconst denote-link-backlink-heading "Denote backlinks"
"String of the backlink's heading.
This heading is appended to a file when another links to it.")
-(defun denote-link-backlink (target-file origin-link)
- "Insert ORIGIN-LINK to TARGET-FILE."
+(defun denote-link--format-backlinks-heading (heading)
+ "Format HEADING for backlinks."
+ (let* ((ext (file-name-extension (buffer-file-name)))
+ (markup (if (string= ext "org") "*" "#"))
+ (warning "Do not edit past this line; this is for denote.el and
related.")
+ (comment (if (string= ext "org")
+ (format "# %s" warning)
+ (format "<!-- %s -->" warning))))
+ (format "%s\n%s %s\n\n" comment markup heading)))
+
+(defun denote-link-backlink (target backlink)
+ "Insert BACKLINK to TARGET file."
(let ((default-directory (denote-directory))
(heading denote-link-backlink-heading)
heading-point)
- (with-current-buffer (find-file-noselect target-file)
+ (with-current-buffer (find-file-noselect target)
(goto-char (point-max))
(unless (save-excursion (setq heading-point (re-search-backward heading
nil t)))
(unless (denote--line-regexp-p 'empty 0)
(newline))
- (insert
- (format "* %s\n%s\n\n" heading "# Do not edit; this is for denote.el
and related")))
- (insert (format "- %s\n" origin-link))
+ (insert (denote-link--format-backlinks-heading heading)))
+ (insert (format "- %s\n" backlink))
;; delete duplicate links
(when heading-point
(delete-duplicate-lines heading-point (point-max) nil nil t)))))
- [elpa] externals/denote 96eee4aeba 068/355: Change placement of findex keyword in the manual, (continued)
- [elpa] externals/denote 96eee4aeba 068/355: Change placement of findex keyword in the manual, ELPA Syncer, 2022/06/26
- [elpa] externals/denote d09b748c8d 063/355: Fix fontification; add denote-dired-directories, ELPA Syncer, 2022/06/26
- [elpa] externals/denote f8ea03abfb 067/355: Add documentation about renaming non-notes, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 431124fea1 060/355: Generalise dired fontification, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 147901f971 072/355: Rename 'denote--directory' to 'denote-directory', ELPA Syncer, 2022/06/26
- [elpa] externals/denote a5120e0e93 061/355: Enable optional EXTENSION in file name creation, ELPA Syncer, 2022/06/26
- [elpa] externals/denote a6303a6101 074/355: Update doc string of variable 'denote-directory', ELPA Syncer, 2022/06/26
- [elpa] externals/denote e2c49771f7 078/355: Placate the compiler about symbol disambiguation, ELPA Syncer, 2022/06/26
- [elpa] externals/denote e8c1e31dec 084/355: Expand gitignore, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 739d485600 079/355: Fix bug about missing point in link de-duplication, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 3df88a05d0 096/355: Make linking aware of file types (extends 299b897),
ELPA Syncer <=
- [elpa] externals/denote e1bd4c9cb8 094/355: BREAKING Put keywords after the title, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 7366004e91 106/355: Fix markdown-toml front matter format, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 5fd4e97dad 105/355: Add support for markdown-toml, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 1a8b57a9a8 104/355: Fix const in denote-file-type (extends 2bc5df6), ELPA Syncer, 2022/06/26
- [elpa] externals/denote c225201c49 124/355: Use appropriate name for internal variable, ELPA Syncer, 2022/06/26
- [elpa] externals/denote a70b4cd32d 114/355: Refine backlinks' heading per file type, ELPA Syncer, 2022/06/26
- [elpa] externals/denote 7cba33e08e 119/355: LAST BREAKING CHANGE to file-naming scheme, ELPA Syncer, 2022/06/26
- [elpa] externals/denote c5a5748594 116/355: Abstract plain text front matter delimiter, ELPA Syncer, 2022/06/26
- [elpa] externals/denote e394057985 134/355: Document how to store multiple types of notes, ELPA Syncer, 2022/06/26
- [elpa] externals/denote d90695213c 151/355: Add minor clarifications in the manual, ELPA Syncer, 2022/06/26