- 浏览: 237570 次
文章分类
最新评论
-
sunyukun8888:
多谢啦!
重新整理后的Oracle OAF学习笔记——离线版本 -
singlespider:
很不错啊,谢楼主
重新整理后的Oracle OAF学习笔记——离线版本 -
000fuli:
000fuli 写道请问各位学长:你们可以下载吗?能下载的烦请 ...
重新整理后的Oracle OAF学习笔记——离线版本 -
000fuli:
请问各位学长:你们可以下载吗?能下载的烦请发一份到fuli.w ...
重新整理后的Oracle OAF学习笔记——离线版本 -
goodscript:
确实是不错的好文章!
重新整理后的Oracle OAF学习笔记——离线版本
一些更复杂的函数
copy-to-buffer的函数定义
这个函数拷贝文本到缓冲区,但它不是追加到第二个缓冲区,而是替换第二个缓冲区之前的文本。copy-to-buffer函数与append-to-buffer代码很类似,但它使用了erase-buffer和二个save-excursion。
该函数的函数体如下:
...代码与append-to-buffer类似:不同处在于,改变buffer后append-to-buffer添加文本到缓冲区;而copy-to- buffer函数先删除缓冲区的内容。在删除之前的缓冲区的内容后,第二次使用了save-excursion,并且插入了新的文本。
(interactive "BCopy to buffer: \nr")
(let ((oldbuf (current-buffer)))
(save-excursion
(set-buffer (get-buffer-create buffer))
(erase-buffer)
(save-excursion
(insert-buffer-substring oldbuf start end)))))
为什么需要执行save-excursion两次?
单独提取copy-to-buffer函数体如下:
(let (bind-oldbuf-to-value-of-current-buffer)
(save-excursion ; First use of save-excursion.
change-buffer
(erase-buffer)
(save-excursion ; Second use of save-excursion.
insert-substring-from-oldbuf-into-buffer)))
第一个save-excursion让Emacs返回被复制文本的缓冲区。很清楚,这与append-to-buffer函数中的使用是一致的。为 什么要使用第二个save-excursion呢?原因在于insert-buffer-substring总是将point设置在被插入的区块 (region)的结束位置。第二个save-excursion将使用Emacs将point设置在被插入区块的开始位置。多数情况下,用户喜欢看到 point停留在被插入文本的开始位置。(copy-to-buffer函数将返回用户最初所在的缓冲区,当用户切换到拷贝的目标缓冲区时,point停 留在缓冲区开始的位置)。
insert-buffer的函数定义
与append-to-buffer和copy-to-buffer相反,这个命令拷贝另一个缓冲区到当前缓冲区。
insert-buffer的代码
(defun insert-buffer (buffer)
"Insert after point the contents of BUFFER.
Puts mark after the inserted text.
BUFFER may be a buffer or a buffer name."
(interactive "*bInsert buffer: ")
(or (bufferp buffer)
(setq buffer (get-buffer buffer)))
(let (start end newmark)
(save-excursion
(save-excursion
(set-buffer buffer)
(setq start (point-min) end (point-max)))
(insert-buffer-substring buffer start end)
(setq newmark (point)))
(push-mark newmark)))
insert-buffer中的交互
insert-buffer中的interactive有两个部分,*号和bInsert buffer:
只读缓冲区
星号用于只读缓冲区。如果insert-buffer是在一个只读缓冲区上被调用,提示信息将在回显区显示提示不允许插入到当前的缓冲区。星号不需要使用\n与下一个参数分隔。
交互表达式b
交互表达式的第二个参数是小写b开头的(append-to-buffer中是大写的B)。小写b告诉Lisp解释器,insert-buffer 需要一个已存在的缓冲区或者已存在的缓冲区名称作为参数。(大写的B可以使用一个不存在的缓冲区)Emacs将提示输入缓冲区名称,并提供了默认的缓冲 区,输入时可以使用自动完成功能。如果缓冲区不存在,将给出"No match"的提示。
insert-buffer函数体
insert-buffer函数有两个主要部分:or语句和let语句。or语句用于确保参数buffer参数不仅仅只是被绑定到缓冲区的名字上。let语句包含复制其它缓冲区到当前缓冲区的代码。
(defun insert-buffer (buffer)要明白or如何确保参数buffer不只是被绑定到缓冲区名称上,先要清楚or函数。
"documentation..."
(interactive "*bInsert buffer: ")
(or ...
...
(let (varlist)
body-of-let... )
在insert-buffer用if替代or
主要工作在于确保buffer变量值是一个缓冲区,而不是缓冲区的名字。如果变量值是名字,则需要获取对对应的缓冲区。
通过if来实现:如果没有获取到buffer就获取它。
这里使用了bufferp函数,这个函数检查参数是否为一个缓冲区(或者缓冲区的名字),我们可以如下编码:
(if (not (bufferp buffer)) ; if-part前面说过bufferp中的字符p是一个约定的函数描述,它意味着函数用于决定某些属性为true或false。这里bufferp就是用于检查参数是否为一个缓冲区。
(setq buffer (get-buffer buffer))) ; then-part
not函数用于取逻辑值的反值。
当buffer参数不是一个缓冲区但它是一个缓冲区名称时,true-or-false-test返回true。这时(set q buffer (get-buffer buffer))被执行。语句使用get-buffer函数获取缓冲区名称所对应的缓冲区。setq将buffer绑定到缓冲区上。
函数体中的or
insert-buffer函数中使用or语句的目的在于确保buffer被绑定到缓冲区。上一节用if实现了这个功能。但在insert-buffer函数中实际使用的却是or函数。
or函数可以接收任何意数量的参数。它依次对每个参数求值并返回第一个结果不为nil的值。or并不会对第一个返回值不为nil的参数的后面的参数求值。
or语句如下:
(or (bufferp buffer)该语句中or的第一个参数为(bufferp buffer)。如果buffer参数是一个缓冲区则返回true(一个非nil值)。在or语句中,这种情况下or将返回true,并且不执行后面的语句。
(setq buffer (get-buffer buffer)))
如果(bufferp buffer)返回值为nil,即buffer是一个缓冲区的名字,Lisp解释器将执行or语句的下一个元素:(setq buffer (get-buffer buffer))。这个语句将返回一个非nil值,这个值为绑定到buffer变量上的缓冲区而不是缓冲区的名字。
使用or的情况:
(or (holding-on-to-guest) (find-and-take-arm-of-guest))
insert-buffer中的let语句
确保了buffer变量绑定到缓冲区后,insert-buffer函数中接下来是一个let语句。它设置了3个局部变量start、end和newmark并初始化为nil。这些变量是let语句中的临时变量。
let语句体包含了两个save-excursion语句。内部的那个save-excursion如下:
(save-excursion(set-buffer buffer)将将当前缓冲区设置为将要复制文本的缓冲区。在那个缓冲区中将start和end分别设置为缓冲区开始位置和结束位置。这里可以看到setq可以在一个语句中设置多个变量。第一个参数值设置为第二个参数,第三个参数值为第四个参数。
(set-buffer buffer)
(setq start (point-min) end (point-max)))
外部的那个save-excursion表达式结构如下:
(save-excursion
(inner-save-excursion-expression
(go-to-new-buffer-and-set-start-and-end)
(insert-buffer-substring buffer start end)
(setq newmark (point)))
insert-buffer-substring函数从原缓冲区中把start和end所定义的区域中的文本拷贝到buffer中。第二个缓冲区所 有内容都处于start和end之间,因此整个缓冲区都将被拷贝到当前编辑的缓冲区中。这时,point位于被插入的文本的结束位置,被保存到 newmark变量中。
在执行外部的save-excursion语句后,point和mark将回到原来的位置。
然而,合适的mark位置应该被设置在被插入的文本块的结束位置,而point应当被设置在这个文本块的开始位置。newmark记录了被插入文本 的结束位置。let语句的最后一行(push-mark newmark)语句将mark设置到了那个位置。(前一个mark仍然可以访问,它被保存在mark ring里面,可以用C-u C-<spc>回到那个位置)。同时,point被设置到被插入文本的开始位置,这也是函数调用前point所在的位置。</spc>
完整的beginning-of-buffer函数的定义
前面讨论过"简化版的beginning-of-buffer函数定义"。在那个版本中,调用的时候没有传递参数。 Emacs中的beginning-of-buffer将光标移到缓冲区开始位置,并将mark设置在之前光标所在位置。调用的时候可以传递1-10之间 的数字给这个命令,函数将把参数当作移动的百分比:整个缓冲区当作10份,C-u 7 M-<将跳转到整个缓冲区70%的位置。M-<将中跳转到缓冲区的开始位置。如果传递的参数大于10,则将移动到缓冲区的结束位置。
beginning-of-buffer的参数是可选的,可以不带参数调用。
可选参数
在调用需要参数的函数时,如果没有设置参数Lisp解释器将报错:Wrong number of arguments。
但Lisp提供了可选参数的功能:用&optional(&是这个关键字的一部分)关键字告诉解释器参数是可选的,如果参数跟在&optional的后面,则在调用函数时可以不传递这个参数
beginning-of-buffer函数定义的第一行:
(defun beginning-of-buffer (&optional arg)整个函数看起来如下:
(defun beginning-of-buffer (&optional arg)
"documentation..."
(interactive "P")
(push-mark)
(goto-char
(if-there-is-an-argument
figure-out-where-to-go
else-go-to
(point-min))))
整个函数与simplified-beginning-of-buffer函数类似,除了interactive语句用了"P"参数和goto-char函数跟了一个用于在传递了参数时计算光标位置if-then-else语句。
"P" interactive语句告诉Emacs传递一个前缀参数,这个参数来自于按键前输入的数字。或者输入C-u时输入的数字。(如果不输入数字,C-u缺省为4)
if语句部分比较简单:如果参数arg的值不为nil,即调用beginning-of-buffer时有带参数,则true-or-false- test返回true,if语句的then部分将被执行。如果beginning-of-buffer调用时没有带参数则if语句将被执行。else部分 (goto-char (point-min))被执行。
带参数执行beginning-of-buffer
当带参数执行时,用于计算传递给goto-char的参数值的语句被执行。这个语句初看起来比较复杂。它内部包含了一个if语句和更多的数学计算。
(if (> (buffer-size) 10000)
;; Avoid overflow for large buffer sizes!
(* (prefix-numeric-value arg) (/ (buffer-size) 10))
(/
(+ 10
(*
(buffer-size) (prefix-numeric-value arg))) 10))
解开beginning-of-buffer
解开上面的条件语句如下:
(if (buffer-is-largeif语句检查缓冲区的大小。这样做主要是由于在由的Emacs 18版本中计算出来的数字不允许大于8百万,Emacs怕缓冲区太大,后面的计算结果超过上限而溢出。在Emacs 21中使用大数字,但这个代码没被改动。
divide-buffer-size-by-10-and-multiply-by-arg
else-use-alternate-calculation
缓冲区很大时的情况
在beginning-of-buffer中,内部的if语句为了检查缓冲区是否大于1000个字符使用了>函数和buffer-size函数。
(if (> (buffer-size) 10000)如果超过了if语句的then部分将执行:
(*语句使用*函数将两个参数相乘。
(prefix-numeric-value arg)
(/ (buffer-size) 10))
第一个参数(prefix-number-value arg)。当使用"P"作为interactive时,传递给函数的参数值是一个"raw prefix argument",不是一个数字(是一个包含了一个数字的列表)。为了执行数字运行,需要通过prefix-number-value来做转换。
第二个参数是(/ (buffer-size) 10)。这个语句将数值与十相除。这计算出了缓冲区中1/10有多少个字符。
在整个相乘的语句如下:
(* numeric-value-of-prefix-arg如果传递的参数是7,计算出的位置就是缓冲区70%的位置。
number-of-characters-in-one-tenth-of-the-buffer)
缓冲区很大的时候,goto-char语句的情况:
(goto-char (* (prefix-numeric-value arg)
(/ (buffer-size) 10)))
缓冲区较小时的情况
如果缓冲区包含的字符数量小于10000,计算上有些不同。也许你会认为这没有必要,因为第一个计算方式(大于10000时的情况)也能工作。然而在小型缓冲区中,第一种方法不能将光标放在需要位置;第二种方法则工作得好一些:
(/ (+ 10 (* (buffer-size) (prefix-numeric-value arg))) 10))格式化后看得更清楚一些:
(/看最内部的括号(prefix-numberic-value arg),它将raw argument转换为数字。然后将数字与缓冲区大小相乘。 <src lang="lisp"></src> 这个操作将得到一个大于缓冲区几倍的数字。然后用这个数字加上10最后再除以10得到一个大于百分比位置的值。
(+ 10
(*
(buffer-size)
(prefix-numeric-value arg)))
10))
这个结果被传递给goto-char将光标移到那个点。
beginning-of-buffer的完整代码
(defun beginning-of-buffer (&optional arg)
"Move point to the beginning of the buffer;
leave mark at previous position.
With arg N, put point N/10 of the way
from the true beginning.
Don't use this in Lisp programs!
\(goto-char (point-min)) is faster
and does not set the mark."
(interactive "P")
(push-mark)
(goto-char
(if arg
(if (> (buffer-size) 10000)
;; Avoid overflow for large buffer sizes!
(* (prefix-numeric-value arg)
(/ (buffer-size) 10))
(/ (+ 10 (* (buffer-size)
(prefix-numeric-value arg)))
10))
(point-min)))
(if arg (forward-line 1)))
代码中的文档字符串中使用了一个语句:
\(goto-char (point-min))语句第一个括号前的\告诉Lisp解释器应该打印这个表达式而不是对它求值。
beginning-of-buffer的最后一行代码:如果执行命令时带了参数,则移动point到下一行的起始位置。
(if arg (forward-line 1)))这行代码将光标移动到了计算位置的下一行的起始位置。(这行代码并非必要的,只是为了看起来更好)
回顾
- or
依次执行各个参数直到遇到一个返回值不为nil的值。如果没有返回值为nil的参数,则返回nil,否则返回第一个返回值不为nil的值。简单来说就是:返回参数中第一个为true的值。
- and
依次执行各个参数,直到遇到返回值为nil时,返回nil;如果没有nil则返回最后一个参数的值。简单来说就是:如果所有参数都为true就返回true;
- &optional
这个关键字用于标明函数定义中的参数是可选的参数。意味着调用函数时可以不传递这个参数。
- prefix-numeric-value
将从(interactive "P")获取到的"raw prefix argument'转换为数字。
- forward-line
将point移到下一行的行首,如果参数大于1,则向下移动多行。如果不能移动那么多行,则forward-line尽量移动到能到达的位置,并返回没有进行操作的多余次数。
- erase-buffer
删除当前整个缓冲区中的内容。
- bufferp
如果参数是一个缓冲区,则返回t,否则返回nil。
发表评论
-
emacs中使用semantic实现c代码自动完成功能
2008-11-25 16:29 9858环境: windows xp emacs 23 自已编译的cv ... -
Emacs Lisp中的hash table
2008-03-10 16:30 2320(defun zj-hash-test () "h ... -
Emacs Lisp与Shell的交互
2008-03-10 16:27 4595一直以来对于w3m、tramp、dired等与shell关系 ... -
Programming in Emacs Lisp笔记(十八) 终结
2007-07-20 11:34 2726笔记连载完毕。感谢大家的支持! 离线版本可以从这里下载。 -
Programming in Emacs Lisp笔记(十七) 调试
2007-07-20 11:11 5479调试 GNU Emacs中有两个高度器,debug和edeb ... -
Programming in Emacs Lisp笔记(十六).emacs文件
2007-07-20 11:10 6541.emacs文件 Emacs的缺省 ... -
Programming in Emacs Lisp笔记(十五)准备图表
2007-07-19 16:36 2445准备图表 我们的目标 ... -
Programming in Emacs Lisp笔记(十四)统计defun中的单词数量
2007-07-19 16:36 2907统计defun中的单词数量 我们的下一个计划是统计函数定义中 ... -
Programming in Emacs Lisp笔记(十三)计数:重复和正则表达式
2007-07-19 16:28 2675计数:重复和正则表达 ... -
Programming in Emacs Lisp笔记(十二)正则表达式查询
2007-07-19 16:26 4589正则表达式查询 在Emacs中正则表达式查询使用得很广泛。在 ... -
Programming in Emacs Lisp笔记(十一)循环和递归
2007-07-04 18:18 3601循环和递归 Emacs Lisp有 ... -
Programming in Emacs Lisp笔记(十)Yanking Text Back
2007-07-04 17:59 2982Yanking Text Back 当使用'kill'命令剪 ... -
Programming in Emacs Lisp笔记的离线版本(2007年7月20日更新,完整版)
2007-07-03 15:45 5249使用muse生成了这个笔记的html版本。里面有带链接的索引, ... -
Programming in Emacs Lisp笔记(九)List的实现
2007-07-03 14:20 2231List的实现 Lisp中list使 ... -
Programming in Emacs Lisp笔记(八)剪切和存储文本
2007-07-02 12:04 2747剪切和存储文本 当使用'kill'命令剪切文本时,Emacs ... -
Programming in Emacs Lisp笔记(七)基础函数:car, cdr, cons
2007-06-29 10:09 3837基础函数:car, cdr, cons Lisp中car,c ... -
Programming in Emacs Lisp笔记(六) Narrowing and Widening
2007-06-28 10:41 2346Narrowing and Widening Narrowi ... -
Programming in Emacs Lisp笔记(四)与缓冲区有关的函数
2007-06-26 13:38 3220部分与缓冲区有关的函数 查找更多信息 可以通过C-h f查看 ... -
Programming in Emacs Lisp笔记(三)编写函数
2007-06-25 15:01 4196编写函数 关于基本函数 ... -
Programming in Emacs Lisp笔记(二)实践
2007-06-25 15:01 2440实践 执行代码 通过C-x C-e执行代码 缓冲区名称 b ...
相关推荐
Programming in Emacs Lisp英文版
- **标题**:“An Introduction to Programming in Emacs Lisp”(Emacs Lisp编程入门) - **描述**:该资源是基于Emacs官方文档的重编版本,旨在提供更易阅读的字体样式。 #### 知识点详解 ##### 1. Emacs Lisp...
- **标题**:“An Introduction to Programming in Emacs Lisp Second Edition” - **描述**:本书是关于Emacs Lisp编程的入门教程,被誉为“经典中的经典”。 该书由Robert J. Chassell撰写,由自由软件基金会出版...
### Robert Chassell:An Introduction to Programming in Emacs Lisp #### 知识点概览 - **Lisp Lists**: 介绍Lisp列表的概念及其在Emacs Lisp中的应用。 - **Lisp Atoms**: 解释Lisp原子的基本概念以及它们在...
An Introduction to Programming in Emacs Lisp [3.10].chm
Programming in Emacs Lisp: An Introduction (美)Robert J.Chassell 著 毛文涛、吕芳 译 洪峰 审校 本书的作者罗伯特·卡塞尔是自由软件基金会的合创人之一,也是理查德·斯托曼博士青年时期结交的挚友,他...
### Emacs Lisp 函数手册知识点概览 #### 一、引言 Emacs Lisp(简称Elisp)是Emacs文本编辑器内置的一种高级编程语言。它不仅支持编辑文档时的脚本化操作,还具备完整的编程功能,使得用户可以扩展Emacs的功能。本...
GNU Emacs Lisp编程入门(清晰版) 英文名:An Introduction to Programming in Emacs Lisp
本书不仅详细介绍了Emacs Lisp编程的基础知识,如变量的定义、函数的创建、数据类型的处理等,还深入讲解了如何通过Emacs Lisp来扩展和定制Emacs编辑器的功能,实现个性化的编辑体验。此外,书中还包含了大量实用的...
GNU emacs Lisp manual This is a very interesting text, useful to write and program in several languages. Emacs is a editor made in Lisp, a artificial intelligence language.
在“Atom-language-emacs-lisp.zip”这个压缩包中,主要关注的是对Emacs Lisp的支持。Emacs Lisp是一种用于扩展和定制GNU Emacs编辑器的Lisp方言。它提供了丰富的API和交互式编程环境,使得开发者可以编写自定义的...
函数是Emacs Lisp中实现复杂数字逻辑的关键工具。这部分内容不仅介绍了如何定义和调用函数,还包括了如何使用参数、返回值以及异常处理等内容。 #### 13. 宏 宏是Emacs Lisp中的一个重要特性,可以用来创建自定义的...
通过深入学习Emacs Lisp,你可以充分利用Emacs的强大功能,从简单的快捷键绑定到复杂的编辑器扩展,都可以通过编写Elisp代码来实现。"GNU Emacs Lisp编程入门.pdf"这本书将是一个很好的起点,带领你探索这个充满可能...
GNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvuGNU EMACS lisp编程入门.djvu
本书不仅对Emacs Lisp语言的基础语法、数据结构、控制结构和函数进行了解释,还介绍了如何利用Emacs Lisp进行更高级的编程实践,包括日历、邮件、写作、编程和调试程序等方面。书中还涵盖了Emacs作为一个集成环境所...