Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/emacs-china/spacemacs-rocks
Happy Hacking Emacs & Spacemacs (Simplified Chinese)
https://github.com/emacs-china/spacemacs-rocks
emacs learn-emacs spacemacs
Last synced: 4 days ago
JSON representation
Happy Hacking Emacs & Spacemacs (Simplified Chinese)
- Host: GitHub
- URL: https://github.com/emacs-china/spacemacs-rocks
- Owner: emacs-china
- Created: 2015-10-10T13:27:28.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2024-03-04T04:40:34.000Z (11 months ago)
- Last Synced: 2025-01-10T12:51:24.516Z (11 days ago)
- Topics: emacs, learn-emacs, spacemacs
- Language: CSS
- Homepage: http://book.emacs-china.org
- Size: 1.02 MB
- Stars: 2,120
- Watchers: 137
- Forks: 323
- Open Issues: 52
-
Metadata Files:
- Readme: README.org
- Contributing: CONTRIBUTING.org
Awesome Lists containing this project
README
# -*- mode: org; -*-
#+HTML_HEAD:
#+HTML_HEAD:#+HTML_HEAD:
#+HTML_HEAD:
# #+HTML_HEAD: // www.pirilamp.org/styles/lib/js/jquery.stickytableheaders.js 404 Now
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD: hljs.initHighlightingOnLoad();#+AUTHOR: zilongshanren
#+CREATOR: li-xinyang
#+TITLE: Master Emacs in 21 Days
#+EMAIL: [email protected]
#+OPTIONS: toc:3 num:nil
#+STARTUP: showall
#+OPTIONS: ^:nil* 21 天学会 Emacs(2022 Edition)
*GitHub* [[https://github.com/emacs-china/Spacemacs-rocks][Emacs Rocks]] *作者* [[https://github.com/zilongshanren/][zilongshanren]] *编者* [[https://github.com/li-xinyang][li-xinyang]], [[https://github.com/lsytj0413][lsytj0413]]
在这一季中我们计划用 21 天学习 Emacs 的使用。从基础安装开始到可以
运用到工作生产环节中。为了确保学习质量,请务必完成和理解计划中的每一项学习任务。(新的系列全部使用 Vallina Emacs)Update(2022 年 1 月 15 日): 本系列视频教程最早录制于 2016 年,距今已经有 5 年多的历史了,
在此期间 Emacs 社区又进化了非常多。出现了更活跃的 Doom Emacs 社区配置,拥有 GCC Emacs,所以
现在回头来看当时的视频教程,显得多少有些过时了。以前 21 天的视频教程显得有些冗长,我打算在 2022 年
更新所有这些视频教程,并且控制每一个视频的时长(20 分钟左右),希望这个系列教程能够帮助到大家。*本视频的代码仓库:* https://gitee.com/emacs-china/emacs.d
原来 21 天的视频地址:
- [[https://www.youtube.com/watch?v=0hpVuoyO8_o&list=PLZx9tb9Niew8qMjpCjeYnsezCE-s5mKw_][Youtube]]
- [[https://www.bilibili.com/video/BV1sp4y1Y73S?from=search&seid=10747273033486124295&spm_id_from=333.337.0.0][Bilibili]]
原来 21 天的教程地址:[[http://book1.emacs-china.org/][《21天学会Emacs》]]
* 第一天:准备开始(安装与改键)
视频地址如下:
- [[https://www.youtube.com/watch?v=0HZa7ttGLiU][Youtube]]
- [[https://www.bilibili.com/video/BV12P4y1j7EL/][Bilibili]]*说在最前面*
如果你第一次听说 Emacs 你可以在[[http://emacs.sexy/][性感的 Emacs(Emacs is Sexy)]]一文中找到使用它的理
由!我相信你一定会被它的强大所吸引。如果你还没有安装 Emacs 可以在 Doom Emacs 的安装文档中查找[[https://github.com/hlissner/doom-emacs/blob/master/docs/getting_started.org#install][安装方法]],根据你所使用的操作系统去下载对应
版本的 Emacs 就行了。(新手不推荐从源码进行编译安装,因为这会比较困难)因为考虑到比较多的用户之前可能没有接触过 Mac 或者 Linux,所以新的系列视频我会直接使用 Windows 系统来
进行演示。Windows 下配置 Emacs 环境可以参考我之前在论坛写的[[https://emacs-china.org/t/windows-emacs/7907][文章]]。由于 Windows 系统的一些限制,某一些 Emacs 的功能(Magit,lsp 等)表现并不是很好(主要指的是性能),读者可以
尝试安装 WLS 来使用 Emacs,具体方法可以参考[[https://hkvim.com/post/windows-setup/][这篇文章]]。在开始本教程之前请务必先完成 Emacs 提供的官方教程(完成时间大约 30 分钟),它可
以通过使用 =C-h t= (同时按住 Ctrl 与 h 键,接着按 t 键 =t= 在这里代表 tutorial)
在 Emacs 中直接将其打开。(当然你也可以在观看视频之后再去阅读 Emacs Tutorial)Emacs Lisp 是 Emacs 所用的编程语言,你可以在阅读[[https://learnxinyminutes.com/docs/elisp/][这篇教程(Learn X in Y Minutes)]]
后很快地了解它的基础用法。** 基础操作
在讲解基本操作之前,先跟大家讲一下改键。改键的作用除了可以让你的小拇指更健康以外,还可以统一我们的交流语言,
让大家后面学习过程可以更轻松。(这部分如果没有相关基础,强烈建议先看视频是怎么操作的)Windows 键盘布局:
[[./Images/1600px-KB_United_States-NoAltGr.svg.png]]
Windows 改键方法:
使用 SharpKeys 来把 Left Window 键改成 Left Alt 键,Left Alt 键改成 App 键,大小写键改成 Ctrl 键。
[[./Images/sharpKeys.png]]
Emacs 默认 Alt 键就是 Meta,而 App 键我们改成 super 键,可以通过下面的 Elisp 代码来完成。
#+begin_src emacs-lisp
(setq w32-apps-modifier 'super) ; 通过SharpKeys改成了 Application
#+end_srcMac 键盘布局:
[[./Images/mac-keyboard-layout.jpeg]]
Mac 下面大小写键改成 Ctrl 键(参考视频),Mac 系列只需要修改这个按键,其他的按键可以通过 Elisp 来修改:
#+begin_src emacs-lisp
(setq mac-option-modifier 'meta
mac-command-modifier 'super)
#+end_src常见符号所代表的意义如下
- M(eta):统一改到 option 键(Mac),left windows 键(Windows)
- s(uper):统一改到 command 键(Mac),left Alt 键(windows)
- S(Shift):不用修改
- C(trl):统一改成 Caps Lock(大小写切换键,这样可以拯救你的小拇指健康)光标的移动是编辑器中最常用的操作所以必须熟知。(只需要掌握这些基础的光标移动操作,后续我会介绍 Vim 的光标移动操作,
我个人认为 Vim 的光标移动更高效,大家先熟知这几个常用的移动命令即可。)- =C-f= 为前移一个字符, =f= 代表 forward。
- =C-b= 为后移一个字符, =b= 代表 backward。
- =C-p= 为上移至前一行, =p= 代表 previous。
- =C-n= 为上移至下一行, =n= 代表 next。
- =C-a= 为移至行首, =a= 代表 ahead。
- =C-e= 为移至行尾, =e= 代表 end。为什么不使用鼠标而去学习这些奇怪的按键组合呢?因为这些按键在某些时候是非常高效的,比如在 Emacs 里面,Shell 终端里面,
甚至整个 Mac 系统都内置了这种按键。我本人在使用 Vim 或者其他 IDE 的时候也会使用 Emacs 的这套按键。*学习可以迁移的技能*,这一点非常重要!一旦学会了将可以终身受用。
现在我们可以把 Mac 下面的复制、粘贴、剪切、全选等命令移植到 Emacs 中来了,并且这一套按键是跨平台的。
#+begin_src emacs-lisp
(global-set-key (kbd "s-a") 'mark-whole-buffer) ;;对应Windows上面的Ctrl-a 全选
(global-set-key (kbd "s-c") 'kill-ring-save) ;;对应Windows上面的Ctrl-c 复制
(global-set-key (kbd "s-s") 'save-buffer) ;; 对应Windows上面的Ctrl-s 保存
(global-set-key (kbd "s-v") 'yank) ;对应Windows上面的Ctrl-v 粘贴
(global-set-key (kbd "s-z") 'undo) ;对应Windows上面的Ctrol-z 撤销
(global-set-key (kbd "s-x") 'kill-region) ;对应Windows上面的Ctrol-x 剪切
#+end_src* 第二天: 打造属于你的记事本
视频地址如下:- [[https://www.youtube.com/watch?v=fxE1L-scvbk][Youtube]]
- [[https://www.bilibili.com/video/BV1jY411h7Ts/][Bilibili]]** 内置功能
Emacs 功能强大,但是部分功能默认情况下并未开启。下面就有几个例子,
编辑器内显示行号可使用 =M-x linum-mode= 来开启。
*获取帮助*
Emacs 是一个富文档编辑器(Self document, extensible editor)而下面的三种方法在学
习 Emacs 的过程中也非常重要。他们分别是,- =C-h k= 寻找快捷键的帮助信息
- =C-h v= 寻找变量的帮助信息
- =C-h f= 寻找函数的帮助信息*** 给 Windows 右键菜单添加 OpenWithEmacs 功能
#+begin_src
Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\*\shell]
[HKEY_CLASSES_ROOT\*\shell\openwemacs]
@="&Edit with Emacs"
[HKEY_CLASSES_ROOT\*\shell\openwemacs\command]
@="C:\\emax64\\bin\\emacsclientw.exe -n \"%1\""
[HKEY_CLASSES_ROOT\Directory\shell\openwemacs]
@="Edit &with Emacs"
[HKEY_CLASSES_ROOT\Directory\shell\openwemacs\command]
@="C:\\emax64\\bin\\emacsclientw.exe -n \"%1\""
#+end_src使用这个 OpenWithEmacs 的功能,Emacs 需要开启 Server Mode,代码如下:
#+begin_src emacs-lisp
(server-mode 1)
#+end_src
* 第三天:Elisp 基础、Org 基础和包管理器视频地址如下:
- [[https://www.bilibili.com/video/BV1yP4y177xj?spm_id_from=333.999.0.0][Bilibili]]
- [[https://www.youtube.com/watch?v=-tX66neahhM&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=4&t=3s][Youtube]]** 学习基础 Elisp
请务必完成[[https://learnxinyminutes.com/docs/elisp/][这篇教程(Learn X in Y Minutes)]]来了解 Elisp 的使用(阅读时间大约 15
分钟),你也可以在[[https://learnxinyminutes.com/docs/zh-cn/elisp-cn/][这里]]找到它的中文版。Emacs Lisp 为一个函数式的语言,所以它全部
功能都是由函数来实现的。下面为一些简单的例子
#+BEGIN_SRC emacs-lisp
;; 2 + 2
(+ 2 2);; 2 + 3 * 4
(+ 2 (* 3 4));; 定义变量
(setq name "username")
(message name) ; -> "username";; 定义函数
(defun func ()
(message "Hello, %s" name));; 执行函数
(func) ; -> Hello, username;; 设置快捷键
(global-set-key (kbd "") 'func);; 使函数可直接被调用可添加 (interactive)
(defun func ()
(interactive)
(message "Hello, %s" name))
#+END_SRC** 开始 Hacking!
Emacs 的配置文件默认保存在 =~/.emacs.d/init.el= 文件中。(如果其不存在可自行创建,
配置文件也可保存在 =~/.emacs= 文件中,他们之间的区别我们会在后面做讨论)**注意:** 如果希望把配置放在 =~/.emacs.d/init.el= 文件中,那么需要手工删除
=~/.emacs= 文件。在开始配置之前让我们先来区别 Emacs 中 Major Mode 与 Minor Mode 的区别。Major
Mode 通常是定义对于一种文件类型编辑的核心规则,例如语法高亮、缩进、快捷键绑定等。
而 Minor Mode 是除去 Major Mode 所提供的核心功能以外的额外编辑功能(辅助功能)。
例如在下面的配置文件中 =tool-bar-mode= 与 =linum-mode= 等均为 Minor Mode*。简单来说就是,一种文件类型同时只能存在一种 Major Mode 但是它可以同时激活一种或多
种 Minor Mode。如果你希望知道当前的模式信息,可以使用 =C-h m= 来显示当前所有开启
的全部 Minor Mode 的信息。*简单的编辑器自定义*
下面是一些简单的编辑器配置信息,你需要做的就是将其写入你的配置文件中
( =~/.emacs.d/init.el= )即可。#+BEGIN_SRC emacs-lisp
;; 关闭工具栏,tool-bar-mode 即为一个 Minor Mode
(tool-bar-mode -1);; 关闭文件滑动控件
(scroll-bar-mode -1);; 显示行号
(global-linum-mode 1);; 更改光标的样式(不能生效,解决方案见第二集)
(setq cursor-type 'bar)(icomplete-mode 1)
;; 快速打开配置文件
(defun open-init-file()
(interactive)
(find-file "~/.emacs.d/init.el"));; 这一行代码,将函数 open-init-file 绑定到 键上
(global-set-key (kbd "") 'open-init-file)#+END_SRC
在每次编辑配置文件后,刚刚做的修改并不会立刻生效。这时你需要重启编辑器或者重新加
载配置文件。重新加载配置文件你需要在当前配置文件中使用 =M-x load-file= 双击两次
回车确认默认文件名,或者使用 =M-x eval-buffer= 去执行当前缓冲区的所有 Lisp 命令。
你也可以使用 =C-x C-e= 来执行某一行的 Lisp 代码。这些可使刚刚修改的配置文件生效。
当然你也可以将这些函数绑定为快捷键。** 插件管理
使用默认的插件管理系统(可在菜单栏 =Options > Manage Emacs Packages= 中找到)安
装 [[http://company-mode.github.io/][Company]] 插件,他是一个用于代码补全的插件。它的名字代表补全一切的意思( *Comp*
lete *Any* thing)。因为默认的插件管理系统提供的插件十分有限,所以我们会在之后的
几天中继续将其强化。使用的下面的配置将 Company-mode 在全局模式下激活
#+BEGIN_SRC emacs-lisp
; 开启全局 Company 补全
(global-company-mode 1);; company mode 默认选择上一条和下一条候选项命令 M-n M-p
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
#+END_SRC** Org-mode
简单的 Org-mode 使用,它可以列出提纲,并方便地使用 =tab= 键来对其进行展开与关闭。
=C-c C-t= 可以将一个条目转换成一条待办事件。#+BEGIN_SRC org
,* 为一级标题
,** 为二级标题
,*** 为三级标题并以此类推
#+END_SRC* 第四天:增强 Emacs 补全,让 Hacking 更加有趣和可视化
视频地址如下:
- [[https://www.youtube.com/watch?v=HzlLxWTD6QY][Youtube]]- [[https://www.bilibili.com/video/BV1uL4y1t7Lm/][Bilibili]]
** 关于 lexical binding
#+begin_src emacs-lisp
;;在文件最开头添加地个 文件作用域的变量设置,设置变量的绑定方式
;; -*- lexical-binding: t -*-
(let ((x 1)) ; x is lexically bound.
(+ x 3))
⇒ 4(defun getx ()
x) ; x is used free in this function.(let ((x 1)) ; x is lexically bound.
(getx))
;;error→ Symbol's value as variable is void: x
#+end_src关于[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] 更多的细节,可以自行阅读 Emacs 的官方文档。
#+begin_src emacs-lisp
;; 更改显示字体大小 16pt
;; http://stackoverflow.com/questions/294664/how-to-set-the-font-size-in-emacs
(set-face-attribute 'default nil :height 160);;;;让鼠标滚动更好用
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control) . nil)))
(setq mouse-wheel-progressive-speed nil)#+end_src
** 配置 gnu 和 melpa 镜像
在进行美化之前我们需要配置插件的源(默认的源非常有限),最常使用的是 [[https://melpa.org/][MELPA]]
(Milkypostman's Emacs Lisp Package Archive)。它有非常多的插件(3000 多个插件)。
添加源后,我们就可以使用 =M-x package-list-packages=
来查看所有 MELPA 上的插件了。在表单中可以使用 =i= 来标记安装 =d= 来标记删除,
=U= 来更新,并用 =x= 来确认。你也可以使用 =u= 来撤销标记操作。你可以直接将下面的代码复制到你的配置文件顶端,从而直接使用 Melpa 作为插件的源。
#+BEGIN_SRC emacs-lisp
(require 'package)
(setq package-archives '(("gnu" . "http://elpa.zilongshanren.com/gnu/")("melpa" . "http://elpa.zilongshanren.com/melpa/")))
(package-initialize);;防止反复调用 package-refresh-contents 会影响加载速度
(when (not package-archive-contents)
(package-refresh-contents));;modeline上显示我的所有的按键和执行的命令
(package-install 'keycast)
(keycast-mode t)
#+END_SRC** 增强 minibuffer 补全:[[https://github.com/minad/vertico][vertico]] 和 [[https://github.com/oantolin/orderless][Orderless]]
#+begin_src emacs-lisp
(package-install 'vertico)
(vertico-mode t)(package-install 'orderless)
(setq completion-styles '(orderless))
#+end_src** 配置 [[https://github.com/minad/marginalia][Marginalia]] 增强 minubuffer 的 annotation
#+begin_src emacs-lisp
(package-install 'marginalia)
(marginalia-mode t)#+end_src
** minibuffer action 和自适应的 context menu:[[https://github.com/oantolin/embark][Embark]]
#+begin_src emacs-lisp(package-install 'embark)
(global-set-key (kbd "C-;") 'embark-act)
(setq prefix-help-command 'embark-prefix-help-command)#+end_src
** 增强文件内搜索和跳转函数定义:[[https://github.com/minad/consult][Consult]]
#+begin_src emacs-lisp
(package-install 'consult)
;;replace swiper
(global-set-key (kbd "C-s") 'consult-line)
;;consult-imenu
#+end_src* 第五天:手动安装插件和使用外部程序
视频地址如下:
- [[https://www.youtube.com/watch?v=EPZe8Ix_dnU][Youtube]]
- [[https://www.bilibili.com/video/BV1Kr4y1Y73S/][Bilibili]]** 手工安装插件和更多 Emacs 内置功能定制
如果你想深入学习 Emacs Lisp 可以阅读 GNU 提供的 [[https://www.gnu.org/software/emacs/manual/html_mono/eintr.html][An Introduction to Programming
in Emacs Lisp]] 。(也可以 =M-x info= 然后选择 Emacs Lisp Intro)我们先解决前一天中遇到的一些问题。首先是在对象是一个缓冲区局部变量(Buffer-local
variable)的时候,比如这里的 =cursor-type= ,我们需要区分 =setq= 与
=setq-default= : =setq= 设置当前缓冲区(Buffer)中的变量值, =setq-default= 设
置的为全局的变量的值(具体内容可以在 [[http://stackoverflow.com/questions/18172728/the-difference-between-setq-and-setq-default-in-emacs-lisp][StackOverflow 找到]])。下面是一个例子,用于
设置光标样式的方法。#+BEGIN_SRC emacs-lisp
(setq-default cursor-type 'bar)
(show-paren-mode t);;另外一件安装插件的方法
(add-to-list 'load-path (expand-file-name "~/.emacs.d/awesome-tab/"))(require 'awesome-tab)
(awesome-tab-mode t)
(defun awesome-tab-buffer-groups ()
"`awesome-tab-buffer-groups' control buffers' group rules.
Group awesome-tab with mode if buffer is derived from `eshell-mode' `emacs-lisp-mode' `dired-mode' `org-mode' `magit-mode'.
All buffer name start with * will group to \"Emacs\".
Other buffer group by `awesome-tab-get-group-name' with project name."
(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")
((derived-mode-p 'eshell-mode)
"EShell")
((derived-mode-p 'dired-mode)
"Dired")
((memq major-mode '(org-mode org-agenda-mode diary-mode))
"OrgMode")
((derived-mode-p 'eaf-mode)
"EAF")
(t
(awesome-tab-get-group-name (current-buffer))))))
#+END_SRC其次就是它使用到了 =quote=, 它其实就是我们之前常常见到的 ='= (单引号)的完全体。
因为它在 Lisp 中十分常用,所以就提供了简写的方法。#+BEGIN_SRC emacs-lisp
;; 下面两行的效果完全相同的
(quote foo)
'foo
#+END_SRC=quote= 的意思是不要执行后面的内容,返回它原本的内容(具体请参考下面的例子)
#+BEGIN_SRC emacs-lisp
(print '(+ 1 1)) ;; -> (+ 1 1)
(print (+ 1 1)) ;; -> 2
#+END_SRC更多关于 =quote= 的内容可以在[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Quoting.html][这里]]找到,或者在[[http://stackoverflow.com/questions/134887/when-to-use-quote-in-lisp][这里]]找到 StackOverflow 上对于它的讨论。
因为通常我们的配置文件以及项目文件均使用版本控制系统,所以自动生成的备份文件就显
得有些多余。我们还可以禁止 Emacs 自动生成备份文件,例如 =init.el~= 。( =~= 为后
缀的文件为自动生成的备份文件)我们可以使用下面的方法将其关闭。#+BEGIN_SRC emacs-lisp
(setq make-backup-files nil)
#+END_SRC使用下面的配置来加入最近打开过文件的选项让我们更快捷的在图形界面的菜单中打开最近
编辑过的文件。#+BEGIN_SRC emacs-lisp
(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-item 10);; 这个快捷键绑定可以用之后的插件 counsel 代替
;; (global-set-key (kbd "C-x C-r") 'recentf-open-files)
#+END_SRC=require= 的意思为从文件中加载特性,你可以在杀哥的网站读到关于 Emacs Lisp 库系统
的更多内容,文章在[[http://ergoemacs.org/emacs/elisp_library_system.html][这里]]。使用下面的配置文件将删除功能配置成与其他图形界面的编辑器相同,即当你选中一段文字
之后输入一个字符会替换掉你选中部分的文字。#+BEGIN_SRC emacs-lisp
(delete-selection-mode 1)
#+END_SRC下面的这些函数可以让你找到不同函数,变量以及快捷键所定义的文件位置。因为非常常用
所以我们建议将其设置为与查找文档类似的快捷键(如下所示),- =find-function= ( =C-h C-f= )
- =find-variable= ( =C-h C-v= )
- =find-function-on-key= ( =C-h C-k= )** 使用外网命令行工具
下载安装 [[https://github.com/m-parashar/emax64/releases/download/20200930/emax.7z][emax]],配置 emacs 加载路径#+begin_src emacs-lisp
(progn
(defvar emax-root (concat (expand-file-name "~") "/emax"))
(defvar emax-bin (concat emax-root "/bin"))
(defvar emax-bin64 (concat emax-root "/bin64"))(setq exec-path (cons emax-bin exec-path))
(setenv "PATH" (concat emax-bin ";" (getenv "PATH")))(setq exec-path (cons emax-bin64 exec-path))
(setenv "PATH" (concat emax-bin64 ";" (getenv "PATH")))(setq emacsd-bin (concat user-emacs-directory "bin"))
(setq exec-path (cons emacsd-bin exec-path))
(setenv "PATH" (concat emacsd-bin ";" (getenv "PATH")));;可选安装msys64
;;下载地址: http://repo.msys2.org/mingw/sources/
(setenv "PATH" (concat "C:\\msys64\\usr\\bin;C:\\msys64\\mingw64\\bin;" (getenv "PATH")));; (dolist (dir '("~/emax/" "~/emax/bin/" "~/emax/bin64/" "~/emax/lisp/" "~/emax/elpa/"))
;; (add-to-list 'load-path dir))
)
#+end_src
使用 M-x shell 来学习命令行操作,可以参考 https://missing.csail.mit.edu/2020/ 来学习,living in Emacs。
* 第六天:Emacs 作为超级前端
视频地址:
- [[https://www.youtube.com/watch?v=sr1mFqjE0YM][Youtube]]
- [[https://www.bilibili.com/video/BV1tm4y1o7pd/][Bilibili]]
** 使用 Emacs 来打开文件管理器
#+begin_src emacs-lisp
(shell-command-to-string "explorer.exe C:\\")(shell-command-to-string "explorer.exe ~/.emacs.d")
(shell-command-to-string
(encode-coding-string
(replace-regexp-in-string "/" "\\\\"
(format "explorer.exe %s" (expand-file-name "~/.emacs.d")))
'gbk))(defun consult-directory-externally (file)
"Open FILE externally using the default application of the system."
(interactive "fOpen externally: ")
(if (and (eq system-type 'windows-nt)
(fboundp 'w32-shell-execute))
(shell-command-to-string (encode-coding-string (replace-regexp-in-string "/" "\\\\"
(format "explorer.exe %s" (file-name-directory (expand-file-name file)))) 'gbk))
(call-process (pcase system-type
('darwin "open")
('cygwin "cygstart")
(_ "xdg-open"))
nil 0 nil
(file-name-directory (expand-file-name file)))))(define-key embark-file-map (kbd "E") #'consult-directory-externally)
;;打开当前文件的目录
(defun my-open-current-directory ()
(interactive)
(consult-directory-externally default-directory))#+end_src
** 增强 embark 和 consult,批量搜索替换大杀器#+BEGIN_SRC emacs-lisp
(package-install 'embark-consult)
(package-install 'wgrep)
(setq wgrep-auto-save-buffer t)(eval-after-load
'consult
'(eval-after-load
'embark
'(progn
(require 'embark-consult)
(add-hook
'embark-collect-mode-hook
#'consult-preview-at-point-mode))))(define-key minibuffer-local-map (kbd "C-c C-e") 'embark-export-write)
;;使用ripgrep来进行搜索
;;consult-ripgrep;;everyting
;;consult-locate
;; 配置搜索中文
(progn
(setq consult-locate-args (encode-coding-string "es.exe -i -p -r" 'gbk))
(add-to-list 'process-coding-system-alist '("es" gbk . gbk))
)
(eval-after-load 'consult
(progn
(setq
consult-narrow-key "<"
consult-line-numbers-widen t
consult-async-min-input 2
consult-async-refresh-delay 0.15
consult-async-input-throttle 0.2
consult-async-input-debounce 0.1)
))
#+END_SRC** 使用拼音进行搜索
#+begin_src emacs-lisp
(package-install 'pyim)(defun eh-orderless-regexp (orig_func component)
(let ((result (funcall orig_func component)))
(pyim-cregexp-build result)))(defun toggle-chinese-search ()
(interactive)
(if (not (advice-member-p #'eh-orderless-regexp 'orderless-regexp))
(advice-add 'orderless-regexp :around #'eh-orderless-regexp)
(advice-remove 'orderless-regexp #'eh-orderless-regexp)))(defun disable-py-search (&optional args)
(if (advice-member-p #'eh-orderless-regexp 'orderless-regexp)
(advice-remove 'orderless-regexp #'eh-orderless-regexp)));; (advice-add 'exit-minibuffer :after #'disable-py-search)
(add-hook 'minibuffer-exit-hook 'disable-py-search)(global-set-key (kbd "s-p") 'toggle-chinese-search)
#+end_src** Emacs 也很美
高亮当前行,当文本内容很多时可以很容易找到光标的位置。
#+BEGIN_SRC emacs-lisp
(global-hl-line-mode 1)
#+END_SRC*安装主题*
#+BEGIN_SRC emacs-lisp
(package-install 'monokai-theme)
#+END_SRC然后使用下面的配置使其每次打开编辑器时加载主题,
#+BEGIN_SRC emacs-lisp
(load-theme 'monokai 1)
#+END_SRC使用 =M-x customize-group= 后选择对应的插件名称,可以进入可视化选项区对指定的插
件做自定义设置。当选择 Save for future session 后,刚刚做的设计就会被保存在你的
配置文件( =init.el= )中。关于各个插件的安装与使用方法通常都可以在其官方页面找
到(GitHub Pages 或者是项目仓库中的 README 文件)。我们强烈建议大家在安装这些插
件后阅读使用方法来更好的将它们使用到你的日常工作当中使效率最大化。* 第七天:模块化配置文件管理
视频地址如下:
- [[https://www.youtube.com/watch?v=_imJVq7KNvA][Youtube]]
- [[https://www.bilibili.com/video/BV1yR4y1P7sD/?vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** 使用多文件存储配置文件
将不同的配置代码放置到不同的文件中,使其模块化,这让我们的后续维护变得更加简单。
下面是我们现在的 =~/.emacs.d/= 目录中的样子,#+BEGIN_EXAMPLE
├── auto-save-list # 自动生成的保存数据
├── elpa # 下载的插件目录
├── init.el # 我们的配置文件
└── recentf # 最近访问的文件列表
#+END_EXAMPLE通常我们只保存配置文件和对其进行版本控制,其他的插件均为在第一次使用编辑器时再通
过网络重新下载,当然你也可以选择将全部配置文件进行版本控制来保证自己时刻拥有最稳
定的生产环境。custom.el
#+begin_src emacs-lisp
(setq custom-file (expand-file-name "~/.emacs.d/custom.el"))
(load custom-file 'no-error 'no-message)
#+end_src现在我们想将原本混合在一起的配置文件分为下面的几个模块(每一个模块为一个独立的配
置文件并将其保存在指定的子目录中),它们分别是#+BEGIN_EXAMPLE
init-packages.el # 插件管理
init-ui.el # 视觉层配置
init-better-defaults.el # 增强内置功能
init-keybindings.el # 快捷键绑定
init-org.el # Org 模式相关的全部设定
custom.el # 存放使用编辑器接口产生的配置信息
#+END_EXAMPLE下面为将配置文件进行模块化后的目录结构,
#+BEGIN_EXAMPLE
├── init.el
└── lisp
├── custom.el
├── init-better-defaults.el
├── init-keybindings.el
├── init-packages.el
├── init-ui.el
└── init-org.el
#+END_EXAMPLE使用模块化配置就可以让我们在之后的配置中迅速的定位与更改配置内容,让整个过程变得
更有条理也更加高效。和之前一样 =init.el= 是配置文件的入口,现在它便成为了所有模块配置文件的入口,所
以要使用这些模块时,我们需要在其中引用需要加载的模块。下面以 =init-packages.el=
(此配置为添加插件的模块) 为例,详细说明如何模块化以及应用的方法。下面为 =~/.emacs.d/lisp/init-packages.el= 模块中的代码
#+BEGIN_SRC emacs-lisp
(require 'package)
(setq package-archives '(("gnu" . "http://elpa.zilongshanren.com/gnu/")("melpa" . "http://elpa.zilongshanren.com/melpa/")))
(package-initialize);;防止反复调用 package-refresh-contents 会影响加载速度
(when (not package-archive-contents)
(package-refresh-contents));; 文件末尾
(provide 'init-packages)
#+END_SRC下面为 =~/.emacs.d/init.el= 入口文件中的代码
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "~/.emacs.d/lisp/");; Package Management
;; -----------------------------------------------------------------
(require 'init-packages)
#+END_SRC模块化要做的其实非常简单,我们要做的其实就是把某一个更改编辑器某定部分(例如,插
件管理,显示层,快捷键绑定等)的配置代码写入一个独立的文件中并在末尾为其添加
=(provide 'module-name)= (这里我们的模块名为 =init-packages= )使其可以在入口文件
中被调用,然后再在入口文件中将其引用既可。这里需要注意的是,我们需要在入口文件中添加 =(add-to-list 'load-path
"~/.emacs.d/lisp/")= 这可以让 Emacs 找到需要加载的模块所处的位置。这里推荐大家两个还不错的 Emacs 配置:
https://github.com/condy0919/.emacs.d
https://github.com/seagle0128/.emacs.d
** 使用 Org 来管理配置文件
Org-mode 下的文学编程将颠覆你对于 Emacs 的看法。因为我们也可以使用 Org 来管理
Emacs 的配置文件(本人其实更倾向于用多个文件来管理配置文件)。在 Org-mode 中你可以直接开启新的缓冲区(Buffer)直接用相应的 Major Mode 来编辑代码块内的内容。在代码块中使用 C-c ' 会直接打开对应模式的缓冲区(不仅限于 Lisp)。 这样就使在 Org-mode 中编辑代码变的十分方便快捷。
使用 ") 'quickrun)
#+end_src** 使用 gdb 调试
1. 运行 M-x compile, 输入 g++ -g -o test.o test.cpp
2. 使用 M-x gud-gdb 输入 gdb ./test.o
3. 常用调试命令
| name | function |
|-----------------+----------------------------------------------------|
| list | 显示源代码 |
| break | 新增断点, break main, break 12(行号) |
| info | 查看断点或者局部变量信息 info breakpoints, info locals |
| run | 开始调试 |
| next | 类似 step over |
| step | 跳转到函数内部 |
| continue | 继续运行到下一个断点 |
| quit | 退出调试 |
| watch | 内存断点 |
| display | 类似 IDE 里面的 watch 功能 |
| break 11 if xxx | 条件断点 |* 第十三天:使用 Evil, 地球上最厉害的 vim 按键模拟
视频地址如下:
- [[https://www.youtube.com/watch?v=QqFaKyQ_pZ8&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=13][Youtube]]
- [[https://www.bilibili.com/video/BV1T14y1X7CW/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** 安装 Evil
*** Install from melpa
#+begin_src emacs-lisp(use-package evil
:ensure t
:init
(setq evil-want-keybinding nil)
(setq evil-want-C-u-scroll t)
(evil-mode);; https://emacs.stackexchange.com/questions/46371/how-can-i-get-ret-to-follow-org-mode-links-when-using-evil-mode
(with-eval-after-load 'evil-maps
(define-key evil-motion-state-map (kbd "RET") nil))
)
#+end_src
*** Install undo tree
#+begin_src emacs-lisp
(use-package undo-tree
:diminish
:init
(global-undo-tree-mode 1)
(setq undo-tree-auto-save-history nil)
(evil-set-undo-system 'undo-tree))
#+end_src
** Modes and States
*** Normal State (N)
This is the default “resting state” of Evil, in which the main body of vi bindings are defined.
*** Insert State (I)
This is the state for insertion of text, where non-modified keys will insert the corresponding character in the buffer.
*** Emacs State (E)
A state that as closely as possible mimics default Emacs behaviour, by eliminating all vi bindings, except for C-z, to re-enter normal state.
*** Visual State (V)
A state for selecting text regions. Motions are available for modifying the selected region, and operators are available for acting on it.
*** Motion State (M)
A special state useful for buffers that are read-only, where motions are available but editing operations are not.
*** Replace State (R)
A special state mostly similar to insert state, except it replaces text instead of inserting.
*** Operator-Pending State (O)
A special state entered after launching an operator, but before specifying the corresponding motion or text object.
** Evil 基础用法
*** 增删改查 (text-obj, commands, replace )
*** 如果对 evil 不太熟悉,还可以使用这个插件来练习 evil 的使用: https://github.com/clsty/evil-tutor-sc
** 自定义快捷键
*** 定义不同 state 下面的快捷键
#+begin_src emacs-lisp
(setcdr evil-insert-state-map nil)
(define-key evil-insert-state-map [escape] 'evil-normal-state)(define-key evil-normal-state-map (kbd "[ SPC") (lambda () (interactive) (evil-insert-newline-above) (forward-line)))
(define-key evil-normal-state-map (kbd "] SPC") (lambda () (interactive) (evil-insert-newline-below) (forward-line -1)))(define-key evil-normal-state-map (kbd "[ b") 'previous-buffer)
(define-key evil-normal-state-map (kbd "] b") 'next-buffer)
(define-key evil-motion-state-map (kbd "[ b") 'previous-buffer)
(define-key evil-motion-state-map (kbd "] b") 'next-buffer)(evil-define-key 'normal dired-mode-map
(kbd "") 'dired-find-alternate-file
(kbd "C-k") 'dired-up-directory
"`" 'dired-open-term
"o" 'dired-find-file-other-window
"s" 'hydra-dired-quick-sort/body
"z" 'dired-get-size
"!" 'zilongshanren/do-shell-and-copy-to-kill-ring
")" 'dired-omit-mode)
#+end_src
*** spacemacs like 快捷键如何定义
#+begin_src emacs-lisp(use-package general
:init
(with-eval-after-load 'evil
(general-add-hook 'after-init-hook
(lambda (&rest _)
(when-let ((messages-buffer (get-buffer "*Messages*")))
(with-current-buffer messages-buffer
(evil-normalize-keymaps))))
nil
nil
t))(general-create-definer global-definer
:keymaps 'override
:states '(insert emacs normal hybrid motion visual operator)
:prefix "SPC"
:non-normal-prefix "C-SPC")(defmacro +general-global-menu! (name infix-key &rest body)
"Create a definer named +general-global-NAME wrapping global-definer.
Create prefix map: +general-global-NAME. Prefix bindings in BODY with INFIX-KEY."
(declare (indent 2))
`(progn
(general-create-definer ,(intern (concat "+general-global-" name))
:wrapping global-definer
:prefix-map ',(intern (concat "+general-global-" name "-map"))
:infix ,infix-key
:wk-full-keys nil
"" '(:ignore t :which-key ,name))
(,(intern (concat "+general-global-" name))
,@body)))(general-create-definer global-leader
:keymaps 'override
:states '(emacs normal hybrid motion visual operator)
:prefix ","
"" '(:ignore t :which-key (lambda (arg) `(,(cadr (split-string (car arg) " ")) . ,(replace-regexp-in-string "-mode$" "" (symbol-name major-mode)))))))(use-package general
:init
(global-definer
"!" 'shell-command
"SPC" 'execute-extended-command
"'" 'vertico-repeat
"+" 'text-scale-increase
"-" 'text-scale-decrease
"u" 'universal-argument
"hdf" 'describe-function
"hdv" 'describe-variable
"hdk" 'describe-key
)(+general-global-menu! "buffer" "b"
"d" 'kill-current-buffer
"b" '(consult-buffer :which-key "consult buffer")
"B" 'switch-to-buffer
"p" 'previous-buffer
"R" 'rename-buffer
"M" '((lambda () (interactive) (switch-to-buffer "*Messages*"))
:which-key "messages-buffer")
"n" 'next-buffer
"i" 'ibuffer
"f" 'my-open-current-directory
"k" 'kill-buffer
"y" 'copy-buffer-name
"K" 'kill-other-buffers)
#+end_src
参考我的配置: https://github.com/zilongshanren/emacs.d/blob/eglot/lisp/init-keybindings.el
** 相关插件列表(推荐我自己经常用的)
*** evil-anzu
#+begin_src emacs-lisp
(use-package evil-anzu
:ensure t
:after evil
:diminish
:demand t
:init
(global-anzu-mode t))
#+end_src
*** evil-collections
#+begin_src emacs-lisp
(use-package evil-collection
:ensure t
:demand t
:config
(setq evil-collection-mode-list (remove 'lispy evil-collection-mode-list))
(evil-collection-init)(cl-loop for (mode . state) in
'((org-agenda-mode . normal)
(Custom-mode . emacs)
(eshell-mode . emacs)
(makey-key-mode . motion))
do (evil-set-initial-state mode state))#+end_src
*** evil-surround
#+begin_src emacs-lisp
(use-package evil-surround
:ensure t
:init
(global-evil-surround-mode 1))
#+end_src
*** evil-nerd-commenter
#+begin_src emacs-lisp
(use-package evil-nerd-commenter
:init
(define-key evil-normal-state-map (kbd ",/") 'evilnc-comment-or-uncomment-lines)
(define-key evil-visual-state-map (kbd ",/") 'evilnc-comment-or-uncomment-lines)
)
#+end_src
*** evil-snipe
#+begin_src emacs-lisp
(use-package evil-snipe
:ensure t
:diminish
:init
(evil-snipe-mode +1)
(evil-snipe-override-mode +1))
#+end_src
*** evil-matchit
#+begin_src emacs-lisp
(use-package evil-matchit
:ensure
:init
(global-evil-matchit-mode 1))
#+end_src
** 高阶用法(自定义 text-obj 或者 自定义 commands)
1. https://github.com/noctuid/evil-guide#modes
2. https://evil.readthedocs.io/en/latest/overview.html* 第十四天:精选 packages, 大大提升你的 Emacs 编辑效率
视频地址如下:
- [[https://www.youtube.com/watch?v=7hAqzTF1iRs&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=14][Youtube]]
- [[https://www.bilibili.com/video/BV1zh4y1k7a5/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** Some minor fix:
#+begin_src emacs-lisp;; make c-j/c-k work in vertico selection
(define-key vertico-map (kbd "C-j") 'vertico-next)
(define-key vertico-map (kbd "C-k") 'vertico-previous);; make consult-ripgrep work
(add-to-list 'process-coding-system-alist
'("[rR][gG]" . (utf-8-dos . windows-1251-dos)))
#+end_src
** 多光标操作 iedit & evil-multiedit
#+begin_src emacs-lisp
(use-package iedit
:ensure t
:init
(setq iedit-toggle-key-default nil)
:config
(define-key iedit-mode-keymap (kbd "M-h") 'iedit-restrict-function)
(define-key iedit-mode-keymap (kbd "M-i") 'iedit-restrict-current-line))(use-package evil-multiedit
:ensure t
:commands (evil-multiedit-default-keybinds)
:init
(evil-multiedit-default-keybinds))
#+end_src
** expand-region
#+begin_src emacs-lisp
(use-package expand-region
:config
(defadvice er/prepare-for-more-expansions-internal
(around helm-ag/prepare-for-more-expansions-internal activate)
ad-do-it
(let ((new-msg (concat (car ad-return-value)
", H to highlight in buffers"
", / to search in project, "
"e iedit mode in functions"
"f to search in files, "
"b to search in opened buffers"))
(new-bindings (cdr ad-return-value)))
(cl-pushnew
'("H" (lambda ()
(interactive)
(call-interactively
'zilongshanren/highlight-dwim)))
new-bindings)
(cl-pushnew
'("/" (lambda ()
(interactive)
(call-interactively
'my/search-project-for-symbol-at-point)))
new-bindings)
(cl-pushnew
'("e" (lambda ()
(interactive)
(call-interactively
'evil-multiedit-match-all)))
new-bindings)
(cl-pushnew
'("f" (lambda ()
(interactive)
(call-interactively
'find-file)))
new-bindings)
(cl-pushnew
'("b" (lambda ()
(interactive)
(call-interactively
'consult-line)))
new-bindings)
(setq ad-return-value (cons new-msg new-bindings)))))
#+end_src
添加一个快捷键,让标记和搜索功能更方便:
#+begin_src emacs-lisp;;;###autoload
(defun my/search-project-for-symbol-at-point ()
(interactive)
(if (use-region-p)
(progn
(consult-ripgrep (project-root (project-current))
(buffer-substring (region-beginning) (region-end))))))(global-definer
"hc" 'zilongshanren/clearn-highlight
"hH" 'zilongshanren/highlight-dwim
"v" 'er/expand-region
)
#+end_src
** interactive replace
#+begin_src emacs-lisp
(defun zilongshanren/evil-quick-replace (beg end )
(interactive "r")
(when (evil-visual-state-p)
(evil-exit-visual-state)
(let ((selection (regexp-quote (buffer-substring-no-properties beg end))))
(setq command-string (format "%%s /%s//g" selection))
(minibuffer-with-setup-hook
(lambda () (backward-char 2))
(evil-ex command-string)))))(define-key evil-visual-state-map (kbd "C-r") 'zilongshanren/evil-quick-replace)
#+end_src
** 安装 quelpa 插件
#+begin_src emacs-lisp
(use-package quelpa)(unless (package-installed-p 'quelpa-use-package)
(quelpa
'(quelpa-use-package
:fetcher git
:url "https://github.com/quelpa/quelpa-use-package.git")))(use-package quelpa-use-package
:init
(setq quelpa-use-package-inhibit-loading-quelpa t)
:demand t)
#+end_src
** symbol-overlay & highlight-global
#+begin_src emacs-lisp
(defun zilongshanren/highlight-dwim ()
(interactive)
(if (use-region-p)
(progn
(highlight-frame-toggle)
(deactivate-mark))
(symbol-overlay-put)))(defun zilongshanren/clearn-highlight ()
(interactive)
(clear-highlight-frame)
(symbol-overlay-remove-all))(use-package symbol-overlay
:config
(define-key symbol-overlay-map (kbd "h") 'nil))(use-package highlight-global
:ensure nil
:commands (highlight-frame-toggle)
:quelpa (highlight-global :fetcher github :repo "glen-dai/highlight-global")
:config
(progn
(setq-default highlight-faces
'(('hi-red-b . 0)
('hi-aquamarine . 0)
('hi-pink . 0)
('hi-blue-b . 0)))))
#+end_src* 第十五天:使用 Treesit + eglot 来打造现代编程 IDE
视频地址如下:
- [[https://www.youtube.com/watch?v=Jzy9Au3CNFY&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=15][Youtube]]
- [[https://www.bilibili.com/video/BV1W8411o7NM/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** 正式版本 Emacs 29
http://ftp.gnu.org/gnu/windows/emacs/emacs-29/
** 安装 treesit-auto 插件
https://github.com/renzmann/treesit-auto
#+begin_src emacs-lisp
(use-package treesit-auto
:demand t
:config
(setq treesit-auto-install 'prompt)
(global-treesit-auto-mode))
#+end_src
** 配置 fontlock level
#+begin_src emacs-lisp
(setq treesit-font-lock-level 4)
#+end_src
** 跳转函数列表 consult-imenu
#+begin_src emacs-lisp
(+general-global-menu! "search" "s"
"j" 'consult-imenu
"p" 'consult-ripgrep
"k" 'consult-keep-lines
"f" 'consult-focus-lines)#+end_src
** 查找定义和引用
使用 ctrl-o 返回
#+begin_src emacs-lisp
xref-find-references
xref-find-definitions
#+end_src
** 添加 snippets 支持
#+begin_src emacs-lisp
(use-package yasnippet
:ensure t
:hook ((prog-mode . yas-minor-mode)
(org-mode . yas-minor-mode))
:init
:config
(progn
(setq hippie-expand-try-functions-list
'(yas/hippie-try-expand
try-complete-file-name-partially
try-expand-all-abbrevs
try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-complete-lisp-symbol-partially
try-complete-lisp-symbol))))(use-package yasnippet-snippets
:ensure t
:after yasnippet)
#+end_src
** 在头文件和源文件之间进行跳转
#+begin_src emacs-lisp
ff-find-related-file
#+end_src
** 参考链接
- https://github.com/emacs-mirror/emacs/blob/master/admin/notes/tree-sitter/starter-guide
- https://www.masteringemacs.org/article/how-to-get-started-tree-sitter
- https://mp.weixin.qq.com/s/kChdHIuh2ch9w5RiCHxo3w (Emacs 29 更新内容)
- [[https://mp.weixin.qq.com/s?__biz=MzA4NDU1NTg2Ng==&mid=2452309008&idx=1&sn=c5f822e36cc38e6d91683495e029adac&chksm=883a8525bf4d0c336f6c1e3c9e2c934b751bd364f3e5565f9bb944b57a022b0d4aa6a5068146&cur_album_id=1930972115608928260&scene=189#wechat_redirect][Emacs Treesitter]]* 第十六天:窗口管理
视频地址如下:
- [[https://www.youtube.com/watch?v=nK6162fLsYM&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=16][Youtube]]
- [[https://www.bilibili.com/video/BV15h4y1c71Z/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** Evil 的窗口选择操作
- C-w h/j/j/k
** 推荐插件
*** [[https://github.com/nschum/window-numbering.el][window numbering]]#+begin_src emacs-lisp
(use-package window-numbering
:init
:hook (after-init . window-numbering-mode))
#+end_src
*** [[https://github.com/sabof/es-windows][es-windows]]#+begin_src emacs-lisp
(use-package es-windows
:ensure t)
#+end_src
*** [[https://github.com/nschum/window-numbering.el][Buffer move]]#+begin_src emacs-lisp
(use-package buffer-move
:ensure t)
#+end_src
*** [[https://github.com/dpsutton/resize-mode][Resize windows]]
#+begin_src emacs-lisp
(use-package resize-window
:ensure t
:init
(defvar resize-window-dispatch-alist
'((?n resize-window--enlarge-down " Resize - Expand down" t)
(?p resize-window--enlarge-up " Resize - Expand up" t)
(?f resize-window--enlarge-horizontally " Resize - horizontally" t)
(?b resize-window--shrink-horizontally " Resize - shrink horizontally" t)
(?r resize-window--reset-windows " Resize - reset window layout" nil)
(?w resize-window--cycle-window-positive " Resize - cycle window" nil)
(?W resize-window--cycle-window-negative " Resize - cycle window" nil)
(?2 split-window-below " Split window horizontally" nil)
(?3 split-window-right " Slit window vertically" nil)
(?0 resize-window--delete-window " Delete window" nil)
(?K resize-window--kill-other-windows " Kill other windows (save state)" nil)
(?y resize-window--restore-windows " (when state) Restore window configuration" nil)
(?? resize-window--display-menu " Resize - display menu" nil))
"List of actions for `resize-window-dispatch-default.
Main data structure of the dispatcher with the form:
\(char function documentation match-capitals\)"))
#+end_src
*** Winner (builtin)
#+begin_src emacs-lisp
(use-package winner
:ensure nil
:commands (winner-undo winner-redo)
:hook (after-init . winner-mode)
:init (setq winner-boring-buffers '("*Completions*"
"*Compile-Log*"
"*inferior-lisp*"
"*Fuzzy Completions*"
"*Apropos*"
"*Help*"
"*cvs*"
"*Buffer List*"
"*Ibuffer*"
"*esh command on file*")))
#+end_src
*** [[https://github.com/karthink/popper][Popper]]
#+begin_src emacs-lisp
(use-package popper
:defines popper-echo-dispatch-actions
:commands popper-group-by-directory
:bind (:map popper-mode-map
("s-`" . popper-toggle-latest)
("s-o" . popper-cycle)
("M-`" . popper-toggle-type))
:hook (emacs-startup . popper-mode)
:init
(setq popper-reference-buffers
'("\\*Messages\\*"
"Output\\*$" "\\*Pp Eval Output\\*$"
"\\*Compile-Log\\*"
"\\*Completions\\*"
"\\*Warnings\\*"
"\\*Flymake diagnostics.*\\*"
"\\*Async Shell Command\\*"
"\\*Apropos\\*"
"\\*Backtrace\\*"
"\\*prodigy\\*"
"\\*Calendar\\*"
"\\*Embark Actions\\*"
"\\*Finder\\*"
"\\*Kill Ring\\*"
"\\*Embark Export:.*\\*"
"\\*Edit Annotation.*\\*"
"\\*Flutter\\*"
bookmark-bmenu-mode
lsp-bridge-ref-mode
comint-mode
compilation-mode
help-mode helpful-mode
tabulated-list-mode
Buffer-menu-mode
occur-mode
gnus-article-mode devdocs-mode
grep-mode occur-mode rg-mode deadgrep-mode ag-mode pt-mode
ivy-occur-mode ivy-occur-grep-mode
process-menu-mode list-environment-mode cargo-process-mode
youdao-dictionary-mode osx-dictionary-mode fanyi-mode"^\\*eshell.*\\*.*$" eshell-mode
"^\\*shell.*\\*.*$" shell-mode
"^\\*terminal.*\\*.*$" term-mode
"^\\*vterm.*\\*.*$" vterm-mode"\\*DAP Templates\\*$" dap-server-log-mode
"\\*ELP Profiling Restuls\\*" profiler-report-mode
"\\*Flycheck errors\\*$" " \\*Flycheck checker\\*$"
"\\*Paradox Report\\*$" "\\*package update results\\*$" "\\*Package-Lint\\*$"
"\\*[Wo]*Man.*\\*$"
"\\*ert\\*$" overseer-buffer-mode
"\\*gud-debug\\*$"
"\\*lsp-help\\*$" "\\*lsp session\\*$"
"\\*quickrun\\*$"
"\\*tldr\\*$"
"\\*vc-.*\\*$"
"\\*eldoc\\*"
"^\\*elfeed-entry\\*$"
"^\\*macro expansion\\**""\\*Agenda Commands\\*" "\\*Org Select\\*" "\\*Capture\\*" "^CAPTURE-.*\\.org*"
"\\*Gofmt Errors\\*$" "\\*Go Test\\*$" godoc-mode
"\\*docker-containers\\*" "\\*docker-images\\*" "\\*docker-networks\\*" "\\*docker-volumes\\*"
"\\*prolog\\*" inferior-python-mode inf-ruby-mode swift-repl-mode
"\\*rustfmt\\*$" rustic-compilation-mode rustic-cargo-clippy-mode
rustic-cargo-outdated-mode rustic-cargo-test-moed))(when (display-grayscale-p)
(setq popper-mode-line
'(:eval
(concat
(propertize " " 'face 'mode-line-emphasis)
(all-the-icons-octicon "pin" :height 0.9 :v-adjust 0.0 :face 'mode-line-emphasis)
(propertize " " 'face 'mode-line-emphasis)))))(setq popper-echo-dispatch-actions t)
(setq popper-group-function nil)
:config
(popper-echo-mode 1)(with-no-warnings
(defun my-popper-fit-window-height (win)
"Determine the height of popup window WIN by fitting it to the buffer's content."
(fit-window-to-buffer
win
(floor (frame-height) 3)
(floor (frame-height) 3)))
(setq popper-window-height #'my-popper-fit-window-height)(defun popper-close-window-hack (&rest _)
"Close popper window via `C-g'."
;; `C-g' can deactivate region
(when (and (called-interactively-p 'interactive)
(not (region-active-p))
popper-open-popup-alist)
(let ((window (caar popper-open-popup-alist)))
(when (window-live-p window)
(delete-window window)))))
(advice-add #'keyboard-quit :before #'popper-close-window-hack)))
#+end_src
** 按键绑定
#+begin_src emacs-lisp
(global-definer
;; 这里是其他的快捷键
"0" 'select-window-0
"1" 'select-window-1
"2" 'select-window-2
"3" 'select-window-3
"4" 'select-window-4
"5" 'select-window-5)(+general-global-menu! "window" "w"
"/" 'split-window-right
"-" 'split-window-below
"m" 'delete-other-windows
"u" 'winner-undo
"z" 'winner-redo
"w" 'esw/select-window
"s" 'esw/swap-two-windows
"d" 'esw/delete-window
"=" 'balance-windows-area
"r" 'esw/move-window
"x" 'resize-window
"H" 'buf-move-left
"L" 'buf-move-right
"J" 'buf-move-down
"K" 'buf-move-up)
#+end_src* 第十七天:工作区间管理
视频地址如下:
- [[https://www.youtube.com/watch?v=DDlgJe4HJNY&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=17][Youtube]]
- [[https://www.bilibili.com/video/BV12p4y1J7Jx/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** Awesome Tab 的问题
偏爱使用 Emacs 内置 package
** 使用内置的 tab-bar-mode
#+begin_src emacs-lisp
(use-package tab-bar
:ensure nil
:init
(tab-bar-mode t)
(setq tab-bar-new-tab-choice "*scratch*") ;; buffer to show in new tabs
(setq tab-bar-close-button-show nil) ;; hide tab close / X button
(setq tab-bar-show 1) ;; hide bar if <= 1 tabs open
(setq tab-bar-format '(tab-bar-format-tabs tab-bar-separator))(custom-set-faces
'(tab-bar ((t (:inherit mode-line))))
'(tab-bar-tab ((t (:inherit mode-line :foreground "#993644"))))
'(tab-bar-tab-inactive ((t (:inherit mode-line-inactive :foreground "black")))))(defvar ct/circle-numbers-alist
'((0 . "⓪")
(1 . "①")
(2 . "②")
(3 . "③")
(4 . "④")
(5 . "⑤")
(6 . "⑥")
(7 . "⑦")
(8 . "⑧")
(9 . "⑨"))
"Alist of integers to strings of circled unicode numbers.")(defun ct/tab-bar-tab-name-format-default (tab i)
(let ((current-p (eq (car tab) 'current-tab))
(tab-num (if (and tab-bar-tab-hints (< i 10))
(alist-get i ct/circle-numbers-alist) "")))
(propertize
(concat tab-num
" "
(alist-get 'name tab)
(or (and tab-bar-close-button-show
(not (eq tab-bar-close-button-show
(if current-p 'non-selected 'selected)))
tab-bar-close-button)
"")
" ")
'face (funcall tab-bar-tab-face-function tab))))
(setq tab-bar-tab-name-format-function #'ct/tab-bar-tab-name-format-default)
(setq tab-bar-tab-hints t))
#+end_src
** 工作区间
#+begin_src emacs-lisp
(use-package tabspaces
;; use this next line only if you also use straight, otherwise ignore it.
:hook (after-init . tabspaces-mode) ;; use this only if you want the minor-mode loaded at startup.
:commands (tabspaces-switch-or-create-workspace
tabspaces-open-or-create-project-and-workspace)
:custom
(tabspaces-use-filtered-buffers-as-default t)
(tabspaces-default-tab "Default")
(tabspaces-remove-to-default t)
(tabspaces-include-buffers '("*scratch*"))
;; maybe slow
(tabspaces-session t)
(tabspaces-session-auto-restore t)
:config
;; Filter Buffers for Consult-Buffer(with-eval-after-load 'consult
;; hide full buffer list (still available with "b" prefix)
(consult-customize consult--source-buffer :hidden nil :default nil)
;; set consult-workspace buffer list
(defvar consult--source-workspace
(list :name "Workspace Buffers"
:narrow ?w
:history 'buffer-name-history
:category 'buffer
:state #'consult--buffer-state
:default t
:items (lambda () (consult--buffer-query
:predicate #'tabspaces--local-buffer-p
:sort 'visibility
:as #'buffer-name)))"Set workspace buffer list for consult-buffer.")
(add-to-list 'consult-buffer-sources 'consult--source-workspace)))
#+end_src
** 按键绑定
#+begin_src emacs-lisp
(+general-global-menu! "layout" "l"
"l" 'tabspaces-switch-or-create-workspace
"L" 'tabspaces-restore-session
"p" 'tabspaces-open-or-create-project-and-workspace
"f" 'tabspaces-project-switch-project-open-file
"s" 'tabspaces-save-session
"B" 'tabspaces-switch-buffer-and-tab
"b" 'tabspaces-switch-to-buffer
"R" 'tab-rename
"TAB" 'tab-bar-switch-to-recent-tab
"r" 'tabspaces-remove-current-buffer
"k" 'tabspaces-close-workspace)
#+end_src
** 工作流介绍
- 自动加载 workspace
- 手动加载 workspace(减少启动时间)* 第十八天: Org-mode 进阶
视频地址如下:
- [[https://www.youtube.com/watch?v=onZfDDctl0Q&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=18][Youtube]]
- [[https://www.bilibili.com/video/BV1oh4y1P73D/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** Org Download
*** how to install
#+begin_src emacs-lisp
(use-package org-download
:ensure t
:demand t
:after org
:config
(add-hook 'dired-mode-hook 'org-download-enable)
(setq org-download-screenshot-method "powershell -c Add-Type -AssemblyName System.Windows.Forms;$image = [Windows.Forms.Clipboard]::GetImage();$image.Save('%s', [System.Drawing.Imaging.ImageFormat]::Png)")
(defun org-download-annotate-default (link)
"Annotate LINK with the time of download."
(make-string 0 ?\s))(setq-default org-download-heading-lvl nil
org-download-image-dir "./img"
;; org-download-screenshot-method "screencapture -i %s"
org-download-screenshot-file (expand-file-name "screenshot.jpg" temporary-file-directory)))
#+end_src
*** Change image size
#+begin_src
#+ATTR_HTML: :width 1000px
#+end_srcuse yasnippets
** Org Protocol
*** How to config
**** 1. Step 1: Get emacsclient to work
**** 2. 生成 org-protocol.reg
#+begin_src sh
Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\org-protocol]
"URL Protocol"=""
@="URL:Org Protocol"[HKEY_CLASSES_ROOT\org-protocol\shell]
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
@="\"C:\\Program Files\\Emacs\\emacs-29.1\\bin\\emacsclientw.exe\" \"%1\""
#+end_src
**** 3. add org templates
#+begin_src emacs-lisp
(setq org-agenda-file-note (expand-file-name "~/notes.org"))
(setq org-capture-templates
'(
("x" "Web Collections" entry
(file+headline org-agenda-file-note "Web")
"* %U %:annotation\n\n%:initial\n\n%?")
))
#+end_src
**** 4. add chrome bookmark
#+begin_src sh
javascript:location.href='org-protocol://capture?template=x&url=%27+encodeURIComponent(location.href)+%27&title=%27+encodeURIComponent(document.title)+%27&body=%27+encodeURIComponent(function(){var html = "";var sel = window.getSelection();if (sel.rangeCount) {var container = document.createElement("div");for (var i = 0, len = sel.rangeCount; i < len; ++i) {container.appendChild(sel.getRangeAt(i).cloneContents());}html = container.innerHTML;}var dataDom = document.createElement(%27div%27);dataDom.innerHTML = html;dataDom.querySelectorAll(%27a%27).forEach(function(item, idx) {console.log(%27find a link%27);var url = new URL(item.href, window.location.href).href;var content = item.innerText;item.innerText = %27[[%27+url+%27][%27+content+%27]]%27;});[%27p%27, %27h1%27, %27h2%27, %27h3%27, %27h4%27].forEach(function(tag, idx){dataDom.querySelectorAll(tag).forEach(function(item, index) {var content = item.innerHTML.trim();if (content.length > 0) {item.innerHTML = content + %27
';}});});return dataDom.innerText.trim();}())
#+end_src
**** 6. return follow link
#+begin_src emacs-lisp
(org-return-follows-link t)
#+end_src** Spell checking
*** Install emacs packages
#+begin_src emacs-lisp(use-package flyspell-correct
:ensure t
:init)(use-package ispell
:ensure nil
:init
(setq ispell-program-name "aspell")
(dolist (hook '(text-mode-hook))
(add-hook hook (lambda () (flyspell-mode 1))))
(setq ispell-personal-dictionary "c:/msys64/mingw64/lib/aspell-0.60/en_GB")
)(define-key evil-insert-state-map (kbd "C-;") 'flyspell-correct-previous)
#+end_src
*** Install spell
#+begin_src sh
pacman -S mingw64/mingw-w64-x86_64-aspell
pacman -S mingw64/mingw-w64-x86_64-aspell-en
#+end_src
*** Configuration
1. add "*C:\msys64\mingw64\bin" to to PATH
2. Error: The file "c:\msys64\mingw64/lib/aspell-0.60/en_US" can not be opened for reading.** Fanyi Dictionary
*** How to install
#+begin_src emacs-lisp
(use-package fanyi
:ensure t
:custom
(fanyi-providers '(;; 海词
;; fanyi-haici-provider
;; 有道同义词词典
fanyi-youdao-thesaurus-provider
;; Etymonline
fanyi-etymon-provider
;; Longman
;; fanyi-longman-provider)
)))
#+end_src
** Some useful keybindings
#+begin_src emacs-lisp
C-RET for creating new headlines
M-RET for creating new lists
M-left/right/up/down
#+end_src* 第十九天: Org Roam
视频地址如下:
- [[https://www.youtube.com/watch?v=M_DPLkiu3Gc&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=19][Youtube]]
- [[https://www.bilibili.com/video/BV1uk4y1P7xr/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** 安装 Org Oram
在 HOME 新建一个 org 目录夹,用来存储你的 org roam 笔记。
#+begin_src emacs-lisp
(use-package org-roam
:ensure t
:custom
(org-roam-directory (file-truename "~/org"))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n i" . org-roam-node-insert)
("C-c n c" . org-roam-capture)
;; Dailies
("C-c n j" . org-roam-dailies-capture-today))
:config
;; If you're using a vertical completion framework, you might want a more informative completion interface
(setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode)
;; If using org-roam-protocol
(require 'org-roam-protocol))
#+end_src
** Org roam 基本使用
*** 安装 corfu 来进行补全
#+begin_src emacs-lisp
(use-package corfu
:init
(progn
(setq corfu-auto t)
(setq corfu-cycle t)
(setq corfu-quit-at-boundary t)
(setq corfu-quit-no-match t)
(setq corfu-preview-current nil)
(setq corfu-min-width 80)
(setq corfu-max-width 100)
(setq corfu-auto-delay 0.2)
(setq corfu-auto-prefix 1)
(setq corfu-on-exact-match nil)
(global-corfu-mode)
))
#+end_src
*** 新建笔记和查找笔记
C-c n f
*** 建立笔记引用
[[]]
*** 查找引用
org-return-follows-link t
c-c n l (org-roam-buffer-toggle)*** 已有的 headline 转换为一个节点
org-id-get-create
refile node
** 直接从 github 安装插件
#+begin_src emacs-lisp
(require 'cl-lib)
(require 'use-package-core)(cl-defun slot/vc-install (&key (fetcher "github") repo name rev backend)
(let* ((url (format "https://www.%s.com/%s" fetcher repo))
(iname (when name (intern name)))
(package-name (or iname (intern (file-name-base repo)))))
(unless (package-installed-p package-name)
(package-vc-install url iname rev backend))))(defvar package-vc-use-package-keyword :vc)
(defun package-vc-use-package-set-keyword ()
(unless (member package-vc-use-package-keyword use-package-keywords)
(setq use-package-keywords
(let* ((pos (cl-position :unless use-package-keywords))
(head (cl-subseq use-package-keywords 0 (+ 1 pos)))
(tail (nthcdr (+ 1 pos) use-package-keywords)))
(append head (list package-vc-use-package-keyword) tail)))))(defun use-package-normalize/:vc (name-symbol keyword args)
(let ((arg (car args)))
(pcase arg
((or `nil `t) (list name-symbol))
((pred symbolp) args)
((pred listp) (cond
((listp (car arg)) arg)
((string-match "^:" (symbol-name (car arg))) (cons name-symbol arg))
((symbolp (car arg)) args)))
(_ nil))))(defun use-package-handler/:vc (name-symbol keyword args rest state)
(let ((body (use-package-process-keywords name-symbol rest state)))
;; This happens at macro expansion time, not when the expanded code is
;; compiled or evaluated.
(if args
(use-package-concat
`((unless (package-installed-p ',(pcase (car args)
((pred symbolp) (car args))
((pred listp) (car (car args)))))
(apply #'slot/vc-install ',(cdr args))))
body)
body)))(defun package-vc-use-package-override-:ensure (func name-symbol keyword ensure rest state)
(let ((ensure (if (plist-member rest :vc)
nil
ensure)))
(funcall func name-symbol keyword ensure rest state)))(defun package-vc-use-package-activate-advice ()
(advice-add
'use-package-handler/:ensure
:around
#'package-vc-use-package-override-:ensure))(defun package-vc-use-package-deactivate-advice ()
(advice-remove
'use-package-handler/:ensure
#'package-vc-use-package-override-:ensure));; register keyword on require
(package-vc-use-package-set-keyword)
#+end_src
** Org roam UI
#+begin_src emacs-lisp
(use-package org-roam-ui
:vc (:fetcher "github" :repo "org-roam/org-roam-ui"))
#+end_src
- 鼠标操作
- 可视化
- 实时显示链接* 第二十天:Emacs 配置问题排查
视频地址如下:
- [[https://www.youtube.com/watch?v=uuGrzmCwu7s&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=20][Youtube]]
- [[https://www.bilibili.com/video/BV1Vz4y1j7LB/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** 配置有问题,启动不了怎么办?
emacs-debug --init
** 不能安装包,提示签名错误
Failed to verify signature archive-contents.sig#+begin_src emacs-lisp
(setq package-check-signature nil)
#+end_src[[https://emacs-china.org/t/failed-to-verify-signature-archive-contents-sig/20508/5][Failed to verify signature archive-contents.sig - Emacs-general - Emacs China]]
** a pax extended header, 包解压失败,可以使用 use-package :vc 直接安装
使用 mysys2 的时候,系统会使用 unix 的 tar 去解压会有问题
windows 上面需要使用 system32/tar 这个程序去解压。
#+begin_src emacs-lisp
解决办法可以是 mv /usr/bin/tar /usr/bin/tarbak
#+end_src
** 上 Emacs China! 上 Emacs China! 上 Emacs China! (重要的事情说 3 遍)* 第二十一天: 优化性能,借鉴其他人的配置
视频地址如下:
- [[https://www.youtube.com/watch?v=Va9lcfsVKgU&list=PLZx9tb9Niew-CXp_C0LfiJo-SpsQBVBq2&index=21][Youtube]]
- [[https://www.bilibili.com/video/BV1Ah4y1N7Kb/?spm_id_from=333.788&vd_source=341db5d3a9324a7e00c10cbce0022a91][Bilibili]]** how to Profile performace
** 怎么度量启动性能
#+begin_src emacs-lisp
(use-package benchmark-init
:ensure t
:demand t
:config
;; To disable collection of benchmark data after init is done.
(add-hook 'after-init-hook 'benchmark-init/deactivate))
#+end_src
** use-package 哪些操作可以优化性能
https://systemcrafters.net/emacs-from-scratch/cut-start-up-time-in-half/
** 借鉴大佬的配置,作为框架
*** 社区配置
Spacemacs & DoomEmacs*** 个人配置
- https://github.com/purcell/emacs.d
- https://github.com/bbatsov/prelude
- https://github.com/bbatsov/prelude
- https://github.com/seagle0128/.emacs.d
- https://github.com/zilongshanren/emacs.d (子龙山人)** 小技巧:
#+begin_src emacs-lisp
(defun spacemacs/alternate-buffer (&optional window)
"Switch back and forth between current and last buffer in the
current window.
If `spacemacs-layouts-restrict-spc-tab' is `t' then this only switches between
the current layouts buffers."
(interactive)
(cl-destructuring-bind (buf start pos)
(if (bound-and-true-p spacemacs-layouts-restrict-spc-tab)
(let ((buffer-list (persp-buffer-list))
(my-buffer (window-buffer window)))
;; find buffer of the same persp in window
(seq-find (lambda (it) ;; predicate
(and (not (eq (car it) my-buffer))
(member (car it) buffer-list)))
(window-prev-buffers)
;; default if found none
(list nil nil nil)))
(or (cl-find (window-buffer window) (window-prev-buffers)
:key #'car :test-not #'eq)
(list (other-buffer) nil nil)))
(if (not buf)
(message "Last buffer not found.")
(set-window-buffer-start-and-point window buf start pos))))
#+end_src
按键绑定:
#+begin_src emacs-lisp
"TAB" 'spacemacs/alternate-buffer
#+end_src