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