Initial Commit
This commit is contained in:
commit
9dc88926e6
|
@ -0,0 +1 @@
|
||||||
|
config.el
|
|
@ -0,0 +1,856 @@
|
||||||
|
# -*- lexical-binding: t; -*-
|
||||||
|
#+title: Nathan's Doom Emacs Configuration
|
||||||
|
#+author: Nathan McCarty
|
||||||
|
#+PROPERTY: header-args:emacs-lisp :tangle yes
|
||||||
|
|
||||||
|
My doom emacs configuration
|
||||||
|
|
||||||
|
* Basic Doom stuff
|
||||||
|
The provided default ~config.el~
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Place your private configuration here! Remember, you do not need to run 'doom
|
||||||
|
;; sync' after modifying this file!
|
||||||
|
|
||||||
|
|
||||||
|
;; Some functionality uses this to identify you, e.g. GPG configuration, email
|
||||||
|
;; clients, file templates and snippets. It is optional.
|
||||||
|
(setq user-full-name "Nathan McCarty"
|
||||||
|
user-mail-address "nathan@mccarty.io")
|
||||||
|
|
||||||
|
;; Doom exposes five (optional) variables for controlling fonts in Doom:
|
||||||
|
;;
|
||||||
|
;; - `doom-font' -- the primary font to use
|
||||||
|
;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable)
|
||||||
|
;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for
|
||||||
|
;; presentations or streaming.
|
||||||
|
;; - `doom-unicode-font' -- for unicode glyphs
|
||||||
|
;; - `doom-serif-font' -- for the `fixed-pitch-serif' face
|
||||||
|
;;
|
||||||
|
;; See 'C-h v doom-font' for documentation and more examples of what they
|
||||||
|
;; accept. For example:
|
||||||
|
;;
|
||||||
|
(setq doom-font (font-spec :family "FiraCode Nerd Font" :size 11 :weight 'semi-light)
|
||||||
|
doom-unicode-font (font-spec :family "FiraCode Nerd Font" :size 11 :weight 'semi-light)
|
||||||
|
doom-variable-pitch-font (font-spec :family "Fira Sans" :size 15))
|
||||||
|
;;
|
||||||
|
;; If you or Emacs can't find your font, use 'M-x describe-font' to look them
|
||||||
|
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
|
||||||
|
;; refresh your font settings. If Emacs still can't find your font, it likely
|
||||||
|
;; wasn't installed correctly. Font issues are rarely Doom issues!
|
||||||
|
|
||||||
|
;; There are two ways to load a theme. Both assume the theme is installed and
|
||||||
|
;; available. You can either set `doom-theme' or manually load a theme with the
|
||||||
|
;; `load-theme' function. This is the default:
|
||||||
|
;; (setq doom-theme 'doom-solarized-dark)
|
||||||
|
(use-package! solarized-theme
|
||||||
|
:demand t
|
||||||
|
:config
|
||||||
|
(setq solarized-distinct-fringe-background t
|
||||||
|
solarized-distinct-doc-face t
|
||||||
|
solarized-scale-markdown-headlines t
|
||||||
|
solarized-scale-org-headlines t)
|
||||||
|
(load-theme 'solarized-selenized-dark t))
|
||||||
|
|
||||||
|
;; This determines the style of line numbers in effect. If set to `nil', line
|
||||||
|
;; numbers are disabled. For relative line numbers, set this to `relative'.
|
||||||
|
(setq display-line-numbers-type t)
|
||||||
|
|
||||||
|
;; If you use `org' and don't want your org files in the default location below,
|
||||||
|
;; change `org-directory'. It must be set before org loads!
|
||||||
|
(setq org-directory "~/Org/")
|
||||||
|
|
||||||
|
|
||||||
|
;; 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.
|
||||||
|
#+end_src
|
||||||
|
** Garbage collector configuration
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! gcmh
|
||||||
|
(setq gcmh-high-cons-threshold (* 64 1024 1024)))
|
||||||
|
#+end_src
|
||||||
|
* Appearance and UI
|
||||||
|
** Mixed Pitch Mode
|
||||||
|
Use mixed pitch mode in prose writing modes, to make the writing experience a bit more pleasant.
|
||||||
|
This tweak applies to:
|
||||||
|
- ~org-mode~
|
||||||
|
- ~markdown-mode~
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! mixed-pitch
|
||||||
|
:hook
|
||||||
|
(org-mode . mixed-pitch-mode)
|
||||||
|
(markdown-mode . mixed-pitch-mode)
|
||||||
|
:config
|
||||||
|
(setq mixed-pitch-set-height t))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Setting ~mixed-pitch-set-height~ is required to get ~mixed-pitch-mode~ to render fonts with the correct size in doom emacs, apparently.
|
||||||
|
** Modeline configuration
|
||||||
|
Configure the modeline to:
|
||||||
|
+ truncate with project (so that ~~/Projects/Asuran/replicator/src/lib.rs~ becomes ~replicator/s/lib.rs~)
|
||||||
|
+ Show the mu4e alert
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq doom-modeline-buffer-file-name-style 'truncate-with-project
|
||||||
|
doom-modeline-mu4e t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Display the current time in the modeline
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(display-time-mode 1)
|
||||||
|
#+end_src
|
||||||
|
** Treemacs
|
||||||
|
Configure treemacs, doing the following:
|
||||||
|
+ Set the width of the buffer to 28 characters
|
||||||
|
+ Bind the select window function to ~M-0~
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! treemacs
|
||||||
|
(setq treemacs-width 28)
|
||||||
|
(bind-key "M-0" #'treemacs-select-window))
|
||||||
|
#+end_src
|
||||||
|
** Alert
|
||||||
|
Configure notifications that originate from within emacs
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! alert
|
||||||
|
:config
|
||||||
|
;; TODO: Make this conditional so we can make the correct choice on macos
|
||||||
|
(setq alert-default-style 'libnotify))
|
||||||
|
#+end_src
|
||||||
|
** Dired
|
||||||
|
Modify the ~dired-omit-files~ regex to exclude the current working directory (~.~), but not the parent directory(~..~).
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! dired
|
||||||
|
(setq dired-omit-files "\\`[.]?#\\|\\`[.]?\\'\\|^\\.DS_Store\\'\\|^\\.project\\(?:ile\\)?\\'\\|^\\.\\(?:svn\\|git\\)\\'\\|^\\.ccls-cache\\'\\|\\(?:\\.js\\)?\\.meta\\'\\|\\.\\(?:elc\\|o\\|pyo\\|swp\\|class\\)\\'"))
|
||||||
|
#+end_src
|
||||||
|
* Basic Editing
|
||||||
|
** Fill Column
|
||||||
|
Set the default fill column to 100
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq-default fill-column 100)
|
||||||
|
#+end_src
|
||||||
|
** Navigation
|
||||||
|
*** Avy
|
||||||
|
More modern ace-jump-mode
|
||||||
|
|
||||||
|
Set up our key bindings
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! avy
|
||||||
|
(define-key!
|
||||||
|
"M-g c" 'avy-goto-char
|
||||||
|
"M-g x" 'avy-goto-char-2
|
||||||
|
"M-g f" 'avy-goto-line
|
||||||
|
"M-g w" 'avy-goto-word-1
|
||||||
|
"M-g e" 'avy-goto-word-0)
|
||||||
|
(cheatsheet-add-group 'Avy
|
||||||
|
'(:key "M-g c" :description "Goto Char")
|
||||||
|
'(:key "M-g x" :description "Goto Char (2)")
|
||||||
|
'(:key "M-g f" :description "Goto line")
|
||||||
|
'(:key "M-g w" :description "Goto word")
|
||||||
|
'(:key "M-g e" :description "Goto word (0)")))
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
*** Swiper
|
||||||
|
Better isearch
|
||||||
|
|
||||||
|
Override old isearch
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! swiper
|
||||||
|
(define-key! "C-s" 'swiper))
|
||||||
|
#+end_src
|
||||||
|
** Crux
|
||||||
|
Smarter replacements for emacs built ins, with the following in use:
|
||||||
|
- ~crux-smart-kill-line~ - Smart ~C-k~ replacement
|
||||||
|
- ~crux-top-join-line~ - ~C-c ^~ Join two lines
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! crux
|
||||||
|
:bind (("C-k" . crux-smart-kill-line)
|
||||||
|
("C-c ^" . crux-top-join-line)))
|
||||||
|
#+end_src
|
||||||
|
** string-inflection
|
||||||
|
Automatically cycle case of names
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(global-unset-key (kbd "C-q"))
|
||||||
|
(use-package! string-inflection
|
||||||
|
:bind (("C-q" . string-inflection-all-cycle)))
|
||||||
|
(cheatsheet-add-group 'string-inflection
|
||||||
|
'(:key "C-q" :description "Rotate case"))
|
||||||
|
#+end_src
|
||||||
|
** Smart Hungry Delete
|
||||||
|
Gobble up whitespace in a smarter way
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! smart-hungry-delete
|
||||||
|
:bind (("M-<backspace>" . smart-hungry-delete-backward-char)))
|
||||||
|
#+end_src
|
||||||
|
** Search
|
||||||
|
*** Deadgrep
|
||||||
|
Ripgrep, but from within emacs
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! deadgrep
|
||||||
|
:bind ("C-c s r" . deadgrep))
|
||||||
|
#+end_src
|
||||||
|
** Spell Checking
|
||||||
|
Add in all of our dictionaries
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! spell-fu
|
||||||
|
(add-hook 'spell-fu-mode
|
||||||
|
(lambda ()
|
||||||
|
(spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "en"))
|
||||||
|
(spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "en-science"))
|
||||||
|
(spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "en-computers"))))
|
||||||
|
(bind-key "C-." #'+spell/correct))
|
||||||
|
#+end_src
|
||||||
|
* Org Mode
|
||||||
|
Improvements to the best mode in emacs
|
||||||
|
|
||||||
|
Setup some basic cosmetic improvements
|
||||||
|
- Disable showing of emphasis markers
|
||||||
|
- Show entities as utf-8 ~test~
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-hide-emphasis-markers t
|
||||||
|
org-pretty-entities t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Setup org-superstar-mode, to make lists and bullets pretty
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! org-superstar
|
||||||
|
:hook (org-mode . org-superstar-mode)
|
||||||
|
:config
|
||||||
|
(setq org-superstart-special-todo-items t))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Automatically add all files in the org dir to the agenda. This performs some filtering of the files returned from ~directory-files~ to exclude some things that would confuse org-agenda.
|
||||||
|
We also setup an idle timer, with a short duration, only 30 seconds, to update the ~org-agenda-files~ list, as well as a longer regular timer with a duration of 300 seconds (5 minutes) to keep the agenda up to date even when we are actively using emacs.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defvar nm/org-agenda-files-timer nil
|
||||||
|
"Timer for automatically updating the org-agenda files")
|
||||||
|
(defvar nm/time-at-agenda-update 0
|
||||||
|
"Time at last agenda update")
|
||||||
|
|
||||||
|
(defun nm/update-org-agenda-files ()
|
||||||
|
"Helper function for updating the org-agenda files."
|
||||||
|
;; Calcuate time since last update
|
||||||
|
(let* ((time-seconds (float-time (current-time)))
|
||||||
|
(seconds-since (- time-seconds nm/time-at-agenda-update))
|
||||||
|
(idle-time (current-idle-time))
|
||||||
|
(idle-seconds (if idle-time (float-time idle-time) 0)))
|
||||||
|
;; If it has been more than 10 minutes since our last agenda file update, then go ahead and update
|
||||||
|
;; Additionally update if the idle timer is greater than 30 seconds
|
||||||
|
(when (or
|
||||||
|
(> seconds-since 600)
|
||||||
|
(> idle-seconds 30))
|
||||||
|
;; Update our time variable
|
||||||
|
(setq nm/time-at-agenda-update seconds-since)
|
||||||
|
;; Update our agenda files
|
||||||
|
(setq org-agenda-files
|
||||||
|
(seq-filter (lambda (item)
|
||||||
|
(and
|
||||||
|
;; Only accept things that are a directory, or an org file
|
||||||
|
(or (file-directory-p item)
|
||||||
|
(string-match-p ".*org$" item))
|
||||||
|
;; Exclude the syncthing folder
|
||||||
|
(not (string-match-p ".*stfolder$" item))
|
||||||
|
;; Exclude the elfeed data folder
|
||||||
|
(not (string-match-p (concat "^" (regexp-quote org-directory) "elfeed/.*") item))))
|
||||||
|
(directory-files-recursively org-directory directory-files-no-dot-files-regexp)))))
|
||||||
|
;; Update the timer, first canceling the old one
|
||||||
|
(when nm/org-agenda-files-timer
|
||||||
|
(cancel-timer nm/org-agenda-files-timer)
|
||||||
|
(setq nm/org-agenda-files-timer (run-with-timer 60 nil 'nm/update-org-agenda-files))))
|
||||||
|
|
||||||
|
(after! org
|
||||||
|
;; Set the agenda files on first start
|
||||||
|
;; This also configures the timer for us
|
||||||
|
(nm/update-org-agenda-files))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Set up two different timers for updating the org-agenda buffer.
|
||||||
|
+ Idle timer
|
||||||
|
The idle timer simply updates the views unconditionally, and is set with a slightly higher timeout than our idle time that updates the org agenda files. This idle time can safely modify the state of the buffer without any other checks, as if the user is idle, they aren't doing anything in the buffer
|
||||||
|
+ Timer timer
|
||||||
|
Setup a timer that attempts to update the org-agenda buffer every 5 minutes. This timer is a little bit unsafe, so it _could_ end up annoying the user by updating the state while they are in the middle of doing something, so it cancels out and does nothing if the user is currently focused on the agenda buffer.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defvar nm/org-agenda-update-timer nil
|
||||||
|
"Timer for automatically updating the org-agenda views")
|
||||||
|
|
||||||
|
(defun nm/org-agenda-refresh-conditional ()
|
||||||
|
"Helper function to only refresh the org-agenda views if it
|
||||||
|
either isn't focused or we have been idle long enough. This
|
||||||
|
avoids updating the buffer, and thus annoying the user, while
|
||||||
|
they are in the middle of doing something.
|
||||||
|
|
||||||
|
This function will run on a 60 second loop, only actually doing
|
||||||
|
work if it thinks it needs to."
|
||||||
|
;; Make sure the org-agenda-buffer exists, bail out if it doesnt
|
||||||
|
(when (boundp 'org-agenda-buffer-name)
|
||||||
|
;; Attempt to get the org agenda buffer
|
||||||
|
(when-let ((buffer (get-buffer org-agenda-buffer-name)))
|
||||||
|
;; Calcuate idle time
|
||||||
|
(let* ((idle-time (current-idle-time))
|
||||||
|
(idle-seconds (if idle-time (float-time idle-time) 0)))
|
||||||
|
;; Update the org-agenda views if any of the following apply:
|
||||||
|
;; - The agenda buffer is not in focus
|
||||||
|
;; - The idle time is greater than one minute
|
||||||
|
(when (or
|
||||||
|
(not (eq (window-buffer (selected-window)) buffer))
|
||||||
|
(> idle-seconds 60))
|
||||||
|
;; Since we are not in the org-agenda-buffer it is safe to rebuild the views
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(org-agenda-redo-all))))))
|
||||||
|
;; Update the timer, first canceling the old one
|
||||||
|
(when nm/org-agenda-update-timer
|
||||||
|
(cancel-timer nm/org-agenda-update-timer))
|
||||||
|
(setq nm/org-agenda-update-timer (run-with-timer 60 nil 'nm/org-agenda-refresh-conditional)))
|
||||||
|
|
||||||
|
(after! org
|
||||||
|
;; This method sets up the timer on its own
|
||||||
|
(nm/org-agenda-refresh-conditional))
|
||||||
|
#+end_src
|
||||||
|
** Log state changes and setup TODO keywords
|
||||||
|
Configure the logging, we want to log into a drawer and also log refiles, reschedules, and repeats
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(setq org-log-into-drawer t
|
||||||
|
org-log-refile 'time
|
||||||
|
org-log-repeat 'time
|
||||||
|
org-log-reschedule 'time
|
||||||
|
org-log-done 'time))
|
||||||
|
#+end_src
|
||||||
|
We'll need to override the doom provided ~org-todo-keywords~ to get the state transitions we want logged
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(setq org-todo-keywords
|
||||||
|
'((sequence
|
||||||
|
"TODO(t)" ; A task that needs doing & is ready to do
|
||||||
|
"PROJ(p)" ; A project, which usually contains other tasks
|
||||||
|
"LOOP(r)" ; A recurring task
|
||||||
|
"STRT(s!)" ; A task that is in progress
|
||||||
|
"WAIT(w!)" ; Something external is holding up this task
|
||||||
|
"HOLD(h!)" ; This task is paused/on hold because of me
|
||||||
|
"IDEA(i)" ; An unconfirmed and unapproved task or notion
|
||||||
|
"|"
|
||||||
|
"DONE(d!)" ; Task successfully completed
|
||||||
|
"KILL(k!)") ; Task was cancelled, aborted or is no longer applicable
|
||||||
|
(sequence
|
||||||
|
"[ ](T)" ; A task that needs doing
|
||||||
|
"[-](S!)" ; Task is in progress
|
||||||
|
"[?](W!)" ; Task is being held up or paused
|
||||||
|
"|"
|
||||||
|
"[X](D!)") ; Task was completed
|
||||||
|
(sequence
|
||||||
|
"|"
|
||||||
|
"OKAY(o!)"
|
||||||
|
"YES(y!)"
|
||||||
|
"NO(n!)"))
|
||||||
|
org-todo-keyword-faces
|
||||||
|
'(("[-]" . +org-todo-active)
|
||||||
|
("STRT" . +org-todo-active)
|
||||||
|
("[?]" . +org-todo-onhold)
|
||||||
|
("WAIT" . +org-todo-onhold)
|
||||||
|
("HOLD" . +org-todo-onhold)
|
||||||
|
("PROJ" . +org-todo-project)
|
||||||
|
("NO" . +org-todo-cancel)
|
||||||
|
("KILL" . +org-todo-cancel))))
|
||||||
|
#+end_src
|
||||||
|
** org-roam
|
||||||
|
A second brain in emacs
|
||||||
|
|
||||||
|
|
||||||
|
Here we:
|
||||||
|
- Set the roam directory to be a sub-directory of the org directory, which I have in syncthing
|
||||||
|
- Use a more informative display template, as we use ivy
|
||||||
|
- Turn on db autosync
|
||||||
|
- Setup dalies to add the time of the capture to the note
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! org-roam
|
||||||
|
:custom
|
||||||
|
(org-roam-directory (concat org-directory "Roam/"))
|
||||||
|
(org-roam-complete-everywhere t)
|
||||||
|
:bind (("C-c r l" . org-roam-buffer-toggle)
|
||||||
|
("C-c r f" . org-roam-node-find)
|
||||||
|
("C-c r g" . org-roam-graph)
|
||||||
|
("C-c r i" . org-roam-node-insert)
|
||||||
|
("C-c r c" . org-roam-capture)
|
||||||
|
("C-c r T" . org-roam-dailies-capture-today)
|
||||||
|
("C-c r t" . org-roam-dailies-goto-today)
|
||||||
|
:map org-mode-map
|
||||||
|
("C-M-i" . completion-at-point))
|
||||||
|
:config
|
||||||
|
(setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
|
||||||
|
(org-roam-db-autosync-mode)
|
||||||
|
(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")))))
|
||||||
|
#+end_src
|
||||||
|
** org-protocol-capture-html
|
||||||
|
[[https://github.com/alphapapa/org-protocol-capture-html][Capture webpages]] really nice like
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! org-protocol-capture-html)
|
||||||
|
#+end_src
|
||||||
|
** Capture Templates
|
||||||
|
The default template for org-protocol-capture-html
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(push
|
||||||
|
'("w" "Web site" entry
|
||||||
|
(file "")
|
||||||
|
"* %a :website:\n\n%U %?\n\n%:initial")
|
||||||
|
org-capture-templates))
|
||||||
|
#+end_src
|
||||||
|
** anki-editor
|
||||||
|
Flash cards from within emacs.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! anki-editor)
|
||||||
|
#+end_src
|
||||||
|
** org-agenda customization
|
||||||
|
Empty out the list and define our prefixes first
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(setq org-agenda-custom-commands
|
||||||
|
'(("p" . "Project Views"))))
|
||||||
|
#+end_src
|
||||||
|
*** Random project selection
|
||||||
|
First some library code
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun org-compare--get-marker (entry)
|
||||||
|
"Return the marker for ENTRY.
|
||||||
|
|
||||||
|
This marker points to the location of the headline referenced by
|
||||||
|
ENTRY."
|
||||||
|
(get-text-property 1 'org-marker entry))
|
||||||
|
|
||||||
|
(defvar org-compare-random-refresh nil
|
||||||
|
"Whether `org-compare-randomly' should refresh its keys.
|
||||||
|
|
||||||
|
See the docs for `org-compare-randomly' for more information.")
|
||||||
|
|
||||||
|
(defun org-compare-randomly--update-sort-key (entry table generator)
|
||||||
|
"Return sort key for ENTRY in TABLE, generating it if necessary.
|
||||||
|
For internal use by `org-compare-randomly-by'."
|
||||||
|
(let* ((marker (org-compare--get-marker entry))
|
||||||
|
(hash-key `(,(marker-buffer marker) . ,(marker-position marker))))
|
||||||
|
(or (gethash hash-key table)
|
||||||
|
(puthash hash-key (funcall generator entry) table))))
|
||||||
|
|
||||||
|
(defun org-compare-randomly-by (generator)
|
||||||
|
"Return a random comparator using GENERATOR.
|
||||||
|
|
||||||
|
The comparator returned is like `org-compare-randomly', except
|
||||||
|
the distribution of random keys is controlled by GENERATOR and
|
||||||
|
may thus be non-uniform.
|
||||||
|
|
||||||
|
The function GENERATOR is called with a single argument, an
|
||||||
|
agenda entry, when that entry lacks a sort key. It should return
|
||||||
|
a number, which is then used for all comparisons until the key
|
||||||
|
list is cleared; see `org-compare-randomly' for more details on
|
||||||
|
this.
|
||||||
|
|
||||||
|
Subsequent calls to `org-compare-randomly-by' produce comparators
|
||||||
|
with independent sets of sort keys."
|
||||||
|
(let ((table (make-hash-table :test #'equal)))
|
||||||
|
(lambda (x y)
|
||||||
|
(when org-compare-random-refresh
|
||||||
|
(clrhash table)
|
||||||
|
(setq org-compare-random-refresh nil))
|
||||||
|
(let ((x-val (org-compare-randomly--update-sort-key x table generator))
|
||||||
|
(y-val (org-compare-randomly--update-sort-key y table generator)))
|
||||||
|
(cond
|
||||||
|
((= x-val y-val) nil)
|
||||||
|
((< x-val y-val) -1)
|
||||||
|
((> x-val y-val) +1))))))
|
||||||
|
|
||||||
|
(defun org-compare-randomly ()
|
||||||
|
"Return a comparator implementing a random shuffle.
|
||||||
|
|
||||||
|
When given distinct agenda entries X and Y, the resulting
|
||||||
|
comparator has an equal chance of returning +1 and -1 (and a
|
||||||
|
miniscule chance of returning nil). Subsequent calls will produce
|
||||||
|
results consistent with a total ordering.
|
||||||
|
|
||||||
|
To accomplish this, a hash table of randomly-generated sort keys
|
||||||
|
is maintained. This table will persist until the comparator is
|
||||||
|
called when the variable `org-compare-random-refresh' is non-nil.
|
||||||
|
This means that setting this variable as part of a custom agenda
|
||||||
|
command using this comparator as `org-agenda-cmp-user-defined'
|
||||||
|
will cause the sort order to change whenever the agenda is
|
||||||
|
refreshed; otherwise, it will persist until Emacs is restarted.
|
||||||
|
|
||||||
|
Note that if you don't want the sort order to change on refresh,
|
||||||
|
you need to be careful that the comparator is created when the
|
||||||
|
custom agenda command is defined, not when it's called, e.g.
|
||||||
|
|
||||||
|
(add-to-list
|
||||||
|
'org-agenda-custom-commands
|
||||||
|
`(\"y\" \"Example Agenda\"
|
||||||
|
((todo
|
||||||
|
\"\"
|
||||||
|
((org-agenda-cmp-user-defined ',(org-compare-randomly))
|
||||||
|
(org-agenda-sorting-strategy '(user-defined-up)))))))
|
||||||
|
|
||||||
|
\(Notice the use of backquote.)
|
||||||
|
|
||||||
|
Comparators resulting from different calls to this function have
|
||||||
|
independent key tables."
|
||||||
|
(org-compare-randomly-by (lambda (_) (random))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Then add our custom command, one section for "TODO"s and another for top level "PROJ"s
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(add-to-list 'org-agenda-custom-commands
|
||||||
|
'("pr" "Random Project TODOs"
|
||||||
|
((tags "proj/TODO"
|
||||||
|
((org-agenda-max-entries 5)
|
||||||
|
(org-agenda-cmp-user-defined (org-compare-randomly))
|
||||||
|
(org-compare-random-refresh t)
|
||||||
|
(org-agenda-sorting-strategy '(user-defined-up))))
|
||||||
|
(tags "proj/STRT"
|
||||||
|
((org-agenda-max-entries 5)
|
||||||
|
(org-agenda-cmp-user-defined (org-compare-randomly))
|
||||||
|
(org-compare-random-refresh t)
|
||||||
|
(org-agenda-sorting-strategy '(user-defined-up))))
|
||||||
|
(tags "proj/PROJ"
|
||||||
|
((org-agenda-max-entries 5)
|
||||||
|
(org-agenda-cmp-user-defined (org-compare-randomly))
|
||||||
|
(org-compare-random-refresh t)
|
||||||
|
(org-agenda-sorting-strategy '(user-defined-up))))
|
||||||
|
(todo "IDEA"
|
||||||
|
((org-agenda-max-entries 5)
|
||||||
|
(org-agenda-cmp-user-defined (org-compare-randomly))
|
||||||
|
(org-compare-random-refresh t)
|
||||||
|
(org-agenda-sorting-strategy '(user-defined-up))))))))
|
||||||
|
#+end_src
|
||||||
|
*** Don't dim blocked tasks
|
||||||
|
Not only does this feature have performance issues, its not useful with how I use org
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(setq org-agenda-dim-blocked-tasks nil))
|
||||||
|
#+end_src
|
||||||
|
** Set tags alist
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(setq org-tag-alist '(("proj" . ?p)
|
||||||
|
("complaint" . ?c)
|
||||||
|
("work" . ?w))))
|
||||||
|
#+end_src
|
||||||
|
** Modules configuration
|
||||||
|
*** org habits
|
||||||
|
Enable the module
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(add-to-list 'org-modules 'org-habit))
|
||||||
|
#+end_src
|
||||||
|
** Babel config
|
||||||
|
*** Ansi colors
|
||||||
|
First, bring in ~ansi-color~
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(require 'ansi-color)
|
||||||
|
#+end_src
|
||||||
|
Then, hook into babel and apply those colors
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! org
|
||||||
|
(defun nm/babel-ansi ()
|
||||||
|
(when-let ((beg (org-babel-where-is-src-block-result nil nil)))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char beg)
|
||||||
|
(when (looking-at org-babel-result-regexp)
|
||||||
|
(let ((end (org-babel-result-end))
|
||||||
|
(ansi-color-context-region nil))
|
||||||
|
(ansi-color-apply-on-region beg end))))))
|
||||||
|
(add-hook 'org-babel-after-execute-hook 'nm/babel-ansi))
|
||||||
|
#+end_src
|
||||||
|
* General Modes
|
||||||
|
** Magit
|
||||||
|
Further configuration for magit
|
||||||
|
*** magit-todos
|
||||||
|
Count the number of todos in the project in the ~magit-status~ buffer
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! magit-todos
|
||||||
|
:hook (magit-mode . magit-todos-mode))
|
||||||
|
#+end_src
|
||||||
|
*** magit-delta
|
||||||
|
Use delta for git diff display
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! magit-delta
|
||||||
|
:hook (magit-mode . magit-delta-mode))
|
||||||
|
#+end_src
|
||||||
|
*** magit-wip-mode
|
||||||
|
Stash autosaves inside of git
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(magit-wip-mode)
|
||||||
|
#+end_src
|
||||||
|
** System integration
|
||||||
|
Various tools for interacting with the system from within emacs
|
||||||
|
*** Terminal
|
||||||
|
Doom already provides pretty nice vterm support, but lets take us a step further, using ~multi-vterm~ to provide ergonomic support for multiple terminals.
|
||||||
|
|
||||||
|
Vterm really doesn't like being installed through emacs on nix, so proper support for it in my setup requires installing it through nix like so:
|
||||||
|
#+begin_src nix :tangle no
|
||||||
|
let emacsPackage = (emacsPackagesFor emacs).emacsWithPackages (epgks: with epkgs; [
|
||||||
|
vterm
|
||||||
|
]);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.systemPackages = [
|
||||||
|
emacsPackage
|
||||||
|
];
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
**** [[https://github.com/suonlight/multi-vterm][multi-vterm]]
|
||||||
|
Add ergonomic support for multiple vterm terminals
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! multi-vterm
|
||||||
|
:bind (("C-c o M" . multi-vterm)
|
||||||
|
("C-c o m" . multi-vterm-project)))
|
||||||
|
#+end_src
|
||||||
|
* Programming
|
||||||
|
** General Editing
|
||||||
|
*** Sepraedit
|
||||||
|
Edit indirect for comments
|
||||||
|
|
||||||
|
Set the default mode to github flavored markdown, turn on smart use of fill column, and bind to the normal edit-indirect keybinding.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! separedit
|
||||||
|
:bind
|
||||||
|
(:map prog-mode-map
|
||||||
|
("C-c '" . separedit))
|
||||||
|
:config
|
||||||
|
(setq separedit-default-mode 'gfm-mode
|
||||||
|
separedit-continue-fill-column t))
|
||||||
|
#+end_src
|
||||||
|
*** Rainbow delimiters
|
||||||
|
Makes pairs of delimiters into pretty colors. Hook this into prog-mode
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! rainbow-delimiters
|
||||||
|
:hook (prog-mode . rainbow-delimiters-mode))
|
||||||
|
#+end_src
|
||||||
|
*** YASnippet
|
||||||
|
Set the snippets directory to inside our org dir, since this gets synced
|
||||||
|
#+begin_src emacs-lisp :tangle yes
|
||||||
|
(after! yasnippet
|
||||||
|
(add-to-list 'yas-snippet-dirs "~/Org/snippets")
|
||||||
|
(yas-reload-all))
|
||||||
|
#+end_src
|
||||||
|
** LSP Mode
|
||||||
|
Custom configuration for lsp-mode
|
||||||
|
*** Exclude nix directories from file watchers
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-mode
|
||||||
|
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\result\\")
|
||||||
|
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\result-doc\\"))
|
||||||
|
#+end_src
|
||||||
|
*** LSP UI
|
||||||
|
Turn on the UI features we want
|
||||||
|
**** Sideline
|
||||||
|
Show as much as possible in the sideline
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-ui
|
||||||
|
(setq lsp-ui-sideline-show-diagnostics t
|
||||||
|
lsp-ui-sideline-show-hover t
|
||||||
|
lsp-ui-sideline-show-code-actions t))
|
||||||
|
#+end_src
|
||||||
|
**** Peeking
|
||||||
|
Turn on peeking, and show us the directory as well
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-ui
|
||||||
|
(setq lsp-ui-peek-enable t
|
||||||
|
lsp-ui-peek-show-directory t))
|
||||||
|
#+end_src
|
||||||
|
**** Documentation
|
||||||
|
Show the documentation in a popup frame in the top right corner
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-ui
|
||||||
|
(setq lsp-ui-doc-enable t
|
||||||
|
lsp-ui-doc-position 'top
|
||||||
|
lsp-ui-doc-show-with-cursor t))
|
||||||
|
#+end_src
|
||||||
|
** Rust
|
||||||
|
Configuration specific for rust
|
||||||
|
*** LSP Tweaks
|
||||||
|
Most of these are defaults, but I like having them explicit for my sanity
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-mode
|
||||||
|
(setq lsp-auto-configure t
|
||||||
|
lsp-lens-enable t
|
||||||
|
lsp-rust-analyzer-cargo-watch-command "clippy"
|
||||||
|
lsp-rust-analyzer-cargo-watch-args ["--all-features"]
|
||||||
|
lsp-rust-analyzer-experimental-proc-attr-macros t
|
||||||
|
lsp-rust-analyzer-proc-macro-enable t
|
||||||
|
lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts t
|
||||||
|
lsp-rust-analyzer-import-enforce-granularity t
|
||||||
|
lsp-rust-analyzer-diagnostics-enable-experimental t
|
||||||
|
lsp-rust-analyzer-display-chaining-hints t))
|
||||||
|
#+end_src
|
||||||
|
** Nix
|
||||||
|
Use rnix-lsp
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! lsp-mode
|
||||||
|
(add-to-list 'lsp-language-id-configuration '(nix-mode . "nix"))
|
||||||
|
(lsp-register-client
|
||||||
|
(make-lsp-client :new-connection (lsp-stdio-connection '("rnix-lsp"))
|
||||||
|
:major-modes '(nix-mode)
|
||||||
|
:server-id 'nix)))
|
||||||
|
#+end_src
|
||||||
|
* Composition
|
||||||
|
Modes for handling plain text and prose
|
||||||
|
** Markdown
|
||||||
|
Everybody's favorite markup format
|
||||||
|
*** Markdown mode
|
||||||
|
Make the following configuration tweaks to result in a better markdown experience:
|
||||||
|
- Use a variable pitch font (this is prose after all)
|
||||||
|
- Turn on header scaling
|
||||||
|
- Default to gfm mode for readmes
|
||||||
|
- Turn on auto-fill mode
|
||||||
|
- Hide mark up
|
||||||
|
- Fontify code blocks with the language's native mode
|
||||||
|
|
||||||
|
The goal here is to create a more pretty and fluid composition environment for prose, closer to what you would get in a word processor, but without the horrors of wysiwyg.
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! markdown-mode
|
||||||
|
:mode ("README\\.md" . gfm-mode)
|
||||||
|
:hook (markdown-mode . variable-pitch-mode)
|
||||||
|
(markdown-mode . auto-fill-mode)
|
||||||
|
:config
|
||||||
|
(setq markdown-header-scaling t
|
||||||
|
markdown-hide-markup t
|
||||||
|
markdown-fontify-code-blocks-natively t))
|
||||||
|
#+end_src
|
||||||
|
*** Grip mode
|
||||||
|
Provide a live, rendered preview when editing markdown readmes using [[https://github.com/joeyespo/grip][grip]].
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! grip-mode
|
||||||
|
:bind (:map markdown-mode-command-map
|
||||||
|
("g" . grip-mode)))
|
||||||
|
#+end_src
|
||||||
|
* Applications
|
||||||
|
Emacs is good for more than just editing text
|
||||||
|
** RSS
|
||||||
|
Use ~elfeed~ for RSS. Doom provides most of the configuration, but we'll make a few minor tweaks:
|
||||||
|
- Automatically update the feed when opening elfeed
|
||||||
|
- Set default filter to only show unread posts
|
||||||
|
- Put the elfeed directory in the org dir (I have it in syncthing)
|
||||||
|
- Create a global keybinding for elfeed (~C-x w~)
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package! elfeed
|
||||||
|
:hook (elfeed-search-mode . elfeed-update)
|
||||||
|
:hook (elfeed-show-mode . variable-pitch-mode)
|
||||||
|
:hook (elfeed-show-mode . visual-line-mode)
|
||||||
|
:bind ("C-x w" . elfeed)
|
||||||
|
:config
|
||||||
|
(setq elfeed-search-filter "@4-weeks-ago +unread"
|
||||||
|
elfeed-db-directory (concat org-directory "elfeed/db/")
|
||||||
|
elfeed-enclosure-default-dir (concat org-directory "elfeed/enclosures/")
|
||||||
|
shr-max-width nil)
|
||||||
|
(make-directory elfeed-db-directory t))
|
||||||
|
#+end_src
|
||||||
|
** Email
|
||||||
|
Use ~mu4e~ for email. Most of the bootstrap is provided by doom emacs.
|
||||||
|
First, tell mu4e to use msmtp
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(setq sendmail-program (executable-find "msmtp")
|
||||||
|
send-mail-function #'smtpmail-send-it
|
||||||
|
message-sendmail-f-is-evil t
|
||||||
|
message-sendmail-extra-arguments '("--read-envelope-from")
|
||||||
|
message-send-mail-function #'message-send-mail-with-sendmail))
|
||||||
|
#+end_src
|
||||||
|
Tell it where our account's stuff is
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(set-email-account! "mccarty.io"
|
||||||
|
'((mu4e-sent-folder . "/nathan@mccarty.io/Sent")
|
||||||
|
(mu4e-drafts-folder . "/nathan@mccarty.io/Drafts")
|
||||||
|
(mu4e-trash-folder . "/nathan@mccarty.io/Trash")
|
||||||
|
(mu4e-refile-folder . "/nathan@mccarty.io/Archive")
|
||||||
|
(smtpmail-smtp-user . "nathan@mccarty.io"))
|
||||||
|
t))
|
||||||
|
#+end_src
|
||||||
|
Setup our bookmarks, resetting the list of bookmarks first so we can go completely custom
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(setq mu4e-bookmarks '())
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
'(:name "All Mail"
|
||||||
|
:key ?a
|
||||||
|
:query "NOT flag:trashed"))
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
'(:name "Unread Notifications - nathan@mccarty.io"
|
||||||
|
:key ?n
|
||||||
|
:query "maildir:\"/nathan@mccarty.io/Folders/Notifications/\" AND NOT flag:trashed AND flag:unread"))
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
'(:name "Unread Mailing Lists - nathan@mccarty.io"
|
||||||
|
:key ?m
|
||||||
|
:query "maildir:\"/nathan@mccarty.io/Folders/Mailing Lists/\" AND NOT flag:trashed AND flag:unread"))
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
'(:name "Inbox - nathan@mccarty.io"
|
||||||
|
:key ?i
|
||||||
|
:query "maildir:\"/nathan@mccarty.io/Inbox\" AND NOT flag:trashed"))
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
'(:name "Unread"
|
||||||
|
:key ?u
|
||||||
|
:query "flag:unread AND NOT flag:trashed AND NOT maildir:\"/nathan@mccarty.io/Folders/Notifications/\" AND NOT maildir:\"/nathan@mccarty.io/Folders/Mailing Lists/\"")))
|
||||||
|
#+end_src
|
||||||
|
Setup the maildirs we want to see, we'll show our notifications
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(setq mu4e-maildir-shortcuts
|
||||||
|
'((:maildir "/nathan@mccarty.io/Folders/Notifications/Github" :key ?h)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Notifications/Gitlab" :key ?l)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Notifications/SourceHut" :key ?s)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Mailing Lists/Lobsters" :key ?a)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Archival/Receipts/2022" :key ?r)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Job Search" :key ?j)
|
||||||
|
(:maildir "/nathan@mccarty.io/Folders/Archival/Informed Delivery" :key ?i))))
|
||||||
|
#+end_src
|
||||||
|
Tell it to enable the modeline display
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(mu4e-alert-enable-mode-line-display))
|
||||||
|
#+end_src
|
||||||
|
Tell it not to update the mail itself, we have a systemd unit for that
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq +mu4e-backend nil)
|
||||||
|
(after! mu4e
|
||||||
|
(setq mu4e-get-mail-command "systemctl start --user mbsync.service"
|
||||||
|
mu4e-update-interval nil))
|
||||||
|
#+end_src
|
||||||
|
We need to tell mu4e to rename files when they are moved, or else mbsync will break, see [[https://github.com/djcb/mu/issues/613#issuecomment-166714305][issue]] and [[http://tiborsimko.org/mbsync-duplicate-uid.html][blog post]]
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(after! mu4e
|
||||||
|
(setq mu4e-change-filenames-when-moving t))
|
||||||
|
#+end_src
|
|
@ -0,0 +1,102 @@
|
||||||
|
;;; init.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; This file controls what Doom modules are enabled and what order they load
|
||||||
|
;; in. Remember to run 'doom sync' after modifying it!
|
||||||
|
|
||||||
|
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
|
||||||
|
;; documentation. There you'll find a link to Doom's Module Index where all
|
||||||
|
;; of our modules are listed, including what flags they support.
|
||||||
|
|
||||||
|
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
|
||||||
|
;; 'C-c c k' for non-vim users) to view its documentation. This works on
|
||||||
|
;; flags as well (those symbols that start with a plus).
|
||||||
|
;;
|
||||||
|
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
|
||||||
|
;; directory (for easy access to its source code).
|
||||||
|
|
||||||
|
(doom! :completion
|
||||||
|
(company +childframe) ; the ultimate code completion backend
|
||||||
|
(ivy +fuzzy +precient +childframe +icons)
|
||||||
|
|
||||||
|
:ui
|
||||||
|
doom ; what makes DOOM look the way it does
|
||||||
|
doom-dashboard ; a nifty splash screen for Emacs
|
||||||
|
(emoji +unicode) ; 🙂
|
||||||
|
hl-todo ; highlight todo-words
|
||||||
|
indent-guides ; highlighted indent columns
|
||||||
|
modeline ; snazzy, Atom-inspired modeline, plus API
|
||||||
|
nav-flash ; blink cursor line after big motions
|
||||||
|
(popup +defaults) ; tame sudden yet inevitable temporary windows
|
||||||
|
(treemacs +lsp) ; a project drawer, like neotree but cooler
|
||||||
|
unicode ; extended unicode support for various languages
|
||||||
|
window-select ; visually switch windows
|
||||||
|
workspaces ; tab emulation, persistence & separate workspaces
|
||||||
|
zen ; distraction-free coding or writing
|
||||||
|
|
||||||
|
:editor
|
||||||
|
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
|
||||||
|
|
||||||
|
:emacs
|
||||||
|
(dired +icons) ; 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
|
||||||
|
|
||||||
|
:term
|
||||||
|
vterm ; the best terminal emulation in Emacs
|
||||||
|
|
||||||
|
:checkers
|
||||||
|
(syntax +childframe) ; tasing you for every semicolon you forget
|
||||||
|
(spell +aspell +everywhere) ; tasing you for misspelling mispelling
|
||||||
|
|
||||||
|
:tools
|
||||||
|
(debugger +lsp) ; stepping through code, to help you add bugs
|
||||||
|
direnv
|
||||||
|
docker
|
||||||
|
editorconfig ; let someone else argue about tabs vs spaces
|
||||||
|
(eval +overlay) ; run code, run (also, repls)
|
||||||
|
lookup ; navigate your code and its documentation
|
||||||
|
lsp ; M-x vscode
|
||||||
|
(magit +forge) ; a git porcelain for Emacs
|
||||||
|
pdf ; pdf enhancements
|
||||||
|
rgb ; creating color strings
|
||||||
|
|
||||||
|
:os
|
||||||
|
(:if IS-MAC macos) ; improve compatibility with macOS
|
||||||
|
(tty +osc)
|
||||||
|
|
||||||
|
:lang
|
||||||
|
data ; config/data formats
|
||||||
|
emacs-lisp ; drown in parentheses
|
||||||
|
json ; At least it ain't XML
|
||||||
|
(latex +fold) ; writing papers in Emacs has never been so fun
|
||||||
|
markdown ; writing docs for people to ignore
|
||||||
|
nix ; I hereby declare "nix geht mehr!"
|
||||||
|
(org +pandoc +present +roam2 +pomodoro) ; organize your plain life in plain text
|
||||||
|
raku ; the artist formerly known as perl6
|
||||||
|
rest ; Emacs as a REST client
|
||||||
|
(rust +lsp)
|
||||||
|
(sh +fish) ; she sells {ba,z,fi}sh shells on the C xor
|
||||||
|
yaml ; JSON, but readable
|
||||||
|
(kotlin +lsp)
|
||||||
|
(java +lsp +meghanada)
|
||||||
|
(javascript +lsp)
|
||||||
|
|
||||||
|
:email
|
||||||
|
(mu4e +org)
|
||||||
|
|
||||||
|
:app
|
||||||
|
(rss +org) ; emacs as an RSS reader
|
||||||
|
|
||||||
|
:config
|
||||||
|
literate
|
||||||
|
(default +bindings +smartparens))
|
||||||
|
|
||||||
|
(add-hook! 'emacs-startup-hook #'doom-init-ui-h)
|
|
@ -0,0 +1,66 @@
|
||||||
|
;; -*- no-byte-compile: t; -*-
|
||||||
|
;;; $DOOMDIR/packages.el
|
||||||
|
|
||||||
|
;; To install a package with Doom you must declare them here and run 'doom sync'
|
||||||
|
;; on the command line, then restart Emacs for the changes to take effect -- or
|
||||||
|
;; use 'M-x doom/reload'.
|
||||||
|
|
||||||
|
|
||||||
|
;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
|
||||||
|
;(package! some-package)
|
||||||
|
|
||||||
|
;; To install a package directly from a remote git repo, you must specify a
|
||||||
|
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
|
||||||
|
;; https://github.com/raxod502/straight.el#the-recipe-format
|
||||||
|
;(package! another-package
|
||||||
|
; :recipe (:host github :repo "username/repo"))
|
||||||
|
|
||||||
|
;; If the package you are trying to install does not contain a PACKAGENAME.el
|
||||||
|
;; file, or is located in a subdirectory of the repo, you'll need to specify
|
||||||
|
;; `:files' in the `:recipe':
|
||||||
|
;(package! this-package
|
||||||
|
; :recipe (:host github :repo "username/repo"
|
||||||
|
; :files ("some-file.el" "src/lisp/*.el")))
|
||||||
|
|
||||||
|
;; If you'd like to disable a package included with Doom, you can do so here
|
||||||
|
;; with the `:disable' property:
|
||||||
|
;(package! builtin-package :disable t)
|
||||||
|
|
||||||
|
;; You can override the recipe of a built in package without having to specify
|
||||||
|
;; all the properties for `:recipe'. These will inherit the rest of its recipe
|
||||||
|
;; from Doom or MELPA/ELPA/Emacsmirror:
|
||||||
|
;(package! builtin-package :recipe (:nonrecursive t))
|
||||||
|
;(package! builtin-package-2 :recipe (:repo "myfork/package"))
|
||||||
|
|
||||||
|
;; Specify a `:branch' to install a package from a particular branch or tag.
|
||||||
|
;; This is required for some packages whose default branch isn't 'master' (which
|
||||||
|
;; our package manager can't deal with; see raxod502/straight.el#279)
|
||||||
|
;(package! builtin-package :recipe (:branch "develop"))
|
||||||
|
|
||||||
|
;; Use `:pin' to specify a particular commit to install.
|
||||||
|
;(package! builtin-package :pin "1a2b3c4d5e")
|
||||||
|
|
||||||
|
|
||||||
|
;; Doom's packages are pinned to a specific commit and updated from release to
|
||||||
|
;; release. The `unpin!' macro allows you to unpin single packages...
|
||||||
|
;(unpin! pinned-package)
|
||||||
|
;; ...or multiple packages
|
||||||
|
;(unpin! pinned-package another-pinned-package)
|
||||||
|
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
|
||||||
|
;(unpin! t)
|
||||||
|
|
||||||
|
(package! avy)
|
||||||
|
(package! cheatsheet)
|
||||||
|
(package! separedit)
|
||||||
|
(package! magit-delta)
|
||||||
|
(package! crux)
|
||||||
|
(package! string-inflection)
|
||||||
|
(package! smart-hungry-delete)
|
||||||
|
(package! solarized-theme)
|
||||||
|
(package! deadgrep)
|
||||||
|
(package! multi-vterm)
|
||||||
|
(package! grip-mode)
|
||||||
|
(package! org-protocol-capture-html)
|
||||||
|
(package! org-superstar)
|
||||||
|
(package! alert)
|
||||||
|
(package! anki-editor)
|
Loading…
Reference in New Issue