#+AUTHOR: Tom Berg #+OPTIONS: num:nil * Lexical Binding #+BEGIN_SRC emacs-lisp ;;; ... -*- lexical-binding: t -*- #+END_SRC * Package #+BEGIN_SRC emacs-lisp ;; Initialize package sources (require 'package) (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("org" . "https://orgmode.org/elpa/") ("elpa" . "https://elpa.gnu.org/packages/"))) (unless package-archive-contents (package-refresh-contents)) ;; Bootstrap use-package (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t) #+END_SRC * UI ** Clean up #+BEGIN_SRC emacs-lisp (setq inhibit-startup-message t) (scroll-bar-mode -1) ; Disable visible scrollbar (tool-bar-mode -1) ; Disable the toolbar (tooltip-mode -1) ; Disable tooltips (set-fringe-mode 10) ; Give some breathing room (menu-bar-mode -1) ; Disable the menu bar ;; Better defaults (setq ring-bell-function 'ignore) ; No bell sound (setq use-dialog-box nil) (setq truncate-lines nil) (setq truncate-partial-width-windows nil) #+END_SRC ** Fonts #+BEGIN_SRC emacs-lisp ;; Set fonts with better distinction for dysgraphia (set-face-attribute 'default nil :font "MesloLGS NF" :height 140) ;; Variable pitch font for Org prose (set-face-attribute 'variable-pitch nil :font "Inter" ; or "Georgia", "Source Sans Pro" :height 150) ;; Fixed pitch font (set-face-attribute 'fixed-pitch nil :font "MesloLGS NF" :height 140) #+END_SRC ** Theme #+BEGIN_SRC emacs-lisp (use-package doom-themes :ensure t :defer t :config ;; Fix circular face inheritance for Gnus faces ;; This prevents "Face inheritance results in inheritance cycle" errors ;; when creating new frames with emacsclient -c on pgtk builds ;; See: https://github.com/doomemacs/themes/issues/875 (setcdr (assoc 'gnus-group-news-low-empty doom-themes-base-faces) '(:inherit 'gnus-group-mail-1-empty :weight 'normal))) ;; Load theme immediately (this triggers doom-themes to load with the fix applied) (load-theme 'doom-tokyo-night t) ;; Enable doom-themes integrations (doom-themes-visual-bell-config) (doom-themes-org-config) ;; All-the-icons for visual indicators ;;(use-package all-the-icons ;; :if (display-graphic-p)) (use-package nerd-icons :ensure t) #+END_SRC ** Modeline #+BEGIN_SRC emacs-lisp (use-package doom-modeline :init (doom-modeline-mode 1) :config (setq doom-modeline-height 35) (setq doom-modeline-bar-width 6) (setq doom-modeline-lsp t) (setq doom-modeline-github nil) (setq doom-modeline-mu4e nil) (setq doom-modeline-irc nil) (setq doom-modeline-buffer-file-name-style 'truncate-except-project) (setq doom-modeline-major-mode-icon t)) #+END_SRC ** Dashboard #+BEGIN_SRC emacs-lisp (use-package dashboard :config (dashboard-setup-startup-hook) (setq dashboard-banner-logo-title "Command Center") (setq dashboard-startup-banner 'logo) (setq dashboard-center-content t) (setq dashboard-items '((recents . 5) (agenda . 5) (bookmarks . 5))) (setq dashboard-set-heading-icons t) (setq dashboard-set-file-icons t) (setq dashboard-week-agenda t) (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))) #+END_SRC ** Help #+BEGIN_SRC emacs-lisp (use-package which-key :init (which-key-mode) :diminish which-key-mode :config (setq which-key-idle-delay 0.5)) ; Quick popup fmory (use-package helpful :ensure t :bind (("C-h f" . helpful-callable) ("C-h v" . helpful-variable) ("C-h k" . helpful-key) ("C-h x" . helpful-command) ("C-h ." . helpful-at-point))) #+END_SRC ** Visual Enhancements #+BEGIN_SRC emacs-lisp ;; Highlight current line - Helps with focus (global-hl-line-mode 1) ;; Smooth scrolling (setq scroll-conservatively 101) (setq scroll-margin 5) (setq mouse-wheel-scroll-amount '(1)) (setq mouse-wheel-progressive-speed nil) ;; Remember cursor position (save-place-mode 1) ;; Matching parentheses (show-paren-mode 1) (setq show-paren-delay 0) ;; Electric pair mode - Auto close brackets (electric-pair-mode 1) #+END_SRC ** Auto-save and Backup #+BEGIN_SRC emacs-lisp ;; aggressive auto-save (setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) (setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-saves/" t))) (setq auto-save-default t) (setq auto-save-timeout 20) (setq auto-save-interval 200) ;; Recent files (recentf-mode 1) (setq recentf-max-menu-items 25) (setq recentf-max-saved-items 25) #+END_SRC * Evil Mode #+BEGIN_SRC emacs-lisp (use-package evil :ensure t :init (setq evil-want-integration t) (setq evil-want-keybinding nil) (setq evil-want-C-u-scroll t) (setq evil-want-C-i-jump nil) :config (evil-mode 1) (define-key evil-normal-state-map (kbd "n") 'evil-backward-char) (define-key evil-normal-state-map (kbd "e") 'evil-next-line) (define-key evil-normal-state-map (kbd "i") 'evil-previous-line) (define-key evil-normal-state-map (kbd "o") 'evil-forward-char) (define-key evil-visual-state-map (kbd "n") 'evil-backward-char) (define-key evil-visual-state-map (kbd "e") 'evil-next-line) (define-key evil-visual-state-map (kbd "i") 'evil-previous-line) (define-key evil-visual-state-map (kbd "o") 'evil-forward-char) (define-key evil-visual-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-visual-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-visual-state-map (kbd "l") 'evil-forward-word-end) (define-key evil-motion-state-map (kbd "n") 'evil-backward-char) (define-key evil-motion-state-map (kbd "e") 'evil-next-line) (define-key evil-motion-state-map (kbd "i") 'evil-previous-line) (define-key evil-motion-state-map (kbd "o") 'evil-forward-char) (define-key evil-motion-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-motion-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-motion-state-map (kbd "l") 'evil-forward-word-end) (define-key evil-normal-state-map (kbd "m") 'evil-insert) (define-key evil-normal-state-map (kbd "M") 'evil-insert-line) (define-key evil-normal-state-map (kbd "j") 'evil-open-below) (define-key evil-normal-state-map (kbd "J") 'evil-open-above) (define-key evil-normal-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-normal-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-normal-state-map (kbd "l") 'evil-forward-word-end) ;;(define-key evil-normal-state-map (kbd "") 'evil-end-of-line) (define-key evil-normal-state-map (kbd "k") 'evil-set-marker) (define-key evil-normal-state-map (kbd "C-w n") 'evil-window-left) (define-key evil-normal-state-map (kbd "C-w e") 'evil-window-down) (define-key evil-normal-state-map (kbd "C-w i") 'evil-window-up) (define-key evil-normal-state-map (kbd "C-w o") 'evil-window-right)) (use-package evil-collection :after evil :ensure t :config (evil-collection-init)) ;; Use hook to ensure our bindings always take precedence (add-hook 'evil-collection-setup-hook (lambda (_mode keymaps) (define-key evil-normal-state-map (kbd "n") 'evil-backward-char) (define-key evil-normal-state-map (kbd "e") 'evil-next-line) (define-key evil-normal-state-map (kbd "i") 'evil-previous-line) (define-key evil-normal-state-map (kbd "o") 'evil-forward-char) (define-key evil-normal-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-normal-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-normal-state-map (kbd "l") 'evil-forward-word-end) (define-key evil-visual-state-map (kbd "n") 'evil-backward-char) (define-key evil-visual-state-map (kbd "e") 'evil-next-line) (define-key evil-visual-state-map (kbd "i") 'evil-previous-line) (define-key evil-visual-state-map (kbd "o") 'evil-forward-char) (define-key evil-visual-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-visual-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-visual-state-map (kbd "l") 'evil-forward-word-end) (define-key evil-motion-state-map (kbd "n") 'evil-backward-char) (define-key evil-motion-state-map (kbd "e") 'evil-next-line) (define-key evil-motion-state-map (kbd "i") 'evil-previous-line) (define-key evil-motion-state-map (kbd "o") 'evil-forward-char) (define-key evil-motion-state-map (kbd "h") 'evil-ex-search-next) (define-key evil-motion-state-map (kbd "H") 'evil-ex-search-previous) (define-key evil-motion-state-map (kbd "l") 'evil-forward-word-end))) (use-package evil-org :after (evil org) :hook (org-mode . evil-org-mode) :config (evil-org-set-key-theme '(navigation insert textobjects additional calendar)) ;; Use hook to ensure our org bindings work (add-hook 'org-mode-hook (lambda () (evil-define-key 'normal evil-org-mode-map (kbd "n") 'evil-backward-char (kbd "e") 'evil-next-line (kbd "i") 'evil-previous-line (kbd "o") 'evil-forward-char (kbd "h") 'evil-ex-search-next (kbd "H") 'evil-ex-search-previous (kbd "l") 'evil-forward-word-end (kbd "m") 'evil-insert (kbd "M") 'evil-insert-line (kbd "j") 'evil-open-below (kbd "J") 'evil-open-above) (evil-define-key 'visual evil-org-mode-map (kbd "n") 'evil-backward-char (kbd "e") 'evil-next-line (kbd "i") 'evil-previous-line (kbd "o") 'evil-forward-char (kbd "h") 'evil-ex-search-next (kbd "H") 'evil-ex-search-previous (kbd "l") 'evil-forward-word-end)))) #+END_SRC * Programming ** UI #+BEGIN_SRC emacs-lisp (column-number-mode) (add-hook 'prog-mode-hook 'display-line-numbers-mode) (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) #+END_SRC ** Magit #+BEGIN_SRC emacs-lisp (use-package magit :commands (magit-status magit-get-current-branch) :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) #+END_SRC ** Git Visual Indicators #+BEGIN_SRC emacs-lisp ;; Show git changes in the editor fringe (use-package diff-hl :ensure t :hook ((prog-mode . diff-hl-mode) (org-mode . diff-hl-mode) (dired-mode . diff-hl-dired-mode)) :config ;; Highlight changes on the fly (diff-hl-flydiff-mode) ;; Update diff-hl after magit operations (add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh) (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh) ;; Better colors for visibility (custom-set-faces '(diff-hl-change ((t (:background "#3c3836" :foreground "#fabd2f")))) '(diff-hl-insert ((t (:background "#3c3836" :foreground "#b8bb26")))) '(diff-hl-delete ((t (:background "#3c3836" :foreground "#fb4934")))))) #+END_SRC ** Format #+BEGIN_SRC emacs-lisp (use-package format-all :commands format-all-mode :hook (prog-mode . format-all-mode) :config (setq-default format-all-formatters '(("C" (astyle "--mode=c")) ("Shell" (shfmt "-i" "4" "-ci"))))) #+END_SRC ** treesit #+BEGIN_SRC emacs-lisp (use-package treesit-auto :custom (treesit-auto-install 'prompt) :config (treesit-auto-add-to-auto-mode-alist 'all) (delete 'rust treesit-auto-langs) (global-treesit-auto-mode)) #+END_SRC ** direnv #+BEGIN_SRC emacs-lisp (use-package direnv :config (direnv-mode)) #+END_SRC ** Rust #+BEGIN_SRC emacs-lisp (use-package rust-mode :init (setq rust-mode-treesitter-derive t) :config (add-hook 'rust-mode-hook 'eglot-ensure) (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode))) #+END_SRC ** Haskell #+BEGIN_SRC emacs-lisp (use-package haskell-mode :config (add-to-list 'auto-mode-alist '("\\.hs\\'" . haskell-mode)) (add-hook 'haskell-mode-hook 'eglot-ensure)) #+END_SRC ** Nix #+BEGIN_SRC emacs-lisp (add-to-list 'auto-mode-alist '("\\.nix\\'" . nix-ts-mode)) #+END_SRC * Claude Code IDE Integration ** Terminal Backend #+BEGIN_SRC emacs-lisp ;; Choose your preferred terminal backend (eat is lighter and faster) (use-package eat :ensure t :vc (:url "https://codeberg.org/akib/emacs-eat" :rev :newest) :config ;; Enhanced eat terminal integration with evil mode (with-eval-after-load 'evil (define-key eat-mode-map (kbd "C-y") 'eat-yank) (add-hook 'eat-mode-hook (lambda () (when (bound-and-true-p evil-mode) (define-key evil-normal-state-local-map (kbd "p") 'eat-yank) (define-key evil-normal-state-local-map (kbd "P") 'eat-yank)))))) ;; Alternative: vterm (more features but heavier) ;; (use-package vterm ;; :ensure t) #+END_SRC ** Claude Code IDE #+BEGIN_SRC emacs-lisp ;; Modern Claude Code integration with Model Context Protocol (MCP) (use-package claude-code-ide :ensure t :vc (:url "https://github.com/manzaltu/claude-code-ide.el" :rev :newest) :bind ("C-c a" . claude-code-ide-menu) :config ;; Enable Emacs MCP tools for Claude to access LSP, tree-sitter, etc. (claude-code-ide-emacs-tools-setup) ;; Window placement - opens on the right side (setq claude-code-ide-window-side 'right claude-code-ide-window-width 100 claude-code-ide-focus-on-open t) ;; Terminal backend configuration (setq claude-code-ide-terminal-backend 'eat) ;; Enable better diff viewing with ediff (setq claude-code-ide-use-ide-diff t claude-code-ide-focus-claude-after-ediff nil claude-code-ide-show-claude-window-in-ediff t) ;; Better diff colors and settings (with-eval-after-load 'ediff ;; Split windows horizontally for better diff viewing (setq ediff-split-window-function 'split-window-horizontally) (setq ediff-window-setup-function 'ediff-setup-windows-plain) ;; Better diff highlighting (custom-set-faces '(ediff-current-diff-A ((t (:background "#2d1b1b" :foreground "#fb4934")))) '(ediff-current-diff-B ((t (:background "#1b2d1b" :foreground "#b8bb26")))) '(ediff-fine-diff-A ((t (:background "#4d2d2d" :foreground "#ff6b6b")))) '(ediff-fine-diff-B ((t (:background "#2d4d2d" :foreground "#4ecdc4")))) '(ediff-even-diff-A ((t (:background "#1c1c1c")))) '(ediff-even-diff-B ((t (:background "#1c1c1c")))) '(ediff-odd-diff-A ((t (:background "#262626")))) '(ediff-odd-diff-B ((t (:background "#262626")))))) ;; Auto-focus settings (setq claude-code-ide-focus-on-open t)) #+END_SRC ** Alternative Diff Viewer #+BEGIN_SRC emacs-lisp ;; Alternative: vdiff for even better diff viewing (use-package vdiff :ensure t :commands (vdiff-buffers vdiff-files) :config ;; Better diff colors for Tokyo Night theme (custom-set-faces '(vdiff-addition-face ((t (:background "#1b2d1b" :foreground "#b8bb26")))) '(vdiff-change-face ((t (:background "#2d1b1b" :foreground "#fabd2f")))) '(vdiff-closed-fold-face ((t (:background "#3c3836")))) '(vdiff-open-fold-face ((t (:background "#504945")))) '(vdiff-subtraction-face ((t (:background "#2d1b1b" :foreground "#fb4934"))))) ;; Keybindings for vdiff (define-key vdiff-mode-map (kbd "C-c v n") 'vdiff-next-hunk) (define-key vdiff-mode-map (kbd "C-c v p") 'vdiff-previous-hunk) (define-key vdiff-mode-map (kbd "C-c v q") 'vdiff-quit)) #+END_SRC ** MCP Server Setup #+BEGIN_SRC emacs-lisp ;; Helper function to set up MCP server for Claude Code (defun setup-claude-code-mcp () "Set up MCP server for Claude Code IDE integration." (interactive) (let ((setup-commands '("npm install -g claude-code-mcp-server" "claude mcp add-json emacs '{\"type\": \"stdio\", \"command\": \"claude-code-mcp\"}'"))) (message "Run these commands in your terminal to set up MCP:") (dolist (cmd setup-commands) (message " %s" cmd)) (with-temp-buffer (insert "# Claude Code MCP Setup Commands\n\n") (dolist (cmd setup-commands) (insert (format "%s\n" cmd))) (insert "\n# After running these commands, restart Emacs and try C-c a") (switch-to-buffer-other-window (current-buffer)) (markdown-mode)))) #+END_SRC ** Font Configuration for Claude Code #+BEGIN_SRC emacs-lisp ;; Ensure Claude Code's unicode characters display properly (defun setup-claude-code-fonts () "Configure font fallbacks for Claude Code's unicode characters." (when (display-graphic-p) ;; Disable default font for symbols to use our fallbacks (setq use-default-font-for-symbols nil) ;; Add fallback fonts for unicode characters Claude Code uses (set-fontset-font t 'symbol "DejaVu Sans" nil 'prepend) (set-fontset-font t 'unicode "Noto Color Emoji" nil 'prepend) (set-fontset-font t 'unicode "Symbola" nil 'prepend) ;; Keep your main font as primary (set-fontset-font t 'symbol "MesloLGS NF" nil 'prepend))) ;; Apply font setup after Emacs starts (add-hook 'emacs-startup-hook #'setup-claude-code-fonts) #+END_SRC ** Project and Directory Setup #+BEGIN_SRC emacs-lisp ;; Automatically create Claude Code directories and config files (defun setup-claude-code-directories () "Create necessary Claude Code directories and example files." (let ((claude-dirs '("~/.claude" "~/.claude/commands" "~/.claude/local")) (example-prompt "~/.claude-code.prompt.md") (example-command "~/.claude/commands/understand-guidelines.md")) ;; Create directories (dolist (dir claude-dirs) (unless (file-exists-p dir) (make-directory dir t))) ;; Create example project prompt (unless (file-exists-p example-prompt) (with-temp-buffer (insert "# Project Context\n\n") (insert "This is an Emacs configuration focused on productivity and brain-friendly workflows.\n\n") (insert "## Key Features\n") (insert "- Evil mode for Vim-like editing\n") (insert "- Org-roam for knowledge management\n") (insert "- Doom themes and modeline\n") (insert "- Focus modes for editing\n\n") (insert "Please maintain consistency with existing patterns and conventions.\n") (write-file example-prompt))) ;; Create example command (unless (file-exists-p example-command) (with-temp-buffer (insert "# Understand Guidelines\n\n") (insert "Please review the project context and understand the coding style.\n") (insert "Focus on:\n") (insert "- Emacs Lisp best practices\n") (insert "- use-package configuration patterns\n") (insert "- Evil mode compatibility\n") (insert "- User experience for friendly workflows\n") (write-file example-command))))) ;; Set up directories when claude-code-ide loads (with-eval-after-load 'claude-code-ide (setup-claude-code-directories)) #+END_SRC ** Evil Mode Integration #+BEGIN_SRC emacs-lisp ;; Evil keybindings for Claude Code IDE (with-eval-after-load 'claude-code-ide ;; Add Evil-friendly keybindings using leader key (with-eval-after-load 'evil (define-key evil-normal-state-map (kbd "SPC a c") 'claude-code-ide) (define-key evil-normal-state-map (kbd "SPC a m") 'claude-code-ide-menu) (define-key evil-normal-state-map (kbd "SPC a r") 'claude-code-ide-resume)) ;; Configure Claude Code buffers for Evil (add-hook 'claude-code-ide-mode-hook (lambda () (when (bound-and-true-p evil-mode) (define-key evil-normal-state-local-map (kbd "q") 'quit-window) (define-key evil-normal-state-local-map (kbd "r") 'revert-buffer))))) #+END_SRC ** Custom Tools for Claude Code #+BEGIN_SRC emacs-lisp ;; Example of exposing custom Emacs functions to Claude via MCP (with-eval-after-load 'claude-code-ide ;; Example: Expose org-roam functions to Claude (with-eval-after-load 'org-roam (claude-code-ide-make-tool :function #'org-roam-node-find :name "find_roam_node" :description "Find and open an org-roam node" :args '((:name "query" :type string :description "Search query for the node" :optional t))) (claude-code-ide-make-tool :function #'org-roam-capture :name "create_roam_note" :description "Create a new org-roam note" :args '((:name "title" :type string :description "Title for the new note" :optional t))))) #+END_SRC * Org ** Agenda Configuration #+BEGIN_SRC emacs-lisp ;; Simple agenda setup for habits (setq org-agenda-custom-commands '(("h" "Habits" agenda "" ((org-agenda-show-log t) (org-agenda-ndays 7) (org-agenda-log-mode-items '(closed clock state)) (org-agenda-skip-function '(org-agenda-skip-entry-if 'notregexp ":habit:")))) ("d" "Daily agenda and habits" ((agenda "" ((org-agenda-ndays 1) (org-agenda-overriding-header "Today's Schedule"))) (tags-todo "+habit" ((org-agenda-overriding-header "Daily Habits"))))) ("w" "Weekly Review" ((agenda "" ((org-agenda-ndays 7) (org-agenda-overriding-header "This Week"))) (todo "TODO" ((org-agenda-overriding-header "All TODOs"))))))) ;; Better agenda display (setq org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s") (todo . " %i %-12:c") (tags . " %i %-12:c") (search . " %i %-12:c"))) #+END_SRC ** Setup #+BEGIN_SRC emacs-lisp (defun dw/org-mode-setup () (org-indent-mode) (variable-pitch-mode 1) (auto-fill-mode 0) (visual-line-mode 1) (setq evil-auto-indent nil) (setq auto-save-timeout 10)) (use-package org :hook (org-mode . dw/org-mode-setup) :config (setq org-ellipsis " β–Ύ" org-hide-emphasis-markers t org-fontify-whole-heading-line t org-startup-folded 'content) ;; Bigger headings for better visual hierarchy (custom-set-faces '(org-level-1 ((t (:inherit outline-1 :height 1.4)))) '(org-level-2 ((t (:inherit outline-2 :height 1.3)))) '(org-level-3 ((t (:inherit outline-3 :height 1.2)))) '(org-level-4 ((t (:inherit outline-4 :height 1.1)))) '(org-level-5 ((t (:inherit outline-5 :height 1.0))))) ;; Keep some things fixed-pitch in Org (set-face-attribute 'org-table nil :inherit 'fixed-pitch) (set-face-attribute 'org-code nil :inherit 'fixed-pitch) (set-face-attribute 'org-block nil :inherit 'fixed-pitch) (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch) ;; TODO states with emojis (setq org-todo-keywords '((sequence "πŸ“₯ INBOX(i)" "πŸ“‹ TODO(t)" "⚑ NEXT(n)" "πŸš€ DOING(s!)" "⏸️ WAIT(w@)" "πŸ”„ ROUTINE(r)" "|" "βœ… DONE(d!)" "❌ CANCEL(c@)"))) ;; Colors for visual processing (setq org-todo-keyword-faces '(("πŸ“₯ INBOX" . (:foreground "gray" :weight bold)) ("πŸ“‹ TODO" . (:foreground "lightblue" :weight bold)) ("⚑ NEXT" . (:foreground "orange" :weight bold)) ("πŸš€ DOING" . (:foreground "red" :weight bold :underline t)) ("⏸️ WAIT" . (:foreground "magenta" :weight bold)) ("πŸ”„ ROUTINE" . (:foreground "cyan" :weight bold)) ("βœ… DONE" . (:foreground "green" :weight bold)) ("❌ CANCEL" . (:foreground "gray" :strike-through t))))) #+END_SRC ** Org Bullets #+BEGIN_SRC emacs-lisp (use-package org-bullets :after org :hook (org-mode . org-bullets-mode) :config (setq org-bullets-bullet-list '("β—‰" "β—‹" "●" "β—‹" "●" "β—‹" "●"))) #+END_SRC ** Org Appear #+BEGIN_SRC emacs-lisp (use-package org-appear :after org :hook (org-mode . org-appear-mode) :config (setq org-appear-autoemphasis t) (setq org-appear-autolinks t) (setq org-appear-autosubmarkers t)) #+END_SRC ** Org Roam #+BEGIN_SRC emacs-lisp (use-package org-roam :ensure t :init (setq org-roam-v2-ack t) :custom (org-roam-directory "~/roam/") (org-roam-completion-everywhere t) ;; Simple capture templates (org-roam-capture-templates '(("d" "default" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("n" "note" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %U\n\n") :unnarrowed t))) ;; Simple daily notes (org-roam-dailies-capture-templates '(("d" "default" entry "* %<%H:%M> %?" :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n\n")))) :bind (("C-c n n" . org-roam-buffer-toggle) ("C-c n f" . org-roam-node-find) ("C-c n g" . org-roam-graph) ("C-c n i" . org-roam-node-insert) ("C-c n c" . org-roam-capture) ("C-c n j" . org-roam-dailies-capture-today) ("C-c n t" . org-roam-dailies-goto-today) ("C-c n y" . org-roam-dailies-capture-yesterday) ("C-c n d" . org-roam-dailies-goto-date)) :config (org-roam-db-autosync-mode) ;; show context in completions (setq org-roam-node-display-template "${title:*} ${tags:20}") ;; Zettelkasten node type indicators (cl-defmethod org-roam-node-type ((node org-roam-node)) "Return the type of node based on its tags." (cond ((member "literature" (org-roam-node-tags node)) "πŸ“š") ((member "fleeting" (org-roam-node-tags node)) "πŸ¦‹") ((member "connection" (org-roam-node-tags node)) "πŸ”—") ((member "question" (org-roam-node-tags node)) "❓") ((member "dump" (org-roam-node-tags node)) "🧠") ((member "journal" (org-roam-node-tags node)) "πŸ“") ((member "daily" (org-roam-node-tags node)) "πŸ“…") ((member "habits" (org-roam-node-tags node)) "πŸ”„") (t "πŸ’‘"))) ;; add type to display (setq org-roam-node-display-template "${type} ${title:*} ${tags:20}")) #+end_src ** org roam ui #+begin_src emacs-lisp (use-package websocket :after org-roam) (use-package org-roam-ui :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)) #+end_src ** focus modes #+begin_src emacs-lisp ;; olivetti - centers text for better focus (use-package olivetti :hook (org-mode . olivetti-mode) :config (setq olivetti-body-width 100) (setq olivetti-minimum-body-width 80)) ;; focus mode - dims other sections (use-package focus :commands focus-mode :config (setq focus-dimness 0.3)) ;; writeroom mode - distraction free writing (use-package writeroom-mode :commands writeroom-mode :config (setq writeroom-width 100)) #+end_src ** Simple Habit Tracking #+begin_src emacs-lisp ;; Simple habit tracking with org-agenda + org-habit (with-eval-after-load 'org (require 'org-habit) (add-to-list 'org-modules 'org-habit) ;; Habit display settings - cleaner view (setq org-habit-graph-column 50) (setq org-habit-preceding-days 14) (setq org-habit-following-days 3) (setq org-habit-show-habits-only-for-today t) ;; Agenda configuration for habits (setq org-agenda-files '("~/roam/habits.org")) (setq org-agenda-include-diary nil) (setq org-habit-show-all-today t) ;; Create habits.org if it doesn't exist (let ((habits-file "~/roam/habits.org")) (unless (file-exists-p habits-file) (with-temp-buffer (insert "#+title: Habits\n#+filetags: :habits:\n\n") (insert "* Daily Habits\n\n") (insert "** TODO Exercise :habit:daily:\n") (insert "SCHEDULED: <" (format-time-string "%Y-%m-%d %a") " .+1d>\n") (insert ":PROPERTIES:\n:STYLE: habit\n:END:\n\n") (insert "** TODO Read 20min :habit:daily:\n") (insert "SCHEDULED: <" (format-time-string "%Y-%m-%d %a") " .+1d>\n") (insert ":PROPERTIES:\n:STYLE: habit\n:END:\n\n") (insert "** TODO Reflect/Journal :habit:daily:\n") (insert "SCHEDULED: <" (format-time-string "%Y-%m-%d %a") " .+1d>\n") (insert ":PROPERTIES:\n:STYLE: habit\n:END:\n\n") (insert "* Weekly Habits\n\n") (insert "** TODO Weekly review :habit:weekly:\n") (insert "SCHEDULED: <" (format-time-string "%Y-%m-%d %a") " .+1w>\n") (insert ":PROPERTIES:\n:STYLE: habit\n:END:\n\n") (write-file habits-file))))) #+end_src ** org clock #+begin_src emacs-lisp ;; time tracking configuration (with-eval-after-load 'org (setq org-clock-persist 'history) (org-clock-persistence-insinuate) ;; clock settings (setq org-clock-in-resume t) (setq org-clock-into-drawer t) (setq org-clock-out-remove-zero-time-clocks t) (setq org-clock-report-include-clocking-task t) ;; save clock history across sessions (setq org-clock-persist-file "~/.emacs.d/org-clock-save.el") ;; Suppress lexical-binding warnings for auto-generated files (setq warning-suppress-types '((files))) ;; keybindings for clocking (global-set-key (kbd "C-c C-x C-i") 'org-clock-in) (global-set-key (kbd "C-c C-x C-o") 'org-clock-out) (global-set-key (kbd "C-c C-x C-x") 'org-clock-in-last) (global-set-key (kbd "C-c C-x C-r") 'org-clock-report)) #+end_src ** org pomodoro #+begin_src emacs-lisp (use-package org-pomodoro :commands org-pomodoro :config (setq org-pomodoro-length 25) (setq org-pomodoro-short-break-length 5) (setq org-pomodoro-long-break-length 15) (setq org-pomodoro-play-sounds t)) #+end_src * command center #+begin_src emacs-lisp (use-package hydra) ;; Simple command center (defhydra hydra-capture-menu (:color blue :hint nil) " command center ----------------------------------------------- capture: _d_: default note _n_: note with date navigate: _f_: find note _t_: today note _g_: roam graph focus: _F_: focus mode _w_: writeroom _o_: olivetti tools: _a_: agenda _P_: pomodoro _C_: claude code _x_: exit " ;; Capture templates ("d" (lambda () (interactive) (require 'org-roam) (org-roam-capture nil "d"))) ; default note ("n" (lambda () (interactive) (require 'org-roam) (org-roam-capture nil "n"))) ; note with date ;; Navigation ("f" (lambda () (interactive) (require 'org-roam) (org-roam-node-find))) ("t" (lambda () (interactive) (require 'org-roam) (org-roam-dailies-goto-today))) ("g" (lambda () (interactive) (require 'org-roam) (org-roam-ui-open))) ;; Focus modes ("F" focus-mode) ("w" writeroom-mode) ("o" olivetti-mode) ;; Tools ("a" org-agenda) ("P" org-pomodoro) ("C" claude-code-ide-menu) ("x" nil)) (global-set-key (kbd "C-c h") 'hydra-capture-menu/body) #+end_src * Completion Stack ** Marginalia #+BEGIN_SRC emacs-lisp ;; Enable rich annotations using the Marginalia package (use-package marginalia ;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding ;; available in the *Completions* buffer, add it to the ;; `completion-list-mode-map'. :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) ;; The :init section is always executed. :init ;; Marginalia must be activated in the :init section of use-package such that ;; the mode gets enabled right away. Note that this forces loading the ;; package. (marginalia-mode)) #+END_SRC ** Orderless #+BEGIN_SRC emacs-lisp (use-package orderless :ensure t :custom (completion-styles '(orderless basic)) (completion-category-defaults nil) (completion-category-overrides '((file (styles basic partial-completion))))) #+END_SRC ** Vertico #+BEGIN_SRC emacs-lisp ;; Enable Vertico. (use-package vertico :custom (vertico-cycle t) ;; Enable cycling :init (vertico-mode)) ;; Persist history over Emacs restarts. Vertico sorts by history position. (use-package savehist :init (savehist-mode)) ;; Emacs minibuffer configurations. (use-package emacs :custom ;; Support opening new minibuffers from inside existing minibuffers. (enable-recursive-minibuffers t) ;; Hide commands in M-x which do not work in the current mode. Vertico ;; commands are hidden in normal buffers. This setting is useful beyond ;; Vertico. (read-extended-command-predicate #'command-completion-default-include-p) ;; Do not allow the cursor in the minibuffer prompt (minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt))) #+END_SRC ** Embark #+BEGIN_SRC emacs-lisp (use-package embark :ensure t :bind (("C-." . embark-act) ;; pick some comfortable binding ("C-;" . embark-dwim) ;; good alternative: M-. ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' :init ;; Optionally replace the key help with a completing-read interface (setq prefix-help-command #'embark-prefix-help-command) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) ;; Consult users will also want the embark-consult package. (use-package embark-consult :ensure t ; only need to install it, embark loads it after consult if found :hook (embark-collect-mode . consult-preview-at-point-mode)) #+END_SRC ** Consult #+BEGIN_SRC emacs-lisp ;; configuration for Consult (use-package consult ;; Replace bindings. Lazily loaded by `use-package'. :bind (;; C-c bindings in `mode-specific-map' ("C-c M-x" . consult-mode-command) ("C-c k" . consult-kmacro) ("C-c m" . consult-man) ("C-c i" . consult-info) ([remap Info-search] . consult-info) ;; C-x bindings in `ctl-x-map' ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command ("C-x b" . consult-buffer) ;; orig. switch-to-buffer ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer ;; Custom M-# bindings for fast register access ("M-#" . consult-register-load) ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) ("C-M-#" . consult-register) ;; Other custom bindings ("M-y" . consult-yank-pop) ;; orig. yank-pop ;; M-g bindings in `goto-map' ("M-g e" . consult-compile-error) ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck ("M-g g" . consult-goto-line) ;; orig. goto-line ("M-g M-g" . consult-goto-line) ;; orig. goto-line ("M-g o" . consult-outline) ;; Alternative: consult-org-heading ("M-g m" . consult-mark) ("M-g k" . consult-global-mark) ("M-g i" . consult-imenu) ("M-g I" . consult-imenu-multi) ;; M-s bindings in `search-map' ("M-s d" . consult-find) ;; Alternative: consult-fd ("M-s c" . consult-locate) ("M-s g" . consult-grep) ("M-s G" . consult-git-grep) ("M-s r" . consult-ripgrep) ("M-s l" . consult-line) ("M-s L" . consult-line-multi) ("M-s k" . consult-keep-lines) ("M-s u" . consult-focus-lines) ;; Isearch integration ("M-s e" . consult-isearch-history) :map isearch-mode-map ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s l" . consult-line) ;; needed by consult-line to detect isearch ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch ;; Minibuffer history :map minibuffer-local-map ("M-s" . consult-history) ;; orig. next-matching-history-element ("M-r" . consult-history)) ;; orig. previous-matching-history-element ;; Enable automatic preview at point in the *Completions* buffer. This is ;; relevant when you use the default completion UI. :hook (completion-list-mode . consult-preview-at-point-mode) ;; The :init configuration is always executed (Not lazy) :init ;; Tweak the register preview for `consult-register-load', ;; `consult-register-store' and the built-in commands. This improves the ;; register formatting, adds thin separator lines, register sorting and hides ;; the window mode line. (advice-add #'register-preview :override #'consult-register-window) (setq register-preview-delay 0.5) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config ;; Configure preview for different commands (consult-customize consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-man consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file ;; :preview-key "M-." :preview-key '(:debounce 0.4 any)) ;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. (setq consult-narrow-key "<")) ;; "C-+" #+END_SRC * Final Touches #+BEGIN_SRC emacs-lisp ;; Frame title (setq frame-title-format '("" "%b - Tom's Emacs")) ;; Create required directories if they don't exist (dolist (dir '("~/.emacs.d/backups" "~/.emacs.d/auto-saves" "~/roam" "~/roam/fleeting" "~/roam/dumps" "~/roam/journal" "~/roam/daily")) (unless (file-exists-p dir) (make-directory dir t))) #+END_SRC