u
[emacs-helper.git] / eh-basic.el
blob8adc02b69fe00da7f0b7de34656ae20b20c1a572
1 ;;; eh-basic.el --- Tumashu's basic emacs configuation -*- lexical-binding: t; -*-
3 ;; * Header
4 ;; Copyright (c) 2011-2019, Feng Shu
6 ;; Author: Feng Shu <tumashu@gmail.com>
7 ;; URL: https://github.com/tumashu/emacs-helper
8 ;; Version: 0.0.3
10 ;; This file is not part of GNU Emacs.
12 ;;; License:
14 ;; This program is free software; you can redistribute it and/or
15 ;; modify it under the terms of the GNU General Public License
16 ;; as published by the Free Software Foundation; either version 3
17 ;; of the License, or (at your option) any later version.
19 ;; This program is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
29 ;;; Commentary:
31 ;; * 简介 :README:
32 ;; 这个文件是tumashu个人专用的emacs配置文件,emacs中文用户可以参考。
34 ;;; Code:
36 ;; * 代码 :code:
37 (require 'cl-lib)
39 (defun eh-directory ()
40 "返回 emacs-helper 所在的目录。"
41 (file-name-directory
42 (locate-library "eh-basic.el")))
44 (defun eh-system-open (path &rest _args)
45 (let ((path (expand-file-name path)))
46 (cond ((string-equal system-type "windows-nt")
47 (with-no-warnings (w32-shell-execute "open" path)))
48 ((string-equal system-type "darwin")
49 (concat "open " (shell-quote-argument path)))
50 ((string-equal system-type "gnu/linux")
51 (let ((process-connection-type nil))
52 (start-process "" nil "xdg-open" path))))))
54 (defun eh-file-extension-match-p (file-name extensions)
55 (cl-find-if
56 (lambda (extension)
57 (string-match-p (format "\\.%s\\'" extension) file-name))
58 extensions))
60 (defun eh-find-file (orig-fun &rest args)
61 (let ((file-name (car args))
62 ;; this-command may be a lambda
63 (cmd (ignore-errors (symbol-name this-command))))
64 (cond ((and (file-exists-p file-name)
65 (eh-file-extension-match-p
66 file-name
67 '("doc" "docx" "xls" "xlsx" "ppt" "pptx" "wps"
68 "pdf" "xps" "oxps" "cbz" "epub" "fb2" "fbz" "djvu"
69 "jpg" "jpeg" "png" "bmp" "gif" "svg" "webp"
70 "avi" "rmvb" "mp4" "mkv" "mp3" "ogg")))
71 (eh-system-open file-name))
72 ((and cmd
73 (or (string-match "^org-" cmd)
74 (string-match "^eh-org-" cmd)
75 (string-match "^eh-share2computer-" cmd))
76 (file-directory-p file-name))
77 (eh-system-open file-name))
78 (t (apply orig-fun args)))))
80 (dolist (f '(find-file
81 find-file-read-only
82 find-file-other-window
83 find-file-other-frame))
84 (advice-add f :around 'eh-find-file))
86 ;; ** Full name and Email
87 (setq user-full-name "Feng Shu")
88 (setq user-mail-address "tumashu@163.com")
90 ;; ** 启动时默认打开的 buffer.
91 (setq inhibit-startup-screen t)
92 (setq initial-buffer-choice nil)
93 (setq initial-major-mode 'emacs-lisp-mode)
94 (setq initial-scratch-message "")
96 ;; ** yes-or-no-p
97 (defalias 'yes-or-no-p 'y-or-n-p)
99 ;; ** 使用空格缩进
100 (setq-default indent-tabs-mode nil)
102 ;; ** 关闭 beep
103 (setq visible-bell t)
105 ;; ** 不使用 dialog
106 (setq use-dialog-box nil)
108 ;; ** 让全角空格不会显示下划线
109 (setq nobreak-char-display nil)
110 ;; (setq eh-space (propertize "  " 'face '(:weight 'bold)))
111 (defvar eh-space "  ")
113 ;; ** 设置 mode-line
114 ;; 在 mode-line 最后追加一个半角空格,一个全角空格,防止因为字体高度原
115 ;; 因,导致 mode-line 抖动。
116 (setq mode-line-end-spaces
117 '(:eval (if (display-graphic-p) eh-space "-%-")))
119 ;; ** 让 *scratch* buffer 无法删除
120 (defun eh-unkillable-scratch-buffer ()
121 (if (string= (buffer-name (current-buffer)) "*scratch*")
122 (progn
123 (delete-region (point-min) (point-max))
124 (insert initial-scratch-message)
125 nil)
128 (add-hook 'kill-buffer-query-functions
129 #'eh-unkillable-scratch-buffer)
131 ;; ** kill buffer
132 (global-set-key (kbd "C-x k") #'kill-current-buffer)
134 ;; ** 设置 emacs 包管理器
135 (require 'package)
136 (setq package-archives
137 '(("gnu" . "https://elpa.gnu.org/packages/")
138 ("nongnu" . "https://elpa.nongnu.org/nongnu/")
139 ("melpa" . "https://melpa.org/packages/")))
141 (setq package-archive-priorities
142 '(("gnu" . 10)
143 ("nongnu" . 9)
144 ("melpa" . 8)))
146 (unless package--initialized
147 (package-initialize))
149 ;; ** 设置 Charset
150 (set-language-environment "UTF-8")
151 (set-buffer-file-coding-system 'utf-8-unix)
152 (set-clipboard-coding-system 'utf-8-unix)
153 (set-file-name-coding-system 'utf-8-unix)
154 (set-keyboard-coding-system 'utf-8-unix)
155 (set-next-selection-coding-system 'utf-8-unix)
156 (set-selection-coding-system 'utf-8-unix)
157 (set-terminal-coding-system 'utf-8-unix)
159 (when (eq system-type 'windows-nt)
160 (set-language-environment "Chinese-GBK")
161 (set-selection-coding-system 'gbk-dos)
162 (set-next-selection-coding-system 'gbk-dos)
163 (set-clipboard-coding-system 'gbk-dos))
165 ;; ** Window 系统下关闭 Emacs 时,强制确认,防止误操作。
166 (when (eq system-type 'windows-nt)
167 (setq confirm-kill-emacs 'yes-or-no-p))
169 ;; ** 关闭自动备份功能,我有 git :-)
170 (setq make-backup-files nil)
172 ;; ** 保存文件之前,删除无用的空格
173 ;; (require 'whitespace)
174 ;; 使用下面这一行配置后,org-mode 的源代码总是莫名其妙的
175 ;; (add-hook 'before-save-hook #'whitespace-cleanup)
176 ;; 更改,这会导致生成的 diff 相当乱。
178 ;; (add-hook 'before-save-hook
179 ;; #'(lambda ()
180 ;; (delete-trailing-whitespace)))
182 ;; ** 设置 recentf
183 (require 'recentf)
184 (setq recentf-auto-cleanup 'never)
185 (recentf-mode 1)
186 (setq recentf-max-saved-items 99)
187 (setq recentf-max-menu-items 99)
188 (setq recentf-show-file-shortcuts-flag nil)
189 (setq recentf-exclude
190 '("COMMIT" "autoloads" "archive-contents" "eld" "newsrc"
191 ".recentf" "emacs-font-size.conf" "eh-scratch"
192 "pyim-dcache-.*"))
193 ;; 自动保存recentf文件。
194 (add-hook 'find-file-hook #'recentf-save-list)
196 ;; ** 设置区域选择快捷键
197 (global-unset-key (kbd "C-x C-x"))
198 (global-set-key (kbd "C-x <SPC>") 'set-mark-command)
199 ;; QQ 将会在 emacs 之前捕捉 M-w 快捷键,记得取消。
200 ;; 另外绑定 C-c w 作为备用。
201 (global-set-key (kbd "C-c w") 'kill-ring-save)
202 (global-set-key (kbd "C-x C-x C-x") 'exchange-point-and-mark)
203 (global-set-key (kbd "C-x C-x <SPC>") 'rectangle-mark-mode)
205 ;; ** 保存 session
206 ;; (desktop-save-mode 1)
208 ;; ** 关闭 tool-bar
209 (when (functionp 'tool-bar-mode)
210 (tool-bar-mode -1))
212 ;; ** 关闭 scroll-bar
213 (when (functionp 'scroll-bar-mode)
214 (scroll-bar-mode -1))
216 ;; ** 启用像素级 scroll
217 (when (functionp 'pixel-scroll-precision-mode)
218 (pixel-scroll-precision-mode 1))
220 ;; ** 解决最大化留缝隙的问题
221 (setq frame-resize-pixelwise t)
223 ;; ** 加载 bookmark
224 (require 'bookmark)
225 (bookmark-maybe-load-default-file)
227 ;; ** 配对括号高亮显示
228 (require 'paren)
229 (show-paren-mode 1)
231 ;; ** 括号自动匹配
232 (require 'elec-pair)
233 (electric-pair-mode 1)
235 ;; ** 处理长行
236 (global-so-long-mode 1)
238 ;; ** 处理折行
239 (toggle-word-wrap 1)
240 (setq word-wrap-by-category t)
242 ;; ** 启用 menu-bar
243 (if (> emacs-major-version 28)
244 (menu-bar-mode -1)
245 (menu-bar-mode 1))
247 ;; ** 启用右键菜单
248 (when (functionp 'context-menu-mode)
249 (context-menu-mode 1))
251 ;; ** 减少 C-g 时的闪烁
252 (setq ring-bell-function 'ignore)
254 ;; ** switch-window
255 (require 'switch-window)
257 (unless (display-graphic-p)
258 (setq switch-window-shortcut-appearance 'asciiart))
259 (setq switch-window-shortcut-style 'qwerty)
260 (setq switch-window-input-style 'minibuffer)
261 (global-set-key (kbd "C-x o") 'switch-window)
263 ;; ** tab-line
264 (require 'tab-line)
265 (global-tab-line-mode 1)
266 (setq tab-line-close-tab-function #'kill-buffer)
267 (setq tab-line-tab-name-truncated-max 22)
268 (setq tab-line-tab-name-ellipsis "…")
269 (setq tab-line-tab-name-function
270 #'tab-line-tab-name-truncated-buffer)
272 (defun eh-tab-line-format (orig_func)
273 "在 tab-line 的最后添加一个全角空格,防止 tab-line 抖动。"
274 (list (funcall orig_func) eh-space))
276 (advice-add 'tab-line-format :around #'eh-tab-line-format)
278 ;; ** save history
279 (require 'savehist)
280 (savehist-mode 1)
282 ;; ** minibuffer and completing-read
283 (require 'simple)
284 (require 'minibuffer)
285 (setq completion-auto-help t)
286 (setq completion-auto-select nil)
287 (setq completion-show-help nil)
288 (setq completion-show-inline-help t)
289 (setq completions-max-height 15)
290 (setq completions-format 'one-column)
291 (setq enable-recursive-minibuffers t)
292 (setq history-delete-duplicates t)
293 (setq minibuffer-prompt-properties
294 '(read-only t cursor-intangible t face minibuffer-prompt))
295 (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
297 (defun eh-crm-indicator (args)
298 (cons (concat "[CRM] " (car args))
299 (cdr args)))
301 (advice-add #'completing-read-multiple :filter-args #'eh-crm-indicator)
303 ;; ** Vertico
304 (require 'vertico)
305 (require 'vertico-directory)
306 (vertico-mode 1)
307 (define-key vertico-map "\r" #'vertico-directory-enter)
308 (define-key vertico-map "\d" #'vertico-directory-delete-char)
309 (define-key vertico-map "\M-\d" #'vertico-directory-delete-word)
310 (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
312 ;; ** orderless
313 (require 'orderless)
314 (require 'pyim-cregexp)
315 (setq completion-styles '(basic orderless)
316 completion-category-defaults nil
317 completion-category-overrides '((file (styles partial-completion))))
319 (defun eh-orderless-regexp (orig_func component)
320 (let ((result (funcall orig_func component)))
321 (pyim-cregexp-build result)))
323 (advice-add 'orderless-regexp :around #'eh-orderless-regexp)
325 ;; ** consult
326 (require 'consult)
327 (setq consult-preview-key nil)
328 (global-set-key (kbd "C-x b") 'consult-buffer)
329 (global-set-key (kbd "C-x f") 'consult-recent-file)
330 (global-set-key (kbd "C-x C-b") 'ibuffer)
331 (global-set-key (kbd "C-c y") 'consult-yank-pop)
333 ;; ** VC
334 (require 'vc)
335 (require 'vc-hg)
336 (setq vc-handled-backends '(Hg Git))
337 (setq vc-hg-revert-switches '("--no-backup"))
339 ;; ** ChangeLog 命令
340 (require 'add-log)
341 (setq add-log-dont-create-changelog-file t)
342 ;; 大多数情况,我不会手动编辑 ChangeLog 文件,防止误操作。
343 (setq change-log-default-name "01-dont-edit-changelog")
345 ;; ** elisp setting
346 (require 'elisp-mode)
348 ;; ** Indent
349 (electric-indent-mode -1)
351 ;; ** wdired
352 (require 'dired)
353 (require 'wdired)
355 ;; ** 设置拼音输入法
356 (require 'pyim)
357 (require 'pyim-cregexp-utils)
359 (global-set-key (kbd "M-j") 'pyim-convert-string-at-point)
360 (define-key minibuffer-local-map (kbd "C-<return>") 'pyim-cregexp-convert-at-point)
362 (setq default-input-method "pyim")
364 ;; 使用全拼
365 (pyim-default-scheme 'quanpin)
367 ;; pyim 探针设置
368 (setq-default pyim-english-input-switch-functions
369 '(pyim-probe-dynamic-english
370 pyim-probe-isearch-mode
371 pyim-probe-program-mode
372 pyim-probe-org-structure-template))
374 (setq-default pyim-punctuation-half-width-functions
375 '(pyim-probe-punctuation-line-beginning
376 pyim-probe-punctuation-after-punctuation))
378 ;; 开启拼音搜索功能
379 (pyim-isearch-mode 1)
381 ;; 显示5个候选词。
382 (setq pyim-page-length 5)
384 ;; 全拼词库 basedict.
385 (require 'pyim-basedict)
386 (pyim-basedict-enable)
388 ;; ;; liberime
389 ;; (setq liberime-auto-build t)
390 ;; (require 'liberime nil t)
391 ;; (require 'pyim-liberime nil t)
392 ;; (with-eval-after-load "liberime"
393 ;; (liberime-try-select-schema "luna_pinyin_simp")
394 ;; (pyim-default-scheme 'rime-quanpin))
396 ;; ** calendar
397 (require 'calendar)
398 (require 'cal-china-x)
400 ;; 使用英文 day-name, 而不是中文: “星期XX”
401 (setq system-time-locale "C")
403 ;; 一周第一天,0表示星期天, 1表示星期一
404 (setq calendar-week-start-day 0)
406 (setq calendar-holidays
407 '(;;公历节日
408 (holiday-fixed 1 1 "元旦")
409 (holiday-fixed 2 14 "情人节")
410 (holiday-fixed 3 8 "妇女节")
411 (holiday-fixed 3 14 "白色情人节")
412 (holiday-fixed 4 1 "愚人节")
413 (holiday-fixed 5 1 "劳动节")
414 (holiday-fixed 5 4 "青年节")
415 (holiday-float 5 0 2 "母亲节")
416 (holiday-fixed 6 1 "儿童节")
417 (holiday-float 6 0 3 "父亲节")
418 (holiday-fixed 9 10 "教师节")
419 (holiday-fixed 10 1 "国庆节")
420 (holiday-fixed 10 24 "程序员节")
421 (holiday-fixed 12 25 "圣诞节")
422 ;; 农历节日
423 (holiday-lunar 1 1 "春节" 0)
424 (holiday-lunar 1 2 "春节" 0)
425 (holiday-lunar 1 3 "春节" 0)
426 (holiday-lunar 1 15 "元宵节" 0)
427 (holiday-solar-term "清明" "清明节")
428 (holiday-solar-term "小寒" "小寒")
429 (holiday-solar-term "大寒" "大寒")
430 (holiday-solar-term "立春" "立春")
431 (holiday-solar-term "雨水" "雨水")
432 (holiday-solar-term "惊蛰" "惊蛰")
433 (holiday-solar-term "春分" "春分")
434 (holiday-solar-term "谷雨" "谷雨")
435 (holiday-solar-term "立夏" "立夏")
436 (holiday-solar-term "小满" "小满")
437 (holiday-solar-term "芒种" "芒种")
438 (holiday-solar-term "夏至" "夏至")
439 (holiday-solar-term "小暑" "小暑")
440 (holiday-solar-term "大暑" "大暑")
441 (holiday-solar-term "立秋" "立秋")
442 (holiday-solar-term "处暑" "处暑")
443 (holiday-solar-term "白露" "白露")
444 (holiday-solar-term "秋分" "秋分")
445 (holiday-solar-term "寒露" "寒露")
446 (holiday-solar-term "霜降" "霜降")
447 (holiday-solar-term "立冬" "立冬")
448 (holiday-solar-term "小雪" "小雪")
449 (holiday-solar-term "大雪" "大雪")
450 (holiday-solar-term "冬至" "冬至")
451 (holiday-lunar 5 5 "端午节" 0)
452 (holiday-lunar 8 15 "中秋节" 0)
453 (holiday-lunar 7 7 "七夕情人节" 0)
454 (holiday-lunar 12 8 "腊八节" 0)
455 (holiday-lunar 9 9 "重阳节" 0)))
457 (setq calendar-month-name-array
458 ["一月" "二月" "三月" "四月" "五月" "六月"
459 "七月" "八月" "九月" "十月" "十一月" "十二月"])
461 (setq calendar-day-name-array
462 ["周日" "周一" "周二" "周三" "周四" "周五" "周六"])
464 (defun eh-org-chinese-anniversary (year lunar-month lunar-day &optional mark)
465 (if year
466 (let* ((d-date (diary-make-date lunar-month lunar-day year))
467 (a-date (calendar-absolute-from-gregorian d-date))
468 (c-date (calendar-chinese-from-absolute a-date))
469 (cycle (car c-date))
470 (yy (cadr c-date))
471 (y (+ (* 100 cycle) yy)))
472 (diary-chinese-anniversary lunar-month lunar-day y mark))
473 (diary-chinese-anniversary lunar-month lunar-day year mark)))
475 ;; * Footer
476 (provide 'eh-basic)
478 ;; Local Variables:
479 ;; coding: utf-8-unix
480 ;; End:
482 ;;; eh-basic.el ends here