diff --git a/Emacs/.config/emacs/config.org b/Emacs/.config/emacs/config.org index 4ddeee4..229aaa7 100644 --- a/Emacs/.config/emacs/config.org +++ b/Emacs/.config/emacs/config.org @@ -239,795 +239,6 @@ the borders for Emacs. :config (fringe-mode 0)) #+end_src -* Core packages - -** General -A good package for defining key bindings. In this case, I generate a -new 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. I also create defines for general root -bindings. -#+begin_src emacs-lisp -(use-package general - :demand t - :config - ;; General which key definitions for leaders - (general-def - :states '(normal motion) - "SPC" nil - "SPC ," '(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 "SPC ,") - - (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 default binds in Emacs -Bindings for core functionality -#+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") - "u" 'universal-argument - ";" '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")) - - (code-leader - "j" #'next-error - "k" #'previous-error - "c" #'compile - "C" #'recompile - "F" (list (proc (interactive) (find-file "~/Code/")) ':which-key "Open ~/Code/")) - - (file-leader - "f" #'find-file - "F" #'find-file-other-frame - "s" #'save-buffer - "p" (list (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 -Evil (Emacs VI Layer) is a package that brings the Vi experience to -Emacs. Packaged with it by default are: -- The modal system -- EX -- Vi mapping functions - -This provides a lot of stuff for the average vim user moving to Emacs. -However there are many other packages surrounding evil that port even -greater functionality from vim to Emacs. Surround, commenting, -multiple cursors and further support to other packages are configured -here. -*** 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 - "'" #'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 -#+begin_src emacs-lisp -(use-package evil-surround - :after evil - :config - (global-evil-surround-mode)) -#+end_src -*** Evil commentary -#+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 -Setup evil collection, but don't turn on the mode. Instead, I'll turn -on setups for specific modes I think benefit from it. -#+begin_src emacs-lisp -(use-package evil-collection - :after evil) -#+end_src -** Completion -Emacs is a text based interface. Though the standard model of -completion may be desirable to some it can be modernised through the -use of 'completion frameworks'. - -These frameworks handle input and present output from the user for -common commands, providing a differing interface to the one Emacs -comes with. Most of these completion frameworks provide a text based -menu that is actively filtered as more input is provided (progressive -input filtering). Along with these frameworks come added -functionality and applications to integrate into the Emacs environment -further. - -One may say that when using a completion framework there is no point -in using any other framework as they encompasses so much of the -default functionality. This is wrong: I'd argue that with a bit of -management and Emacs lisp it's totally possible to pick and mix your -options. For small number selections (like finding files) use -something like Ido and for something larger like searching buffers use -ivy. - -Along with frameworks, there is a configuration for the -completions-list, which is actually the original and default method of -completion within Emacs. When you first install Emacs without a -config, any 'completing-read' function leverages the completions-list when -~TAB~ is used. - -Though I believe Ido is a better completion system than the -completions-list, it still has it's place and can be used in tandem -with ido. -*** 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 -*** 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 -*** Completions-list -#+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 -*** Ivy -Ivy is a completion framework for Emacs, and my preferred (sometimes -second favourite) 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-c C-e" #'ivy-occur) - (general-def - :keymaps 'ivy-switch-buffer-map - "M-j" #'ivy-next-line-or-history - "M-k" #'ivy-previous-line-or-history) - :config - (require 'counsel nil t) - (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) - (with-eval-after-load "amx" - (setq amx-backend 'ivy))) -#+end_src -**** Counsel -Setup for counsel. Load after ivy and helpful. - -Along with that, set the help function and variable functions to their -helpful counterparts. -#+begin_src emacs-lisp -(use-package counsel - :after ivy - :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 nil - 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 -**** Ivy posframe -:PROPERTIES: -:header-args:emacs-lisp: :tangle no -:END: -This makes ivy minibuffer windows use child frames. Very nice eyecandy. -#+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 -**** 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. -#+begin_src emacs-lisp -(use-package counsel-etags - :after counsel - :general - (search-leader - "t" #'counsel-etags-find-tag)) -#+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. For example, you may replace the -'for' word in c-mode for [[https://en.wikipedia.org/wiki/Universal_quantification][universal quantification]]. Though this may -seem like useless eye candy, it has aided my comprehension and speed -of recognition (recognising symbols is easier than words). - -Here I provide a macro +pretty/set-alist. This macro works pretty -simply: given a mode hook, as well as a list of pairs typed (text to -substitute, symbol to replace with). Then I add a hook to the given -mode, setting the prettify-symbols-alist to the symbols given. - -I've declared it high up into my config so that the rest of my -packages can leverage it. Furthermore I've added a use-package -keyword which makes declaring this for language modes incredibly easy. -Checkout my [[C/C++][C/C++]] configuration for an example. - -2023-03-08: I've removed the +pretty/set-alist macro and corresponding -function as the use-package declaration is really enough. -#+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) - (let ((arg args) - (forms nil)) - (while arg - (let ((mode (caar arg)) - (rest (cdr (car arg)))) - (add-to-list - 'forms - `(add-hook - ',mode - (lambda nil - (setq prettify-symbols-alist ',rest) - (prettify-symbols-mode))))) - (setq arg (cdr arg))) - forms))))) -#+end_src - -Here's a collection of symbols I have currently that may be used -later. -#+begin_example -("null" . "Ø") -("list" . "ℓ") -("string" . "𝕊") -("true" . "⊤") -("false" . "⊥") -("char" . "ℂ") -("int" . "ℤ") -("float" . "ℝ") -("!" . "¬") -("&&" . "∧") -("||" . "∨") -("for" . "∀") -("return" . "⟼") -("print" . "ℙ") -("lambda" . "λ") -#+end_example -** Window management -Window management is really important. I find the default window -handling of Emacs incredibly annoying: sometimes consuming my windows, -sometimes creating new ones. Of course, anything and everything is -adaptable in Emacs, this behavior is no different. - -Here I create a use-package extension that manages the whole ordeal of -adding a new record to the display-buffer-alist, a useful abstraction -that makes it easy to manage the various buffers created by packages. -I also provide bindings for buffer management. -#+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) - (let ((arg args) - forms) - (while arg - (add-to-list 'forms - `(add-to-list 'display-buffer-alist - ',(car arg))) - (setq arg (cdr arg))) - forms))))) -#+end_src -*** Setup 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 - ("\\*\\(Wo\\)?Man.*" - (display-buffer-at-bottom) - (window-height . 0.25)) - - ("\\*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 system by which pieces of code can be inserted via -prefixes. For example, an 'if' snippet would work by first inserting -the word 'if' then pressing some _expansion key_ such as TAB. This -will insert a set of text that may be have some components that need -to be further filled by the user. - -The popular 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. - -However, Emacs provides its own 'auto typing' facilities. Abbrevs and -skeletons make up the popular solution within Emacs default. Abbrevs -are for simple expressions wherein there is only one user input (say, -getting today's time which only requires you asking for it). They -provide a lot of inbuilt functionality and are quite useful. -Skeletons, on the other hand, are for higher level insertions -*** 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 +autotyping/deff-abbrev (ABBREV-TABLE ABBREV EXPANSION) - "Wraps around define-abbrev to fill in some repeated stuff -when expansion is a function." - `(define-abbrev - ,ABBREV-TABLE - ,ABBREV - "" - (proc (insert ,EXPANSION)))) - - (setq save-abbrevs nil) - :config - (+autotyping/deff-abbrev - global-abbrev-table - "sdate" - (format-time-string "%Y-%m-%d" (current-time))) - - (+autotyping/deff-abbrev - global-abbrev-table - "stime" - (format-time-string "%H:%M:%S" (current-time))) - - (+autotyping/deff-abbrev - text-mode-abbrev-table - "sday" - (format-time-string "%A" (current-time))) - - (+autotyping/deff-abbrev - text-mode-abbrev-table - "smon" - (format-time-string "%B" (current-time)))) -#+end_src -*** Skeletons -Defining some basic skeletons and a macro to help generate an abbrev -as well. -#+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 -#+begin_src emacs-lisp -(use-package autoinsert - :straight nil - :hook (after-init-hook . auto-insert-mode) - :config - (add-to-list - 'auto-insert-alist - '(("\\.html\\'" . "HTML Skeleton") - "" - " - - - - - "(read-string "Enter title: ") | """ - - - - - - - - - - - -" - _ - " -")) - (add-to-list - 'auto-insert-alist - '(("Makefile" . "Makefile skeleton") - "" - "CC=g++ -CFLAGS=-Wall -ggdb -OBJECTS=main.o -OUT=main -ARGS= - -%.o: %.cpp - $(CC) $(CFLAGS) -c $^ -o $@ - -$(OUT): $(OBJECTS) - $(CC) $(CFLAGS) $^ -o $@ - -.PHONY: -clean: - rm -rfv $(OUT) $(OBJECTS) - -.PHONY: run -run: $(OUT) - ./$^ $(ARGS) - -.PHONY: memcheck -memcheck: $(OUT) - sh /etc/profile.d/debuginfod.sh && valgrind --leak-check=full -s --tool=memcheck ./$^ $(ARGS)" - _))) -#+end_src -*** Yasnippet default -Setup global mode after evil mode has been loaded -#+begin_src emacs-lisp -(use-package yasnippet - :after evil - :hook - (prog-mode-hook . yas-minor-mode) - (text-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 ** Mode line A mode line in an editor can provide a LOT of information, or very little. I customised the Emacs modeline to give me a bit of info, @@ -1157,36 +368,778 @@ with colouring and a ton of presentations to choose from. (evil telephone-line-evil-tag-segment))) (telephone-line-mode)) #+end_src -** Olivetti -Olivetti provides a focus mode for Emacs, which makes it look a bit -nicer with fringes. I also define ~+olivetti-mode~ which will -remember and clear up any window configurations on the frame, then -when turned off will reinsert them - provides a nice way to quickly -focus on a buffer. +* Core packages +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 olivetti - :commands (+olivetti-mode) - :general - (mode-leader - "o" #'+olivetti-mode) - :init - (setq-default olivetti-body-width 0.6) - (setq olivetti-style nil) - (add-hook 'olivetti-mode-on-hook (proc (interactive) (text-scale-increase 1))) - (add-hook 'olivetti-mode-off-hook (proc (interactive) (text-scale-decrease 1))) +(use-package general + :demand t :config - (defun +olivetti-mode () - (interactive) - (if (not olivetti-mode) - (progn - (window-configuration-to-register 1) - (delete-other-windows) - (olivetti-mode t)) - (jump-to-register 1) - (olivetti-mode 0)))) + ;; General which key definitions for leaders + (general-def + :states '(normal motion) + "SPC" nil + "SPC ," '(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 "SPC ,") + + (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") + "u" 'universal-argument + ";" '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")) + + (code-leader + "j" #'next-error + "k" #'previous-error + "c" #'compile + "C" #'recompile + "F" (list (proc (interactive) (find-file "~/Code/")) ':which-key "Open ~/Code/")) + + (file-leader + "f" #'find-file + "F" #'find-file-other-frame + "s" #'save-buffer + "p" (list (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 + "'" #'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-c C-e" #'ivy-occur) + (general-def + :keymaps 'ivy-switch-buffer-map + "M-j" #'ivy-next-line-or-history + "M-k" #'ivy-previous-line-or-history) + :config + (require 'counsel nil t) + (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) + (with-eval-after-load "amx" + (setq amx-backend 'ivy))) +#+end_src +**** Counsel +Setup for counsel. Load after ivy and helpful. +#+begin_src emacs-lisp +(use-package counsel + :after ivy + :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 nil + 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 +**** Ivy posframe +:PROPERTIES: +:header-args:emacs-lisp: :tangle no +:END: +This makes ivy minibuffer windows use child frames. Very nice eyecandy. +#+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 +**** 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 +*** 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) + (let ((arg args) + (forms nil)) + (while arg + (let ((mode (caar arg)) + (rest (cdr (car arg)))) + (add-to-list + 'forms + `(add-hook + ',mode + (lambda nil + (setq prettify-symbols-alist ',rest) + (prettify-symbols-mode))))) + (setq arg (cdr arg))) + forms))))) +#+end_src + +Here's a collection of keywords and their associated symbols, for a +pseudo language. +#+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 +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. +#+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) + (let ((arg args) + forms) + (while arg + (add-to-list 'forms + `(add-to-list 'display-buffer-alist + ',(car arg))) + (setq arg (cdr arg))) + forms))))) +#+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 + ("\\*\\(Wo\\)?Man.*" + (display-buffer-at-bottom) + (window-height . 0.25)) + + ("\\*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 +autotyping/deff-abbrev (ABBREV-TABLE ABBREV EXPANSION) + "Wraps around define-abbrev to fill in some repeated stuff +when expansion is a function." + `(define-abbrev + ,ABBREV-TABLE + ,ABBREV + "" + (proc (insert ,EXPANSION)))) + + (setq save-abbrevs nil) + :config + (+autotyping/deff-abbrev + global-abbrev-table + "sdate" + (format-time-string "%Y-%m-%d" (current-time))) + + (+autotyping/deff-abbrev + global-abbrev-table + "stime" + (format-time-string "%H:%M:%S" (current-time))) + + (+autotyping/deff-abbrev + text-mode-abbrev-table + "sday" + (format-time-string "%A" (current-time))) + + (+autotyping/deff-abbrev + text-mode-abbrev-table + "smon" + (format-time-string "%B" (current-time)))) +#+end_src +*** Skeletons +Defining some basic skeletons and a macro to help generate an abbrev +as well. +#+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 on creating of a new buffer with a given name. +Supports skeletons for inserting text. Here I define an HTML skeleton +and a Makefile skeleton. +#+begin_src emacs-lisp +(use-package autoinsert + :straight nil + :hook (after-init-hook . auto-insert-mode) + :config + (add-to-list + 'auto-insert-alist + '(("\\.html\\'" . "HTML Skeleton") + "" + " + + + + + "(read-string "Enter title: ") | """ + + + + + + + + + + + +" + _ + " +")) + (add-to-list + 'auto-insert-alist + '(("Makefile" . "Makefile skeleton") + "" + "CC=g++ +CFLAGS=-Wall -ggdb +OBJECTS=main.o +OUT=main +ARGS= + +%.o: %.cpp + $(CC) $(CFLAGS) -c $^ -o $@ + +$(OUT): $(OBJECTS) + $(CC) $(CFLAGS) $^ -o $@ + +.PHONY: +clean: + rm -rfv $(OUT) $(OBJECTS) + +.PHONY: run +run: $(OUT) + ./$^ $(ARGS) + +.PHONY: memcheck +memcheck: $(OUT) + sh /etc/profile.d/debuginfod.sh && valgrind --leak-check=full -s --tool=memcheck ./$^ $(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 + :after evil + :hook + (prog-mode-hook . yas-minor-mode) + (text-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 * Small packages ** ISearch +ISearch is the default incremental search application in Emacs. I use +~evil-search-forward~ so I don't interact with isearch that much, but +I may need it occasionally. #+begin_src emacs-lisp (use-package isearch :straight nil @@ -1195,6 +1148,8 @@ focus on a buffer. "M-s" #'isearch-repeat-forward)) #+end_src ** Info +Info is GNU's attempt at better man pages. Most Emacs packages have +info pages so I'd like nice navigation options. #+begin_src emacs-lisp (use-package info :straight nil @@ -1208,9 +1163,10 @@ focus on a buffer. "L" #'Info-history-forward)) #+end_src ** Display line numbers -I don't like using this mode by default, but I'd like to configure it -if possible. Line numbers are a necessary evil a lot of times, and -it's useful for presentations. +I don't really like line numbers, I find them similar to [[*Fringes][fringes]] as +useless space, but at least it provides some information. Sometimes +it can help with doing repeated commands so a toggle option is +necessary. #+begin_src emacs-lisp (use-package display-line-numbers :straight nil @@ -1221,22 +1177,26 @@ it's useful for presentations. :init (setq-default display-line-numbers-type 'relative)) #+end_src -** esup (profiling) +** esup I used to be able to just use [[file:elisp/profiler-dotemacs.el][profile-dotemacs.el]], when my Emacs config was smaller, but now it tells me very little information about -where my setup is inefficient. Just found this ~esup~ thing and it -works perfectly, exactly how I would prefer getting this kind of -information. +where my setup is inefficient due to the literate config. Just found +this ~esup~ thing and it works perfectly, exactly how I would prefer +getting this kind of information. It runs an external Emacs instance +and collects information from it, so it doesn't require restarting +Emacs to profile. #+begin_src emacs-lisp (use-package esup :defer t) #+end_src ** xref -Find definitions, references using tags for free! Such an underrated -utility, particularly now that I'm not using Eglot (in some sense, -returning to the nature of Emacs). All you need is a way of -generating tags, probably a make recipe. +Find definitions, references and general objects using tags without +external packages. Provided by default in Emacs and just requires a +way of generating a =TAGS= file for your project. Helps with minimal +setups for programming without heavier packages like [[*Eglot][Eglot]]. + +[[*Projectile][Projectile]] provides a nice way to generate tags. #+begin_src emacs-lisp (use-package xref :straight nil @@ -1262,21 +1222,24 @@ generating tags, probably a make recipe. "q" #'quit-window)) #+end_src ** Hl-line -Hl-line is a useful tool, best line indicator in the game. +Highlights the current line, much better than a blinking cursor. #+begin_src emacs-lisp (use-package hl-line :defer t :hook (text-mode-hook . hl-line-mode)) #+end_src ** Recentf -Recentf makes it easy to +Recentf provides a method of keeping track of recently opened files. #+begin_src emacs-lisp (use-package recentf :straight nil :hook (emacs-startup-hook . recentf-mode)) #+end_src ** Projectile -Setup projectile, along with the tags command. +Projectile is a project management package which integrates with Emacs +very well. It essentially provides alternative Emacs commands scoped +to the current 'project', based on differing signs that a directory is +a 'project'. #+begin_src emacs-lisp (use-package projectile :after evil @@ -1287,8 +1250,7 @@ Setup projectile, along with the tags command. (setq projectile-tags-command "ctags -Re -f \"%s\" %s \"%s\"")) #+end_src *** Counsel projectile -Counsel projectile provides the ivy interface to projectile commands, -which is really useful. +Counsel integration for projectile commands, very nice. #+begin_src emacs-lisp (use-package counsel-projectile :after (projectile counsel) @@ -1303,17 +1265,16 @@ need to use it. (use-package avy :after evil :general - (search-leader - "l" #'avy-goto-line) (nmmap - (kbd "C-s") #'avy-goto-char-timer - (kbd "M-s") #'isearch-forward)) + "C-s" #'avy-goto-char-timer + "M-s" #'isearch-forward) + (search-leader + "l" #'avy-goto-line)) #+end_src ** Ace window Though evil provides a great many features in terms of window -management, much greater than what's easily available in Emacs, ace -window can provide some nicer chords for higher management of windows -(closing, switching, etc). +management, ace window can provide some nicer chords for higher +management of windows (closing, switching, etc). #+begin_src emacs-lisp (use-package ace-window @@ -1325,8 +1286,9 @@ window can provide some nicer chords for higher management of windows [remap evil-window-next] #'ace-window)) #+end_src ** Helpful -Basic setup that replaces commands and configures -~display-buffer-alist~ for helpful. +Helpful provides a modernised interface for some common help +commands. I replace ~describe-function~, ~describe-variable~ and +~describe-key~ by their helpful counterparts. #+begin_src emacs-lisp (use-package helpful :after ivy @@ -1345,7 +1307,8 @@ Basic setup that replaces commands and configures (evil-define-key 'normal helpful-mode-map "q" #'quit-window)) #+end_src ** Which-key -Pretty simple, just activate after init. +Which key uses the minibuffer when performing a keybind to provide +possible options for the next key. #+begin_src emacs-lisp (use-package which-key :config @@ -1353,7 +1316,7 @@ Pretty simple, just activate after init. #+end_src ** Keychord Keychord is only really here for this one chord I wish to define: "jk" -for exiting insert state. Otherwise, I don't really need it. +for exiting insert state. #+begin_src emacs-lisp (use-package key-chord :after evil @@ -1362,35 +1325,27 @@ for exiting insert state. Otherwise, I don't really need it. (key-chord-mode)) #+end_src ** (Rip)grep -Grep is likely one of the most important programs ever invented; a -must-have tool for any Linux users inventory. It is a searching -utility that allows one to search files for certain regex patterns. -The fact that there have been so many attempts to replace grep (with -limited success) only goes to show how important its general function -is to people. +Grep is a great piece of software, a necessary tool in any Linux +user's inventory. By default Emacs has a family of functions to use +grep, presenting results in a ~compilation~ style. ~grep~ searches +files, ~rgrep~ searches in a directory using the ~find~ program and +~zgrep~ searches archives. This is a great solution for a general +computer environment; essentially all Linux installs will have ~grep~ +and ~find~ installed. -Ripgrep is a grep-like utility written in Rust. It subsumes not only -the ability to search a given file but also to search multiple files -within a directory (which is usually only done by composing the -program find with grep to search multiple files). It is incredibly -fast by virtue of its regex optimisations and the use of ignore files -such as ~.gitignore~ to filter files when searching. +Ripgrep is a Rust program that attempts to perform better than grep, +and it actually does. This is because of a set of optimisations, such +as checking the =.gitignore= to exclude certain files from being +searched. The ripgrep package provides utilities to ripgrep projects +and files for strings. Though [[*Ivy][ivy]] comes with ~counsel-rg~, it uses +Ivy's completion framework rather than the ~compilation~ style +buffers, which sometimes proves very useful. -Grep has default Emacs utilities that use a ~compilation~ style buffer -to search a variety of differing data sets. ~grep~ searches files, -~rgrep~ searches in a directory using the ~find~ binary and ~zgrep~ -searches archives. This is a great solution for most computer -environments as basically all of them will have grep and find -installed. Even when you ~ssh~ into a remote machine, they're likely -to have these tools. - -The ripgrep package provides utilities to ripgrep projects and files -for strings via the rg binary. Though [[*Ivy][ivy]] comes with ~counsel-rg~ -using it makes me dependent on the ivy framework, and this -configuration is intentionally built to be modular and switchable. Of -course, this requires installing the rg binary which is available in -most repositories nowadays. +Of course, this requires installing the rg binary which is available +in most repositories nowadays. *** Grep +I have no use for standard 'grep'; ~counsel-swiper~ does the same +thing faster and within Emacs lisp. ~rgrep~ is useful though. #+begin_src emacs-lisp (use-package grep :display @@ -1423,6 +1378,34 @@ most repositories nowadays. rg-default-alias-fallback "all" rg-buffer-name "*ripgrep*")) #+end_src +** Olivetti +Olivetti provides a focus mode for Emacs, which makes it look a bit +nicer with fringes. I also define ~+olivetti-mode~ which will +remember and clear up any window configurations on the frame, then +when turned off will reinsert them - provides a nice way to quickly +focus on a buffer. +#+begin_src emacs-lisp +(use-package olivetti + :commands (+olivetti-mode) + :general + (mode-leader + "o" #'+olivetti-mode) + :init + (setq-default olivetti-body-width 0.6) + (setq olivetti-style nil) + (add-hook 'olivetti-mode-on-hook (proc (interactive) (text-scale-increase 1))) + (add-hook 'olivetti-mode-off-hook (proc (interactive) (text-scale-decrease 1))) + :config + (defun +olivetti-mode () + (interactive) + (if (not olivetti-mode) + (progn + (window-configuration-to-register 1) + (delete-other-windows) + (olivetti-mode t)) + (jump-to-register 1) + (olivetti-mode 0)))) +#+end_src ** All the Icons Nice set of icons with a great user interface to manage them. #+begin_src emacs-lisp @@ -1457,9 +1440,13 @@ at last. (save-place-mode)) #+end_src * Applications +Applications are greater than packages; they provide a set of +functionality to create an interface in Emacs. Emacs comes with +applications and others may be installed. ** Dashboard Dashboard creates a custom dashboard for Emacs that replaces the -initial startup screen in default Emacs. +initial startup screen in default Emacs. It has a lot of customising +options. #+begin_src emacs-lisp (use-package dashboard :straight t @@ -1499,18 +1486,24 @@ initial startup screen in default Emacs. (dashboard-setup-startup-hook)) #+end_src ** EWW +Emacs Web Wowser is the inbuilt text based web browser for Emacs. It +can render images and basic CSS styles but doesn't have a JavaScript +engine, which makes sense as it's primarily a text interface. #+begin_src emacs-lisp (use-package eww :defer t + :general + (app-leader + "w" #'eww) :straight nil :config (with-eval-after-load "evil-collection" (evil-collection-eww-setup))) #+end_src ** Calendar -Calendar is a simple inbuilt application within Emacs that helps with -date functionalities. I add functionality to copy dates from the -calendar to the kill ring and bind it to "Y". +Calendar is a simple inbuilt application that helps with date +functionalities. I add functionality to copy dates from the calendar +to the kill ring and bind it to "Y". #+begin_src emacs-lisp (use-package calendar :straight nil @@ -2016,6 +2009,9 @@ don't need to write everything myself. (display-buffer-same-window)) :general (leader "g" '(magit-status :which-key "Magit")) + (nmmap + :keymaps 'magit-status-mode-map + "TAB" #'magit-section-toggle) :init (setq vc-follow-symlinks t) (with-eval-after-load "autoinsert" @@ -2025,6 +2021,8 @@ don't need to write everything myself. (read-string "Enter simple description: ") "\n\n" _))) :config + (with-eval-after-load "evil" + (evil-set-initial-state 'magit-status-mode 'motion)) (with-eval-after-load "evil-collection" (evil-collection-magit-setup))) #+end_src @@ -2165,8 +2163,13 @@ Of course Emacs has a cool screensaver software. Colourising the compilation buffer so ANSI colour codes get computed. #+begin_src emacs-lisp (use-package compile - :defer t :straight nil + :general + (code-leader + "j" #'next-error + "k" #'previous-error + "c" #'compile + "C" #'recompile) :display ("\\*compilation\\*" (display-buffer-at-bottom) @@ -2179,10 +2182,9 @@ Colourising the compilation buffer so ANSI colour codes get computed. (ansi-color-apply-on-region (point-min) (point-max)))) (add-hook 'compilation-filter-hook #'+compile/colourise)) #+end_src -* Major modes, programming and text -Setups for common major modes and languages. -** Text Configuration -Standard packages and configurations for the text-mode. +* Text modes +Standard packages and configurations for text-mode and its derived +modes. *** Flyspell Flyspell allows me to quickly spell check text documents. I use flyspell primarily in org mode, as that is my preferred prose writing @@ -2239,7 +2241,9 @@ limit), so set it for specific modes need the help. whitespace-line-column 80)) #+end_src *** Set auto-fill-mode for all text-modes -Auto fill mode is nice for most text modes, 80 char limit is great. +Auto fill mode automatically newlines text on 80 characters, which +looks nice and integrates well with Evil's sentence and paragraph text +objects. #+begin_src emacs-lisp (add-hook 'text-mode-hook #'auto-fill-mode) #+end_src @@ -2270,8 +2274,10 @@ context and easier to use. (sp-local-pair sp-lisp-modes "(" ")" :unless '(:rem sp-point-before-same-p)) (require 'smartparens-config)) #+end_src -** Programming Configuration -*** Eldoc +* Programming modes +Packages that help with programming in general, providing IDE like +capabilities. +** Eldoc Eldoc presents documentation to the user upon placing ones cursor upon any symbol. This is very useful when programming as it: - presents the arguments of functions while writing calls for them @@ -2292,10 +2298,17 @@ in the minibuffer. A lot cleaner. (setq eldoc-box-position-function #'eldoc-box--default-upper-corner-position-function eldoc-box-clear-with-C-g t)) #+end_src -*** Eglot -Eglot is a library of packages to communicate with LSP servers for -better programming capabilities. Interactions with a server provide -results to the client, done through JSON. +** Eglot +Eglot is package to communicate with LSP servers for better +programming capabilities. Interactions with a server provide results +to the client, done through JSON. + +NOTE: Emacs 28.1 comes with better JSON parsing, which makes Eglot +much faster. + +2023-03-26: I've found Eglot to be useful sometimes, but many of the +projects I work on don't require a heavy server setup to efficiently +edit and check for errors; Emacs provides a lot of functionality. #+begin_src emacs-lisp (use-package eglot :after project @@ -2310,10 +2323,9 @@ results to the client, done through JSON. ;; :init ;; (setq eglot-stay-out-of '(flymake)) :config - (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd")) - (add-to-list 'eglot-server-programs `(csharp-mode "~/.local/src/omnisharp-roslyn/run" "-lsp"))) + (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd"))) #+end_src -*** Flycheck +** Flycheck Flycheck is the checking system for Emacs. I don't necessarily like having all my code checked all the time, so I haven't added a hook to prog-mode as it would be better for me to decide when I want checking @@ -2337,7 +2349,7 @@ and when I don't. (with-eval-after-load "evil-collection" (evil-collection-flycheck-setup))) #+end_src -*** Tabs and spaces +** Tabs and spaces By default, turn off tabs and set the tab width to two. #+begin_src emacs-lisp (setq-default indent-tabs-mode nil @@ -2350,11 +2362,11 @@ However, if necessary later, define a function that may activate tabs locally. (interactive) (setq-local indent-tabs-mode t)) #+end_src -*** Highlight todo items -TODO items are highlighted in org buffers, but not necessarily in -every buffer. This minor mode highlights all TODO like items via a -list of strings to match. It also configures faces to use when -highlighting. +** Highlight todo items +TODO items are highlighted in org-mode, but not necessarily in every +mode. This minor mode highlights all TODO like items via a list of +strings to match. It also configures faces to use when highlighting. +I hook it to prog-mode. #+begin_src emacs-lisp (use-package hl-todo @@ -2364,20 +2376,20 @@ highlighting. (setq hl-todo-keyword-faces '(("TODO" . "#E50000") ("WAIT" . "#00CC00") - ("FIXME" . "#d02090"))) - ) + ("FIXME" . "#d02090")))) #+end_src -*** Hide-show mode -Turn on ~hs-minor-mode~ for all prog-mode. +** Hide-show mode +Turn on ~hs-minor-mode~ for all prog-mode. This provides folds for +free. #+begin_src emacs-lisp (use-package hideshow :straight nil :hook (prog-mode-hook . hs-minor-mode)) #+end_src -*** Aggressive indenting -Essentially my dream editing experience, when I type stuff in try and -indent it for me on the fly. Just checkout the [[https://github.com/Malabarba/aggressive-indent-mode][page]], any way I -describe it won't do it justice. +** Aggressive indenting +Essentially my dream editing experience: when I type stuff in, try and +indent it for me on the fly. Just checkout the [[https://github.com/Malabarba/aggressive-indent-mode][page]], any description +I give won't do it justice. #+begin_src emacs-lisp (use-package aggressive-indent @@ -2386,11 +2398,13 @@ describe it won't do it justice. :hook (prog-mode-hook . aggressive-indent-mode)) #+end_src +* Languages +Configuration for specific languages or file formats. ** PDF -I use PDFs mostly for reading reports or papers, providing great -formatting options. Though Emacs isn't my favourite application for -viewing PDFs (I highly recommend [[https://pwmt.org/projects/zathura/][Zathura]]), similar to most things with -Emacs, having a PDF viewer builtin can be a very useful asset. +I use PDFs mostly for reading reports or papers. Though Emacs isn't +my preferred application for viewing PDFs (I highly recommend +[[https://pwmt.org/projects/zathura/][Zathura]]), similar to most things with Emacs, having a PDF viewer +builtin can be a very useful asset. For example if I were editing an org document which I was eventually compiling into a PDF, my workflow would be much smoother with a PDF @@ -2414,8 +2428,10 @@ There is no proper PDF viewing without this package. (evil-collection-pdf-setup))) #+end_src *** PDF grep -PDF grep is a Linux tool that allows for searches against PDFs similar -to standard grep (but for PDFs!). +PDF grep is a Linux tool that allows for searches against the text +inside of PDFs similar to standard grep. This cannot be performed by +standard grep due to how PDFs are encoded; they are not a clear text +format. #+begin_src emacs-lisp (use-package pdfgrep :after pdf-tools @@ -2426,8 +2442,10 @@ to standard grep (but for PDFs!). "M-g" #'pdfgrep)) #+end_src ** SQL -SQL package, with support for connecting to common database types -(sqlite, mysql, etc) for auto completion and query execution. +The default SQL package provides support for connecting to common +database types (sqlite, mysql, etc) for auto completion and query +execution. I don't use SQL currently but whenever I need it it's +there. #+begin_src emacs-lisp (use-package sql :straight nil @@ -2438,9 +2456,9 @@ SQL package, with support for connecting to common database types :PROPERTIES: :header-args:emacs-lisp: :tangle no :END: -Check out [[file:elisp/ada-mode.el][ada-mode*]], my custom ~ada-mode~ that replaces the default one. -This mode just colourises stuff, and uses eglot to do the important -stuff. +Check out [[file:elisp/ada-mode.el][ada-mode]], my custom ~ada-mode~ that replaces the default +one. This mode just colourises stuff, and uses eglot and a language +server to do the hard work. #+begin_src emacs-lisp (use-package ada-mode @@ -2464,6 +2482,7 @@ the [[https://elpa.gnu.org/packages/nhexl-mode.html][page]] yourself. :mode "\\.bin") #+end_src ** Org +Org mode *** Org Core Variables Tons of variables for org-mode, including a ton of latex ones. Can't really explain because it sets up quite a lot of local stuff. Also I