#+TITLE: rogs DOOM Emacs config #+AUTHOR: Roger Gonzalez (rogs) #+DESCRIPTION: rogs personal Doom Emacs config. * Introduction :PROPERTIES: :ID: 4e8ec984-b517-4e34-b018-7464650b2b9f :END: This configuration represents my personal Doom Emacs setup, focused on productivity, organization with Org-mode, and programming. The file is organized into logical sections, starting with basic settings, then appearance, followed by major functionality areas like Org-mode and programming language support. Key principles in this configuration: - Prioritize keyboard-driven workflows - Integrate personal productivity systems through Org-mode - Optimize for both writing and coding tasks This document serves both as configuration and as documentation. Each section explains not just what the code does, but why it's important to my workflow. If you're new to Doom Emacs, you can use this as a reference for setting up your own configuration. To navigate this file efficiently: - Use `SPC n s` to search for specific settings - Use `TAB` on headings to expand/collapse sections - Look for the explanatory text before each code block * Basic configuration :PROPERTIES: :ID: 4e8ec984-b517-4e34-b018-7464650b2b9f :END: This section contains fundamental identity settings that are used by various Emacs packages, particularly for version control systems like Git and for email clients. These settings ensure that my contributions are properly attributed. First off, set my user and email #+begin_src emacs-lisp (setq user-full-name "Roger Gonzalez" user-mail-address "roger@rogs.me") #+end_src * Look and feel :PROPERTIES: :ID: 0b198a7a-c736-4dd4-84a3-0ea21bcdc4fb :END: This section configures the visual aspects of my Emacs experience. I prefer a clean, distraction-free interface with a dark theme that's easy on the eyes during long coding sessions. Font choices prioritize readability and support for programming ligatures. ** Fonts :PROPERTIES: :ID: b4df4ef4-d0ca-4047-90b3-f4128425aa9f :END: This works only in Linux. On MacOS we keep the default fonts. #+begin_src emacs-lisp (if (not (eq system-type 'darwin)) (progn (setq doom-font (font-spec :family "MesloLGS Nerd Font" :size 14) doom-variable-pitch-font (font-spec :family "sans") doom-big-font (font-spec :family "MesloLGS Nerd Font" :size 24)))) #+end_src ** Theme :PROPERTIES: :ID: 3bae130e-3336-4bc7-9378-82c315e2aea6 :END: #+begin_src emacs-lisp (after! doom-themes (setq doom-themes-enable-bold t doom-themes-enable-italic t)) (custom-set-faces! '(font-lock-comment-face :slant italic) '(font-lock-keyword-face :slant italic)) (setq doom-theme 'doom-badger) (setq fancy-splash-image "~/.config/doom/logo.png") #+end_src ** Misc :PROPERTIES: :ID: cf3c202b-7610-4038-8e15-654a95a9d1dc :END: *** Display relative numbers on the buffer :PROPERTIES: :ID: 6a510691-0b78-44b8-ab92-518971051d8a :END: #+begin_src emacs-lisp (setq display-line-numbers-type 'relative) #+end_src * Org Mode + Org Roam :PROPERTIES: :ID: 96b93a81-3272-4f7a-a667-8a8783849d64 :END: The cornerstone of my productivity system. My entire life is managed through Org Mode and Org Roam, from task management and note-taking to project planning and knowledge management. This extensive configuration reflects years of refinement to match my personal workflow. The setup includes custom agenda views, capture templates, and todo states that implement a GTD-inspired system with my own modifications for different types of tasks and projects. Key components of this system: - Custom TODO states that reflect my workflow (NEXT, WAITING, SOMEDAY, etc.) - Visual styling to quickly identify task states and priorities - Capture templates for different types of information - Custom agenda views for different perspectives on my tasks - Recurring task handling with org-recur - ID-based linking for creating a personal knowledge graph This section is organized into logical subsections, each focusing on a specific aspect of the Org Mode configuration. The most frequently used features are placed earlier in the file. ** Set the directory :PROPERTIES: :ID: 99cbc04c-604c-4427-94fc-aa0603c78809 :END: #+begin_src emacs-lisp (setq org-directory "~/org/") (setq org-roam-directory "~/roam/") #+end_src ** Basic Org Setup :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e89f5 :END: This section contains the foundational settings for Org mode, including directory paths and basic behavior. #+begin_src emacs-lisp (after! org ;; Include diary (setq org-agenda-include-diary t) ;; Enforce ordered tasks (setq org-enforce-todo-dependencies t) (setq org-enforce-todo-checkbox-dependencies t) (setq org-track-ordered-property-with-tag t) ;; Text formatting (add-hook 'org-mode-hook #'auto-fill-mode) (setq-default fill-column 105) ;; Save all org buffers on each save (add-hook 'auto-save-hook 'org-save-all-org-buffers) (add-hook 'after-save-hook 'org-save-all-org-buffers) (require 'org-download) (add-hook 'dired-mode-hook 'org-download-enable) (add-hook 'org-mode-hook 'org-auto-tangle-mode)) #+end_src ** Task Management :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e89f6 :END: Configuration for task tracking, including TODO keywords, priorities, and logging behavior. This implements a GTD-inspired workflow with custom states to track different stages of task completion. The TODO keywords are carefully chosen to represent distinct states in my workflow: - REPEAT: Tasks that recur on a schedule - NEXT: The immediate next actions I should focus on - DELEGATED: Tasks I've assigned to someone else - TODO: Standard tasks that need to be done - WAITING: Tasks blocked by external factors - SOMEDAY: Ideas or tasks for future consideration - PROJ: Project containers that group related tasks Priorities follow a simple decision matrix: - A: Do it now (urgent and important) - B: Decide when to do it (important but not urgent) - C: Delegate it (urgent but not important) - D: Just an idea (neither urgent nor important) The logging configuration ensures I maintain a history of state changes, completion times, and notes about rescheduling. #+begin_src emacs-lisp (after! org ;; Logs (setq org-log-state-notes-insert-after-drawers nil org-log-into-drawer "LOGBOOK" org-log-done 'time org-log-repeat 'time org-log-redeadline 'note org-log-reschedule 'note) ;; TODO keywords and states (setq-default org-todo-keywords '((sequence "REPEAT(r)" "NEXT(n@/!)" "DELEGATED(e@/!)" "TODO(t@/!)" "WAITING(w@/!)" "SOMEDAY(s@/!)" "PROJ(p)" "|" "DONE(d@)" "CANCELLED(c@/!)" "FORWARDED(f@)"))) ;; Priorities configuration ;; A: Do it now ;; B: Decide when to do it ;; C: Delegate it ;; D: Just an idea (setq org-highest-priority ?A) (setq org-lowest-priority ?D) (setq org-default-priority ?B)) #+end_src ** Visual Styling :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e89f7 :END: Visual appearance settings for Org mode, including fonts, colors, and formatting. #+begin_src emacs-lisp (after! org ;; TODO keyword faces (setq-default org-todo-keyword-faces '(("REPEAT" . (:foreground "white" :background "indigo" :weight bold)) ("NEXT" . (:foreground "red" :background "orange" :weight bold)) ("DELEGATED" . (:foreground "white" :background "blue" :weight bold)) ("TODO" . (:foreground "white" :background "violet" :weight bold)) ("WAITING" (:foreground "white" :background "#A9BE00" :weight bold)) ("SOMEDAY" . (:foreground "white" :background "#00807E" :weight bold)) ("PROJ" . (:foreground "white" :background "deeppink3" :weight bold)) ("DONE" . (:foreground "white" :background "forest green" :weight bold)) ("CANCELLED" . (:foreground "light gray" :slant italic)) ("FORWARDED" . (:foreground "light gray" :slant italic)))) ;; Priority faces (setq org-priority-faces '((?A . (:foreground "white" :background "dark red" :weight bold)) (?B . (:foreground "white" :background "dark green" :weight bold)) (?C . (:foreground "yellow")) (?D . (:foreground "gray")))) ;; Headline styling (setq org-fontify-done-headline t) (setq org-fontify-todo-headline t) ;; Org bullets for prettier headings (require 'org-bullets) (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))) #+end_src ** Capture Templates :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e89f8 :END: Templates for quickly capturing various types of information into Org mode. #+begin_src emacs-lisp (after! org (setq org-capture-templates (quote (("G" "Define a goal" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/goal.org") :empty-lines-after 1) ("R" "REPEAT entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/repeat.org") :empty-lines-before 1) ("N" "NEXT entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/next.org") :empty-lines-before 1) ("T" "TODO entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/todo.org") :empty-lines-before 1) ("W" "WAITING entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/waiting.org") :empty-lines-before 1) ("S" "SOMEDAY entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/someday.org") :empty-lines-before 1) ("P" "PROJ entry" entry (file+headline "~/org/capture.org" "Capture") (file "~/org/templates/proj.org") :empty-lines-before 1) ("B" "Book on the to-read-list" entry (file+headline "~/org/private.org" "Libros para leer") (file "~/org/templates/book.org") :empty-lines-after 2) ("p" "Create a daily plan") ("pP" "Daily plan private" plain (file+olp+datetree "~/org/plan-free.org") (file "~/org/templates/dailyplan.org") :immediate-finish t :jump-to-captured t) ("pL" "Daily plan Lazer" plain (file+olp+datetree "~/org/plan-lazer.org") (file "~/org/templates/dailyplan.org") :immediate-finish t :jump-to-captured t) ("j" "Journal entry") ("jP" "Journal entry private" entry (file+olp+datetree "~/org/journal-private.org") "** %U - %^{Heading}") ("jL" "Journal entry Lazer" entry (file+olp+datetree "~/org/journal-lazer.org") "** %U - %^{Heading}"))))) #+end_src ** Agenda Views :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e89f9 :END: Custom agenda views for different perspectives on tasks and events. #+begin_src emacs-lisp (after! org (setq org-agenda-custom-commands (quote (("A" . "Agendas") ("AT" "Daily overview" ((tags-todo "URGENT" ((org-agenda-overriding-header "Urgent Tasks"))) (tags-todo "RADAR" ((org-agenda-overriding-header "On my radar"))) (tags-todo "PHONE+TODO=\"NEXT\"" ((org-agenda-overriding-header "Phone Calls"))) (tags-todo "COMPANY" ((org-agenda-overriding-header "Cuquitoni"))) (tags-todo "SHOPPING" ((org-agenda-overriding-header "Shopping"))) (tags-todo "Depth=\"Deep\"/NEXT" ((org-agenda-overriding-header "Next Actions requiring deep work"))) (agenda "" ((org-agenda-overriding-header "Today") (org-agenda-span 1) (org-agenda-start-day "1d") (org-agenda-sorting-strategy (quote (time-up priority-down))))) nil nil)) ("AW" "Weekly overview" agenda "" ((org-agenda-overriding-header "Weekly overview"))) ("AM" "Monthly overview" agenda "" ((org-agenda-overriding-header "Monthly overview")) (org-agenda-span (quote month)) (org-deadline-warning-days 0) (org-agenda-sorting-strategy (quote (time-up priority-down tag-up)))) ("W" . "Weekly Review Helper") ("Wn" "New tasks" tags "NEW" ((org-agenda-overriding-header "NEW Tasks"))) ("Wd" "Check DELEGATED tasks" todo "DELEGATED" ((org-agenda-overriding-header "DELEGATED tasks"))) ("Ww" "Check WAITING tasks" todo "WAITING" ((org-agenda-overriding-header "WAITING tasks"))) ("Ws" "Check SOMEDAY tasks" todo "SOMEDAY" ((org-agenda-overriding-header "SOMEDAY tasks"))) ("Wf" "Check finished tasks" todo "DONE|CANCELLED|FORWARDED" ((org-agenda-overriding-header "Finished tasks"))) ("WP" "Planing ToDos (unscheduled) only" todo "TODO|NEXT" ((org-agenda-overriding-header "To plan") (org-agenda-skip-function (quote (org-agenda-skip-entry-if (quote scheduled) (quote deadline)))))))))) #+end_src ** Org Recur :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e8910 :END: Configuration for handling recurring tasks with org-recur. #+begin_src emacs-lisp (after! org ;; Load org-recur (require 'org-recur) (after! org-recur (add-hook 'org-mode-hook #'org-recur-mode) (add-hook 'org-agenda-mode-hook #'org-recur-agenda-mode) (map! :map org-recur-mode-map "C-c d" #'org-recur-finish) (map! :map org-recur-agenda-mode-map "C-c d" #'org-recur-finish "C-c 0" #'org-recur-schedule-today) (setq org-recur-finish-done t org-recur-finish-archive t))) #+end_src ** Custom Org Functions :PROPERTIES: :ID: 37915445-e875-4da0-bab0-3f8f8b8e8911 :END: Custom functions to enhance Org mode functionality. These functions extend Org mode's capabilities to better support my specific workflow needs, including: - Automatic agenda refreshing after rescheduling tasks - Focus functions to filter agenda views by context - Automatic ID generation for reliable linking between notes - Clipboard functions for quick creation of Org links - Checkbox reset functionality for recurring tasks - Streamlined node insertion for Org-roam These functions represent solutions to friction points I've encountered in my daily use of Org mode, making the system more efficient and tailored to my needs. #+begin_src emacs-lisp (after! org ;; Refresh org-agenda after rescheduling a task (defun org-agenda-refresh () "Refresh all `org-agenda' buffers more efficiently." (let ((agenda-buffers (seq-filter (lambda (buf) (with-current-buffer buf (derived-mode-p 'org-agenda-mode))) (buffer-list)))) (dolist (buffer agenda-buffers) (with-current-buffer buffer (org-agenda-maybe-redo))))) (defadvice org-schedule (after refresh-agenda activate) "Refresh org-agenda." (org-agenda-refresh)) ;; Focus functions (defun org-focus (files msg) "Set focus on specific org FILES with notification MSG." (setq org-agenda-files files) (message msg)) (defun org-focus-private () "Set focus on private things." (interactive) (org-focus '("~/org/private.org") "Focusing on private Org files")) (defun org-focus-lazer () "Set focus on Lazer things." (interactive) (org-focus '("~/org/lazer.org") "Focusing on Lazer Org files")) (defun org-focus-all () "Set focus on all things." (interactive) (org-focus '("~/org/") "Focusing on all Org files")) ;; ID management (defun my/org-add-ids-to-headlines-in-file () "Add ID properties to all headlines in the current file which do not already have one." (interactive) (org-map-entries 'org-id-get-create)) (add-hook 'org-mode-hook (lambda () (add-hook 'before-save-hook 'my/org-add-ids-to-headlines-in-file nil 'local))) (defun my/copy-idlink-to-clipboard () "Copy an ID link with the headline to killring. If no ID exists, create a new unique ID. This function works only in org-mode or org-agenda buffers. The purpose of this function is to easily construct id:-links to org-mode items. If its assigned to a key it saves you marking the text and copying to the killring. This function is a cornerstone of my note-linking workflow. It creates and copies an org-mode ID link to the current heading, making it easy to reference content across my knowledge base. I use this constantly when creating connections between related notes or tasks." (interactive) (when (eq major-mode 'org-agenda-mode) ;if we are in agenda mode we switch to orgmode (org-agenda-show) (org-agenda-goto)) (when (eq major-mode 'org-mode) ; do this only in org-mode buffers (let* ((heading (nth 4 (org-heading-components))) (id (org-id-get-create)) (link (format "[[id:%s][%s]]" id heading))) (kill-new link) (message "Copied %s to killring (clipboard)" link)))) (global-set-key (kbd "") 'my/copy-idlink-to-clipboard) ;; Checkbox handling (defun org-reset-checkbox-state-maybe () "Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set." (interactive "*") (when (org-entry-get (point) "RESET_CHECK_BOXES") (org-reset-checkbox-state-subtree))) (defun org-checklist () (when (member org-state org-done-keywords) ;; org-state dynamically bound in org.el/org-todo (org-reset-checkbox-state-maybe))) (add-hook 'org-after-todo-state-change-hook 'org-checklist) ;; Org-roam functions (defun org-roam-node-insert-immediate (arg &rest args) "Insert a node immediately without the capture process." (interactive "P") (let ((args (cons arg args)) (org-roam-capture-templates (list (append (car org-roam-capture-templates) '(:immediate-finish t))))) (apply #'org-roam-node-insert args)))) #+end_src * Programming languages :PROPERTIES: :ID: fcb176c9-c9e5-42f6-b31d-3dafe8d0f64b :END: This section configures language-specific settings for the programming languages I use regularly. Each language has its own requirements for linting, formatting, and IDE-like features, which are handled through LSP where possible. My development workflow relies on having consistent tooling across different languages, with features like: - Code completion and documentation - Syntax checking and linting - Formatting according to language standards - Navigation and refactoring tools LSP (Language Server Protocol) provides most of these features in a standardized way across languages, while language-specific configurations handle unique requirements for each language ecosystem. ** LSP :PROPERTIES: :ID: 84836840-8642-46ad-8068-dc07086708f3 :END: #+begin_src emacs-lisp (after! lsp-mode (setq lsp-headerline-breadcrumb-enable t) (setq lsp-headerline-breadcrumb-icons-enable t)) #+end_src ** Python :PROPERTIES: :ID: 8f3279cf-53e2-4fe5-b30b-724d2d081cbe :END: #+begin_src emacs-lisp (after! python :init (require 'auto-virtualenv) (setq auto-virtualenv-global-dirs '("~/.virtualenvs/" "~/.pyenv/versions/" "~/.envs/" "~/.conda/" "~/.conda/envs/" "./.venv")) (add-hook 'python-mode-hook 'auto-virtualenv-setup) (setq enable-local-variables :all) (setq poetry-tracking-strategy 'projectile) (setq cov-coverage-mode t) (add-hook 'python-mode-hook 'cov-mode)) #+end_src ** Groovy :PROPERTIES: :ID: 8f8956c2-a7a3-4508-8f30-dc7a2f5e105b :END: #+begin_src emacs-lisp (after! groovy-mode (define-key groovy-mode-map (kbd "") 'my/jenkins-verify)) #+end_src ** Go :PROPERTIES: :ID: ee0c0fc1-7801-45ba-9302-73a78ce3d329 :END: #+begin_src emacs-lisp (setq lsp-go-analyses '((shadow . t) (simplifycompositelit . :json-false))) #+end_src ** RestClient :PROPERTIES: :ID: cf97ccd8-7023-48f0-8273-a1a64fad3fd0 :END: #+begin_src emacs-lisp (setq restclient-same-buffer-response nil) #+end_src * Custom :PROPERTIES: :ID: cd8a28bd-d91f-4ba8-b637-cb542ff5cca4 :END: Here's where custom functionalities get configured. ** Custom packages :PROPERTIES: :ID: 483ed79c-9eba-4544-8333-dda0139e9a08 :END: These are additional packages that aren't part of the standard Doom modules but that I find essential for my workflow: | Package name | Description | URL | |-----------------+------------------------------------------------+-----------------------------------------| | ~screenshot.el~ | Good for taking screenshots directly in Emacs. | https://github.com/tecosaur/screenshot | | ~private.el~ | This is a file for private values and API keys that shouldn't be in version control. | ~./custom-packages/private.el.example~. | #+begin_src emacs-lisp (add-to-list 'load-path "~/.config/doom/custom-packages") (require 'screenshot) (require 'private) #+end_src ** Custom functions :PROPERTIES: :ID: 0888b2db-9a0d-463d-89ad-371fcbfa0473 :END: *** Update DOOM Emacs init.el file :PROPERTIES: :ID: af485cc4-be52-4bb4-889d-7de8bea1ed66 :END: This function brings up a comparison between the current ~init.el~ file and the example file (~templates/init.example.el~). Very useful for upgrading manually. More info here: https://github.com/doomemacs/doomemacs/issues/581#issuecomment-645448095 #+begin_src emacs-lisp (defun my/ediff-init-and-example () "Compare init.el with the example init file." (interactive) (let ((init-file (concat doom-user-dir "init.el")) (example-file (concat doom-emacs-dir "templates/init.example.el"))) (if (and (file-exists-p init-file) (file-exists-p example-file)) (ediff-files init-file example-file) (message "Cannot find init.el or example file")))) (define-key! help-map "di" #'my/ediff-init-and-example) #+end_src *** HTTP Statuses :PROPERTIES: :ID: 3fa9d843-f163-4f04-8129-918fb57603a4 :END: This is a custom helm command that displays all the HTTP status codes with their descriptions. As a developer working with web APIs, I frequently need to reference these codes. This function provides a quick, searchable reference without leaving Emacs or disrupting my workflow. Usage: `M-x helm-httpstatus` or through the applications menu with `SPC a h` #+begin_src emacs-lisp (defvar helm-httpstatus-source '((name . "HTTP STATUS") (candidates . (("100 Continue") ("101 Switching Protocols") ("102 Processing") ("200 OK") ("201 Created") ("202 Accepted") ("203 Non-Authoritative Information") ("204 No Content") ("205 Reset Content") ("206 Partial Content") ("207 Multi-Status") ("208 Already Reported") ("300 Multiple Choices") ("301 Moved Permanently") ("302 Found") ("303 See Other") ("304 Not Modified") ("305 Use Proxy") ("307 Temporary Redirect") ("400 Bad Request") ("401 Unauthorized") ("402 Payment Required") ("403 Forbidden") ("404 Not Found") ("405 Method Not Allowed") ("406 Not Acceptable") ("407 Proxy Authentication Required") ("408 Request Timeout") ("409 Conflict") ("410 Gone") ("411 Length Required") ("412 Precondition Failed") ("413 Request Entity Too Large") ("414 Request-URI Too Large") ("415 Unsupported Media Type") ("416 Request Range Not Satisfiable") ("417 Expectation Failed") ("418 I'm a teapot") ("421 Misdirected Request") ("422 Unprocessable Entity") ("423 Locked") ("424 Failed Dependency") ("425 No code") ("426 Upgrade Required") ("428 Precondition Required") ("429 Too Many Requests") ("431 Request Header Fields Too Large") ("449 Retry with") ("500 Internal Server Error") ("501 Not Implemented") ("502 Bad Gateway") ("503 Service Unavailable") ("504 Gateway Timeout") ("505 HTTP Version Not Supported") ("506 Variant Also Negotiates") ("507 Insufficient Storage") ("509 Bandwidth Limit Exceeded") ("510 Not Extended") ("511 Network Authentication Required"))) (action . message))) (defun helm-httpstatus () (interactive) (helm-other-buffer '(helm-httpstatus-source) "*helm httpstatus*")) #+end_src *** Convert HTML to org :PROPERTIES: :ID: b81dff7f-9bc5-4601-97fe-6c2b9e78366c :END: This function converts clipboard contents from HTML to Org format and then pastes (yanks) the result. It's extremely useful when researching online and wanting to capture formatted content directly into my org notes without losing structure. Dependencies: - ~pandoc~ for the format conversion - ~xclip~ for clipboard access Usage: Press F4 in any org-mode buffer to convert and paste HTML from clipboard #+begin_src emacs-lisp (defun my/html2org-clipboard () "Convert HTML in clipboard to Org format and paste it." (interactive) (condition-case err (progn (kill-new (shell-command-to-string "timeout 1 xclip -selection clipboard -o -t text/html | pandoc -f html -t json | pandoc -f json -t org --wrap=none")) (yank) (message "Pasted HTML in org")) (error (message "Error converting HTML to Org: %s" (error-message-string err))))) (after! org (define-key org-mode-map (kbd "") 'my/html2org-clipboard)) #+end_src *** My own menu :PROPERTIES: :ID: 60a0316f-8bb8-40fe-af45-e42cdb6da60a :END: This is a custom menu for my own functions #+begin_src emacs-lisp (map! :leader (:prefix-map ("a" . "applications") :desc "HTTP Status cheatsheet" "h" #'helm-httpstatus) (:prefix-map ("ao" . "org") :desc "Org focus Lazer" "l" #'org-focus-lazer :desc "Org focus private" "p" #'org-focus-private :desc "Org focus all" "a" #'org-focus-all )) #+end_src * Misc :PROPERTIES: :ID: b57fe5fe-18ce-4215-ba94-8deee3a2b64f :END: ** Clipmon :PROPERTIES: :ID: 7b6776af-f357-4f87-9850-4eae4f8daa76 :END: Clipmon serves as my clipboard manager within Emacs. I chose it over alternatives like ~helm-clipboard~ because it offers better integration with my workflow and provides automatic monitoring of clipboard changes. This allows me to maintain a history of copied text without manual intervention. The configuration below sets up Clipmon to check the clipboard every second and makes the kill ring accessible through M-y with helm integration. #+begin_src emacs-lisp ;; Ensure clipmon is loaded (require 'clipmon) (after! clipmon (global-set-key (kbd "M-y") 'helm-show-kill-ring) (add-to-list 'after-init-hook 'clipmon-mode-start) (defadvice clipmon--on-clipboard-change (around stop-clipboard-parsing activate) (let ((interprogram-cut-function nil)) ad-do-it)) (setq clipmon-timer-interval 1)) #+end_src ** Git :PROPERTIES: :ID: 51176440-f985-4c90-94a7-bed48286272c :END: *** Set ~delta~ as the default magit diff :PROPERTIES: :ID: fa6dc3cb-50d7-49cd-96cb-e91a122b1316 :END: #+begin_src emacs-lisp (add-hook 'magit-mode-hook (lambda () (magit-delta-mode +1))) #+end_src *** Accept pre-commit messages when creating git commits with magit-gptcommit mode :PROPERTIES: :ID: 2c8ead63-0929-4f52-9816-85d8e24b8123 :END: #+begin_src emacs-lisp (defun my/magit-gptcommit-commit-accept-wrapper (orig-fun &rest args) "Wrapper for magit-gptcommit-commit-accept to preserve original message." (when-let ((buf (magit-commit-message-buffer))) (with-current-buffer buf (let ((orig-message (string-trim-right (or (git-commit-buffer-message) "") "\n$"))) (apply orig-fun args) (unless (string-empty-p orig-message) (save-excursion (goto-char (point-min)) (insert orig-message))))))) (advice-add 'magit-gptcommit-commit-accept :around #'my/magit-gptcommit-commit-accept-wrapper) #+end_src ** LLM :PROPERTIES: :ID: 0a32d2a9-2156-42a3-90f7-419ac1a25496 :END: This section configures various AI assistants and Large Language Model integrations. These tools augment my workflow by providing code suggestions, helping with documentation, and automating repetitive tasks like writing commit messages. I use a combination of local models (via Ollama) and cloud services (OpenAI, Anthropic) depending on the task requirements and privacy considerations: - GitHub Copilot: For real-time code suggestions while typing - ChatGPT Shell: For general programming assistance and problem-solving - Magit GPT: For automatically generating meaningful commit messages - Forge LLM: For analyzing and summarizing GitHub issues and PRs - Aider: For more complex code generation and refactoring tasks Each tool has specific strengths, and I've configured them to complement each other in my development workflow. The API keys are stored in a separate private.el file for security. *** ChatGPT Shell :PROPERTIES: :ID: 9bdfbd96-deec-4335-8d2c-77fff0283708 :END: #+begin_src emacs-lisp (setq chatgpt-shell-model-version "gpt-4o") (setq chatgpt-shell-streaming "t") (setq chatgpt-shell-system-prompt "You are a senior developer knowledgeable in every programming language") (setq chatgpt-shell-openai-key openai-key) (setq dall-e-shell-openai-key openai-key) #+end_src *** Magit GPT :PROPERTIES: :ID: 3f720f16-b7a3-4127-81e9-87d849827639 :END: #+begin_src emacs-lisp (require 'llm-ollama) (setq magit-gptcommit-llm-provider (make-llm-ollama :scheme "http" :host "192.168.0.122" :embedding-model "gemma3:12b" :chat-model "gemma3:12b")) (setq llm-warn-on-nonfree nil) (after! magit (magit-gptcommit-mode 1) (setq magit-gptcommit-prompt "You are an expert programmer crafting a Git commit message. Carefully review the following file diffs as if you had read each line. Your goal is to generate a commit message that follows the kernel Git commit style guide. SUMMARY INSTRUCTIONS: - Write a one-line summary of the change, no more than 50 characters. - Use the imperative tense (for example, use 'Improve logging output' instead of 'Improved logging' or 'Improves logging'). - Do not include prefixes like Fix:, Feat:, or Chore: at the beginning of the summary. - The summary must not end with a period. - Ensure the summary reflects a single, specific, and cohesive purpose. COMMENT INSTRUCTIONS: - After the summary, write concise developer-facing comments explaining the commit. - Each comment must be on its own line and prefixed with '-'. - Each comment must end with a period. - Do not include any paragraphs, introductions, or extra explanations. - Do not use backticks (`) anywhere in the summary or comments. - Do not use Markdown formatting (e.g., *, **, #, _, or inline code). THE FILE DIFFS: %s Now, write the commit message in this exact format: - comment1 - comment2 - commentN") (magit-gptcommit-status-buffer-setup)) #+end_src *** Forge LLM :PROPERTIES: :ID: 51b0f8e3-68b3-46af-91d4-a9b87b1e6b94 :END: #+begin_src emacs-lisp (require 'forge-llm) (forge-llm-setup) (require 'llm-claude) (setq forge-llm-llm-provider (make-llm-claude :key anthropic-key :chat-model "claude-3-7-sonnet-latest")) (setq forge-llm-max-diff-size 'nil) #+end_src *** Github Copilot :PROPERTIES: :ID: 7f88ce20-846c-47e4-aeed-d853212c9db5 :END: #+begin_src emacs-lisp ;; Load copilot (require 'copilot) (after! copilot (add-hook 'prog-mode-hook #'copilot-mode) (map! :map copilot-completion-map "" #'copilot-accept-completion "TAB" #'copilot-accept-completion "C-TAB" #'copilot-accept-completion-by-word "C-" #'copilot-accept-completion-by-word)) #+end_src *** Aider :PROPERTIES: :ID: 42318f75-3a25-44ad-bfeb-d83338045385 :END: #+begin_src emacs-lisp (after! aidermacs ;; Set API keys (setenv "ANTHROPIC_API_KEY" anthropic-key) (setenv "OPENAI_API_KEY" openai-key) (setenv "GEMINI_API_KEY" gemini-key) (setenv "OLLAMA_API_BASE" "https://ollama.rogs.casa") ;; General settings (setq aidermacs-use-architect-mode t) (setq aidermacs-auto-commits nil) (setq aidermacs-backend 'vterm) (setq aidermacs-vterm-multiline-newline-key "S-") (add-to-list 'aidermacs-extra-args "--no-gitignore --chat-mode ask --no-auto-commits --cache-prompts --dark-mode --pretty --stream --vim --cache-keepalive-pings 2")) ;; Keybinding for Aidermacs menu (map! :leader :desc "Aidermacs" "l" #'aidermacs-transient-menu) #+end_src ** Others :PROPERTIES: :ID: ccd2e4f2-d58d-4fd3-8d79-1ccd41719122 :END: *** PlantUML :PROPERTIES: :ID: 87ed3201-3df7-4ee1-a4ce-4fe8312f9d08 :END: #+begin_src emacs-lisp (setq plantuml-executable-path "/usr/bin/plantuml") (setq plantuml-default-exec-mode 'executable) (setq org-plantuml-exec-mode 'plantuml) (setq plantuml-server-url 'nil) (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t))) (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) (setq org-babel-default-header-args:plantuml '((:results . "verbatim") (:exports . "results") (:cache . "no"))) (after! org (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))) #+end_src