;; -*- lexical-binding: t -*- ;;; UI customization ;;; (column-number-mode) (electric-pair-mode) (global-so-long-mode) (menu-bar-mode -1) (scroll-bar-mode -1) (show-paren-mode) (tool-bar-mode -1) (setq frame-title-format "%b — Emacs") (setq uniquify-buffer-name-style 'forward) (setq-default truncate-lines t) (load-theme 'monokai t) ;; <102 or >109 will make Ioveska look squished rather than tall, ;; narrow, and beautiful. (set-face-attribute 'default nil :height 104) ;; Disabling bidirectional text will make Emacs less slow with very ;; long lines. (setq bidi-paragraph-direction 'left-to-right) (setq bidi-inhibit-bpa t) ;;; Utility functions ;;; ;; Set an environment variable value for a single buffer. (defun setenv-local (variable &optional value substitute-env-vars) ;; If process-environment is the global one, make a copy of it. (when (eq process-environment (default-value 'process-environment)) (make-local-variable 'process-environment) (setq process-environment (mapcar 'concat process-environment))) (setenv variable value substitute-env-vars)) (defun enable-ansi-color () (setenv-local "TERM" "dumb-emacs-ansi")) ;;; Major modes ;;; (add-to-list 'auto-mode-alist '("\\.adoc\\'" . adoc-mode)) (add-to-list 'auto-mode-alist '("\\.quirks\\'" . conf-unix-mode)) (add-to-list 'auto-mode-alist '("\\.tmac\\'" . nroff-mode)) (add-to-list 'auto-mode-alist '("/Cargo\\.lock\\'" . toml-mode)) ;;; Backups ;;; (let ((backup-dir (concat (file-name-as-directory user-emacs-directory) "backups"))) (make-directory backup-dir t) (setq backup-directory-alist `(("." . ,backup-dir))) (setq message-auto-save-directory backup-dir)) ;;; CC Mode ;;; (with-eval-after-load 'cc-styles ;; Default to kernel style. (add-to-list 'c-default-style '(other . "linux"))) ;;; Comint ;;; ;; This relies on an Emacs patch to apply to async-shell-command. (setq comint-terminfo-terminal "dumb-emacs-ansi") ;;; Diff Mode ;;; ;; Unbind M-DEL from scroll-down-command, so it does the same thing as ;; in the rest of Emacs (backward-kill-word). (with-eval-after-load 'diff-mode (define-key diff-mode-map (kbd "M-DEL") nil)) ;;; Dired ;;; (with-eval-after-load 'dired ;; Use human-readable sizes. (setq dired-listing-switches (combine-and-quote-strings `(,dired-listing-switches "-h"))) ;; Don't open new windows when clicking directory entries. (define-key dired-mode-map [mouse-2] 'dired-find-file)) ;;; Direnv ;;; (direnv-mode) (global-set-key (kbd "C-c d") #'direnv-update-environment) ;;; Ediff ;;; ;; Don't make a new frame for Ediff controls. (setq ediff-window-setup-function 'ediff-setup-windows-plain) ;;; EditorConfig ;;; (editorconfig-mode) ;;; Eglot ;;; (with-eval-after-load 'eglot ;; Override default LSPs for languages. (add-to-list 'eglot-server-programs '(rust-mode "rust-analyzer")) (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd")) ;; Underline all occurrences of the symbol at point in the current ;; buffer (default is to bold instead). (set-face-attribute 'eglot-highlight-symbol-face nil :inherit 'underline) ;; Add keybindings for eglot actions. (define-key eglot-mode-map (kbd "C-c e a") #'eglot-code-actions) (define-key eglot-mode-map (kbd "C-c e r") #'eglot-rename)) ;; Tell rust-analyzer not to allow colons inside Rust import. (setq-default eglot-workspace-configuration '((:rust-analyzer . (:assist (:importMergeBehaviour "last"))))) ;;; Environment ;;; ;; Provide a way to turn paging back on for modes like terminal emulators. (let ((pager (getenv "PAGER"))) (defun enable-pager () (setenv-local "PAGER" pager))) ;; Set PAGER to the empty string, which Git and journalctl will ;; interpret as an explicit opt-out of paging. (setenv "PAGER" "") ;;; Eshell ;;; (add-hook 'eshell-mode-hook #'enable-ansi-color) ;;; Ibuffer ;;; ;; Open ibuffer in other window, to match behaviour of the default ;; list-buffers. (global-set-key (kbd "C-x C-b") (lambda () (interactive) (ibuffer t))) ;;; ispell ;;; ;; System locale is Esperanto, but I write in English much more, and ;; spelling in Esperanto is easy anyway. ;) (setq ispell-dictionary "english") ;;; Magit ;;; (setq magit-delete-by-moving-to-trash delete-by-moving-to-trash) (setq magit-repository-directories `((,(expand-file-name "~/src") . 1))) (global-set-key (kbd "C-x g") #'magit-status) (global-set-key (kbd "C-x M-g") #'magit-dispatch) (with-eval-after-load "magit" ;; Add a --no-gpg-sign option to Magit. This is only useful with ;; commit.gpgsign=true. It would be nice if commit.gpgsign=true just ;; meant that Magit showed the --gpg-sign option as enabled by ;; default, and disabling it would make Magit pass --no-gpg-sign to ;; git, but that's not currently the case, so we need a seperate ;; option for --no-gpg-sign. See ;; . (dolist (command '(magit-commit magit-merge magit-cherry-pick magit-revert magit-am magit-rebase)) (transient-append-suffix command ["-S"] '("=S" "Don't sign using gpg" "--no-gpg-sign")))) ;;; Man ;;; ;; Open man pages in the current window. I don't really care what ;; happens when I do M-x man, but I don't want my whole frame to be ;; taken over with man buffers if I'm following a bunch of ;; cross-references. (setq Man-notify-method 'pushy) ;;; MML ;;; (setq mml-secure-openpgp-signers '("757356D779BBB888773E415E736CCDF9EF51BD97")) ;;; Nix support ;;; (defun browse-url-nixpkgs (attr) "Open a browser to the homepage for the Nixpkgs attribute ATTR." (interactive "sAttribute: ") (let* ((full-attr-quoted (shell-quote-argument (concat attr ".meta.homepage"))) (command (concat "nix eval --raw -f '' " full-attr-quoted)) (homepage (shell-command-to-string command))) (browse-url homepage))) ;;; Rainbow Delimiters ;;; (add-hook 'prog-mode-hook #'rainbow-delimiters-mode) ;;; Revert buffers ;;; (global-set-key (kbd "C-c r") #'revert-buffer) ;;; Rust ;;; ;; Indent with spaces in Rust code. (add-hook 'rust-mode-hook (lambda () (setq indent-tabs-mode nil))) (with-eval-after-load 'rust-mode ;; Cargo keybindings (define-key rust-mode-map (kbd "C-c c b") 'rust-compile) (define-key rust-mode-map (kbd "C-c c c") 'rust-check) (define-key rust-mode-map (kbd "C-c c r") 'rust-run) (define-key rust-mode-map (kbd "C-c c t") 'rust-test)) ;;; save-some-buffers ;;; ;; Allow reverting buffers directly from the "Save file ...?" message. (add-to-list 'save-some-buffers-action-alist `(?r ,(lambda (buf) (with-current-buffer buf (revert-buffer t t))) ,(purecopy "revert this buffer"))) ;;; sendmail ;;; ;; Use the system "sendmail" program to send mail. (setq send-mail-function 'sendmail-send-it) ;;; Term ;;; (add-hook 'term-mode-hook #'enable-pager) ;;; Transient ;;; ;; Make all Magit options available, even those that are disabled by ;; default because they're too obscure. (setq transient-default-level 7) ;;; with-editor ;;; (add-hook 'eshell-mode-hook 'with-editor-export-editor) (add-hook 'shell-mode-hook 'with-editor-export-editor) (add-hook 'term-exec-hook 'with-editor-export-editor)