From 437aaf1a29b8469a27b44754376bc78b3b61d77c Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sun, 15 Mar 2020 15:17:53 +0000 Subject: Add backlink to parent --- zettelkasten.el | 115 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 41 deletions(-) diff --git a/zettelkasten.el b/zettelkasten.el index dde92e1..c3d62f3 100644 --- a/zettelkasten.el +++ b/zettelkasten.el @@ -21,82 +21,115 @@ After that, changing the prefix key requires manipulating keymaps." :type 'string :group 'zettelkasten) -(defcustom zettelkasten-file-format "%y%W%u%%03d.org" +(defcustom zettelkasten-file-format "%y%W%u%%02d" "Format for new zettelkasten files. For supported options, please consult `format-time-string'." :type 'string :group 'zettelkasten) -(defcustom zettelkasten-top-level "index.org" - "Top level zettelkasten file that starts the DAG hierarchy." +(defcustom zettelkasten-link-format "[[./%2$s.%3$s][%1$s]]" + "Zettelkasten link format." :type 'string :group 'zettelkasten) -(defun zettelkasten-make-filename (filename) - "Make a filename using the default directory and the FILENAME passed to it." - (expand-file-name (concat zettelkasten-directory "/" filename))) +(defcustom zettelkasten-extension "org" + "Default extension for notes." + :type 'string + :group 'zettelkasten) + +(defun zettelkasten-make-filename (note) + "Make a filename using the default directory and the NOTE passed to it." + (expand-file-name (concat zettelkasten-directory "/" note "." zettelkasten-extension))) (defun zettelkasten-filename-to-id (filename) "Convert FILENAME to id." - (progn (string-match "\\(.*\\)\\.org\\'" filename) - (match-string 1 filename))) + (string-match (format "\\(.*\\)\\.%s\\'" zettelkasten-extension) filename) + (match-string 1 filename)) (defun zettelkasten-list-notes-by-id () "Return all the ids that are currently available." (mapcar #'zettelkasten-filename-to-id (directory-files - (expand-file-name zettelkasten-directory) nil "\\.org$" t))) + (expand-file-name zettelkasten-directory) nil + (format "\\.%s$" zettelkasten-extension) t))) (defun zettelkasten-list-notes () "Return all the ids and titles of notes in the `zettelkasten-directory'." - (progn (shell-command (concat "grep -i \"#+TITLE:\" " zettelkasten-directory "/*")) - (setq match-list nil) - (with-current-buffer "*Shell Command Output*" - (progn - (set-buffer "*Shell Command Output*") - (setq morelines t) - (goto-char 1) - (while morelines - (setq current-string (buffer-substring-no-properties (line-beginning-position) (line-end-position))) - (when (string-match "\\([0-9]*\\)\\.org:#\\+TITLE: \\(.*\\)" current-string) - (setq matched-string (concat (match-string 1 current-string) " - " (match-string 2 current-string))) - (setq match-list (append match-list (list matched-string)))) - (setq morelines (= 0 (forward-line 1)))))) - (kill-buffer "*Shell Command Output*") - match-list)) - -(defun zettelkasten-find-new-note-name (file iteration) - "Iterate on ITERATION until a usable file based on FILE is found." + (shell-command (concat "grep -i \"#+TITLE:\" " zettelkasten-directory "/*")) + (setq match-list nil) + (with-current-buffer "*Shell Command Output*" + (set-buffer "*Shell Command Output*") + (setq morelines t) + (goto-char 1) + (while morelines + (setq current-string (buffer-substring-no-properties (line-beginning-position) (line-end-position))) + (when (string-match + (format "\\([0-9]*\\)\\.%s:#\\+TITLE: \\(.*\\)" zettelkasten-extension) + current-string) + (setq matched-string (concat (match-string 1 current-string) " - " (match-string 2 current-string))) + (setq match-list (append match-list (list matched-string)))) + (setq morelines (= 0 (forward-line 1))))) + (kill-buffer "*Shell Command Output*") + match-list) + +(defun zettelkasten-find-new-note-name (note iteration) + "Iterate on ITERATION until a usable file based on NOTE is found." (let ((expanded-name (zettelkasten-make-filename - (format file iteration)))) + (format note iteration)))) (if (file-exists-p expanded-name) - (zettelkasten-find-new-note-name file (+ iteration 1)) - expanded-name))) + (zettelkasten-find-new-note-name note (+ iteration 1)) + (format note iteration)))) (defun zettelkasten-generate-note-name () "Create the new note name." (zettelkasten-find-new-note-name (format-time-string zettelkasten-file-format) 0)) -(defun zettelkasten-create-new-note (title) - "Create a new zettelkasten note using the TITLE it is passed." - (interactive "MNote title: ") - (progn (find-file (zettelkasten-generate-note-name)) - (insert (concat "#+TITLE: " title - (format-time-string "\n#+DATE: %c\n#+TAGS:\n\n"))) - (save-buffer))) +(defun zettelkasten-get-id (note) + "Return the id for a NOTE." + (string-match "\\([0-9]*\\)" note) + (match-string 1 note)) + +(defun zettelkasten-format-link (note) + "Format a link to a NOTE." + (format zettelkasten-link-format note (zettelkasten-get-id note) zettelkasten-extension)) + +(defun zettelkasten-add-link-to-parent (note parent) + "Add a link to NOTE from PARENT." + (with-temp-file (zettelkasten-make-filename parent) + (insert-file-contents-literally (zettelkasten-make-filename parent)) + (goto-char (point-max)) + (insert (concat "\n" (zettelkasten-format-link note))))) + +(defun zettelkasten-create-new-note-non-interactive (title parent) + "Create a new note based on the TITLE and it's PARENT note. + +If PARENT is nil, it will not add a link from a parent." + (let ((note (zettelkasten-generate-note-name))) + (zettelkasten-add-link-to-parent note (zettelkasten-get-id parent)) + (find-file (zettelkasten-make-filename note)) + (insert (concat "#+TITLE: " title + (format-time-string "\n#+DATE: %c\n#+TAGS:\n\n"))) + (save-buffer))) + +(defun zettelkasten-create-new-note (prefix) + "Create a new zettelkasten. + +If PREFIX is used, does not create a parent." + (interactive "P") + (let ((title (read-string "Note title: ")) + (parent (unless prefix (completing-read "Parent note: " + (zettelkasten-list-notes) nil 'match)))) + (zettelkasten-create-new-note-non-interactive title parent))) (defun zettelkasten-insert-link (note) "Insert a link to another NOTE in the current note." (interactive (list (completing-read "Notes: " (zettelkasten-list-notes) nil 'match))) - (let ((note-id - (progn (string-match "\\([0-9]*\\)" note) - (match-string 1 note)))) - (insert (concat "[[./" note-id ".org][" note "]]")))) + (insert (zettelkasten-format-link note))) (defvar zettelkasten-mode-map (let ((map (make-sparse-keymap))) -- cgit