#+TITLE: my Emacs configuration #+AUTHOR: Franck Cuny #+PROPERTY: header-args :tangle-mode o444 :results silent :tangle ~/.config/emacs/init.el #+STARTUP: overview indent #+AUTO_TANGLE: t To use this file, run =org-tangle= (or =C-c C-v C-t=). To exclude specific source blocks from being tangled add =:tangle no= to the header. * Startup ** early initialization :PROPERTIES: :header-args: :tangle-mode o444 :results silent :tangle ~/.config/emacs/early-init.el :END: Using an =early-init.el= file can speedup loading emacs. This is only available after emacs version 27. #+begin_src emacs-lisp :lexical t ;;; early-init.el --- Early initialization -*- lexical-binding: t -*- ;;; Commentary: ;;; Code: ;; disable GUI elements (scroll-bar-mode -1) ; hide the scroll bar (tool-bar-mode -1) ; hide the tool bar (menu-bar-mode -1) ; hide the menu (blink-cursor-mode -1) ; don't blink the cursor (setq make-pointer-invisible t) ;; hide cursor while typing (setq use-dialog-box nil) ;; do not show GUI dialogs (setq use-file-dialog nil) (setq inhibit-startup-screen t) ;; hide the startup screen ;; don't report warnings and errors related to native compilation (setq native-comp-async-report-warnings-errors nil) ;; increase font size (set-face-attribute 'default nil :height 130) ;;; early-init.el ends here #+end_src ** set headers #+begin_src emacs-lisp :epilogue (format-time-string ";; Last generated on %c") ;;; init.el --- This is where all emacs start. -*- lexical-binding: t -*- ;;; Commentary: ;;; Code: #+end_src ** garbage collection Set the garbage collection threshold. #+begin_src emacs-lisp (setq gc-cons-percentage 0.5 gc-cons-threshold (* 128 1024 1024)) #+end_src ** report time While I don't restart emacs that often, it's still useful to know how much time was spend loading the modules. #+begin_src emacs-lisp (defconst emacs-start-time (current-time)) (defun report-time-since-load (&optional suffix) (message "Loading init...done (%.3fs)%s" (float-time (time-subtract (current-time) emacs-start-time)) suffix)) (add-hook 'after-init-hook #'(lambda () (report-time-since-load " [after-init]")) t) #+end_src ** generic configuration #+begin_src emacs-lisp (fset 'yes-or-no-p 'y-or-n-p) ; replace yes/no prompts with y/n ;; set utf-8 as the default encoding (prefer-coding-system 'utf-8-unix) (setq locale-coding-system 'utf-8) (set-language-environment 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) #+end_src ** load =use-package= Add MELPA and NonGNU ELPA repositories. #+begin_src emacs-lisp (setq load-prefer-newer t) (setq init-file-debug t) (package-initialize) (setq package-archives (append package-archives '(("melpa" . "https://melpa.org/packages/") ("elpa" . "https://elpa.nongnu.org/nongnu/")))) #+end_src Then we load =use-package=. #+begin_src emacs-lisp (eval-and-compile (defsubst emacs-path (path) (expand-file-name path user-emacs-directory)) (setq package-enable-at-startup nil load-path (append (list (emacs-path "use-package")) (delete-dups load-path) (list (emacs-path "lisp"))))) (require 'use-package) (setq use-package-verbose init-file-debug use-package-expand-minimally (not init-file-debug) use-package-compute-statistics nil debug-on-error init-file-debug) #+end_src *** diminish Since =use-package= no longer requires =diminish= as a dependency (see [[https://github.com/jwiegley/use-package/blob/a6e856418d2ebd053b34e0ab2fda328abeba731c/NEWS.md?plain=1#LL103C3-L103C62][changelog]]), we need to require it before other packages. #+begin_src emacs-lisp (use-package diminish :ensure t) #+end_src ** define data environment #+begin_src emacs-lisp (defconst user-data-directory (emacs-path "data")) (defun user-data (dir) (expand-file-name dir user-data-directory)) (setq custom-file (user-data "customizations.el")) (load custom-file 'noerror) #+end_src * Helper functions ** Push and pop window configurations #+begin_src emacs-lisp (defvar saved-window-configuration nil) (defun push-window-configuration () (interactive) (push (current-window-configuration) saved-window-configuration)) (defun pop-window-configuration () (interactive) (let ((config (pop saved-window-configuration))) (if config (set-window-configuration config) (if (> (length (window-list)) 1) (delete-window) (bury-buffer))))) #+end_src ** Rename the current buffer #+begin_src emacs-lisp (defun my/rename-this-buffer-and-file () "Renames current buffer and file it is visiting." (interactive) (let ((name (buffer-name)) (filename (buffer-file-name)) (read-file-name-function 'read-file-name-default)) (if (not (and filename (file-exists-p filename))) (error "Buffer '%s' is not visiting a file!" name) (let ((new-name (read-file-name "New name: " filename))) (cond ((get-buffer new-name) (error "A buffer named '%s' already exists!" new-name)) (t (rename-file filename new-name 1) (rename-buffer new-name) (set-visited-file-name new-name) (set-buffer-modified-p nil) (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name)))))))) #+end_src ** Is this my work issued machine #+begin_src emacs-lisp (defun my/check-work-machine-p () "Return t if this is a work machine." (string-match "HQ\\.*" (system-name))) #+end_src ** GitHub's code search #+begin_src emacs-lisp (defun my/github-code-search () "Search code on github for a given language." (interactive) (let ((language (completing-read "Language: " '("Emacs Lisp" "Python" "Go" "Nix"))) (code (read-string "Code: "))) (browse-url (concat "https://github.com/search?lang=" language "&type=code&q=" code)))) #+end_src ** Search work's repositories #+begin_src emacs-lisp (defun my/work-code-search () "Search code on sourcegraph for a given language." (interactive) (let ((language (completing-read "Language: " '("Ruby" "Python" "Go"))) (code (read-string "Code: "))) (browse-url (concat "https://sourcegraph.rbx.com/search?q=context:global+lang:" language "+" code)))) #+end_src * Packages ** abbrev If you want 'btw' to expand to 'by the way', type 'btw' followed by =C-x a i g=. The =g= is flow global, and you can define abbreviations per mode. | keys | action | |-----------+--------------------------------------------------| | =C-x a i g= | add a new abbreviation for all modes | | =C-x a i l= | add a new abbreviation local to the current mode | #+begin_src emacs-lisp (use-package abbrev :diminish :hook ((text-mode prog-mode) . abbrev-mode) :custom (abbrev-file-name (emacs-path "abbrevs.el")) ;; save abbrevs when files are saved (save-abbrevs 'silently) :config (if (file-exists-p abbrev-file-name) (quietly-read-abbrev-file))) #+end_src ** autorevert Automatically revert buffers if the file has changed on disk. #+begin_src emacs-lisp (use-package autorevert :custom (auto-revert-use-notify nil) :config (global-auto-revert-mode t)) #+end_src ** bookmark | keys | action | |---------+------------------------------------| | =C-x r m= | add a new bookmark | | =C-x r l= | list all the bookmarks in a buffer | | =C-x r b= | list the bookmarks with consul | #+begin_src emacs-lisp (use-package bookmark :defer t :custom (bookmark-default-file (user-data "bookmarks"))) #+end_src ** compile #+begin_src emacs-lisp (use-package compile :bind (:map compilation-mode-map ("z" . delete-window)) :custom (compilation-always-kill t) ;; Don't freeze when process reads from stdin (compilation-disable-input t) (compilation-ask-about-save nil) (compilation-context-lines 10) (compilation-scroll-output 'first-error) (compilation-skip-threshold 2) (compilation-window-height 100)) #+end_src ** completions *** consult #+begin_src emacs-lisp (use-package consult :ensure t :bind (("C-c m" . consult-mode-command) ("M-g o" . consult-org-heading) ("C-x b" . consult-buffer) ("C-x 5 b" . consult-buffer-other-frame) ("C-x r b" . consult-bookmark) ("C-x p b" . consult-project-buffer) ("C-c i" . consult-imenu) ("M-g e" . consult-compile-error) ("M-g g" . consult-goto-line) ("M-g M-g" . consult-goto-line) ("M-g l" . consult-goto-line) ("M-g m" . consult-mark) ("M-g k" . consult-global-mark)) ;; Enable automatic preview at point in the *Completions* buffer. This is ;; relevant when you use the default completion UI. :hook (completion-list-mode . consult-preview-at-point-mode) :custom (consult-narrow-key "<") :functions (consult-register-format consult-register-window consult-xref) :init ;; Optionally configure the register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. (setq register-preview-delay 0.5 register-preview-function #'consult-register-format) ;; Optionally tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config (use-package consult-xref) (consult-customize consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file :preview-key '(:debounce 0.4 any))) #+end_src *** corfu #+begin_src emacs-lisp (use-package corfu :ensure t :demand t :bind (("M-/" . completion-at-point) :map corfu-map ("C-n" . corfu-next) ("C-p" . corfu-previous) ("" . corfu-quit) ("" . corfu-insert) ("M-d" . corfu-info-documentation) ("M-l" . corfu-info-location) ("M-." . corfu-move-to-minibuffer)) :custom ;; Works with `indent-for-tab-command'. Make sure tab doesn't indent when you ;; want to perform completion (tab-always-indent 'complete) (completion-cycle-threshold t) ; Always show candidates in menu (corfu-auto t) (corfu-auto-prefix 2) (corfu-auto-delay 0.25) (corfu-min-width 80) (corfu-max-width corfu-min-width) ; Always have the same width (corfu-count 14) (corfu-scroll-margin 4) (corfu-cycle t) ;; `nil' means to ignore `corfu-separator' behavior, that is, use the older ;; `corfu-quit-at-boundary' = nil behavior. Set this to separator if using ;; `corfu-auto' = `t' workflow (in that case, make sure you also set up ;; `corfu-separator' and a keybind for `corfu-insert-separator', which my ;; configuration already has pre-prepared). Necessary for manual corfu usage with ;; orderless, otherwise first component is ignored, unless `corfu-separator' ;; is inserted. (corfu-quit-at-boundary nil) (corfu-separator ?\s) ; Use space (corfu-quit-no-match 'separator) ; Don't quit if there is `corfu-separator' inserted (corfu-preview-current 'insert) ; Preview first candidate. Insert on input if only one (corfu-preselect-first t) ; Preselect first candidate? ;; Other (corfu-echo-documentation nil) ; Already use corfu-popupinfo :config (global-corfu-mode)) #+end_src **** corfu-popupinfo #+begin_src emacs-lisp (use-package corfu-popupinfo :after corfu :hook (corfu-mode . corfu-popupinfo-mode) :bind (:map corfu-map ("M-n" . corfu-popupinfo-scroll-up) ("M-p" . corfu-popupinfo-scroll-down) ([remap corfu-show-documentation] . corfu-popupinfo-toggle)) :custom (corfu-popupinfo-delay 0.5) (corfu-popupinfo-max-width 70) (corfu-popupinfo-max-height 20) ;; Also here to be extra-safe that this is set when `corfu-popupinfo' is ;; loaded. I do not want documentation shown in both the echo area and in ;; the `corfu-popupinfo' popup. (corfu-echo-documentation nil)) #+end_src *** cape #+begin_src emacs-lisp (use-package cape :demand t :ensure t :bind (("C-c . p" . completion-at-point) ("C-c . t" . complete-tag) ("C-c . d" . cape-dabbrev) ("C-c . h" . cape-history) ("C-c . f" . cape-file) ("C-c . k" . cape-keyword) ("C-c . s" . cape-symbol) ("C-c . a" . cape-abbrev) ("C-c . l" . cape-line) ("C-c . w" . cape-dict) ("C-c . \\" . cape-tex) ("C-c . _" . cape-tex) ("C-c . ^" . cape-tex) ("C-c . &" . cape-sgml) ("C-c . r" . cape-rfc1345)) :init ;; Add `completion-at-point-functions', used by `completion-at-point'. (add-to-list 'completion-at-point-functions #'cape-dabbrev) (add-to-list 'completion-at-point-functions #'cape-ispell) (add-to-list 'completion-at-point-functions #'cape-file) (add-to-list 'completion-at-point-functions #'cape-abbrev)) #+end_src *** elisp-mode-cape #+begin_src emacs-lisp (use-package elisp-mode-cape :after (cape elisp-mode) :hook (emacs-lisp-mode . my/setup-elisp) :preface (defun my/setup-elisp () (setq-local completion-at-point-functions `(,(cape-super-capf #'elisp-completion-at-point #'cape-dabbrev) cape-file) cape-dabbrev-min-length 5))) #+end_src *** embark #+begin_src emacs-lisp (use-package embark :ensure t :bind (("M-." . embark-act) ("C-h b" . embark-bindings) ;; alternative for `describe-bindings' :map embark-collect-mode-map ("C-c C-a" . embark-collect-direct-action-minor-mode)) :init ;; Optionally replace the key help with a completing-read interface (setq prefix-help-command #'embark-prefix-help-command) ;; Show the Embark target at point via Eldoc. You may adjust the Eldoc ;; strategy, if you want to see the documentation from multiple providers. (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) #+end_src **** embark-consult #+begin_src emacs-lisp (use-package embark-consult :ensure t :hook (embark-collect-mode . consult-preview-at-point-mode)) #+end_src *** marginalia #+begin_src emacs-lisp (use-package marginalia :ensure t ;; Either bind `marginalia-cycle' globally or only in the minibuffer :bind (("M-A" . marginalia-cycle) :map minibuffer-local-map ("M-A" . marginalia-cycle)) ;; The :init configuration is always executed (Not lazy!) :config ;; 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)) #+end_src *** orderless #+begin_src emacs-lisp (use-package orderless :demand t :ensure t :custom (completion-styles '(orderless basic)) (completion-category-defaults nil)) #+end_src *** vertico #+begin_src emacs-lisp (use-package vertico :demand t :ensure t :bind (("C-c . ." . vertico-repeat) :map vertico-map ("C-j" . vertico-exit-input) ("C-M-n" . vertico-next-group) ("C-M-p" . vertico-previous-group)) :hook (minibuffer-setup . vertico-repeat-save) (rfn-eshadow-update-overlay . vertico-directory-tidy) :custom (vertico-count 10) (vertico-resize nil) (vertico-cycle t) :preface (defun crm-indicator (args) (cons (format "[CRM%s] %s" (replace-regexp-in-string "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" crm-separator) (car args)) (cdr args))) :config (vertico-mode) ;; Add prompt indicator to `completing-read-multiple'. ;; We display [CRM], e.g., [CRM,] if the separator is a comma. (advice-add #'completing-read-multiple :filter-args #'crm-indicator) ;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) ;; Hide commands in M-x which do not work in the current mode. Vertico ;; commands are hidden in normal buffers. (setq read-extended-command-predicate #'command-completion-default-include-p)) #+end_src *** yasnippet #+begin_src emacs-lisp (use-package yasnippet :ensure t :demand t :diminish :commands yas-minor-mode-on :bind (("C-c y d" . yas-load-directory) ("C-c y i" . yas-insert-snippet) ("C-c y f" . yas-visit-snippet-file) ("C-c y n" . yas-new-snippet) ("C-c y t" . yas-tryout-snippet) ("C-c y l" . yas-describe-tables) ("C-c y g" . yas-global-mode) ("C-c y m" . yas-minor-mode) ("C-c y r" . yas-reload-all) ("C-c y x" . yas-expand) :map yas-keymap ("C-i" . yas-next-field-or-maybe-expand)) :mode ("/emacs\\.d/snippets/" . snippet-mode) :hook (prog-mode . yas-minor-mode-on) :custom (yas-prompt-functions '(yas-completing-prompt yas-no-prompt)) (yas-snippet-dirs (list (emacs-path "snippets"))) (yas-triggers-in-field t) (yas-wrap-around-region t) :config (yas-load-directory (emacs-path "snippets"))) #+end_src ** dired #+begin_src emacs-lisp (use-package dired :diminish :bind (:map dired-mode-map ("j" . dired) ("z" . pop-window-configuration) ("^" . dired-up-directory) ("q" . pop-window-configuration) ("M-!" . shell-command) ("" . dired-next-window)) :custom (dired-clean-up-buffers-too nil) (dired-dwim-target t) (dired-hide-details-hide-information-lines nil) (dired-hide-details-hide-symlink-targets nil) (dired-listing-switches "-lah") (dired-no-confirm '(byte-compile chgrp chmod chown copy hardlink symlink touch)) (dired-omit-mode nil t) (dired-omit-size-limit 60000) (dired-recursive-copies 'always) (dired-recursive-deletes 'always) :functions (dired-dwim-target-directory)) #+end_src ** direnv Invokes [[https://direnv.net/][direnv]] to obtain environment for the current file. #+begin_src emacs-lisp (use-package direnv :ensure t :custom (direnv-always-show-summary nil) :config (direnv-mode)) #+end_src ** docker #+begin_src emacs-lisp (use-package docker :bind ("C-c d" . docker) :diminish :init (use-package docker-image :commands docker-images) (use-package docker-volume :commands docker-volumes) (use-package docker-network :commands docker-containers) (use-package docker-compose :commands docker-compose) (use-package docker-container :commands docker-containers :custom (docker-containers-shell-file-name "/bin/bash") (docker-containers-show-all nil))) #+end_src *** docker-compose-mode #+begin_src emacs-lisp (use-package docker-compose-mode :mode "docker-compose.*\.yml\\'") #+end_src *** dockerfile-mode #+begin_src emacs-lisp (use-package dockerfile-mode :mode "Dockerfile[a-zA-Z.-]*\\'") #+end_src ** elfeed #+begin_src emacs-lisp (use-package elfeed :ensure t :custom (elfeed-db-directory (user-data "elfeed/")) (elfeed-search-filter "@2-weeks-ago +unread") (elfeed-show-entry-switch 'pop-to-buffer) (elfeed-show-entry-delete 'delete-window)) (defface elfeed-face-tag-mustread '((t :foreground "#f00")) "This is a custom font face for the `mustread' tag in Elfeed." :group 'elfeed) (push '(mustread elfeed-face-tag-mustread) elfeed-search-face-alist) #+end_src *** elfeed-org #+begin_src emacs-lisp (use-package elfeed-org :ensure t :init (setq rmh-elfeed-org-files (list (expand-file-name "etc/elfeed.org" user-emacs-directory))) :config (elfeed-org)) #+end_src ** emacs #+begin_src emacs-lisp (use-package emacs :bind* ("M-j" . join-line) :custom-face (cursor ((t (:background "hotpink")))) ;; (highlight ((t (:background "blue4")))) ;; (minibuffer-prompt ((t (:foreground "grey80")))) ;; (mode-line-inactive ((t (:background "grey50")))) (nobreak-space ((t nil))) :custom (auto-save-default nil) ;; don't auto save files (auto-save-list-file-prefix nil) ;; no backups (create-lockfiles nil) ;; don't use a lock file (confirm-kill-emacs #'yes-or-no-p) ;; ask before killing emacs (make-backup-files nil) ;; really no backups (minibuffer-message-timeout 0.5) ;; How long to display an echo-area message (next-screen-context-lines 5) ;; scroll 5 lines at a time (require-final-newline t) ;; ensure newline exists at the end of the file (ring-bell-function 'ignore) ;; really no bell (tab-always-indent 'complete) ;; when using TAB, always indent (visible-bell nil) ;; no bell (column-number-mode t) ;; show column number in the mode line (electric-pair-mode 1) ;; matches parens and brackets (indent-tabs-mode nil) ;; turn off tab indentation (cursor-type 'box) ;; cursor is a horizontal bar (delete-by-moving-to-trash t) ;; delete files by moving them to the trash (initial-scratch-message "") ;; empty scratch buffer (garbage-collection-messages t) ;; log when the gc kicks in ;; bytecomp.el (byte-compile-verbose nil) ;; prog-mode.el (prettify-symbols-unprettify-at-point 'right-edge) ;; startup.el (auto-save-list-file-prefix (user-data "auto-save-list/.saves-")) (initial-buffer-choice t) (initial-major-mode 'fundamental-mode) (initial-scratch-message "") (user-full-name "Franck Cuny") (user-mail-address "franck@fcuny.net") (add-log-mailing-address "franck@fcuny.net") (history-length 200) (history-delete-duplicates t) (completion-ignored-extensions '(".class" ".cp" ".elc" ".fmt" ".git/" ".pyc" ".so" "~")) ;; paragraphs.el (sentence-end-double-space nil) ;; switch to view-mode whenever you are in a read-only buffer (e.g. ;; switched to it using C-x C-q). (view-read-only t) ;; window.el (switch-to-buffer-preserve-window-point t) ;; warnings.el (warning-minimum-log-level :error) ;; frame.el (window-divider-default-bottom-width 1) (window-divider-default-places 'bottom-only) ;; paren.el (show-paren-delay 0) (show-paren-highlight-openparen t) (show-paren-when-point-inside-paren t) (show-paren-when-point-in-periphery t) :config (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)) #+end_src ** eshell #+begin_src emacs-lisp (use-package eshell :commands (eshell eshell-command) :custom (eshell-directory-name (emacs-path "eshell")) (eshell-hist-ignoredups t) (eshell-history-size 50000) (eshell-ls-dired-initial-args '("-h")) (eshell-ls-exclude-regexp "~\\'") (eshell-ls-initial-args "-h") (eshell-modules-list '(eshell-alias eshell-basic eshell-cmpl eshell-dirs eshell-glob eshell-hist eshell-ls eshell-pred eshell-prompt eshell-rebind eshell-script eshell-term eshell-unix eshell-xtra)) (eshell-prompt-function (lambda nil (concat (abbreviate-file-name (eshell/pwd)) (if (= (user-uid) 0) " # " " $ ")))) (eshell-save-history-on-exit t) (eshell-stringify-t nil) (eshell-term-name "ansi") :preface (defun eshell-initialize () (add-hook 'eshell-expand-input-functions #'eshell-spawn-external-command) :init (add-hook 'eshell-first-time-mode-hook #'eshell-initialize))) #+end_src ** flymake #+begin_src emacs-lisp (use-package flymake :bind (("C-c ! n" . flymake-goto-next-error) ("C-c ! p" . flymake-goto-next-error)) :custom (flymake-start-on-save-buffer t) (flymake-fringe-indicator-position 'left-fringe) (flymake-suppress-zero-counters t) (flymake-start-on-flymake-mode t) (flymake-no-changes-timeout nil) (flymake-proc-compilation-prevents-syntax-check t) (flymake-wrap-around nil) (elisp-flymake-byte-compile-load-path load-path)) #+end_src ** font Somehow I need to set the font to a higher height on MacOS. #+BEGIN_SRC emacs-lisp (set-face-attribute 'default nil :family "JetBrains Mono" :height 130) (set-face-attribute 'fixed-pitch nil :family "JetBrain Mono" :height 130) (set-face-attribute 'variable-pitch nil :family "Roboto" :height 130) (use-package default-text-scale :bind (("C-)" . default-text-scale-reset) ("C-=" . default-text-scale-increase) ("C--" . default-text-scale-decrease))) #+END_SRC ** fringe #+begin_src emacs-lisp (use-package fringe :config ;;; no fringe on the right side (set-fringe-mode '(8 . 0))) #+end_src ** git-link A convenient package to create link to a code location in GitHub, or other forges. This is very useful to get a link and share with others when looking at some code. #+begin_src emacs-lisp (use-package git-link :defines git-link-remote-alist :ensure t :bind ("C-c Y" . git-link) :commands (git-link git-link-commit git-link-homepage) :custom (git-link-open-in-browser t) :preface (defun git-link-fcuny-net (hostname dirname filename branch commit start end) (format "http://git.fcuny.net/%s/tree/%s?id=%s#n%s" (replace-regexp-in-string "^r/\\(.*\\)" "\\1.git" dirname) filename commit start)) (defun git-link-commit-fcuny-net (hostname dirname commit) (format "http://git.fcuny.net/%s/commit/?id=%s" (replace-regexp-in-string "^r/\\(.*\\)" "\\1.git" dirname) commit)) :config (add-to-list 'git-link-remote-alist '("git\\.fcuny\\.net" git-link-fcuny-net)) (add-to-list 'git-link-commit-remote-alist '("git\\.fcuny\\.net" git-link-commit-fcuny-net)) ;; sets up roblox git enterprise as a git-link handler (add-to-list 'git-link-remote-alist '("github\\.rblx\\.com" git-link-github)) (add-to-list 'git-link-commit-remote-alist '("github\\.rblx\\.com" git-link-commit-github))) #+end_src ** ibuffer #+begin_src emacs-lisp (use-package ibuffer :bind ("C-x C-b" . ibuffer) :custom (ibuffer-default-display-maybe-show-predicates t) (ibuffer-expert t) (ibuffer-formats '((mark modified read-only " " (name 16 -1) " " (size 6 -1 :right) " " (mode 16 16) " " filename) (mark " " (name 16 -1) " " filename))) (ibuffer-maybe-show-regexps nil) (ibuffer-saved-filter-groups '(("default" ("Magit" (or (mode . magit-status-mode) (mode . magit-log-mode) (name . "\\*magit") (name . "magit-") (name . "git-monitor"))) ("Commands" (or (mode . shell-mode) (mode . eshell-mode) (mode . term-mode) (mode . compilation-mode))) ("Rust" (or (mode . rust-mode) (mode . cargo-mode) (name . "\\*Cargo") (name . "^\\*rls\\(::stderr\\)?\\*") (name . "eglot"))) ("Nix" (mode . nix-mode)) ("Lisp" (mode . emacs-lisp-mode)) ("Dired" (mode . dired-mode)) ("Org" (or (name . "^\\*Calendar\\*$") (name . "^\\*Org Agenda") (name . "^ \\*Agenda") (name . "^diary$") (mode . org-mode))) ("Emacs" (or (name . "^\\*scratch\\*$") (name . "^\\*Messages\\*$") (name . "^\\*\\(Customize\\|Help\\)") (name . "\\*\\(Echo\\|Minibuf\\)")))))) (ibuffer-show-empty-filter-groups nil) (ibuffer-shrink-to-minimum-size t t) (ibuffer-use-other-window t) :init (add-hook 'ibuffer-mode-hook #'(lambda () (ibuffer-switch-to-saved-filter-groups "default")))) #+end_src ** indent #+begin_src emacs-lisp (use-package indent :commands indent-according-to-mode :custom (tab-always-indent 'complete)) #+end_src ** ispell #+begin_src emacs-lisp (use-package ispell :custom (ispell-program-name (executable-find "aspell")) (ispell-dictionary "en_US") (ispell-extra-args '("--camel-case"))) #+end_src ** jq-mode #+begin_src emacs-lisp (use-package jq-mode :ensure t :mode "\\.jq\\'") #+end_src ** js2-mode ** languages *** eglot After experimenting with [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode]] and [[https://github.com/joaotavora/eglot][eglot]] I decided to go with eglot for LSP integration. For languages where I want to use LSP, I need to add ~:hook (nix-mode . englot-ensure)~ in the ~use-package~ definition for the language. #+begin_src emacs-lisp (use-package eglot) #+end_src *** tree-sitter #+begin_src emacs-lisp (use-package tree-sitter :ensure t :config (global-tree-sitter-mode)) #+end_src **** tree-sitter-langs #+begin_src emacs-lisp (use-package tree-sitter-langs :after tree-sitter :ensure t) #+end_src *** lisp-mode **** elisp-mode #+begin_src emacs-lisp (use-package emacs-lisp-mode :bind (:map emacs-lisp-mode-map ("C-c C-r" . eval-region) ("C-c C-d" . eval-defun) ("C-c C-b" . eval-buffer)) :hook ((emacs-lisp-mode . flymake-mode))) #+end_src **** eldoc #+begin_src emacs-lisp (use-package eldoc :diminish :hook ((c-mode-common emacs-lisp-mode) . eldoc-mode) :custom (eldoc-idle-delay 1) (eldoc-documentation-strategy #'eldoc-documentation-default) (eldoc-echo-area-use-multiline-p 3) (eldoc-echo-area-prefer-doc-buffer 'maybe) (eldoc-echo-area-display-truncation-message nil)) #+end_src *** hcl-mode #+begin_src emacs-lisp (use-package hcl-mode :ensure t :mode "\.nomad\\'") #+end_src *** json-mode #+begin_src emacs-lisp (use-package json-mode :mode "\\.json\\'") #+end_src **** json-reformat #+begin_src emacs-lisp (use-package json-reformat :ensure t :after json-mode) #+end_src *** go-mode #+begin_src emacs-lisp (use-package go-mode :ensure t :hook ((go-mode . tree-sitter-hl-mode) (go-mode . eglot-ensure) (go-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t)))) :bind (:map go-mode-map ("C-c C-c" . compile))) #+end_src **** gotest #+begin_src emacs-lisp (use-package gotest :ensure t :after go-mode :custom (go-test-verbose t)) #+end_src *** nix-mode #+begin_src emacs-lisp (use-package nix-mode :ensure t :hook ((nix-mode . eglot-ensure) (nix-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t)))) :custom (nix-indent-function 'nix-indent-line)) #+end_src *** protobuf-mode #+begin_src emacs-lisp (use-package protobuf-mode :ensure t :mode "\\.proto\\'") #+end_src *** python-mode Enable eglot and tree-sitter when working with python. #+begin_src emacs-lisp (use-package python-mode :hook ((python-mode . tree-sitter-hl-mode) (python-mode . eglot-ensure) (python-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t)))) :interpreter "python" :bind (:map python-mode-map ("C-c c") ("C-c C-z" . python-shell))) #+end_src **** blacken [[https://pypi.org/project/black/][black]] is a code formatter for python. #+begin_src emacs-lisp (use-package blacken :ensure t :hook (python-mode . blacken-mode)) #+end_src **** isort [[https://pypi.org/project/isort/][Sort imports]]. #+begin_src emacs-lisp (use-package py-isort :ensure t :commands (py-isort-buffer py-isort-region)) #+end_src *** ruby-mode #+begin_src emacs-lisp (use-package ruby-mode :mode "\\.rb\\'" :interpreter "ruby" :bind (:map ruby-mode-map ("" . my-ruby-smart-return)) :preface (defun my-ruby-smart-return () (interactive) (when (memq (char-after) '(?\| ?\" ?\')) (forward-char)) (call-interactively 'newline-and-indent))) #+end_src *** rustic-mode #+begin_src emacs-lisp (use-package rustic :ensure t :custom (rustic-format-on-save t) (rustic-format-trigger 'on-save) (rustic-lsp-server 'rust-analyzer) (rustic-lsp-client 'eglot)) #+end_src *** sh-script #+begin_src emacs-lisp (use-package sh-script :defer t :preface (defvar sh-script-initialized nil) (defun initialize-sh-script () (unless sh-script-initialized (setq sh-script-initialized t) (info-lookup-add-help :mode 'shell-script-mode :regexp ".*" :doc-spec '(("(bash)Index"))))) :init (add-hook 'shell-mode-hook #'initialize-sh-script)) #+end_src *** terraform-mode #+begin_src emacs-lisp (use-package terraform-mode :ensure t :mode "\.tf\\'") #+end_src *** toml-mode #+begin_src emacs-lisp (use-package toml-mode :ensure t) #+end_src *** yaml-mode #+begin_src emacs-lisp (use-package yaml-mode :mode "\\.ya?ml\\'") #+end_src ** MacOS specific #+begin_src emacs-lisp (when (memq window-system '(mac ns)) (add-to-list 'default-frame-alist '(fullscreen . maximized)) (add-to-list 'default-frame-alist '(ns-appearance . nil)) (add-to-list 'default-frame-alist '(ns-transparent-titlebar . nil)) (when (boundp 'ns-use-native-fullscreen) (setq ns-use-native-fullscreen nil)) (when (boundp 'mac-allow-anti-aliasing) (setq mac-allow-anti-aliasing t))) #+end_src ** magit #+begin_src emacs-lisp (use-package magit :ensure t :bind (("C-x g" . magit-status) ("C-x G" . magit-status-with-prefix)) :custom (magit-diff-options nil) (magit-diff-refine-hunk t) (magit-fetch-arguments nil) (magit-log-section-commit-count 10) (magit-pre-refresh-hook nil) (magit-process-popup-time 15) (magit-clone-default-directory "~/workspace/") (magit-section-initial-visibility-alist '((untracked . hide))) :hook (magit-mode . hl-line-mode) :config (use-package magit-commit :defer t :config (use-package git-commit :custom (git-commit-major-mode 'markdown-mode) (git-commit-setup-hook '(git-commit-save-message git-commit-turn-on-auto-fill git-commit-turn-on-flyspell bug-reference-mode)))) (use-package magit-status :defer t :config (dolist (func '(magit-insert-unpushed-to-upstream-or-recent magit-insert-unpulled-from-pushremote magit-insert-unpulled-from-upstream )) (remove-hook 'magit-status-sections-hook func)) (dolist (func '(magit-insert-diff-filter-header magit-insert-tags-header)) (remove-hook 'magit-status-headers-hook func)))) #+end_src ** markdown-mode #+begin_src emacs-lisp (use-package markdown-mode :mode (("\\`README\\.md\\'" . gfm-mode) ("\\.md\\'" . markdown-mode) ("\\.markdown\\'" . markdown-mode)) :custom (markdown-command "pandoc -f markdown_github+smart") (markdown-command-needs-filename t) (markdown-enable-math t) (markdown-open-command "marked") :init (setq markdown-command "multimarkdown")) #+end_src *** markdown-preview-mode #+begin_src emacs-lisp (use-package markdown-preview-mode :ensure t :after markdown-mode :config (setq markdown-preview-stylesheets (list (concat "https://github.com/dmarcotte/github-markdown-preview/" "blob/master/data/css/github.css")))) #+end_src ** midnight #+begin_src emacs-lisp (use-package midnight :demand t :bind ("C-c z" . clean-buffer-list) :custom (midnight-delay 18000) (clean-buffer-list-kill-never-buffer-names '("*scratch*" "*Messages*" "*server*" "*Group*" "*Org Agenda*" "todo.org")) (clean-buffer-list-kill-never-regexps '("^ \\*Minibuf-.*\\*$" "^\\*Summary" "^\\*Article" "^#")) (clean-buffer-list-kill-regexps '(".*")) :config (midnight-mode t)) #+end_src ** my-cheeseboard get the pizzas for this week at cheeseboard. #+begin_src emacs-lisp (use-package my-cheeseboard) #+end_src ** my-uptime an uptime / SLO calculator. #+begin_src emacs-lisp (use-package my-uptime :init (add-to-list 'display-buffer-alist '("\\*slo-calculator\\*" (display-buffer-in-side-window) (side . left) (slot . 0) (window-width . 0.35)))) #+end_src ** org-mode #+begin_src emacs-lisp (use-package org :commands org-resolve-clocks :bind* (("C-c c" . org-capture) ("C-c a" . org-agenda)) :bind (:map org-mode-map ("C-,") ("C-c #" . org-priority) ("C-c .") ("C-c ," . org-priority) ("C-c !" . org-time-stamp-inactive) ("C-c <" . org-time-stamp) ("C-c x" . org-todo) ("C-c C-x @" . visible-mode) ("C-c C-x U" . org-insert-url-link) ("C-c C-x o" . my-org-todoize) ([(control meta return)] . org-insert-heading-after-current)) :hook (org-mode . abbrev-mode) (org-mode . turn-on-flyspell) (org-mode . visual-line-mode) (org-mode . org-indent-mode) (org-log-buffer-setup . abbrev-mode) (org-log-buffer-setup . visual-line-mode) (org-log-buffer-setup . turn-on-flyspell) (org-capture-after-finalize . org-save-all-org-buffers) (org-capture-prepare-finalize-hook . org-save-all-org-buffers) :custom ;;; general settings (org-startup-folded t) (org-startup-indented t) (org-hide-emphasis-markers t) (org-hide-leading-stars t) (org-pretty-entities t) (org-return-follows-link t) (org-startup-with-inline-images t) (org-startup-indented t) (org-clone-delete-id t) (org-deadline-warning-days 14) (org-default-notes-file "~/documents/notes/inbox.org") (org-directory "~/documents/notes/") (org-export-backends '(html md)) (org-export-use-babel nil) (org-footnote-section nil) (org-icalendar-timezone "America/Los_Angeles") (org-image-actual-width 800) (org-imenu-depth 4) (org-insert-heading-respect-content t) (org-outline-path-complete-in-steps nil) (org-src-fontify-natively t) (org-src-preserve-indentation t) (org-src-tab-acts-natively t) (org-src-window-setup 'current-window) (org-yank-adjusted-subtrees t) (org-structure-template-alist '(("s" . "src") ("E" . "src emacs-lisp") ("p" . "src python") ("e" . "example") ("q" . "quote") ("V" . "verbatim"))) ;;; refile (org-refile-targets '(("~/documents/notes/tasks.org" :maxlevel . 1) ("~/documents/notes/notes.org" :maxlevel . 1))) (org-refile-use-cache nil) (org-refile-use-outline-path t) (org-reverse-note-order t) (org-todo-keywords '((sequence "TODO(t)" "STARTED(s)" "|" "DONE(d@)" "CANCELED(x@)"))) (org-todo-repeat-to-state "TODO") (org-fontify-done-headline t) (org-fontify-quote-and-verse-blocks t) (org-fontify-todo-headline nil) (org-fontify-whole-block-delimiter-line t) (org-fontify-whole-heading-line nil) (org-enforce-todo-dependencies t) (org-track-ordered-property-with-tag t) (org-highest-priority ?A) (org-lowest-priority ?C) (org-default-priority ?A) (org-confirm-babel-evaluate nil) (org-tags-column -97) ;;; log (org-log-done 'time) (org-log-into-drawer t) (org-log-note-clock-out nil) (org-log-redeadline 'time) (org-log-reschedule 'time) (org-read-date-prefer-future 'time) ;;; capture (org-capture-templates '(("t" "tasks" entry (file "inbox.org") "* TODO [#D] %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n") ("T" "TIL" entry (file+headline "til.org" "Today I learned") "* %^{title} :%^{tag}:\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?\nSource: %^C") ("n" "note" entry (file "notes.org") "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n") ("f" "feed" entry (file "inbox.org") ,(concat "* TODO [#D] %:elfeed-entry-title :feed:\n" ":PROPERTIES:\n:CREATED: %T\n:END:\n" "%a\n")) ("b" "bookmark" entry (file "bookmarks.org") ,(concat "* %(org-cliplink-capture) :%^{tag}:\n" ":PROPERTIES:\n:CREATED: %T\n:END:%?\n") :prepend t :empty-lines 1) ("j" "journal" entry (file+olp+datetree "journal.org") "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n" :tree-type day))) :config (font-lock-add-keywords 'org-mode '(("^ *\\(-\\) " (0 (ignore (compose-region (match-beginning 1) (match-end 1) "•"))))))) #+end_src *** org-agenda #+begin_src emacs-lisp (use-package org-agenda :commands org-agenda-list :bind* (("C-c a" . org-agenda)) :bind (:map org-agenda-mode-map (" " . org-agenda-tree-to-indirect-buffer) (">" . org-agenda-filter-by-top-headline) ("C-n" . next-line) ("C-p" . previous-line) ("F" . org-agenda-follow-mode) ("M-m") ("M-n" . org-agenda-later) ("M-p" . org-agenda-earlier) ("b" . org-agenda-date-earlier) ("f" . org-agenda-date-later) ("g" . org-agenda-redo) ("q" . delete-window) ("r" . org-agenda-refile) ("x" . org-agenda-todo) ("z" . pop-window-configuration)) :custom (org-agenda-auto-exclude-function 'org-my-auto-exclude-function) (org-agenda-cmp-user-defined 'org-compare-todo-age) (org-agenda-compact-blocks t) (org-agenda-deadline-leaders '("!D!: " "D%02d: " "D-%02d:")) (org-agenda-default-appointment-duration 60) (org-agenda-files '("~/documents/notes/inbox.org" "~/documents/notes/notes.org" "~/documents/notes/tasks.org" "~/documents/notes/bookmarks.org" "~/documents/notes/journal.org")) (org-agenda-fontify-priorities t) (org-agenda-include-diary t) (org-agenda-inhibit-startup t) (org-agenda-log-mode-items '(closed clock state)) (org-agenda-ndays 1) (org-agenda-persistent-filter t) (org-agenda-prefix-format '((agenda . " %-11c%?-12t% s") (timeline . " % s") (todo . " %-11c") (tags . " %-11c"))) (org-agenda-show-all-dates t) (org-agenda-show-outline-path nil) (org-agenda-skip-deadline-if-done t) (org-agenda-skip-scheduled-if-deadline-is-shown t) (org-agenda-skip-scheduled-if-done t) (org-agenda-skip-unavailable-files t) (org-agenda-sorting-strategy '((agenda habit-down time-up todo-state-up priority-down) (todo priority-down category-keep) (tags priority-down category-keep) (search category-keep))) (org-agenda-span 'day) (org-agenda-start-on-weekday 1) (org-agenda-tags-column -100) (org-agenda-tags-todo-honor-ignore-options t) (org-agenda-text-search-extra-files '(agenda-archives)) (org-agenda-todo-ignore-scheduled 'past) (org-agenda-use-time-grid nil) (org-agenda-window-frame-fractions '(0.5 . 0.75))) #+end_src *** org-bullet This is to make =org-mode= document looks a bit nicer. #+begin_src emacs-lisp (use-package org-bullets :ensure t :hook (org-mode . org-bullets-mode)) #+end_src *** org-auto-tangle #+begin_src emacs-lisp (use-package org-auto-tangle :ensure t :hook (org-mode . org-auto-tangle-mode)) #+end_src *** org-habit #+begin_src emacs-lisp (use-package org-habit :after org-agenda :custom (org-habit-preceding-days 42) (org-habit-today-glyph 45)) #+end_src *** org-attach #+begin_src emacs-lisp (use-package org-attach :after org :init (defun my-org-attach-visit-headline-from-dired () "Go to the headline corresponding to this org-attach directory." (interactive) (let* ((id-parts (last (split-string default-directory "/" t) 2)) (id (apply #'concat id-parts))) (let ((m (org-id-find id 'marker))) (unless m (user-error "Cannot find entry with ID \"%s\"" id)) (pop-to-buffer (marker-buffer m)) (goto-char m) (move-marker m nil))))) #+end_src *** org-babel #+begin_src emacs-lisp (use-package org-babel :no-require t :after (org ob-emamux) :config (org-babel-do-load-languages 'org-babel-load-languages '((python . t) (emacs-lisp . t) (calc . t) (shell . t) (sql . t) (dot . t))) (remove-hook 'kill-emacs-hook 'org-babel-remove-temporary-directory) (advice-add 'org-babel-edit-prep:emacs-lisp :after #'(lambda (_info) (run-hooks 'emacs-lisp-mode-hook)))) #+end_src *** org-bookmark-heading #+begin_src emacs-lisp (use-package org-bookmark-heading :ensure t :after org) #+end_src *** org-download #+begin_src emacs-lisp (use-package org-download :after org :ensure t :bind (:map org-mode-map ("C-c C-x C" . org-download-clipboard) ("C-c C-x Y" . org-download-yank)) :custom (org-download-method 'attach)) #+end_src *** org-id #+begin_src emacs-lisp (use-package org-id :after org :bind (:map org-mode-map ("C-c C-x i" . org-id-get-create)) :custom (org-id-locations-file (user-data "org-id-locations"))) #+end_src *** org-protocol #+begin_src emacs-lisp (use-package org-protocol :after org) #+end_src *** org-ql #+begin_src emacs-lisp (use-package org-ql :ensure t :commands org-ql-search) #+end_src *** org-rich-yank #+begin_src emacs-lisp (use-package org-rich-yank :ensure t :bind (:map org-mode-map ("C-M-y" . org-rich-yank))) #+end_src *** org-sticky-header #+begin_src emacs-lisp (use-package org-sticky-header :ensure t :commands org-sticky-header-mode) #+end_src *** org-super-agenda #+begin_src emacs-lisp (use-package org-super-agenda :after org :ensure t :custom (org-super-agenda-groups '((:name "Important" :priority "A") (:name "Needs review" :todo "WAITING" :todo "DELEGATED") (:name "Optional" :priority "C" :order 9) (:name "Tasks" :not (:priority "A" :priority "C")))) (org-super-agenda-header-separator "") :config (org-super-agenda-mode)) #+end_src *** org-web-tools #+begin_src emacs-lisp (use-package org-web-tools :ensure t :bind (("C-c w C-y" . my-org-insert-url) ("C-c w C-M-y" . org-web-tools-insert-web-page-as-entry)) :functions (org-web-tools--org-link-for-url org-web-tools--get-first-url) :preface (defun my-org-insert-url (&optional arg) (interactive "P") (require' org-web-tools) (let ((link (org-web-tools--org-link-for-url (org-web-tools--get-first-url)))) (if arg (progn (org-set-property "URL" link) (message "Added pasteboard link to URL property")) (insert link))))) #+end_src *** orgit #+begin_src emacs-lisp (use-package orgit :ensure t :after org) #+end_src *** ox **** ox-gfm #+begin_src emacs-lisp (use-package ox-gfm :ensure t :after org) #+end_src **** ox-md #+begin_src emacs-lisp (use-package ox-md :after org) #+end_src **** ox-pandoc #+begin_src emacs-lisp (use-package ox-pandoc :ensure t :after org :preface (defun markdown-to-org-region (start end) "Convert region from markdown to org, replacing selection" (interactive "r") (shell-command-on-region start end "pandoc -f markdown -t org" t t))) #+end_src ** path setup #+begin_src emacs-lisp (use-package exec-path-from-shell :ensure t :demand t :if (memq window-system '(mac ns)) :config (exec-path-from-shell-initialize)) #+end_src ** project #+begin_src emacs-lisp (use-package project :ensure nil :custom (project-switch-commands '((project-dired "Root" ?d) (project-find-file "File" ?f) (project-switch-to-buffer "Buffer" ?b) (project-eshell "Shell" ?e) (magit-project-status "Git" ?g))) :init (setq-default project-list-file (user-data "projects.eld"))) #+end_src ** recentf #+begin_src emacs-lisp (use-package recentf :demand t :commands (recentf-mode recentf-add-file recentf-apply-filename-handlers) :custom (recentf-auto-cleanup 60) (recentf-exclude '("~\\'" "\\`out\\'" "\\.log\\'" "^/[^/]*:" "\\.el\\.gz\\'" "\\.gz\\'")) (recentf-max-saved-items 2000) (recentf-save-file (user-data "recentf")) :preface :config (recentf-mode 1)) #+end_src ** rg #+begin_src emacs-lisp (use-package rg :ensure t :custom ((rg-group-result t) (rg-show-columns t) (rg-align-line-number-field-length 3) (rg-align-column-number-field-length 3) (rg-align-line-column-separator "#") (rg-align-position-content-separator "|") (rg-hide-command nil) (rg-align-position-numbers t) (rg-command-line-flags '("--follow")))) #+end_src ** savehist #+begin_src emacs-lisp (use-package savehist :unless noninteractive :custom (savehist-additional-variables '(file-name-history kmacro-ring compile-history compile-command)) (savehist-autosave-interval 60) (savehist-file (user-data "history")) (savehist-ignored-variables '(load-history flyspell-auto-correct-ring org-roam-node-history magit-revision-history org-read-date-history query-replace-history yes-or-no-p-history kill-ring)) (savehist-mode t) :config (savehist-mode 1)) #+end_src ** saveplace #+begin_src emacs-lisp (use-package saveplace :unless noninteractive :custom (save-place-file (user-data "places")) :config (save-place-mode 1)) #+end_src ** theme *** modus-themes This theme is clean and readable. The [[https://protesilaos.com/emacs/modus-themes][online documentation]] is pretty detailed too. #+begin_src emacs-lisp (use-package emacs :custom ;; Syntax Highlighting ;; Increase the number of bolded syntax elements (modus-themes-bold-constructs t) ;; Increase the number of italicized syntax elements (modus-themes-italic-constructs t) ;; Org Mode ;; Make headings in org files more distinct (modus-themes-headings '((t . (background bold rainbow 1)))) ;; Tint the background of code blocks in org files (modus-themes-org-blocks 'tinted-background) ;; Make tags less colorful and tables look the same as ;; the default foreground. (prose-done cyan-cooler) (prose-tag fg-dim) (prose-table fg-main) ;; Other ;; Make the fringe more intense (modus-themes-common-palette-overrides '((fringe bg-active))) ;; Enhance minibuffer completions (modus-themes-completions 'minimal) ;; Make the current line of `hl-line-mode' a fine shade of gray (bg-hl-line bg-dim) ;; Make matching parentheses a shade of magenta (bg-paren-match bg-magenta-intense) (bg-mode-line-inactive bg-dim) :config (load-theme 'modus-operandi t)) #+end_src *** COMMENT standard-themes I like the default theme, but there's not enough contrast. The package =standard-themes= fix this problem. The full documentation can be [[https://protesilaos.com/emacs/standard-themes][read online]]. #+begin_src emacs-lisp (use-package standard-themes :ensure t :init (setq standard-themes-bold-constructs t standard-themes-italic-constructs t standard-themes-mixed-fonts t standard-themes-variable-pitch-ui nil standard-themes-mode-line-accented t ;; Accepts a symbol value: standard-themes-fringes 'intense ;; The following accept lists of properties standard-themes-links '(italic neutral-underline) standard-themes-region '(no-extend neutral intense) standard-themes-prompts '(bold italic) standard-themes-headings (quote ((1 . (bold 1.2)) (2 . (regular 1.1)) (agenda-date (1.1)) (agenda-structure (regular 1.1))))) (load-theme 'standard-light :no-confirm)) #+end_src ** time #+begin_src emacs-lisp (use-package time :custom (display-time-interval 60) (display-time-mode t) (display-time-24hr-format t) (display-time-day-and-date t) (display-time-default-load-average nil) (world-clock-list t) (world-clock-timer-enable t) (world-clock-timer-second 60) ;; UTC => 02:42 +0000 Wednesday 20 April ;; Berkeley => 19:42 -0700 Tuesday 19 April (world-clock-time-format "%R %z %A %d %B") (zoneinfo-style-world-list '(("UTC" "UTC") ("America/Los_Angeles" "Berkeley") ("America/Denver" "Mountain Time") ("America/Chicago" "Central Time") ("America/New_York" "New York") ("Europe/London" "London") ("Europe/Paris" "Paris"))) :init (add-to-list 'display-buffer-alist '("\\*wclock\\*" (display-buffer-in-side-window) (side . left) (slot . 0) (window-width . 0.35)))) #+end_src ** tramp #+begin_src emacs-lisp (use-package tramp :defer t :custom (tramp-default-method "ssh") (tramp-auto-save-directory "~/.cache/emacs/backups") (tramp-ssh-controlmaster-options "-o ControlMaster=auto -o ControlPath='tramp.%%C'") :config ;; Setting this with `:custom' does not take effect. (setq tramp-persistency-file-name (user-data "tramp"))) #+end_src ** transient #+begin_src emacs-lisp (use-package transient :defer t :custom (transient-history-file (user-data "transient/history.el")) (transient-values-file (user-data "transient/values.el"))) #+end_src ** vc #+begin_src emacs-lisp (use-package vc :defer t :custom (vc-command-messages t) (vc-follow-symlinks t)) #+end_src ** which-key #+begin_src emacs-lisp (use-package which-key :demand t :diminish :ensure t :config (which-key-mode)) #+end_src ** whitespace #+begin_src emacs-lisp (use-package whitespace :diminish (global-whitespace-mode whitespace-mode whitespace-newline-mode) :commands (whitespace-buffer whitespace-cleanup whitespace-mode whitespace-turn-off) :init (dolist (hook '(prog-mode-hook text-mode-hook)) (add-hook hook #'whitespace-mode)) :custom (whitespace-auto-cleanup t t) (whitespace-rescan-timer-time nil t) (whitespace-silent t t) (whitespace-style '(face trailing space-before-tab)) :defines (whitespace-auto-cleanup whitespace-rescan-timer-time whitespace-silent)) #+end_src * Finalization #+begin_src emacs-lisp (report-time-since-load) ;; Local Variables: ;; byte-compile-warnings: (not docstrings lexical noruntime) ;; End: #+end_src