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