remacs.org

\n:设置文档的标题

参考链接

面向产品经理的Emacs系列教程

面向产品经理的Emacs系列教程配套配置文件

early-init.el

在Emacs刚启动,还未加载主要配置文件时的配置文件。

在 Emacs Lisp 中,可以使用 functionp 函数来判断一个符号是否绑定到一个函数上。functionp 函数用于检查一个对象是否是一个函数。如果对象是一个函数,functionp 将返回 t,否则返回 nil。

下面是一个示例代码,演示了如何使用 if 条件判断函数是否存在:

1
2
3
  (if (functionp 'g-org-insert-note-header)
	  (message "函数 g-org-insert-note-header 存在")
	(message "函数 g-org-insert-note-header 不存在"))
 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
	 ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*-
	 ;;; Commentary:

	 ;;; Code:

  ;; 设置垃圾回收参数
  (setq gc-cons-threshold most-positive-fixnum)
  (setq gc-cons-percentage 0.6)

  ;; 启动早期不加载`package.el'包管理器
  (setq package-enable-at-startup nil)
  ;; 不从包缓存中加载
  (setq package-quickstart nil)

  ;; 禁止展示菜单栏、工具栏和纵向滚动条
  (push '(menu-bar-lines . 0) default-frame-alist)
  (push '(tool-bar-lines . 0) default-frame-alist)
  (push '(vertical-scroll-bars) default-frame-alist)

  ;; 禁止自动缩放窗口先
  (setq frame-inhibit-implied-resize t)

  ;; 禁止Echo Area显示For information about GNU Emacs and the GNU system,type C-h C-a
  (fset 'display-startup-echo-area-message 'ignore)

  ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框
  (menu-bar-mode -1)  
  (if(functionp 'scroll-bar-mode)
	  (scroll-bar-mode -1))
  (if(functionp 'toogle-menu-bar)
	  (toogle-menu-bar -1)
	)
  (if(functionp 'tool-bar-mode)
	  (tool-bar-mode -1)
	)

  (setq inhibit-splash-screen t)
  (setq use-file-dialog nil)

  ;; 在这个阶段不编译
  (setq comp-deferred-compilation nil)

  (setq frame-title-format "emacs@%b")
  ;;在标题栏显示buffer的名字,而不是 emacs@wangyin.com 这样没用的提示。

  (provide 'early-init)
	 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	 ;;; early-init.el ends here

init.el

init.el 是Emacs的主要配置文件。

init.el 文件头

1
2
3
4
  ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

package包管理配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  (require 'package)
  (setq package-archives
		'(
		  ("melpa-cn" . "https://mirrors.ustc.edu.cn/elpa/melpa/")
		  ("nongnu-cn"   . "https://mirrors.ustc.edu.cn/elpa/nongnu/")
		  ("gnu-cn"   . "https://mirrors.ustc.edu.cn/elpa/gnu/")
		  ;; ("melpa"  . "https://melpa.org/packages/")
		  ;; ("gnu"    . "https://elpa.gnu.org/packages/")
		  ;; ("nongnu" . "https://elpa.nongnu.org/nongnu/")
		  ))

  (package-initialize)

安装use-package插件

use-package 是一个让Emacs配置更加结构化更加清晰的一个宏插件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  ;; 安装 `use-package'
  (unless (package-installed-p 'use-package)
	(package-refresh-contents)
	(package-install 'use-package))

  ;; 配置 `use-package'
  (eval-and-compile
	(setq use-package-always-ensure nil)
	(setq use-package-always-defer nil)
	(setq use-package-expand-minimally nil)
	(setq use-package-enable-imenu-support t)
	(if (daemonp)
		(setq use-package-always-demand t)))

  (eval-when-compile
	(require 'use-package))

  ;; 安装 `use-package' 的集成模块
  (use-package use-package-ensure-system-package
	:ensure t)
  (use-package diminish
	:ensure t)
  (use-package bind-key
	:ensure t)

quelpa包管理器

quelpa 是配合 package.el 使用的,基于git的一个包管理器。

使用示例:

示例1 常规操作

1
2
3
4
5
  (use-package org-super-links
	:quelpa (org-super-links :fetcher github :repo "toshism/org-super-links")
	:bind 
	:config
	)

示例2 github访问不了,使用项目镜像链接

1
2
3
4
5
6
7
  (quelpa
   '(org-super-liks
	 :fetcher git
	 :url "https://hub.nuaa.cf/toshism/org-super-links"))

  (use-package org-super-links
	:ensure nil
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  ;; 安装 `quelpa'
  (use-package quelpa
	:ensure t
	:commands quelpa
	:config  
	:custom
	(quelpa-git-clone-depth 1)
	(quelpa-update-melpa-p nil)
	(quelpa-self-upgrade-p nil)
	(quelpa-checkout-melpa-p nil))

  ;; `quelpa' 与 `use-package' 集成
  (use-package quelpa-use-package
	:ensure t)

加载模块化配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  ;; 将lisp目录放到加载路径的前面以加快启动速度
  (let ((dir (locate-user-emacs-file "lisp")))
	(add-to-list 'load-path (file-name-as-directory dir)))

  ;; 加载各模块化配置
  ;; 不要在`*message*'缓冲区显示加载模块化配置的信息
  (with-temp-message ""
	(require 'init-base)                  ; 一些基本配置
	(require 'init-ui)                    ; UI交互
	(require 'init-edit)                  ; 编辑行为
	(require 'init-completion)            ; 补全系统
	(require 'init-dired)                 ; 文件管理
	(require 'init-tools)                 ; 相关工具
	(require 'init-org)                   ; org相关设置
	(require 'init-rss)                   ; RSS配置
	(require 'init-shell)                 ; Shell配置
	(require 'init-browser)               ; 浏览器配置
	)

init.el 文件尾

1
2
3
4

  (provide 'init)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init.el ends here

init-ui.el

init-ui.el 文件头

1
2
3
4
  ;;; init-ui.el --- UI settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

spacemacs-theme主题

spacemacs-theme 是我非常喜欢的一个主题包。

1
2
3
4
5
6
7
  (use-package spacemacs-theme
	:ensure t
	:config
	(load-theme 'spacemacs-dark t)  ; Dark theme
	;; 或者
	;; (load-theme 'spacemacs-light t) ; Light theme
	)

其他UI零散设置项

  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
  ;; 禁用一些GUI特性
  (setq use-dialog-box nil)               ; 鼠标操作不使用对话框
  (setq inhibit-default-init t)           ; 不加载 `default' 库
  (setq inhibit-startup-screen t)         ; 不加载启动画面
  (setq inhibit-startup-message t)        ; 不加载启动消息
  (setq inhibit-startup-buffer-menu t)    ; 不显示缓冲区列表

  ;; ;; 草稿缓冲区默认文字设置
  ;; (setq initial-scratch-message (concat ";; Happy hacking, "
  ;;                                       (capitalize user-login-name) " - Emacs ♥ you!\n\n"))

  ;; 设置缓冲区的文字方向为从左到右
  (setq bidi-paragraph-direction 'left-to-right)
  ;; 禁止使用双向括号算法
  ;; (setq bidi-inhibit-bpa t)

  ;; 设置自动折行宽度为80个字符,默认值为70
  (setq-default fill-column 80)

  ;; 设置大文件阈值为100MB,默认10MB
  (setq large-file-warning-threshold 100000000)

  ;; ;; 以16进制显示字节数
  ;; (setq display-raw-bytes-as-hex t)
  ;; 有输入时禁止 `fontification' 相关的函数钩子,能让滚动更顺滑
  (setq redisplay-skip-fontification-on-input t)

  ;; 禁止响铃
  (setq ring-bell-function 'ignore)

  ;; 禁止闪烁光标
  (blink-cursor-mode -1)

  ;; 在光标处而非鼠标所在位置粘贴
  (setq mouse-yank-at-point t)

  ;; 拷贝粘贴设置
  (setq select-enable-primary nil)        ; 选择文字时不拷贝
  (setq select-enable-clipboard t)        ; 拷贝时使用剪贴板

  ;; 鼠标滚动设置
  (setq scroll-step 2)
  (setq scroll-margin 0)
  (setq hscroll-step 2)
  (setq hscroll-margin 2)
  (setq scroll-conservatively 101)
  (setq scroll-up-aggressively 0.01)
  (setq scroll-down-aggressively 0.01)
  (setq scroll-preserve-screen-position 'always)

  ;; 对于高的行禁止自动垂直滚动
  (setq auto-window-vscroll nil)

  ;; 设置新分屏打开的位置的阈值
  (setq split-width-threshold (assoc-default 'width default-frame-alist))
  (setq split-height-threshold nil)

  ;; TAB键设置,在Emacs里不使用TAB键,所有的TAB默认为4个空格
  ;; (setq-default indent-tabs-mode nil)
  ;; (setq-default tab-width 4)
  (setq-default indent-tabs-mode t)
  (setq-default tab-width 4)
  (setq c-default-style "linux")
  (setq c-basic-offset 4)

  ;; yes或no提示设置,通过下面这个函数设置当缓冲区名字匹配到预设的字符串时自动回答yes
  (setq original-y-or-n-p 'y-or-n-p)
  (defalias 'original-y-or-n-p (symbol-function 'y-or-n-p))
  (defun default-yes-sometimes (prompt)
	"automatically say y when buffer name match following string"
	(if (or
		 (string-match "has a running process" prompt)
		 (string-match "does not exist; create" prompt)
		 (string-match "modified; kill anyway" prompt)
		 (string-match "Delete buffer using" prompt)
		 (string-match "Kill buffer of" prompt)
		 (string-match "still connected.  Kill it?" prompt)
		 (string-match "Shutdown the client's kernel" prompt)
		 (string-match "kill them and exit anyway" prompt)
		 (string-match "Revert buffer from file" prompt)
		 (string-match "Kill Dired buffer of" prompt)
		 (string-match "delete buffer using" prompt)
		 (string-match "Kill all pass entry" prompt)
		 (string-match "for all cursors" prompt)
		 (string-match "Do you want edit the entry" prompt))
		t
	  (original-y-or-n-p prompt)))
  (defalias 'yes-or-no-p 'default-yes-sometimes)
  (defalias 'y-or-n-p 'default-yes-sometimes)

  ;; 设置剪贴板历史长度300,默认为60
  (setq kill-ring-max 200)

  ;; 在剪贴板里不存储重复内容
  (setq kill-do-not-save-duplicates t)

  ;; 设置位置记录长度为6,默认为16
  ;; 可以使用 `counsel-mark-ring' or `consult-mark' (C-x j) 来访问光标位置记录
  ;; 使用 C-x C-SPC 执行 `pop-global-mark' 直接跳转到上一个全局位置处
  ;; 使用 C-u C-SPC 跳转到本地位置处
  (setq mark-ring-max 6)
  (setq global-mark-ring-max 6)

  ;; 设置 emacs-lisp 的限制
  (setq max-lisp-eval-depth 10000)        ; 默认值为 800
  (setq max-specpdl-size 10000)           ; 默认值为 1600

  ;; 启用 `list-timers', `list-threads' 这两个命令
  (put 'list-timers 'disabled nil)
  (put 'list-threads 'disabled nil)

  ;; 在命令行里支持鼠标
  (xterm-mouse-mode 1)

  ;; 退出Emacs时进行确认
  (setq confirm-kill-emacs 'y-or-n-p)

  ;; 在模式栏上显示当前光标的列号
  (column-number-mode t)

  (add-hook 'org-mode-hook (lambda () (setq truncate-lines nil))) ;自动换行(折行)

  ;; 显示行号
  (if (>= emacs-major-version 29)
	  (global-display-line-numbers-mode)
	(global-linum-mode t))

  (defun reload-emacs-config ()
	(interactive)
	(load-file "~/.emacs.d/init.el"))
  (global-set-key (kbd "C-c C-SPC") 'reload-emacs-config)

  (defun close-current-window ()
	(interactive)
	(delete-window)
	)
  (global-set-key (kbd "C-c z") 'close-current-window)

编码设置

统一使用 UTF-8 编码。

1
2
3
  ;; 配置编码
  (prefer-coding-system 'utf-8)
  (setq-default buffer-file-coding-system 'utf-8)

keycast按键展示

keycast mode 插件可以在模式栏上展示所有的按键,以及对应的函数。

 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
  (use-package keycast
	:ensure t
	:hook (after-init . keycast-mode)
	;; :custom-face
	;; (keycast-key ((t (:background "#0030b4" :weight bold))))
	;; (keycast-command ((t (:foreground "#0030b4" :weight bold))))
	:config
	;; set for doom-modeline support
	;; With the latest change 72d9add, mode-line-keycast needs to be modified to keycast-mode-line.
	(define-minor-mode keycast-mode
	  "Show current command and its key binding in the mode line (fix for use with doom-mode-line)."
	  :global t
	  (if keycast-mode
		  (progn
			(add-hook 'pre-command-hook 'keycast--update t)
			(add-to-list 'global-mode-string '("" keycast-mode-line "  ")))
		(remove-hook 'pre-command-hook 'keycast--update)
		(setq global-mode-string (delete '("" keycast-mode-line "  ") global-mode-string))
		))

	(dolist (input '(self-insert-command
					 org-self-insert-command))
	  (add-to-list 'keycast-substitute-alist `(,input "." "Typing…")))

	(dolist (event '(mouse-event-p
					 mouse-movement-p
					 mwheel-scroll))
	  (add-to-list 'keycast-substitute-alist `(,event nil)))

	(setq keycast-log-format "%-20K%C\n")
	(setq keycast-log-frame-alist
		  '((minibuffer . nil)))
	(setq keycast-log-newest-first t)
	)

shackle窗口管理

shackle 插件能自定义窗口的弹出方式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  (use-package shackle
	:ensure t
	:hook (after-init . shackle-mode)
	:init
	(setq shackle-lighter "")
	(setq shackle-select-reused-windows nil) ; default nil
	(setq shackle-default-alignment 'below)  ; default below
	(setq shackle-default-size 0.4)          ; default 0.5
	(setq shackle-rules
		  ;; CONDITION(:regexp)            :select     :inhibit-window-quit   :size+:align|:other     :same|:popup
		  '((compilation-mode              :ignore t)
			("\\*Async Shell.*\\*" :regexp t :ignore t)
			("\\*corfu.*\\*"       :regexp t :ignore t)
			("*eshell*"                    :select t                          :size 0.4  :align t     :popup t)
			(helpful-mode                  :select t                          :size 0.6  :align right :popup t)
			("*Messages*"                  :select t                          :size 0.4  :align t     :popup t)
			("*Calendar*"                  :select t                          :size 0.3  :align t     :popup t)
			("*info*"                      :select t                                                  :same t)
			(magit-status-mode             :select t   :inhibit-window-quit t                         :same t)
			(magit-log-mode                :select t   :inhibit-window-quit t                         :same t)
			))
	)

popper窗口弹出管理

我们通过 popper 插件,来控制窗口的弹出行为,与 shackle 一起配合使用。

 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
  (use-package popper
	:ensure t
	:bind (("M-`"     . popper-toggle-latest)
		   ("M-<tab>" . popper-cycle)
		   ("M-\\"    . popper-toggle-type)
		   )
	:init
	(setq popper-reference-buffers
		  '("\\*Messages\\*"
			"\\*Async Shell Command\\*"
			help-mode
			helpful-mode
			occur-mode
			pass-view-mode
			"^\\*eshell.*\\*$" eshell-mode ;; eshell as a popup
			"^\\*shell.*\\*$"  shell-mode  ;; shell as a popup
			("\\*corfu\\*" . hide)
			(compilation-mode . hide)
			;; derived from `fundamental-mode' and fewer than 10 lines will be considered a popup
			(lambda (buf) (with-current-buffer buf
							(and (derived-mode-p 'fundamental-mode)
								 (< (count-lines (point-min) (point-max))
									10))))
			)
		  )
	(popper-mode +1)
	(popper-echo-mode +1)
	:config
	;; group by project.el, projectile, directory or perspective
	(setq popper-group-function nil)

	;; pop in child frame or not
	(setq popper-display-function #'display-buffer-in-child-frame)

	;; use `shackle.el' to control popup
	(setq popper-display-control nil)
	)

winner窗口管理

内置的 winner 插件是一个窗口管理器,可以通过 winner-undowinner-redo 命令恢复或重做窗口布局。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  (use-package winner
	:ensure nil
	:hook (after-init . winner-mode)
	:commands (winner-undo winner-redo)
	:config
	(setq winner-boring-buffers
		  '("*Completions*"
			"*Compile-Log*"
			"*inferior-lisp*"
			"*Fuzzy Completions*"
			"*Apropos*"
			"*Help*"
			"*cvs*"
			"*Buffer List*"
			"*Ibuffer*"
			"*esh command on file*"))
	)

init-ui.el 文件尾

1
2
3
4

  (provide 'init-ui)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-ui.el ends here

init-base.el

init-base.el 文件头

1
2
3
4
  ;;; init-base.el --- Basical settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

savehist记住迷你缓冲区历史

记住迷你缓冲区历史。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  (use-package savehist
	:ensure nil
	:hook (after-init . savehist-mode)
	:config
	;; Allow commands in minibuffers, will affect `dired-do-dired-do-find-regexp-and-replace' command:
	(setq enable-recursive-minibuffers t)
	(setq history-length 1000)
	(setq savehist-additional-variables '(mark-ring
										  global-mark-ring
										  search-ring
										  regexp-search-ring
										  extended-command-history))
	(setq savehist-autosave-interval 300))

saveplace记住每个文件的光标位置

自动记住每个文件的最后一次访问的光标位置。

1
2
3
  (use-package saveplace
	:ensure nil
	:hook (after-init . save-place-mode))

undo-tree撤销设置

undo-tree 插件可以提供一个可视化的撤销、重做系统,我们使用 C-/ 来撤销,使用 M-_ 来重做。

1
2
3
4
5
6
7
  (use-package undo-tree
	:ensure t
	:hook (after-init . global-undo-tree-mode)
	:config
	;; don't save undo history to local files
	(setq undo-tree-auto-save-history nil)
	)

super-save自动保存

super-save 插件能自动保存缓冲区。它可以设置在某些行为(如窗口切换、或窗口空闲一段时间)下自动保存。

 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
  (use-package super-save
	:ensure t
	:hook (after-init . super-save-mode)
	:config
	;; Emacs空闲是否自动保存,这里不设置
	(setq super-save-auto-save-when-idle nil)
	;; 切换窗口自动保存
	(add-to-list 'super-save-triggers 'other-window)
	;; 查找文件时自动保存
	(add-to-list 'super-save-hook-triggers 'find-file-hook)
	;; 远程文件编辑不自动保存
	(setq super-save-remote-files nil)
	;; 特定后缀名的文件不自动保存
	(setq super-save-exclude '(".gpg"))
	;; 自动保存时,保存所有缓冲区
	(defun super-save/save-all-buffers ()
	  (save-excursion
		(dolist (buf (buffer-list))
		  (set-buffer buf)
		  (when (and buffer-file-name
					 (buffer-modified-p (current-buffer))
					 (file-writable-p buffer-file-name)
					 (if (file-remote-p buffer-file-name) super-save-remote-files t))
			(save-buffer)))))
	(advice-add 'super-save-command :override 'super-save/save-all-buffers)
	)

init-base.el 文件尾

1
2
3
4

  (provide 'init-base)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-base.el ends here

init-edit.el

init-edit.el 文件头

1
2
3
4
  ;;; init-edit.el --- Editing settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

Emacs备份设置

不使用Emacs的自动备份设置。

1
2
  (setq make-backup-files nil)                                  ; 不自动备份
  (setq auto-save-default nil)                                  ; 不使用Emacs自带的自动保存

解除一些不常用的快捷键

将一些不常用的快捷键解除,防止误操作。

1
2
3
4
5
6
  ;; 解除不常用的快捷键定义
  (global-set-key (kbd "s-q") nil)
  (global-set-key (kbd "M-z") nil)
  (global-set-key (kbd "M-m") nil)
  (global-set-key (kbd "C-x C-z") nil)
  (global-set-key [mouse-2] nil)

delsel选择文本输入时直接替换

Emacs默认选择文本后直接输入,是不会直接删除所选择的文本进行替换的。通过内置的 delsel 插件来实现这个行为。

1
2
3
4
  ;; Directly modify when selecting text
  (use-package delsel
	:ensure t
	:hook (after-init . delete-selection-mode))

自动重载设置

当我们的文件发生了改变后,我们希望Emacs里打开的永远是最新的文件,这个时候,我们需要对自动重载进行设置,让我们的Emacs在文件发生改变的时候自动重载文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  (use-package autorevert
	:ensure t
	:hook (after-init . global-auto-revert-mode)
	;; :bind ("s-u" . revert-buffer)
	:custom
	(auto-revert-interval 10)
	(auto-revert-avoid-polling t)
	(auto-revert-verbose nil)
	(auto-revert-remote-files t)
	(auto-revert-check-vc-info t)
	(global-auto-revert-non-file-buffers t))

avy光标移动

avy 是一个光标移动插件,能快速将光标移动到屏幕上的任意字符,非常强大!

1
2
3
4
  (use-package avy
	:ensure t
	:bind
	(("M-j" . avy-goto-char-timer)))

amx 记录命令历史

amx - GitHub 主页

这个插件可以记录我们每次调用 M-x 时输入的命令历史,然后每次将最常用的显示在前面,这对于我们短时间希望频繁输入某几个命令的场景非常有用。

1
2
3
  (use-package amx
	:ensure t
	:init (amx-mode))

window-numbering 快捷键切换窗口

分屏之后的emacs在屏幕切换的时候会比较麻烦,针对这个功能有一个可以实现这个的插件,也就是window-numbering。

使用方法:<M-number>

1
2
3
4
5
  (use-package window-numbering
	:ensure t
	;; :defer 3
	:init (window-numbering-mode t)
	)

mwim 优化光标移动到行首/行尾

mwim - GitHub 主页

C-a 对应了 move-beginning-of-line,M-m 对应了 back-to-indentation。当代码有缩进时,前者会把光标移动到行首(到空格之前),后者会移动到代码文字的开头(到空格之后)。那么实际中这两个按法差别较大,且不易区分,使用起来不方便。mwim 就将二者合并,覆盖 C-a 为 mwim-beginning-of-code-or-line,这样按一次 C-a 时移动到代码文字开头,再按一次则是移动到整行的行首,如此反复。

同时,更有意义的是,它还可以覆盖 C-e move-end-of-line 为 mwim-end-of-code-or-line,当本行代码结尾有注释时,第一次按 C-e 将光标移动到代码尾部、注释之前。再按一次则是移动到整行的行尾。 这就大大提高了写代码的效率。

1
2
3
4
5
  (use-package mwim
	:ensure t
	:bind
	("C-a" . mwim-beginning-of-code-or-line)
	("C-e" . mwim-end-of-code-or-line))

dashboard 配置欢迎页面

dashboard - GitHub 主页

起初每当我们打开 Emacs 都有一个欢迎界面,显示了一些 Emacs 的帮助信息。这对刚入门而言比较方便,但当我们熟练后这个页面就逐渐无用了。dashboard 就是一个新的欢迎界面,可以列出最近打开的项目、最近打开的文件等等。按下 p 或 r 就可以快速 跳转到相应小结里。还可以列出来标记过的书签、org-mode (Emacs 自带的一个强大的笔记系统)日程、自定义控件等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  (use-package dashboard
	:ensure t
	:config
	;; (setq dashboard-banner-logo-title "Welcome to Emacs!") ;; 个性签名,随读者喜好设置
	;; (setq dashboard-projects-backend 'projectile) ;; 读者可以暂时注释掉这一行,等安装了 projectile 后再使用
	(setq dashboard-startup-banner 'official) ;; 也可以自定义图片
	(setq dashboard-items '((recents  . 10)   ;; 显示多少个最近文件
							(bookmarks . 10)  ;; 显示多少个最近书签
							(projects . 10))) ;; 显示多少个最近项目
	(dashboard-setup-startup-hook))

projectile

配合dashboard使用

1
2
  (use-package projectile
	:ensure t)

marginalia 为 Emacs minibuffer 中的选项添加注解

marginalia - GitHub 主页

一个为 Emacs minibuffer 中的选项添加注解的插件。

1
2
3
4
5
  (use-package marginalia
	:ensure t
	:init (marginalia-mode)
	:bind (:map minibuffer-local-map
				("M-A" . marginalia-cycle)))

which-key 根据快捷键前缀提示快捷键

which-key - GitHub 主页

当按下部分快捷键前缀时,它会通过 minibuffer 提示你都有哪些可以按的快捷键及其命令名。

1
2
3
  (use-package which-key
	:ensure t
	:init (which-key-mode))

hydra 把一组特定场景的命令组织到一起, 通过简单按键来进行调用

hydra - GitHub 主页

hydra 主要功能是把一组特定场景的命令组织到一起, 通过简单按键来进行调用。

1
2
  (use-package hydra
	:ensure t)

use-package-hydra

配合hydra使用

1
2
3
  (use-package use-package-hydra
	:ensure t
	:after hydra)

multiple-cursors多光标编辑

multiple-cursors 插件能让Emacs实现多光标编辑和移动。

 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
  (use-package multiple-cursors
	:ensure t
	:after hydra
	:bind
	(("C-x M-h m" . hydra-multiple-cursors/body)
	 ("C-M-<mouse-1>" . mc/toggle-cursor-on-click))
	:hydra (hydra-multiple-cursors
			(:hint nil)
			"
  Up^^             Down^^           Miscellaneous           % 2(mc/num-cursors) cursor%s(if (> (mc/num-cursors) 1) \"s\" \"\")
  ------------------------------------------------------------------
   [_p_]   Prev     [_n_]   Next     [_l_] Edit lines  [_0_] Insert numbers
   [_P_]   Skip     [_N_]   Skip     [_a_] Mark all    [_A_] Insert letters
   [_M-p_] Unmark   [_M-n_] Unmark   [_s_] Search      [_q_] Quit
   [_|_] Align with input CHAR       [Click] Cursor at point"
			("l" mc/edit-lines :exit t)
			("a" mc/mark-all-like-this :exit t)
			("n" mc/mark-next-like-this)
			("N" mc/skip-to-next-like-this)
			("M-n" mc/unmark-next-like-this)
			("p" mc/mark-previous-like-this)
			("P" mc/skip-to-previous-like-this)
			("M-p" mc/unmark-previous-like-this)
			("|" mc/vertical-align)
			("s" mc/mark-all-in-region-regexp :exit t)
			("0" mc/insert-numbers :exit t)
			("A" mc/insert-letters :exit t)
			("<mouse-1>" mc/add-cursor-on-click)
			;; Help with click recognition in this hydra
			("<down-mouse-1>" ignore)
			("<drag-mouse-1>" ignore)
			("q" nil)))

highlight-symbol 高亮出当前 Buffer 中所有的、与光标所在处的符号相同的符号

highlight-symbol - GitHub 主页

这个插件可以高亮出当前 Buffer 中所有的、与光标所在处的符号相同的符号。也就是例如一些同名变量、函数名等。虽然在后面我们使用一些其他插件时也会捎带有类似功能,但它可以同时高亮很多字符,便于阅读代码等。

1
2
3
4
5
6
7
8
  (use-package highlight-symbol
	:ensure t
	:init (highlight-symbol-mode)
	:bind (
		   ("<f10>" . highlight-symbol)	; 按下 F10 键就可高亮当前符号
		   ("<f9>" . highlight-symbol-remove-all) ; 取消 Emacs 中所有当前高亮的符号
		   )
	)

rainbow-delimiters 用不同颜色标记多级括号,方便看清代码块

rainbow-delimiters - GitHub 主页

这个插件可以用不同颜色标记多级括号,方便看清代码块(尤其在 EmacsLisp 中)。

1
2
3
  (use-package rainbow-delimiters
	:ensure t
	:hook (prog-mode . rainbow-delimiters-mode))

evil(为 Vim 用户)

evil - GitHub 主页

evil 可以让习惯了 Vim 的用户在 Emacs 中使用 Vim 按键方式,大大减轻了 Vim 用户转入 Emacs 的成本。

1
2
3
4
5
  (use-package evil
	:ensure t
	;; :init (evil-mode)
	:bind
	(("C-x C-z" . evil-mode)))

WorkLogReport 工作日志报告

插入工作日志报告模板

为什么%s会被替换为时间戳而不是其他内容被替换为时间戳,原理是什么 这是因为在 Emacs Lisp 中,`format` 函数的工作方式类似于 C 语言中的 `printf` 函数。`format` 函数接受一个格式字符串和一系列参数,然后根据格式字符串中的格式指定符(如 `%s`、`%d` 等)将后续的参数插入到格式字符串中。

在你的代码中,`format` 函数的格式字符串是:

```lisp "* %s ,#+BEGIN_SRC emacs-lisp :tangle %s.txt %s: name\n1、 ,#+END_SRC" ```

这个字符串中有三个 `%s`,所以 `format` 函数需要三个额外的参数。在你的代码中,这三个参数都是 `block-name`,即你处理过的时间戳。

所以,当 `format` 函数运行时,它会依次取出 `block-name`,并将其插入到格式字符串中的 `%s` 的位置。这就是为什么 `%s` 会被替换为时间戳的原理。

如果你希望将不同的内容插入到格式字符串中,你只需提供不同的参数即可。例如:

```lisp (format "Hello, %s! Today is %s." "Alice" "Monday") ```

这段代码会返回字符串 "Hello, Alice! Today is Monday."。 ,****************************************************************************** 这句有什么用:(block-name (concat clean-time)) ; 构建代码块名 这一句 `(block-name (concat clean-time))` 的作用是创建一个新的变量 `block-name`,并将其设置为 `clean-time` 的值。

在这个上下文中,`clean-time` 是一个已经去除了破折号和冒号的时间字符串。`concat` 函数通常用于连接多个字符串,但在这里,它只有一个参数 `clean-time`,所以它实际上只是返回 `clean-time` 的值。

因此,这一句的效果就是创建了一个新的变量 `block-name`,并将其设置为与 `clean-time` 相同的值。后面的代码中使用 `block-name` 作为代码块的名字。

如果你的代码中没有需要使用不同的名称来表示清理过的时间戳,那么这一行代码实际上是不必要的,你可以直接使用 `clean-time`。但是,如果你打算在后续的代码中修改 `block-name` 或 `clean-time` 的值,那么这一行代码就很有用了,因为它确保了 `block-name` 和 `clean-time` 是两个独立的变量,修改一个不会影响另一个。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  (defun add-code-block ()
	"在当前位置添加一个代码块,并以时间作为块名进行命名"
	(interactive)
	(let* ((time (format-time-string "%Y-%m-%d"))  ; 获取当前时间
		   (clean-time (replace-regexp-in-string "[-:]" "" time))  ; 去除时间中的破折号和冒号
		   (block-name (concat clean-time))  ; 构建代码块名
		   (code-block (format
						"*** %s\n
  ,#+BEGIN_SRC emacs-lisp :tangle %s.txt
  %s: name\n1、
  ,#+END_SRC\n\n"
						block-name clean-time block-name)))
	  (insert code-block)))  ; 在当前位置插入代码块

  ;; 设置快捷键 C-c b 绑定到 add-code-block 函数
  (global-set-key (kbd "C-c SPC r") 'add-code-block)

g-org-insert-note-header 插入一些 Org 模式的头部信息

用于在当前光标位置插入一些 Org 模式的头部信息。这些头部信息包括了一些选项,标题,作者以及一些其他设置

1
2
3
4
5
6
  (defun g-org-insert-note-header () ;;; 定义一个名为g-org-insert-note-header ()的函数
	(interactive) ;;; 函数的一个特殊声明,表示函数可以被用户调用
	(insert
	 "#+TITLE: \n#+AUTHOR: yenao\n#+OPTIONS: toc:t num:10 H:10 ^:nil \\n:t broken-links:nil pri:t\n#+STARTUP: overview\n#+HTML_HEAD: \<link rel=\"stylesheet\" type=\"text\/css\" href=\"http:\/\/gongzhitaao.org\/orgcss\/org.css\"\/\>\n"
	 )) ;;; insert函数用于在当前 光标位置插入指定的文本内容,当你调用这个函数时,它会在当前光标位置插入文本#+OPTIONS: ^:nil、#+TITLE:  和#+AUTHOR: yenao
  ;; #+LANGUAGE: zh-CN ;; zh-CN或者en

g-org-emacs-lisp-code-block 插入emacs-lisp代码块

用于插入emacs-lisp代码块

1
2
3
4
  (defun g-org-emacs-lisp-code-block ()
	(interactive)
	(insert "#+begin_src emacs-lisp\n\n#+end_src")
	)

g-org-c-code-block 插入C语言代码块

用于插入c语言的代码块

1
2
3
4
  (defun g-org-c-code-block ()
	(interactive)
	(insert "#+begin_src c\n\n#+end_src")
	)

g-org-bash-code-block 插入bash语言的代码块

用于插入bash语言的代码块

1
2
3
4
  (defun g-org-bash-code-block ()
	(interactive)
	(insert "#+begin_src bash\n\n#+end_src")
	)

g-org-html-code-block 插入html语言的代码块

用于插入html语言的代码块

1
2
3
4
  (defun g-org-html-code-block ()
   (interactive)
   (insert "#+begin_src html\n\n#+end_src")
  )

markdown

使emacs支持markdown模式编辑文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  (use-package markdown-mode
	:ensure t
	:defer t
	:config
	;;markdown设置
	(autoload 'markdown-mode "markdown-mode"
	  "Major mode for editing Markdown files" t)
	(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
	(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
	)

init-edit.el 文件尾

1
2
3
4
5
6
  ;; (message "init-base configuration: %.2fs"
  ;;          (float-time (time-subtract (current-time) my/init-base-start-time)))

  (provide 'init-edit)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-edit.el ends here

init-org.el

init-org.el 文件头

1
2
3
4
  ;;; init-org.el --- Org mode settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

org-appear自动展开强调链接

通过 org-appear 插件,当我们的光标移动到Org mode里的强调、链接上时,会自动展开,这样方便进行编辑。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  (use-package org-appear
	:ensure t
	:hook (org-mode . org-appear-mode)
	:config
	(setq org-appear-autolinks t)
	(setq org-appear-autosubmarkers t)
	(setq org-appear-autoentities t)
	(setq org-appear-autokeywords t)
	(setq org-appear-inside-latex t)
	)

org-auto-tangle自动tangle设置

org-auto-tangle 插件可以在Org mode下自动进行tangle。

1
2
3
4
5
6
  (use-package org-auto-tangle
	:ensure t
	:hook (org-mode . org-auto-tangle-mode)
	:config
	(setq org-auto-tangle-default t)
	)

org-capture快速记录设置

 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
  (use-package org-capture
	:ensure nil
	:bind ("C-c c" . (lambda () (interactive) (org-capture)))
	:hook ((org-capture-mode . (lambda ()
								 (setq-local org-complete-tags-always-offer-all-agenda-tags t)))
		   (org-capture-mode . delete-other-windows))
	:custom
	(org-capture-use-agenda-date nil)
	;; define common template
	(org-capture-templates `(("t" "Tasks" entry (file+headline "tasks.org" "Reminders")
							  "* TODO %i%?"
							  :empty-lines-after 1
							  :prepend t)
							 ("n" "Notes" entry (file+headline "capture.org" "Notes")
							  "* %? %^g\n%i\n"
							  :empty-lines-after 1)
							 ;; For EWW
							 ("b" "Bookmarks" entry (file+headline "capture.org" "Bookmarks")
							  "* %:description\n\n%a%?"
							  :empty-lines 1
							  :immediate-finish t)
							 ("d" "Diary")
							 ("dt" "Today's TODO list" entry (file+olp+datetree "diary.org")
							  "* Today's TODO list [/]\n%T\n\n** TODO %?"
							  :empty-lines 1
							  :jump-to-captured t)
							 ("do" "Other stuff" entry (file+olp+datetree "diary.org")
							  "* %?\n%T\n\n%i"
							  :empty-lines 1
							  :jump-to-captured t)
							 ))
	)

denote笔记设置

denote 是一个轻量级的笔记插件,拥有良好的文件名命名模板。

 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
  (use-package denote
	:ensure t
	:hook (dired-mode . denote-dired-mode-in-directories)
	:bind (("C-c d n" . denote)
		   ("C-c d d" . denote-date)
		   ("C-c d t" . denote-type)
		   ("C-c d s" . denote-subdirectory)
		   ("C-c d f" . denote-open-or-create)
		   ("C-c d r" . denote-dired-rename-file))
	:init
	(with-eval-after-load 'org-capture
	  (setq denote-org-capture-specifiers "%l\n%i\n%?")
	  (add-to-list 'org-capture-templates
				   '("N" "New note (with denote.el)" plain
					 (file denote-last-path)
					 #'denote-org-capture
					 :no-save t
					 :immediate-finish nil
					 :kill-buffer t
					 :jump-to-captured t)))
	:config
	(setq denote-directory (expand-file-name "~/org/denote/"))
	(setq denote-known-keywords '("emacs" "entertainment" "reading" "studying"))
	(setq denote-infer-keywords t)
	(setq denote-sort-keywords t)
	;; org is default, set others such as text, markdown-yaml, markdown-toml
	(setq denote-file-type nil)
	(setq denote-prompts '(title keywords))

	;; We allow multi-word keywords by default.  The author's personal
	;; preference is for single-word keywords for a more rigid workflow.
	(setq denote-allow-multi-word-keywords t)
	(setq denote-date-format nil)

	;; If you use Markdown or plain text files (Org renders links as buttons
	;; right away)
	(add-hook 'find-file-hook #'denote-link-buttonize-buffer)
	(setq denote-dired-rename-expert nil)

	;; OR if only want it in `denote-dired-directories':
	(add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
	)

consult-notes查找笔记

consult-notes 插件可以通过consult快速找到笔记。

 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
  (use-package consult-notes
	:ensure t
	:commands (consult-notes
			   consult-notes-search-in-all-notes)
	:bind (("C-c n f" . consult-notes)
		   ("C-c n c" . consult-notes-search-in-all-notes))
	:config
	(setq consult-notes-file-dir-sources
		  `(
			("work"    ?w ,(concat org-directory "/midea/"))
			("article" ?a ,(concat org-directory "/article/"))
			("org"     ?o ,(concat org-directory "/"))
			("hugo"    ?h ,(concat org-directory "/hugo/"))
			("books"   ?b ,(concat (getenv "HOME") "/Books/"))
			))

	;; embark support
	(with-eval-after-load 'embark
	  (defun consult-notes-open-dired (cand)
		"Open notes directory dired with point on file CAND."
		(interactive "fNote: ")
		;; dired-jump is in dired-x.el but is moved to dired in Emacs 28
		(dired-jump nil cand))

	  (defun consult-notes-marked (cand)
		"Open a notes file CAND in Marked 2.
  Marked 2 is a mac app that renders markdown."
		(interactive "fNote: ")
		(call-process-shell-command (format "open -a \"Marked 2\" \"%s\"" (expand-file-name cand))))

	  (defun consult-notes-grep (cand)
		"Run grep in directory of notes file CAND."
		(interactive "fNote: ")
		(consult-grep (file-name-directory cand)))

	  (embark-define-keymap consult-notes-map
							"Keymap for Embark notes actions."
							:parent embark-file-map
							("d" consult-notes-dired)
							("g" consult-notes-grep)
							("m" consult-notes-marked))

	  (add-to-list 'embark-keymap-alist `(,consult-notes-category . consult-notes-map))

	  ;; make embark-export use dired for notes
	  (setf (alist-get consult-notes-category embark-exporters-alist) #'embark-export-dired)
	  )
	)

org-super-links反链设置

org-super-links 插件可以设置反向链接。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  (quelpa
   '(org-super-liks
	 :fetcher git
	 :url "https://hub.nuaa.cf/toshism/org-super-links"))

  (use-package org-super-links
	:ensure nil
	:bind (("C-c s s"   . org-super-links-link)
		   ("C-c s l"   . org-super-links-store-link)
		   ("C-c s C-l" . org-super-links-insert-link)
		   ("C-c s d"   . org-super-links-quick-insert-drawer-link)
		   ("C-c s i"   . org-super-links-quick-insert-inline-link)
		   ("C-c s C-d" . org-super-links-delete-link))
	:config
	(setq org-super-links-related-into-drawer t)
	(setq	org-super-links-link-prefix 'org-super-links-link-prefix-timestamp))

ox文件导出通用设置

下面是org文件导出的通用设置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  (use-package ox
	:ensure nil
	:custom
	(org-export-with-toc t)
	(org-export-with-tags 'not-in-toc)
	(org-export-with-drawers nil)
	(org-export-with-priority t)
	(org-export-with-footnotes t)
	(org-export-with-smart-quotes t)
	(org-export-with-section-numbers t)
	(org-export-with-sub-superscripts '{})
	;; `org-export-use-babel' set to nil will cause all source block header arguments to be ignored This means that code blocks with the argument :exports none or :exports results will end up in the export.
	;; See:
	;; https://stackoverflow.com/questions/29952543/how-do-i-prevent-org-mode-from-executing-all-of-the-babel-source-blocks
	(org-export-use-babel t)
	(org-export-headline-levels 9)
	(org-export-coding-system 'utf-8)
	(org-export-with-broken-links 'mark)
	(org-export-default-language "zh-CN") ; 默认是en
	;; (org-ascii-text-width 72)
	)

org导出后端设置

ox-html导出HTML设置

我们先来对HTML导出做一个基本设置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  (use-package ox-html
	:ensure nil
	:init
	;; add support for video
	(defun org-video-link-export (path desc backend)
	  (let ((ext (file-name-extension path)))
		(cond
		 ((eq 'html backend)
		  (format "<video width='800' preload='metadata' controls='controls'><source type='video/%s' src='%s' /></video>" ext path))
		 ;; fall-through case for everything else
		 (t
		  path))))
	(org-link-set-parameters "video" :export 'org-video-link-export)
	:custom
	(org-html-doctype "html5")
	(org-html-html5-fancy t)
	(org-html-checkbox-type 'unicode)
	(org-html-validation-link nil))

  (use-package htmlize
	:ensure t
	:custom
	(htmlize-pre-style t)
	(htmlize-output-type 'inline-css))

ox-latex导出PDF设置

ox-latex 是Org mode自带的功能,可以将Org文件导出为latex文件和PDF文件。

 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
  (use-package ox-latex
	:ensure nil
	:defer t
	:config
	(add-to-list 'org-latex-classes
				 '("cn-article"
				   "\\documentclass[UTF8,a4paper]{article}"
				   ("\\section{%s}" . "\\section*{%s}")
				   ("\\subsection{%s}" . "\\subsection*{%s}")
				   ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
				   ("\\paragraph{%s}" . "\\paragraph*{%s}")
				   ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

	(add-to-list 'org-latex-classes
				 '("cn-report"
				   "\\documentclass[11pt,a4paper]{report}"
				   ("\\chapter{%s}" . "\\chapter*{%s}")
				   ("\\section{%s}" . "\\section*{%s}")
				   ("\\subsection{%s}" . "\\subsection*{%s}")
				   ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
	(setq org-latex-default-class "cn-article")
	(setq org-latex-image-default-height "0.9\\textheight"
		  org-latex-image-default-width "\\linewidth")
	(setq org-latex-pdf-process
		  '("xelatex -interaction nonstopmode -output-directory %o %f"
			"bibtex %b"
			"xelatex -interaction nonstopmode -output-directory %o %f"
			"xelatex -interaction nonstopmode -output-directory %o %f"
			"rm -fr %b.out %b.log %b.tex %b.brf %b.bbl auto"
			))
	;; 使用 Listings 宏包格式化源代码(只是把代码框用 listing 环境框起来,还需要额外的设置)
	(setq org-latex-listings t)
	;; mapping jupyter-python to Python
	(add-to-list 'org-latex-listings-langs '(jupyter-python "Python"))
	;; Options for \lset command(reference to listing Manual)
	(setq org-latex-listings-options
		  '(
			("basicstyle" "\\small\\ttfamily")       ; 源代码字体样式
			("keywordstyle" "\\color{eminence}\\small")                 ; 关键词字体样式
			;; ("identifierstyle" "\\color{doc}\\small")
			("commentstyle" "\\color{commentgreen}\\small\\itshape")    ; 批注样式
			("stringstyle" "\\color{red}\\small")                       ; 字符串样式
			("showstringspaces" "false")                                ; 字符串空格显示
			("numbers" "left")                                          ; 行号显示
			("numberstyle" "\\color{preprocess}")                       ; 行号样式
			("stepnumber" "1")                                          ; 行号递增
			("xleftmargin" "2em")                                       ;
			;; ("backgroundcolor" "\\color{background}")                   ; 代码框背景色
			("tabsize" "4")                                             ; TAB 等效空格数
			("captionpos" "t")                                          ; 标题位置 top or buttom(t|b)
			("breaklines" "true")                                       ; 自动断行
			("breakatwhitespace" "true")                                ; 只在空格分行
			("showspaces" "false")                                      ; 显示空格
			("columns" "flexible")                                      ; 列样式
			("frame" "tb")                                              ; 代码框:single, or tb 上下线
			("frameleftmargin" "1.5em")                                 ; frame 向右偏移
			;; ("frameround" "tttt")                                       ; 代码框: 圆角
			;; ("framesep" "0pt")
			;; ("framerule" "1pt")                                         ; 框的线宽
			;; ("rulecolor" "\\color{background}")                         ; 框颜色
			;; ("fillcolor" "\\color{white}")
			;; ("rulesepcolor" "\\color{comdil}")
			("framexleftmargin" "5mm")                                  ; let line numer inside frame
			))
	)

ox-gfm导出Markdown设置

我们通过 ox-gfm 插件来导出Github样式的Markdown文件。

1
2
3
  (use-package ox-gfm
	:ensure t
	:after ox)

ox-publish导出静态站点设置

 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
  (unless (file-exists-p "~/org")
	(make-directory "~/org")) 

  (use-package ox-publish
	:ensure nil
	:commands (org-publish org-publish-all)
	:config
	(setq org-export-global-macros
		  '(("timestamp" . "@@html:<span class=\"timestamp\">[$1]</span>@@")))

	;; sitemap 生成函数
	(defun my/org-sitemap-date-entry-format (entry style project)
	  "Format ENTRY in org-publish PROJECT Sitemap format ENTRY ENTRY STYLE format that includes date."
	  (let ((filename (org-publish-find-title entry project)))
		(if (= (length filename) 0)
			(format "*%s*" entry)
		  (format "{{{timestamp(%s)}}} [[file:%s][%s]]"
				  (format-time-string "%Y-%m-%d"
									  (org-publish-find-date entry project))
				  entry
				  filename))))

	;; 设置 org-publish 的项目列表
	(setq org-publish-project-alist
		  '(
			;; 笔记部分
			("org-notes"
			 :base-directory "~/org/"
			 :base-extension "org"
			 :exclude "\\(tasks\\|test\\|scratch\\|diary\\|capture\\|mail\\|habits\\|resume\\|meetings\\|personal\\|org-beamer-example\\)\\.org\\|test\\|article\\|roam\\|hugo"
			 :publishing-directory "~/public_html/"
			 :recursive t                 ; include subdirectories if t
			 :publishing-function org-html-publish-to-html
			 :headline-levels 6
			 :auto-preamble t
			 :auto-sitemap t
			 :sitemap-filename "sitemap.org"
			 :sitemap-title "Sitemap"
			 :sitemap-format-entry my/org-sitemap-date-entry-format)

			;; 静态资源部分
			("org-static"
			 :base-directory "~/org/"
			 :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|mov"
			 :publishing-directory "~/public_html/"
			 :recursive t
			 :publishing-function org-publish-attachment)

			;; 项目集合
			("org"
			 :components ("org-notes" "org-static"))
			))
	)

ox-hugo导出博客设置

ox-hugo 插件可以将 org 文件导出为 hugo 需要的 Markdown 文件,并快速通过 hugo 进行博客的生成和发布。

 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
  (use-package ox-hugo
	:ensure t
	:config    

	(setq org-hugo-base-dir "~/ox-hugo/")
	(with-eval-after-load 'org-capture
	  (defun org-hugo-new-subtree-post-capture-template ()
		"Returns `org-capture' template string for new Hugo post.
  See `org-capture-templates' for more information."
		(let* ((title (read-from-minibuffer "Post Title: ")) ; Prompt to enter the post title
			   (fname (org-hugo-slug title)))
		  (mapconcat #'identity
					 `(
					   ,(concat "* TODO " title)
					   ":PROPERTIES:"
					   ,(concat ":EXPORT_FILE_NAME: " fname)
					   ":END:"
					   "%?\n")          ; Place the cursor here finally
					 "\n")))

	  (add-to-list 'org-capture-templates
				   '("h"                ; `org-capture' binding + h
					 "Hugo post"
					 entry
					 ;; It is assumed that below file is present in `org-directory'
					 ;; and that it has a "Blog Ideas" heading. It can even be a
					 ;; symlink pointing to the actual location of capture.org!
					 (file+olp "capture.org" "Notes")
					 (function org-hugo-new-subtree-post-capture-template))))
	)

toc-org目录自动生成

toc-org 插件可以在Org文件里自动生成目录,只需给一个标题行设置一个标签为 toctoc_2 即可(后者只生成2层)。

1
2
3
  (use-package toc-org
	:ensure t
	:hook (org-mode . toc-org-mode))

ol新增链接类型

google Org mode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  (use-package ol
	:ensure nil
	:defer t
	:custom
	(org-link-keep-stored-after-insertion t)
	(org-link-abbrev-alist '(("github"        . "https://github.com/")
							 ("gitlab"        . "https://gitlab.com/")
							 ("google"        . "https://google.com/search?q=")
							 ("baidu"         . "https://baidu.com/s?wd=")
							 ("rfc"           . "https://tools.ietf.org/html/")
							 ("wiki"          . "https://en.wikipedia.org/wiki/")
							 ("youtube"       . "https://youtube.com/watch?v=")
							 ("zhihu"         . "https://zhihu.com/question/"))))

图片粘贴

通过 pngpaste 这个命令行工具,将系统剪贴板里的图片,输出到当前文件同名的 assets 文件夹下,然后自动在当前org文件的光标处插入图片链接,并设置图片链接的宽度属性。

 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
  (use-package emacs
	:ensure nil
	:after org
	:bind (:map org-mode-map
				("M-p" . my/org-insert-clipboard-image))
	:config
	(defun my/org-insert-clipboard-image (width)
	  "create a time stamped unique-named file from the clipboard in the sub-directory
   (%filename.assets) as the org-buffer and insert a link to this file."
	  (interactive (list
					(read-string (format "Input image width, default is 800: ")
								 nil nil "800")))
	  ;; 设置图片存放的文件夹位置为 `当前Org文件同名.assets'
	  (setq foldername (concat (file-name-base (buffer-file-name)) ".assets/"))
	  (if (not (file-exists-p foldername))
		  (mkdir foldername))
	  ;; 设置图片的文件名,格式为 `img_年月日_时分秒.png'
	  (setq imgName (concat "img_" (format-time-string "%Y%m%d_%H%M%S") ".png"))
	  ;; 图片文件的相对路径
	  (setq relativeFilename (concat (file-name-base (buffer-name)) ".assets/" imgName))
	  ;; 根据不同的操作系统设置不同的命令行工具
	  (cond ((string-equal system-type "gnu/linux")
			 (shell-command (concat "xclip -selection clipboard -t image/png -o > " relativeFilename)))
			((string-equal system-type "darwin")
			 (shell-command (concat "pngpaste " relativeFilename))))
	  ;; 给粘贴好的图片链接加上宽度属性,方便导出
	  (insert (concat "\n#+DOWNLOADED: screenshot @ "
					  (format-time-string "%Y-%m-%d %a %H:%M:%S" (current-time))
					  "\n#+CAPTION: \n#+ATTR_ORG: :width "
					  width
					  "\n#+ATTR_LATEX: :width "
					  (if (>= (/ (string-to-number width) 800.0) 1.0)
						  "1.0"
						(number-to-string (/ (string-to-number width) 800.0)))
					  "\\linewidth :float nil\n"
					  "#+ATTR_HTML: :width "
					  width
					  "\n[[file:" relativeFilename "]]\n"))
	  ;; 重新显示一下图片
	  (org-redisplay-inline-images)
	  )
	)

init-org.el 文件尾

1
2
3
4

  (provide 'init-org)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-org.el ends here

init-completion.el

Emacs的补全设置。

init-completion.el 文件头

1
2
3
4
  ;;; init-completion.el --- Completion settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

vertico 提供了一个垂直样式的补全系统

vertico 插件提供了一个垂直样式的补全系统。

 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
  (use-package vertico
	:ensure t
	:hook (after-init . vertico-mode)
	:bind (:map minibuffer-local-map
				("M-<DEL>" . my/minibuffer-backward-kill)
				:map vertico-map
				("M-q" . vertico-quick-insert)) ; use C-g to exit
	:config
	(defun my/minibuffer-backward-kill (arg)
	  "When minibuffer is completing a file name delete up to parent
  folder, otherwise delete a word"
	  (interactive "p")
	  (if minibuffer-completing-file-name
		  ;; Borrowed from https://github.com/raxod502/selectrum/issues/498#issuecomment-803283608
		  (if (string-match-p "/." (minibuffer-contents))
			  (zap-up-to-char (- arg) ?/)
			(delete-minibuffer-contents))
		(backward-kill-word arg)))

	;; Do not allow the cursor in the minibuffer prompt
	(setq minibuffer-prompt-properties
		  '(read-only t cursor-intangible t face minibuffer-prompt))
	(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

	(setq vertico-cycle t)                ; cycle from last to first
	:custom
	(vertico-count 15)                    ; number of candidates to display, default is 10
	)

orderless 插件提供一种无序的补全新姿势,将一个搜索的范式变成数个以空格分隔的部分

oderless 插件提供一种无序的补全新姿势,将一个搜索的范式变成数个以空格分隔的部分,各部分之间没有顺序,你要做的就是根据记忆输入关键词、空格、关键词。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  ;; support Pinyin first character match for orderless, avy etc.
  (use-package pinyinlib
	:ensure t)

  ;; orderless 是一种哲学思想
  (use-package orderless
	:ensure t
	:init
	(setq completion-styles '(orderless partial-completion basic))
	(setq orderless-component-separator "[ &]") ; & is for company because space will break completion
	(setq completion-category-defaults nil)
	(setq completion-category-overrides nil)
	:config
	;; make completion support pinyin, refer to
	;; https://emacs-china.org/t/vertico/17913/2
	(defun completion--regex-pinyin (str)
	  (orderless-regexp (pinyinlib-build-regexp-string str)))
	(add-to-list 'orderless-matching-styles 'completion--regex-pinyin)
	)

marginalia 给迷你缓冲区的补全候选条目添加一些提示

marginalia 插件给迷你缓冲区的补全候选条目添加一些提示。

1
2
3
4
5
6
  ;; minibuffer helpful annotations
  (use-package marginalia
	:ensure t
	:hook (after-init . marginalia-mode)
	:custom
	(marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))

consult 基于Emacs自带的补全机制,提供了一系列的补全命令

consult 插件基于Emacs自带的补全机制,提供了一系列的补全命令。

For locate on MacOS:

  1. locate is not enabled in MacOS by default. We need to enable it via: sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist
  2. Then we need to wait locate to build db for the whole file system.
  3. If there is something wrong with updating locate db, we can update it manually via: chomd 755 ~/Library ~/Downloads ~/Documents ~/Desktop sudo /usr/libexec/locate.updatedb
 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
  (use-package consult
	:ensure t
	:after org
	:bind (([remap goto-line]                     . consult-goto-line)
		   ([remap isearch-forward]               . consult-line-symbol-at-point) ; my-consult-ripgrep-or-line
		   ([remap switch-to-buffer]              . consult-buffer)
		   ([remap switch-to-buffer-other-window] . consult-buffer-other-window)
		   ([remap switch-to-buffer-other-frame]  . consult-buffer-other-frame)
		   ([remap yank-pop]                      . consult-yank-pop)
		   ([remap apropos]                       . consult-apropos)
		   ([remap bookmark-jump]                 . consult-bookmark)
		   ([remap goto-line]                     . consult-goto-line)
		   ([remap imenu]                         . consult-imenu)
		   ([remap multi-occur]                   . consult-multi-occur)
		   ([remap recentf-open-files]            . consult-recent-file)
		   ("C-x j"                               . consult-mark)
		   ("C-c g"                               . consult-ripgrep)
		   ("C-c f"                               . consult-find)
		   ("\e\ef"                               . consult-locate) ; need to enable locate first
		   ("C-c n h"                             . my/consult-find-org-headings)
		   :map org-mode-map
		   ("C-c C-j"                             . consult-org-heading)
		   :map minibuffer-local-map
		   ("C-r"                                 . consult-history)
		   :map isearch-mode-map
		   ("C-;"                                 . consult-line)
		   :map prog-mode-map
		   ("C-c C-j"                             . consult-outline)
		   )
	:hook (completion-list-mode . consult-preview-at-point-mode)
	:init
	;; Optionally configure the register formatting. This improves the register
	;; preview for `consult-register', `consult-register-load',
	;; `consult-register-store' and the Emacs built-ins.
	(setq register-preview-delay 0
		  register-preview-function #'consult-register-format)

	;; Optionally tweak the register preview window.
	;; This adds thin lines, sorting and hides the mode line of the window.
	(advice-add #'register-preview :override #'consult-register-window)

	;; Use Consult to select xref locations with preview
	(setq xref-show-xrefs-function #'consult-xref
		  xref-show-definitions-function #'consult-xref)

	;; MacOS locate doesn't support `--ignore-case --existing' args.
	(setq consult-locate-args (pcase system-type
								('gnu/linux "locate --ignore-case --existing --regex")
								('darwin "mdfind -name")))
	:config
	(consult-customize
	 consult-theme
	 :preview-key '(:debounce 0.2 any)
	 consult-ripgrep consult-git-grep consult-grep
	 consult-bookmark consult-recent-file consult-xref
	 consult--source-recent-file consult--source-project-recent-file consult--source-bookmark
	 :preview-key '(:debounce 0.4 any))

	;; Optionally configure the narrowing key.
	;; Both < and C-+ work reasonably well.
	(setq consult-narrow-key "<") ;; (kbd "C-+")

	(autoload 'projectile-project-root "projectile")
	(setq consult-project-root-function #'projectile-project-root)

	;; search all org file headings under a directory, see:
	;; https://emacs-china.org/t/org-files-heading-entry/20830/4
	(defun my/consult-find-org-headings (&optional match)
	  "find headngs in all org files."
	  (interactive)
	  (consult-org-heading match (directory-files org-directory t "^[0-9]\\{8\\}.+\\.org$")))

	;; Use `consult-ripgrep' instead of `consult-line' in large buffers
	(defun consult-line-symbol-at-point ()
	  "Consult line the synbol where the point is"
	  (interactive)
	  (consult-line (thing-at-point 'symbol)))
	)

company Emacs最广为使用的补全插件

Emacs最广为使用的补全插件便是 company-mode,其官方主页上已有详细的说明。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  (use-package company
	:ensure t
	:defer 3
	:init (global-company-mode t)
	:config
	(setq company-minimum-prefix-length 1)
	(setq company-tooltip-align-annotations t)
	(setq company-idle-delay 0.0)
	(setq company-show-numbers t)
	(setq company-selection-wrap-around t)
	(setq company-transformers '(company-sort-by-occurrence)))

yasnippet模板补全

yasnippet 插件是一个非常强大的模板补全系统。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  ;; yasnippet settings
  (use-package yasnippet
	:ensure t
	:diminish yas-minor-mode
	:hook ((after-init . yas-reload-all)
		   ((prog-mode LaTeX-mode org-mode) . yas-minor-mode))
	:config
	;; Suppress warning for yasnippet code.
	(require 'warnings)
	(add-to-list 'warning-suppress-types '(yasnippet backquote-change))

	(setq yas-prompt-functions '(yas-x-prompt yas-dropdown-prompt))
	(defun smarter-yas-expand-next-field ()
	  "Try to `yas-expand' then `yas-next-field' at current cursor position."
	  (interactive)
	  (let ((old-point (point))
			(old-tick (buffer-chars-modified-tick)))
		(yas-expand)
		(when (and (eq old-point (point))
				   (eq old-tick (buffer-chars-modified-tick)))
		  (ignore-errors (yas-next-field))))))

css for html export

1
2
3
4
5
6
7
8
9
  # -*- mode: snippet -*-
  # name: CssForHtmlExport
  # key: <css
  # --
  ,#+TITLE: ${1:`(file-name-base buffer-file-name)`}
  ,#+OPTIONS: toc:nil num:3 H:4 ^:nil pri:t
  ,#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://gongzhitaao.org/orgcss/org.css"/>

  $0

emacslisp

1
2
3
4
5
6
7
  # -*- mode: snippet -*-
  # name: emacslisp
  # key: <el
  # --
  ,#+BEGIN_SRC emacs-lisp
  $0
  \#+END_SRC

embark 插件提供了一系列的迷你缓冲区的类似右键机制的增强

embark 插件提供了一系列的迷你缓冲区的类似右键机制的增强。

 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
  (use-package embark
	:ensure t
	:bind (([remap describe-bindings] . embark-bindings)
		   ("C-'" . embark-act)
		   :map minibuffer-local-map
		   :map minibuffer-local-completion-map
		   ("TAB" . minibuffer-force-complete)
		   :map embark-file-map
		   ("E" . consult-file-externally)      ; Open file externally, or `we' in Ranger
		   ("O" . consult-directory-externally) ; Open directory externally
		   )
	:init
	;; Optionally replace the key help with a completing-read interface
	(setq prefix-help-command #'embark-prefix-help-command)
	:config
	;; Show Embark actions via which-key
	(setq embark-action-indicator
		  (lambda (map)
			(which-key--show-keymap "Embark" map nil nil 'no-paging)
			#'which-key--hide-popup-ignore-command)
		  embark-become-indicator embark-action-indicator)

	;; open directory
	(defun consult-directory-externally (file)
	  "Open directory externally using the default application of the system."
	  (interactive "fOpen externally: ")
	  (if (and (eq system-type 'windows-nt)
			   (fboundp 'w32-shell-execute))
		  (shell-command-to-string (encode-coding-string (replace-regexp-in-string "/" "\\\\"
																				   (format "explorer.exe %s" (file-name-directory (expand-file-name file)))) 'gbk))
		(call-process (pcase system-type
						('darwin "open")
						('cygwin "cygstart")
						(_ "xdg-open"))
					  nil 0 nil
					  (file-name-directory (expand-file-name file)))))

	;; Hide the mode line of the Embark live/completions buffers
	(add-to-list 'display-buffer-alist
				 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
				   nil
				   (window-parameters (mode-line-format . none))))
	)

  (use-package embark-consult
	:ensure t
	:hook (embark-collect-mode . consult-preview-at-point-mode))

init-completion.el 文件尾

1
2
3
4

  (provide 'init-completion)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-completion.el ends here

init-dired.el

Emacs文件管理设置。

init-dired.el 文件头

1
2
3
4
  ;;; init-dired.el --- Dired settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

init-dired.el 文件尾

1
2
3
4

  (provide 'init-dired)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-dired.el ends here

init-tools.el

init-tools.el 文件头

1
2
3
4
  ;;; init-tools.el --- Tools settings -*- lexical-binding: t -*-
  ;;; Commentary: Useful tools to make Emacs efficient!

  ;;; Code:

helpful帮助增强

helpful 插件提供了帮助增强。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  (use-package helpful
	:ensure t
	:commands (helpful-callable helpful-variable helpful-command helpful-key helpful-mode)
	:bind (([remap describe-command] . helpful-command)
		   ("C-h f" . helpful-callable)
		   ("C-h v" . helpful-variable)
		   ("C-h s" . helpful-symbol)
		   ("C-h S" . describe-syntax)
		   ("C-h m" . describe-mode)
		   ("C-h F" . describe-face)
		   ([remap describe-key] . helpful-key))
	)

pass密码管理

通过 pass 插件来进行密码管理。

1
2
3
4
  (use-package pass
	:ensure t
	:commands (pass)
	)

cnfonts 用于缩放字体

cnfonts 原来叫: chinese-fonts-setup, 是一个 Emacs 中英文字体配置工 具。可以比较方便地实现中文字体和英文字体等宽(也就是大家常说的中英 文对齐)。

1
2
3
4
5
6
7
8
  (use-package cnfonts
	:ensure t
	:defer 3
	:init (cnfonts-mode t)
	:config
	(define-key cnfonts-mode-map (kbd "C--") #'cnfonts-decrease-fontsize)
	(define-key cnfonts-mode-map (kbd "C-=") #'cnfonts-increase-fontsize)
	)

bhj-fonts字体配置

参考链接

狠狠地折腾了一把Emacs中文字体

全局放大Emacs字体

bhj-fonts

  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
  (defun qiang-font-existsp (font)
	(if (null (x-list-fonts font))
		nil t))

  (defun qiang-make-font-string (font-name font-size)
	(if (and (stringp font-size)
			 (equal ":" (string (elt font-size 0))))
		(format "%s%s" font-name font-size)
	  (format "%s-%s" font-name font-size)))

  (defvar bhj-english-font-size nil)
  (defun qiang-set-font (english-fonts
						 english-font-size
						 chinese-fonts
						 &optional chinese-fonts-scale
						 )
	(setq chinese-fonts-scale (or chinese-fonts-scale 1.2))
	(save-excursion
	  (with-current-buffer (find-file-noselect "~/.config/system-config/emacs-font-size")
		(delete-region (point-min) (point-max))
		(insert (format "%s" english-font-size))
		(let ((before-save-hook nil)
			  (after-save-hook nil))
		  (save-buffer))
		(kill-buffer)))
	(setq face-font-rescale-alist `(("Microsoft Yahei" . ,chinese-fonts-scale)
									("Microsoft_Yahei" . ,chinese-fonts-scale)
									("微软雅黑" . ,chinese-fonts-scale)
									("WenQuanYi Zen Hei" . ,chinese-fonts-scale)))
	"english-font-size could be set to \":pixelsize=18\" or a integer.
  If set/leave chinese-font-size to nil, it will follow english-font-size"
	(require 'cl)                         ; for find if
	(setq bhj-english-font-size english-font-size)
	(let ((en-font (qiang-make-font-string
					(find-if #'qiang-font-existsp english-fonts)
					english-font-size))
		  (zh-font (font-spec :family (find-if #'qiang-font-existsp chinese-fonts))))

	  ;; Set the default English font
	  ;;
	  ;; The following 2 method cannot make the font settig work in new frames.
	  ;; (set-default-font "Consolas:pixelsize=18")
	  ;; (add-to-list 'default-frame-alist '(font . "Consolas:pixelsize=18"))
	  ;; We have to use set-face-attribute
	  (set-face-attribute
	   'default nil :font en-font)
	  (condition-case font-error
		  (progn
			(set-face-font 'italic (font-spec :family "JetBrains Mono" :slant 'italic :weight 'normal :size (+ 0.0 english-font-size)))
			(set-face-font 'bold-italic (font-spec :family "JetBrains Mono" :slant 'italic :weight 'bold :size (+ 0.0 english-font-size)))

			(set-fontset-font t 'symbol (font-spec :family "JetBrains Mono")))
		(error nil))
	  (set-fontset-font t 'symbol (font-spec :family "Unifont") nil 'append)
	  (set-fontset-font
	   t '(#x2009 . #x2009) (font-spec :family "B&H LucidaBright"))
	  (set-fontset-font t nil (font-spec :family "DejaVu Sans"))

	  ;; Set Chinese font
	  ;; Do not use 'unicode charset, it will cause the english font setting invalid
	  (dolist (charset '(kana han cjk-misc bopomofo))
		(set-fontset-font t charset zh-font)))
	(when (and (boundp 'global-emojify-mode)
			   global-emojify-mode)
	  (global-emojify-mode 1))
	(shell-command-to-string "setsid sawfish-client -e '(maximize-window (input-focus))'"))


  (defvar bhj-english-fonts '("JetBrains Mono" "Monaco" "Consolas" "DejaVu Sans Mono" "Monospace" "Courier New"))
  (defvar bhj-chinese-fonts '("Microsoft Yahei" "Microsoft_Yahei" "微软雅黑" "文泉驿等宽微米黑" "黑体" "新宋体" "宋体"))

  (qiang-set-font
   bhj-english-fonts
   (if (file-exists-p "~/.config/system-config/emacs-font-size")
	   (save-excursion
		 (find-file "~/.config/system-config/emacs-font-size")
		 (goto-char (point-min))
		 (let ((monaco-font-size (read (current-buffer))))
		   (kill-buffer (current-buffer))
		   (if (numberp monaco-font-size)
			   monaco-font-size
			 12.5)))
	 12.5)
   bhj-chinese-fonts)

  (defvar chinese-font-size-scale-alist nil)

  ;; On different platforms, I need to set different scaling rate for
  ;; differnt font size.
  (cond
   ((and (boundp '*is-a-mac*) *is-a-mac*)
	(setq chinese-font-size-scale-alist '((10.5 . 1.3) (11.5 . 1.3) (16 . 1.3) (18 . 1.25))))
   ((and (boundp '*is-a-win*) *is-a-win*)
	(setq chinese-font-size-scale-alist '((11.5 . 1.25) (16 . 1.25))))
   (t ;; is a linux:-)
	(setq chinese-font-size-scale-alist '((12 . 1.25) (12.5 . 1.25) (14 . 1.20) (16 . 1.25) (20 . 1.20)))))

  (defvar bhj-english-font-size-steps '(9 10.5 11.5 12 12.5 13 14 16 18 20 22 40))
  (defun bhj-step-frame-font-size (step)
	(let ((steps bhj-english-font-size-steps)
		  next-size)
	  (when (< step 0)
		(setq steps (reverse bhj-english-font-size-steps)))
	  (setq next-size
			(cadr (member bhj-english-font-size steps)))
	  (when next-size
		(qiang-set-font bhj-english-fonts next-size bhj-chinese-fonts (cdr (assoc next-size chinese-font-size-scale-alist)))
		(message "Your font size is set to %.1f" next-size))))

  ;; (global-set-key (kbd "C-x M--") (lambda () (interactive) (bhj-step-frame-font-size -1)))
  ;; (global-set-key (kbd "C-x M-=") (lambda () (interactive) (bhj-step-frame-font-size 1)))
  (global-set-key (kbd "C--") (lambda () (interactive) (bhj-step-frame-font-size -1)))
  (global-set-key (kbd "C-=") (lambda () (interactive) (bhj-step-frame-font-size 1)))

  (set-face-attribute 'default nil :font (font-spec))

  ;; {%org-mode%}
  ;; here are 20 hanzi and 40 english chars, see if they are the same width
  ;; 你你你你你你你你你你你你你你你你你你你你
  ;; aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  ;; /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/
  ;; {%/org-mode%}

init-tools.el 文件尾

1
2
3
4

  (provide 'init-tools)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-tools.el ends here

init-rss.el

Emacs的RSS新闻阅读设置

init-rss.el 文件头

1
2
3
4
  ;;; init-rss.el --- RSS settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

elfeed 一个非常棒的RSS新闻阅读客户端

elfeed 插件是一个非常棒的RSS新闻阅读客户端。

 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
  (use-package elfeed
	:ensure t
	:hook ((elfeed-new-entry . (lambda () (elfeed-make-tagger :feed-url "video" :add '(video))
								 (elfeed-make-tagger :entry-title "图卦" :add '(pic)))))
	:bind (("C-x M-r" . elfeed)
		   :map elfeed-search-mode-map
		   ("g" . elfeed-update)
		   ("G" . elfeed-search-update--force)
		   ("o" . elfeed-default-browser-open)
		   :map elfeed-show-mode-map
		   ("M-v" . scroll-down-command)
		   ("j" . scroll-up-line)
		   ("k" . scroll-down-line))
	:config
	(setq elfeed-db-directory "~/.elfeed")
	;; capture template for elfeed
	(with-eval-after-load 'org-capture
	  (add-to-list 'org-capture-templates '("r" "Elfeed RSS" entry (file+headline "capture.org" "Elfeed")
											"* %:elfeed-entry-title :READ:\n%?\n%a"
											:empty-lines-after 1
											:prepend t))
	  (add-to-list 'org-capture-templates-contexts '("r" ((in-mode . "elfeed-show-mode")
														  (in-mode . "elfeed-search-mode")))))
	;; ================================
	;; open entry with browser
	;; ================================
	(defun elfeed-default-browser-open (&optional use-generic-p)
	  "open with default browser"
	  (interactive "P")
	  (let ((entries (elfeed-search-selected)))
		(cl-loop for entry in entries
				 do (elfeed-untag entry 'unread)
				 when (elfeed-entry-link entry)
				 do (browse-url it))
		(mapc #'elfeed-search-update-entry entries)
		(unless (use-region-p) (forward-line))))
	:custom
	(elfeed-feeds '(
					("https://planet.emacslife.com/atom.xml" emacs)
					("http://www.dapenti.com/blog/rss2.asp?name=xilei" news)
					("https://remacs.cc/index.xml" emacs)
					))
	(elfeed-use-curl t)
	(elfeed-curl-max-connections 10)
	(elfeed-enclosure-default-dir "~/Downloads/")
	;; (elfeed-search-filter "@4-months-ago +")
	(elfeed-search-filter "")
	(elfeed-sort-order 'descending)
	(elfeed-search-clipboard-type 'CLIPBOARD)
	(elfeed-search-title-max-width 100)
	(elfeed-search-title-min-width 30)
	(elfeed-search-trailing-width 25)
	(elfeed-show-truncate-long-urls t)
	(elfeed-show-unique-buffers t)
	(elfeed-search-date-format '("%F %R" 16 :left))
	)

elfeed-goodies给elfeed优化增强

我们通过 elfeed-goodies 插件给 elfeed 进行优化增强:

1
2
3
4
5
6
7
  (use-package elfeed-goodies
	:ensure t
	:hook (after-init . elfeed-goodies/setup)
	:config
	;; set elfeed show entry switch function
	(setq elfeed-show-entry-switch #'elfeed-goodies/switch-pane) ; switch-to-buffer, pop-to-buffer
	)

init-rss.el 文件尾

1
2
3
4

  (provide 'init-rss)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-rss.el ends here

init-shell.el

Emacs里的shell设置。

init-shell.el 文件头

1
2
3
4
  ;;; init-shell.el --- (E)shell settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

eshell 基本配置

 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
  (use-package eshell
	:ensure nil
	:functions eshell/alias
	:hook ((eshell-mode . (lambda ()
							(term-mode-common-init)
							;; Remove cmd args word by word
							(modify-syntax-entry ?- "w")
							(visual-line-mode 1)
							(setenv "PAGER" "cat")))
		   )
	:config
	(defun term-mode-common-init ()
	  "The common initialization for term."
	  (setq-local scroll-margin 0)
	  (setq-local truncate-lines t)
	  )

	;; 在Emacs里输入vi,直接在buffer里打开文件
	(defalias 'eshell/vi 'find-file)
	(defalias 'eshell/vim 'find-file)

	;; 语法高亮显示
	(defun eshell/bat (file)
	  "cat FILE with syntax highlight."
	  (with-temp-buffer
		(insert-file-contents file)
		(let ((buffer-file-name file))
		  (delay-mode-hooks
			(set-auto-mode)
			(font-lock-ensure)))
		(buffer-string)))
	(defalias 'eshell/cat 'eshell/bat)

	;; 交互式进入目录
	(defun eshell/z ()
	  "cd to directory with completion."
	  (let ((dir (completing-read "Directory: " (ring-elements eshell-last-dir-ring) nil t)))
		(eshell/cd dir)))

	;; 查找文件
	(defun eshell/f (filename &optional dir)
	  "Search for files matching FILENAME in either DIR or the
  current directory."
	  (let ((cmd (concat
				  ;; using find
				  (executable-find "find")
				  " " (or dir ".")
				  " -not -path '*/.git*'"            ; ignore .git directory
				  " -and -not -path 'build'"         ; ignore cmake build directory
				  " -and -not -path '*/eln-cache*'"  ; ignore eln cache
				  " -and -type f -and -iname "
				  "'*" filename "*'")))
		(eshell-command-result cmd)))

	:custom
	(eshell-banner-message
	 '(format "%s %s\n"
			  (propertize (format " %s " (string-trim (buffer-name)))
						  'face 'mode-line-highlight)
			  (propertize (current-time-string)
						  'face 'font-lock-keyword-face)))
	(eshell-scroll-to-bottom-on-input 'all)
	(eshell-scroll-to-bottom-on-output 'all)
	(eshell-kill-on-exit t)
	(eshell-kill-processes-on-exit t)
	;; Don't record command in history if starts with whitespace
	(eshell-input-filter 'eshell-input-filter-initial-space)
	(eshell-error-if-no-glob t)
	(eshell-glob-case-insensitive t)
	;; set scripts
	(eshell-rc-script (locate-user-emacs-file "etc/eshell/profile"))
	(eshell-login-script (locate-user-emacs-file "etc/eshell/login"))
	)

eshell alias 设置

1
2
3
4
5
6
7
8
9
  alias ff find-file $1
  alias fo find-file-other-window $1
  alias d dired $1
  alias ll ls -alh
  alias l. ls -dh .*
  alias up eshell-up $1
  alias pk eshell-up-peek $1
  alias less view-file $1
  alias more view-file $1

eshell 里的 C-d

C-d 更智能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  (use-package em-rebind
	:ensure nil
	:commands eshell-delchar-or-maybe-eof)

  (use-package esh-mode
	:ensure nil
	:bind (:map eshell-mode-map
				("C-d" . eshell-delchar-or-maybe-eof)
				("C-r" . consult-history)
				("C-l" . eshell/clear))
	)

Eshell 的命令历史

1
2
3
4
5
6
7
  (use-package em-hist
	:ensure nil
	:defer t
	:custom
	(eshell-history-size 1024)
	(eshell-hist-ignoredups t)
	(eshell-save-history-on-exit t))

有些命令使用 term

有一些命令如 top,我们还是使用 term:

1
2
3
4
5
6
7
8
9
  ;; following commands will run on term instead
  (use-package em-term
	:ensure nil
	:defer t
	:custom
	(eshell-visual-commands '("top" "htop" "less" "more"))
	(eshell-visual-subcommands '(("git" "help" "lg" "log" "diff" "show")))
	(eshell-visual-options '(("git" "--help" "--paginate")))
	(eshell-destroy-buffer-when-process-dies t))

eshell-git-prompt 命令行主题

eshell-git-prompt 插件提供了数个好看的 Eshell 命令行主题。

1
2
3
4
5
6
7
8
  (use-package eshell-git-prompt
	:ensure t
	:after esh-mode
	:custom-face
	(eshell-git-prompt-multiline2-dir-face ((t (:foreground "#c09035" :bold t))))
	:config
	(eshell-git-prompt-use-theme 'multiline2)
	)

eshell-syntax-highlighting 语法高亮

eshell-syntax-highlighting 插件为Eshell提供语法高亮。

1
2
3
4
5
6
7
  (use-package eshell-syntax-highlighting
	:after esh-mode
	:ensure t
	:hook (eshell-mode . eshell-syntax-highlighting-global-mode)
	:custom-face
	(eshell-syntax-highlighting-shell-command-face ((t (:foreground "#7cc77f" :bold t))))
	)

capf-autosuggest自动补全

capf-autosuggest 提供Fish类似的Eshell命令自动补全功能。类似的插件还有 esh-autosuggest

1
2
3
4
5
6
  (use-package capf-autosuggest
	:ensure t
	:hook ((eshell-mode comint-mode) . capf-autosuggest-mode)
	:custom-face
	(capf-autosuggest-face ((t (:foreground "#dae7ff"))))
	)

eshell-up快速进入父级文件夹

eshell-up 插件可以快速进入当前文件夹的任何一个父级文件夹。通过 up 命令(已经设置了up 在eshell里的alias)进入当前文件夹的任何一级父目录。

1
2
3
4
5
6
7
  (use-package eshell-up
	:ensure t
	:commands (eshell-up eshell-up-peek)
	:config
	;; to print the matching parent directory before changing to it
	(setq eshell-up-print-parent-dir t)
	)

init-shell.el 文件尾

1
2
3
4

  (provide 'init-shell)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-shell.el ends here

init-browser.el

init-browser.el 文件头

1
2
3
4
  ;;; init-browser.el --- Browser settings -*- lexical-binding: t -*-
  ;;; Commentary:

  ;;; Code:

EWW 配置

Emacs 内置 EWW 浏览器配置。

 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
  (use-package shr
	:ensure nil
	:defer t
	:custom
	(shr-inhibit-images t)                ; 不显示图片
	(shr-image-animate nil)               ; 不显示 gif    
	)

  (use-package eww
	:ensure nil
	:commands eww eww-follow-link
	:hook (eww-mode . visual-line-mode)
	:bind (
		   :map eww-mode-map
		   ("o" . eww-browse-with-external-browser)
		   ("D" . eww-forward-url)
		   ("S" . eww-back-url)
		   ("f" . link-hint-open-link)
		   ("TAB" . shr-next-link)
		   ("<backtab>" . shr-previous-link)
		   ("j" . scroll-up-line)
		   ("k" . scroll-down-line)
		   )
	:config
	(setq eww-download-directory (expand-file-name "~/Downloads"))
	(custom-set-variables  
	 '(eww-search-prefix "https://cn.bing.com/search?q="))
	)

init-browser.el 文件尾

1
2
3
4

  (provide 'init-browser)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;; init-browser.el ends here
Licensed under CC BY-NC-SA 4.0