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