aboutsummaryrefslogtreecommitdiff
path: root/Emacs/.config/emacs/core.org
diff options
context:
space:
mode:
authorAryadev Chavali <aryadev@aryadevchavali.com>2023-09-29 22:30:58 +0100
committerAryadev Chavali <aryadev@aryadevchavali.com>2023-09-29 22:30:58 +0100
commita0a5b2e05d3beae7ed3d5ed14b6b65bbc811c7a9 (patch)
treeb0482444d66b598c13aa47636306aa42986de8d2 /Emacs/.config/emacs/core.org
parentcc25dcf8121c7a0431f5fc1f27675b1229818041 (diff)
downloaddotfiles-a0a5b2e05d3beae7ed3d5ed14b6b65bbc811c7a9.tar.gz
dotfiles-a0a5b2e05d3beae7ed3d5ed14b6b65bbc811c7a9.tar.bz2
dotfiles-a0a5b2e05d3beae7ed3d5ed14b6b65bbc811c7a9.zip
(Emacs)~config->app,core
The two largest sections of my config are separated into their own files now. Does increase init time, but I just can't handle how big this thing is. It'll be a bit nicer to look at and manage with separate files.
Diffstat (limited to 'Emacs/.config/emacs/core.org')
-rw-r--r--Emacs/.config/emacs/core.org738
1 files changed, 738 insertions, 0 deletions
diff --git a/Emacs/.config/emacs/core.org b/Emacs/.config/emacs/core.org
new file mode 100644
index 0000000..687b226
--- /dev/null
+++ b/Emacs/.config/emacs/core.org
@@ -0,0 +1,738 @@
+#+title: Core packages
+#+author: Aryadev Chavali
+#+description: The core components of my configuration
+#+date: 2023-09-29
+#+property: header-args:emacs-lisp :tangle core.el :comments link :results none
+#+options: toc:nil
+#+startup: noindent
+
+Packages that are absolutely necessary for the rest of the
+configuration. These yield core functionality such as keybinding,
+modal editing, completion, auto typing to name a few.
+* General
+General provides a great solution for binding keys. It has evil and
+use-package support so it fits nicely into configuration. In this
+case, I define a "definer" for the "LEADER" keys. Leader is bound to
+~SPC~ and it's functionally equivalent to the doom/spacemacs leader.
+Local leader is bound to ~SPC ,~ and it's similar to doom/spacemacs
+leader but doesn't try to fully assimilate the local-leader map,
+instead just picking stuff I think is useful. This forces me to learn
+only as many bindings as I find necessary; no more, no less.
+
+I also define prefix leaders for differing applications. These are
+quite self explanatory by their name and provide a nice way to
+visualise all bindings under a specific heading just by searching the
+code.
+#+begin_src emacs-lisp
+(use-package general
+ :straight t
+ :demand t
+ :config
+ ;; General which key definitions for leaders
+ (general-def
+ :states '(normal motion)
+ "SPC" 'nil
+ "\\" '(nil :which-key "Local leader")
+ "SPC c" '(nil :which-key "Code")
+ "SPC f" '(nil :which-key "File")
+ "SPC t" '(nil :which-key "Shell")
+ "SPC m" '(nil :which-key "Toggle modes")
+ "SPC a" '(nil :which-key "Applications")
+ "SPC s" '(nil :which-key "Search")
+ "SPC b" '(nil :which-key "Buffers")
+ "SPC q" '(nil :which-key "Quit/Literate")
+ "SPC i" '(nil :which-key "Insert")
+ "SPC d" '(nil :which-key "Directories"))
+
+ (general-create-definer leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC")
+
+ (general-create-definer local-leader
+ :states '(normal motion)
+ :prefix "\\")
+
+ (general-create-definer code-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC c")
+
+ (general-create-definer file-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC f")
+
+ (general-create-definer shell-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC t")
+
+ (general-create-definer mode-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC m")
+
+ (general-create-definer app-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC a")
+
+ (general-create-definer search-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC s")
+
+ (general-create-definer buffer-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC b")
+
+ (general-create-definer quit-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC q")
+
+ (general-create-definer insert-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC i")
+
+ (general-create-definer dir-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC d")
+
+ (general-create-definer general-nmmap
+ :states '(normal motion))
+
+ (defalias 'nmmap #'general-nmmap)
+
+ (general-evil-setup t))
+#+end_src
+** Some binds in Emacs
+Some bindings that I couldn't fit elsewhere easily.
+#+begin_src emacs-lisp
+(use-package emacs
+ :straight nil
+ :general
+ (general-def
+ "C-x d" #'delete-frame)
+
+ (nmmap
+ "C--" #'text-scale-decrease
+ "C-=" #'text-scale-increase)
+
+ (leader
+ "SPC" '(execute-extended-command :which-key "M-x")
+ "'" '(browse-url-emacs :which-key "Open url in Emacs")
+ ";" 'eval-expression
+ ":" `(,(proc (interactive) (switch-to-buffer "*scratch*"))
+ :which-key "Switch to *scratch*")
+ "!" '(async-shell-command :which-key "Async shell command")
+ "h" '(help-command :which-key "Help"))
+
+ (mode-leader
+ "t" #'+oreo/switch-theme)
+
+ (code-leader
+ "F" `(,(proc (interactive) (find-file "~/Code/"))
+ :which-key "Open ~/Code/"))
+
+ (file-leader
+ "f" #'find-file
+ "F" #'find-file-other-frame
+ "s" #'save-buffer
+ "p" `(,(proc (interactive)
+ (find-file (concat user-emacs-directory "config.org")))
+ :which-key "Open config.org"))
+
+ (quit-leader
+ "q" #'save-buffers-kill-terminal
+ "c" #'+literate/compile-config
+ "l" #'+literate/load-config
+ "d" #'delete-frame)
+
+ (search-leader "i" #'imenu))
+#+end_src
+* Evil
+My editor journey started off with Vim rather than Emacs, so my brain
+has imprinted on its style. Thankfully Emacs is super extensible so
+there exists a package (more of a supreme system) for porting Vim's
+modal editing style to Emacs, called Evil (Emacs Vi Layer).
+
+However there are a lot of packages in Vim that provide greater
+functionality, for example 'vim-surround'. Emacs, by default, has
+these capabilities but there are further packages which integrate them
+into Evil.
+** Evil core
+Setup the evil package, with some opinionated keybindings:
+- Switch ~evil-upcase~ and ~evil-downcase~ because I use ~evil-upcase~
+ more
+- Switch ~evil-goto-mark~ and ~evil-goto-mark-line~ as I'd rather have
+ the global one closer to the home row
+- Use 'T' character as an action for transposing objects
+#+begin_src emacs-lisp
+(use-package evil
+ :demand t
+ :hook (after-init-hook . evil-mode)
+ :general
+ (leader
+ "w" '(evil-window-map :which-key "Window")
+ "wd" #'delete-frame)
+
+ (nmmap
+ "TAB" #'evil-jump-item
+ "r" #'evil-replace-state
+ "zC" #'hs-hide-level
+ "zO" #'hs-show-all
+ "'" #'evil-goto-mark
+ "`" #'evil-goto-mark-line
+ "C-w" #'evil-window-map
+ "gu" #'evil-upcase
+ "gU" #'evil-downcase
+ "T" nil)
+
+ (nmmap
+ :infix "T"
+ "w" #'transpose-words
+ "c" #'transpose-chars
+ "s" #'transpose-sentences
+ "p" #'transpose-paragraphs
+ "e" #'transpose-sexps
+ "l" #'transpose-lines)
+ :init
+ (setq evil-want-keybinding nil
+ evil-split-window-below t
+ evil-vsplit-window-right t
+ evil-want-abbrev-expand-on-insert-exit t
+ evil-undo-system #'undo-tree)
+ :config
+ (fset #'evil-window-vsplit #'make-frame))
+#+end_src
+** Evil surround
+Evil surround is a port for vim-surround.
+#+begin_src emacs-lisp
+(use-package evil-surround
+ :after evil
+ :config
+ (global-evil-surround-mode))
+#+end_src
+** Evil commentary
+Allows generalised commenting of objects easily.
+#+begin_src emacs-lisp
+(use-package evil-commentary
+ :after evil
+ :config
+ (evil-commentary-mode))
+#+end_src
+** Evil multi cursor
+Setup for multi cursors in Evil mode. Don't let evil-mc setup it's own
+keymap because it uses 'gr' as its prefix, which I don't like.
+#+begin_src emacs-lisp
+(use-package evil-mc
+ :after evil
+ :init
+ (defvar evil-mc-key-map (make-sparse-keymap))
+ :general
+ (nmap
+ :infix "gz"
+ "q" #'evil-mc-undo-all-cursors
+ "d" #'evil-mc-make-and-goto-next-match
+ "j" #'evil-mc-make-cursor-move-next-line
+ "k" #'evil-mc-make-cursor-move-prev-line
+ "j" #'evil-mc-make-cursor-move-next-line
+ "m" #'evil-mc-make-all-cursors
+ "z" #'evil-mc-make-cursor-here
+ "r" #'evil-mc-resume-cursors
+ "s" #'evil-mc-pause-cursors
+ "u" #'evil-mc-undo-last-added-cursor)
+ :config
+ ;; (evil-mc-define-vars)
+ ;; (evil-mc-initialize-vars)
+ ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-pause-incompatible-modes)
+ ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-initialize-active-state)
+ ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-teardown-active-state)
+ ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-resume-incompatible-modes)
+ ;; (advice-add #'evil-mc-initialize-hooks :override #'ignore)
+ ;; (advice-add #'evil-mc-teardown-hooks :override #'evil-mc-initialize-vars)
+ ;; (advice-add #'evil-mc-initialize-active-state :before #'turn-on-evil-mc-mode)
+ ;; (advice-add #'evil-mc-teardown-active-state :after #'turn-off-evil-mc-mode)
+ ;; (add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors)
+ (global-evil-mc-mode))
+#+end_src
+
+** Evil collection
+Provides a community based set of keybindings for most modes in
+Emacs. I don't necessarily like all my modes having these bindings
+though, as I may disagree with some. So I use it in a mode to mode basis.
+#+begin_src emacs-lisp
+(use-package evil-collection
+ :after evil)
+#+end_src
+* Completion
+Emacs is a text based interface. Completion is its bread and butter
+in providing good user experience. By default Emacs provides
+'completions-list' which produces a buffer of options which can be
+searched and selected. We can take this further though!
+
+Ido and Icomplete are packages distributed with Emacs to provide
+greater completion interfaces. They utilise the minibuffer to create
+a more interactive experience, allowing incremental searches and
+option selection.
+
+Ivy and Helm provide more modern interfaces, though Helm is quite
+heavy. Ivy, on the other hand, provides an interface similar to Ido
+with less clutter and better customisation options.
+** Ivy
+Ivy is a completion framework for Emacs, and my preferred one. It has
+a great set of features with little to no pain with setting up.
+*** Ivy Core
+Setup for ivy, in preparation for counsel. Turn on ivy-mode just
+after init.
+
+Setup vim-like bindings for the minibuffer ("M-(j|k)" for down|up the
+selection list).
+#+begin_src emacs-lisp
+(use-package ivy
+ :defer t
+ :hook (after-init-hook . ivy-mode)
+ :general
+ (general-def
+ :keymaps 'ivy-minibuffer-map
+ "C-j" #'ivy-yank-symbol
+ "M-j" #'ivy-next-line-or-history
+ "M-k" #'ivy-previous-line-or-history
+ "C-SPC" #'ivy-occur)
+ (general-def
+ :keymaps 'ivy-switch-buffer-map
+ "M-j" #'ivy-next-line-or-history
+ "M-k" #'ivy-previous-line-or-history)
+ (nmap
+ :keymaps '(ivy-occur-mode-map ivy-occur-grep-mode-map)
+ "RET" #'ivy-occur-press-and-switch
+ "J" #'ivy-occur-press
+ "gr" #'ivy-occur-revert-buffer
+ "q" #'quit-window
+ "D" #'ivy-occur-delete-candidate
+ "W" #'ivy-wgrep-change-to-wgrep-mode
+ "{" #'compilation-previous-file
+ "}" #'compilation-next-file)
+ :init
+ (with-eval-after-load "evil"
+ (evil-set-initial-state 'ivy-occur-mode 'normal)
+ (evil-set-initial-state 'ivy-occur-grep-mode 'normal))
+ (with-eval-after-load "amx"
+ (setq amx-backend 'ivy))
+
+ (setq ivy-height 10
+ ivy-wrap t
+ ivy-fixed-height-minibuffer t
+ ivy-use-virtual-buffers nil
+ ivy-virtual-abbreviate 'full
+ ivy-on-del-error-function #'ignore
+ ivy-use-selectable-prompt t)
+ :config
+ (require 'counsel nil t))
+#+end_src
+*** Counsel
+Setup for counsel. Load after ivy and helpful.
+#+begin_src emacs-lisp
+(use-package counsel
+ :defer t
+ :general
+ (search-leader
+ "s" #'counsel-grep-or-swiper
+ "r" #'counsel-rg)
+ (file-leader
+ "r" #'counsel-recentf)
+ (insert-leader
+ "c" #'counsel-unicode-char)
+ (general-def
+ [remap describe-bindings] #'counsel-descbinds
+ [remap load-theme] #'counsel-load-theme)
+ :config
+ (setq ivy-initial-inputs-alist '((org-insert-link . "^"))
+ counsel-describe-function-function #'helpful-callable
+ counsel-describe-variable-function #'helpful-variable
+ counsel-grep-swiper-limit 1500000
+ ivy-re-builders-alist '((swiper . ivy--regex-plus)
+ (counsel-grep-or-swiper . ivy--regex-plus)
+ (counsel-rg . ivy--regex-plus)
+ (t . ivy--regex-ignore-order)))
+ (counsel-mode))
+#+end_src
+*** WIP Ivy posframe
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+This makes ivy minibuffer windows use child frames.
+Very nice eyecandy, but can get kinda annoying.
+#+begin_src emacs-lisp
+(use-package ivy-posframe
+ :hook (ivy-mode-hook . ivy-posframe-mode)
+ :straight t
+ :init
+ (setq ivy-posframe-parameters
+ '((left-fringe . 0)
+ (right-fringe . 0)
+ (background-color . "grey7")))
+
+ (setq ivy-posframe-display-functions-alist
+ '((t . ivy-posframe-display-at-window-center))))
+#+end_src
+*** WIP Counsel etags
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Counsel etags allows me to search generated tag files for tags. I
+already have a function defined to generate the tags, so it's just
+searching them which I find to be a bit of a hassle, and where this
+package comes in.
+
+This has been replaced by [[*xref][xref]] which is inbuilt.
+#+begin_src emacs-lisp
+(use-package counsel-etags
+ :after counsel
+ :general
+ (search-leader
+ "t" #'counsel-etags-find-tag))
+#+end_src
+** WIP Ido
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Ido is a very old completion package that still works great to this
+day. Though it is limited in its scope (and may thus be called a
+completion add-on rather than a full on framework), it is still a very
+powerful package. With the use of ido-completing-read+, it may be used
+similarly to a fully fledged completion framework.
+
+#+begin_src emacs-lisp
+(use-package ido
+ :demand t
+ :general
+ (general-def
+ :keymaps '(ido-buffer-completion-map
+ ido-file-completion-map
+ ido-file-dir-completion-map
+ ido-common-completion-map)
+ (kbd "M-j") #'ido-next-match
+ (kbd "M-k") #'ido-prev-match
+ (kbd "C-x o") #'evil-window-up)
+ :init
+ (setq ido-decorations
+ (list "{" "}" " \n" " ..." "[" "]" " [No match]" " [Matched]"
+ " [Not readable]" " [Too big]" " [Confirm]")
+ completion-styles '(flex partial-completion intials emacs22))
+ (setq-default ido-enable-flex-matching t
+ ido-enable-dot-prefix t
+ ido-enable-regexp nil)
+ (with-eval-after-load "magit"
+ (setq magit-completing-read-function 'magit-ido-completing-read))
+ :config
+ (ido-mode)
+ (ido-everywhere))
+#+end_src
+*** Ido ubiquitous
+Ido completing-read+ is a package that extends the ido package to work
+with more text based functions.
+#+begin_src emacs-lisp
+(use-package ido-completing-read+
+ :after ido
+ :config
+ (ido-ubiquitous-mode +1))
+#+end_src
+** Amx
+Amx is a fork of Smex that works to enhance the
+execute-extended-command interface. It also provides support for ido
+or ivy (though I'm likely to use ido here) and allows you to switch
+between them.
+
+It provides a lot of niceties such as presenting the key bind when
+looking for a command.
+
+#+begin_src emacs-lisp
+(use-package amx
+ :config
+ (amx-mode))
+#+end_src
+** Orderless
+Orderless sorting method for completion, probably one of the best
+things ever.
+#+begin_src emacs-lisp
+(use-package orderless
+ :after (ivy ido)
+ :config
+ (setf (alist-get t ivy-re-builders-alist) 'orderless-ivy-re-builder))
+#+end_src
+** Completions-list
+In case I ever use the completions list, some basic commands to look
+around.
+#+begin_src emacs-lisp
+(use-package simple
+ :straight nil
+ :general
+ (nmmap
+ :keymaps 'completion-list-mode-map
+ "l" #'next-completion
+ "h" #'previous-completion
+ "ESC" #'delete-completion-window
+ "q" #'quit-window
+ "RET" #'choose-completion)
+ :config
+ (with-eval-after-load "evil"
+ (setq evil-emacs-state-modes (cl-remove-if
+ #'(lambda (x) (eq 'completions-list-mode x))
+ evil-emacs-state-modes))
+ (add-to-list 'evil-normal-state-modes 'completions-list-mode)))
+#+end_src
+** Company
+Company is the auto complete system I use. I don't like having heavy
+setups for company as it only makes it slower to use. In this case,
+just setup some evil binds for company.
+#+begin_src emacs-lisp
+(use-package company
+ :straight t
+ :hook
+ (prog-mode-hook . company-mode)
+ (eshell-mode-hook . company-mode)
+ :general
+ (imap
+ "C-SPC" #'company-complete)
+ (general-def
+ :states '(normal insert)
+ "M-j" #'company-select-next
+ "M-k" #'company-select-previous))
+#+end_src
+* Pretty symbols
+Prettify symbols mode allows for users to declare 'symbols' that
+replace text within certain modes. Though this may seem like useless
+eye candy, it has aided my comprehension and speed of recognition
+(recognising symbols is easier than words).
+
+Essentially a use-package keyword which makes declaring pretty symbols
+for language modes incredibly easy. Checkout my [[C/C++][C/C++]] configuration
+for an example.
+#+begin_src emacs-lisp
+(use-package prog-mode
+ :straight nil
+ :init
+ (setq prettify-symbols-unprettify-at-point t)
+ :config
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':pretty)
+ (defun use-package-normalize/:pretty (_name-symbol _keyword args)
+ args)
+
+ (defun use-package-handler/:pretty (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ (let ((mode (car arg))
+ (rest (cdr arg)))
+ `(add-hook
+ ',mode
+ #'(lambda nil
+ (setq prettify-symbols-alist ',rest)
+ (prettify-symbols-mode)))))
+ args)))))
+#+end_src
+
+Here's a collection of keywords and possible associated symbols for
+any prog language of choice. Mostly for reference and copying.
+#+begin_example
+("null" . "Ø")
+("list" . "ℓ")
+("string" . "𝕊")
+("true" . "⊤")
+("false" . "⊥")
+("char" . "ℂ")
+("int" . "ℤ")
+("float" . "ℝ")
+("!" . "¬")
+("&&" . "∧")
+("||" . "∨")
+("for" . "∀")
+("return" . "⟼")
+("print" . "ℙ")
+("lambda" . "λ")
+#+end_example
+* Window management
+Emacs' default window management is quite bad, eating other windows on
+a whim and not particularly caring for the current window setup.
+Thankfully you can change this via the ~display-buffer-alist~ which
+matches buffer names with how the window for the buffer should be
+displayed. I add a use-package keyword to make ~display-buffer-alist~
+records within use-package.
+
+I have no idea whether it's optimal AT ALL, but it works for me.
+#+begin_src emacs-lisp
+(use-package window
+ :straight nil
+ :general
+ (buffer-leader
+ "b" #'switch-to-buffer
+ "d" #'kill-current-buffer
+ "K" #'kill-buffer
+ "j" #'next-buffer
+ "k" #'previous-buffer
+ "D" '(+oreo/clean-buffer-list :which-key "Kill most buffers"))
+ :init
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':display)
+ (defun use-package-normalize/:display (_name-symbol _keyword args)
+ args)
+
+ (defun use-package-handler/:display (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ `(add-to-list 'display-buffer-alist
+ ',arg))
+ args)))))
+#+end_src
+** Some display records
+Using the ~:display~ keyword, setup up some ~display-buffer-alist~
+records. This is mostly for packages that aren't really configured
+(like [[info:woman][woman]]) or packages that were configured before
+(like [[Ivy][Ivy]]).
+#+begin_src emacs-lisp
+(use-package window
+ :straight nil
+ :defer t
+ :display
+ ("\\*Process List\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25))
+
+ ("\\*\\(Ido \\)?Completions\\*"
+ (display-buffer-in-side-window)
+ (window-height . 0.25)
+ (side . bottom))
+
+ ("\\*ivy-occur.*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25))
+
+ ("\\*Async Shell Command\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25)))
+#+end_src
+* Auto typing
+Snippets are a pretty nice way of automatically inserting code. Emacs
+provides a ton of packages by default to do this, but there are great
+packages to install as well.
+
+Abbrevs and skeletons make up a popular solution within Emacs default.
+Abbrevs are for simple expressions wherein the only input is the key,
+and the output is some Elisp function. They provide a lot of inbuilt
+functionality and are quite useful. Skeletons, on the other hand, are
+for higher level insertions
+
+The popular external solution is Yasnippet. Yasnippet is a great
+package for snippets, which I use heavily in programming and org-mode.
+I setup here the global mode for yasnippet and a collection of
+snippets for ease of use.
+** Abbrevs
+Just define a few abbrevs for various date-time operations. Also
+define a macro that will assume a function for the expansion, helping
+with abstracting a few things away.
+#+begin_src emacs-lisp
+(use-package abbrev
+ :straight nil
+ :hook
+ (prog-mode-hook . abbrev-mode)
+ (text-mode-hook . abbrev-mode)
+ :init
+ (defmacro +abbrev/define-abbrevs (abbrev-table &rest abbrevs)
+ `(progn
+ ,@(mapcar #'(lambda (abbrev)
+ `(define-abbrev
+ ,abbrev-table
+ ,(car abbrev)
+ ""
+ (proc (insert ,(cadr abbrev)))))
+ abbrevs)))
+ (setq save-abbrevs nil)
+ :config
+ (+abbrev/define-abbrevs
+ global-abbrev-table
+ ("sdate"
+ (format-time-string "%Y-%m-%d" (current-time)))
+ ("stime"
+ (format-time-string "%H:%M:%S" (current-time)))
+ ("sday"
+ (format-time-string "%A" (current-time)))
+ ("smon"
+ (format-time-string "%B" (current-time)))))
+#+end_src
+** WIP Skeletons
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Defines a macro for generating a skeleton + abbrev for a given mode.
+Doesn't sanitise inputs because I assume callers are /rational/ actors
+who would *only* use this for their top level Emacs config.
+
+Honestly didn't find much use for this currently, so disabled.
+#+begin_src emacs-lisp
+(use-package skeleton
+ :straight nil
+ :after abbrev
+ :config
+ (defmacro +autotyping/gen-skeleton-abbrev (mode abbrev &rest skeleton)
+ (let* ((table (intern (concat (symbol-name mode) "-abbrev-table")))
+ (skeleton-name (intern (concat "+skeleton/" (symbol-name mode) "/" abbrev))))
+ `(progn
+ (define-skeleton
+ ,skeleton-name
+ ""
+ ,@skeleton)
+ (define-abbrev ,table
+ ,abbrev
+ ""
+ ',skeleton-name)))))
+#+end_src
+** Auto insert
+Allows inserting text immediately upon creating a new buffer with a
+given name. Supports skeletons for inserting text. To make it easier
+for later systems to define their own auto inserts, I define a
+~use-package~ keyword ~auto-insert~ which allows one to define an
+entry for ~auto-insert-alist~.
+#+begin_src emacs-lisp
+(use-package autoinsert
+ :straight nil
+ :demand t
+ :hook (after-init-hook . auto-insert-mode)
+ :config
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':auto-insert)
+ (defun use-package-normalize/:auto-insert (_name-symbol _keyword args)
+ args)
+ (defun use-package-handler/:auto-insert (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ `(add-to-list
+ 'auto-insert-alist
+ ',arg))
+ args)))))
+#+end_src
+** Yasnippet default
+Look at the snippets [[file:../.config/yasnippet/snippets/][folder]]
+for all snippets I've got.
+#+begin_src emacs-lisp
+(use-package yasnippet
+ :defer t
+ :hook
+ (prog-mode-hook . yas-minor-mode)
+ :general
+ (insert-leader
+ "i" #'yas-insert-snippet)
+ :config
+ (yas-load-directory (no-littering-expand-etc-file-name "yasnippet/snippets")))
+#+end_src