-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinit.el
2092 lines (1875 loc) · 70.4 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
;;; init.el --- douo's emacs config -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
;;; 个人用
;; disable first narrow hint
(put 'narrow-to-region 'disabled nil)
;; Move customization variables to sparate file
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
(load custom-file 'noerror 'nomessage)
;; 正确处理 CJK 字符的自动断行
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=29364#11
;; https://emacs-china.org/t/topic/2616/18
(setq word-wrap-by-category t)
;; 自动加载外部修改过的文件,如果当前 buffer 未修改
;; revert buffers automatically when underlying files are changed externally
(global-auto-revert-mode 1)
;; 禁止 Emacs 自动生成备份文件,例如 init.el~ 。
(setq make-backup-files nil)
;; the toolbar/menubar/scrollbar is just a waste of valuable screen estate
(when (fboundp 'tool-bar-mode)
(tool-bar-mode -1))
(when (fboundp 'menu-bar-mode)
(menu-bar-mode -1))
(when (fboundp 'scroll-bar-mode)
(scroll-bar-mode -1))
;; disable the annoying bell ring
(setq ring-bell-function 'ignore)
;; disable startup screen
(setq inhibit-startup-screen t)
;; nice scrolling
(setq scroll-margin 0
scroll-conservatively 100000
scroll-preserve-screen-position 1)
;; mode line settings
(line-number-mode t)
(column-number-mode t)
(size-indication-mode t)
;; enable y/n answers
(fset 'yes-or-no-p 'y-or-n-p)
;; more useful frame title, that show either a file or a
;; buffer name (if the buffer isn't visiting a file)
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))))
;; Emacs modes typically provide a standard means to change the
;; indentation width -- eg. c-basic-offset: use that to adjust your
;; personal indentation width, while maintaining the style (and
;; meaning) of any files you load.
(setq-default indent-tabs-mode nil) ;; don't use tabs to indent
(setq-default tab-width 8) ;; but maintain correct appearance
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(when (not (version< emacs-version "29"))
;; https://www.masteringemacs.org/article/whats-new-in-emacs-29-1?utm_source=newsletter&utm_medium=rss#:~:text=C%2Dc%20j%20might%20be%20good.
(keymap-global-set "C-c j" #'duplicate-dwim)
;; sqlite-mode 不能通过 find-file 直接打开,需要通过 sqlite-mode-open-file
(keymap-global-set "C-x t s" #'sqlite-mode-open-file)
(custom-set-variables
;; 如果光标在一个闭合分隔符内且开放分隔符不在屏幕上显示,则在回显区域显示开放分隔符周围的一些上下文。默认值为nil。
'(show-paren-context-when-offscreen 'child-frame)
;; flymake mode-line prefix
'(flymake-mode-line-lighter " ")
;; 进程列表(proced)显示颜色
'(proced-enable-color-flag 't)
)
)
;; 长行优化
;; https://emacs-china.org/t/topic/25811/9
(setq-default bidi-display-reordering nil)
(setq bidi-inhibit-bpa t
long-line-threshold 1000
large-hscroll-threshold 1000
syntax-wholeline-max 1000)
;;初始化包管理器
(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))
(straight-use-package 'package-lint)
(straight-use-package '(org :type built-in))
;; 以下代码可以用于调试 use-package,将宏展开后的代码输出到当前位置
;; (let ((use-package-expand-minimally t))
;; (pp-emacs-lisp-code
;; (macroexpand-all
;; '(use-package foo
;; :after bar))))
(straight-use-package 'use-package)
(use-package transient
:straight `(transient :type git :host github :repo "magit/transient" :branch "main"))
;; 提供简单的方法修改 minor-mode 在 modeline 中的 indicator
(straight-use-package 'diminish)
;; 与 diminish 不兼容
(use-package minions
:straight t
:config
(minions-mode 1)
;; (add-to-list 'minions-promoted-modes 'flymake-mode)
;; 不隐藏 flymake-mode 的 indicator
(add-to-list 'minions-prominent-modes 'flymake-mode)
)
;;
(use-package benchmark-init
:straight t
:config
;; To disable collection of benchmark data after init is done.
(add-hook 'after-init-hook 'benchmark-init/deactivate))
(require 'minibuffer)
(setq use-package-verbose t)
;;On OS X (and perhaps elsewhere) the $PATH environment variable and
;; `exec-path' used by a windowed Emacs instance will usually be the
;; system-wide default path, rather than that seen in a terminal window.
(use-package exec-path-from-shell
:straight t
:config
(when (or (memq window-system '(mac ns x)) (daemonp))
(dolist (var '("RG_EXECUTABLE" "WRITING_HOME" "GTD_HOME" ;; personal
"CONDA_EXE" ;; conda
))
(add-to-list 'exec-path-from-shell-variables var))
(exec-path-from-shell-initialize)))
(use-package load-relative
:straight t)
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(require 'init-vars)
(require 'init-utils)
(with-system darwin
(require 'init-osx))
(with-system windows-nt
(require 'init-windows))
(with-system darwin
;; https://stackoverflow.com/questions/57591432/gpg-signing-failed-inappropriate-ioctl-for-device-on-macos-with-maven
;; 让 EPA 使用 Emacs 自己的密码提示,而不是外部的 Pinentry 程序。
(setq epa-pinentry-mode 'loopback))
;; repeat-mode
;; emacs 28 之后内置
(use-package repeat
:straight (:type built-in)
:init
(defun repeatize (keymap)
"Add `repeat-mode' support to a KEYMAP."
(map-keymap
(lambda (_key cmd)
(when (symbolp cmd)
(put cmd 'repeat-map keymap)))
(symbol-value keymap)))
:config
(repeatize 'smerge-basic-map)
:hook
;; 当repeat-mode处于活动状态时,第一次调用前缀 ( ex:M-g ) 会“激活”键盘映射
;; 此后仅需要命令的“基本”键(ex: n/p) 即可重复调用命令
;; 按任意非 keymap 里的按键会退出 repeat-mode(也可以通过`repeat-exit-key'配置)
;; 类似的包有 hydra, smartrep
(after-init . repeat-mode)
)
;;; 用 embark 或 which-key 代替原来的 `repeat-echo-function'
;;; 能显示函数名和描述,而不仅仅是按键名
(use-package repeat-help
:straight t
;; 进入 repeat-mode 时自动显示 repeat-help
;; 默认是通过 C-h (`repeat-help-key')手动触发
;; 因为 repeat-help 会 disable `repeat-echo-function',
:hook (repeat-mode . repeat-help-mode)
:config
;; 取消 repeat-help 对 repeat-echo-function 的修改
;; `ignore' 的话,进入 repeat-mode 时会没有任何提示
(advice-add 'repeat-help-mode :after (lambda (&rest _) (setq repeat-echo-function #'repeat-echo-message))))
;; begin_casual
(use-package casual
:straight (:type git :host github :repo "kickingvegas/casual")
:defer t
:custom (casual-lib-use-unicode t))
(use-package casual-symbol-overlay
:straight (:type git :host github :repo "kickingvegas/casual-symbol-overlay")
:after symbol-overlay
:bind
(:map symbol-overlay-map
("C-o" . casual-symbol-overlay-tmenu)))
(use-package casual-avy
:straight (:type git :host github :repo "kickingvegas/casual-avy")
:after avy
:bind
("M-g a" . casual-avy-tmenu))
(keymap-global-set "C-o" #'casual-editkit-main-tmenu)
;; 参考 https://github.com/kickingvegas/casual/discussions/60
(use-package calendar
:bind
(:map calendar-mode-map ("C-o" . casual-calendar-tmenu))
:defer t)
;; Calc 模式的绑定
(use-package calc
:bind
(:map calc-mode-map ("C-o" . casual-calc-tmenu))
:defer t)
;; Dired 模式绑定
(use-package dired
:bind
:config
(add-hook 'dired-mode-hook 'dired-async-mode) ; 启用异步模式
(:map dired-mode-map
("C-o" . casual-dired-tmenu)
("s" . casual-dired-sort-by-tmenu)
("/" . casual-dired-search-replace-tmenu)
;; build-in
("<C-return>" . dired-do-open)
("E" . wdired-change-to-wdired-mode) ;; default is `dired-do-open'
("M-n" . dired-next-dirline)
("M-p" . dired-prev-dirline)
("]" . dired-next-subdir)
("[" . dired-prev-subdir)
("A-M-<mouse-1>" . browse-url-of-dired-file)
("<backtab>" . dired-prev-subdir)
("TAB" . dired-next-subdir)
("M-j" . dired-goto-subdir)
(";" . image-dired-dired-toggle-marked-thumbs))
:defer t)
(use-package dired-x
; dired-x 是 dired 的扩展,Emacs 内置
:after dired)
(use-package wdired
; wdired 是 Emacs 内置的
:after dired)
(use-package image-dired
; image-dired 是 Emacs 内置的
:after dired
:bind
(:map image-dired-thumbnail-mode-map
("n" . image-dired-display-next)
("p" . image-dired-display-previous)))
;; Isearch 模式绑定
(use-package isearch
:bind
(:map isearch-mode-map ("C-o" . casual-isearch-tmenu))
:defer t)
;; Ibuffer 模式绑定
(use-package ibuffer
:hook (ibuffer-mode . ibuffer-auto-mode)
:bind
(:map ibuffer-mode-map
("C-o" . casual-ibuffer-tmenu)
("F" . casual-ibuffer-filter-tmenu)
("s" . casual-ibuffer-sortby-tmenu)
;; build-in
("{" . ibuffer-backwards-next-marked)
("}" . ibuffer-forward-next-marked)
("[" . ibuffer-backward-filter-group)
("]" . ibuffer-forward-filter-group)
("$" . ibuffer-toggle-filter-group))
:defer t)
;; Info 模式绑定
(use-package info
:hook
(Info-mode . scroll-lock-mode)
:bind
(:map Info-mode-map
("C-o" . casual-info-tmenu)
;; 历史导航
("M-[" . Info-history-back)
("M-]" . Info-history-forward)
;; 段落导航
("p" . casual-info-browse-backward-paragraph)
("n" . casual-info-browse-forward-paragraph)
;; 节点和引用导航
("h" . Info-prev)
("j" . Info-next-reference)
("k" . Info-prev-reference)
("l" . Info-next)
;; 搜索和书签
("/" . Info-search)
("B" . bookmark-set))
:defer t)
;; Reb 模式绑定
(use-package re-builder
:bind
(:map reb-mode-map ("C-o" . casual-re-builder-tmenu)
:map reb-lisp-mode-map ("C-o" . casual-re-builder-tmenu))
:defer t)
;; Bookmark 模式绑定
(use-package bookmark
:bind
(:map bookmark-bmenu-mode-map
("C-o" . casual-bookmarks-tmenu)
("J" . bookmark-jump))
:defer t)
;; end_casual
;; begin_nerd-icons
(use-package nerd-icons
:straight t
;; The Nerd Font you want to use in GUI
;; "Symbols Nerd Font Mono" is the default and is recommended
;; set font-family to `Hack Nerd Font Mono' if it exist in (font-family-list)
:config
;; NL 表示 no-ligatures 即没有使用连字,保留了字符的原始样式。这样的变体通常在代码编辑器和终端中更具有可读性,因为它们保留了字符的独特形状。
;; Mono 变体: "Mono" 变体意味着该字体是等宽字体,适用于代码编辑器和终端。每个字符的宽度相同,从而确保代码的对齐和格式化保持一致,提高了代码的可读性。
;; Propo 变体: "Propo" 变体意味着该字体是比例字体,适用于文本编辑器和图形应用程序。每个字符的宽度不同,从而确保文本的对齐和格式化保持一致,提高了文本的可读性。
;; https://github.com/ryanoasis/nerd-fonts/discussions/1103
(if (member "JetBrainsMonoNL Nerd Font Propo" (font-family-list))
(setq nerd-icons-font-family "JetBrainsMonoNL Nerd Font Propo")
(if (member "Hack Nerd Font Mono" (font-family-list))
(setq nerd-icons-font-family "Hack Nerd Font Mono")
)
)
;; temporary fix for https://github.com/rainstormstudio/nerd-icons.el/issues/29
(setf (alist-get 'benchmark-init/tree-mode nerd-icons-mode-icon-alist) '(nerd-icons-faicon "nf-fa-dashboard"))
)
(use-package nerd-icons-dired
:straight t
:hook
(dired-mode . nerd-icons-dired-mode))
(use-package nerd-icons-ibuffer
:straight t
:hook (ibuffer-mode . nerd-icons-ibuffer-mode))
;; 提供 minibuf 补全的图标(文件)
(use-package nerd-icons-completion
:straight t
:after marginalia
:config
(nerd-icons-completion-mode)
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
(use-package nerd-icons-corfu
:straight t
:after corfu
:config
;; Add formatter to Corfu margin
(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
;; Optionally customize icon mapping
(setq nerd-icons-corfu-mapping
'((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
(boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
;; ...
(t :style "cod" :icon "code" :face font-lock-warning-face))))
;; end_nerd-icons
;; https://github.com/akermu/emacs-libvterm
(if (not IS-WINDOWS)
(progn
(use-package vterm
:straight t)
(use-package multi-vterm
:straight t
:init
(transient-define-prefix multi-vterm-transient ()
"Multi vterm transient"
["Multi vterm"
("c" "Create new terminal" multi-vterm)
("n" "Switch to next terminal" multi-vterm-next :transient t)
("p" "Switch to next terminal" multi-vterm-prev :transient t)
;; dedicated ;在当前 window 中 按照高度百分比创建一个 terminal(单例)
("t" "Toggle dedicated terminal" multi-vterm-dedicated-toggle)
("g" "Create/toggle terminal based on current project" multi-vterm-project)
]
)
(defun douo/multi-vterm-dedicated-toggle (arg)
"Toggle dedicated vterm."
(interactive "P")
(if arg
(call-interactively 'multi-vterm-transient)
(multi-vterm-dedicated-toggle)))
:bind (
("s-t" . douo/multi-vterm-dedicated-toggle)
("C-c t" . douo/multi-vterm-dedicated-toggle)))))
;; Library for converting first letter of Pinyin to Simplified/Traditional Chinese characters.
(use-package pinyinlib
:straight t)
(use-package recentf
:bind (("C-x C-r" . 'recentf-open-files))
:config
(setq recentf-max-menu-items 10
recentf-max-saved-items 25)
(recentf-mode +1))
;; 高亮当前行
(use-package hl-line
:config
(global-hl-line-mode +1))
;; 同文件名的 buffer 名更容易识别
(use-package uniquify
:config
(setq uniquify-buffer-name-style 'forward)
(setq uniquify-separator "/")
;; rename after killing uniquified
(setq uniquify-after-kill-buffer-p t)
;; don't muck with special buffers
(setq uniquify-ignore-buffers-re "^\\*"))
;; saveplace 上次保存文件时光标的位置
(use-package saveplace
:config
;; activate it for all buffers
(save-place-mode +1))
;;; 高亮括号
(use-package paren
:config
(show-paren-mode +1))
;; 自动补全引号、括号等
;; 类似 smartparens paredit fingertip
(use-package elec-pair
:config
(electric-pair-mode +1))
;;光标移动方案
;; https://github.com/abo-abo/avy
(use-package avy
:straight t
:init
(transient-define-prefix douo/avy-goto-transient ()
"Avy goto transient menu"
["Avy Goto"
["Char"
("c" "Type 1" avy-goto-char)
("b" "Type 2" avy-goto-char-2)
("t" "Jump to the char when stop typing" avy-goto-char-timer)]
["Line"
("l" "Type 0" avy-goto-line)]
["Word"
("w" "Type 1" avy-goto-word-1)
("W" "Type 0" avy-goto-word-0)
("s" "Type 1 or subword" avy-goto-word-or-subword-1)
]
["Org"
;; `consult-org-heading' 比较方便
("o" "Jump to org heading when stop typing" avy-org-goto-heading-timer)
("r" "Refile as Child with point in an entry" avy-org-refile-as-child)
]
])
(defun douo/avy-goto-char (arg)
"`avy-goto-char' or create a avy-goto transient menu or `avy-resume' depend on `ARG'."
(interactive "P")
(cond
((equal arg '(4))
(call-interactively 'douo/avy-goto-transient))
((null arg)
(call-interactively 'avy-goto-char))
(t (call-interactively 'avy-resume))))
:bind
("C-;" . douo/avy-goto-char)
(:map isearch-mode-map
("C-;" . avy-isearch))
:config
(setq avy-background t)
)
;; avy 支持拼音
(use-package ace-pinyin
:straight t
:diminish "拼"
:config
;;(setq ace-pinyin-treat-word-as-char nil)
(setq ace-pinyin-simplified-chinese-only-p nil)
(ace-pinyin-global-mode +1)
)
;; git
(use-package magit
:straight `(magit :type git :host github :repo "magit/magit")
:after transient
:bind (("C-x g" . magit-status)))
(use-package git-timemachine
:straight t
:bind (("C-x v t" . git-timemachine)))
;;; 高亮未提交更改
;;; alternative: https://github.com/nonsequitur/git-gutter-plus
(use-package diff-hl
:straight t
:after magit
:demand t ;; 保证启动后生效
:config
;; `diff-hl-margin-symbols-alist' 可以自定义显示的符号
(global-diff-hl-mode)
;; 开启实时更新,默认情况需要保存文件才会更新
(diff-hl-flydiff-mode)
:hook
(magit-post-refresh . diff-hl-magit-post-refresh)
;; 在终端模式下开启 margin 显示,默认是 fringe(窗边) 模式,但是终端不支持
;; 用 hook 实现同时兼顾 gui 和终端
;; margin 默认显示的符号是 (insert . "+") (delete . "-") (change . "!") (unknown . "?") (ignored . "i")
(diff-hl-mode .
(lambda ()
(unless (window-system)
(diff-hl-margin-local-mode)))))
;; rg
(use-package rg
:straight t
:config
(rg-enable-default-bindings))
;; https://github.com/magnars/expand-region.el
(use-package expand-region
:straight t
:bind ("C-=" . er/expand-region))
;; 更强大的 kill&yank
;; 代替 expand-region?
(use-package easy-kill
:straight t
:config
(keymap-global-set "<remap> <kill-ring-save>" 'easy-kill))
;; 显示匹配数量
(use-package anzu
:straight t
:bind (("M-%" . anzu-query-replace)
("C-M-%" . anzu-query-replace-regexp))
:config
(global-anzu-mode))
;; 移动整个选择文本
(use-package move-text
:straight t
:bind
(([(meta shift up)] . move-text-up)
([(meta shift down)] . move-text-down)))
;; 用不同颜色区别嵌套的括号引号等
(use-package rainbow-delimiters
:straight t
:hook (prog-mode . rainbow-delimiters-mode))
;; 代码中的颜色值可视化
(use-package colorful-mode
:straight t
:diminish "括";;" " ;; "🌈"
:hook prog-mode)
;; 空格可视化
(use-package whitespace
:init
(dolist (hook '(prog-mode-hook))
(add-hook hook #'whitespace-mode))
(add-hook 'before-save-hook #'whitespace-cleanup)
:diminish "空";;" "
:config
(setq whitespace-style '(face tabs empty trailing )))
;; temporarily highlight changes from yanking, etc
(use-package volatile-highlights
:straight t
:config
(volatile-highlights-mode +1))
;; Save Emacs buffers when they lose focus
(use-package super-save
:straight t
:diminish "存";;" "
:config
(super-save-mode +1))
;; 旋转 frame 布局
(use-package transpose-frame
:straight t)
;; 隐藏文本内容
;; 保留颜色用方块代替字符
;; 类似内置的 `toggle-rot13-mode'
(use-package redacted
:straight t
:commands redacted-mode)
;; 翻译
(use-package go-translate
:straight t
:init
(defun douo/go-do-translate (text-property-string)
(gt-start (gt-translator
:taker (gt-taker
;; 单个换行替换为空格
:text (replace-regexp-in-string
"\\([^\n]\\)\n\\([^\n]\\)" "\\1 \\2"
text-property-string))
:engines (gt-google-engine)
:render (gt-posframe-pop-render))))
:custom
(gt-cache-p t)
(gt-langs '(en zh))
(gt-default-translator
(gt-translator
:taker (gt-taker :langs '(en zh) :text (lambda () (replace-regexp-in-string
"\\([^\n]\\)\n\\([^\n]\\)" "\\1 \\2"
(thing-at-point 'paragraph)))
:prompt t
)
:engines (gt-google-engine)
:render (gt-buffer-render)))
:bind
(:map embark-prose-map
;; 覆盖 transpose-xxx
("t" . douo/go-do-translate)
)
(:map embark-region-map
;; 覆盖 transpose-regions
("t" . douo/go-do-translate)
))
;; begin_epub
(use-package nov
:straight t
:config
:mode ("\\.epub\\'" . nov-mode))
;; TODO
;; - [ ] search
;; - [ ] selection
(use-package nov-xwidget
:straight `(nov-xwidget :type git :host github :repo "chenyanming/nov-xwidget")
:demand t
:after nov
:config
(define-key nov-mode-map (kbd "o") 'nov-xwidget-view)
(add-hook 'nov-mode-hook 'nov-xwidget-inject-all-files)
:bind
(:map nov-xwidget-webkit-mode-map
("n" . nov-xwidget-next-document)
("p" . nov-xwidget-previous-document)
("t" . nov-xwidget-goto-toc)))
;; end_epub
;; begin_pdf
(use-package pdf-tools
:straight t
:config
(custom-set-variables
'(pdf-tools-handle-upgrades nil)) ; Use brew upgrade pdf-tools instead.
(setq pdf-info-epdfinfo-program "/usr/local/bin/epdfinfo")
;; 自定义 pdf 翻译文本提取器
;; 如果有高亮返回高亮文本,无则返回整页文本
(defun douo/gts-pdf-view-selection-texter ()
(unless (pdf-view-active-region-p)
(pdf-view-mark-whole-page))
;; remove-newline-characters-if-not-at-the-end-of-sentence
;; ::HACK:: 解决 pdf 提取文本不能正确断行的问题
;; 移除不是处于句尾[.!?]的换行符
(replace-regexp-in-string "\\([^.!?]\\)\n\\([^ ]\\)" "\\1 \\2"
(car (pdf-view-active-region-text))))
(defvar douo/pdf-translater
(gt-translator
:taker (gt-taker :text 'douo/gts-pdf-view-selection-texter)
:engines (list (gt-google-engine))
:render (gt-buffer-render)
;; :splitter (gts-paragraph-splitter)
))
(defun douo/pdf-view-translate ()
(interactive)
(gt-start douo/pdf-translater)
;; cancel selection in emacs
(deactivate-mark))
;; 如果没有 epdfinfo,以下命令重新编译
(pdf-tools-install)
:bind
(:map pdf-view-mode-map
;; consult 不支持与 pdf-tools 的交互
("C-s" . isearch-forward)
("C-r" . isearch-backward)
("T" . douo/pdf-view-translate))
:mode ("\\.pdf\\'" . pdf-view-mode))
;; end_pdf
;; A Collection of Ridiculously Useful eXtensions for Emacs
(use-package crux
:straight t
:bind (
;; 同步常用 macOS 快捷键到其他系统
("s-," . customize)
("s-u" . revert-buffer)
("s-?" . info)
("s-?" . info)
("s-a" . mark-whole-buffer)
("s-w" . delete-frame)
("s-n" . make-frame)
("s-`" . other-frame)
("s-'" . next-window-any-frame)
("s-q" . save-buffers-kill-emacs)
("s-f" . isearch-forward)
("s-F" . isearch-backward)
("s-d" . isearch-repeat-backward)
("s-g" . isearch-repeat-forward)
("s-d" . isearch-repeat-forward)
("s-e" . isearch-yank-kill)
;; crux
("C-s-k" . kill-current-buffer)
;; ("C-c o" . crux-open-with)
("C-c N" . crux-cleanup-buffer-or-region)
("C-c f" . crux-recentf-find-file)
("C-M-z" . crux-indent-defun)
("C-c u" . crux-view-url)
("C-c e" . crux-eval-and-replace)
("C-c D" . crux-delete-file-and-buffer)
("C-c r" . crux-rename-buffer-and-file)
("C-c p" . crux-kill-buffer-truename)
("C-c TAB" . crux-indent-rigidly-and-copy-to-clipboard)
("C-c I" . crux-find-user-init-file)
("C-c S" . crux-find-shell-init-file)
("s-r" . crux-recentf-find-file)
("s-j" . crux-top-join-line)
("C-^" . crux-top-join-line)
("s-k" . crux-kill-whole-line)
("C-<backspace>" . crux-kill-line-backwards)
([remap move-beginning-of-line] . crux-move-beginning-of-line)
;; ("M-o" . crux-smart-open-line)
([(shift return)] . crux-smart-open-line)
;; ("s-o" . crux-smart-open-line-above)
([(control shift return)] . crux-smart-open-line-above)
([remap kill-whole-line] . crux-kill-whole-line)))
(use-package undo-tree
:straight t
:config
;; autosave the undo-tree history
(setq undo-tree-history-directory-alist
`((".*" . ,temporary-file-directory)))
(setq undo-tree-auto-save-history t))
;; 核心扩展
(use-package dired
:config
;; dired - reuse current buffer by pressing 'a'
(put 'dired-find-alternate-file 'disabled nil)
;; always delete and copy recursively
(setq dired-recursive-deletes 'always)
(setq dired-recursive-copies 'always)
;; if there is a dired buffer displayed in the next window, use its
;; current subdir, instead of the current subdir of this dired buffer
(setq dired-dwim-target t)
;; enable some really cool extensions like C-x C-j(dired-jump)
(require 'dired-x))
(use-package eldoc
:diminish "显")
;; 显示音频视频信息
;; require https://archlinux.org/packages/extra/x86_64/mediainfo/
(use-package mediainfo-mode
:straight (mediainfo-mode :type git :host github :repo "xFA25E/mediainfo-mode"))
;;
;; 代码补完前端,当前位置代码补完,弹出补全菜单。
(use-package corfu
;; straight hack. 加载扩展
:straight (:files (:defaults "extensions/*"))
:custom
;; :custom
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
;; (corfu-auto nil) ;; Enable auto completion
;; orderless 是一种高级补完 style
;; 通过 spearator 划分过滤关键字
(corfu-separator ?\s) ;; Orderless field separator
;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect 'prompt) ;; Preselect the prompt
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
;; (corfu-scroll-margin 5) ;; Use scroll margin
:init
(global-corfu-mode)
:config
(defun corfu-move-to-minibuffer ()
(interactive)
(pcase completion-in-region--data
(`(,beg ,end ,table ,pred . ,extras)
(let ((completion-extra-properties (car extras))
completion-cycle-threshold completion-cycling)
(consult-completion-in-region beg end table pred)))))
(keymap-set corfu-map "M-m" #'corfu-move-to-minibuffer)
(add-to-list 'corfu-continue-commands #'corfu-move-to-minibuffer)
:bind
(:map corfu-map
("SPC" . corfu-insert-separator)
("C-M-m" . corfu-move-to-minibuffer)))
;; M-g 跳转候选位置
;; M-h 显示候选文档
;; 自动显示可用 corfu-popupinfo
;; 通过 corfu 引入无需再手动 straight
(use-package corfu-info
:after corfu)
(use-package kind-icon
:straight t
:after corfu
:custom
(kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
;; 提供补完后端 capfs(completion-at-point-functions)
;; 能将 company 后端转换为 capfs
(use-package cape
:straight t
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
;; NOTE: The order matters!
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-file)
;;(add-to-list 'completion-at-point-functions #'cape-elisp-block)
;;(add-to-list 'completion-at-point-functions #'cape-history)
;;(add-to-list 'completion-at-point-functions #'cape-keyword)
;;(add-to-list 'completion-at-point-functions #'cape-tex)
;;(add-to-list 'completion-at-point-functions #'cape-sgml)
;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
;;(add-to-list 'completion-at-point-functions #'cape-abbrev)
;;(add-to-list 'completion-at-point-functions #'cape-dict)
;;(add-to-list 'completion-at-point-functions #'cape-symbol)
;;(add-to-list 'completion-at-point-functions #'cape-line)
;; Bind dedicated completion commands
;; Alternative prefix keys: C-c p, M-p, M-+, ...
:bind-keymap ("M-p" . my-cape-map)
:bind (:map my-cape-map
("p" . completion-at-point) ;; capf
("t" . complete-tag) ;; etags
("d" . cape-dabbrev) ;; or dabbrev-completion
("h" . cape-history)
("f" . cape-file)
("k" . cape-keyword)
("s" . cape-elisp-symbol)
("b" . cape-elisp-block)
("a" . cape-abbrev)
("l" . cape-line)
("w" . cape-dict)
("\\" . cape-tex)
("_" . cape-tex)
("^" . cape-tex)
("&" . cape-sgml)
("r" . cape-rfc1345))
:config
(define-prefix-command 'my-cape-map))
(use-package ace-window
:straight t
:custom
(aw-background t)
(aw-minibuffer-flag t)
(aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
(aw-scope 'frame)
:config
(set-face-attribute
'aw-mode-line-face nil
:inherit 'mode-line-buffer-id
:foreground "lawn green")
;; 默认模式某些 buffer 经常无法显示 override layer
;;; 终端模式也经常遇到显示问题
;; posframe 又不支持终端
;; 直接在 mode-line 固定显示 ace-window 热键
(ace-window-display-mode t) ;;
(setq aw-display-mode-overlay nil)
;; (ace-window-posframe-mode nil)
:bind (
;; 代替 `ace-window' 不用按 ? 就能显示帮助(打印到*Message*)
;; 会导致即便关闭 `aw-dispatch-always' 也会一直显示帮助
("M-o" . aw-show-dispatch-help)
("C-c w" . ace-swap-window)))
;; 内置的 winner-mode 可以记忆窗口布局
(use-package winner-mode
:config
(winner-mode 1)
:bind (;; 回退窗口布局
("M-S-<left>" . winner-undo)
("M-S-<right>" . winner-redo)
;; 与 ace-window 重复
("M-<right>" . windmove-right)
("M-<left>" . windmove-left)
("M-<up>" . windmove-up)
("M-<down>" . windmove-down)))
;; alternative to the built-in Emacs help that provides much more contextual information.
(use-package helpful
:straight t
:bind
("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)
)
;; start vertico
;; minibuffer completion UIs
(use-package vertico
:straight (:files (:defaults "extensions/*"))
:init
(vertico-mode)
:custom
(vertico-cycle t)
(vertico-count 10))
;; extensions
;; 在普通 buffer 而不是 minibuffer 中显示候选项
(use-package vertico-buffer
:after vertico)
(use-package vertico-reverse
:after vertico)
(use-package vertico-multiform
:after vertico
:init
(vertico-multiform-mode +1)
:config
;; bind 可以 vertico buffer 中切换显示方式
;; M-V -> vertico-multiform-vertical
;; M-G -> vertico-multiform-grid
;; M-F -> vertico-multiform-flat
;; M-R -> vertico-multiform-reverse
;; M-U -> vertico-multiform-unobtrusive
)
;; Persist history over Emacs restarts. Vertico sorts by history position.
;; 可以实现访问越频繁的项越靠前
(use-package savehist
:straight t
:init
(savehist-mode))
;; 为 minibuffer 候选项提供更多信息(旁注)
;; Marginalia 连接到 Emacs 补全框架并运行变量 `marginalia-classifiers' 中列出的分类器,这些分类器使用命令的提示符或候选项的其他属性来指定补全类别。
;; 一旦知道候选者的类别,Marginalia 就会在 `marginalia-annotator-registry' 中查找要使用的关联注释器。注释器是一个函数,它将完成候选字符串作为参数,并返回要在迷你缓冲区中的候选后面显示的注释字符串。
(use-package marginalia
:after vertico
:straight t