[bin] Remove pf and pd commands; I’ve not used them in years
[mina86-dot-files.git] / emacs / init.el
blob66c4592703df73aadff22c8b7e97e7f511fe46dd
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.
6 ;;; Code:
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)
11 (list start end)))
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
19 (require 'package)
21 ;; Emacs 26.1 does this automatically but older don’t.
22 (unless package--initialized
23 (package-initialize))
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)
37 (condition-case err
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
44 (lambda (args)
45 (list (sort (if args (car args) package-selected-packages)
46 #'string-lessp)))
47 '(name sort))
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)
59 ;; Utilities
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)))
65 (use-local-map map)
66 map)))
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.:
78 (let ((key \"a\"))
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)
102 For example:
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
115 lambdas are used."
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))))
122 (unless def
123 (error "DEF argument missing"))
124 (list
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))
132 ((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."
139 (declare (indent 1))
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))
144 (cadr hook))))
145 `(add-hook ,hook (lambda () ,@body))))
147 ;; Bindings
149 ;; Sequence commands
151 (defvar seq-times 0
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."
161 (declare (indent 1))
162 `(setq seq-times
163 (if (eq last-command this-command)
164 ,(if (or (null max) (eq max 'nil))
165 '(1+ seq-times)
166 `(% (1+ seq-times) ,max))
167 ,@body
168 0)))
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."
176 (declare (indent 1))
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
184 will wrap around."
185 (declare (indent 1))
186 `(eval (nth (seq-times ,(length commands) ,body) ',commands)))
188 ;; Home/End
190 ;; My home
191 (defvar my-home-end--point 0)
192 (defun my-home ()
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."
196 (interactive)
197 (seq-times-do (setq my-home-end--point (point))
198 (beginning-of-line)
199 (goto-char (point-min))
200 (goto-char my-home-end--point)))
202 (global-set-key [remap move-beginning-of-line] #'my-home)
204 ;; My end
205 (defun my-end ()
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."
209 (interactive)
210 (seq-times-do (setq my-home-end--point (point))
211 (end-of-line)
212 (goto-char (point-max))
213 (goto-char my-home-end--point)))
215 (global-set-key [remap move-end-of-line] #'my-end)
217 ;; Pulse on recenter
218 (setq-default pulse-delay 0.05
219 pulse-iterations 10)
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'."
231 (interactive "P")
232 (unless no-strip
233 (save-restriction
234 (delete-trailing-whitespace)))
235 (save-buffer))
237 (defun save-no-blanks-done (&optional no-strip)
238 "Save file and mark it done if there are any server clients."
239 (interactive "P")
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)
250 ;; Misc
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"
263 (split-window-right)
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))))
273 (require 'windmove)
274 (defun mpn-windmove (dir delete)
275 (if 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)))
292 ;; Jump
294 (require 'ffap)
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)))
308 ;; Minibuffer
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))
340 ;; Just one space
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
350 ; try-expand-list
351 ; try-expand-line
352 try-expand-dabbrev
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'."
374 (interactive)
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)))
394 ;; Fkeys
396 ;; F1 - Help
398 (defun my-help ()
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'."
402 (interactive)
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))
417 (lst `(("i" . ,(cond
418 ;; Called with -Q
419 ((not user-init-file)
420 "init.el")
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
426 ;; open init.el.
427 ((string-match "\\.eln$" user-init-file)
428 "init.el")
429 ;; Open whatever init file we’re loading.
430 (user-init-file)))
431 ("e" . "early-init.el")
432 ("m" . "mail.el")
433 ("c" . "customize.el")
434 ("b" . "~/.bashrc")
435 ("S" . "~/.shellrc")
436 ("s" . "~/.sawfish/rc"))))
437 (while lst
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)))
445 map)
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."
458 (interactive "P")
459 (cond
460 (defining-kbd-macro
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)))
469 ((use-region-p)
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)
477 ;; F5 - Mail
479 (when (file-exists-p (concat user-emacs-directory "mail.el"))
480 (set-key [(f5)]
481 (load (concat user-emacs-directory "mail.el"))
482 (with-no-warnings
483 (set-key [(f5)] notmuch)
484 (notmuch))))
486 ;; F6 - notes
488 (require 'remember)
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)))
497 (kill-buffer buf))
498 (save-current-buffer
499 (remember-notes t)
500 (condition-case nil
501 (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest _) t)))
502 (recover-this-file))
503 (error)
504 (user-error))
505 (current-buffer))))
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
513 (require 'ispell)
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'
533 returned."
534 (interactive
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)))
539 nil t)))
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."
549 (interactive "P")
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)))
555 global))
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
564 :group 'flyspell)
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))
570 (minibufferp)
571 (derived-mode-p 'notmuch-hello-mode 'notmuch-search-mode
572 'notmuch-show-mode 'package-menu-mode
573 'dired-mode)))
574 ((derived-mode-p 'prog-mode 'diff-mode) (flyspell-prog-mode))
575 (t (flyspell-mode t))))
577 (global-flyspell-mode 1)
579 ;; F9 - Compilation
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."
586 (interactive "P")
587 (save-buffer)
588 (if (derived-mode-p 'emacs-lisp-mode)
589 (byte-compile-file (buffer-file-name))
590 (if (and recompile (fboundp 'recompile))
591 (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)
598 (require 'compile)
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)
619 (setq-default
620 avy-background t
621 avy-timeout-seconds 0.3
622 avy-keys (string-to-list "htnsueoagcrlp.,;mwvzkjq'difybx/-\\@#)(+}]{![*=&$"))
624 ;; Copy/Kill
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)))
629 (set-key "\M-w"
630 (if (use-region-p)
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
637 ;; Font lock
638 (require 'font-lock)
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))
647 ;; Other
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."
654 :group 'whitespace)
656 (defface my-todo-face
657 '((t :foreground "red" :weight bold))
658 "Face used to show TODO markers in the text."
659 :group 'whitespace)
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
670 ;; characters.
671 (setq-default whitespace-style '(face
672 space-before-tab::tab
673 tab-mark
674 tabs
675 big-indent
676 trailing)
677 whitespace-big-indent-regexp "^\\(\t\\{4,\\}\\)")
678 (global-whitespace-mode)
680 ;; Modeline
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
692 column-number-mode t
694 mode-line-format
695 '((:propertize (buffer-read-only "» " " ")
696 face mode-line-de-em
697 display (min-width (10.0)))
698 (:eval (concat
699 (propertize
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)
705 "%2c")
706 (propertize ":" 'face 'mode-line-de-em)
707 "%l"))
708 (:eval (let ((min (point-min)) (max (point-max)))
709 (and (= min 1)
710 (= max (1+ (buffer-size)))
711 (concat
712 (propertize "/" 'face 'mode-line-de-em)
713 (save-excursion
714 (goto-char (point-max))
715 (format-mode-line "%l"))))))
716 vc-mode
718 mode-name
720 mode-line-process
721 minor-mode-alist))
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)
728 (with-no-warnings
729 (set-key "\M-." mc/mark-next-like-this)
730 (set-key "\M-," mc/unmark-next-like-this)))
732 ;; Other
733 (require 'icomplete)
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.
751 cursor-type 'box)
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))
766 ;; Saving etc
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)
776 ;; Indention
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.")
783 (defun set-tab (tab)
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))
799 (mapc (lambda (var)
800 (when (boundp var)
801 (set (make-local-variable var) tab-width)))
802 set-tab--variables)
803 (cond
804 (negative (setq indent-tabs-mode nil))
805 (prefix-arg (setq indent-tabs-mode t)))))
807 (setq indent-tabs-mode t
808 tab-width 8)
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))
813 (set-default var 8))
814 (eval-when-compile (require 'tabify))
815 (setq tabify-regexp "^\t* [ \t]+");tabify only at the beginning of line
817 ;; Scrolling/moving
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))
827 ;; Major Modes
829 ;; CC Mode
831 (add-lambda-hook 'c-initialization-hook
832 (c-add-style
833 "mina86"
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
848 (incomposition . 0)
849 (inextern-lang . 0)
850 (inmodule . 0)
851 (innamespace . 0)
853 ;; Preprocessor macros
854 (cpp-define-intro c-lineup-cpp-define +)
855 (cpp-macro . [ 0 ])
856 (cpp-macro-cont . +)
858 ;; Brace after newline newer indents
859 (block-open . 0)
860 (brace-entry-open . 0)
861 (brace-list-open . 0)
862 (class-open . 0)
863 (composition-open . 0)
864 (defun-open . 0)
865 (extern-lang-open . 0)
866 (inline-open . 0)
867 (module-open . 0)
868 (namespace-open . 0)
869 (statement-case-open . 0)
870 (substatement-open . 0)
872 ;; Obviously, do not indent closing brace
873 (arglist-close . 0)
874 (block-close . 0)
875 (brace-list-close . 0)
876 (class-close . 0)
877 (composition-close . 0)
878 (defun-close . 0)
879 (extern-lang-close . 0)
880 (inline-close . 0)
881 (module-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 . +)
887 (substatement . +)
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 +)
893 (arglist-intro . +)
895 ;; Misc
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)
928 (knr-argdecl . 0)
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
939 ;; it here.
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
946 ;; knows better.
947 (defun-open after)
948 (defun-close after)
949 (class-open after)
950 (class-close after)
951 (inline-open after)
952 (inline-close after)
953 (extern-lang-open after)
954 (extern-lang-close after)
955 (namespace-open after)
956 (namespace-close after)
957 (module-open after)
958 (module-close after)
959 (composition-open after)
960 (composition-close after)
962 ;; No new line after closing brace if it matches do { or if (...) {
963 (block-open after)
964 (substatement-open after)
965 (block-close . c-snug-do-while)
967 ;; With brace-lists however, do nothing automatically -- user knows
968 ;; better
969 (brace-list-open )
970 (brace-list-close )
971 (brace-list-intro )
972 (brace-entry-open )
974 ;; Others
975 (statement-cont )
976 (statement-case-open after)
977 (inexpr-class-open )
978 (inexpr-class-close )
979 (arglist-cont-nonempty )
982 (c-hanging-colons-alist
983 ;; Add new line after labels
984 (case-label after)
985 (label after)
986 (access-label after)
987 ;; But nothing else
988 (member-init-intro )
989 (inher-intro )
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."
1011 nil)
1013 (when (load "thingatpt" t)
1014 (let ((url-regexp
1015 (or (bound-and-true-p thing-at-point-url-regexp)
1016 (bound-and-true-p ffap-url-regexp))))
1017 (when 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."
1021 (interactive "*")
1022 (when (save-excursion
1023 (save-restriction
1024 (let ((end (point)))
1025 (beginning-of-line)
1026 (narrow-to-region (point) end)
1027 (looking-at
1028 (concat ".*\\(" url-regexp "\\)\\'")))))
1029 (let ((url (delete-and-extract-region (match-beginning 1)
1030 (match-end 1))))
1031 (insert "<a href=\"" url "\">" url "</a>")))))))
1034 (require 'sgml-mode)
1035 (setq-default sgml-quick-keyss 'close
1036 sgml-specials ())
1038 (defvar mpn-sgml-never-close-regexp
1039 (concat "\\`" (regexp-opt '("p" "tbody" "tr" "td" "th" "li" "dd" "dt") nil)
1040 "\\'"))
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
1047 <div><p>
1049 return context for \"div\" tag rather than \"p\" since p’s close
1050 tag is optional."
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)))
1056 (car 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)))
1070 (progn
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’
1082 instead."
1083 (interactive (list current-prefix-arg last-command-event))
1084 (if-let ((ent (and (eq char (preceding-char))
1085 (alist-get char '((?< . "&lt;")
1086 (?> . "&gt;")
1087 (?& . "&amp;"))))))
1088 (progn
1089 (delete-char -1)
1090 (insert ent))
1091 (self-insert-command (prefix-numeric-value prefix) char)))
1093 (defun mpn-sgml-magic-delete-backward-char (prefix)
1094 (interactive "P")
1095 (let* ((p (point))
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)
1100 str))
1101 (progn (delete-region (- p (length str)) p)
1102 (insert chr))))))
1103 (when (or prefix
1104 (and (use-region-p) delete-active-region)
1105 (not (eq (preceding-char) ?\;))
1106 (and (funcall undo "&amp;" ?&)
1107 (funcall undo "&lt;" ?<)
1108 (funcall undo "&gt;" ?>)))
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."
1134 `(and
1135 (>= (- (point) (point-min)) ,len)
1136 (save-excursion
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
1151 space.
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."
1155 (interactive "P")
1156 (cond
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))
1164 (insert-char ?~ 1))
1165 ((or (my-tex-looking-back "[a-z][a-z]\\." 3)
1166 (my-tex-looking-back "\\(?:tz[wn]\\|it[pd]\\)\\." 4))
1167 (insert "\\ "))
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."
1185 (interactive "p")
1186 (cond
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))
1200 ;; Misc
1202 ;; Alt+q - Fill
1203 (defun my-fill ()
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."
1207 (interactive)
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)
1238 ;; Text mode
1239 (add-lambda-hook 'text-mode-hook
1240 (setq word-wrap t))
1242 ;; Org mode
1243 (setq-default
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"
1256 (with-no-warnings
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)))
1271 (if buffer
1272 (let ((window (get-buffer-window buffer)))
1273 (if window
1274 (select-window window)
1275 (switch-to-buffer buffer)))
1276 (org-agenda nil "t")))))
1278 ;; Rust mode
1279 (defvar rust-indent-offset)
1280 (add-lambda-hook 'rust-mode-hook
1281 (setq indent-tabs-mode nil
1282 rust-indent-offset 4))
1284 ;; Lisp/Scheme mode
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)))
1290 ;; Sawfish 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))
1299 (mapc
1300 (lambda (list)
1301 (mapc
1302 (lambda (pair)
1303 (if (eq (cdr pair) 'perl-mode)
1304 (setcdr pair 'cperl-mode)))
1305 list))
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 '+)
1315 ;; Various features
1317 ;; uniquify
1318 (require 'uniquify)
1319 (setq uniquify-buffer-name-style 'reverse
1320 uniquify-strip-common-suffix t)
1322 (unless (daemonp)
1323 (server-start))
1325 (provide 'init)
1327 ;; Local
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