X-Git-Url: https://git.shemshak.org/~bandali/configs/blobdiff_plain/35ea1ba40ebdaff54de627a98d2785058cf74ac1..51fb5bd8c02b8a0a6fd698309f40527be6abb3ac:/emacs/init.org?ds=inline diff --git a/emacs/init.org b/emacs/init.org index 1801baf..f404ad1 100644 --- a/emacs/init.org +++ b/emacs/init.org @@ -3,11 +3,23 @@ * Intro -TODO: description +This org file is tangled to [[./init.el][init.el]] and constitutes my Emacs +configuration. =straight.el=, =use-package=, =general.el=, =exwm=, +=org-mode=, and =magit= are some of the awesome packages powering my +Emacs setup. -TODO: toc +* Contents :toc_1:noexport: + +- [[#intro][Intro]] +- [[#header][Header]] +- [[#initial-setup][Initial setup]] +- [[#core][Core]] +- [[#footer][Footer]] * Header +:PROPERTIES: +:CUSTOM_ID: header +:END: ** First line @@ -41,7 +53,7 @@ file. ** Commentary -#+begin_src emacs-lisp +#+begin_src emacs-lisp :comments none ;;; Commentary: ;; Emacs configuration of Amin Bandali, computer scientist and functional @@ -50,17 +62,403 @@ file. ;; THIS FILE IS AUTO-GENERATED FROM `init.org'. #+end_src -* Config +** Naming conventions -#+begin_src emacs-lisp +The conventions below were inspired by [[https://github.com/hlissner/doom-emacs][Doom]]'s conventions, found +[[https://github.com/hlissner/doom-emacs/blob/5dacbb7cb1c6ac246a9ccd15e6c4290def67757c/core/core.el#L3-L17][here]]. Naturally, I use my initials, =ab=, instead of =doom=. + +#+begin_src emacs-lisp :comments none +;; Naming conventions: +;; +;; ab-... public variables or non-interactive functions +;; ab--... private anything (non-interactive), not safe for direct use +;; ab/... an interactive function; safe for M-x or keybinding +;; ab:... an evil operator, motion, or command +;; ab|... a hook function +;; ab*... an advising function +;; ab@... a hydra command +;; ...! a macro +#+end_src + +* Initial setup +:PROPERTIES: +:CUSTOM_ID: initial-setup +:END: + +#+begin_src emacs-lisp :comments none ;;; Code: #+end_src -TODO +** Startup time + +Measure and display startup time. Also, temporarily increase +~gc-cons-threshhold~ during startup to reduce reduce garbage +collection frequency. Taken from [[https://github.com/dieggsy/dotfiles/tree/3d95bc08033920e077855caf545a975eba52d28d/emacs.d#startup-time][here]]. + +#+begin_src emacs-lisp +(defconst ab--emacs-start-time (current-time)) +(defconst ab--gc-cons-threshold gc-cons-threshold) +(defconst ab--gc-cons-percentage gc-cons-percentage) +(defvar ab--file-name-handler-alist file-name-handler-alist) +(setq gc-cons-threshold 400000000 + gc-cons-percentage 0.6 + file-name-handler-alist nil + ;; sidesteps a bug when profiling with esup + esup-child-profile-require-level 0) +#+end_src + +Reset the variables back to default after init. + +#+begin_src emacs-lisp +(add-hook + 'after-init-hook + `(lambda () + (setq gc-cons-threshold ab--gc-cons-threshold + gc-cons-percentage ab--gc-cons-percentage + file-name-handler-alist ab--file-name-handler-alist) + (let ((elapsed (float-time (time-subtract (current-time) + ab--emacs-start-time)))) + (message "Loading %s...done (%.3fs) [after-init]" + ,load-file-name elapsed)))) +#+end_src + +** Package management + +*** =straight.el= + +#+begin_quote +Next-generation, purely functional package manager for the Emacs +hacker. +#+end_quote + +=straight.el= allows me to have a fully reproducible Emacs setup. + +**** Bootstrap + +#+begin_src emacs-lisp +(let ((bootstrap-file (concat user-emacs-directory "straight/repos/straight.el/bootstrap.el")) + (bootstrap-version 3)) + (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)) +#+end_src + +**** Useful helpers + +#+begin_src emacs-lisp +(defun ab/reload-init () + "Reload init.el." + (interactive) + (straight-transaction + (straight-mark-transaction-as-init) + (message "Reloading init.el...") + (load user-init-file nil 'nomessage) + (message "Reloading init.el... done."))) + +(defun ab/eval-buffer () + "Evaluate the current buffer as Elisp code." + (interactive) + (message "Evaluating %s..." (buffer-name)) + (straight-transaction + (if (null buffer-file-name) + (eval-buffer) + (when (string= buffer-file-name user-init-file) + (straight-mark-transaction-as-init)) + (load-file buffer-file-name))) + (message "Evaluating %s... done." (buffer-name))) +#+end_src + +*** =use-package= + +#+begin_quote +A use-package declaration for simplifying your .emacs +#+end_quote + +=use-package= is an awesome utility for managing and configuring +packages in a neatly organized way and without compromising on +performance. So let's install it using =striaght.el= and have it use +=straight.el= for installing packages. + +#+begin_src emacs-lisp +(straight-use-package 'use-package) +(setq straight-use-package-by-default t) +#+end_src + +** No littering in =~/.emacs.d= + +#+begin_quote +Help keeping ~/.emacs.d clean +#+end_quote + +By default, even for Emacs' built-in packages, the configuration files +and persistent data are all over the place. Use =no-littering= to help +contain the mess. + +#+begin_src emacs-lisp +(use-package no-littering + :demand t + :config + (savehist-mode 1) + (add-to-list 'savehist-additional-variables 'kill-ring) + (save-place-mode 1) + (setq auto-save-file-name-transforms + `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))) +#+end_src + +** Custom file (=custom.el=) + +I'm not planning on using the custom file much, but even so, I +definitely don't want it mixing with =init.el=. So, here, let's give +it it's own file. + +#+begin_src emacs-lisp +(setq custom-file (no-littering-expand-etc-file-name "custom.el")) +(when (file-exists-p custom-file) + (load custom-file)) +#+end_src + +** Better =$PATH= handling + +Let's use [[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] to make Emacs use the =$PATH= as set up +in my shell. + +#+begin_src emacs-lisp +(use-package exec-path-from-shell + :defer 1 + :init + (setq exec-path-from-shell-check-startup-files nil) + :config + (exec-path-from-shell-initialize) + ;; while we're at it, let's fix access to our running ssh-agent + (exec-path-from-shell-copy-env "SSH_AGENT_PID") + (exec-path-from-shell-copy-env "SSH_AUTH_SOCK")) +#+end_src + +** Server + +Start server if not already running. Alternatively, can be done by +issuing =emacs --daemon= in the terminal, which can be automated with +a systemd service or using =brew services start emacs= on macOS. I use +Emacs as my window manager (via =exwm=), so I always start Emacs on +login; so starting the server from inside Emacs is good enough for me. + +See [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server][Using Emacs as a Server]]. + +#+begin_src emacs-lisp +(require 'server) +(unless (server-running-p) + (server-start)) +#+end_src + +* Core +:PROPERTIES: +:CUSTOM_ID: core +:END: + +** Defaults + +*** Disable disabled commands + +Emacs disables some commands by default that could persumably be +confusing for novice users. Let's disable that. + +#+begin_src emacs-lisp +(setq disabled-command-function nil) +#+end_src + +*** Kill-ring + +Save what I copy into clipboard from other applications into Emacs' +kill-ring, which would allow me to still be able to easily access it +in case I kill (cut or copy) something else inside Emacs before +yanking (pasting) what I'd originally intended to. + +#+begin_src emacs-lisp +(setq save-interprogram-paste-before-kill t) +#+end_src + +*** Keep more =*Messages*= + +#+begin_src emacs-lisp +(setq message-log-max 10000) +#+end_src + +*** Minibuffer + +#+begin_src emacs-lisp +(setq enable-recursive-minibuffers t + resize-mini-windows t) +#+end_src + +*** Lazy-person-friendly yes/no prompts + +Lazy people would prefer to type fewer keystrokes, especially for yes +or no questions. I'm lazy. + +#+begin_src emacs-lisp +(defalias 'yes-or-no-p #'y-or-n-p) +#+end_src + +*** =*scratch*= + +Let's customize the =*scratch*= buffer a bit. First off, I don't need +the default hint. + +#+begin_src emacs-lisp +(setq initial-scratch-message "") +#+end_src + +Also, let's use Text mode as the major mode, in case I want to +customize it (=*scratch*='s default major mode, Fundamental mode, +can't really be customized). + +#+begin_src emacs-lisp +(setq initial-major-mode 'text-mode) +#+end_src + +*** More useful frame titles + +Show either the file name or the buffer name (in case the buffer isn't +visiting a file). Borrowed from Emacs Prelude. + +#+begin_src emacs-lisp +(setq frame-title-format + '("" invocation-name " - " + (:eval (if (buffer-file-name) + (abbreviate-file-name (buffer-file-name)) + "%b")))) +#+end_src + +*** Backups + +Emacs' default backup settings aren't that great. Let's use more +sensible options. See documentation for the ~make-backup-file~ +variable. + +#+begin_src emacs-lisp +(setq backup-by-copying t + version-control t) +#+end_src + +** Packages + +The packages in this section are absolutely essential to my everyday +workflow, and they play key roles in how I do my computing. They +immensely enhance the Emacs experience for me; both using Emacs, and +customizing it. + +*** [[https://github.com/noctuid/general.el][general.el]] + +#+begin_quote +More convenient key definitions in emacs +#+end_quote + +More like /the most/ convenient key definitions in Emacs. + +#+begin_src emacs-lisp +(use-package general + :demand t + :config) +#+end_src + +*** [[https://github.com/ch11ng/exwm][exwm]] (window manager) + +#+begin_src emacs-lisp +(use-package exwm + :config + (require 'exwm-config) + (exwm-config-default) + (require 'exwm-systemtray) + (exwm-systemtray-enable)) +#+end_src + +*** [[https://orgmode.org/][Org mode]] + +#+begin_quote +Org mode is for keeping notes, maintaining TODO lists, planning +projects, and authoring documents with a fast and effective plain-text +system. +#+end_quote + +In short, my favourite way of life. + +#+begin_src emacs-lisp +(setq org-src-tab-acts-natively t + org-src-preserve-indentation nil + org-edit-src-content-indentation 0) +#+end_src + +*** [[https://magit.vc/][Magit]] + +#+begin_quote +It's Magit! A Git porcelain inside Emacs. +#+end_quote + +Not just how I do git, but /the/ way to do git. + +#+begin_src emacs-lisp +(use-package magit + :general + ("s-g" 'magit-status)) +#+end_src + +*** [[https://github.com/abo-abo/swiper][Ivy]] (and friends) + +#+begin_quote +Ivy - a generic completion frontend for Emacs, Swiper - isearch with +an overview, and more. Oh, man! +#+end_quote + +There's no way I could top that, so I won't attempt to. + +**** Ivy + +#+begin_src emacs-lisp +(use-package ivy + :general + (ivy-minibuffer-map + [escape] 'keyboard-escape-quit + "C-j" 'ivy-next-line + "C-k" 'ivy-previous-line + [S-up] 'ivy-previous-history-element + [S-down] 'ivy-next-history-element + "DEL" 'ivy-backward-delete-char) + :config + (ivy-mode 1)) +#+end_src + +**** Swiper + +#+begin_src emacs-lisp +(use-package swiper + :general ("C-s" 'swiper)) +#+end_src + +**** Counsel + +#+begin_src emacs-lisp +(use-package counsel + :general + ("M-x" 'counsel-M-x + "C-x C-f" 'counsel-find-file + "s-r" 'counsel-recentf) + (imap minibuffer-local-map + "C-r" 'counsel-minibuffer-history) + :config + (counsel-mode 1) + (defalias 'locate #'counsel-locate)) +#+end_src * Footer +:PROPERTIES: +:CUSTOM_ID: footer +:END: #+begin_src emacs-lisp :comments none - ;;; init.el ends here #+end_src