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