(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.
This commit is contained in:
738
Emacs/.config/emacs/core.org
Normal file
738
Emacs/.config/emacs/core.org
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user