注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

My Unix World

不要迷恋Unix,Unix只是计算世界很小的一部分!

 
 
 

日志

 
 

【Copy】Emacs Fill 详解  

2008-12-28 22:19:01|  分类: L-Emacs |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
from:http://mingtaoli.blogbus.com/logs/1700020.html

Emacs 具有非常智能的文本编辑能力。它可以自动对文字断行,并且在断开的行首都加入一些 prefix(前缀)。

你编辑 C 程序多行注释的时候,你想要编辑器能够自动缩进到合适的位置并且插入一个 "*",就像这样?

 /* seed the random number generator
* first try the random file /dev/random
* if there isn't such a file in the system
* use current time to seed the RNG.
*/

在你写新闻组的文章的时候,你又想让编辑器使你的文档出现这样漂亮的缩进:

1. I seed the random number generator first try the random file
/dev/random if there isn't such a file in the system use current
time to seed the RNG.

2. I need more powerful randomized binary search tree algorithm to
store my wavefront elements.

这些 * 和 行首留出的空白就叫做 prefix。每当使用 fill-paragraph 等操作或者启动了 auto-fill-mode 的时候,文字在断行时,Emacs 可能会在断开的每行前面加入 prefix(前缀)。这大大方便了编辑类似程序注释这一类文字。

设置 fill-column

fill-column就是说到多少列的时候断行。你可以使用

C-u 70 C-x f
这样的命令把 fill-column 设置为 70. 也可以把光标移动到你想要断行的位置,然后按
C-u C-x f

断开的行可能会被自动加上一个前缀(prefix)。设置prefix的方式主要有两种,手动设置和 adaptive prefix 自动设置。

手动设置 prefix

如果把光标放在段落首后面一个位置,使用

C-x . (set-fill-prefix)
就可以把段落头到光标处的那段字符作为 prefix.

Adaptive Filling

但是没有手动设置 prefix 的时候,Emacs 也可以自动识别段落首的一些字符作为 prefix。这就叫做 Adaptive Filling。

提取候选前缀

Emacs 使用变量 adaptive-fill-regexp 来提取前缀。这个变量是一个正则表达式。它会把fill区域开头的能够匹配的部分作为候选的前缀。很多 major mode 会自动帮你设置好这个变量,所以你通常不用操心。

但是某些时候,你可能希望能够自己操纵这一切。我们下面就来看一个具体的例子。假设如果你要达到这种效果,在同一个文本文件里:

  1. 有一些段落每行由3个 * 开头,这可以被作为一小节的标题以及简短的说明。比如:
    *** Section "Files". The location
    of the RGB database. Note, this
    is the name of the file minus
    the extension (like ".txt" or
    ".db").
  2. 有一些段落每行由一个 * 号开头,这叫做“强调”。像这样:
    * There is normally no need to
    * change the default. Multiple
    * FontPath entries are allowed
    * (they are concatenated together)
    * By default, Red Hat 6.0 and later
    * now use a font server independent
    * of the X server to render fonts.
  3. 有一些段落由数字编号 1. 2. 3. 开头,以后的每一行要求缩进到标号之后。所有的数字后面的点号要对齐。
    1. I seed the random number generator first try the random file
    /dev/random if there isn't such a file in the system use current
    time to seed the RNG.

    2. I need more powerful randomized binary search tree algorithm to
    store my wavefront elements.

这些 "*** ", "* ", "1. ", "2. ", "   " 就叫做前缀。为了识别这些前缀,我们把 adaptive-fill-regexp 设置为:

(setq adaptive-fill-regexp "[ \t]+\\|[ \t]*\\([0-9]+\\.\\|\\*+\\)[ \t]*")

这表示前缀可以全是空白字符。或者开头可以有一些空白,接着数字加点或者一个以上的 *,接着一些空白。那么 Emacs 发现开头有这样的字样时,就会把这个字符串作为一个“候选前缀”。

候选前缀的选择

我们已经轻松提取了可能作为前缀的部分,但是一个候选前缀是否被使用,还有很多因素。Emacs 的策略是非常聪明的。我们下面来看看 Emacs 是怎样为用户着想的。

  1. 多行文字的前缀 — 使用第二行的前缀

    首先,我们经常有这样一种想法:如果我两行开头都有符合候选前缀条件的符号,编辑器应该把第二行的那个候选作为前缀。如果我们输入一些文字:

    1. I seed the random number generator 
    first try the random file
    /dev/random if there isn't such a file in the system use current time to seed the RNG.
    我们第一行输入了一个前缀 "1. ",第二行我们故意退了几格,使得 "1. " 这种数字标号突出在段落之外。但是其它的文字我们可以先不用管。那么第一行找到的候选前缀就是 "1. "(1,一个点,一个空格),第二行的候选前缀是"   "(3个空格)。

    写完一段时,我们按 M-q,这段话就自动采用了第二行的前缀(3个空格)作为 prefix。变成这个样子:

    1. I seed the random number generator first try the random file
    /dev/random if there isn't such a file in the system use current
    time to seed the RNG.
    如果我们后来不满意。想把第二行开始的那些行多缩进一些,而且把 fill-column 减小一些。我们可以设置 fill-column,然后在第二行开头再加一些空格,按 M-q。就成了这样:
    1. I seed the random number generator
    first try the random file
    /dev/random if there isn't such
    a file in the system use
    current time to seed the RNG.
    想一下你如果不用 Emacs,如何把上面那段文字变成现在这样!
  2. 单行文字的前缀选择

    那么如果我们只输入了一行字就要求把这行的前缀作为所有断开的行的前缀呢?比如,我们输入一行,开头以 * 开始。我们希望它在fill的时候断开的行都以 * 开头。

    这是通过设置 adaptive-fill-first-line-regexp 这个变量实现的。这个变量是一个正则表达式。如果它能够匹配我们用 adaptive-fill-regexp 提取出来的前缀,那么这个前缀就被采用。

    (setq adaptive-fill-first-line-regexp "^\\* *$")

    注意我们没有使用简单的 "\\* *",而是使用了行首和行尾的匹配符号,因为我们只希望 "* " 这样的符号作为单行重复前缀,出现在每行的开头,而不希望 "***" 成为每行的开头。 adaptive-fill-regexp 提取出来的候选前缀被作为了 adaptive-fill-first-line-regexp 的输入行,它有行首和行尾。

    我们这是在告诉 Emacs,单行文字如果由一个 * 开头,那么断行后每一行都以 * 作为 prefix。

    如果我们输入一行(麻烦你拖动一下:P) :

    * There is normally no need to change the default. Multiple FontPath entries are allowed (they are concatenated together) By default, Red Hat 6.0 and later now use a font server independent of the X server to render fonts.
    按 M-q,它就变成了:
    * There is normally no need to change the default. Multiple FontPath
    * entries are allowed (they are concatenated together) By default, Red
    * Hat 6.0 and later now use a font server independent of the X server
    * to render fonts.

    如果adaptive-fill-first-line-regexp 不能匹配从单行取出的前缀,Emacs 会把这个前缀转成同样长度的空格作为前缀,这正是我们想要的结果。比如我们输入:

    *** Section "Files". The location of the RGB database. Note, this    is the name of the file minus    the extension (like ".txt" or    ".db"). 
    由于 "^\\* *$" 不能匹配提取出来的候选前缀 "*** ",所以 Emacs 把跟它同样长度的4个空格作为了前缀。这样 fill 之后变成了:
    *** Section "Files". The location of the RGB database. Note, this is
    the name of the file minus the extension (like ".txt" or ".db").
    这正是我们希望的样子。
  3. 另外一些条件

    前面两种情况有一个前提条件,就是候选前缀不能是用来决定段落开头的字符,否则不采用。这很好理解:如果采用这个前缀,我们自动断行的时候插入的字符会把一段话分成好几段话,那么文档的逻辑结构就被破坏了,这是不合理的。

    另外,编辑程序的时候,前缀的选择还跟当前的注释符号有关。这个问题超出了本文的范围。

总结

这个规则看起来挺复杂,不过我们可以用算法描述的方式简单的描述出来:
1. 使用 adaptive-fill-regexp 把每行开头部分能够匹配的字符提取出来,作
为“候选前缀”。

2. 如果文字有两行以上,把第二行的候选前缀插入到断开的所有行开头。

3. 如果文字只有一行,看看 adaptive-fill-first-line-regexp 能不能匹配这
行的候选前缀。如果能匹配,使用这个前缀。否则,把这个前缀转成同样长
度的空格,把这些空格作为前缀。


  评论这张
 
阅读(331)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017