├── etc ├── yasnippet │ └── snippets │ │ ├── python-mode │ │ ├── lambda │ │ ├── impnumpy │ │ ├── imppandas │ │ ├── main │ │ ├── printline │ │ ├── classinit │ │ ├── try │ │ ├── withopen │ │ ├── definefunc │ │ └── impplt │ │ ├── org-mode │ │ ├── src │ │ ├── notes │ │ ├── quote │ │ ├── revealsplit │ │ ├── sql │ │ ├── startup │ │ ├── conf │ │ ├── orgsrc │ │ ├── properties │ │ ├── shell │ │ ├── comment │ │ ├── eshell │ │ ├── example │ │ ├── latexred │ │ ├── revealfrag │ │ ├── apples │ │ ├── emacslisp │ │ ├── markdown │ │ ├── authinfo │ │ ├── dalle │ │ ├── einpython │ │ ├── option │ │ ├── tangleno │ │ ├── nevereval │ │ ├── htmlcolor │ │ ├── python │ │ ├── revealinit │ │ ├── latextable │ │ ├── headerargs │ │ ├── imageattr │ │ ├── hugoexport │ │ ├── jupyterpython │ │ ├── htmlhead │ │ ├── ditaa │ │ ├── listtable │ │ ├── orgai │ │ ├── resume │ │ ├── customid │ │ ├── d2 │ │ ├── dot │ │ ├── revealbackground │ │ ├── table │ │ ├── mermaid │ │ ├── sqlstudy │ │ ├── gnuplot │ │ ├── sqlmidea │ │ ├── video │ │ ├── lilypond │ │ ├── math │ │ ├── salt │ │ ├── setupfile │ │ ├── json │ │ ├── orgroam │ │ ├── yaml │ │ ├── hugo │ │ ├── mindmap │ │ ├── plantuml │ │ ├── title │ │ ├── timelinehorizon │ │ └── timelinevertical │ │ └── emacs-lisp-mode │ │ ├── usepackage │ │ └── defun └── eshell │ └── aliases ├── early-init.el ├── lisp ├── init-browser.el ├── init-rss.el ├── init-dev.el ├── init-shell.el ├── init-base.el ├── init-tools.el ├── init-edit.el ├── init-mail.el ├── init-dired.el ├── init-completion.el └── init-ui.el ├── README.org ├── config-mirror ├── resume-template.org ├── emacs-config-l4.org ├── emacs-config-l5.org ├── emacs-config-l6.org └── emacs-config-l7.org └── init.el /etc/yasnippet/snippets/python-mode/lambda: -------------------------------------------------------------------------------- 1 | # -*- mode: snippet -*- 2 | # name: lambda 3 | # key: @@$0@@html:@@ -------------------------------------------------------------------------------- /etc/yasnippet/snippets/python-mode/definefunc: -------------------------------------------------------------------------------- 1 | # -*- mode: snippet -*- 2 | # name: definefunc 3 | # key: -------------------------------------------------------------------------------- /etc/yasnippet/snippets/org-mode/ditaa: -------------------------------------------------------------------------------- 1 | # -*- mode: snippet -*- 2 | # name: ditaa 3 | # key:
9 | #+END_video 10 | -------------------------------------------------------------------------------- /etc/yasnippet/snippets/org-mode/lilypond: -------------------------------------------------------------------------------- 1 | # -*- mode: snippet -*- 2 | # name: lilypond 3 | # key:
  • 9 | #+TIMELINE_HEADER:

    10 | #+TIMELINE_FOOTER:

    11 | #+TIMELINE_FOOTER:

    12 | #+HTML_HEAD: 13 | #+TIMELINE_MODE: horizontal 14 | #+TIMELINE_FORCE_VERTICAL_MODE: 800 15 | #+TIMELINE_VISIBLE_ITEMS: 5 -------------------------------------------------------------------------------- /etc/yasnippet/snippets/org-mode/timelinevertical: -------------------------------------------------------------------------------- 1 | # -*- mode: snippet -*- 2 | # name: timeline-vertical 3 | # key: 9 | #+TIMELINE_HEADER:

    10 | #+TIMELINE_FOOTER:

    11 | #+TIMELINE_FOOTER:

    12 | #+HTML_HEAD: 13 | #+TIMELINE_MODE: vertical 14 | #+TIMELINE_VERTICAL_START_POSITION: left 15 | #+TIMELINE_VERTICAL_TRIGGER: 150x -------------------------------------------------------------------------------- /early-init.el: -------------------------------------------------------------------------------- 1 | ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | ;; 设置垃圾回收参数 7 | (setq gc-cons-threshold most-positive-fixnum) 8 | (setq gc-cons-percentage 0.6) 9 | 10 | ;; 启动早期不加载`package.el'包管理器 11 | (setq package-enable-at-startup nil) 12 | ;; 不从包缓存中加载 13 | (setq package-quickstart nil) 14 | 15 | ;; 禁止展示菜单栏、工具栏和纵向滚动条 16 | (push '(menu-bar-lines . 0) default-frame-alist) 17 | (push '(tool-bar-lines . 0) default-frame-alist) 18 | (push '(vertical-scroll-bars) default-frame-alist) 19 | 20 | ;; 禁止自动缩放窗口先 21 | (setq frame-inhibit-implied-resize t) 22 | 23 | ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框 24 | (menu-bar-mode -1) 25 | (tool-bar-mode -1) 26 | (scroll-bar-mode -1) 27 | (setq inhibit-splash-screen t) 28 | (setq use-file-dialog nil) 29 | 30 | ;; 在这个阶段不编译 31 | (setq comp-deferred-compilation nil) 32 | 33 | (provide 'early-init) 34 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 35 | ;;; early-init.el ends here 36 | -------------------------------------------------------------------------------- /lisp/init-browser.el: -------------------------------------------------------------------------------- 1 | ;;; init-browser.el --- Browser settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package shr 7 | :ensure nil 8 | :defer t 9 | :custom 10 | (shr-inhibit-images t) ; 不显示图片 11 | (shr-image-animate nil) ; 不显示 gif 12 | ) 13 | 14 | (use-package eww 15 | :ensure nil 16 | :commands eww eww-follow-link 17 | :hook (eww-mode . visual-line-mode) 18 | :bind (("\e\e w" . eww) 19 | :map eww-mode-map 20 | ("o" . eww-browse-with-external-browser) 21 | ("D" . eww-forward-url) 22 | ("S" . eww-back-url) 23 | ("f" . link-hint-open-link) 24 | ("TAB" . shr-next-link) 25 | ("" . shr-previous-link) 26 | ("j" . scroll-up-line) 27 | ("k" . scroll-down-line) 28 | ) 29 | :config 30 | (setq eww-download-directory (expand-file-name "~/Downloads")) 31 | (setq eww-form-checkbox-symbol "☐") 32 | (setq eww-form-checkbox-selected-symbol "☑") 33 | ) 34 | 35 | (provide 'init-browser) 36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 37 | ;;; init-browser.el ends here 38 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: 面向产品经理的Emacs系列教程配套配置文件 2 | #+SUBTITLE: 3 | #+AUTHOR: Randolph HUANG 4 | #+DATE: 2023/05/03 15:33:53 5 | #+EMAIL: xiaojianghuang@gmail.com 6 | 7 | #+STARTUP: overview 8 | #+SETUPFILE: ~/.emacs.d.default/org-setupfile.org 9 | #+OPTIONS: author:nil date:nil email:nil timestamp:nil num:nil 10 | 11 | * 简介 12 | 13 | 本仓库主要配合 [[https://remacs.fun][remacs.fun]] 博客的系列教程,具体的配置文件详见 [[file:emacs-config.org][emacs-config.org]]。 14 | 15 | * 初衷 16 | 17 | 一直想站在一个非程序员的视角来写一个新手教程。乘着新冠变🐏期间,慢慢开始了这个系列教程,这个系列教程尽可能站在一个新手的角度,来循序渐进地介绍 Emacs 的相关使用: 18 | 19 | 1. Emacs 实在是一个太强大的工具,不仅仅是对开发,对产品、运营等都很有用(甚至还有公司的 CEO 在用 Emacs 的); 20 | 2. Emacs 并不是一个容易上手的工具,有一定的门槛,如果没有耐心,没有良好的引导,很容易中途放弃; 21 | 3. Emacs 使用较多的还是开发,因此很多教程大多从开发的角度来讲解,有一定的认知门槛; 22 | 4. 产品经理是一个比较有代表性的群体,如果一个教程,产品经理能轻易的看懂学会,那其他人估计也不会太难; 23 | 24 | 25 | 由于本人的 Emacs 水平有限,对 Emacs Lisp 也知之不多,内容难免粗浅和有很多错误,有问题可以给我提 issue。 26 | 27 | 另外,Emacs的配置文件抄了很多 [[https://emacs-china.org][emacs-china 论坛]]还有互联网上的很多大神,这里统一表示感谢!!! 28 | 29 | #+BEGIN_QUOTE 30 | 声明一下: 31 | 1. 我虽然很早就开始用 Emacs(2008年),但中间很长时间因为职业的原因,中间大概有10年没有用过了,也是从2020年开始逐渐又用了起来。我并不是高手,在 Emacs 社区,我只是个幼儿园学生,但这并不妨碍我对Emacs的热爱和使用。所以这个教程的定位也只是入门,出错在所难免,如果发现有任何问题,请随时提 issue 给我。 32 | 2. Emacs 是高度自由的,我的选择未必适合你,你可以参考,但不用盲从,在初识的时候,可以照抄,有了一定认识和思考后,请按照自己的喜好调教它,这也是 Emacs 的迷人之处。 33 | #+END_QUOTE 34 | -------------------------------------------------------------------------------- /config-mirror/resume-template.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Randolph的简历 2 | #+OPTIONS: toc:nil H:10 tex:t author:nil date:nil 3 | #+STARTUP: hidestars indent 4 | #+LaTex_CLASS: article 5 | #+LaTeX_CLASS_OPTIONS: [letterpaper] 6 | #+LaTeX_HEADER: \usepackage{/Users/randolph/org/template/resume/resume} 7 | #+LATEX_HEADER: \usepackage[explicit]{titlesec} 8 | #+LATEX_HEADER: \usepackage[left=0.4in,right=0.5in,top=0.5in,bottom=0.5in]{geometry} 9 | #+LATEX_HEADER: \pagenumbering{gobble} % remove page number 10 | #+LaTeX_HEADER: \usepackage{tabularx} 11 | #+LaTeX_HEADER: \hypersetup{colorlinks=true, urlcolor={url-blue}} 12 | #+LaTeX_HEADER: \usepackage{enumitem} 13 | #+LaTeX_HEADER: \setlist{leftmargin=0.25in,nosep} 14 | #+LATEX_HEADER: \usepackage{xeCJK,fontspec,xunicode,xltxtra} 15 | #+LATEX_HEADER: \setCJKmainfont{Microsoft YaHei} 16 | #+LATEX_HEADER: \setCJKmonofont{Microsoft YaHei} 17 | #+LATEX_HEADER: \setCJKfamilyfont{Microsoft YaHei}{Microsoft YaHei} 18 | #+LATEX_HEADER: \setmainfont{Microsoft YaHei} 19 | #+LATEX_HEADER: \setmonofont{Source Code Pro} 20 | #+LATEX_HEADER: \usepackage{setspace} 21 | #+LATEX_HEADER: \onehalfspacing 22 | 23 | 24 | #+BEGIN_CENTER 25 | | 手机:(+86) 1860xxxxxxxx | 邮箱:[[mailto:xxxxxxx@gmail.com][xxxxxxx@gmail.com]] | 26 | #+END_CENTER 27 | 28 | * 自我评价 29 | - 走在人工智能人机交互领域应用@@latex:{\color{red}@@ *创新* @@latex:}@@最前端 30 | - 一个有技术背景、有商业洞察力、能力@@latex:{\color{red}@@ *综合* @@latex:}@@的产品经理 31 | - 富有@@latex:{\color{red}@@ *好奇心和激情* @@latex:}@@ 32 | 33 | * 工作经历 34 | ** xx集团 | AI研究院 | 资深产品经理 35 | *** 2020.11 至今 36 | 37 | - 带领团队从 0 开始负责xxxx的工作。 38 | + xxxx; 39 | + xxxx; 40 | \smallskip 41 | - 赋能集团xxxx。 42 | + xxxx *加粗* xxxx; 43 | + xxxx; 44 | 45 | ** xxx公司 | AI产品经理 46 | *** 2020.9 - 2020.11 47 | - 负责xxx。 48 | 49 | 50 | * 教育经历 51 | ** xxx大学 52 | *** 2006 - 2008 53 | xx信息技术,硕士,xxxxxx 54 | 55 | ** xxx 大学 56 | *** 2002 - 2006 57 | xx信息技术,本科 58 | 59 | * 语言及技能 60 | - CET-6,熟练的英语读写听说能力 61 | - 有研发、服务、产品等技术背景 62 | - 有带领团队经验 63 | - 有销售经验和市场洞察力 64 | - 有人工智能、大模型、知识图谱、NLP、互联网等领域经验 65 | - 有良好的沟通表达能力 66 | - 富有好奇心和激情 67 | -------------------------------------------------------------------------------- /lisp/init-rss.el: -------------------------------------------------------------------------------- 1 | ;;; init-rss.el --- RSS settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package elfeed 7 | :ensure t 8 | :hook ((elfeed-new-entry . (lambda () (elfeed-make-tagger :feed-url "video" :add '(video)) 9 | (elfeed-make-tagger :entry-title "图卦" :add '(pic))))) 10 | :bind (("\e\e n" . elfeed) 11 | :map elfeed-search-mode-map 12 | ("g" . elfeed-update) 13 | ("G" . elfeed-search-update--force) 14 | ("o" . elfeed-default-browser-open) 15 | :map elfeed-show-mode-map 16 | ("M-v" . scroll-down-command) 17 | ("j" . scroll-up-line) 18 | ("k" . scroll-down-line)) 19 | :config 20 | (setq elfeed-db-directory "~/.elfeed") 21 | ;; capture template for elfeed 22 | (with-eval-after-load 'org-capture 23 | (add-to-list 'org-capture-templates '("r" "Elfeed RSS" entry (file+headline "capture.org" "Elfeed") 24 | "* %:elfeed-entry-title :READ:\n%?\n%a" 25 | :empty-lines-after 1 26 | :prepend t)) 27 | (add-to-list 'org-capture-templates-contexts '("r" ((in-mode . "elfeed-show-mode") 28 | (in-mode . "elfeed-search-mode"))))) 29 | ;; ================================ 30 | ;; open entry with browser 31 | ;; ================================ 32 | (defun elfeed-default-browser-open (&optional use-generic-p) 33 | "open with default browser" 34 | (interactive "P") 35 | (let ((entries (elfeed-search-selected))) 36 | (cl-loop for entry in entries 37 | do (elfeed-untag entry 'unread) 38 | when (elfeed-entry-link entry) 39 | do (browse-url it)) 40 | (mapc #'elfeed-search-update-entry entries) 41 | (unless (use-region-p) (forward-line)))) 42 | :custom 43 | (elfeed-feeds '( 44 | ("https://planet.emacslife.com/atom.xml" emacs) 45 | ("http://www.dapenti.com/blog/rss2.asp?name=xilei" news) 46 | ("https://remacs.cc/index.xml" emacs product) 47 | )) 48 | (elfeed-use-curl t) 49 | (elfeed-curl-max-connections 10) 50 | (elfeed-enclosure-default-dir "~/Downloads/") 51 | (elfeed-search-filter "@4-months-ago +") 52 | (elfeed-sort-order 'descending) 53 | (elfeed-search-clipboard-type 'CLIPBOARD) 54 | (elfeed-search-title-max-width 100) 55 | (elfeed-search-title-min-width 30) 56 | (elfeed-search-trailing-width 25) 57 | (elfeed-show-truncate-long-urls t) 58 | (elfeed-show-unique-buffers t) 59 | (elfeed-search-date-format '("%F %R" 16 :left)) 60 | ) 61 | 62 | (use-package elfeed-goodies 63 | :ensure t 64 | :hook (after-init . elfeed-goodies/setup) 65 | :config 66 | ;; set elfeed show entry switch function 67 | (setq elfeed-show-entry-switch #'elfeed-goodies/switch-pane) ; switch-to-buffer, pop-to-buffer 68 | ) 69 | 70 | (provide 'init-rss) 71 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 72 | ;;; init-rss.el ends here 73 | -------------------------------------------------------------------------------- /config-mirror/emacs-config-l4.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Emacs配置文件 2 | #+AUTHOR: Randolph 3 | #+DATE: 2022/12/22 14:23:50 4 | 5 | #+STARTUP: overview 6 | 7 | * early-init.el 8 | :PROPERTIES: 9 | :HEADER-ARGS: :tangle early-init.el 10 | :END: 11 | 12 | 在Emacs刚启动,还未加载主要配置文件时的配置文件。 13 | 14 | #+BEGIN_SRC emacs-lisp 15 | ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*- 16 | ;;; Commentary: 17 | 18 | ;;; Code: 19 | 20 | ;; 设置垃圾回收参数 21 | (setq gc-cons-threshold most-positive-fixnum) 22 | (setq gc-cons-percentage 0.6) 23 | 24 | ;; 启动早期不加载`package.el'包管理器 25 | (setq package-enable-at-startup nil) 26 | ;; 不从包缓存中加载 27 | (setq package-quickstart nil) 28 | 29 | ;; 禁止展示菜单栏、工具栏和纵向滚动条 30 | (push '(menu-bar-lines . 0) default-frame-alist) 31 | (push '(tool-bar-lines . 0) default-frame-alist) 32 | (push '(vertical-scroll-bars) default-frame-alist) 33 | 34 | ;; 禁止自动缩放窗口先 35 | (setq frame-inhibit-implied-resize t) 36 | 37 | ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框 38 | (menu-bar-mode -1) 39 | (tool-bar-mode -1) 40 | (scroll-bar-mode -1) 41 | (setq inhibit-splash-screen t) 42 | (setq use-file-dialog nil) 43 | 44 | ;; 在这个阶段不编译 45 | (setq comp-deferred-compilation nil) 46 | 47 | (provide 'early-init) 48 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 49 | ;;; early-init.el ends here 50 | #+END_SRC 51 | 52 | * init.el 53 | :PROPERTIES: 54 | :HEADER-ARGS: :tangle init.el 55 | :END: 56 | 57 | =init.el= 是Emacs的主要配置文件。 58 | 59 | ** init.el 文件头 60 | #+BEGIN_SRC emacs-lisp 61 | ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*- 62 | ;;; Commentary: 63 | 64 | ;;; Code: 65 | 66 | #+END_SRC 67 | 68 | ** package包管理配置 69 | #+begin_src emacs-lisp 70 | (require 'package) 71 | (setq package-archives 72 | '(("melpa" . "https://melpa.org/packages/") 73 | ("gnu" . "https://elpa.gnu.org/packages/") 74 | ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) 75 | 76 | (package-initialize) 77 | #+end_src 78 | 79 | ** 安装use-package插件 80 | [[https://github.com/jwiegley/use-package][use-package]] 是一个让Emacs配置更加结构化更加清晰的一个宏插件。 81 | 82 | #+begin_src emacs-lisp 83 | ;; 安装 `use-package' 84 | (unless (package-installed-p 'use-package) 85 | (package-refresh-contents) 86 | (package-install 'use-package)) 87 | 88 | ;; 配置 `use-package' 89 | (eval-and-compile 90 | (setq use-package-always-ensure nil) 91 | (setq use-package-always-defer nil) 92 | (setq use-package-expand-minimally nil) 93 | (setq use-package-enable-imenu-support t) 94 | (if (daemonp) 95 | (setq use-package-always-demand t))) 96 | 97 | (eval-when-compile 98 | (require 'use-package)) 99 | 100 | ;; 安装 `use-package' 的集成模块 101 | (use-package use-package-ensure-system-package 102 | :ensure t) 103 | (use-package diminish 104 | :ensure t) 105 | (use-package bind-key 106 | :ensure t) 107 | #+end_src 108 | 109 | ** quelpa包管理器 110 | [[https://github.com/quelpa/quelpa][quelpa]] 是配合 =package.el= 使用的,基于git的一个包管理器。 111 | #+BEGIN_SRC emacs-lisp 112 | ;; 安装 `quelpa' 113 | (use-package quelpa 114 | :ensure t 115 | :commands quelpa 116 | :config 117 | :custom 118 | (quelpa-git-clone-depth 1) 119 | (quelpa-update-melpa-p nil) 120 | (quelpa-self-upgrade-p nil) 121 | (quelpa-checkout-melpa-p nil)) 122 | 123 | ;; `quelpa' 与 `use-package' 集成 124 | (use-package quelpa-use-package 125 | :ensure t) 126 | #+END_SRC 127 | 128 | ** init.el 文件尾 129 | #+BEGIN_SRC emacs-lisp 130 | 131 | (provide 'init) 132 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 133 | ;;; init.el ends here 134 | #+END_SRC 135 | 136 | -------------------------------------------------------------------------------- /init.el: -------------------------------------------------------------------------------- 1 | ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (require 'package) 7 | (setq package-archives 8 | '(("melpa" . "https://melpa.org/packages/") 9 | ("gnu" . "https://elpa.gnu.org/packages/") 10 | ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) 11 | 12 | (package-initialize) 13 | 14 | ;; 安装 `use-package' 15 | (unless (package-installed-p 'use-package) 16 | (package-refresh-contents) 17 | (package-install 'use-package)) 18 | 19 | ;; 配置 `use-package' 20 | (eval-and-compile 21 | (setq use-package-always-ensure nil) 22 | (setq use-package-always-defer nil) 23 | (setq use-package-expand-minimally nil) 24 | (setq use-package-enable-imenu-support t) 25 | (if (daemonp) 26 | (setq use-package-always-demand t))) 27 | 28 | (eval-when-compile 29 | (require 'use-package)) 30 | 31 | ;; 安装 `use-package' 的集成模块 32 | (use-package use-package-ensure-system-package 33 | :ensure t) 34 | (use-package diminish 35 | :ensure t) 36 | (use-package bind-key 37 | :ensure t) 38 | 39 | ;; 安装 `quelpa' 40 | (use-package quelpa 41 | :ensure t 42 | :commands quelpa 43 | :config 44 | :custom 45 | (quelpa-git-clone-depth 1) 46 | (quelpa-update-melpa-p nil) 47 | (quelpa-self-upgrade-p nil) 48 | (quelpa-checkout-melpa-p nil)) 49 | 50 | ;; `quelpa' 与 `use-package' 集成 51 | (use-package quelpa-use-package 52 | :ensure t) 53 | 54 | ;; 将lisp目录放到加载路径的前面以加快启动速度 55 | (let ((dir (locate-user-emacs-file "lisp"))) 56 | (add-to-list 'load-path (file-name-as-directory dir))) 57 | 58 | ;; 加载各模块化配置 59 | ;; 不要在`*message*'缓冲区显示加载模块化配置的信息 60 | (with-temp-message "" 61 | (require 'init-base) ; 一些基本配置 62 | (require 'init-ui) ; UI交互 63 | (require 'init-edit) ; 编辑行为 64 | (require 'init-org) ; org相关设置 65 | (require 'init-completion) ; 补全系统 66 | (require 'init-dired) ; 文件管理 67 | (require 'init-tools) ; 相关工具 68 | (require 'init-dev) ; 开发相关配置 69 | (require 'init-mail) ; 邮件配置 70 | (require 'init-rss) ; RSS配置 71 | (require 'init-shell) ; Shell配置 72 | (require 'init-browser) ; 浏览器配置 73 | ) 74 | 75 | (provide 'init) 76 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 77 | ;;; init.el ends here 78 | (custom-set-variables 79 | ;; custom-set-variables was added by Custom. 80 | ;; If you edit it by hand, you could mess it up, so be careful. 81 | ;; Your init file should contain only one such instance. 82 | ;; If there is more than one, they won't work right. 83 | '(package-selected-packages 84 | '(all-the-icons-completion all-the-icons-dired cal-china-x calibredb cape 85 | capf-autosuggest consult-notes corfu crux denote 86 | diff-hl diminish diredfl dirvish doom-modeline 87 | ef-themes elfeed-goodies embark-consult 88 | eshell-git-prompt eshell-syntax-highlighting 89 | eshell-up fanyi fontaine gnuplot helpful htmlize 90 | keycast magit-delta marginalia minions mpvi 91 | multiple-cursors no-littering nov ol-notmuch 92 | orderless org-ai org-appear org-auto-tangle 93 | org-contrib org-modern org-super-links ox-gfm 94 | ox-hugo ox-odt ox-pandoc ox-reveal pass pinyinlib 95 | plantuml-mode popper py-autopep8 96 | quelpa-use-package rainbow-delimiters sdcv shackle 97 | super-save toc-org undo-tree 98 | use-package-ensure-system-package vertico 99 | which-key yasnippet))) 100 | (custom-set-faces 101 | ;; custom-set-faces was added by Custom. 102 | ;; If you edit it by hand, you could mess it up, so be careful. 103 | ;; Your init file should contain only one such instance. 104 | ;; If there is more than one, they won't work right. 105 | ) 106 | -------------------------------------------------------------------------------- /lisp/init-dev.el: -------------------------------------------------------------------------------- 1 | ;;; init-dev.el --- Development settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package vc 7 | :ensure nil 8 | :custom 9 | ;; 打开链接文件时,不进行追问 10 | (vc-follow-symlinks t) 11 | (vc-allow-async-revert t) 12 | (vc-handled-backends '(Git))) 13 | 14 | (use-package magit 15 | :ensure t 16 | :hook (git-commit-mode . flyspell-mode) 17 | :bind (("C-x g" . magit-status) 18 | ("C-x M-g" . magit-dispatch) 19 | ("C-c M-g" . magit-file-dispatch)) 20 | :custom 21 | (magit-diff-refine-hunk t) 22 | (magit-ediff-dwim-show-on-hunks t)) 23 | 24 | (use-package diff-hl 25 | :ensure t 26 | :hook ((dired-mode . diff-hl-dired-mode-unless-remote) 27 | (magit-pre-refresh . diff-hl-magit-pre-refresh) 28 | (magit-post-refresh . diff-hl-magit-post-refresh)) 29 | :init 30 | (global-diff-hl-mode t) 31 | :config 32 | ;; When Emacs runs in terminal, show the indicators in margin instead. 33 | (unless (display-graphic-p) 34 | (diff-hl-margin-mode))) 35 | 36 | (use-package magit-delta 37 | :ensure t 38 | :hook (magit-mode . magit-delta-mode) 39 | :config 40 | (setq magit-delta-hide-plus-minus-markers nil) 41 | ) 42 | 43 | (use-package paren 44 | :ensure nil 45 | :hook (after-init . show-paren-mode) 46 | :custom 47 | (show-paren-when-point-inside-paren t) 48 | (show-paren-when-point-in-periphery t)) 49 | 50 | (use-package rainbow-delimiters 51 | :ensure t 52 | :hook (prog-mode . rainbow-delimiters-mode)) 53 | 54 | (use-package elisp-mode 55 | :ensure nil 56 | :after org 57 | :bind (:map emacs-lisp-mode-map 58 | ("C-c C-b" . eval-buffer) 59 | ("C-c C-c" . eval-to-comment) 60 | :map lisp-interaction-mode-map 61 | ("C-c C-c" . eval-to-comment) 62 | :map org-mode-map 63 | ("C-c C-;" . eval-to-comment) 64 | ) 65 | :init 66 | ;; for emacs-lisp org babel 67 | (add-to-list 'org-babel-default-header-args:emacs-lisp 68 | '(:results . "value pp")) 69 | :config 70 | (defconst eval-as-comment-prefix " ⇒ ") 71 | (defun eval-to-comment (&optional arg) 72 | (interactive "P") 73 | ;; (if (not (looking-back ";\\s*")) 74 | ;; (call-interactively 'comment-dwim)) 75 | (call-interactively 'comment-dwim) 76 | (progn 77 | (search-backward ";") 78 | (forward-char 1)) 79 | (delete-region (point) (line-end-position)) 80 | (save-excursion 81 | (let ((current-prefix-arg '(4))) 82 | (call-interactively 'eval-last-sexp))) 83 | (insert eval-as-comment-prefix) 84 | (end-of-line 1)) 85 | ) 86 | 87 | (use-package python 88 | :ensure nil 89 | :mode ("\\.py\\'" . python-mode) 90 | :init 91 | (add-list-to-list 'org-babel-default-header-args:python '((:results . "output pp") 92 | (:noweb . "yes") 93 | (:session . "py") 94 | (:async . "yes") 95 | (:exports . "both") 96 | )) 97 | :config 98 | (setq python-indent-offset 4) 99 | ;; Disable readline based native completion 100 | (setq python-shell-completion-native-enable nil) 101 | (setq python-indent-guess-indent-offset-verbose nil) 102 | (setq python-shell-interpreter "python3" 103 | python-shell-prompt-detect-failure-warning nil) 104 | ;; disable native completion 105 | (add-to-list 'python-shell-completion-native-disabled-interpreters "python3") 106 | ;; Env vars 107 | (with-eval-after-load 'exec-path-from-shell 108 | (exec-path-from-shell-copy-env "PYTHONPATH")) 109 | ) 110 | 111 | ;; need to pip install autopep8 first 112 | (use-package py-autopep8 113 | :ensure t 114 | :hook (python-mode . py-autopep8-mode) 115 | ) 116 | 117 | (use-package sh-script 118 | :ensure nil 119 | :mode (("\\.sh\\'" . sh-mode) 120 | ("zshrc" . sh-mode) 121 | ("zshenv" . sh-mode) 122 | ("/PKGBUILD\\'" . sh-mode)) 123 | :hook (sh-mode . sh-mode-setup) 124 | :bind (:map sh-mode-map 125 | ("C-c C-e" . sh-execute-region)) 126 | :init 127 | ;; for org babel 128 | (add-list-to-list 'org-babel-default-header-args:shell 129 | '((:results . "output") 130 | (:tangle . "no"))) 131 | :config 132 | (defun sh-mode-setup () 133 | (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p nil t)) 134 | :custom 135 | (sh-basic-offset 2) 136 | (sh-indentation 2)) 137 | 138 | (provide 'init-dev) 139 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 140 | ;;; init-dev.el ends here 141 | -------------------------------------------------------------------------------- /lisp/init-shell.el: -------------------------------------------------------------------------------- 1 | ;;; init-shell.el --- (E)shell settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package eshell 7 | :ensure nil 8 | :functions eshell/alias 9 | :hook ((eshell-mode . (lambda () 10 | (term-mode-common-init) 11 | ;; Remove cmd args word by word 12 | (modify-syntax-entry ?- "w") 13 | (visual-line-mode 1) 14 | (setenv "PAGER" "cat"))) 15 | ) 16 | :config 17 | (defun term-mode-common-init () 18 | "The common initialization for term." 19 | (setq-local scroll-margin 0) 20 | (setq-local truncate-lines t) 21 | ) 22 | 23 | ;; 在Emacs里输入vi,直接在buffer里打开文件 24 | (defalias 'eshell/vi 'find-file) 25 | (defalias 'eshell/vim 'find-file) 26 | 27 | ;; 语法高亮显示 28 | (defun eshell/bat (file) 29 | "cat FILE with syntax highlight." 30 | (with-temp-buffer 31 | (insert-file-contents file) 32 | (let ((buffer-file-name file)) 33 | (delay-mode-hooks 34 | (set-auto-mode) 35 | (font-lock-ensure))) 36 | (buffer-string))) 37 | (defalias 'eshell/cat 'eshell/bat) 38 | 39 | ;; 交互式进入目录 40 | (defun eshell/z () 41 | "cd to directory with completion." 42 | (let ((dir (completing-read "Directory: " (ring-elements eshell-last-dir-ring) nil t))) 43 | (eshell/cd dir))) 44 | 45 | ;; 查找文件 46 | (defun eshell/f (filename &optional dir) 47 | "Search for files matching FILENAME in either DIR or the 48 | current directory." 49 | (let ((cmd (concat 50 | ;; using find 51 | (executable-find "find") 52 | " " (or dir ".") 53 | " -not -path '*/.git*'" ; ignore .git directory 54 | " -and -not -path 'build'" ; ignore cmake build directory 55 | " -and -not -path '*/eln-cache*'" ; ignore eln cache 56 | " -and -type f -and -iname " 57 | "'*" filename "*'"))) 58 | (eshell-command-result cmd))) 59 | 60 | :custom 61 | (eshell-banner-message 62 | '(format "%s %s\n" 63 | (propertize (format " %s " (string-trim (buffer-name))) 64 | 'face 'mode-line-highlight) 65 | (propertize (current-time-string) 66 | 'face 'font-lock-keyword-face))) 67 | (eshell-scroll-to-bottom-on-input 'all) 68 | (eshell-scroll-to-bottom-on-output 'all) 69 | (eshell-kill-on-exit t) 70 | (eshell-kill-processes-on-exit t) 71 | ;; Don't record command in history if starts with whitespace 72 | (eshell-input-filter 'eshell-input-filter-initial-space) 73 | (eshell-error-if-no-glob t) 74 | (eshell-glob-case-insensitive t) 75 | ;; set scripts 76 | (eshell-rc-script (locate-user-emacs-file "etc/eshell/profile")) 77 | (eshell-login-script (locate-user-emacs-file "etc/eshell/login")) 78 | ) 79 | 80 | (use-package em-rebind 81 | :ensure nil 82 | :commands eshell-delchar-or-maybe-eof) 83 | 84 | (use-package esh-mode 85 | :ensure nil 86 | :bind (:map eshell-mode-map 87 | ("C-d" . eshell-delchar-or-maybe-eof) 88 | ("C-r" . consult-history) 89 | ("C-l" . eshell/clear)) 90 | ) 91 | 92 | (use-package em-hist 93 | :ensure nil 94 | :defer t 95 | :custom 96 | (eshell-history-size 1024) 97 | (eshell-hist-ignoredups t) 98 | (eshell-save-history-on-exit t)) 99 | 100 | ;; following commands will run on term instead 101 | (use-package em-term 102 | :ensure nil 103 | :defer t 104 | :custom 105 | (eshell-visual-commands '("top" "htop" "less" "more")) 106 | (eshell-visual-subcommands '(("git" "help" "lg" "log" "diff" "show"))) 107 | (eshell-visual-options '(("git" "--help" "--paginate"))) 108 | (eshell-destroy-buffer-when-process-dies t)) 109 | 110 | (use-package eshell-git-prompt 111 | :ensure t 112 | :after esh-mode 113 | :custom-face 114 | (eshell-git-prompt-multiline2-dir-face ((t (:foreground "#c09035" :bold t)))) 115 | :config 116 | (eshell-git-prompt-use-theme 'multiline2) 117 | ) 118 | 119 | (use-package eshell-syntax-highlighting 120 | :after esh-mode 121 | :ensure t 122 | :hook (eshell-mode . eshell-syntax-highlighting-global-mode) 123 | :custom-face 124 | (eshell-syntax-highlighting-shell-command-face ((t (:foreground "#7cc77f" :bold t)))) 125 | ) 126 | 127 | (use-package capf-autosuggest 128 | :ensure t 129 | :hook ((eshell-mode comint-mode) . capf-autosuggest-mode) 130 | :custom-face 131 | (capf-autosuggest-face ((t (:foreground "#dae7ff")))) 132 | ) 133 | 134 | (use-package eshell-up 135 | :ensure t 136 | :commands (eshell-up eshell-up-peek) 137 | :config 138 | ;; to print the matching parent directory before changing to it 139 | (setq eshell-up-print-parent-dir t) 140 | ) 141 | 142 | (provide 'init-shell) 143 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 144 | ;;; init-shell.el ends here 145 | -------------------------------------------------------------------------------- /lisp/init-base.el: -------------------------------------------------------------------------------- 1 | ;;; init-base.el --- Basical settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package no-littering 7 | :ensure t) 8 | 9 | (use-package savehist 10 | :ensure nil 11 | :hook (after-init . savehist-mode) 12 | :config 13 | ;; Allow commands in minibuffers, will affect `dired-do-dired-do-find-regexp-and-replace' command: 14 | (setq enable-recursive-minibuffers t) 15 | (setq history-length 1000) 16 | (setq savehist-additional-variables '(mark-ring 17 | global-mark-ring 18 | search-ring 19 | regexp-search-ring 20 | extended-command-history)) 21 | (setq savehist-autosave-interval 300)) 22 | 23 | (use-package saveplace 24 | :ensure nil 25 | :hook (after-init . save-place-mode)) 26 | 27 | (use-package recentf 28 | :ensure nil 29 | :defines no-littering-etc-directory no-littering-var-directory 30 | :hook (after-init . recentf-mode) 31 | :custom 32 | (recentf-max-saved-items 300) 33 | (recentf-auto-cleanup 'never) 34 | ;; `recentf-add-file' will apply handlers first, then call `string-prefix-p' 35 | ;; to check if it can be pushed to recentf list. 36 | (recentf-filename-handlers '(abbreviate-file-name)) 37 | (recentf-exclude `(,@(cl-loop for f in `(,package-user-dir 38 | ,no-littering-var-directory 39 | ,no-littering-etc-directory) 40 | collect (abbreviate-file-name f)) 41 | ;; Folders on MacOS start 42 | "^/private/tmp/" 43 | "^/var/folders/" 44 | ;; Folders on MacOS end 45 | ".cache" 46 | ".cask" 47 | ".elfeed" 48 | "elfeed" 49 | "bookmarks" 50 | "cache" 51 | "ido.*" 52 | "persp-confs" 53 | "recentf" 54 | "undo-tree-hist" 55 | "url" 56 | "^/tmp/" 57 | "/ssh\\(x\\)?:" 58 | "/su\\(do\\)?:" 59 | "^/usr/include/" 60 | "/TAGS\\'" 61 | "COMMIT_EDITMSG\\'"))) 62 | 63 | (use-package undo-tree 64 | :ensure t 65 | :hook (after-init . global-undo-tree-mode) 66 | :config 67 | ;; don't save undo history to local files 68 | (setq undo-tree-auto-save-history nil) 69 | ) 70 | 71 | (use-package super-save 72 | :ensure t 73 | :hook (after-init . super-save-mode) 74 | :config 75 | ;; Emacs空闲是否自动保存,这里不设置 76 | (setq super-save-auto-save-when-idle nil) 77 | ;; 切换窗口自动保存 78 | (add-to-list 'super-save-triggers 'other-window) 79 | ;; 查找文件时自动保存 80 | (add-to-list 'super-save-hook-triggers 'find-file-hook) 81 | ;; 远程文件编辑不自动保存 82 | (setq super-save-remote-files nil) 83 | ;; 特定后缀名的文件不自动保存 84 | (setq super-save-exclude '(".gpg")) 85 | ;; 自动保存时,保存所有缓冲区 86 | (defun super-save/save-all-buffers () 87 | (save-excursion 88 | (dolist (buf (buffer-list)) 89 | (set-buffer buf) 90 | (when (and buffer-file-name 91 | (buffer-modified-p (current-buffer)) 92 | (file-writable-p buffer-file-name) 93 | (if (file-remote-p buffer-file-name) super-save-remote-files t)) 94 | (save-buffer))))) 95 | (advice-add 'super-save-command :override 'super-save/save-all-buffers) 96 | ) 97 | 98 | (use-package crux 99 | :ensure t 100 | :bind (("C-a" . crux-move-beginning-of-line) 101 | ("C-x 4 t" . crux-transpose-windows) 102 | ("C-x K" . crux-kill-other-buffers) 103 | ("C-k" . crux-smart-kill-line) 104 | ("C-c r" . crux-rename-file-and-buffer) 105 | ("C-x DEL" . crux-kill-line-backwards)) 106 | :config 107 | (crux-with-region-or-buffer indent-region) 108 | (crux-with-region-or-buffer untabify) 109 | (crux-with-region-or-point-to-eol kill-ring-save) 110 | (defalias 'rename-file-and-buffer #'crux-rename-file-and-buffer)) 111 | 112 | ;; 将列表加入到列表 113 | (defun add-list-to-list (dst src) 114 | "Similar to `add-to-list', but accepts a list as 2nd argument" 115 | (set dst 116 | (append (eval dst) src))) 117 | 118 | ;; 打开当前配置Org文件 119 | (defun open-emacsconfig () 120 | "Opens emacs config org file." 121 | (interactive) 122 | (find-file (locate-user-emacs-file "emacs-config.org"))) 123 | 124 | ;; 从剪贴板获取内容 125 | (defun clipboard/get () 126 | "return the content of clipboard as string" 127 | (interactive) 128 | (with-temp-buffer 129 | (clipboard-yank) 130 | (buffer-substring-no-properties (point-min) (point-max)))) 131 | 132 | (defalias 'e #'eshell) 133 | (defalias 's #'scratch) 134 | (defalias 'conf #'open-emacsconfig) 135 | 136 | (provide 'init-base) 137 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 138 | ;;; init-base.el ends here 139 | -------------------------------------------------------------------------------- /lisp/init-tools.el: -------------------------------------------------------------------------------- 1 | ;;; init-tools.el --- Tools settings -*- lexical-binding: t -*- 2 | ;;; Commentary: Useful tools to make Emacs efficient! 3 | 4 | ;;; Code: 5 | 6 | (use-package helpful 7 | :ensure t 8 | :commands (helpful-callable helpful-variable helpful-command helpful-key helpful-mode) 9 | :bind (([remap describe-command] . helpful-command) 10 | ("C-h f" . helpful-callable) 11 | ("C-h v" . helpful-variable) 12 | ("C-h s" . helpful-symbol) 13 | ("C-h S" . describe-syntax) 14 | ("C-h m" . describe-mode) 15 | ("C-h F" . describe-face) 16 | ([remap describe-key] . helpful-key)) 17 | ) 18 | 19 | (use-package which-key 20 | :ensure t 21 | :hook (after-init . which-key-mode) 22 | :config 23 | (which-key-add-key-based-replacements 24 | "C-c !" "flycheck" 25 | "C-c @" "hideshow" 26 | "C-c i" "ispell" 27 | "C-c t" "hl-todo" 28 | "C-x a" "abbrev" 29 | "C-x n" "narrow" 30 | "C-x t" "tab") 31 | :custom 32 | (which-key-idle-delay 0.7) 33 | (which-key-add-column-padding 1)) 34 | 35 | ;; 这个插件依赖于 `posframe' 这个插件 36 | (use-package posframe 37 | :ensure t 38 | ) 39 | 40 | (use-package sdcv 41 | :quelpa (sdcv :fetcher github :repo "manateelazycat/sdcv") 42 | :commands (sdcv-search-pointer+) 43 | :bind ("C-," . sdcv-search-pointer+) 44 | :config 45 | (setq sdcv-say-word-p t) 46 | (setq sdcv-dictionary-data-dir (expand-file-name "~/Backup/stardict/")) 47 | (setq sdcv-dictionary-simple-list 48 | '("懒虫简明英汉词典" 49 | "懒虫简明汉英词典")) 50 | (setq sdcv-dictionary-complete-list 51 | '("朗道英汉字典5.0" 52 | "牛津英汉双解美化版" 53 | "21世纪双语科技词典" 54 | "quick_eng-zh_CN" 55 | "新世纪英汉科技大词典")) 56 | (setq sdcv-tooltip-timeout 10) 57 | (setq sdcv-fail-notify-string "没找到释义") 58 | (setq sdcv-tooltip-border-width 2) 59 | ) 60 | 61 | (use-package fanyi 62 | :ensure t 63 | :bind-keymap ("\e\e =" . fanyi-map) 64 | :bind (:map fanyi-map 65 | ("w" . fanyi-dwim2) 66 | ("i" . fanyi-dwim)) 67 | :init 68 | ;; to support `org-store-link' and `org-insert-link' 69 | (require 'ol-fanyi) 70 | ;; 如果当前指针下有单词,选择当前单词,否则选择剪贴板 71 | (with-eval-after-load 'org-capture 72 | (add-to-list 'org-capture-templates 73 | '("w" "New word" entry (file+olp+datetree "20221001T221032--vocabulary__studying.org" "New") 74 | "* %^{Input the new word:|%(cond ((with-current-buffer (org-capture-get :original-buffer) (thing-at-point 'word 'no-properties))) ((clipboard/get)))}\n\n[[fanyi:%\\1][%\\1]]\n\n[[http://dict.cn/%\\1][海词:%\\1]]%?" 75 | :tree-type day 76 | :empty-lines 1 77 | :jump-to-captured t))) 78 | :config 79 | (defvar fanyi-map nil "keymap for `fanyi") 80 | (setq fanyi-map (make-sparse-keymap)) 81 | (setq fanyi-sound-player "mpv") 82 | :custom 83 | (fanyi-providers '(;; 海词 84 | fanyi-haici-provider 85 | ;; 有道同义词词典 86 | fanyi-youdao-thesaurus-provider 87 | ;; ;; Etymonline 88 | ;; fanyi-etymon-provider 89 | ;; Longman 90 | fanyi-longman-provider 91 | ;; ;; LibreTranslate 92 | ;; fanyi-libre-provider 93 | ))) 94 | 95 | (use-package org-ai 96 | :ensure t 97 | :bind ( 98 | ("C-c q" . org-ai-prompt) 99 | ("C-c x" . org-ai-on-region) 100 | ) 101 | :hook (org-mode . org-ai-mode) 102 | :config 103 | ;; (setq org-ai-openai-api-token "Your Key") ; 以明文的方式存储key,或者放入到 ~/.authinfo.gpg 文件里 104 | (setq org-ai-default-max-tokens 480) 105 | (setq org-ai-default-chat-system-prompt "你是一个Emacs助手,请以Org-mode的格式来回复我") 106 | ) 107 | 108 | (use-package pass 109 | :ensure t 110 | :commands (pass) 111 | ) 112 | 113 | (use-package nov 114 | :ensure t 115 | :mode ("\\.epub\\'" . nov-mode) 116 | :bind (:map nov-mode-map 117 | ("j" . scroll-up-line) 118 | ("k" . scroll-down-line)) 119 | ) 120 | 121 | (use-package calibredb 122 | :ensure t 123 | :commands calibredb 124 | :bind ("\e\e b" . calibredb) 125 | :config 126 | (setq calibredb-root-dir "~/Calibre") 127 | (setq calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir)) 128 | (setq calibredb-library-alist '(("~/Books/books") 129 | )) 130 | ) 131 | 132 | (use-package mpvi 133 | :ensure t 134 | :commands (mpvi-open mpvi-seek mpvi-insert) 135 | :bind (("C-c v o" . mpvi-open) 136 | ("C-c v s" . mpvi-seek) 137 | :map mpvi-seek-map 138 | ("C-i" . my/mpvi-seeking-capture-as-screenshot)) 139 | :config 140 | ;; 如果不设置这个值,会提示ipc的错误需要你update mpv 141 | (setq emms-player-mpv-ipc-method 'ipc-server) 142 | 143 | ;; 通过这个函数来对视频截图,我不喜欢使用attach的方式 144 | (defun my/mpvi-seeking-capture-as-screenshot () 145 | "Capture current video screenshot and insert as a link." 146 | (interactive) 147 | (with-current-buffer (window-buffer (minibuffer-selected-window)) 148 | (unless (derived-mode-p 'org-mode) 149 | (user-error "This is not org-mode, should not insert org link"))) 150 | (with-current-buffer (window-buffer (minibuffer-selected-window)) 151 | (when (mpvi-parse-link-at-point) 152 | (end-of-line) (insert "\n")) 153 | (let ((foldername (concat (file-name-base (buffer-file-name)) ".assets/")) 154 | (imgName (concat "img_" (format-time-string "%Y%m%d_%H%M%S") ".png"))) 155 | (if (not (file-exists-p foldername)) 156 | (mkdir foldername)) 157 | (let ((imgPath (concat foldername imgName)) 158 | (relativeFilename (concat (file-name-base (buffer-name)) ".assets/" imgName))) 159 | (mpvi-screenshot-current-playing imgPath "video") 160 | (insert (concat "#+DOWNLOADED: screenshot @ " 161 | (format-time-string "%Y-%m-%d %a %H:%M:%S" (current-time)) 162 | "\n#+CAPTION: \n#+ATTR_ORG: :width 600" 163 | "\n#+ATTR_LATEX: :width 1.0\\linewidth :float nil\n" 164 | "#+ATTR_HTML: :width 600" 165 | " :class zoomImage\n[[file:" relativeFilename "]]")) 166 | )) 167 | (org-redisplay-inline-images)) 168 | (throw 'mpvi-seek "Capture and insert done.")) 169 | ) 170 | 171 | (provide 'init-tools) 172 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 173 | ;;; init-tools.el ends here 174 | -------------------------------------------------------------------------------- /lisp/init-edit.el: -------------------------------------------------------------------------------- 1 | ;;; init-edit.el --- Editing settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (setq make-backup-files nil) ; 不自动备份 7 | (setq auto-save-default nil) ; 不使用Emacs自带的自动保存 8 | 9 | ;; 解除不常用的快捷键定义 10 | (global-set-key (kbd "C-z") nil) 11 | (global-set-key (kbd "s-q") nil) 12 | (global-set-key (kbd "M-z") nil) 13 | (global-set-key (kbd "M-m") nil) 14 | (global-set-key (kbd "C-x C-z") nil) 15 | (global-set-key [mouse-2] nil) 16 | 17 | ;; Directly modify when selecting text 18 | (use-package delsel 19 | :ensure nil 20 | :hook (after-init . delete-selection-mode)) 21 | 22 | (use-package autorevert 23 | :ensure nil 24 | :hook (after-init . global-auto-revert-mode) 25 | :bind ("s-u" . revert-buffer) 26 | :custom 27 | (auto-revert-interval 10) 28 | (auto-revert-avoid-polling t) 29 | (auto-revert-verbose nil) 30 | (auto-revert-remote-files t) 31 | (auto-revert-check-vc-info t) 32 | (global-auto-revert-non-file-buffers t)) 33 | 34 | (use-package avy 35 | :ensure t 36 | :bind (("C-." . my/avy-goto-char-timer) 37 | ("C-。" . my/avy-goto-char-timer) 38 | :map isearch-mode-map 39 | ("C-." . avy-isearch)) 40 | :config 41 | ;; Make `avy-goto-char-timer' support pinyin, refer to: 42 | ;; https://emacs-china.org/t/avy-avy-goto-char-timer/20900/2 43 | (defun my/avy-goto-char-timer (&optional arg) 44 | "Make avy-goto-char-timer support pinyin" 45 | (interactive "P") 46 | (let ((avy-all-windows (if arg 47 | (not avy-all-windows) 48 | avy-all-windows))) 49 | (avy-with avy-goto-char-timer 50 | (setq avy--old-cands (avy--read-candidates 51 | 'pinyinlib-build-regexp-string)) 52 | (avy-process avy--old-cands)))) 53 | 54 | (defun avy-action-kill-whole-line (pt) 55 | "avy action: kill the whole line where avy selection is" 56 | (save-excursion 57 | (goto-char pt) 58 | (kill-whole-line)) 59 | (select-window 60 | (cdr 61 | (ring-ref avy-ring 0))) 62 | t) 63 | 64 | (defun avy-action-copy-whole-line (pt) 65 | "avy action: copy the whole line where avy selection is" 66 | (save-excursion 67 | (goto-char pt) 68 | (cl-destructuring-bind (start . end) 69 | (bounds-of-thing-at-point 'line) 70 | (copy-region-as-kill start end))) 71 | (select-window 72 | (cdr 73 | (ring-ref avy-ring 0))) 74 | t) 75 | 76 | (defun avy-action-yank-whole-line (pt) 77 | "avy action: copy the line where avy selection is and paste to current point" 78 | (avy-action-copy-whole-line pt) 79 | (save-excursion (yank)) 80 | t) 81 | 82 | (defun avy-action-teleport-whole-line (pt) 83 | "avy action: kill the line where avy selection is and paste to current point" 84 | (avy-action-kill-whole-line pt) 85 | (save-excursion (yank)) t) 86 | 87 | (defun avy-action-helpful (pt) 88 | "avy action: get helpful information at point" 89 | (save-excursion 90 | (goto-char pt) 91 | (helpful-at-point)) 92 | ;; (select-window 93 | ;; (cdr (ring-ref avy-ring 0))) 94 | t) 95 | 96 | (defun avy-action-mark-to-char (pt) 97 | "avy action: mark from current point to avy selection" 98 | (activate-mark) 99 | (goto-char pt)) 100 | 101 | (defun avy-action-flyspell (pt) 102 | "avy action: flyspell the word where avy selection is" 103 | (save-excursion 104 | (goto-char pt) 105 | (when (require 'flyspell nil t) 106 | (flyspell-correct-wrapper)))) 107 | 108 | (defun avy-action-define (pt) 109 | "avy action: define the word in dictionary where avy selection is" 110 | (save-excursion 111 | (goto-char pt) 112 | (fanyi-dwim2))) 113 | 114 | (defun avy-action-embark (pt) 115 | "avy action: embark where avy selection is" 116 | (unwind-protect 117 | (save-excursion 118 | (goto-char pt) 119 | (embark-act)) 120 | (select-window 121 | (cdr (ring-ref avy-ring 0)))) 122 | t) 123 | 124 | (defun avy-action-google (pt) 125 | "avy action: google the avy selection when it is a word or browse it when it is a link" 126 | (save-excursion 127 | (goto-char pt) 128 | (my/search-or-browse))) 129 | 130 | (setf (alist-get ?k avy-dispatch-alist) 'avy-action-kill-stay 131 | (alist-get ?K avy-dispatch-alist) 'avy-action-kill-whole-line 132 | (alist-get ?w avy-dispatch-alist) 'avy-action-copy 133 | (alist-get ?W avy-dispatch-alist) 'avy-action-copy-whole-line 134 | (alist-get ?y avy-dispatch-alist) 'avy-action-yank 135 | (alist-get ?Y avy-dispatch-alist) 'avy-action-yank-whole-line 136 | (alist-get ?t avy-dispatch-alist) 'avy-action-teleport 137 | (alist-get ?T avy-dispatch-alist) 'avy-action-teleport-whole-line 138 | (alist-get ?H avy-dispatch-alist) 'avy-action-helpful 139 | (alist-get ? avy-dispatch-alist) 'avy-action-mark-to-char 140 | (alist-get ?\; avy-dispatch-alist) 'avy-action-flyspell 141 | (alist-get ?= avy-dispatch-alist) 'avy-action-define 142 | (alist-get ?o avy-dispatch-alist) 'avy-action-embark 143 | (alist-get ?G avy-dispatch-alist) 'avy-action-google 144 | ) 145 | 146 | :custom 147 | ;; (avy-case-fold-search t) ; default is t 148 | (avy-timeout-seconds 1.0) 149 | (avy-all-windows t) 150 | (avy-background t) 151 | (avy-keys '(?a ?s ?d ?f ?g ?h ?j ?l ?q ?e ?r ?u ?i ?p ?n)) 152 | ) 153 | 154 | (use-package multiple-cursors 155 | :ensure t 156 | :bind-keymap ("C-c o" . multiple-cursors-map) 157 | :bind (("C-`" . mc/mark-next-like-this) 158 | ("C-\\" . mc/unmark-next-like-this) 159 | :map multiple-cursors-map 160 | ("SPC" . mc/edit-lines) 161 | (">" . mc/mark-next-like-this) 162 | ("<" . mc/mark-previous-like-this) 163 | ("a" . mc/mark-all-like-this) 164 | ("n" . mc/mark-next-like-this-word) 165 | ("p" . mc/mark-previous-like-this-word) 166 | ("r" . set-rectangular-region-anchor) 167 | ) 168 | :config 169 | (defvar multiple-cursors-map nil "keymap for `multiple-cursors") 170 | (setq multiple-cursors-map (make-sparse-keymap)) 171 | (setq mc/list-file (concat user-emacs-directory "/etc/mc-lists.el")) 172 | (setq mc/always-run-for-all t) 173 | ) 174 | 175 | ;; (message "init-base configuration: %.2fs" 176 | ;; (float-time (time-subtract (current-time) my/init-base-start-time))) 177 | 178 | (provide 'init-edit) 179 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 180 | ;;; init-edit.el ends here 181 | -------------------------------------------------------------------------------- /lisp/init-mail.el: -------------------------------------------------------------------------------- 1 | ;;; init-mail.el --- Mail settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package ol-notmuch 7 | :ensure t 8 | ) 9 | 10 | (use-package notmuch 11 | :ensure t 12 | :commands notmuch 13 | :hook ((window-setup . notmuch) 14 | (notmuch-hello-refresh . notmuch-unread-count)) 15 | :bind (("\e\em" . notmuch) 16 | ("C-x m" . notmuch-mua-new-mail) ; override `compose mail' 17 | :map notmuch-hello-mode-map 18 | ("q" . quit-window) 19 | :map notmuch-show-mode-map 20 | ("C-c f" . my/capture-mail-follow-up) 21 | ("C-c r" . my/capture-mail-read-later) 22 | :map notmuch-search-mode-map 23 | ("/" . notmuch-search-filter) 24 | ("C-c f" . my/capture-mail-follow-up)) 25 | :init 26 | (setq notmuch-search-oldest-first nil) ; newest on the top 27 | :config 28 | ;; 设置notmuch邮件快速记录的模板 29 | (require 'org-capture) 30 | (add-to-list 'org-capture-templates 31 | '("e" "Email follow up" entry 32 | (file+headline "mail.org" "Follow Up") 33 | "* TODO [#A] %:subject :mail:\nSCHEDULED: %t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a%?" 34 | :empty-lines-after 1 35 | :prepend t 36 | :immediate-finish t 37 | :jump-to-captured t 38 | )) 39 | (add-to-list 'org-capture-templates-contexts 40 | '("e" ((in-mode . "notmuch-search-mode") 41 | (in-mode . "notmuch-show-mode")))) 42 | 43 | ;; 在邮件界面快速记录需要跟进的邮件 44 | (defun my/capture-mail-follow-up () 45 | (interactive) 46 | (call-interactively 'org-store-link) 47 | (org-capture nil "e")) 48 | 49 | ;; custom UI 50 | (setq notmuch-show-logo t) 51 | (setq notmuch-column-control 1.0) 52 | (setq notmuch-hello-recent-searches-max 20) 53 | (setq notmuch-hello-thousands-separator ",") 54 | (setq notmuch-hello-sections '(notmuch-hello-insert-header 55 | notmuch-hello-insert-saved-searches 56 | notmuch-hello-insert-alltags 57 | notmuch-hello-insert-footer)) 58 | (setq notmuch-show-all-tags-list t) 59 | 60 | ;; set saved searches, use `j' to jump to the search 61 | (setq notmuch-saved-searches '( 62 | (:name "all" 63 | :query "*" 64 | :sort-order newest-first 65 | :key "l") 66 | 67 | (:name "archived" 68 | :query "tag:archived" 69 | :sort-order newest-first 70 | :key "A") 71 | 72 | (:name "inbox" 73 | :query "tag:inbox" 74 | :sort-order newest-first 75 | :key "i") 76 | 77 | (:name "sent" 78 | :query "tag:sent" 79 | :sort-order newest-first 80 | :key "s") 81 | )) 82 | (setq notmuch-archive-tags '("-inbox" "+archived")) 83 | 84 | ;; Email composition 85 | (setq notmuch-mua-user-agent-function #'notmuch-mua-user-agent-full) 86 | 87 | ;; Reading messages 88 | (setq notmuch-wash-citation-lines-prefix 6) ; default is 3 89 | (setq notmuch-wash-citation-lines-suffix 6) 90 | (setq notmuch-unthreaded-show-out nil) 91 | (setq notmuch-message-headers '("To" "Cc" "Subject" "Date")) 92 | 93 | ;; notmuch notifications on mode-line based from notmuch-unread-mode, refer to: 94 | ;; https://www.reddit.com/r/emacs/comments/esxjh5/my_notmuch_email_count_display_in_modeline/ 95 | (defvar notmuch-unread-mode-line-string "") 96 | (defvar notmuch-unread-email-count nil) 97 | (defconst my-mode-line-map (make-sparse-keymap)) 98 | 99 | (defun notmuch-unread-count () 100 | (setq notmuch-unread-email-count (string-to-number (replace-regexp-in-string "\n" "" (notmuch-command-to-string "count" "tag:unread")))) 101 | (if (eq notmuch-unread-email-count 0) 102 | (setq notmuch-unread-mode-line-string (format " 0 ")) 103 | (setq notmuch-unread-mode-line-string (format " %d " notmuch-unread-email-count))) 104 | (force-mode-line-update)) 105 | 106 | (defun notmuch-open-emails () 107 | (interactive) 108 | (if (eq notmuch-unread-email-count 0) (notmuch-search "tag:inbox") (notmuch-search "tag:unread"))) 109 | 110 | (setq global-mode-string 111 | (append global-mode-string (list '(:eval (propertize notmuch-unread-mode-line-string 'help-echo "notmuch emails" 'mouse-face 'mode-line-highlight 'local-map my-mode-line-map))))) 112 | 113 | (define-key my-mode-line-map 114 | (vconcat [mode-line down-mouse-1]) 115 | (cons "hello" 'notmuch-open-emails)) 116 | 117 | ;; 每三分钟刷新一下notmuch,在刷新的时候会执行 `notmuch-unread-count' hook 118 | ;; 来执行状态栏的邮件数量更新 119 | (run-at-time t 180 #'notmuch-refresh-all-buffers) 120 | ) 121 | 122 | (use-package message 123 | :ensure nil 124 | :hook ((message-mode . auto-fill-mode) 125 | (message-mode . (lambda () (display-line-numbers-mode 0))) 126 | (message-mode . turn-on-orgtbl) 127 | ) 128 | ;; :bind (:map message-mode-map ("TAB" . message-display-abbrev)) 129 | :config 130 | ;; add Cc and Bcc headers to the message buffer 131 | (setq message-default-mail-headers "Cc: \nBcc: \n") 132 | ;; change the directory to store the sent mail and mkdir sent ahead 133 | (setq message-directory "~/Mail/") 134 | (setq message-auto-save-directory "~/Mail/drafts/") 135 | :custom 136 | ;; make sure `user-full-name' and `user-mail-address' are configed 137 | (message-kill-buffer-on-exit t) 138 | (message-mail-alias-type 'ecomplete) 139 | (message-send-mail-function #'message-use-send-mail-function) 140 | (message-signature (concat "Best regards,\n" user-full-name)) 141 | ) 142 | 143 | (use-package sendmail 144 | :ensure nil 145 | :defer t 146 | :custom 147 | (send-mail-function 'sendmail-send-it) 148 | ;; msmtp config 149 | (sendmail-program "/usr/local/bin/msmtp") 150 | (mail-specify-envelope-from t) 151 | (message-sendmail-envelope-from 'header) 152 | (mail-envelope-from 'header) 153 | ) 154 | 155 | (use-package emacs 156 | :ensure nil 157 | :hook (notmuch-hello-refresh . notmuch-hello-refresh-status-message) 158 | :config 159 | (defvar notmuch-hello-refresh-count 0) 160 | (defun notmuch-hello-refresh-status-message () 161 | (let* ((new-count 162 | (string-to-number 163 | (car (process-lines notmuch-command "count")))) 164 | (diff-count (- new-count notmuch-hello-refresh-count))) 165 | (cond 166 | ((= notmuch-hello-refresh-count 0) 167 | (progn 168 | (message "You have new messages.") 169 | (notify-send :title "Notmuch email" 170 | :body (concat "You have " (notmuch-hello-nice-number new-count) " messages.") 171 | :timeout 5 172 | :urgency 'critical) 173 | )) 174 | ((> diff-count 0) 175 | (progn 176 | (message "You have new messages.") 177 | (notify-send :title "Notmuch email" 178 | :body (concat "You have " (notmuch-hello-nice-number diff-count) " more messages since last refresh.") 179 | :timeout 5 180 | :urgency 'critical) 181 | )) 182 | ((< diff-count 0) 183 | (progn 184 | (message "You have new messages.") 185 | (notify-send :title "Notmuch email" 186 | :body (concat "You have " (notmuch-hello-nice-number (- diff-count)) " fewer messages since last refresh.") 187 | :timeout 5 188 | :urgency 'critical) 189 | ))) 190 | (setq notmuch-hello-refresh-count new-count))) 191 | ) 192 | 193 | (provide 'init-mail) 194 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 195 | ;;; init-mail.el ends here 196 | -------------------------------------------------------------------------------- /lisp/init-dired.el: -------------------------------------------------------------------------------- 1 | ;;; init-dired.el --- Dired settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package dired 7 | :ensure nil 8 | :bind (:map dired-mode-map 9 | ("C-" . xah-open-in-external-app) 10 | ("W" . dired-copy-path) 11 | ) 12 | :config 13 | ;; Enable the disabled dired commands 14 | (put 'dired-find-alternate-file 'disabled nil) 15 | 16 | ;; open files via external program based on file types, See: 17 | ;; https://emacs.stackexchange.com/questions/3105/how-to-use-an-external-program-as-the-default-way-to-open-pdfs-from-emacs 18 | (defun xdg-open (filename) 19 | (interactive "fFilename: ") 20 | (let ((process-connection-type)) 21 | (start-process "" nil (cond ((eq system-type 'gnu/linux) "xdg-open") 22 | ((eq system-type 'darwin) "open") 23 | ((eq system-type 'windows-nt) "start") 24 | (t "")) (expand-file-name filename)))) 25 | ;; open files via external program when using find-file 26 | (defun find-file-auto (orig-fun &rest args) 27 | (let ((filename (car args))) 28 | (if (cl-find-if 29 | (lambda (regexp) (string-match regexp filename)) 30 | '( 31 | ;; "\\.html?\\'" 32 | "\\.xlsx?\\'" 33 | "\\.pptx?\\'" 34 | "\\.docx?\\'" 35 | "\\.mp4\\'" 36 | "\\.app\\'" 37 | )) 38 | (xdg-open filename) 39 | (apply orig-fun args)))) 40 | (advice-add 'find-file :around 'find-file-auto) 41 | 42 | (defun dired-copy-path () 43 | "In dired, copy file path to kill-buffer. 44 | At 2nd time it copy current directory to kill-buffer." 45 | (interactive) 46 | (let (path) 47 | (setq path (dired-file-name-at-point)) 48 | (if (string= path (current-kill 0 1)) (setq path (dired-current-directory))) 49 | (message path) 50 | (kill-new path))) 51 | 52 | (defun xah-open-in-external-app (&optional @fname) 53 | "Open the current file or dired marked files in external app. 54 | The app is chosen from your OS's preference. 55 | 56 | When called in emacs lisp, if @fname is given, open that. 57 | 58 | URL `http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html' 59 | Version 2019-11-04" 60 | (interactive) 61 | (let* ( 62 | ($file-list 63 | (if @fname 64 | (progn (list @fname)) 65 | (if (or (string-equal major-mode "dired-mode") 66 | (string-equal major-mode "dirvish-mode")) 67 | (dired-get-marked-files) 68 | (list (buffer-file-name))))) 69 | ($do-it-p (if (<= (length $file-list) 5) 70 | t 71 | (y-or-n-p "Open more than 5 files? ")))) 72 | (when $do-it-p 73 | (cond 74 | ((string-equal system-type "windows-nt") 75 | (mapc 76 | (lambda ($fpath) 77 | (w32-shell-execute "open" $fpath)) $file-list)) 78 | ((string-equal system-type "darwin") 79 | (mapc 80 | (lambda ($fpath) 81 | (shell-command 82 | (concat "open " (shell-quote-argument $fpath)))) $file-list)) 83 | ((string-equal system-type "gnu/linux") 84 | (mapc 85 | (lambda ($fpath) (let ((process-connection-type nil)) 86 | (start-process "" nil "xdg-open" $fpath))) $file-list)))))) 87 | :custom 88 | ;; (dired-recursive-deletes 'always) 89 | (delete-by-moving-to-trash t) 90 | (dired-dwim-target t) 91 | (dired-bind-vm nil) 92 | (dired-bind-man nil) 93 | (dired-bind-info nil) 94 | (dired-auto-revert-buffer t) 95 | (dired-hide-details-hide-symlink-targets nil) 96 | (dired-kill-when-opening-new-dired-buffer t) 97 | (dired-listing-switches "-AFhlv")) 98 | 99 | (use-package dired-aux 100 | :ensure nil 101 | :bind (:map dired-mode-map 102 | ("C-c +" . dired-create-empty-file)) 103 | :config 104 | ;; with the help of `evil-collection', P is bound to `dired-do-print'. 105 | (define-advice dired-do-print (:override (&optional _)) 106 | "Show/hide dotfiles." 107 | (interactive) 108 | (if (or (not (boundp 'dired-dotfiles-show-p)) dired-dotfiles-show-p) 109 | (progn 110 | (setq-local dired-dotfiles-show-p nil) 111 | (dired-mark-files-regexp "^\\.") 112 | (dired-do-kill-lines)) 113 | (revert-buffer) 114 | (setq-local dired-dotfiles-show-p t))) 115 | :custom 116 | (dired-isearch-filenames 'dwim) 117 | (dired-create-destination-dirs 'ask) 118 | (dired-vc-rename-file t)) 119 | 120 | (use-package dired-x 121 | :ensure nil 122 | :hook (dired-mode . dired-omit-mode) 123 | :init 124 | (setq dired-guess-shell-alist-user `((,(rx "." 125 | (or 126 | ;; Videos 127 | "mp4" "avi" "mkv" "flv" "ogv" "ogg" "mov" 128 | ;; Music 129 | "wav" "mp3" "flac" 130 | ;; Images 131 | "jpg" "jpeg" "png" "gif" "xpm" "svg" "bmp" 132 | ;; Docs 133 | "pdf" "md" "djvu" "ps" "eps" "doc" "docx" "xls" "xlsx" "ppt" "pptx") 134 | string-end) 135 | ,(cond ((eq system-type 'gnu/linux) "xdg-open") 136 | ((eq system-type 'darwin) "open") 137 | ((eq system-type 'windows-nt) "start") 138 | (t ""))))) 139 | :custom 140 | (dired-omit-verbose nil) 141 | (dired-omit-files (rx string-start 142 | (or ".DS_Store" 143 | ".cache" 144 | ".vscode" 145 | ".ccls-cache" ".clangd") 146 | string-end)) 147 | ;; Dont prompt about killing buffer visiting delete file 148 | (dired-clean-confirm-killing-deleted-buffers nil) 149 | ) 150 | 151 | (use-package diredfl 152 | :ensure t 153 | :hook (dired-mode . diredfl-mode)) 154 | 155 | (use-package all-the-icons-dired 156 | :ensure t 157 | :hook (dired-mode . all-the-icons-dired-mode) 158 | ) 159 | 160 | (use-package dirvish 161 | :ensure t 162 | :hook (after-init . dirvish-override-dired-mode) 163 | :bind (:map dired-mode-map 164 | ("TAB" . dirvish-toggle-subtree) 165 | ("SPC" . dirvish-show-history) 166 | ("*" . dirvish-mark-menu) 167 | ("r" . dirvish-roam) 168 | ("b" . dirvish-goto-bookmark) 169 | ("f" . dirvish-file-info-menu) 170 | ("M-n" . dirvish-go-forward-history) 171 | ("M-p" . dirvish-go-backward-history) 172 | ("M-s" . dirvish-setup-menu) 173 | ("M-f" . dirvish-toggle-fullscreen) 174 | ([remap dired-sort-toggle-or-edit] . dirvish-quicksort) 175 | ([remap dired-do-redisplay] . dirvish-ls-switches-menu) 176 | ([remap dired-summary] . dirvish-dispatch) 177 | ([remap dired-do-copy] . dirvish-yank-menu) 178 | ([remap mode-line-other-buffer] . dirvish-other-buffer)) 179 | :config 180 | (dirvish-peek-mode) 181 | (setq dirvish-hide-details t) 182 | ;; open mp4 file via external program which is mpv here. 183 | (add-to-list 'mailcap-mime-extensions '(".mp4" . "video/mp4")) 184 | (add-list-to-list 'dirvish-open-with-programs '( 185 | (("html") . ("open" "%f")) 186 | (("xlsx") . ("open" "%f")) 187 | (("pptx") . ("open" "%f")) 188 | (("docx") . ("open" "%f")) 189 | (("md") . ("open" "%f")) 190 | )) 191 | :custom 192 | (dirvish-menu-bookmarks '(("h" "~/" "Home") 193 | ("d" "~/Downloads/" "Downloads") 194 | ("e" "~/.emacs.d.default/" "Emacs") 195 | ("o" "~/org/" "org") 196 | ("i" "~/iCloud/" "iCloud") 197 | ;; ("t" "~/.local/share/Trash/files/" "TrashCan") 198 | )) 199 | (dirvish-mode-line-format '(:left 200 | (sort file-time " " file-size symlink) ; it's ok to place string inside 201 | :right 202 | ;; For `dired-filter' users, replace `omit' with `filter' segment defined below 203 | (omit yank index))) 204 | (dirvish-attributes '(subtree-state 205 | file-size 206 | vc-state 207 | git-msg 208 | file-time 209 | ;; all-the-icons 210 | )) 211 | ) 212 | 213 | (provide 'init-dired) 214 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 215 | ;;; init-dired.el ends here 216 | -------------------------------------------------------------------------------- /lisp/init-completion.el: -------------------------------------------------------------------------------- 1 | ;;; init-completion.el --- Completion settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package vertico 7 | :ensure t 8 | :hook (after-init . vertico-mode) 9 | :bind (:map minibuffer-local-map 10 | ("M-" . my/minibuffer-backward-kill) 11 | :map vertico-map 12 | ("M-q" . vertico-quick-insert)) ; use C-g to exit 13 | :config 14 | (defun my/minibuffer-backward-kill (arg) 15 | "When minibuffer is completing a file name delete up to parent 16 | folder, otherwise delete a word" 17 | (interactive "p") 18 | (if minibuffer-completing-file-name 19 | ;; Borrowed from https://github.com/raxod502/selectrum/issues/498#issuecomment-803283608 20 | (if (string-match-p "/." (minibuffer-contents)) 21 | (zap-up-to-char (- arg) ?/) 22 | (delete-minibuffer-contents)) 23 | (backward-kill-word arg))) 24 | 25 | ;; Do not allow the cursor in the minibuffer prompt 26 | (setq minibuffer-prompt-properties 27 | '(read-only t cursor-intangible t face minibuffer-prompt)) 28 | (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) 29 | 30 | (setq vertico-cycle t) ; cycle from last to first 31 | :custom 32 | (vertico-count 15) ; number of candidates to display, default is 10 33 | ) 34 | 35 | ;; support Pinyin first character match for orderless, avy etc. 36 | (use-package pinyinlib 37 | :ensure t) 38 | 39 | ;; orderless 是一种哲学思想 40 | (use-package orderless 41 | :ensure t 42 | :init 43 | (setq completion-styles '(orderless partial-completion basic)) 44 | (setq orderless-component-separator "[ &]") ; & is for company because space will break completion 45 | (setq completion-category-defaults nil) 46 | (setq completion-category-overrides nil) 47 | :config 48 | ;; make completion support pinyin, refer to 49 | ;; https://emacs-china.org/t/vertico/17913/2 50 | (defun completion--regex-pinyin (str) 51 | (orderless-regexp (pinyinlib-build-regexp-string str))) 52 | (add-to-list 'orderless-matching-styles 'completion--regex-pinyin) 53 | ) 54 | 55 | ;; minibuffer helpful annotations 56 | (use-package marginalia 57 | :ensure t 58 | :hook (after-init . marginalia-mode) 59 | :custom 60 | (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))) 61 | 62 | (use-package consult 63 | :ensure t 64 | :after org 65 | :bind (([remap goto-line] . consult-goto-line) 66 | ([remap isearch-forward] . consult-line-symbol-at-point) ; my-consult-ripgrep-or-line 67 | ([remap switch-to-buffer] . consult-buffer) 68 | ([remap switch-to-buffer-other-window] . consult-buffer-other-window) 69 | ([remap switch-to-buffer-other-frame] . consult-buffer-other-frame) 70 | ([remap yank-pop] . consult-yank-pop) 71 | ([remap apropos] . consult-apropos) 72 | ([remap bookmark-jump] . consult-bookmark) 73 | ([remap goto-line] . consult-goto-line) 74 | ([remap imenu] . consult-imenu) 75 | ([remap multi-occur] . consult-multi-occur) 76 | ([remap recentf-open-files] . consult-recent-file) 77 | ("C-x j" . consult-mark) 78 | ("C-c g" . consult-ripgrep) 79 | ("C-c f" . consult-find) 80 | ("\e\ef" . consult-locate) ; need to enable locate first 81 | ("C-c n h" . my/consult-find-org-headings) 82 | :map org-mode-map 83 | ("C-c C-j" . consult-org-heading) 84 | :map minibuffer-local-map 85 | ("C-r" . consult-history) 86 | :map isearch-mode-map 87 | ("C-;" . consult-line) 88 | :map prog-mode-map 89 | ("C-c C-j" . consult-outline) 90 | ) 91 | :hook (completion-list-mode . consult-preview-at-point-mode) 92 | :init 93 | ;; Optionally configure the register formatting. This improves the register 94 | ;; preview for `consult-register', `consult-register-load', 95 | ;; `consult-register-store' and the Emacs built-ins. 96 | (setq register-preview-delay 0 97 | register-preview-function #'consult-register-format) 98 | 99 | ;; Optionally tweak the register preview window. 100 | ;; This adds thin lines, sorting and hides the mode line of the window. 101 | (advice-add #'register-preview :override #'consult-register-window) 102 | 103 | ;; Use Consult to select xref locations with preview 104 | (setq xref-show-xrefs-function #'consult-xref 105 | xref-show-definitions-function #'consult-xref) 106 | 107 | ;; MacOS locate doesn't support `--ignore-case --existing' args. 108 | (setq consult-locate-args (pcase system-type 109 | ('gnu/linux "locate --ignore-case --existing --regex") 110 | ('darwin "mdfind -name"))) 111 | :config 112 | (consult-customize 113 | consult-theme 114 | :preview-key '(:debounce 0.2 any) 115 | consult-ripgrep consult-git-grep consult-grep 116 | consult-bookmark consult-recent-file consult-xref 117 | consult--source-recent-file consult--source-project-recent-file consult--source-bookmark 118 | :preview-key '(:debounce 0.4 any)) 119 | 120 | ;; Optionally configure the narrowing key. 121 | ;; Both < and C-+ work reasonably well. 122 | (setq consult-narrow-key "<") ;; (kbd "C-+") 123 | 124 | (autoload 'projectile-project-root "projectile") 125 | (setq consult-project-root-function #'projectile-project-root) 126 | 127 | ;; search all org file headings under a directory, see: 128 | ;; https://emacs-china.org/t/org-files-heading-entry/20830/4 129 | (defun my/consult-find-org-headings (&optional match) 130 | "find headngs in all org files." 131 | (interactive) 132 | (consult-org-heading match (directory-files org-directory t "^[0-9]\\{8\\}.+\\.org$"))) 133 | 134 | ;; Use `consult-ripgrep' instead of `consult-line' in large buffers 135 | (defun consult-line-symbol-at-point () 136 | "Consult line the synbol where the point is" 137 | (interactive) 138 | (consult-line (thing-at-point 'symbol))) 139 | ) 140 | 141 | (use-package corfu 142 | :ensure t 143 | :hook (after-init . global-corfu-mode) 144 | :bind 145 | (:map corfu-map 146 | ("SPC" . corfu-insert-separator) ; configure space for separator insertion 147 | ("M-q" . corfu-quick-complete) ; use C-g to exit 148 | ("TAB" . corfu-next) 149 | ([tab] . corfu-next) 150 | ("S-TAB" . corfu-previous) 151 | ([backtab] . corfu-previous)) 152 | :config 153 | ;; TAB cycle if there are only few candidates 154 | (setq completion-cycle-threshold 0) 155 | (setq tab-always-indent 'complete) 156 | 157 | (defun corfu-enable-always-in-minibuffer () 158 | "Enable Corfu in the minibuffer if Vertico/Mct are not active." 159 | (unless (or (bound-and-true-p mct--active) 160 | (bound-and-true-p vertico--input)) 161 | ;; (setq-local corfu-auto nil) Enable/disable auto completion 162 | (corfu-mode 1))) 163 | (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1) 164 | 165 | ;; enable corfu in eshell 166 | (add-hook 'eshell-mode-hook 167 | (lambda () 168 | (setq-local corfu-auto nil) 169 | (corfu-mode))) 170 | 171 | ;; For Eshell 172 | ;; =========== 173 | ;; avoid press RET twice in Eshell 174 | (defun corfu-send-shell (&rest _) 175 | "Send completion candidate when inside comint/eshell." 176 | (cond 177 | ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input)) 178 | (eshell-send-input)) 179 | ((and (derived-mode-p 'comint-mode) (fboundp 'comint-send-input)) 180 | (comint-send-input)))) 181 | ;; (advice-add #'corfu-insert :after #'corfu-send-shell) 182 | 183 | :custom 184 | (corfu-cycle t) ;; Enable cycling for `corfu-next/previous' 185 | ) 186 | 187 | (use-package cape 188 | :ensure t 189 | :hook (after-init . set-completion-backends) 190 | :init 191 | (defun set-completion-backends () 192 | (setq-local completion-at-point-functions 193 | (list 194 | (cape-capf-buster 195 | (cape-capf-super 196 | #'codeium-completion-at-point 197 | #'cape-abbrev 198 | #'cape-dabbrev 199 | #'cape-keyword 200 | #'cape-elisp-block 201 | #'cape-elisp-symbol 202 | #'cape-file 203 | #'cape-line 204 | ) 205 | 'equal) 206 | ))) 207 | :config 208 | (setq cape-dict-file (expand-file-name "etc/hunspell_dict.txt" user-emacs-directory)) 209 | 210 | ;; for Eshell: 211 | ;; =========== 212 | ;; Silence the pcomplete capf, no errors or messages! 213 | (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) 214 | 215 | ;; Ensure that pcomplete does not write to the buffer 216 | ;; and behaves as a pure `completion-at-point-function'. 217 | (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify) 218 | ) 219 | 220 | ;; yasnippet settings 221 | (use-package yasnippet 222 | :ensure t 223 | :diminish yas-minor-mode 224 | :hook ((after-init . yas-reload-all) 225 | ((prog-mode LaTeX-mode org-mode) . yas-minor-mode)) 226 | :config 227 | ;; Suppress warning for yasnippet code. 228 | (require 'warnings) 229 | (add-to-list 'warning-suppress-types '(yasnippet backquote-change)) 230 | 231 | (setq yas-prompt-functions '(yas-x-prompt yas-dropdown-prompt)) 232 | (defun smarter-yas-expand-next-field () 233 | "Try to `yas-expand' then `yas-next-field' at current cursor position." 234 | (interactive) 235 | (let ((old-point (point)) 236 | (old-tick (buffer-chars-modified-tick))) 237 | (yas-expand) 238 | (when (and (eq old-point (point)) 239 | (eq old-tick (buffer-chars-modified-tick))) 240 | (ignore-errors (yas-next-field)))))) 241 | 242 | (use-package all-the-icons-completion 243 | :ensure t 244 | :hook ((after-init . all-the-icons-completion-mode) 245 | (marginalia-mode . all-the-icons-completion-marginalia-setup)) 246 | ) 247 | 248 | (use-package embark 249 | :ensure t 250 | :bind (([remap describe-bindings] . embark-bindings) 251 | ("C-'" . embark-act) 252 | :map minibuffer-local-map 253 | :map minibuffer-local-completion-map 254 | ("TAB" . minibuffer-force-complete) 255 | :map embark-file-map 256 | ("E" . consult-file-externally) ; Open file externally, or `we' in Ranger 257 | ("O" . consult-directory-externally) ; Open directory externally 258 | ) 259 | :init 260 | ;; Optionally replace the key help with a completing-read interface 261 | (setq prefix-help-command #'embark-prefix-help-command) 262 | :config 263 | ;; Show Embark actions via which-key 264 | (setq embark-action-indicator 265 | (lambda (map) 266 | (which-key--show-keymap "Embark" map nil nil 'no-paging) 267 | #'which-key--hide-popup-ignore-command) 268 | embark-become-indicator embark-action-indicator) 269 | 270 | ;; open directory 271 | (defun consult-directory-externally (file) 272 | "Open directory externally using the default application of the system." 273 | (interactive "fOpen externally: ") 274 | (if (and (eq system-type 'windows-nt) 275 | (fboundp 'w32-shell-execute)) 276 | (shell-command-to-string (encode-coding-string (replace-regexp-in-string "/" "\\\\" 277 | (format "explorer.exe %s" (file-name-directory (expand-file-name file)))) 'gbk)) 278 | (call-process (pcase system-type 279 | ('darwin "open") 280 | ('cygwin "cygstart") 281 | (_ "xdg-open")) 282 | nil 0 nil 283 | (file-name-directory (expand-file-name file))))) 284 | 285 | ;; Hide the mode line of the Embark live/completions buffers 286 | (add-to-list 'display-buffer-alist 287 | '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" 288 | nil 289 | (window-parameters (mode-line-format . none)))) 290 | ) 291 | 292 | (use-package embark-consult 293 | :ensure t 294 | :hook (embark-collect-mode . consult-preview-at-point-mode)) 295 | 296 | (provide 'init-completion) 297 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 298 | ;;; init-completion.el ends here 299 | -------------------------------------------------------------------------------- /lisp/init-ui.el: -------------------------------------------------------------------------------- 1 | ;;; init-ui.el --- UI settings -*- lexical-binding: t -*- 2 | ;;; Commentary: 3 | 4 | ;;; Code: 5 | 6 | (use-package ef-themes 7 | :ensure t 8 | :bind ("C-c t" . ef-themes-toggle) 9 | :init 10 | ;; set two specific themes and switch between them 11 | (setq ef-themes-to-toggle '(ef-summer ef-winter)) 12 | ;; set org headings and function syntax 13 | (setq ef-themes-headings 14 | '((0 . (bold 1)) 15 | (1 . (bold 1)) 16 | (2 . (rainbow bold 1)) 17 | (3 . (rainbow bold 1)) 18 | (4 . (rainbow bold 1)) 19 | (t . (rainbow bold 1)))) 20 | (setq ef-themes-region '(intense no-extend neutral)) 21 | ;; Disable all other themes to avoid awkward blending: 22 | (mapc #'disable-theme custom-enabled-themes) 23 | 24 | ;; Load the theme of choice: 25 | ;; The themes we provide are recorded in the `ef-themes-dark-themes', 26 | ;; `ef-themes-light-themes'. 27 | 28 | ;; 如果你不喜欢随机主题,也可以直接固定选择一个主题,如下: 29 | ;; (ef-themes-select 'ef-summer) 30 | 31 | ;; 随机挑选一款主题,如果是命令行打开Emacs,则随机挑选一款黑色主题 32 | (if (display-graphic-p) 33 | (ef-themes-load-random) 34 | (ef-themes-load-random 'dark)) 35 | 36 | :config 37 | ;; auto change theme, aligning with system themes. 38 | (defun my/apply-theme (appearance) 39 | "Load theme, taking current system APPEARANCE into consideration." 40 | (mapc #'disable-theme custom-enabled-themes) 41 | (pcase appearance 42 | ('light (if (display-graphic-p) (ef-themes-load-random 'light) (ef-themes-load-random 'dark))) 43 | ('dark (ef-themes-load-random 'dark)))) 44 | 45 | (if (eq system-type 'darwin) 46 | ;; only for emacs-plus 47 | (add-hook 'ns-system-appearance-change-functions #'my/apply-theme) 48 | (ef-themes-select 'ef-summer) 49 | ) 50 | ) 51 | 52 | (use-package fontaine 53 | :ensure t 54 | :when (display-graphic-p) 55 | ;; :hook (kill-emacs . fontaine-store-latest-preset) 56 | :config 57 | (setq fontaine-latest-state-file 58 | (locate-user-emacs-file "etc/fontaine-latest-state.eld")) 59 | (setq fontaine-presets 60 | '((regular 61 | :default-height 140 62 | :default-weight regular 63 | :fixed-pitch-height 1.0 64 | :variable-pitch-height 1.0 65 | ) 66 | (large 67 | :default-height 180 68 | :default-weight normal 69 | :fixed-pitch-height 1.0 70 | :variable-pitch-height 1.05 71 | ) 72 | (t 73 | :default-family "Source Code Pro" 74 | :fixed-pitch-family "Source Code Pro" 75 | :variable-pitch-family "Source Code Pro" 76 | :italic-family "Source Code Pro" 77 | :variable-pitch-weight normal 78 | :bold-weight normal 79 | :italic-slant italic 80 | :line-spacing 0.1) 81 | )) 82 | ;; (fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular)) 83 | (fontaine-set-preset 'regular) 84 | 85 | ;; set emoji font 86 | (set-fontset-font 87 | t 88 | (if (version< emacs-version "28.1") 89 | '(#x1f300 . #x1fad0) 90 | 'emoji) 91 | (cond 92 | ((member "Noto Emoji" (font-family-list)) "Noto Emoji") 93 | ((member "Symbola" (font-family-list)) "Symbola") 94 | ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji") 95 | ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji") 96 | ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji") 97 | )) 98 | 99 | ;; set Chinese font 100 | (dolist (charset '(kana han symbol cjk-misc bopomofo)) 101 | (set-fontset-font 102 | (frame-parameter nil 'font) 103 | charset 104 | (font-spec :family 105 | (cond 106 | ((eq system-type 'darwin) 107 | (cond 108 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 109 | ((member "PingFang SC" (font-family-list)) "PingFang SC") 110 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 111 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 112 | )) 113 | ((eq system-type 'gnu/linux) 114 | (cond 115 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 116 | ((member "WenQuanYi Micro Hei" (font-family-list)) "WenQuanYi Micro Hei") 117 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 118 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 119 | )) 120 | (t 121 | (cond 122 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 123 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 124 | ))) 125 | ))) 126 | 127 | ;; set Chinese font scale 128 | (setq face-font-rescale-alist `( 129 | ("Symbola" . 1.3) 130 | ("Microsoft YaHei" . 1.2) 131 | ("WenQuanYi Zen Hei" . 1.2) 132 | ("Sarasa Mono SC Nerd" . 1.2) 133 | ("PingFang SC" . 1.16) 134 | ("Lantinghei SC" . 1.16) 135 | ("Kaiti SC" . 1.16) 136 | ("Yuanti SC" . 1.16) 137 | ("Apple Color Emoji" . 0.91) 138 | )) 139 | ) 140 | 141 | ;; 设置窗口大小,仅仅在图形界面需要设置 142 | (when (display-graphic-p) 143 | (let ((top 0) ; 顶不留空 144 | (left (/ (x-display-pixel-width) 10)) ; 左边空10% 145 | (height (round (* 0.8 ; 窗体高度为0.8倍的显示高度 146 | (/ (x-display-pixel-height) 147 | (frame-char-height)))))) 148 | (let ((width (round (* 2.5 height)))) ; 窗体宽度为2.5倍高度 149 | (setq default-frame-alist nil) 150 | (add-to-list 'default-frame-alist (cons 'top top)) 151 | (add-to-list 'default-frame-alist (cons 'left left)) 152 | (add-to-list 'default-frame-alist (cons 'height height)) 153 | (add-to-list 'default-frame-alist (cons 'width width))))) 154 | 155 | ;; 禁用一些GUI特性 156 | (setq use-dialog-box nil) ; 鼠标操作不使用对话框 157 | (setq inhibit-default-init t) ; 不加载 `default' 库 158 | (setq inhibit-startup-screen t) ; 不加载启动画面 159 | (setq inhibit-startup-message t) ; 不加载启动消息 160 | (setq inhibit-startup-buffer-menu t) ; 不显示缓冲区列表 161 | 162 | ;; 草稿缓冲区默认文字设置 163 | (setq initial-scratch-message (concat ";; Happy hacking, " 164 | (capitalize user-login-name) " - Emacs ♥ you!\n\n")) 165 | 166 | ;; 设置缓冲区的文字方向为从左到右 167 | (setq bidi-paragraph-direction 'left-to-right) 168 | ;; 禁止使用双向括号算法 169 | ;; (setq bidi-inhibit-bpa t) 170 | 171 | ;; 设置自动折行宽度为80个字符,默认值为70 172 | (setq-default fill-column 80) 173 | 174 | ;; 设置大文件阈值为100MB,默认10MB 175 | (setq large-file-warning-threshold 100000000) 176 | 177 | ;; 以16进制显示字节数 178 | (setq display-raw-bytes-as-hex t) 179 | ;; 有输入时禁止 `fontification' 相关的函数钩子,能让滚动更顺滑 180 | (setq redisplay-skip-fontification-on-input t) 181 | 182 | ;; 禁止响铃 183 | (setq ring-bell-function 'ignore) 184 | 185 | ;; 禁止闪烁光标 186 | (blink-cursor-mode -1) 187 | 188 | ;; 在光标处而非鼠标所在位置粘贴 189 | (setq mouse-yank-at-point t) 190 | 191 | ;; 拷贝粘贴设置 192 | (setq select-enable-primary nil) ; 选择文字时不拷贝 193 | (setq select-enable-clipboard t) ; 拷贝时使用剪贴板 194 | 195 | ;; 鼠标滚动设置 196 | (setq scroll-step 2) 197 | (setq scroll-margin 2) 198 | (setq hscroll-step 2) 199 | (setq hscroll-margin 2) 200 | (setq scroll-conservatively 101) 201 | (setq scroll-up-aggressively 0.01) 202 | (setq scroll-down-aggressively 0.01) 203 | (setq scroll-preserve-screen-position 'always) 204 | 205 | ;; 对于高的行禁止自动垂直滚动 206 | (setq auto-window-vscroll nil) 207 | 208 | ;; 设置新分屏打开的位置的阈值 209 | (setq split-width-threshold (assoc-default 'width default-frame-alist)) 210 | (setq split-height-threshold nil) 211 | 212 | ;; TAB键设置,在Emacs里不使用TAB键,所有的TAB默认为4个空格 213 | (setq-default indent-tabs-mode nil) 214 | (setq-default tab-width 4) 215 | 216 | ;; yes或no提示设置,通过下面这个函数设置当缓冲区名字匹配到预设的字符串时自动回答yes 217 | (setq original-y-or-n-p 'y-or-n-p) 218 | (defalias 'original-y-or-n-p (symbol-function 'y-or-n-p)) 219 | (defun default-yes-sometimes (prompt) 220 | "automatically say y when buffer name match following string" 221 | (if (or 222 | (string-match "has a running process" prompt) 223 | (string-match "does not exist; create" prompt) 224 | (string-match "modified; kill anyway" prompt) 225 | (string-match "Delete buffer using" prompt) 226 | (string-match "Kill buffer of" prompt) 227 | (string-match "still connected. Kill it?" prompt) 228 | (string-match "Shutdown the client's kernel" prompt) 229 | (string-match "kill them and exit anyway" prompt) 230 | (string-match "Revert buffer from file" prompt) 231 | (string-match "Kill Dired buffer of" prompt) 232 | (string-match "delete buffer using" prompt) 233 | (string-match "Kill all pass entry" prompt) 234 | (string-match "for all cursors" prompt) 235 | (string-match "Do you want edit the entry" prompt)) 236 | t 237 | (original-y-or-n-p prompt))) 238 | (defalias 'yes-or-no-p 'default-yes-sometimes) 239 | (defalias 'y-or-n-p 'default-yes-sometimes) 240 | 241 | ;; 设置剪贴板历史长度300,默认为60 242 | (setq kill-ring-max 200) 243 | 244 | ;; 在剪贴板里不存储重复内容 245 | (setq kill-do-not-save-duplicates t) 246 | 247 | ;; 设置位置记录长度为6,默认为16 248 | ;; 可以使用 `counsel-mark-ring' or `consult-mark' (C-x j) 来访问光标位置记录 249 | ;; 使用 C-x C-SPC 执行 `pop-global-mark' 直接跳转到上一个全局位置处 250 | ;; 使用 C-u C-SPC 跳转到本地位置处 251 | (setq mark-ring-max 6) 252 | (setq global-mark-ring-max 6) 253 | 254 | ;; 设置 emacs-lisp 的限制 255 | (setq max-lisp-eval-depth 10000) ; 默认值为 800 256 | (setq max-specpdl-size 10000) ; 默认值为 1600 257 | 258 | ;; 启用 `list-timers', `list-threads' 这两个命令 259 | (put 'list-timers 'disabled nil) 260 | (put 'list-threads 'disabled nil) 261 | 262 | ;; 在命令行里支持鼠标 263 | (xterm-mouse-mode 1) 264 | 265 | ;; 退出Emacs时进行确认 266 | (setq confirm-kill-emacs 'y-or-n-p) 267 | 268 | ;; 在模式栏上显示当前光标的列号 269 | (column-number-mode t) 270 | 271 | ;; 配置所有的编码为UTF-8,参考: 272 | ;; https://thraxys.wordpress.com/2016/01/13/utf-8-in-emacs-everywhere-forever/ 273 | (setq locale-coding-system 'utf-8) 274 | (set-terminal-coding-system 'utf-8) 275 | (set-keyboard-coding-system 'utf-8) 276 | (set-selection-coding-system 'utf-8) 277 | (set-default-coding-systems 'utf-8) 278 | (set-language-environment 'utf-8) 279 | (set-clipboard-coding-system 'utf-8) 280 | (set-file-name-coding-system 'utf-8) 281 | (set-buffer-file-coding-system 'utf-8) 282 | (prefer-coding-system 'utf-8) 283 | (modify-coding-system-alist 'process "*" 'utf-8) 284 | (when (display-graphic-p) 285 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) 286 | 287 | (use-package doom-modeline 288 | :ensure t 289 | :hook (after-init . doom-modeline-mode) 290 | :custom 291 | (doom-modeline-irc nil) 292 | (doom-modeline-mu4e nil) 293 | (doom-modeline-gnus nil) 294 | (doom-modeline-github nil) 295 | (doom-modeline-buffer-file-name-style 'truncate-upto-root) ; : auto 296 | (doom-modeline-persp-name nil) 297 | (doom-modeline-unicode-fallback t) 298 | (doom-modeline-enable-word-count nil)) 299 | 300 | (use-package minions 301 | :ensure t 302 | :hook (after-init . minions-mode)) 303 | 304 | (use-package keycast 305 | :ensure t 306 | :hook (after-init . keycast-mode) 307 | :config 308 | ;; set for doom-modeline support 309 | ;; With the latest change 72d9add, mode-line-keycast needs to be modified to keycast-mode-line. 310 | (define-minor-mode keycast-mode 311 | "Show current command and its key binding in the mode line (fix for use with doom-mode-line)." 312 | :global t 313 | (if keycast-mode 314 | (progn 315 | (add-hook 'pre-command-hook 'keycast--update t) 316 | (add-to-list 'global-mode-string '("" keycast-mode-line " "))) 317 | (remove-hook 'pre-command-hook 'keycast--update) 318 | (setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string)) 319 | )) 320 | 321 | (dolist (input '(self-insert-command 322 | org-self-insert-command)) 323 | (add-to-list 'keycast-substitute-alist `(,input "." "Typing…"))) 324 | 325 | (dolist (event '(mouse-event-p 326 | mouse-movement-p 327 | mwheel-scroll)) 328 | (add-to-list 'keycast-substitute-alist `(,event nil))) 329 | 330 | (setq keycast-log-format "%-20K%C\n") 331 | (setq keycast-log-frame-alist 332 | '((minibuffer . nil))) 333 | (setq keycast-log-newest-first t) 334 | ) 335 | 336 | (use-package notifications 337 | :ensure nil 338 | :commands notify-send 339 | :config 340 | (cond ((eq system-type 'darwin) 341 | (defun notify-send (&rest params) 342 | "Send notifications via `terminal-notifier'." 343 | (let ((title (plist-get params :title)) 344 | (body (plist-get params :body))) 345 | (start-process "terminal-notifier" 346 | nil 347 | "terminal-notifier" 348 | "-group" "Emacs" 349 | "-title" title 350 | "-message" body 351 | "-activate" "org.gnu.Emacs")))) 352 | (t 353 | (defalias 'notify-send 'notifications-notify))) 354 | ) 355 | 356 | (use-package all-the-icons 357 | :ensure t 358 | :when (display-graphic-p) 359 | :commands all-the-icons-install-fonts 360 | ) 361 | 362 | (use-package shackle 363 | :ensure t 364 | :hook (after-init . shackle-mode) 365 | :init 366 | (setq shackle-lighter "") 367 | (setq shackle-select-reused-windows nil) ; default nil 368 | (setq shackle-default-alignment 'below) ; default below 369 | (setq shackle-default-size 0.4) ; default 0.5 370 | (setq shackle-rules 371 | ;; CONDITION(:regexp) :select :inhibit-window-quit :size+:align|:other :same|:popup 372 | '((compilation-mode :ignore t) 373 | ("\\*Async Shell.*\\*" :regexp t :ignore t) 374 | ("\\*corfu.*\\*" :regexp t :ignore t) 375 | ("*eshell*" :select t :size 0.4 :align t :popup t) 376 | (helpful-mode :select t :size 0.6 :align right :popup t) 377 | ("*Messages*" :select t :size 0.4 :align t :popup t) 378 | ("*Calendar*" :select t :size 0.3 :align t :popup t) 379 | ("*info*" :select t :same t) 380 | (magit-status-mode :select t :inhibit-window-quit t :same t) 381 | (magit-log-mode :select t :inhibit-window-quit t :same t) 382 | )) 383 | ) 384 | 385 | (use-package popper 386 | :ensure t 387 | :bind (("M-`" . popper-toggle-latest) 388 | ("M-" . popper-cycle) 389 | ("M-\\" . popper-toggle-type) 390 | ) 391 | :init 392 | (setq popper-reference-buffers 393 | '("\\*Messages\\*" 394 | "\\*Async Shell Command\\*" 395 | help-mode 396 | helpful-mode 397 | occur-mode 398 | pass-view-mode 399 | "^\\*eshell.*\\*$" eshell-mode ;; eshell as a popup 400 | "^\\*shell.*\\*$" shell-mode ;; shell as a popup 401 | ("\\*corfu\\*" . hide) 402 | (compilation-mode . hide) 403 | ;; derived from `fundamental-mode' and fewer than 10 lines will be considered a popup 404 | (lambda (buf) (with-current-buffer buf 405 | (and (derived-mode-p 'fundamental-mode) 406 | (< (count-lines (point-min) (point-max)) 407 | 10)))) 408 | ) 409 | ) 410 | (popper-mode +1) 411 | (popper-echo-mode +1) 412 | :config 413 | ;; group by project.el, projectile, directory or perspective 414 | (setq popper-group-function nil) 415 | 416 | ;; pop in child frame or not 417 | (setq popper-display-function #'display-buffer-in-child-frame) 418 | 419 | ;; use `shackle.el' to control popup 420 | (setq popper-display-control nil) 421 | ) 422 | 423 | (use-package winner 424 | :ensure nil 425 | :hook (after-init . winner-mode) 426 | :commands (winner-undo winner-redo) 427 | :config 428 | (setq winner-boring-buffers 429 | '("*Completions*" 430 | "*Compile-Log*" 431 | "*inferior-lisp*" 432 | "*Fuzzy Completions*" 433 | "*Apropos*" 434 | "*Help*" 435 | "*cvs*" 436 | "*Buffer List*" 437 | "*Ibuffer*" 438 | "*esh command on file*")) 439 | ) 440 | 441 | (provide 'init-ui) 442 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 443 | ;;; init-ui.el ends here 444 | -------------------------------------------------------------------------------- /config-mirror/emacs-config-l5.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Emacs配置文件 2 | #+AUTHOR: Randolph 3 | #+DATE: 2022/12/22 14:23:50 4 | 5 | #+STARTUP: overview 6 | 7 | * early-init.el 8 | :PROPERTIES: 9 | :HEADER-ARGS: :tangle early-init.el 10 | :END: 11 | 12 | 在Emacs刚启动,还未加载主要配置文件时的配置文件。 13 | 14 | #+BEGIN_SRC emacs-lisp 15 | ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*- 16 | ;;; Commentary: 17 | 18 | ;;; Code: 19 | 20 | ;; 设置垃圾回收参数 21 | (setq gc-cons-threshold most-positive-fixnum) 22 | (setq gc-cons-percentage 0.6) 23 | 24 | ;; 启动早期不加载`package.el'包管理器 25 | (setq package-enable-at-startup nil) 26 | ;; 不从包缓存中加载 27 | (setq package-quickstart nil) 28 | 29 | ;; 禁止展示菜单栏、工具栏和纵向滚动条 30 | (push '(menu-bar-lines . 0) default-frame-alist) 31 | (push '(tool-bar-lines . 0) default-frame-alist) 32 | (push '(vertical-scroll-bars) default-frame-alist) 33 | 34 | ;; 禁止自动缩放窗口先 35 | (setq frame-inhibit-implied-resize t) 36 | 37 | ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框 38 | (menu-bar-mode -1) 39 | (tool-bar-mode -1) 40 | (scroll-bar-mode -1) 41 | (setq inhibit-splash-screen t) 42 | (setq use-file-dialog nil) 43 | 44 | ;; 在这个阶段不编译 45 | (setq comp-deferred-compilation nil) 46 | 47 | (provide 'early-init) 48 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 49 | ;;; early-init.el ends here 50 | #+END_SRC 51 | 52 | * init.el 53 | :PROPERTIES: 54 | :HEADER-ARGS: :tangle init.el 55 | :END: 56 | 57 | =init.el= 是Emacs的主要配置文件。 58 | 59 | ** init.el 文件头 60 | #+BEGIN_SRC emacs-lisp 61 | ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*- 62 | ;;; Commentary: 63 | 64 | ;;; Code: 65 | 66 | #+END_SRC 67 | 68 | ** package包管理配置 69 | #+begin_src emacs-lisp 70 | (require 'package) 71 | (setq package-archives 72 | '(("melpa" . "https://melpa.org/packages/") 73 | ("gnu" . "https://elpa.gnu.org/packages/") 74 | ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) 75 | 76 | (package-initialize) 77 | #+end_src 78 | 79 | ** 安装use-package插件 80 | [[https://github.com/jwiegley/use-package][use-package]] 是一个让Emacs配置更加结构化更加清晰的一个宏插件。 81 | 82 | #+begin_src emacs-lisp 83 | ;; 安装 `use-package' 84 | (unless (package-installed-p 'use-package) 85 | (package-refresh-contents) 86 | (package-install 'use-package)) 87 | 88 | ;; 配置 `use-package' 89 | (eval-and-compile 90 | (setq use-package-always-ensure nil) 91 | (setq use-package-always-defer nil) 92 | (setq use-package-expand-minimally nil) 93 | (setq use-package-enable-imenu-support t) 94 | (if (daemonp) 95 | (setq use-package-always-demand t))) 96 | 97 | (eval-when-compile 98 | (require 'use-package)) 99 | 100 | ;; 安装 `use-package' 的集成模块 101 | (use-package use-package-ensure-system-package 102 | :ensure t) 103 | (use-package diminish 104 | :ensure t) 105 | (use-package bind-key 106 | :ensure t) 107 | #+end_src 108 | 109 | ** quelpa包管理器 110 | [[https://github.com/quelpa/quelpa][quelpa]] 是配合 =package.el= 使用的,基于git的一个包管理器。 111 | #+BEGIN_SRC emacs-lisp 112 | ;; 安装 `quelpa' 113 | (use-package quelpa 114 | :ensure t 115 | :commands quelpa 116 | :config 117 | :custom 118 | (quelpa-git-clone-depth 1) 119 | (quelpa-update-melpa-p nil) 120 | (quelpa-self-upgrade-p nil) 121 | (quelpa-checkout-melpa-p nil)) 122 | 123 | ;; `quelpa' 与 `use-package' 集成 124 | (use-package quelpa-use-package 125 | :ensure t) 126 | #+END_SRC 127 | 128 | ** 加载模块化配置 129 | 130 | #+BEGIN_SRC emacs-lisp 131 | ;; 将lisp目录放到加载路径的前面以加快启动速度 132 | (let ((dir (locate-user-emacs-file "lisp"))) 133 | (add-to-list 'load-path (file-name-as-directory dir))) 134 | 135 | ;; 加载各模块化配置 136 | ;; 不要在`*message*'缓冲区显示加载模块化配置的信息 137 | (with-temp-message "" 138 | (require 'init-ui) ; UI交互 139 | ) 140 | #+END_SRC 141 | 142 | ** init.el 文件尾 143 | #+BEGIN_SRC emacs-lisp 144 | 145 | (provide 'init) 146 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 147 | ;;; init.el ends here 148 | #+END_SRC 149 | 150 | * init-ui.el 151 | :PROPERTIES: 152 | :HEADER-ARGS: :tangle lisp/init-ui.el :mkdirp yes 153 | :END: 154 | 155 | ** init-ui.el 文件头 156 | #+BEGIN_SRC emacs-lisp 157 | ;;; init-ui.el --- UI settings -*- lexical-binding: t -*- 158 | ;;; Commentary: 159 | 160 | ;;; Code: 161 | 162 | #+END_SRC 163 | 164 | ** ef主题 165 | 166 | [[https://protesilaos.com/emacs/ef-themes#h:ac76ded0-af9b-4566-aff9-75142ef2d4ef][ef themes]] 是我非常喜欢的一个主题包。 167 | 168 | #+BEGIN_SRC emacs-lisp 169 | (use-package ef-themes 170 | :ensure t 171 | :bind ("C-c t" . ef-themes-toggle) 172 | :init 173 | ;; set two specific themes and switch between them 174 | (setq ef-themes-to-toggle '(ef-summer ef-winter)) 175 | ;; set org headings and function syntax 176 | (setq ef-themes-headings 177 | '((0 . (bold 1)) 178 | (1 . (bold 1)) 179 | (2 . (rainbow bold 1)) 180 | (3 . (rainbow bold 1)) 181 | (4 . (rainbow bold 1)) 182 | (t . (rainbow bold 1)))) 183 | (setq ef-themes-region '(intense no-extend neutral)) 184 | ;; Disable all other themes to avoid awkward blending: 185 | (mapc #'disable-theme custom-enabled-themes) 186 | 187 | ;; Load the theme of choice: 188 | ;; The themes we provide are recorded in the `ef-themes-dark-themes', 189 | ;; `ef-themes-light-themes'. 190 | ;; (ef-themes-select 'ef-summer) 191 | (if (display-graphic-p) 192 | (ef-themes-load-random) 193 | (ef-themes-load-random 'dark)) 194 | 195 | :config 196 | ;; auto change theme, aligning with system themes. 197 | (defun my/apply-theme (appearance) 198 | "Load theme, taking current system APPEARANCE into consideration." 199 | (mapc #'disable-theme custom-enabled-themes) 200 | (pcase appearance 201 | ('light (if (display-graphic-p) (ef-themes-load-random 'light) (ef-themes-load-random 'dark))) 202 | ('dark (ef-themes-load-random 'dark)))) 203 | 204 | (if (eq system-type 'darwin) 205 | ;; only for emacs-plus 206 | (add-hook 'ns-system-appearance-change-functions #'my/apply-theme) 207 | (ef-themes-select 'ef-summer) 208 | ) 209 | ) 210 | #+END_SRC 211 | 212 | ** 字体设置 213 | 214 | [[https://protesilaos.com/emacs/fontaine][fontaine]] 插件可以根据需要高度定制字体。 215 | 216 | #+BEGIN_QUOTE 217 | 这篇文章可以作为字体设置的参考: 218 | [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html]] 219 | #+END_QUOTE 220 | 221 | #+BEGIN_SRC emacs-lisp 222 | (use-package fontaine 223 | :ensure t 224 | :when (display-graphic-p) 225 | ;; :hook (kill-emacs . fontaine-store-latest-preset) 226 | :config 227 | (setq fontaine-latest-state-file 228 | (locate-user-emacs-file "etc/fontaine-latest-state.eld")) 229 | (setq fontaine-presets 230 | '((regular 231 | :default-height 140 232 | :default-weight regular 233 | :fixed-pitch-height 1.0 234 | :variable-pitch-height 1.0 235 | ) 236 | (large 237 | :default-height 180 238 | :default-weight normal 239 | :fixed-pitch-height 1.0 240 | :variable-pitch-height 1.05 241 | ) 242 | (t 243 | :default-family "Source Code Pro" 244 | :fixed-pitch-family "Source Code Pro" 245 | :variable-pitch-family "Source Code Pro" 246 | :italic-family "Source Code Pro" 247 | :variable-pitch-weight normal 248 | :bold-weight normal 249 | :italic-slant italic 250 | :line-spacing 0.1) 251 | )) 252 | ;; (fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular)) 253 | (fontaine-set-preset 'regular) 254 | 255 | ;; set emoji font 256 | (set-fontset-font 257 | t 258 | (if (version< emacs-version "28.1") 259 | '(#x1f300 . #x1fad0) 260 | 'emoji) 261 | (cond 262 | ((member "Noto Emoji" (font-family-list)) "Noto Emoji") 263 | ((member "Symbola" (font-family-list)) "Symbola") 264 | ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji") 265 | ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji") 266 | ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji") 267 | )) 268 | 269 | ;; set Chinese font 270 | (dolist (charset '(kana han symbol cjk-misc bopomofo)) 271 | (set-fontset-font 272 | (frame-parameter nil 'font) 273 | charset 274 | (font-spec :family 275 | (cond 276 | ((eq system-type 'darwin) 277 | (cond 278 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 279 | ((member "PingFang SC" (font-family-list)) "PingFang SC") 280 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 281 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 282 | )) 283 | ((eq system-type 'gnu/linux) 284 | (cond 285 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 286 | ((member "WenQuanYi Micro Hei" (font-family-list)) "WenQuanYi Micro Hei") 287 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 288 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 289 | )) 290 | (t 291 | (cond 292 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 293 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 294 | ))) 295 | ))) 296 | 297 | ;; set Chinese font scale 298 | (setq face-font-rescale-alist `( 299 | ("Symbola" . 1.3) 300 | ("Microsoft YaHei" . 1.2) 301 | ("WenQuanYi Zen Hei" . 1.2) 302 | ("Sarasa Mono SC Nerd" . 1.2) 303 | ("PingFang SC" . 1.16) 304 | ("Lantinghei SC" . 1.16) 305 | ("Kaiti SC" . 1.16) 306 | ("Yuanti SC" . 1.16) 307 | ("Apple Color Emoji" . 0.91) 308 | )) 309 | ) 310 | #+END_SRC 311 | 312 | #+CAPTION: 测试中英文字体对齐 313 | #+NAME: 测试中英文字体对齐 314 | | 中文 | | 315 | | abcd | | 316 | 317 | ** 窗口设置 318 | *** 调整启动窗口大小 319 | 在Mac下,我的默认启动窗口大小 320 | #+BEGIN_SRC emacs-lisp 321 | ;; 设置窗口大小,仅仅在图形界面需要设置 322 | (when (display-graphic-p) 323 | (let ((top 0) ; 顶不留空 324 | (left (/ (x-display-pixel-width) 10)) ; 左边空10% 325 | (height (round (* 0.8 ; 窗体高度为0.8倍的显示高度 326 | (/ (x-display-pixel-height) 327 | (frame-char-height)))))) 328 | (let ((width (round (* 2.5 height)))) ; 窗体宽度为2.5倍高度 329 | (setq default-frame-alist nil) 330 | (add-to-list 'default-frame-alist (cons 'top top)) 331 | (add-to-list 'default-frame-alist (cons 'left left)) 332 | (add-to-list 'default-frame-alist (cons 'height height)) 333 | (add-to-list 'default-frame-alist (cons 'width width))))) 334 | #+END_SRC 335 | 336 | ** 其他UI零散设置项 337 | 338 | #+begin_src emacs-lisp 339 | ;; 禁用一些GUI特性 340 | (setq use-dialog-box nil) ; 鼠标操作不使用对话框 341 | (setq inhibit-default-init t) ; 不加载 `default' 库 342 | (setq inhibit-startup-screen t) ; 不加载启动画面 343 | (setq inhibit-startup-message t) ; 不加载启动消息 344 | (setq inhibit-startup-buffer-menu t) ; 不显示缓冲区列表 345 | 346 | ;; 草稿缓冲区默认文字设置 347 | (setq initial-scratch-message (concat ";; Happy hacking, " 348 | (capitalize user-login-name) " - Emacs ♥ you!\n\n")) 349 | 350 | ;; 设置缓冲区的文字方向为从左到右 351 | (setq bidi-paragraph-direction 'left-to-right) 352 | ;; 禁止使用双向括号算法 353 | ;; (setq bidi-inhibit-bpa t) 354 | 355 | ;; 设置自动折行宽度为80个字符,默认值为70 356 | (setq-default fill-column 80) 357 | 358 | ;; 设置大文件阈值为100MB,默认10MB 359 | (setq large-file-warning-threshold 100000000) 360 | 361 | ;; 以16进制显示字节数 362 | (setq display-raw-bytes-as-hex t) 363 | ;; 有输入时禁止 `fontification' 相关的函数钩子,能让滚动更顺滑 364 | (setq redisplay-skip-fontification-on-input t) 365 | 366 | ;; 禁止响铃 367 | (setq ring-bell-function 'ignore) 368 | 369 | ;; 禁止闪烁光标 370 | (blink-cursor-mode -1) 371 | 372 | ;; 在光标处而非鼠标所在位置粘贴 373 | (setq mouse-yank-at-point t) 374 | 375 | ;; 拷贝粘贴设置 376 | (setq select-enable-primary nil) ; 选择文字时不拷贝 377 | (setq select-enable-clipboard t) ; 拷贝时使用剪贴板 378 | 379 | ;; 鼠标滚动设置 380 | (setq scroll-step 2) 381 | (setq scroll-margin 2) 382 | (setq hscroll-step 2) 383 | (setq hscroll-margin 2) 384 | (setq scroll-conservatively 101) 385 | (setq scroll-up-aggressively 0.01) 386 | (setq scroll-down-aggressively 0.01) 387 | (setq scroll-preserve-screen-position 'always) 388 | 389 | ;; 对于高的行禁止自动垂直滚动 390 | (setq auto-window-vscroll nil) 391 | 392 | ;; 设置新分屏打开的位置的阈值 393 | (setq split-width-threshold (assoc-default 'width default-frame-alist)) 394 | (setq split-height-threshold nil) 395 | 396 | ;; TAB键设置,在Emacs里不使用TAB键,所有的TAB默认为4个空格 397 | (setq-default indent-tabs-mode nil) 398 | (setq-default tab-width 4) 399 | 400 | ;; yes或no提示设置,通过下面这个函数设置当缓冲区名字匹配到预设的字符串时自动回答yes 401 | (setq original-y-or-n-p 'y-or-n-p) 402 | (defalias 'original-y-or-n-p (symbol-function 'y-or-n-p)) 403 | (defun default-yes-sometimes (prompt) 404 | "automatically say y when buffer name match following string" 405 | (if (or 406 | (string-match "has a running process" prompt) 407 | (string-match "does not exist; create" prompt) 408 | (string-match "modified; kill anyway" prompt) 409 | (string-match "Delete buffer using" prompt) 410 | (string-match "Kill buffer of" prompt) 411 | (string-match "still connected. Kill it?" prompt) 412 | (string-match "Shutdown the client's kernel" prompt) 413 | (string-match "kill them and exit anyway" prompt) 414 | (string-match "Revert buffer from file" prompt) 415 | (string-match "Kill Dired buffer of" prompt) 416 | (string-match "delete buffer using" prompt) 417 | (string-match "Kill all pass entry" prompt) 418 | (string-match "for all cursors" prompt) 419 | (string-match "Do you want edit the entry" prompt)) 420 | t 421 | (original-y-or-n-p prompt))) 422 | (defalias 'yes-or-no-p 'default-yes-sometimes) 423 | (defalias 'y-or-n-p 'default-yes-sometimes) 424 | 425 | ;; 设置剪贴板历史长度300,默认为60 426 | (setq kill-ring-max 200) 427 | 428 | ;; 在剪贴板里不存储重复内容 429 | (setq kill-do-not-save-duplicates t) 430 | 431 | ;; 设置位置记录长度为6,默认为16 432 | ;; 可以使用 `counsel-mark-ring' or `consult-mark' (C-x j) 来访问光标位置记录 433 | ;; 使用 C-x C-SPC 执行 `pop-global-mark' 直接跳转到上一个全局位置处 434 | ;; 使用 C-u C-SPC 跳转到本地位置处 435 | (setq mark-ring-max 6) 436 | (setq global-mark-ring-max 6) 437 | 438 | ;; 设置 emacs-lisp 的限制 439 | (setq max-lisp-eval-depth 10000) ; 默认值为 800 440 | (setq max-specpdl-size 10000) ; 默认值为 1600 441 | 442 | ;; 启用 `list-timers', `list-threads' 这两个命令 443 | (put 'list-timers 'disabled nil) 444 | (put 'list-threads 'disabled nil) 445 | 446 | ;; 在命令行里支持鼠标 447 | (xterm-mouse-mode 1) 448 | 449 | ;; 退出Emacs时进行确认 450 | (setq confirm-kill-emacs 'y-or-n-p) 451 | 452 | ;; 在模式栏上显示当前光标的列号 453 | (column-number-mode t) 454 | #+end_src 455 | 456 | ** 编码设置 457 | 458 | 统一使用 UTF-8 编码。 459 | 460 | #+begin_src emacs-lisp 461 | ;; 配置所有的编码为UTF-8,参考: 462 | ;; https://thraxys.wordpress.com/2016/01/13/utf-8-in-emacs-everywhere-forever/ 463 | (setq locale-coding-system 'utf-8) 464 | (set-terminal-coding-system 'utf-8) 465 | (set-keyboard-coding-system 'utf-8) 466 | (set-selection-coding-system 'utf-8) 467 | (set-default-coding-systems 'utf-8) 468 | (set-language-environment 'utf-8) 469 | (set-clipboard-coding-system 'utf-8) 470 | (set-file-name-coding-system 'utf-8) 471 | (set-buffer-file-coding-system 'utf-8) 472 | (prefer-coding-system 'utf-8) 473 | (modify-coding-system-alist 'process "*" 'utf-8) 474 | (when (display-graphic-p) 475 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) 476 | #+end_src 477 | 478 | ** 模式栏设置 479 | *** doom-modeline插件 480 | 481 | [[https://github.com/seagle0128/doom-modeline][doom-modeline]] 是一个模式栏美化插件。 482 | 483 | #+begin_src emacs-lisp 484 | (use-package doom-modeline 485 | :ensure t 486 | :hook (after-init . doom-modeline-mode) 487 | :custom 488 | (doom-modeline-irc nil) 489 | (doom-modeline-mu4e nil) 490 | (doom-modeline-gnus nil) 491 | (doom-modeline-github nil) 492 | (doom-modeline-buffer-file-name-style 'truncate-upto-root) ; : auto 493 | (doom-modeline-persp-name nil) 494 | (doom-modeline-unicode-fallback t) 495 | (doom-modeline-enable-word-count nil)) 496 | #+end_src 497 | 498 | *** minions插件 499 | [[https://github.com/tarsius/minions][minions]] 插件能让模式栏变得清爽,将次要模式隐藏起来。 500 | 501 | #+BEGIN_SRC emacs-lisp 502 | (use-package minions 503 | :ensure t 504 | :hook (after-init . minions-mode)) 505 | #+END_SRC 506 | 507 | *** keycast按键展示 508 | [[https://github.com/tarsius/keycast][keycast mode]] 插件可以在模式栏上展示所有的按键,以及对应的函数。 509 | 510 | #+BEGIN_SRC emacs-lisp 511 | (use-package keycast 512 | :ensure t 513 | :hook (after-init . keycast-mode) 514 | :config 515 | ;; set for doom-modeline support 516 | ;; With the latest change 72d9add, mode-line-keycast needs to be modified to keycast-mode-line. 517 | (define-minor-mode keycast-mode 518 | "Show current command and its key binding in the mode line (fix for use with doom-mode-line)." 519 | :global t 520 | (if keycast-mode 521 | (progn 522 | (add-hook 'pre-command-hook 'keycast--update t) 523 | (add-to-list 'global-mode-string '("" keycast-mode-line " "))) 524 | (remove-hook 'pre-command-hook 'keycast--update) 525 | (setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string)) 526 | )) 527 | 528 | (dolist (input '(self-insert-command 529 | org-self-insert-command)) 530 | (add-to-list 'keycast-substitute-alist `(,input "." "Typing…"))) 531 | 532 | (dolist (event '(mouse-event-p 533 | mouse-movement-p 534 | mwheel-scroll)) 535 | (add-to-list 'keycast-substitute-alist `(,event nil))) 536 | 537 | (setq keycast-log-format "%-20K%C\n") 538 | (setq keycast-log-frame-alist 539 | '((minibuffer . nil))) 540 | (setq keycast-log-newest-first t) 541 | ) 542 | #+END_SRC 543 | 544 | ** init-ui.el 文件尾 545 | #+BEGIN_SRC emacs-lisp 546 | 547 | (provide 'init-ui) 548 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 549 | ;;; init-ui.el ends here 550 | #+END_SRC 551 | -------------------------------------------------------------------------------- /config-mirror/emacs-config-l6.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Emacs配置文件 2 | #+SUBTITLE: 面向产品经理的Emacs教程 3 | #+AUTHOR: Randolph 4 | #+DATE: 2022/12/22 14:23:50 5 | 6 | #+STARTUP: overview 7 | 8 | * early-init.el 9 | :PROPERTIES: 10 | :HEADER-ARGS: :tangle early-init.el 11 | :END: 12 | 13 | 在Emacs刚启动,还未加载主要配置文件时的配置文件。 14 | 15 | #+BEGIN_SRC emacs-lisp 16 | ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*- 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | ;; 设置垃圾回收参数 22 | (setq gc-cons-threshold most-positive-fixnum) 23 | (setq gc-cons-percentage 0.6) 24 | 25 | ;; 启动早期不加载`package.el'包管理器 26 | (setq package-enable-at-startup nil) 27 | ;; 不从包缓存中加载 28 | (setq package-quickstart nil) 29 | 30 | ;; 禁止展示菜单栏、工具栏和纵向滚动条 31 | (push '(menu-bar-lines . 0) default-frame-alist) 32 | (push '(tool-bar-lines . 0) default-frame-alist) 33 | (push '(vertical-scroll-bars) default-frame-alist) 34 | 35 | ;; 禁止自动缩放窗口先 36 | (setq frame-inhibit-implied-resize t) 37 | 38 | ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框 39 | (menu-bar-mode -1) 40 | (tool-bar-mode -1) 41 | (scroll-bar-mode -1) 42 | (setq inhibit-splash-screen t) 43 | (setq use-file-dialog nil) 44 | 45 | ;; 在这个阶段不编译 46 | (setq comp-deferred-compilation nil) 47 | 48 | (provide 'early-init) 49 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 50 | ;;; early-init.el ends here 51 | #+END_SRC 52 | 53 | * init.el 54 | :PROPERTIES: 55 | :HEADER-ARGS: :tangle init.el 56 | :END: 57 | 58 | =init.el= 是Emacs的主要配置文件。 59 | 60 | ** init.el 文件头 61 | #+BEGIN_SRC emacs-lisp 62 | ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*- 63 | ;;; Commentary: 64 | 65 | ;;; Code: 66 | 67 | #+END_SRC 68 | 69 | ** package包管理配置 70 | #+begin_src emacs-lisp 71 | (require 'package) 72 | (setq package-archives 73 | '(("melpa" . "https://melpa.org/packages/") 74 | ("gnu" . "https://elpa.gnu.org/packages/") 75 | ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) 76 | 77 | (package-initialize) 78 | #+end_src 79 | 80 | ** 安装use-package插件 81 | [[https://github.com/jwiegley/use-package][use-package]] 是一个让Emacs配置更加结构化更加清晰的一个宏插件。 82 | 83 | #+begin_src emacs-lisp 84 | ;; 安装 `use-package' 85 | (unless (package-installed-p 'use-package) 86 | (package-refresh-contents) 87 | (package-install 'use-package)) 88 | 89 | ;; 配置 `use-package' 90 | (eval-and-compile 91 | (setq use-package-always-ensure nil) 92 | (setq use-package-always-defer nil) 93 | (setq use-package-expand-minimally nil) 94 | (setq use-package-enable-imenu-support t) 95 | (if (daemonp) 96 | (setq use-package-always-demand t))) 97 | 98 | (eval-when-compile 99 | (require 'use-package)) 100 | 101 | ;; 安装 `use-package' 的集成模块 102 | (use-package use-package-ensure-system-package 103 | :ensure t) 104 | (use-package diminish 105 | :ensure t) 106 | (use-package bind-key 107 | :ensure t) 108 | #+end_src 109 | 110 | ** quelpa包管理器 111 | [[https://github.com/quelpa/quelpa][quelpa]] 是配合 =package.el= 使用的,基于git的一个包管理器。 112 | #+BEGIN_SRC emacs-lisp 113 | ;; 安装 `quelpa' 114 | (use-package quelpa 115 | :ensure t 116 | :commands quelpa 117 | :config 118 | :custom 119 | (quelpa-git-clone-depth 1) 120 | (quelpa-update-melpa-p nil) 121 | (quelpa-self-upgrade-p nil) 122 | (quelpa-checkout-melpa-p nil)) 123 | 124 | ;; `quelpa' 与 `use-package' 集成 125 | (use-package quelpa-use-package 126 | :ensure t) 127 | #+END_SRC 128 | 129 | ** 加载模块化配置 130 | 131 | #+BEGIN_SRC emacs-lisp 132 | ;; 将lisp目录放到加载路径的前面以加快启动速度 133 | (let ((dir (locate-user-emacs-file "lisp"))) 134 | (add-to-list 'load-path (file-name-as-directory dir))) 135 | 136 | ;; 加载各模块化配置 137 | ;; 不要在`*message*'缓冲区显示加载模块化配置的信息 138 | (with-temp-message "" 139 | (require 'init-ui) ; UI交互 140 | (require 'init-edit) ; 编辑行为 141 | (require 'init-org) ; org相关设置 142 | ) 143 | #+END_SRC 144 | 145 | ** init.el 文件尾 146 | #+BEGIN_SRC emacs-lisp 147 | 148 | (provide 'init) 149 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 150 | ;;; init.el ends here 151 | #+END_SRC 152 | 153 | * init-ui.el 154 | :PROPERTIES: 155 | :HEADER-ARGS: :tangle lisp/init-ui.el :mkdirp yes 156 | :END: 157 | 158 | ** init-ui.el 文件头 159 | #+BEGIN_SRC emacs-lisp 160 | ;;; init-ui.el --- UI settings -*- lexical-binding: t -*- 161 | ;;; Commentary: 162 | 163 | ;;; Code: 164 | 165 | #+END_SRC 166 | 167 | ** ef主题 168 | 169 | [[https://protesilaos.com/emacs/ef-themes][ef themes]] 是我非常喜欢的一个主题包。 170 | 171 | #+BEGIN_SRC emacs-lisp 172 | (use-package ef-themes 173 | :ensure t 174 | :bind ("C-c t" . ef-themes-toggle) 175 | :init 176 | ;; set two specific themes and switch between them 177 | (setq ef-themes-to-toggle '(ef-summer ef-winter)) 178 | ;; set org headings and function syntax 179 | (setq ef-themes-headings 180 | '((0 . (bold 1)) 181 | (1 . (bold 1)) 182 | (2 . (rainbow bold 1)) 183 | (3 . (rainbow bold 1)) 184 | (4 . (rainbow bold 1)) 185 | (t . (rainbow bold 1)))) 186 | (setq ef-themes-region '(intense no-extend neutral)) 187 | ;; Disable all other themes to avoid awkward blending: 188 | (mapc #'disable-theme custom-enabled-themes) 189 | 190 | ;; Load the theme of choice: 191 | ;; The themes we provide are recorded in the `ef-themes-dark-themes', 192 | ;; `ef-themes-light-themes'. 193 | 194 | ;; 如果你不喜欢随机主题,也可以直接固定选择一个主题,如下: 195 | ;; (ef-themes-select 'ef-summer) 196 | 197 | ;; 随机挑选一款主题,如果是命令行打开Emacs,则随机挑选一款黑色主题 198 | (if (display-graphic-p) 199 | (ef-themes-load-random) 200 | (ef-themes-load-random 'dark)) 201 | 202 | :config 203 | ;; auto change theme, aligning with system themes. 204 | (defun my/apply-theme (appearance) 205 | "Load theme, taking current system APPEARANCE into consideration." 206 | (mapc #'disable-theme custom-enabled-themes) 207 | (pcase appearance 208 | ('light (if (display-graphic-p) (ef-themes-load-random 'light) (ef-themes-load-random 'dark))) 209 | ('dark (ef-themes-load-random 'dark)))) 210 | 211 | (if (eq system-type 'darwin) 212 | ;; only for emacs-plus 213 | (add-hook 'ns-system-appearance-change-functions #'my/apply-theme) 214 | (ef-themes-select 'ef-summer) 215 | ) 216 | ) 217 | #+END_SRC 218 | 219 | ** 字体设置 220 | 221 | [[https://protesilaos.com/emacs/fontaine][fontaine]] 插件可以根据需要高度定制字体。 222 | 223 | #+BEGIN_QUOTE 224 | 这篇文章可以作为字体设置的参考: 225 | [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html]] 226 | #+END_QUOTE 227 | 228 | #+BEGIN_SRC emacs-lisp 229 | (use-package fontaine 230 | :ensure t 231 | :when (display-graphic-p) 232 | ;; :hook (kill-emacs . fontaine-store-latest-preset) 233 | :config 234 | (setq fontaine-latest-state-file 235 | (locate-user-emacs-file "etc/fontaine-latest-state.eld")) 236 | (setq fontaine-presets 237 | '((regular 238 | :default-height 140 239 | :default-weight regular 240 | :fixed-pitch-height 1.0 241 | :variable-pitch-height 1.0 242 | ) 243 | (large 244 | :default-height 180 245 | :default-weight normal 246 | :fixed-pitch-height 1.0 247 | :variable-pitch-height 1.05 248 | ) 249 | (t 250 | :default-family "Source Code Pro" 251 | :fixed-pitch-family "Source Code Pro" 252 | :variable-pitch-family "Source Code Pro" 253 | :italic-family "Source Code Pro" 254 | :variable-pitch-weight normal 255 | :bold-weight normal 256 | :italic-slant italic 257 | :line-spacing 0.1) 258 | )) 259 | ;; (fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular)) 260 | (fontaine-set-preset 'regular) 261 | 262 | ;; set emoji font 263 | (set-fontset-font 264 | t 265 | (if (version< emacs-version "28.1") 266 | '(#x1f300 . #x1fad0) 267 | 'emoji) 268 | (cond 269 | ((member "Noto Emoji" (font-family-list)) "Noto Emoji") 270 | ((member "Symbola" (font-family-list)) "Symbola") 271 | ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji") 272 | ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji") 273 | ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji") 274 | )) 275 | 276 | ;; set Chinese font 277 | (dolist (charset '(kana han symbol cjk-misc bopomofo)) 278 | (set-fontset-font 279 | (frame-parameter nil 'font) 280 | charset 281 | (font-spec :family 282 | (cond 283 | ((eq system-type 'darwin) 284 | (cond 285 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 286 | ((member "PingFang SC" (font-family-list)) "PingFang SC") 287 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 288 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 289 | )) 290 | ((eq system-type 'gnu/linux) 291 | (cond 292 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 293 | ((member "WenQuanYi Micro Hei" (font-family-list)) "WenQuanYi Micro Hei") 294 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 295 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 296 | )) 297 | (t 298 | (cond 299 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 300 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 301 | ))) 302 | ))) 303 | 304 | ;; set Chinese font scale 305 | (setq face-font-rescale-alist `( 306 | ("Symbola" . 1.3) 307 | ("Microsoft YaHei" . 1.2) 308 | ("WenQuanYi Zen Hei" . 1.2) 309 | ("Sarasa Mono SC Nerd" . 1.2) 310 | ("PingFang SC" . 1.16) 311 | ("Lantinghei SC" . 1.16) 312 | ("Kaiti SC" . 1.16) 313 | ("Yuanti SC" . 1.16) 314 | ("Apple Color Emoji" . 0.91) 315 | )) 316 | ) 317 | #+END_SRC 318 | 319 | #+CAPTION: 测试中英文字体对齐 320 | #+NAME: 测试中英文字体对齐 321 | | 中文 | | 322 | | abcd | | 323 | 324 | ** 窗口设置 325 | *** 调整启动窗口大小 326 | 在Mac下,我的默认启动窗口大小 327 | #+BEGIN_SRC emacs-lisp 328 | ;; 设置窗口大小,仅仅在图形界面需要设置 329 | (when (display-graphic-p) 330 | (let ((top 0) ; 顶不留空 331 | (left (/ (x-display-pixel-width) 10)) ; 左边空10% 332 | (height (round (* 0.8 ; 窗体高度为0.8倍的显示高度 333 | (/ (x-display-pixel-height) 334 | (frame-char-height)))))) 335 | (let ((width (round (* 2.5 height)))) ; 窗体宽度为2.5倍高度 336 | (setq default-frame-alist nil) 337 | (add-to-list 'default-frame-alist (cons 'top top)) 338 | (add-to-list 'default-frame-alist (cons 'left left)) 339 | (add-to-list 'default-frame-alist (cons 'height height)) 340 | (add-to-list 'default-frame-alist (cons 'width width))))) 341 | #+END_SRC 342 | 343 | ** 其他UI零散设置项 344 | 345 | #+begin_src emacs-lisp 346 | ;; 禁用一些GUI特性 347 | (setq use-dialog-box nil) ; 鼠标操作不使用对话框 348 | (setq inhibit-default-init t) ; 不加载 `default' 库 349 | (setq inhibit-startup-screen t) ; 不加载启动画面 350 | (setq inhibit-startup-message t) ; 不加载启动消息 351 | (setq inhibit-startup-buffer-menu t) ; 不显示缓冲区列表 352 | 353 | ;; 草稿缓冲区默认文字设置 354 | (setq initial-scratch-message (concat ";; Happy hacking, " 355 | (capitalize user-login-name) " - Emacs ♥ you!\n\n")) 356 | 357 | ;; 设置缓冲区的文字方向为从左到右 358 | (setq bidi-paragraph-direction 'left-to-right) 359 | ;; 禁止使用双向括号算法 360 | ;; (setq bidi-inhibit-bpa t) 361 | 362 | ;; 设置自动折行宽度为80个字符,默认值为70 363 | (setq-default fill-column 80) 364 | 365 | ;; 设置大文件阈值为100MB,默认10MB 366 | (setq large-file-warning-threshold 100000000) 367 | 368 | ;; 以16进制显示字节数 369 | (setq display-raw-bytes-as-hex t) 370 | ;; 有输入时禁止 `fontification' 相关的函数钩子,能让滚动更顺滑 371 | (setq redisplay-skip-fontification-on-input t) 372 | 373 | ;; 禁止响铃 374 | (setq ring-bell-function 'ignore) 375 | 376 | ;; 禁止闪烁光标 377 | (blink-cursor-mode -1) 378 | 379 | ;; 在光标处而非鼠标所在位置粘贴 380 | (setq mouse-yank-at-point t) 381 | 382 | ;; 拷贝粘贴设置 383 | (setq select-enable-primary nil) ; 选择文字时不拷贝 384 | (setq select-enable-clipboard t) ; 拷贝时使用剪贴板 385 | 386 | ;; 鼠标滚动设置 387 | (setq scroll-step 2) 388 | (setq scroll-margin 2) 389 | (setq hscroll-step 2) 390 | (setq hscroll-margin 2) 391 | (setq scroll-conservatively 101) 392 | (setq scroll-up-aggressively 0.01) 393 | (setq scroll-down-aggressively 0.01) 394 | (setq scroll-preserve-screen-position 'always) 395 | 396 | ;; 对于高的行禁止自动垂直滚动 397 | (setq auto-window-vscroll nil) 398 | 399 | ;; 设置新分屏打开的位置的阈值 400 | (setq split-width-threshold (assoc-default 'width default-frame-alist)) 401 | (setq split-height-threshold nil) 402 | 403 | ;; TAB键设置,在Emacs里不使用TAB键,所有的TAB默认为4个空格 404 | (setq-default indent-tabs-mode nil) 405 | (setq-default tab-width 4) 406 | 407 | ;; yes或no提示设置,通过下面这个函数设置当缓冲区名字匹配到预设的字符串时自动回答yes 408 | (setq original-y-or-n-p 'y-or-n-p) 409 | (defalias 'original-y-or-n-p (symbol-function 'y-or-n-p)) 410 | (defun default-yes-sometimes (prompt) 411 | "automatically say y when buffer name match following string" 412 | (if (or 413 | (string-match "has a running process" prompt) 414 | (string-match "does not exist; create" prompt) 415 | (string-match "modified; kill anyway" prompt) 416 | (string-match "Delete buffer using" prompt) 417 | (string-match "Kill buffer of" prompt) 418 | (string-match "still connected. Kill it?" prompt) 419 | (string-match "Shutdown the client's kernel" prompt) 420 | (string-match "kill them and exit anyway" prompt) 421 | (string-match "Revert buffer from file" prompt) 422 | (string-match "Kill Dired buffer of" prompt) 423 | (string-match "delete buffer using" prompt) 424 | (string-match "Kill all pass entry" prompt) 425 | (string-match "for all cursors" prompt) 426 | (string-match "Do you want edit the entry" prompt)) 427 | t 428 | (original-y-or-n-p prompt))) 429 | (defalias 'yes-or-no-p 'default-yes-sometimes) 430 | (defalias 'y-or-n-p 'default-yes-sometimes) 431 | 432 | ;; 设置剪贴板历史长度300,默认为60 433 | (setq kill-ring-max 200) 434 | 435 | ;; 在剪贴板里不存储重复内容 436 | (setq kill-do-not-save-duplicates t) 437 | 438 | ;; 设置位置记录长度为6,默认为16 439 | ;; 可以使用 `counsel-mark-ring' or `consult-mark' (C-x j) 来访问光标位置记录 440 | ;; 使用 C-x C-SPC 执行 `pop-global-mark' 直接跳转到上一个全局位置处 441 | ;; 使用 C-u C-SPC 跳转到本地位置处 442 | (setq mark-ring-max 6) 443 | (setq global-mark-ring-max 6) 444 | 445 | ;; 设置 emacs-lisp 的限制 446 | (setq max-lisp-eval-depth 10000) ; 默认值为 800 447 | (setq max-specpdl-size 10000) ; 默认值为 1600 448 | 449 | ;; 启用 `list-timers', `list-threads' 这两个命令 450 | (put 'list-timers 'disabled nil) 451 | (put 'list-threads 'disabled nil) 452 | 453 | ;; 在命令行里支持鼠标 454 | (xterm-mouse-mode 1) 455 | 456 | ;; 退出Emacs时进行确认 457 | (setq confirm-kill-emacs 'y-or-n-p) 458 | 459 | ;; 在模式栏上显示当前光标的列号 460 | (column-number-mode t) 461 | #+end_src 462 | 463 | ** 编码设置 464 | 465 | 统一使用 UTF-8 编码。 466 | 467 | #+begin_src emacs-lisp 468 | ;; 配置所有的编码为UTF-8,参考: 469 | ;; https://thraxys.wordpress.com/2016/01/13/utf-8-in-emacs-everywhere-forever/ 470 | (setq locale-coding-system 'utf-8) 471 | (set-terminal-coding-system 'utf-8) 472 | (set-keyboard-coding-system 'utf-8) 473 | (set-selection-coding-system 'utf-8) 474 | (set-default-coding-systems 'utf-8) 475 | (set-language-environment 'utf-8) 476 | (set-clipboard-coding-system 'utf-8) 477 | (set-file-name-coding-system 'utf-8) 478 | (set-buffer-file-coding-system 'utf-8) 479 | (prefer-coding-system 'utf-8) 480 | (modify-coding-system-alist 'process "*" 'utf-8) 481 | (when (display-graphic-p) 482 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) 483 | #+end_src 484 | 485 | ** 模式栏设置 486 | *** doom-modeline插件 487 | 488 | [[https://github.com/seagle0128/doom-modeline][doom-modeline]] 是一个模式栏美化插件。 489 | 490 | #+begin_src emacs-lisp 491 | (use-package doom-modeline 492 | :ensure t 493 | :hook (after-init . doom-modeline-mode) 494 | :custom 495 | (doom-modeline-irc nil) 496 | (doom-modeline-mu4e nil) 497 | (doom-modeline-gnus nil) 498 | (doom-modeline-github nil) 499 | (doom-modeline-buffer-file-name-style 'truncate-upto-root) ; : auto 500 | (doom-modeline-persp-name nil) 501 | (doom-modeline-unicode-fallback t) 502 | (doom-modeline-enable-word-count nil)) 503 | #+end_src 504 | 505 | *** minions插件 506 | [[https://github.com/tarsius/minions][minions]] 插件能让模式栏变得清爽,将次要模式隐藏起来。 507 | 508 | #+BEGIN_SRC emacs-lisp 509 | (use-package minions 510 | :ensure t 511 | :hook (after-init . minions-mode)) 512 | #+END_SRC 513 | 514 | *** keycast按键展示 515 | [[https://github.com/tarsius/keycast][keycast mode]] 插件可以在模式栏上展示所有的按键,以及对应的函数。 516 | 517 | #+BEGIN_SRC emacs-lisp 518 | (use-package keycast 519 | :ensure t 520 | :hook (after-init . keycast-mode) 521 | :config 522 | ;; set for doom-modeline support 523 | ;; With the latest change 72d9add, mode-line-keycast needs to be modified to keycast-mode-line. 524 | (define-minor-mode keycast-mode 525 | "Show current command and its key binding in the mode line (fix for use with doom-mode-line)." 526 | :global t 527 | (if keycast-mode 528 | (progn 529 | (add-hook 'pre-command-hook 'keycast--update t) 530 | (add-to-list 'global-mode-string '("" keycast-mode-line " "))) 531 | (remove-hook 'pre-command-hook 'keycast--update) 532 | (setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string)) 533 | )) 534 | 535 | (dolist (input '(self-insert-command 536 | org-self-insert-command)) 537 | (add-to-list 'keycast-substitute-alist `(,input "." "Typing…"))) 538 | 539 | (dolist (event '(mouse-event-p 540 | mouse-movement-p 541 | mwheel-scroll)) 542 | (add-to-list 'keycast-substitute-alist `(,event nil))) 543 | 544 | (setq keycast-log-format "%-20K%C\n") 545 | (setq keycast-log-frame-alist 546 | '((minibuffer . nil))) 547 | (setq keycast-log-newest-first t) 548 | ) 549 | #+END_SRC 550 | 551 | ** init-ui.el 文件尾 552 | #+BEGIN_SRC emacs-lisp 553 | 554 | (provide 'init-ui) 555 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 556 | ;;; init-ui.el ends here 557 | #+END_SRC 558 | 559 | * init-edit.el 560 | :PROPERTIES: 561 | :HEADER-ARGS: :tangle lisp/init-edit.el :mkdirp yes 562 | :END: 563 | 564 | ** init-edit.el 文件头 565 | 566 | #+BEGIN_SRC emacs-lisp 567 | ;;; init-edit.el --- Editing settings -*- lexical-binding: t -*- 568 | ;;; Commentary: 569 | 570 | ;;; Code: 571 | 572 | #+END_SRC 573 | 574 | ** Emacs备份设置 575 | 576 | 不使用Emacs的自动备份设置。 577 | 578 | #+BEGIN_SRC emacs-lisp 579 | (setq make-backup-files nil) ; 不自动备份 580 | (setq auto-save-default nil) ; 不使用Emacs自带的自动保存 581 | #+END_SRC 582 | 583 | ** 解除一些不常用的快捷键 584 | 585 | 将一些不常用的快捷键解除,防止误操作。 586 | 587 | #+BEGIN_SRC emacs-lisp 588 | ;; 解除不常用的快捷键定义 589 | (global-set-key (kbd "C-z") nil) 590 | (global-set-key (kbd "s-q") nil) 591 | (global-set-key (kbd "M-z") nil) 592 | (global-set-key (kbd "M-m") nil) 593 | (global-set-key (kbd "C-x C-z") nil) 594 | (global-set-key [mouse-2] nil) 595 | #+END_SRC 596 | 597 | ** delsel选择文本输入时直接替换 598 | 599 | Emacs默认选择文本后直接输入,是不会直接删除所选择的文本进行替换的。通过内置的 =delsel= 插件来实现这个行为。 600 | 601 | #+begin_src emacs-lisp 602 | ;; Directly modify when selecting text 603 | (use-package delsel 604 | :ensure nil 605 | :hook (after-init . delete-selection-mode)) 606 | #+end_src 607 | 608 | ** 自动重载设置 609 | 610 | 当我们的文件发生了改变后,我们希望Emacs里打开的永远是最新的文件,这个时候,我们需要对自动重载进行设置,让我们的Emacs在文件发生改变的时候自动重载文件。 611 | 612 | #+BEGIN_SRC emacs-lisp 613 | (use-package autorevert 614 | :ensure nil 615 | :hook (after-init . global-auto-revert-mode) 616 | :bind ("s-u" . revert-buffer) 617 | :custom 618 | (auto-revert-interval 10) 619 | (auto-revert-avoid-polling t) 620 | (auto-revert-verbose nil) 621 | (auto-revert-remote-files t) 622 | (auto-revert-check-vc-info t) 623 | (global-auto-revert-non-file-buffers t)) 624 | #+END_SRC 625 | 626 | ** init-edit.el 文件尾 627 | 628 | #+BEGIN_SRC emacs-lisp 629 | ;; (message "init-base configuration: %.2fs" 630 | ;; (float-time (time-subtract (current-time) my/init-base-start-time))) 631 | 632 | (provide 'init-edit) 633 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 634 | ;;; init-edit.el ends here 635 | #+END_SRC 636 | 637 | * init-org.el 638 | :PROPERTIES: 639 | :HEADER-ARGS: :tangle lisp/init-org.el :mkdirp yes 640 | :END: 641 | 642 | ** init-org.el 文件头 643 | 644 | #+BEGIN_SRC emacs-lisp 645 | ;;; init-org.el --- Org mode settings -*- lexical-binding: t -*- 646 | ;;; Commentary: 647 | 648 | ;;; Code: 649 | 650 | #+END_SRC 651 | 652 | ** org-auto-tangle自动tangle设置 653 | 654 | [[https://github.com/yilkalargaw/org-auto-tangle][org-auto-tangle]] 插件可以在Org mode下自动进行tangle。 655 | 656 | #+BEGIN_SRC emacs-lisp 657 | (use-package org-auto-tangle 658 | :ensure t 659 | :hook (org-mode . org-auto-tangle-mode) 660 | :config 661 | (setq org-auto-tangle-default t) 662 | ) 663 | #+END_SRC 664 | 665 | ** init-org.el 文件尾 666 | 667 | #+BEGIN_SRC emacs-lisp 668 | 669 | (provide 'init-org) 670 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 671 | ;;; init-org.el ends here 672 | #+END_SRC 673 | -------------------------------------------------------------------------------- /config-mirror/emacs-config-l7.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Emacs配置文件 2 | #+SUBTITLE: 面向产品经理的Emacs教程 3 | #+AUTHOR: Randolph 4 | #+DATE: 2022/12/22 14:23:50 5 | 6 | #+STARTUP: overview 7 | 8 | * early-init.el 9 | :PROPERTIES: 10 | :HEADER-ARGS: :tangle early-init.el 11 | :END: 12 | 13 | 在Emacs刚启动,还未加载主要配置文件时的配置文件。 14 | 15 | #+BEGIN_SRC emacs-lisp 16 | ;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*- 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | ;; 设置垃圾回收参数 22 | (setq gc-cons-threshold most-positive-fixnum) 23 | (setq gc-cons-percentage 0.6) 24 | 25 | ;; 启动早期不加载`package.el'包管理器 26 | (setq package-enable-at-startup nil) 27 | ;; 不从包缓存中加载 28 | (setq package-quickstart nil) 29 | 30 | ;; 禁止展示菜单栏、工具栏和纵向滚动条 31 | (push '(menu-bar-lines . 0) default-frame-alist) 32 | (push '(tool-bar-lines . 0) default-frame-alist) 33 | (push '(vertical-scroll-bars) default-frame-alist) 34 | 35 | ;; 禁止自动缩放窗口先 36 | (setq frame-inhibit-implied-resize t) 37 | 38 | ;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框 39 | (menu-bar-mode -1) 40 | (tool-bar-mode -1) 41 | (scroll-bar-mode -1) 42 | (setq inhibit-splash-screen t) 43 | (setq use-file-dialog nil) 44 | 45 | ;; 在这个阶段不编译 46 | (setq comp-deferred-compilation nil) 47 | 48 | (provide 'early-init) 49 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 50 | ;;; early-init.el ends here 51 | #+END_SRC 52 | 53 | * init.el 54 | :PROPERTIES: 55 | :HEADER-ARGS: :tangle init.el 56 | :END: 57 | 58 | =init.el= 是Emacs的主要配置文件。 59 | 60 | ** init.el 文件头 61 | #+BEGIN_SRC emacs-lisp 62 | ;;; init.el --- The main init entry for Emacs -*- lexical-binding: t -*- 63 | ;;; Commentary: 64 | 65 | ;;; Code: 66 | 67 | #+END_SRC 68 | 69 | ** package包管理配置 70 | #+begin_src emacs-lisp 71 | (require 'package) 72 | (setq package-archives 73 | '(("melpa" . "https://melpa.org/packages/") 74 | ("gnu" . "https://elpa.gnu.org/packages/") 75 | ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) 76 | 77 | (package-initialize) 78 | #+end_src 79 | 80 | ** 安装use-package插件 81 | [[https://github.com/jwiegley/use-package][use-package]] 是一个让Emacs配置更加结构化更加清晰的一个宏插件。 82 | 83 | #+begin_src emacs-lisp 84 | ;; 安装 `use-package' 85 | (unless (package-installed-p 'use-package) 86 | (package-refresh-contents) 87 | (package-install 'use-package)) 88 | 89 | ;; 配置 `use-package' 90 | (eval-and-compile 91 | (setq use-package-always-ensure nil) 92 | (setq use-package-always-defer nil) 93 | (setq use-package-expand-minimally nil) 94 | (setq use-package-enable-imenu-support t) 95 | (if (daemonp) 96 | (setq use-package-always-demand t))) 97 | 98 | (eval-when-compile 99 | (require 'use-package)) 100 | 101 | ;; 安装 `use-package' 的集成模块 102 | (use-package use-package-ensure-system-package 103 | :ensure t) 104 | (use-package diminish 105 | :ensure t) 106 | (use-package bind-key 107 | :ensure t) 108 | #+end_src 109 | 110 | ** quelpa包管理器 111 | [[https://github.com/quelpa/quelpa][quelpa]] 是配合 =package.el= 使用的,基于git的一个包管理器。 112 | #+BEGIN_SRC emacs-lisp 113 | ;; 安装 `quelpa' 114 | (use-package quelpa 115 | :ensure t 116 | :commands quelpa 117 | :config 118 | :custom 119 | (quelpa-git-clone-depth 1) 120 | (quelpa-update-melpa-p nil) 121 | (quelpa-self-upgrade-p nil) 122 | (quelpa-checkout-melpa-p nil)) 123 | 124 | ;; `quelpa' 与 `use-package' 集成 125 | (use-package quelpa-use-package 126 | :ensure t) 127 | #+END_SRC 128 | 129 | ** 加载模块化配置 130 | 131 | #+BEGIN_SRC emacs-lisp 132 | ;; 将lisp目录放到加载路径的前面以加快启动速度 133 | (let ((dir (locate-user-emacs-file "lisp"))) 134 | (add-to-list 'load-path (file-name-as-directory dir))) 135 | 136 | ;; 加载各模块化配置 137 | ;; 不要在`*message*'缓冲区显示加载模块化配置的信息 138 | (with-temp-message "" 139 | (require 'init-ui) ; UI交互 140 | (require 'init-edit) ; 编辑行为 141 | (require 'init-org) ; org相关设置 142 | (require 'init-completion) ; 补全系统 143 | ) 144 | #+END_SRC 145 | 146 | ** init.el 文件尾 147 | #+BEGIN_SRC emacs-lisp 148 | 149 | (provide 'init) 150 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 151 | ;;; init.el ends here 152 | #+END_SRC 153 | 154 | * init-ui.el 155 | :PROPERTIES: 156 | :HEADER-ARGS: :tangle lisp/init-ui.el :mkdirp yes 157 | :END: 158 | 159 | ** init-ui.el 文件头 160 | #+BEGIN_SRC emacs-lisp 161 | ;;; init-ui.el --- UI settings -*- lexical-binding: t -*- 162 | ;;; Commentary: 163 | 164 | ;;; Code: 165 | 166 | #+END_SRC 167 | 168 | ** ef主题 169 | 170 | [[https://protesilaos.com/emacs/ef-themes][ef themes]] 是我非常喜欢的一个主题包。 171 | 172 | #+BEGIN_SRC emacs-lisp 173 | (use-package ef-themes 174 | :ensure t 175 | :bind ("C-c t" . ef-themes-toggle) 176 | :init 177 | ;; set two specific themes and switch between them 178 | (setq ef-themes-to-toggle '(ef-summer ef-winter)) 179 | ;; set org headings and function syntax 180 | (setq ef-themes-headings 181 | '((0 . (bold 1)) 182 | (1 . (bold 1)) 183 | (2 . (rainbow bold 1)) 184 | (3 . (rainbow bold 1)) 185 | (4 . (rainbow bold 1)) 186 | (t . (rainbow bold 1)))) 187 | (setq ef-themes-region '(intense no-extend neutral)) 188 | ;; Disable all other themes to avoid awkward blending: 189 | (mapc #'disable-theme custom-enabled-themes) 190 | 191 | ;; Load the theme of choice: 192 | ;; The themes we provide are recorded in the `ef-themes-dark-themes', 193 | ;; `ef-themes-light-themes'. 194 | 195 | ;; 如果你不喜欢随机主题,也可以直接固定选择一个主题,如下: 196 | ;; (ef-themes-select 'ef-summer) 197 | 198 | ;; 随机挑选一款主题,如果是命令行打开Emacs,则随机挑选一款黑色主题 199 | (if (display-graphic-p) 200 | (ef-themes-load-random) 201 | (ef-themes-load-random 'dark)) 202 | 203 | :config 204 | ;; auto change theme, aligning with system themes. 205 | (defun my/apply-theme (appearance) 206 | "Load theme, taking current system APPEARANCE into consideration." 207 | (mapc #'disable-theme custom-enabled-themes) 208 | (pcase appearance 209 | ('light (if (display-graphic-p) (ef-themes-load-random 'light) (ef-themes-load-random 'dark))) 210 | ('dark (ef-themes-load-random 'dark)))) 211 | 212 | (if (eq system-type 'darwin) 213 | ;; only for emacs-plus 214 | (add-hook 'ns-system-appearance-change-functions #'my/apply-theme) 215 | (ef-themes-select 'ef-summer) 216 | ) 217 | ) 218 | #+END_SRC 219 | 220 | ** 字体设置 221 | 222 | [[https://protesilaos.com/emacs/fontaine][fontaine]] 插件可以根据需要高度定制字体。 223 | 224 | #+BEGIN_QUOTE 225 | 这篇文章可以作为字体设置的参考: 226 | [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html]] 227 | #+END_QUOTE 228 | 229 | #+BEGIN_SRC emacs-lisp 230 | (use-package fontaine 231 | :ensure t 232 | :when (display-graphic-p) 233 | ;; :hook (kill-emacs . fontaine-store-latest-preset) 234 | :config 235 | (setq fontaine-latest-state-file 236 | (locate-user-emacs-file "etc/fontaine-latest-state.eld")) 237 | (setq fontaine-presets 238 | '((regular 239 | :default-height 140 240 | :default-weight regular 241 | :fixed-pitch-height 1.0 242 | :variable-pitch-height 1.0 243 | ) 244 | (large 245 | :default-height 180 246 | :default-weight normal 247 | :fixed-pitch-height 1.0 248 | :variable-pitch-height 1.05 249 | ) 250 | (t 251 | :default-family "Source Code Pro" 252 | :fixed-pitch-family "Source Code Pro" 253 | :variable-pitch-family "Source Code Pro" 254 | :italic-family "Source Code Pro" 255 | :variable-pitch-weight normal 256 | :bold-weight normal 257 | :italic-slant italic 258 | :line-spacing 0.1) 259 | )) 260 | ;; (fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular)) 261 | (fontaine-set-preset 'regular) 262 | 263 | ;; set emoji font 264 | (set-fontset-font 265 | t 266 | (if (version< emacs-version "28.1") 267 | '(#x1f300 . #x1fad0) 268 | 'emoji) 269 | (cond 270 | ((member "Noto Emoji" (font-family-list)) "Noto Emoji") 271 | ((member "Symbola" (font-family-list)) "Symbola") 272 | ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji") 273 | ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji") 274 | ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji") 275 | )) 276 | 277 | ;; set Chinese font 278 | (dolist (charset '(kana han symbol cjk-misc bopomofo)) 279 | (set-fontset-font 280 | (frame-parameter nil 'font) 281 | charset 282 | (font-spec :family 283 | (cond 284 | ((eq system-type 'darwin) 285 | (cond 286 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 287 | ((member "PingFang SC" (font-family-list)) "PingFang SC") 288 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 289 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 290 | )) 291 | ((eq system-type 'gnu/linux) 292 | (cond 293 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 294 | ((member "WenQuanYi Micro Hei" (font-family-list)) "WenQuanYi Micro Hei") 295 | ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei") 296 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 297 | )) 298 | (t 299 | (cond 300 | ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd") 301 | ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei") 302 | ))) 303 | ))) 304 | 305 | ;; set Chinese font scale 306 | (setq face-font-rescale-alist `( 307 | ("Symbola" . 1.3) 308 | ("Microsoft YaHei" . 1.2) 309 | ("WenQuanYi Zen Hei" . 1.2) 310 | ("Sarasa Mono SC Nerd" . 1.2) 311 | ("PingFang SC" . 1.16) 312 | ("Lantinghei SC" . 1.16) 313 | ("Kaiti SC" . 1.16) 314 | ("Yuanti SC" . 1.16) 315 | ("Apple Color Emoji" . 0.91) 316 | )) 317 | ) 318 | #+END_SRC 319 | 320 | #+CAPTION: 测试中英文字体对齐 321 | #+NAME: 测试中英文字体对齐 322 | | 中文 | | 323 | | abcd | | 324 | 325 | ** 窗口设置 326 | *** 调整启动窗口大小 327 | 在Mac下,我的默认启动窗口大小 328 | #+BEGIN_SRC emacs-lisp 329 | ;; 设置窗口大小,仅仅在图形界面需要设置 330 | (when (display-graphic-p) 331 | (let ((top 0) ; 顶不留空 332 | (left (/ (x-display-pixel-width) 10)) ; 左边空10% 333 | (height (round (* 0.8 ; 窗体高度为0.8倍的显示高度 334 | (/ (x-display-pixel-height) 335 | (frame-char-height)))))) 336 | (let ((width (round (* 2.5 height)))) ; 窗体宽度为2.5倍高度 337 | (setq default-frame-alist nil) 338 | (add-to-list 'default-frame-alist (cons 'top top)) 339 | (add-to-list 'default-frame-alist (cons 'left left)) 340 | (add-to-list 'default-frame-alist (cons 'height height)) 341 | (add-to-list 'default-frame-alist (cons 'width width))))) 342 | #+END_SRC 343 | 344 | ** 其他UI零散设置项 345 | 346 | #+begin_src emacs-lisp 347 | ;; 禁用一些GUI特性 348 | (setq use-dialog-box nil) ; 鼠标操作不使用对话框 349 | (setq inhibit-default-init t) ; 不加载 `default' 库 350 | (setq inhibit-startup-screen t) ; 不加载启动画面 351 | (setq inhibit-startup-message t) ; 不加载启动消息 352 | (setq inhibit-startup-buffer-menu t) ; 不显示缓冲区列表 353 | 354 | ;; 草稿缓冲区默认文字设置 355 | (setq initial-scratch-message (concat ";; Happy hacking, " 356 | (capitalize user-login-name) " - Emacs ♥ you!\n\n")) 357 | 358 | ;; 设置缓冲区的文字方向为从左到右 359 | (setq bidi-paragraph-direction 'left-to-right) 360 | ;; 禁止使用双向括号算法 361 | ;; (setq bidi-inhibit-bpa t) 362 | 363 | ;; 设置自动折行宽度为80个字符,默认值为70 364 | (setq-default fill-column 80) 365 | 366 | ;; 设置大文件阈值为100MB,默认10MB 367 | (setq large-file-warning-threshold 100000000) 368 | 369 | ;; 以16进制显示字节数 370 | (setq display-raw-bytes-as-hex t) 371 | ;; 有输入时禁止 `fontification' 相关的函数钩子,能让滚动更顺滑 372 | (setq redisplay-skip-fontification-on-input t) 373 | 374 | ;; 禁止响铃 375 | (setq ring-bell-function 'ignore) 376 | 377 | ;; 禁止闪烁光标 378 | (blink-cursor-mode -1) 379 | 380 | ;; 在光标处而非鼠标所在位置粘贴 381 | (setq mouse-yank-at-point t) 382 | 383 | ;; 拷贝粘贴设置 384 | (setq select-enable-primary nil) ; 选择文字时不拷贝 385 | (setq select-enable-clipboard t) ; 拷贝时使用剪贴板 386 | 387 | ;; 鼠标滚动设置 388 | (setq scroll-step 2) 389 | (setq scroll-margin 2) 390 | (setq hscroll-step 2) 391 | (setq hscroll-margin 2) 392 | (setq scroll-conservatively 101) 393 | (setq scroll-up-aggressively 0.01) 394 | (setq scroll-down-aggressively 0.01) 395 | (setq scroll-preserve-screen-position 'always) 396 | 397 | ;; 对于高的行禁止自动垂直滚动 398 | (setq auto-window-vscroll nil) 399 | 400 | ;; 设置新分屏打开的位置的阈值 401 | (setq split-width-threshold (assoc-default 'width default-frame-alist)) 402 | (setq split-height-threshold nil) 403 | 404 | ;; TAB键设置,在Emacs里不使用TAB键,所有的TAB默认为4个空格 405 | (setq-default indent-tabs-mode nil) 406 | (setq-default tab-width 4) 407 | 408 | ;; yes或no提示设置,通过下面这个函数设置当缓冲区名字匹配到预设的字符串时自动回答yes 409 | (setq original-y-or-n-p 'y-or-n-p) 410 | (defalias 'original-y-or-n-p (symbol-function 'y-or-n-p)) 411 | (defun default-yes-sometimes (prompt) 412 | "automatically say y when buffer name match following string" 413 | (if (or 414 | (string-match "has a running process" prompt) 415 | (string-match "does not exist; create" prompt) 416 | (string-match "modified; kill anyway" prompt) 417 | (string-match "Delete buffer using" prompt) 418 | (string-match "Kill buffer of" prompt) 419 | (string-match "still connected. Kill it?" prompt) 420 | (string-match "Shutdown the client's kernel" prompt) 421 | (string-match "kill them and exit anyway" prompt) 422 | (string-match "Revert buffer from file" prompt) 423 | (string-match "Kill Dired buffer of" prompt) 424 | (string-match "delete buffer using" prompt) 425 | (string-match "Kill all pass entry" prompt) 426 | (string-match "for all cursors" prompt) 427 | (string-match "Do you want edit the entry" prompt)) 428 | t 429 | (original-y-or-n-p prompt))) 430 | (defalias 'yes-or-no-p 'default-yes-sometimes) 431 | (defalias 'y-or-n-p 'default-yes-sometimes) 432 | 433 | ;; 设置剪贴板历史长度300,默认为60 434 | (setq kill-ring-max 200) 435 | 436 | ;; 在剪贴板里不存储重复内容 437 | (setq kill-do-not-save-duplicates t) 438 | 439 | ;; 设置位置记录长度为6,默认为16 440 | ;; 可以使用 `counsel-mark-ring' or `consult-mark' (C-x j) 来访问光标位置记录 441 | ;; 使用 C-x C-SPC 执行 `pop-global-mark' 直接跳转到上一个全局位置处 442 | ;; 使用 C-u C-SPC 跳转到本地位置处 443 | (setq mark-ring-max 6) 444 | (setq global-mark-ring-max 6) 445 | 446 | ;; 设置 emacs-lisp 的限制 447 | (setq max-lisp-eval-depth 10000) ; 默认值为 800 448 | (setq max-specpdl-size 10000) ; 默认值为 1600 449 | 450 | ;; 启用 `list-timers', `list-threads' 这两个命令 451 | (put 'list-timers 'disabled nil) 452 | (put 'list-threads 'disabled nil) 453 | 454 | ;; 在命令行里支持鼠标 455 | (xterm-mouse-mode 1) 456 | 457 | ;; 退出Emacs时进行确认 458 | (setq confirm-kill-emacs 'y-or-n-p) 459 | 460 | ;; 在模式栏上显示当前光标的列号 461 | (column-number-mode t) 462 | #+end_src 463 | 464 | ** 编码设置 465 | 466 | 统一使用 UTF-8 编码。 467 | 468 | #+begin_src emacs-lisp 469 | ;; 配置所有的编码为UTF-8,参考: 470 | ;; https://thraxys.wordpress.com/2016/01/13/utf-8-in-emacs-everywhere-forever/ 471 | (setq locale-coding-system 'utf-8) 472 | (set-terminal-coding-system 'utf-8) 473 | (set-keyboard-coding-system 'utf-8) 474 | (set-selection-coding-system 'utf-8) 475 | (set-default-coding-systems 'utf-8) 476 | (set-language-environment 'utf-8) 477 | (set-clipboard-coding-system 'utf-8) 478 | (set-file-name-coding-system 'utf-8) 479 | (set-buffer-file-coding-system 'utf-8) 480 | (prefer-coding-system 'utf-8) 481 | (modify-coding-system-alist 'process "*" 'utf-8) 482 | (when (display-graphic-p) 483 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) 484 | #+end_src 485 | 486 | ** 模式栏设置 487 | *** doom-modeline插件 488 | 489 | [[https://github.com/seagle0128/doom-modeline][doom-modeline]] 是一个模式栏美化插件。 490 | 491 | #+begin_src emacs-lisp 492 | (use-package doom-modeline 493 | :ensure t 494 | :hook (after-init . doom-modeline-mode) 495 | :custom 496 | (doom-modeline-irc nil) 497 | (doom-modeline-mu4e nil) 498 | (doom-modeline-gnus nil) 499 | (doom-modeline-github nil) 500 | (doom-modeline-buffer-file-name-style 'truncate-upto-root) ; : auto 501 | (doom-modeline-persp-name nil) 502 | (doom-modeline-unicode-fallback t) 503 | (doom-modeline-enable-word-count nil)) 504 | #+end_src 505 | 506 | *** minions插件 507 | [[https://github.com/tarsius/minions][minions]] 插件能让模式栏变得清爽,将次要模式隐藏起来。 508 | 509 | #+BEGIN_SRC emacs-lisp 510 | (use-package minions 511 | :ensure t 512 | :hook (after-init . minions-mode)) 513 | #+END_SRC 514 | 515 | *** keycast按键展示 516 | [[https://github.com/tarsius/keycast][keycast mode]] 插件可以在模式栏上展示所有的按键,以及对应的函数。 517 | 518 | #+BEGIN_SRC emacs-lisp 519 | (use-package keycast 520 | :ensure t 521 | :hook (after-init . keycast-mode) 522 | :config 523 | ;; set for doom-modeline support 524 | ;; With the latest change 72d9add, mode-line-keycast needs to be modified to keycast-mode-line. 525 | (define-minor-mode keycast-mode 526 | "Show current command and its key binding in the mode line (fix for use with doom-mode-line)." 527 | :global t 528 | (if keycast-mode 529 | (progn 530 | (add-hook 'pre-command-hook 'keycast--update t) 531 | (add-to-list 'global-mode-string '("" keycast-mode-line " "))) 532 | (remove-hook 'pre-command-hook 'keycast--update) 533 | (setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string)) 534 | )) 535 | 536 | (dolist (input '(self-insert-command 537 | org-self-insert-command)) 538 | (add-to-list 'keycast-substitute-alist `(,input "." "Typing…"))) 539 | 540 | (dolist (event '(mouse-event-p 541 | mouse-movement-p 542 | mwheel-scroll)) 543 | (add-to-list 'keycast-substitute-alist `(,event nil))) 544 | 545 | (setq keycast-log-format "%-20K%C\n") 546 | (setq keycast-log-frame-alist 547 | '((minibuffer . nil))) 548 | (setq keycast-log-newest-first t) 549 | ) 550 | #+END_SRC 551 | 552 | ** init-ui.el 文件尾 553 | #+BEGIN_SRC emacs-lisp 554 | 555 | (provide 'init-ui) 556 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 557 | ;;; init-ui.el ends here 558 | #+END_SRC 559 | 560 | * init-edit.el 561 | :PROPERTIES: 562 | :HEADER-ARGS: :tangle lisp/init-edit.el :mkdirp yes 563 | :END: 564 | 565 | ** init-edit.el 文件头 566 | 567 | #+BEGIN_SRC emacs-lisp 568 | ;;; init-edit.el --- Editing settings -*- lexical-binding: t -*- 569 | ;;; Commentary: 570 | 571 | ;;; Code: 572 | 573 | #+END_SRC 574 | 575 | ** Emacs备份设置 576 | 577 | 不使用Emacs的自动备份设置。 578 | 579 | #+BEGIN_SRC emacs-lisp 580 | (setq make-backup-files nil) ; 不自动备份 581 | (setq auto-save-default nil) ; 不使用Emacs自带的自动保存 582 | #+END_SRC 583 | 584 | ** 解除一些不常用的快捷键 585 | 586 | 将一些不常用的快捷键解除,防止误操作。 587 | 588 | #+BEGIN_SRC emacs-lisp 589 | ;; 解除不常用的快捷键定义 590 | (global-set-key (kbd "C-z") nil) 591 | (global-set-key (kbd "s-q") nil) 592 | (global-set-key (kbd "M-z") nil) 593 | (global-set-key (kbd "M-m") nil) 594 | (global-set-key (kbd "C-x C-z") nil) 595 | (global-set-key [mouse-2] nil) 596 | #+END_SRC 597 | 598 | ** delsel选择文本输入时直接替换 599 | 600 | Emacs默认选择文本后直接输入,是不会直接删除所选择的文本进行替换的。通过内置的 =delsel= 插件来实现这个行为。 601 | 602 | #+begin_src emacs-lisp 603 | ;; Directly modify when selecting text 604 | (use-package delsel 605 | :ensure nil 606 | :hook (after-init . delete-selection-mode)) 607 | #+end_src 608 | 609 | ** 自动重载设置 610 | 611 | 当我们的文件发生了改变后,我们希望Emacs里打开的永远是最新的文件,这个时候,我们需要对自动重载进行设置,让我们的Emacs在文件发生改变的时候自动重载文件。 612 | 613 | #+BEGIN_SRC emacs-lisp 614 | (use-package autorevert 615 | :ensure nil 616 | :hook (after-init . global-auto-revert-mode) 617 | :bind ("s-u" . revert-buffer) 618 | :custom 619 | (auto-revert-interval 10) 620 | (auto-revert-avoid-polling t) 621 | (auto-revert-verbose nil) 622 | (auto-revert-remote-files t) 623 | (auto-revert-check-vc-info t) 624 | (global-auto-revert-non-file-buffers t)) 625 | #+END_SRC 626 | 627 | ** init-edit.el 文件尾 628 | 629 | #+BEGIN_SRC emacs-lisp 630 | ;; (message "init-base configuration: %.2fs" 631 | ;; (float-time (time-subtract (current-time) my/init-base-start-time))) 632 | 633 | (provide 'init-edit) 634 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 635 | ;;; init-edit.el ends here 636 | #+END_SRC 637 | 638 | * init-org.el 639 | :PROPERTIES: 640 | :HEADER-ARGS: :tangle lisp/init-org.el :mkdirp yes 641 | :END: 642 | 643 | ** init-org.el 文件头 644 | 645 | #+BEGIN_SRC emacs-lisp 646 | ;;; init-org.el --- Org mode settings -*- lexical-binding: t -*- 647 | ;;; Commentary: 648 | 649 | ;;; Code: 650 | 651 | #+END_SRC 652 | 653 | ** org-auto-tangle自动tangle设置 654 | 655 | [[https://github.com/yilkalargaw/org-auto-tangle][org-auto-tangle]] 插件可以在Org mode下自动进行tangle。 656 | 657 | #+BEGIN_SRC emacs-lisp 658 | (use-package org-auto-tangle 659 | :ensure t 660 | :hook (org-mode . org-auto-tangle-mode) 661 | :config 662 | (setq org-auto-tangle-default t) 663 | ) 664 | #+END_SRC 665 | 666 | ** init-org.el 文件尾 667 | 668 | #+BEGIN_SRC emacs-lisp 669 | 670 | (provide 'init-org) 671 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 672 | ;;; init-org.el ends here 673 | #+END_SRC 674 | 675 | * init-completion.el 676 | :PROPERTIES: 677 | :HEADER-ARGS: :tangle lisp/init-completion.el :mkdirp yes 678 | :END: 679 | 680 | Emacs的补全设置。 681 | 682 | ** init-completion.el 文件头 683 | #+BEGIN_SRC emacs-lisp 684 | ;;; init-completion.el --- Completion settings -*- lexical-binding: t -*- 685 | ;;; Commentary: 686 | 687 | ;;; Code: 688 | 689 | #+END_SRC 690 | 691 | ** vertico 692 | 693 | [[https://github.com/minad/vertico][vertico]] 插件提供了一个垂直样式的补全系统。 694 | 695 | #+BEGIN_SRC emacs-lisp 696 | (use-package vertico 697 | :ensure t 698 | :hook (after-init . vertico-mode) 699 | :bind (:map minibuffer-local-map 700 | ("M-" . my/minibuffer-backward-kill) 701 | :map vertico-map 702 | ("M-q" . vertico-quick-insert)) ; use C-g to exit 703 | :config 704 | (defun my/minibuffer-backward-kill (arg) 705 | "When minibuffer is completing a file name delete up to parent 706 | folder, otherwise delete a word" 707 | (interactive "p") 708 | (if minibuffer-completing-file-name 709 | ;; Borrowed from https://github.com/raxod502/selectrum/issues/498#issuecomment-803283608 710 | (if (string-match-p "/." (minibuffer-contents)) 711 | (zap-up-to-char (- arg) ?/) 712 | (delete-minibuffer-contents)) 713 | (backward-kill-word arg))) 714 | 715 | ;; Do not allow the cursor in the minibuffer prompt 716 | (setq minibuffer-prompt-properties 717 | '(read-only t cursor-intangible t face minibuffer-prompt)) 718 | (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) 719 | 720 | (setq vertico-cycle t) ; cycle from last to first 721 | :custom 722 | (vertico-count 15) ; number of candidates to display, default is 10 723 | ) 724 | #+END_SRC 725 | 726 | ** orderless 727 | 728 | [[https://github.com/oantolin/orderless][oderless]] 插件提供一种无序的补全新姿势,将一个搜索的范式变成数个以空格分隔的部分,各部分之间没有顺序,你要做的就是根据记忆输入关键词、空格、关键词。 729 | 730 | #+BEGIN_SRC emacs-lisp 731 | ;; support Pinyin first character match for orderless, avy etc. 732 | (use-package pinyinlib 733 | :ensure t) 734 | 735 | ;; orderless 是一种哲学思想 736 | (use-package orderless 737 | :ensure t 738 | :init 739 | (setq completion-styles '(orderless partial-completion basic)) 740 | (setq orderless-component-separator "[ &]") ; & is for company because space will break completion 741 | (setq completion-category-defaults nil) 742 | (setq completion-category-overrides nil) 743 | :config 744 | ;; make completion support pinyin, refer to 745 | ;; https://emacs-china.org/t/vertico/17913/2 746 | (defun completion--regex-pinyin (str) 747 | (orderless-regexp (pinyinlib-build-regexp-string str))) 748 | (add-to-list 'orderless-matching-styles 'completion--regex-pinyin) 749 | ) 750 | #+END_SRC 751 | 752 | ** marginalia 753 | 754 | [[https://github.com/minad/marginalia][marginalia]] 插件给迷你缓冲区的补全候选条目添加一些提示。 755 | 756 | #+BEGIN_SRC emacs-lisp 757 | ;; minibuffer helpful annotations 758 | (use-package marginalia 759 | :ensure t 760 | :hook (after-init . marginalia-mode) 761 | :custom 762 | (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))) 763 | #+END_SRC 764 | 765 | ** consult 766 | 767 | [[https://github.com/minad/consult][consult]] 插件基于Emacs自带的补全机制,提供了一系列的补全命令。 768 | 769 | #+BEGIN_QUOTE 770 | For locate on MacOS: 771 | 772 | 1. =locate= is not enabled in MacOS by default. We need to enable it via: 773 | sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist 774 | 775 | 2. Then we need to wait =locate= to build db for the whole file system. 776 | 777 | 3. If there is something wrong with updating locate db, we can update it manually via: 778 | chomd 755 ~/Library ~/Downloads ~/Documents ~/Desktop 779 | sudo /usr/libexec/locate.updatedb 780 | #+END_QUOTE 781 | 782 | #+BEGIN_SRC emacs-lisp 783 | (use-package consult 784 | :ensure t 785 | :after org 786 | :bind (([remap goto-line] . consult-goto-line) 787 | ([remap isearch-forward] . consult-line-symbol-at-point) ; my-consult-ripgrep-or-line 788 | ([remap switch-to-buffer] . consult-buffer) 789 | ([remap switch-to-buffer-other-window] . consult-buffer-other-window) 790 | ([remap switch-to-buffer-other-frame] . consult-buffer-other-frame) 791 | ([remap yank-pop] . consult-yank-pop) 792 | ([remap apropos] . consult-apropos) 793 | ([remap bookmark-jump] . consult-bookmark) 794 | ([remap goto-line] . consult-goto-line) 795 | ([remap imenu] . consult-imenu) 796 | ([remap multi-occur] . consult-multi-occur) 797 | ([remap recentf-open-files] . consult-recent-file) 798 | ("C-x j" . consult-mark) 799 | ("C-c g" . consult-ripgrep) 800 | ("C-c f" . consult-find) 801 | ("\e\ef" . consult-locate) ; need to enable locate first 802 | ("C-c n h" . my/consult-find-org-headings) 803 | :map org-mode-map 804 | ("C-c C-j" . consult-org-heading) 805 | :map minibuffer-local-map 806 | ("C-r" . consult-history) 807 | :map isearch-mode-map 808 | ("C-;" . consult-line) 809 | :map prog-mode-map 810 | ("C-c C-j" . consult-outline) 811 | ) 812 | :hook (completion-list-mode . consult-preview-at-point-mode) 813 | :init 814 | ;; Optionally configure the register formatting. This improves the register 815 | ;; preview for `consult-register', `consult-register-load', 816 | ;; `consult-register-store' and the Emacs built-ins. 817 | (setq register-preview-delay 0 818 | register-preview-function #'consult-register-format) 819 | 820 | ;; Optionally tweak the register preview window. 821 | ;; This adds thin lines, sorting and hides the mode line of the window. 822 | (advice-add #'register-preview :override #'consult-register-window) 823 | 824 | ;; Use Consult to select xref locations with preview 825 | (setq xref-show-xrefs-function #'consult-xref 826 | xref-show-definitions-function #'consult-xref) 827 | 828 | ;; MacOS locate doesn't support `--ignore-case --existing' args. 829 | (setq consult-locate-args (pcase system-type 830 | ('gnu/linux "locate --ignore-case --existing --regex") 831 | ('darwin "mdfind -name"))) 832 | :config 833 | (consult-customize 834 | consult-theme 835 | :preview-key '(:debounce 0.2 any) 836 | consult-ripgrep consult-git-grep consult-grep 837 | consult-bookmark consult-recent-file consult-xref 838 | consult--source-recent-file consult--source-project-recent-file consult--source-bookmark 839 | :preview-key (kbd "M-.")) 840 | 841 | ;; Optionally configure the narrowing key. 842 | ;; Both < and C-+ work reasonably well. 843 | (setq consult-narrow-key "<") ;; (kbd "C-+") 844 | 845 | (autoload 'projectile-project-root "projectile") 846 | (setq consult-project-root-function #'projectile-project-root) 847 | 848 | ;; Use `consult-ripgrep' instead of `consult-line' in large buffers 849 | (defun consult-line-symbol-at-point () 850 | "Consult line the synbol where the point is" 851 | (interactive) 852 | (consult-line (thing-at-point 'symbol))) 853 | ) 854 | #+END_SRC 855 | 856 | ** corfu 857 | 858 | [[https://github.com/minad/corfu][corfu]] 通过弹窗进行补全。 859 | 860 | #+BEGIN_SRC emacs-lisp 861 | (use-package corfu 862 | :ensure t 863 | :hook (after-init . global-corfu-mode) 864 | :bind 865 | (:map corfu-map 866 | ("SPC" . corfu-insert-separator) ; configure space for separator insertion 867 | ("M-q" . corfu-quick-complete) ; use C-g to exit 868 | ("TAB" . corfu-next) 869 | ([tab] . corfu-next) 870 | ("S-TAB" . corfu-previous) 871 | ([backtab] . corfu-previous)) 872 | :config 873 | ;; TAB cycle if there are only few candidates 874 | (setq completion-cycle-threshold 0) 875 | (setq tab-always-indent 'complete) 876 | 877 | (defun corfu-enable-always-in-minibuffer () 878 | "Enable Corfu in the minibuffer if Vertico/Mct are not active." 879 | (unless (or (bound-and-true-p mct--active) 880 | (bound-and-true-p vertico--input)) 881 | ;; (setq-local corfu-auto nil) Enable/disable auto completion 882 | (corfu-mode 1))) 883 | (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1) 884 | 885 | ;; enable corfu in eshell 886 | (add-hook 'eshell-mode-hook 887 | (lambda () 888 | (setq-local corfu-auto nil) 889 | (corfu-mode))) 890 | 891 | ;; For Eshell 892 | ;; =========== 893 | ;; avoid press RET twice in Eshell 894 | (defun corfu-send-shell (&rest _) 895 | "Send completion candidate when inside comint/eshell." 896 | (cond 897 | ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input)) 898 | (eshell-send-input)) 899 | ((and (derived-mode-p 'comint-mode) (fboundp 'comint-send-input)) 900 | (comint-send-input)))) 901 | 902 | (advice-add #'corfu-insert :after #'corfu-send-shell) 903 | 904 | :custom 905 | (corfu-cycle t) ;; Enable cycling for `corfu-next/previous' 906 | ) 907 | #+END_SRC 908 | 909 | *** cape 910 | 911 | [[https://github.com/minad/cape][Cape]] 提供了一系列开箱即用的补全后端,跟corfu联合使用。 912 | 913 | #+BEGIN_SRC emacs-lisp 914 | (use-package cape 915 | :ensure t 916 | :init 917 | ;; Add `completion-at-point-functions', used by `completion-at-point'. 918 | (add-to-list 'completion-at-point-functions #'cape-file) 919 | (add-to-list 'completion-at-point-functions #'cape-dabbrev) 920 | (add-to-list 'completion-at-point-functions #'cape-keyword) ; programming language keyword 921 | (add-to-list 'completion-at-point-functions #'cape-ispell) 922 | (add-to-list 'completion-at-point-functions #'cape-dict) 923 | (add-to-list 'completion-at-point-functions #'cape-symbol) ; elisp symbol 924 | (add-to-list 'completion-at-point-functions #'cape-line) 925 | 926 | :config 927 | (setq cape-dict-file (expand-file-name "etc/hunspell_dict.txt" user-emacs-directory)) 928 | 929 | ;; for Eshell: 930 | ;; =========== 931 | ;; Silence the pcomplete capf, no errors or messages! 932 | (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) 933 | 934 | ;; Ensure that pcomplete does not write to the buffer 935 | ;; and behaves as a pure `completion-at-point-function'. 936 | (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify) 937 | ) 938 | #+END_SRC 939 | 940 | ** yasnippet模板补全 941 | 942 | [[https://github.com/joaotavora/yasnippet][yasnippet]] 插件是一个非常强大的模板补全系统。 943 | 944 | #+begin_src emacs-lisp 945 | ;; yasnippet settings 946 | (use-package yasnippet 947 | :ensure t 948 | :diminish yas-minor-mode 949 | :hook ((after-init . yas-reload-all) 950 | ((prog-mode LaTeX-mode org-mode) . yas-minor-mode)) 951 | :config 952 | ;; Suppress warning for yasnippet code. 953 | (require 'warnings) 954 | (add-to-list 'warning-suppress-types '(yasnippet backquote-change)) 955 | 956 | (setq yas-prompt-functions '(yas-x-prompt yas-dropdown-prompt)) 957 | (defun smarter-yas-expand-next-field () 958 | "Try to `yas-expand' then `yas-next-field' at current cursor position." 959 | (interactive) 960 | (let ((old-point (point)) 961 | (old-tick (buffer-chars-modified-tick))) 962 | (yas-expand) 963 | (when (and (eq old-point (point)) 964 | (eq old-tick (buffer-chars-modified-tick))) 965 | (ignore-errors (yas-next-field)))))) 966 | #+end_src 967 | 968 | ** init-completion.el 文件尾 969 | #+BEGIN_SRC emacs-lisp 970 | 971 | (provide 'init-completion) 972 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 973 | ;;; init-completion.el ends here 974 | #+END_SRC 975 | 976 | --------------------------------------------------------------------------------