emacs/init.org
2021-02-16 09:06:14 -06:00

333 lines
11 KiB
Org Mode

#+TITLE: Init
#+AUTHOR: Chris Cochrun
* Early Init
#+PROPERTY: header-args:emacs-lisp :tangle early-init.el
#+begin_src emacs-lisp :tangle no
;;; early-init.el -*- lexical-binding: t; -*-
;; Emacs 27.1 introduced early-init.el, which is run before init.el, before
;; package and UI initialization happens, and before site files are loaded.
;; A big contributor to startup times is garbage collection. We up the gc
;; threshold to temporarily prevent it from running, then reset it later by
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
(setq gc-cons-threshold most-positive-fixnum)
;; In noninteractive sessions, prioritize non-byte-compiled source files to
;; prevent the use of stale byte-code. Otherwise, it saves us a little IO time
;; to skip the mtime checks on every *.elc file.
(setq load-prefer-newer noninteractive)
;; In Emacs 27+, package initialization occurs before `user-init-file' is
;; loaded, but after `early-init-file'. Doom handles package initialization, so
;; we must prevent Emacs from doing it early!
(setq package-enable-at-startup nil)
(fset #'package--ensure-init-file #'ignore) ; DEPRECATED Removed in 28
;; `file-name-handler-alist' is consulted on every `require', `load' and various
;; path/io functions. You get a minor speed up by nooping this. However, this
;; may cause problems on builds of Emacs where its site lisp files aren't
;; byte-compiled and we're forced to load the *.el.gz files (e.g. on Alpine)
(unless (daemonp)
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
;; Restore `file-name-handler-alist' later, because it is needed for handling
;; encrypted or compressed files, among other things.
(defun doom-reset-file-handler-alist-h ()
;; Re-add rather than `setq', because changes to `file-name-handler-alist'
;; since startup ought to be preserved.
(dolist (handler file-name-handler-alist)
(add-to-list 'doom--initial-file-name-handler-alist handler))
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h))
;; Ensure Doom is running out of this file's directory
(setq user-emacs-directory (file-name-directory load-file-name))
;; Load the heart of Doom Emacs
(load (concat user-emacs-directory "core/core") nil 'nomessage)
#+end_src
* Init
#+PROPERTY: header-args:emacs-lisp :tangle init.el
** Set basic UI config
Let's start by making some basic ui changes like turning off the scrollbar, toolbar, menu, tooltips, and setting our font and some things.
#+begin_src emacs-lisp :tangle yes
;;; init.el -*- lexical-binding: t; -*-
(setq inhibit-startup-message t)
(scroll-bar-mode -1)
(tool-bar-mode -1)
(tooltip-mode -1)
(set-fringe-mode 10)
(menu-bar-mode -1)
(blink-cursor-mode -1)
(column-number-mode +1)
(set-face-attribute 'default nil :font "VictorMono Nerd Font" :height 120)
(setq display-line-numbers-type 'relative)
#+end_src
Also, real quick let's make sure that ~<escape>~ works as the same as ~<C-g>~
#+begin_src emacs-lisp :tangle yes
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
#+end_src
** Let's bootstrap straight.el
#+begin_src emacs-lisp :tangle yes
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(setq straight-use-package-by-default t)
(straight-use-package 'use-package)
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package command-log-mode)
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package all-the-icons)
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package doom-modeline
:ensure t
:init
(doom-modeline-mode 1)
(setq doom-modeline-height 35
doom-modeline-bar-width 3
all-the-icons-scale-factor 0.9))
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package doom-themes
:ensure t
:init (load-theme 'doom-snazzy t))
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package which-key
:init (which-key-mode)
:config
(setq which-key-idle-delay 0.3))
#+end_src
** Keybindings
There are two major packages we need to get the functionality I desire. Evil and general.
#+begin_src emacs-lisp :tangle yes
(use-package evil
:init
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-i-jump nil
evil-want-C-u-scroll t
evil-want-C-u-delete t)
:config
(evil-mode +1))
#+end_src
This evil-collection package includes a lot of other evil based things.
#+begin_src emacs-lisp :tangle yes
(use-package evil-collection
:after evil
:config (evil-collection-init))
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package general
:init
(general-evil-setup)
:config
(general-create-definer chris/leader-keys
:keymaps '(normal visual emacs)
:prefix "SPC")
(chris/leader-keys
"t" '(:ignore t :which-key "toggle")
"f" '(:ignore t :which-key "file")
"w" '(:ignore t :which-key "window")
"tt" '(consult-theme :which-key "choose theme")
"ff" '(find-file :which-key "find file")
"fs" '(save-buffer :which-key "save")
"ww" '(other-window :which-key "other window")
))
#+end_src
#+begin_src emacs-lisp :tangle yes
(use-package evil-escape
:after evil
:init (evil-escape-mode +1)
:config (setq evil-escape-key-sequence "fd"))
#+end_src
** Completion
*** SELECTRUM
I prefer selectrum over Ivy or Helm for completions. It is using the basic completing read system and therefore it is more inline with basic emacs. Also, let's add prescient to be able to filter selectrum well. We'll add some keybindings too for easier navigation on the home row.
#+BEGIN_SRC elisp :tangle yes
(use-package selectrum
:init
(selectrum-mode +1)
:config
(general-define-key
:keymaps 'selectrum-minibuffer-map
"C-j" 'selectrum-next-candidate
"C-k" 'selectrum-previous-candidate
"C-S-j" 'selectrum-goto-end
"C-S-k" 'selectrum-goto-beginning
"TAB" 'selectrum-insert-current-candidate))
#+END_SRC
We need prescient so we can have smarter sorting and filtering by default. Ontop of that, setting persistance in prescient makes it get better over time.
#+begin_src emacs-lisp :tangle yes
(use-package prescient
:config
(prescient-persist-mode +1))
#+end_src
#+BEGIN_SRC elisp :tangle yes
(use-package selectrum-prescient
:init
(selectrum-prescient-mode +1))
#+END_SRC
#+BEGIN_SRC elisp :tangle no
;; enable company use of prescient
(company-prescient-mode +1)
;; enable magit to read with prescient
(setq magit-completing-read-function #'selectrum-completing-read)
#+END_SRC
Here we use posframe to make a prettier minibuffer. Posframe will work with EXWM with some tweaking, but I only stole some code for Ivy's posframe version, not selectrum's. So, I'll need to work on that.
#+BEGIN_SRC elisp :tangle no
(setq selectrum-display-action '(display-buffer-show-in-posframe))
(setq selectrum-display-action nil)
(defun display-buffer-show-in-posframe (buffer _alist)
(frame-root-window
(posframe-show buffer
:min-height 10
:min-width (/ (frame-width) 2)
:internal-border-width 1
:left-fringe 18
:right-fringe 18
:parent-frame nil
:z-group 'above
:poshandler 'posframe-poshandler-frame-center)))
(add-hook 'minibuffer-exit-hook 'posframe-delete-all)
#+END_SRC
#+RESULTS:
| exwm-input--on-minibuffer-exit | posframe-delete-all |
This is similar but using mini-frame. Mini-frame works well, but not if using exwm. With exwm the X windows get displayed above the mini-frame, so the minibuffer isn't visible. Best to let Selectrum or Consult push the frame up and view the vertical completions below the frame.
#+BEGIN_SRC elisp :tangle no
(mini-frame-mode +1)
(mini-frame-mode -1)
(setq resize-mini-frames t)
(custom-set-variables
'(mini-frame-show-parameters
'((top . 400)
(width . 0.7)
(left . 0.5))))
;; workaround bug#44080, should be fixed in version 27.2 and above, see #169
(define-advice fit-frame-to-buffer (:around (f &rest args) dont-skip-ws-for-mini-frame)
(cl-letf* ((orig (symbol-function #'window-text-pixel-size))
((symbol-function #'window-text-pixel-size)
(lambda (win from to &rest args)
(apply orig
(append (list win from
(if (and (window-minibuffer-p win)
(frame-root-window-p win)
(eq t to))
nil
to))
args)))))
(apply f args)))
#+END_SRC
#+RESULTS:
: fit-frame-to-buffer@dont-skip-ws-for-mini-frame
*** CONSULT
Consult has a lot of nice functions like Ivy's Counsel functions (enhanced searching functions), lets set some of them in the keymap so they are easily used.
#+begin_src emacs-lisp :tangle yes
(use-package consult)
#+end_src
#+begin_src emacs-lisp :tangle no
(map! :leader "s s" 'consult-line
:leader "f r" 'consult-recent-file)
#+end_src
*** MARGINALIA
Marginalia makes for some great decoration to our minibuffer completion items. Works great with Selectrum which does not have this out of the box.
#+begin_src emacs-lisp :tangle yes
;; Enable richer annotations using the Marginalia package
(use-package marginalia
:bind (:map minibuffer-local-map
("C-M-a" . marginalia-cycle)
;; :map embark-general-map
;; ("A" . marginalia-cycle)
)
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode)
;; When using Selectrum, ensure that Selectrum is refreshed when cycling annotations.
(advice-add #'marginalia-cycle :after
(lambda () (when (bound-and-true-p selectrum-mode) (selectrum-exhibit))))
;; Prefer richer, more heavy, annotations over the lighter default variant.
(setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
#+end_src
#+RESULTS:
** Help
#+begin_src emacs-lisp :tangle yes
(use-package helpful
:config
)
#+end_src
** Org Mode
Need to setup auto tangle yes
#+begin_src emacs-lisp :tangle yes
(use-package org
:config
(setq org-startup-indented t)
(defun chris/org-babel-tangle-config ()
(when (string-equal (buffer-file-name)
(expand-file-name "~/.personal-emacs/init.org"))
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'chris/org-babel-tangle-config))))
#+end_src