guest@dotshare [~/groups/emacs/config] $ ls My-tmux-like-workflow-config/ | cat

My tmux-like workflow config

linuxkitty Nov 29, 2020 (emacs/config)

init-basic.el(raw, dl)

  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
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
;; dont ask if file doesn't exist
(setq confirm-nonexistent-file-or-buffer nil)

;; dont ask for comfirmation when killing a buffer with a process in it
(setq kill-buffer-query-functions
  (remq 'process-kill-buffer-query-function
         kill-buffer-query-functions))

(unless (getenv "LC_ALL")
  (setenv "LC_ALL" "en_US.utf8")
  (setenv "LANG" "en_US.utf8"))

(defun my-path-join* (rest)
  (if (cdr rest)
      (concat (file-name-as-directory (car rest)) (my-path-join* (cdr rest)))
    (car rest)))
(defun my-path-join (&rest args)
  (my-path-join* args))

(defconst emacs-root-init-dir (file-name-directory load-file-name))
(defun emacs-root-join (&rest args)
  (apply 'my-path-join (cons emacs-root-init-dir args)))

(defconst user-home-dir (getenv "HOME"))
(defun user-home-join (&rest args)
  (apply 'my-path-join (cons user-home-dir args)))

;; Tmp dir for saving backups
(defconst my-emacs-backups-dir (emacs-root-join "backups~"))
(setq backup-directory-alist
      `((".*" . ,my-emacs-backups-dir)))
(setq auto-save-file-name-transforms
      `((".*" ,my-emacs-backups-dir t)))
(setq auto-save-list-file-prefix
      my-emacs-backups-dir)

;; Don't disable downcase
(put 'downcase-region 'disabled nil)

;;;;;;;;;;;;;
;; HELPERS ;;
;;;;;;;;;;;;;

(defun sh (proc &rest args)
  (string-trim-right
   (car (apply 'call-process-with-output (cons proc args)))))

(defun set-in-alist (alist key value)
  (let ((cur alist)
        (ret nil)
        (repl (cons key value))
        (foundq nil))
    (while cur
      (let* ((cell (car cur))
             (iseq (equal key (car cell)))
             (new (if iseq repl cell)))
        (if iseq (setq foundq t))
        (setq ret (cons new ret)))
      (setq cur (cdr cur)))

    (unless foundq
      (setq ret (cons repl ret)))

    ret))

(defmacro set-in-alist! (alist key value)
  `(setq ,alist (set-in-alist ,alist ,key ,value)))

(defun cl--mapcar-many (cl-func cl-seqs &optional acc)
  (if (cdr (cdr cl-seqs))
      (let* ((cl-res nil)
             (cl-n (apply 'min (mapcar 'length cl-seqs)))
             (cl-i 0)
             (cl-args (copy-sequence cl-seqs))
             cl-p1 cl-p2)
        (setq cl-seqs (copy-sequence cl-seqs))
        (while (< cl-i cl-n)
          (setq cl-p1 cl-seqs cl-p2 cl-args)
          (while cl-p1
            (setcar cl-p2
                    (if (consp (car cl-p1))
                        (prog1 (car (car cl-p1))
                          (setcar cl-p1 (cdr (car cl-p1))))
                      (aref (car cl-p1) cl-i)))
            (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)))
          (if acc
              (push (apply cl-func cl-args) cl-res)
            (apply cl-func cl-args))
          (setq cl-i (1+ cl-i)))
        (and acc (nreverse cl-res)))
    (let ((cl-res nil)
          (cl-x (car cl-seqs))
          (cl-y (nth 1 cl-seqs)))
      (let ((cl-n (min (length cl-x) (length cl-y)))
            (cl-i -1))
        (while (< (setq cl-i (1+ cl-i)) cl-n)
          (let ((val (funcall cl-func
                              (if (consp cl-x) (pop cl-x) (aref cl-x cl-i))
                              (if (consp cl-y) (pop cl-y) (aref cl-y cl-i)))))
            (when acc
              (push val cl-res)))))
      (and acc (nreverse cl-res)))))

(defun zip-with (cl-func cl-x &rest cl-rest)
  "Apply FUNCTION to each element of SEQ, and make a list of the results.
If there are several SEQs, FUNCTION is called with that many arguments,
and mapping stops as soon as the shortest list runs out.  With just one
SEQ, this is like `mapcar'.  With several, it is like the Common Lisp
`mapcar' function extended to arbitrary sequence types.
\n(fn FUNCTION SEQ...)"
  (if cl-rest
      (if (or (cdr cl-rest) (nlistp cl-x) (nlistp (car cl-rest)))
          (cl--mapcar-many cl-func (cons cl-x cl-rest) 'accumulate)
        (let ((cl-res nil) (cl-y (car cl-rest)))
          (while (and cl-x cl-y)
            (push (funcall cl-func (pop cl-x) (pop cl-y)) cl-res))
          (nreverse cl-res)))
    (mapcar cl-func cl-x)))

(defun repeat-n (n f)
    (funcall f)
    (if (> n 0) (repeat-n (- n 1) f)))

(defun list-to-string (list)
  (mapconcat 'string list ""))

;;;; scrolling

(defun window-half-height ()
  (max 1 (/ (1- (window-height (selected-window))) 4)))

(defun scroll-up-half ()
  (interactive)
  (scroll-up (window-half-height))
  )

(defun scroll-down-half ()
  (interactive)
  (scroll-down (window-half-height))
  )

;;;; buffers

(defun my-save-buffer-force ()
  (let ((save-silently t)
        (inhibit-message t))
    (basic-save-buffer-1)))

(defun my-save-buffer (buf)
  (when (and (buffer-file-name buf)
             (buffer-modified-p buf))
    (with-current-buffer buf
      (make-thread 'my-save-buffer-force))))

(defun my-save-current-buffer ()
  (my-save-buffer (current-buffer)))

(defun my-save-current-buffer-sync ()
  (let ((maybe-thread (my-save-current-buffer)))
    (and maybe-thread (thread-join maybe-thread))))

(defun kill-buffer-fast ()
  "Saves and kills CURRENT buffer."
  (interactive)
  (when (and buffer-file-name
             (file-writable-p buffer-file-name))
    (my-save-current-buffer-sync))
  (kill-buffer (current-buffer)))

;;;; editor
(defun move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode)
  )

(defun move-line-down ()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode)
  )

;;;; other

(defun my-grep ()
  (interactive)
  (let ((arg (read-shell-command "grep: " nil 'grep-history)))
    (let ((command (concat grep-command " " arg)))
      (compilation-start
       command
       'grep-mode))))

(defun program-resolve-path (program)
  (string-trim
   (car
    (call-process-with-output "which" "fish"))))

(defun call-process-with-output (proc &rest args)
  (let ((return-code -1))
    (list
     (with-output-to-string
       (with-current-buffer
           standard-output
         (setq return-code (apply 'call-process (append (list proc nil t nil) args)))))
     return-code)))

(defun my-git-save ()
  (interactive)
  (my-save-current-buffer)
  (let ((out (call-process-with-output "gcma" "save")))
    (message "%s" (string-trim (car out)))))

(defun my-git-status ()
  (interactive)
  (my-save-current-buffer)
  (let ((out (sh "git" "status" "--short")))
    (when (string-empty-p out)
      (setq out (sh "git" "status")))
    (message "%s" out)))

(defun my-revert-buffer ()
  (interactive)
  (message
   (if (revert-buffer nil t nil)
       "I reverted buffer :)"
     "I failed you, sensei")))

;;;;;;;;;;
;; KEYS ;;
;;;;;;;;;;

(global-set-key (kbd "M-e") 'forward-paragraph)
(global-set-key (kbd "M-a") 'backward-paragraph)

(global-set-key (kbd "C-{") 'shrink-window-horizontally)
(global-set-key (kbd "C-}") 'enlarge-window-horizontally)
(global-set-key (kbd "C-^") 'enlarge-window)

(global-set-key (kbd "M-<up>")  'move-line-up)
(global-set-key (kbd "M-<down>") 'move-line-down)
(global-set-key (kbd "C-z") nil)

;; for terminal compatibilty
(global-set-key (kbd "C-x ;") 'comment-line)

;; transient keymap used once cycling starts
(setq buffer-flip-map
      (let ((map (make-sparse-keymap)))
        (define-key map (kbd "M-p") 'buffer-flip-forward)
        (define-key map (kbd "M-n") 'buffer-flip-backward)
        (define-key map (kbd "M-g") 'buffer-flip-abort)
        map))

(defmacro my-bind-all (&rest pairs)
  `(progn
     ,@(mapcar
        (lambda (p)
          (let ((key (car p))
                (val (cdr p)))
            (if (consp (car val))
                `(define-key keymap (kbd ,key) (lambda () (interactive) ,@val))
              `(define-key keymap (kbd ,key) (quote ,(car val))))))
        pairs)))

(setq my-window-map
      (let ((keymap (make-sparse-keymap)))
        (my-bind-all
         ("M-b"   split-window-below)
         ("M-v"   split-window-right)
         ("M-q"   delete-window)
         ("M-S-q" (quit-window 1))
         ("M-k"   kill-buffer-fast)
         ("M-a"   windmove-left)
         ("M-s"   windmove-down)
         ("M-w"   windmove-up)
         ("M-d"   windmove-right)

         ("e"     buffer-menu)
         ("M-e"   switch-to-buffer)
         ("M-i"   (find-file "."))
         ("M-x"   (save-buffers-kill-terminal t))

         ("M-f"   projectile-find-file)
         ("M-g"   my-grep)
         ("r"     my-revert-buffer)
         ("M-r"   query-replace)

         ("M--"   my-default-font-size-dec!)
         ("M-="   my-default-font-size-inc!)
         ("M-j"   my-git-save)
         ("M-h"   my-git-status)

         ("M-p"   buffer-flip)
         ("M-n"   (buffer-flip) (buffer-flip-forward) (buffer-flip-forward) (buffer-flip-forward))

         ("M-c"   shell-command)
         ("c"     my-term-exe)
         ("M-t"   my-term)
         ("M-y"   my-term-taged))

        ;; terminal for each number
        (defmacro macr (z)
          `(define-key
             keymap
             (kbd
              (format "M-%d" ,z))
             (lambda ()
               (interactive)
               (my-term-indexed ,z))))
        (mapc
         #'(lambda (i) (eval `(macr ,i)))
         (list 1 2 3 4 5 6 7 8 9))

        keymap))

(global-set-key (kbd "M-o") my-window-map)

;;;;;;;;;;;;;;
;; AUTOSAVE ;;
;;;;;;;;;;;;;;

(defun my-select-window-advice
    (orig-fun &rest args)
  (let ((old (current-buffer)))
    (apply orig-fun args)
    (unless (or (= ? (elt (buffer-name (current-buffer)) 0)) ; internal?
                (equal old (current-buffer)))
      (my-save-buffer old))))
(advice-add 'select-window :around 'my-select-window-advice)
(advice-add 'switch-to-buffer :around 'my-select-window-advice)
(add-function :after after-focus-change-function #'my-save-current-buffer)

;;;;;;;;;;
;; LOOK ;;
;;;;;;;;;;

(font-lock-add-keywords
 'scheme-mode
 '(("\\('\\([^] (){}[]+\\)\\|\\b[0-9]+\\b\\)" . font-lock-constant-face)))

(setq-default frame-title-format '("%b"))

(defun my-default-font-size-set! (size)
  (set-face-attribute 'default nil :height size))
(defun my-default-font-size ()
  (interactive)
  (face-attribute 'default :height nil))
(defun my-default-font-size-inc! ()
  (interactive)
  (my-default-font-size-set!
   (round (* 1.1 (my-default-font-size)))))
(defun my-default-font-size-dec! ()
  (interactive)
  (my-default-font-size-set!
   (round (* 0.9 (my-default-font-size)))))
(my-default-font-size-set! 180)

(setq whitespace-style '(face trailing tab-mark))

(setq-default truncate-lines 1)

(defun my-prog-mode-hook ()
  (whitespace-mode 1)
  (line-number-mode t)
  (column-number-mode t)
  (setq buffer-face-mode-remapping
        (face-remap-add-relative 'default '(:family "Fira Code")))

  (set-input-method "TeX"))

(add-hook 'prog-mode-hook 'my-prog-mode-hook)

(defconst initial-scroll-preserve-screen-position scroll-preserve-screen-position)
(defconst initial-scroll-conservatively scroll-conservatively)
(defconst initial-maximum-scroll-margin maximum-scroll-margin)
(defconst initial-scroll-margin scroll-margin)

(define-minor-mode my-centered-cursor-mode
  "Major mode for editing Work Time pseudocode"
  :lighter " Centered"
  :after-hook
  (if my-centered-cursor-mode
      (setq-local scroll-preserve-screen-position t
                  scroll-conservatively 1
                  maximum-scroll-margin 0.5
                  scroll-margin 99999)
    (setq-local scroll-preserve-screen-position initial-scroll-preserve-screen-position
                scroll-conservatively initial-scroll-conservatively
                maximum-scroll-margin initial-maximum-scroll-margin
                scroll-margin initial-scroll-margin)))

;;;;;;;;;;;;;;;
;; LOOK/TABS ;;
;;;;;;;;;;;;;;;

;; Make the backspace properly erase the tab instead of
;; removing 1 space at a time.
(setq backward-delete-char-untabify-method 'hungry)

;; tab width
(defconst my-default-tab-width 4)
(setq-default tab-width my-default-tab-width)
(setq custom--width 4)
(setq indent-tabs-mode t)
(setq-default indent-tabs-mode t)
(setq my-global-tab-mode t)

(defun disable-tabs ()
  (interactive)
  (setq-local indent-tabs-mode nil))
(defun enable-tabs  ()
  (interactive)
  (local-set-key (kbd "TAB") 'self-insert-command)
  (setq-local indent-tabs-mode t))

(defun global-disable-tabs ()
  (interactive)
  (setq my-global-tab-mode nil)
  (tabs-reset-defaults-local))
(defun global-enable-tabs ()
  (interactive)
  (setq my-global-tab-mode t)
  (tabs-reset-defaults-local))

(defun tabs-reset-defaults-local  ()
  (setq-local tab-width my-default-tab-width)
  (if (or (not my-global-tab-mode)
          (memq major-mode
                '(lisp-mode
                  emacs-lisp-mode
                  racket-mode
                  scheme-mode
                  guile-mode
                  agda-mode
                  agda2-mode)))
      (disable-tabs)
    (enable-tabs)))

(add-hook 'prog-mode-hook 'tabs-reset-defaults-local)

;; (defun reset-local-tab-with ()
;;   (setq-local tab-width my-default-tab-width))
;; (add-hook 'haskell-mode-hook 'reset-local-tab-width)


;;;;;;;;;;;;;;;;;;;;;;
;; BUILTIN PACKAGES ;;
;;;;;;;;;;;;;;;;;;;;;;

;; always use minimal dired
(add-hook 'dired-mode-hook 'dired-hide-details-mode)

(set-in-alist! auto-mode-alist "\\.jsx\\'" 'javascript-mode)
(set-in-alist! auto-mode-alist "\\.ts\\'" 'javascript-mode)
(set-in-alist! auto-mode-alist "\\.tsx\\'" 'javascript-mode)

;; (mode (latex

;; (disable latex autoindent
(defun JH/remove-electric-indent-mode ()
  (electric-indent-local-mode -1))

(add-hook 'LaTeX-mode-hook 'JH/remove-electric-indent-mode)
(add-hook 'tex-mode-hook 'JH/remove-electric-indent-mode)
;; disable latex autoindent)

;; latex) mode)

;; ido mode
;; alternatives are `iswitchb-mode' (obsolete but faster) and `icomplete-mode'
;; remaps `switch-to-buffer' only
;; use `ido-find-file' command for ido files
(ido-mode 'buffer)

(setq-default grep-command "grep --color -HRIn")
(setq grep-command "grep --color -HRIn")

(defun my-c-mode-hook ()
  (c-set-style "user"))

(add-hook 'c-mode-hook 'my-c-mode-hook)

(setq-default c-syntactic-indentation nil)

(defun my-haskell-mode-hook ()
  (haskell-tab-indent-mode))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)

(global-set-key (kbd "C-x g") 'magit-status)

(defun my-text-mode-hook ()
  (visual-line-mode 1)
  (my-centered-cursor-mode 1))
(add-hook 'text-mode-hook 'my-text-mode-hook)

;;;;;;;;;;;;
;; CUSTOM ;;
;;;;;;;;;;;;

(defun my-temp-project ()
  (interactive)
  (let* ((name (make-temp-name "my-emacs-"))
         (dir (temporary-file-directory))
         (s (my-path-join dir name)))
    (mkdir s)
    (find-file (my-path-join s "main.scm"))))

CLICK TO VIEW

x

init.el(raw, dl)

  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
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(ansi-color-faces-vector
   [default default default italic underline success warning error])
 '(blink-cursor-mode nil)
 '(custom-enabled-themes '(abyss))
 '(dired-hide-details-hide-information-lines t)
 '(dired-hide-details-hide-symlink-targets nil)
 '(grep-use-null-device nil)
 '(inhibit-startup-screen t)
 '(menu-bar-mode nil)
 '(message-default-mail-headers "Cc: 
Bcc: 
")
 '(package-archives
   '(("gnu" . "http://elpa.gnu.org/packages/")
     ("melpa" . "https://melpa.org/packages/")
     ("marmalade" . "http://marmalade-repo.org/packages/")))
 '(scroll-bar-mode nil)
 '(send-mail-function 'smtpmail-send-it)
 '(tool-bar-mode nil))

(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )

;;;;;;;;;;;
;; BASIC ;;
;;;;;;;;;;;

(load "~/.emacs.d/init-basic")

;;;;;;;;;;;;;;
;; PACKAGES ;;
;;;;;;;;;;;;;;

;; Added by Package.el.  This must come before configurations of
;; installed packages.  Don't delete this line.  If you don't want it,
;; just comment it out by adding a semicolon to the start of the line.
;; You may delete these explanatory comments.
(package-initialize)

(require 'bind-key)

(eval-when-compile
  ;; Following line is not needed if use-package.el is in ~/.emacs.d
  (add-to-list 'load-path (emacs-root-join "custom" "use-package"))
  (require 'use-package))

(require 'subr-x) ;; for "string-trim" and other string operations
(require 'face-remap) ;; for custom face mode

;; reopen last session buffers
;; (desktop-save-mode 1)

;; ;; save buffer on emacs lost focus (not buffer lost focus)
;; (defun save-buffer-on-lost ()
;;         (interactive)
;;         (if (or (null buffer-file-name) (not (file-writable-p buffer-file-name)))
;;             () ;; not writable
;;             (save-buffer)))
;; (add-hook 'focus-out-hook 'save-buffer-on-lost)

;; current emacs session env variable

(defconst MY-EMACS-SERVER-NAME
  (or (getenv "EMACS_SERVER_NAME")
      (concat "emacs-server-" (number-to-string (random)))))

(setenv "EMACS_SERVER_NAME" MY-EMACS-SERVER-NAME)

(setq server-name MY-EMACS-SERVER-NAME)

(defvar MY-EMACS-SERVER-STARTED nil)

(unless MY-EMACS-SERVER-STARTED
  (setq MY-EMACS-SERVER-STARTED t)
  (server-start))

;;;;;;;;;;
;; MAIL ;;
;;;;;;;;;;

; Outgoing email (msmtp + msmtpq)
(setq send-mail-function 'sendmail-send-it
      sendmail-program "msmtp"
      mail-specify-envelope-from t
      message-sendmail-envelope-from 'header
      mail-envelope-from 'header)

(defun my-message-setup-hook ()
  (gnus-alias-determine-identity)
  ;; (define-key message-mode-map (kbd "C-c f")
  ;;   (lambda ()
  ;;     (interactive)
  ;;     (message-remove-header "Fcc")
  ;;     (message-remove-header "Organization")
  ;;     ;; (gnus-alias-select-identity)
  ;;     (notmuch-fcc-header-setup)))
  (flyspell-mode))

(add-hook 'message-setup-hook 'my-message-setup-hook)

(setq gnus-button-url 'browse-url-generic
      browse-url-generic-program "my-browser-open-link"
      browse-url-browser-function gnus-button-url)

;;;;;;;;;;
;; TERM ;;
;;;;;;;;;;

(require 'term)

;; add my window map to term raw mode as well
(define-key term-raw-map (kbd "M-o") my-window-map)
(define-key term-raw-map (kbd "C-c C-y") 'term-paste)

(defconst my-term-prefix "my-term-mt")

(defun my-term-base (bufname &rest arguments)
  (set-buffer
   (apply #'make-term
          (append
           (list
            bufname
            (car arguments)
            nil)
           (cdr arguments))))
  (term-mode)
  (term-char-mode)
  (switch-to-buffer (concat "*" bufname "*")))

(defun my-term-sentinel-advice
    (orig-fun &rest args)
  "Kill buffer on terminal close"

  (apply orig-fun args)
  (let* ((proc (car args))
         (buffer (process-buffer proc)))
    (unless (eq 0 my-term-self-id)
      (my-term-put-unique my-term-self-id)
      (kill-buffer buffer))))
(advice-add 'term-sentinel :around
            #'my-term-sentinel-advice)

(defvar my-term-shell-program
  (or (getenv "SHELL")
      (program-resolve-path "fish")
      (program-resolve-path "bash")))

(defun my-term-taged (name)
  "Start a terminal-emulator in a new buffer named `name'
The buffer is in Term mode;"
  (interactive (list (read-from-minibuffer "tag: ")))
  (my-term-base name my-term-shell-program))

(defvar my-term-unique-free (list 1 2 3 4 5 6 7 8 9))
(defvar my-term-unique-max (car (last my-term-unique-free)))
(defvar my-term-self-id 0)

(defun my-term-get-unique ()
  (when (null my-term-unique-free)
    (setq my-term-unique-max (1+ my-term-unique-max))
    (push my-term-unique-max my-term-unique-free))
  (pop my-term-unique-free))

(defun my-term-put-unique (i)
  "Say that index `i' is free for use
This is optimized for `get-` not `put-`
because noone cares how long does the terminal take to close
"
  (if (null my-term-unique-free)
      (push i my-term-unique-free)
    (let ((lst my-term-unique-free)
          (going t))
      (while going
        (let ((cur (car lst)))
          (if (<= i cur)
              (progn
                (setcar lst i)
                (setcdr lst (cons cur (cdr lst)))
                (setq going nil))
            (if (null (cdr lst))
                (progn
                  (setcdr lst (list i))
                  (setq going nil))
              (setq lst (cdr lst)))))))))

(defun my-term-unsafe (self-id)
  "Unsafely start or open a term indexed by self-id"
  (let* ((name (number-to-string self-id))
         (bufname (concat my-term-prefix name)))
    (my-term-taged bufname)
    (setq-local my-term-self-id self-id)))

(defun my-term-indexed (self-id)
  "Start or open a term indexed by self-id"
  (delete self-id my-term-unique-free)
  (my-term-unsafe self-id))

(defun my-term ()
  "Start a new term indexed by unique index"
  (interactive)
  (my-term-unsafe (my-term-get-unique)))

(defvar my-term-exe-unique-counter 0)

(defun my-term-exe (cmd)
  "Start a terminal-emulator in a new buffer named `program'
The buffer is in Term mode;"
  (interactive (list (read-from-minibuffer "cmd: ")))
  (setq my-term-exe-unique-counter
        (+ 1 my-term-exe-unique-counter))
  (my-term-base
   (format "exe-%d" my-term-exe-unique-counter)
   "/bin/sh" "-c" cmd))

;;;;;;;;;;;;;;;;;;;;;
;; CYRILLIC LAYOUT ;;
;;;;;;;;;;;;;;;;;;;;;

(defun support-cyrillic-layout ()
  "Make emacs output english characters, regardless whether
the OS keyboard is english or russian"

;;   ;; Uncomment below if want to disable all cyrillic and use latin instead
;;   (defun literal-insert ()
;;     (interactive)
;;     (insert-char last-input-event 1))

;;   (define-minor-mode literal-insert-mode
;;     "Make emacs output characters corresponging to the OS keyboard,
;; ignoring the key-translation-map"
;;     :keymap (let ((new-map (make-sparse-keymap))
;;                   (english-chars "qwertyuiop[]asdfghjkl;'zxcvbnm,.QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>#"))
;;               (mapc (lambda (char)
;;                       (define-key new-map (string char)
;;                         'literal-insert))
;;                     english-chars)
;;               new-map))

;;   (defun run-literal-mode ()
;;     (literal-insert-mode 1))

;;   (add-hook 'text-mode-hook 'run-literal-mode)

  (defun translate-keystrokes-ru->en ()
    "Make emacs output english characters, regardless whether
the OS keyboard is english or russian"
    (let ((make-key-stroke (lambda (prefix char)
                             (eval `(kbd ,(if (and (string-match "^C-" prefix)
                                                   (string-match "[A-Z]" (string char)))
                                              (concat "S-" prefix (string (downcase char)))
                                            (concat prefix (string char)))))))
          (case-fold-search nil)
          (keys-pairs (zip-with 'cons
                                "йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖ\ЭЯЧСМИТЬБЮ№"
                                "qwertyuiop[]asdfghjkl;'zxcvbnm,.QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>#"))
          ;; (prefixes '("" "s-" "M-" "M-s-"
          ;; "C-" "C-s-" "C-M-" "C-M-s-")))
          (prefixes '( "s-" "M-" "M-s-"
                       "C-" "C-s-" "C-M-" "C-M-s-")))
      (mapc (lambda (prefix)
              (mapc (lambda (pair)
                      (define-key key-translation-map
                        (funcall make-key-stroke prefix (car pair))
                        (funcall make-key-stroke prefix (cdr pair))))
                    keys-pairs))
            prefixes)))

  (translate-keystrokes-ru->en))

(support-cyrillic-layout)

;;;;;;;;;;;;;;;;;;;;;;;
;; LOOK/TRANSPARENCY ;;
;;;;;;;;;;;;;;;;;;;;;;;

(defconst MY-DEFAULT-TRANSPARENCY 100)

(set-in-alist! default-frame-alist 'alpha MY-DEFAULT-TRANSPARENCY)

(defun my-set-transparency (value)
  "Sets the transparency of the frame window. 0=transparent/100=opaque"
  (interactive "nTransparency Value 0 - 100 opaque: ")
  (set-frame-parameter (selected-frame) 'alpha value))

(defun my-toggle-transparency ()
  (interactive)
  (let ((alpha (frame-parameter nil 'alpha)))
    (if (eql (cond ((numberp alpha) alpha)
                   ((numberp (cdr alpha)) (cdr alpha))
                   ;; Also handle undocumented (<active> <inactive>) form.
                   ((numberp (cadr alpha)) (cadr alpha)))
             100)
        (my-set-transparency MY-DEFAULT-TRANSPARENCY)
      (my-set-transparency 100))))

;;;;;;;;;;;;;;
;; PACKAGES ;;
;;;;;;;;;;;;;;

(use-package buffer-flip
  :ensure nil)

(defun my-elfeed-update ()
  (interactive)
  (elfeed-update)
  (elfeed-search--update-list))

(use-package elfeed
  :bind (:map elfeed-search-mode-map
              ("g" . 'my-elfeed-update))

  :config
  ;; Save elfeed db automatically, because if Emacs crashes or is killed (which happens to me
  ;; occasionally, especially since I develop packages in a single instance), we'd lose the db
  ;; updates not saved.
  (unless (cl-loop for timer in timer-idle-list
                   thereis (equal (aref timer 5) #'elfeed-db-save))
    (run-with-idle-timer 10000 'repeat #'elfeed-db-save)))

;; don't skip same buffer
(defun my-buffer-flip-skip-buffer-advice
    (orig-fun buf)
  (or (= ? (elt (buffer-name buf) 0)) ; internal?
      (eq (get-buffer-window buf)
          (get-buffer-window (current-buffer)))))
(advice-add 'buffer-flip-skip-buffer
            :around #'my-buffer-flip-skip-buffer-advice)

(defun agda-mode-exists? ()
  (= 0 (car (list (call-process "which" nil nil nil "agda-mode")))))

(if (agda-mode-exists?)
    (condition-case nil
        (load-file
         (let ((coding-system-for-read 'utf-8))
           (shell-command-to-string "agda-mode locate")))
      (error (message "could not load agda-mode")))
    (print "agda-mode is not installed"))

(with-eval-after-load 'company
  (let ((m company-active-map))
    (define-key m [return] nil)
    (define-key m (kbd "RET") nil)
    (define-key m [tab] 'company-complete-selection)
    (define-key m (kbd "TAB") 'company-complete-selection)
    (define-key m (kbd "C-n") 'company-select-next)
    (define-key m (kbd "C-p") 'company-select-previous)

    ;; ;; optionaly don't use same keys as for movement
    ;; (define-key m (kbd "C-n") nil)
    ;; (define-key m (kbd "C-p") nil) ; optionaly don't use same keys as for movement
    ;; (define-key m [backtab] 'company-select-next)
    ;; (define-key m (kbd "S-TAB") 'company-select-next)
    )
  )

(use-package company
             :ensure nil
             :config
             (setq company-minimum-prefix-length 1)
             (setq company-idle-delay 0))

(add-hook 'after-init-hook 'global-company-mode)

(use-package company-tabnine
  :ensure nil)

(defvar company-tabnine-restart-enabled nil)

(defun company-tabnine-toggle ()
  (interactive)
  (setq company-tabnine-restart-enabled (not company-tabnine-restart-enabled))
  (company-tabnine-kill-process)
  (company-tabnine-restart-server)
  (if company-tabnine-restart-enabled
      (progn
        (add-to-list 'company-backends #'company-tabnine)
        (message "tabnine was turned on"))
    (progn
      (setq company-backends
            (delete #'company-tabnine company-backends))
      (message "tabnine was turned off"))))

(defun company-tabnine-start-process-wrapper (orig-fun &rest args)
  (if company-tabnine-restart-enabled
      (apply orig-fun args)))

(advice-add 'company-tabnine-start-process :around #'company-tabnine-start-process-wrapper)

(haskell-tab-indent-mode 1)

(use-package projectile
  :ensure nil
  :init (projectile-mode))

(use-package markdown-mode)
 

x

Notes

There are two files - the basic and the “bloated” one.
Place both in ~/.emacs.d/

When starting emacs normally, it will use the bloated file.
If you want to just quickly open emacs and you don’t want to use emacsclient, then do “emacs –Q –load ~/.emacs.d/init-basic.el”