Cover image for 我的Emacs配置

我的Emacs配置

字数 7k
阅读
访客

时间轴

时间轴

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

WSL2 Arch Linux
WSL2 Arch Linux

配置

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>切换到下一个 Tabcentaur-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 gmagit statusmagit
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-treeundo-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

可以用以下按键操作:

按键功能
Enterf切换到光标所在行的缓冲区
o切换到该缓冲区,并保留*Buffer List*
d标记该缓冲区为“待删除”(不会立即删)
x真正删除所有被标记的缓冲区
s保存该缓冲区(如果已修改)
u取消标记(如果之前按了d
q关闭*Buffer List*窗口
g刷新列表(重新加载最新状态)

按d标记删除后,按x才是真正删除

magit

Magit 的设计哲学是:一个按键 = 一个操作

按键功能
sStage 当前光标下的文件/区域(相当于git add
uUnstage(取消暂存)
cCommit(提交) → 再按c确认
PPush 推送到远程
FFetch 从远程拉取更新
pPull(拉取并合并)
b分支操作(创建/切换/合并)
l查看 log(提交历史)
L查看带图形的 log(类似git log --graph
dDiff 查看变更内容
=在 commit 上按=查看该次提交的 diff
qQuit 关闭当前 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暂时还不能关闭

评论加载中…