Masimaro's blog - 文本操作术
type: channel
link: https://www.masimaro.top/tag/%E6%96%87%E6%9C%AC%E6%93%8D%E4%BD%9C%E6%9C%AF/
items: Emacs 折腾日记(二十五)——目录管理
items: Emacs 折腾日记(二十三)——进一步提升编辑效率
items: Emacs 折腾日记(五)——elisp 数字类型
items: Emacs折腾日记(三)——简单的elisp 入门
items: emacs 折腾日记(一)——序言
items: 从零开始配置vim(32)——最后再说两句
items: 从零开始配置vim(31)——git 配置
items: 从零开始配置vim(30)——DAP的其他配置
items: 从零开始配置vim(29)——DAP 配置
items: 从零开始配置vim(28)——代码的编译、运行与调试

Emacs 折腾日记(二十五)——目录管理
type: item
date: 2025-05-22T10:13:00+08:00
description: 在之前的文章中，分了几篇着重介绍了Emacs编辑方面的功能改造。作为一个文本编辑器，要想坚持用下去首先应该改造成自己熟悉的编辑方式。本节我们来介绍Emacs的目录管理Dired ModeEmacs自带一个名为 Dired (Directory Editor) 的插件，它负责对目录进行操作。默认的，我们可以使用 C-x d 来进入Dired Mode。启动后它会等待用户输入想进入的目录，默认是当前目录。Dired Mode 是提供了一种类似操作文本的方式来操作目录。我们可以像操作文本那样来对目录进行类似于拷贝剪切粘贴删除创建跳转查找重命名批量操作得益于前面的篇章配置的一些插件，可以很方便的使用Dired Modedired 美化在正式介绍dired 使用之前，先稍微对它进行一些美化，原始的界面太素了，看着不太好看。首先介绍 diredfl ，原始的dired 只能使用两种颜色来区别文件和目录，而 diredfl 可以使用多种颜色，让dired显示的更加漂亮(use-package diredfl :ensure t :hook (dired-mode . diredfl-mode))接着我们再使用 all-the-icons-dired 来给dired显示的前面加上一个图标。这个插件依赖 all-the-icons 插件。(use-package all-the-icons :ensure t :when (display-graphic-p) :commands all-the-icons-install-fonts) ;; 安装完成之后需要执行 all-the-icons-install-fonts 命令安装对应字体 (use-package all-the-icons-dired :ensure t :hook (dired-mode . all-the-icons-dired-mode))我们也可以通过安装 all-the-icons-completion 插件，给minibuffer中的补全系统也加上图标(use-package all-the-icons-completion :ensure t :hook ((after-init . all-the-icons-completion-mode) (marginalia-mode . all-the-icons-completion-mode)))dirvish 增强direddirvish 是在dired 基础之上的文件管理增强插件。相对与dired 它提供快速跳转、实时预览、并且能兼容对dired的一些扩展。(use-package dirvish :ensure t :hook (after-init . dirvish-override-dired-mode) :bind( ("C-x d" . dirvish) )) 我们使用命令 dirvish 就能打开对应的窗口，或者像上面那样绑定快捷键来打开对应的窗口使用vim的方式来操作目录这里的使用vim的方式来操作多少有点标题党的意思。我无法做到完全按照vim编辑文本那样来编辑目录，但是这里我可以修改以下对应的快捷键已达到某些操作可以使用vim的快捷键。(use-package dirvish :ensure t :hook (after-init . dirvish-override-dired-mode) :bind(:map dired-mode-map ("C-x d" . dirvish) ("y" . dired-do-copy) ;; 拷贝粘贴 ("d" . dired-do-delete) ;; 删除 ("r" . dired-do-rename) ;; 重命名 ("a" . dired-create-empty-file) ;; 创建空文件 ("+" . dired-create-directory) ;; 创建文件 ("SPC" . nil) ;; 取消空格键的绑定 ) :config (with-eval-after-load 'evil (evil-define-key 'normal dired-mode-map "r" 'dired-do-rename)) ;; 排除evil模式下默认键的覆盖 (my-leader-def "j" #'dired-goto-file) )在上述的配置中，我绑定的快捷键如下快捷键功能C-x d打开diredy拷贝d删除r重命名a创建空文件+创建空目录SPC j跳转到指定文件需要注意的是，在 config 中调用了这样的语句 (with-eval-after-load 'evil (evil-define-key 'normal dired-mode-m…

Emacs 折腾日记(二十三)——进一步提升编辑效率
type: item
date: 2025-05-14T11:24:21+08:00
description: 在前面的几篇，我们完成了Emacs的vim模拟器、中文输入、多行编辑以及基本的补全功能的添加。这一篇没有具体的提升哪一方面的能力，这一篇我想整合我在其他教程中看到的我认为对我比较有用的用法和插件，算是对前期功能的一个总结。让Emacs记住一些信息一般的编辑器都会在下次打开时记住上次的一些信息，例如记住之前打开过的文件，执行过的命令，或者记住上次的窗口布局。记住上次执行的命令我们每次使用 M-x 执行命令时，minibuffer中显示的提示都是一样的，那些常用命令要么不在上面要么太靠下了，我们希望能记住某些命令，以便能快速找到它。记住上次执行的命令可以使用 savehist 插件。它是一个Emacs自带的插件，默认是关闭的状态，我们可以通过将 use-package 来加载它，但是因为是自带的，不需要从镜像中下载所以它的 :ensure 项应该设置为 nil(use-package savehist :ensure nil :hook (after-init . savehist-mode) :custom (savehist-file (locate-user-emacs-file "custom/savehist")) ;; 设置保存文件的位置 (savehist-additional-variables '(kill-rings shell-command-history)) ;; 额外保存剪切板和shell命令行历史 (savehist-ignored-variables '(message-history)) ;; 不保存消息历史 (history-delete-duplicates t) ;; 自动去重 (history-length 1000) ;; 保存历史数据条目 )在执行一些操作关掉Emacs之后，我们会发现它在 ~/.emacs.d/custom 生成了一个名为 savehist 的文件，它记录了之前在minibuffer中执行的命令。为了保持git工程的干净，我打算将这种历史文件排除在git管理之外，所以单独将它放到custom目录，并忽略它其实该插件不光可以保留执行的命令，minibuffer中的许多信息它都可以保存和持久化。minibuffer-history (所有 minibuffer 输入历史)command-history (执行过的命令)search-ring (搜索历史)regexp-search-ring (正则搜索历史)extended-command-history (M-x 命令历史)file-name-history (文件路径历史)记住上次打开的文件一般的编辑器都可以记录上次打开的文件，并列出来。Emacs也有一个类似的内置插件—— recentf(use-package recentf :ensure nil :hook (after-init . recentf-mode) :custom (recentf-max-menu-item 10) ;; 最多只记录10条历史记录 (recentf-save-file (locate-user-emacs-file "custom/.recentf")) ;; 定义保存历史记录的临时文件路径 )搜索功能的增强实现全局搜索我们可以依赖Linux上的命令行工具 grep 和最近(也不算近了)的 ripgrep。之前在介绍vim的时候，vim内部集成了 grep。但是我们使用更为强大的 ripgrep。在Emacs中可以配合插件 consult 和 ripgrep，调用 consult-ripgrep 来进行全局搜索。它会自动搜索当前项目下的所有目录。我们对之前 consult 插件的配置代码进行一些修改，并添加 ripgrep 的配置(use-package consult :ensure t) (use-package ripgrep :ensure t :after consult :bind (("C-s" . consult-ripgrep)) )这里我们将 C-s 绑定的快捷键修改为 consult-ripgrep。神奇的是，配合之前安装的orderless，我们只需要按照一个模糊的记忆来匹配想要的内容。同时它也能支持输入中文批量替换批量替换这个功能，根据我找到的教程，它需要依赖 embark、consult、和 wgrep 这么三个插件。其中 consult 用来进行搜索，而 embark 可以为不同场景下的文本/候选项（如搜索结果、补全列表、文件路径等）提供动态的快捷操作菜单。简化了minibuffer上的一些操作。而 wgrep 则是其中的核心插件，用来批量修改内容并保存(use-package embark :ens…

Emacs 折腾日记(五)——elisp 数字类型
type: item
date: 2024-12-21T20:27:21+08:00
description: 本文是参考 emacs lisp 简明教程 写的，很多东西都是照搬里面的内容，如果各位读者觉得本文没有这篇教程优秀或者有抄袭嫌疑、又或者觉得我更新比较慢、再或者其他什么原因，请直接阅读上述链接中的教程。上一篇我们讲了elisp中的流程控制结构相关的内容，下面就该进入到对应数据结构的学习了。elisp中主要的数据结构有：整数、浮点数、列表、符号、向量、散列表等等类型。下面我们先从最简单的类型——整数和浮点数说起数字类型与C/C++对比起来，elisp数字类型少的多，C/C++ 整数类型就有好几种，包括有符号、无符号、int、short、long之类的。elisp不区分这些，它仅仅有整数和浮点数。而且elisp 中只有浮点数这一种小数类型，不像C/C++还有双精度浮点数和单精度浮点数之分。elisp的整数范围与具体的机器有关，它的范围可以通过变量 most-positive-fixnum 和 most-negative-fixnum 来得到。例如在我的机器上它们的值如下most-positive-fixnum ;; 2305843009213693951 most-negative-fixnum ;; -2305843009213693952在给变量使用数字类型赋值的时候，我们可以使用10进制或者其他任意进制的形式。例如#b101100 => 44 ; 二进制 #o54 => 44 ; 八进制 #x2c => 44 ; 十进制 #24r1k => 44 ; 二十四进制因为26个英文字母+10个数字的原因，我们最大只能使用36进制来表示一个数字，但是基本不用到这么大的。日常最多也就用用10进制、二进制、16进制、8进制都算用的少。浮点数的表达遵循 IEEE 标准，也就是可以使用带小数点的数字来表示，或者带上 e 来使用科学计数法，例如3.14 1.0e-10数字类型的测试作为动态类型的语言，在代码执行阶段，变量的类型是会发生变化的。我们无法仅通过变量名或者变量的初始化值来判断变量类型。emacs的变量在执行阶段都知道自己的类型，但是它无法主动向我们报告，我们需要使用一些函数来进行判断，关于数字类型，提供了下列的函数integerp floatp numberp从字面上能理解它们分别判断是否是整形、浮点数、以及数字类型。elisp 测试函数一般都是用 p 来结尾，p 是 predicate 的第一个字母。如果函数名是一个单词，通常只是在这个单词后加一个 p，如果是多个单词，一般是加 -p数的比较与C/C++ 类似，数字的比较一般有 >、<、>=、<= 。但是也有不同的地方，因为elisp中都是使用 setq 来进行赋值的，所以它采用 = 来表示数学意义上的相等。还有一个不同的地方因为elisp中没有 += 、-=、/= 、*= 这样的运算符，所以它使用 /= 来作为不等的判断符号与其他语言类似的，浮点数直接使用等于或者不等于来判断并不准确，需要在一定范围内忽略误差。在C/C++中，我们常见的写法是给定一个误差值，然后二者差的绝对值在这个误差值范围内则认为它们相等。我们将这个算法使用elisp改写一下就得到下面的代码(defun approx-equal (x y) (let ((fuzz-factor 1.0e-6)) (< (abs (- x y)) fuzz-factor))) (approx-equal 1.000001 1.00000000000000001) ;; => t上述的写法并不严谨，在一定误差范围内，它是对的，但是在某些情况下它就不对了，例如 1.0e-7 和 1.0e-12 。它们本身并不相等，但是它们都超过了这个误差范围，相减之后的值小于这个误差范围。但是我们看到其实它们直接的差距还是挺大的，间隔1.0e5 的数量积。我们可以将上述算法进行一些改进(defun approx-equal(x y) (let ((fuzz-factor 1.0e-6)) (or (and (= x 0) (= y 0)) (< (/ (abs (- x y)) (max (abs x) (abs y))) fuzz-factor)))) (approx-equal 1.0e-7 1.0e-12) ;; => t这段代码采用的是比较相对差距的办法。因为涉及到除法，所以先把二者等于0的情况排除了，避免发生除0的问题。上述代码改造成对应的C代码就是#define FUZZ_FACTOR 1.0e-6 // 定义误差范围 bool approx_equal(double x, double y) { // 处理特殊情况：如果两个数都是 0 if (x == 0 && y == 0) { return true; } // 计算相对差并进行…

Emacs折腾日记(三)——简单的elisp 入门
type: item
date: 2024-12-11T22:29:00+08:00
description: Emacs本身的使用并不复杂，利用帮助文档，差不多半小时左右就能把一些常见的操作方式和快捷键过一遍，剩下的就是慢慢使用并且熟悉了。Emacs真正有价值的是它高度的客制化。任何人都可以利用elisp代码将Emacs改造成只属于自己的编辑器。会elisp 的不一定是高手，但是高手没有一个是不会elisp的。学习Emacs也绕不开elisp。下面我们就来简单的学点elisp一个简单的 Hello Word(message "hello world")这是一个简单的elisp版本的hello world程序。麻雀虽小但是五脏俱全。从这个简单的程序来说我们可以看出lisp的最大特点，就是以括号作为作为一个完整的表达式。曾今有一个段子说苏联的特工冒死偷到了美国阿波罗计划代码的最后一页，结果回来一看全是括号。这也鲜明的表达了一个lisp的特点，那就是大量的括号我们简单的解析一下上面的代码，上面的代码调用了一个函数，函数的参数就是一个字符串的 hello world。我们可以打开Emacs，进入 scratch buffer，输入上述代码。之后可以将光标移动到代码尾部，按下快捷键 C-x C-e 来执行代码，或者使用 M-x 输入命令 eval-buffer 来看效果。我们可以看到，mini-buffer 位置出现了 "hello world" 的字符串变量我们可以使用 setq 来定义变量，它类似于C/C++ 中的= ，用来给变量赋值或者定义并初始化一个变量。例如我们可以改一下上述的代码(setq name "Emacs") (message "hello, %s" name)将上述代码输入到scratch buffer之后就需要依次在每行的最后执行 C-x C-e 或者直接执行eval-buffer 命令，这样就可以看到效果了上面我们说，elisp的表达式是使用括号来表示的，但是如果在上面代码的基础上加上一句(name)此时就会报错，显示的错误为 void-function name 。我们的本意是想让解释器返回name的值，但是解释器将它作为了一个函数。通过这个错误我们能了解到，elisp基本的表达式中函数需要用括号括起来，但是变量自己本身被作为一个完整的表达式。除了使用setq我们还可以使用 defvar 来定义变量，defvar 的使用如下(defvar variable-name value "variable document")例如(defvar name "Emacs" "a defvar demo name") name ;; ==> "Emacs"我们将光标放到name上，按下 C-h v 可以看到关于name的说明文档。需要注意的是，defvar与setq 除了defvar可以指定变量的说明文档外，还有一个区别就是defvar在定义变量前，这个变量已经有值的话，defvar不会改变变量的值例如下面的例子(setq foo "foo") (defvar foo "this is foo" "document for variable foo") (defvar bar "this is bar" "document for variable bar") foo ;; =>"foo" bar ;; =>"this is bar"C-x C-e(eval-last-sexp) treatsdefvarexpressions specially. Normally, evaluating adefvarexpression does nothing if the variable it defines already has a value. But this command unconditionally resets the variable to the initial value specified by thedefvar; this is convenient for debugging Emacs Lisp programs.defcustomanddeffaceexpressions are treated similarly. Note the other commands documented in this section, excepteval-defun, do not have this special feature.上述英文翻译过来就是 eval-last-sexp 对 defvar 做了特殊处理，默认情况下 defvar 在变量有值的情况下不做任何操作，但是在这个命令中，defvar 会无条件的将变量值重置为它指定的值。主要是为了方便调试代码。同时 defcustom 和 deface 做了同…

emacs 折腾日记(一)——序言
type: item
date: 2024-12-05T22:01:28+08:00
description: 初次知道emacs这个东西是在《程序员的呐喊》这本书。书中的作者提倡学习编译原理，推崇emacs。现在距离我知道emacs已经过去了快8年，期间不断的重复学习——放弃——学习的路子。与过去学习vim类似，vim我也经历过放弃到学习，最后有项目需要使用Vim在Linux上开发，没办法慢慢学会了它的操作，以及一些简单的配置。后来我写了vim的操作和配置，我发现这样做很有用首先就是在写vim操作的时候，相关的概念和操作技巧我又重新梳理了一遍，加深了它的印象，过去一些不怎么用的操作我发现在之后我用的越来越顺手。其次就是我目前使用的配置在出错或者需要做修改的时候根据之前的文章我又梳理了一遍，很方便我回顾之前的思路能快速定位到每个模块当初的思路以及一些被遗忘的知识点。既然之前的教程对我有这么大的帮助，那么我想这次学习emacs就采用这种策略。首先日常记笔记，记录工作的日志之类的操作就从markdown转化到emacs的org-mode中以便熟悉emacs的日常操作。另外通过写博客的方式记笔记，记录自己做的一些配置以及一些操作技巧。日后用来回顾也好或者仅仅为了加深印象也好都可以。另外我想这一系列既然是折腾日记，而且我还是emacs的小白，那么这一系列的文章自然是不成体系的，基本上是想到什么就写什么。如果看这一系列的文章的读者存在问题我可能也没有能力解答。在这里给读者说一声抱歉。emacs 是什么任何技术或者工具我都喜欢从这几个方面先了解一下，再考虑是不是值得学。首先一个问题就是“是是什么”，其次是“为什么”，最后是“怎么做”。我想现在就来说说我对这几个问题的理解首先Emacs是什么呢？Emacs 其实并不特指某一款编辑器，而是一个文本编辑器大家族的统称。最初由理查德·斯托曼于1975年在MIT协同盖伊·史提尔二世共同完成。这一创意的灵感来源于TECO宏编辑器TECMAC和TMACS。这里我们提到Emacs主要特指 GNU EMacs，它是由理查德·斯托曼于1984年开始开发，至今已经有40多年的历史。它的核心理念官网上是这么介绍的An extensible, customizable, free/libre text editor — and more它是一个 可扩展、可定制、自由的文本编辑器，并且远不止于此。EMacs 是自由软件，它没有对用户做出任何限制，包括内核代码完全是开放的。你可以在此基础之上进行任何改动。同时它提供了一个完成的lisp解释器，随着这些年的发展，它的插件系统已经特别丰富了，利用插件几乎可以实现任何功能。有人戏称Emacs是一个伪装成文本编辑器的操作系统，在Emacs上几乎无所不能。emacs 是否值得学我个人认为Emacs还是很值的学习的。说说我学习Emacs的理由：它是一个与vim齐名的编辑器，因为它的插件丰富，结构设计良好，它几乎可以做到vim能做的所有事情，包括vim那一套操作逻辑它使用lisp作为扩展语言，我目前掌握了面向过程的语言C，面向对象的语言 C++/Python，但是还从来没有完整的学习过函数式编程语言，而且《黑客与画家》的作者也推荐lisp语言。平时写普通的脚本我都是用shell 或者 python 就搞定了，没什么几乎接触到lisp的实战，借这个机会学习一下lisp并且用于实战，也是一个不错的选择emacs 的 orgmode很吸引我，它的功能比markdown要丰富，借助Emacs这个平台能提供非常棒的体验，包括但不限于写博客，做计划，管理日程，甚至能在里面运行代码如何学下面是一张网上流传的图，各个编辑器的难易程度虽然有点夸张，但是Emacs的学习过程并不算简单。目前我也没有好的学习路径，而且这一系列的文章只是我的尝试。目前我也没有掌握Emacs，甚至是一个小白。我想以写文章的方式来慢慢学习关于Emac的内容网上有很多Emacs的教程，最经典应该要数这篇 一年成为Emacs高手但是我之前尝试过使用高手的配置，总是用着不是那么舒服，总想要折腾出一套属于自己的配置，后面慢慢的就放弃了。这次我想慢慢的根据其他人的教程折腾出一套属于自己的配置，然后通过使用 org-mode 来写博客、记笔记、并且进行日程管理，后续慢慢的将写脚本之类的简单开发工作转移到Emacs上，通过折腾配置并且多用Emacs来学习。祝我好运吧。

从零开始配置vim(32)——最后再说两句
type: item
date: 2023-03-04T09:50:00+08:00
description: 很抱歉我决定结束这个系列的内容了。原本我打算介绍markdown、orgmode相关的配置，甚至还打算介绍如何在vim 中使用 emacs 的 org-agenda 来进行日常的任务管理。但是出于一些原因我打算放弃了。首先如果将markdown 理解为另一种类似于HTML 的标记语言的话，我们在介绍LSP 的时候已经介绍过该如何新增新的编程语言的支持，再另外介绍Markdown 的配置就显得多余了。而且本系列也并不打算事无巨细的带领大家从零开始配置一套完整的配置，我仅仅希望通过这一系列的内容介绍一下vimscript 或者lua 接口以及vim 的一些特性，让大家看完之后又能力自行动手弄出一套属于自己的配置。至于orgmode 的内容，我发现目前还没有任何插件能完美的模拟emacs 的orgmode 功能。vim 上的插件也仅仅能做到渲染样式，语法高亮而已。也就没有必要单独介绍了。如果后续我能掌握 emacs 的话，再来介绍也不迟总之就是本系列到此结束了。一些建议不知道各位小伙伴在跟着我这一系列文章尝试自己配置vim 的时候有什么感觉？我当初在整理这些配置的时候发现它越来越像vs code ，甚至最近几年新推出的LSP以及 DAP 的一些插件几乎都是原生的用于 vscode 上的或者从它上面移植过来的。有些主题也是照搬 vscode 的。我们发现自己费劲心力终于将vim 变成的 vscode 。有没有觉得在做无用功？既然要将它变成 vscode 那为何不直接使用 vscode 呢？可能有人会说， vscode 对于vim的一些模式和 ex 命令的支持并不好。我想这就是我们使用 vim 的理由，也是vim 比其他编辑器强的地方。我们仅仅是在使用工具而已，哪个工具好用，哪个工具能帮助我们快速完成工作，那就用哪个。工具本身没有高低贵贱之分，只有合适与否的差异。作为程序员要拥抱新技术，千万不要抱着某个技术某个工具不放。也不要觉得用vim 的比用 vscode 或者其他编辑器的高级，就高人一等。vim自身也在吸收其他技术不断的成长，例如它从 vscode 那边学来了LSP 和 DAP 。这就有点像武侠小说中的吸功大法，集万物所长为我所用。另外一条建议就是千万不要拿我给出的配置直接来进行使用。这一套配置仅仅是为了教学使用，很多地方没有进行深度定制，并且基本采用白话的写法，完全不考虑封装性和程序设计，另外我也没有考虑通用性，很多小伙伴评论出现了各种各样的问题，最后就是它的效率也不算高。我也不希望自己的文章仅仅给各位小伙伴提供了一套配置。我更希望小伙伴们能通过这一系列文章学到一点东西，从这套配置中衍生出一套适合自己的内容。若干年以后，各位小伙伴在对vim有更深的理解回过头来看到这套配置时可能发出这样的声音：“这是什么破烂配置，连 xxx 的支持都没有；有些功能有时候会报错，我看看把它改好；启动时间咋这么慢，我能把它优化到xx毫秒；现在还在用xx技术早就落伍了，看我把它改成用xx技术”。（我自认为本系列最有价值的是开始配置之前，vim相关特性的介绍）最后的一条建议就是，如果各位小伙伴未来将长时间使用vim 进行代码的编写和日常的开发。那么我推荐使用一些社区比较活跃的第三方通用配置，例如我最近在使用的lunarVim。使用这类的配置有一些好处：不用费力折腾配置，节约时间学习高手的配置，提升自己对编辑器的审美。就像没学习vim之前我一直觉得使用编辑器用鼠标选中文本是天经地义的事，我习惯了它，甚至习惯了用鼠标翻页等操作，完全不知道这样有多么的浪费时间。通过高手配置可能能使你重新审视自己使用编辑器的习惯，从而找到一套真正适合自己的高效的文本操作术。社区活跃的话，除了问题不用自己死磕，可能有人能帮忙解决PS: 如果各位觉得我的教程不好或者有些内容没有提到，各位可以去看看lunarVim作者的另一个项目，Neovim-from-scratch 该项目也是从0开始配置vim，并且在油管上有对应的教学视频。后面的学习通过本系列的学习相信各位小伙伴已经有能力能看懂各种第三方配置的代码，能在此基础之上衍生出一套属于自己的配置。甚至能完全抛弃第三方配置独立弄出一套自己的配置。所以后面我推荐的学习路线就是：不断阅读vim官方手册熟练使用某一个第三方配置在熟练的基础之上根据自己的习惯来定制一些只属于自己的功能形成一套只属于自己的科学的、高效的文本操作习惯根据这套习惯尝试定制自己的配置在其他编辑器中通过一定的配置尝试复刻这一套科学而又高效的操作习惯目前我正在第三部分努力。希望本系列文章能带领大家真正入门vim ，不会再出现因为觉得难而中途放弃。最后祝愿各位小伙伴在vim的使用中能收获快乐，并坚持下去！

从零开始配置vim(31)——git 配置
type: item
date: 2023-02-01T12:14:00+08:00
description: 很抱歉又拖更了这么久了，在这个新公司我想快速度过试用期，所以大部分的精力主要花在日常工作上面。但是这个系列还是得更新下去，平时只能抽有限的业余时间来准备。这就导致我写这些文章就慢了一些。废话不多说，咱们正式开始有关git相关的配置。这些配置都是根据我自身使用习惯来定义的，不一定符合各位的习惯，各位可以根据自身的习惯来调整gitsigns第一个要推荐的插件是 gitsigns。就像它的名字一样，该插件可以将最近的更改以标签的形式展现出来方便我们查看。我们可以使用这样的代码进行安装 use {'lewis6991/gitsigns.nvim' }。需要注意最新的版本需要 neovim 的版本在0.7 以上。安装完成之后我们通过配置 require('gitsigns').setup()来使用它。这样我们就可以通过 Gitsigns toggle_signs来打开或者关闭符号显示了。除了采用最基本的符号显示以外，它还可以对改变位置的行号进行标记以及高亮显示变更的行。这两个功能可以通过 Gitsigns toggle_numl和 Gitsigns toggle_linel来打开，打开之后显示如下：从图中可以看到，更改行行号被用绿色显示了出来并且更改行进行了高亮显示另外它还有其他的显示效果：它主要的一些显示功能主要有下面几个：toggle_signs: 显示变更记录toggle_numl: 显示变更行号toggle_linel：高亮变更的行toggle_delete: 显示被删除的行，以红色背景高亮显示toggle_word_diff: 在两行分别显示修改前和修改后的内容toggle_current_line_blame: 在对应行后面显示提交记录我们将所有的这些功能都打开将得到这么一个效果是不是看着有点乱？这是我修改了一处的，一旦修改多了看着会更混乱。所以我自己的经验告诉我在这个buffer里面最好是只打开 signs、numl、linel、current_line_blame的功能，其他的都关掉。也就是在当前buffer中只显示现在的代码，然后辅助以简单的符号来显示哪行是新加的，哪行被删除了，哪行被修改了，至于修改前是什么样子的，我可以通过其他方式来查阅。所有内容都在一个buffer 中显示会比较乱，不利于阅读代码。我们可以通过配置将我们要显示的内容进行定义，也可以定义使用何种图标来表示修改记录。我们采用如下的配置gitsigns.setup({ signs = { add = {hl = 'GitSignsAdd' , text = '+', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, change = {hl = 'GitSignsChange', text = '│', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, delete = {hl = 'GitSignsDelete', text = '-', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, topdelete = {hl = 'GitSignsDelete', text = '-', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, untracked = {hl = 'GitSignsAdd', text = '+', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, changedelete = {hl = 'GitSignsChange', text = '~', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, }, signcolumn = true, -- Toggle with `:Gitsigns toggle_signs` numhl = true, -- Toggle with `:Gitsigns toggle_numhl` linehl = true, -- Toggle with `:Gitsigns toggle_linehl` word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff` watch_gitdir = { interval = 1000, follow_files = true }, attach_to_untracked = true, current_line_blame = false, -- Toggle with …

从零开始配置vim(30)——DAP的其他配置
type: item
date: 2022-12-30T16:57:00+08:00
description: 很抱歉这么久才来更新这一系列，主要是来新公司还在试用期，我希望在试用期干出点事来，所以摸鱼的时间就少了。加上前面自己阳了休息了一段时间。在想起来更新就过去一个多月了。废话不多说了，让我们开始进入正题。在前一章，我们谈论了如何在 neovim 中使用cpptools 这个DAP 的适配器对代码进行调试，目前针对编译型和解释型语言来说我们都有了对应的方法来配置调试器对其进行调试。本节将要介绍关于dap的其他一些功能，主要包括 repl窗口和 gdb的集成repl 窗口什么是 repl 呢？它的全称是 Read Eval Print Loop 中文一般翻译为交互式解析器，可能看到这你还是一脸懵逼，你可以想想 python 或者nodejs，在控制台输入python 就可以进入到它的交互式解析器中，随着我们输入python 的语句，它会实时的给出运行的结果。交互式解析器就是这么一个东西，输入命令，它给你一个实时的结果。在调试中使用交互式解析器还是很有用的，比如我想显示当前某个变量的值，当前执行到哪个语句了等等。nvim-dap已经提供了一个内置的 repl 窗口，我们每次启动调试的时候都会看到它每次都会创建一个新的名为 dap-repl的buffer。之前我们没怎么关注它主要还是因为那个时候的重点在于如何进行调试，现在我们将要来优化这部分的显示和功能。首先我们发现每次调试结束的时候这个buffer 都会被遗留，需要我们手动的进行关闭，除了针对buffer通用的 :q 或者 :bd命令进行关闭，还可以使用 :lua require('dap').repl.close()。当然也可以配套使用 :lua require('dap').repl.open()来打开一个 repl的窗口，既然每次都会自动新建，那么这里我们就不需要进行新建，主要用于想办法关闭就可以了。还记得之前介绍 nvim-dapui 插件的时候介绍的那两个监听函数吗，同样的我们要在监听调试结束的函数中添加代码来关闭repl 窗口，函数的整个代码如下dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close({}) dap.repl.close() end dap.listeners.before.event_exited["dapui_config"] = function() dapui.close({}) dap.repl.close() end再启动调试的时候发现它已经可以在调试结束的时候自动关闭了。还有另外一个问题就是我不太喜欢现在这样在最下角显示 repl。我希望它能够在最下方以整行的形式显示。或者可以方便的不显示，只有在需要的时候显示。要达成这个目的我们需要修改 dapui 的配置。dapui 的配置主要以 element为基础，每个 element 代表一个提供对应功能的窗口。我们先来根据它默认的配置来讲解每部分的含义require("dapui").setup({ icons = { expanded = "", collapsed = "", current_frame = "" }, mappings = { -- Use a table to apply multiple mappings expand = { "<CR>", "<2-LeftMouse>" }, open = "o", remove = "d", edit = "e", repl = "r", toggle = "t", }, -- Use this to override mappings for specific elements element_mappings = { -- Example: -- stacks = { -- open = "<CR>", -- expand = "o", -- } }, -- Expand lines larger than the window -- Requires >= 0.7 expand_lines = vim.fn.has("nvim-0.7") == 1, -- Layouts define sections of the screen to place windows. -- The position can be "left", "right", "top" or "bottom". -- The size specifies the height/width depending on position. It can be an Int -- or a Float. Integer specifies height/wid…

从零开始配置vim(29)——DAP 配置
type: item
date: 2022-11-18T14:17:00+08:00
description: 首先给大家说一声抱歉，前段时间一直在忙换工作的事，包括但不限于交接、背面试题准备面试。好在最终找到了工作，也顺利入职了。期间也有朋友在催更，在这里我对关注本系列的朋友表示感谢。多的就不说了，我们正式进入vim 的配置吧上一节通过配置 python 的调试环境，我们大概了解了配置 dap 的基本步骤。首先需要一个 dap 的客户端负责在编辑器上显示各种调试信息，并且与用户进行交互。然后需要一个服务端，与客户端通信并完成调试的实际步骤。然后需要配置两个东西， dap.adapters 用来配置如何启动调试器，dap.configurations用来配置如何将当前项目加载到调试器上。本篇我们进一步配置 dap。让它变得更好用，并且介绍编译型语言(C/C++)调试的配置。优化界面回顾一下上一篇中在演示图片里面看到的效果。默认界面在断点位置以 B 来标识，当前运行的代码以 -> 来标识。看起来不那么的直观，我们先对它进行优化，我们采用 Visual Code 的调试图标来进行标识我们采用以下代码进行配置local dap_breakpoint_color = { breakpoint = { ctermbg=0, fg='#993939', bg='#31353f', }, logpoing = { ctermbg=0, fg='#61afef', bg='#31353f', }, stopped = { ctermbg=0, fg='#98c379', bg='#31353f' }, } vim.api.nvim_set_hl(0, 'DapBreakpoint', dap_breakpoint_color.breakpoint) vim.api.nvim_set_hl(0, 'DapLogPoint', dap_breakpoint_color.logpoing) vim.api.nvim_set_hl(0, 'DapStopped', dap_breakpoint_color.stopped) local dap_breakpoint = { error = { text = "", texthl = "DapBreakpoint", linehl = "DapBreakpoint", numhl = "DapBreakpoint", }, condition = { text = 'ﳁ', texthl = 'DapBreakpoint', linehl = 'DapBreakpoint', numhl = 'DapBreakpoint', }, rejected = { text = "", texthl = "DapBreakpint", linehl = "DapBreakpoint", numhl = "DapBreakpoint", }, logpoint = { text = '', texthl = 'DapLogPoint', linehl = 'DapLogPoint', numhl = 'DapLogPoint', }, stopped = { text = '', texthl = 'DapStopped', linehl = 'DapStopped', numhl = 'DapStopped', }, } vim.fn.sign_define('DapBreakpoint', dap_breakpoint.error) vim.fn.sign_define('DapBreakpointCondition', dap_breakpoint.condition) vim.fn.sign_define('DapBreakpointRejected', dap_breakpoint.rejected) vim.fn.sign_define('DapLogPoint', dap_breakpoint.logpoint) vim.fn.sign_define('DapStopped', dap_breakpoint.stopped)上面的代码主要配置了显示的颜色和图标。最终调试的效果如下图所示然后我们需要提供一个可用的界面用来显示调试过程中的各种信息，包括变量值和调用栈。完成这个工作的是插件 nvim-dap-ui 。我们使用如下的代码进行安装use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }这个插件里面包装了很多调试相关的窗口，例如变量监控、调用栈等等。我们可以对他进行配置，让这些窗口元素出现在我们希望它出现的位置。为了加载这个插件我们还是按照之前的惯例，为它准备一个单独的配置文件，并且加载它。local dapui = …

从零开始配置vim(28)——代码的编译、运行与调试
type: item
date: 2022-10-24T11:17:00+08:00
description: 在前面几个章节，我们逐渐为 Vim 配置了语法高亮、代码的跳转和自动补全功能。现在的 Vim 已经可以作为代码编辑器来使用了。但是想将它作为日常发开的主力编辑器来用还需要很长一段路要走，其中一个就是要为它配置代码的一键编译与运行功能。这里我们仍然以 C 和 Python 为例。一个是需要编译运行的一个是直接就可以运行的，这两个语言应该能代表大多数语言的情况。自动运行C 语言的配置在之前 vim 入门的一系列教程中我们介绍过 vim 自带 make 命令的运行机制以及如何进行自定义。对于其他语言要实现这个自动编译运行的效果我们核心的操作就是在修改 make 命令。而 C/C++ 本身采用 make 命令来进行编译和运行，所以这里 C/C++ 我们直接采用 vim 自带的 :make 命令在之前 vim 入门的一系列教程中我们介绍过 vim 自带 make 命令的运行机制以及如何进行自定义。对于其他语言要实现这个自动编译运行的效果我们核心的操作就是在修改 make 命令。而 C/C++ 本身采用 make 命令来进行编译和运行，所以这里 C/C++ 我们直接采用 vim 自带的 :make 命令我们先创建一个 C 的工程。让后使用上一节的生成 hello world 的代码片段生成一个基本的程序。然后提供一个供 :make 命令使用的 Makefile 文件main.out: main.o gcc main.o -o main.out main.o: main.c gcc -c main.c clean: rm -rf *.o *.out run: ./main.out然后我们执行 make 用来编译。如果出错了，可以使用 quickfix 相关命令跳转到对应位置。我们一般的流程是 :make 进行编译，然后使用 :make run 来进行运行。把命令搞清楚了，下面就考虑如何加快这个流程，做到一键编译运行。我们的思路还是绑定快捷键。每种语言虽然定义相同的快捷键但是运行的命令不同，我们需要根据不同的语言类型绑定对应的命令。这个时候最好的办法就是在 filetype 的机制上完成绑定的操作。我们在 lua/lsp/cpp.lua 中绑定快捷键。local on_attach = function(client, bufnr) lsp_set_keymap.set_keymap(bufnr) -- 编译 vim.api.nvim_buf_set_keymap(bufnr, "n", "<F7>", "<cmd>make<CR>", {silent = true, noremap = true}) -- 编译运行 vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>make run<CR>", {silent = true, noremap = true}) end到此我们关于 C/C++ 的配置就完成了。可能显的有些简单但是已经初步可用了，小伙伴可以根据自己的需求来进一步修改这个配置。使用这个配置的前提是 C/C++ 的工程中有已经定义好的 Makefile 文件Python的配置之前我们在讲解命令的模式的提到过可以使用 % 来代表当前 buffer 所对应的文件。所以 python 的配置就比较简单了。因为 Python 不需要编译，所以这里直接绑定 <F5> 来运行vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>!python %<CR>", {silent = true, noremap = true})dap 配置我们经常看到有人配置 neovim 或者 vim 的时候会介绍到 dap ，那么什么是 dap 呢? dap 的全称是 Debug Adapter Protocol 从名称上看它又是一个协议。它为多种调试器提供了一层统一的适配抽象层。有点类似于前面的介绍的 lsp。只要在适配层提供接口的实现，那么在客户端，也就是代码编辑器这端可以不做任何修改的集成不同调试联想到 lsp 的配置，我们配置dap 首先需要的是有一个 dap 的客户端，用来向调试器发送各种命令，例如下断点、显示变量名等等。另外想要能够调试也需要有具体的调试器，用来接收处理这些命令。现在思路有了，我们 这里先以 Python 为例来介绍 dap 的基本配置。首先是需要一个客户端，用于通过 neovim下发各种调试命令并实时显示调试信息。截止到 0.7 版本 NeoVim 并没有在内部集成 dap 客户端的功能，需要我们单独安装相关插件来实现这部分的功能。这里我们使用的客户端是 nvim-dap 插件。我们先使用 use {'mfussenegg…