时间轴
时间轴
2025-01-12
init
2025-10-17
add clang-format
2025-12-03
modify indent style
2025-12-15
add desktop-save-mode, add ibuffer, add magit
本文介绍了作者在Windows Terminal与WSL2环境下配置Emacs的完整过程,包括安装clang-format、ibuffer、magit等插件,并启用desktop-save-mode。文章详细说明了Windows Terminal的配色方案(GitHub-Dark-Default)、字体(FiraCode Nerd Font)、背景透明度及亚克力材料设置,以及安装win32yank.exe以支持剪贴板。同时针对Arch Linux和Ubuntu20.04给出了软件包安装与换源建议。文章重点以表格形式列举了丰富的快捷键配置,涵盖窗口尺寸调整、Tab切换、行移动、错误导航、LSP代码修复与跳转、文件浏览、magit状态、代码格式化等功能,展示了通过LSP实现高效代码编辑与导航的配置思路。
环境
使用 Windows Terminal + WSL2

配置
Windows Terminal
Windows Terminal 中打开设置,选择打开 JSON 文件,在 schemes 中添加配色方案
123456789101112131415161718192021222324252627 | "schemes": [ { "background": "#0D1117", "black": "#484F58", "blue": "#58A6FF", "brightBlack": "#6E7681", "brightBlue": "#79C0FF", "brightCyan": "#56D4DD", "brightGreen": "#56D364", "brightPurple": "#D2A8FF", "brightRed": "#FFA198", "brightWhite": "#FFFFFF", "brightYellow": "#E3B341", "cursorColor": "#2F81F7", "cyan": "#39C5CF", "foreground": "#E6EDF3", "green": "#3FB950", "name": "GitHub-Dark-Default", "purple": "#BC8CFF", "red": "#FF7B72", "selectionBackground": "#E6EDF3", "white": "#B1BAC4", "yellow": "#D29922" } ], |
- 在 archlinux 的配置中选择 外观 选项卡
- 配色方案选择 GitHub-Dark-Default
- 字体选择 FiraCode Nerd Font
- 背景不透明度 86%,选择启用亚克力材料
- 在 archlinux 的配置中选择 高级 选项卡
- 铃声通知样式取消勾选声音,选择闪烁窗口和闪烁任务栏
- 安装 win32yank.exe 加入到环境变量中,使得在命令行可以直接访问到
如果亚克力失效,关闭Windows节能模式即可
Arch Linux
archlinux 需要下载一些软件包
下载 yay 参考
注意下载后最好对 pacman 和 yay 进行换源,否则速度巨慢
12345678910111213141516171819202122232425262728293031 | # 设置localesudo nano /etc/locale.gen# 找到#en_US.UTF-8 UTF-8解除注释sudo locale-gensudo pacman -Sy emacs-noxsudo pacman -Sy clang nvm ripgrep bear pandoc# python/bash developmentsource /usr/share/nvm/init-nvm.shnvm list-remotenvm install v20.19.4nvm use v20.19.4npm i -g pyright bash-language-server devicetree-language-server prettier# rust developmentcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shrustup component add rust-analyzer# 替换系统ls命令为exa命令sudo pacman -S exa# 如果是bash,则写入bashrcecho 'alias ll="ls -alF"' >> ~/.bashrcecho 'alias ls="exa --icons"' >> ~/.bashrcsource ~/.bashrcmkdir -p ~/.emacs.d/data/backupmkdir -p ~/.emacs.d/data/autosavegit config --global core.editor "emacs" |
Ubuntu20.04
参考:
Emacs
安装
archlinux可直接通过pacman安装,如果是Ubuntu考虑自己编译,参考:
配置
.emacs(点击展开)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914 | ;;不显示menu-bar(menu-bar-mode -1);;显示行号(global-display-line-numbers-mode t);;在ModeLine显示列号(column-number-mode 1);;代码的折叠(add-hook 'prog-mode-hook 'hs-minor-mode);; 自动重载更改的文件(global-auto-revert-mode 1);;开启可视化换行,自动折行(global-visual-line-mode 1);; 括号匹配(electric-pair-mode 1);; 自动缩进(electric-indent-mode 1);; 鼠标模式(xterm-mouse-mode 1);; 中文显示(set-language-environment "utf-8")(set-buffer-file-coding-system 'utf-8)(set-terminal-coding-system 'utf-8)(set-keyboard-coding-system 'utf-8)(set-selection-coding-system 'utf-8)(set-default-coding-systems 'utf-8)(set-clipboard-coding-system 'utf-8)(modify-coding-system-alist 'process "*" 'utf-8)(prefer-coding-system 'utf-8)(setq-default pathname-coding-system 'utf-8)(setq default-process-coding-system '(utf-8 . utf-8) locale-coding-system 'utf-8 file-name-coding-system 'utf-8 default-buffer-file-coding-system 'utf-8 slime-net-coding-system 'utf-8-unix )(setq find-file-encoding 'auto)(setq-default coding-system-for-read 'utf-8)(setq-default coding-system-for-write 'utf-8);; 基本设置(setq-default window-combination-resize t ;; 新窗口平均其他左右窗口 x-stretch-cursor t ;; 将光标拉伸到字形宽度 indent-tabs-mode nil tab-width 8 )(setq ring-bell-function 'ignore initial-scratch-message nil inhibit-startup-message t auto-save-file-name-transforms '((".*" "~/.emacs.d/data/autosave/" t)) ;; Write auto-save files to a separate directory backup-directory-alist '(("." . "~/.emacs.d/data/backup/")) ;; Write backup files to a separate directory create-lockfiles nil ;; Disable lockfiles scroll-conservatively 10000 ;;防止页面滚动时跳动 scroll-step 1 ;; 当光标移动到边缘时,窗口每次只滚动一行 undo-limit 80000 ;; 提升撤销限制 display-time-default-load-average nil ;; 不显示系统负载 use-short-answers t comp-deferred-compilation t ;; Emacs 28+ native-comp-async-report-warnings-errors nil )(defun my/kill-unwanted-buffers () "在 Emacs 启动时关闭一些不想要的 buffer." (dolist (buf-name '("*scratch*" ;;"*Async-native-compile-log*" ;; can't be killed ;;"*Messages*" )) (when (get-buffer buf-name) (kill-buffer buf-name))))(add-hook 'emacs-startup-hook #'my/kill-unwanted-buffers);; 启动速度统计(add-hook 'emacs-startup-hook (lambda () (message "Emacs ready in %s with %d garbage collections." (format "%.2f seconds" (float-time (time-subtract after-init-time before-init-time))) gcs-done)));; 如果用emacs打开文件则只打开文件,如果直接打开emacs则开启上次退出的非空界面;; (add-hook 'after-init-hook;; (defun if-desktop-read ();; (setq desktop-dirname "~/.emacs.d/desktop/";; desktop-base-file-name "emacs.desktop";; desktop-base-lock-name "lock";; desktop-path (list desktop-dirname);; desktop-save t;; desktop-files-not-to-save "^$" ;reload tramp paths;; desktop-load-locked-desktop nil;; desktop-auto-save-timeout 10);; (desktop-save-mode 1);; (if (< (length command-line-args) 2);; (desktop-read)));; 'if-desktop-read);; 使用 Fira Code Nerd Font 字体(when (display-graphic-p) (set-face-attribute 'default nil :font "FiraCode Nerd Font" :height 120));; 剪贴板与系统共享:根据环境自动选择 WSL(Windows) 或 Ubuntu(Wayland/X11) 方案(cond ;; 1. WSL 与 Windows 共享剪贴板(win32yank.exe) ((executable-find "win32yank.exe") (defun my/clipboard-to-windows (text &optional push) (let ((process-connection-type nil)) (with-temp-buffer (insert text) (call-process-region (point-min) (point-max) "win32yank.exe" nil nil nil "-i")))) (defun my/clipboard-from-windows () (string-trim-right (with-output-to-string (call-process "win32yank.exe" nil standard-output nil "-o")))) (setq interprogram-cut-function 'my/clipboard-to-windows) (setq interprogram-paste-function 'my/clipboard-from-windows)) ;; 2. Ubuntu (Wayland) 终端环境(必须同时满足有 wl-copy 且环境变量存在) ((and (getenv "WAYLAND_DISPLAY") (executable-find "wl-copy") (executable-find "wl-paste")) (defun my/clipboard-to-wayland (text &optional push) (let ((process-connection-type nil)) (with-temp-buffer (insert text) (call-process-region (point-min) (point-max) "wl-copy" nil nil nil)))) (defun my/clipboard-from-wayland () (string-trim-right (with-output-to-string (call-process "wl-paste" nil standard-output nil)))) (setq interprogram-cut-function 'my/clipboard-to-wayland) (setq interprogram-paste-function 'my/clipboard-from-wayland)) ;; 3. Ubuntu (X11) 终端环境(备用方案,针对非 Wayland 环境) ((and (getenv "DISPLAY") (executable-find "xclip")) (defun my/clipboard-to-x11 (text &optional push) (let ((process-connection-type nil)) (with-temp-buffer (insert text) (call-process-region (point-min) (point-max) "xclip" nil nil nil "-selection" "clipboard")))) (defun my/clipboard-from-x11 () (string-trim-right (with-output-to-string (call-process "xclip" nil standard-output nil "-selection" "clipboard" "-o")))) (setq interprogram-cut-function 'my/clipboard-to-x11) (setq interprogram-paste-function 'my/clipboard-from-x11)));;设置镜像源;; (setq package-archives;; '(("melpa" . "https://melpa.org/packages/");; ("gnu" . "https://elpa.gnu.org/packages/")))(setq package-archives '(("gnu" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/") ("nongnu" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/nongnu/") ("melpa" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")))(use-package package :config (unless (bound-and-true-p package--initialized) (package-initialize)))(setq use-package-verbose t use-package-always-ensure t use-package-minimum-reported-time 0.01);;通过github下载包;; (unless (package-installed-p 'quelpa);; (with-temp-buffer;; (url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el");; (eval-buffer);; (quelpa-self-upgrade)));; ;; 关闭自动升级和 verbose(减少启动开销);; (setq quelpa-upgrade-p nil;; quelpa-verbose nil;; quelpa-checkout-melpa-p nil);; (quelpa;; '(quelpa-use-package;; :fetcher git;; :url "https://github.com/quelpa/quelpa-use-package.git"));; (require 'quelpa-use-package);; 防止 GC 触发太频繁(use-package benchmark-init :ensure t :config ;; To disable collection of benchmark data after init is done. (add-hook 'after-init-hook 'benchmark-init/deactivate))(setq gc-cons-threshold (* 128 1024 1024 ))(add-hook 'after-init-hook (lambda () (setq gc-cons-threshold (* 5 1024 1024))));; 最近打开的文件(use-package recentf :ensure t ;; Loads after 2 second of idle time. :defer 2)(use-package nerd-icons :defer t :custom (nerd-icons-font-family "FiraCode Nerd Font") );;doom主题(use-package doom-themes :ensure t :init :config (setq doom-themes-enable-bold t ; if nil, bold is universally disabled doom-themes-enable-italic nil ; if nil, italics is universally disabled ) ;; 加载主题(例如 doom-one) (load-theme 'doom-tomorrow-night t) (global-hl-line-mode 1) (doom-themes-visual-bell-config) ;; 视觉提示“响铃”(visual bell) );; dire 高亮(use-package diredfl :ensure t :defer t :hook ((dired-mode . diredfl-mode) (dirvish-directory-view-mode . diredfl-mode)) :config (set-face-attribute 'diredfl-dir-name nil :bold t))(setq dired-free-space nil)(setq dired-listing-switches "-l --almost-all --human-readable --group-directories-first --no-group")(add-hook 'dired-mode-hook #'dired-hide-details-mode)(use-package dirvish :ensure t :config (setq dirvish-default-layout '(main preview 0.75)) ; 移除 parent 面板 (setq dirvish-mode-line-bar-image-width 0) ; hide the leading bar image (setq dirvish-mode-line-format '(:left (sort symlink) :right (omit yank index))) (setq dirvish-attributes ; The order *MATTERS* for some attributes '(vc-state subtree-state nerd-icons git-msg) dirvish-side-attributes '(vc-state nerd-icons)) ;; 修复:为 Dirvish 预览缓冲区开启行号 (defun my-dirvish-preview-enable-line-numbers () (unless (derived-mode-p 'dirvish-special-preview-mode) (display-line-numbers-mode 1))) ;; 将行号函数添加到预览缓冲区的钩子中 (add-hook 'dirvish-preview-setup-hook #'my-dirvish-preview-enable-line-numbers) :hook (after-init . dirvish-override-dired-mode) :bind ("C-x C-j" . dirvish));; (use-package nerd-icons-dired;; :defer t;; :quelpa (nerd-icons-dired :fetcher github :repo "rainstormstudio/nerd-icons-dired");; :vc (:url "https://github.com/rainstormstudio/nerd-icons-dired" :rev :newest);; :after nerd-icons;; :hook (dired-mode . nerd-icons-dired-mode));;(add-hook 'dired-mode-hook 'nerd-icons-dired-mode);; Enable rich annotations using the Marginalia package(use-package marginalia ;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding ;; available in the *Completions* buffer, add it to the ;; `completion-list-mode-map'. :defer t ;;:quelpa (marginalia :fetcher github :repo "") :vc (:url "https://github.com/minad/marginalia" :rev :newest) :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) ;; The :init section is always executed. :init ;; Marginalia must be activated in the :init section of use-package such that ;; the mode gets enabled right away. Note that this forces loading the ;; package. (marginalia-mode))(use-package nerd-icons-completion :after marginalia :config (nerd-icons-completion-mode) (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))(use-package nerd-icons-ibuffer :ensure t :config (setq nerd-icons-ibuffer-human-readable-size t) :hook (ibuffer-mode . nerd-icons-ibuffer-mode))(use-package ibuffer :ensure nil :config (setq ibuffer-expert t) (setq ibuffer-display-summary nil) (setq ibuffer-use-other-window nil) (setq ibuffer-show-empty-filter-groups nil) (setq ibuffer-default-sorting-mode 'filename/process) (setq ibuffer-title-face 'font-lock-doc-face) (setq ibuffer-use-header-line t) (setq ibuffer-default-shrink-to-minimum-size nil) (setq ibuffer-formats '((mark modified read-only locked " " (name 40 40 :left :elide) " " (size 9 -1 :right) " " (mode 16 16 :left :elide) " " filename-and-process) (mark " " (name 16 -1) " " filename))) (setq ibuffer-saved-filter-groups '(("Main" ("Directories" (mode . dired-mode)) ("C/C++" (or (mode . c++-mode) (mode . c++-ts-mode) (mode . c-mode) (mode . c-ts-mode) (mode . c-or-c++-ts-mode))) ("Devicetree" (or (mode . dts-mode) )) ("Python" (or (mode . python-ts-mode) (mode . c-mode) (mode . python-mode))) ("Build" (or (mode . make-mode) (mode . makefile-gmake-mode) (name . "^Makefile$") (mode . change-log-mode))) ("Scripts" (or (mode . shell-script-mode) (mode . shell-mode) (mode . sh-mode) (mode . lua-mode) (mode . bat-mode))) ("Config" (or (mode . conf-mode) (mode . conf-toml-mode) (mode . toml-ts-mode) (mode . conf-windows-mode) (name . "^\\.clangd$") (name . "^\\.gitignore$") (name . "^Doxyfile$") (name . "^config\\.toml$") (mode . yaml-mode))) ("Web" (or (mode . mhtml-mode) (mode . html-mode) (mode . web-mode) (mode . nxml-mode))) ("CSS" (or (mode . css-mode) (mode . sass-mode))) ("JS" (or (mode . js-mode) (mode . rjsx-mode))) ("Markup" (or (mode . markdown-mode) (mode . adoc-mode))) ("Org" (mode . org-mode)) ("LaTeX" (name . "\.tex$")) ("Magit" (or (mode . magit-blame-mode) (mode . magit-cherry-mode) (mode . magit-diff-mode) (mode . magit-log-mode) (mode . magit-process-mode) (mode . magit-status-mode))) ("Apps" (or (mode . elfeed-search-mode) (mode . elfeed-show-mode))) ("Claude Code" (and (mode . vterm-mode) (name . "^\\*claude\\*$"))) ("Fundamental" (or (mode . fundamental-mode) (mode . text-mode))) ("Emacs" (or (mode . emacs-lisp-mode) (name . "^\\*Help\\*$") (name . "^\\*Custom.*") (name . "^\\*Org Agenda\\*$") (name . "^\\*info\\*$") (name . "^\\*scratch\\*$") (name . "^\\*Backtrace\\*$") (name . "^\\*Messages\\*$")))))) :hook (ibuffer-mode . (lambda () (ibuffer-switch-to-saved-filter-groups "Main"))) );;tab栏显示buffer;; (use-package centaur-tabs;; :ensure t;; :demand;; :init;; :config;; (defun centaur-tabs-hide-tab (x);; "隐藏特殊 buffer,保留 GUD/GDB buffer.";; (let ((name (format "%s" x)));; (cond;; ;; 保留所有 GDB/GUD 相关 buffer;; ((string-match-p;; "^\\*\\(gud\\|gdb\\)" name);; nil);; ;; 隐藏 *Messages*、*Async-native-compile-log* 等内部 buffer;; ((string-prefix-p "*" name) t);; ;; Magit buffer;; ((and (string-prefix-p "magit" name);; (not (file-name-extension name))) t);; ;;非文件不显示;; ((not (buffer-file-name x)) t);; ;; 其他 buffer 显示;; (t nil))));; (defun centaur-tabs-buffer-groups ();; "`centaur-tabs-buffer-groups' control buffers' group rules.";; (list;; (cond;; ((or (string-equal "*" (substring (buffer-name) 0 1));; (memq major-mode '(magit-process-mode;; magit-status-mode;; magit-diff-mode;; magit-log-mode;; magit-file-mode;; magit-blob-mode;; magit-blame-mode;; ))) "Emacs");; ((memq major-mode '(helpful-mode;; help-mode)) "Help");; (t;; (centaur-tabs-get-group-name (current-buffer))))));; (setq centaur-tabs-style "bar";; centaur-tabs-set-bar 'over;; centaur-tabs-enable-key-bindings nil;; centaur-tabs-set-icons t;; centaur-tabs-icon-type 'nerd-icons;; centaur-tabs-set-close-button nil;; centaur-tabs-show-new-tab-button nil;; centaur-tabs-set-modified-marker t;; centaur-tabs-modified-marker "M";; centaur-tabs-cycle-scope 'tabs);; (centaur-tabs-mode t);; :bind;; ("C-<left>" . centaur-tabs-backward);; ("C-<right>" . centaur-tabs-forward);; :hook;; (dired-mode . centaur-tabs-local-mode);; );; modeline主题(use-package doom-modeline :ensure t :custom (doom-modeline-buffer-file-name-style 'truncate-except-project) ; 更智能的文件名截断 (doom-modeline-env-version t) ; 显示 Python/Rust 版本等 (doom-modeline-major-mode-icon t) :init (doom-modeline-mode 1));;文件导航栏;; (use-package neotree;; :defer t;; :ensure t;; :bind (("<f8>" . neotree-toggle));; :config;; (setq neo-theme 'nerd-icons);; (setq neo-smart-open t) ;; 打开时自动跳到当前文件路径;; (setq neo-show-hidden-files t);; 显示隐藏文件;; );; ;; neotree buffer 中强制截断长行;; (add-hook 'neo-after-create-hook;; (lambda (_);; ;; 不换行,禁用 visual-line(你全局开了的话);; (visual-line-mode -1);; (setq-local truncate-lines t);; ;; 用 “…” 代替右侧的 $ 截断标记;; (let ((tbl (or buffer-display-table (make-display-table))));; (set-display-table-slot tbl 'truncation (make-glyph-code ?…));; (setq-local buffer-display-table tbl))));; ;; 允许 neotree 窗口宽度可调整;; (with-eval-after-load 'neotree;; (setq neo-window-fixed-size nil))(use-package undo-tree :ensure t :init (global-undo-tree-mode) :config ;;将undo-tree生成的文件,都写入到~/.emacs.d/.cache,方便管理. (setq undo-tree-history-directory-alist `(("." . "~/.emacs.d/.cache"))) );; enhancement for amx;; 命令按历史排序(use-package amx :ensure t :defer t :init (amx-mode))(use-package exec-path-from-shell :ensure t :init :config (when (memq window-system '(mac ns x)) (exec-path-from-shell-initialize)));; Git工具(use-package magit :ensure t :defer t :bind (("C-x g" . magit-status)) )(use-package markdown-mode :ensure t :defer t :mode ("\\.md\\'" . markdown-mode) :init (setq markdown-command "pandoc") ;; 额外添加 README/readme 等文件的关联 (add-to-list 'auto-mode-alist '("README\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("readme\\'" . markdown-mode)) ;; 可选:也支持 README.md, Readme.md 等大小写变体 (add-to-list 'auto-mode-alist '("[Rr]eadme\\(?:\\.md\\)?\\'" . markdown-mode)))(use-package dts-mode :ensure t :defer t );; 语法解析(use-package tree-sitter :ensure t ;; :when (and (fboundp 'treesit-available-p) ;; (treesit-available-p)) :config (setq treesit-font-lock-level 4) ;;:init (setq treesit-language-source-alist '((bash . ("https://github.com/tree-sitter/tree-sitter-bash" "v0.20.0")) (c . ("https://github.com/tree-sitter/tree-sitter-c" "v0.21.3")) (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp")) (python . ("https://github.com/tree-sitter/tree-sitter-python")) (rust . ("https://github.com/tree-sitter/tree-sitter-rust")) (toml . ("https://github.com/tree-sitter/tree-sitter-toml")) (elisp . ("https://github.com/Wilfred/tree-sitter-elisp")) (cmake . ("https://github.com/uyha/tree-sitter-cmake")) (dockerfile . ("https://github.com/camdencheek/tree-sitter-dockerfile")) (make . ("https://github.com/alemuller/tree-sitter-make")) (yaml . ("https://github.com/ikatyang/tree-sitter-yaml")) (json . ("https://github.com/tree-sitter/tree-sitter-json")) (java . ("https://github.com/tree-sitter/tree-sitter-java")) (html . ("https://github.com/tree-sitter/tree-sitter-html")) (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript")) (css . ("https://github.com/tree-sitter/tree-sitter-css")) (go . ("https://github.com/tree-sitter/tree-sitter-go")) )) ;;没有内置<languate>-mode的需要添加 (add-to-list 'auto-mode-alist '("\\.c\\.[^/]*\\'" . c-ts-mode)) (add-to-list 'auto-mode-alist '("\\.include\\.[^/]*\\'" . c-ts-mode)) (add-to-list 'auto-mode-alist '("\\.y[a]?ml\\'" . yaml-ts-mode)) (add-to-list 'auto-mode-alist '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . dockerfile-ts-mode)) (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode)) (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)) (add-to-list 'auto-mode-alist '("\\.js\\'" . js-ts-mode)) );; 安装 tree-sitter 语法解析器(仅 Emacs 29+)(run-with-idle-timer 3 nil ; 启动后3秒空闲时执行 (lambda () (dolist (lang '(bash c cpp python rust toml elisp cmake dockerfile make yaml json java html javascript css go)) (unless (treesit-language-available-p lang) (treesit-install-language-grammar lang)))));; 优先使用 Tree-sitter mode(setq major-mode-remap-alist '((bash-mode . bash-ts-mode) (c-mode . c-ts-mode) (c++-mode . c++-ts-mode) (python-mode . python-ts-mode) ;;(rust-mode . rust-ts-mode) (conf-toml-mode . toml-ts-mode) (elisp-mode . elisp-ts-mode) (cmake-mode . cmake-ts-mode) ;;(dockerfile-mode . dockerfile-ts-mode) (json-mode . json-ts-mode) (java-mode . java-ts-mode) ;;(yaml-mode . yaml-ts-mode) (makefile-mode . makefile-ts-mode) (mhtml-mode . html-ts-mode) (html-mode . html-ts-mode) ;;(js-mode . js-ts-mode) (css-mode . css-ts-mode) ;;(go-mode . go-ts-mode) ));; 设置 C/C++ 模式的缩进为 8 个空格(defun my-c-cpp-indent-setup () "Customize C/C++ mode." (setq c-ts-mode-indent-offset 8) ;; 缩进单位为 8 (setq c-ts-mode-indent-style 'linux))(dolist (hook '(c-mode-hook c++-mode-hook c-ts-mode-hook c++-ts-mode-hook)) (add-hook hook #'my-c-cpp-indent-setup));; lsp语言服务器配置(use-package eglot :ensure t :defer 1 :config (setq eglot-server-programs '(((c-mode-hook c++-mode-hook c++-ts-mode c-ts-mode) . ("clangd" ;; "-j=4" "--enable-config" "--background-index" ;; "--background-index-priority=low" "--clang-tidy" "--completion-style=detailed" "--ranking-model=decision_forest" "--header-insertion=never" ;; "--all-scopes-completion" "--pretty" ;; "--fallback-style=none" ;;"--query-driver=aarch64-linux-gnu-*" ;;"--query-driver=gcc,g++" "--query-driver=/usr/bin/g++,/usr/bin/gcc" )) ((dts-mode) . ("devicetree-language-server" "--stdio")) ((rust-mode rust-ts-mode) . ("rust-analyzer" :initializationOptions (:cargo (:buildScripts (:enable t)) :procMacro (:enable t)))) ((python-mode python-ts-mode) . ("pyright-langserver" "--stdio")) ;; ((bash-mode bash-ts-mode sh-mode sh-ts-mode) . ("bash-language-server" "start")) ;; ((toml-mode toml-ts-mode) . ("taplo" "lsp" "stdio")) ;; ((yaml-mode yaml-ts-mode) . ("yaml-language-server" "--stdio")) ;; ((markdown-mode markdown-ts-mode) . ("marksman")) )) ;; 关闭lsp自动格式化 (setq eglot-ignored-server-capabilities '(:documentOnTypeFormattingProvider)) );;自动打开eglot(dolist (hook '(c-mode-hook c-ts-mode-hook c++-mode-hook c++-ts-mode-hook dts-mode-hook rust-mode-hook rust-ts-mode-hook python-mode-hook python-ts-mode-hook ;;bash-mode-hook bash-ts-mode-hook ;;sh-mode-hook sh-ts-mode-hook ;; markdown-mode-hook markdown-ts-mode-hook ;; toml-mode-hook toml-ts-mode-hook ;; yaml-mode-hook yaml-ts-mode-hook )) (add-hook hook 'eglot-ensure));; eglot快捷键(global-set-key (kbd "M-,") 'xref-find-definitions) ;; 跳转到定义(global-set-key (kbd "M-.") 'xref-pop-marker-stack) ;; 跳回(global-set-key (kbd "M-?") 'xref-find-references) ;; 查找引用;; comment(defun my-cpp-line-comments () "Use // comments instead of /* */ in C/C++." (setq-local comment-start "// " comment-end "" comment-start-skip "//+\\s-*"))(dolist (hook '(c-mode-hook c++-mode-hook c-ts-mode-hook c++-ts-mode-hook rust-mode-hook rust-ts-mode-hook python-mode-hook python-ts-mode-hook java-mode-hook java-ts-mode-hook)) (add-hook hook #'my-cpp-line-comments))(use-package yasnippet :ensure t :hook (after-init . yas-global-mode) :config ;; 可选:设置 snippet 目录(默认已包含 ~/.emacs.d/snippets) ;; (setq yas-snippet-dirs '("~/.emacs.d/snippets")) );; 自动补全(use-package company :defer 1 :ensure t :hook (after-init . global-company-mode) :config ;; 光标停留 0 秒立即弹出补全 (setq company-idle-delay 0) ;; 后端 (setq company-backends '((company-capf :with company-yasnippet) company-keywords company-files)) ;; 最少 1 个字符触发补全,0 表示空白处也可以触发 (setq company-minimum-prefix-length 1) ;; 补全候选最多显示 30 个 (setq company-tooltip-limit 30) (setq eldoc-idle-delay 0.3) ;; GDB配置 (add-hook 'gud-mode-hook (lambda () (company-mode -1))) ;; gud模式下禁用 company ;; 在 eshell 模式下禁用 company-mode (add-hook 'eshell-mode-hook (lambda () (company-mode -1))) );; 格式化(use-package format-all :ensure t :defer t :commands format-all-mode ;; :hook (prog-mode . format-all-mode) ;; 禁用自动保存格式化 :config (setq-default format-all-formatters '(("C" (clang-format)) ("C++" (clang-format)) ;; ("Java" (clang-format)) ("Rust" (rustfmt)) ("JavaScript" (prettier)) ("Markdown" (prettier)) ("YAML" (prettier)) ;;("TOML" (taplo-fmt)) ;;("Devicetree" (dtsfmt)) )))(global-set-key (kbd "C-x f") 'format-all-buffer);; claude code;; install required inheritenv dependency:(use-package inheritenv :vc (:url "https://github.com/purcell/inheritenv" :rev :newest))(use-package monet :vc (:url "https://github.com/stevemolitor/monet" :rev :newest));; for vterm terminal backend:(use-package vterm :ensure t);; install claude-code.el(use-package claude-code :ensure t :vc (:url "https://github.com/stevemolitor/claude-code.el" :rev :newest) :config ;; optional IDE integration with Monet (add-hook 'claude-code-process-environment-functions #'monet-start-server-function) (monet-mode 1) (setq claude-code-terminal-backend 'vterm) (claude-code-mode) :bind-keymap ("C-c c" . claude-code-command-map) ;; Optionally define a repeat map so that "M" will cycle thru Claude auto-accept/plan/confirm modes after invoking claude-code-cycle-mode / C-c M. :bind (:repeat-map my-claude-code-map ("M" . claude-code-cycle-mode)));; which-key 显示键绑定提示(use-package which-key :ensure t :defer t :config (which-key-mode));; 窗格切换(use-package ace-window :ensure t :defer t :bind (("M-o" . ace-window)));; 窗格移动(use-package buffer-move :ensure t :defer t :bind (("C-c <up>" . buf-move-up) ("C-c <down>" . buf-move-down) ("C-c <left>" . buf-move-left) ("C-c <right>" . buf-move-right)));; 智能按键C-a C-c k(use-package crux :ensure t :defer t :bind (("C-a" . 'crux-move-beginning-of-line) ("C-c k" . 'crux-smart-kill-line)));; 预览要跳转的行(use-package goto-line-preview :ensure t :defer t :bind (("M-g g" . goto-line-preview)));;代码整行上移下移(use-package move-dup :ensure t :defer t :bind (("C-M-p" . move-dup-move-lines-up) ;; ("C-M-p" . move-dup-duplicate-up) ("C-M-n" . move-dup-move-lines-down) ;; ("C-M-n" . move-dup-duplicate-down) ));; 项目识别,通过创建.projectile文件识别为一个项目(setq project-find-functions nil)(use-package projectile :ensure t ;;:init ;; :bind-keymap ;; ("C-c p" . projectile-command-map) :config (projectile-mode +1) (setq projectile-enable-caching t) (setq projectile-project-search-path '("~/repository")) (setq projectile-completion-system 'auto) ;; 或 ivy / helm / default (use-package rg :defer t :ensure t))(use-package multiple-cursors :ensure t :config (global-set-key (kbd "C-c m") 'mc/mark-all-dwim));; 快捷键定义必须放在后面否则容易被其他插件覆盖;; next error(global-set-key (kbd "M-n") #'flymake-goto-next-error)(global-set-key (kbd "M-p") #'flymake-goto-prev-error);; 快捷键绑定:使用调整窗口大小(global-set-key (kbd "M-<up>") 'enlarge-window)(global-set-key (kbd "M-<down>") 'shrink-window)(global-set-key (kbd "M-<left>") 'shrink-window-horizontally)(global-set-key (kbd "M-<right>") 'enlarge-window-horizontally);;撤销(global-set-key (kbd "C-/") 'undo-only);;全局搜索(global-set-key (kbd "C-c C-s") 'projectile-ripgrep)(defun k-insert-timestamp () (interactive) (insert (format-time-string "%Y-%m-%d %H:%M")))(defun k-insert-date () (interactive) (insert (format-time-string "%Y-%m-%d")))(global-set-key (kbd "C-c t") 'k-insert-timestamp)(global-set-key (kbd "C-c d") 'k-insert-date)(global-unset-key (kbd "C-x C-b"))(global-set-key (kbd "C-x C-b") 'ibuffer)(global-set-key (kbd "TAB") 'tab-to-tab-stop)(global-set-key (kbd "C-x k") (lambda () (interactive) (kill-this-buffer)))(add-hook 'prog-mode-hook (lambda () (local-set-key (kbd "C-c p") #'flymake-show-buffer-diagnostics) ;; problem (local-set-key (kbd "C-c f") #'eglot-code-actions))) ;; fix(custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(package-selected-packages nil) '(package-vc-selected-packages '((claude-code :url "https://github.com/stevemolitor/claude-code.el"))))(custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. ) |
快捷键配置总览
“C” 在 Emacs 中表示Ctrl
“M” 在 Emacs 中表示Alt
| 快捷键 | 功能描述 | 来源配置 |
|---|---|---|
| C-/ | 撤销(undo-only) | 手动绑定 |
| M-<up> | 增大当前窗口高度 | 手动绑定 |
| M-<down> | 减小当前窗口高度 | 手动绑定 |
| M-<left> | 减小当前窗口宽度 | 手动绑定 |
| M-<right> | 增大当前窗口宽度 | 手动绑定 |
| C-<left> | 切换到前一个 Tab(Centaur Tabs) | centaur-tabs |
| C-<right> | 切换到下一个 Tab | centaur-tabs |
| M-g g | 预览跳转到指定行(goto-line-preview) | goto-line-preview |
| M-C-p | 将当前行上移 | move-dup |
| M-C-n | 将当前行下移 | move-dup |
| M-p | 下一个错误 | flymake |
| M-n | 上一个错误 | flymake |
| C-c p | 显示所有错误 | flymake |
| C-c f | 利用 lsp 修复代码(eglot-code-actions) | eglot |
| C-x C-j | 打开文件浏览器(dirvish) | dirvish |
| C-x C-f | 查找文件并打开 | 内置 |
| C-x C-b | 打开buffer浏览器 | Ibuffer |
| C-x g | magit status | magit |
| C-x f | 格式化当前 buffer(clang-format / rustfmt) | format-all |
| M-, | 跳转到定义(xref-find-definitions,需 LSP 支持) | 手动绑定 |
| M-. | 跳回上一个位置(xref-pop-marker-stack) | 手动绑定 |
| M-? | 查找引用(xref-find-references,需 LSP 支持) | 手动绑定 |
| M-o | 在多个窗口间切换焦点 | ace-window |
| C-c <up> | 当前 buffer 上移到另一个窗口 | buffer-move |
| C-c <down> | 当前 buffer 下移到另一个窗口 | buffer-move |
| C-c <left> | 当前 buffer 左移到另一个窗口 | buffer-move |
| C-c <right> | 当前 buffer 右移到另一个窗口 | buffer-move |
| C-a | 智能移动光标到行首(再次按可回到代码开始处) | crux |
| C-c k | 智能删除一行(不会破坏缩进) | crux |
| C-x SPC | 矩形选择模式,可以选择某些列 | 内置 |
| M-< | 移到缓冲区开头 | 内置 |
| M-> | 移到缓冲区末尾 | 内置 |
| C-c t | 插入时间戳 | 手动绑定 |
| C-c d | 插入日期 | 手动绑定 |
| C-x u | 打开undo-tree | undo-tree |
- M-X projectile-ripgrep ripgrep全局查找
- C-c C-s 项目里全局查找
- M-x recenter 把当前行放在窗口中间
- M-x eglot-rename 更改编程时的symbol名字
- M-x man, 然后输入要查找的函数比如
shmget(2),这里2表示查找syscall,然后在*Man*缓冲区中用:- M-n → 下一个手册页
- M-p → 上一个手册页
buffer-menu
可以用以下按键操作:
| 按键 | 功能 |
|---|---|
Enter或f | 切换到光标所在行的缓冲区 |
o | 切换到该缓冲区,并保留*Buffer List* |
d | 标记该缓冲区为“待删除”(不会立即删) |
x | 真正删除所有被标记的缓冲区 |
s | 保存该缓冲区(如果已修改) |
u | 取消标记(如果之前按了d) |
q | 关闭*Buffer List*窗口 |
g | 刷新列表(重新加载最新状态) |
按d标记删除后,按x才是真正删除
magit
Magit 的设计哲学是:一个按键 = 一个操作。
| 按键 | 功能 |
|---|---|
s | Stage 当前光标下的文件/区域(相当于git add) |
u | Unstage(取消暂存) |
c | Commit(提交) → 再按c确认 |
P | Push 推送到远程 |
F | Fetch 从远程拉取更新 |
p | Pull(拉取并合并) |
b | 分支操作(创建/切换/合并) |
l | 查看 log(提交历史) |
L | 查看带图形的 log(类似git log --graph) |
d | Diff 查看变更内容 |
= | 在 commit 上按=查看该次提交的 diff |
q | Quit 关闭当前 Magit 缓冲区 |
⚠️ 注意:这些命令只在 Magit 状态缓冲区(
*magit: xxx*)中有效!
使用一个按键后,按 Ctrl-g 取消
编程设置
对于有 makefile 的 project 可以用 bear 生成 compile_command.json 供 clangd 索引
123456 | # 在项目根目录下创建,标识这是一个项目touch .projectile# 生成compile_command.jsonmake cleanbear -- make |
对于linux内核相关设置,参考
.clang-format 配置
直接用的 Linux Kernel 的配置,但没有使用TAB,而是空格,ColumnLimit调大为100
.clang-format
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 | # SPDX-License-Identifier: GPL-2.0## clang-format configuration file. Intended for clang-format >= 11.## For more information, see:## Documentation/dev-tools/clang-format.rst# https://clang.llvm.org/docs/ClangFormat.html# https://clang.llvm.org/docs/ClangFormatStyleOptions.html#AccessModifierOffset: -4AlignAfterOpenBracket: AlignAlignConsecutiveAssignments: falseAlignConsecutiveDeclarations: falseAlignEscapedNewlines: LeftAlignOperands: trueAlignTrailingComments: falseAllowAllParametersOfDeclarationOnNextLine: falseAllowShortBlocksOnASingleLine: falseAllowShortCaseLabelsOnASingleLine: falseAllowShortFunctionsOnASingleLine: NoneAllowShortIfStatementsOnASingleLine: falseAllowShortLoopsOnASingleLine: falseAlwaysBreakAfterDefinitionReturnType: NoneAlwaysBreakAfterReturnType: NoneAlwaysBreakBeforeMultilineStrings: falseAlwaysBreakTemplateDeclarations: falseBinPackArguments: trueBinPackParameters: trueBraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: trueBreakBeforeBinaryOperators: NoneBreakBeforeBraces: CustomBreakBeforeInheritanceComma: falseBreakBeforeTernaryOperators: falseBreakConstructorInitializersBeforeComma: falseBreakConstructorInitializers: BeforeCommaBreakAfterJavaFieldAnnotations: falseBreakStringLiterals: falseColumnLimit: 100CommentPragmas: "^ IWYU pragma:"CompactNamespaces: falseConstructorInitializerAllOnOneLineOrOnePerLine: falseConstructorInitializerIndentWidth: 8ContinuationIndentWidth: 8Cpp11BracedListStyle: falseDerivePointerAlignment: falseDisableFormat: falseExperimentalAutoDetectBinPacking: falseFixNamespaceComments: falseIncludeBlocks: PreserveIncludeCategories: - Regex: ".*" Priority: 1IncludeIsMainRegex: "(Test)?$"IndentCaseLabels: falseIndentGotoLabels: falseIndentPPDirectives: NoneIndentWidth: 8IndentWrappedFunctionNames: falseJavaScriptQuotes: LeaveJavaScriptWrapImports: trueKeepEmptyLinesAtTheStartOfBlocks: falseMacroBlockBegin: ""MacroBlockEnd: ""MaxEmptyLinesToKeep: 1NamespaceIndentation: NoneObjCBinPackProtocolList: AutoObjCBlockIndentWidth: 8ObjCSpaceAfterProperty: trueObjCSpaceBeforeProtocolList: true# Taken from git's rulesPenaltyBreakAssignment: 10PenaltyBreakBeforeFirstCallParameter: 30PenaltyBreakComment: 10PenaltyBreakFirstLessLess: 0PenaltyBreakString: 10PenaltyExcessCharacter: 100PenaltyReturnTypeOnItsOwnLine: 60PointerAlignment: RightReflowComments: falseSortIncludes: falseSortUsingDeclarations: falseSpaceAfterCStyleCast: falseSpaceAfterTemplateKeyword: trueSpaceBeforeAssignmentOperators: trueSpaceBeforeCtorInitializerColon: trueSpaceBeforeInheritanceColon: trueSpaceBeforeParens: ControlStatementsExceptForEachMacrosSpaceBeforeRangeBasedForLoopColon: trueSpaceInEmptyParentheses: falseSpacesBeforeTrailingComments: 1SpacesInAngles: falseSpacesInContainerLiterals: falseSpacesInCStyleCastParentheses: falseSpacesInParentheses: falseSpacesInSquareBrackets: falseStandard: Cpp03TabWidth: 8UseTab: false |
以守护进程形式运行Emacs
systemd
需要systemd
12 | systemctl --user enable --now emacsemacsclient file.txt |
Shell
12 | emacs --daemonemacsclient file.txt |
完成编辑后,按 Ctrl+x,然后 #退出,Emacs 会将该缓冲区标记为已完成,然后emacsclient 会退出。如果没有其他缓冲区在使用,该 buffer 启动的 LSP(例如 clangd)也会随之退出。
而如果按Ctrl+x退出,然后 c,Emacs会认为这个buffer暂时还不能关闭

