Emacs Lisp 学习(4)

作者: 桂叶圣 | 来源:发表于2016-10-12 20:16 被阅读632次

上一次我们学习了 let 特殊形式, 今天学习的内容学习它的表弟: let*. 之后, 我们学习几个和 Buffer 操作相关的一些函数, 并试着在用这些函数来写自己的 Emacs Lisp 函数.

let* 长得和 let 非常像, 用起来也非常的像, 只有很少的区别. 首先看一下 let* 的使用模版:

(let* VARLIST BODY...)

其中 VARLIST 是一个列表, 这个列表的元素可以是两种:

  1. 符号, 就是定义一个参数, 值绑定为 nil.
  2. 子列表, 形式是 (SYMBOL VALUEFORM) 把 SYMBOL 的值绑定为了 VALUEFORM 的值.

依次的计算 BODY 的每个语句, 最后一个 BODY 语句的值, 作为 let* 的返回值返回.

以上的内容, 和 let 的用法其实是完全一样的, 那么和 let 的不同在哪里呢? 不同在于 VALUEFORM 的内容上. let 中的 VALUEFORM 的内容, VARLIST 列表中的符号都还没有定义, 所以 VALUEFORM 如果使用 VARLIST 中的符号就会提示知道不到变量. let* 中不是这样. let* 中 VALUEFORM 可以是在同一个 VARLIST 中, 位于前面的符号. 那个例子来看一下:

(setq test-variable 'global); this variable "test-variable" is global define
(let ((a "hello")
      (b a))                  ;let can NOT find variable "a", a error happend.
     (message "b:%s" b))
(let* ((a "hello")
      (b a))                  ;let* CAN find varibale "a"
     (message "b:%s" b))
(let ((test-variable 'local) ;this variable is a local varibale
      (b test-variable))      ;What's is value of b?
     (message "b:%s" b))
(let* ((test-variable 'local);this variable also local
       (b test-variable))     ;What's is value of b?
      (message "b:%s" b))

执行第一个 let 语句, 会发生一个错误, 提示信息就是说找不到变量 a. 第一个 let* 不会提示错误, b:hello 会出现在回显区域. 这说明 let 对 VARLIST 中的符号做值绑定的时候, 是不会在 VARLIST 中查找符号的定义的, 而 let* 却会在 VARLIST 中找. 执行第二个 let 会看到回显区域显示的是: b:global. 执行第二个 let* 在回显区域中看到的是 b:local. let 情况容易解释, 因为 let 对 b 做值绑定的时候, 根本在在它的 VARLIST 中查找符号的值, 所以 VARLIST 的第二个元素 (b test-variable) 中的 test-variable 只能是我们全局定义的那个 test-variable. 在第一个 let* 的调用的时候, 我们知道 let* 也会到外面的找符号的值, 第二个 let* 的计算告诉我们, let* 不仅仅在内部找符号的值, 而且如果在内部找到的话就不再到外部去找了. 第二个 let* 的例子还告诉我们 let* 是从内向外找符号的值的. 仔细体会这几个例子, 就应该能明白 letlet* 的差别.

在 Emacs 中如果要选中全部的内容, 使用的快捷键是 C-x h, 对应的 Emacs Lisp 函数是 mark-whole-buffer. 现在我们来写一个我们自己的版本. 在 Emacs 中选定一个区域的内容, 首先创建一个标记, 然后移动光标到目的位置, 创建标记的位置到目的位置之间的内容, 就是区域的内容, 也是 Emacs 选中的内容. 选中一个buffer 的全部的内容, 值需要在这个 buffer 开始的位置设置一个标记, 然后把光标移动到这个 buffer 结尾的地方就可以了(反过来, 把标记设置到 buffer 的结尾, 把光标放到 buferr 开始的地方也可以, 我们这里使用第一种方法). 那么问题就变成了:

  1. 如何使用 Emacs Lisp 在特定的位置设置标记?
  2. 如何把光标移动到特定的位置呢?
  3. buffer 开始的是固定的 1. 但是怎么获得一个 buffer 最后的位置呢?

我们依次来说, 首先是如何获得一个buffer 的最大位置, 简单来说使用函数 point-max, 但是实际上, 调用 point-max 返回的不总是是 buffer的最后的位置, 当这个 buffer 处于 narrow 模式的时候, point-max 返回的值就不在是这个 buffer 最后的位置了, 而是 这个narrow 区域的最后的位置. 可以猜到 point-min 正常模式下一定就是1 , 在 narrow 模式下不是 1, 而是这个 narrow 开始的位置在这个 buffer 中的位置. 现在我们不考虑 narrow 的情况, 假设就是在正常模式下, 那么 buffer 开始位置和结束位置问题加解决了.

移动光标到一个特定的位置, 用的是函数 goto-char. 在特定位置设置标记是 push-mark. 更多的内容, 可以参考 Emacs 帮助文档来 C-h f goto-char , C-h f push-mark 来了解. 一下是我写的最简单的选择全部 buffer 内容的版本.

(defun select-whole-buffer ()
    "selecte whole buffer to regin"
    (interactive)
    (push-mark 1 nil 't)
    (goto-char (point-max)))

我发现, 现在学习的内容, 其实更多的已经不是 Emacs Lisp 语言的问题了, 更多的是 Emacs Lisp 的库函数怎么使用的问题了. 如果后面的内容没有更多的关于 Emacs Lisp 语言的问题, 我就不在更新内容, 等我学习完 Emacs Lisp 语言之后, 库的问题在一点点看. 或者集中起来把 Emacs Lisp 常用的库介绍一下.

相关文章

  • 简介

    1. 为什么学习 Emacs Lisp 2. Lisp 的历史 3. Lisp 的特点 4. E...

  • Emacs Lisp 学习(4)

    上一次我们学习了 let 特殊形式, 今天学习的内容学习它的表弟: let*. 之后, 我们学习几个和 Buffe...

  • Emacs Lisp 学习(2)

    昨天, 学习了 Emacs Lisp 的一些基本的概念, 今天学习如何定义函数, 如何使用函数. 在 Emacs ...

  • emacs笔记

    前言 最初接触emacs是因为org-mode,后来学习lisp又把玩了几把。我还是无法放弃Lisp,就从emac...

  • Emacs Lisp 学习(1)

    这是一个读书笔记, 是我学习 Emacs Lisp 的笔记. 这是这个笔记的第一篇. 使用 Emacs 做编辑器的...

  • Emacs Lisp 学习(3)

    我们学习了如何定义一个全局的变量 (set, setq), 以及如何定义一个函数. 函数可以有参数, 这个函数的参...

  • Emacs Lisp 学习(5)

    今天学习 Lisp 中几个基础的函数, car, cdr 和 cons. 名字问题

  • Emacs资料汇总

    Emacs 官方手册 Emacs Lisp 15 分钟入门 从零开始——Emacs 安装配置使用教程 2015 E...

  • 我也说说Emacs吧(6) - Lisp速成

    前面我们学习了基本操作,也走马观花地看了不少emacs lisp的代码。这一章我们做一个lisp的速成讲座。 Li...

  • Macos下spacemacs+slime+sbcl配置comm

    基本工具 spacemacs: 优秀的第三方 emacs 配置 slime: The Superior Lisp ...

网友评论

    本文标题:Emacs Lisp 学习(4)

    本文链接:https://www.haomeiwen.com/subject/figiyttx.html