fix
All checks were successful
Build Quartz Notes / build (push) Successful in 52s

This commit is contained in:
2026-06-02 15:12:22 +01:00
parent 6276bf5fd3
commit 8664b217df
21 changed files with 23547 additions and 48 deletions

63
Technical/Emacs/Elisp.md Normal file
View File

@@ -0,0 +1,63 @@
use `<s` followed by `TAB`
``` elisp
(defun my-echo-input ()
"Prompt the user for input and echo it back."
(interactive)
(message "hello"))
```
``` commonlisp
(shell-command "thunar ~/Documents/ &")
(run-at-time "1 sec" nil #'delete-other-windows)
```
``` elisp
(defun open-current-dir()
(interactive)
(cond ((string-equal system-type "gnu/linux")
(shell-command (concat "thunar " ".")))
((string-equal system-type "darwin")
(shell-command (concat "open " "."))))
)
```
``` elisp
(defun test()
(interactive)
(cond ((string-equal system-type "gnu/linux")
(message "linux"))
((string-equal system-type "darwin")
(message "mac"))
)
)
(defun kill-other-buffers-startup ()
"Kill all buffers except the current one."
(interactive)
(mapc (lambda (buffer)
(unless (eq buffer (current-buffer))
(kill-buffer buffer)))
(buffer-list)))
;(add-hook 'emacs-startup-hook #'kill-other-buffers-startup)
```
``` elisp
(defun create-weekly-entry ()
(interactive)
(let* ((current-date-time-format "[%Y-week-%V]")
(timestamp (format-time-string current-date-time-format))
(entry (concat "* Weekly Entry: " timestamp "\n"
"** Tasks:\n"
"** Notes:\n"
)))
(write-region entry nil "~/master-folder/org_files/todo/master-tl.org" 'append)))
```

View File

@@ -0,0 +1,62 @@
****For the config, see [[Emacs Config]] for the Source of truth****
# Config:
``` commonlisp
(require 'org-caldav)
(require 'url)
(require 'icalendar)
(modify-coding-system-alist 'file "caldav-work\\.org\\'" 'utf-8-unix)
(setq org-icalendar-timezone "Europe/London")
(setq calendar-time-zone 60) ;; minutes offset from UTC (BST = +60)
(setq calendar-standard-time-zone-name "GMT")
(setq calendar-daylight-time-zone-name "BST")
(setq org-caldav-timezone "Europe/London")
(defvar my/outlook-ics-url
"https://outlook.office365.com/owa/calendar/b910ea835e414663831e505f3d10baa2@microlise.com/d2568a0134fb49af92d39c1669c4729317662288011094411305/calendar.ics")
(defvar my/outlook-org-file
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-work.org")
(defvar my/ics-python-script
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\ics_to_org.py")
(defun my/sync-outlook-calendar ()
"Fetch and expand Outlook ICS (including recurrences) into org file."
(interactive)
(message "Syncing Outlook calendar...")
(let* ((cmd (format "python \"%s\" \"%s\" \"%s\""
my/ics-python-script
my/outlook-ics-url
my/outlook-org-file))
(result (shell-command-to-string cmd)))
(message "Outlook calendar sync: %s" (string-trim result))))
;; Sync on startup and every 30 minutes
(my/sync-outlook-calendar)
(run-with-timer (* 30 60) (* 30 60) #'my/sync-outlook-calendar)
;; --- CalDAV for native Nextcloud calendars ---
(setq org-caldav-url "https://nextcloud.zainezq.com/remote.php/dav/calendars/zaine/")
(setq org-caldav-calendars
'((:calendar-id "personal"
:inbox "D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-personal.org"
:files nil)
(:calendar-id "zxh"
:inbox "D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-family.org"
:files nil)))
;; --- Agenda files ---
(setq org-agenda-files
'("D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-personal.org"
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-work.org"
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-family.org"
"D:\\_nextcloud\\master-folder\\org_files\\org_roam\\Books\\20250724230557-books_org_agenda.org"))
```
## Explanation:
- This configuration sets up Emacs to sync with both a Nextcloud calendar (via CalDAV) and an Outlook calendar (via ICS). It uses a Python script to fetch and convert the Outlook ICS data into an org file format that Emacs can read. The Nextcloud calendar is synced directly using the org-caldav package. Both calendars are included in the org-agenda files, so that I can view all events in one place. The sync for the Outlook calendar runs every 30 minutes to keep it up to date.
- To sync the Outlook calendar, you call the `my/sync-outlook-calendar` function, which runs the Python script to fetch and convert the ICS data. The Nextcloud calendar is synced automatically by org-caldav whenever you open Emacs or refresh the calendar.

View File

@@ -0,0 +1,822 @@
# Org Noter
``` commonlisp
(setq org-noter-notes-search-path
'("D:\\_nextcloud\\master-folder\\org_files\\org_roam\\"))
(setq org-noter-always-create-frame nil)
(setq org-noter-property-doc-file "NOTER_DOCUMENT")
(require 'pdf-tools)
(pdf-tools-install)
(use-package pdf-view-restore
:after pdf-tools
:config
(add-hook 'pdf-view-mode-hook 'pdf-view-restore-mode)
(setq pdf-view-restore-filename "~/.emacs.d/.pdf-view-restore"))
```
## Saving images in epdf mode (org roam):
``` commonlisp
;; epdf stuff
(require 'seq)
(require 'subr-x)
(defvar zaine/pdf-image-save-dir
"d:/_nextcloud/master-folder/org_files/org_roam/assets/_books/"
"Folder where cropped PDF images should be saved.")
(defvar zaine/org-roam-root
"d:/_nextcloud/master-folder/org_files/org_roam/"
"Root folder used for relative Org image links.")
(defvar zaine/pdf-image-kill-buffer-after-save t
"If non-nil, close the *PDF image* buffer after saving.")
(defvar zaine/pdf-image-insert-link-into-org t
"If non-nil, insert the image link into a visible Org buffer.")
(defun zaine/pdf-image--slugify (s)
"Turn S into a safe filename slug."
(let* ((s (downcase (string-trim (or s ""))))
(s (replace-regexp-in-string "['`]" "" s))
(s (replace-regexp-in-string "[^[:alnum:]]+" "-" s))
(s (replace-regexp-in-string "-+" "-" s))
(s (replace-regexp-in-string "\\`-+\\|-+\\'" "" s)))
(if (string-empty-p s) "pdf-image" s)))
(defun zaine/pdf-image--current-pdf-title ()
"Try to get the title from the most recently used PDF buffer."
(when-let ((buf
(seq-find
(lambda (b)
(with-current-buffer b
(derived-mode-p 'pdf-view-mode)))
(delq (current-buffer) (buffer-list)))))
(with-current-buffer buf
(if buffer-file-name
(file-name-base buffer-file-name)
(buffer-name buf)))))
(defun zaine/pdf-image--unique-file (dir stem ext)
"Return a unique filename in DIR using STEM and EXT."
(let ((file (expand-file-name (concat stem ext) dir))
(n 1))
(while (file-exists-p file)
(setq file
(expand-file-name
(format "%s-%02d%s" stem n ext)
dir))
(setq n (1+ n)))
file))
(defun zaine/pdf-image--org-link (file)
"Create a relative Org file link for FILE."
(format "[[file:%s]]"
(file-relative-name
(expand-file-name file)
(file-name-as-directory (expand-file-name zaine/org-roam-root)))))
(defun zaine/pdf-image--visible-org-buffer ()
"Find a visible Org buffer, usually your org-noter notes buffer."
(seq-find
(lambda (buf)
(with-current-buffer buf
(derived-mode-p 'org-mode)))
(delete-dups (mapcar #'window-buffer (window-list)))))
(defun zaine/pdf-image--insert-link-into-org (link)
"Insert LINK into a visible Org buffer, if one exists."
(when-let ((buf (zaine/pdf-image--visible-org-buffer)))
(with-current-buffer buf
(goto-char (point))
(unless (bolp)
(insert "\n"))
(insert link "\n")
(when (fboundp 'org-display-inline-images)
(org-display-inline-images)))
t))
(defun zaine/pdf-image--visible-org-window ()
"Find a visible Org window, usually the org-noter notes window."
(seq-find
(lambda (win)
(with-current-buffer (window-buffer win)
(derived-mode-p 'org-mode)))
(window-list nil 'no-minibuf)))
(defun zaine/pdf-image-save-and-insert (&optional ask-title)
"Save the current *PDF image* buffer into `_books` and insert an Org link.
With prefix argument, prompt for the title/name instead of using the PDF filename.
Also closes the temporary *PDF image* window afterwards."
(interactive "P")
(unless (or (derived-mode-p 'image-mode)
(string-match-p "\\`\\*PDF image\\*" (buffer-name)))
(user-error "Run this from the *PDF image* buffer"))
(let* ((image-buffer (current-buffer))
(image-windows (get-buffer-window-list image-buffer nil t))
(org-window (zaine/pdf-image--visible-org-window))
(default-title (or (zaine/pdf-image--current-pdf-title)
"pdf-image"))
(title (if ask-title
(read-string "Image/article name: " default-title)
default-title))
(stem (concat (format-time-string "%Y-%m-%d")
"-"
(zaine/pdf-image--slugify title)))
(file (zaine/pdf-image--unique-file
zaine/pdf-image-save-dir
stem
".png"))
(link (zaine/pdf-image--org-link file)))
(make-directory (file-name-directory file) t)
;; Save the raw image data from the *PDF image* buffer.
(let ((coding-system-for-write 'binary)
(require-final-newline nil))
(with-current-buffer image-buffer
(save-restriction
(widen)
(write-region (point-min) (point-max) file nil 'silent))
(set-buffer-modified-p nil)))
;; Copy the link just in case.
(kill-new link)
;; Insert the link into the visible Org notes window.
(when org-window
(with-selected-window org-window
(unless (bolp)
(insert "\n"))
(insert link "\n")
(when (fboundp 'org-display-inline-images)
(org-display-inline-images))))
;; Close the temporary *PDF image* window instead of letting Emacs reuse it.
(dolist (win image-windows)
(when (window-live-p win)
(ignore-errors
(delete-window win))))
;; Kill the temporary image buffer after its window has gone.
(when (buffer-live-p image-buffer)
(kill-buffer image-buffer))
;; Put focus back on the notes window if it still exists.
(when (and org-window (window-live-p org-window))
(select-window org-window))
(message "Saved %s and inserted Org link"
(file-name-nondirectory file))))
(with-eval-after-load 'image-mode
(define-key image-mode-map (kbd "C-c i p") #'zaine/pdf-image-save-and-insert))
```
# CALDAV and org agenda calendars:
``` commonlisp
(require 'org-caldav)
(require 'url)
(require 'icalendar)
(modify-coding-system-alist 'file "caldav-work\\.org\\'" 'utf-8-unix)
(setq org-icalendar-timezone "Europe/London")
(setq calendar-time-zone 60) ;; minutes offset from UTC (BST = +60)
(setq calendar-standard-time-zone-name "GMT")
(setq calendar-daylight-time-zone-name "BST")
(setq org-caldav-timezone "Europe/London")
(defvar my/outlook-ics-url
"https://outlook.office365.com/owa/calendar/b910ea835e414663831e505f3d10baa2@microlise.com/d2568a0134fb49af92d39c1669c4729317662288011094411305/calendar.ics")
(defvar my/outlook-org-file
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-work.org")
(defvar my/ics-python-script
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\ics_to_org.py")
(defun my/sync-outlook-calendar ()
"Fetch and expand Outlook ICS (including recurrences) into org file."
(interactive)
(message "Syncing Outlook calendar...")
(let* ((cmd (format "python \"%s\" \"%s\" \"%s\""
my/ics-python-script
my/outlook-ics-url
my/outlook-org-file))
(result (shell-command-to-string cmd)))
(message "Outlook calendar sync: %s" (string-trim result))))
;; Sync on startup and every 30 minutes
(my/sync-outlook-calendar)
(run-with-timer (* 30 60) (* 30 60) #'my/sync-outlook-calendar)
;; --- CalDAV for native Nextcloud calendars ---
(setq org-caldav-url "https://nextcloud.zainezq.com/remote.php/dav/calendars/zaine/")
(setq org-caldav-calendars
'((:calendar-id "personal"
:inbox "D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-personal.org"
:files nil)
(:calendar-id "zxh"
:inbox "D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-family.org"
:files nil)))
;; --- Agenda files ---
(setq org-agenda-files
'("D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-personal.org"
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-work.org"
"D:\\_nextcloud\\master-folder\\org_files\\calendar\\caldav-family.org"
"D:\\_nextcloud\\master-folder\\org_files\\org_roam\\Books\\20250724230557-books_org_agenda.org"))
```
# Notes when reading physical book
``` commonlisp
("b" "Book Note" entry
(file+headline (lambda () (buffer-file-name)) "Notes")
"** p. %^{Page}\n[%^{Type|Insight|Important|Quote|Confusing}] %?\n")
```
# Org image inserter:
``` commonlisp
;;; --- Org image inserter (improved search UX) -----------------------------
(use-package vertico
:init (vertico-mode))
(use-package orderless
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil))
(defgroup zq/org-assets nil
"Insert image links from predefined asset profiles."
:group 'org)
(defcustom zq/org-asset-profiles
'(("org-roam" . "D:\\_nextcloud\\master-folder\\org_files\\org_roam\\assets")
("org-web" . "D:\\_nextcloud\\master-folder\\org_files\\org_web\\assets"))
"Alist of (PROFILE-NAME . ASSETS-DIR)."
:type '(alist :key-type string :value-type directory)
:group 'zq/org-assets)
(defcustom zq/org-image-extensions
'("png" "jpg" "jpeg" "gif" "svg" "webp" "mov" "mp4" "mp3")
"File extensions considered when offering candidates."
:type '(repeat string)
:group 'zq/org-assets)
(defun zq/org--image-regexp ()
(concat "\\." (regexp-opt zq/org-image-extensions t) "\\'"))
(defun zq/org--image-files (dir)
"Return image/media files in DIR, newest modified first."
(when (and dir (file-directory-p dir))
(sort
(directory-files-recursively dir (zq/org--image-regexp))
#'file-newer-than-file-p)))
(defun zq/org--parse-name (filename)
"Split FILENAME into (DATE . REST)."
(if (string-match "^\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-\\(.*\\)" filename)
(cons (match-string 1 filename)
(match-string 2 filename))
(cons nil filename)))
(defun zq/org--display-name (path)
(let* ((name (file-name-nondirectory path))
(dir (file-name-nondirectory (directory-file-name (file-name-directory path))))
(parsed (zq/org--parse-name name))
(date (car parsed))
(rest (cdr parsed)))
(format "%s (%s | %s)" rest (or date "no-date") dir)))
(defun zq/org--build-candidates (files)
"Return an alist of (DISPLAY . FULLPATH), handling duplicates.
Preserves the order of FILES, so newest files can appear first."
(let ((table (make-hash-table :test 'equal))
result)
(dolist (path files)
(let* ((display (zq/org--display-name path))
(existing (gethash display table)))
(if existing
;; duplicate → include full filename to disambiguate
(push (cons (file-name-nondirectory path) path) result)
(puthash display t table)
(push (cons display path) result))))
(nreverse result)))
(defun zq/org-insert-asset-image (&optional profile use-file-prefix)
"Insert an Org link to an image chosen from a PROFILEs assets dir.
Features:
- Fuzzy search (with Vertico/Orderless/Ivy/Helm)
- Clean names (date stripped)
- Relative paths inserted
With prefix arg (C-u), use file: links."
(interactive
(list (completing-read
"Profile: "
(mapcar #'car zq/org-asset-profiles)
nil t nil nil "org-roam")
current-prefix-arg))
(let* ((base-dir (cdr (assoc profile zq/org-asset-profiles)))
(_ (unless (and base-dir (file-directory-p base-dir))
(user-error "Invalid directory for profile '%s'" profile)))
(files (or (zq/org--image-files base-dir)
(user-error "No assets found in %s" base-dir)))
(candidates (zq/org--build-candidates files))
;; user selects clean name, we resolve full path
(selected (completing-read "Image: " candidates nil t))
(abs-path (cdr (assoc selected candidates)))
(here (or (buffer-file-name) default-directory))
(rel (file-relative-name abs-path (file-name-directory here)))
(link (format "[[%s%s]]"
(if use-file-prefix "file:" "")
rel)))
(insert link)
(when (derived-mode-p 'org-mode)
(org-display-inline-images t t))))
```
# Weekly org review file:
``` commonlisp
;; Create weekly review files for Sundays, with catch-up command to fill in any missing ones up to the current week.
(require 'seq)
(defvar zaine/weekly-review-base-dir
"D:/_nextcloud/master-folder/org_files/org_web/blogs/"
"Base directory for weekly review blog entries.")
(defun zaine/weekly-review--month-dir (time)
"Return the directory for TIME in the format YYYY/MM-month."
(let ((year (format-time-string "%Y" time))
(month-num (format-time-string "%m" time))
(month-name (downcase (format-time-string "%B" time))))
(expand-file-name (format "%s/%s-%s" year month-num month-name)
zaine/weekly-review-base-dir)))
(defun zaine/weekly-review--normalize-to-review-time (time)
"Normalize TIME to 12:00 on the same date."
(let* ((decoded (decode-time time))
(day (nth 3 decoded))
(month (nth 4 decoded))
(year (nth 5 decoded)))
(encode-time 0 0 12 day month year)))
(defun zaine/weekly-review--sunday-of-week (&optional time)
"Return the most recent Sunday on or before TIME, normalized to 12:00."
(let* ((time (or time (current-time)))
(decoded (decode-time time))
(dow (nth 6 decoded))
(day (nth 3 decoded))
(month (nth 4 decoded))
(year (nth 5 decoded)))
(encode-time 0 0 12 (- day dow) month year)))
(defun zaine/weekly-review--next-sunday (&optional time)
"Return the next Sunday strictly after TIME, normalized to 12:00.
If TIME is a Sunday, returns the following Sunday."
(let* ((time (or time (current-time)))
(decoded (decode-time time))
(dow (nth 6 decoded))
(days-ahead (if (= dow 0) 7 (- 7 dow))))
(zaine/weekly-review--normalize-to-review-time
(time-add time (days-to-time days-ahead)))))
(defun zaine/weekly-review--coming-sunday (&optional time)
"Return the coming Sunday relative to TIME, normalized to 12:00.
If TIME is a Sunday, return that day. Otherwise return the next Sunday."
(let* ((time (or time (current-time)))
(decoded (decode-time time))
(dow (nth 6 decoded)))
(if (= dow 0)
(zaine/weekly-review--normalize-to-review-time time)
(zaine/weekly-review--next-sunday time))))
(defun zaine/weekly-review--file-name (time)
"Return the weekly review filename for TIME."
(format-time-string "%d-%m-week-review.org" time))
(defun zaine/weekly-review--slug (time)
"Return the weekly review slug for TIME."
(format-time-string "%d-%m-%y-week-review" time))
(defun zaine/weekly-review--title (time)
"Return the title for TIME."
(format "%s - Weekly Review"
(format-time-string "[%d-%m-%Y]" time)))
(defun zaine/weekly-review--header (time)
"Return Org header text for weekly review at TIME."
(concat
(format "#+TITLE: %s\n" (zaine/weekly-review--title time))
"#+OPTIONS: num:nil\n"
(format "#+DATE: %s\n" (format-time-string "<%Y-%m-%d %a 12:00>" time))
"#+filetags: :review:\n"
"#+COMMENTS: t\n"
(format "#+SLUG: %s\n\n" (zaine/weekly-review--slug time))))
(defun zaine/weekly-review--all-review-files ()
"Return all weekly review files under `zaine/weekly-review-base-dir`."
(when (file-directory-p zaine/weekly-review-base-dir)
(directory-files-recursively
zaine/weekly-review-base-dir
"^[0-9]\\{2\\}-[0-9]\\{2\\}-week-review\\.org$")))
(defun zaine/weekly-review--extract-date-from-file (file)
"Extract review date from FILE path.
Expected path like:
.../blogs/YYYY/MM-month/DD-MM-week-review.org"
(when (string-match
"/blogs/\\([0-9]\\{4\\}\\)/[0-9]\\{2\\}-[[:lower:]]+/\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)-week-review\\.org$"
file)
(let* ((year (string-to-number (match-string 1 file)))
(day (string-to-number (match-string 2 file)))
(month (string-to-number (match-string 3 file))))
(encode-time 0 0 12 day month year))))
(defun zaine/weekly-review--latest-existing-sunday ()
"Return the latest Sunday review time found, or nil if none exist."
(let* ((files (zaine/weekly-review--all-review-files))
(dates (delq nil (mapcar #'zaine/weekly-review--extract-date-from-file files))))
(when dates
(seq-reduce
(lambda (latest current)
(if (time-less-p latest current) current latest))
(cdr dates)
(car dates)))))
(defun zaine/weekly-review--create-file-for-sunday (sunday)
"Create a weekly review file for SUNDAY if it doesn't exist.
Opens the file and returns its path. If it already exists, just opens it."
(let* ((target-dir (zaine/weekly-review--month-dir sunday))
(file-name (zaine/weekly-review--file-name sunday))
(file-path (expand-file-name file-name target-dir)))
(make-directory target-dir t)
(unless (file-exists-p file-path)
(with-temp-file file-path
(insert (zaine/weekly-review--header sunday))))
file-path))
;;; Public commands
(defun zaine/weekly-review-catchup ()
"Create all missing weekly review files from the oldest gap up to this week's Sunday.
If today is Monday 30 March, catches up through Sunday 29 March.
Creates one file per call so you can review each before continuing."
(interactive)
(let* ((past-sunday (zaine/weekly-review--sunday-of-week (current-time)))
(latest (zaine/weekly-review--latest-existing-sunday))
(next-needed (if latest
(zaine/weekly-review--normalize-to-review-time
(time-add latest (days-to-time 7)))
past-sunday)))
(if (time-less-p past-sunday next-needed)
(message "Weekly reviews are already up to date through %s."
(format-time-string "%d-%m-%Y" past-sunday))
(let ((file-path (zaine/weekly-review--create-file-for-sunday next-needed)))
(find-file file-path)
(message "Created missing review for Sunday %s — call again to catch up further."
(format-time-string "%d-%m-%Y" next-needed))))))
(defun zaine/weekly-review-create-coming ()
"Create the weekly review for the coming Sunday.
If today is Wednesday 1 April, creates the file for Sunday 5 April
in the April directory, creating it if needed.
If today is Sunday, creates today's review.
If the file already exists, just opens it."
(interactive)
(let* ((coming-sunday (zaine/weekly-review--coming-sunday (current-time)))
(file-path (zaine/weekly-review--create-file-for-sunday coming-sunday)))
(find-file file-path)
(message "%s review for Sunday %s."
(if (file-exists-p file-path) "Opened existing" "Created")
(format-time-string "%d-%m-%Y" coming-sunday))))
(global-set-key (kbd "C-c w r") #'zaine/weekly-review-catchup)
(global-set-key (kbd "C-c w c") #'zaine/weekly-review-create-coming)
```
# Insert org web entries
``` commonlisp
;; Create org web entries for blogs and posts with a consistent template and naming convention.
(defun zaine/create-org-web-entry ()
"Create a new org web entry in either blogs or posts."
(interactive)
(let* ((entry-type (completing-read "Choose type (blogs/posts): " '("blogs" "posts") nil t))
(slug (read-string "Filename / slug: "))
(title (read-string "Title: "))
(now (current-time))
(date-for-title (format-time-string "[%d-%m-%Y]" now))
(date-for-org (format-time-string "<%Y-%m-%d %a %H:%M>" now))
(year (format-time-string "%Y" now))
(month-num (format-time-string "%m" now))
(month-name (downcase (format-time-string "%B" now)))
(blog-dir (format "D:/_nextcloud/master-folder/org_files/org_web/blogs/%s/%s-%s"
year month-num month-name))
(post-dir "D:/_nextcloud/master-folder/org_files/org_web/posts/career")
(target-dir (if (string= entry-type "blogs") blog-dir post-dir))
(file-path (expand-file-name (concat slug ".org") target-dir))
(filetags (if (string= entry-type "blogs") ":life:" ":post:")))
;; Create directory if it does not exist
(unless (file-directory-p target-dir)
(make-directory target-dir t))
;; Open file and insert template if new
(find-file file-path)
(when (= (buffer-size) 0)
(insert (format "#+TITLE: %s\n" title))
(insert "#+OPTIONS: num:nil\n")
(insert (format "#+DATE: %s\n" date-for-org))
(insert (format "#+filetags: %s\n" filetags))
(insert "#+COMMENTS: t\n")
(insert (format "#+SLUG: %s\n\n" slug))
(save-buffer))))
```
# Insert org macros:
``` commonlisp
(defun org-insert-macro ()
"Interactively select and insert an Org macro with prompted values."
(interactive)
(let* ((macro-defs
'(("sidenote" . ("ID" "Content"))
("epigraph" . ("Quote" "Footer"))
("epigraph_single" . ("Quote"))
("epigraph3" . ("Quote" "Author" "Work"))
("kbd" . ("Key"))
("margimg" . ("Image URL" "Alt text" "Caption (optional)"))
("countdown" . ("ISO datetime (e.g. 2025-12-31T00:00:00)" "Label"))))
(name (completing-read "Insert macro: " (mapcar #'car macro-defs) nil t))
(args (cdr (assoc name macro-defs)))
(values (mapcar (lambda (prompt)
(read-string (format "%s: " prompt)))
args))
(macro (format "{{{%s(%s)}}}"
name
(mapconcat #'identity values ","))))
(insert macro)))
(define-key org-mode-map (kbd "C-c m") #'org-insert-macro)
```
# Insert Dailies into `20260421100223-dailies.org`
``` commonlisp
;; ─── org-roam daily auto-linker ───────────────────────────────────────────
(defvar my/org-roam-last-capture-file nil
"Stores the daily file path captured via org-roam-capture-new-node-hook.")
(defun my/org-roam-capture-store-file ()
"Store file path when a new org-roam node is created."
(when-let ((f (buffer-file-name)))
(setq my/org-roam-last-capture-file f)))
(defun my/org-roam-daily-already-linked-p (index-file date-str)
"Return t if DATE-STR already appears in INDEX-FILE."
(when (file-exists-p index-file)
(with-temp-buffer
(insert-file-contents index-file)
(search-forward date-str nil t))))
(defun my/org-roam-daily-add-link (index-file date-str)
"Append a heading linking DATE-STR daily into INDEX-FILE."
(message " Adding link for %s..." date-str)
(with-current-buffer (find-file-noselect index-file)
(save-excursion
(goto-char (point-max))
(unless (bolp) (insert "\n"))
(insert (format "** [[file:daily/%s.org][%s]]\n" date-str date-str)))
(save-buffer))
(org-roam-db-update-file index-file))
(defun my/org-roam-daily-link-to-index ()
"After capture, link today's daily into the index file."
(let ((captured-file
(or my/org-roam-last-capture-file
(ignore-errors
(plist-get org-capture-current-plist :original-file)))))
(when (and captured-file
(string-match-p (regexp-quote "daily") captured-file))
(let* ((today-date (file-name-base captured-file))
(index-file (expand-file-name
"20260421100223-dailies.org"
org-roam-directory)))
(if (my/org-roam-daily-already-linked-p index-file today-date)
(message " %s already linked, skipping." today-date)
(my/org-roam-daily-add-link index-file today-date)))
(setq my/org-roam-last-capture-file nil))))
(add-hook 'org-roam-capture-new-node-hook #'my/org-roam-capture-store-file)
(add-hook 'org-capture-after-finalize-hook #'my/org-roam-daily-link-to-index)
```
# Old stuff:
## org image inserter:
``` commonlisp
;; Core group & settings (dedupe: define these only once)
;; (defgroup zq/org-assets nil
;; "Insert image links from predefined asset profiles."
;; :group 'org)
;; (defcustom zq/org-asset-profiles
;; '(("org-roam" . "D:\\_nextcloud\\master-folder\\org_files\\org_roam\\assets")
;; ("org-web" . "D:\\_nextcloud\\master-folder\\org_files\\org_web\\assets"))
;; "Alist of (PROFILE-NAME . ASSETS-DIR)."
;; :type '(alist :key-type string :value-type directory)
;; :group 'zq/org-assets)
;; (defcustom zq/org-image-extensions '("png" "jpg" "jpeg" "gif" "svg" "webp" "mov" "mp4" "mp3")
;; "Image file extensions considered when offering candidates."
;; :type '(repeat string)
;; :group 'zq/org-assets)
;; (defun zq/org--image-regexp ()
;; "Build a regexp that matches configured image extensions."
;; (concat "\\." (regexp-opt zq/org-image-extensions t) "\\'"))
;; (defun zq/org--image-files (dir)
;; "Return a list of image files under DIR (recursively)."
;; (when (and dir (file-directory-p dir))
;; (directory-files-recursively dir (zq/org--image-regexp))))
;; (defun zq/org-insert-asset-image (&optional profile use-file-prefix)
;; "Insert an Org link to an image chosen from a PROFILEs assets dir.
;; Interactively:
;; - Prompts for PROFILE (from `zq/org-asset-profiles`).
;; - Presents only image files under that profiles assets directory.
;; - Inserts a relative link like [[path/to/image.png]].
;; - With prefix arg (C-u), uses [[file:path/to/image.png]].
;; Non-interactively:
;; PROFILE is the profile name string, USE-FILE-PREFIX non-nil forces file: prefix."
;; (interactive
;; (list (completing-read "Profile: "
;; (mapcar #'car zq/org-asset-profiles)
;; nil t nil nil "org-roam")
;; current-prefix-arg))
;; (let* ((base-dir (cdr (assoc profile zq/org-asset-profiles)))
;; (_ (unless (and base-dir (file-directory-p base-dir))
;; (user-error "Profile '%s' has no valid directory: %s" profile base-dir)))
;; (candidates (or (zq/org--image-files base-dir)
;; (user-error "No images found in %s" base-dir)))
;; (abs-path (expand-file-name (completing-read "Image: " candidates nil t)))
;; (here (or (buffer-file-name) default-directory))
;; (rel (file-relative-name abs-path (file-name-directory here)))
;; (link (format "[[%s%s]]"
;; (if use-file-prefix "file:" "")
;; rel)))
;; (insert link)
;; (when (derived-mode-p 'org-mode)
;; (org-display-inline-images t t))))
;;; --- Robust paste-into-profile without org-download--clipboard-image-p ---
;; (require 'url) ;; for url-copy-file
;; (require 'org-download) ;; for org-download-clipboard
;; (defun zq/org--ensure-dir (dir)
;; "Ensure DIR exists and is a directory; error if invalid."
;; (unless (and dir (file-directory-p dir))
;; (user-error "Profile directory invalid or not found: %s" dir))
;; (make-directory dir t)
;; dir)
;; (defun zq/org--unique-image-filename (&optional ext)
;; "Return a unique filename like 20260227_160404.png. Default EXT is png."
;; (concat (format-time-string "%Y%m%d_%H%M%S") "." (or ext "png")))
;; (defun zq/org--rel-link-to (abs-path)
;; "Return a relative Org link for ABS-PATH from current buffer."
;; (let* ((here (or (buffer-file-name) default-directory))
;; (rel (file-relative-name abs-path (file-name-directory here))))
;; (format "[[%s]]" rel)))
;; (defun zq/org--clipboard-text ()
;; "Return current clipboard text (or nil) without altering kill ring."
;; (let ((str (current-kill 0 t)))
;; (when (and str (stringp str) (> (length str) 0)) str)))
;; (defun zq/org--grab-clipboard-image-to-temp ()
;; "Try to capture clipboard image into a temporary PNG file.
;; Return the temp filename on success; nil otherwise. Temp file is caller-managed."
;; (let ((tmp (make-temp-file "zq-clip-" nil ".png"))
;; (ok nil))
;; (unwind-protect
;; (progn
;; ;; Try to save clipboard to TMP; some systems signal error when no image
;; (condition-case _err
;; (org-download-clipboard tmp)
;; (error
;; ;; ignore; ok remains nil
;; ))
;; ;; Validate: file exists, non-empty, and Emacs recognizes image type
;; (when (and (file-exists-p tmp)
;; (> (nth 7 (file-attributes tmp)) 0)
;; (ignore-errors (image-type-from-file tmp)))
;; (setq ok t)))
;; (unless ok
;; (when (file-exists-p tmp) (delete-file tmp))))
;; (when ok tmp)))
;; (defun zq/org--save-data-uri (data-uri target)
;; "Save a data:image/...;base64,... DATA-URI to TARGET."
;; (unless (string-match "\\`data:image/\\([a-zA-Z0-9+.-]+\\);base64,\\(.*\\)\\'" data-uri)
;; (user-error "Clipboard looks like a data URI but not an image/base64"))
;; (let ((bytes (base64-decode-string (match-string 2 data-uri))))
;; (with-temp-file target
;; (set-buffer-multibyte nil)
;; (insert bytes))))
;; (defun zq/org--download-url-to-file (url target)
;; "Download image from URL to TARGET (synchronously)."
;; (url-copy-file url target t))
;; (defun zq/org-paste-image-into-profile (&optional profile)
;; "Paste image (clipboard/URL/data-URI) into PROFILE assets and insert a relative Org link."
;; (interactive
;; (list (completing-read "Profile: "
;; (mapcar #'car zq/org-asset-profiles)
;; nil t nil nil "org-roam")))
;; (let* ((assets-dir (cdr (assoc profile zq/org-asset-profiles))))
;; (zq/org--ensure-dir assets-dir)
;; (let* ((filename (zq/org--unique-image-filename "png"))
;; (target (expand-file-name filename assets-dir))
;; (handled nil))
;; ;; 1) Preferred: raw image from clipboard via org-download backends
;; (let ((tmp (zq/org--grab-clipboard-image-to-temp)))
;; (when tmp
;; (rename-file tmp target t) ;; move tmp → target
;; (setq handled t)))
;; ;; 2) If no raw image, try clipboard text: data URI or URL
;; (unless handled
;; (let ((clip (zq/org--clipboard-text)))
;; (cond
;; ;; data URI
;; ((and clip (string-prefix-p "data:image/" clip))
;; (zq/org--save-data-uri clip target)
;; (setq handled t))
;; ;; http(s) URL
;; ((and clip (string-match-p "\\`https?://" clip))
;; (zq/org--download-url-to-file clip target)
;; (setq handled t)))))
;; (unless handled
;; (user-error
;; (concat
;; "No image found in clipboard.\n\n"
;; "Tips:\n"
;; "• In your browser, use **Copy image** (not “Copy image address”)\n"
;; "• Or copy from an image viewer / screenshot tool (to clipboard)\n"
;; "• On Wayland: install `wl-clipboard` (provides `wl-paste`)\n"
;; "• On X11: install `xclip` or `xsel`\n"
;; "• Alternatively: copy an image URL or a data:image/...;base64,... and retry")))
;; ;; Insert the relative link and display inline
;; (insert (zq/org--rel-link-to target))
;; (when (derived-mode-p 'org-mode)
;; (org-display-inline-images t t))
;; (message "Saved image → %s" target))))
```

View File

@@ -0,0 +1,28 @@
The purpose of this file is to store things related to emacs (that being packages, or community projects that i stumble across).
# Links
- [[Org Roam]] for roam related things
- [[GTD]]
- [[Keybindings Emacs]]
- [[Elisp]]
- [[Magit]]
- [[Evil Mode]]
- [[Org Publish]]
- [[Org Noter]]
- [[Emacs Calendar]]
- [[Emacs Config]]
# Resources
- A link that contains all the key bindings for emacs: [Keybindings list](http://xahlee.info/emacs/emacs/emacs_keybinding_list.html)
- the theme 'ef-dream' repository: [ef-themes](https://github.com/protesilaos/ef-themes)
- something to look into: [combobulate](https://github.com/mickeynp/combobulate)
- the use package git hub: [use-package](https://github.com/jwiegley/use-package)
- hamacs (someones emacs config) [hamacs](https://www.howardabrams.com/hamacs/)
- projectile doc [proj doc](https://docs.projectile.mx/projectile/configuration.html)
- doom style dashboard [doom dash](https://gist.github.com/DevelopmentCool2449/ffc91d1d9b7b16e0f48402b698386f3d#file-dashboard-doom-style-el)
- soft charcoal theme [sc](https://github.com/mswift42/soft-charcoal-theme?tab=readme-ov-file)
- the theme im currently using: [kaolin](https://github.com/ogdenwebb/emacs-kaolin-themes?tab=readme-ov-file)
- config: [config-dwt](https://gitlab.com/dwt1/configuring-emacs)
- simplenote to self hosted: [Link](https://ru2saig.github.io/posts/switching-from-simplenote-to-a-self-hosted-approach-nextcloud-orgzly-and-emacs/)

View File

@@ -0,0 +1,40 @@
C-u Cc . - timestamp
# Keybindings for moving:
## Search
To search use
Then if you want to get the hits, hit enter, then you can use 'n' for next and 'N' for previous hits.
## moving
- To move forward use 'e' and 'E'
- To move forward use 'b' and 'B'
(for beginning and end)
you can also use '{' and '}' for paragraph movement
- To move to the next line use: 'j'
- To move to the previous line use: 'k'
## replacement
that is a sample text
- Use 'r' To replace a single letter
- Use 'R' To enter replace mode and use ESC to exit it
To do a replace all:
- :%s//replacement/g
thats if the '/' has stored the last search, the /g is for all. if you dont use it, itll just replace the first one in each line. you can also use /gc which will prompt for confirmation.
- :'\<,'\>s//bar/g
thats if you are in visual mode
- :s/\<search<sub>string</sub>\>/\<replace<sub>string</sub>\>/g
thats a more generic one

1
Technical/Emacs/GTD.md Normal file
View File

@@ -0,0 +1 @@
- article: [gtd](https://hamberg.no/gtd)

View File

@@ -0,0 +1,14 @@
Keybindings I have come across:
# Get help for a major mode:
Type \`C-h m\` to get information for a major mode.
# TO indent a region n amount of spaces (where n is a number): \`C-u n C-x Tab\`
# Projectile:
- \`SPC-p p\` - switch project
- \`SPC-p f\` - find project
# Use C-u SPC X P to run powershell with args

71
Technical/Emacs/Magit.md Normal file
View File

@@ -0,0 +1,71 @@
# Magit Key Guide (Quick Reference)
## Open Magit
- C-x g
Open Magit status buffer
## Staging & Unstaging
- s
Stage (file or hunk)
- u
Unstage
- S
Stage all
- U
Unstage all
## Committing
- c c
Commit
- C-c C-c
Confirm commit (in commit buffer)
- c a
Amend last commit
## Branching
- b b
Switch branch
- b c
Create new branch
- b m
Merge into current
- b M
Rebase onto another branch
## Push / Pull
- P u
Push to upstream
- F u
Pull from upstream
- f u
Fetch from upstream
## Logs & Diffs
- l l
Show log for current branch
- d
Show diff (between commits, etc.)
- RET
View diff at point
## Help & Dispatch
- ?
Show help for current buffer
- x
Open Magit dispatch menu (magit-dispatch)
- \!
Run Git command (rebase, cherry-pick, etc.)
## Other Essentials
- k
Discard changes (careful)
- q
Quit Magit buffer

View File

@@ -0,0 +1,79 @@
****For the config, see [[Emacs Config]] for the Source of truth****
In order to create notes for a book:
1. Create an empty org roam file
2. Add the relative file path in metadata for that node, with the title `NOTER_DOCUMENT`
See the example below (auto save and page will get filled in)
3. Hover over the Notes heading created and click `SPC-n n` to open org noter
<!-- end list -->
``` org
* Ikigai Notes
:PROPERTIES:
:NOTER_DOCUMENT: ../../../pdfs/_misc/Ikigai.pdf
:NOTER_AUTO_SAVE_LAST_LOCATION: t
:NOTER_PAGE: 61
:END:
```
# Config needed:
``` commonlisp
(setq org-noter-notes-search-path
'("D:\\_nextcloud\\master-folder\\org_files\\org_roam\\"))
(setq org-noter-always-create-frame nil)
(setq org-noter-property-doc-file "NOTER_DOCUMENT")
(require 'pdf-tools)
(pdf-tools-install)
(use-package pdf-view-restore
:after pdf-tools
:config
(add-hook 'pdf-view-mode-hook 'pdf-view-restore-mode)
(setq pdf-view-restore-filename "~/.emacs.d/.pdf-view-restore"))
```
For non pdfs notes:
``` commonlisp
(setq org-capture-templates
'(("d" "Daily TODO" entry
(file+headline (lambda () (z/find-current-week-file)) "TODOs")
"* TODO %?\nSCHEDULED: %t\n"
:empty-lines 1)
("c" "Add to calendar.org" entry
(file+headline "~/master-folder/org_files/calendar.org" "Calendar")
"* TODO %?\nSCHEDULED: %^t\n"
:empty-lines 1)
("n" "Add notes" entry
(file+headline (lambda () (z/find-current-week-file)) "Notes")
"* Note: %?\n"
:empty-lines 1)
("w" "Weekly Review" entry
(file+function (lambda () (z/find-current-week-file)) z/goto-weekly-review)
"* Review: %?\nEntered on %U\n"
:empty-lines 1)
("b" "Book Note" entry
(file+headline (lambda () (buffer-file-name)) "Notes")
"** p. %^{Page}\n[%^{Type|Insight|Important|Quote|Confusing}] %?\n")
))
```
# Keybindings:
``` commonlisp
(dt/leader-keys
"n" '(:ignore t :wk "Org Noter")
"n n" '(org-noter :wk "Open org-noter")
)
```

View File

@@ -0,0 +1,163 @@
# How to insert footnotes:
The Org website\[1\] now looks a lot better than it used to.
# Resources:
<https://ogbe.net/blog/blogging_with_org>
<https://systemcrafters.net/publishing-websites-with-org-mode/building-the-site/>
<https://orgmode.org/manual/Publishing-options.html>
<https://www.orgroam.com/manual.html#Configuration>
<https://www.reddit.com/r/emacs/comments/1j7febh/my_static_website_is_generated_from_org_mode_and/?chainedPosts=t3_116yit2>
<https://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html>
<https://taingram.org/blog/org-mode-blog.html>
<https://karthinks.com/software/emacs-window-management-almanac/>
<https://gongzhitaao.org/orgcss/>
<https://ogbe.net/blog/emacs_org_static_site>
<https://edwardtufte.github.io/tufte-css/>
<https://zilongli.org/code/org-tufte-example>
# Extra snippets of code:
``` commonlisp
;; Commented out things:
;; (defvar z-head
;; "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
;; <link rel=\"stylesheet\" href=\"/style.css\" />")
;; (setq org-html-validation-link nil
;; org-html-head-include-scripts nil
;; org-html-head-include-default-style nil
;; org-html-head z-head)
;; (type-of (car '(rose violet daisy buttercup)))
;; (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))
;; (let ((list '(("post1.org") ("post2.org"))))
;; (mapconcat (lambda (entry)
;; (format "- [[file:%s]]" (car entry)))
;; list
;; "\n"))
;; ("website"
;; :components ("org-main" "org-categories-sitemap" "org-assets" "org-posts" "org-blogs" "org-static"))
;; :html-head "
;; <link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
;; <link rel=\"stylesheet\" href=\"../style.css\" />
;; <script src=\"../script.js\" defer></script>
;; "
(defun z/write-tag-pages ()
"Generate tags/*.org pages listing posts for each tag."
(let* ((site-root (expand-file-name "~/master-folder/org_files/org_web/"))
(tags-dir (expand-file-name "tags" site-root)))
(unless (file-directory-p tags-dir)
(make-directory tags-dir t))
(let ((idx (z/gather-tag-index)))
(maphash
(lambda (tag items)
(let* ((slug (z/tag-slug tag))
(outfile (expand-file-name (format "%s.org" slug) tags-dir)))
(with-temp-file outfile
(insert (format "#+TITLE: Tag: %s\n#+OPTIONS: toc:nil num:nil title:nil \n\n* Posts tagged %s\n"
tag tag))
;; sort newest first if DATE present
(setq items (sort items (lambda (a b) (string> (nth 2 a) (nth 2 b)))))
(dolist (it items)
(let* ((file (nth 0 it))
(title (nth 1 it))
(rel (file-relative-name file tags-dir)))
;; link to the source .org; org-publish will rewrite to the .html
(insert (format "- [[file:%s][%s]]\n" rel title)))))))
idx)
;; Also write an index page listing all tag pages
;; (let* ((all ()))
;; (maphash (lambda (tag _items) (push tag all)) (z/gather-tag-index))
;; (with-temp-file (expand-file-name "index.org" (expand-file-name "tags" site-root))
;; (insert "#+TITLE: All Tags\n#+OPTIONS: toc:nil num:nil\n\n* Tags\n")
;; (dolist (tag (sort all #'string-lessp))
;; (insert (format "- [[file:%s.org][%s]]\n" (z/tag-slug tag) tag)))))
)))
```
# Options stuff:
In Org mode, you can control per-file publishing behavior using special keywords (known as ****file-local metadata****) at the top of the file. These are written like:
\`\`\`org
\`\`\`
Here are ****useful options**** you can set ****per file****:
| | |
| -------------------------------- | --------------------------------------------------------- |
| Keyword | Purpose |
| ——————– | —————————————————– |
| \`\#+TITLE:\` | Title of the document |
| \`\#+AUTHOR:\` | Author name |
| \`\#+EMAIL:\` | Email address |
| \`\#+DATE:\` | Date |
| \`\#+OPTIONS:\` | Control export behavior (e.g. toc, num, author, etc.) |
| \`\#+HTML<sub>HEAD</sub>:\` | Custom HTML for \`\<head\>\` (like styles or scripts) |
| \`\#+HTML<sub>HEADEXTRA</sub>:\` | Extra HTML inserted in \`\<head\>\` |
| \`\#+HTML<sub>PREAMBLE</sub>:\` | Whether to include the preamble (\`t\`, \`nil\`, or HTML) |
| \`\#+HTML<sub>POSTAMBLE</sub>:\` | Same but for postamble |
| \`\#+LANGUAGE:\` | Language used for export |
| \`\#+DESCRIPTION:\` | Adds a \`\<meta name="description"\>\` tag |
| \`\#+KEYWORDS:\` | Adds a \`\<meta name="keywords"\>\` tag |
\#\#\# ✅ Example: Disable TOC and Section Numbers **for one file**
You can use the \`\#+OPTIONS:\` line like so:
\`\`\`org
\`\`\`
This disables the Table of Contents and section numbers ****just for that file****.
Your updated file might look like this:
``` commonlisp
#+TITLE: Welcome to My Org Website
#+OPTIONS: toc:nil num:nil
#+HTML_HEAD: <link rel="stylesheet" href="style.css">
#+HTML_HEAD: <script src="theme-toggle.js" defer></script>
```
Here's a reference for some values you can tweak via \`\#+OPTIONS:\`:
| | | |
| --------------- | ------------------------------------ | ------------------ |
| Option | Meaning | Example |
| ————- | ——————————– | —————- |
| \`toc:\` | Table of contents (\`t\` or \`nil\`) | \`toc:nil\` |
| \`num:\` | Section numbering | \`num:nil\` |
| \`author:\` | Show author name | \`author:nil\` |
| \`creator:\` | Show Emacs/Org creator info | \`creator:nil\` |
| \`date:\` | Show date | \`date:nil\` |
| \`html-style:\` | Disable default style | \`html-style:nil\` |
1. The link is: <https://orgmode.org>

View File

@@ -0,0 +1,38 @@
This base will contain information on org roam. Although its closely linked to the [[GTD]] node, that one will contain articles, notes and videos related to how to get things done.
# Main
[User Manual](https://www.orgroam.com/manual.html)
Here is the current config in my init.el
``` elisp
;;roam config
(use-package org-roam
:ensure t
:custom
(org-roam-directory "~/master-folder/org_files/org_roam")
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n i" . org-roam-node-insert))
:config
(org-roam-setup))
```
- for the org-roam-ui (the graphical interface for nodes): [org-roam-ui](https://github.com/org-roam/org-roam-ui)
- an article: [example-org-roam-workflow.org](https://gist.github.com/nickanderson/00005b5b03e323a65ada98c5fa5ebb11)
- An article to read: [How i use org in 2023](https://cmdln.org/2023/03/25/how-i-org-in-2023/)
- An article: [org-roam-guide](https://jethrokuan.github.io/org-roam-guide/)
- An article: [Own your second brain](https://ianjones.info/own-your-second-brain)
- article: [my-org-roam-workflows-for-taking-notes-and-writing-articles](https://honnef.co/articles/my-org-roam-workflows-for-taking-notes-and-writing-articles/)
- article: [how-i-use-org-roam-to-takes-notes-for-cs](https://michaelneuper.com/posts/how-i-use-org-roam-to-takes-notes-for-cs/)
The command below starts emacs in a terminal and kills it after 10 seconds. this is useful for when I add a note in the main machine, but the server's DB doesn't pick up the changes until Emacs is restarted in the server.
``` bash
timeout 10 emacs >/dev/null 2>&1
```
# Articles
- <https://orgmode.org/worg/index.html>