about summary refs log tree commit diff
path: root/modules/workstation/emacs/init.el
blob: 85799ea1813750e3b7c571300f3f0af19af763b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
;; -*- 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))

;;; 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
  (setq dired-listing-switches
	(combine-and-quote-strings `(,dired-listing-switches "-h"))))

;;; 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)

;;; 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")))

;;; 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
  ;; <https://github.com/magit/magit/issues/3832>.
  (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)

;;; 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)