© 第253页图灵笔记,2020 -
Emacs初体验
教程简介
最初视频版本的理念(其中带*的也是文字版的理念):
- *带领认识Emacs这款传说中的编辑器
- 每节课五分钟左右,没有废话,干货
- *每节课一个技巧或知识点,轻松学习
- *对笔者也是个学习的过程,共同进步
- *新手视角,向老鸟学习,向高手迈进
Emacs简介
- 讲解的版本是
GNU Emacs,非其他的衍生版本 - GNU Emacs于1984年,
Richard Stallman发起并维护 - GNU顶级项目
- 竞争对手VIM,VSCode等
- 跨平台,内核解释器C写成,通过ELisp语言进行扩展
Emacs安装
Windows
建议使用Scoop或Chocolatey等包管理器安装。
scoop bucket add extras
scoop install emacs
choco install emacs
或者也可以直接在Emacs官网进行下载解压使用。
或者下载测试版(版本比较新,其实功能也挺稳定):alpha.gnu.org/gnu/emacs/p…
Linux
建议使用分发版自带的包管理器进行安装,如:
# Ubuntu / Debian
sudo apt install emacs
# Fedora
sudo dnf install emacs
# Arch
sudo pacman -S emacs
或者也可以通过官网下载源代码编译安装。
macOS
建议使用Homebrew包管理器进行安装。
brew install --cask emacs
或者也可以在官网通过下载后拖动到Applications目录中即可使用。
Emacs版本
截止到本文编写的时候:
- 最新版本:28.1 (2022年4月4日)
- 开发中不稳定版本:29.0.50
最初的教程以27.2为演示版本,同时兼容28/29版本(所以在使用本教程的时候,完全可以直接使用最新的28.1)。安装前可查看包管理器安装的是否是对应版本。
注:随着时间的推移,笔者从2022年初开始将版本普遍提高到了28.1+。
# Windows
scoop info emacs
# Linux
apt info emacs
dnf info emacs
# macOS
brew info emacs
启动Emacs,然后查看版本。 M-x emacs-version
或者在命令行中查看版本。 emacs --version
Emacs初识
绿色:菜单栏
红色:工具栏
黄色:编辑区域
蓝色:状态栏
紫色:交互区域(输出信息,M-x操作等)
基本操作速记
别太多,先学习一点点光标的移动。
- C,代表
CTRL键 - M,代表
Meta键,往往是ALT(部分键盘是ESC)
光标移动,形成肌肉记忆之前可通过速记法来记忆:
- C-n,下一行(速记:Nextline)
- C-p,前一行(速记:Previous line)
- C-f,向前移动一个字符(速记:Forward)
- C-b,向后退一个字符(速记:Backforward)
- C-k,从光标位置到末尾删掉(速记:Kill)
- C-a,回到行首(速记:a是字母表的开始)
- C-e,去往行尾(速记:End of line)
- M - <,回到编辑区域最开始位置(速记:<)
- M - >,去往编辑区域最后的位置(速记:>)
- C-v,向下翻一屏
- M-v,向上翻一屏
自带文档
C-h t ;速记 Help Tutorial
查看快捷键的含义:
C-h k ;速记 Help Keybind
查看函数的定义以及快捷键绑定:
C-h f ;速记 Help Function
对外观做点改变
图形化配置 M-x customize
- 菜单栏 menu-bar-mode
- 工具栏 tool-bar-mode
- 滚动条 scroll-bar-mode
体验下用配置文件配置
创建文件 ~/.emacs 并写入一下内容:
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
重启Emacs看看实际的效果。
Emacs配置初体验
认识配置文件
Emacs配置文件的位置,会按照一下顺序去查找:
- ~/.emacs
- ~/.emacs.d
- ~/.config/emacs/init.el
第一个是一个单一文件配置;第二个更符合工程化;第三个仅适用于≥27的版本。
教程会从第一个入手,逐渐变为第二种的模式。
为什么不用大牛配置
- 大牛配置有哪些
- Spacemacs
- Centaur Emacs
- Doom Emacs
- Steve Purcell
- redguardtoo(陈斌,一年成为emacs高手作者)
- ……
- 我的建议
- 当然建议用大牛配置,大牛的配置是最优,而且经历了时间和项目考验的,就算你将来不日常使用,学习价值也非常大。
- 为什么不用:你一定是经历了很长的使用后才该有这样的想法,想学习,想配置,了解了Emacs后想打造一些属于自己的东西的时候。而且强烈建议你以大牛的配置为基础进行增减。
第一行emacs配置代码
已经体验了关掉菜单栏、工具栏、滚动条等。现在尝试关掉启动界面:
(setq inhibit-startup-screen t)
重启Emacs看看?
软件源
- 什么是软件源,你安装第三方插件的来源(或许叫插件源更合理?)。
- 为什么要用软件源,不同的软件源有不同的软件包,所以为了找到更多的需要的包。
- 为什么要改成国内的软件源,有些软件源可能无法访问,有些软件源在国内连接的时候可能速度不理想。
(setq package-archives
'(("melpa" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")
("gnu" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")
("org" . "https://mirrors.tuna.tsinghua.edu.cn/elpa/org/")))
安装第一个emacs扩展
安装扩展前,需要先刷新软件源的索引。
;;个别时候会出现签名检验失败
(setq package-check-signature nil)
;; 初始化软件包管理器
(require 'package)
(unless (bound-and-true-p package--initialized)
(package-initialize))
;; 刷新软件源索引
(unless package-archive-contents
(package-refresh-contents))
;; 第一个扩展插件:use-package,用来批量统一管理软件包
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
使用use-package管理扩展
- 什么是use-package
- 怎么用
最简洁的格式
(use-package restart-emacs)
常用的格式
(use-package SOME-PACKAGE-NAME
:ensure t ; 是否一定要确保已安装
:defer t ; 是否要延迟加载,很多时候可以加速Emacs的启动速度
:init (setq ...) ; 初始化配置
:config (...) ; 初始化后的基本配置参数
:bind (...) ; 快捷按键绑定
:hook (...) ; hook的绑定
)
建议添加的配置:
;; `use-package-always-ensure' 避免每个软件包都需要加 ":ensure t"
;; `use-package-always-defer' 避免每个软件包都需要加 ":defer t"
(setq use-package-always-ensure t
use-package-always-defer t
use-package-enable-imenu-support t
use-package-expand-minimally t)
更换个主题
最初教程演示采用的主题是 gruvbox-theme。
(use-package gruvbox-theme
:init (load-theme 'gruvbox-dark-soft t))
最初教程顺便配置一个好看一点的Mode Line。
(use-package smart-mode-line
:init
(setq sml/no-confirm-load-theme t
sml/theme 'respectful)
(sml/setup))
但后来我还是倾向于使用内置的
modus主题(28+),审美这东西,还是看你自己的爱好。
工程化管理配置(1)功能拆分
到此为止,在~/.emacs 中配置了很多的内容,开始显得很乱:
- 初始化Elpa
- 安装扩展
- 添加主题
是时候分类处理了。就像一个开发项目那样。尝试着把配置按照功能不同拆分成不同的文件。如:
- lisp/init-elpa.el用于存放Elpa和Package初始化
- lisp/init-package.el用于存放安装的扩展
- lisp/init-ui.el用于存放界面主题相关配置
- 如何在初始化文件中把它们联系在一起(调用)?
工程化管理配置(2)文件加载与调用
先设置加载的目标目录到 load-path 中。
(add-to-list 'load-path (expand-file-name (concat user-emacs-directory "lisp")))
各个文件通过 provide 暴露对外调用的名称。如:
(provide 'init-ui)
然后在 init.el 文件中通过 require 调用:
(require 'init-ui)
关于自定义的配置
建议写入一个单独的文件,对外开源的时候,该文件不被提交到Git中。如,custom.el
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
这样就会把通过图形界面做的一些配置,写入到这里了。
操作系统判断
后面的部分配置会因操作系统不同而产生不同配置代码,所以有必要对操作系统进行判断。
(defconst *is-mac* (eq system-type 'darwin))
(defconst *is-linux* (eq system-type 'gnu/linux))
(defconst *is-windows* (or (eq system-type 'ms-dos) (eq system-type 'windows-nt)))
其中Windows的判断还可以放的宽一点:
(defconst *is-windows* (memq system-type '(ms-dos windows-nt cygwin)))
macOS平台将Command键映射为Meta
对于Mac键盘来说,Command键距离x的位置与Windows键盘更相近,所以习惯上可以修改这个按键映射为Meta,如果你不需要这个设置,可以不用管。
(when *is-mac* (setq mac-command-modifier 'meta)
(setq mac-option-modifier 'none))
通过修改字体解决Windows上Emacs的卡顿
方案是修改字体,最初的版本中我会建议你这样修改字体:
现在的方案中我会推荐你这样修改字体:
(defvar cn-fonts-list '("黑体" "STHeiti" "微软雅黑" "文泉译微米黑")
"定义使用的中文字体候选列表.")
(defvar en-fonts-list '("Cascadia Code" "Courier New" "Monaco" "Ubuntu Mono")
"定义使用的英文字体候选列表.")
(defvar emoji-fonts-list '("Apple Color Emoji" "Segoe UI Emoji" "Noto Color Emoji" "Symbola" "Symbol")
"定义使用Emoji字体候选列表.")
;;;###autoload
(defun tenon--font-setup ()
"Font setup."
(interactive)
(let* ((cf (tenon--available-font cn-fonts-list))
(ef (tenon--available-font en-fonts-list))
(em (tenon--available-font emoji-fonts-list)))
(when ef
(dolist (face '(default fixed-pitch fixed-pitch-serif variable-pitch))
(set-face-attribute face nil :family ef)))
(when em
(dolist (charset `(unicode unicode-bmp ,(if (> emacs-major-version 27) 'emoji 'symbol)))
(set-fontset-font t charset em nil 'prepend)))
(when cf
(dolist (charset '(kana han cjk-misc bopomofo))
(set-fontset-font t charset cf))
(setq face-font-rescale-alist
(mapcar (lambda (item) (cons item 1.2)) `(,cf ,em))))))
你可以在你的custom.el中设置cn-fonts-list来自定义字体,而不需要改写配置代码,配置中的字体仅做兜底使用。
建议增加的一点启动配置
设置系统的编码,避免各处的乱码。我最初的教程中是建议你这样写:
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setq default-buffer-file-coding-system 'utf-8)
其实,最新的配置里面我会推荐你这样写。这两行代码足够了。
(prefer-coding-system 'utf-8)
(unless *is-windows*
(set-selection-coding-system 'utf-8))
设置垃圾回收阈值,加速启动速度。
(setq gc-cons-threshold most-positive-fixnum)
测试启动耗时
通过 benchmark-init 包进行启动耗时的测量。
(use-package benchmark-init
:init (benchmark-init/activate)
:hook (after-init . benchmark-init/deactivate))
启动完成后可以执行:
M-x benchmark-init/show-durations-tree 或者 M-x benchmark-init/show-durations-tabulated来查看启动的耗时细节。
中断命令输入
C-g在输入任何命令的时候,可随时通过该快捷键放弃命令的继续键入。
用y/n来代替yes/no
(defalias 'yes-or-no-p 'y-or-n-p)
为了项目管理的统一化,可以用如下的use-package写法(其实完全没有必要,就一行代码,不要过度包装):
(use-package emacs
:config (defalias 'yes-or-no-p 'y-or-n-p))
显示行号
行号的类型
从Emacs 26开始,自带了行号显示功能,可以通过设置display-line-numbers-type变量的值,来改变行号的类型。可取值有:
- relative,相对行号
- visual,可视化行号
- t
行号配置(不一定非要用use-package,只保留config后面两行即可)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
Emacs文本编辑
文本编辑之选中/复制/剪切/粘贴
选中
- 方法一,使用鼠标拖动选中
- 方法二,标记开始位置,然后通过移动光标到结束位置
复制 M-w
剪切 C-w
粘贴 C-y ;; 速记 Yank
文本编辑之删除
场景一:从光标位置到行尾的删除
C-k
场景二:删除当前行
我最初的视频教程中认为默认没有这样的快捷键,可以安装一个扩展来实现,crux,该扩展提供了包含该场景在内的一系列优化快捷命令。
(use-package crux
:bind ("C-c k" . crux-smart-kill-line))
但其实是有这样的快捷按键的,C-S-<Backspace> (kill-whole-line)。
场景三:一次性删除到前/后面的第一个非空字符(删除连续的空白)
通过hungry-delete扩展实现,该功能。
(use-package hungry-delete
:bind (("C-c DEL" . hungry-delete-backward)
("C-c d" . hungry-delete-forward)))
文本编辑之行/区域上下移动
在VSCode或Jetbrains家族的编辑器中,上下移动行/块是非常容易的,但原生的Emacs没有提供这样的功能。可通过插件drag-stuff来辅助实现。
(use-package drag-stuff
:bind (("<M-up>" . drag-stuff-up)
("<M-down>" . drag-stuff-down)))
或者使用move-dup插件:
(use-package move-dup
:hook (after-init . global-move-dup-mode))
文本编辑之原生搜索/替换
Emacs原生提供了强大的搜索和替换功能。
-
当前位置到文档结尾的搜索 C-s
-
当前位置到文档开始的搜索 C-r
-
替换 M-%
替换时按下y确认替换,n跳过本处的替换,!全部替换。
文本编辑之强化搜索
著名的ivy-counsel-swiper三剑客,就是为了强化搜索(同时优化了一系列Minibuffer的操作)。
文本编辑之自动补全
Emacs界补全两大垄断插件,Auto-Complete和Company(Complete Anything)。时代和特性原因,Company呈现压倒性优势。
我最早的代码建议你这样写:
最新的代码我会建议你这样写:
(use-package company
:hook (after-init . global-company-mode)
:config (setq company-minimum-prefix-length 1
company-show-quick-access t))
文本编辑之语法检查
最初的教程中我建议你使用Flycheck,而不是Flymake,受其他的大牛以及历史的影响。但如今我还是建议你使用内置的Flymake,因为它已经非常好用了。
(use-package flymake
:hook (prog-mode . flymake-mode)
:config
(global-set-key (kbd "M-n") #'flymake-goto-next-error)
(global-set-key (kbd "M-p") #'flymake-goto-prev-error))
文本编辑之行排序
M-x sort-lines
文本编辑之顺序更换
光标前后两个字符互换 C-t
光标前后两个单词互换 M-t
文本编辑之字数统计
整个Buffer统计
M-= 或者 M-x count-words-region
选中区域统计
先选中需要统计的区域,然后执行 M-x count-words
Emacs常用插件
crux优化Emacs常用操作
- 优化版的回到行首
- 快速打开Emacs配置文件
- 快速连接两行等
(use-package crux
:bind (("C-a" . 'crux-move-beginning-of-line)
("C-c ^" . 'crux-top-join-line)
("C-x ," . 'crux-find-user-init-file)
("C-c k" . 'crux-smart-kill-line)))
其实,快速回到行首这个功能我现在更推荐你使用C-a以及M-m。这样的快捷按键既是内置,而且明确。
如何记忆越来越长的快捷键
如果你不喜欢用鼠标在菜单栏点击的化,你其实可以用Which-Key这款插件来辅助你“记忆”。
(use-package which-key
:defer nil
:config (which-key-mode))
当你按下一个按键时,它会提示你下一个按键的含义。并等待你去按下。
Emacs窗口管理
窗口管理之Buffer管理
Buffer切换
C-x b
杀死当前Buffer
C-x k
批量管理Buffer
C-x C-b ;; 进入Buffer列表
- d ;; 标记删除
- u ;; 取消当前行标记
- U ;; 取消全部标记
- x ;; 执行操作
- ? ;; 查看按键帮助
窗口管理之MiniBuffer交互优化
显示在左下角的MiniBuffer移动视线范围大,移动到中央位置,更合适一些。
窗口管理之分屏
开启横向分屏 C-x 3
开启纵向分屏 C-x 2
只保留当前分屏 C-x 1
关闭当前分屏 C-x 0
窗口管理之分屏宽度调整
增加高度 C-x ^
增加/减少宽度 C-x { C-x }
窗口管理之快速切换分屏
默认可通过以下快捷键进行窗口的循环跳转: C-x o
当分屏很多的时候效率非常低。通过ace-window可快速进行窗口间的跳转。类似的插件较多,但该款为最佳方案。
(use-package ace-window
:bind (("M-o" . 'ace-window)))
窗口管理之Tab标签页管理
C-x t 后面继续输入
- 2 ;; 新建Tab
- 1 ;; 关闭其它Tab
- 0 ;; 关闭当前Tab
- b ;; 在新Tab中打开Buffer
编程语言
eglot实现IDE
在Emacs编程的世界里,快速实现IDE,有两种方案,分别是这一节的eglot以及下一节的lsp-mode。关于两者的对比可能会形成非常大量的文字。此处我挑选几个典型的来说明一下:
- eglot比较轻量级,lsp-mode相对比较重
- eglot无第三方依赖,lsp-mode有非常多的第三方依赖
- eglot实现的功能够用,但不丰富;lsp-mode功能非常丰富
所以两者我都会进行讲解,使用哪个的选择权留给读者。
如果你只是想体验一下,其实可以通过 package-install 的方式安装eglot,然后进入到某一个编程语言的文件中,通过 M-x eglot来启动。而如果你像我一样喜欢它,则下面的配置供你参考。
(use-package eglot
:hook ((c-mode
c++-mode
go-mode
java-mode
js-mode
python-mode
rust-mode
web-mode) . eglot-ensure)
:bind (("C-c e f" . #'eglot-format)
("C-c e a" . #'eglot-code-actions)
("C-c e i" . #'eglot-code-action-organize-imports)
("C-c e q" . #'eglot-code-action-quickfix))
:config
;; (setq eglot-ignored-server-capabilities '(:documentHighlightProvider))
(add-to-list 'eglot-server-programs '(web-mode "vls"))
(defun eglot-actions-before-save()
(add-hook 'before-save-hook
(lambda ()
(call-interactively #'eglot-format)
(call-interactively #'eglot-code-action-organize-imports))))
(add-hook 'eglot--managed-mode-hook #'eglot-actions-before-save))
上面是我的eglot的配置,添加了我日常使用的一些编程语言、快捷按键以及一些自动格式化与自动保存/管理导入的包的配置。
注意:你一定要先安装对应的language-server,并配置好环境变量。例如对c/cpp来说就需要是ccls或者clangd,对于rust来说,就需要是rust-analyzer,对于go来说就是gopls。
lsp-mode实现IDE
lsp-mode的配置相对来说也差不多。但是它有非常丰富的特性可配置。下图是一个比较简化的配置。
(use-package lsp-mode
:commands (lsp lsp-deferred)
:init
(defun lsp-save-actions ()
"LSP actions before save."
(add-hook 'before-save-hook #'lsp-organize-imports t t)
(add-hook 'before-save-hook #'lsp-format-buffer t t))
:hook ((lsp-mode . #'lsp-enable-which-key-integration)
(lsp-mode . #'lsp-save-actions)
((c-mode
c++-mode
go-mode
java-mode
js-mode
python-mode
rust-mode
web-mode) . lsp-deferred))
:config
(setq lsp-auto-guess-root t
lsp-headerline-breadcrumb-enable nil
lsp-keymap-prefix "C-c l"
lsp-log-io nil)
(define-key lsp-mode-map (kbd "C-c l") lsp-command-map))
更多的配置可参考官网:github.com/emacs-lsp/l…
同样的,你也需要提前安装好language-server并配置好环境变量。
由于lsp-mode的丰富性,你还可以安装lsp-ui来提升图形操作的体验:
(use-package lsp-ui
:after lsp-mode
:init
(setq lsp-ui-doc-include-signature t
lsp-ui-doc-position 'at-point
lsp-ui-sideline-ignore-duplicate t)
(add-hook 'lsp-mode-hook 'lsp-ui-mode)
(add-hook 'lsp-ui-mode-hook 'lsp-modeline-code-actions-mode)
:config
(define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
(define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references))
对于调试的场景,你还可以安装dap-mode以及对应的调试器来使用:
(use-package dap-mode
:init
(add-hook 'lsp-mode-hook 'dap-mode)
(add-hook 'dap-mode-hook 'dap-ui-mode)
(add-hook 'dap-mode-hook 'dap-tooltip-mode)
;; (add-hook 'python-mode-hook (lambda() (require 'dap-python)))
;; (add-hook 'go-mode-hook (lambda() (require 'dap-go)))
;; (add-hook 'java-mode-hook (lambda() (require 'dap-java)))
)
看上去lsp-mode是不是比eglot丰富更多?但你也要注意,在一些机器上,尤其是Windows机器,lsp-mode会出现卡顿等性能问题,而eglot基本不会。
Java特殊配置
使用了上面的LSP客户端后,一般的环境应该很容易配置或者无需配置,例如gopls,pylsp等,但也有一些编程语言的服务器需要一些额外的配置。例如c/c++的情况下,例如Java的情况。
Java的语言服务器是来自Eclipse的jdtls,最新版本的jdtls提供了一个可执行的文件,对于非Windows环境,只要把这个bin目录放到环境变量中即可。但他们提供的可执行脚本是基于Python写成的,这在Windows上无法变成可执行文件。
所以你需要额外生成一个可执行文件,或者自己写一个jdtls.bat的适合Windows的可执行文件。
@echo off
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
cd /d %~dp0
java^
-Declipse.application=org.eclipse.jdt.ls.core.id1^
-Dosgi.bundles.defaultStartLevel=4^
-Declipse.product=org.eclipse.jdt.ls.core.product^
-Dosgi.checkConfiguration=true^
-Dosgi.sharedConfiguration.area=../config_win^
-Dosgi.sharedConfiguration.area.readOnly=true^
-Dosgi.configuration.cascaded=true^
-noverify^
-Xms1G^
--add-modules=ALL-SYSTEM^
--add-opens java.base/java.util=ALL-UNNAMED^
--add-opens java.base/java.lang=ALL-UNNAMED^
-jar ../plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar^
%CMD_LINE_ARGS%
或者使用pyinstaller --onefile来生成(源代码如下)。
import os
import sys
if getattr(sys, "frozen", False):
dir_path = os.path.dirname(os.path.dirname(os.path.abspath(sys.executable)))
else:
dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
cmd = (
"java"
" -Declipse.application=org.eclipse.jdt.ls.core.id1"
" -Dosgi.bundles.defaultStartLevel=4"
" -Declipse.product=org.eclipse.jdt.ls.core.product"
" -Dosgi.checkConfiguration=true"
f" -Dosgi.sharedConfiguration.area={dir_path}/config_win"
" -Dosgi.sharedConfiguration.area.readOnly=true"
" -Dosgi.configuration.cascaded=true"
" -noverify"
" -Xms1G"
" --add-modules=ALL-SYSTEM"
" --add-opens java.base/java.util=ALL-UNNAMED"
" --add-opens java.base/java.lang=ALL-UNNAMED"
f" -jar {dir_path}/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar"
f" {' '.join(sys.argv[1:])}"
)
os.system(cmd)
针对Windows
很久以来,很多人对在Windows下使用Emacs的体验,给的评价并不高。包括我。经过了一段时间的折腾之后,我想说的是,没有我们说的那么差。它可能无法与Linux/macOS下的体验进行媲美,但绝对可以日常使用,甚至有可能成为你的主力编辑器。
一般来说,Windows下需要解决几个方面的问题就可以了:
- 字体,这是卡顿的罪魁祸首
- 如果你喜欢mactype这样的插件,一定记得把emacs排除掉,非常明显的解决卡顿
- 部分插件替代,例如用VC替代magit,例如用内置的project代替projectile等
- Windows也可以使用daemon
结束语
之所以会重写,而且以后还会继续不断的升级(这就是为什么这篇已经加上了版本号的原因),更多的还是希望自己对Emacs的使用和理解,能够保持更新,同时希望把这些更新带给更多的初学者,以及有需要的人。交更多的志同道合的朋友。
不出意外,我后面应该会**一年出一个大版本**,虽然可能更新的内容不多。而且基本上,后面会融合更多的《Emacs轻奢之路》的内容(如果你感兴趣,可以阅读那一本小册)。我觉得那是使用Emacs的必经之路。如果你喜欢,可以保持对我以及这两个系列的关注。同时我也欢迎有更多的内容补充进来,欢迎给我提意见/建议。
发布版本历史:
- v0.1,视频版本,2020年3月起陆续发布
- v1.0,当前版本,2022年4月