optimize startup
[dot-emacs] / init.el
1 ;; Copyright (C) 2019 Ian Kelling
2
3 ;; This program is free software: you can redistribute it and/or modify
4 ;; it under the terms of the GNU General Public License as published by
5 ;; the Free Software Foundation, either version 3 of the License, or
6 ;; (at your option) any later version.
7
8 ;; This program is distributed in the hope that it will be useful,
9 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ;; GNU General Public License for more details.
12
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 ;; do m-x benchmark-init to see some benchmark stats
17 ;;(add-to-list 'load-path "~/.emacs.d/src/benchmark-init-el/")
18 ;;(require 'benchmark-init-loaddefs)
19 ;;(benchmark-init/activate)
20
21 ;;; init.el --- the start of customization
22
23 ;; (toggle-debug-on-error) ;uncomment to help debug
24
25
26 ;; stop from minimizing & freezing the gui
27 ;; used to freeze emacs and was really annoying,
28 ;; seems its changed now. no harm in keeping this though.
29 (global-unset-key (kbd "C-z"))
30
31 ;; speed up init https://www.reddit.com/r/emacs/comments/3kqt6e/2_easy_little_known_steps_to_speed_up_emacs_start/
32 ;; https://github.com/jwiegley/dot-emacs/blob/master/init.el
33 (defvar file-name-handler-alist-old file-name-handler-alist)
34 (setq package-enable-at-startup nil
35 file-name-handler-alist nil
36 message-log-max 16384
37 gc-cons-threshold 402653184
38 gc-cons-percentage 0.6
39 auto-window-vscroll nil)
40
41 (add-hook 'after-init-hook
42 `(lambda ()
43 (setq file-name-handler-alist file-name-handler-alist-old
44 ;; 100 mb
45 gc-cons-threshold 100000000))
46 ;; taken from wiegley, dunno why the t is there.
47 t)
48
49 ;; 2019-6-26, 1.26s
50 ;; ; to profile init:
51 ;; ; uncomment the following block
52 (require 'benchmark-init)
53 (add-hook 'after-init-hook 'benchmark-init/deactivate)
54 ;; ; Then run:
55 ;; ; emacs -f benchmark-init/show-durations-tabulated
56 ;; ; emacs -f benchmark-init/show-durations-tree
57 ;; ; to catch things post-init
58 ;; ; emacs -f benchmark-init/deactivate
59
60
61 ;; these need to be done before the hook in order to satisfy the byte compiler or batch mode
62
63 ;; this is the builtin org mode
64 ;;(add-to-list 'load-path "~/.emacs.d/emacs/site-lisp/org")
65
66 (add-to-list 'load-path "~/.emacs.d/src/readline-complete")
67
68 ;; disabled since not used.
69 ;;(add-to-list 'load-path "~/.emacs.d/src/bbdb-csv-import")
70 ;;(add-to-list 'load-path "~/.emacs.d/src/ghci-completion")
71 ;;(add-to-list 'load-path "~/.emacs.d/src/mediawiki-el")
72 ;;(add-to-list 'load-path "~/.emacs.d/src/spray")
73
74 (add-to-list 'load-path "~/.emacs.d/src/visible-mark")
75
76
77
78 (setq init-dir (file-name-directory load-file-name))
79 ;; previously, i was doing byte-recompile-directory, but
80 ;; now i just have one init file
81 (unless (equal (user-uid) 0) ; don't make root owned files
82 (byte-recompile-file (expand-file-name "init.el" init-dir) nil 0)
83 (when (file-exists-p "/p/c/mymu4e.el")
84 (byte-recompile-file "/p/c/mymu4e.el" nil 0))
85 )
86
87 ;;; misc emacs documentation
88
89 ;;;; how to find auto-saved files that need recovering
90 ;; find a recently dated file in ~/.emacs.d/auto-save-list/, and see the files listed in it.
91 ;; #file# is an auto-save file. It may or may not be different than the file is corresponds to.
92 ;; If it is different, emacs will give a message about recovering it when you open it.
93
94 ;;;; misc org functions
95
96 ;; ;; these are usefull with (goto-char)
97 ;; ;; find named entity, other than headline
98 ;; (org-find-entry-with-id "string-number-or-symbol")
99
100 ;; (org-find-exact-headline-in-buffer "heading" nil t)
101
102 ;; ;; remove any indent level which is throughout the buffer
103 ;; (org-do-remove-indentation)
104
105
106 ;;;; gnus
107
108 ;; good info http://www.emacswiki.org/emacs/GnusTutorial
109 ;; good info http://www.emacs.uniyar.ac.ru/doc/em24h/emacs183.htm
110
111
112 ;; After downloading mailing list archives, once you have an mbox file,
113 ;; there are rather straightforward ways to get it into any mail program,
114 ;; but I will cover gnus, which I use and is a bit tricky.
115
116 ;; gnus has a native search (limited, too slow for body text searches), and external search engine integration.
117 ;; gnus manual recommends converting to maildir for searching local mail, but importing lots of maildir messages to gnus
118 ;; takes 10+ minutes, so scratch that option. it suggests 2 alternate options
119 ;; mairix. for mbox, it doesn't integrate 100% with gnus, it copies the search results to a mbox
120 ;; and tells gnus to make a group of that mbox and display it. This means the read state won't be persistent, but otherwise
121 ;; works great.
122
123 ;; local imap server which will use the mbox and provide search.
124 ;; dovecot is modular, theres a dovecot-common which uses recommends to install i guess it's most used modules. Its
125 ;; description is completely not useful. Anyways, I'm not sure if there is any benefit to installing this over just the
126 ;; module we need.
127 ;; pi dovecot-imapd
128
129 ;; dovecot by default also makes a an inbox folder based on the normal local mail location /var/mail/<username>
130 ;; those locations are adjustable and well documented via the var mail_location in
131 ;; /etc/dovecot/conf.d/10-mail.conf
132 ;; I forward my local mail, didn't see immediately how to turn off the inbox, but it will always be empty, so I left as
133 ;; is. you could make the var be empty, which apparently has the same effect.
134
135 ;; Originally just linked the default location ~/.mail, but I changed to altering the config since ~/.mail since it seems
136 ;; other things like postfix use that location
137
138 ;; based on http://roland.entierement.nu/blog/2010/09/08/gnus-dovecot-offlineimap-search-a-howto.html
139 ;; other links that poped up contained outdated, innacurate information
140 ;; http://sachachua.com/blog/2008/05/geek-how-to-use-offlineimap-and-the-dovecot-mail-server-to-read-your-gmail-in-emacs-efficiently/
141 ;; http://www.emacswiki.org/emacs/JamesFerguson
142 ;; http://www.sanityinc.com/articles/read-mailing-lists-in-emacs-over-imap/
143
144 ;; Within emacs you can move messages between mbox and maildir etc, which is a nice flexibility.
145
146
147
148 ;; doc group for mbox:
149 ;; in gnus, do gnus-group-make-doc-group (G f in groups buffer) and point to the file
150
151 ;; info about groups created within gnus is stored in ~/.newsrc.eld
152 ;; also stored is a duplication of what email messages are read/unread,
153 ;; what newsgroups are subsribed to and read/unread,
154 ;; probably more stuff, everything that gnus saves.
155
156
157 ;; searching the body of the messages, i cut off after a few minutes.
158 ;; i can grep the file in just a couple seconds
159
160
161 ;; random side note
162 ;; we can also get mbox from gmane
163 ;; http://notmuchmail.org/howto/#index7h2
164
165
166 ;; gnus can't search mboxes except with its builtin search which is extremely slow. mairix can do mbox files from the command
167 ;; line, but not from within gnus, but from mairix.el, which can then open the results in gnus
168
169 ;; mbox can be converted to maildir easily, but gnus loads lots of maildir messages extremely slow. it parses all the
170 ;; headers and generates a nov file for each.
171
172 ;; nnfolder-generate-active-file
173
174 ;; to reset things, when changing mail group. I duno all the proper way, but it works to delete
175 ;; ~/Mail ~/.newsrc.eld ~/.newsrc-dribble
176
177
178 ;;;;; mail sources vs select methods background
179 ;; I found this very confusing when first reading through the manual. "mail sources" is a term that does not simply mean
180 ;; sources of mail, it is much narrower for gnus. sources of mail can be either "mail sources" or select methods. Mail
181 ;; sources will move mail to ~/Mail (not sure what format), and split it into groups according to variables. You can use
182 ;; "mail sources" for maildir / imap, but those can also be read via select methods, which do not move the mail from their
183 ;; location, but use them in their native format. This is what I want to do, and I can simply ignore mail
184 ;; sources. Confusing terminology is that "fetching mail" "scanning mail", lots of things mail doesn't mean all mail, it
185 ;; means specifically from "mail sources". The words "articles" and "news" is used in connection with select methods, aka my actual mail.
186
187
188
189 ;;;;; caching background
190
191 ;; caching:
192 ;; there is also ~/News/cache, filled with a bunch of articles, like 300 megs. can't figure out why.
193 ;; Grepped for caching in the manual, found 2 main things.
194 ;; cache is for 2 purposes. to cache locally, and to keep articles from expiring, called persistence
195 ;; gnus-use-cache, which puts things if they are
196 ;; gnus-cache-enter-articles
197 ;; things go in cache when they are marked certain ways by default, ticked and dormant
198 ;; and read articles are moved out of the cache
199 ;; still no idea why i have a bunch in the cache, but I set a var so that my mail won't get cached
200 ;; I'm gonna delete the cache, and check on it later see what exactly is going in there
201 ;; And of course, I moved ~/News to my encrypted drive and symlinked it
202
203
204
205 ;;; things that should be at the beginning
206
207 ;; from its README.md
208 (eval-when-compile
209 (require 'use-package))
210
211
212 ;; Ubiquitous Packages. these could go anywhere actually
213 (use-package saveplace
214 :unless noninteractive
215 :config
216 (save-place-mode 1))
217 ;; find file at point
218 (use-package ffap)
219
220
221 (setq package-archives
222 (quote
223 (("gnu" . "https://elpa.gnu.org/packages/")
224 ("MELPA" . "https://melpa.org/packages/"))))
225
226 ;;(add-to-list 'package-archives
227 ;; '("marmalade" .
228 ;; "http://marmalade-repo.org/packages/"))
229
230 ;; down atm 2020-08-30
231 ;;(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
232
233
234 ;; keep our init.el clean, by moving customization elisp to it's own file
235 (setq custom-file "~/.emacs.d/custom.el")
236 ;; empty atm
237 ;;(load custom-file 'noerror)
238
239
240 ;;; auto-complete
241
242 ;; auto-completion in minibuffer
243 ;; disabled while I look for another alternative
244 ;;(icomplete-mode)
245
246 (require 'auto-complete-config)
247 (ac-config-default)
248
249
250 ;; complete after 1 char instead of default 2
251 (setq ac-auto-start 1)
252 (setq ac-delay 0.001)
253
254 (add-to-list 'ac-modes 'org-mode 'sql-mode)
255
256
257 ;; for org mode completion source taken from wiki.
258 ;; it did not work. no idea why. todo, investigate
259 ;; the ac-sources code is at http://www.emacswiki.org/emacs/AutoCompleteSources
260 ;; i've deleted it here so as to save space and not spam this file
261 ;;(defun my-ac-org-mode ()
262 ;; (setq ac-sources (append ac-sources '(ac-source-org))))
263
264
265 ;; this makes the org-self-insert command not do a flyspell spell check.
266 ;; low priority thing to look into sometime
267 (ac-flyspell-workaround)
268
269
270 (define-key ac-completing-map (kbd "<up>") nil)
271 (define-key ac-completing-map (kbd "<down>") nil)
272 (define-key ac-completing-map (kbd "<S-return>") 'ac-expand)
273 (define-key ac-completing-map "\t" 'ac-complete)
274 ;;(define-key ac-completing-map (kbd "<tab>") 'ac-complete)
275 (define-key ac-completing-map (kbd "TAB") 'ac-complete)
276
277
278
279 ;;; auto-complete readline-complete
280
281 (require 'readline-complete)
282 ;; not sure how I made these, but I deleted, and
283 ;; it would be nice to make them again sometime
284 ;;(require 'src-loaddefs)
285
286 ;; disabled cuz broken
287 ;; redefining function in readline-complete so ac-complete only uses readline as a source
288 (defun ac-rlc-setup-sources ()
289 "Add me to shell-mode-hook!"
290 (setq ac-sources '(ac-source-shell)))
291 (add-hook 'shell-mode-hook 'ac-rlc-setup-sources)
292
293 ;; generally unnecessary, but why not
294 (setq explicit-shell-file-name "bash")
295
296 ;; readline-complete says to add this line.
297 ;; however, it up my procfs directory tracking hook
298 ;; because get-process doesn't notice the child shell.
299 ;; instead, I've removed export EMACS=t from
300 ;; comint-exec-1 (the function which initially sets it)
301 ;; by finding it in emacs sources and redefinind it here
302 ;; and done stty echo in my bashrc
303 ;;(setq explicit-bash-args '("-c" "export EMACS=; stty echo; bash"))
304
305 (setenv "EMACS" "")
306 (setq explicit-bash-args nil)
307 (setq comint-process-echoes t)
308 ;; default of 30 is way too slow. todo, consider pushing this upstream
309 (setq rlc-attempts 5)
310
311 (add-to-list 'ac-modes 'shell-mode)
312
313 ;; readline-complete recommends this (i assume this format),
314 ;; but greping finds no reference in emacs or my .emacs.d
315 ;; so I'm assuming it is for an older emacs
316 ;;(setq explicit-ssh-args '("-t"))
317
318 (add-hook 'shell-mode-hook
319 (lambda ()
320 ;;(define-key shell-mode-map (kbd "<tab>") 'auto-complete)
321 (define-key shell-mode-map (kbd "TAB") 'auto-complete)
322 ))
323
324
325 ;;; readline complete fix
326
327 ;; I need this function here, where INSIDE_EMACS is replaced with LC_INSIDE_EMACS.
328 ;; ian: last update 2017-1-7. update this periodically from upstream
329 ;; like when we do a major emacs update
330 (defun comint-exec-1 (name buffer command switches)
331 (let ((process-environment
332 (nconc
333 ;; If using termcap, we specify `emacs' as the terminal type
334 ;; because that lets us specify a width.
335 ;; If using terminfo, we specify `dumb' because that is
336 ;; a defined terminal type. `emacs' is not a defined terminal type
337 ;; and there is no way for us to define it here.
338 ;; Some programs that use terminfo get very confused
339 ;; if TERM is not a valid terminal type.
340 ;; ;; There is similar code in compile.el.
341 (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
342 (list "TERM=dumb" "TERMCAP="
343 (format "COLUMNS=%d" (window-width)))
344 (list "TERM=emacs"
345 (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width))))
346 (list (format "LC_INSIDE_EMACS=%s,comint" emacs-version))
347 process-environment))
348 (default-directory
349 (if (file-accessible-directory-p default-directory)
350 default-directory
351 "/"))
352 proc decoding encoding changed)
353 (let ((exec-path (if (and command (file-name-directory command))
354 ;; If the command has slashes, make sure we
355 ;; first look relative to the current directory.
356 (cons default-directory exec-path) exec-path)))
357 (setq proc (apply 'start-file-process name buffer command switches)))
358 ;; Some file name handler cannot start a process, fe ange-ftp.
359 (unless (processp proc) (error "No process started"))
360 (let ((coding-systems (process-coding-system proc)))
361 (setq decoding (car coding-systems)
362 encoding (cdr coding-systems)))
363 ;; Even if start-file-process left the coding system for encoding data
364 ;; sent from the process undecided, we had better use the same one
365 ;; as what we use for decoding. But, we should suppress EOL
366 ;; conversion.
367 (if (and decoding (not encoding))
368 (setq encoding (coding-system-change-eol-conversion decoding 'unix)
369 changed t))
370 (if changed
371 (set-process-coding-system proc decoding encoding))
372 proc))
373
374 ;;; auto save
375
376 ;; todo: patch this so i can turn it off like my-as-off-local.
377 ;; then try it out and see if it can replace my autosave.
378 ;; Or maybe with the new auto-save-visited-mode.
379 ;; (use-package super-save
380 ;; :ensure t
381 ;; :config
382 ;; (setq super-save-exclude '("")
383 ;; super-save-triggers
384 ;; '(balance-windows
385 ;; next-buffer
386 ;; org-babel-execute-src-block
387 ;; other-window
388 ;; previous-buffer
389 ;; split-window-below
390 ;; split-window-horizontally
391 ;; start-process-shell-command
392 ;; switch-to-buffer
393 ;; windmove-down
394 ;; windmove-left
395 ;; windmove-right
396 ;; windmove-up)
397 ;; )
398 ;; (super-save-mode +1))
399
400
401
402 (setq auto-save-timeout 1) ; idle time before auto-save.
403
404 ;; main hook for my auto save
405 (add-hook 'auto-save-hook 'my-auto-save)
406 ;; additional hook to try to deal with emacs not auto-saving when a buffer isn't active
407 (add-hook 'window-configuration-change-hook 'my-auto-save-win)
408
409 ;; this function from mu4e really does not like buffer saving
410 (advice-add 'message-send-and-exit :before 'my-as-off)
411 (advice-add 'message-send-and-exit :after 'my-as-on)
412
413 ;; avoid window config hook saving too much, it can
414 ;; get into loops in some random situations
415 (setq my-auto-save-last nil)
416 (defun my-auto-save-win ()
417 (unless (eq (current-buffer) my-auto-save-last)
418 (my-auto-save (current-buffer))))
419
420 (defun my-auto-save (&optional last)
421 (when (and
422 my-as
423 (buffer-file-name)
424 ;; mu4e has a bug right now, undo breaks when saving drafts
425 (not (string= (buffer-file-name) "*draft*"))
426 (buffer-modified-p)
427 (not (and (boundp 'org-src-edit-buffer-p) (org-src-edit-buffer-p))))
428 ;; serial is incremented on each save, so let's do a bit less of them
429 (not (derived-mode-p 'dns-mode))
430 (setq my-auto-save-last last)
431 (let (message-log-max)
432 ;; a bit of a hack to partially suppress the constant saving in the echo area
433 (with-temp-message ""
434 (basic-save-buffer)))))
435
436 ;; in the message-send-and-exit advice, got an error because it passed an arg.
437 ;; didn't look into why, just add ignored args.
438 (defun my-as-off (&rest ignore)
439 (interactive)
440 (setq my-as nil))
441
442 (defun my-as-off-local (&rest ignore)
443 (interactive)
444 (setq-local my-as nil))
445
446 (defun my-as-on (&rest ignore)
447 (interactive)
448 (setq my-as t))
449
450 (defun my-as-on-local (&rest ignore)
451 (interactive)
452 (setq-local my-as on))
453
454 ;; based on suggestion in the emacs docs, redefine these 2 functions
455 ;; to avoid prompt spamming the user when we do auto-save
456 (defun ask-user-about-supersession-threat (fn)
457 (discard-input)
458 (message
459 "File for %s has changed on disk outside of emacs. Auto-save is overwriting it, however
460 a backup is being created in case that is not what you intended." buffer-file-name)
461 (setq buffer-backed-up nil))
462
463 (defadvice ask-user-about-lock (before lock-deactivate-as activate)
464 (make-local-variable 'my-as)
465 (setq my-as nil)
466 (message "proper autosave has been turned off for this buffer because of lock file problem.
467 In this buffer, do M-x my-as-on to reenable"))
468
469 ;; todo, this doesn't work consistently to override the auto-save message
470 (defalias 'do-auto-save-original (symbol-function 'do-auto-save))
471 (defun do-auto-save (&optional no-message current-only)
472 "This function has been modified to wrap the original so that NO-MESSAGE
473 is always set to t, since we auto-save a lot, it spams otherwise.
474 The original doc string is as follows:
475
476 Auto-save all buffers that need it.
477 This is all buffers that have auto-saving enabled
478 and are changed since last auto-saved.
479 Auto-saving writes the buffer into a file
480 so that your editing is not lost if the system crashes.
481 This file is not the file you visited; that changes only when you save.
482 Normally we run the normal hook `auto-save-hook' before saving.
483
484
485 A non-nil NO-MESSAGE argument means do not print any message if successful.
486 A non-nil CURRENT-ONLY argument means save only current buffer."
487 (interactive)
488 (do-auto-save-original t current-only))
489
490 ;; enable MY auto-save
491 (my-as-on)
492
493 ;;; backups, separate from auto-save
494
495
496 ;; set backup file location
497 (setq backup-directory-alist '(("." . "~/.editor-backups")))
498 (setq auto-save-file-name-transforms
499 '((".*" "~/.editor-backups/" t)))
500
501 (setq version-control t ;; Use version numbers for backups
502 kept-new-versions 100
503 kept-old-versions 2
504 delete-old-versions t ;; delete old versions silently
505 ;; assume hard linked files are done on purpose, don't screw them up
506 backup-by-copying-when-linked t)
507
508 ;; todo, the time needs to be an integer, not a vector type thing
509 (defun constant-backup ()
510 "Backup conditioned on some time passing since last one.
511 Hooked into 'before-save-hook."
512 (cl-flet ((b-time (minutes)
513 (< last-backup-time
514 (- (current-time) (* 60 minutes)))))
515 (when (or (not (boundp 'last-backup-time)) (and (< (buffer-size) 10000000) (b-time 5)) (b-time 30))
516 (setq buffer-backed-up nil)
517 (setq-local last-backup-time (current-time)))))
518
519 ;; make a backup on auto-save, because the backup feature is not
520 ;; utilized with my-auto-save, only normal interactive save.
521 ;; todo, enable when fixed
522 ;;(add-hook 'before-save-hook 'constant-backup)
523
524 (add-hook 'auto-save-hook 'auto-save-size-limit)
525
526 (defun auto-save-size-limit ()
527 (when (and (not backup-inhibited) (> (buffer-size) 2000000))
528 (message "Backups disabled for this buffer due to size > 2 megs")
529 (make-local-variable 'backup-inhibited)
530 (setq backup-inhibited t)))
531
532
533 ;; ;; background:
534 ;; ;; the faq suggests to auto-save using
535 ;; (setq auto-save-visited-file-name t)
536 ;; and to toggle auto-saving in the current buffer, type `M-x auto-save-mode'
537
538 ;; however, this is buggy.
539 ;; it leaves around lock files, which can be disabled with
540 ;; (setq create-lockfiles nil)
541 ;; but it is also buggy on other things that appear to hook onto file saving
542 ;; so i created my own function, which originally had bugs,
543 ;; but new emacs version fixed all that, yay!.
544
545
546 ;; not using, but here for documentation,
547 ;; alternate way to enable and specify how long between autosaves.
548 ;; number of input events between autosave.
549 ;; lowest bound of functionality is actually about 15 input events
550 ;; (setq auto-save-interval ...)
551
552 ;;; c-like settings
553 ;; change last thing from gnu.
554 ;; notably this avoids brace indent after if, and 4 space indent
555 (setq c-default-style '((java-mode . "java")
556 (awk-mode . "awk")
557 (other . "stroustrup")))
558 ;; for emacs itself, use
559 ;; (setq c-default-style '((java-mode . "java")
560 ;; (awk-mode . "awk")
561 ;; (other . "gnu")))
562 ;; (setq-default c-basic-offset 2)
563
564 ;;; color theme
565
566 ;; A Theme builder is available at http://elpa.gnu.org/themes/ along with
567 ;; a list of pre-built themes at http://elpa.gnu.org/themes/view.html and
568 ;; themes are available through ELPA.
569
570
571 (defun override-theme (arg)
572 (interactive)
573 (while custom-enabled-themes
574 (disable-theme (car custom-enabled-themes)))
575 (load-theme arg t))
576 (setq color-theme-is-global t)
577
578 ;; temporary, make night be default
579
580 (defun toggle-night ()
581 (interactive)
582 (cond ((equal (car custom-enabled-themes) 'naquadah)
583 (override-theme 'leuven))
584 (t
585 (override-theme 'naquadah))))
586
587
588 ;; in the leuven theme file, i made this change. will need to remake it
589 ;; on package updates. I could fork, but its a pretty simple change
590 ;; < `(default ((,class (:foreground "#333333" :background "#FFFFFF"))))
591 ;; > `(default ((,class (:foreground "#333333" :background "#F6F6F0"))))
592 (override-theme 'leuven)
593
594
595 ;; disable color thing with this:
596 ;;(disable-theme (car custom-enabled-themes))
597
598 ;; decent dark themes
599
600 ;;(override-theme 'tangotango)
601 ;;(override-theme 'deeper-blue)
602 ;;(override-theme 'tango-dark)
603 ;;(override-theme 'tsdh-dark)
604
605 ;;(override-theme 'heroku)
606 ;;(override-theme 'inkpot) ;; part of inkpot-theme package
607 ;;(override-theme 'naquadah) ; org mode features, part of naquadah-theme package
608 ;;(override-theme 'spolsky) ;; part of sublime-themes package
609 ;;(override-theme 'twilight-anti-bright) ;; from twilight-anti-bright-theme package
610
611 ;; interesting but not usable colors
612 ;;(override-theme 'cyberpunk) ; cool org mode features, from cyberpunk-theme package
613 ;;(override-theme 'wombat) ; cursor not visible enough. from a wombat package, not sure which
614 ;;(override-theme 'misterioso) ; cursor not visible enough
615
616 ;;decent light themes
617 ;;(override-theme 'alect-light) ; theres a -alt version, don't see a dif. could use this without dimming. from alect-something package
618 ;;(override-theme 'occidental) ; from occidental-theme package
619
620
621 ;;color-theme is deprecated in emacs 24.
622
623 ;; theme packages i tried then removed:
624 ;; ignored ones that didn't use the new theme engine
625
626 ;;66 packages (zenburn-theme-2.1, zen-and-art-theme-1.0.1, waher-theme-20130917.7, ujelly-theme-1.0.35, twilight-theme-1.0.0, twilight-bright-theme-20130605.143, twilight-anti-bright-theme-20120713.316, tronesque-theme-1.3, tron-theme-12, toxi-theme-0.1.0, tommyh-theme-1.2, tango-2-theme-1.0.0, sunny-day-theme-20131203.1250, sublime-themes-20140117.323, subatomic-theme-20131011.1048, soothe-theme-0.3.16, soft-morning-theme-20131211.1342, soft-charcoal-theme-20130924.1206, sea-before-storm-theme-0.3, purple-haze-theme-20130929.1751, phoenix-dark-pink-theme-20130905.941, phoenix-dark-mono-theme-20130306.1215, pastels-on-dark-theme-0.3, obsidian-theme-20130920.937, nzenburn-theme-20130513, noctilux-theme-20131019.31, mustang-theme-20130920.939, monokai-theme-0.0.10, molokai-theme-20130828.0, late-night-theme-0.0, jujube-theme-0.1, ir-black-theme-20130302.2355, gruvbox-theme-20131229.1458, gruber-darker-theme-0.6, grandshell-theme-20140118.1003, github-theme-0.0.3, gandalf-theme-0.1, flatland-theme-20131204.858, django-theme-20131022.202, deep-thought-theme-0.1.1, dakrone-theme-20131212.1159, colorsarenice-theme-20131128.1106, color-theme-wombat+-0.0.2, color-theme-wombat-0.0.1, color-theme-twilight-0.1, color-theme-tango-0.0.2, color-theme-solarized-20120301, color-theme-sanityinc-solarized-2.25, color-theme-railscasts-0.0.2, color-theme-monokai-0.0.5, color-theme-molokai-0.1, color-theme-ir-black-1.0.1, color-theme-heroku-1.0.0, color-theme-github-0.0.3, color-theme-eclipse-0.0.2, color-theme-dpaste-0.0.1, color-theme-dawn-night-1.0, color-theme-colorful-obsolescence-0.0.1, color-theme-cobalt-0.0.2, color-theme-20080305.34, clues-theme-20130908.801, busybee-theme-20130920.942, bubbleberry-theme-0.1.2, mblage-theme-20130715.621, anti-zenburn-theme-20140104.1542, ample-zen-theme-0.2)
627
628
629
630
631 ;;; cross session settings
632
633 (use-package recentf
634 ;; defer & commands from jwiegley
635 :defer 10
636 :commands (recentf-mode
637 recentf-add-file
638 recentf-apply-filename-handlers)
639 :config
640 (recentf-mode 1)
641 (setq recentf-max-saved-items 400
642 recentf-max-menu-items 15)
643 )
644
645 (use-package saveplace
646 :unless noninteractive
647 :config
648 save-place-version-control 'nospecial
649 save-place-limit 4000
650 save-place-file "~/.emacs.d/places"
651 (save-place-mode 1))
652
653
654 ;; savehist keeps track of some history search entries
655 (use-package savehist
656 :unless noninteractive
657 :config
658 (setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring)
659 ;; save every minute
660 savehist-autosave-interval 60
661 ;; keep the home clean
662 savehist-file "~/.emacs.d/.savehist")
663 (savehist-mode 1))
664
665 ;;; dired
666
667 ;; dired - reuse current buffer by pressing 'a'
668 (put 'dired-find-alternate-file 'disabled nil)
669
670 ;;; mu4e
671
672 ;; alsot tried notmuch, it had some glitches, and it's config has a list
673 ;; of folders which i'd rather not publish, so it's config is archived.
674
675 ;;(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
676 ;;(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
677 ;; (require 'mu4e)
678
679 ;; (setq mu4e-headers-results-limit 2000)
680
681
682
683 (defun my-mu4e-init ()
684 (setq mu4e-headers-fields (delq (assoc :mailing-list mu4e-headers-fields) mu4e-headers-fields))
685 ;; it's implemented in mu4e, but not in the actions list for
686 ;; some reason.
687 (add-to-list 'mu4e-view-actions
688 '("browser view" . mu4e-action-view-in-browser) t)
689
690 (add-to-list 'mu4e-headers-actions
691 '("from this sender" . mu4e-action-msgs-by-this-sender) t)
692 (add-to-list 'mu4e-view-actions
693 '("from this sender" . mu4e-action-msgs-by-this-sender) t)
694 ;; normally, you would add to this, but we want to
695 ;; modify unread messages. the first 4 are defined by default.
696 (setq mu4e-bookmarks
697 `( ,(make-mu4e-bookmark
698 :name "Unread messages"
699 ;; old less restrictive unread, for adapting in the future:
700 ;; flag:unread AND NOT flag:trashed AND NOT maildir:/Junk AND NOT maildir:/fwfw AND NOT maildir:/log
701 :query "flag:unread maildir:/INBOX"
702 :key ?u)
703 ,(make-mu4e-bookmark
704 :name "Today's messages"
705 :query "date:today..now"
706 :key ?t)
707 ,(make-mu4e-bookmark
708 :name "Last 7 days"
709 :query "date:7d..now"
710 :key ?w)
711 ,(make-mu4e-bookmark
712 :name "Messages with images"
713 :query "mime:image/*"
714 :key ?p))
715 )
716 )
717
718 (eval-after-load "mu4e" '(my-mu4e-init))
719
720 (setq
721 ;; message mode prompted me on first message.
722 ;; a function which describes options then sets this
723 ;; the other options were to use smtp directly or pass to another mail client
724 ;; here we use the standard sendmail interface. This applies for gnus too.
725 send-mail-function (quote sendmail-send-it)
726 ;; https://github.com/djcb/mu/issues/1025
727 mail-user-agent 'mu4e-user-agent
728 ;; common to gnus. default sendmail-query-once asks us, then sets this via customize.
729 send-mail-function (quote sendmail-send-it)
730 ;; use the standard imap folders
731 mu4e-sent-folder "/Sent"
732 mu4e-drafts-folder "/Drafts"
733 mu4e-trash-folder "/Trash"
734 ;; reindex new mail this often in seconds
735 ;; show addresses instead of just names
736 mu4e-view-show-addresses t
737 mu4e-use-fancy-chars t
738 mu4e-confirm-quit nil
739 mu4e-headers-leave-behavior 'apply ;; dont ask, do whatever was marked
740 ;; default 500.
741 mu4e-headers-results-limit 1000
742 ;; tell exim to use from: as envelope from.
743 ;; exim's default is use outgoing_msg_localpart@hostname.
744 mail-specify-envelope-from t
745
746 ;; looking up the list of maildirs when doing jo from summary
747 ;; can take a few seconds if we have a ton of messages.
748 ;; Only take that time for the first lookup.
749 ;; if we add a new maildir, just restart mu4e for it to be in that list.
750 mu4e-cache-maildir-list t
751 ;; default is 8, way too small for my big monitors
752 mu4e-headers-visible-lines 50
753 message-sendmail-envelope-from 'header
754 ;; trying this out
755 ;;mu4e-view-use-gnus t
756 ;; had problems where mu4e and gnus would hang verifying signatures, gnus man
757 ;; said this should help, but it didnt work. they still got verified.
758 ;; mm-verify-option 'never
759 )
760
761 ;; fucks up reading unread bookmark. when that is fixed, enable it
762 ;; (setq mu4e-update-interval 60)
763
764
765 ;; this file includes setting up my email addresses, which are not public,
766 ;; including
767 ;; mu4e-user-mail-address-list
768 ;; and a function
769 ;; inspired by mu4e info manual, search for mu4e-compose-pre-hook.
770 (when (file-exists-p "/p/c/mymu4e.el")
771 (load "/p/c/mymu4e.el"))
772
773 (defun my-decrypt ()
774 ;; use for decrypting in mu4e
775 (interactive)
776 (beginning-of-buffer)
777 (when (search-forward "-----BEGIN PGP MESSAGE-----" nil t)
778 (read-only-mode 0)
779 (let ((start (match-beginning 0))
780 (end (search-forward "-----END PGP MESSAGE-----" nil t)))
781 (shell-command-on-region start end "gpg2 -dq" nil t shell-command-default-error-buffer t)
782 )))
783 (add-hook 'mu4e-view-mode-hook 'my-decrypt)
784
785 (defun iank-set-from-name (regexes)
786 "If we find an address matching regex, then set that address as the to,
787 and whatever was used"
788 (when mu4e-compose-parent-message
789 (let ((found nil))
790 (while (and regexes (not found))
791 (setq re (car regexes)
792 regexes (cdr regexes)
793 found (mu4e-message-contact-field-matches
794 mu4e-compose-parent-message :to re)))
795 (when found
796 (setq user-full-name (car found))
797 ;; we get an error unless we do this. that is a bug. I could
798 ;; send a patch... also a bug: setting message-from-style nil
799 ;; doesnt work in mu4e unless user-full-name is also nil.
800 (unless user-full-name
801 (setq message-from-style nil))
802 (setq user-mail-address (cdr found)
803 mail-signature nil))
804 found)))
805 (defun iank-set-from (regexes)
806 "If we find an address matching regex, then set that address as the to,
807 and Ian Kelling as the name"
808 (when mu4e-compose-parent-message
809 (let ((found nil))
810 (while (and regexes (not found))
811 (setq re (car regexes)
812 sig (cadr regexes)
813 regexes (cddr regexes)
814 found (cdr (mu4e-message-contact-field-matches
815 mu4e-compose-parent-message :to re))))
816 (when found (setq user-mail-address found
817 user-full-name "Ian Kelling"))
818 found)))
819
820
821 (defun mu-exit-wait ()
822 (interactive)
823 ;; taken from the mu source
824 (let* ((buf (get-buffer mu4e~proc-name))
825 (proc (and (buffer-live-p buf) (get-buffer-process buf))))
826 (mu4e-quit)
827 ;; without sleep, we get database locked by another process error when hitting u
828 ;; if another mu was running.
829 (if proc (sleep-for 0 1000))))
830
831 (defun fsf-mu4e ()
832 (interactive)
833 (my-mu4e-commmon)
834 (setq
835 user-mail-address "iank@fsf.org"
836 iank-user-mail-address user-mail-address
837 ;; WARNING: be careful editing this, there needs to be a space after --, and my editor
838 ;; and git will automatically remove it unless i manually disable it.
839 mail-signature fsf-sig
840 ) ;; end setq
841 (add-hook 'mu4e-compose-pre-hook 'my-mu4e-to)
842 (mu4e))
843
844
845
846
847 (defun mu4e-action-msgs-by-this-sender (msg)
848 "In header view, view messages by the sender of the message under point."
849 (let ((from (mu4e-message-field msg :from)))
850 (unless from
851 (mu4e-error "No from header for this message"))
852 ;; from is structured like: (("Anacron" . "root@x2.lan"))
853 (mu4e-headers-search (concat "f:" (cdar from)))))
854
855
856
857 ;;; elisp settings
858 ;; when manually evaluating lisp, go into debugger on error
859 (setq eval-expression-debug-on-error t)
860
861
862 (eval-after-load "python-mode"
863 '(progn
864 (define-key python-mode-map (kbd "C-j") nil)))
865
866 ;;; isearch
867 (setq
868 isearch-allow-scroll t
869 search-ring-update t) ;; dont start an edit when going to previous search
870
871 (defun isearch-yank-regexp (regexp)
872 "Pull REGEXP into search regexp."
873 (let ((isearch-regexp nil)) ;; Dynamic binding of global.
874 (isearch-yank-string regexp))
875 (isearch-search-and-update))
876
877 (defun isearch-yank-symbol (&optional partialp backward)
878 "Put symbol at current point into search string.
879
880 If PARTIALP is non-nil, find all partial matches."
881 (interactive "P")
882
883 (let (from to bound sym)
884 (setq sym
885 ; this block taken directly from find-tag-default
886 ; we couldn't use the function because we need the internal from and to values
887 (when (or (progn
888 ;; Look at text around `point'.
889 (save-excursion
890 (skip-syntax-backward "w_") (setq from (point)))
891 (save-excursion
892 (skip-syntax-forward "w_") (setq to (point)))
893 (> to from))
894 ;; Look between `line-beginning-position' and `point'.
895 (save-excursion
896 (and (setq bound (line-beginning-position))
897 (skip-syntax-backward "^w_" bound)
898 (> (setq to (point)) bound)
899 (skip-syntax-backward "w_")
900 (setq from (point))))
901 ;; Look between `point' and `line-end-position'.
902 (save-excursion
903 (and (setq bound (line-end-position))
904 (skip-syntax-forward "^w_" bound)
905 (< (setq from (point)) bound)
906 (skip-syntax-forward "w_")
907 (setq to (point)))))
908 (buffer-substring-no-properties from to)))
909 (cond ((null sym)
910 (message "No symbol at point"))
911 ((null backward)
912 (goto-char (1+ from)))
913 (t
914 (goto-char (1- to))))
915 (isearch-search)
916 (if partialp
917 (isearch-yank-string sym)
918 (isearch-yank-regexp
919 (concat "\\_<" (regexp-quote sym) "\\_>")))))
920
921 (defun isearch-current-symbol (&optional partialp)
922 "Incremental search forward with symbol under point.
923
924 Prefixed with \\[universal-argument] will find all partial
925 matches."
926 (interactive "P")
927 (let ((start (point)))
928 (isearch-forward-regexp nil 1)
929 (isearch-yank-symbol partialp)))
930 ;; todo, make this
931
932 (defun isearch-backward-current-symbol (&optional partialp)
933 "Incremental search backward with symbol under point.
934
935 Prefixed with \\[universal-argument] will find all partial
936 matches."
937 (interactive "P")
938 (let ((start (point)))
939 (isearch-backward-regexp nil 1)
940 (isearch-yank-symbol partialp)))
941
942
943 ;; automatically wrap to the top of the buffer when isearch fails
944 (defadvice isearch-search (after isearch-no-fail activate)
945 (unless isearch-success
946 (ad-disable-advice 'isearch-search 'after 'isearch-no-fail)
947 (ad-activate 'isearch-search)
948 (isearch-repeat (if isearch-forward 'forward))
949 (ad-enable-advice 'isearch-search 'after 'isearch-no-fail)
950 (ad-activate 'isearch-search)))
951
952 ;; Activate occur easily inside isearch
953 (define-key isearch-mode-map (kbd "C-o")
954 (lambda () (interactive)
955 (let ((case-fold-search isearch-case-fold-search))
956 (occur (if isearch-regexp
957 isearch-string
958 (regexp-quote isearch-string))))))
959 ;;; lisp / elisp mode setings
960
961 (add-hook 'emacs-lisp-mode-hook 'starter-kit-remove-elc-on-save)
962 (defun starter-kit-remove-elc-on-save ()
963 "If you're saving an elisp file, likely the .elc is no longer valid."
964 (make-local-variable 'after-save-hook)
965 (add-hook 'after-save-hook
966 (lambda ()
967 (if (file-exists-p (concat buffer-file-name "c"))
968 (delete-file (concat buffer-file-name "c"))))))
969
970
971 (defun emacs-lisp-mode-defaults ()
972 ;; checkdoc has an annoying feature that wants a header and footer
973 ;; in every elisp buffer as if they all were packages
974 ;; todo, see if there is a way
975 ;; to make checkdoc usable instead of just disabling it as I do here
976 (if (boundp 'flycheck-checkers)
977 (setq flycheck-checkers (remove 'emacs-lisp-checkdoc flycheck-checkers)))
978 (eldoc-mode 1))
979 (add-hook 'emacs-lisp-mode-hook 'emacs-lisp-mode-defaults)
980
981 (define-key lisp-mode-map (kbd "<M-up>") 'backward-up-list)
982 (define-key lisp-mode-map (kbd "<M-down>") 'down-list)
983 (define-key emacs-lisp-mode-map (kbd "<M-up>") 'backward-up-list)
984 (define-key emacs-lisp-mode-map (kbd "<M-down>") 'down-list)
985 (define-key emacs-lisp-mode-map (kbd "<M-escape>") 'find-function-at-point)
986
987 ;; interactive modes don't need whitespace checks
988 (defun interactive-lisp-coding-defaults ()
989 (whitespace-mode -1))
990 (setq prelude-interactive-lisp-coding-hook 'prelude-interactive-lisp-coding-defaults)
991
992
993 ;; ielm is an interactive Emacs Lisp shell
994 (defun ielm-mode-defaults ()
995 (run-hooks 'prelude-interactive-lisp-coding-hook)
996 (turn-on-eldoc-mode))
997 (add-hook 'ielm-mode-hook 'ielm-mode-defaults)
998
999 ;;; modes with little configuration needed
1000
1001 (setq outline-minor-mode-prefix "\ 3\ 1"
1002 css-indent-offset 2
1003 ;; auto indent shell script comments
1004 sh-indent-comment t
1005 sh-here-document-word "'EOF'"
1006 tramp-default-method "ssh"
1007 ;; ediff-buffers is the main command to use
1008 ;; don't start another frame for the control panel
1009 ;; unfortunately, this doesn't allow me to use 2 frames for the diff buffers
1010 ;; so disable this temporarily with the next line if you want that
1011 ;; sometime I should setup 2 functions to explicitly do each type
1012 ediff-window-setup-function 'ediff-setup-windows-plain
1013 ;;(setq ediff-window-setup-function 'ediff-setup-windows-default)
1014 ;; do side by side diffs
1015 ediff-split-window-function 'split-window-horizontally
1016 ;; ediff things I tried which didn't work, which intuitively I think should
1017 ;; work better: I can open the second diff buffer in a new frame, and
1018 ;; close it's window in the first frame after starting ediff, but when I
1019 ;; hit n to go to the next diff, it restores the window in the first
1020 ;; frame. Another thing I tried is to open 2 new frames and set them up
1021 ;; as I want. However, if I try to open the *Ediff Control Panel* buffer
1022 ;; in a different window from its original one, my mouse jumps to one of
1023 ;; the diff frames, or if that isn't visible, the buffer just hangs
1024 ;; until I select the original ediff control panel window. This seems
1025 ;; like a bug to me. I am using a very recent development version of
1026 ;; emacs.
1027
1028 )
1029
1030 ;; disabled temporarily. todo, look into it
1031 ;;(add-hook 'outline-minor-mode-hook 'outshine-mode)
1032
1033
1034 (when (file-exists-p "/a/h/iank-mod.el")
1035 (load-file "/a/h/iank-mod.el"))
1036
1037 ;; from when i was running my own patches
1038 ;;(add-to-list 'load-path "/a/opt/ws-butler")
1039
1040 (require 'ws-butler)
1041 ;; todo: I think this is broken, it keeps collapsing the last line
1042 ;; for empty messages.
1043
1044 ;; the main problem is when it deletes the blank line at the end
1045 ;; of a message with an empty body. but I might also
1046 ;; be pasting whitespace significant things in here, so
1047 ;; just don't do anything.
1048 ;; todo: propose this upstream
1049 (add-to-list 'ws-butler-global-exempt-modes 'message-mode)
1050
1051 (ws-butler-global-mode)
1052
1053 ;; disabled because i dont edit nginx files enough
1054 ;; to have this loaded at startup
1055 ;;(use-package nginx-mode)
1056 ;;The mode should automatically activate for files called nginx.conf and files under /etc/nginx - if not, you can add something like this to your init file:
1057 ;;(add-to-list 'auto-mode-alist '("/etc/nginx/sites-available/.*" . nginx-mode))
1058
1059 ;; todo, put this on a hook with prog mode
1060 ;;(highlight-indentation-mode 1)
1061
1062 (add-hook 'auto-revert-tail-mode-hook
1063 (lambda ()
1064 (when (string=
1065 buffer-file-name
1066 "/var/log/cloudman/development/cm-service.log")
1067 (setq-local prev-auto-revert-max 0)
1068 ;; set buffer-local hook
1069 (add-hook 'after-revert-hook 'tail-colorize nil t))))
1070 (defun tail-colorize ()
1071 (ansi-color-apply-on-region prev-auto-revert-max (point-max))
1072 (setq-local prev-auto-revert-max (point-max)))
1073
1074
1075 ;; delete active selection with self-insert commands
1076 (delete-selection-mode t)
1077
1078 ;; Transparently open compressed files
1079 (auto-compression-mode t)
1080
1081 ;; dot mode, repeats last action
1082 (require 'dot-mode)
1083 (add-hook 'find-file-hooks 'dot-mode-on)
1084
1085 ;; clean up obsolete buffers automatically at midnight
1086 (require 'midnight)
1087
1088 ;; saner regex syntax
1089 (require 're-builder)
1090 (setq reb-re-syntax 'string)
1091
1092
1093 ;; show the name of the current function definition in the modeline
1094 (setq which-func-modes t)
1095 (which-function-mode 1)
1096
1097 ;; enable winner-mode to manage window configurations
1098 (winner-mode +1)
1099
1100 ;; meaningful names for buffers with the same name
1101 (require 'uniquify)
1102 (setq uniquify-buffer-name-style 'forward
1103 uniquify-separator "/"
1104 ;; for sdx work. until I figure out a better way.
1105 ;; maybe something like projectile can do it,
1106 ;; or hacking around the status bar
1107 uniquify-min-dir-content 2
1108 uniquify-after-kill-buffer-p t ; rename after killing uniquified
1109 uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers
1110
1111
1112 ;; makefiles require tabs
1113 ;; todo: find a makefile indent function that works,
1114 ;; best I could find is this one which means don't indent at all
1115 ;;
1116 (add-hook 'makefile-mode-hook
1117 (lambda ()
1118 (setq indent-tabs-mode t)
1119 (setq indent-line-function (lambda () 'no-indent))))
1120
1121
1122 ;; todo, turn on auto-fill just for txt files
1123 ;;(add-hook 'text-mode-hook 'turn-on-auto-fill)
1124 (add-hook 'text-mode-hook 'turn-on-flyspell)
1125
1126 ;; random extra highlights
1127 (require 'volatile-highlights)
1128 (volatile-highlights-mode t)
1129
1130
1131 ;; make help buffers smaller when it makes sense
1132 (temp-buffer-resize-mode 1)
1133
1134
1135 (defun my-info-init()
1136 (require 'info+)
1137 ;; based on suggestions in info+.el, I also installed misc-fns, strings, and thingatpt+
1138 ;; remove some bad keybinds from info+
1139 (define-key Info-mode-map [mouse-4] nil)
1140 (define-key Info-mode-map [mouse-5] nil))
1141
1142 (add-hook 'info-mode-hook 'my-info-init)
1143
1144
1145 ;;; misc general settings
1146
1147
1148 ;; I tried to look for a function that would set this that is
1149 ;; not part of the emacs interactive customize stuff, but didn't see one
1150 ;; in the faces documentation.
1151
1152 (custom-set-faces
1153 ;; custom-set-faces was added by Custom.
1154 ;; If you edit it by hand, you could mess it up, so be careful.
1155 ;; Your init file should contain only one such instance.
1156 ;; If there is more than one, they won't work right.
1157 '(header-line ((t (:background "default" :foreground "default" :overline nil :underline nil))))
1158 '(region ((t nil))))
1159
1160
1161 ;; from tramp manual, use the same ssh controlmaster. I was having problems with
1162 ;; tramp prompting me for a username and pass.
1163 (customize-set-variable 'tramp-use-ssh-controlmaster-options nil)
1164
1165 (setq
1166 auto-revert-interval 2
1167 ;; fix eof end of file newline
1168 mode-require-final-newline t
1169 require-final-newline t
1170 auto-revert-verbose nil
1171 auto-revert-remote-files t
1172 ;; save bookmarks whenever they are changed instead of just when emacs quits
1173 bookmark-save-flag 1
1174 ;; increase bookmark context size for better functionality
1175 bookmark-search-size 2000
1176 ;; https://www.emacswiki.org/emacs/FillParagraph
1177 ;; make list items start paragraphs.
1178 paragraph-start "\f\\|[ \t]*$\\|[ \t]*[-+*] "
1179 sh-basic-offset 2
1180 vc-follow-symlinks t
1181 )
1182
1183 (ivy-mode 1)
1184 (add-hook 'text-mode-hook (lambda () (auto-fill-mode t)))
1185 (setq counsel-find-file-at-point t)
1186
1187 (eval-after-load "ido"
1188 ;; easier to read with just spaces as separator
1189 (quote (setf (nth 2 ido-decorations) " ")))
1190
1191 ;; Seed the random-number generator
1192 (random t)
1193
1194 ;; easier to remember than keybinds
1195 (defalias 'scrypt 'mml-secure-message-encrypt-pgpmime)
1196 (defalias 'sign 'mml-secure-message-sign-pgpmime)
1197 ;; otherwise we get error on sending:
1198 ;; mml-secure-epg-sign: Couldn’t find any signer names; try setting `mml-secure-smime-sign-with-sender'.
1199 ;; i dunno why sign+encrypt doesnt cause this, seems kinda dumb,
1200 ;;
1201 (setq mml-secure-openpgp-sign-with-sender t)
1202 ;; i dun use smime, the smime signing fails complaining it doesnt have
1203 ;; my key. todo: learn about smime
1204 (setq mml-secure-smime-sign-with-sender t)
1205 (defun encrypt ()
1206 (interactive)
1207 (mml-secure-message-encrypt-pgpmime 'dontsign))
1208
1209 ;; don't highlight the region.
1210 (set-face-background 'region nil)
1211
1212 ;; this fixes save error for python example code
1213 (define-coding-system-alias 'UTF-8 'utf-8)
1214
1215 ;; i don't use frame titles, but if I ever do
1216 ;; this starter kit setting is probably good
1217 (if window-system (setq frame-title-format '(buffer-file-name "%f" ("%b"))))
1218
1219
1220 ;;(prefer-coding-system 'utf-8-unix)
1221
1222 ;; remove ugly 3d box feature
1223 (set-face-attribute 'mode-line nil :box nil)
1224
1225 (add-to-list 'default-frame-alist
1226 '(font . "DejaVu Sans Mono-11"))
1227 ; the default will jump 2 sizes.
1228 (setq text-scale-mode-step 1.1)
1229 (setq font-lock-maximum-decoration t
1230 inhibit-startup-message t
1231 transient-mark-mode t
1232 delete-by-moving-to-trash t
1233 shift-select-mode nil
1234 truncate-partial-width-windows nil
1235 uniquify-buffer-name-style 'forward
1236 oddmuse-directory "~/.emacs.d/oddmuse"
1237 echo-keystrokes 0.1
1238 mark-ring-max 160
1239 sort-fold-case t ; case insensitive line sorting
1240 global-mark-ring-max 1000
1241 ;; the visible bell seems to lag the ui
1242 ;;visible-bell t
1243 ;; turn off audible bell
1244 ;; https://www.emacswiki.org/emacs/AlarmBell
1245 ring-bell-function 'ignore
1246 case-replace nil
1247 revert-without-query '(".*")
1248 ;; don't pause display code on input.
1249 ;; smoother display performance at slight cost of input performance
1250 redisplay-dont-pause t
1251 font-lock-maximum-decoration t) ; probably default and not necesary
1252
1253
1254 (setq-default indent-tabs-mode nil ;; don't use tabs to indent
1255 cursor-type 'box
1256 fill-column 72
1257
1258 ;; wrap at word boundaries instead of mid-word
1259 word-wrap t
1260 imenu-auto-rescan t
1261 indicate-empty-lines t) ; mark end of buffer
1262
1263 (require 'smooth-scroll)
1264 ;; long gnus summary buffers lags too much with this,
1265 ;; but I like it enough to leave it enabled by default
1266 ;; and crank up the step size to be faster
1267 ;; and it doesn't have a way to enable it only for certain modes etc.
1268 ;; todo sometime, make it work for certain modes only
1269 (smooth-scroll-mode t)
1270 ;; its too slow with the default of 2
1271 (setq smooth-scroll/vscroll-step-size 6)
1272 ;; sublimity doesn't work as good going fast by default
1273 ;; smooth-scrolling.el, does not do smooth scrolling. its about cursor location
1274
1275
1276 (blink-cursor-mode '(-4))
1277 (menu-bar-mode -1)
1278 (tool-bar-mode -1)
1279
1280
1281 ;; enable various commands
1282 (put 'narrow-to-region 'disabled nil)
1283 (put 'narrow-to-page 'disabled nil)
1284 (put 'narrow-to-defun 'disabled nil)
1285 (put 'upcase-region 'disabled nil)
1286 (put 'downcase-region 'disabled nil)
1287 (put 'scroll-left 'disabled nil)
1288 ;; these from graphene, haven't read about them yet
1289 (put 'ido-complete 'disabled nil)
1290 (put 'ido-exit-minibuffer 'disabled nil)
1291 (put 'dired-find-alternate-file 'disabled nil)
1292 (put 'autopair-newline 'disabled nil)
1293
1294
1295
1296 ;;disable and minimize various prompts/messages
1297 (fset 'yes-or-no-p 'y-or-n-p)
1298 (setq confirm-nonexistent-file-or-buffer nil
1299 inhibit-startup-message t
1300 inhibit-startup-echo-area-message t
1301 inhibit-startup-screen t
1302 kill-buffer-query-functions (remq 'process-kill-buffer-query-function
1303 kill-buffer-query-functions))
1304
1305
1306 ;; exit without bothering me
1307 ;; http://stackoverflow.com/questions/2706527/make-emacs-stop-asking-active-processes-exist-kill-them-and-exit-anyway/2708042#2708042
1308 (add-hook 'comint-exec-hook
1309 (lambda () (set-process-query-on-exit-flag (get-buffer-process (current-buffer)) nil)))
1310 ;; based on save-buffers-kill-emacs help string, don't ask about clients when exiting
1311 ;; apparently this would need to be in some later hook. dunno where is best, but this works
1312 (defadvice save-buffers-kill-emacs (before no-client-prompt-advice activate)
1313 (setq kill-emacs-query-functions (delq 'server-kill-emacs-query-function kill-emacs-query-functions)))
1314
1315
1316
1317 ;; (custom-set-faces
1318 ;; ;; setting header-line-format to " " as a hack for a top margin the oly thning I could find to do a top margin
1319 ;; '(header-line ((t (:background "default" :foreground "default" :overline nil :underline nil))))
1320 ;; ;; don't highlight the region
1321 ;; '(region ((t nil))))
1322 (setq-default header-line-format " ")
1323
1324
1325 (setq initial-scratch-message nil)
1326
1327
1328 ;; vertical margin background.
1329 ;; google turned up: http://lists.gnu.org/archive/html/help-gnu-emacs/2014-03/msg00544.html
1330 ;; the xresource doesn't work for me, probably an xmonad thing.
1331
1332 ;; figured out I needed to customize the header line face. To find the face, M-x list-faces-display or just google / search
1333 ;; info,
1334 ;; then M-x customize-face
1335 ;; header-line
1336 ;; unchecked some stuff so that it inherits from default.
1337
1338 ;;; misc function definitions
1339
1340
1341 (defun fill-buffer ()
1342 (interactive)
1343 (save-mark-and-excursion
1344 (beginning-of-buffer)
1345 (while (= (forward-line) 0)
1346 (fill-paragraph))))
1347
1348
1349 (defun next-backup-dir ()
1350 "In a directory listing from rsync -n,
1351 Go to the next directory based on where the cursor is."
1352 (interactive)
1353 (let* ((start-col (current-column))
1354 (end-col (progn (skip-chars-forward "^/\n") (current-column)))
1355 (dir (progn
1356 (beginning-of-line 1)
1357 (buffer-substring-no-properties (point) (+ (point) end-col)))))
1358 (message dir)
1359 (forward-line 1)
1360 (while (and (not (eobp))
1361 (string= dir (buffer-substring-no-properties (point) (+ (point) end-col))))
1362 (forward-line 1))
1363 (forward-char-same-line start-col)))
1364 ;; copy paste this for fast keybind
1365 ;;(local-set-key (kbd "<kp-enter>"))
1366
1367
1368 (defun goto-buffer-or-find-file (file-name)
1369 "If buffer is with FILE-NAME exists, go to it, else open the file using full path."
1370 (interactive)
1371 (let ((b (get-buffer (file-name-nondirectory file-name))))
1372 (if b
1373 (switch-to-buffer b)
1374 (find-file file-name))))
1375
1376
1377
1378
1379 ;; todo, i think this is broken. perhaps the last goto-char is not accounting for buffer or something
1380 (defun unpop-global-mark ()
1381 "Unpop off global mark ring. Does nothing if mark ring is empty."
1382 (interactive)
1383 (when global-mark-ring
1384 (setq global-mark-ring (cons (copy-marker (mark-marker)) global-mark-ring))
1385 (let ((lm (car (last global-mark-ring))))
1386 (set-marker (mark-marker) (marker-position lm) (marker-buffer lm)))
1387 (when (null (mark t)) (ding))
1388 (setq global-mark-ring (nbutlast global-mark-ring))
1389 (goto-char (marker-position (mark-marker)))))
1390
1391 (defun indent-buffer ()
1392 "Indents the entire buffer."
1393 (interactive)
1394 (cond ((derived-mode-p 'org-mode)
1395 (org-indent-region (point-min) (point-max)))
1396 ((derived-mode-p 'python-mode)
1397 (py-autopep8))
1398 (t
1399 (indent-region (point-min) (point-max)))))
1400
1401
1402 ;; TODO doesn't work with uniquify
1403 (defun rename-file-and-buffer ()
1404 "Renames current buffer and file it is visiting."
1405 (interactive)
1406 (let ((name (buffer-name))
1407 (filename (buffer-file-name)))
1408 (if (not (and filename (file-exists-p filename)))
1409 (message "Buffer '%s' is not visiting a file!" name)
1410 (let ((new-name (read-file-name "New name: " filename)))
1411 (cond ((get-buffer new-name)
1412 (message "A buffer named '%s' already exists!" new-name))
1413 (t
1414 (rename-file name new-name 1)
1415 (rename-buffer new-name)
1416 (set-visited-file-name new-name)
1417 (set-buffer-modified-p nil)))))))
1418
1419
1420
1421 (defun sudo-edit (&optional arg)
1422 (interactive "P")
1423 (if (or arg (not buffer-file-name))
1424 (find-file (concat "/sudo::" (ido-read-file-name "File: ")))
1425 (find-alternate-file (concat "/sudo::" buffer-file-name))))
1426
1427
1428
1429 (defun backward-symbol (arg)
1430 (interactive "p")
1431 (forward-symbol (- arg)))
1432
1433 ;;; mode line
1434 ;; make window title be the buffer name
1435 (setq frame-title-format "%b")
1436
1437 ;; -----------------------------
1438 ;; fixing up the mode line
1439 ;; modified from mastering emacs blog
1440 ;; ----------------------------
1441
1442 (defvar mode-line-cleaner-alist
1443 `((auto-complete-mode . "")
1444 (yas/minor-mode . "")
1445 (paredit-mode . "")
1446 (auto-fill-function . "")
1447 (eldoc-mode . "")
1448 (abbrev-mode . "")
1449 (flyspell-mode . "")
1450 (glasses-mode . "")
1451 (dot-mode . "")
1452 (yas-global-mode . "")
1453 (yas-minor-mode . "")
1454 (undo-tree-mode . "")
1455 (volatile-highlights-mode . "")
1456 (highlight-symbol-mode . "")
1457 ;; Major modes
1458 (lisp-interaction-mode . "λ")
1459 (hi-lock-mode . "")
1460 (python-mode . "Py")
1461 (emacs-lisp-mode . "EL")
1462 (nxhtml-mode . "nx"))
1463 "Alist for `clean-mode-line'.
1464
1465 When you add a new element to the alist, keep in mind that you
1466 must pass the correct minor/major mode symbol and a string you
1467 want to use in the modeline *in lieu of* the original.")
1468
1469
1470 (defun clean-mode-line ()
1471 (interactive)
1472 (loop for cleaner in mode-line-cleaner-alist
1473 do (let* ((mode (car cleaner))
1474 (mode-str (cdr cleaner))
1475 (old-mode-str (cdr (assq mode minor-mode-alist))))
1476 (when old-mode-str
1477 (setcar old-mode-str mode-str))
1478 ;; major mode
1479 (when (eq mode major-mode)
1480 (setq mode-name mode-str)))))
1481
1482 ; disabled
1483 ; (add-hook 'after-change-major-mode-hook 'clean-mode-line)
1484
1485
1486 ;; alias the new `flymake-report-status-slim' to
1487 ;; `flymake-report-status'
1488 (defalias 'flymake-report-status 'flymake-report-status-slim)
1489 (defun flymake-report-status-slim (e-w &optional status)
1490 "Show \"slim\" flymake status in mode line."
1491 (when e-w
1492 (setq flymake-mode-line-e-w e-w))
1493 (when status
1494 (setq flymake-mode-line-status status))
1495 (let* ((mode-line " Φ"))
1496 (when (> (length flymake-mode-line-e-w) 0)
1497 (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
1498 (setq mode-line (concat mode-line flymake-mode-line-status))
1499 (setq flymake-mode-line mode-line)
1500 (force-mode-line-update)))
1501
1502
1503 (defun my-after-change-major-mode-hook ()
1504 (setq mode-line-mule-info nil
1505 minor-mode-alist nil
1506 mode-line-position nil)) ; todo, make only flymake status show up
1507
1508 (add-hook 'after-change-major-mode-hook 'my-after-change-major-mode-hook)
1509
1510 ;;; mouse related
1511 ;;;; settings
1512 (setq focus-follows-mouse t
1513 mouse-autoselect-window t
1514 xterm-mouse-mode t)
1515 ;;;; move-mouse-to-point
1516 ;; todo, this is buggy with multiple windows open.
1517 (defun move-mouse-to-point ()
1518 (interactive)
1519 (let* ((pos (posn-col-row (posn-at-point)))
1520 (x (+ (car pos) 2)) ; no idea why this is off by 1-2
1521 (y (cdr pos)))
1522 (set-mouse-position (selected-frame) x y)))
1523
1524 ;;; org mode
1525
1526 ;; todo work on org-cycle-emulate-tab
1527
1528 ;; todo, this doesn't work for a non-standard keybind
1529 ;;(setq org-special-ctrl-k t)
1530
1531 ;; todo, generally fix org mode keys
1532 ;; todo, org-mark-element, unbdind from M-h, bind to mark defun key
1533
1534 ;(org-babel-do-load-languages
1535 ; 'org-babel-load-languages
1536 ; '((emacs-lisp . t)
1537 ; (sh . t)))
1538
1539
1540
1541 ;; make shell work like interactive bash shell
1542 (setq org-babel-default-header-args:sh
1543 '((:results . "output") (:shebang . "#!/bin/bash -l")))
1544
1545 ;; my patch to output stderr
1546 (setq org-babel-use-error-buffer nil)
1547
1548 ;
1549 ;; org-mode manual suggests these, but I haven't used them.
1550 ;;(global-set-key "\C-cl" 'org-store-link)
1551 ;;(global-set-key "\C-ca" 'org-agenda)
1552 ;; this got in the way of a haskell mode command
1553 ;;(global-set-key "\C-cb" 'org-iswitchb)
1554
1555
1556
1557 ;; org-src-tab-acts-natively t ; broken option. using next instead, todo fix
1558
1559 (setq org-src-fontify-natively t ; make babel blocks nice
1560 org-adapt-indentation nil
1561 org-src-preserve-indentation t
1562 ;; The most basic logging is to keep track of when a TODO item was finished.
1563 org-log-done 'time
1564 ;; use a drawer to keep the logs tidy
1565 org-log-into-drawer t
1566 org-extend-today-until 0
1567 org-startup-truncated nil
1568 org-clock-persist t
1569 org-use-sub-superscripts "{}"
1570 org-export-with-sub-superscripts nil
1571 org-clock-mode-line-total 'today
1572 ;; global STYLE property values for completion
1573 org-global-properties (quote (("STYLE_ALL" . "habit")))
1574 org-special-ctrl-a/e t ;; home and end work special in headlines
1575 org-completion-use-ido t
1576 org-catch-invisible-edits 'smart)
1577
1578 (setq
1579 org-default-notes-file "/a/t.org"
1580 org-directory "/p")
1581
1582 ;; modeilne populated from (org-clock-get-clocked-time)
1583 ;; which is populated from the var org-clock-total-time
1584 ;; which is populated by a function which starts from (org-clock-get-sum-start)
1585 ;;
1586
1587 (eval-after-load "org"
1588 '(org-clock-persistence-insinuate))
1589
1590 (defun time-to-org-day (time)
1591 (round (time-to-number-of-days
1592 (time-subtract time (list 0 (* 3600 org-extend-today-until) 0)))))
1593
1594 (defun my-org-confirm-babel-evaluate (lang body)
1595 (not (or (string= (buffer-file-name) "/a/t.org")
1596 )))
1597 (setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate)
1598
1599
1600 (defun org-time-stamp-with-time (arg)
1601 (interactive "P")
1602 ;; '(4) is the argument passed by universal prefix
1603 (org-time-stamp (if arg arg '(4)) t))
1604
1605 ;; based on http://stackoverflow.com/questions/3758139/variable-pitch-for-org-mode-fixed-pitch-for-tables
1606 ;; keywords: proportional font, monospace
1607
1608 (defun variable-pitch-on ()
1609 (variable-pitch-mode 1))
1610 (add-hook 'fundamental-mode-hook 'variable-pitch-on)
1611 (add-hook 'org-mode-hook 'variable-pitch-on)
1612 (add-hook 'text-mode-hook 'variable-pitch-on)
1613 (defun variable-pitch-off ()
1614 (variable-pitch-mode 0))
1615 (add-hook 'yaml-mode-hook 'variable-pitch-off)
1616
1617 (eval-after-load "org" '(my-org-face-init))
1618
1619 (defun my-org-face-init()
1620 (set-face-attribute 'org-table nil :family (face-attribute 'fixed-pitch :family))
1621 (set-face-attribute 'org-code nil :family (face-attribute 'fixed-pitch :family))
1622 (set-face-attribute 'org-formula nil :family (face-attribute 'fixed-pitch :family))
1623 (set-face-attribute 'org-link nil :family (face-attribute 'fixed-pitch :family))
1624 (set-face-attribute 'org-block nil :family (face-attribute 'fixed-pitch :family))
1625 (set-face-attribute 'org-date nil :family (face-attribute 'fixed-pitch :family))
1626 )
1627
1628 (defun remove-org-binds ()
1629 (define-key org-mode-map (kbd "<M-return>") nil)
1630 (define-key org-mode-map (kbd "C-'") nil)
1631 (define-key org-mode-map (kbd "C-y") nil)
1632 (define-key org-mode-map (kbd "<C-return>") nil)
1633 (define-key org-mode-map (kbd "<C-M-kp-enter>") nil)
1634 (define-key org-mode-map (kbd "C-,") nil)
1635 (define-key org-mode-map (kbd "C-M-m") nil)
1636 (define-key org-mode-map (kbd "C-k") nil)
1637 (define-key org-mode-map (kbd "C-j") nil)
1638 (define-key org-mode-map (kbd "C-M-i") nil)
1639 (define-key org-mode-map (kbd "C-M-t") nil)
1640 (define-key org-mode-map (kbd "M-a") 'nil)
1641 (define-key org-mode-map (kbd "C-a") nil)
1642 (define-key org-mode-map (kbd "M-e") nil)
1643 (define-key org-mode-map (kbd "C-e") nil)
1644 (define-key org-mode-map (kbd "C-3") nil)
1645 (define-key org-mode-map (kbd "<M-left>") nil)
1646 (define-key org-mode-map (kbd "<M-right>") nil)
1647 (define-key org-mode-map (kbd "<S-return>") nil)
1648 (define-key org-mode-map (kbd "<tab>") nil)
1649 (define-key org-mode-map (kbd "<C-S-down>") nil)
1650 (define-key org-mode-map (kbd "<C-S-up>") nil)
1651 (define-key org-mode-map (kbd "<S-down>") nil)
1652 (define-key org-mode-map (kbd "<S-up>") nil)
1653 (define-key org-mode-map "\t" nil))
1654 (add-hook 'org-mode-hook 'remove-org-binds)
1655
1656 ;;; prog-mode-defaults
1657
1658
1659 (defun prog-mode-defaults ()
1660 "Default coding hook, useful with any programming language."
1661 ;; so that I can do completion before the dialog pops up
1662 ;;(local-set-key (kbd "<tab>") 'auto-complete)
1663 (local-set-key (kbd "TAB") 'auto-complete)
1664 ;; todo, this is causing error message on loading file, prolly not working
1665 ;;(flycheck-mode +1)
1666 (setq ac-sources (delq 'ac-source-dictionary ac-sources))
1667 (highlight-symbol-mode)
1668 (make-local-variable 'column-number-mode)
1669 ;; this says do autofilling using newcomment.el. The "only" is a misnomer.
1670 (set (make-local-variable 'comment-auto-fill-only-comments) t)
1671 (column-number-mode t)
1672 ;; trying without
1673 ;; (turn-on-smartparens-mode)
1674
1675 ;; prettify lambdas
1676 (font-lock-add-keywords
1677 nil `(("(\\(lambda\\>\\)"
1678 (0 (progn (compose-region (match-beginning 1) (match-end 1)
1679 ,(make-char 'greek-iso8859-7 107))
1680 nil))))))
1681 (add-hook 'prog-mode-hook 'prog-mode-defaults)
1682
1683 ;; enable flyspell in prog mode. text mode is handled
1684 (add-hook 'prog-mode-hook 'flyspell-prog-mode)
1685
1686
1687 ;;; yank auto-indent
1688 ;; automatically indenting yanked text if in programming-modes
1689 (defvar yank-indent-modes
1690 '(LaTeX-mode TeX-mode)
1691 "Modes in which to indent regions that are yanked (or yank-popped).
1692 Only modes that don't derive from `prog-mode' should be listed here.")
1693
1694 (defvar yank-indent-blacklisted-modes
1695 '(python-mode slim-mode haml-mode)
1696 "Modes for which auto-indenting is suppressed.")
1697
1698 (defvar yank-advised-indent-threshold 2000
1699 "Threshold (# chars) over which indentation does not automatically occur.")
1700
1701 (defun yank-advised-indent-function (beg end)
1702 "Do indentation, as long as the region isn't too large."
1703 (if (<= (- end beg) yank-advised-indent-threshold)
1704 (indent-region beg end nil)))
1705
1706 (defadvice yank (after yank-indent activate)
1707 "If current mode is one of 'yank-indent-modes,
1708 indent yanked text (with prefix arg don't indent)."
1709 (if (and (not (ad-get-arg 0))
1710 (not (member major-mode yank-indent-blacklisted-modes))
1711 (or (derived-mode-p 'prog-mode)
1712 (member major-mode yank-indent-modes)))
1713 (let ((transient-mark-mode nil))
1714 (yank-advised-indent-function (region-beginning) (region-end)))))
1715
1716 (defadvice yank-pop (after yank-pop-indent activate)
1717 "If current mode is one of 'yank-indent-modes,
1718 indent yanked text (with prefix arg don't indent)."
1719 (if (and (not (ad-get-arg 0))
1720 (not (member major-mode yank-indent-blacklisted-modes))
1721 (or (derived-mode-p 'prog-mode)
1722 (member major-mode yank-indent-modes)))
1723 (let ((transient-mark-mode nil))
1724 (yank-advised-indent-function (region-beginning) (region-end)))))
1725
1726
1727 ;;; shell mode
1728
1729
1730 ;; # eval: (outline-minor-mode)
1731 ;; # outline-regexp: "\\( *\\)# [*]\\{1,8\\} "
1732
1733
1734 ;; avoid stupid git crap like "warning, terminal not fully functional"
1735 (setenv "PAGER" "cat")
1736 ;; don't store successive duplicates in comint command history
1737 (setq comint-input-ignoredups t)
1738
1739 (defun add-mode-line-dirtrack ()
1740 (add-to-list 'mode-line-buffer-identification
1741 '(:propertize (" " default-directory " ") face dired-directory)))
1742 (add-hook 'shell-mode-hook 'add-mode-line-dirtrack)
1743
1744
1745 ;; don't fully understand it, but it works.
1746 ;; http://www.emacswiki.org/emacs/ShellDirtrackByProcfs
1747 (defun track-shell-directory/procfs ()
1748 (shell-dirtrack-mode 0)
1749 (add-hook 'comint-preoutput-filter-functions
1750 (lambda (str)
1751 (prog1 str
1752 (when (string-match comint-prompt-regexp str)
1753 (cd (file-symlink-p
1754 (format "/proc/%s/cwd" (process-id
1755 (get-buffer-process
1756 (current-buffer)))))))))
1757 nil t))
1758 (setq comint-buffer-maximum-size 100000)
1759 (add-to-list 'comint-output-filter-functions 'comint-truncate-buffer)
1760 (defun new-shell ()
1761 (interactive)
1762 (shell (generate-new-buffer-name "*shell*")))
1763 ;;
1764 (defun shell-wrap (prefix)
1765 "wrap the shell function, automatically generate a new name for a prefix arg"
1766 (interactive "P")
1767 (if prefix
1768 (new-shell)
1769 (shell)))
1770
1771 (add-hook 'shell-mode-hook 'track-shell-directory/procfs)
1772 ;;; spell correction
1773 (setq
1774 ispell-program-name "hunspell"
1775 ispell-silently-savep t) ; don't prompt to save personal dictionary
1776
1777 (use-package rw-hunspell
1778 :defer t)
1779 ;; rw-hunspell sets up hunspell dictionary automagically.
1780
1781
1782 ;; Rant: Hunspell SHOULD be standard. its used by firefox and openoffice and
1783 ;; osx. In contrast, the first few words I added to aspell dictionary were
1784 ;; "emacs" "customizable" and "timestamp". Hunspell already has those,
1785 ;; thank god.
1786
1787 ;; ispell-personal-dictionary does not document where the hunspell
1788 ;; dictionary goes by default, but it is ~/.hunspell_en_US for me
1789
1790
1791 ;;; tex
1792 (setq-default TeX-PDF-mode t) ; use pdf
1793 ;; more sensible defaults based on info manual quickstart
1794 (setq TeX-auto-save t
1795 TeX-parse-self t
1796 ;; not documented, but looking at the source, I find this
1797 ;; stops me from being asked what command on every C-c-c
1798 ;; when doing a latex document.
1799 TeX-command-force "LaTeX"
1800 )
1801
1802 ;;; visible mark mode
1803
1804 ;; since it is not easy to change the mark overlay priority, I change this one.
1805 (setq show-paren-priority 999)
1806
1807 (defface visible-mark-active
1808 '((((type tty) (class mono)))
1809 (t (:background "magenta"))) "")
1810
1811 (defface mouse-cursor-face
1812 '((((type tty) (class mono)))
1813 (t (:background "DeepPink1"))) "")
1814
1815
1816 (require 'visible-mark)
1817
1818 (setq
1819 visible-mark-faces '(visible-mark-face1 visible-mark-face2)
1820 visible-mark-forward-faces '(visible-mark-forward-face1)
1821 ;; highlight the last 2 marks
1822 visible-mark-max 2
1823 ;; highlight 1 forward mark
1824 visible-mark-forward-max 1)
1825 ;; globally activate visible-mark-mode
1826 (global-visible-mark-mode +1)
1827
1828
1829 ;; todo, it doesn't seem to be exposed in elisp, but it would be nice
1830 ;; if I could define overlay faces to use inverse foreground color
1831
1832
1833 ;;; znc/erc
1834 (defun chirp()
1835 (interactive)
1836 (setq vol 50)
1837 (when (string= (system-name) "kd") (setq vol 80))
1838 ;; speed is there so i can adjust and make it go slow so it plays long enough to adjust in pavucontrol
1839 (start-process-shell-command "ignoreme" nil (format "mpv --speed=1 --no-terminal --vo=null --volume=%d /a/bin/data/bird.mp3" vol)))
1840 ;; from https://www.emacswiki.org/emacs/ErcSound
1841 (defun chirp-slow()
1842 (interactive)
1843 (setq vol 50)
1844 (when (string= (system-name) "tp") (setq vol 80))
1845 ;; speed is there so i can adjust and make it go slow so it plays long enough to adjust in pavucontrol
1846 (start-process-shell-command "ignoreme" nil (format "mpv --speed=.2 --no-terminal --vo=null --volume=%d /a/bin/data/bird.mp3" vol)))
1847
1848 (defun erc-my-privmsg-sound (proc parsed)
1849 (let* ((tgt (car (erc-response.command-args parsed)))
1850 (privp (erc-current-nick-p tgt)))
1851 (and
1852 privp (chirp)
1853 ;; We must return nil. See help for `erc-server-PRIVMSG-functions'
1854 nil)))
1855
1856 (defun erc-sound-if-not-server (match-type nickuserhost msg)
1857 (unless (string-match "Server:[0-9]+" nickuserhost)
1858 (chirp)))
1859
1860 (use-package erc
1861 :defer t
1862 :init
1863 (setq erc-fill-prefix ""
1864 ;; consider invisible frames to be unseen. seems like an obvious default
1865 erc-track-visibility 'visible
1866 ;; switch to buffer where i've been mentioned, etc instead of oldest
1867 erc-track-switch-direction 'importance
1868 ;; defaults minus fill. todo: modify the list instead of specifying it explicitly in case the defaults change
1869 erc-modules
1870 '(autojoin button completion irccontrols list match menu move-to-prompt netsplit networks noncommands readonly ring stamp track)
1871 ) ; end setq
1872 :config
1873 (add-hook 'erc-server-PRIVMSG-functions
1874 'erc-my-privmsg-sound)
1875 (add-hook 'erc-text-matched-hook 'erc-sound-if-not-server)
1876 (erc-track-mode 1))
1877 ;;; named commands
1878 (defun rm-file-and-buffer ()
1879 "Removes file connected to current buffer and kills buffer."
1880 (interactive)
1881 (let ((filename (buffer-file-name))
1882 (buffer (current-buffer))
1883 (name (buffer-name)))
1884 (if (not (and filename (file-exists-p filename)))
1885 (error "Buffer '%s' is not visiting a file!" name)
1886 (delete-file filename)
1887 (kill-buffer buffer)
1888 (message "File '%s' successfully removed" filename))))
1889
1890 ;;; persistent registers
1891 ;; This needs to be at the end, because I visit a file, thus setting a
1892 ;; mode, and the mode hook needs to be setup before that.
1893
1894 ;; I'm using persistent registers instead of bookmarks. I dun use them
1895 ;; much, so the added hassle of having to set it within this file is
1896 ;; worth the benefit of only having one concept in my mind.
1897 (dolist
1898 (r `(
1899 (?i (file . ,"~/.emacs.d/init.el"))
1900 (?o (file . ,"/a/work.org"))
1901 (?t (file . ,"/a/t.org"))
1902 (?s (file . ,"/usr/share/doc/exim4-base/spec.txt.gz"))
1903 (?w (file . ,"/p/w.org"))
1904 (?k (file . ,"/a/bin/ds/Arduino/Model01-Firmware/Model01-Firmware.ino"))
1905 (?x (file . ,"/a/x.txt"))
1906 ))
1907 (set-register (car r) (cadr r)))
1908
1909 (setq undo-outer-limit 100000000 ; per undo command
1910 undo-limit 500000000 ; undo history limit
1911 undo-strong-limit 600000000) ; undo history limit plus some extra
1912
1913
1914 ;;; undo tree mode
1915
1916 ;; note, this has weird errors when it was before recentf-mode
1917
1918 (use-package undo-tree
1919 :config
1920 ;; more resilient undo-tree-history if we have its location set up front.
1921 (setq undo-tree-history-directory-alist '(("." . "~/.undo-tree-history"))
1922 undo-outer-limit 100000000 ; per undo command
1923 undo-limit 500000000 ; undo history limit
1924 undo-strong-limit 600000000 ; undo history limit plus some extra
1925 ;; Undo in region just happens accidentally, and throws me off
1926 undo-tree-enable-undo-in-region nil)
1927 ;; disabled due to bug, something like unknown entry in undo tree canary
1928 ;; (setq undo-tree-auto-save-history t)
1929
1930 ;; todo, send patch undo-tree-visualize should scroll with the scroll key, instead of just pgup pgdn (aka next/prior)
1931 (global-undo-tree-mode)
1932 ;; simple way to fix that enable undo-tree starts out disabled in org-mode
1933 (defun undo-tree-overridden-undo-bindings-p() nil))
1934
1935 ;;; keybinds
1936
1937 ;;;; misc
1938
1939 (define-prefix-command 'terminal-key-map)
1940 (global-set-key (kbd "\e[") 'terminal-key-map)
1941
1942 (global-set-key (kbd "C-x C-b") 'ibuffer)
1943
1944
1945 ;; isearch-occur
1946 ;; Activate occur easily inside isearch
1947 ;; from starter-kit
1948
1949 (define-key isearch-mode-map (kbd "C-o")
1950 (lambda () (interactive)
1951 (let ((case-fold-search isearch-case-fold-search))
1952 (occur (if isearch-regexp
1953 isearch-string
1954 (regexp-quote isearch-string))))))
1955
1956
1957 (defun my-isearch-toggle-regexp ()
1958 (interactive)
1959 (isearch-toggle-regexp)
1960 (cond (isearch-regexp
1961 (global-set-key (kbd "C-r") 'isearch-backward-regexp)
1962 (define-key global-map (kbd "<f12>") 'isearch-forward-regexp))
1963 (t
1964 (global-set-key (kbd "C-r") 'isearch-backward)
1965 (define-key global-map (kbd "<f12>") 'isearch-forward))))
1966 (define-key isearch-mode-map (kbd "M-r") 'my-isearch-toggle-regexp)
1967
1968
1969 (define-key Info-mode-map "x" 'Info-follow-nearest-node)
1970
1971
1972 ;;;; single/special keys
1973 ;;;;; tab - isearch
1974 ;; todo: this doesnt work. needs <tab>, which doesnt work in terminal. fix that.
1975 (define-key isearch-mode-map (kbd "TAB") 'isearch-query-replace)
1976
1977 ;;;;; f12 - isearch-forward
1978 ;; explained in http://stackoverflow.com/questions/7411920/how-to-bind-search-and-search-repeat-to-c-f-in-emacs
1979 (global-set-key (kbd "<kp-add>") 'isearch-forward)
1980 (global-set-key (kbd "<f12>") 'isearch-forward)
1981 (define-key isearch-mode-map (kbd "<kp-add>") 'isearch-repeat-forward)
1982 (define-key isearch-mode-map (kbd "<f12>") 'isearch-repeat-forward)
1983 ;; get rid of the standard completion binding, always use auto-complete
1984 ;; this didn't work very well
1985 ;;(global-set-key (kbd "TAB") 'auto-complete)
1986 (define-key global-map [remap completion-at-point] 'auto-complete)
1987
1988 ;;;;; end - move-end-of-line
1989 ;; taken from emacs wiki, along with home function
1990 ;; http://www.emacswiki.org/emacs/BackToIndentationOrBeginning
1991 (defun point-in-comment ()
1992 "Determine if the point is inside a comment"
1993 (interactive)
1994 (let ((syn (syntax-ppss)))
1995 (and (nth 8 syn)
1996 (not (nth 3 syn)))))
1997 (defun end-of-code-or-line (arg)
1998 "Move to end of line, or before start of comments depending on situation.
1999 Toggle back and forth positions if we are already at one.
2000 Comments are recognized in any mode that sets syntax-ppss
2001 properly."
2002 (interactive "P")
2003 (when (catch 'bol
2004 (let ((start (point))
2005 (bol (save-excursion
2006 (beginning-of-line)
2007 (point)))
2008 (eol (progn (move-end-of-line arg) (point))))
2009 (while (point-in-comment)
2010 (backward-char)
2011 (when (= (point) bol)
2012 (throw 'bol t)))
2013 (throw 'bol (and (not (= eol start)) (>= start (point))))))
2014 (move-end-of-line arg)))
2015
2016 (global-set-key (kbd "<end>") 'end-of-code-or-line)(add-hook 'org-mode-hook (lambda () (define-key org-mode-map (kbd "<end>") 'org-end-of-line)))
2017
2018 ;;;;; home - back-to-indentation
2019 (defun back-to-indentation-or-beginning ()
2020 (interactive)
2021 (if (= (point) (progn (back-to-indentation) (point)))
2022 (if (derived-mode-p 'org-mode)
2023 (org-beginning-of-line)
2024 (beginning-of-line))))
2025 (global-set-key (kbd "<home>") 'back-to-indentation-or-beginning)
2026
2027 ;;;;; s-tab - indent-buffer
2028 ;; graphical
2029 (global-set-key (kbd "<S-iso-lefttab>") 'indent-buffer)
2030 ;; terminal
2031 (global-set-key (kbd "<backtab>") 'indent-buffer)
2032 ;;;;; s-delete - send-shell
2033
2034 (global-set-key (kbd "<S-delete>") 'send-shell)
2035
2036 ;; optional variables used by send-shell
2037 (setq shell-send-yank-key nil)
2038
2039 (defun repeat-shell ()
2040 (interactive)
2041 "Repeat the last command in shell-mode, displaying the window if needed."
2042 (let ((shell-buffer (get-buffer "*shell*")))
2043 (if shell-buffer
2044 (buffer-window-show shell-buffer)
2045 (let ((original-buffer (current-buffer)))
2046 (funcall 'shell)
2047 (setq shell-buffer (current-buffer))
2048 (switch-to-buffer original-buffer)))
2049 (with-current-buffer shell-buffer
2050 (goto-char (point-max))
2051 (call-interactively 'comint-previous-input)
2052 ;; the t flag makes the buffer advance
2053 (comint-send-input nil t))))
2054
2055 (setq compilation-filenames '("Makefile" "makefile"))
2056
2057 (defun get-nearest-compilation-file ()
2058 "Search for the compilation file traversing up the directory tree."
2059 (interactive)
2060 (let ((dir default-directory)
2061 (parent-dir (file-name-directory (directory-file-name default-directory)))
2062 (nearest-compilation-file 'nil))
2063 (while (and (not (string= dir parent-dir))
2064 (not nearest-compilation-file))
2065 (dolist (filename compilation-filenames)
2066 (setq file-path (concat dir filename))
2067 (when (file-readable-p file-path)
2068 (setq nearest-compilation-file file-path)))
2069 (setq dir parent-dir
2070 parent-dir (file-name-directory (directory-file-name parent-dir))))
2071 nearest-compilation-file))
2072 (defun run ()
2073 (interactive)
2074 "call run-fun if it is set, else run make if there is a makefile,
2075 else save and repeat last shell command.
2076 run-fun is meant to store file local variables, which show how to
2077 do the main thing we want on this file, generally compile and
2078 run.
2079
2080 example of setting it in a file:
2081 ;; Local Variables:
2082 ;; run-fun: merge-test
2083 ;; End: "
2084 (basic-save-buffer)
2085 (if (and (boundp 'run-fun) run-fun)
2086 (funcall run-fun)
2087 (let ((makefile (get-nearest-compilation-file)))
2088 (if (and makefile (stringp mode-name) (string= mode-name "C/l"))
2089 (compile (format
2090 "make -f %s" (get-nearest-compilation-file)))
2091 (repeat-shell)))))
2092
2093
2094 (defun send-shell ()
2095 (interactive)
2096 (send-shell-buffer "*shell*" 'shell (kbd "C-v")))
2097
2098 (defun send-python ()
2099 (interactive)
2100 (send-shell-buffer "*Python*" 'py-shell (kbd "C-v")))
2101
2102
2103 (defun send-shell-buffer (buffer-name &optional init shell-send-yank-key)
2104 "Send current line or region to shell-mode buffer.
2105 When in shell-mode, copy the current line to the
2106 most recently visited visible window.
2107
2108 SHELL-SEND-YANK-KEY: key to use instead
2109 of yank to paste into recent window. This allows compatibility with
2110 modes like org-mode which have their own yank function."
2111 (if (string= (buffer-name) buffer-name)
2112 ;; this section is copied out of comint-send-input
2113 (progn
2114 (let ((proc (get-buffer-process (current-buffer))))
2115 (if (not proc) (user-error "Current buffer has no process")
2116 (widen)
2117
2118 (let* ((pmark (process-mark proc))
2119 (intxt (if (>= (point) (marker-position pmark))
2120 (progn (if comint-eol-on-send (end-of-line))
2121 (buffer-substring pmark (point)))
2122 (let ((copy (funcall comint-get-old-input)))
2123 (goto-char pmark)
2124 (insert copy)
2125 copy))))
2126
2127 (if (= (length intxt) 0)
2128 (kill-new (comint-previous-matching-input-string "." 1))
2129 (kill-new intxt)))))
2130 (kill-append "\n" nil)
2131 (select-window (previous-window nil nil 'visible))
2132 (if (and (boundp 'shell-send-yank-key) shell-send-yank-key)
2133 (call-interactively (global-key-binding shell-send-yank-key))
2134 (yank))
2135 (select-window (next-window nil nil 'visible)))
2136 (let (start end)
2137 (if mark-active
2138 (setq start (mark)
2139 end (point))
2140 (setq start (save-excursion (beginning-of-line) (point))
2141 end (save-excursion (end-of-line) (point)))
2142 (let (line-move-visual)
2143 (call-interactively 'next-line)))
2144 (send-comint-input buffer-name start end init))))
2145
2146 ;; supporting functions
2147 (defun send-comint-input (buffer-name start end &optional init)
2148 "Input the region to BUFFER-NAME, assuming it is a comint-derived buffer.
2149 Show BUFFER-NAME if it is not show.
2150 Call INIT if BUFFER-NAME does not exist."
2151 (let ((input (filter-buffer-substring start end)))
2152 (send-comint-string buffer-name input init)))
2153
2154 (defun send-comint-string (buffer-name string &optional init)
2155 "Input the string to BUFFER-NAME, assuming it is a comint-derived buffer.
2156 Show BUFFER-NAME if it is not show.
2157 Call INIT if BUFFER-NAME does not exist."
2158 (let ((buffer (get-buffer buffer-name)))
2159 (unless buffer
2160 (message "nobuffer")
2161 ;; save-excursion etc. don't work for (shell), so I do this instead
2162 (if init (let ((original-buffer (current-buffer)))
2163 (funcall init (and (boundp 'send-shell-buffer-name) send-shell-buffer-name))
2164 (switch-to-buffer original-buffer)
2165 (setq buffer (get-buffer buffer-name)))
2166 (error "No existing buffer found and no init function argument. ")))
2167 (buffer-window-show buffer)
2168 (with-current-buffer buffer
2169 (let ((proc (get-buffer-process buffer)))
2170 (goto-char (process-mark proc))
2171 (insert string)
2172 (comint-send-input nil t)))))
2173
2174 (defun buffer-window-show (&optional buffer action)
2175 "Like temp-buffer-window-show, but removed stuff
2176 relevant to it being temp or help."
2177 (let (window frame)
2178 (with-current-buffer buffer
2179 (when (let ((window-combination-limit
2180 ;; When `window-combination-limit' equals
2181 ;; `temp-buffer' or `temp-buffer-resize' and
2182 ;; `temp-buffer-resize-mode' is enabled in this
2183 ;; buffer bind it to t so resizing steals space
2184 ;; preferably from the window that was split.
2185 (if (or (eq window-combination-limit 'temp-buffer)
2186 (and (eq window-combination-limit
2187 'temp-buffer-resize)
2188 temp-buffer-resize-mode))
2189 t
2190 window-combination-limit)))
2191 ;; debug
2192 ;;(message "window-combination-limit")
2193 ;;(print window-combination-limit)
2194 (setq window (display-buffer buffer action)))
2195 (setq frame (window-frame window))
2196 (unless (eq frame (selected-frame))
2197 (raise-frame frame))
2198 (setq minibuffer-scroll-window window)
2199 (set-window-hscroll window 0)
2200 ;; Return the window.
2201 window))))
2202
2203
2204 ;; when poping help, etc, allow reusing a window in a different frame if it is visible
2205 ;; figured this out after spending quite a while reading doc string for display-buffer
2206 ;; which is the main function which uses this.
2207 ;; it will use other vars or its arg to override this,
2208 ;; but those things are often nil.
2209 ;; aha moments in reading it: ACTION = (FUNCTION-or-FUNCTIONLIST ALIST)
2210 ;; FRAME adds an association to ACTION's alist, but it's not used if ACTION arg is nil.
2211 (setq display-buffer-fallback-action `(,(car display-buffer-fallback-action) . '(reusable-frames . visible)))
2212 ;; stop splitting windows verticallly when I open a buffer or shell
2213 (setq split-height-threshold nil)
2214
2215 ;;;;; s-left arrow - ---
2216 ;; cant be used in terminal
2217 ;; When I had a binding, i did this so org-mode wouldnt clobber it
2218 ;; (add-hook 'org-mode-hook
2219 ;; (lambda ()
2220 ;; (define-key org-mode-map (kbd "<S-left>") nil)))
2221
2222 ;;;;; s-right arrow - keyboard-yank-primary
2223 (defun keyboard-yank-primary ()
2224 (interactive)
2225 (let ((mouse-yank-at-point t))
2226 (mouse-yank-primary nil)))
2227 ;; paste selection
2228 (global-set-key (kbd "<S-right>") 'keyboard-yank-primary)
2229 (add-hook 'org-mode-hook
2230 (lambda ()
2231 (define-key org-mode-map (kbd "<S-right>") nil)))
2232 ;;;;; esc --- terminal dup
2233 ;; todo, test out if this can be used
2234 ;;;;; return - new line
2235
2236 ;; todo, this doesn't set the keybind for the help minibuffer
2237
2238
2239 (global-set-key (kbd "\r") 'indent-new-comment-line)
2240
2241 ;; don't use enter for autocomplete, we use tab or something
2242 (define-key ac-completing-map (kbd "<return>") nil)
2243 (define-key ac-completing-map "\r" nil)
2244
2245 (add-hook 'org-mode-hook
2246 (lambda ()
2247 ;; copied from org-mode, replace org-enter with org-enter-indent
2248 (org-defkey org-mode-map "\C-m" 'org-return-indent)))
2249
2250
2251 (add-hook 'comint-mode-hook
2252 (lambda ()
2253 (define-key comint-mode-map "\r" nil)
2254 (define-key comint-mode-map (kbd "RET") 'comint-send-input)))
2255
2256 (add-hook 'comint-mode-hook
2257 (lambda ()
2258 (define-key comint-mode-map "\C-m" nil)
2259 (define-key comint-mode-map "\C-d" nil)))
2260
2261 ;;;;; s-return - auto-correct-prev-word
2262 (global-set-key (kbd "<S-return>") 'flyspell-auto-correct-previous-word)
2263 ;; kp-enter is shift return in terminal
2264 (global-set-key (kbd "<kp-enter>") 'flyspell-auto-correct-previous-word)
2265
2266 ;;;;; s-up arrow - my-contract-region
2267 (global-set-key (kbd "<S-up>") 'my-contract-region)
2268 ;;;;; c-up/down move 8 lines
2269
2270 ;; compiling warns that next-line should be called interactively,
2271 ;; but we would have to do something dumb, like give it a
2272 ;; vector of keys in order to supply the 8 argument
2273 (defun down-fast ()
2274 (interactive)
2275 (next-line 8))
2276 (defun up-fast ()
2277 (interactive)
2278 (next-line -8))
2279
2280 (global-set-key (kbd "<C-up>") 'up-fast)
2281 (global-set-key (kbd "<C-down>") 'down-fast)
2282
2283 ;;;;; c-scroll comint prev/next prompt
2284
2285 (add-hook 'comint-mode-hook
2286 (lambda ()
2287 (define-key comint-mode-map (kbd "<C-mouse-4>") 'comint-previous-prompt)
2288 (define-key comint-mode-map (kbd "<C-mouse-5>") 'comint-next-prompt)))
2289 ;;;;; m-scroll prev/next sexp
2290 (global-set-key (kbd "<M-mouse-4>") 'backward-sexp)
2291 (global-set-key (kbd "<M-mouse-5>") 'forward-sexp)
2292 ;;;;; S-scroll expand/contract region
2293 (global-set-key (kbd "<S-mouse-13>") 'my-contract-region)
2294 (global-set-key (kbd "<S-mouse-14>") 'er/expand-region)
2295 (global-set-key (kbd "<S-mouse-4>") 'my-contract-region)
2296 (global-set-key (kbd "<S-mouse-5>") 'er/expand-region)
2297
2298 (defun my-contract-region (arg)
2299 (interactive "p")
2300 (let ((current-prefix-arg '-))
2301 (call-interactively 'er/expand-region)))
2302
2303 ;; todo: define c-m scroll. i manually set to normal scrolling, i dunno why
2304
2305
2306 ;;;;; c-s-scroll scale text
2307
2308 (global-set-key (kbd "<C-S-mouse-4>") 'text-scale-increase)
2309 (global-set-key (kbd "<C-S-mouse-5>") 'text-scale-decrease)
2310 (global-set-key (kbd "<C-S-mouse-13>") 'text-scale-increase)
2311 (global-set-key (kbd "<C-S-mouse-14>") 'text-scale-decrease)
2312 (global-set-key (kbd "<C-S-down>") 'text-scale-increase)
2313 (global-set-key (kbd "<C-S-up>") 'text-scale-decrease)
2314
2315
2316 ;;;;; s-up arrow er/expand-region
2317 (global-set-key (kbd "<S-down>") 'er/expand-region)
2318 ;;;;; c-left/right move symbol
2319
2320 (global-set-key (kbd "<C-left>") 'backward-symbol)
2321 (global-set-key (kbd "<C-right>") 'forward-symbol)
2322
2323 ;;;; left primary
2324
2325 ;;;;; M-2 shell-cd-to-file
2326
2327
2328 (defun shell-cd-to-file ()
2329 (interactive)
2330 (let ((file (buffer-file-name)))
2331 (if file
2332 (send-comint-string "*shell*"
2333 (concat "c " (file-name-directory file))
2334 'shell)
2335 (message "%s" "shell-cd-to-file: buffer has no file name"))))
2336 (global-set-key (kbd "M-2") 'shell-cd-to-file)
2337
2338 ;;;;; C-M-2 copy-symbol
2339 (global-unset-key (kbd "C-M-2"))
2340 (defun copy-symbol (&optional arg)
2341 "Copy symbol at point into kill-ring"
2342 (interactive "P")
2343 (kill-new (thing-at-point 'symbol)))
2344
2345 (global-set-key (kbd "C-M-2") 'copy-symbol)
2346
2347 ;;;;; M-3 dot-mode-execute
2348
2349 (global-set-key (kbd "M-3") 'dot-mode-execute)
2350
2351 ;;;;; C-M-3 recenter-top-bottom
2352
2353 (global-set-key (kbd "C-M-3") 'recenter-top-bottom)
2354
2355 ;;;;; C-q org-cycle, comint previous arg
2356
2357 (global-set-key (kbd "C-q") 'bicycle-cycle)
2358 (add-hook 'org-mode-hook
2359 (lambda () (define-key org-mode-map (kbd "C-q") 'org-cycle)))
2360 (define-key widget-keymap (kbd "C-q") 'widget-forward)
2361 (add-hook 'comint-mode-hook
2362 (lambda () (define-key comint-mode-map (kbd "C-q") 'comint-insert-previous-argument)))
2363
2364 ;;;;; M-q ?? unused
2365 ;;;;; C-M-q quoted-insert
2366
2367 (global-set-key (kbd "C-M-q") 'quoted-insert)
2368
2369 ;;;;; C-w counsel-find-file
2370
2371 (global-set-key (kbd "C-w") 'counsel-find-file)
2372
2373 ;;;;; M-w shell
2374
2375 (global-set-key (kbd "M-w") 'shell-wrap)
2376
2377 ;;;;; C-e copy-line
2378
2379 ;; todo, make repeated calls to this append the kills
2380 (defun copy-line (&optional arg)
2381 "Copy lines (as many as prefix argument) in the kill ring.
2382 Ease of use features:
2383 - Move to start of next line.
2384 - Appends the copy on sequential calls.
2385 - Use newline as last char even on the last line of the buffer.
2386 - If region is active, copy its lines."
2387 (interactive "p")
2388 (let ((beg (line-beginning-position))
2389 (end (line-end-position (or arg 1))))
2390 (when mark-active
2391 (if (> (point) (mark))
2392 (setq beg (save-excursion (goto-char (mark)) (line-beginning-position)))
2393 (setq end (save-excursion (goto-char (mark)) (line-end-position)))))
2394 (if (eq last-command 'copy-line)
2395 (kill-append (buffer-substring beg end) (< end beg))
2396 (kill-ring-save beg end)))
2397 (kill-append "\n" nil)
2398 ;; dun need cuz I have yank-better
2399 ;;(beginning-of-line (or (and arg (1+ arg)) 2))
2400 (if (and arg (not (= 1 arg))) (message "%d lines copied" arg)))
2401
2402 (global-set-key (kbd "C-e") 'copy-line)
2403
2404 ;;;;; M-e ?? unused
2405
2406 ;;;;; C-r isearch-backward
2407
2408 (global-set-key (kbd "C-r") 'isearch-backward)
2409 (add-hook 'comint-mode-hook
2410 (lambda ()
2411 (define-key comint-mode-map (kbd "C-r") 'comint-history-isearch-backward-regexp)))
2412
2413 ;;;;; M-r ?? unused
2414 ;;;;; C-a copy buffer
2415
2416 (defun copy-all ()
2417 "Copy entire buffer to clipboard"
2418 (interactive)
2419 (clipboard-kill-ring-save (point-min) (point-max)))
2420 (global-set-key (kbd "C-a") 'copy-all)
2421
2422 ;;;;; C-s - c-x prefix
2423 ;; prefix key binds.
2424 ;; good info http://www.masteringemacs.org/articles/2011/02/08/mastering-key-bindings-emacs/
2425 ;; rebinding the prefix keys are tricky. apparently, some modes ignore any redefinition of a prefix key and use it explicitly,
2426 ;; so you have to dig into their key maps and redo things.
2427 ;; There are 2 simpler alternatives which have their own downsides.
2428 ;; One is cua mode, which I do not like because it smashes 2 keybinds onto 1 and limits what you can do.
2429 ;; The other is keyboard-translate, which translates the key presses before anything else.
2430 ;; The downside is that it translates them when you aren't using them as a prefix.
2431 ;; Since the swaps I'm using are all very accessible, the only downside is some mental jugling when reading docs etc about these keybinds.
2432
2433 ;; I've seen this as an another suggestion, it was a total fail. The prefix command took over both keys.
2434 ;; (define-key key-translation-map [f12] "\C-c")
2435 ;; (define-key key-translation-map "\C-c" [left])
2436
2437
2438 ;;idea to remove the hook later since it is only needed at startup.
2439 ;; did not work however, and there is not a real need to fix it, so I did not investigate
2440 ;;(defun removeSwapHook ()
2441 ;; (remove-hook 'buffer-list-update-hook 'myKeySwap)
2442 ;; (remove-hook 'change-major-mode-hook 'removeSwapHook))
2443 ;;(add-hook 'change-major-mode-hook 'removeSwapHook)
2444
2445
2446 ;; went through almost all the relevant standard hooks,
2447 ;; this overcomes a known bug that (keyboard-translate) does not get applied when running emacs daemon
2448 (add-hook 'buffer-list-update-hook (lambda () (interactive)
2449 (keyboard-translate ?\C-x ?\C-s)
2450 (keyboard-translate ?\C-s ?\C-x)
2451 (keyboard-translate ?\C-c ?\C-d)
2452 (keyboard-translate ?\C-d ?\C-c)))
2453
2454
2455
2456 ;; these all don't work
2457 ;; don't know why this doesn't error but reversing the keys does
2458 ;;(keyboard-translate ?\t ?\M-\t)
2459 ;;(keyboard-translate [M-tab] [tab])
2460 ;; from what i can tell, it wants to use a keyboard-translate-table,
2461 ;; which is a char table, which is a vector indexed by chars,
2462 ;; and mod+tab is not a char (it has too many bits), it is an integer
2463 ;; it actually says it can hold vectors or strings, but that it is obsolete to do so
2464 ;;(characterp ?\M-a)
2465 ;;(characterp ?\C-a)
2466
2467 ;;;;; C-M-s - split-window-vertically
2468
2469 (global-set-key (kbd "C-M-s") 'split-window-vertically)
2470
2471 ;;;;; C-d - C-c prefix
2472
2473 ;;;;; M-d - run
2474
2475 (global-set-key (kbd "M-d") 'run)
2476
2477 ;;;;; C-M-d - swap buffer across windows
2478 ;; from http://www.emacswiki.org/emacs/TransposeWindows
2479
2480 (setq swapping-buffer nil)
2481 (setq swapping-window nil)
2482 (defun swap-buffers-in-windows ()
2483 "Swap buffers between two windows"
2484 (interactive)
2485 (if (and swapping-window
2486 swapping-buffer)
2487 (let ((this-buffer (current-buffer))
2488 (this-window (selected-window)))
2489 (if (and (window-live-p swapping-window)
2490 (buffer-live-p swapping-buffer))
2491 (progn (switch-to-buffer swapping-buffer)
2492 (select-window swapping-window)
2493 (switch-to-buffer this-buffer)
2494 (select-window this-window)
2495 (message "Swapped buffers."))
2496 (message "Old buffer/window killed. Aborting."))
2497 (setq swapping-buffer nil)
2498 (setq swapping-window nil))
2499 (progn
2500 (setq swapping-buffer (current-buffer))
2501 (setq swapping-window (selected-window))
2502 (message "Buffer and window marked for swapping."))))
2503
2504 (global-set-key (kbd "C-M-d") 'swap-buffers-in-windows)
2505
2506 ;;;;; C-f - kill-whole-line
2507
2508 (global-set-key (kbd "C-f") 'kill-whole-line-wrapper)
2509 (defun kill-whole-line-wrapper (&optional arg)
2510 "If we are at the end of the file, kill backwards instead of doing nothing."
2511 (interactive "P")
2512 (if (= (point) (point-max))
2513 (kill-whole-line -1)
2514 (kill-whole-line arg)))
2515
2516 ;;;;; M-f - print-var-at-point
2517
2518 (defun print-var-at-point ()
2519 (interactive)
2520 (let ((v (variable-at-point)))
2521 (if (symbolp v)
2522 (message "%s: %s" v (symbol-value v))
2523 (message "no symbol found at point"))))
2524 (global-set-key (kbd "M-f") 'print-var-at-point)
2525
2526
2527 ;;;;; C-M-f - kill rest of line
2528
2529
2530 (add-hook 'org-mode-hook
2531 (lambda ()
2532 (define-key org-mode-map (kbd "C-M-f") 'org-kill-line)))
2533
2534 (global-set-key (kbd "C-M-f") 'kill-line)
2535 ;;;;; C-g - keyboard-quit
2536 ;;;;; M-g - abort-recursive-edit
2537
2538 (global-set-key (kbd "M-g") 'abort-recursive-edit)
2539
2540 ;;;;; C-M-g - gnus
2541
2542 (global-set-key (kbd "C-M-g") 'mu4e)
2543
2544 ;;;;; C-z - undo-only
2545 (global-set-key (kbd "C-z") 'undo-tree-undo)
2546 ;;;;; C-M-z - suspend-frame
2547 (global-set-key (kbd "C-M-z") 'suspend-frame)
2548 ;; this is never good in a gui
2549 (when (window-system)
2550 (defun suspend-frame() (interactive)))
2551
2552 ;;;;; C-x - kill-region
2553
2554 (global-set-key (kbd "C-s") 'kill-region)
2555
2556 ;;;;; M-x - counsel-m-x
2557
2558
2559 ;; todo; check out smex-show-unbound-commands shows frequently used commands that have no key bindings.
2560 ;; this must be before smex-initialize
2561 (setq
2562 smex-save-file "~/.emacs.d/.smex-items")
2563
2564 ;; this uses smex
2565 (global-set-key (kbd "M-x") 'counsel-M-x)
2566
2567 ;;;;; C-M-x - cut-to-register
2568
2569 ;; same args as copy-to-register
2570 (defun cut-to-register (register start end &optional delete-flag region)
2571 (interactive (list (register-read-with-preview "Cut to register: ")
2572 (region-beginning)
2573 (region-end)
2574 current-prefix-arg
2575 t))
2576 (copy-to-register register start end t region))
2577
2578 (global-set-key (kbd "C-M-x") 'cut-to-register)
2579
2580 ;;;;; C-c - copy
2581
2582 (global-set-key (kbd "C-d") 'kill-ring-save)
2583 (add-hook 'c-mode-hook
2584 (lambda () (define-key c-mode-map (kbd "C-d") nil)))
2585 (add-hook 'comint-mode-hook
2586 (lambda ()
2587 (define-key comint-mode-map (kbd "C-d") nil)))
2588 ;; the base map is shared by many c-modes, like java
2589 (add-hook 'c-mode-hook
2590 (lambda ()
2591 (define-key c-mode-base-map "\C-d" nil)
2592 (define-key c-mode-base-map (kbd "<deletechar>") 'c-electric-delete-forward)))
2593
2594
2595 ;;;;; M-c - delete-other-windows
2596
2597 (define-key global-map "\M-c" 'delete-other-windows)
2598
2599 ;;;;; C-M-c - copy-to-register
2600
2601 (global-set-key (kbd "C-M-c") 'copy-to-register)
2602
2603 ;;;;; C-v - yank
2604
2605 (global-set-key (kbd "C-v") 'yank-better)
2606
2607
2608
2609 (defun yank-better (arg)
2610 "Paste, linewise if our kill ends with a newline.
2611 I change the behavior of plain prefix. It makes it not do linewise paste,
2612 because sometimes you want to yank pop and a linewise paste screws that up.
2613 c-u with no number normally makes the point go before the yank.
2614 That is pointless for me, as it would be just as easier and less
2615 thought to pop the mark after yanking cuz it is set to before the mark."
2616 (interactive "*P")
2617 (if (and (not (equal arg '(4))) (string-suffix-p "\n" (current-kill 0 t)))
2618 (beginning-of-line))
2619 (if (and (stringp mode-name) (string= mode-name "Org"))
2620 (call-interactively 'org-yank)
2621 (setq this-command 'yank)
2622 (call-interactively 'yank (and (not (equal arg '(4)))))))
2623
2624 (put 'yank-better 'delete-selection 'yank)
2625
2626 ;;;;; M-v - insert-register
2627
2628 (global-set-key (kbd "M-v") 'insert-register)
2629
2630 ;;;;; C-M-v - yank-pop
2631
2632 (global-set-key (kbd "C-M-v") 'yank-pop)
2633
2634 ;;;;; C-b - other-window
2635
2636 (global-set-key (kbd "C-b") 'other-window)
2637
2638 ;;;;; M-b - isearch-backward-current-symbol
2639
2640 (global-set-key (kbd "M-b") 'isearch-backward-current-symbol)
2641
2642 ;;;;; C-M-b - isearch-current-symbol
2643
2644 (global-set-key (kbd "C-M-b") 'isearch-current-symbol)
2645
2646 ;;;;; C-tab - ---
2647 ;; in terminal, it's just TAB, duplicate keybind.
2648 ;;;;; M-tab - ---
2649 ;; in terminal it's duplicated of C-M-i
2650 ;;;;; C-delete - kill-symbol
2651
2652 (global-set-key (kbd "<C-delete>") 'kill-symbol)
2653 (defun kill-symbol (arg)
2654 (interactive "p")
2655 (kill-region (point) (save-excursion (forward-symbol arg) (point))))
2656
2657
2658 ;;;;; C-M-delete - kill-sexp
2659
2660 (global-set-key (kbd "<C-M-delete>") 'kill-sexp)
2661
2662 ;;;;; C-left-arrow - compile / comint search
2663
2664 (defun set-p (var)
2665 (and (bound-and-true-p var)
2666 (not (eq var 'unset))))
2667 (global-set-key (kbd "C-(") 'run)
2668
2669 ;; make compile work from the gtags root dir
2670 (defadvice compile (before pre-compile-advice activate)
2671 (basic-save-buffer)
2672 (when (set-p ggtags-project-root)
2673 (setq-local compile-saved-dir default-directory)
2674 (setq default-directory ggtags-project-root)))
2675 (defadvice compile (after post-compile-advice activate)
2676 (when (bound-and-true-p compile-saved-dir)
2677 (setq default-directory compile-saved-dir)))
2678
2679
2680 (add-hook 'c-mode-hook (lambda () (define-key c-mode-map (kbd "C-(") 'compile)))
2681 (add-hook 'comint-mode-hook
2682 (lambda ()
2683 (define-key isearch-mode-map (kbd "C-(") 'isearch-repeat-backward)
2684 (define-key comint-mode-map (kbd "C-(") 'isearch-backward)))
2685
2686
2687 ;;;;; C-M-left-arrow - org-shiftup
2688
2689 (add-hook 'org-mode-hook
2690 (lambda () (define-key org-mode-map (kbd "C-M-(") 'org-shiftup)))
2691
2692 ;;;;; C-right-arrow - forward-symbol
2693 ;;;;; C-M-right-arrow - org-shiftdown
2694 (add-hook 'org-mode-hook
2695 (lambda () (define-key org-mode-map (kbd "C-M-)") 'org-shiftdown)))
2696
2697 ;;;;; C-backspace - backward-kill-symbol
2698
2699 (define-key terminal-key-map (kbd "4b") 'backward-kill-symbol) ;c-backspace in my konsole
2700
2701 ;; c-w is duplicate in terminal
2702 (global-set-key (kbd "<C-backspace>") 'backward-kill-symbol)
2703 (add-hook 'comint-mode-hook
2704 (lambda ()
2705 (define-key comint-mode-map (kbd "<C-backspace>") 'backward-kill-word)))
2706 (defun backward-kill-symbol (arg)
2707 (interactive "p")
2708 (kill-region (point) (save-excursion (backward-symbol arg) (point))))
2709
2710 ;;;;; C-M-backspace - backward-kill-sexp
2711
2712 (global-set-key (kbd "<C-M-backspace>") 'backward-kill-sexp)
2713
2714 ;;;; right primary
2715 ;;;;; M-8 - delete-window-or-exit
2716
2717 (global-set-key (kbd "M-8") 'delete-window-or-exit)
2718
2719 (defun delete-window-or-exit ()
2720 "Delete window or exit emacs."
2721 (interactive)
2722 (if (condition-case nil (delete-window) (error t))
2723 (if (or (boundp 'server-process) (> (length (frame-list)) 1))
2724 (progn (basic-save-buffer) (delete-frame))
2725 (save-buffers-kill-terminal t))))
2726
2727 ;;;;; C-* - split-window-horizontally
2728 (global-set-key (kbd "C-*") 'split-window-horizontally)
2729 ;;;;; C-M-* - calc-dispatch
2730
2731 (global-set-key (kbd "C-M-*") 'calc-dispatch)
2732
2733 ;;;;; M-9 - kill-buffer
2734
2735 (defun kill-buffer-no-ido ()
2736 "kill-buffer, avoid the ido remapping"
2737 (interactive)
2738 (kill-buffer))
2739 (global-set-key (kbd "M-9") 'kill-buffer-no-ido)
2740
2741 ;; strangely, in simple mode, this is overridden.
2742 ;; I found this map to override, but it didn't work, so it seems its being bound some other way.
2743 ;; I did a grep of the emacs sources, but couldn't find anything.
2744 ;; (define-key universal-argument-map [?9 nil)
2745
2746 ;;;;; C-M-9 - end server edit
2747 ;; save & kill buffer if it was opened externally via emacsclient
2748
2749
2750 (defun server-edit-save ()
2751 (interactive)
2752 (save-buffer)
2753 (server-edit))
2754 (global-set-key (kbd "C-M-9") 'server-edit-save)
2755
2756 ;;;;; C-u - universal-argument
2757 ;;;;; C-M-u - search-keybind
2758
2759 (global-set-key (kbd "C-M-u") 'search-keybind)
2760
2761 (defun search-keybind (regexp &optional nlines)
2762 (interactive (occur-read-primary-args))
2763 (save-excursion
2764 (describe-bindings)
2765 (set-buffer "*Help*")
2766 (occur regexp)
2767 (delete-windows-on "*Help*")
2768 ))
2769
2770 ;;;;; C-i -
2771 ;; todo: try making use
2772 ;; this is the key in terminal
2773 ;;M-[ 4 d is undefined
2774
2775 ;; previously had this for enhancing graphical keybinds,
2776 ;; but afaik its no help since i want terminal to work
2777 ;; the same.
2778 ;; (define-key input-decode-map [?\C-i] [C-i])
2779
2780 ;;;;; C-M-i - query-replace-regexp
2781
2782 (global-set-key (kbd "C-M-i") 'query-replace-regexp)
2783 (add-hook 'flyspell-mode-hook
2784 (lambda () (define-key flyspell-mode-map (kbd "C-M-i") nil)))
2785 (add-hook 'text-mode-hook
2786 (lambda () (define-key text-mode-map (kbd "C-M-i") nil)))
2787
2788
2789 ;;;;; C-o - occur
2790
2791 (global-set-key (kbd "C-o") 'occur)
2792
2793 ;;;;; C-M-o - counsel-imenu
2794
2795 (global-set-key (kbd "C-M-o") 'counsel-imenu)
2796
2797 ;;;;; C-p - move-mouse-to-point
2798
2799 (global-set-key (kbd "C-p") 'move-mouse-to-point)
2800
2801 ;;;;; C-M-p - delete-horizontal-space
2802
2803 (global-set-key (kbd "C-M-p") 'delete-horizontal-space)
2804
2805 ;;;;; C-j - pop-to-mark
2806
2807 (defun my-pop-to-mark-command ()
2808 "Jump to mark, and pop a new position for mark off the ring.
2809 \(Does not affect global mark ring\)."
2810 (interactive)
2811 (pop-to-mark-command)
2812 (if (and (derived-mode-p 'org-mode) (outline-invisible-p))
2813 (org-show-context 'mark-goto)))
2814
2815 (global-set-key (kbd "C-j") 'my-pop-to-mark-command)
2816 (add-hook 'ido-setup-hook
2817 (lambda ()
2818 (define-key ido-common-completion-map (kbd "C-j") 'ido-select-text)
2819 ))
2820 (add-hook 'lisp-interaction-mode-hook
2821 (lambda ()
2822 (define-key lisp-interaction-mode-map (kbd "C-j") nil)))
2823
2824
2825 ;;;;; M-j - previous-error
2826
2827 (global-set-key (kbd "M-j") 'previous-error)
2828
2829 ;;;;; C-M-j - register prefix
2830
2831 (define-key global-map (kbd "C-M-j") ctl-x-r-map)
2832 (define-key ctl-x-r-map "m" 'kmacro-to-register)
2833
2834
2835 ;;;;; C-k - jump-to-register
2836
2837
2838 (global-set-key (kbd "C-k") 'jump-to-register)
2839
2840 ;;;;; M-k - next-error
2841
2842 (global-set-key (kbd "M-k") 'next-error)
2843
2844 ;;;;; C-M-k - man
2845
2846 (global-set-key (kbd "C-M-k") 'man)
2847
2848 ;;;;; C-l - ivy-switch-buffer
2849
2850 (global-set-key (kbd "C-l") 'ivy-switch-buffer)
2851
2852 ;;;;; C-M-l - move cursor top bottom mid, comint clear screen
2853
2854 (global-set-key (kbd "C-M-l") 'move-to-window-line-top-bottom)
2855
2856 ;;;;; C-; - used in flyspell, not sure what for, otherwise unbound
2857 ;;;;; M-; - comment-dwim
2858 ;;;;; C-M-; - comment-current-line-dwim
2859
2860 (defun comment-current-line-dwim ()
2861 "Comment or uncomment the current line."
2862 (interactive)
2863 (save-excursion
2864 (push-mark (beginning-of-line) t t)
2865 (end-of-line)
2866 (comment-dwim nil))
2867 (move-beginning-of-line 2))
2868 (global-set-key (kbd "C-M-;") 'comment-current-line-dwim)
2869
2870 ;;;;; C-m - ---
2871 ;; terminal/console needs this. otherwise, we could do this
2872 ;; to make C-m be a valid key in graphical mode.
2873 ;; (define-key input-decode-map [?\C-m] [C-m])
2874 ;;;;; C-M-m - recursive grep
2875
2876 (define-key global-map (kbd "C-M-m") 'rgrep)
2877
2878 ;;;;; C-, - ---
2879 ;; not recognized by terminal, can't get konsole keydef file to recognize comma,
2880 ;; todo: dig into konsole sources, or try newer version than t8
2881
2882 (add-hook 'flyspell-mode-hook
2883 (lambda () (define-key flyspell-mode-map (kbd "C-,") nil)))
2884
2885 ;;;;; C-M-, - ind-file-in-project
2886
2887 (global-set-key (kbd "C-M-,") 'find-file-in-project)
2888
2889 ;;;;; C-. - find recent file
2890
2891 (add-hook 'flyspell-mode-hook
2892 (lambda () (define-key flyspell-mode-map (kbd "C-.") nil)))
2893 (define-key dot-mode-map (kbd "C-.") nil)
2894 (define-key terminal-key-map (kbd "4c") 'counsel-recentf)
2895 (global-set-key (kbd "C-.") 'counsel-recentf)
2896 (add-hook 'php-mode-hook
2897 (lambda () (define-key php-mode-map (kbd "C-.") nil)))
2898
2899 ;;;;; C-M-. - -
2900
2901 (define-key dot-mode-map (kbd "C-M-.") nil)
2902 ;; (global-set-key (kbd "C-M-.") 'execute-extended-command)
2903
2904 ;;;;; C-/ - join lines
2905
2906 (defun vim-style-join-line ()
2907 (interactive)
2908 (join-line '(4)))
2909 (global-set-key (kbd "C-/") 'vim-style-join-line)
2910 (define-key undo-tree-map (kbd "C-/") nil)
2911
2912 ;;;;; C-M-/ - copy-buffer-file-name
2913
2914 ;; haven't bound this atm, todo, maybe someday?
2915 (defun copy-variable (variable)
2916 (interactive
2917 (let ((v (variable-at-point))
2918 (enable-recursive-minibuffers t)
2919 val)
2920 (setq val (completing-read (if (symbolp v)
2921 (format
2922 "Describe variable (default %s): " v)
2923 "Describe variable: ")
2924 obarray
2925 (lambda (vv)
2926 (or (get vv 'variable-documentation)
2927 (and (boundp vv) (not (keywordp vv)))))
2928 t nil nil
2929 (if (symbolp v) (symbol-name v))))
2930 (list (if (equal val "")
2931 v (intern val)))))
2932 (kill-new (symbol-value variable)))
2933
2934 (defun copy-buffer-file-name ()
2935 (interactive)
2936 (let ((name (cond
2937 ((derived-mode-p 'mu4e-view-mode) (mu4e-message-field-at-point :path))
2938 (t buffer-file-name))
2939 ))
2940 (kill-new name)
2941 (message name)))
2942
2943
2944 (global-set-key (kbd "C-M-/") 'copy-buffer-file-name)
2945
2946
2947
2948 ;;;;; C-up-arrow - org prev headline
2949
2950 ;; disabled just because i don't want to accidentally hit it
2951 (define-key global-map "\C-_" nil)
2952 (global-set-key (kbd "<C-_>") 'beginning-of-defun)
2953
2954 (add-hook 'org-mode-hook
2955 (lambda ()
2956 (define-key org-mode-map (kbd "\C-_") 'outline-previous-visible-heading)))
2957
2958
2959
2960
2961 ;;;;; C-S-up-arrow - winner undo
2962
2963 (global-set-key (kbd "<C-S-_>") 'winner-undo)
2964
2965 ;;;;; C-down-arrow - org next headline
2966
2967 (global-set-key (kbd "<C-kp-enter>") 'end-of-defun)
2968
2969 (add-hook 'org-mode-hook
2970 (lambda ()
2971 (define-key org-mode-map (kbd "<C-kp-enter>") 'outline-next-visible-heading)))
2972
2973
2974
2975
2976 ;;;;; C-M-down-arrow - toggle-mark-activation
2977
2978 (defun toggle-mark-activation ()
2979 (interactive)
2980 (if mark-active
2981 (deactivate-mark t)
2982 (activate-mark)))
2983
2984 (global-set-key (kbd "<C-M-kp-enter>") 'toggle-mark-activation)
2985
2986 ;;;;; C-S-down-arrow winner redo
2987
2988 (global-set-key (kbd "<C-S-kp-enter>") 'winner-redo)
2989
2990
2991 ;;;;; C-S-down-arrow - m-x for major mode
2992
2993 ;; todo, update this for ivy
2994 (global-set-key (kbd "<C-S-kp-enter>") 'smex-major-mode-commands)
2995
2996 ;;;;; C-lbracket - ----
2997 ;;;;; C-M-lbracket - scroll-right
2998
2999 (global-set-key (kbd "C-M-[") 'scroll-right)
3000
3001 ;;;;; C-rbracket - fill-paragraph
3002
3003 (global-set-key (kbd "C-]") 'fill-paragraph)
3004
3005 ;;;;; C-M-rbracket - scroll-left
3006
3007 (global-set-key (kbd "C-M-]") 'scroll-left)
3008
3009 ;;;;; C-return - newline-anywhere
3010
3011 (defun newline-anywhere ()
3012 "Add a newline from anywhere in the line."
3013 (interactive)
3014 (end-of-line)
3015 (newline-and-indent))
3016 ;; todo use alternate keybind make this work for terminal
3017 (global-set-key (kbd "<C-return>") 'newline-anywhere)
3018
3019
3020 ;;;;; M-return - plain newline
3021
3022 (defun plain-newline ()
3023 (interactive)
3024 (insert "\n"))
3025 (global-set-key (kbd "M-RET") 'plain-newline)
3026
3027
3028 ;;;;; C-space - org-edit-special
3029
3030 ;; commented due to new keyboard needing ctrl-space for mark
3031 ;; (kbd "<C-space>") does not work, (kbd "C-SPC") should work
3032 ;; (add-hook 'org-mode-hook
3033 ;; (lambda ()
3034 ;; (define-key org-mode-map (kbd "C-SPC") 'org-edit-special)
3035 ;; ;; org-src-mode-map is broken in git version of emacs.
3036 ;; ;; temporarily use this for exiting edit-special mode.
3037 ;; (global-set-key (kbd "C-M--") 'org-edit-src-exit)
3038 ;; (define-key org-src-mode-map (kbd "C-SPC") 'org-edit-src-exit)))
3039
3040 ;;;;; C-M-space - before or under cursor
3041
3042 (global-set-key (kbd "C-M-SPC") 'ispell-word)
3043 ;;;; left secondary
3044 ;;;;; C-M-4 - widen
3045
3046 (global-set-key (kbd "C-M-4") 'widen)
3047
3048 ;;;;; C-tab-key - query-replace
3049
3050
3051 (global-set-key (kbd "<C-kp-add>") 'query-replace)
3052
3053 ;;;;; C-t - org cycle todo / toggle comint motion
3054
3055 (add-hook 'org-mode-hook
3056 (lambda ()
3057 (define-key org-mode-map (kbd "C-t") 'org-todo)))
3058
3059 (defun my-comint-previous-input (arg)
3060 (interactive "*p")
3061 (if (comint-after-pmark-p)
3062 (comint-previous-input arg)
3063 (forward-line -1)))
3064
3065 (defun my-comint-next-input (arg)
3066 (interactive "*p")
3067 (if (comint-after-pmark-p)
3068 (comint-next-input arg)
3069 (forward-line)))
3070
3071 (add-hook 'comint-mode-hook
3072 (lambda ()
3073 (define-key comint-mode-map (kbd "C-t") 'comint-toggle-arrow-keys)
3074 (define-key comint-mode-map (kbd "<up>") 'my-comint-previous-input)
3075 (define-key comint-mode-map (kbd "<down>") 'my-comint-next-input)))
3076
3077
3078 (defun comint-toggle-arrow-keys ()
3079 (interactive)
3080 (toggle-arrow-keys comint-mode-map))
3081
3082 (setq-default comint-arrow-movement nil)
3083 (defun toggle-arrow-keys (map)
3084 (cond ((lookup-key map (kbd "<up>"))
3085 (setq-local comint-arrow-movement t)
3086 (define-key map (kbd "<up>") nil)
3087 (define-key map (kbd "<down>") nil))
3088 (t
3089 (setq-local comint-arrow-movement nil)
3090 (define-key map (kbd "<up>") 'my-comint-previous-input)
3091 (define-key map (kbd "<down>") 'my-comint-next-input)
3092 (goto-char (point-max)))))
3093
3094 (eval-after-load "message"
3095 '(define-key message-mode-map (kbd "C-t") 'mail-signature))
3096
3097
3098 ;;;;; C-M-t - org timestamp
3099
3100 (global-set-key (kbd "C-M-t") 'org-time-stamp-with-time)
3101
3102 ;;;;; C-home - start of buffer
3103 ;;;;; C-end - end of buffer
3104 ;;;; right secondary
3105 ;;;;; C-^ - save-buffers-kill-emacs
3106
3107 (global-set-key (kbd "C-^") 'save-buffers-kill-emacs)
3108
3109 ;;;;; C-M-6 - insert-small-copyright
3110
3111 (defun insert-small-copyright ()
3112 (interactive)
3113 (beginning-of-line)
3114 (let ((beg (point)))
3115 (insert "Copyright (C) 2019 Ian Kelling\nThis program is under GPL v. 3 or later, see <http://www.gnu.org/licenses/>")
3116 (comment-region beg (point))))
3117
3118 (global-set-key (kbd "C-M-6") 'insert-small-copyright)
3119
3120 ;;;;; M-7 - calc-embedded-word
3121
3122 (global-set-key (kbd "M-7") 'calc-embedded-word)
3123
3124 ;;;;; C-M-7 - insert-full-copyright
3125
3126 (defun insert-full-copyright ()
3127 (interactive)
3128 (beginning-of-line)
3129 (let ((beg (point)))
3130 (insert "Copyright (C) 2019 Ian Kelling\n")
3131 (insert "\n")
3132 (insert "This program is free software: you can redistribute it and/or modify\n")
3133 (insert "it under the terms of the GNU General Public License as published by\n")
3134 (insert "the Free Software Foundation, either version 3 of the License, or\n")
3135 (insert "(at your option) any later version.\n")
3136 (insert "\n")
3137 (insert "This program is distributed in the hope that it will be useful,\n")
3138 (insert "but WITHOUT ANY WARRANTY; without even the implied warranty of\n")
3139 (insert "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n")
3140 (insert "GNU General Public License for more details.\n")
3141 (insert "\n")
3142 (insert "You should have received a copy of the GNU General Public License\n")
3143 (insert "along with this program. If not, see <http://www.gnu.org/licenses/>.\n")
3144 (comment-region beg (point))))
3145
3146 (global-set-key (kbd "C-M-7") 'insert-full-copyright)
3147
3148
3149 ;;;;; C-0 - text-scale-reset
3150
3151 (defun text-scale-reset ()
3152 (interactive)
3153 (text-scale-set 0))
3154 (global-set-key (kbd "C-0") 'text-scale-reset)
3155
3156 ;;;;; C-M-0 - insert-apache
3157
3158 (defun insert-apache ()
3159 (interactive)
3160 (beginning-of-line)
3161 (let ((beg (point)))
3162 (insert "Copyright (C) 2017 Ian Kelling\n")
3163 (insert "\n")
3164 (insert "Licensed under the Apache License, Version 2.0 (the \"License\");\n")
3165 (insert "you may not use this file except in compliance with the License.\n")
3166 (insert "You may obtain a copy of the License at\n")
3167 (insert "\n")
3168 (insert " http://www.apache.org/licenses/LICENSE-2.0\n")
3169 (insert "\n")
3170 (insert "Unless required by applicable law or agreed to in writing, software\n")
3171 (insert "distributed under the License is distributed on an \"AS IS\" BASIS,\n")
3172 (insert "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n")
3173 (insert "See the License for the specific language governing permissions and\n")
3174 (insert "limitations under the License.\n")
3175 (comment-region beg (point))))
3176 (global-set-key (kbd "C-M-0") 'insert-apache)
3177
3178
3179 ;;;;; C-M-- - org-edit-src-exit
3180 ;;;;; C-y - undo
3181
3182 (global-set-key (kbd "C-y") 'undo-tree-redo)
3183 (add-hook 'org-mode-hook
3184 (lambda () (define-key org-mode-map (kbd "C-y") nil)))
3185
3186
3187 ;;;;; C-\ - sr-speedbar-toggle
3188 (global-set-key (kbd "C-\\") 'sr-speedbar-toggle)
3189
3190 ;;;;; C-M-\ - mark-defun
3191
3192 (global-set-key (kbd "C-M-\\") 'mark-defun)
3193
3194 ;;;;; C-h - help-prefix
3195
3196 ;;;;; C-' - val-expression
3197
3198 (global-set-key (kbd "C-'") 'eval-expression)
3199
3200 ;;;;; C-n - unpop to mark
3201
3202 (defun unpop-to-mark-command ()
3203 "Unpop off mark ring. Does nothing if mark ring is empty."
3204 (interactive)
3205 (when mark-ring
3206 (let ((pos (marker-position (car (last mark-ring)))))
3207 (if (not (= (point) pos))
3208 (goto-char pos)
3209 (setq mark-ring (cons (copy-marker (mark-marker)) mark-ring))
3210 (set-marker (mark-marker) pos)
3211 (setq mark-ring (nbutlast mark-ring))
3212 (goto-char (marker-position (car (last mark-ring))))))))
3213
3214 (global-set-key (kbd "C-n") 'unpop-to-mark-command)
3215
3216 ;;;;; C-M-n - narrow-to-region
3217
3218 (global-set-key (kbd "C-M-n") 'narrow-to-region)
3219
3220 ;;;;; C-escape - find-tag
3221
3222 (global-set-key (kbd "<C-escape>") 'find-tag)
3223
3224
3225 ;; Local Variables:
3226 ;; eval: (outline-minor-mode)
3227 ;; outline-regexp: "\\( *\\);;;\\{1,8\\} "
3228 ;; End: