一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Emacs 編輯器

 helloworld 2005-09-29

Emacs 是什么的簡(jiǎn)稱?

Emacs 能做什么

一個(gè)簡(jiǎn)略的介紹,講述一下我已經(jīng)知道的 Emacs 的功能。

Emacs 資料

這里可以找到很多有關(guān) Emacs 的資料。包括入門書籍,網(wǎng)址等。

Emacs Lisp 功能擴(kuò)展集錦

我搜集到的一些很好的 emacs 擴(kuò)展。它們使得 Emacs 成為一個(gè)多 才多藝的編輯器。

Emacs 筆記

這里簡(jiǎn)要記錄一些 Emacs 的使用技巧。便于查詢。

  1. Emacs 鍵綁定技巧
  2. Emacs 的一些簡(jiǎn)單舒服的設(shè)置
  3. 移動(dòng)光標(biāo)命令總結(jié)
  4. Emacs Fill 詳解
  5. Outline Mode 詳解

返回

Emacs 綁定鍵盤的技巧。

萬(wàn)無(wú)一失的綁定方法

很多人綁定一些比較特殊的鍵的時(shí)候,都搞不清楚在

(global-set-key ... ‘my-funtion)

里寫些什么。特別是在 xterm 里的時(shí)候就更不知所措了。其實(shí)有一個(gè)萬(wàn)無(wú)一失的辦法保證你一定寫對(duì)。這個(gè)辦法就是:

  1. M-x global-set-key RET 交互式的綁定你的鍵。
  2. C-x Esc Esc 調(diào)出上一條“復(fù)雜命令”。

好了,你現(xiàn)在就能在 minibuffer 里看到你應(yīng)該寫在 .emacs 的東西了。

如果你還是失敗了……

如果你在第1步的時(shí)候發(fā)現(xiàn) Emacs 根本對(duì)你的按鍵沒有反應(yīng),那么應(yīng)該懷疑是你的窗口管理器攔截了這個(gè)按鍵。比如,我的 FVWM 設(shè)置把 C-f3 設(shè)定成了打開一個(gè) FvwmCommand, 所以 Emacs 接收不到這個(gè)按鍵。如果我要綁定一個(gè)函數(shù)到 C-f3, 我必須讓 FVWM 放過 C-f3。

綁定新的前綴鍵

其實(shí)上面的辦法只能讓你綁定一個(gè)已有的前綴。你有可能想綁定一個(gè) save-buffer 到 "C-c C-w C-b a"。上面的辦法就不靈了。我們必須使用另外的辦法:

(global-set-key (kbd "C-c C-w C-b a") ‘save-buffer)

一點(diǎn)解釋

上面的那個(gè) "C-c C-w C-b a" 是自動(dòng)把 "C-c C-w", "C-c C-w C-b" 都定義成了一個(gè) prefix-command. 你可以這樣看到它們:

  1. C-h C-b 顯示綁定
  2. C-x o 切換到顯示綁定的窗口
  3. C-x C-q 消除這個(gè)窗口的只讀屬性
  4. M-x delete-non-matching-lines RET prefix RET 刪除所有不含 "prefix" 字樣的行。

現(xiàn)在你清楚的看到了 "C-c C-w", "C-c C-w C-b" 都是 prefix command 吧?

創(chuàng)建新的 prefix command

上面這個(gè)辦法只對(duì)開頭的鍵已經(jīng)是 prefix command 的鍵序列起作用,如果你的第一個(gè)鍵不是一個(gè) prefix,那么就會(huì)出錯(cuò)。你可以試試:

(global-set-key (kbd "C-z C-c C-w b") ‘find-file)

出現(xiàn)錯(cuò)誤:(error "Key sequence C-z C-c C-w b uses invalid prefix characters")

所以你必須事先把第一個(gè)鍵設(shè)定為 prefix:

(define-prefix-command ‘ctl-z-map)
(global-set-key (kbd "C-z") ‘ctl-z-map)

然后再用

(global-set-key (kbd "C-z C-c C-w b") ‘find-file)

就行了。"C-z C-c" 和 "C-z C-c C-w" 都會(huì)自動(dòng)被定義為 prefix command.

綁定中文命令

現(xiàn)在我舉一個(gè)例子來(lái)說明 prefix command 是如何工作的。我們可以把中文的 存盤 兩個(gè)字綁定到save-buffer. 這樣你用中文輸入法敲入“存盤”兩個(gè)字時(shí),就可以把當(dāng)前 buffer 保存起來(lái)。

(define-prefix-command ‘存-map)
(global-set-key (kbd "存") ‘存-map)
(define-key 存-map (kbd "盤") ‘save-buffer)

有趣吧?你可以猜到這里面是怎么回事吧?太簡(jiǎn)單了是不是?當(dāng)你輸入“存”的時(shí)候,看到 minibuffer 是這樣:

../images/bind-cun.png

這是因?yàn)槲覀儼选按妗边@個(gè)字綁定到了 存-map 這個(gè) prefix-command. 當(dāng)讀到“存”的時(shí)候,Emacs 就會(huì)等待下一條命令,這個(gè)命令是定義在 存-map 這個(gè) map 里的。它讀到“盤”,就會(huì)執(zhí)行 save-buffer 了。

不過注意,你真的要在文檔里輸入“存盤”兩個(gè)字就得先打 C-q 了。剛才我就打了好多次 C-q,真累啊。還是用一些不常用的詞組比較好,或者加一個(gè) ctrl 什么的前綴,就像這個(gè),"C-z 存盤"。

(define-prefix-command ‘ctl-z-map)
(global-set-key (kbd "C-z") ‘ctl-z-map)
(define-key ctl-z-map (kbd "存盤") ‘save-buffer)

看我們更 bt 一點(diǎn):

(define-prefix-command ‘ctl-z-map)
(global-set-key (kbd "C-z") ‘ctl-z-map)
(define-key ctl-z-map (kbd "給我存盤啦!") ‘save-buffer)

嗨喲!yes sir!!

define-key 會(huì)自動(dòng)建立很多 prefix command. 不過自己顯式用 define-prefix-command 定義前綴命令有一個(gè)好處,就是你可以在你的 prefix 里再方便的定義更多的命令,而不用把整個(gè)前綴都寫一遍。

(define-prefix-command ‘ctl-z-map)
(define-prefix-command ‘存-map)
(define-prefix-command ‘盤-map)

(global-set-key (kbd "C-z") ‘ctl-z-map)
(define-key ctl-z-map (kbd "存") ‘存-map)
(define-key 存-map (kbd "盤") ‘盤-map)

(define-key 盤-map (kbd "!") ‘save-buffer)
(define-key 盤-map (kbd "到") ‘write-file)
(define-key 盤-map (kbd "退出") 
  (lambda ()
    (interactive)
    (save-buffer)
    (kill-emacs)))

這樣,到了“C-z 存盤-” 這個(gè)時(shí)候,我們定義了3個(gè)分支:

  • “C-z 存盤!”,表示保存這個(gè)文件;
  • “C-z 存盤到”,表示保存到另一個(gè)文件;
  • “C-z 存盤退出”,這個(gè)不用解釋了吧。

自定義 prefix command 的另外一個(gè)更大的好處就是:你可以修改最上層對(duì) prefix command 的綁定,從而修改許多鍵的綁定。比如,我們可以把 “存盤” 輕而易舉的改成 “保存”:

(define-key ctl-z-map (kbd "保存") ‘盤-map)

這樣一來(lái), “C-z 保存!” ,“C-z 保存到” , “C-z 保存退出” 就分別有了 “C-z 存盤!” , “C-z 存盤到” 和 “C-z 存盤退出” 的含義了。

Emacs 的簡(jiǎn)單設(shè)置

我覺得這里的設(shè)置對(duì)我來(lái)說比缺省的設(shè)置方便。

  • (setq visible-bell t)
    

關(guān)閉煩人的出錯(cuò)時(shí)的提示聲。

  • (setq inhibit-startup-message t)
    

關(guān)閉起動(dòng)時(shí)的那個(gè)“開機(jī)畫面”。

  • (setq column-number-mode t) 
    

顯示列號(hào)。

  • (setq mouse-yank-at-point t)

不要在鼠標(biāo)點(diǎn)擊的那個(gè)地方插入剪貼板內(nèi)容。我不喜歡那樣,經(jīng)常把我的文檔搞的一團(tuán)糟。我覺得先用光標(biāo)定位,然后鼠標(biāo)中鍵點(diǎn)擊要好的多。不管你的光標(biāo)在文檔的那個(gè)位置,或是在 minibuffer,鼠標(biāo)中鍵一點(diǎn)擊,X selection 的內(nèi)容就被插入到那個(gè)位置。

  • (setq kill-ring-max 200)
    

用一個(gè)很大的 kill ring. 這樣防止我不小心刪掉重要的東西。我很努莽的,你知道 :P

  • (setq default-fill-column 60)
    

把 fill-column 設(shè)為 60. 這樣的文字更好讀。

  • (setq-default indent-tabs-mode nil)
    (setq default-tab-width 8)
    (setq tab-stop-list ())
    (loop for x downfrom 40 to 1 do
          (setq tab-stop-list (cons (* x 4) tab-stop-list)))
    

不用 TAB 字符來(lái)indent, 這會(huì)引起很多奇怪的錯(cuò)誤。編輯 Makefile 的時(shí)候也不用擔(dān)心,因?yàn)?makefile-mode 會(huì)把 TAB 鍵設(shè)置成真正的 TAB 字符,并且加亮顯示的。

  • (setq sentence-end "\\([。???]\\|……\\|[.?!][]\"‘)}]*\\($\\|[ \t]\\)\\)[ \t\n]*")
    (setq sentence-end-double-space nil)
    

設(shè)置 sentence-end 可以識(shí)別中文標(biāo)點(diǎn)。不用在 fill 時(shí)在句號(hào)后插入兩個(gè)空格。

  • (setq enable-recursive-minibuffers t)
    

可以遞歸的使用 minibuffer。我經(jīng)常需要這么做。

  • (setq scroll-margin 3
          scroll-conservatively 10000)
    

防止頁(yè)面滾動(dòng)時(shí)跳動(dòng), scroll-margin 3 可以在靠近屏幕邊沿3行時(shí)就開始滾動(dòng),可以很好的看到上下文。

  • (setq default-major-mode ‘text-mode)
    

把缺省的 major mode 設(shè)置為 text-mode, 而不是幾乎什么功能也沒有的 fundamental-mode.

  • (show-paren-mode t)
    (setq show-paren-style ‘parentheses)
    

括號(hào)匹配時(shí)顯示另外一邊的括號(hào),而不是煩人的跳到另一個(gè)括號(hào)。

  • (mouse-avoidance-mode ‘a(chǎn)nimate)
    

光標(biāo)靠近鼠標(biāo)指針時(shí),讓鼠標(biāo)指針自動(dòng)讓開,別擋住視線。

  • (setq frame-title-format "emacs@%b")
    

在標(biāo)題欄顯示buffer的名字,而不是 emacs@wangyin.com 這樣沒用的提示。

  • (auto-image-file-mode)
    

讓 Emacs 可以直接打開和顯示圖片。

  • (global-font-lock-mode t)
    

進(jìn)行語(yǔ)法加亮。

  • (put ‘set-goal-column ‘disabled nil)
    (put ‘narrow-to-region ‘disabled nil)
    (put ‘upcase-region ‘disabled nil)
    (put ‘downcase-region ‘disabled nil)
    (put ‘LaTeX-hide-environment ‘disabled nil)
    

把這些缺省禁用的功能打開。

  • (setq version-control t)
    (setq kept-new-versions 3)
    (setq delete-old-versions t)
    (setq kept-old-versions 2)
    (setq dired-kept-versions 1)
    

設(shè)置一下備份時(shí)的版本控制,這樣更加安全。

  • (mapcar
     (function (lambda (setting)
    	     (setq auto-mode-alist
    		   (cons setting auto-mode-alist))))
     ‘(("\\.xml$".  sgml-mode)
       ("\\\.bash" . sh-mode)
       ("\\.rdf$".  sgml-mode)
       ("\\.session" . emacs-lisp-mode)
       ("\\.l$" . c-mode)
       ("\\.css$" . css-mode)
       ("\\.cfm$" . html-mode)
       ("gnus" . emacs-lisp-mode)
       ("\\.idl$" . idl-mode)))
    

一個(gè)簡(jiǎn)單的辦法設(shè)置 auto-mode-alist, 免得寫很多 add-to-list.

  • (setq user-full-name "Wang Yin")
    (setq user-mail-address "wang-y01@mails.")
    

設(shè)置有用的個(gè)人信息。這在很多地方有用。

  • (setq dired-recursive-copies ‘top)
    (setq dired-recursive-deletes ‘top)
    

讓 dired 可以遞歸的拷貝和刪除目錄。

移動(dòng)光標(biāo)

  1. 基本操作。
    • C-f, C-b: 以字符為單位移動(dòng)。
    • M-f, M-b: 以單詞為單位移動(dòng)。
    • C-a, C-e: 移動(dòng)到行首,行末。
    • M-m: 移動(dòng)到第一個(gè)非空格字符。(back-to-indentation)
    • M-a, M-e: 移動(dòng)到句子頭,句子尾。
    • M-{, M-}: 移動(dòng)到段落頭,段落尾。
    • C-v, M-v: 翻頁(yè)。
    • M-<, M->: 到文件頭和文件尾。
    • M-r: 加參數(shù),移動(dòng)到窗口里的某一行。不加參數(shù)缺省移動(dòng)到窗口中間。
    • M-x goto-char: 到文件的第 N 字節(jié)。
    • M-x goto-line: 到文件第 N 行。
    • C-x C-n: 設(shè)定 goal-column.
    • C-u C-x C-n: 取消 goal-column.
  2. 以語(yǔ)法結(jié)構(gòu)為單位移動(dòng)。

    文檔一般都有各種結(jié)構(gòu),比如LISP里有S表達(dá)式,C語(yǔ)言里的函數(shù),LaTeX 里的 \begin{...}...\end{...} ... 如果我們能夠已文檔的語(yǔ)法單位來(lái)移動(dòng),就會(huì)使操作非常高效。

    1. defun。defun 在 LISP 里就是最高一級(jí)的 sexp,而在 C 語(yǔ)言里,它的含義就是函數(shù)。
      C-M-a   到 defun 頭
      C-M-e   到 defun 尾
      
      這樣,我們?cè)贑語(yǔ)言程序里可以一個(gè)函數(shù)一個(gè)函數(shù)的跳過。也可以從一個(gè)函數(shù)中間一下跳到函數(shù)開頭或末尾。
    2. 語(yǔ)法單位(sexp)。語(yǔ)法單位在各種 major mode 有不同的定義:
      • lisp-mode: 一個(gè)S表達(dá)式。
      • c-mode: 一個(gè)變量名,一個(gè) (...), 一個(gè) {...}, 一個(gè) [...], ...

        所以在 Emacs 里,尋找匹配的括號(hào)可以在括號(hào)處使用 C-M-f 和 C-M-b.

      • Gnus: 一個(gè)thread。包括所有的 Re:
      其實(shí) defun 可以被看作最高一級(jí)的 sexp。所以范圍小一點(diǎn)的移動(dòng)操作就是在同級(jí) sexp 之間移動(dòng)。
      C-M-f   到下一個(gè)同級(jí)語(yǔ)法結(jié)構(gòu)
      C-M-b   到上一個(gè)同級(jí)語(yǔ)法結(jié)構(gòu)
      

      注意,這種移動(dòng)不能越過語(yǔ)法結(jié)構(gòu)的邊界而進(jìn)入上一級(jí)結(jié)構(gòu)。所以,你如果在

      for (i=0; i<10; i++) { ...}
      
      的 for 循環(huán)的括號(hào)里向右移動(dòng),到達(dá)右邊括號(hào)時(shí),就會(huì)被提示到達(dá)邊界。

      注意,文檔中的注釋在這兩個(gè)操作中會(huì)被跳過,這是非常方便的。

    3. 進(jìn)入和退出子結(jié)構(gòu)。

      在LISP中,S表達(dá)式是嵌套的括號(hào),進(jìn)入子結(jié)構(gòu)就是進(jìn)入到這一級(jí) (...) 里面。而在 C 語(yǔ)言中,進(jìn)入子結(jié)構(gòu)就是進(jìn)入 (...), {...}, [...] 的里面。 C-M-d: 進(jìn)入到下一級(jí)結(jié)構(gòu)里。C-M-u: 進(jìn)入到上一級(jí)結(jié)構(gòu)里。

      C-M-a, C-M-e, C-M-f, C-M-b, C-M-d, C-M-u 這幾個(gè)命令組合起來(lái)可以迅速的在程序里移動(dòng)。往往手可以按住 C-M 不放,所以還是很順手的。

    4. 段落:
      M-} (forward-paragraph)
      M-{ (backward-paragraph)
      
      段落在不同的mode有不同的含義,它的含義是由 paragraph-start 變量決定的。這個(gè)正則表達(dá)式可以告訴 Emacs 那些符號(hào)出現(xiàn)被認(rèn)為是一個(gè)段落開始了。
    5. 句子:
      M-e (backward-sentence)
      M-a (forward-sentence)
      

      句子在不同的模式有不同的含義。比如在 c-mode, “句子”成為了“語(yǔ)句”的代名詞,所以 M-a 和 M-e 可以以語(yǔ)句為單位移動(dòng)。

      句子的含義是由 sentence-end 變量決定的。這個(gè)正則表達(dá)式可以告訴 Emacs 那些符號(hào)出現(xiàn)被認(rèn)為是一個(gè)句子結(jié)束了……比如我的 sentence-end 是這樣設(shè)置的:

      (setq sentence-end "\\([。!?]\\|……\\|[.?!][]\"‘)}]*\\($\\|[ \t]\\)\\)[ \t\n]*")
      
      這樣中文的句子就可以被正確識(shí)別了。
  3. 一些特殊模式專有的移動(dòng)方式。
    • HTML 模式。
      1. 跳過同一級(jí) tag。
        C-c C-f  向前跳過同一級(jí) tag (sgml-skip-tag-forward)
        C-c C-b  向后跳過同一級(jí) tag (sgml-skip-tag-backward)
        
    • LaTeX 模式。
        C-c C-u   到最近的上一級(jí) \begin{...} 處。
        
        C-c }     到最近的上一級(jí)匹配 {...} 處。
        


返回

Emacs Fill 詳解

Emacs 具有非常智能的文本編輯能力。它可以自動(dòng)對(duì)文字?jǐn)嘈?,并且在斷開的行首都加入一些 prefix(前綴)。

你編輯 C 程序多行注釋的時(shí)候,你想要編輯器能夠自動(dòng)縮進(jìn)到合適的位置并且插入一個(gè) "*",就像這樣?

	/* 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.
	 */

在你寫新聞組的文章的時(shí)候,你又想讓編輯器使你的文檔出現(xiàn)這樣漂亮的縮進(jìn):

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。每當(dāng)使用 fill-paragraph 等操作或者啟動(dòng)了 auto-fill-mode 的時(shí)候,文字在斷行時(shí),Emacs 可能會(huì)在斷開的每行前面加入 prefix(前綴)。這大大方便了編輯類似程序注釋這一類文字。

設(shè)置 fill-column

fill-column就是說到多少列的時(shí)候斷行。你可以使用

C-u 70 C-x f

這樣的命令把 fill-column 設(shè)置為 70. 也可以把光標(biāo)移動(dòng)到你想要斷行的位置,然后按

C-u C-x f

斷開的行可能會(huì)被自動(dòng)加上一個(gè)前綴(prefix)。設(shè)置prefix的方式主要有兩種,手動(dòng)設(shè)置和 adaptive prefix 自動(dòng)設(shè)置。

手動(dòng)設(shè)置 prefix

如果把光標(biāo)放在段落首后面一個(gè)位置,使用

C-x . (set-fill-prefix)

就可以把段落頭到光標(biāo)處的那段字符作為 prefix.

Adaptive Filling

但是沒有手動(dòng)設(shè)置 prefix 的時(shí)候,Emacs 也可以自動(dòng)識(shí)別段落首的一些字符作為 prefix。這就叫做 Adaptive Filling。

提取候選前綴

Emacs 使用變量 adaptive-fill-regexp 來(lái)提取前綴。這個(gè)變量是一個(gè)正則表達(dá)式。它會(huì)把fill區(qū)域開頭的能夠匹配的部分作為候選的前綴。很多 major mode 會(huì)自動(dòng)幫你設(shè)置好這個(gè)變量,所以你通常不用操心。

但是某些時(shí)候,你可能希望能夠自己操縱這一切。我們下面就來(lái)看一個(gè)具體的例子。假設(shè)如果你要達(dá)到這種效果,在同一個(gè)文本文件里:

  1. 有一些段落每行由3個(gè) * 開頭,這可以被作為一小節(jié)的標(biāo)題以及簡(jiǎn)短的說明。比如:
    *** Section "Files". The location
        of the RGB database. Note, this
        is the name of the file minus
        the extension (like ".txt" or
        ".db"). 
    
  2. 有一些段落每行由一個(gè) * 號(hào)開頭,這叫做“強(qiáng)調(diào)”。像這樣:
    * 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. 有一些段落由數(shù)字編號(hào) 1. 2. 3. 開頭,以后的每一行要求縮進(jìn)到標(biāo)號(hào)之后。所有的數(shù)字后面的點(diǎn)號(hào)要對(duì)齊。
    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. ", "   " 就叫做前綴。為了識(shí)別這些前綴,我們把 adaptive-fill-regexp 設(shè)置為:

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

這表示前綴可以全是空白字符?;蛘唛_頭可以有一些空白,接著數(shù)字加點(diǎn)或者一個(gè)以上的 *,接著一些空白。那么 Emacs 發(fā)現(xiàn)開頭有這樣的字樣時(shí),就會(huì)把這個(gè)字符串作為一個(gè)“候選前綴”。

候選前綴的選擇

我們已經(jīng)輕松提取了可能作為前綴的部分,但是一個(gè)候選前綴是否被使用,還有很多因素。Emacs 的策略是非常聰明的。我們下面來(lái)看看 Emacs 是怎樣為用戶著想的。

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

    首先,我們經(jīng)常有這樣一種想法:如果我兩行開頭都有符合候選前綴條件的符號(hào),編輯器應(yīng)該把第二行的那個(gè)候選作為前綴。如果我們輸入一些文字:

    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.
    
    我們第一行輸入了一個(gè)前綴 "1. ",第二行我們故意退了幾格,使得 "1. " 這種數(shù)字標(biāo)號(hào)突出在段落之外。但是其它的文字我們可以先不用管。那么第一行找到的候選前綴就是 "1. "(1,一個(gè)點(diǎn),一個(gè)空格),第二行的候選前綴是"   "(3個(gè)空格)。

    寫完一段時(shí),我們按 M-q,這段話就自動(dòng)采用了第二行的前綴(3個(gè)空格)作為 prefix。變成這個(gè)樣子:

    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.
    
    如果我們后來(lái)不滿意。想把第二行開始的那些行多縮進(jìn)一些,而且把 fill-column 減小一些。我們可以設(shè)置 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,如何把上面那段文字變成現(xiàn)在這樣!
  2. 單行文字的前綴選擇

    那么如果我們只輸入了一行字就要求把這行的前綴作為所有斷開的行的前綴呢?比如,我們輸入一行,開頭以 * 開始。我們希望它在fill的時(shí)候斷開的行都以 * 開頭。

    這是通過設(shè)置 adaptive-fill-first-line-regexp 這個(gè)變量實(shí)現(xiàn)的。這個(gè)變量是一個(gè)正則表達(dá)式。如果它能夠匹配我們用 adaptive-fill-regexp 提取出來(lái)的前綴,那么這個(gè)前綴就被采用。

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

    注意我們沒有使用簡(jiǎn)單的 "\\* *",而是使用了行首和行尾的匹配符號(hào),因?yàn)槲覀冎幌M?"* " 這樣的符號(hào)作為單行重復(fù)前綴,出現(xiàn)在每行的開頭,而不希望 "***" 成為每行的開頭。 adaptive-fill-regexp 提取出來(lái)的候選前綴被作為了 adaptive-fill-first-line-regexp 的輸入行,它有行首和行尾。

    我們這是在告訴 Emacs,單行文字如果由一個(gè) * 開頭,那么斷行后每一行都以 * 作為 prefix。

    如果我們輸入一行(麻煩你拖動(dòng)一下: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 會(huì)把這個(gè)前綴轉(zhuǎn)成同樣長(zhǎng)度的空格作為前綴,這正是我們想要的結(jié)果。比如我們輸入:

    *** Section "Files". The location of the RGB database. Note, this    is the name of the file minus    the extension (like ".txt" or    ".db"). 
    
    由于 "^\\* *$" 不能匹配提取出來(lái)的候選前綴 "*** ",所以 Emacs 把跟它同樣長(zhǎng)度的4個(gè)空格作為了前綴。這樣 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. 另外一些條件

    前面兩種情況有一個(gè)前提條件,就是候選前綴不能是用來(lái)決定段落開頭的字符,否則不采用。這很好理解:如果采用這個(gè)前綴,我們自動(dòng)斷行的時(shí)候插入的字符會(huì)把一段話分成好幾段話,那么文檔的邏輯結(jié)構(gòu)就被破壞了,這是不合理的。

    另外,編輯程序的時(shí)候,前綴的選擇還跟當(dāng)前的注釋符號(hào)有關(guān)。這個(gè)問題超出了本文的范圍。

總結(jié)

這個(gè)規(guī)則看起來(lái)挺復(fù)雜,不過我們可以用算法描述的方式簡(jiǎn)單的描述出來(lái):

1. 使用 adaptive-fill-regexp 把每行開頭部分能夠匹配的字符提取出來(lái),作
   為“候選前綴”。

2. 如果文字有兩行以上,把第二行的候選前綴插入到斷開的所有行開頭。

3. 如果文字只有一行,看看 adaptive-fill-first-line-regexp 能不能匹配這
   行的候選前綴。如果能匹配,使用這個(gè)前綴。否則,把這個(gè)前綴轉(zhuǎn)成同樣長(zhǎng)
   度的空格,把這些空格作為前綴。

返回

Emacs Outline Mode 示例

Outline mode 是 Emacs 的一個(gè)強(qiáng)有力的模式。它可以使你輕松的操縱結(jié)構(gòu)化的文檔。它可以讓你只顯示文檔的某一個(gè)分支,只顯示主干,只顯示一個(gè)子樹。

下面就是一個(gè) LaTeX 文檔的各種 outline 操作的結(jié)果示范。由于 outline-minor-mode 的鍵綁定前綴 C-c @ 過于復(fù)雜,大部分經(jīng)常使用 outline 的人想把它設(shè)置為另一個(gè)鍵,所以以后我在敘述時(shí)直接稱呼函數(shù)名字和簡(jiǎn)化前綴的鍵綁定。具體的鍵綁定請(qǐng)用 C-h w 查詢。

更改前綴可以在啟動(dòng) outline-minor-mode 之前,用改變 outline-minor-mode-prefix 變量的辦法一次完成。比如:

(setq outline-minor-mode-prefix [(control o)])

就可以把前綴改成 C-o. 以后我們實(shí)例中的鍵綁定都使用 C-o.

本文的 Outline

首先,給大家一個(gè) outline 的總體印象。我們使用 outline 來(lái)看看本文的主要內(nèi)容 :)

原文檔

這是一個(gè)非常簡(jiǎn)單的 LaTeX 文檔: outline.tex

我們來(lái)把文檔的各部分術(shù)語(yǔ)解釋一下。

  1. heading: 是指文檔里的標(biāo)題,比如 Chapter 1, Chapter 2, Section 1, ... 的那些行。
  2. branch: 是指一顆子樹下所有 heading 的集合。想一想“樹干”。
  3. entry: 是指文檔里不是 heading 的那些內(nèi)容。比如,"Entry for topmost level", "Entry for Chapter 1", "Entry for Chapter 2", ... 這些才是文檔的主要內(nèi)容。
  4. leaves: 是指一棵子樹里的所有 entry。
  5. body: 是指文檔里所有 entry 的集合。注意這個(gè)概念跟 leaves 的區(qū)別是范圍上的區(qū)別。

啟動(dòng) Outline

M-x outline-minor-mode 就可以啟動(dòng) Outline。還有一個(gè) outline-mode 是一個(gè) major mode,一般都不用它。

全局隱藏操作

光標(biāo)在任何位置,只要執(zhí)行這些操作,文檔的顯示就會(huì)變化成需要的樣子。

hide-sublevels(C-o C-q)

這個(gè)操作如果不帶參數(shù),隱藏所有文檔子結(jié)構(gòu),只剩最上層。

M-4 hide-sublevels(M-4 C-o C-q)

這是參數(shù)為4的操作,顯示至文檔第4層子結(jié)構(gòu)。

hide-body(C-o C-t)

文檔的所有 Entry 都被隱藏。只顯示主干。

對(duì)一個(gè)子樹(Chapter 1)的隱藏操作

hide-subtree(C-o C-d)

所有文檔部分展開時(shí),光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 hide-subtree。整個(gè) Chapter 1 的子樹被折疊起來(lái)。

hide-other(C-o C-o)

所有文檔部分展開時(shí),光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 hide-other。除了 Chapter 1,其它子樹全部被折疊起來(lái)。這個(gè)操作正好與 hide-subtree 互補(bǔ)。

hide-leaves(C-o C-l)

所有文檔部分展開時(shí),光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 hide-leaves。所有 Chapter 1 子樹下的所有級(jí)別的 entry 被隱藏。也就是說,Chapter 1 下,只顯示 branch.

hide-entry(C-o C-c)

所有文檔部分展開時(shí),光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 hide-entry。Chapter 1 的 Entry 被隱藏,但是所有子樹都不動(dòng)。

全局顯示操作

show-all(C-o C-a)

顯示所有文檔。結(jié)果就是原文檔

對(duì)一個(gè)子樹的顯示操作

為了演示,我們從全部隱藏的情況開始:

show-children(C-o C-i)

show-children 只顯示直接的下一代子樹,而不顯示間接的下一代。這里, \begin{document} 的直接的下一代就是 \chapter{...}。

show-entry(C-o C-e)

把光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 show-entry。Chapter 1 的 Entry 被顯示,但是所有子結(jié)構(gòu)還是保持隱藏。

show-branches(C-o C-k)

把光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 show-branches。Chapter 1 這棵子樹之下的各級(jí)“樹干”被顯示,但是各級(jí) entry 還是保持隱藏。Chapter 1 自己的 entry,由于我們上一步已經(jīng)顯示,所以保持不變。

show-subtree(C-o C-s)

把光標(biāo)移動(dòng)到 Chapter 1,執(zhí)行 show-subtree。Chapter 1 及其所有子結(jié)構(gòu)全部被擴(kuò)展。

Outline mode 下的移動(dòng)操作

在 outline 模式下,有幾種特殊方便的移動(dòng)方式。

  1. C-o C-n (outline-next-visible-heading) 移動(dòng)到下一個(gè)可見標(biāo)題。
  2. C-o C-p (outline-previous-visible-heading) 移動(dòng)到上一個(gè)可見標(biāo)題。
  3. C-o C-f (outline-forward-same-level) 移動(dòng)到下一個(gè)同級(jí)可見標(biāo)題。
  4. C-o C-b (outline-backward-same-level) 移動(dòng)到上一個(gè)同級(jí)可見標(biāo)題。
  5. C-o C-u (outline-up-heading) 到上一級(jí)標(biāo)題。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美有码黄片免费在线视频| 国内真实露脸偷拍视频| 日本99精品在线观看| 欧美日韩无卡一区二区| 亚洲国产综合久久天堂| 欧美日韩最近中国黄片| 日韩成人中文字幕在线一区| 欧美日韩视频中文字幕| 国产欧美日产久久婷婷| 日韩三级黄色大片免费观看 | 九九蜜桃视频香蕉视频| 暴力性生活在线免费视频| 一区二区三区精品人妻| 色播五月激情五月婷婷| 久久国产亚洲精品赲碰热| 微拍一区二区三区福利| 午夜精品一区二区三区国产| 日韩一本不卡在线观看| 欧美日韩国产综合特黄| 少妇被粗大进猛进出处故事| 国产精品日韩欧美一区二区| 国产又大又黄又粗的黄色| 亚洲一区二区久久观看| 日韩中文字幕视频在线高清版 | 日本一区不卡在线观看| 国产香蕉国产精品偷在线观看 | 中文字幕一区二区免费| 亚洲免费视频中文字幕在线观看 | 在线免费国产一区二区三区 | 日本丰满大奶熟女一区二区| 俄罗斯胖女人性生活视频| 草草夜色精品国产噜噜竹菊| 激情综合五月开心久久| 国产精品不卡免费视频| 亚洲另类欧美综合日韩精品 | 69老司机精品视频在线观看| 午夜福利直播在线视频| 九九热精彩视频在线播放| 中文字幕免费观看亚洲视频| 精品精品国产欧美在线| 国产精品丝袜一二三区|