1842 lines
69 KiB
Org Mode
1842 lines
69 KiB
Org Mode
#+PROPERTY: header-args:emacs-lisp :tangle "~/.config/emacs/init.el"
|
||
#+OPTIONS: toc:nil title:nil
|
||
#+EXPORT_FILE_NAME: ~/code/website/src/content/dotfiles/emacs.md
|
||
|
||
#+BEGIN_EXPORT markdown
|
||
+++
|
||
title = "Emacs Configuration"
|
||
author = ["Ian Keane"]
|
||
date = 2023-02-09
|
||
tags = ["Config", "Text editing"]
|
||
description = 'My emacs configuration.'
|
||
+++
|
||
#+END_EXPORT
|
||
|
||
* Preamble
|
||
My emacs configuration. It tangles to =.emacs.d/init.el= and exports to this markdown file on save. If you're viewing this in a repo, it's better to visit the website at <https://iankeane.srht.site/dotfiles>. If you are viewing this on the website and want the repo, you can find it at <https://sr.ht/~iankeane/dotfiles>. To see the hugo front-matter configuration, you'll have to view the raw code.
|
||
|
||
#+TOC: headlines 2
|
||
|
||
* First things first
|
||
** Literate Config Setup
|
||
To get started, run =C-c C-v t=
|
||
#+begin_src emacs-lisp
|
||
(defun dotfiles/org-babel-tangle-config ()
|
||
(when (string-equal (buffer-file-name)
|
||
(expand-file-name "~/.dotfiles/emacs-config.org"))
|
||
(let ((org-confirm-babel-evaluate nil))
|
||
(org-babel-tangle)
|
||
(load-file (expand-file-name "~/.config/emacs/init.el")))))
|
||
|
||
(add-hook 'org-mode-hook
|
||
(lambda ()
|
||
(add-hook 'after-save-hook
|
||
#'dotfiles/org-babel-tangle-config
|
||
nil
|
||
t)))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
| org-appear-mode | org-tempo-setup | yas-minor-mode | #[nil (evil-org-mode) nil] | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-fold-show-all append local] 5] | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-babel-show-result-all append local] 5] | org-babel-result-hide-spec | org-babel-hide-all-hashes | #[0 \301\211\207 [imenu-create-index-function org-imenu-get-tree] 2] | #[nil ((display-line-numbers-mode 0)) nil] | #[nil ((add-hook 'after-save-hook #'dotfiles/org-babel-tangle-config nil t)) nil] |
|
||
|
||
** Package initialization
|
||
=TODO:= savehist mode doesn't seem to save the history correctly
|
||
#+begin_src emacs-lisp
|
||
(require 'package)
|
||
|
||
(setq package-archives
|
||
'(("melpa" . "https://melpa.org/packages/")
|
||
("org" . "https://orgmode.org/elpa/")
|
||
("elpa" . "https://elpa.gnu.org/packages/")))
|
||
(package-initialize)
|
||
|
||
;; Initialize use-package on non-linux platforms
|
||
(unless (package-installed-p 'use-package)
|
||
(package-install 'use-package))
|
||
|
||
(require 'use-package)
|
||
(setq use-package-always-ensure t)
|
||
|
||
(package-refresh-contents)
|
||
|
||
(use-package savehist
|
||
:init
|
||
(savehist-mode))
|
||
#+end_src
|
||
** Paths
|
||
#+begin_src emacs-lisp
|
||
;; (add-to-list 'exec-path "/opt/homebrew/bin")
|
||
;; (setenv "PATH" (concat "/opt/homebrew/bin:" (getenv "PATH")))
|
||
#+end_src
|
||
** Straight
|
||
I don't use straight for much currently, but needed it in order to install beancount-mode and intend to migrate all my packages to it eventually.
|
||
#+begin_src emacs-lisp
|
||
(defvar bootstrap-version)
|
||
(let ((bootstrap-file
|
||
(expand-file-name
|
||
"straight/repos/straight.el/bootstrap.el"
|
||
(or (bound-and-true-p straight-base-dir)
|
||
user-emacs-directory)))
|
||
(bootstrap-version 7))
|
||
(unless (file-exists-p bootstrap-file)
|
||
(with-current-buffer
|
||
(url-retrieve-synchronously
|
||
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
|
||
'silent 'inhibit-cookies)
|
||
(goto-char (point-max))
|
||
(eval-print-last-sexp)))
|
||
(load bootstrap-file nil 'nomessage))
|
||
|
||
(setq package-enable-at-startup nil)
|
||
#+end_src
|
||
** Password Retrieval
|
||
=password-store= integrations require you to have =pass= and =pinentry= configured on your local system outside of emacs.
|
||
#+begin_src emacs-lisp
|
||
(use-package pinentry)
|
||
(use-package pass)
|
||
(use-package password-store)
|
||
(pinentry-start)
|
||
(auth-source-pass-enable)
|
||
#+end_src
|
||
** Variables
|
||
Things referenced throughout the config which are specific to me
|
||
#+begin_src emacs-lisp
|
||
(setq user-init-file (expand-file-name "~/.config/emacs/init.el"))
|
||
|
||
(setq IS-MACOS (eq system-type 'darwin))
|
||
|
||
(setq openai-key-string
|
||
(if IS-MACOS "self/openai-alt" "openai-alt"))
|
||
|
||
(setq gptel-api-key (password-store-get openai-key-string))
|
||
#+end_src
|
||
** Required directories for emacs setup
|
||
Eventually I'll set this up so that all these directories are set in the config of their respective packages; I'll still run ensure-directory on all of them beforehand though.
|
||
#+begin_src emacs-lisp
|
||
(defun ian/ensure-directory (dir)
|
||
"Ceate a dir if it doesn't exist."
|
||
(unless (file-directory-p dir)
|
||
(make-directory dir t)))
|
||
|
||
(ian/ensure-directory "~/.config/emacs/backups/")
|
||
(ian/ensure-directory "~/.config/emacs/autosaves")
|
||
(ian/ensure-directory "~/notes/roam")
|
||
(ian/ensure-directory "~/notes/deft")
|
||
(ian/ensure-directory "~/notes/code")
|
||
(ian/ensure-directory "~/notes/work")
|
||
(ian/ensure-directory "~/.config/emacs/video")
|
||
(ian/ensure-directory "~/.config/emacs/audio")
|
||
|
||
(setq projectile-project-search-path '("~/code/")
|
||
empv-video-dir "~/.config/emacs/video"
|
||
empv-audio-dir "~/.config/emacs/audio"
|
||
backup-directory-alist `(("." . "~/.config/emacs/backups/"))
|
||
auto-save-file-name-transforms `((".*" "~/.config/emacs/autosaves/" t)))
|
||
|
||
;; (projectile-mode)
|
||
#+end_src
|
||
** Helper Functions
|
||
#+begin_src emacs-lisp
|
||
(defun ian/eval-region-or-buffer ()
|
||
"Eval the region if anything is selected, otherwise eval the whole buffer."
|
||
(interactive)
|
||
(if mark-active
|
||
(eval-region (region-beginning) (region-end))
|
||
(eval-buffer)))
|
||
|
||
(defun ian/conditional-imenu ()
|
||
"Call `consult-org-heading` in Org mode, otherwise `consult-imenu`."
|
||
(interactive)
|
||
(if (eq major-mode 'org-mode)
|
||
(consult-org-heading)
|
||
(consult-imenu)))
|
||
|
||
(defun ian/reload-config ()
|
||
"Reload the Emacs configuration."
|
||
(interactive)
|
||
(load-file user-init-file))
|
||
|
||
(defun ian/open-from-project-root (filename)
|
||
"Open a file from the root of the current Projectile project."
|
||
(interactive)
|
||
(find-file (expand-file-name filename (projectile-project-root))))
|
||
#+end_src
|
||
** Evil-want-keybinding
|
||
Setting this in the :init of evil doesn't work for some reason. It has to be early in the file
|
||
=TODO:= find a better solution
|
||
#+begin_src emacs-lisp
|
||
(setq evil-want-keybinding nil)
|
||
#+end_src
|
||
* Basic Appearance and Behaviors
|
||
** Font and Theme
|
||
#+begin_src emacs-lisp
|
||
(use-package doom-themes
|
||
:config
|
||
;; Global settings (defaults)
|
||
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
|
||
doom-themes-enable-italic t) ; if nil, italics is universally disabled
|
||
;; Enable flashing mode-line on errors
|
||
(setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
|
||
(doom-themes-treemacs-config)
|
||
;; Corrects (and improves) org-mode's native fontification.
|
||
(doom-themes-org-config))
|
||
|
||
;; (set-frame-font "DejaVu Sans Mono 16")
|
||
;; (add-to-list 'default-frame-alist
|
||
;; '(font . "Fira Code Mono 16"))
|
||
|
||
(set-face-attribute 'default nil
|
||
:family "FiraCode Nerd Font Mono"
|
||
:height 160)
|
||
|
||
;; (load-theme 'doom-oceanic-next t)
|
||
|
||
(use-package base16-theme)
|
||
(load-theme 'base16-oceanicnext t)
|
||
|
||
(use-package default-text-scale
|
||
:defer 1
|
||
:config
|
||
(default-text-scale-mode))
|
||
#+end_src
|
||
|
||
** Cosmetic
|
||
#+begin_src emacs-lisp
|
||
(setq fancy-splash-image "~/.dotfiles/sink.png") ;; the best emacs logo
|
||
(setq lsp-lens-enable nil) ;; gets rid of the '0 references' note from lsp
|
||
|
||
;; remove visual noise
|
||
(menu-bar-mode -1)
|
||
(tool-bar-mode -1)
|
||
(scroll-bar-mode -1)
|
||
(recentf-mode 1)
|
||
(savehist-mode 1) ; remember previous commands in minibuffer
|
||
(save-place-mode 1) ; put cursor in last place when opening a file
|
||
|
||
(global-display-line-numbers-mode t)
|
||
|
||
(use-package rainbow-delimiters
|
||
:hook (prog-mode . rainbow-delimiters-mode))
|
||
|
||
(use-package solaire-mode
|
||
:config (solaire-global-mode +1))
|
||
|
||
(use-package nerd-icons
|
||
:ensure t
|
||
:config
|
||
(unless (find-font (font-spec :name "Symbols Nerd Font"))
|
||
(nerd-icons-install-fonts t)))
|
||
|
||
(use-package doom-modeline
|
||
:hook (after-init . doom-modeline-mode)
|
||
:config
|
||
(setq doom-modeline-minor-modes t
|
||
doom-modeline-height 24
|
||
nerd-icons-font-family "Symbols Nerd Font Mono")
|
||
(set-face-attribute 'mode-line nil :height 0.9)
|
||
(set-face-attribute 'mode-line-inactive nil :height 0.9))
|
||
|
||
(use-package minions
|
||
:config (minions-mode 1))
|
||
|
||
;; turn off number mode in some contexts
|
||
(dolist (mode
|
||
'(org-mode-hook
|
||
term-mode-hook
|
||
eshell-mode-hook
|
||
treemacs-mode-hook
|
||
vterm-mode-hook
|
||
nov-mode-hook))
|
||
(add-hook mode (lambda () (display-line-numbers-mode 0))))
|
||
(column-number-mode)
|
||
#+end_src
|
||
** Buffers
|
||
=TODO:= Make this use currently selected buffer
|
||
|
||
The base display action tries to reuse an existing window showing the same
|
||
mode or buffer before opening a new one, falling back to the same window.
|
||
This is the default for buffers not covered by =display-buffer-alist= in the
|
||
Popper section. The goal is to avoid gratuitous window splits for ordinary
|
||
buffer switching — splits should be intentional.
|
||
|
||
#+begin_src emacs-lisp
|
||
;; Generate buffers in last window
|
||
(setq display-buffer-base-action
|
||
'(display-buffer-reuse-mode-window
|
||
display-buffer-reuse-window
|
||
display-buffer-same-window))
|
||
#+end_src
|
||
** Behavioral Tweaks
|
||
#+begin_src emacs-lisp
|
||
|
||
(setq ring-bell-function 'ignore)
|
||
|
||
(when IS-MACOS
|
||
(setq mac-pass-command-to-system nil))
|
||
|
||
;; Avoid customization UI auto-variables in init.el
|
||
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
|
||
(load custom-file 'noerror 'nomessage)
|
||
|
||
;; Don't show popup UI when prompting
|
||
(setq use-dialog-box nil)
|
||
|
||
;; Update files when changed on disk
|
||
(global-auto-revert-mode 1)
|
||
|
||
(use-package helpful
|
||
:ensure t
|
||
:bind
|
||
([remap describe-function] . helpful-callable)
|
||
([remap describe-variable] . helpful-variable)
|
||
([remap describe-key] . helpful-key)
|
||
([remap describe-command] . helpful-command))
|
||
|
||
;; If a popup does happen, don't resize windows to be equal-sized
|
||
(setq even-window-sizes nil)
|
||
(setq whitespace-style '(trailing tabs newline tab-mark )) ; show tab characters
|
||
(setq tab-always-indent 'complete)
|
||
(setq tab-first-completion 'word)
|
||
(setq indent-tabs-mode nil) ; tabs not spaces
|
||
|
||
(visual-line-mode) ; wrap long lines visually
|
||
(whitespace-mode)
|
||
(setq-default indent-tabs-mode nil)
|
||
#+end_src
|
||
** Tab bar
|
||
#+begin_src emacs-lisp
|
||
(use-package tab-bar-echo-area
|
||
:ensure
|
||
:config
|
||
(tab-bar-echo-area-mode 1)
|
||
(setq tab-bar-show nil))
|
||
#+end_src
|
||
** Tabspaces
|
||
Buffers, and much of buffer-selection UI (=consult-buffer=, ibuffer, etc.),
|
||
are scoped per tab via =tabspaces=. Each tab gets its own isolated buffer
|
||
list, similar to workspaces in other editors — switching tabs only shows you
|
||
the buffers relevant to that tab.
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package tabspaces
|
||
:ensure t
|
||
:hook (after-init . tabspaces-mode)
|
||
:commands (tabspaces-switch-or-create-workspace
|
||
tabspaces-open-or-create-project-and-workspace)
|
||
:config
|
||
(setq tabspaces-use-filtered-buffers-as-default t)
|
||
(setq tabspaces-default-tab "Default")
|
||
(setq tabspaces-remove-to-default t)
|
||
(setq tabspaces-include-buffers '("*scratch*"))
|
||
;; Keep consult-buffer scoped to the current tab's buffer list.
|
||
;; tabspaces doesn't ship a consult source itself, so define one here
|
||
;; using its own buffer-list function, and put it ahead of consult's
|
||
;; default (unfiltered) buffer source.
|
||
(with-eval-after-load 'consult
|
||
(defvar consult--source-tabspaces
|
||
`(:name "Workspace Buffers"
|
||
:narrow ?w
|
||
:category buffer
|
||
:face consult-buffer
|
||
:history buffer-name-history
|
||
:state ,#'consult--buffer-state
|
||
:items ,(lambda () (mapcar #'buffer-name (tabspaces--buffer-list)))))
|
||
(consult-customize consult--source-buffer :hidden t :default nil)
|
||
(add-to-list 'consult-buffer-sources 'consult--source-tabspaces)))
|
||
#+end_src
|
||
* Evil
|
||
#+begin_src emacs-lisp
|
||
(use-package evil
|
||
:ensure t
|
||
:config
|
||
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
|
||
(define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line)
|
||
(define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line)
|
||
(define-key evil-normal-state-map (kbd "ghp") 'git-gutter-previous-hunk)
|
||
(define-key evil-normal-state-map (kbd "ghn") 'git-gutter-next-hunk)
|
||
(define-key evil-normal-state-map (kbd "ghr") 'git-gutter-revert-hunk)
|
||
(define-key evil-normal-state-map (kbd "ghs") 'git-gutter-popup-hunk)
|
||
(define-key evil-normal-state-map (kbd "ghS") 'git-gutter-stage-hunk)
|
||
(define-key evil-normal-state-map (kbd "gp") nil)
|
||
(define-key evil-normal-state-map (kbd "gpn") 'popper-cycle)
|
||
(define-key evil-normal-state-map (kbd "gpp") 'popper-cycle-backwards)
|
||
(define-key evil-normal-state-map (kbd "gpq") 'popper-kill-latest-popup)
|
||
(define-key evil-normal-state-map (kbd "gpt") 'popper-toggle-type)
|
||
(define-key evil-normal-state-map (kbd "gbn") 'projectile-next-project-buffer)
|
||
(define-key evil-normal-state-map (kbd "gbp") 'projectile-previous-project-buffer)
|
||
(evil-mode 1))
|
||
|
||
(use-package undo-tree
|
||
:ensure t
|
||
:after evil
|
||
:diminish
|
||
:config
|
||
(evil-set-undo-system 'undo-tree)
|
||
(setq undo-tree-history-directory-alist '(("." . "~/.config/emacs/undo")))
|
||
(global-undo-tree-mode 1))
|
||
|
||
|
||
(use-package evil-org
|
||
:ensure t
|
||
:after org
|
||
:hook (org-mode . (lambda () evil-org-mode)))
|
||
|
||
|
||
(use-package evil-collection
|
||
:after evil
|
||
:ensure t
|
||
:diminish evil-collection-unimpaired-mode
|
||
:init
|
||
:config
|
||
(setq evil-respect-visual-line-mode t)
|
||
(setq evil-collection-repl-submit-state 'insert)
|
||
(evil-collection-init))
|
||
|
||
|
||
(use-package evil-commentary
|
||
:config
|
||
(evil-commentary-mode))
|
||
#+end_src
|
||
* Navigation
|
||
** Helper Functions
|
||
#+begin_src emacs-lisp
|
||
(defun split-and-follow-horizontally ()
|
||
(interactive)
|
||
(split-window-below)
|
||
(balance-windows)
|
||
(other-window 1))
|
||
|
||
(defun split-and-follow-vertically ()
|
||
(interactive)
|
||
(split-window-right)
|
||
(balance-windows)
|
||
(other-window 1))
|
||
#+end_src
|
||
** Windows and Workspaces
|
||
[[https://github.com/abo-abo/ace-window/issues/216][Credit]] for manual dispatch function.
|
||
|
||
General window management uses =ace-window= for jumping and splitting, with
|
||
=winner-mode= for undo/redo of window layouts. The philosophy here is to keep
|
||
manual window control lightweight — ace-window covers most navigation needs
|
||
with single keypresses, and winner catches mistakes. Workspaces are handled
|
||
at the tab level rather than with a dedicated workspace package.
|
||
|
||
- =SPC w= jumps to a window by label
|
||
- =SPC W= opens the full ace-window dispatch menu for splits, swaps, etc.
|
||
- =C-c <left>= / =C-c <right>= undo/redo window layouts via winner
|
||
|
||
=TODO:= Window width controls
|
||
#+begin_src emacs-lisp
|
||
(use-package winner
|
||
:after evil
|
||
:config
|
||
(winner-mode))
|
||
|
||
(use-package ace-window)
|
||
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
|
||
(setq aw-dispatch-alist
|
||
'(
|
||
(?x aw-delete-window "Delete Window")
|
||
(?m aw-swap-window "Swap Windows")
|
||
(?M aw-move-window "Move Window")
|
||
;; (?c aw-copy-window "Copy Window")
|
||
;; (?j aw-switch-buffer-in-window "Select Buffer")
|
||
;; (?n aw-flip-window)
|
||
;; ;;
|
||
(?b aw-switch-buffer-other-window "Switch Buffer Other Window")
|
||
(?u winner-undo)
|
||
(?U winner-redo)
|
||
(?c aw-split-window-fair "Split Fair Window")
|
||
(?v aw-split-window-vert "Split Vert Window")
|
||
(?H aw-split-window-horz "Split Horz Window")
|
||
(?o delete-other-windows "Delete Other Windows")
|
||
(?? aw-show-dispatch-help)))
|
||
(setq aw-scope 'frame)
|
||
|
||
(defun ace-window-manual-dispatch (arg)
|
||
"Calls `ace-window' with ARG asking for the dispatch, even if `aw-dispatch-always' is nil.
|
||
This could be useful to use the advanced commands"
|
||
(interactive "p")
|
||
(let ((aw-dispatch-always t))
|
||
(ace-window arg)
|
||
))
|
||
#+end_src
|
||
|
||
*** StumpWM-aware window navigation
|
||
=s-h/j/k/l= (mod+hjkl) move between Emacs windows using =windmove=. When
|
||
there's no further Emacs window in that direction (i.e. we're at the edge of
|
||
Emacs's frame), the command instead shells out to StumpWM via =stumpish= to
|
||
move focus to the next tiled frame in that direction — so navigation flows
|
||
seamlessly out of Emacs and into the rest of the WM using the same keys
|
||
StumpWM itself binds to =s-h/j/k/l=.
|
||
|
||
#+begin_src emacs-lisp
|
||
(defvar stumpwm-stumpish-path
|
||
(expand-file-name "~/.stumpwm.d/modules/util/stumpish/stumpish")
|
||
"Path to the stumpish binary used to talk to a running StumpWM.")
|
||
|
||
(defun stumpwm-move-focus (direction)
|
||
"Ask StumpWM to move focus to the frame in DIRECTION (\"left\" \"right\" \"up\" \"down\").
|
||
No-op on macOS (or anywhere StumpWM isn't running/available)."
|
||
(when (and (not IS-MACOS)
|
||
(file-executable-p stumpwm-stumpish-path))
|
||
(call-process stumpwm-stumpish-path nil nil nil
|
||
(concat "move-focus " direction))))
|
||
|
||
(defun stumpwm-windmove-or-escape (windmove-fn direction)
|
||
"Call WINDMOVE-FN; if it errors (no Emacs window in DIRECTION),
|
||
fall through to StumpWM and move focus to the next tiled frame there."
|
||
(condition-case nil
|
||
(funcall windmove-fn)
|
||
(error (stumpwm-move-focus direction))))
|
||
|
||
(defun stumpwm-windmove-left () (interactive) (stumpwm-windmove-or-escape #'windmove-left "left"))
|
||
(defun stumpwm-windmove-right () (interactive) (stumpwm-windmove-or-escape #'windmove-right "right"))
|
||
(defun stumpwm-windmove-up () (interactive) (stumpwm-windmove-or-escape #'windmove-up "up"))
|
||
(defun stumpwm-windmove-down () (interactive) (stumpwm-windmove-or-escape #'windmove-down "down"))
|
||
|
||
(global-set-key (kbd "s-h") #'stumpwm-windmove-left)
|
||
(global-set-key (kbd "s-j") #'stumpwm-windmove-down)
|
||
(global-set-key (kbd "s-k") #'stumpwm-windmove-up)
|
||
(global-set-key (kbd "s-l") #'stumpwm-windmove-right)
|
||
#+end_src
|
||
** Popper
|
||
Transient/popup buffers — terminals, help, compilation, messages — are managed
|
||
by popper, which tracks them as a group and lets you cycle or dismiss them
|
||
together. Popper's display control is enabled, meaning it defers to
|
||
=display-buffer-alist= (below) for the actual placement logic rather than
|
||
using its own defaults. Buffers are grouped by projectile project so popup
|
||
state is workspace-local.
|
||
|
||
- Popper decides /what/ is a popup
|
||
- =display-buffer-alist= decides /where/ it goes
|
||
- Terminals always go to the bottom
|
||
- Help and compilation go to the bottom unless the window is too narrow (<65
|
||
columns), in which case they replace the current buffer instead
|
||
- Messages appear at the bottom without stealing focus
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package popper
|
||
:after projectile
|
||
:init
|
||
(setq popper-reference-buffers
|
||
'(("\\*Messages\\*" . hide)
|
||
"\\*Error\\*"
|
||
"Output\\*$"
|
||
("\\*Warnings\\*" . hide)
|
||
"\\*scratch\\*"
|
||
"\\*Async Shell Command\\*"
|
||
"^\\*eshell.*\\*$" eshell-mode
|
||
"^\\*shell.*\\*$" shell-mode
|
||
"^\\*term.*\\*$" term-mode
|
||
"^\\*vterm.*\\*$" vterm-mode
|
||
helpful-mode
|
||
help-mode
|
||
compilation-mode
|
||
inferior-python-mode
|
||
consult-flymake-mode))
|
||
:config
|
||
(setq popper-display-control t)
|
||
(setq popper-group-function #'popper-group-by-projectile)
|
||
(popper-mode +1)
|
||
(popper-echo-mode +1))
|
||
|
||
;; display-buffer-alist rules (replaces shackle)
|
||
(setq display-buffer-alist
|
||
`(;; Help buffers: bottom split, fall back to same window if narrow
|
||
((or (derived-mode . help-mode)
|
||
(derived-mode . helpful-mode))
|
||
(display-buffer-reuse-window
|
||
,(lambda (buf alist)
|
||
(when (< (window-width) 65)
|
||
(display-buffer-same-window buf alist)))
|
||
display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(slot . 0)
|
||
(window-height . 0.35)
|
||
(select . t))
|
||
|
||
;; Compilation: bottom split
|
||
((derived-mode . compilation-mode)
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(slot . 1)
|
||
(window-height . 0.35)
|
||
(select . t))
|
||
|
||
;; Messages: bottom, no focus steal
|
||
("\\*Messages\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(slot . 2)
|
||
(window-height . 0.25)
|
||
(select . nil))
|
||
|
||
;; Terminals: always bottom
|
||
((or "^\\*eshell.*\\*$"
|
||
"^\\*shell.*\\*$"
|
||
"^\\*term.*\\*$"
|
||
"^\\*vterm.*\\*$")
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(slot . 3)
|
||
(window-height . 0.35)
|
||
(select . t))))
|
||
#+end_src
|
||
** Dired
|
||
#+begin_src emacs-lisp
|
||
(setq dired-listing-switches "-alh --group-directories-first")
|
||
|
||
;; opening 'other window' on a subdir enters 2 window dired mode for copy/paste
|
||
(setq dired-dwim-target t)
|
||
|
||
;; refresh dired buffers automatically after file operations
|
||
(setq dired-auto-revert-buffer t)
|
||
(add-hook 'dired-mode-hook 'dired-hide-details-mode)
|
||
|
||
(use-package dired-open
|
||
:config
|
||
(setq dired-open-extensions '(("png" . "nsxiv")
|
||
("mkv" . "mpv")
|
||
("avi" . "mpv"))))
|
||
|
||
(use-package nerd-icons-dired
|
||
:hook (dired-mode . nerd-icons-dired-mode))
|
||
|
||
;; Reuse dired buffer when navigating directories
|
||
(put 'dired-find-alternate-file 'disabled nil)
|
||
(with-eval-after-load 'dired
|
||
(evil-collection-define-key 'normal 'dired-mode-map
|
||
(kbd "RET") 'dired-find-alternate-file
|
||
(kbd "^") 'dired-up-directory))
|
||
#+end_src
|
||
|
||
** Treemacs
|
||
#+begin_src emacs-lisp
|
||
(use-package treemacs
|
||
:config
|
||
(setq treemacs-width 45))
|
||
|
||
;; Follow project buffers instantly
|
||
(setq treemacs--project-follow-delay 0)
|
||
|
||
(defun ian/treemacs-open-current-or-jump ()
|
||
"Find the current file and open treemacs if it's not open, otherwise jump
|
||
to the treemacs window"
|
||
(interactive)
|
||
(if
|
||
(not(eq (treemacs-current-visibility) 'visible))
|
||
(treemacs-find-file))
|
||
(treemacs-select-window))
|
||
|
||
(use-package all-the-icons)
|
||
(use-package treemacs-all-the-icons)
|
||
(use-package treemacs-evil)
|
||
|
||
#+end_src
|
||
** Which-key
|
||
#+begin_src emacs-lisp
|
||
(use-package which-key
|
||
:ensure nil
|
||
:init (which-key-mode)
|
||
:diminish which-key-mode
|
||
:config
|
||
(setq which-key-idle-delay 0.3
|
||
which-key-add-column-padding 1
|
||
which-key-max-description-length 32
|
||
which-key-min-column-description-width 20))
|
||
#+end_src
|
||
** General
|
||
I know these could be bound on a per-package basis, but since this is my primary interface with emacs I'd rather keep all keymaps in one place, both for reference and to discourage myself from organizing my top-level bindings on a per-plugin basis rather than keeping the focus on functionality.
|
||
=TODO:=
|
||
- bind lispy for colemak-dh
|
||
- bind lispy doc features and ide-like features
|
||
- bind embark
|
||
#+begin_src emacs-lisp
|
||
(use-package general
|
||
:ensure t
|
||
:after nov evil evil-collection treemacs
|
||
:config
|
||
|
||
(general-create-definer general-definition
|
||
;; :keymaps '(normal insert visual emacs nov-mode-map nov-button-map dired-mode-map)
|
||
:states '(normal visual symex)
|
||
:keymaps 'override
|
||
:prefix "SPC"
|
||
:global-prefix "C-SPC")
|
||
|
||
(general-definition
|
||
|
||
;; Top level bindings
|
||
"SPC" '(projectile-find-file :which-key "Find project file")
|
||
"<backspace>" '(ian/treemacs-open-current-or-jump :which-key "Find current file in sidebar")
|
||
"TAB" '(popper-toggle :which-key "Toggle popup")
|
||
"," '(projectile-ibuffer :which-key "Buffers (workspace)")
|
||
"/" '(consult-ripgrep :which-key "Search project")
|
||
":" '(execute-extended-command :which-key "M-x")
|
||
";" '(eval-expression :which-key "Eval")
|
||
"<" '(consult-buffer :which-key "Buffers (all)")
|
||
"-" '(dired-jump :which-key "Find Directory")
|
||
"d" '(docker :which-key "Docker")
|
||
"i" '(ian/conditional-imenu :which-key "Imenu")
|
||
"w" '(ace-window :which-key "Window")
|
||
"W" '(ace-window-manual-dispatch :which-key "Window (dispatch)")
|
||
|
||
;; Agenda
|
||
"a" '(:ignore t :which-key "Agenda")
|
||
"aa" '(org-agenda :which-key "Open Agenda")
|
||
"a/" '(consult-org-agenda :which-key "Search agenda headlines")
|
||
|
||
"ac" '(:ignore t :which-key "Clock")
|
||
"acc" '(org-clock-goto :which-key "Active clock")
|
||
"ack" '(org-clock-cancel :which-key "Cancel current clock")
|
||
"act" '(+org/toggle-last-clock :which-key "Toggle last clock")
|
||
|
||
|
||
;; Buffers / bookmarks
|
||
"b" '(:ignore t :which-key "Buffers")
|
||
"bb" '(consult-bookmark :which-key "Goto Bookmark") ;; consult-bookmark
|
||
"bk" '(kill-current-buffer :which-key "Kill buffer")
|
||
"bm" '(bookmark-set :which-key "Set bookmark")
|
||
"bM" '(bookmark-delete :which-key "Delete bookmark")
|
||
;; "bo" '(NEEDS CUSTOM FUNCTION :which-key "Kill other buffers")
|
||
"br" '(revert-buffer :which-key "Revert buffer")
|
||
"bR" '(rename-buffer :which-key "Rename buffer")
|
||
"bz" '(bury-buffer :which-key "Bury buffer")
|
||
;; "bZ" '(NEEDS CUSTOM FUNCTION :which-key "Kill buried buffers")
|
||
"bj" '(+ivy/jump-list :which-key "Jump list")
|
||
"bu" '(vundo :which-key "Undo history")
|
||
|
||
;; Code
|
||
"c" '(:ignore t :which-key "Code")
|
||
"cc" '(compile :which-key "Compile")
|
||
"cC" '(recompile :which-key "Recompile")
|
||
"cd" '(+lookup/definition :which-key "Goto definition")
|
||
"cr" '(+lookup/references :which-key "Goto references")
|
||
"ce" '(ian/eval-region-or-buffer :which-key "Eval buffer/region")
|
||
"cE" '(consult-flymake :which-key "Errors")
|
||
;; "cf" '(NOT A COMMAND (re-do) :which-key "Format buffer/region")
|
||
"ci" '(+lookup/implementations :which-key "Find implementations")
|
||
"cj" '(lsp-ivy-workspace-symbol :which-key "Goto symbol (curr. workspace)")
|
||
"cJ" '(lsp-ivy-global-workspace-symbol :which-key "Goto symbol (any workspace)")
|
||
"ck" '(+lookup/documentation :which-key "Jump to documentation")
|
||
"cl" '(+default/lsp-command-map :which-key "LSP")
|
||
"co" '(lsp-organize-imports :which-key "LSP organize imports")
|
||
"cp" '(completion-at-point :which-key "Completion at point")
|
||
"cR" '(lsp-rename :which-key "LSP rename")
|
||
"cs" '(+eval/send-region-to-repl :which-key "Send to repl")
|
||
"ct" '(+lookup/type-definition :which-key "Find type definition")
|
||
"cw" '(delete-trailing-whitespace :which-key "Delete trailing whitespace")
|
||
;; "cn" '(doom/delete-trailing-newlines :which-key "Delete trailing newlines")
|
||
"cx" '(consult-lsp-diagnostics :which-key "List errors")
|
||
|
||
;; File
|
||
"f" '(:ignore t :which-key "File")
|
||
;; "fp" '(doom/open-private-config :which-key "Browse private config")
|
||
"fr" '(projectile-recentf :which-key "Recent files")
|
||
"fR" '(consult-recent-file :which-key "Recent files")
|
||
"fc" '(ian/reload-config :which-key "Reload config")
|
||
;; "fm" '(doom/move-this-file :which-key "Move/rename file")
|
||
;; "fS" '(doom/sudo-find-file :which-key "Sudo find file")
|
||
;; "fs" '(doom/sudo-this-file :which-key "Sudo this file")
|
||
"fy" '(+default/yank-buffer-path :which-key "yank file path")
|
||
"fY" '(+default/yank-buffer-path-relative-to-project :which-key "Yank file path from project")
|
||
|
||
;; Git
|
||
"g" '(:ignore t :which-key "git")
|
||
"gb" '(magit-branch-checkout :which-key "magit switch branch")
|
||
"gB" '(magit-blame-addition :which-key "magit blame")
|
||
"gF" '(magit-fetch :which-key "magit fetch")
|
||
"gg" '(magit-status :which-key "magit status")
|
||
"gG" '(magit-status-here :which-key "magit status here")
|
||
"gL" '(magit-log-buffer-file :which-key "magit buffer log")
|
||
"gt" '(git-timemachine-toggle :which-key "git time machine")
|
||
"g/" '(consult-git-log-grep :which-key "Search git log")
|
||
"gd" '(:ignore t :which-key "dispatch")
|
||
"gdF" '(forge-dispatch :which-key "Forge dispatch")
|
||
"gdd" '(magit-dispatch :which-key "Magit dispatch")
|
||
"gdf" '(magit-file-dispatch :which-key "Magit file dispatch")
|
||
|
||
"gf" '(:ignore t :which-key "find")
|
||
"gfc" '(magit-show-commit :which-key "find commit")
|
||
"gff" '(magit-find-file :which-key "find file")
|
||
"gfg" '(magit-find-git-config-file :which-key "find gitconfig file")
|
||
"gfi" '(forge-visit-issue :which-key "find issue")
|
||
"gfp" '(forge-visit-pullreq :which-key "find pull request")
|
||
|
||
"gh" '(:ignore t :which-key "hunk")
|
||
|
||
"ghn" '(git-gutter-previous-hunk :which-key "jump to previous hunk")
|
||
"ghp" '(git-gutter-next-hunk :which-key "jump to next hunk")
|
||
"ghr" '(git-gutter-revert-hunk :which-key "revert hunk at point")
|
||
"ghs" '(git-gutter-popup-hunk :which-key "show hunk")
|
||
"ghS" '(git-gutter-stage-hunk :which-key "stage hunk at point")
|
||
|
||
"gl" '(:ignore t :which-key "list")
|
||
"gli" '(forge-list-issues :which-key "list issues")
|
||
"gln" '(forge-list-notifications :which-key "list notifications")
|
||
"glp" '(forge-list-pullreqs :which-key "list pull requests")
|
||
"glr" '(forge-list-issues :which-key "list repositories")
|
||
"gls" '(magit-list-submodules :which-key "list submodules")
|
||
|
||
"go" '(:ignore t :which-key "open")
|
||
"goI" '(forge-browse-issues :which-key "Browse issues")
|
||
"goP" '(forge-browse-pullreqs :which-key "Browse pull requests")
|
||
"goc" '(forge-browse-commit :which-key "Browse commit")
|
||
"goh" '(+vc/browse-at-remote-homepage :which-key "Browse homepage")
|
||
"goi" '(forge-browse-issue :which-key "Browse an issue")
|
||
"goo" '(+vc/browse-at-remote :which-key "Browse file or region")
|
||
"gop" '(forge-browse-pullreq :which-key "Browse a pull request")
|
||
"gor" '(forge-browse-remote :which-key "Browse remote")
|
||
|
||
;; Help
|
||
"h" '(:ignore t :which-key "help")
|
||
"h<return>" '(info-emacs-manual :which-key "Emacs manual")
|
||
"h'" '(describe-char :which-key "Describe character")
|
||
"ha" '(apropos :which-key "Apropos")
|
||
"hb" '(embark-bindings :which-key "Describe bindings")
|
||
"he" '(view-echo-area-messages :which-key "View echo area messages")
|
||
"hf" '(helpful-function :which-key "Describe function")
|
||
"hi" '(info :which-key "Info")
|
||
"hk" '(helpful-key :which-key "Describe key")
|
||
"hm" '(describe-mode :which-key "Describe mode")
|
||
"ho" '(helpful-symbol :which-key "Describe symbol")
|
||
"hp" '(explain-pause-top :which-key "Processes")
|
||
"hs" '(yas-describe-tables :which-key "Describe symbol")
|
||
"hv" '(helpful-variable :which-key "Describe variable")
|
||
"hx" '(helpful-command :which-key "Describe command")
|
||
"hA" '(apropos-documentation :which-key "Apropos(documentation)")
|
||
"hF" '(describe-face :which-key "Describe Face")
|
||
"hM" '(popwin:messages :which-key "View system messages")
|
||
|
||
"hw" '(:ignore t :which-key "which-key")
|
||
"hwf" '(which-key-show-full-keymap :which-key "Full keymap")
|
||
"hwi" '(which-key-show-minor-mode-keymap :which-key "Minor mode keymap")
|
||
"hwk" '(which-key-show-keymap :which-key "Show keymap")
|
||
"hwm" '(which-key-show-major-mode :which-key "Show major mode")
|
||
"hwt" '(which-key-show-top-level :which-key "Show top-level")
|
||
|
||
"m" '(:ignore t :which-key "media")
|
||
"my" '(empv-youtube :which-key "youtube")
|
||
"mt" '(empv-toggle :which-key "toggle")
|
||
"mT" '(empv-toggle-video :which-key "toggle-video")
|
||
"mq" '(empv-exit :which-key "quit")
|
||
"ms" '(empv-display-current :which-key "show currently playing")
|
||
|
||
"mr" '(:ignore t :which-key "radio")
|
||
"mrr" '(empv-play-radio :which-key "play")
|
||
"mrR" '(empv-play-random-channel :which-key "play random")
|
||
"mrl" '(empv-log-current-radio-song-name :which-key "log song name")
|
||
|
||
"mp" '(:ignore t :which-key "playlist")
|
||
"mpP" '(empv-playlist :which-key "playlist")
|
||
"mps" '(empv-playlist-select :which-key "select")
|
||
"mpn" '(empv-playlist-next :which-key "next")
|
||
"mpp" '(empv-playlist-prev :which-key "prev")
|
||
"mpc" '(empv-playlist-clear :which-key "clear")
|
||
"mpS" '(empv-playlist-shuffle :which-key "shuffle")
|
||
|
||
"mf" '(:ignore t :which-key "file")
|
||
"mff" '(empv-play-file :which-key "play file")
|
||
"mfd" '(empv-play-directory :which-key "play directory")
|
||
|
||
"mv" '(:ignore t :which-key "volume")
|
||
"mvd" '(empv-volume-down :which-key "down")
|
||
"mvu" '(empv-volume-up :which-key "up")
|
||
|
||
"mc" '(:ignore t :which-key "chapter")
|
||
"mcp" '(empv-chapter-prev :which-key "prev")
|
||
"mcn" '(empv-chapter-next :which-key "next")
|
||
"mcs" '(empv-chapter-select :which-key "select")
|
||
|
||
;; Notes
|
||
"nd" '(deft :which-key "Deft")
|
||
"nt" '(org-todo-list :which-key "Todo list")
|
||
"nf" '(org-roam-node-find :which-key "Find node")
|
||
"ng" '(org-roam-ui-open :which-key "Show graph")
|
||
"nr" '(org-roam-buffer-toggle :which-key "Toggle roam buffer")
|
||
"nb" '(org-roam-buffer-display-dedicated :which-key "Launch roam buffer")
|
||
"ns" '(org-roam-db-sync :which-key "Sync database")
|
||
"nc" '(org-roam-capture :which-key "Capture to node")
|
||
"ni" '(org-roam-node-insert :which-key "Insert node at point")
|
||
|
||
;; Org mode
|
||
"o" '(:ignore t :which-key "org")
|
||
"ol" '(org-store-link :which-key "Store link")
|
||
"oC" '(org-capture-goto-target :which-key "Goto Capture")
|
||
"oo" '(org-open-at-point :which-key "Open link")
|
||
"ot" '(org-babel-tangle :which-key "Tangle")
|
||
"oy" '(+org/export-to-clipboard :which-key "Export to clipboard")
|
||
"oY" '(+org/export-to-clipboard-as-rich-text :which-key "Export to clipboard (rich)")
|
||
"oc" '(:ignore t :which-key "Capture")
|
||
"ocn" '(ian/capture-to-notes-org :which-key "Capture to local notes")
|
||
"oct" '(ian/capture-to-todo-org :which-key "Capture to local todo")
|
||
"oe" '(:ignore t :which-key "export")
|
||
"oeh" '(org-html-export-to-html :which-key "Export Org to HTML")
|
||
"oa" '(:ignore t :which-key "attach")
|
||
"oaa" '(org-attach :which-key "Attach")
|
||
"oac" '(org-download-clipboard :which-key "Org download clipboard")
|
||
"oad" '(org-attach-delete-one :which-key "Delete one attachment")
|
||
"oaD" '(org-attach-delete-all :which-key "Delete all attachments")
|
||
"oas" '(org-attach-sync :which-key "Sync attachments")
|
||
"oay" '(org-download-yank :which-key "Org download yank")
|
||
|
||
;; Project
|
||
"p" '(:ignore t :which-key "project")
|
||
"ps" '(+neotree/open :which-key "Open project sidebar")
|
||
"pa" '(projectile-add-known-project :which-key "Add new project")
|
||
"pc" '(+ivy/project-compile :which-key "Compile in project")
|
||
"pd" '(projectile-remove-known-project :which-key "Remove known project")
|
||
"ps" '(projectile-switch-project :which-key "Switch projects")
|
||
"pC" '(projectile-configure-project :which-key "Configure project")
|
||
"pr" '(projectile-run-project :which-key "Run project")
|
||
"pt" '(magit-todos-list :which-key "List project todos")
|
||
"pT" '(projectile-test-project :which-key "Test project")
|
||
"pz" '(+taskrunner/project-tasks :which-key "List project tasks")
|
||
|
||
;; Reference buffers
|
||
"r" '(:ignore t :which-key "reference buffers")
|
||
"rs" '(scratch-buffer :which-key "Scratch")
|
||
"rm" '(view-echo-area-messages :which-key "Messages")
|
||
"rc" '(view-lossage :which-key "Commands History")
|
||
"rn" '((lambda () (interactive) (ian/open-from-project-root "notes.org")) :which-key "Notes")
|
||
"rt" '((lambda () (interactive) (ian/open-from-project-root "todo.org")) :which-key "Todo")
|
||
"rl" '((lambda () (interactive) (find-file "~/notes/work/time.org")) :which-key "Time Log")
|
||
|
||
;; Shell
|
||
"s" '(:ignore t :which-key "shell")
|
||
"se" '(+eshell/toggle :which-key "Toggle eshell popup")
|
||
"sE" '(+eshell/here :which-key "Open eshell here")
|
||
"sr" '(+eval/open-repl-other-window :which-key "Repl")
|
||
"st" '(+vterm/toggle :which-key "Toggle vterm popup")
|
||
"sT" '(+vterm/here :which-key "Open vterm here")
|
||
|
||
;; Toggle
|
||
"t" '(:ignore t :which-key "toggle")
|
||
"tc" '(global-display-fill-column-indicator-mode :which-key "Fill Column Indicator")
|
||
"tf" '(flycheck-mode :which-key "Flycheck")
|
||
"tm" '(consult-minor-mode-menu :which-key "Minor modes")
|
||
"tp" '(org-tree-slide-mode :which-key "Org-tree-slide-mode")
|
||
"tw" '(+word-wrap-mode :which-key "Soft line wrapping")
|
||
"tz" '(+zen/toggle :which-key "Zen mode")
|
||
;; "tl" '(doom/toggle-line-numbers :which-key "Line numbers")
|
||
|
||
;; Visual / appearance
|
||
"v" '(:ignore t :which-key "visual/appearance")
|
||
"vt" '(load-theme :which-key "load theme")
|
||
|
||
))
|
||
#+end_src
|
||
|
||
* Notes
|
||
#+begin_src emacs-lisp
|
||
(use-package deft)
|
||
(setq deft-recursive t
|
||
deft-extensions '("org" "txt"))
|
||
#+end_src
|
||
* AI
|
||
#+begin_src emacs-lisp
|
||
(use-package gptel)
|
||
(setq gptl-default-mode 'org-mode)
|
||
#+end_src
|
||
* Org Mode
|
||
#+begin_src emacs-lisp
|
||
(use-package org)
|
||
|
||
(add-hook 'org-mode-hook 'yas-minor-mode)
|
||
|
||
(org-babel-do-load-languages
|
||
'org-babel-load-languages
|
||
'((emacs-lisp . t)
|
||
(python . t)))
|
||
|
||
(setq org-confirm-babel-evaluate nil)
|
||
|
||
(require 'org-tempo)
|
||
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
|
||
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
|
||
|
||
(add-to-list 'org-structure-template-alist '("py" . "src python"))
|
||
|
||
(setq org-hide-emphasis-markers t)
|
||
|
||
(use-package org-appear
|
||
:hook (org-mode . org-appear-mode))
|
||
|
||
(use-package org-roam
|
||
:custom
|
||
(org-roam-directory "~/notes/roam")
|
||
:config
|
||
(org-roam-db-autosync-mode)
|
||
(setq org-link-frame-setup '((file . find-file))))
|
||
|
||
(use-package deft
|
||
:commands (deft)
|
||
:config
|
||
(setq deft-directory "~/notes/deft"
|
||
deft-extensions '("org" "txt")
|
||
deft-recursive t))
|
||
|
||
(use-package ox-hugo
|
||
:after ox)
|
||
|
||
(use-package org-roam-ui
|
||
:after org-roam
|
||
:config
|
||
(setq org-roam-ui-sync-theme t
|
||
org-roam-ui-follow t
|
||
org-roam-ui-update-on-save t
|
||
org-roam-ui-open-on-start t))
|
||
|
||
(use-package ox-gfm) ; github-flavored-markdown exporter
|
||
|
||
(use-package org-download)
|
||
|
||
#+end_src
|
||
** Agenda
|
||
#+begin_src emacs-lisp
|
||
(setq org-agenda-start-with-log-mode t)
|
||
(setq org-agenda-files '("~/notes/deft/tasks.org" "~/notes/roam/daily"))
|
||
|
||
(setq org-agenda-span 10)
|
||
|
||
|
||
(setq org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "EVENT(e)" "|" "DONE(d!)" "CANCELLED(c@)")))
|
||
#+end_src
|
||
** Capture templates
|
||
#+begin_src emacs-lisp
|
||
(defun ian/capture-to-notes-org ()
|
||
"Capture the current region (if selected) or a link to the point into 'notes.org' at the top of the Projectile project directory."
|
||
(interactive)
|
||
(let* ((selected-text (if (use-region-p)
|
||
(buffer-substring-no-properties (mark) (point))
|
||
nil))
|
||
(file-path (buffer-file-name))
|
||
(project-root (projectile-project-root))
|
||
(notes-file (expand-file-name "notes.org" project-root))
|
||
(link (format "[[file:%s::%d][Link to %s::%d]]\n\n"
|
||
file-path
|
||
(line-number-at-pos)
|
||
(file-name-nondirectory file-path)
|
||
(line-number-at-pos)))
|
||
(template (if selected-text
|
||
(concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n#+BEGIN_SRC\n" selected-text "\n#+END_SRC\n\n" link)
|
||
(concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n" link)))
|
||
(org-capture-entry `("r" "Capture" entry
|
||
(file ,notes-file)
|
||
,template)))
|
||
(org-capture nil "r")
|
||
(with-current-buffer (find-file-noselect notes-file)
|
||
(save-buffer))))
|
||
|
||
(defun ian/capture-to-todo-org ()
|
||
"Capture the current region (if selected) or a link to the point into 'todo.org' at the top of the Projectile project directory."
|
||
(interactive)
|
||
(let* ((selected-text (if (use-region-p)
|
||
(buffer-substring-no-properties (mark) (point))
|
||
nil))
|
||
(file-path (buffer-file-name))
|
||
(project-root (projectile-project-root))
|
||
(notes-file (expand-file-name "todo.org" project-root))
|
||
(link (format "[[file:%s::%d][Link to %s::%d]]\n\n"
|
||
file-path
|
||
(line-number-at-pos)
|
||
(file-name-nondirectory file-path)
|
||
(line-number-at-pos)))
|
||
(template (if selected-text
|
||
(concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n#+BEGIN_SRC\n" selected-text "\n#+END_SRC\n\n" link)
|
||
(concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n" link)))
|
||
(org-capture-entry `("r" "Capture" entry
|
||
(file ,notes-file)
|
||
,template)))
|
||
(org-capture nil "r")
|
||
(with-current-buffer (find-file-noselect notes-file)
|
||
(save-buffer))))
|
||
|
||
(defun checklist-daily-capture ()
|
||
"Generates daily checklist content."
|
||
(concat "* Daily Checklist\n"
|
||
"- [ ] Brush teeth\n"
|
||
"- [ ] Stretch\n"
|
||
"- [ ] Clean 20m\n"))
|
||
|
||
(defun weekday-specific-daily-capture (day-of-week)
|
||
"Generate checklist content which is specific to the weekday"
|
||
(cond
|
||
((string= day-of-week "Monday")
|
||
(concat ""))
|
||
((string= day-of-week "Tuesday")
|
||
(concat "* Tuesday Checklist\n"
|
||
"- [ ] Rollout trash\n"))
|
||
((string= day-of-week "Thursday")
|
||
(concat
|
||
"- [ ] Water Houseplants\n"))
|
||
((string= day-of-week "Friday")
|
||
(concat ""))
|
||
((string= day-of-week "Saturday")
|
||
(concat ""))
|
||
((string= day-of-week "Sunday")
|
||
(concat "* Sunday Checklist\n"
|
||
"- [ ] Start Sourdough\n"))
|
||
))
|
||
|
||
(defun workout-daily-capture (day-of-week)
|
||
"Generate workout table content based on DAY-OF-WEEK."
|
||
(concat
|
||
"* Workout\n"
|
||
"| Exercise | Weight | Sets | Reps | Notes |\n"
|
||
"|----------+--------+------+------+-------|\n"
|
||
(cond
|
||
((string= day-of-week "Monday")
|
||
(concat
|
||
"| VSQ | | | | |\n"
|
||
"| CGB | | | | |\n"
|
||
"| BTN | | | | |\n"
|
||
"| OHP | | | | |\n"
|
||
"| SC | | | | |\n"))
|
||
((string= day-of-week "Tuesday")
|
||
(concat
|
||
"| RDL | | | | |\n"
|
||
"| ROW | | | | |\n"
|
||
"| WCHP | | | | |\n"
|
||
"| CU | | | | |\n"))
|
||
((string= day-of-week "Thursday")
|
||
(concat
|
||
"| BP | | | | |\n"
|
||
"| JMP | | | | |\n"
|
||
"| SQ | | | | |\n"
|
||
"| SC | | | | |\n"))
|
||
((string= day-of-week "Friday")
|
||
(concat
|
||
"| DL | | | | |\n"
|
||
"| WPU | | | | |\n"
|
||
"| CU | | | | |\n"))
|
||
(t "Rest Day\n"))))
|
||
|
||
(defun diet-daily-capture ()
|
||
"Capture for calorie tracking"
|
||
(concat
|
||
"* Diet\n"
|
||
"- Weight :: \n"
|
||
"| Food | Calories | Total |\n"
|
||
"|------|----------|-------|\n"
|
||
"| | | |\n"))
|
||
|
||
(defun spending-daily-capture ()
|
||
"Capture for spending"
|
||
(concat
|
||
"* Spending\n"
|
||
"| Expense | Price | Total |\n"
|
||
"|---------|-------|-------|\n"
|
||
"| | | |\n"))
|
||
|
||
(setq org-roam-dailies-capture-templates
|
||
`(("d" "Daily Routine" entry
|
||
,(concat
|
||
"* Scheduled Today\n\n"
|
||
"%(weekday-specific-daily-capture \"%<%A>\")\n"
|
||
"%(checklist-daily-capture)\n"
|
||
"%(workout-daily-capture \"%<%A>\")\n"
|
||
"%(diet-daily-capture)\n"
|
||
"%(spending-daily-capture)\n")
|
||
:target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
| d | Daily Routine | entry | * Scheduled Today |
|
||
|
||
|
||
|
||
|
||
* Project management
|
||
#+begin_src emacs-lisp
|
||
(use-package projectile) ; todo config inside use-package
|
||
(use-package treemacs-projectile)
|
||
#+end_src
|
||
* Autocomplete
|
||
** Vertico
|
||
#+begin_src emacs-lisp
|
||
(use-package vertico
|
||
:init
|
||
(vertico-mode)
|
||
:config
|
||
(setq vertico-cycle t)
|
||
:bind (:map vertico-map
|
||
("DEL" . vertico-directory-delete-char)
|
||
("M-DEL" . vertico-directory-delete-word)))
|
||
#+end_src
|
||
** Consult
|
||
#+begin_src emacs-lisp
|
||
(use-package consult
|
||
:bind (:map minibuffer-local-map ("C-r" . consult-history))
|
||
:init
|
||
(setq register-preview-delay 0.3
|
||
register-preview-function #'consult-register-format)
|
||
(advice-add #'register-preview :override #'consult-register-window)
|
||
(setq xref-show-xrefs-function #'consult-xref
|
||
xref-show-definitions-function #'consult-xref)
|
||
:config
|
||
(setq consult-ripgrep-args "rg --null --line-buffered --color=never --max-columns=1000 --path-separator / --smart-case --no-heading --with-filename --line-number --search-zip --hidden")
|
||
(consult-customize
|
||
consult-recent-file consult-buffer :preview-key "M-.")
|
||
(setq completion-in-region-function #'consult-completion-in-region))
|
||
|
||
#+end_src
|
||
|
||
** Generic completion
|
||
Idk I think this came from the vertico readme
|
||
#+begin_src emacs-lisp
|
||
(use-package emacs
|
||
:init
|
||
;; Add prompt indicator to `completing-read-multiple'.
|
||
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
|
||
(defun crm-indicator (args)
|
||
(cons (format "[CRM%s] %s"
|
||
(replace-regexp-in-string
|
||
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
|
||
crm-separator)
|
||
(car args))
|
||
(cdr args)))
|
||
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
|
||
|
||
;; Do not allow the cursor in the minibuffer prompt
|
||
(setq minibuffer-prompt-properties
|
||
'(read-only t cursor-intangible t face minibuffer-prompt))
|
||
|
||
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
|
||
|
||
(setq enable-recursive-minibuffers t))
|
||
(setq completion-styles '(basic substring partial-completion flex))
|
||
;; Note: overridden below by orderless
|
||
#+end_src
|
||
** Orderless
|
||
#+begin_src emacs-lisp
|
||
(use-package orderless
|
||
:init
|
||
(setq completion-styles '(orderless basic)
|
||
completion-category-defaults nil
|
||
completion-category-overrides '((file (styles partial-completion)))))
|
||
#+end_src
|
||
** Marginalia
|
||
#+begin_src emacs-lisp
|
||
(use-package marginalia
|
||
:bind (:map minibuffer-local-map ("M-A" . marginalia-cycle))
|
||
:init
|
||
(marginalia-mode))
|
||
#+end_src
|
||
** Company-mode
|
||
#+begin_src emacs-lisp
|
||
(use-package company
|
||
:ensure t
|
||
:hook (prog-mode . company-mode)
|
||
:diminish
|
||
:bind (:map company-active-map
|
||
("<tab>" . company-select-next)
|
||
("TAB" . company-select-next)
|
||
("<backtab>" . company-select-previous)
|
||
("<S-tab>" . company-select-previous))
|
||
(:map lsp-mode-map ; more general mode than this?
|
||
("<tab>" . company-indent-or-complete-common))
|
||
:config
|
||
(global-company-mode 1)
|
||
:init
|
||
(setq company-idle-delay nil))
|
||
#+end_src
|
||
** Embark
|
||
#+begin_src emacs-lisp
|
||
(use-package embark
|
||
:ensure t
|
||
:after evil evil-collection evil-org
|
||
:diminish eldoc-mode
|
||
:bind
|
||
(("C-." . embark-act) ;; pick some comfortable binding
|
||
("C-;" . embark-dwim) ;; good alternative: M-.
|
||
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
|
||
:init
|
||
|
||
;; Show the Embark target at point via Eldoc. You may adjust the Eldoc
|
||
;; strategy, if you want to see the documentation from multiple providers.
|
||
;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
|
||
(general-def :states '(normal visual) "C-." 'embark-act)
|
||
(general-def :states '(normal visual) "C-;" 'embark-dwim)
|
||
|
||
|
||
:config
|
||
;; Hide the mode line of the Embark live/completions buffers
|
||
(add-to-list 'display-buffer-alist
|
||
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
|
||
nil
|
||
(window-parameters (mode-line-format . none)))))
|
||
|
||
;; Consult users will also want the embark-consult package.
|
||
(use-package embark-consult
|
||
:ensure t ; only need to install it, embark loads it after consult if found
|
||
:hook
|
||
(embark-collect-mode . consult-preview-at-point-mode))
|
||
|
||
;; Use mixed indicator: minimal prompt that switches to completing-read for narrowing
|
||
(setq embark-indicators
|
||
'(embark-mixed-indicator
|
||
embark-highlight-indicator
|
||
embark-isearch-highlight-indicator))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
** Snippets
|
||
#+begin_src emacs-lisp
|
||
(use-package yasnippet
|
||
:diminish yas-minor-mode)
|
||
(use-package yasnippet-snippets
|
||
:after lsp-mode)
|
||
(yas-global-mode)
|
||
#+end_src
|
||
* Languages
|
||
** LSP
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-mode
|
||
:commands (lsp lsp-deferred)
|
||
:init
|
||
(setq lsp-keymap-prefix "C-c l")
|
||
:config
|
||
(lsp-enable-which-key-integration t)
|
||
(setq lsp-headerline-breadcrumb-enable nil)
|
||
:hook (terraform-mode . lsp-deferred)
|
||
:hook (rust-mode . lsp-deferred))
|
||
|
||
(use-package lsp-ui)
|
||
(use-package lsp-treemacs)
|
||
(use-package flycheck
|
||
:ensure t
|
||
:diminish
|
||
:init (global-flycheck-mode))
|
||
#+end_src
|
||
** Rust
|
||
#+begin_src emacs-lisp
|
||
(use-package rust-mode
|
||
:ensure t
|
||
:mode "\\.rs\\'"
|
||
:config
|
||
(setq rust-format-on-save t))
|
||
|
||
(use-package cargo
|
||
:ensure t
|
||
:hook (rust-mode . cargo-minor-mode))
|
||
#+end_src
|
||
** Terraform
|
||
#+begin_src emacs-lisp
|
||
(use-package terraform-mode
|
||
:ensure t)
|
||
#+end_src
|
||
** Lisp
|
||
All lisp-family languages
|
||
#+begin_src emacs-lisp
|
||
; Required for some reason
|
||
;; symex's deps are all countvajhula packages not in any recipe
|
||
;; repo. Pre-register all recipes so straight can resolve
|
||
;; transitive deps regardless of build order.
|
||
(dolist (recipe '((pubsub :host github :repo "countvajhula/pubsub")
|
||
(virtual-ring :host github :repo "countvajhula/virtual-ring")
|
||
(mantra :host github :repo "countvajhula/mantra")
|
||
(repeat-ring :host github :repo "countvajhula/repeat-ring")
|
||
(lithium :host github :repo "countvajhula/lithium")))
|
||
(straight-register-package recipe))
|
||
|
||
(use-package pubsub :straight (pubsub :host github :repo "countvajhula/pubsub"))
|
||
(use-package virtual-ring :straight (virtual-ring :host github :repo "countvajhula/virtual-ring"))
|
||
(use-package mantra :straight (mantra :host github :repo "countvajhula/mantra"))
|
||
(use-package repeat-ring :straight (repeat-ring :host github :repo "countvajhula/repeat-ring"))
|
||
(use-package lithium :straight (lithium :host github :repo "countvajhula/lithium"))
|
||
|
||
;; rigpa and symex-rigpa disabled for now — rigpa pulls in a
|
||
;; newer transient that needs cond-let which straight can't resolve
|
||
;; (use-package rigpa
|
||
;; :straight
|
||
;; (rigpa
|
||
;; :host github
|
||
;; :repo "countvajhula/rigpa"))
|
||
|
||
(use-package symex-core
|
||
:straight
|
||
(symex-core
|
||
:host github
|
||
:repo "drym-org/symex.el"
|
||
:files ("symex-core/symex*.el")))
|
||
|
||
(use-package symex
|
||
:after (symex-core)
|
||
:straight
|
||
(symex
|
||
:host github
|
||
:repo "drym-org/symex.el"
|
||
:files ("symex/symex*.el" "symex/doc/*.texi" "symex/doc/figures"))
|
||
:config
|
||
(symex-mode 1)
|
||
(global-set-key (kbd "s-;") #'symex-mode-interface)
|
||
;; RET in normal mode enters symex
|
||
(evil-define-key 'normal symex-lisp-mode-map
|
||
(kbd "RET") #'symex-mode-interface)
|
||
;; ESC in insert mode goes to symex, then normal on next ESC
|
||
(evil-define-key 'insert symex-lisp-mode-map
|
||
(kbd "<escape>") (lambda ()
|
||
(interactive)
|
||
(evil-normal-state)
|
||
(symex-mode-interface))))
|
||
|
||
(use-package symex-evil
|
||
:after (symex evil)
|
||
:straight
|
||
(symex-evil
|
||
:host github
|
||
:repo "drym-org/symex.el"
|
||
:files ("symex-evil/symex*.el"))
|
||
:config
|
||
(symex-evil-mode 1))
|
||
|
||
(use-package symex-ide
|
||
:after (symex)
|
||
:straight
|
||
(symex-ide
|
||
:host github
|
||
:repo "drym-org/symex.el"
|
||
:files ("symex-ide/symex*.el"))
|
||
:config
|
||
(define-key symex-editing-mode-map
|
||
(kbd "?")
|
||
#'symex-describe)
|
||
(define-key symex-editing-mode-map
|
||
(kbd "g d")
|
||
#'geiser-edit-symbol-at-point)
|
||
(symex-ide-mode 1))
|
||
|
||
;; (use-package symex-rigpa
|
||
;; :after (symex rigpa symex-evil)
|
||
;; :straight
|
||
;; (symex-rigpa
|
||
;; :host github
|
||
;; :repo "drym-org/symex.el"
|
||
;; :files ("symex-rigpa/symex*.el"))
|
||
;; :config
|
||
;; (symex-rigpa-mode 1))
|
||
|
||
#+end_src
|
||
*** Scheme
|
||
**** Guile
|
||
#+begin_src emacs-lisp
|
||
(use-package geiser)
|
||
(use-package geiser-guile)
|
||
|
||
;; Guile debug mode uses ',' to bind a bunch of useful command
|
||
;; None of my evil packages seem to account for this
|
||
(with-eval-after-load 'geiser-debug
|
||
(evil-define-key 'motion geiser-debug-mode-map
|
||
(kbd ",") #'geiser-guile-debug-menu))
|
||
|
||
;; Why why why doesn't homebrew just handle this?
|
||
(when IS-MACOS
|
||
(let ((brew-guile-share "/opt/homebrew/share/guile/site/3.0")
|
||
(brew-guile-cache "/opt/homebrew/lib/guile/3.0/site-ccache")
|
||
(brew-guile-ext "/opt/homebrew/lib/guile/3.0/extensions"))
|
||
(setenv "GUILE_LOAD_PATH" brew-guile-share)
|
||
(setenv "GUILE_LOAD_COMPILED_PATH" brew-guile-cache)
|
||
(setenv "GUILE_SYSTEM_EXTENSIONS_PATH" brew-guile-ext)
|
||
(setenv "GUILE_TLS_CERTIFICATE_DIRECTORY"
|
||
"/opt/homebrew/etc/gnutls/")
|
||
(setenv "GUILE_LOAD_PATH"
|
||
(string-join
|
||
'("/opt/homebrew/share/guile/site/3.0"
|
||
"/opt/homebrew/share/guile-lib")
|
||
":"))
|
||
))
|
||
#+end_src
|
||
** Go
|
||
#+begin_src emacs-lisp
|
||
(use-package go-mode)
|
||
(add-hook 'go-mode-hook 'lsp-deferred)
|
||
#+end_src
|
||
* Markups
|
||
** Markdown
|
||
#+begin_src emacs-lisp
|
||
(use-package markdown-mode)
|
||
(use-package evil-markdown
|
||
:after evil
|
||
:straight (evil-markdown :type git :host github :repo "somelauw/evil-markdown")
|
||
:mode ("\\.md\\'" . evil-markdown-mode))
|
||
(use-package json-mode)
|
||
(use-package yaml-mode)
|
||
#+end_src
|
||
** Beancount
|
||
This is mostly lifted from the doom emacs config. Beancount-mode by default has a pretty borked tab function.
|
||
#+begin_src emacs-lisp
|
||
(defun beancount-tab-function ()
|
||
"Improved beancount tab ripped off from doom emacs"
|
||
(interactive)
|
||
(if (and outline-minor-mode (outline-on-heading-p))
|
||
(beancount-outline-cycle)
|
||
(indent-according-to-mode)))
|
||
|
||
(use-package beancount
|
||
:straight (beancount :type git :host github :repo "beancount/beancount-mode")
|
||
:mode ("\\.beancount\\'" . beancount-mode)
|
||
:hook (beancount-mode . outline-minor-mode)
|
||
:config
|
||
(evil-define-key 'normal 'beancount-mode-map
|
||
(kbd "TAB") 'beancount-tab-function)) ;; Bind the TAB key
|
||
|
||
(add-hook 'beancount-mode-hook #'flymake-bean-check-enable)
|
||
#+end_src
|
||
** Epub
|
||
#+begin_src emacs-lisp
|
||
(use-package nov
|
||
:after evil evil-collection
|
||
:config
|
||
;; (define-key nov-button-map (kbd "SPC") nil)
|
||
;; (evil-define-key 'normal nov-mode-map (kbd "SPC") nil)
|
||
;; (evil-define-key 'normal nov-button-map (kbd "SPC") nil)
|
||
;; (define-key nov-mode-map (kbd "SPC") nil)
|
||
(setq nov-text-width 80))
|
||
|
||
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
|
||
#+end_src
|
||
|
||
* Containers
|
||
** Docker
|
||
#+begin_src emacs-lisp
|
||
(use-package dockerfile-mode)
|
||
(use-package docker-compose-mode)
|
||
;; (use-package docker)
|
||
;; Todo: lsp-docker? docker-tramp? docker-cli?
|
||
#+end_src
|
||
** Kubernetes
|
||
#+begin_src emacs-lisp
|
||
(use-package k8s-mode)
|
||
;; kubernetes
|
||
;; kubernetes-evil
|
||
;; kubernetes-helm
|
||
;; kubernetes-tramp
|
||
#+end_src
|
||
* Shells
|
||
** Enable fish completions
|
||
Uses the external fish program to provide fish-style completions to eshell etc
|
||
#+begin_src emacs-lisp
|
||
(use-package fish-completion)
|
||
(when (and (executable-find "fish")
|
||
(require 'fish-completion nil t))
|
||
(global-fish-completion-mode))
|
||
#+end_src
|
||
* Git
|
||
#+begin_src emacs-lisp
|
||
(use-package magit)
|
||
(use-package magit-todos)
|
||
(use-package git-gutter
|
||
:diminish)
|
||
(global-git-gutter-mode t)
|
||
(setq magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1)
|
||
|
||
(use-package git-timemachine)
|
||
#+end_src
|
||
* Web browsing and youtube
|
||
#+begin_src emacs-lisp
|
||
;; Using straight:
|
||
;;(use-package empv
|
||
;; :straight (:host github :repo "isamert/empv.el"))
|
||
|
||
(use-package empv)
|
||
|
||
(setq empv-radio-channels
|
||
'(("SomaFM - Groove Salad" . "http://www.somafm.com/groovesalad.pls")
|
||
("SomaFM - Drone Zone" . "http://www.somafm.com/dronezone.pls")
|
||
("SomaFM - Sonic Universe" . "https://somafm.com/sonicuniverse.pls")
|
||
("SomaFM - Metal" . "https://somafm.com/metal.pls")
|
||
("SomaFM - Vaporwaves" . "https://somafm.com/vaporwaves.pls")
|
||
("ADHD 1" . "https://www.youtube.com/watch?v=CmMrm4BpQHU")
|
||
("WREK FM" . "http://streaming.wrek.org:8000/wrek_live-128kb.m3u")
|
||
))
|
||
|
||
(with-eval-after-load 'embark (empv-embark-initialize-extra-actions))
|
||
(add-to-list 'empv-mpv-args "--ytdl-format=best")
|
||
(add-to-list 'empv-mpv-args "--save-position-on-quit")
|
||
(add-hook 'empv-init-hook #'empv-override-quit-key)
|
||
|
||
(setq empv-invidious-instance "https://invidious.projectsegfau.lt/api/v1")
|
||
|
||
#+end_src
|
||
|
||
* Email, rss, newsgroups
|
||
Oh, boy. Here we go.
|
||
[[https://www.gnu.org/software/emacs/manual/html_node/auth][This]] will come in handy.
|
||
(=TODO=: smtp header)
|
||
#+begin_src emacs-lisp
|
||
|
||
(setq user-mail-address "ian@keane.sh"
|
||
user-full-name "Ian Keane")
|
||
|
||
;; Assuming your passwords are stored in Password Store with names like:
|
||
;; "email/fastmail" and "email/gmail"
|
||
|
||
;; IMAP configuration for Fastmail
|
||
|
||
(setq gnus-select-method
|
||
'(nnimap "Fastmail-emacs"
|
||
(nnimap-user "ian@keane.sh")
|
||
(nnimap-address "imap.fastmail.com")
|
||
(nnimap-server-port 993)
|
||
(nnimap-stream ssl)))
|
||
|
||
|
||
;; Additional secondary IMAP account for Gmail
|
||
;; (add-to-list 'gnus-secondary-select-methods
|
||
;; '(nnimap "Gmail"
|
||
;; (nnimap-address "imap.gmail.com")
|
||
;; (nnimap-server-port 993)
|
||
;; (nnimap-stream ssl)
|
||
;; (nnimap-authinfo-file nil) ; Not using .authinfo for Gmail
|
||
;; (nnir-search-engine imap)
|
||
;; (nnimap-authenticator login)
|
||
;; (nnimap-login "your-gmail-username") ; Replace with your Gmail username
|
||
;; (nnimap-password (password-store-get "email/gmail"))))
|
||
|
||
(setq send-mail-function 'smtpmail-send-it
|
||
message-send-mail-function 'smtpmail-send-it
|
||
smtpmail-default-smtp-server "smtp.fastmail.com"
|
||
smtpmail-smtp-server "smtp.fastmail.com"
|
||
smtpmail-smtp-service 587
|
||
smtpmail-stream-type 'starttls
|
||
smtpmail-smtp-user "ian@keane.sh"
|
||
smtpmail-debug-info t)
|
||
|
||
;; You may also want to add a conditional to choose the SMTP server based on the current 'From' address.
|
||
|
||
;; RSS Feeds
|
||
;; (add-to-list 'gnus-secondary-select-methods '(nnrss ""))
|
||
|
||
;; Configure RSS feed subscriptions
|
||
;; (setq gnus-secondary-sources
|
||
;; '((nnrss "http://example.com/rss") ; replace with actual RSS URL
|
||
;; ;; Add more RSS feeds here
|
||
;; ))
|
||
|
||
|
||
;; Use Gnus for composing email
|
||
(setq mail-user-agent 'gnus-user-agent)
|
||
|
||
;; Set up HTML email rendering
|
||
(setq mm-text-html-renderer 'shr)
|
||
|
||
#+end_src
|
||
* Emacs Meta
|
||
** Explain-Pause
|
||
Scrutinize which processes are gumming up emacs
|
||
#+begin_src emacs-lisp
|
||
;; (use-package explain-pause-mode
|
||
;; :straight (explain-pause-mode :type git :host github :repo "lastquestion/explain-pause-mode")
|
||
;; :diminish explain-pause-mode
|
||
;; :config
|
||
;; (explain-pause-mode))
|
||
#+end_src
|
||
* Todo
|
||
** General
|
||
- Refactor to use use-package more effectively
|
||
- Use :mode and :config like [[https://ianyepan.github.io/posts/setting-up-use-package/][here]]
|
||
- Set things which should be set before package install in :init
|
||
- Disable source editing issue
|
||
- Goes away when I run =(defun org-edit-src-code nil)=
|
||
- Go through AWB's notes about using gnus
|
||
- TODO aggregation
|
||
- Suppress evilmarkdown mode and org-roam-ui minor mode
|
||
|
||
** Terminals
|
||
- More terminals
|
||
- emacs-fish-completions
|
||
- setup terminals to complete to vertico
|
||
- starship prompts
|
||
|
||
** New functions
|
||
- Git-time-machine-or-vc-region-history
|
||
** Note taking
|
||
- deft
|
||
- org : roam2, hugo, pretty, dragndrop, bullet
|
||
- meetlog reference buffer
|
||
- work roam directory
|
||
- [[https://www.youtube.com/watch?v=3-sLBaJAtew][Dalies]] for scheduling things
|
||
- Fix org indentation stuff
|
||
|
||
** Lisp stuff
|
||
- paredit
|
||
- lispy
|
||
- no tabs for yaml-mode (wtf?)
|
||
|
||
** One-offs
|
||
- 'ex' snippet for the most common example of a thing I do per filetype
|
||
- docker-compose example
|
||
- hl-todo
|
||
- persistent undo
|
||
- commentary
|
||
- highlight tabs and newlines
|
||
- [[https://youtu.be/UtqE-lR2HCA?t=5027][Vertico backwards delete]]
|
||
- alphabetical keybindings
|
||
- brighter modeline
|
||
- surpress global minor modes
|
||
- Undo-Tree, company, flycheck, which-key
|
||
- ignore case in imenu
|
||
- improve which-key visibility
|
||
- gpt popup
|
||
- org-roam-buffer popup
|
||
- conflicts with global popup buffers
|
||
- init popup buffer binding? spc r i?
|
||
- org-roam buffer in popup (follow)
|
||
- [[https://old.reddit.com/r/emacs/comments/o04it0/share_your_prettifysymbolsalist/][prettify-symbols-mode]]
|
||
- create 'context' keybinding
|
||
- map smerge mode
|
||
|
||
** Embark
|
||
- open file in other window
|
||
|
||
** NFS stuff
|
||
- map music from nfs
|
||
- map books from nfs with nov.el
|
||
|
||
** LSP stuff
|
||
- look into treemacs integrations
|
||
- consider eglot
|
||
- dap-mode
|
||
|
||
** Completion
|
||
- dabbrev-expand or company on c-n c-p
|
||
- c-N c-P for expand full line
|
||
- yasnippet
|
||
- company-mode to corfu (or vertico completions? or cofu-in-vertico?)
|
||
- get vertico as completion box
|
||
|
||
** Keybindings
|
||
- bind (custom?) git-view-from-other-branch
|
||
- want to be able to view a file as it is in another branch
|
||
- bind (custom?) git diff from other branch
|
||
- bind capture to init todo
|
||
- bind capture to project todo
|
||
- bind org-set-property
|
||
- treemacs-open-other-window
|
||
- treemacs | to open in split
|
||
- create-tab-with-name function
|
||
- buffer to spc b b local, spc b B global
|
||
- do somthing useful with ','
|
||
- custom function for toggle between last 2 windows
|
||
- custom function to scroll-other-window using last 2 windows
|
||
- evil-define-key instead of define-key everywhere
|
||
- bind something to create file in dired / treemacs
|
||
- fix general prefix in treemacs mode
|
||
- fix vim-surround
|
||
- snippets help =spc h y=, helpful-symbol =spc h s=
|
||
- put general bindings in separate keymaps in separate sections
|
||
- map hyper bindings for buffer nav and jumping
|
||
- evil-org
|
||
- map alignment functions in 'code'section
|
||
- fix c-u in evil mode
|
||
- fix tab key
|
||
- window size functions, winner undo/redo
|
||
- map default-text-scale operations
|
||
- org-capture from string and org-ripgrep
|
||
- move spc p s back to spc p p
|
||
- org eval block
|
||
- explain-pause spc h p
|
||
- Want this for org-roam, don't want to rebind tab here
|
||
- empv
|
||
- map
|
||
- configure
|
||
- empv-radio-log-file
|
||
- empv-radio-log-format
|
||
- spc m y(outube)
|
||
- spc m l(ocal)
|
||
- spc m r(adio)
|
||
- empv-video-dir empv-audio-dir?
|
||
- empv-play-file
|
||
- Set display-buffer-alist values for how I want windows treated (integrates with popper), e.g.
|
||
#+begin_src emacs-lisp :tangle no
|
||
(add-to-list 'display-buffer-alist
|
||
'("\\*ielm\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . left)
|
||
(window-width . 50)))
|
||
#+end_src
|
||
|
||
selected radio (See empv-radio-log-file and empv-radio-log-format
|
||
variables and their documentations).
|
||
|
||
|
||
** New plugins
|
||
- tramp
|
||
- k8s
|
||
- docker
|
||
- terraform
|
||
- straight?
|
||
- embark?
|
||
- emms, emms-play-url binding (youtube view)
|
||
- [[https://youtu.be/UtqE-lR2HCA?t=5134][consult-lsp]] (better for errors than treemacs integrations probably)
|
||
- srht.el
|
||
- affe
|
||
- gnus
|
||
|
||
** Appearance switches
|
||
- fonts
|
||
- random theme
|
||
- org mode bullets / pretty / etc
|
||
|
||
** Research
|
||
- What does C-d do when in a minibuffer for vertico?
|
||
- embark
|
||
- ace-window / embark integration
|
||
|
||
** System crafters videos
|
||
- [[https://www.youtube.com/watch?v=CUkuyW6hr18][5 Hacks to improve org roam]]
|
||
- [[https://www.youtube.com/watch?v=C1kwStlEick][Improving the IRC experience]]
|
||
- [[https://www.youtube.com/watch?v=J0OaRy85MOo][Streamlined completions with vertico]]
|
||
- [[https://www.youtube.com/watch?v=XZjyJG-sFZI][Keeping your folders clean while using emacs]]
|
||
- [[https://www.youtube.com/watch?v=zMzkorlfqLA][Static site generator from org mode]]
|
||
- [[https://www.youtube.com/watch?v=za99DwdZEyg][Automated website publishing w/ org and sourcehut]]
|
||
- [[https://www.youtube.com/watch?v=SCPoF1PTZpI][Emacs presentations]]
|
||
- [[https://www.youtube.com/watch?v=0C16LLHGYzk&t=1882s][Converting a literate config to guix home]]
|
||
- [[https://www.youtube.com/playlist?list=PLEoMzSkcN8oM-kA19xOQc8s0gr0PpFGJQ][Emacs mail playlist]]
|
||
- [[https://www.youtube.com/watch?v=qk2Is_sC8Lk][Embark]]
|
||
|
||
** Annoyances
|
||
- set require-final-newline = nil
|
||
- fix gitgutter behavior
|
||
- remove extra line file modifying behavior
|
||
- fix missing snippets in note-taking mode
|
||
- always open treemacs from most recent window
|
||
- prevent :wq from killing frame
|
||
*** Ediff
|
||
- vertical
|
||
- no new frame
|
||
- bind magit-ediff-compare
|
||
#+begin_src emacs-lisp
|
||
(setq ediff-window-setup-function #'ediff-setup-windows-plain)
|
||
#+end_src
|
||
- bind ediff two files
|
||
- fix fuzzy searching for functions
|
||
- bind =SPC -= to dired-jump
|
||
- fix markdown-mode (doesn't start with .md files automatically)
|
||
- bind magit-log-buffer-file (handles selection-based history)
|
||
- adaptive wrap (plus fix visual-line-mode to always load)
|
||
- [[https://elpa.gnu.org/packages/adaptive-wrap.html]]
|
||
- install / configure consult-org-roam
|
||
- map default-text-scale-increase/decrease (better than regular text scaling)
|
||
- set default-text-scale-amount to 5 instead of 10
|
||
- map outline-toggle-children in tf mode
|
||
- map ripgrep in parent dir
|
||
- map ripgrep in (dired select)
|
||
- add .git to ripgrep ignore
|
||
- fix vterm
|
||
- make the popup frame-wide
|
||
- fix spc v t
|
||
- maybe just make spc tab open shell and exclude it from ace managed windows
|
||
- make eshell pretty
|
||
- when toggling shell, enter insert mode
|
||
- migrate to wezterm, impelement popup term
|
||
- look into letting org fold blocks or folding bracket blocks in general cases
|
||
- try (add-hook 'magit-post-refresh-hook 'git-gutter:refresh)
|
||
- make treemacs enter always open in most recent buffer
|
||
- add meeting log to reference reaches
|
||
- install ini-mode plugin
|
||
- install lua-mode plugin
|
||
- install fish-mode plugin
|