天天看點

我也說說Emacs吧(4) - 光标的移動

在說基本編輯指令之前,我們先加一個小tip,說說如何将函數和鍵綁定在一起。

define-key函數需要三個參數,第一個是綁定表的名稱,不同的模式下的描述表是不同的。第二個參數是鍵名,第三個參數是鍵要綁定的函數名。

emacs是一種無模式的編輯器,這也是除了vi之外大部分編輯器的标準做法。每個輸入的字元都會直接輸入到緩沖區裡。編輯要用到的功能函數,就隻好綁定到組合鍵上,主要是ctrl鍵,esc或alt鍵的組合鍵。

比如,最基本的光标移動。如果有上下左右鍵,就用上下左右鍵。沒有的話,emacs會用c-f向右,c-b向左,c-n向下一行,c-p向上一行。c-a移動到行首,c-e移動到行尾。

大量使用ctrl和alt,esc鍵,使得手需要經常移動,小指被過度使用。

而vi的采用正常模式和編輯模式分離來解決這個問題,在正常模式下,不能輸入字元,所有的字元都被當成指令來執行。此時,j是下一行,k是上一行,h是向左,l向右。效率要比c-n,c-p,c-b,c-f要高。0到行首,$到行尾。

但是vi的問題就是,需要經常在正常模式和編輯模式來回切換。

spacemacs使用evil來模拟vi的這種模式,而且有些鍵的綁定與标準emacs有所不同。

移動光标是最基本的指令了,這其中最基本的是光标左右移動,和上下移動。

我們先學習emacs的标準方式:

向右一個字元: c-f (forward-char)

向左一個字元: c-b (backward-char)

這兩個函數都是用c語言實作的,是以沒有lisp源碼,目前我們暫時先關注lisp部分。

但是,在spacemacs的預設情況下,這兩個綁定已經被取消了。因為spacemacs預設是用vi的模式方案,在正常模式下,使用h鍵左移,l鍵右移。

l鍵和右箭頭鍵,綁定到evil-forward-char函數上. 最終,evil-forward-char還是會調用到forward-char來實作移動的功能的:

而左箭頭和h鍵,則是調用的evil-backward-char函數:

就是行間移動,标準emacs的方式是:

向下一行:c-n (next-line)

向上一行:c-p (previous-line)

這兩種方式在spacemacs中,在編輯模式下仍然可以使用。但是正常模式下已經被綁定到其他函數上了,因為有更友善的j和k可以用。

spacemacs支援在普通模式下使用j來移動到下一行,k來移動到上一行。j綁定的是evil-next-line函數,k綁定的是evil-previous-line函數。

上面兩個函數都是對evil-line-move的封裝,evil-next-line的參數是正的,evil-previous-line是負的。

很多時候,我們需要移動到行首或行尾,而不是向左或向右一點一點移動。

我們還是先看emacs的标準實作方式:

到行首:c-a (move-beginning-of-line) spacemacs支援

到行尾:c-e (move-end-of-line) spacemacs不支援

move-beginning-of-line的實作如下:

最終會調用到我們後面要學的goto-char函數,通過goto-char跳到真正的位置上。

spacemacs支援vi的方式,在普通模式下,0移動到行首,$移動到行尾

0 (evil-digit-argument-or-evil-beginning-of-line)

$ (evil-end-of-line)

evil-end-of-line其實還是要調用move-end-of-line函數來實作功能的。

emacs的标準方式:

到緩沖區頭 a-< (beginning-of-buffer)

到緩沖區尾 a-> (end-of-buffer)

spacemacs支援這兩種方式,在正常模式下,還支援"<"鍵綁定beginning-of-buffer,">"綁定end-of-buffer的方式。

我們先看下beginning-of-buffer,雖然也是goto-char的封裝,但是确實不隻是(goto-char 0)這麼簡單:

end-of-buffer的話,除了goto-char之外,還得考慮recenter的問題

emacs提供了兩個函數,可以跳到任意一行,或者是任意一個字元。

a-g g 或 a-g a-g (goto-line n) :跳轉到第n行

a-g c (goto-char n): 跳轉到第n個字元

spacemacs還支援vi的方式來跳轉行

行号 g (evil-goto-line),如果沒有行号,則跳到緩沖區末尾

goto-char不出意料的,是用c實作的。

我們先來看看goto-line:

evil-goto-line寫得簡短一些:

如果一行一行的移動,實在是太慢了,我們可以使用重複指令,給函數傳遞一個參數。

标準emacs的做法是esc + 數字和c-u加數字兩種方式:

esc n + 指令:執行n次指令。如果無法執行完n次,就盡最大的努力。比如向下移動n行,到是沒到n行就到檔案末尾了。那麼就停在檔案末尾。

例:

esc 10 c-n,向下移動10行

(universal-argument)函數,它綁定在c-u鍵上。

universal-argument如果不指定參數的話,預設執行4次。

但是在spacemacs上,universal-argument函數綁定在"空格 u"和"alt-m u"兩個鍵上。

c-u在spacemacs中被移做綁定到evil-scroll-up上,用于翻屏。

有的時候,需要重新繪制一下螢幕,讓我們移動到的那行變為中心:

c-l (recenter-top-bottom)

做錯了,撤銷是很關鍵的操作。

在标準emacs中,使用undo函數來進行這個操作。它綁定到c-_或c-/或c-x u三個鍵上。

在spacemacs中,c-x u被綁定到undo-tree-visualize函數上。 還可以用"空格 a u"來通路它。

而c-_,c-/,在spacemacs中,被綁定在undo-tree-undo上。

功能

函數名

快捷鍵

leader鍵

光标右移

forward-char

evil-forward-char

l

光标左移

backward-char

evil-backward-char

h

下移一行

next-line

正常模式c-n無效

evil-next-line

j

上移一行

previous-line

正常模式c-p無效

evil-previous-line

k

光标移至行首

move-beginning-of-line

c-a

evil-digit-argument-or-evil-beginning-of-line

光标移至行尾

move-end-of-line

evil-end-of-line

$

跳轉到某一行

goto-line

a-g g或a-g a-g

evil-goto-line

g

跳到某一字元

goto-char

a-g c

跳到緩沖區頭

beginning-of-buffer

a-<或>

跳到緩沖區尾

end-of-buffer

a->或>

重複執行

universal-argument

a-m u

空格 u

居中重繪螢幕

recenter-top-bottom

c-l

撤銷上一次的操作

undo

undo-tree-visualize

c-x u

undo-tree-undo

c-_或c-/