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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
|
#+TITLE: My configuration
#+AUTHOR: Andrew Guschin
#+PROPERTY: tangle yes
* Basic settings
This replaces default Emacs welcome screen with custom simple splash. This is based on some
combination of https://github.com/rougier/emacs-splash and splash screen of
https://github.com/rougier/nano-emacs. Big thanks to original author, but I wanted simple splash
screen that doesn't disappear after I start pressing buttons.
I also want for this splash screen to be able to respond to window size changes, but for now I like
it as it is.
#+BEGIN_SRC emacs-lisp
(setq inhibit-startup-screen t)
(setq inhibit-startup-message t)
(setq inhibit-startup-echo-area-message t)
(setq initial-scratch-message nil)
(setq initial-buffer-choice nil)
(load-file (expand-file-name "scratch-splash.el" user-emacs-directory))
(add-hook 'window-setup-hook 'scratch-splash)
#+END_SRC
This starts with some settings that are useful for already initialized configuration. I set up
theme first thing so that the default one doesn't blind me at night. Also set up the correct font.
#+BEGIN_SRC emacs-lisp
;; (when (package-installed-p 'ayu-theme)
;; (load-theme 'ayu-grey t))
(when (package-installed-p 'kaolin-themes)
(load-theme 'kaolin-galaxy t)
;; (load-theme 'kaolin-breeze t)
)
(add-to-list 'default-frame-alist
'(font . "FiraCode Nerd Font 15"))
#+END_SRC
Menu bar looks okay in macOS because it's contained in global menu bar of OS for focused window.
I'd say that bar without application's menu looks strange on macOS. On linux menu is attached to
every client, so this doesn't look that good, so it better be turned off.
#+BEGIN_SRC emacs-lisp
(when (eq system-type 'gnu/linux)
(menu-bar-mode -1))
(when (eq system-type 'darwin)
(menu-bar-mode t))
#+END_SRC
Disable more of unneeded app decorations (now for all OSes), enable some niceties, and disable
several annoying things. Looks like pixel scrolling works only on macOS.
#+BEGIN_SRC emacs-lisp
(tool-bar-mode -1)
(scroll-bar-mode -1)
(toggle-scroll-bar -1)
(xterm-mouse-mode t)
(buffer-face-mode t)
;; (pixel-scroll-precision-mode t)
;; (setq frame-resize-pixelwise t)
(setq-default fill-column 100)
(global-display-fill-column-indicator-mode t)
(global-set-key (kbd "C-<wheel-up>") 'ignore)
(global-set-key (kbd "C-<wheel-down>") 'ignore)
(setq ring-bell-function 'ignore)
#+END_SRC
#+BEGIN_SRC emacs-lisp
(setq-default indent-tabs-mode nil)
(setq-default tab-width 8)
(setq-default c-default-style "bsd")
(setq-default c-basic-offset 4)
#+END_SRC
#+BEGIN_SRC emacs-lisp
(defun my-backup-file-name (fpath)
"Return a new file path of a given file path. If the new path's
directories does not exist, create them."
(let* ((backupRootDir (expand-file-name "backup" user-emacs-directory))
(filePath (replace-regexp-in-string "[A-Za-z]:" "" fpath )) ; remove Windows driver letter in path, for example, “C:”
(backupFilePath (replace-regexp-in-string "//" "/" (concat backupRootDir filePath "~") )))
(make-directory (file-name-directory backupFilePath) (file-name-directory backupFilePath))
backupFilePath))
(setq make-backup-file-name-function 'my-backup-file-name)
#+END_SRC
I don't want this autogenerated code to be added to main config file automatically. Now it will be
placed in its own file and won't annoy me.
#+BEGIN_SRC emacs-lisp
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file)
#+END_SRC
* Package management
Several packages are not present in GNU ELPA, so I need to add MELPA archive.
#+BEGIN_SRC emacs-lisp
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
#+END_SRC
For package management I use use-package with always-ensure flag turned on. That way on new installs
this config bootstraps itself.
#+BEGIN_SRC emacs-lisp
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(setq-default use-package-always-ensure t)
(setq-default use-package-always-defer t)
(require 'use-package)
#+END_SRC
* Plugins
** Theme
Install some nice theme. It is loaded in the beginning of the config, so after bootstrapping emacs
should be restarted. Or this theme can be loaded by hand...
#+BEGIN_SRC emacs-lisp
(use-package ayu-theme)
(use-package kaolin-themes)
(use-package auto-dark
:custom
(auto-dark-themes '((ayu-grey) (kaolin-breeze))))
#+END_SRC
** Small plugins
#+BEGIN_SRC emacs-lisp
(use-package adoc-mode)
(use-package docker :bind ("C-c d" . docker))
(use-package vterm)
(use-package origami :hook ((prog-mode . origami-mode)))
(use-package diff-hl
:hook ((text-mode . diff-hl-mode)
(prog-mode . diff-hl-mode)
(dired-mode . diff-hl-dired-mode)))
(use-package benchmark-init)
#+END_SRC
** evil-mode
Emacs is great operating system that doesn't have good editor.
It is useful to enable relative numbering of lines in normal state, for easier use of motions. But
in insert mode it is not so useful, so this turns on regular numbering for this mode.
But in some major modes evil shadows their keymaps, so I set their initial state to emacs's keymaps.
#+BEGIN_SRC emacs-lisp
(global-display-line-numbers-mode -1)
(use-package evil
:init
(use-package undo-fu)
(setq evil-undo-system 'undo-fu)
(setq evil-want-keybinding nil)
:config
;; (evil-set-initial-state 'dired-mode 'emacs)
(evil-set-initial-state 'eshell-mode 'emacs)
(evil-set-initial-state 'shell-mode 'emacs)
(evil-set-initial-state 'buffer-menu-mode 'emacs)
(define-key universal-argument-map (kbd "C-u") nil)
(define-key evil-motion-state-map (kbd "C-u") 'evil-scroll-up)
:hook
((prog-mode . evil-mode)
(text-mode . evil-mode)
(prog-mode . display-line-numbers-mode)
(text-mode . display-line-numbers-mode)
(evil-insert-state-entry . (lambda () (setq-local display-line-numbers t)))
(evil-normal-state-entry . (lambda () (setq-local display-line-numbers 'relative)))))
;; (eval-after-load "dired"
;; '(progn
;; (dired-listing-switches )
;; ))
(use-package evil-collection
:after evil
:after dired
:init
(evil-collection-init '(dired))
(use-package dired-subtree)
:config
(evil-collection-define-key 'normal 'dired-mode-map
"o" 'dired-subtree-toggle
"c" 'dired-subtree-remove
"i" nil
"a" nil
"A" nil
))
#+END_SRC
I use `C-u` keymap from vim very often, but in emacs it is bound to 'universal argument'.
Universal argument is quite useful in some circumstances, but scrolling is used much more often.
So this remaps universal argument to `C-f`, and scrolling to `C-u`.
#+BEGIN_SRC emacs-lisp
(define-key global-map (kbd "C-f") 'universal-argument)
(define-key universal-argument-map (kbd "C-u") nil)
(define-key universal-argument-map (kbd "C-f") 'universal-argument-more)
(define-key global-map (kbd "C-u") 'kill-whole-line)
(eval-after-load 'evil-maps
'(progn
(define-key evil-motion-state-map (kbd "C-f") nil)
))
#+END_SRC
** magit
Just great git client. I don't have any configurations for it yet.
#+BEGIN_SRC emacs-lisp
(use-package magit)
(use-package magit-todos
:after magit
:config (magit-todos-mode 1))
#+END_SRC
** lisp packages
#+BEGIN_SRC emacs-lisp
(use-package paredit
:hook
(emacs-lisp-mode . paredit-mode))
(use-package rainbow-delimiters
:hook
(emacs-lisp-mode . rainbow-delimiters-mode))
#+END_SRC
** exec-path-from-shell
I like to follow XDG Base Directory specification, and have many environment variables for tools,
that don't use XDG directories. To use these tools within Emacs, I need to get some variables, that
are set within my `.profile`.
#+BEGIN_SRC emacs-lisp
(use-package exec-path-from-shell
:config
(when (memq window-system '(mac ns x))
;; I set up this variable, so that shell would know that it is being executed from emacs, and
;; not really interactively
(setenv "EMACS" "emacs")
(setq exec-path-from-shell-variables
'("PATH" "CARGO_HOME" "RUSTUP_HOME" "GOPATH"
"RYE_HOME" "NPM_CONFIG_USERCONFIG"
"STACK_ROOT" "GHCUP_USE_XDG_DIRS"))
(exec-path-from-shell-initialize)))
#+END_SRC
** LSP
Configuration for some languages that I used in Emacs. Not all the languages that I used, but most
recent ones. If I decide to try something new, or open some old project in Emacs, this config
(probably) will be updated.
#+BEGIN_SRC emacs-lisp
(setq major-mode-remap-alist
'(;; (typescript-mode . typescript-ts-mode)
(rust-mode . rust-ts-mode)
))
(use-package lsp-mode
:init
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
(setq lsp-keymap-prefix "C-l")
(use-package company)
(use-package rust-mode)
(use-package go-mode)
(use-package projectile)
(use-package lsp-java
:custom (setq lsp-java-server-install-dir
(concat (getenv "HOME") "/.local/share/jdtls/")))
;; (use-package typescript-mode)
(use-package lsp-tailwindcss
:after lsp-mode
:init (setq lsp-tailwindcss-add-on-mode t))
(use-package web-mode)
;; if you want which-key integration
;;(lsp-mode . lsp-enable-which-key-integration))
:hook ((lsp-mode . company-mode)
(rust-ts-mode . lsp)
(rust-ts-mode . projectile-mode)
(go-mode . lsp)
(java-mode . lsp)
(c++-mode . lsp)
;; (web-mode . lsp)
;; (typescript-mode . add-node-modules-path)
;; (typescript-mode . web-mode)
(typescript-ts-mode . lsp)
(typescript-ts-mode . projectile-mode)
(typescript-ts-mode . prettier-js-mode)
(tsx-ts-mode . lsp)
(tsx-ts-mode . projectile-mode)
(tsx-ts-mode . prettier-js-mode)
;; (typescript-mode . (lambda ()
;; (projectile-mode)
;; (lsp)
;; ))
)
:commands lsp
:custom
(lsp-clients-typescript-prefer-use-project-ts-server 1)
(lsp-clients-typescript-tls-path
(concat (projectile-project-root)
"node_modules/.bin/typescript-language-server"))
;; ()
;; Saved in case I use vue.js with lsp some other time
;; :custom
;; (lsp-clients-typescript-plugins
;; (vector (list :name "@vue/typescript-plugin"
;; :location (concat (getenv "BUN_INSTALL")
;; "/install/global/node_modules/@vue/typescript-plugin")
;; :languages (vector "typescript" "javascript" "vue"))))
)
(use-package flycheck :hook (after-init . #'global-flyckeck-mode))
(use-package lsp-ui :commands lsp-ui-mode)
(use-package helm-lsp :commands helm-lsp-workspace-symbol)
#+END_SRC
Web development tools need more configuration, than most other languages. So all of this
configuration is done inside web-mode, because most web projects are used with multiple language
servers (most of the time with multiple for single buffer, even).
#+BEGIN_SRC emacs-lisp
;; (use-package web-mode
;; :init
;; (use-package prettier-js)
;; (use-package vue-mode)
;; (use-package svelte-mode)
;; (use-package lsp-tailwindcss
;; :after web-mode
;; :init (setq lsp-tailwindcss-add-on-mode t))
;; :after lsp-mode
;; :hook ((web-mode . prettier-js-mode))
;; :mode (("\\.ts\\'" . web-mode)
;; ("\\.js\\'" . web-mode)
;; ("\\.vue\\'" . web-mode)
;; ("\\.tsx\\'" . web-mode)
;; ("\\.jsx\\'" . web-mode))
;; :config
;; (setq web-mode-markup-indent-offset 2)
;; (setq web-mode-css-indent-offset 2)
;; (setq web-mode-code-indent-offset 2)
;; (setq web-mode-script-padding 0)
;; (setq web-mode-style-padding 0)
;; (setq web-mode-block-padding 0)
;; (setq web-mode-content-types-alist
;; '(("jsx" . "\\.js[x]?\\'"))))
;; (use-package add-node-modules-path :commands add-node-modules-path)
#+END_SRC
** Tree-sitter
#+BEGIN_SRC emacs-lisp
;; (use-package treesit
;; :ensure nil
;; :config
;; (setq-default
;; treesit-language-source-alist
;; '((tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src"))
;; (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))
;; ))
;; (treesit-install-language-grammar 'tsx)
;; (treesit-install-language-grammar 'typescript)
;; )
(use-package treesit-auto
:config
(add-to-list 'treesit-auto-recipe-list
(make-treesit-auto-recipe
:lang 'typescript
:ts-mode 'tsx-ts-mode
:url "https://github.com/tree-sitter/tree-sitter-typescript"
:source-dir "tsx/src"
:ext "\\.tsx\\'"))
:custom
(treesit-auto-langs '(tsx))
)
;; (use-package tree-sitter
;; :init
;; (use-package tree-sitter-langs)
;; :hook (tree-sitter-after-on . tree-sitter-hl-mode))
#+END_SRC
** Spelling
#+BEGIN_SRC emacs-lisp
(setq ispell-program-name "hunspell")
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(add-hook 'text-mode-hook 'ispell-minor-mode)
(add-hook 'prog-mode-hook 'ispell-minor-mode)
#+END_SRC
|