Programming in Emacs Lisp笔记 编写函数

编写函数 
关于基本函数(Primitive Function) 

除了少数C编写的基本函数外,所有的函数都是由其它函数语句定义的。当编写自己函数时,C所编写的函数与Emacs Lisp编写的函数看起来是一样的。 

除非你想去考究,否则不需要知道知道一个函数是用Emacs Lisp编写的还是C编写的。 
defun 

在一个函数的定义中,在defun关键字后面有5个部分: 

   1. 函数符号的名称 
   2. 传递给函数的参数列表,如果没有参数则传递给函数的是一个空列表,() 
   3. 描述函数的文档字符串。(可选) 
   4. 当用户按M-x func_name以交互方式运行函数时的提示信息;或按键组合。(可选) 
   5. 函数体 

模板 

(defun function-name (arguments...) 
    "optional-documentation..." 
    (interactive argument-passing-info) ; optional 
    body...) 

一个实例(非交互) 

(defun multiply-by-seven (number) 
  "Multiply NUMBER by seven." 
  (* 7 number)) 

函数参数列表中的变量名对每个函数是私有的,不同函数的参数名可以相同。 

参数列表后面是描述函数功能的文档字符串。也就是按C-h f name_of_function时所看到的信息。 

在调用的时候使用 

(multiply-by-seven 3) 

尽管传递给函数的参数外面没有加括号。但函数能计算出来。 

当对这个表达式求值时将出错。这是因为我们只编写了函数定义,但并未告诉机器在Emacs中安装(install/load)这个函数定义。 
安装函数定义 

将光标停留上节所写的函数定义的最后一个括号后面,按C-x C-e。这时回显区将显示multiply-by-seven(这表示函数定义被计算,计算的返回值是所定义的函数的名字)。这时函数就已经安装好,可以在像使用Emacs中其它函数一样使用了。 
安装后的效果 

可以在 

(multiply-by-seven 3) 

的最后一个括号后按C-x C-e,回显区将显示计算结果21。还可以查看函数帮助文档。按C-h f(describe-function) function_name,multiply-by-seven。y 
修改函数定义 

可以直接修改函数的定义,然后重新把光标停留在在函数定义的最后一个括号后面按C-x C-e。 
制作交互式函数 

用户可以通过按键或者M-x 函数名来调用。 
交互式函数multiply-by-seven预览 

交互式版本的multiply-by-seven: 

(defun multiply-by-seven (number) 
  "Multiply NUMBER by seven." 
  (interactive "p") 
  (message "The result is %d" (* 7 number))) 

安装上面的函数后,可以使用C-u number参数,然后输入M-x multiply-by-seven然后回车。回显区将显示计算结果。 

调用这个函数的两种方法: 

   1. 输入前缀参数,然后输入M-x和函数名,比如C-u 3 M-x forward-sentence 
   2. 输入任意按键绑定例如:C-u 3 M-e 

输入C-u不带数字,则参数默认为4。 
交互式函数multiply-by-seven 

在上节所写的函数中,表达式(interactive "p")中的"p"告诉Emacs把前缀参数(C-u后带的参数)作为函数参数(number)传递给函数。 

message是一个Emacs Lisp函数,用于显示信息给用户。 
不同的interactive选项 

emacs有超过20过的选项可以传递给interactive。具体可以查阅elisp手册。 

例如,字符r,Emacs将把当前选中区域作为两个参数传递给函数。 

(interactive "r") 

B告诉Emacs提示用户输入缓冲区名称,并把该缓冲区作为参数传递给函数。例如: 

(interactive "BAppend to buffer:") 

当函数需要2个或更多参数时,可以在interactive中添加新的部分。每个部分用\n分隔。例如: 

(defun name-of-function (buffer start end) 
  "documentation..." 
  (interactive "BAppend to buffer: \nr") 
  body-of-function...) 

如果一个函数不需要参数,可以直接使用 

(interactive) 

永久的安装函数 

安装函数的几种方法: 

   1. 把代码放在.emacs文件中。 
   2. 把代码放在其它文件中,使用load函数装载文件。 
   3. 如果所有用户都要使用可以把代码放在site-init.el文件中 

let 

let表达式是在多数函数中都要用到的一个Lisp表。 

let用于修改或者绑定值到符号上。 
let 可以防止混乱 

let创建的是本地变量,作用范围止于let表达式范围内,不影响let外部的变量。let可以一次创建多个变量,并给每个变量赋值,初始值也可以是nil。在let执行完后,将返回最后一个语句的值。 
let表达式的组成 

let表达式分为3个部分,第一部分是符号"let"。第二个部分被称为变量列表(varlist),每个元素都一个符号或者包含二个元素的列表,每个列表中的一个元素是一个符号。第三部分是let的体(body)。 

(let ((variable value) 
      (variable value) 
      ...) 
  body...) 

let表达式举例 

(let ((zebra 'stripes) 
      (tiger 'fierce)) 
  (message "One kind of animal has %s and another is %s." 
           zebra tiger)) 

let语句中的未初始化变量 

(let ((birch 3) 
      pine 
      fir 
      (oak 'some)) 
  (message 
   "Here are %d variables with %s, %s, and %s value." 
   birch pine fir oak)) 

这里的pine、fir的值都是nil。 
if语句 

if的基本理念就是,如果if测试为真则表达式被执行。 
if 细节 

(if true-or-false-test 
    action-to-carry-out-if-test-is-true) 

例: 

(defun type-of-animal (characteristic) 
  "Print message in echo area depending on CHARACTERISTIC. 
If the CHARACTERISTIC is the symbol `fierce', 
then warn of a tiger." 
  (if (equal characteristic 'fierce) 
      (message "It's a tiger!"))) 

(type-of-animal 'fierce) 
(type-of-animal 'zebra) 

(type-of-animal 'fierce)将在回显区显示"It's a tiger!",第二行将返回nil。 
if-then-else语句 

(if true-or-false-test 
    action-to-carry-out-if-the-test-returns-true 
  action-to-carry-out-if-the-test-returns-false) 

例: 

(defun type-of-animal (characteristic)  ; Second version. 
  "Print message in echo area depending on CHARACTERISTIC. 
If the CHARACTERISTIC is the symbol `fierce', 
then warn of a tiger; 
else say it's not fierce." 
  (if (equal characteristic 'fierce) 
      (message "It's a tiger!") 
    (message "It's not fierce!"))) 

Emacs Lisp中的真值与假值 

符号nil作为假值,nil外的其它值都为真。 
对nil的解释 

在Emacs Lisp中对符号nil有两种解释。一种代表空的列表,另一种为真假判断中的假值。nil可以被写作:()、nil。对Lisp解释器来说两种写法是相同的。推荐用nil表示false,()表示空的列表。 

在Emacs lisp里,任何非nil非空列表的值都被当作真。 
save-excursion 

save-excursion函数保存当前的point和mark,然后执行函数体,然后恢复point和mark的位置。它的主要目的是为了保存用户在调用函数前所设置的point和mark。 
point和mark 

Point指当前光标之前的一个位置。在Emacs Lisp中,point是一个整数。缓冲区中第一个字符的point数字是1,函数point返回当前光标位置。 

Mark是缓冲区中的另一个位置。其值是通过C-<SPC>(set-mark-command)设置的。通过C-x C-x(exchange-point-and-mark)可以在point和mark间跳转。如果设置了另一个mark,前一个mark被保存到 mark ring里去。可以通过C-u C-<SPC>将光标跳转到被保存的mark。 

缓冲区中point和mark之间的区域叫作region。大量命令用于region上,例:center-region,count-lines-region,kill-region和print-region。 

Emacs里函数工作时经常移动point尽管用户感觉不到这一点。例如:count-lines-region。为防止用户的point被移动到非预期的位置(相对于执行函数之前),save-excursion常用于保存point的位置,使用save-excursion是一个好的习惯。 

不论代码运行是否成功(非正常结束),save-execursion总是恢复point和mark的位置。 

另外,save-excursion也将记录当前所在的缓冲区,并恢复它。这意味着可以在代码中修改当前缓冲区,结果后save-excursion将切换回原来的缓冲区。 
save-excursion语句模板 

(save-excursion 
  body...) 

更详细一些的模板: 

(save-excursion 
  first-expression-in-body 
  second-expression-in-body 
  third-expression-in-body 
   ... 
  last-expression-in-body) 

在Emacs Lisp代码中,save-excursion语句通常放在let语句中: 

(let varlist 
  (save-excursion 
    body...)) 

回顾 

部分函数 

    * eval-last-sexp 

对当前poing前的表达式求值。通常被绑定到C-x C-e上。 

    * defun 

定义函数。这个表(form)有5个部分:名称、参数定义、文档字符串、可选的交互式描述,函数体定义。例: 

(defun back-to-indentation () 
  "Move point to first visible character on line." 
  (interactive) 
  (beginning-of-line 1) 
  (skip-chars-forward " \t")) 

    * interactive 

告诉解释器函数可以交互。跟在字符串后的特殊的表(form)可以作为参数传递给函数。多个部分之间用\n分隔。常用的字符代码如下: 
b 一个buffer的名称 
f 一个文件名 
p 数字前缀(按C-u时输入的数字,默认为4) 
r 传递poing和mark两个数字参数,小的数字在前。这是唯一一个传递两个参数的字符代码。 

    * let 

申明并初始化作用于let函数体的局部变量,变量值可以为nil。在let内部,Lisp解释器对外部的同名变量不可见。例: 

(let ((foo (buffer-name)) 
      (bar (buffer-size))) 
  (message 
   "This buffer is %s and has %d characters." 
   foo bar)) 

    * save-excursion 

记录当前point、mark和当前所在缓冲区,在函数体执行完后恢复这些值。例: 

(message "We are %d characters into this buffer." 
         (- (point) 
            (save-excursion 
              (goto-char (point-min)) (point)))) 


    * if 

对第一个参数求值;如果返回的为true,则对第二个参数求值;否则如果第三个参数存在,则对第三个参数求值。if被称作条件语句。Emacs Lisp也有其它的条件语句,但if是最常用的。例: 

(if (string-equal 
     (number-to-string 21) 
     (substring (emacs-version) 10 12)) 
    (message "This is version 21 Emacs") 
  (message "This is not version 21 Emacs")) 

    * equal 
    * eq 

检查两个对象是否相同。equal检测是否”相同(same)“,如果两个对象有相似的结构和内容就返回true。eq则需要两个参数指向同一个对象才返回true。 

    * < 
    * > 
    * <= 
    * >= 

上面的比较函数的参数都必须是数字或者mark(C-<SPC>产生的)。 

    * string< 
    * string-lessp 
    * string= 
    * string-equal 

string-lessp函数检测第一个参数是否小于第二个参数。string<是它的简写。传递给string-lessp的参数必须是字符串或者符号(symbols)。空字符串""小于任何其它字符串。 

string-equal用于检查字符串的一致性。string=是它的简写。没有针对字符串>、>=或<=的函数定义。 

    * message 

在回显区显示消息。第一个参数是一个字符串,它可以包含%s,%d或%c这些占位符。%s必须对应于字符串或符号。%d对应于整数。%c必须是一个ascii编码数字。 

    * setq 
    * set 

setq函数设置第一个变量的值为第二个变量。第一个变量自动被加上单引号。setq可以同时对多个变量赋值。set只能给带两个参数。 

    * buffer-name 

不需要参数,返回缓冲区的名字。 

    * buffer-file-name 

不需要参数,返回缓冲区所对应的文件名。 

    * current-buffer 

返回当前活动的缓冲区;它可以不是当前屏幕上显示的缓冲区(编程时使用)。 

    * other-buffer 

返回最近访问过的访问区。 

    * switch-to-buffer 

选择一个缓冲区显示到当前用户窗口。磁盘被绑定到C-x b。 

    * set-buffer 

在程序运行时切换Emacs的焦点到某个缓冲区。并不会改变当前窗口中显示的内容。 

    * buffer-size 

返回当前缓冲区的字符数。 

    * point 

返回当前光标所在位置,返回值是从缓冲区开始处到光标位置的字符数。 

    * point-min 

返回当前缓冲区的开始位置。默认为1。 

    * point-max 

返回当前缓冲区的结束位置。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值