-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.el
1954 lines (1489 loc) · 65.6 KB
/
init.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; Notes ----------------------------------------------------------------------
;; If something goes wrong, run Emacs with "--debug-init" to get a stack trace.
;; If you are on OS X, you can use:
;;
;; $ open -n /Applications/Emacs.app --args --debug-init
;;; Minimal Setup --------------------------------------------------------------
;; Get keys, fonts, and colors setup early so if something goes wrong
;; troubleshooting won't be so frustrating.
;;; Code:
(when (eq system-type 'darwin)
;; On Mac make the Cmd key Meta. First, it is much more comfortable to use
;; than Option and has the added benefit of being in the same place as Alt on
;; Windows keyboards making it easier to switch back and forth.
(setq mac-option-key-is-meta nil
mac-command-key-is-meta t
mac-command-modifier 'meta
mac-option-modifier 'hyper)
;; Enable Mac window switching. Overrides tmm-menubar which I don't use.
(global-set-key (kbd "M-`") 'other-frame)
;; The mouse wheel is crazy fast by default.
;; http://krismolendyke.github.io/.emacs.d/#sec-7
(setq mouse-wheel-scroll-amount '(0.01)
mouse-wheel-progressive-speed nil
scroll-step 1)
(if (find-font (font-spec :name "Inconsolata-18"))
(set-frame-font "Inconsolata-18") ; http://levien.com/type/myfonts/inconsolata.html
;; (set-frame-font "Source Code Pro-20") ; https://github.com/adobe/Source-Code-Pro
;; (set-frame-font "Inconsolata-24") ; http://levien.com/type/myfonts/inconsolata.html
;; (set-frame-font "Inconsolata-18") ; http://levien.com/type/myfonts/inconsolata.html
;; (set-frame-font "Hack-20") ; https://github.com/chrissimpkins/Hack#about
)
)
(when (eq system-type 'windows-nt)
(if (find-font (font-spec :name "Inconsolata-14"))
(set-frame-font "Inconsolata-14")
;; (set-frame-font "Consolas-14")
))
;; A good idea in general, but particularly helpful with package-list-packages
;; for MELPA stable which apparently has a package with a Unicode name.
(prefer-coding-system 'utf-8)
;;; Garbage Collection ----------------------------------------------------------
;; http://bling.github.io/blog/2016/01/18/why-are-you-changing-gc-cons-threshold/
;;
;; For performance, increase the GC size, but not naively.
(defun my-minibuffer-setup-hook ()
(setq gc-cons-threshold most-positive-fixnum))
(defun my-minibuffer-exit-hook ()
(setq gc-cons-threshold 800000))
(add-hook 'minibuffer-setup-hook #'my-minibuffer-setup-hook)
(add-hook 'minibuffer-exit-hook #'my-minibuffer-exit-hook)
;;; Custom File ----------------------------------------------------------------
;; Normally changes made through the emacs customization interface are stored in
;; your init.el file. Move them to a separate file.
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file 'noerror)
;;; Theme ----------------------------------------------------------------------
(setq custom--inhibit-theme-enable nil)
(let ((theme "~/.emacs.d/dark-plain-theme.el"))
(if (file-exists-p theme)
(load-file theme)))
;;(set-foreground-color "white")
;;(set-background-color "black")
(set-cursor-color"orchid")
;;(add-to-list 'load-path "/Users/anderson/elisp/color-theme-6.6.0")
;;(require 'color-theme)
;;(setq load-path (cons "/Users/anderson/elisp/themes/emacs-color-theme-solarized" load-path))
;;(setq custom-theme-load-path (cons "/Users/anderson/elisp/themes/emacs-color-theme-solarized" ()))
;;(require 'color-theme-solarized)
;;(color-theme-solarized-dark)
;;; Personal Information -------------------------------------------------------
(setq user-full-name "Scott Anderson"
user-mail-address "[email protected]")
;;; Package Sources ------------------------------------------------------------
;; Add MELPA stable to the list of package repositories. Stable only builds
;; commits with version tags, so it has proper version numbers and only builds
;; things the author intended to be a release. Normal MELPA builds whatever's
;; been committed to master and uses the date as a version.
;; emacs-async is breaking normal installations. It might be because I am
;; loading a few packages from /misc? It doesn't matter - *anything* in the
;; packaging system needs to be bullet proof. Reading the bug reports doesn't
;; give me a lot of confidence.
(setq async-bytecomp-allowed-packages nil)
(require 'package)
(setq package-archives
(append package-archives
'(("gnu" . "http://elpa.gnu.org/packages/")
("melpa-stable" . "http://stable.melpa.org/packages/")
;; ("melpa" . "http://melpa.milkbox.net/packages/")
;; ("marmalade" . "http://marmalade-repo.org/packages/")
)))
(package-initialize)
(setq package-enable-at-startup nil)
(unless package-archive-contents
(message "Refreshing ELPA package archives...")
(package-refresh-contents))
;; Make sure the fantastic use-package macro is installed.
(unless (package-installed-p 'use-package)
(message "Installing use-package")
(package-install 'use-package))
(require 'use-package)
;;; Look and Feel --------------------------------------------------------------
;; Hide the toolbar, etc. and include the buffer name in the window title. On
;; Mac ("ns-") don't pop up alerts - use the message buffer.
(when window-system
(tooltip-mode -1)
(tool-bar-mode -1)
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))))
(setq icon-title-format "%f - emacs"
ns-pop-up-frames nil))
;; Remove the clock from the mode line since the OS has one and add columns.
;; Show line numbers on the left. The default is to show 3 digits, but that's
;; not nearly enough for log files.
(setq global-mode-string '("")
column-number-mode t)
(global-display-line-numbers-mode t)
(setq display-line-numbers "%4d \u2502 ")
(setq line-number-display-limit nil
line-number-display-limit-width 1000000)
;; Default to line wrapping but have "C-x l" to toggle.
(setq-default truncate-lines nil)
;; (global-set-key (kbd "C-x l") 'toggle-truncate-lines)
;; Make sure C-n can add lines at the end of the file
(setq next-line-add-newlines t)
;;; System Tweaks --------------------------------------------------------------
;; I don't know why this option even exists, but if you don't set it to true,
;; emacs will use compiled code that is old over newer source. That is a
;; /really/ bad default. However, since I'm using use-package whenever
;; possible, this matters a lot less.
(setq load-prefer-newer t)
;; Replace "yes" and "no" prompts with a simple y/n keypress.
(fset 'yes-or-no-p 'y-or-n-p)
;; Turn off backups and auto-save.
;;(setq backup-inhibited t
;; auto-save-default nil
;; create-lockfiles nil
;; delete-old-versions t)
;;(auto-save-mode nil)
(setq create-lockfiles nil)
(setq backup-directory-alist
`((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
`((".*" ,temporary-file-directory t)))
;; Anyone working around me will appreciate it if emacs doesn't ding every time
;; I hit the wrong key...
(setq ring-bell-function 'ignore)
;; Set window splitting back to its old behavior. I forgot the difference -
;; need to document this.
(setq split-width-threshold most-positive-fixnum)
;; If I remember correctly, this ensures that when if you page down, paging up
;; puts the cursor in the same place.
;; (setq scroll-preserve-screen-position 'always)
(setq scroll-preserve-screen-position nil)
;; Enable some really handy functions. These already have keys assigned and
;; will ask you for confirmation when you execute them unless you enable them.
(put 'narrow-to-region 'disabled nil)
(put 'erase-buffer 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(defun save-all()
"Save all buffers without prompting"
(interactive) (save-some-buffers t))
(global-set-key (kbd "C-x s") 'save-all)
;; Normally C-x s prompts for each buffer, which is safe but I don't think I've
;; ever not saved. In projects that monitor directories and rebuild I often
;; don't save individual files and save all at once to keep the rebuild from
;; happening over and over. (If it was fast enough I wouldn't care...) Since
;; I'm using this a lot, it is more convenient to have the key not prompt.
;;; Editing Tweaks -------------------------------------------------------------
;; Default to text-mode intead of fundamental-mode and 4-space tabs. Turn on
;; word wrapping (auto-fill) in text mode and wrap at 95. This width is about
;; right for printed text on US letter.
(setq major-mode 'text-mode
initial-major-mode 'text-mode)
(setq-default tab-width 4
indent-tabs-mode nil)
(defun personal-text-mode-hook ()
(turn-on-auto-fill))
(add-hook 'text-mode-hook 'personal-text-mode-hook)
(setq-default fill-column 95)
;; Turn this on everywhere, for craft.
(global-subword-mode t)
;; Automatically move the mouse cursor out of the way of the emacs cursor.
(mouse-avoidance-mode 'animate)
;; Insert a closing paren or quote character. Since I almost always have to
;; type the ending one or move right to pass it, I'm not sure this is really
;; helping. I do like closing Javascript braces though. This might need
;; tweaking.
(electric-pair-mode t)
(use-package paren
;; Highlight matching parens.
:config
(show-paren-mode 1))
;; Case inflection, like a bawss.
(use-package string-inflection
:ensure t
:bind (("C-c i" . string-inflection-cycle)
("C-c C" . string-inflection-camelcase)
("C-c P" . string-inflection-lower-camelcase)
("C-c S" . string-inflection-underscore)
("C-c U" . string-inflection-upcase)
)
)
;;; Global Key Bindings --------------------------------------------------------
;; Key bindings for external packages are set where the package is loaded.
(use-package hydra
:ensure t)
;; I want to use standard emacs keys where possible but I like CUA's rectangle
;; mode. If you just enable cua mode, it does weird things to try to match Windows
;; keys. I know it sounds tempting, but don't.
;; I may be switching from this soon. Multiple cursor helps and I believe built-in
;; rectangle commands are coming in emacs 25.
(cua-mode t)
(setq cua-auto-tabify-rectangles nil) ; Don't tabify after rectangle commands
(cua-selection-mode t) ; Use rectangle mode, etc., but continue to use emacs keys.
;; Some familiar Windows bindings that don't interfere with standard emacs keys.
(global-set-key (kbd "<home>") 'beginning-of-line)
(global-set-key (kbd "<end>") 'end-of-line)
(global-set-key (kbd "C-<home>") 'beginning-of-buffer)
(global-set-key (kbd "C-<end>") 'end-of-buffer)
(global-set-key (kbd "C-<backspace>") (quote backward-kill-word))
;; Hopping between visible buffers is something I do a lot so a key without a
;; prefix is necessary. To help me remember, I've disabled the original key and
;; put a message in to remind (annoy) me.
(global-set-key (kbd "M-o") 'other-window)
(global-set-key (kbd "C-x o") 'mk/annoy-other-window)
(defun mk/annoy-other-window()
(interactive)
(message "Use M-o instead!"))
;; Replacing is something else I do a lot so a quick key is needed. (Once you
;; get used to buffer narrowing, search and replace becomes a lot more powerful.)
(global-set-key (kbd "M-r") 'replace-string)
;; Compare windows.
(global-set-key (kbd "C-c C-w") 'compare-windows)
;; Semantic mode
(global-set-key (kbd "C-x .") 'semantic-complete-jump)
(global-set-key (kbd "C-x ,") 'semantic-ia-fast-jump)
;; Common paired programming characters.
;;(global-set-key (kbd "M-[") 'insert-pair)
;;(global-set-key (kbd "M-{") 'insert-pair)
;;(global-set-key (kbd "M-\"") 'insert-pair)
;;(global-set-key (kbd "M-\'") 'insert-pair)
(global-set-key (kbd "M-)") 'delete-pair)
;; Complete tag finding
(global-set-key (kbd "M-RET") 'hippie-expand) ;; used to be 'complete-tag'
;; Commenting/uncommenting. I have no idea why this immensely useful function
;; is not defaulted.
(global-set-key (kbd "C-c k") 'comment-or-uncomment-region)
;; Used for indenting code.
;; M-S-right and M-S-left will shift left and right one space at a time.
;; These will do python indentation shifting, so 4 chars
(global-set-key [(control c) (>)] `python-indent-shift-right)
(global-set-key [(control c) (<)] `python-indent-shift-left)
(transient-mark-mode 0)
;; The cycle-spacing function does the job of multiple functions. Replace
;; delete-horizontal-whitespace. Particularly useful since Cmd-SPC is used by
;; spotlight on OS X.
;;
;; Note that a function that behaves differently based on how many times you call
;; it in a row is something I'm seeing more of. C-l used to just recenter the
;; window, but at some point pressing it again moves the line to the top and then
;; to the bottom. M-r behaves similarly.
(global-set-key "\M-\\" 'cycle-spacing)
;; To open info directly to a manual, e.g. "Python". I really need to use this
;; more.
(global-set-key (kbd "C-x C-i") 'info-display-manual)
;; Recolor the current buffer. This is handy when you paste from one type of
;; buffer to another and emacs keeps the previous buffer's coloring (or when
;; emacs just gets confused). I haven't needed this as much as I used to.
(global-set-key (kbd "<f6>") 'font-lock-fontify-buffer)
;; wdired mode
(global-set-key (kbd "C-c w d") 'wdired-change-to-wdired-mode)
;; customized dired: will display directory recursively when called with an argument
(defun op-i:dired (rec)
(interactive "P")
(let ((dir (car (find-file-read-args "Dired: " nil)))
(opts (if rec (read-string "options: " "-lhAR") "-lhA")))
(if (file-directory-p dir) (dired dir opts))))
(define-key (current-global-map) (kbd "C-x C-d") 'op-i:dired)
;;; Bookmarks and registers
(set-register ?0 (cons 'file "/Users/anderson/src/ivory"))
(set-register ?1 (cons 'file "/Users/anderson/src/ivory/web/static_src/coffee"))
;;; OS Integration -------------------------------------------------------------
;; Copy the PATH from the shell. On OS X, GUI programs don't pick up
;; environment variables from your login shell.
(use-package exec-path-from-shell
:ensure t
:if (eq system-type 'darwin)
:config (exec-path-from-shell-initialize))
;; Support drag-and-drop in OS X. (I think it already works on Windows.)
;;
;; - normally the file opens a new buffer
;; - Holding meta inserts file contents instead
;; - Holding shift inserts filename instead
;;
;; Emacs must be the current window for this to work. However, you can Cmd-tab
;; while dragging to make it current.
(when (eq system-type 'darwin)
(define-key global-map [M-ns-drag-file] 'ns-insert-file)
(define-key global-map [S-ns-drag-file] 'ns-insert-filename)
(define-key global-map [ns-drag-file] 'ns-find-file-in-frame)
(defun ns-insert-filename ()
"Insert contents of first element of `ns-input-file' at point."
(interactive)
(let ((f (pop ns-input-file)))
(insert f))
(if ns-input-file ; any more? Separate by " "
(insert " ")))
(defun ns-find-file-in-frame ()
"Do a `find-file' with the `ns-input-file' as argument; staying in frame."
(interactive)
(let ((ns-pop-up-frames nil))
(ns-find-file))))
(defun sudo-edit (&optional arg)
"Edit currently visited file as root.
With a prefix ARG prompt for a file to visit.
Will also prompt for a file to visit if current
buffer is not visiting a file."
;; From http://emacsredux.com/blog/2013/04/21/edit-files-as-root/
(interactive "P")
(if (or arg (not buffer-file-name))
(find-file (concat "/sudo:root@localhost:"
(ido-read-file-name "Find file(as root): ")))
(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
;;; dired ----------------------------------------------------------------------
;; This allows dired-x to intercept find-file.
(setq dired-x-hands-off-my-keys nil)
(add-hook 'dired-mode-hook (lambda () (dired-omit-mode t)))
(eval-after-load "dired-aux"
'(add-to-list 'dired-compress-file-suffixes
'("\\.zip\\'" ".zip" "unzip")))
(define-key global-map "\C-x\C-j" 'dired-jump)
(define-key global-map "\C-x4\C-j" 'dired-jump-other-window)
;; http://stackoverflow.com/questions/1431351/how-do-i-uncompress-unzip-within-emacs
(eval-after-load "dired"
'(define-key dired-mode-map "z" 'dired-zip-files))
(defun dired-zip-files (zip-file)
"Create an archive containing the marked files."
(interactive "sEnter name of zip file: ")
;; create the zip file
(let ((zip-file (if (string-match ".zip$" zip-file) zip-file (concat zip-file ".zip"))))
(shell-command
(concat "zip -9 "
zip-file
" "
(concat-string-list
(mapcar
'(lambda (filename)
(file-name-nondirectory filename))
(dired-get-marked-files))))))
(revert-buffer)
;; remove the mark on all the files "*" to " "
;; (dired-change-marks 42 ?\040)
;; mark zip file
;; (dired-mark-files-regexp (filename-to-regexp zip-file))
)
(defun concat-string-list (list)
"Return a string which is a concatenation of all elements of the list separated by spaces"
(mapconcat '(lambda (obj) (format "%s" obj)) list " "))
(require 'dired)
(require 'dired-x)
;; Sort directories to the top like the operating systems do.
(setq ls-lisp-dirs-first t)
(when (eq system-type 'darwin)
(setq dired-listing-switches "-lah"))
;; http://xahlee.org/emacs/emacs_dired_open_file_in_ext_apps.html
(defun open-in-external-app ()
"Open the current file or dired marked files in external app.
Works in Microsoft Windows, Mac OS X, Linux."
(interactive)
(let ( doIt
(myFileList
(cond
((string-equal major-mode "dired-mode") (dired-get-marked-files))
(t (list (buffer-file-name))))))
(setq doIt (if (<= (length myFileList) 5)
t
(y-or-n-p "Open more than 5 files?")))
(when doIt
(cond
((string-equal system-type "windows-nt")
(mapc (lambda (fPath) (w32-shell-execute "open" (replace-regexp-in-string "/" "\\" fPath t t))) myFileList)
)
((string-equal system-type "darwin")
(mapc (lambda (fPath) (let ((process-connection-type nil)) (start-process "" nil "open" fPath))) myFileList))
((string-equal system-type "gnu/linux")
(mapc (lambda (fPath) (let ((process-connection-type nil)) (start-process "" nil "xdg-open" fPath))) myFileList))))))
;; M-x reveal-in-finder
;;
;; From dired, open Finder to the current file. No key binding since it isn't
;; used often.
(use-package reveal-in-osx-finder
:ensure t
:if (eq system-type 'darwin))
;;; ediff ----------------------------------------------------------------------
(defconst ediff-ignore-similar-regions t)
(defconst ediff-use-last-dir t)
(defconst ediff-diff-options " -b ") ; add "w" for ignore whitespace
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-horizontally)
;;; smerge
(setq smerge-command-prefix "v")
;;; grep -----------------------------------------------------------------------
;; Don't grep into generated directories. I'm sure this list will get much
;; longer. There is probably a better way to do this.
(eval-after-load "grep"
'(progn
(add-to-list 'grep-find-ignored-directories "node_modules")
(add-to-list 'grep-find-ignored-directories "build")))
(global-set-key (kbd "C-M-g") 'rgrep)
;; wgrep - "writable grep results". Let's you edit the grep results and then
;; write the changes back to the original files. Not in MELPA stable so loading
;; a local copy.
(use-package wgrep
:load-path "misc"
;;:bind (("C-c C-p" . wgrep-change-to-wgrep-mode)
;; ("C-x C-q" . wgrep-change-to-wgrep-mode)) ; match dired
:config
(progn
;; wgrep-finish-edit has multiple bindings, but the one that makes the most
;; sense to me is "C-c C-c". Remove the others so the help text actually
;; displays the key I like.
(define-key wgrep-mode-map (kbd "C-x C-s") nil)
(define-key wgrep-mode-map (kbd "C-c C-e") nil)
(setq wgrep-auto-save-buffer t)))
;;; Buffers --------------------------------------------------------------------
;; Eliminate the confirmation when killing a buffer by setting the standard
;; "C-x k" key to our own function.
(defun kill-current-buffer ()
"Kill the current buffer, without confirmation."
(interactive)
(kill-buffer (current-buffer)))
;;(global-set-key (kbd "C-x k") 'kill-current-buffer)
;; Eliminate 'kill buffer' query for running processes (SQL windows, etc.).
(setq kill-buffer-query-functions
(remove 'process-kill-buffer-query-function
kill-buffer-query-functions))
;; When I complete a task on a project, I usually kill either everything or
;; everything except the current magit buffer. I run these with M-x.
(defun kill-all-buffers ()
"Kill all buffers, asking permission on modified ones."
(interactive)
(let ((list (buffer-list)))
(while list
(let* ((buffer (car list))
(name (buffer-name buffer)))
(and (not (string-equal name ""))
(kill-buffer buffer)))
(setq list (cdr list))))
(cd "~"))
;; kill-other-buffers normally doesn't delete any special buffers (e.g. those
;; with a star like the scratch buffer). Use C-u before running to kill all
;; other buffers.
(defun kill-other-buffers (&optional arg)
"Kill all buffers but the current one.
Don't mess with special buffers unless prefix is provided."
(interactive "P")
(dolist (buffer (buffer-list))
(unless (or
(eql buffer (current-buffer))
(and (not arg) (not (buffer-file-name buffer))))
(kill-buffer buffer))))
;; Swap two buffers. Often when I split, they are in the opposite order of what
;; I want.
;;
;; http://emacswiki.org/emacs/TransposeWindows
(defun swap-windows ()
"*Swap the positions of this window and the next one."
(interactive)
(let ((other-window (next-window (selected-window) 'no-minibuf)))
(let ((other-window-buffer (window-buffer other-window))
(other-window-hscroll (window-hscroll other-window))
(other-window-point (window-point other-window))
(other-window-start (window-start other-window)))
(set-window-buffer other-window (current-buffer))
(set-window-hscroll other-window (window-hscroll (selected-window)))
(set-window-point other-window (point))
(set-window-start other-window (window-start (selected-window)))
(set-window-buffer (selected-window) other-window-buffer)
(set-window-hscroll (selected-window) other-window-hscroll)
(set-window-point (selected-window) other-window-point)
(set-window-start (selected-window) other-window-start))
(select-window other-window)))
(define-key ctl-x-4-map (kbd "t") 'swap-windows)
;; toggle between most recent buffers
(defun switch-to-previous-buffer ()
"Switch to most recent buffer. Repeated calls toggle back and forth between the most recent two buffers."
(interactive)
(switch-to-buffer (other-buffer (current-buffer) 1)))
(global-set-key (kbd "M-O") 'switch-to-previous-buffer)
;;; Editing --------------------------------------------------------------------
(use-package align
;; Set "M-[" to align current variables. Also provides some other handy
;; functions such as align-cols and align-regexp.
:bind (("M-|" . align)))
(use-package align2)
(use-package expand-region
;; Keep pressing "M-2" to expand the region.
;; This project has not added a release tag for a while. Once use-package
;; gets released (ironic, yes) with a default pin, we can load this one
;; package from MELPA unstable. For now, issue #130 is so annoying that I'll
;; just check it out here.
;; :ensure t
:load-path "misc/expand-region"
:bind (("M-+" . er/expand-region)))
(use-package zop-to-char
;; By default "M-z" is zap-to-char (with an "a") and is incredibly handy.
;; This package replaces that with *selecting* up to the character instead of
;; deleting. The old behavior now requires one more key, but you have more
;; options. It's worth using, but it doesn't always do what I expect so I
;; might need to write a simpler one.
:ensure t
:bind ("C-z" . zop-to-char))
(use-package whole-line-or-region
;; This package makes cut and copy take the whole line if there is no
;; selection. Even better, if a line is copied, it is pasted back in as a
;; line above the current one instead of being inserted exactly where the
;; cursor is, possibly breaking a line.
:ensure t
:diminish whole-line-or-region-mode
:config (whole-line-or-region-mode 1))
(defun dup-line ()
"Duplicate the current line and move down to the new line."
;; This was my goto for duplicating the current line, but now that I've
;; installed whole-line-or-region I might not need it.
(interactive nil)
(let ((str (concat
(buffer-substring (point) (save-excursion (end-of-line) (point)))
"\n"
(buffer-substring (save-excursion (beginning-of-line) (point)) (point)))))
(insert str)))
(global-set-key (kbd "M-S-<return>") 'dup-line)
;; This binding uses the same prefix as moving lines up and down, which are
;; operations I often do together. It is also more comfortable to use.
(use-package drag-stuff
;; drag-stuff allows you to use M-up/dn to "drag" text around. Works with a
;; selection too. You can also use M-left/right with selected text. (If text
;; is not selected, left and right appear to try to move the current word but
;; does something weird with cursor placement.)
:ensure t
:diminish drag-stuff-mode
:config
(progn
(drag-stuff-global-mode t)
;; drag-stuff includes the line the cursor is on even when the cursor is at
;; the beginning because you highlighted the lines above it:
;; https://github.com/rejeep/drag-stuff.el/issues/4
;;
;; Use the before and after hooks to change the region being dragged, then
;; change it back after to eliminate this case.
;; https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-drag-stuff.el
;; http://emacs.stackexchange.com/a/13942/115
(defvar modi/drag-stuff--point-adjusted nil)
(defvar modi/drag-stuff--point-mark-exchanged nil)
(defun modi/drag-stuff--adj-pt-pre-drag ()
"If a region is selected AND the `point' is in the first column, move
back the point by one char so that it ends up on the previous line. If the
point is above the mark, exchange the point and mark temporarily."
(when (region-active-p)
(when (< (point) (mark)) ; selection is done starting from bottom to up
(exchange-point-and-mark)
(setq modi/drag-stuff--point-mark-exchanged t))
(if (zerop (current-column))
(progn
(backward-char 1)
(setq modi/drag-stuff--point-adjusted t))
;; If point did not end up being on the first column after the
;; point/mark exchange, revert that exchange.
(when modi/drag-stuff--point-mark-exchanged
(exchange-point-and-mark) ; restore the original point and mark loc
(setq modi/drag-stuff--point-mark-exchanged nil)))))
(defun modi/drag-stuff--rst-pt-post-drag ()
"Restore the `point' to where it was by forwarding it by one char after
athe vertical drag is done."
(when modi/drag-stuff--point-adjusted
(forward-char 1)
(setq modi/drag-stuff--point-adjusted nil))
(when modi/drag-stuff--point-mark-exchanged
(exchange-point-and-mark) ; restore the original point and mark loc
(setq modi/drag-stuff--point-mark-exchanged nil)))
(add-hook 'drag-stuff-before-drag-hook #'modi/drag-stuff--adj-pt-pre-drag)
(add-hook 'drag-stuff-after-drag-hook #'modi/drag-stuff--rst-pt-post-drag)))
;; Shift the selected region right if distance is postive, left if negative. I
;; only need this because drag-stuff doesn't always work.
(defun shift-region (distance)
(let ((mark (mark)))
(save-excursion
(indent-rigidly (region-beginning) (region-end) distance)
(push-mark mark t t)
;; Tell the command loop not to deactivate the mark
;; for transient mark mode
(setq deactivate-mark nil))))
(defun shift-right ()
(interactive)
(shift-region 1))
(defun shift-left ()
(interactive)
(shift-region -1))
(global-set-key [M-S-right] 'shift-right)
(global-set-key [M-S-left] 'shift-left)
(defun fill-buffer ()
"Runs fill-region on the entire buffer. (Word wrap the entire
file."
(interactive)
(save-excursion
(fill-region (point-min) (point-max))))
;; A function to insert a new line below the current without breaking the
;; current line. This is useful because of the automatic closing quotes and
;; parens means I'm often finished typing the current line but not at the end of
;; it.
(defun newline-without-break ()
"Insert a new line below current and move cursor there."
(interactive)
(end-of-line)
(newline-and-indent))
(global-set-key (kbd "<S-return>") 'newline-without-break)
;;; Inserting Info Into The Buffer ---------------------------------------------
(defun insert-date ()
"Insert date in YYYY-MM-DD format at point."
(interactive)
(insert (format-time-string "%Y-%m-%d")))
(defun uuidgen ()
"Insert a new UUID at point."
(interactive)
(insert
(downcase (substring (shell-command-to-string "uuidgen") 0 36))))
;; F11 inserts a comment with "REVIEW: ", used like "TODO".
(defun mk-insert-review ()
(interactive)
(comment-dwim nil)
(insert "REVIEW: "))
(global-set-key (kbd "<f11>") 'mk-insert-review)
;; C-F11 inserts "DO NOT CHECK IN" as a comment. (The comment character is
;; determined by the current mode.) I sometimes set a git precommit hook to
;; reject a file if it has this. Use this when adding something you *really*
;; don't want checked in.
(defun mk-insert-donotcheckin ()
(interactive)
(comment-dwim nil)
(insert "DO NOT CHECK IN")
(newline-and-indent))
(global-set-key (kbd "C-<f11>") 'mk-insert-donotcheckin)
;;; Search ---------------------------------------------------------------------
;; In isearch you normally press Enter to exit isearch and leave the cursor at
;; the current search result. Pressing C-Enter will exit isearch but leave the
;; cursor at the /other/ end of the search string.
(defun isearch-exit-other-end (rbeg rend)
"Exit isearch, but at the other end of the search string.
This is useful when followed by an immediate kill."
(interactive "r")
(isearch-exit)
(goto-char isearch-other-end))
(define-key isearch-mode-map [(control return)] 'isearch-exit-other-end)
;; "M-s _" starts an isearch for the current symbols, but the binding feels very
;; different from "C-s". Instead, use the prefix to initiate. (This is still a
;; bit awkward to press.
(global-set-key (kbd "C-.") 'isearch-forward-symbol-at-point)
;;; Scratch Buffer -------------------------------------------------------------
;; The scratch buffer should be easy to get to. Press F8 to go to it, creating
;; a new one if necessary. If it is not already visible, it will be opened at
;; the bottom of the window 8 lines tall. This is useful for taking quick notes
;; or pasting something you don't want to lose without taking over the window.
(defvar scratch-window-height 8
"*Number of lines in scratch window. If nil, use Emacs default.")
(defun show-scratch ()
"Makes the scratch buffer the current one, creating it if necessary."
(interactive)
(let ((buf (get-buffer-create "*scratch*")))
(pop-to-buffer buf nil)
(scratch-set-window-height (get-buffer-window buf))
(switch-to-buffer buf)))
(global-set-key (kbd "<f8>") 'show-scratch)
; Enlarge the current window. Useful after compiling splits the window in half.
(global-set-key (quote [f2]) 'enlarge-window-mk)
(fset 'enlarge-window-mk "\C-u19\C-x^")
;; modified copy of compilation-set-window-height
(defun scratch-set-window-height (window)
"Set the height of WINDOW according to `scratch-window-height'."
(and scratch-window-height
(= (window-width window) (frame-width (window-frame window)))
;; If window is alone in its frame, aside from a minibuffer,
;; don't change its height.
(not (eq window (frame-root-window (window-frame window))))
;; This save-excursion prevents us from changing the current buffer,
;; which might not be the same as the selected window's buffer.
(save-excursion
(let ((w (selected-window)))
(unwind-protect
(progn
(select-window window)
(enlarge-window (- scratch-window-height
(window-height))))
;; The enlarge-window above may have deleted W, if
;; scratch-window-height is large enough.
(when (window-live-p w)
(select-window w)))))))
;;; Miscellaneous Text Functions -----------------------------------------------
(defun uniquify-region (beg end)
"remove duplicate adjacent lines in the given region"
(interactive "*r")
(goto-char beg)
(while (re-search-forward "^\\(.*\n\\)\\1+" end t)
(replace-match "\\1")))
(defun uniquify-buffer ()
(interactive)
(uniquify-region (point-min) (point-max)))
;;; System Functions -----------------------------------------------------------
(defun copy-buffer-file-name (use-backslashes)
"Puts the file name of the current buffer (or the current directory,
if the buffer isn't visiting a file) onto the kill ring, so that it
can be retrieved with \\[yank], or by another program. With argument,
uses backslashes instead of forward slashes."
(interactive "P")
(let ((fn (subst-char-in-string
?/
(if use-backslashes ?\\ ?/)
(or
(buffer-file-name (current-buffer))
;; Perhaps the buffer isn't visiting a file at all. In
;; that case, let's return the directory.
(expand-file-name default-directory)))))
(when (null fn)
(error "Buffer doesn't appear to be associated with any file or directory."))
(kill-new fn)
(message "%s" fn)
fn))
(global-set-key (quote [S-f6]) 'copy-buffer-file-name)
;; Sometimes it isn't obvious what face you are trying to customize. This tells
;; you what face is under the cursor.
(defun font-lock-face()
"Displays the font-lock face at point."
(interactive)
(prin1 (get-text-property (point) 'face)))
;;; Project Support ------------------------------------------------------------
;; projectile provides completion for files in a project. It has a lot of other
;; features, so be sure to read up on it. This is one of those packages you
;; should spend time researching.
;; The `projectile-other-file-alist` allows me to use "C-c p a" to quickly
;; switch to another file with the same filename but a different extension.
;; recentf is required for "C-c p e" (projectile-recentf).
(recentf-mode 1)