[elisp]针对Emacs中文本编辑的编程简介

emacs

Elisp是Emacs下的Lisp方言,而Emacs是一款编辑器。那么针对于Emacs,Lisp要做的很重要一部分工作当然就是对编辑的自动化支持。比如移动鼠标,输入句子,查找替换,代码高亮等等,简单地说,就是为更好更方便地支持文本编辑提供支持。而把这些函数都重合起来,就起成了Emacs mode。如我们常用的C++ mode,python mode。还有之前我一直在介绍的org-mode等,都是由Elisp拼成的。

学习Elisp,可以满足对Emacs进行定制的需求,你可以把想要的功能写在.el文件里面,让Emacs来调用。一方面可以实现一些简单的轻量级的功能,而不需要为此寻找和安装一个完整的mode。另一方面,可以修改现有的mode,使得更符合自己的习惯。这符合开源的作法,不爽即改。

Elisp函数的简单例子

光标位置

  ;返回当前光标的位置
  (point)
  ;region的头跟尾
  (region-beginning)
  (region-end)
  ;最大光标位置(即文件尾),elisp还提供最小光标位置(point-min),不过我觉得那应该都是1吧。
  (point-max)
  ;返回buffer结尾的绝对位置,无视narrow-to-region
  (buffer-end 1)

移动光标和搜索

;移动光标到392
(goto-char 392)

; 向前/向后移动n字符
(forward-char n)
(backward-char n)

; 跳过所有\n\t,即把光标移动第一个不是换行或制表符那里
; 返回移动的字符数
(skip-chars-forward "\n\t")
(skip-chars-backward "\n\t")

#移动光标到myStr后面,向前和向后
#返回新的光标位置
(search-forward myStr)
(search-backward myStr)

; 同上,但是参数是正则表达式,myRegex
; 返回新的光标位置
(re-search-forward myRegex)
(re-search-backward myRegex)

文本编辑

; 删除光标后的九个字符
(delete-char 9)

; 删除选中的两点之前的文本
(delete-region mystartpos myendpos)

; 在当前光标位置插入一字符串
(insert "Forza Inter")

; 从buffer中获得一个字符串并赋给mystr
(setq Mystr (buffer-substring mystartpos myendpos))

; 改变字符大小写
;这个例子是指当前光标之前的20个字符
(rapitalize-region (- (point) 20) (point))

字符串

; 长度
(length "abc") ; returns 3

; 获取一个子串
(substring myStr startIndex endIndex)

; 替换,以正则方式
(replace-regexp-in-string myRegex myReplacement myStr)

Buffers

; 当前buffer的名字
(buffer-name)

; 文件名(全路径)
(buffer-file-name)

; 设定一个buffer名
(set-buffer myBufferName)

; 保存
(save-buffer)

; 关闭指定的buffer
(kill-buffer myBuffName)

; 关闭当前buffer
(kill-this-buffer)

; 临时指定一个buffer作为当前buffer
(with-current-buffer myBuffer
  ;; do something here ...
)

Files

; 打开一个文件
(find-file myPath)

; 另存
; 会关闭当前的buffer,打开另存好的文件
(write-file myPath)

; 把一个文件内容插入到当前位置
(insert-file-contents myPath)

; 将选中的评论文本加到某个文件后面
(append-to-file myStartPos myEndPos myPath)

; 重命名
(rename-file fileName newName)

; 复制
(copy-file oldName newName)

; 删除
(delete-file fileName)

; 获取路径
(file-name-directory myFullPath)

; 获取文件名(不含路径)
(file-name-nondirectory myFullPath)

; 得到文件名后缀
(file-name-extension myFileName)

; 获得不含后缀的文件名。
(file-name-sans-extension "abc.htm")

简单的例子

  (defun insert-p-tag ()
  "Insert

 at cursor point."
  (interactive)
  (insert "

")
  (backward-char 4))

在当前光标处插入一个p tag。做法是插放一个串,然后将光标移回4位。

编写一个mode

理论上来讲,知道上面这些东西,你就有能力编写一个mode了。但是,编写mode毕竟是一个复杂的工作,需要编写者对elisp编程具有”hello world”以上很多级的熟练度。

在李杀网,作者有一个系列文章来讨论如何为一个编程语言编写mode

The End. Have fun!

[elisp]EmacsLisp 基础

来源:李杀网

李杀网有一枚elisp教程我很喜欢,原因是它不解释太多的名词,而从实际动作方面入手,对我的胃口。

以下是相关的笔记。

运行方式:

作为一个实践的手册,第一件事当然是告诉如果运行一行代码,让你在看指南的过程中可以方便地动手尝试。

寻找帮助:

可以使用”Alt + x describe-function”(快捷键”C-h f”)来查找一个函数的用法。也可以使用”Alt+x elisp-index-search”在手参考手册中查询。

常用函数

打印

  (message "hi")
  (message "her age is:%d" 16) ;%d 数字
  (message "her name is: %s" "Vicky") ;%s 字符串
  (message "her min init is: %c" 86) ;%c 字符

注意:你可以在*message* buffer中看到打印出来的结果。

运算函数

(+ 4 5 1 )  ;=10
(- 9 2)     ;=7
(* 2 3)     ;=6
(* 2 3 4)   ;=24
(/ 7 2)     ;=3  结果的整数部分
(/ 7 2.0)   ;=3.5
(% 7 4)     ;=3 余数

注意,如果你的操作数是小数,必须把后面的0带上。就是说你应该写2.0,而不是2.。

  (integerp 3.)  ;T
  (floatp 3.)    ;nil
  (floatp 3.0)   ;T

以字符p结尾的函数通常意味着它的返回值是True或者False。p意味着”predicate”(判定)。

True和False

在elisp中,标识”nil”代表false,其它的一切都是true,包括0。”nil”是空链表”()”的同义词。所以”()”也是false。

按惯例,标识”t”用来表示true。

  (and t nil) ; nil
  (or t nil)  ; t

在elisp中没有布尔型,只需记住”nil”和”()”是false,其它一切都是true。

比较函数

比较数字

  (< 3 4) ;小于
  (<= 3 4)  ;小于等于
  (> 3 4)  ;大于
  (>= 3 4) ;大于等于
  (= 3 3)  ;等于

比较字符串

  (string= "this" "thiS")
  (string< "a" "b")
  (string< "B" "b")

在字符串比较中大小写是敏感的。比较依据是字典顺序。

要比较两个sysbols是否有相同的数据类型和值,使用"equal"。

(equal "abc" "abc") ;t
(equal 3 3)         ;t
(equal 3 3.0)       ;nil.类型不同
(equal '(3 4 5) '(3 4 5))  ; t
(equal '(3 4 5) '(3 4 "5"))  ;nil

在Elisp中并没有"!="或者“not-equal”。判断不等,可以在对整个等式取非。

  (not (= 3 4))  ;t

全局和局部变量

"setq"用于给变量赋值。格式一般为"setq 变量1 值1 变量2 值2..."

在lisp中,变量不需要声时,并且是全局的。

  (setq a 3 b 2 c 7)  ;三个变是,a=3 b=2 c=7

定义局部变量,使用let。格式为"(let (变量1 变量2) body)"。"body"代表其它的表达式。其中最后一个表达式的取值是整个语句块的返回值。

  (let (a b)
  (setq a 3)
  (setq b 4)
  (+ a b)
  )

a和b都是这个语句块的局部变量,返值是最后一个表达式"(+ a b)"的取值。

另一种格式是"(let ((变量1 值1)(变量2 值2)) body )"。例如:

  (let ((a 3) (b 4))
  (+ a b)
  )

如果你的变量很少,并且值都是已经确定的,可以用这种方法。

表达式块

有时需要把一些表达式括起来。这时可以使用"progn"。

  (progn (message "hi"))

它相当于

  (message "hi")

"progn"类似于C语言中的"{...}"。它使用于某些需要把语句合并起来的场合,其实这跟C语言中也是一样的。比如:"(if something (progn this that))"。这里,如果把progn去掉,变成"(if somethong this that",在lisp中表示如果something,那么this,否则that。在有progn把this和that括真情 为情况下,表示的是如果something,那么执行this和that。

If then else

格式为"(if test then )"。"else"是可选的。例:

  (if (< 3 2) (message "yes")))
  (if (< 3 2) (message "yes") (message "no")))

迭代循环

使用while。

  (setq x 0)
  (while (< x 4)
     (princ (format "yay %d." x))
     (setq x (+ 1 x)))

在elisp中,并没有for语句。

Lists

在lisp中的List是这样的:“'(x y z)”。括号前面那个单引号是很重要的。不需要太在意它的含义,把它当成句法的一部份即可。

  (message "%S" '(a b c))
  (setq mylist '(a b c))  ;定义
  (let ((x 3) (y 4) (z 5))
      (message "%S" (list x y z))
  )

以下是List的一些函数:

Function 目的
(car mylist) 取第一个元素
(nth n mylist) 最第n个元素
(car (last mylist)) 取最后一个元素
(cdr mylist) 从第二个到最后一个
(nthcdr n mylist) 从第n个到最后一个元素
(butlast mylist n) 不包含n到最后一个元素

这里所说的n,都是从0开始的。

下列是一些例子。

  (car (list "a" "b" "c"))
  (nth 2 (list "a" "b" "c"))
  (last (list "a" "b" "c"))
Basic List Functions
Function 目的
(length mylist) List长度
(cons x mylist) 把x加到list前面
(append mylist1 mylist2) 连接两个List

例如:

  (length (list "a" "b" "c"))
Function Purpose
(pop mylist) 删除第一个元素并返回
(nbutlast mylist n) 删除第n个元素,返回删除后的list.
(setcar mylist x) 替换第一个元素,并返回
(setcdr mylist x) 替换除第一个之外的所有元素

遍历运算数组

  (mapcar '1+ '(1 2 3 4))

上例的做所是遍历list中的每一个元素,并对它进行"1+"的操作。

当然,也可以用while循环来完成这件事。

定义函数

基本的函数定义方式是"defun (param) "doc" "。

  (defun myFunction () "testing" (message "Yay!"))

myFunction是函数名,这个函数无参,函数注释"testing",后面是函数体。

可以在doctsing后面加一个"interactive"来使得函数能跟环境进行交互(在emacs中,就呆以可用"Alt + x"来调用)

interactive的一些常用语法:

这就是乔不死同学的ipad?

hardware

私人表示有点失望。

从规格上来讲,这就是一枚大号的iPhone,乔不死同学敢不敢给它加一个打电话的功能?

乔不死同学之前放话说这是他迄今最重要的事,如果只是把iPhone加大的话,这确实让人失望得多。

凭心而论,iPad是一款很好的产品,操作感应该没得说,这点我们不需要亲自上手就可以信任苹果。

只不过,我觉得,大伙儿的失望,从某种意义上来说是对苹果公司的高期望引起的。如果是微软,我们觉得他们把我们想得到的东西实现就了不得了,而苹果不同,我们对苹果的期望是这样的:“告诉我,这玩意比你想得更酷。你想不到机器还可以这样操作吗?”

乔布斯带来了一个大玩具,可惜我们觉得不是太新鲜。

G3入手

G3

G3入手,花了约六分之一平米房子的钱。感觉1.5的固件在重力感应横竖屏切换的时候慢得难受。其它一切都好

新人在团队中应该问什么样的问题

最近团队中来一个外包,一起搞一个要得很急的项目,大概是年底发。

新人最近提的问题,让我总是忍不住想扔给他一篇《提问的智慧》,砸砸他的脑袋。

此君动不动就咬死了原来的代码行不通,这倒没什么,问题是在此基础上,他并不会提出自己的办法,而是拼命地问你怎么办怎么办怎么办,要求你给出一个方案来实行。

我觉得这样的问题不如不问,对谁都没有好处。

那么刚到团队的新人应该怎么问问题呢?

我个人觉得,如果团队有文档,那当然最重要的是先RTFM,没文档的团队免不了要问问题,其实我们喜欢新人问问题多过新人把代码弄得一团糟。但要注意的是,新人应该问的是老人能够几十秒之内回答的问题。

比如说,作为新人,不应该直接问为什么调用这个功能是为什么弹出提示说“没有权限”,而应该跟代码跟到相关的数据表,然后问在这种情况下为什么这个数据库表的值不对。

因为,一个团队,加进一个程序员,本质上来说目的只有一个:加快团队开发的效率,而前少项目交付的时间。

新人来问我问题,如果这个问题我知道,很好,我乐意告诉你。这样节省了走弯路的时间,有利于整个团队的效率。如果我不知道,那么这个问题应该打住,请君自己去看代码,而不是要求我帮忙看代码,或者要求我去思考出一个方案由你来执行。

因为不管是让我去帮忙读代码或让我出方案,都是一个时间浪费的问题。一方面,我得停下手头的工作,另一方面,在我帮忙的这段时间,新人实际上是闲着的。

并且,团队招一个新人,并不是为了写代码,而是为了解决问题。我们招一个人来,应该是看中其独立思考解决问题的能力,而不是为了得到一个编写代码的工具。如果只是一个按给定方案来写代码的工具的话,相比于人类,某些二进制代码组成的工具说不定是更好的选择。

而且,这样的问题并不能培养一个人的编码能力,天天从天上掉下来大鱼的话,人是会懒地,他必然学不会渔的能力。

R.I.P Sun

RIP,SUN

Emacs的orgmode [remember]

remember1

Inbox,在GTD的定义里面是收集材料的工具。最好的Inbox工具是纸和笔。而Remember在Orgmode里面算是较好的Inbox工具。它比每次打开org文件来写好非常非常多。它提供的是在emacs启动的情况下,快速的录入工具。如果你的emacs没启动,那用便箋或纸笔会好得多。原因很简单,emacs什么都好,就是启动太龟了。

配置和基本使用

remember.el在emacs23以上版本是自带的,emacs22及以下版本如果发现没有自带,请自行放狗搜。

    (setq org-default-notes-file "~/.notes")
  

在.emacs中作如上设置,表示你希望将remember产生的note存放在~/.notes中,要我说这可一点也不重要,重要的是下面这一行:

  (define-key global-map [f12] 'org-remember)

快键键。当然,快捷键从来很重要。不过在remember模式中,它显得尤其重要。因为本身remember是随时需要的东西,用完后又应该随时忘掉。所以调用remember应该越不影响当前的思路又好。一个要键入”M-x org-remember”这么多字符才能调出来的remember又有什么用?

我觉得remeber的用法应该是这样的:

现在我想起来晚上海贼王的汉化应该出新的了,接F12调出remember,输入OP,然后“C-c C-c”保存(C-c C-k是取消),remember buffer自动消失,整个emacs又恢复成写这篇blog的界面。

现在的问题是,我一天可能乱七八糟的出现不少想法,每次都按F12来记录是好的,晚上回家一看,~/.noet里面充满了记录,一条一条分门另类地复制了不同的org文件中。我承认这是重要的工作,无可避免。可是有些想法我在记录的时候就知道它应该是todo还是普通的笔记,能不能让它们自动归位呢?

于是我们应该开始介绍:

模版

模版的配置文件如下:

  (setq org-remember-templates
      '(("TODO" ?t "* TODO %?\n %x\n %a" "~/doc/org/home.org" "Tasks")
	("IDEA" ?i "* IDEA %?\n %i\n %a" "~/doc/org/home.org" "Idea")
	))

它的参数是这样的,”TODO”是这个模版的名,”?t”是快捷键,”* TODO %?\n %x\n %a”是整个模版体,然后是该模版要保存的文件,保存后的项目在文件中处于哪个父节点下面(如果没有会自动新建)。

我们以第一个模版为例说一下使用中会发生什么?

当你按下F12(这是我的快捷键)时,会看到buffer被切分成两块,下面出现一个rememeber fuffer。以及一个输入提示,按我们之前的设定,出现两个快捷提示。

remembertemp

这时按下“t”,在remember buffer中,会自动接模版体的格式显示出补好的TODO,第一行是“* TODO”,第二行是%x,%x是你触发remember时kill ring(类似于剪贴板)中的内容。最后一行是%a,一个指向你触发remember的地方的link。

这时如果你按下”C-c C-c”保存,这一条TODO项目将会被送到”~/doc/org/home.org”文件中的”Tasks”条目下面。

模版还有一些好玩的用法,比如说写日记

关于模版参数的更详细说明,可以在这里找到

参考资料

org手册remember

Remembering to Org and Planner

塔希里亚三出来了。

__

淼大以出手要快为题在他的博客上宣布 了塔希里亚三的到来。

吴淼大人是我最喜欢的漫画家,很真实的养猫人。以前就在blog上推荐过他的一个画

推荐一下。

Emacs的orgmode [tags]

tags

标签(tags)在管理东西方面有很多应用。比如blog,flickr,前阵子还在小众软件上看到用标签管理文件的软件。

本身,我们在做org管理文件的时候就已经把不同的东西放在不同文件里了。比如我们建了home.org,work.org两个文件,把在家的工作做在home.org里,把公司的放在work.org里面。

但这种用文件来分类的方法有不便的地方:其一,如果我想到一个新的分类,那就必须新建一个文件;其二,如果我有一个工作同时属于两个文件,怎么办?

于是,tags来了。

tags只做一件事:标记这个项目是什么?它的展示样式是这样的

TODO 跟特留尼西特握手                    :苦差:薪水:逃不掉:

你可以按C-c C-c组合键,这里在mini buffer(就是下面的小框)会出现”Tags:”,等待你输入标签,支持中英文。

就是这么简单。

tags的继承

如前所述,本来我们的想法是用文件来进行不同的分类的,也就是说实际上文件就是一种分类,放在work.org中的项目本来就应该拥有work属性,我不想在每一个项目上添一个:work:的蛇足。

这就得说到tags继承的org特性了。

tagsin

如图,叶项目“新门”本身有一个属性”苦差”,同时它继续了两个属性,一个来自它的父项目apartment,还有一个来自文件属件work。给一个文件设置属性,需要在文件头加上一行。

更简单的方法

如果有一些常用的标签不想每次都敲。可以使用orgmode的标签快捷键功能.比如你可以用k来代表苦差,用s来代表薪水。跟很多org设置一样,可以在两个地方完成这些设置。

一个是.emacs文件。它的语法是这样的。

(setq org-tag-alist '(("苦差" . ?k)
                            ("薪水" . ?s)))

还有一种做法是在文件的头部加声明。类似这样:

#+FILETAGS: :work:

它们的分别在于,前者对于本机所有的org文件都有效。后者刚只对当前文件有效。

这时再给一个项目加标签就会变成这样

tagsshortcut

敲相应的快捷键就可以了。

搜索查看tags

使用tags来给项目打标签当然不是为了打打好看而已。我们是要用的。最常用的用法就是用tags来表示context的概念。

江湖传言把事情分类来做能提高工作效率。即是说,如果你有十个电话要打,十个email要回。最好不要打一个电话回一封email再打一个电话再回一封email,比较好的做法是先打十个电话,然后再连回十个email。还有一个秘笈,是威尔史密斯在<当幸福来敲门>里面教给我们的,如果你不把话筒放下来,能节约很多打电话的时间。

这就需要我们能够把十个电话项目都取出来,在文件里面一个一个找:phone:标签?别傻了。敲一个C-c a吧,然后再敲m,下方的mini buffer里出现了几个大字”MATCH:”,这里输入”phone”,回车。你的列表中所有文件里的带有phone标签或者属性的项目就都列出来了。不想要所有项目,只想看TODO?简单,C-c a后不要加m,加个M吧。

输入关键词的时候还可以使用与或非运算,算符如下:phone&work,同时有两个标签的。phone|work,有两个标签之一的。phone-work有phone标签而没有work标签的。

这里,C-c a表示你要求调出agenda view,后面那个命令则指明你想要调出什么样的view。敲后C-c a之后,不要急着敲m,可以看看org都提供了哪些view,我们熟知的有C-c a a,C-c a t等。

不要每次都输关键字

这样看起来,C-a a a也是一种检索,只不过它们是org-mode内置而已,那我也有一些数据视图是经常要用的,有一些是没事就搜一下的。我也要敲三个键就弄出来,不想每次都敲tags。

嘿嘿,改源码把我自己的搜索置进去。倒是不用着急,读代码总是麻烦的。事实上org-mode已经开放了一个自定义view的接口。唤作org-agenda-custom-commands。可以在.emacs文件中设置自己的。

(setq org-agenda-custom-commands
'(("k" "work haha"
((agenda "")
(tags-todo "work")
(tags-todo "支持")))))

这段代码表示您定了一个可以用C-c a k 调出来的view,它的描述是”work haha”,view中包含三段数据。最上面是agenda,就是调C-c a a出来的界面,然后一个分隔行,列出tags为“work”的项目,再一个分隔行,列出tags为支持的项目。

caak

官方的说法是提供了一个GUI界面,M-x customize-variable RET org-agenda-custom-commands可以打开。界面如下:

GUIconfig

但我个人还是喜欢使用.emacs文件手写配置。不是我装13,而是GUI界面设计得实在太难用了,我到现在也没弄明白它的用法。

[ZT]百度孙云丰说,Google市侩,我感到恶心

今天下午1时20分,百度首席产品设计师孙云丰在自己的博客中撰文关于谷歌退出中国,直指Google退出中国的姿态证明自己是市侩分子,对此感到恶心。
他的博客全文如下:
google宣称要退出中国,所证明的,恰恰不是市面上的那些g粉所宣称的那样,google是个人权斗士,而刚好反了过来,正好证明google是个市侩分子。
google 的首席法律顾问的调调让我感到恶心。因经济利益退出,就直白白的说好了,把自己涂脂抹粉一番,还煞有介事的提到google被中国人攻击,中国异议分子的 Gmail信箱被攻击,把这些事情作为退出中国的铺垫,这种论调是侮辱中国普通老百姓的智商,但还真有可能迎合那帮目空一切,但从未到过中国、对中国没有丝毫了解,却又喜欢对中国说三道四的西方人的假想。

只提一个假设,如果谷歌占据了中国80%的搜索市场份额,google的高管,还会这么高调的宣称要do no evil,从中国退出吗?

整个事情给我的唯一感受,就是恶心。

————–

以上是作为一个曾经的忠实google用户而说的,和百度无关。市面上沾沾自喜于了解一点google的产品技术细节将google奉为道德楷模而自封G粉的兄弟,请勿跟帖瞎喷,你们根本不懂什么叫搜索引擎,什么叫自由人权。

立此存照的原因在于,原帖 http://news.csdn.net/a/20100113/216459.html 被百度的人要求删掉,所以本着对历史负责的态度,保存与此,欢迎转帖。