;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- ;; Place your private configuration here! Remember, you do not need to run 'doom ;; sync' after modifying this file! ;; Some functionality uses this to identify you, e.g. GPG configuration, email ;; clients, file templates and snippets. It is optional. ;; (setq user-full-name "John Doe" ;; user-mail-address "john@doe.com") ;; Doom exposes five (optional) variables for controlling fonts in Doom: ;; ;; - `doom-font' -- the primary font to use ;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable) ;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for ;; presentations or streaming. ;; - `doom-symbol-font' -- for symbols ;; - `doom-serif-font' -- for the `fixed-pitch-serif' face ;; ;; See 'C-h v doom-font' for documentation and more examples of what they ;; accept. For example: ;; ;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light) ;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13)) ;; ;; If you or Emacs can't find your font, use 'M-x describe-font' to look them ;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to ;; refresh your font settings. If Emacs still can't find your font, it likely ;; wasn't installed correctly. Font issues are rarely Doom issues! ;; There are two ways to load a theme. Both assume the theme is installed and ;; available. You can either set `doom-theme' or manually load a theme with the ;; `load-theme' function. This is the default: (setq doom-theme 'doom-plain-dark) (custom-set-faces! '(default :background "#131313" :foreground "#FCFCFC")) (defvar my/syntax-comment "#6a6a6a") (defvar my/syntax-string "#b5bd68") (defvar my/syntax-keyword "#afd7ff") (defvar my/syntax-type "#ffd787") (defvar my/syntax-function "#d7afaf") (defun my/setup-syntax-highlighting (&rest _) "Apply a 5-color scheme to font-lock faces." (set-face-attribute 'font-lock-comment-face nil :foreground my/syntax-comment :slant 'italic) (set-face-attribute 'font-lock-comment-delimiter-face nil :foreground my/syntax-comment :slant 'italic) (set-face-attribute 'font-lock-doc-face nil :foreground my/syntax-comment :slant 'italic) (set-face-attribute 'font-lock-string-face nil :foreground my/syntax-string) (set-face-attribute 'font-lock-doc-markup-face nil :foreground my/syntax-string) (set-face-attribute 'font-lock-keyword-face nil :foreground my/syntax-keyword :weight 'bold) (set-face-attribute 'font-lock-builtin-face nil :foreground my/syntax-keyword) (set-face-attribute 'font-lock-preprocessor-face nil :foreground my/syntax-keyword) (set-face-attribute 'font-lock-negation-char-face nil :foreground my/syntax-keyword) (set-face-attribute 'font-lock-type-face nil :foreground my/syntax-type) (set-face-attribute 'font-lock-constant-face nil :foreground my/syntax-type) (set-face-attribute 'font-lock-function-name-face nil :foreground my/syntax-function) (set-face-attribute 'font-lock-variable-name-face nil :foreground "#FCFCFC") (set-face-attribute 'font-lock-warning-face nil :foreground my/syntax-function :weight 'bold) (set-face-attribute 'font-lock-regexp-grouping-backslash nil :foreground my/syntax-function) (set-face-attribute 'font-lock-regexp-grouping-construct nil :foreground my/syntax-function)) (my/setup-syntax-highlighting) (add-hook 'doom-load-theme-hook #'my/setup-syntax-highlighting 40) ;; This determines the style of line numbers in effect. If set to `nil', line ;; numbers are disabled. For relative line numbers, set this to `relative'. (setq display-line-numbers-type 'relative) ;; If you use `org' and don't want your org files in the default location below, ;; change `org-directory'. It must be set before org loads! (setq org-directory "~/Documents/notes/") ;; Keep terminal and editor typography aligned and ensure Nerd Font glyphs render. (setq doom-font (font-spec :family "FiraCode Nerd Font Mono" :size 15) doom-variable-pitch-font (font-spec :family "FiraCode Nerd Font" :size 15) doom-symbol-font (font-spec :family "FiraCode Nerd Font Mono" :size 15)) (defun my/setup-icon-font-fallback (&optional frame) "Ensure Nerd Font glyphs are available in FRAME." (with-selected-frame (or frame (selected-frame)) (when (display-graphic-p) (set-fontset-font t 'unicode "FiraCode Nerd Font Mono" nil 'append)))) (add-hook 'after-make-frame-functions #'my/setup-icon-font-fallback) (my/setup-icon-font-fallback) ;; Whenever you reconfigure a package, make sure to wrap your config in an ;; `after!' block, otherwise Doom's defaults may override your settings. E.g. ;; ;; (after! PACKAGE ;; (setq x y)) ;; ;; The exceptions to this rule: ;; ;; - Setting file/directory variables (like `org-directory') ;; - Setting variables which explicitly tell you to set them before their ;; package is loaded (see 'C-h v VARIABLE' to look up their documentation). ;; - Setting doom variables (which start with 'doom-' or '+'). ;; ;; Here are some additional functions/macros that will help you configure Doom. ;; ;; - `load!' for loading external *.el files relative to this one ;; - `use-package!' for configuring packages ;; - `after!' for running code after a package has loaded ;; - `add-load-path!' for adding directories to the `load-path', relative to ;; this file. Emacs searches the `load-path' when you load packages with ;; `require' or `use-package'. ;; - `map!' for binding new keys ;; ;; To get information about any of these functions/macros, move the cursor over ;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k'). ;; This will open documentation for it, including demos of how they are used. ;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces, ;; etc). ;; ;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how ;; they are implemented. (after! evil (require 'evil-collection)) (after! solaire-mode (solaire-global-mode -1) (defun my/neutralize-solaire-faces (&optional _frame) "Force solaire's lighter backgrounds to match the default background." (dolist (face '(solaire-default-face solaire-hl-line-face solaire-org-hide-face solaire-mode-line-face solaire-mode-line-inactive-face solaire-header-line-face solaire-header-line-inactive-face solaire-line-number-face solaire-fringe-face)) (when (facep face) (set-face-attribute face nil :background 'unspecified :inherit 'default)))) (my/neutralize-solaire-faces) (add-hook 'doom-load-theme-hook #'my/neutralize-solaire-faces 30) (add-hook 'after-make-frame-functions #'my/neutralize-solaire-faces)) (defvar my/gui-transparency 99 "Alpha background value for GUI frames (0-100).") (defun my/make-all-faces-transparent (&optional frame) "Make face backgrounds transparent in both terminal and GUI Emacs." (or frame (setq frame (selected-frame))) (if (display-graphic-p frame) ;; GUI: prefer alpha-background; keep alpha as macOS-compatible fallback. (progn (set-frame-parameter frame 'alpha-background my/gui-transparency) (set-frame-parameter frame 'alpha (cons my/gui-transparency my/gui-transparency))) ;; TTY: use terminal background (lets terminal emulator transparency show through). (progn (set-face-background 'default "unspecified-bg" frame) (mapc (lambda (face) (when (facep face) (let ((bg (face-background face nil nil))) (when (and bg (not (equal bg "unspecified-bg"))) (set-face-background face "unspecified-bg" frame))))) (face-list))))) (add-hook 'doom-load-theme-hook #'my/make-all-faces-transparent) (add-hook 'after-make-frame-functions #'my/make-all-faces-transparent) (add-hook 'window-setup-hook #'my/make-all-faces-transparent) (add-hook 'server-after-make-frame-hook #'my/make-all-faces-transparent) (add-to-list 'default-frame-alist `(alpha-background . ,my/gui-transparency)) (add-to-list 'default-frame-alist `(alpha . (,my/gui-transparency . ,my/gui-transparency))) (my/make-all-faces-transparent) (after! diff-hl (defun my/setup-diff-hl-faces () (set-face-attribute 'diff-hl-insert nil :foreground "green" :background 'unspecified) (set-face-attribute 'diff-hl-delete nil :foreground "red" :background 'unspecified) (set-face-attribute 'diff-hl-change nil :foreground "yellow" :background 'unspecified)) (my/setup-diff-hl-faces) (add-hook 'doom-load-theme-hook #'my/setup-diff-hl-faces 20) (defun my/diff-hl-hunk-text (ov) "Return the diff hunk text for overlay OV." (save-excursion (goto-char (overlay-start ov)) (let* ((line (line-number-at-pos)) (file (buffer-file-name)) (diff (when file (shell-command-to-string (format "git diff -U0 -- %s" (shell-quote-argument file)))))) (when (and diff (string-match (format "@@ [^ ]+ \\+\\([0-9]+\\)[, ].*@@\\([^@]*\\)" ) diff)) (let ((result nil)) (with-temp-buffer (insert diff) (goto-char (point-min)) (while (re-search-forward "^@@ -\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)? \\+\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)? @@.*$" nil t) (let* ((new-start (string-to-number (match-string 3))) (new-count (if (match-string 4) (string-to-number (match-string 4)) 1)) (hunk-start (match-beginning 0)) (hunk-end (or (save-excursion (when (re-search-forward "^@@ " nil t) (match-beginning 0))) (point-max)))) (when (and (>= line new-start) (< line (+ new-start (max new-count 1)))) (setq result (buffer-substring-no-properties hunk-start hunk-end)))))) result))))) (defun my/diff-hl-add-tooltips (&rest _) "Add help-echo tooltips to diff-hl overlays." (dolist (ov (overlays-in (point-min) (point-max))) (when (overlay-get ov 'diff-hl) (overlay-put ov 'help-echo (lambda (_win ov _pos) (my/diff-hl-hunk-text ov)))))) (advice-add 'diff-hl-update :after #'my/diff-hl-add-tooltips)) (after! (diff-hl magit) (add-hook 'magit-pre-refresh-hook #'diff-hl-magit-pre-refresh) (add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh)) (defun my/diff-hl-margin-setup (frame) (with-selected-frame frame (if (display-graphic-p) (diff-hl-margin-mode -1) (diff-hl-margin-mode +1)))) (add-hook 'after-make-frame-functions #'my/diff-hl-margin-setup) (when (daemonp) (add-hook 'server-after-make-frame-hook (lambda () (my/diff-hl-margin-setup (selected-frame))))) (defun my/yank-to-clipboard () "Yank to system clipboard via Evil's + register." (interactive) (let ((evil-this-register ?+)) (call-interactively #'evil-yank))) (defun my/yank-line-to-clipboard () "Yank current line to system clipboard via Evil's + register." (interactive) (let ((evil-this-register ?+)) (call-interactively #'evil-yank-line))) (map! :leader :desc "Yank to system clipboard" "y" #'my/yank-to-clipboard :desc "Yank line to system clipboard" "Y" #'my/yank-line-to-clipboard) (defun my/setup-selection-face () (unless (display-graphic-p) (set-face-attribute 'region nil :background "brightblack" :foreground "white" :extend t))) (add-hook 'doom-load-theme-hook #'my/setup-selection-face 10) (after! evil-goggles (set-face-attribute 'evil-goggles-default-face nil :background "brightblack" :foreground "white")) (setq scroll-margin 8) (remove-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h) (after! which-key (setq which-key-idle-delay 0.5)) (add-function :after after-focus-change-function (lambda () (unless (frame-focus-state) (save-some-buffers t)))) (defun my/dashboard-widget-loaded-centered () (when doom-init-time (let* ((msg (doom-display-benchmark-h 'return)) (width (with-current-buffer (doom-fallback-buffer) (window-width (get-buffer-window (current-buffer))))) (pad (max 0 (/ (- width (length msg)) 2)))) (insert "\n" (make-string pad ?\s) (propertize msg 'face '+dashboard-loaded) "\n")))) (setq +dashboard-functions '(+dashboard-widget-banner my/dashboard-widget-loaded-centered)) (setq org-startup-with-inline-images t) (defun my/open-pdf-in-sioyek () "Open PDF files in sioyek and close the Emacs buffer." (when (and buffer-file-name (string-match-p "\\.pdf\\'" buffer-file-name)) (let ((file buffer-file-name)) (kill-buffer (current-buffer)) (start-process "sioyek" nil "flatpak" "run" "com.github.ahrm.sioyek" file)))) (add-hook 'find-file-hook #'my/open-pdf-in-sioyek) ;; Move visual-line selection up/down with J/K; preserve original behavior in other visual modes (map! :v "J" (cmd! (if (eq evil-visual-selection 'line) (drag-stuff-down 1) (evil-join (region-beginning) (region-end)))) :v "K" (cmd! (if (eq evil-visual-selection 'line) (drag-stuff-up 1) (evil-lookup)))) (after! lsp-clangd (setq lsp-clients-clangd-executable "/usr/lib64/rocm/llvm/bin/clangd" lsp-clients-clangd-args '("--header-insertion=never" "--background-index" "--compile-commands-dir=."))) (after! lsp-mode (setq lsp-idle-delay 0.5 lsp-log-io nil lsp-completion-provider :capf lsp-completion-enable t lsp-enable-file-watchers nil lsp-auto-guess-root t lsp-enable-folding nil lsp-enable-text-document-color nil lsp-enable-on-type-formatting nil lsp-enable-snippet t lsp-enable-symbol-highlighting nil lsp-enable-links nil lsp-restart 'auto-restart lsp-keep-workspace-alive nil ;; Go / gopls lsp-go-hover-kind "FullDocumentation" lsp-go-analyses '((nilness . t) (unusedwrite . t) (unusedparams . t)) lsp-gopls-completeUnimported t lsp-gopls-staticcheck t lsp-gopls-use-placeholders t lsp-gopls-analyses '((unusedparams . t) (unusedwrite . t) (nilness . t)))) (after! lsp-ui (setq lsp-ui-doc-enable t lsp-ui-doc-position 'at-point lsp-ui-doc-max-height 8 lsp-ui-doc-max-width 72 lsp-ui-doc-show-with-cursor t lsp-ui-doc-delay 0.5 lsp-ui-sideline-enable nil lsp-ui-peek-enable t)) ;; Attach LSP to Go tree-sitter modes too (harmless if those modes never load) (add-hook 'go-ts-mode-hook #'lsp-deferred) (add-hook 'go-mod-ts-mode-hook #'lsp-deferred) ;;; --- Project detection (go/rust/node/python, fall back to .git) ----------- (after! project (add-hook 'project-find-functions (lambda (dir) (cond ((locate-dominating-file dir "go.mod") (cons 'transient (locate-dominating-file dir "go.mod"))) ((locate-dominating-file dir "Cargo.toml") (cons 'transient (locate-dominating-file dir "Cargo.toml"))) ((locate-dominating-file dir "package.json") (cons 'transient (locate-dominating-file dir "package.json"))) ((or (locate-dominating-file dir "pyproject.toml") (locate-dominating-file dir "setup.py") (locate-dominating-file dir "requirements.txt")) (cons 'transient (or (locate-dominating-file dir "pyproject.toml") (locate-dominating-file dir "setup.py") (locate-dominating-file dir "requirements.txt")))) ((locate-dominating-file dir ".git") (cons 'transient (locate-dominating-file dir ".git"))))))) (with-eval-after-load 'treesit (setq treesit-language-source-alist '((go "https://github.com/tree-sitter/tree-sitter-go" "master" "src") (gomod "https://github.com/camdencheek/tree-sitter-go-mod" "main" "src") (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src") (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src") (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src") (html "https://github.com/tree-sitter/tree-sitter-html" "master" "src") (css "https://github.com/tree-sitter/tree-sitter-css" "master" "src") (templ "https://github.com/vrischmann/tree-sitter-templ" "master" "src")))) (defun jb/install-treesit-grammars () "Install any missing tree-sitter grammars in `treesit-language-source-alist'." (interactive) (require 'treesit) (dolist (lang '(go gomod javascript typescript tsx html css templ)) (unless (treesit-language-available-p lang) (message "Installing grammar for %s..." lang) (treesit-install-language-grammar lang))) (message "Tree-sitter grammar installation complete!")) ;; Let org-babel source edits use the tree-sitter major modes (after! org (setq org-src-lang-modes (append org-src-lang-modes '(("go" . go-ts) ("javascript" . js-ts) ("typescript" . typescript-ts) ("html" . html-ts) ("css" . css-ts))))) ;;; --- Emmet ---------------------------------------------------------------- (add-hook 'sgml-mode-hook #'emmet-mode) (add-hook 'css-mode-hook #'emmet-mode) (setq emmet-expand-jsx-className? nil) (after! emmet-mode (map! :map emmet-mode-keymap :n "" #'emmet-expand-line)) ;;; --- vterm ---------------------------------------------------------------- (setq vterm-environment '("TERM=xterm-256color")) (set-language-environment "UTF-8") (set-default-coding-systems 'utf-8) (after! vterm (setq vterm-buffer-name-string "vterm %s") ;; Open vterm in the directory of the current buffer / dired location (defadvice! +vterm-use-current-directory-a (fn &rest args) "Make `vterm' open in the directory of the current buffer." :around #'vterm (let ((default-directory (or (and (buffer-file-name) (file-name-directory (buffer-file-name))) (and (eq major-mode 'dired-mode) (dired-current-directory)) default-directory))) (apply fn args))) (defadvice! +vterm-use-current-directory-b (fn &rest args) "Make Doom's `+vterm/here' open in the directory of the current buffer." :around #'+vterm/here (let ((default-directory (or (and (buffer-file-name) (file-name-directory (buffer-file-name))) (and (eq major-mode 'dired-mode) (dired-current-directory)) default-directory))) (apply fn args)))) (defun open-vterm-in-current-context () "Open vterm in the context of the current buffer/window." (interactive) (when-let ((buf (current-buffer))) (with-current-buffer buf (call-interactively #'+vterm/here)))) (after! magit (defun my/quick-commit-push () "Stage all, commit with a prompted message, and push to origin." (interactive) (let ((msg (read-string "Commit message: "))) (magit-call-git "add" "-A") (magit-call-git "commit" "-m" msg) (magit-call-git "push" "--set-upstream" "origin" (magit-get-current-branch)) (message "Committed and pushed: %s" msg)))) ;; Additive: keep Doom's full SPC g menu, just add quick commit+push on SPC g z (map! :leader :desc "Quick commit & push" "g z" #'my/quick-commit-push) (after! tramp (setq tramp-default-method "ssh" tramp-verbose 1 tramp-use-ssh-controlmaster-options nil tramp-chunksize 500 tramp-connection-timeout 10 remote-file-name-inhibit-cache nil tramp-cache-read-persistent-data t) (setq vc-ignore-dir-regexp (format "%s\\|%s" vc-ignore-dir-regexp tramp-file-name-regexp))) (after! treemacs (setq treemacs-position 'left treemacs-display-in-side-window t treemacs-width 35)) (defvar my/notes-dir (file-name-as-directory (expand-file-name "~/Documents/notes")) "Root directory for org notes, agenda, and capture files.") ;;; --- Org core: habits, logging, auto-clock on STRT ----------------------- (after! org (setq org-modules '(org-habit) org-log-done 'time org-clock-out-when-done nil) ;; Promote/demote with M-left/right in normal state (map! :map org-mode-map :n "" #'org-do-promote :n "" #'org-do-demote)) ;; Auto clock-in when a task enters STRT (a Doom default keyword), out when it leaves (defun my/org-clock-in-if-starting () "Clock in when the task state changes to STRT." (when (and (string= org-state "STRT") (not (org-clock-is-active))) (org-clock-in))) (defun my/org-clock-out-if-not-starting () "Clock out when leaving the STRT state." (when (and (org-clock-is-active) (not (string= org-state "STRT"))) (org-clock-out))) (add-hook 'org-after-todo-state-change-hook #'my/org-clock-in-if-starting) (add-hook 'org-after-todo-state-change-hook #'my/org-clock-out-if-not-starting) ;;; --- Org agenda: time grid + "Dashboard" custom view --------------------- (after! org (setq org-agenda-time-grid '((daily today require-timed) (500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000 2100) " " "────────────────") org-agenda-current-time-string "<── NOW ────────────────────────────────────────" org-habit-show-habits-only-for-today t org-habit-graph-column 50 org-agenda-remove-tags t org-agenda-block-separator ?─ org-agenda-custom-commands '(("d" "Dashboard" ((tags "PRIORITY=\"A\"" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nPRIORITY\n") (org-agenda-prefix-format " %?-12t %s"))) (agenda "" ((org-agenda-start-day "+0d") (org-agenda-span 1) (org-agenda-remove-tags t) (org-agenda-todo-keyword-format "") (org-agenda-scheduled-leaders '("" "")) (org-agenda-overriding-header "\nTODAY\n") (org-agenda-prefix-format " %?-12t %s"))) (tags-todo "-STYLE=\"habit\"" ((org-agenda-overriding-header "\ALL TASKS\n") (org-agenda-sorting-strategy '(priority-down)) (org-agenda-remove-tags t) (org-agenda-prefix-format " %?-12t %s")))))))) (defun my/org-agenda-dashboard () "Open the custom org-agenda dashboard." (interactive) (org-agenda nil "d")) (map! :leader :desc "Org dashboard" "o A" #'my/org-agenda-dashboard) ;;; --- Capture templates (paths under my/notes-dir) ------------------------ (after! org (setq org-capture-templates `(("t" "Todo" entry (file+headline ,(concat my/notes-dir "inbox.org") "Inbox") "* TODO %^{Task}\n:PROPERTIES:\n:CREATED: %U\n:CAPTURED: %a\n:END:\n%?") ("n" "Note" entry (file+headline ,(concat my/notes-dir "notes.org") "Inbox") "* [%<%Y-%m-%d %a>] %^{Title}\n:PROPERTIES:\n:CREATED: %U\n:CAPTURED: %a\n:END:\n%?" :prepend t) ("e" "Event" entry (file+headline ,(concat my/notes-dir "calendar.org") "Events") "* %^{Event}\n%^{SCHEDULED}T\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?") ("d" "Deadline" entry (file+headline ,(concat my/notes-dir "calendar.org") "Deadlines") "* TODO %^{Task}\nDEADLINE: %^{Deadline}T\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?")))) (use-package! org-roam :defer t :commands (org-roam-node-find org-roam-node-insert org-roam-dailies-goto-today org-roam-buffer-toggle org-roam-db-sync org-roam-capture) :init (setq org-roam-directory (concat my/notes-dir "roam") org-roam-database-connector 'sqlite-builtin org-roam-db-location (expand-file-name "org-roam.db" (concat my/notes-dir "roam")) org-roam-v2-ack t) :config (setq org-roam-db-update-on-save nil org-roam-completion-everywhere t) (unless (file-exists-p org-roam-directory) (make-directory org-roam-directory t)) (add-hook 'org-roam-find-file-hook (lambda () (unless org-roam-db-autosync-mode (org-roam-db-autosync-mode 1)))) (setq org-roam-capture-templates '(("d" "default" plain "%?" :target (file+head "${slug}.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: ${title}\n#+filetags: \n\n") :unnarrowed t) ("c" "concept" plain "%?" :target (file+head "concepts/${slug}.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: ${title}\n#+filetags: :concept:\n\n") :unnarrowed t) ("b" "book" plain "%?" :target (file+head "books/${slug}.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: ${title}\n#+author: \n#+filetags: :book:\n\n* Summary\n\n* Key Ideas\n\n* Quotes\n\n* Related\n\n") :unnarrowed t) ("p" "person" plain "%?" :target (file+head "people/${slug}.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: ${title}\n#+filetags: :person:\n\n* Background\n\n* Key Ideas\n\n* Works\n\n") :unnarrowed t) ("P" "project" plain "%?" :target (file+head "projects/${slug}.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: ${title}\n#+filetags: :project:\n\n* Overview\n\n* Goals\n\n* Status\n\n* Notes\n\n") :unnarrowed t))) (setq org-roam-dailies-directory "daily/" org-roam-dailies-capture-templates '(("d" "default" entry "* %<%H:%M>: %?" :target (file+head "%<%Y-%m-%d>.org" ":PROPERTIES:\n:ID: %(org-id-new)\n:END:\n#+title: %<%Y-%m-%d %A>\n#+filetags: :daily:\n\n"))))) (use-package! org-roam-ui :commands (org-roam-ui-mode org-roam-ui-open) :after org-roam :config (setq org-roam-ui-sync-theme t org-roam-ui-follow t org-roam-ui-update-on-save t org-roam-ui-open-on-start nil)) (defun my/org-insert-image () "Select and insert an image into the current org file." (interactive) (let ((file (read-file-name "Select image: " "~/Pictures/" nil t))) (when file (insert (format "[[file:%s]]\n" file)) (org-display-inline-images)))) (after! org (map! :map org-mode-map :localleader "I" #'my/org-insert-image)) (use-package! calfw :commands (cfw:open-calendar-buffer) :config (require 'calfw-org)) (use-package! calfw-org :commands (cfw:open-org-calendar) :after (calfw org)) (defun +calendar/open-calfw () (interactive) (require 'calfw-org) (cfw:open-org-calendar)) (map! :leader :desc "Calendar (calfw)" "o c" #'+calendar/open-calfw)