1 ;; init.el -- Emacs configuration file -*- lexical-binding: t -*-
3 ;; Copyright 2004-2020 by Michal Nazarewicz (mina86@mina86.com)
4 ;; Some parts of the code may be © by their respective authors.
8 ;; Mitigate Bug#28350 (security) in Emacs 25.2 and earlier.
9 (with-eval-after-load "enriched"
10 (defun enriched-decode-display-prop (start end
&optional _param
)
13 ;; Emacs 26 and older does not load early-init.el so make sure it’s loaded.
14 (let ((path (expand-file-name "early-init.el" user-emacs-directory
)))
15 (when (file-exists-p path
)
16 (require 'early-init path
)))
18 ;; Configure and activate packages
21 ;; Emacs 26.1 does this automatically but older don’t.
22 (unless package--initialized
25 (setq package-archives
'(("gnu" .
"https://elpa.gnu.org/packages/")
26 ("nongnu" .
"https://elpa.nongnu.org/nongnu/")
27 ("melpa" .
"https://melpa.org/packages/"))
28 package-menu-hide-low-priority t
29 package-archive-priorities
'(("gnu" .
100) ("nongnu" .
50)))
31 (unless package-archive-contents
32 (package-refresh-contents))
33 ;; This is similar to ‘package-install-selected-packages’ except it doesn’t ask
34 ;; any questions and doesn’t stop on errors (merely reports them).
35 (dolist (pkg package-selected-packages
)
36 (unless (package-installed-p pkg
)
38 (package-install pkg t
)
39 (error (message (error-message-string err
))))))
41 ;; Make sure ‘package-selected-packages’ list is sorted so that it’s easier to
42 ;; see a difference when the value is saved in customise.el.
43 (advice-add #'package--save-selected-packages
:filter-args
45 (list (sort (if args
(car args
) package-selected-packages
)
49 (when (fboundp 'auto-package-update-maybe
)
50 (setq-default auto-package-update-delete-old-versions t
)
51 (run-at-time "03:00" 86400
52 #'run-with-idle-timer
1 nil
53 #'auto-package-update-maybe
))
55 (when (fboundp 'auto-compile-on-save-mode
)
56 (auto-compile-on-save-mode))
57 (setq load-prefer-newer t
)
61 (defun set-key--current-local-map ()
62 "Return current local map creating one if not set yet."
63 (or (current-local-map)
64 (let ((map (make-sparse-keymap)))
68 (defmacro set-key
(keymap key
&rest def
)
69 "(set-key [KEYMAP] KEY . DEF)
71 In KEYMAP, define key sequence KEY as DEF.
73 KEYMAP can be :global (to mean global keymap, the default), :local (to mean
74 the local keymap) or an unquoted symbol (to mean a keymap in given variable).
76 KEY is anything ‘define-key’ accepts as a key except that if KEYMAP was not
77 given, KEY cannot be an unquoted symbol, i.e.:
79 (set-key key self-insert-command) ; will *not* work
80 (set-key :global key self-insert-command)) ; will work
82 If DEF is a single unquoted symbol it will be quoted, otherwise if it is
83 a single non-cons value it will not be quoted, otherwise it will be processed
84 as a lambda (see below). Thus the following do what one might expect:
85 (set-key \"a\" self-insert-command)
86 ;; same as (global-set-key \"a\" #\\='self-insert-command)
87 (set-key \"\\C-h\" [(backspace)])
88 ;; same as (global-set-key \"\\C-h\" [(backspace)])
89 (set-key \"\\C-d\" ())
90 ;; same as (global-set-key \"\\C-h\" ())
91 However, the following will not work:
92 (let ((callback \\='self-insert-command))
93 (set-key \"a\" callback))
94 ;; same as (global-set-key \"a\" #\\='callback)
96 If DEF is a cons value, it’s format is:
97 ([:args ARGS INTERACTIVE] . BODY)
98 and results in the following lambda:
99 (lambda ARGS (interactive INTERACTIVE) . BODY)
100 or if :args is not given (at which point DEF == BODY):
101 (lambda () (interactive) . BODY)
103 (set-key \"\\C-B\" (goto-char (- (point) 2)))
104 ;; same as (global-set-key \"\\C-B\"
105 ;; (lambda () (interactive) (goto-char (- (point) 2))))
106 (set-key \"\\C-B\" :args (n) \"P\" (goto-char (- (point) (* 2 n))))
107 ;; same as (global-set-key \"\\C-B\"
108 ;; (lambda (n) (interactive \"P\")
109 ;; (goto-char (- (point) (* 2 n)))))
111 This macro is not designed to be a complete replacement for ‘define-key’,
112 ‘global-set-key’ or ‘local-set-key’, since it is not capable of dealing with
113 some forms of DEFs that those functions accept, but instead it is meant as
114 a helper to use in user configuration file to save on typing especially when
116 (setq keymap
(cond ((eq :local keymap
) '(set-key--current-local-map))
117 ((eq :global keymap
) '(current-global-map))
118 ((symbolp keymap
) keymap
)
120 (setq def
(cons key def
) key keymap
) ; shift args
121 '(current-global-map))))
123 (error "DEF argument missing"))
125 'define-key keymap key
126 (cond ((or (cdr def
) (consp (car def
)))
127 (let ((args (if (eq :args
(car def
)) (cadr def
)))
128 (interactive (if (eq :args
(car def
)) (list (car (cddr def
)))))
129 (body (if (eq :args
(car def
)) (cdr (cddr def
)) def
)))
130 `(lambda ,args
(interactive .
,interactive
) ,@body
)))
131 ((symbolp (car def
)) `#',(car def
))
134 (defmacro add-lambda-hook
(hook &rest body
)
135 "Add a lambda to a hook.
136 HOOK is either a hook (just as with `add-hook' function) or a list of
137 hooks in which case lambda will be added to all the hooks in HOOK
138 list. BODY is body of the lambda to be added."
140 (if (and (listp hook
) (eq (car hook
) 'quote
) (listp (cadr hook
)))
141 (let ((func (make-symbol "func")))
142 `(let ((,func
(lambda () ,@body
)))
143 ,@(mapcar (lambda (h) `(add-hook (quote ,h
) ,func
))
145 `(add-hook ,hook
(lambda () ,@body
))))
152 "Number of times command was executed.
153 Contains random data before `seq-times' macro is called.")
155 (defmacro seq-times
(&optional max
&rest body
)
156 "Returns number of times ‘this-command’ was executed.
157 Updates `seq-times' variable accordingly to keep track. If MAX
158 is specified the counter will wrap around at the value of MAX
159 never reaching it. If body is given it will be evaluated if the
160 command is run for the first time in a sequence."
163 (if (eq last-command this-command
)
164 ,(if (or (null max
) (eq max
'nil
))
166 `(%
(1+ seq-times
) ,max
))
170 (defmacro seq-times-nth
(body &rest list
)
171 "Return element of the LIST depending on number of ‘times-command’ was called.
172 BODY has the same meaning as in `seq-times' function. LIST is
173 a list of values from which to choose value to return. Depending
174 how many times command was called, element with that index will
175 be returned. The counter will wrap around."
177 `(nth (seq-times ,(length list
) ,body
) ',list
))
179 (defmacro seq-times-do
(body &rest commands
)
180 "Evaluates command depending on number of times command was called.
181 BODY has the same meaning as in `seq-times' function. COMMANDS
182 is a list of sexps to evaluate. Depending how many times command
183 was called, sexp with that index will be evaluated. The counter
186 `(eval (nth (seq-times ,(length commands
) ,body
) ',commands
)))
191 (defvar my-home-end--point
0)
193 "Go to beginning of line, indent or buffer.
194 When called once move point to beginning of line, twice - beginning of
195 the buffer, thrice - back to where it was at the beginning."
197 (seq-times-do (setq my-home-end--point
(point))
199 (goto-char (point-min))
200 (goto-char my-home-end--point
)))
202 (global-set-key [remap move-beginning-of-line
] #'my-home
)
206 "Go to end of line or buffer.
207 When called once move point to end of line, twice - end of buffer,
208 three times - back to where it was at the beginning."
210 (seq-times-do (setq my-home-end--point
(point))
212 (goto-char (point-max))
213 (goto-char my-home-end--point
)))
215 (global-set-key [remap move-end-of-line
] #'my-end
)
218 (setq-default pulse-delay
0.05
220 (advice-add #'recenter-top-bottom
:after
221 (lambda (&rest _args
)
222 (pulse-momentary-highlight-one-line (point))))
224 ;; Save with no blanks
226 ;; Save with no trailing whitespaces
227 (defun save-no-blanks (&optional no-strip
)
228 "Save file stripping all trailing white space and empty lines from EOF.
229 When called with prefix argument (or NO-STRIP being non-nill) does not
230 perform stripping and behaves as plain `save-buffer'."
234 (delete-trailing-whitespace)))
237 (defun save-no-blanks-done (&optional no-strip
)
238 "Save file and mark it done if there are any server clients."
240 (save-no-blanks no-strip
)
241 (and (boundp 'server-buffer-clients
)
242 (fboundp 'server-buffer-done
)
243 server-buffer-clients
244 (server-buffer-done (current-buffer) t
))
245 (kill-buffer (current-buffer)))
247 (global-set-key [remap save-buffer
] #'save-no-blanks
)
248 (set-key "\C-c\C-c" save-no-blanks-done
)
252 (when (fboundp 'save-buffers-kill-terminal
)
253 (set-key ctl-x-map
"\C-c" save-buffers-kill-emacs
)
254 (set-key ctl-x-map
"c" save-buffers-kill-terminal
))
256 (set-key "\C-h" [(backspace)])
257 (set-key [(backspace)] delete-backward-char
)
258 (set-key [(delete)] delete-forward-char
)
259 (set-key "\C-d" [(delete)])
261 (set-key ctl-x-map
"1" delete-other-windows-vertically
)
262 (set-key ctl-x-map
"3"
264 ;; Balance horizontally. This is copied from balance-windows
265 (let* ((window (frame-root-window))
266 (frame (window-frame window
)))
267 (window--resize-reset (window-frame window
) t
)
268 (balance-windows-1 window t
)
269 (when (window--resize-apply-p frame t
)
270 (window-resize-apply frame t
)
271 (window--pixel-to-total frame t
))))
274 (defun mpn-windmove (dir delete
)
276 (windmove-delete-in-direction dir
)
277 (windmove-do-window-select dir
)
278 (pulse-momentary-highlight-one-line)))
279 (set-key "\M-F" :args
(delete) "P" (mpn-windmove 'right delete
))
280 (set-key "\M-B" :args
(delete) "P" (mpn-windmove 'left delete
))
281 (set-key "\M-P" :args
(delete) "P" (mpn-windmove 'up delete
))
282 (set-key "\M-N" :args
(delete) "P" (mpn-windmove 'down delete
))
284 (set-key ctl-x-map
"k" kill-this-buffer
) ; don't ask which buffer to kill
285 (set-key "\C-cr" revert-buffer
) ; Reload buffer
286 (set-key ctl-x-map
"\C-b" (switch-to-buffer (other-buffer))) ; C-x C-b switch
288 (when (fboundp 'shift-number-up
)
289 (with-no-warnings (set-key "\M-+" shift-number-up
)
290 (set-key "\M--" shift-number-down
)))
295 (defun my-jump () "Jump to the thing at point." (interactive)
296 (let ((thing (ffap-guesser))) (if thing
(ffap thing
)) t
))
298 (set-key [(control return
)] my-jump
)
299 (set-key [(control shift mouse-1
)] ffap-at-mouse
)
300 (set-key ctl-x-map
"\C-f" ffap
)
302 ;; Make q close current buffer if it's read-only
303 (set-key "q" :args
(n) "p"
304 (if (and buffer-read-only
(not (= n
0)))
305 (kill-buffer (current-buffer))
306 (self-insert-command n
)))
310 (set-key minibuffer-local-map
"\C-c" ; C-c clears minibuffer
311 delete-minibuffer-contents
)
312 (set-key minibuffer-local-map
"\C-p" previous-history-element
)
313 (set-key minibuffer-local-map
"\C-n" next-history-element
)
315 ;; Killing, yanking, X selection, etc
317 ;; Regions, selections and marks
318 (setq mouse-yank-at-point t
;mouse yank at point not at cursor (X-win)
319 kill-read-only-ok t
;be silent when killing text from RO buffer
320 set-mark-command-repeat-pop t
321 kill-do-not-save-duplicates t
)
322 (delete-selection-mode 1) ;deleting region by typing or del (like Win)
324 (set-key esc-map
"Y" (yank-pop -
1)) ;move back in kill ring
326 (set-key [(shift insert
)]
327 (let ((mouse-yank-at-point nil
))
328 (mouse-yank-primary nil
)))
330 ;; Use browse-kill-ring
331 (when (fboundp 'browse-kill-ring-default-keybindings
)
332 (setq-default browse-kill-ring-display-duplicates nil
333 browse-kill-ring-highlight-current-entry t
334 browse-kill-ring-highlight-inserted-item t
335 browse-kill-ring-separator
"\x0C")
336 (when (fboundp 'form-feed-mode
)
337 (add-hook 'browse-kill-ring-hook
#'form-feed-mode
))
338 (browse-kill-ring-default-keybindings))
342 (set-key "\M- " (cycle-spacing -
1))
344 ;; Tab - indent or complete
346 (eval-when-compile (require 'hippie-exp
))
347 (setq hippie-expand-try-functions-list
349 ; try-expand-all-abbrevs
353 try-expand-dabbrev-all-buffers
354 try-expand-dabbrev-from-kill
355 try-complete-file-name-partially
356 try-complete-file-name
357 try-complete-lisp-symbol-partially
358 try-complete-lisp-symbol
)
359 hippie-expand-verbose nil
)
361 ;; Indent or complete
362 (defvar indent-or-complete-complete-function
'hippie-expand
363 "Function to complete the word when using `indent-or-complete'.
364 It is called with one argument - nil.")
366 (defvar indent-or-complete--last-was-complete nil
)
368 (defun indent-or-complete ()
369 "Indent or complete depending on context.
370 In minibuffer run `minibuffer-complete', if `use-region-p' run
371 `indent-region', if point is at end of a word run
372 `inent-or-complete-complete-function', else run
373 `indent-for-tab-command'."
375 (cond ((and (fboundp 'minibufferp
) (minibufferp)) (minibuffer-complete))
376 ((use-region-p) (indent-region (region-beginning) (region-end)))
377 ((setq indent-or-complete--last-was-complete
378 (or (and (char-before)
379 (= ?w
(char-syntax (char-before)))
380 (or (not (char-after))
381 (/= ?w
(char-syntax (char-after)))))
382 (and (eq last-command this-command
)
383 indent-or-complete--last-was-complete
)))
384 (funcall indent-or-complete-complete-function nil
))
385 ((indent-for-tab-command))))
387 ;; (set-key "\t" indent-or-complete)
388 ;; (set-key [(tab)] indent-or-complete)
390 (add-lambda-hook 'find-file-hook
391 (unless (eq major-mode
'org-mode
)
392 (set-key :local
[(tab)] indent-or-complete
)))
399 "Show context dependent help.
400 If function given tries to `describe-function' otherwise uses
401 `manual-entry' to display manpage of a `current-word'."
403 (or (let ((var (variable-at-point)))
404 (when (symbolp var
) (describe-variable var
) t
))
405 (let ((fn (function-called-at-point)))
406 (when fn
(describe-function fn
) t
))
407 (man (current-word))))
409 (global-set-key [(f1)] help-map
)
410 (set-key help-map
[(f1)] my-help
)
413 ;; F2 - find configuration files
415 (defvar mpn-find-file-map
416 (let ((map (make-sparse-keymap))
419 ((not user-init-file
)
421 ;; Compiled file. Open the source.
422 ((string-match "\\.elc$" user-init-file
)
423 (substring user-init-file
0 -
1))
424 ;; Native compiled file. Finding the source isn’t as
425 ;; simple as changing extension from .eln to .el. Just
427 ((string-match "\\.eln$" user-init-file
)
429 ;; Open whatever init file we’re loading.
431 ("e" .
"early-init.el")
433 ("c" .
"customize.el")
436 ("s" .
"~/.sawfish/rc"))))
438 (when-let ((path (cdar lst
)))
439 (unless (eq ?
/ (aref path
0))
440 (setq path
(expand-file-name path user-emacs-directory
)))
441 (when (file-exists-p path
)
442 (define-key map
(caar lst
)
443 (lambda () (interactive) (find-file path
)))))
444 (setq lst
(cdr lst
)))
446 "Keymap for characters following the F2 key.")
448 (global-set-key [(f2)] mpn-find-file-map
)
450 ;; F3/F4 - keyboard macros
452 (eval-when-compile (require 'kmacro
))
453 (defun kmacro-end-or-call-possibly-on-region-lines (arg &optional no-repeat
)
454 "End keyboard macro or call it.
455 End defining a keyboard macro if one is being defined and if not call
456 last keyboard macro ARG times or on region if `use-region-p'.
457 Optional argument NO-REPEAT is passed to `kmacro-call-macro' function."
461 (if kmacro-call-repeat-key
462 (kmacro-call-macro arg no-repeat t
)
463 (kmacro-end-macro arg
)))
464 ((and (eq this-command
'kmacro-view-macro
) ;; We are in repeat mode!
465 kmacro-view-last-item
)
466 (funcall (car kmacro-view-last-item
) arg
))
467 ((and arg
(listp arg
))
468 (with-no-warnings (kmacro-call-ring-2nd 1)))
470 (apply-macro-to-region-lines (region-beginning) (region-end)))
472 (kmacro-call-macro arg no-repeat
))))
474 (set-key [(f3)] kmacro-start-macro-or-insert-counter
)
475 (set-key [(f4)] kmacro-end-or-call-possibly-on-region-lines
)
479 (when (file-exists-p (concat user-emacs-directory
"mail.el"))
481 (load (concat user-emacs-directory
"mail.el"))
483 (set-key [(f5)] notmuch
)
490 (defun remember-notes-initial-buffer ()
491 (if-let ((buf (find-buffer-visiting remember-data-file
)))
492 ;; If notes are already open, simply return the buffer. No further
493 ;; processing necessary. This case is needed because with daemon mode,
494 ;; ‘initial-buffer-choice’ function can be called multiple times.
496 (if-let ((buf (get-buffer remember-notes-buffer-name
)))
501 (cl-letf (((symbol-function 'yes-or-no-p
) (lambda (&rest _
) t
)))
507 (setq remember-notes-buffer-name
"*scratch*"
508 initial-buffer-choice
#'remember-notes-initial-buffer
)
509 (set-key [(f6)] remember-notes
)
511 ;; F7 - spell checking
515 (setq-default ispell-program-name
"aspell")
516 (ispell-change-dictionary "british" t
)
518 (defvar mn-spell-dictionaries
'("polish" "british")
519 "List of dictionaries to cycle through with `mn-spell-switch-dictionary'.")
521 (defun mn-spell (&optional lang start end
)
522 "Spell check region, buffer or from point.
523 If LANG is not-nil sets Ispell dictionary to LANG, then checks
524 region from START to END for spelling errors. The default values
525 for START and END are `region-beginning' and `region-end' if
526 `use-region-p' or `point-min' and `point-max' otherwise.
528 If LANG is an empty string local dictionary is set to
529 nil (ie. the global dictionary is used).
531 If START >= END this function only sets the dictionary and
532 returns nil. Otherwise it returns whatever `ispell-region'
535 (list (completing-read
536 "Use new dictionary (RET for current, SPC to complete): "
537 (if (fboundp 'ispell-valid-dictionary-list
)
538 (mapcar 'list
(ispell-valid-dictionary-list)))
540 (if lang
(ispell-change-dictionary (if (string= lang
"") nil lang
)))
541 (let* ((rp (use-region-p))
542 (s (or start
(if rp
(region-beginning) (point-min))))
543 (e (or end
(if rp
(region-end) (point-max)))))
544 (if (< s e
) (ispell-region s e
))))
546 (defun mn-spell-switch-dictionary (&optional global
)
547 "Switche dictionary to the next dictionary from `mn-spell-dictionaries'.
548 If GLOBAL is non-nil, or with a prefix argument set global dictionary."
550 (ispell-change-dictionary
551 (let ((dic (or (and (not global
) ispell-local-dictionary
) ispell-dictionary
))
552 (list mn-spell-dictionaries
))
553 (while (and list
(not (string= (car list
) dic
))) (setq list
(cdr list
)))
554 (or (cadr list
) (car mn-spell-dictionaries
)))
557 (set-key [(f7)] (mn-spell))
558 (set-key [(control f7
)] (mn-spell nil
(point)))
559 (set-key [(meta f7
)] mn-spell-switch-dictionary
)
560 (set-key [(shift f7
)] ispell-word
)
562 (define-globalized-minor-mode global-flyspell-mode
563 flyspell-mode mn-turn-flyspell-on
566 (defun mn-turn-flyspell-on ()
567 "Turn `flyspell-mode' or `flyspell-prog-mode' depending on major mode."
568 (cond ((or (string-prefix-p " *" (buffer-name))
569 (string-prefix-p "*" (buffer-name))
571 (derived-mode-p 'notmuch-hello-mode
'notmuch-search-mode
572 'notmuch-show-mode
'package-menu-mode
574 ((derived-mode-p 'prog-mode
'diff-mode
) (flyspell-prog-mode))
575 (t (flyspell-mode t
))))
577 (global-flyspell-mode 1)
581 (defun mn-compile (&optional recompile
)
582 "Compile current file.
583 Executes `recompile' function if RECOMPILE is non-nill or
584 `compile' otherwise. If TOUCH is non-nil marks buffer as
585 modified beforehand."
588 (if (derived-mode-p 'emacs-lisp-mode
)
589 (byte-compile-file (buffer-file-name))
590 (if (and recompile
(fboundp 'recompile
))
592 (call-interactively 'compile
))))
594 (set-key [(f9)] mn-compile
)
595 (set-key [(control f9
)] (mn-compile t
))
596 (set-key [(shift f9
)] next-error
)
599 (setq compilation-scroll-output
'first-error
; scroll until first error
600 compilation-window-height
12 ; keep it readable
601 compilation-auto-jump-to-first-error t
)
603 (require 'ansi-color
)
604 (add-lambda-hook 'compilation-filter-hook
605 (ansi-color-apply-on-region compilation-filter-start
(point)))
607 ;; Search and jumping
609 (set-key isearch-mode-map
[(f1)] isearch-describe-mode
)
610 (set-key isearch-mode-map
"\C-t" isearch-toggle-regexp
)
611 (set-key isearch-mode-map
"\C-c" isearch-toggle-case-fold
)
612 (set-key isearch-mode-map
"\C-j" isearch-edit-string
)
613 (set-key isearch-mode-map
"\C-h" isearch-del-char
)
614 (set-key isearch-mode-map
[backspace] isearch-del-char)
616 (setq search-whitespace-regexp "[ \t\r]+")
618 (set-key "\M-s" avy-goto-char-timer)
621 avy-timeout-seconds 0.3
622 avy-keys (string-to-list "htnsueoagcrlp.,;mwvzkjq'difybx/-\\@#)(+}]{![*=&$"))
626 ;; Make C-w, M-w work on word if no selection
627 (set-key "\C-w" (call-interactively
628 (if (use-region-p) 'kill-region 'kill-word)))
631 (call-interactively 'kill-ring-save)
632 (kill-ring-save (point) (progn (forward-word 1) (point)))
633 (setq this-command 'kill-region)))
635 ;; Syntax highlighting
639 (global-font-lock-mode t)
640 (setq font-lock-global-modes '(not notmuch-search-mode notmuch-hello-mode))
642 ;; Let customize keep config there
643 (setq custom-file (concat user-emacs-directory "custom.el"))
644 (when (file-exists-p custom-file)
645 (load-file custom-file))
648 (show-paren-mode t) ;show matching parenthesis.
649 (setq show-paren-context-when-offscreen t)
651 (defface my-fixme-face
652 '((t :background "red" :foreground "white" :weight bold))
653 "Face use to show FIXME and XXX markers in the text."
656 (defface my-todo-face
657 '((t :foreground "red" :weight bold))
658 "Face used to show TODO markers in the text."
661 ;; Show TODO and FIXME
662 ;; http://www.emacswiki.org/cgi-bin/wiki/EightyColumnRule
663 (add-lambda-hook 'font-lock-mode-hook
664 (unless (eq 'diff-mode major-mode)
665 (font-lock-add-keywords nil
666 '(("\\<\\(TODO:?\\)\\>" 1 'my-todo-face t)
667 ("\\<\\(FIXME:?\\|XXX\\)\\>" 1 'my-fixme-face t)))))
669 ;; 'lines-tail would be great but it does not really work with tabs ≠ 8
671 (setq-default whitespace-style '(face
672 space-before-tab::tab
677 whitespace-big-indent-regexp "^\\(\t\\{4,\\}\\)")
678 (global-whitespace-mode)
681 (defface mode-line-de-em
682 '((t (:foreground "#696")))
683 "Face used for de-emphasised elements on mode-line."
684 :group 'mode-line-faces)
686 (defface mode-line-modified-buffer-id
687 '((t (:slant italic :inherit (mode-line-buffer-id))))
688 "Face used for buffer id part of the mode line when the buffer is modified."
689 :group 'mode-line-faces)
691 (setq-default line-number-mode t
695 '((:propertize (buffer-read-only "» " " ")
697 display (min-width (10.0)))
700 "%14b " 'face (if (buffer-modified-p)
701 'mode-line-modified-buffer-id
702 'mode-line-buffer-id))
703 (if (> (current-column) 80)
704 (propertize "%2c" 'face 'warning)
706 (propertize ":" 'face 'mode-line-de-em)
708 (:eval (let ((min (point-min)) (max (point-max)))
710 (= max (1+ (buffer-size)))
712 (propertize "/" 'face 'mode-line-de-em)
714 (goto-char (point-max))
715 (format-mode-line "%l"))))))
723 ;; Highlight groups of three digits
724 (when (fboundp 'global-num3-mode)
725 (global-num3-mode t))
727 (when (fboundp 'mc/mark-next-like-this)
729 (set-key "\M-." mc/mark-next-like-this)
730 (set-key "\M-," mc/unmark-next-like-this)))
734 (icomplete-mode 1) ;nicer completion in minibuffer
735 (setq icomplete-prospects-height 2) ; don't spam my minibuffer
736 (setq suggest-key-bindings 3) ;suggestions for shortcut keys for 3 seconds
737 (setq history-delete-duplicates t)
738 (setq inhibit-startup-screen t ;don't show splash screen
739 inhibit-startup-buffer-menu t) ;don't show buffer menu when oppening
740 ; many files (EMACS 21.4+)
741 (setq paragraph-start " *\\([*+-]\\|\\([0-9]+\\|[a-zA-Z]\\)[.)]\\|$\\)"
742 require-final-newline t) ;always end file with NL
743 (fset 'yes-or-no-p 'y-or-n-p) ;make yes/no be y/n
744 (setq use-short-answers t)
745 (setq-default indicate-empty-lines t) ;show empty lines at the end of file
746 (setq-default indicate-buffer-boundaries t) ;show buffer boundries on fringe
747 (setq x-alt-keysym 'meta) ;treat Alt as Meta even if real Meta found
748 (blink-cursor-mode -1) ;do not blink cursor
749 (setq blink-cursor-alist '((t . box) ;seriously, don't blink, for some reason
750 (box . box)) ;blink-cursor-mode dosn’t work for me.
752 (setq ring-bell-function (lambda ()
753 (invert-face 'mode-line)
754 (run-with-timer 0.05 nil 'invert-face 'mode-line)))
755 (setq line-move-visual nil) ;move by logical lines not screen lines
756 (setq byte-count-to-string-function
757 (lambda (size) (file-size-human-readable size 'si " ")))
758 (when (fboundp 'describe-char-eldoc)
759 (if (boundp 'eldoc-documentation-functions)
760 (add-hook 'eldoc-documentation-functions #'describe-char-eldoc -50)
761 (setq-default eldoc-documentation-function #'describe-char-eldoc)))
763 ; Don’t warn when undo is discarded in large buffers
764 (add-to-list 'warning-suppress-types '(undo discard-info))
767 (when (fboundp recentf-mode)
768 (recentf-mode -1)) ;no recent files
769 (setq backup-by-copying-when-linked t) ;preserve hard links
770 (auto-compression-mode 1) ;automatic compression
771 (setq make-backup-files nil) ;no backup
772 (global-auto-revert-mode 1) ;automaticly reload buffer when changed
773 (setq vc-handled-backends nil) ;I don't use vc-mode
774 (setq auto-save-no-message t)
777 (defconst set-tab--variables
778 '(c-basic-offset perl-indent-level cperl-indent-level js-indent-level
779 sh-basic-offset python-indent-offset css-indent-offset
780 typescript-indent-level rust-indent-offset)
781 "List of variables which specify indent level in various modes.")
784 "Adjust `tab-width' indent level in current buffer.
785 `tab-width' is set to absolute value of TAB.
787 If called interactively user will be prompted for desired width. With
788 prefix argument, `indent-tabs-mode' will also be set to t.
790 If TAB is negative, `indent-tabs-mode' will be set to nil and an
791 absolute value will be taken.
793 This function also tries to set indent-level for current buffer's
794 major mode. This is not very inteligent nor has complete list of
795 rules so it is likely not to work."
796 (interactive "nTab-width: ")
797 (let ((negative (< tab 0)))
798 (setq tab-width (abs tab))
801 (set (make-local-variable var) tab-width)))
804 (negative (setq indent-tabs-mode nil))
805 (prefix-arg (setq indent-tabs-mode t)))))
807 (setq indent-tabs-mode t
809 ;; Don’t set-default 'c-basic-offset. We want to take value from c-style and
810 ;; setting the default to something other than 'set-from-style prevents
811 ;; dir-local c-file-style variable to work.
812 (dolist (var (cdr set-tab--variables))
814 (eval-when-compile (require 'tabify))
815 (setq tabify-regexp "^\t* [ \t]+");tabify only at the beginning of line
818 (setq scroll-step 1 ;scroll one line
819 hscroll-step 1 ;scroll one column
820 next-line-add-newlines nil ;no new lines with down arrow key
821 scroll-error-top-bottom t
822 scroll-preserve-screen-position t)
824 (when (fboundp 'auto-dim-other-buffers-mode)
825 (auto-dim-other-buffers-mode 1))
831 (add-lambda-hook 'c-initialization-hook
834 '((c-basic-offset . 8) ; 8-char wide indention...
835 (tab-width . 8) ; ...which equals single tab...
836 (indent-tabs-mode . t) ; ...so use tabs
837 (c-comment-only-line-offset . 0) ; XXX no idea what it does
838 (c-label-minimum-indentation . 1) ; no min. indention for labels
840 (c-cleanup-list ; Clean ups
841 brace-else-brace ; "} else {" in one line
842 brace-elseif-brace ; "} else if (...) {" in one line
843 brace-catch-brace ; "} catch (...) {" in one line
844 defun-close-semi) ; "};" together
846 (c-offsets-alist ; Indention levels:
847 ;; Don't indent inside namespaces, extern, etc
853 ;; Preprocessor macros
854 (cpp-define-intro c-lineup-cpp-define +)
858 ;; Brace after newline newer indents
860 (brace-entry-open . 0)
861 (brace-list-open . 0)
863 (composition-open . 0)
865 (extern-lang-open . 0)
869 (statement-case-open . 0)
870 (substatement-open . 0)
872 ;; Obviously, do not indent closing brace
875 (brace-list-close . 0)
877 (composition-close . 0)
879 (extern-lang-close . 0)
882 (namespace-close . 0)
884 ;; Obviously, indent next line after opening brace and single statements
885 (defun-block-intro . +)
886 (statement-block-intro . +)
889 ;; Handle nicely multi line argument lists
890 (arglist-close c-lineup-arglist 0)
891 (arglist-cont c-lineup-gcc-asm-reg +)
892 (arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist +)
896 (brace-list-intro . +) ; Indent elements in brace-lists
897 (brace-list-entry . 0)
898 (c . c-lineup-C-comments) ; Indent comments nicely
899 (comment-intro . c-lineup-comment)
900 (catch-clause . 0) ; catch/finally where try
901 (do-while-closure . 0) ; while (...) where do
902 (else-clause . 0) ; else where if
903 (func-decl-cont . +) ; Indent stuff after function
904 (friend . 0) ; friend need no additional indention
905 (inclass . +) ; Indent stuff inside class...
906 (access-label . -) ; ...expect for access labels
907 (inexpr-statement . 0) ; No unneeded indent in ({ ... })...
908 (inexpr-class . 0) ; ...& anonymous classes
909 (inher-intro . +) ; ndent & lineup inheritance list
910 (inher-cont . c-lineup-multi-inher)
911 (member-init-intro . +) ; Indent & lineup initialisation list
912 (member-init-cont . c-lineup-multi-inher)
913 (label . [ 0 ]) ; Labels always on first column
914 (substatement-label . [ 0 ])
915 (statement . 0) ; Statement same as line above...
916 (statement-cont c-lineup-cascaded-calls +) ; ...but indent cont.
917 (statement-case-intro . +) ; Indent statements in switch...
918 (case-label . 0) ; ...but not the labels
919 (stream-op . c-lineup-streamop) ; Lineup << operators in C++
920 (string . c-lineup-dont-change) ; Do not touch strings!
921 (template-args-cont c-lineup-template-args +) ; Lineup template args
922 (topmost-intro . 0) ; Topmost stay topmost
923 (topmost-intro-cont c-lineup-topmost-intro-cont 0)
925 ;; Other stuff I don't really care about
926 ;; I keep it here for the sake of having all symbols specified.
927 (inlambda . c-lineup-inexpr-block)
929 (knr-argdecl-intro . +)
930 (lambda-intro-cont . +)
931 (objc-method-args-cont . c-lineup-ObjC-method-args)
932 (objc-method-call-cont
933 ;;c-lineup-ObjC-method-call-colons
934 c-lineup-ObjC-method-call +)
935 (objc-method-intro . [0]))
937 ;; I don't care about anything that is below -- not using any
938 ;; automagick -- but for the sake of having everything set I'll keep
941 (c-hanging-braces-alist ; Auto new lines around braces
942 ;; In most cases new line after open brace and both before and
943 ;; after close brace. The "before" is however ommited
944 ;; from *-close symbols because when editing normally we will
945 ;; be on the new line already -- if we're not, user probably
953 (extern-lang-open after)
954 (extern-lang-close after)
955 (namespace-open after)
956 (namespace-close after)
959 (composition-open after)
960 (composition-close after)
962 ;; No new line after closing brace if it matches do { or if (...) {
964 (substatement-open after)
965 (block-close . c-snug-do-while)
967 ;; With brace-lists however, do nothing automatically -- user knows
976 (statement-case-open after)
978 (inexpr-class-close )
979 (arglist-cont-nonempty )
982 (c-hanging-colons-alist
983 ;; Add new line after labels
991 (c-hanging-semi&comma-criteria
992 (c-semi&comma-no-newlines-before-nonblanks
993 c-semi&comma-inside-parenlist)))))
995 (eval-when-compile (require 'cc-mode))
996 (setq c-default-style '((awk-mode . "awk")
997 (other . "mina86"))))
999 (setq-default python-fill-docstring-style 'pep-257-nn)
1001 ;; HTML/XML & comapny Mode
1003 ;; Create a link out of the preceeding word if it appears to be a URL
1004 (defun mn-linkify-maybe ()
1005 "Maybe turn URL before cursor into a link.
1006 If the word before cursor appears to be an URL wrap it around in a <a
1007 href=\"...\">...</a>. Returns whether it happend.
1009 This is however a stub implementation (because thingatpt could not be
1010 loaded) which does nothing and returns nil."
1013 (when (load "thingatpt" t)
1015 (or (bound-and-true-p thing-at-point-url-regexp)
1016 (bound-and-true-p ffap-url-regexp))))
1018 (defun mn-linkify-maybe ()
1019 "If the word before cursor appears to be an URL wrap it around
1020 in a <a href=\"...\">...</a>. Returns whether it happend."
1022 (when (save-excursion
1024 (let ((end (point)))
1026 (narrow-to-region (point) end)
1028 (concat ".*\\(" url-regexp "\\)\\'")))))
1029 (let ((url (delete-and-extract-region (match-beginning 1)
1031 (insert "<a href=\"" url "\">" url "</a>")))))))
1034 (require 'sgml-mode)
1035 (setq-default sgml-quick-keyss 'close
1038 (defvar mpn-sgml-never-close-regexp
1039 (concat "\\`" (regexp-opt '("p" "tbody" "tr" "td" "th" "li" "dd" "dt") nil)
1042 (defun mpn-sgml-get-context-for-close ()
1043 "Return context of a tag to be closed.
1044 This is like ‘sgml-get-context’ except it omits elements with
1045 optional closing tags. For example, if buffer is
1049 return context for \"div\" tag rather than \"p\" since p’s close
1051 (when-let ((ctx (save-excursion (sgml-get-context t))))
1052 (setq ctx (nreverse ctx))
1053 (while (and ctx (string-match-p mpn-sgml-never-close-regexp
1054 (sgml-tag-name (car ctx))))
1055 (setq ctx (cdr ctx)))
1058 (defun mpn-sgml-magic-slash (prefix)
1059 "Close tag if ‘</’ has been typed; otherwise insert slash.
1060 If point is just after a less than sign, instead of inserting
1061 slash, close the element. Omits close tags for elements with
1062 optional close tags (see ‘mpn-sgml-never-close-regexp’). If
1063 called with prefix argument (even if it’s equal one) or preceding
1064 character is not less than, call ‘self-insert-command’ instead."
1065 (interactive (list current-prefix-arg))
1066 (if-let ((context (and (not prefix)
1067 (eq (preceding-char) ?<)
1068 (mpn-sgml-get-context-for-close)))
1069 (tag-name (sgml-tag-name context)))
1071 (insert "/" tag-name ">")
1072 (indent-according-to-mode))
1073 (self-insert-command (prefix-numeric-value prefix) ?/)))
1075 (defun mpn-sgml-magic-self-insert-command (prefix char)
1076 "Replace character with HTML entity if typed twice.
1077 If <, > or & is typed for the second time in a row (i.e. the
1078 preceding character is the same as the one being typed) replace
1079 it with corresponding HTML entity. If called with prefix
1080 argument (even if it’s equal one) or preceding character is not
1081 the same as the one being inserted, call ‘self-insert-command’
1083 (interactive (list current-prefix-arg last-command-event))
1084 (if-let ((ent (and (eq char (preceding-char))
1085 (alist-get char '((?< . "<")
1091 (self-insert-command (prefix-numeric-value prefix) char)))
1093 (defun mpn-sgml-magic-delete-backward-char (prefix)
1096 (n (- p (point-min)))
1097 (undo (lambda (str chr)
1098 (or (< n (length str))
1099 (not (string-equal (buffer-substring (- p (length str)) p)
1101 (progn (delete-region (- p (length str)) p)
1104 (and (use-region-p) delete-active-region)
1105 (not (eq (preceding-char) ?\;))
1106 (and (funcall undo "&" ?&)
1107 (funcall undo "<" ?<)
1108 (funcall undo ">" ?>)))
1109 (with-suppressed-warnings ((interactive-only delete-backward-char))
1110 (delete-backward-char (prefix-numeric-value prefix))))))
1112 (define-key sgml-mode-map " " nil)
1113 (define-key sgml-mode-map "&" #'mpn-sgml-magic-self-insert-command)
1114 (define-key sgml-mode-map "<" #'mpn-sgml-magic-self-insert-command)
1115 (define-key sgml-mode-map ">" #'mpn-sgml-magic-self-insert-command)
1116 (define-key sgml-mode-map "/" #'mpn-sgml-magic-slash)
1117 (define-key sgml-mode-map "\C-h" #'mpn-sgml-magic-delete-backward-char)
1118 (define-key sgml-mode-map [(backspace)]
1119 #'mpn-sgml-magic-delete-backward-char)
1122 ;; http://github.com/nelhage/elisp/blob/master/dot-emacs
1123 (declare-function rng-first-error "rng-valid")
1124 (declare-function rng-next-error "rng-valid")
1125 (defun nxml-next-error (arg reset)
1126 (if reset (rng-first-error))
1127 (rng-next-error arg))
1129 ;; (La)TeX and nroff mode
1131 ;; Helper for tex-space
1132 (defmacro my-tex-looking-back (regexp len)
1133 "Return non-nil if REGEXP prefixed with \\b matches LEN chars backward."
1135 (>= (- (point) (point-min)) ,len)
1137 (backward-char ,len)
1138 (looking-at ,(concat "\\b" regexp)))))
1140 ;; insert '~' or '\ ' instead of ' ' in LaTeX when needed
1141 ;; Also removes '~' when 2nd space added
1142 ;; http://www.debianusers.pl/article.php?aid=39
1143 (defun tex-space (arg)
1144 "Insert \"~\", \"\\ \" or just a space depending on context.
1146 If point follows a tilde or \"\\ \" sequence, replace it with a space
1147 \(or ARG spaces); otherwise if ARG is specified (or called with prefix
1148 argument), insert ARG spaces; otherwise if point follows a one-letter
1149 word, insert \"~\"; otherwise if point follows something that looks
1150 like an abbreviation with a dot, insert \"\\ \"; otherwise just insert
1153 Function actually uses `self-insert-command' to insert spaces so if
1154 it's not bound to space, the results may be somehow surprising."
1157 ((re-search-backward "\\\\ " (- (point) 2) t)
1158 (delete-char 2) (self-insert-command arg))
1159 ((re-search-backward "\\~" (- (point) 1) t)
1160 (delete-char 1) (self-insert-command (prefix-numeric-value arg)))
1161 (arg (self-insert-command (prefix-numeric-value arg)))
1162 ((my-tex-looking-back "[a-z]" 1)
1163 ; (my-tex-looking-back "[a-z][a-z]" 2))
1165 ((or (my-tex-looking-back "[a-z][a-z]\\." 3)
1166 (my-tex-looking-back "\\(?:tz[wn]\\|it[pd]\\)\\." 4))
1168 (t (self-insert-command 1))))
1170 (eval-when-compile (require 'tex-mode))
1171 (add-lambda-hook '(tex-mode-hook latex-mode-hook)
1172 (set-key tex-mode-map " " tex-space))
1174 ;; Insert '\ ' instead of ' ' in nroff when needed
1175 ;; Also removes '\' when 2nd space added
1176 (defun nroff-space (arg)
1177 "Insert \"\\ \" or just a space depending on context.
1178 If point follows a \"\\ \" sequence, replace it with a space (or ARG
1179 spaces); otherwise if ARG is specified (or called with prefix
1180 argument), insert ARG spaces; otherwise if point follows a one-letter
1181 word, insert \"\\ \"; otherwise if just insert space.
1183 Function actually uses `self-insert-command' to insert spaces so if
1184 it's not bound to space, the results may be somehow surprising."
1187 ((re-search-backward "\\\\ " (- (point) 2) t)
1188 (delete-char 2) (self-insert-command arg))
1189 (arg (self-insert-command arg))
1190 ((my-tex-looking-back "[a-z]" 1)
1191 ; (my-tex-looking-back "[a-z][a-z]" 2))
1192 ; (my-tex-search-back "do\\|na\\|od\\|po\\|za\\|we\\|to\\|co" 2))
1193 (insert-char ?\\ 1) (self-insert-command 1))
1194 (t (self-insert-command 1))))
1196 (eval-when-compile (require 'nroff-mode))
1197 (add-lambda-hook 'nroff-mode-hook
1198 (set-key nroff-mode-map " " nroff-space))
1204 "Fills paragraph (or region) using a cyclic order alignment.
1205 If called once fills the paragraph to the left, twice - justifies,
1206 three times - to the right, four times - centers."
1208 (fill-paragraph (seq-times-nth () left full right center) t))
1210 (set-key "\M-q" my-fill)
1212 (when (fboundp 'fill-single-char-nobreak-p)
1213 (add-hook 'fill-nobreak-predicate 'fill-single-char-nobreak-p))
1215 (setq-default tildify-pattern "\\<[a-zA-Z]\\([ \t\n]+\\)")
1216 (setq-default tildify-space-pattern "")
1218 (defun mn-tildify-space-needs-hard-space-p ()
1219 (not (or (<= ?0 (char-before (1- (point))) ?9)
1220 (let ((ch (char-before (- (point) 2))))
1221 (and ch (or (eq ?’ ch) (eq ?w (char-syntax ch)))))
1222 (and (derived-mode-p 'sgml-mode)
1223 (fboundp 'sgml-lexical-context)
1224 (not (eq 'text (car (sgml-lexical-context))))))))
1226 (add-hook 'tildify-space-predicates #'mn-tildify-space-needs-hard-space-p)
1228 (add-hook 'prog-mode-hook (lambda () (setq fill-column 80)))
1229 (add-hook 'csv-mode-hook 'turn-off-auto-fill)
1230 (add-hook 'wdired-mode-hook 'turn-off-auto-fill)
1231 (add-hook 'minibuffer-setup-hook 'turn-off-auto-fill)
1233 (setq-default display-fill-column-indicator t
1234 display-fill-column-indicator-character ?│
1235 auto-fill-function 'do-auto-fill
1236 comment-auto-fill-only-comments t)
1239 (add-lambda-hook 'text-mode-hook
1244 org-insert-mode-line-in-empty-file t
1245 org-hide-leading-stars t
1246 org-startup-indented t
1247 org-src-fontify-natively t
1248 org-catch-invisible-edits 'smart
1249 org-agenda-start-with-follow-mode t
1250 org-agenda-window-setup 'current-window
1251 org-agenda-restore-windows-after-quit t
1252 org-blank-before-new-entry '((heading . t) (plain-list-item . auto))
1253 org-list-demote-modify-bullet '(("+" . "-") ("-" . "+") ("+" . "*")))
1254 (eval-when-compile (require 'org))
1255 (with-eval-after-load "org"
1257 (define-key org-mode-map "\M-p" #'org-backward-element)
1258 (define-key org-mode-map "\M-n" #'org-forward-element))
1259 (define-key org-mode-map "\C-a" nil)
1260 (define-key org-mode-map "\C-e" nil)
1261 (when (fboundp 'form-feed-mode)
1262 (add-lambda-hook 'org-mode (form-feed-mode 1)))
1263 (add-lambda-hook 'org-agenda-mode-hook (hl-line-mode 1)))
1265 (eval-when-compile (require 'org-agenda))
1266 (set-key [(control f6)]
1267 (require 'org-agenda)
1268 (if (equal (buffer-name) org-agenda-buffer-name)
1269 (message "You're already in the agenda view!")
1270 (let ((buffer (get-buffer org-agenda-buffer-name)))
1272 (let ((window (get-buffer-window buffer)))
1274 (select-window window)
1275 (switch-to-buffer buffer)))
1276 (org-agenda nil "t")))))
1279 (defvar rust-indent-offset)
1280 (add-lambda-hook 'rust-mode-hook
1281 (setq indent-tabs-mode nil
1282 rust-indent-offset 4))
1285 (add-lambda-hook '(emacs-lisp-mode-hook lisp-mode-hook scheme-mode-hook)
1286 (setq indent-tabs-mode nil)
1287 ;; Show ^L as a line
1288 (if (fboundp 'form-feed-mode) (form-feed-mode)))
1291 (let ((filename "/usr/share/emacs/site-lisp/sawfish/sawfish.el"))
1292 (when (file-exists-p filename)
1293 (autoload 'sawfish-mode filename "Mode for editing Sawfish config files")
1294 (add-to-list 'auto-mode-alist '("sawfish/?rc\\'" . sawfish-mode))
1295 (add-to-list 'auto-mode-alist '("\\.jl\\'" . sawfish-mode))))
1297 ;; Use cperl-mode for Perl
1298 (eval-when-compile (require 'cperl-mode))
1303 (if (eq (cdr pair) 'perl-mode)
1304 (setcdr pair 'cperl-mode)))
1306 (list auto-mode-alist interpreter-mode-alist))
1307 (setq cperl-invalid-face nil ; don't highlight trailing white-space
1308 cperl-highlight-variables-indiscriminately t
1309 cperl-electric-backspace-untabify nil)
1311 ;; shell-script-mode
1312 (setq-default sh-indent-for-case-label 0
1313 sh-indent-for-case-alt '+)
1319 (setq uniquify-buffer-name-style 'reverse
1320 uniquify-strip-common-suffix t)
1328 (load (concat user-emacs-directory "local.el") t)
1330 (global-set-key "\C-u" ctl-x-map)
1331 (global-set-key "\C-x" 'universal-argument)
1333 ;;; init.el ends here