-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathinit.el
2118 lines (1877 loc) · 77.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
;; -*- lexical-binding: t -*-
;;; package管理システムの初期設定
;; package.el
(customize-set-variable
'package-archives '(("melpa" . "https://melpa.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")
("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;; straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 6))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;; leaf.el
(eval-and-compile
(unless (package-installed-p 'leaf)
(package-refresh-contents)
(package-install 'leaf))
(leaf leaf-keywords
:ensure t
:init
;; optional packages if you want to use :hydra, :el-get, :blackout,,,
(leaf blackout :ensure t)
(leaf diminish :ensure t)
:config
;; initialize leaf-keywords.el
(leaf-keywords-init)))
(leaf leaf-tree :ensure t)
(leaf leaf-convert :ensure t)
(leaf cus-edit
:doc "init.elに自動的に書き込ませない。
書き出し先は雑に決定している。
基本的に書き出さないで良いが、
稀にGUIなどから値を設定したいときがあるかもしれないので/dev/nullにはしないでいる。"
:custom `((custom-file . ,(locate-user-emacs-file "custom.el")))) ;
(leaf package
:init
(defun package-menu-mode-setup ()
"パッケージ名の幅を広く取る。"
(setf (cadr (aref tabulated-list-format 0)) 50))
(defun package-load-path-native-compile-async (&rest _)
"だいたいのパッケージをネイティブコンパイルする。
最初に読み込むより先にコンパイルすることにより、更新後のストレスなどを抑える。"
(interactive)
(native-compile-async load-path 'recursively))
:hook (package-menu-mode-hook . package-menu-mode-setup)
:advice (:after package-install package-load-path-native-compile-async))
;;; 早めにserverを起動することで二重起動の可能性を減らす
(leaf server :global-minor-mode t)
;;; PATH
(leaf exec-path-from-shell
:doc "Windowsのwslg.exeやmacOSのランチャーなどから起動したときはシェルの環境変数を引き継がないため、
Emacs側でシェルを読み込む。"
:ensure t
:when window-system
;; wslg.exeでshell-typeをnoneにすると何故かここで新しいインスタンスが起動してループするため注意。
:config (exec-path-from-shell-initialize))
(leaf nix-mode
:ensure t
:init
(defun nix-mode-setup ()
(add-hook 'before-save-hook #'nix-format-before-save nil t))
:hook (nix-mode-hook . nix-mode-setup)
:bind
(:nix-mode-map
([remap indent-whole-buffer] . nix-format-buffer)))
(leaf envrc
:ensure t
:global-minor-mode envrc-global-mode
:custom (envrc-none-lighter . nil))
(leaf add-node-modules-path :ensure t :defun add-node-modules-path)
;;; 初期時実行
(leaf startup
:custom
(inhibit-startup-screen . t) ; スタートアップ画面を出さない
(mail-host-address . "ncaq.net")) ; これでuser-mail-addressも設定されます
(defun kill-buffer-if-exist (BUFFER-OR-NAME)
"バッファが存在すればkillする. 無ければ何もしない."
(when (get-buffer BUFFER-OR-NAME)
(kill-buffer BUFFER-OR-NAME)))
;; 起動時に作られる使わないバッファを削除する
(kill-buffer-if-exist "*scratch*")
;;; 設定からある程度独立した定義
(leaf f
:ensure t
:require t
:defun f-file? f-read-text
:config
(defconst system-type-wsl
(let ((osrelease-file "/proc/sys/kernel/osrelease"))
(and
(eq system-type 'gnu/linux)
(f-file? osrelease-file)
(string-match-p "WSL" (f-read-text osrelease-file))))
"EmacsがWSLで動いているか?"))
(leaf ncaq-emacs-utils :vc (:url "https://github.com/ncaq/ncaq-emacs-utils") :require t)
(defun open-home ()
(interactive)
(find-file "~/"))
(defun open-desktop ()
(interactive)
(find-file "~/Desktop/"))
(defun open-downloads ()
(interactive)
(find-file "~/Downloads/"))
(defun open-google-drive ()
(interactive)
(find-file "~/GoogleDrive/"))
(defun open-win-downloads ()
(interactive)
(find-file "~/WinDownloads/"))
(defun open-document-current ()
(interactive)
(let ((find-file-visit-truename t))
(find-file "~/Documents/current/")))
(defun open-ncaq-entry ()
(interactive)
(find-file "~/Desktop/www.ncaq.net/site/entry/"))
(defun open-ncaq-entry-current-time ()
(interactive)
(find-file (concat
"~/Desktop/www.ncaq.net/site/entry/"
(format-time-string "%Y-%m-%d-%H-%M-%S" (current-time)) ".md")))
;;; Dvorak設定をするための関数達
(defun reverse-cons (c)
"consセル、つまりpairをswap。"
(cons (cdr c) (car c)))
(defun trans-bind (key-map key-pair)
"(入れ替え先のキー, 再設定するコマンド)を生成。"
(cons (kbd (car key-pair)) (command-or-nil (lookup-key key-map (kbd (cdr key-pair))))))
(defun command-or-nil (symbol)
"対象がコマンドでない場合はnilを返す。"
(when (commandp symbol) symbol))
(defun swap-set-key (key-map key-pairs)
"key-pairsのデータに従ってキーを入れ替える。"
(mapc
(lambda (kc)
(when (or (cdr kc) (lookup-key key-map (car kc)))
;; 無駄にnilを増やさないように新規コマンドがnilで挿入先キーマップのコマンドもnilならキーを挿入しない。
(define-key key-map (car kc) (cdr kc))))
(mapcar
(lambda (kp)
(trans-bind key-map kp))
(append key-pairs (mapcar 'reverse-cons key-pairs)))))
(defconst qwerty-dvorak
'(("b" . "h")
("f" . "s")
("p" . "t"))
"htnsbf形式のために標準的に入れ替える必要があるキー。")
(defun prefix-key-pair (from-prefix to-prefix key-pair)
"プレフィクス付きの入れ替えキーペアを作る。"
(cons (concat from-prefix (car key-pair)) (concat to-prefix (cdr key-pair))))
(defun dvorak-set-key (key-map)
"標準的なモードをhtnsbf形式にする。"
(let ((prefixes '(("" . "")
("C-" . "C-")
("M-" . "M-")
("C-M-" . "C-M-")
("C-c C-" . "C-c C-")
("M-g M-" . "M-g M-"))))
(mapc
(lambda (pp)
(swap-set-key key-map (mapcar
(lambda (kp)
(prefix-key-pair (car pp) (cdr pp) kp))
qwerty-dvorak)))
prefixes)))
(defun dvorak-set-key-prog (key-map)
"prog-modeベースのマップに対して入れ替えを設定する。"
(swap-set-key key-map '(("M-h" . "C-x p") ("C-M-h" . "C-x d")))
(mapc
(lambda (key)
(when (lookup-key key-map key)
(define-key key-map (kbd key) 'nil)))
'("C-o" "M-b" "C-M-b" "C-q" "M-q" "C-M-q"))
(dvorak-set-key key-map))
;;; Dvorak設定をするだけのコード
(dvorak-set-key global-map)
(swap-set-key global-map '(("M-g p" . "M-g t")))
;; minibuffer-local-map is a variable defined in `C source code'.
(dvorak-set-key-prog minibuffer-local-map)
(leaf isearch
:bind (:isearch-mode-map
("C-b" . isearch-delete-char)
("M-b" . isearc-del-char)
("M-m" . isearch-exit-previous))
:config (dvorak-set-key-prog isearch-mode-map))
(leaf popup
:ensure t
;; 何故か`popup-close'などは`interactive'ではないため自前で書いて強制的に書き換える
;; 何故`interactive'じゃないのに動くんでしょう…
:bind (:popup-menu-keymap
("C-f" . popup-isearch)
("C-b" . nil)
("C-p" . nil)
("C-t" . popup-previous)
("C-s" . popup-open)))
(leaf compile
:after t
:defvar compilation-minor-mode-map compilation-mode-map compilation-shell-minor-mode-map
:config
(dvorak-set-key-prog compilation-minor-mode-map)
(dvorak-set-key-prog compilation-mode-map)
(dvorak-set-key-prog compilation-shell-minor-mode-map))
(leaf hexl
:bind (:hexl-mode-map
("C-t" . nil) ; undefinedを無効化する
("M-g" . nil)
([remap quoted-insert] . hexl-quoted-insert))
:config (dvorak-set-key-prog hexl-mode-map))
(leaf info :after t :config (dvorak-set-key-prog Info-mode-map))
(leaf prog-mode :after t :config (dvorak-set-key-prog prog-mode-map))
(leaf comint :after t :defvar comint-mode-map :config (dvorak-set-key-prog comint-mode-map))
(leaf diff-mode :after t :defvar diff-mode-map :config (dvorak-set-key-prog diff-mode-map))
(leaf doc-view :after t :defvar doc-view-mode-map :config (dvorak-set-key-prog doc-view-mode-map))
(leaf help-mode :after t :defvar help-mode-map :config (dvorak-set-key-prog help-mode-map))
(leaf make-mode :after t :defvar makefile-mode-map :config (dvorak-set-key-prog makefile-mode-map))
(leaf pascal :after t :defvar pascal-mode-map :config (dvorak-set-key-prog pascal-mode-map))
(leaf rect :after t :defvar rectangle-mark-mode-map :config (dvorak-set-key-prog rectangle-mark-mode-map))
(leaf rst :after t :defvar rst-mode-map :config (dvorak-set-key-prog rst-mode-map))
;;; global-set-key
(leaf *global-set-key
:leaf-autoload nil
:bind
("<tab>" . indent-for-tab-command) ; <tab>に何かしらを割り当てることでC-iと別扱いになります
("C-'" . mc/mark-all-dwim)
("C-+" . text-scale-increase)
("C-," . off-input-method)
("C--" . text-scale-decrease)
("C-." . on-input-method)
("C-=" . text-scale-reset)
("C-^" . dired-jump)
("C-a" . smart-move-beginning-of-line)
("C-b" . backward-delete-char-untabify)
("C-i" . indent-whole-buffer)
("C-j" . helm-do-grep-ag-project-dir-or-fallback)
("C-o" . helm-for-files-prefer-recentf)
("C-p" . other-window-fallback-split)
("C-q" . kill-this-buffer)
("C-u" . kill-whole-line)
("C-w" . kill-region-or-symbol-at-point)
("C-z" . nil)
("C-\\" . quoted-insert)
("C-S-b" . delete-whitespace-backward)
("C-S-d" . delete-whitespace-forward)
("C-S-m" . quoted-newline)
("M-'" . er/expand-region)
("M-/" . point-undo)
("M-?" . point-redo)
("M-b" . backward-kill-word)
("M-c" . help-command)
("M-f" . helm-swoop)
("M-j" . helm-do-grep-ag)
("M-l" . sort-dwim)
("M-m" . newline-under)
("M-n" . scroll-up-one)
("M-o" . helm-for-files-prefer-near)
("M-p" . other-window-backward)
("M-q" . delete-other-windows-force)
("M-r" . revert-buffer-safe-confirm)
("M-t" . scroll-down-one)
("M-u" . duplicate-dwim)
("M-w" . kill-ring-save-region-or-symbol-at-point)
("M-x" . helm-M-x)
("M-y" . helm-show-kill-ring)
("C-M-'" . mc/edit-lines)
("C-M-," . helm-imenu)
("C-M-;" . string-inflection-dwim-style-cycle)
("C-M-b" . backward-kill-sexp)
("C-M-d" . kill-sexp)
("C-M-l" . delete-duplicate-lines)
("C-M-m" . comment-indent-new-line)
("C-M-o" . ibuffer)
("C-M-p" . split-window-dwim-and-other)
("C-M-q" . kill-buffer-and-window)
("C-M-w" . copy-to-register-@)
("C-M-y" . yank-register-@)
("C-M-S-q" . kill-file-or-dired-buffers)
("C-c '" . google-this)
("C-c ;" . align-regexp)
("C-c E" . open-ncaq-entry)
("C-c a" . open-downloads)
("C-c c" . quickrun)
("C-c d" . docker)
("C-c e" . open-ncaq-entry-current-time)
("C-c g" . open-google-drive)
("C-c h" . open-home)
("C-c i" . open-win-downloads)
("C-c j" . rg)
("C-c o" . open-desktop)
("C-c p" . package-list-packages)
("C-c r" . recentf-cleanup)
("C-c s" . customize-set-variable)
("C-c u" . open-document-current)
("C-c v" . envrc-allow)
("C-x d" . mark-defun)
("C-x g" . insert-random-uuid)
("C-x p" . mark-paragraph)
("C-x t" . insert-iso-datetime)
("C-x w" . mark-whole-word)
("C-x x" . mark-whole-sexp)
("C-c C-;" . align-space)
("C-x C-f" . helm-find-files)
("<help> c" . helpful-command)
("<help> w" . helm-man-woman)
("C-x <RET> u" . revert-buffer-with-coding-system-utf-8-unix)
("C-x <RET> s" . revert-buffer-with-coding-system-japanese-cp932-dos))
;;; History
(leaf recentf
:custom
((recentf-max-saved-items . 2000)
(recentf-exclude . '("\\.elc$" "\\.o$" "~$" "\\.file-backup/" "\\.undo-tree/" "EDITMSG" "PATH" "TAGS" "autoloads"))))
(leaf recentf-ext :ensure t :after docker-tramp :require t)
(leaf recentf-remove-sudo-tramp-prefix :ensure t :global-minor-mode t :blackout t)
(leaf savehist :global-minor-mode t)
(leaf desktop
:global-minor-mode desktop-save-mode
:defvar desktop-minor-mode-table
:custom
(desktop-globals-to-save . nil)
(desktop-restore-frames . nil))
(leaf save-place-mode :global-minor-mode t)
(leaf files
:defvar auto-save-file-dir
:pre-setq `(auto-save-file-dir . ,(concat user-emacs-directory "auto-save-file/"))
:custom
;; バックアップ先をカレントディレクトリから変更
(backup-directory-alist . `(("." . ,(concat user-emacs-directory "file-backup/"))))
;; askだと件数を超えた自動削除時時に一々聞いてくるのでtに変更
(delete-old-versions . t)
;; backupに新しいものをいくつ残すか
(kept-new-versions . 10)
;; 複数バックアップ
(version-control . t)
;; 自動保存ファイルを同じディレクトリに作らない
(auto-save-file-name-transforms . `((".*" ,auto-save-file-dir t)))
:config (unless (file-directory-p auto-save-file-dir) (make-directory auto-save-file-dir)))
(leaf tramp :custom (tramp-allow-unsafe-temporary-files . t)) ; バックアップファイルをroot絡みでも自動許可する。
(leaf filelock :custom (create-lockfiles . nil)) ; percelがバグるのでロックファイルとしてシンボリックリンクを作らない
;;; テキストなどの見た目
(leaf *font
:init
(defun font-setup ()
(set-face-attribute
'default
nil
:family "HackGen Console NF"
;; 2画面分割でだいたい横120文字を表示できるフォントサイズにする。
;; フルHDと4Kを想定。
:height (if (<= (frame-pixel-width) 1920) 108 130))
(set-fontset-font t 'unicode (font-spec :name "HackGen Console NF") nil 'append)
(unless (eq system-type 'darwin)
(set-fontset-font t '(#x1F000 . #x1FAFF) (font-spec :name "Noto Color Emoji") nil 'append)))
;; `frame-pixel-width'がフレーム作成後でないと実用的な値を返さないので、
;; 初期化後にフォントサイズを設定します。
:hook (window-setup-hook . font-setup))
;; シンタックスハイライトをグローバルで有効化
(leaf font-core :config (global-font-lock-mode 1))
;; テーマを読み込む
(leaf solarized-theme :ensure t :config (load-theme 'solarized-dark t))
(leaf treesit-auto
:ensure t
:require t
:custom (treesit-auto-install. . t))
;; 以下の順番で読み込まないと正常に動かなかった
;; rainbow-delimiters -> rainbow-mode
;; 括弧の対応を色対応でわかりやすく
(leaf rainbow-delimiters
:ensure t
:hook
prog-mode-hook
web-mode-hook
:custom-face (rainbow-delimiters-depth-1-face . '((t (:foreground "#586e75"))))) ; 文字列の色と被るため変更
;; 色コードを可視化
(leaf rainbow-mode
:ensure t
:hook
css-mode-hook
emacs-lisp-mode-hook
hamlet-mode-hook
help-mode-hook
lisp-mode-hook
sass-mode-hook
scss-mode-hook
web-mode-hook)
;; カットペーストなど挿入削除時にハイライト
(leaf volatile-highlights :ensure t :global-minor-mode t :blackout t)
;; 置換の動きを可視化
(leaf anzu
:ensure t
:global-minor-mode global-anzu-mode
:blackout t
:bind
([remap query-replace] . anzu-query-replace)
([remap query-replace-regexp] . anzu-query-replace-regexp))
;;; toolkit
(leaf frame
:doc "全画面化。"
:init
(eval-and-compile
(defun frame-maximized ()
"画面を全画面化する(not fullscreen)。
`toggle-frame-maximized'のトグルじゃないバージョン。"
(interactive)
(set-frame-parameter nil 'fullscreen 'maximized)))
:config (frame-maximized))
(leaf image-file :global-minor-mode auto-image-file-mode)
(leaf bindings
:config
;; ((ファイル名 or バッファ名) モード一覧)
(setq frame-title-format '(:eval (list "emacs " (or (buffer-file-name) (buffer-name)) " " mode-line-modes)))
;; mode-line line and column and sum char numbar
(setq mode-line-position
'(:eval
(list
"l%l/"
(number-to-string (count-lines (point-min) (point-max)))
" c"
(number-to-string (- (point) (line-beginning-position)))
"/"
(number-to-string (- (line-end-position) (line-beginning-position)))
" s"
(number-to-string (point))
"/%i"))))
;; バッファの名前にディレクトリ名を付けることでユニークになりやすくする
(leaf uniquify :require t :custom (uniquify-buffer-name-style . 'forward))
;;; Emacs同梱パッケージの小さな設定
(leaf *c-source-code
:custom
(delete-by-moving-to-trash . t) ; ごみ箱を有効
(indent-tabs-mode . nil) ; インデントをスペースで行う
(message-log-max . 100000) ; メッセージをたくさん残す
(read-buffer-completion-ignore-case . t) ; 大文字と小文字を区別しない バッファ名
(read-file-name-completion-ignore-case . t) ; 大文字と小文字を区別しない ファイル名
(read-process-output-max . 3145728) ; プロセスから一度に読み込む量を増やす、3MB
(ring-bell-function . #'ignore) ; ビープ音を消す
(scroll-conservatively . 1) ; 最下段までスクロールした時のカーソルの移動量を減らす
(scroll-margin . 5) ; 最下段までスクロールしたという判定を伸ばす
`(user-full-name . ,(user-login-name))) ; WSL2などでは環境変数`NAME'が`hostname'と同じ値になってしまうことへの対応
(leaf autorevert :global-minor-mode global-auto-revert-mode) ; 自動再読込
(leaf executable :hook (after-save-hook . executable-make-buffer-file-executable-if-script-p)) ; スクリプトに実行権限付加
(leaf files :custom (require-final-newline . t)) ; ファイルの最後に改行
(leaf indent :custom (standard-indent . 2)) ; フォールバック標準インデント値を2にする
(leaf novice :custom (disabled-command-function . nil)) ; 初心者向けに無効にされているコマンドを有効にする
(leaf select :custom (select-enable-clipboard . t)) ; クリップボードをX11と共有
(leaf subr :config (fset 'yes-or-no-p 'y-or-n-p)) ; "yes or no"を"y or n"に
(leaf vc-hooks :custom (vc-follow-symlinks . t)) ; 常にシンボリックリンクをたどる
(leaf warnings :custom (warning-minimum-level . :error)) ; 警告はエラーレベルでないとポップアップ表示しない
(leaf simple
:custom
(blink-matching-paren . nil) ; 括弧移動無効
(kill-ring-max . 600)) ; メモリに余裕があるのでクリップボードの履歴数を増やす
;;; 操作補助
(leaf dired
:custom
(dired-auto-revert-buffer . t) ; diredの自動再読込
(dired-dwim-target . t) ; コピーなどを行う時に隣のバッファを対象にする
(dired-isearch-filenames . t) ; isearchの対象をファイル名のみにする
(dired-recursive-copies . 'always) ; 聞かずに再帰的コピー
(dired-recursive-deletes . 'always) ; 聞かずに再帰的削除
`(dired-listing-switches
. ,(concat "-Fhval" (when (string-prefix-p "gnu" (symbol-name system-type)) " --group-directories-first")))
:bind (:dired-mode-map
("C-o" . nil)
("C-p" . nil)
("M-o" . nil)
("C-^" . dired-jump)
("C-c C-t" . wdired-change-to-wdired-mode))
:config (dvorak-set-key-prog dired-mode-map))
(leaf helm
:ensure t
:global-minor-mode t
:blackout t
:custom
;; モードを短縮する基準
(helm-buffer-max-len-mode . 25)
;; デフォルトはファイル名を短縮する区切りが20
(helm-buffer-max-length . 50)
;; デフォルトは50で全体画面表示するから足りない
(helm-candidate-number-limit . 200)
;; kill-line sim
(helm-delete-minibuffer-contents-from-point . t)
;; helm-find-filesにrecentfを使用する
(helm-ff-file-name-history-use-recentf . t)
;; ウインドウ全体に表示
(helm-full-frame . t)
;; `helm-for-files'を多用するためソースは`helm-next-line'などで移動したい。
(helm-move-to-line-cycle-in-source . nil)
:defvar helm-for-files-preferred-list
:init
(defun helm-for-files-prefer-recentf ()
"recentfを優先する`helm-for-files'。"
(interactive)
(let ((helm-for-files-preferred-list
'(helm-source-buffers-list
helm-source-recentf
helm-source-ls-git
helm-source-locate)))
(helm-for-files)))
(defun helm-for-files-prefer-near ()
"git管理下など近い場所のファイルを優先する`helm-for-files'。"
(interactive)
(let ((helm-for-files-preferred-list
'(helm-source-buffers-list
helm-source-ls-git
helm-source-recentf
helm-source-locate)))
(helm-for-files)))
:bind (:helm-map
("C-M-b" . nil)
("C-b" . nil)
("C-h" . nil)
("C-s" . nil)
("M-b" . nil)
("M-s" . nil)
("C-p" . helm-toggle-resplit-and-swap-windows)
("C-t" . helm-previous-line)
("<tab>" . helm-select-action))
:config
(leaf helm-buffers
:bind (:helm-buffer-map ("C-s" . nil))
:defvar helm-boring-buffer-regexp-list
:config
(mapc (lambda (regex) (add-to-list 'helm-boring-buffer-regexp-list (concat "^\\*" regex "\\*$")))
'("Flycheck errors"
"Copilot-chat-list"
"Flymake log"
"WoMan-Log"
"copilot events"
"copilot-balancer"
"copilot-chat-curl-stderr"
"copilot-chat-shell-maker-temp"
"envrc"
"nixfmt"
"prettier.+"
"straight-process"
"sweep Messages"
"tramp.+"
"vc"
".+ls\\(::stderr\\)?"
".+lsp\\(::stderr\\)?"
"eslint\\(::stderr\\)?"
"lsp-.+\\(::stderr\\)?"
"marksman\\(::stderr\\)?"
"nix-nil\\(::stderr\\)?"
"pyright\\(::stderr\\)?")))
(leaf helm-files :bind (:helm-find-files-map ("C-s" . nil)))
(leaf helm-types :bind (:helm-generic-files-map ("C-s" . nil)))
(leaf helm-grep
:custom
;; ripgrepは自動認識されるが、オプションを少し追加。
(helm-grep-ag-command
. "rg --color=always --smart-case --search-zip --no-heading --line-number --type-not=svg --sort=path %s -- %s %s")
;; 検索結果でファイル名だけではなくパスも表示する。
(helm-grep-file-path-style . 'absolute)
:defun project-root helm-grep-ag
:init
(eval-and-compile
(defun helm-do-grep-ag-project-dir (arg)
"プロジェクトディレクトリ以下のファイルを対象に`helm-do-grep-ag'検索を行う。"
(interactive "P")
(helm-grep-ag (expand-file-name (project-root (project-current))) arg))
(defun helm-do-grep-ag-project-dir-or-fallback (arg)
"`helm-do-grep-ag-project-dir' OR `helm-do-grep-ag'."
(interactive "P")
(let ((in-project (ignore-errors (project-root (project-current)))))
(if in-project
(helm-do-grep-ag-project-dir arg)
(helm-do-grep-ag arg)))))
:advice (:before helm-grep-action (lambda (&rest _ignored) (xref-push-marker-stack))))
(leaf helm-descbinds :ensure t :global-minor-mode t)
(leaf helm-swoop :ensure t)
(leaf helm-ls-git
:ensure t
:require t
:defvar helm-source-ls-git-status helm-source-ls-git helm-source-ls-git-buffers helm-ls-git-rebase-todo-mode-map
:defun helm-ls-git-build-git-status-source helm-ls-git-build-ls-git-source helm-ls-git-build-buffers-source
:config
;; git-commmit.elなど特化型のものが存在するためバッファ向けのモードは不要。
(setq auto-mode-alist
(cl-remove-if
(lambda (pair)
(member
(cdr pair)
'(helm-ls-git-commit-mode helm-ls-git-rebase-todo-mode)))
auto-mode-alist))
;; helm-for-filesで出力するのには手動初期化が必要。
(setq helm-source-ls-git-status
(helm-ls-git-build-git-status-source)
helm-source-ls-git
(helm-ls-git-build-ls-git-source)
helm-source-ls-git-buffers
(helm-ls-git-build-buffers-source))
(swap-set-key helm-ls-git-rebase-todo-mode-map '(("M-p" . "M-t")))))
(leaf ibuffer
:custom `(ibuffer-formats . '((mark modified read-only " " (name 60 30) " " (size 6 -1) " " (mode 16 16) " " filename)
(mark " " (name 60 -1) " " filename))) ; 幅を大きくする
:bind (:ibuffer-mode-map
("C-o" . nil)
("C-t" . nil)
("M-g" . nil))
:after t
:defvar ibuffer-mode-map
:config (dvorak-set-key-prog ibuffer-mode-map))
(leaf man
:custom
(Man-notify-method . 'bully) ; Manページを現在のウィンドウで表示
(Man-width-max . nil) ; Manページのwidthの最大幅を除去
:after t
:defvar Man-mode-map
:config (dvorak-set-key-prog Man-mode-map))
(leaf ediff
:custom
(ediff-split-window-function . 'split-window-horizontally) ; ediffでウィンドウを横分割
(ediff-window-setup-function . 'ediff-setup-windows-plain)) ; ediffにframeを生成させない
(leaf auto-sudoedit :ensure t :global-minor-mode t :blackout t)
;;; ジャンプ
(leaf browse-url
:doc "WSLの場合のURLへの紐付けをラップする。"
:when system-type-wsl
:custom
(browse-url-generic-program . "wslview")
(browse-url-browser-function . 'browse-url-generic))
(leaf google-this :ensure t)
(leaf rg
:ensure t
:after t
:defvar rg-mode-map
:config
(dvorak-set-key-prog rg-mode-map)
(swap-set-key rg-mode-map '(("M-P" . "M-T"))))
(leaf xref
:defun xref-push-marker-stack xref-set-marker-ring-length
:config
;; 履歴のサイズを上げるために、
;; `xref-marker-ring-length'を設定したいだけですが、
;; 設定したタイミングでリングのサイズ変更などを行う必要があるので専用関数が用意されているようです。
(xref-set-marker-ring-length 'xref-marker-ring-length 128))
(leaf smart-jump
:ensure t
:custom
(smart-jump-find-references-fallback-function . 'smart-jump-find-references-with-rg)
(smart-jump-refs-key . "C-M-.")
:bind
("M-." . smart-jump-go)
("M-," . smart-jump-back)
("C-M-." . smart-jump-references))
;;; 補完
(leaf company
:ensure t
:global-minor-mode global-company-mode
:blackout t
:custom
;; companyの自動補完スタートを無効化します。
;; 理由はhaskell-mode, company-posframeの組み合わせの時、自動補完が一瞬現れては消える謎の挙動をするためです。
;; 原因は不明ですが、もともと自動補完開始をあまり使っていなかったため、手動補完開始のみを使うことにします。
(company-idle-delay . nil)
(company-dabbrev-code-other-buffers . 'all)
(company-dabbrev-downcase . nil)
(company-dabbrev-other-buffers . 'all)
:bind
(:company-mode-map
("<C-iso-lefttab>" . company-dabbrev)
("C-<tab>" . company-complete))
(:company-active-map
("<backtab>" . company-select-previous)
("<tab>" . company-complete-common-or-cycle)
("C-h" . nil))
:defvar company-backends company-search-map
:config
(dvorak-set-key-prog company-active-map)
;; company-search-mapの入力をそのまま受け付ける特殊性に対応するワークアラウンド。
(define-key company-search-map (kbd "C-c") nil)
(dvorak-set-key company-search-map)
(leaf company-box
:when window-system
:ensure t
:require t
:blackout t
:hook company-mode-hook))
(leaf yasnippet
:ensure t
:global-minor-mode yas-global-mode
:blackout yas-minor-mode
:defun yas-expand-snippet yas-lookup-snippet
:bind (:yas-minor-mode-map
("<tab>" . nil)
("TAB" . nil)
("C-c C-y" . company-yasnippet)
("M-z" . yas-insert-snippet))
:config (leaf yasnippet-snippets :ensure t))
;;; GitHub copilot
(leaf copilot
:vc (:url "https://github.com/copilot-emacs/copilot.el")
:init
(defun turn-on-copilot-mode ()
(interactive)
(copilot-mode 1))
;; 起動時に無限再帰してしまう問題から`global-copilot-mode'をしばらく諦める。
;; [global-copilot-mode uses entire system memory · Issue #226 · copilot-emacs/copilot.el](https://github.com/copilot-emacs/copilot.el/issues/226)
:hook ((text-mode-hook prog-mode-hook) . turn-on-copilot-mode)
:bind
("C-; C-k" . copilot-mode)
(:copilot-completion-map
("<tab>" . copilot-accept-completion)
("TAB" . copilot-accept-completion)
("C-M-n" . copilot-next-completion)
("C-M-t" . copilot-previous-completion)))
(leaf copilot-chat
:ensure t
:after request ; 要求しないとトークンが無視され毎回認証が必要になる。
:require t
:bind
("C-; C-;" . copilot-chat-display)
("C-; C-a" . copilot-chat-ask-and-insert)
("C-; C-b" . copilot-chat-list)
("C-; C-c" . copilot-chat-custom-prompt-selection)
("C-; C-d" . copilot-chat-doc)
("C-; C-e" . copilot-chat-explain)
("C-; C-f" . copilot-chat-fix)
("C-; C-l" . copilot-chat-add-current-buffer)
("C-; C-m" . copilot-chat-set-model)
("C-; C-o" . copilot-chat-optimize)
("C-; C-q" . copilot-chat-reset)
("C-; C-r" . copilot-chat-review)
("C-; C-t" . copilot-chat-test)
("C-; C-u" . copilot-chat-del-current-buffer)
:defvar copilot-chat-prompt
:init
(defconst copilot-chat-prompt-japanese "Please respond in Japanese.")
(defun copilot-chat-set-japanese ()
"日本語を使うように小さくプロンプトを再設定する。"
(setq copilot-chat-prompt copilot-chat-prompt-japanese))
:custom
(copilot-chat-commit-prompt . "Here is the result of running `git diff --cached`.
Generate a commit message in Conventional Commits specification.
Do not use any markers around the commit message.
Don't add anything else to the response.
The following describes Conventional Commits.
# Conventional Commits 1.0.0
## Summary
The Conventional Commits specification is a lightweight convention on top of commit messages.
It provides an easy set of rules for creating an explicit commit history;
which makes it easier to write automated tools on top of.
This convention dovetails with [SemVer](http://semver.org),
by describing the features, fixes, and breaking changes made in commit messages.
The commit message should be structured as follows:
---
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
---
<br />
The commit contains the following structural elements, to communicate intent to the
consumers of your library:
1. **fix:** a commit of the _type_ `fix` patches a bug in your codebase (this correlates with [`PATCH`](http://semver.org/#summary) in Semantic Versioning).
1. **feat:** a commit of the _type_ `feat` introduces a new feature to the codebase (this correlates with [`MINOR`](http://semver.org/#summary) in Semantic Versioning).
1. **BREAKING CHANGE:** a commit that has a footer `BREAKING CHANGE:`, or appends a `!` after the type/scope, introduces a breaking API change (correlating with [`MAJOR`](http://semver.org/#summary) in Semantic Versioning).
A BREAKING CHANGE can be part of commits of any _type_.
1. _types_ other than `fix:` and `feat:` are allowed, for example [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) (based on the [Angular convention](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)) recommends `build:`, `chore:`,
`ci:`, `docs:`, `style:`, `refactor:`, `perf:`, `test:`, and others.
1. _footers_ other than `BREAKING CHANGE: <description>` may be provided and follow a convention similar to
[git trailer format](https://git-scm.com/docs/git-interpret-trailers).
Additional types are not mandated by the Conventional Commits specification, and have no implicit effect in Semantic Versioning (unless they include a BREAKING CHANGE).
<br /><br />
A scope may be provided to a commit's type, to provide additional contextual information and is contained within parenthesis, e.g., `feat(parser): add ability to parse arrays`.
## Examples
### Commit message with description and breaking change footer
```
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
```
### Commit message with `!` to draw attention to breaking change
```
feat!: send an email to the customer when a product is shipped
```
### Commit message with scope and `!` to draw attention to breaking change
```
feat(api)!: send an email to the customer when a product is shipped
```
### Commit message with both `!` and BREAKING CHANGE footer
```
chore!: drop support for Node 6
BREAKING CHANGE: use JavaScript features not available in Node 6.
```
### Commit message with no body
```
docs: correct spelling of CHANGELOG
```
### Commit message with scope
```
feat(lang): add Polish language
```
### Commit message with multi-paragraph body and multiple footers
```
fix: prevent racing of requests
Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.
Remove timeouts which were used to mitigate the racing issue but are
obsolete now.
Reviewed-by: Z
Refs: #123
```
## Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).
1. Commits MUST be prefixed with a type, which consists of a noun, `feat`, `fix`, etc., followed
by the OPTIONAL scope, OPTIONAL `!`, and REQUIRED terminal colon and space.
1. The type `feat` MUST be used when a commit adds a new feature to your application or library.
1. The type `fix` MUST be used when a commit represents a bug fix for your application.
1. A scope MAY be provided after a type. A scope MUST consist of a noun describing a
section of the codebase surrounded by parenthesis, e.g., `fix(parser):`
1. A description MUST immediately follow the colon and space after the type/scope prefix.
The description is a short summary of the code changes, e.g., _fix: array parsing issue when multiple spaces were contained in string_.
1. A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.
1. A commit body is free-form and MAY consist of any number of newline separated paragraphs.
1. One or more footers MAY be provided one blank line after the body. Each footer MUST consist of
a word token, followed by either a `:<space>` or `<space>#` separator, followed by a string value (this is inspired by the
[git trailer convention](https://git-scm.com/docs/git-interpret-trailers)).
1. A footer's token MUST use `-` in place of whitespace characters, e.g., `Acked-by` (this helps differentiate
the footer section from a multi-paragraph body). An exception is made for `BREAKING CHANGE`, which MAY also be used as a token.
1. A footer's value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer
token/separator pair is observed.
1. Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the
footer.
1. If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g.,
_BREAKING CHANGE: environment variables now take precedence over config files_.
1. If included in the type/scope prefix, breaking changes MUST be indicated by a
`!` immediately before the `:`. If `!` is used, `BREAKING CHANGE:` MAY be omitted from the footer section,
and the commit description SHALL be used to describe the breaking change.
1. Types other than `feat` and `fix` MAY be used in your commit messages, e.g., _docs: update ref docs._
1. The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.
1. BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.
---
The following describes type.
# type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs, GitHub Actions)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
---
Here is the result of `git diff --cached`: