| config.org | ||
| README.org | ||
| TransparentGNU.png | ||
| TransparentGNU_catpuccin.png | ||
| TransparentGNU_small.png | ||
My (Doom) Emacs Config
- About
- Modules
- Config
- Packages
About
This is my Doom Emacs configuration.
I've separated this file in three main sections, to correspond to Doom's three config files: /mbarria/.doom.d/src/branch/master/init.el (/mbarria/.doom.d/src/branch/master/Modules), /mbarria/.doom.d/src/branch/master/config.el (/mbarria/.doom.d/src/branch/master/Config), and /mbarria/.doom.d/src/branch/master/packages.el (/mbarria/.doom.d/src/branch/master/Packages). However, these don't correspond one-to-one. /mbarria/.doom.d/src/branch/master/Config consists mostly of changes to stuff included in Doom Emacs (such as configuration of the enabled modules), while /mbarria/.doom.d/src/branch/master/Packages corresponds to installation and configuration of packages not included in Doom modules.
Why Emacs?
There's a lot of reasons to use Emacs, but most of the ones that matter to me can be grouped as "Unifying my work flow"
- Whether I'm working with Python, LaTeX, or simple text files; I can always use the same keybinds to move around and make changes.
- Whenever I change computers (like between my work computer and my personal computers), I can just use sync my config with git (currently to github).
- Continuing the previous point, if I want access to all my agenda files, I just need to install Dropbox.
This file is an Org Mode file, an Emacs mode that has markdown-like features for working with simple text, but also allows for Literate programming with Babel. Whenever the term tangle comes up, it refers to org-babel's feature to export blocks of text from an org-mode file to other files. This was leveraged here to mantain one file for documentation (this one) while keeping actual code in different files (as explained in the /mbarria/.doom.d/src/branch/master/About section).
Prerequisites
This list might be incomplete. Remember to always run doom doctor after syncing and/or upgrading Doom Emacs.
| Prereq | Description | Required by |
|---|---|---|
| CommitMono | A really nice font. | My config for doom-font |
| pueue | A simple queue for commands | pueue package, to interface with the queue |
| Spotify | Music Streaming | emacs-spotify, for obvious reasons |
| mu | Email client | mu4e |
Initializing/changing config files
We tangle some comments to each config file.
;;; init.el -*- lexical-binding: t; -*-
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
Modifications to /mbarria/.doom.d/src/branch/master/init.el won't take effect until doom sync is run.
But changes to /mbarria/.doom.d/src/branch/master/config.el and to /mbarria/.doom.d/src/branch/master/packages.el can be applied by reloading the config (doom/reload, bound to SPC h r r).
On installing additional packages in Doom
New packages must be declared in /mbarria/.doom.d/src/branch/master/packages.el, and if they are in MELPA, ELPA, or emacsmirror they can be installed with package!.
(package! some-package)
By specifying a :recipe, you can install fom a github repo.
(package! another-package :recipe (:host github :repo "username/repo"))
The recipe will look for a PACKAGENAME.el file in the project root. If it's not called that of if it's in a subdirectory, it can be specified with :files (within :recipe).
(package! this-package
:recipe (:host github :repo "username/repo"
:files ("some-file.el" "src/lisp/*.el")))
Included packages can also be disabled, though so far I've had no need of this.
(package! builtin-package :disable t)
Packages can also be overriden while keeping the :recipe (either from Doom or MELPA/ELPA/emacsmirror)
(package! builtin-package :recipe (:nonrecursive t)) (package! builtin-package-2 :recipe (:repo "myfork/package"))
It's also possible to specify a branch or a specific commit.
(package! builtin-package :recipe (:branch "develop")) (package! builtin-package :pin "1a2b3c4d5e")
Or to unpin a package, multiple packages, or even all packages (not recommended) to use their latest version.
(unpin! pinned-package) (unpin! pinned-package another-pinned-package) (unpin! t)
On configuring installed packages.
This is totally copy pasted from the default config.el comments.
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.
Modules
Preface
Doom modules are loaded in init.el.
We can get information on any of them from Doom using doom/help-modules (SPC h d m), or at point with +lookup/documentation (K).
Any changes to this won't take effect until doom sync is run.
We start by calling doom
(doom!
:input
Doom has input modules to accomodate other languages and keyboards; I don't use any of them.
For the record, these currently include bidi (right-to-left), chinese, japanese, and layout (for accomodating different layouts).
:completion
For completion at point I use company-mode, and for completion of commands (searching commands, files, directories, etc) I use vertico.
:completion
;; (company +childframe) ; the ultimate code completion backend
(corfu +icons +orderless +dabbrev) ; the ultimate code completion backend
(vertico +icons +childframe) ; the search engine of the future
I do not make any further changes to configuration for these modules, but it is important to keep in mind which you have enabled, as they affect many other modules. Doom also provides modules for Helm, Ido (Interactive Do), and Ivy.
:ui
We use several of the doom ui modules. These all work great to make Emacs fell more modern.
:ui
doom ; what makes DOOM look the way it does
doom-dashboard ; a nifty splash screen for Emacs
modeline ; snazzy, Atom-inspired modeline, plus API
workspaces ; tab emulation, persistence & separate workspaces
(smooth-scroll +interpolate) ; So smooth you won't believe it's not butter
Doom by itself has great window navigation (under the SPC w leader),but the window-select module makes it even better.
(window-select +numbers) ; visually switch windows
It also provides some other small tweaks to ui that I really like.
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
indent-guides ; highlighted indent columns
ophints ; highlight the region an operation acts on
vc-gutter ; vcs diff in the fringe
vi-tilde-fringe ; fringe tildes to mark beyond EOB
(popup +defaults +all) ; tame sudden yet inevitable temporary windows
nav-flash ; blink cursor line after big motions
Doom also has a module for ligatures, though it requires the use of a compatible font. (TODO: Link to config)
(ligatures +extra) ; ligatures and symbols to make your code pretty again
And it provides a module for treemacs. With configuration for language server protocol compatibility. (Alternatively, there's a module for neotree)
(treemacs) ; a project drawer, like neotree but cooler
It should be noted that Doom also provides modules for deft, emoji support, better unicode support, a quit-message prompt, a minimap, tabs, and a zen mode.
(emoji +ascii +github +unicode)
:editor
Of course, we use evil-mode in Doom.
:editor
(evil +everywhere); come to the dark side, we have cookies
There's modules that help with editing in any language, programming or otherwise.
file-templates ; auto-snippets for empty files
fold ; (nigh) universal code folding
(format +onsave) ; automated prettiness
multiple-cursors ; editing in many places at once
rotate-text ; cycle region at point between text candidates
snippets ; my elves. They type so I don't have to
word-wrap ; soft wrapping with language-aware indent
For the fold module, note that some useful default bindings are:
| binding | action |
|---|---|
z a |
Open/close fold |
z p |
Close fold |
z o |
Open fold |
z j |
Previous fold |
z k |
Next fold |
z m |
Change fold level of area |
z M |
Close all folds |
z R |
Open all folds |
And there's some modules for programming (Lisp in particular), that I haven't played around with yet, but I'll keep in my config as "someday" comments.
;;lispy ; vim for lisp, for people who don't like vim
;;objed ; text object editing for the innocent
;;parinfer ; turn lisp into python, sort of
:emacs
Doom provides some modules that enhance the vanila emacs experience. I'm all for them.
:emacs
(dired +icons +dirvish) ; making dired pretty [functional]
electric ; smarter, keyword-based electric-indent
(ibuffer +icons) ; interactive buffer management
undo ; persistent, smarter undo for your inevitable mistakes
vc ; version-control and Emacs, sitting in a tree
tramp ; remote files at your arthritic fingertips
:term
:checkers
The doom spell/syntax checkers all work really well. Writegood mode (installed by :checkers grammar) can be a bit annoying when writing formally, but it does no harm to have it activated.
:checkers
syntax ; tasing you for every semicolon you forget
(spell +flyspell +hunspell) ; tasing you for misspelling mispelling
grammar ; tasing grammar mistake every you make
TODO :tools
Doom has a bunch of modules under :tools that are really useful.
Biblio allows for better bibliography management.
:tools
biblio ; Writes a PhD for you (citation needed)
editorconfig ; let someone else argue about tabs vs spaces
ein ; tame Jupyter notebooks with emacs
(eval +overlay) ; run code, run (also, repls)
(lookup +dictionary) ; navigate your code and its documentation
(lsp +eglot) ; M-x vscode
magit ; a git porcelain for Emacs
make ; run make tasks from Emacs
(pass +pass) ; password manager for nerds
pdf ; pdf enhancements
tmux ; an API for interacting with tmux
tree-sitter
upload ; map local to remote projects via ssh/ftp
(Note: Eval can be called with gr on a region)
Doom also provides modules for Ansible, debugging, direnv, Docker, Terraform
:os
Here we just activate tty module for better terminal experience. There's also a module to improve the MacOS experience; but I don't use Apple products.
:os
tty ; improve the terminal Emacs experience
:lang
Doom has modules to help set it up as an IDE for a variety of programming languages.
Here are the ones I have enabled; the +lsp and +tree-sitter options are common and just enable integration with the respective modules.
:lang
(cc +lsp +tree-stitter) ; C > C++ == 1
emacs-lisp ; drown in parentheses
(julia +lsp +tree-sitter +snail) ; a better, faster MATLAB
(latex +latexmk +cdlatex +lsp +fold) ; writing papers in Emacs has never been so fun
(nix +tree-sitter +lsp) ; I hereby declare "nix geht mehr!"
(python +lsp +tree-sitter +pyenv) ; beautiful is better than ugly
(sh +lsp) ; she sells {ba,z,fi}sh shells on the C xor
(lua +lsp +tree-sitter) ; one-based indices? one-based indices
There's also support for simple text formats (not exactly programming languages, but quite powerfull in their own right).
data ; config/data formats
ledger ; be audit you can be
markdown ; writing docs for people to ignore
Org-mode in particular deserves some attention, as it has many more options.
(org ; organize your plain life in plain text
+pretty ; prettier defaults
+dragndrop ; drag images to org files
+gnnuplot ; Render images from gnuplot / plot org-tables
+org-noter ; Take notes of documents
+hugo ; Use Hugo to export websites
+present ; Use org-mode for presentations
+roam ; A Zettelkasten for Emacs
+journal ; for keeping a work diary
+pomodoro) ; Use org-mode timers for productivity
Finally, a (commented) list of languages I don't use, as it might be useful in the future.
;;agda ; types of types of types of types...
;;beancount ; mind the GAAP
;;clojure ; java with a lisp
;;common-lisp ; if you've seen one lisp, you've seen them all
;;coq ; proofs-as-programs
;;crystal ; ruby at the speed of c
;;csharp ; unity, .NET, and mono shenanigans
;;(dart +flutter) ; paint ui and not much else
;;dhall
;;elixir ; erlang done right
;;elm ; care for a cup of TEA?
;;erlang ; an elegant language for a more civilized age
;;ess ; emacs speaks statistics
;;factor
;;faust ; dsp, but you get to keep your soul
;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER)
;;fsharp ; ML stands for Microsoft's Language
;;fstar ; (dependent) types and (monadic) effects and Z3
;;gdscript ; the language you waited for
;;(go +lsp) ; the hipster dialect
;;(graphql +lsp) ; Give queries a REST
;;(haskell +lsp) ; a language that's lazier than I am
;;hy ; readability of scheme w/ speed of python
;;idris ; a language you can depend on
;;json ; At least it ain't XML
;;(java +lsp) ; the poster child for carpal tunnel syndrome
;;javascript ; all(hope(abandon(ye(who(enter(here))))))
;;kotlin ; a better, slicker Java(Script)
;;lean ; for folks with too much to prove
;;nim ; python + lisp at the speed of c
;;ocaml ; an objective camel
;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more
;;purescript ; javascript, but functional
;;qt ; the 'cutest' gui framework ever
;;racket ; a DSL for DSLs
;;raku ; the artist formerly known as perl6
;;rest ; Emacs as a REST client
;;rst ; ReST in peace
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
;;scala ; java, but good
;;(scheme +guile) ; a fully conniving family of lisps
;;sml
;;solidity ; do you need a blockchain? No.
;;swift ; who asked for emoji variables?
;;terra ; Earth and Moon in alignment for performance.
;;web ; the tubes
;;yaml ; JSON, but readable
;;zig ; C, but simpler
For email we use mu (with mu4e).
:email
(mu4e +org +gmail)
There's also a module for NotMuch and another for Wanderlust. I didn't like NotMuch much, and as of writing, there's basically no documentation for the wanderlust module.
:app
Doom has a few apps.
Calendar requires an OAuth client ID. TODO: Configure gmail; see also the :email modules. Everywhere configures Emacs Everywhere. And rss adds an rss feed, of course.
:app
calendar
everywhere ; *leave* Emacs!? You must be joking
(rss +org +youtube) ; emacs as an RSS reader
There's also a module for music plaing (emms) and one for IRC.
:config
Some meta modules that affect the config itself. Obviously this is a literate config, so it benefits from literate, but I still tangle manually (for some reason when Doom tangles the format is different). default adds a lot of really nice keybinds (inspired by Spacemacs)
:config
;; literate
(default +bindings +smartparens)
End
We finish by closing the doom! list.
)
Could've done so in the last module, but didn't want to keep track of that if it happens to change.
Config
On package reconfiguration…
Since Doom configures a bunch of stuff, it's important to use after! to configure packages.
(after! PACKAGE
(setq x y))
The expection to this is paths to files/directories, doom variables (prepended with either doom or +), and of course, variables that are explicitly required to be set up before loading their package.
Other useful macros (copy-pasted from the default config.el that comes with 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).
Basic configuration
Personal information
Some personal information is accesed by GPG configuration, emails clients, snippets, etc… (This is optional)
(setq user-full-name "Mateo Barria-Urenda"
user-mail-address "mateobarria@gmail.com")
Fonts
I use the CommitMono font.
;; Fonts
(setq doom-font (font-spec :family "CommitMono" :size 14) ; Primary font
doom-variable-pitch-font (font-spec :family "DejaVu Sans" :size 15) ; non-monospace where applicable
doom-serif-font (font-spec :family "CommitMono") ; for 'fixed-pitch-serif' face
doom-big-font (font-spec :family "CommitMono" :size 24)) ; for big font mode ('SPC t b')
Theme
I really like the catppuccin theme.
(package! catppuccin-theme)
I use the frappe "flavor" of catppuccin.
(setq catppuccin-flavor 'frappe) ;; 'frappe or 'latte, 'macchiato, or 'mocha
(setq catppuccin-highlight-matches t)
(setq catppuccin-italic-comments t)
(setq catppuccin-italic-blockquotes t)
(setq doom-theme 'catppuccin)
(add-hook 'server-after-make-frame-hook #'catppuccin-reload)
Treemacs Colors
Set treemacs to use doom colors.
(setq doom-themes-treemacs-theme "doom-colors")
hl-todo-mode
I like to highlight TODOs regardless of mode, so I can see comments that say TODO.
(global-hl-todo-mode)
Sync theme in pdf-mode
(add-hook 'pdf-view-mode-hook #'pdf-view-themed-minor-mode)
More leader keys
Since I have a split kb, it makes sense to have both halves have a thumb-located leader key.
(map! :map general-override-mode-map :nvm [backspace] 'doom/leader)
Modeline config
Doom's modeline exposes some configuration. I change some defaults mostly because sometimes I use /mbarria/.doom.d/src/branch/master/EXWM as my window manager and desktop environment.
(display-battery-mode)
(display-time-mode)
(timeclock-mode-line-display)
Line Numbers
I use absolute line numbers by default, as I jump to lines using numpad+G.
(setq display-line-numbers-type t)
Line numbers can be turned off or switched to relative numbers (for easier navigation with number+jk) by setting display-line-numbers to nil or relative, respectively.
Splash Image
I've seen two ways of setting the splash image and I'm not sure of the difference so for now here's both.
(setq fancy-splash-image (concat doom-user-dir "TransparentGNU_catpuccin.png"))
(setq +doom-dashboard-banner-dir doom-user-dir )
(setq +doom-dashboard-banner-file "TransparentGNU_catpuccin.png")
TODO add the source for the image
Snipe
I like setting evil-snipe to visible.
(setq evil-snipe-scope 'visible)
Dirvish
An extension of dired. My main configuration change is setting quick access locations.
(after! dirvish
(setq dirvish-quick-access-entries '(
("h" "~/" "Home")
("d" "~/Documents" "Documents")
("o" "/ssh:don-elias:/home/mbarria" "don-elias")
("i" "/ssh:diego-armando:/home/mbarria" "diego-armando")
("a" "/ssh:chamaco:/home/mbarria" "chamaco")
("u" "/ssh:chupete:/home/mbarria" "chupete")
("n" "~/org" "Org-mode")
)))
Tramp
Some configurations to make connections more stable and to make sure it finds Julia and Python in the servers I frequent.
(after! tramp
(setq tramp-remote-process-environment
(append tramp-remote-process-environment
'("PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/mbarria/.juliaup/bin"
"LANG=en_US.UTF-8"
"LD_LIBRARY_PATH=/usr/local/lib")))
;; Increase connection attempt interval (prevents rapid retries)
(setq tramp-connection-min-time-diff 30))
Org-mode
Latex Preview Branch
Tecosaur and Karthink have made a bunch of improvements to LaTeX preview in org-mode.
(package! org :recipe
(:host nil :repo "https://git.tecosaur.net/mirrors/org-mode.git" :remote "mirror" :fork
(:host nil :repo "https://git.tecosaur.net/tec/org-mode.git" :branch "dev" :remote "tecosaur")
:files
(:defaults "etc")
:build t :pre-build
(with-temp-file "org-version.el"
(require 'lisp-mnt)
(let
((version
(with-temp-buffer
(insert-file-contents "lisp/org.el")
(lm-header "version")))
(git-version
(string-trim
(with-temp-buffer
(call-process "git" nil t nil "rev-parse" "--short" "HEAD")
(buffer-string)))))
(insert
(format "(defun org-release () \"The release version of Org.\" %S)\n" version)
(format "(defun org-git-version () \"The truncate git commit hash of Org mode.\" %S)\n" git-version)
"(provide 'org-version)\n"))))
:pin nil)
(unpin! org)
Some config to make use of latex preview.
(use-package! org-latex-preview
:config
;; Increase preview width
(plist-put org-latex-preview-appearance-options
:page-width 1.0)
;; Use dvisvgm to generate previews
;; You don't need this, it's the default:
(setq org-latex-preview-process-default 'dvisvgm)
;; Turn on auto-mode, it's built into Org and much faster/more featured than
;; org-fragtog. (Remember to turn off/uninstall org-fragtog.)
(add-hook 'org-mode-hook 'org-latex-preview-mode)
;; Block C-n, C-p etc from opening up previews when using auto-mode
(setq org-latex-preview-auto-ignored-commands
'(next-line previous-line mwheel-scroll
scroll-up-command scroll-down-command))
;; Enable consistent equation numbering
(setq org-latex-preview-numbered t)
;; Bonus: Turn on live previews. This shows you a live preview of a LaTeX
;; fragment and updates the preview in real-time as you edit it.
;; To preview only environments, set it to '(block edit-special) instead
(setq org-latex-preview-live t)
;; More immediate live-previews -- the default delay is 1 second
(setq org-latex-preview-live-debounce 0.25))
t
Org Config
I keep my org files in my Dropbox folder, which I always keep or link to in my home directory.
In it, in keep most transient notes in an !nbox file. (The ! helps keep it on top of sorts by name)
(setq org-directory "~/org/")
(setq +org-capture-inbox-file (doom-path org-directory "agenda/!nbox.org"))
(setq +org-capture-projects-file (doom-path org-directory "agenda/projects.org"))
(setq +org-capture-journal-file (doom-path org-directory "agenda/journal.org"))
(setq +org-capture-todo-file (doom-path org-directory "agenda/todo.org"))
(setq +org-capture-toread-file (doom-path org-directory "agenda/toread.org"))
(setq +org-capture-work-log-file (doom-path org-directory "agenda/work-log.org"))
;; (setq +org-capture-notes-file (doom-path org-directory "!nbox.org"))
;; timestamp DONEs
(setq org-log-done 'time)
(after! org (setq org-agenda-files (list "~/org/agenda/!nbox.org"
"~/org/agenda/todo.org"
"~/org/agenda/done.org"
"~/org/agenda/projects.org"
"~/org/agenda/someday.org"
"~/org/agenda/toread.org"
"~/org/agenda/work-log.org"
"~/org/agenda/meetings.org")))
Templates
Capture templates:
- i: Inbox. Everything that comes from outside the inbox should go here first.
- s: Work-log/Lab Notebook: Record results so that they are easy to report later.
- t: General todo. For tasks from the inbox that take more than two minutes.
- e: Email. For when an email requires some task before replying.
- p: Creating new projects.
- m: Taking notes of Meetings.
(after! org
(add-hook 'org-capture-prepare-finalize-hook 'org-id-get-create) ; make it so all captures add an ID
(setq org-capture-templates
'(("i" "Inbox"
entry (file +org-capture-inbox-file)
"* TODO %?\n:Created: %T\n%i\n%a"
:prepend t
:empty-lines 0)
("t" "General To-Do"
entry (file+headline +org-capture-todo-file "Actions")
"* TODO [#B] %?\n:Created: %T\n%i\n%a"
:prepend t
:empty-lines 0)
("e" "Email"
entry (file+headline +org-capture-todo-file "Emails")
"* TODO [#B] %? :email: \n:Created: %T\n** Correspondent(s)\n***\n** Notes\n** Sub-actions \n%a"
:prepend t
:empty-lines 0)
("s" "Lab Work-Log"
entry (file+datetree +org-capture-work-log-file)
"* %? \n SCHEDULED: %T \n %a"
:prepend nil
:tree-type week
:empty-lines 0)
("p" "Project"
entry (file +org-capture-projects-file)
"* PROJ [#B] %?\n:Created: %T\n** Collaborators(s)\n***\n** Notes\n** [0%]Actions \n*** TODO\n%a"
:prepend t
:empty-lines 0)
;; Reading List
("r" "Paper"
entry (file+headline +org-capture-toread-file "Scientific Articles")
"* TODO [#B] %?\n:Created: %T\n** Author(s)\n***\n** Notes\n** Metadata \n*** URL: \n*** DOI: \n*** Magazine: \n***Discussion: \n%a"
:prepend t
:empty-lines 0)
("m" "Meeting"
entry (file+datetree "~/org/agenda/meetings.org")
"* %? :meeting:%^g \n:Created: %T\n** Attendees\n*** \n** Notes\n** Action Items\n*** TODO [#A] "
:tree-type week
:empty-lines 0))))
;; Define a function for capturing to Inbox, to bind it
(defun org-capture-inbox ()
(interactive)
(call-interactively 'org-store-link)
(org-capture nil "i"))
;; Specific Capture for Inbox + Shortcut to inbox file
(map! :map doom-leader-notes-map
:desc "Capture to Inbox" "i" #'org-capture-inbox
;; :desc "Open Inbox" "I" (cmd! (find-file +org-capture-inbox-file))
)
Priorities
(after! org-fancy-priorities
(setq org-fancy-priorities-list '((?A . "🔴")
(?B . "🟠")
(?C . "🟢"))))
Tags
From a headline or body, use SPC m q to set tags from this list.
(setq org-tag-alist '(
;; ;; Ticket types
;; (:startgroup . nil)
;; ("@bug" . ?b)
;; ("@feature" . ?f)
;; (:endgroup . nil)
;; ;; Ticket flags
;; ("@emergency" . ?e)
;; ("@research" . ?r)
;; ;; Special tags
;; ("CRITICAL" . ?x)
;; ("obstacle" . ?o)
;; Meeting tags
("meeting" . ?m)
("misc" . ?z)
("planning" . ?p)
("progress" . ?s)
;; Context Tags
(:startgroup . nil)
("personal" . ?g)
("work" . ?t)
("phone" . ?c)
(:endgroup . nil)
;; ;; Work Log Tags
;; ("accomplishment" . ?a)
))
;; Tag colors
(setq org-tag-faces
'(
("work" . (:foreground "mediumPurple1" :weight bold))
("planning" . (:foreground "royalblue1" :weight bold))
("progress" . (:foreground "forest green" :weight bold))
("personal" . (:foreground "sienna" :weight bold))
("meeting" . (:foreground "yellow1" :weight bold))
)
)
Agenda View
Agenda view
;; Agenda View "d"
(defun air-org-skip-subtree-if-priority (priority)
"Skip an agenda subtree if it has a priority of PRIORITY.
PRIORITY may be one of the characters ?A, ?B, or ?C."
(let ((subtree-end (save-excursion (org-end-of-subtree t)))
(pri-value (* 1000 (- org-lowest-priority priority)))
(pri-current (org-get-priority (thing-at-point 'line t))))
(if (= pri-value pri-current)
subtree-end
nil)))
(setq org-agenda-skip-deadline-if-done t)
;; Function to display current clocked task at the top of agenda
(defun my/insert-current-clock ()
"Insert the current clocked task at the top of the agenda."
(when (org-clocking-p)
(save-excursion
(goto-char (point-min))
(insert (format "Currently clocked in: %s\n\n" org-clock-current-task)))))
(after! org-agenda
(setq org-agenda-custom-commands
'(
;; Daily Agenda & TODOs
("d" "Daily agenda and Next Actions"
(
;; Display items with priority A
(tags-todo "PRIORITY=\"A\"+Actions-Someday+work"
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-overriding-header "High-priority unfinished tasks:")))
;; View 7 days in the calendar view
(agenda "" ((org-agenda-span 7)))
;; Display items with priority B (really it is view all items minus A & C)
(tags-todo "+Actions-Someday+work"
((org-agenda-skip-function '(or (air-org-skip-subtree-if-priority ?A)
(air-org-skip-subtree-if-priority ?C)
(org-agenda-skip-if nil '(scheduled deadline))))
(org-agenda-overriding-header "ALL normal priority tasks:")))
;; Display items with pirority C
(tags-todo "PRIORITY=\"C\"+Actions-Someday+work"
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-overriding-header "Low-priority Unfinished tasks:")))
)
;; Extra settings
;; Don't compress things (change to suite your tastes)
((org-agenda-compact-blocks nil)
;; Add our function to the finalize hook just for this view
(org-agenda-finalize-hook '(my/insert-current-clock))))
;; GTD Inbox Tray
("i" "Inbox"
;; Display TODO items tagged as inbox_tray
((agenda ""
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-files +org-capture-inbox-file)
(org-agenda-overriding-header "Inbox")))
))
;; Personal TODOs
("p" "Personal"
;; Display TODO items tagged as personal
((tags-todo "+personal"
((org-agenda-overriding-header "Personal")))
))
;; Weekly look at my work-log file
("r" "Weekly report"
((agenda ""
(
(org-agenda-span 7) ;; Set the agenda to cover the last 7 days
(org-agenda-start-day "-7d") ;; Start from 7 days ago
(org-agenda-shew-all-dates nil) ;; ignore empty days
;; (org-agenda-files +org-capture-work-log-file) ;; Specify the file
(org-agenda-files '("/home/mbarria/org/agenda/work-log.org")) ;; Specify the file
;; (org-agenda-skip-function
;; '(lambda ()
;; (let ((level (org-outline-level)))
;; (if (<= level 1) ;; Adjust the level number to match your desired depth
;; nil ;; Do not skip
;; (org-end-of-subtree t))))))
))))
("j" "Someday"
;; Display items with priority A
((tags-todo "PRIORITY=\"A\"+Someday"
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-overriding-header "High-priority unfinished tasks:")))
;; Display items with priority B (really it is view all items minus A & C)
(tags-todo "+Someday"
((org-agenda-skip-function '(or (air-org-skip-subtree-if-priority ?A)
(air-org-skip-subtree-if-priority ?C)
(org-agenda-skip-if nil '(scheduled deadline))))
(org-agenda-overriding-header "ALL normal priority tasks:")))
;; Display items with pirority C
(tags-todo "PRIORITY=\"C\"+Someday"
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-overriding-header "Low-priority Unfinished tasks:")))
)
;; Don't compress things (change to suite your tastes)
((org-agenda-compact-blocks nil)))
)))
Refiling
Let's make it so that refiling leaves some mark. Useful for refilign from meetings to projects. But with an exception for the inbox.
(defun org-refile--insert-link ( &rest _ )
(unless (string-suffix-p "!nbox.org" buffer-file-name)
(org-back-to-heading)
(let* ((refile-region-marker (point-marker))
(source-link (org-store-link nil)))
(org-insert-heading)
(insert source-link)
(goto-char refile-region-marker))))
Clocking in
This is taken wholesale from http://doc.norang.ca/org-mode.html#Clocking
;;
;; Resume clocking task when emacs is restarted
(org-clock-persistence-insinuate)
;;
;; Show lot of clocking history so it's easy to pick items off the C-F11 list
(setq org-clock-history-length 23)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
;; Change tasks to NEXT when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK")))
;; Save clock data and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)
;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist t)
;; Do not prompt to resume an active clock
(setq org-clock-persist-query-resume nil)
;; Enable auto clock resolution for finding open clocks
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)
(setq bh/keep-clock-running nil)
(defun bh/is-task-p ()
"Any task with a todo keyword and no subtask"
(save-restriction
(widen)
(let ((has-subtask)
(subtree-end (save-excursion (org-end-of-subtree t)))
(is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
(save-excursion
(forward-line 1)
(while (and (not has-subtask)
(< (point) subtree-end)
(re-search-forward "^\*+ " subtree-end t))
(when (member (org-get-todo-state) org-todo-keywords-1)
(setq has-subtask t))))
(and is-a-task (not has-subtask)))))
(defun bh/is-project-p ()
"Any task with a todo keyword subtask"
(save-restriction
(widen)
(let ((has-subtask)
(subtree-end (save-excursion (org-end-of-subtree t)))
(is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
(save-excursion
(forward-line 1)
(while (and (not has-subtask)
(< (point) subtree-end)
(re-search-forward "^\*+ " subtree-end t))
(when (member (org-get-todo-state) org-todo-keywords-1)
(setq has-subtask t))))
(and is-a-task has-subtask))))
(defun bh/clock-in-to-next (kw)
"Switch a task from TODO to STRT when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from STRT back to TODO"
(when (not (and (boundp 'org-capture-mode) org-capture-mode))
(cond
((and (member (org-get-todo-state) (list "TODO"))
(bh/is-task-p))
"STRT")
((and (member (org-get-todo-state) (list "STRT"))
(bh/is-project-p))
"TODO"))))
(defun bh/find-project-task ()
"Move point to the parent (project) task if any"
(save-restriction
(widen)
(let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
(while (org-up-heading-safe)
(when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
(setq parent-task (point))))
(goto-char parent-task)
parent-task)))
(defun bh/punch-in (arg)
"Start continuous clocking and set the default task to the
selected task. If no task is selected set the Organization task
as the default task."
(interactive "p")
(setq bh/keep-clock-running t)
(if (equal major-mode 'org-agenda-mode)
;;
;; We're in the agenda
;;
(let* ((marker (org-get-at-bol 'org-hd-marker))
(tags (org-with-point-at marker (org-get-tags-at))))
(if (and (eq arg 4) tags)
(org-agenda-clock-in '(16))
(bh/clock-in-organization-task-as-default)))
;;
;; We are not in the agenda
;;
(save-restriction
(widen)
; Find the tags on the current task
(if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4))
(org-clock-in '(16))
(bh/clock-in-organization-task-as-default)))))
(defun bh/punch-out ()
(interactive)
(setq bh/keep-clock-running nil)
(when (org-clock-is-active)
(org-clock-out))
(org-agenda-remove-restriction-lock))
(defun bh/clock-in-default-task ()
(save-excursion
(org-with-point-at org-clock-default-task
(org-clock-in))))
(defun bh/clock-in-parent-task ()
"Move point to the parent (project) task if any and clock in"
(let ((parent-task))
(save-excursion
(save-restriction
(widen)
(while (and (not parent-task) (org-up-heading-safe))
(when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
(setq parent-task (point))))
(if parent-task
(org-with-point-at parent-task
(org-clock-in))
(when bh/keep-clock-running
(bh/clock-in-default-task)))))))
(defvar bh/organization-task-id "98031ad5-b008-4476-9d39-79c878a52609")
;; (defun bh/clock-in-organization-task-as-default ()
;; (interactive)
;; (org-with-point-at (org-id-find bh/organization-task-id 'marker)
;; (org-clock-in '(16))))
;; Modified to work from anywhere
(defun bh/clock-in-organization-task-as-default ()
(interactive)
(let ((marker (org-id-find bh/organization-task-id 'marker)))
(if marker
(with-current-buffer (marker-buffer marker)
(goto-char (marker-position marker))
(org-clock-in '(16)))
(message "Organization task not found"))))
(defun bh/clock-out-maybe ()
(when (and bh/keep-clock-running
(not org-clock-clocking-in)
(marker-buffer org-clock-default-task)
(not org-clock-resolving-clocks-due-to-idleness))
(bh/clock-in-parent-task)))
(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append)
(require 'org-id)
(defun bh/clock-in-task-by-id (id)
"Clock in a task by id"
(org-with-point-at (org-id-find id 'marker)
(org-clock-in nil)))
(defun bh/clock-in-last-task (arg)
"Clock in the interrupted task if there is one
Skip the default task and get the next one.
A prefix arg forces clock in of the default task."
(interactive "p")
(let ((clock-in-to-task
(cond
((eq arg 4) org-clock-default-task)
((and (org-clock-is-active)
(equal org-clock-default-task (cadr org-clock-history)))
(caddr org-clock-history))
((org-clock-is-active) (cadr org-clock-history))
((equal org-clock-default-task (car org-clock-history)) (cadr org-clock-history))
(t (car org-clock-history)))))
(widen)
(org-with-point-at clock-in-to-task
(org-clock-in nil))))
To make it part of my habits it helps to have accessible bindings.
(map! :leader
(:prefix-map ("C" . "Clock")
;; For start of work before deciding on a task
:desc "Punch in" "I" 'bh/punch-in
;; When leaving work
:desc "Punch out" "O" 'bh/punch-out
;; Clocking in to a specific task
:desc "Clock in" "i" 'org-clock-in
:desc "Clock out" "o" 'org-clock-out
:desc "Clock in to last task" "l" 'bh/clock-in-last-task
:desc "Clock in recent" "r" (lambda ()
(interactive)
(let ((current-prefix-arg '(4)))
(call-interactively 'org-clock-in)))
;; Misc
:desc "Visit clock" "v" 'org-clock-goto
))
Org-roam
I keep org-roam updated
(unpin! org-roam)
My capture templates are for my personal notes (main), notes on specific sources (reference) and on videos (video).
(after! org-roam-capture
(setq org-roam-capture-templates
'(("m" "main" plain
"%?"
:if-new (file+head "main/${slug}.org"
"#+title: ${title}\n#+filetags:\n#+date: %u\n#+lastmod: %u\n\n")
:immediate-finish t
:unnarrowed t)
("r" "reference" plain
"%?"
:if-new (file+head "reference/${title}.org"
"#+title: ${title}\n#+filetags: :Reference:\n#+date: %u\n#+lastmod: %u\n\n")
:immediate-finish t
:unnarrowed t)
("b" "bibliography" plain
"%?"
:if-new (file+head "bibliography/${citar-citekey}.org"
"#+title: ${title}\n#+filetags: :Bibliography:\n#+date: %u\n#+lastmod: %u\n\n- authors :: ${citar-author}\n- date :: ${citar-date}\n- DOI :: [[https://dx.doi.org/${citar-doi}][${citar-doi}]]\n- tags ::\n\n%i\n\n* PDF Notes\n:PROPERTIES:\n:NOTER_DOCUMENT: ../../Bib/pdfs/${citar-citekey}.pdf\n:END:")
:immediate-finish t
:unnarrowed t)
("v" "video" plain
"%?"
:if-new (file+head "videos/${title}.org"
"#+title: ${title}\n#+filetags: :Video: \n#+date: %u\n#+lastmod: %u\n\n")
:immediate-finish t
:unnarrowed t))))
Set dailies capture template to mark the time
(setq org-roam-dailies-capture-templates
'(("d" "default" entry "* %<%I:%M %p>: %?"
:if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
I use org-roam-protocol which requires some setup.
(require 'org-roam-protocol)
Bibliograhy
I try to keep an organised bibliography using Org Babel.
And I want access in Emacs to the .bib entries tangled from it.
Citar lets me acces my bibiography from anywhere.
It also lets me access notes (citar-open-notes), pdfs (citar-open-files), and the bibtex entry themselves (citar-open-entry).
Doom's biblio module already binds some functions, but I found that opening files and inserting citations (which works both in org-mode and TeX mode) were some glaring omissions. Here I also set up my bibliography files that I want to be able to access anywhere. The "reference" folder is mostly set up as a fallback. I try to keep my notes in a single Bibliography.org file.
(require 'oc-bibtex)
(after! citar
(setq! citar-bibliography '(
"/home/mbarria/org/Bib/biochem.bib"
"/home/mbarria/org/Bib/biology.bib"
"/home/mbarria/org/Bib/forcefields.bib"
"/home/mbarria/org/Bib/free_energy.bib"
"/home/mbarria/org/Bib/graphene.bib"
"/home/mbarria/org/Bib/md_software.bib"
"/home/mbarria/org/Bib/md_theory.bib"
"/home/mbarria/org/Bib/membranes.bib"
"/home/mbarria/org/Bib/nano_other.bib"
"/home/mbarria/org/Bib/nanotubes.bib"
"/home/mbarria/org/Bib/orgchem.bib"
"/home/mbarria/org/Bib/physics.bib"
))
(setq org-cite-global-bibliography citar-bibliography)
(setq! citar-library-paths '("/home/mbarria/org/Bib/pdfs/"))
(setq! citar-notes-paths '("/home/mbarria/org/roam/reference/"))
(setq! citar-library-file-extensions (list "pdf"))
(setq! citar-file-additional-files-separator "-")
)
(map! :map doom-leader-notes-map
:desc "Insert Citation" "k" 'citar-insert-citation
:desc "Open Reference" "p" 'citar-open)
;; org-roam + citar config
(after! citar-org-roam
(setq citar-org-roam-subdir "bibliography")
(setq citar-org-roam-note-title-template "${title}")
(setq citar-org-roam-capture-template-key "b")
(setq citar-org-roam-template-fields
'((:citar-title . ("title"))
(:citar-author . ("author" "editor"))
(:citar-date . ("date" "year" "issued"))
(:citar-doi . ("doi"))
(:citar-pages . ("pages"))
(:citar-type . ("=type="))))
)
I also keep a longer Bibliography file which I want to access in my LaTeX projects, so I make sure reftex knows about it.
(after! reftex
(setq! reftex-default-bibliography '("/home/mbarria/org/Bib/Bibliography.bib"))
)
This is kinda redundant though, since I've switched to just running citar-export-local-bib-file in my latex projects.
To manage my bibliography files I run this function (which I don't remember where I copied it from) to get a bibtex entry from a DOI.
(defun get-bibtex-from-doi (doi)
"Get a BibTeX entry from the DOI"
(interactive "MDOI: ")
(let ((url-mime-accept-string "text/bibliography;style=bibtex"))
(with-current-buffer
(url-retrieve-synchronously
(format "http://dx.doi.org/%s"
(replace-regexp-in-string "http://dx.doi.org/" "" doi)))
(switch-to-buffer (current-buffer))
(goto-char (point-max))
(setq bibtex-entry
(buffer-substring
(string-match "@" (buffer-string))
(point)))
(kill-buffer (current-buffer))))
(insert (decode-coding-string bibtex-entry 'utf-8))
(bibtex-fill-entry))
Async babel
ob-sync allows for running babel code blocks asynchronously.
(package! ob-async
:recipe (:host github
:repo "astahlman/ob-async"))
(use-package! ob-async)
To use, just include :async in the header-args.
Auto git mode
Technically not org-mode related, but I enable it in my org directory.
(package! git-auto-commit-mode)
Enable it in a directory with a dir-locals.el file.
((nil . ((eval git-auto-commit-mode 1))))
Auto update lastmod
Update property lastmod when saving files.
From Zaeph
;;--------------------------
;; Handling file properties for ‘CREATED’ & ‘LAST_MODIFIED’
;;--------------------------
(defun zp/org-find-time-file-property (property &optional anywhere)
"Return the position of the time file PROPERTY if it exists.
When ANYWHERE is non-nil, search beyond the preamble."
(save-excursion
(goto-char (point-min))
(let ((first-heading
(save-excursion
(re-search-forward org-outline-regexp-bol nil t))))
(when (re-search-forward (format "^#\\+%s:" property)
(if anywhere nil first-heading)
t)
(point)))))
(defun zp/org-has-time-file-property-p (property &optional anywhere)
"Return the position of time file PROPERTY if it is defined.
As a special case, return -1 if the time file PROPERTY exists but
is not defined."
(when-let ((pos (zp/org-find-time-file-property property anywhere)))
(save-excursion
(goto-char pos)
(if (and (looking-at-p " ")
(progn (forward-char)
(org-at-timestamp-p 'lax)))
pos
-1))))
(defun zp/org-set-time-file-property (property &optional anywhere pos)
"Set the time file PROPERTY in the preamble.
When ANYWHERE is non-nil, search beyond the preamble.
If the position of the file PROPERTY has already been computed,
it can be passed in POS."
(when-let ((pos (or pos
(zp/org-find-time-file-property property))))
(save-excursion
(goto-char pos)
(if (looking-at-p " ")
(forward-char)
(insert " "))
(delete-region (point) (line-end-position))
(let* ((now (format-time-string "[%Y-%m-%d %a %H:%M]")))
(insert now)))))
(defun zp/org-set-last-modified ()
"Update the LAST_MODIFIED file property in the preamble."
(when (derived-mode-p 'org-mode)
(zp/org-set-time-file-property "lastmod")))
el-secretario
el-secretario handles to-do reminders and reviews.
(package! el-secretario)
(package! el-secretario-org)
(package! el-secretario-mu4e)
(package! el-secretario-elfeed)
It needs some config, but that's because it's meant to be a very personalized experience. First for review functions:
;; Create a function to start the review
(defun el-secretario-daily-review ()
(interactive)
(el-secretario-start-session
(lambda ()
(list
;; Clean up folders
(el-secretario-files)
;; Take care of inbox using the variable
(el-secretario-org-make-source nil (list +org-capture-inbox-file))
;; Go through TODOs
(el-secretario-org-make-source '(todo "TODO") '(list +org-capture-todo-file))))))
(defun el-secretario-inbox-review ()
(interactive)
(el-secretario-start-session
(lambda ()
(list
;; Take care of inbox using the variable
(el-secretario-org-make-source nil (list +org-capture-inbox-file))
))))
Also I'll run my reviews on a timer
;; (run-with-idle-timer 300 t (lambda () (unless (org-clocking-p) (el-secretario-daily-review))))
For mapping keybindings in el-secretario reviews, it's recommended to use define-key.
(use-package! el-secretario-org
:after el-secretario
:config
(define-key el-secretario-org-keymap
"a" '("Archive" . org-archive-subtree))
(define-key el-secretario-org-keymap
"t" '("Tags" . org-set-tags-command))
(define-key el-secretario-org-keymap
"T" '("State" . org-todo))
(define-key el-secretario-org-keymap
"u" '("Priority Up" . org-priority-up))
(define-key el-secretario-org-keymap
"d" '("Priority Down" . org-priority-down))
)
But for mapping reviews it should not be a problem.
(map! :map doom-leader-notes-map
:desc "Daily Review" "d" 'el-secretario-daily-review
:desc "Inbox Review" "I" 'el-secretario-inbox-review
)
org-modern
The +fancy flag in init.el enables org-modern. There's some defaults I don't quite like so…
(after! org-modern
(setq org-modern-star 'replace))
Ligatures
Julia
Last I checked, the ligatures module doesn't include julia. So I set those up.
;; Julia
(after! julia-mode
(set-ligatures! 'julia-mode
;; Functional
:lambda "->"
:def "function"
:composition "struct"
:map "Dict"
;; Types
:null "Nothing"
:true "true"
:false "false"
:int "Int"
:float "Float64"
:str "String"
:bool "Bool"
;; Flow
:not "!"
:in "in"
:not-in "!in"
:and "&&"
:or "||"
:for "for"
;; :some "some keyword"
:return "return"
;; Other
:union "union"
:intersect "intersect"
:pipe "|>"
)
)
Ledger
The ledger module configures pretty much everything I need. I just add a binding to access my ledger.
(map! :map doom-leader-notes-map
:desc "Ledger" "e" (cmd! (find-file (doom-path org-directory "agenda/ledger.org"))))
\LaTeX
I like how tex-fold looks, but I find it weird that it only recognizes the base \\cite command.
(after! tex-fold
(add-to-list 'TeX-fold-macro-spec-list '("[c]" ("cite" "bibitem" "citep" "citet" "autocite" "fullcite")))
)
mu4e
mu4e requires some external config. The docs for the Doom module are really helpful and without them I couldn't have set it up for myself.
My config is nothing special.
;; Each path is relative to the path of the maildir you passed to mu
(set-email-account! "gmail"
'((mu4e-sent-folder . "/gmail/[Gmail]/Enviados")
(mu4e-drafts-folder . "/gmail/[Gmail]/Borradores")
(mu4e-trash-folder . "/gmail/[Gmail]/Papelera")
(mu4e-refile-folder . "/gmail/[Gmail]/Todos")
(smtpmail-smtp-user . "mateobarria@gmail.com")
(user-mail-address . "mateobarria@gmail.com") ;; only needed for mu < 1.4
(mu4e-compose-signature . "---\nSaludos,\n\nMateo Barría\n\n(Sent with Mu4e)"))
t)
(setq org-msg-signature "\nMateo Barria-Urenda\n\n(Sent with Mu4e+Org-msg)")
(setq +mu4e-gmail-accounts '(("mateobarria@gmail.com" . "/mateobarria")))
;; don't need to run cleanup after indexing for gmail
(setq mu4e-index-cleanup nil
;; because gmail uses labels as folders we can use lazy check since
;; messages don't really "move"
mu4e-index-lazy-check t)
(setq mu4e-update-interval 60)
;; Set default search to my inbox; as that is what I prioritize keeping clean
(after! mu4e
(add-to-list 'mu4e-bookmarks '(:name "Inbox" :query "maildir:/gmail/INBOX" :key 105 :favorite t))
(mu4e-modeline-mode))
;; Show it in modeline
Julia
While I'm most proficient with Python, I'm trying to switch to Julia whenever possible.
LSP Configuration
Let eglot find the julia installation.
(setq eglot-jl-language-server-project "~/.julia/environments/v1.12")
julia-snail ob-julia
Enable this extension to use snail with babel.
(after! julia-snail
(add-to-list 'julia-snail-extensions 'ob-julia))
Snail Configuration
projectile
(after! projectile
(setq projectile-project-search-path '("~/Projects/" "~/Code/" ("~/Lab" . 1))) )
Shell
Set vterm to nushell
(setq nu--path "/etc/profiles/per-user/mbarria/bin/nu")
(if (file-exists-p nu--path)
(setq vterm-shell nu--path))
Multi Vterm
Multiple Vterms. I've decided to map multi-vterm to SPC v.
(package! multi-vterm)
(use-package! multi-vterm
:config
(setq multi-vterm-dedicated-window-height-percent 33))
(after! multi-vterm
(map! :leader
(:prefix-map ("v" . "vterm")
:desc "Dedicated Terminal" "o" 'multi-vterm-dedicated-toggle
:desc "New terminal" "v" 'multi-vterm
:desc "Next" "n" 'multi-vterm-next
:desc "Previous" "p" 'multi-vterm-prev
:desc "Project" "P" 'multi-vterm-project
:desc "Rename" "r" 'multi-vterm-rename-buffer
)))
multi-vterm-project
TRAMP Shell
By default, only a default shell for docker is specified. I specify one for ssh (bash).
(setq vterm-tramp-shells '(("ssh" "/bin/bash") ("docker" "/bin/sh")))
pandoc
Take advantage of Pandoc to never leave org-mode!
(package! org-pandoc-import
:recipe (:host github
:repo "tecosaur/org-pandoc-import"
:files ("*.el" "filters" "preprocessors")))
(package! ox-pandoc)
(use-package! org-pandoc-import :after org)
(use-package! ox-pandoc :after org)
elfeed
The RSS module already installs elfeed and sets it up to configure with an elfeed.org file in your org folder. But I want some more features and syncing the database with syncthing.
(package! elfeed-protocol)
(package! elfeed-score)
(after! elfeed
(setq elfeed-db-directory "~/.elfeed-data")
(add-hook 'elfeed-search-mode-hook #'elfeed-update))
(use-package! elfeed-protocol
:after elfeed
:config
(setq elfeed-curl-extra-arguments '("--insecure"))
;; setup feeds
(setq elfeed-protocol-feeds '(("owncloud+https://admin@nc.mbarria.cl"
:use-authinfo t )))
;; enable elfeed-protocol
(setq elfeed-protocol-enabled-protocols '(fever newsblur owncloud ttrss))
(setq elfeed-protocol-owncloud-maxsize 1000)
(setq elfeed-protocol-owncloud-update-with-modified-time t)
(setq elfeed-protocol-owncloud-fetch-category-as-tag t)
(elfeed-protocol-enable)
)
Packages
Spotify
Possibly peak "I don't want to leave Emacs" for me is controlling Spotify. These's multiple packages that do this, but I use SnootierMoon's emacs-spotify. +begin_src elisp :tangle packages.el (package! spotify :recipe (:host github :repo "SnootierMoon/emacs-spotify"))
#+end_src Which I bind to it's own prefix map after the Doom leader.
(map! :leader
(:prefix-map ("S" . "Spotify")
:desc "START" "s" 'spotify-start
:desc "Play" "j" 'spotify-play
:desc "Pause" "k" 'spotify-pause
:desc "Next" "l" 'spotify-next
:desc "Previous" "h" 'spotify-prev
))
Pueue
Pueue is a super useful tool for running data analysis and other long processes. I find it very useful to open and add to the queue from Emacs, particularly when working with python/julia scripts.
(package! pueue
:recipe (:host github
:repo "xFA25E/pueue"))
I add a binding to the open map too see how everything is doing, and another to the code map to easily add scripts I'm looking at to the queue.
;; Pueue
(map! :map doom-leader-open-map
:desc "Pueue" "q" 'pueue
)
(map! :map doom-leader-code-map
:desc "Add to Pueue" "q" 'pueue-add
)
Beacon
A small but powerfull change: a big beacon of light whenever you switch windows/buffers.
(package! beacon)
Of course, I ant it to be always active.
(use-package! beacon
:config (beacon-mode 1))
Nyan-mode
Add a bit of life to the modeline.
(package! nyan-mode)
(use-package! nyan-mode
:after doom-modeline
:config
(setq nyan-bar-length 15
nyan-wavy-trail t)
(nyan-mode)
(nyan-start-animation))
Slurm
(package! slurm-mode)
(use-package! slurm-mode)
gptel
Karthink's LLM client for emacs
(package! gtpel
:recipe (:host github :repo "karthink/gptel"))
(use-package! gptel
:config
;; (gptel-make-ollama "Ollama" ;Any name of your choosing
;; :host "localhost:11434" ;Where it's running
;; :stream t ;Stream responses
;; :models '("llama3.1:latest")) ;List of models
;; Set default
;; OPTIONAL configuration
(setq
gptel-model 'deepseek-r1
gptel-default-mode #'org-mode
gptel-backend (gptel-make-ollama "Ollama"
:host "localhost:11434"
:stream t
:models '(
"deepseek-r1"
"llama3.1:latest"
"deepseek-coder-v2:latest"
"mistral:latest"
"mistral-nemo:latest"
"gemma2:latest"
"gemma2:27b"))))
(map! :leader
(:prefix-map ("l" . "gptel")
:desc "Dedicated Buffer" "l" 'gptel
:desc "Menu" "m" 'gptel-menu
:desc "Send text" "s" 'gptel-send
:desc "Send text (Menu)" "S" (cmd! (gptel-send 1))
:desc "Add/remove region" "a" 'gptel-add
:desc "Add file" "A" 'gptel-add-file
(:mode (org-mode)
:desc "Limit to Heading" "h" 'gptel-org-set-topic
:desc "Set properties" "p" 'gptel-org-set-properties)))
gptel-rg-set-properties
whisper
Voice to Text using OpenAI's whisper, locally.
(package! whisper
:recipe (:host github :repo "natrys/whisper.el"))
(use-package! whisper
:config
(map! :desc "Voice to Text" :g "C-c i" #'whisper-run)
(defun whisper--break-sentences (n)
"Put a line break every N sentences."
(catch 'return
(while t
(dotimes (_ n)
(forward-sentence 1)
(when (eobp) (throw 'return nil)))
(insert "\n")
(when (= (char-after) ?\ )
(delete-horizontal-space)))))
(add-hook 'whisper-post-process-hook
(lambda ()
(whisper--break-sentences 1)))
)
Typst
A "markup-based pysetting language".
To get it working we use typst-ts-mode,
(package! typst-ts-mode
:recipe (:host codeberg :repo "meow_king/typst-ts-mode"))
(package! outline-indent-mode
:recipe (:host sourcehut :repo "meow_king/outline-indent-mode"))
(use-package! typst-ts-mode
:custom
(typst-ts-watch-options "--open")
(typst-ts-mode-grammar-location (expand-file-name "tree-sitter/libtree-sitter-typst.so" user-emacs-directory))
(typst-ts-mode-enable-raw-blocks-highlight t)
:config
(keymap-set typst-ts-mode-map "C-c C-c" #'typst-ts-tmenu))
(use-package! outline-indent-mode
:config
(add-hook 'typst-ts-mode-hook #'outline-indent-mode))
Of course want to export org-mode to typst. We use ox-typst
(package! ox-typst)
(use-package! ox-typst
:after org)
Denote
Denote is a note taking (and file naming) package for Emacs.
(package! denote)
; Denote submodules
(package! denote-sequence) ; more options for exploring denote files
(package! denote-org) ; compatibility
(package! consult-denote) ; consult integration for denote
(package! denote-explore) ; more options for exploring denote files
Mostly a mix of sample configurations.
(use-package! denote
:custom
(denote-directory (expand-file-name "~/Documents/denotes/"))
;; Set medium as known keywords. Let topics be discovered.
(denote-known-keywords '("Book" "Article" "Meeting" "Metanote"))
(denote-date-prompt-use-org-read-date t)
(denote-exclude-files-regexp "export/")
:config
;; Automatically rename Denote buffers when opening them so that
;; instead of their long file name they have, for example, a literal
;; "[D]" followed by the file's title. Read the doc string of
;; `denote-rename-buffer-format' for how to modify this.
(denote-rename-buffer-mode 1))
(use-package! denote-sequence
:after denote
:custom
(denote-sequence-scheme 'alphanumeric))
(use-package! consult-denote
:after denote
:config
(consult-denote-mode))
(use-package! denote-explore
:after denote)
(use-package! denote-org
:after denote)
And we add some bindings
(map! :leader
(:prefix-map ("d" . "Denotes")
:desc "Denote" "n" 'denote
:desc "Backlinks" "b" 'denote-backlinks
:desc "Sort Dired" "d" 'denote-sort-dired
;; :desc "Open Note" "f" 'consult-denote-find
:desc "Open Note" "f" 'denote-open-or-create
:desc "Link" "l" 'denote-link
:desc "Multiple Links" "L" 'denote-add-links
:desc "Rename" "r" 'denote-rename-file
:desc "Front Matter Rename" "R" 'denote-rename-file-using-front-matter
:desc "Sequence Dired" "D" 'denote-sequence-dired
:desc "Child Note" "c" 'denote-sequence-new-child
:desc "Child of this Note" "C" 'denote-sequence-new-child-of-current
:desc "Parent Note" "p" 'denote-sequence-new-parent
:desc "Sibling Note" "s" 'denote-sequence-new-sibling
:desc "Sibling of this Note" "S" 'denote-sequence-new-sibling-of-current
:desc "Search Note" "F" 'consult-denote-grep
(:prefix-map ("e" . "Explore")
:desc "Chart Keywords" "b" 'denote-explore-barchart-keywords
:desc "Chart Degrees" "B" 'denote-explore-barchart-degree
:desc "Count Notes" "c" 'denote-explore-count-notes
:desc "Count Keywords" "C" 'denote-explore-count-keywords
:desc "Identify Duplicates" "d" 'denote-explore-duplicate-notes
:desc "Isolated notes" "i" 'denote-explore-isolated-files
:desc "Single-use keywords" "k" 'denote-explore-single-keywords
:desc "Zero keywords" "K" 'denote-explore-zero-keywords
:desc "Sync Metadata" "m" 'denote-explore-sync-metadata
:desc "Network" "n" 'denote-explore-network
:desc "Regenerate Network" "N" 'denote-explore-network-regenerate
:desc "Random note" "r" 'denote-explore-random-note
:desc "Rename keyword" "R" 'denote-explore-rename-keyword
:desc "Chart Timeline" "t" 'denote-explore-barchart-timeline
)))
MPDel
An MPD (Music Player Daemon) client
(package! libmpdel)
(package! mpdel)
(use-package! mpdel
:config
(setq mpdel-prefix-key (kbd "C-c m")))
Zoom
Automatically resize windows, keeping current window as the largest. From cyrus-and I have it installed but I don't like enabling it by default.
(package! zoom)
(use-package! zoom
:custom
(zoom-size '(0.618 . 0.618))
:config
(map! :map evil-window-map :desc "Toggle Zoom mode" "z" 'zoom-mode))
org-auto-tangle
From yilkalargaw
If the minor mode is on, it will try to automatically tangle your org files if they contain a non nil value for the #+auto_tangle: option.
You can configure auto-tangle as the default behavior for all org buffers by setting the org-auto-tangle-default variable to t. In this case, you can disable it for some buffers by setting the #+auto_tangle: option to nil.
(package! org-auto-tangle
:recipe (:host github :repo "yilkalargaw/org-auto-tangle"))
(use-package! org-auto-tangle
:after org
:config
(add-hook 'org-src-mode-hook 'org-auto-tangle-mode)
:custom
(org-auto-tangle-default t))