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