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