前一篇《紅藥丸,還是藍藥丸》講述了一個 Emacs Lisp 程序如何在自己的人生的十字路口上選擇的故事。
現在,我們已經有了原子,有了發動機,也有了選擇前進方向的能力,因此不用等明天,今天就可以餵馬,劈柴,周遊世界。
在 Emacs 裏,世界就是緩衝區。(goto-char (point-min))
可以讓準備周遊世界的光標跳到世界的起點,同理 (goto-char (point-max))
可以讓光標跳到世界的盡頭。於是,光標就以光的速度周遊了一遍世界。
當然不是這樣。光標實際上是通過異次元空間從世界的起點開始僅用一步就跳到了世界的盡頭。倘若讓光標從起點開始一步一步走到終點,可以像下面這樣做:
(defun 周遊世界 (起點 終點)
(if (= 起點 終點)
(message "到終點了!")
(progn
(goto-char 起點)
(sit-for 0.5)
(周遊世界 (+ 起點 1) 終點))))
(周遊世界 1 (point-max))
之前,我們一直是在 init.el 中試驗一些 Emacs Lisp 代碼,主要是因爲 Emacs 重新啓動時,會自動加載 init.el,這樣 init.el 中的函數定義就會生效。現在我們換一種方式,這種方式更方便隨時測試一些代碼片段。
隨便找個目錄,用 Emacs 隨便創建一份空文件,只是讓這個文件的擴展名爲 .el
,例如 foo.el
。倘若你已經忘記了如何用 Emacs 創建一份新文件,那麼我在此會友善地幫助你回憶一下。要麼是啓動 Emacs,然後向它發送指令,例如 C-x C-f ~/foo.el<RET>
,要麼是在命令行窗口中,以指定文件名的方式啓動 Emacs,例如:
$ emacs foo.el
假設你已經用 Emacs 創建了 foo.el 文件。現在,將上述代碼複製到該文件在 Emacs 中對應的緩衝區,然後將光標移動到 周遊世界
的函數定義的末尾,執行 C-x C-e
,再將光標移動到 周遊世界
函數的求值表達式的末尾,執行 C-x C-e
,
倘若上述操作執行無誤,那麼接下來,你會看到光標會跳到緩衝區的起始位置,然後每隔 0.5 秒向前移動 1 個字符的距離。當光標走到緩衝區末尾的時候,周遊世界
函數的求值過程結束,求值結果是:在微緩衝區中顯現字符串原子 到終點了!
。
上述代碼中,只有 message
與 sit-for
這兩個函數第一次遇到。message
可以將字符串顯示於微緩衝區。sit-for
可以讓 Emacs Lisp 解釋器在求值過程中停下來「休息」一段時間。
注:實際上,message
函數是將字符串顯示於 Emacs 的*Message*
緩衝區。使用C-x b *Message* <RET>
可以切換到*Messages*
緩衝區,查看message
的輸出。
當我們將 goto-char
、sit-for
以及 message
這些函數形成的表達式與 周遊世界
這個類似於發動機的函數「連接」起來,就形成了一種自駕車周遊世界的運動,是不是很奇妙?
很快,我們就可以發現,世界是可以周遊的,但也是可以毀滅的。看下面的代碼:
(defun 毀滅世界 (起點 終點)
(if (= 起點 終點)
(message "吃掉了所有字符!")
(progn
(delete-char 1)
(sit-for 0.5)
(毀滅世界 (+ 起點 1) 終點))))
(progn
(goto-char (point-min))
(毀滅世界 1 (point-max)))
在重新按照上述的方法重新求值,結果可以看到,當光標移動到緩衝器的起點之後,它會像黑洞一樣,每隔 0.5 秒吞噬掉一個字符。
delete-char
的作用是從緩衝區中刪除光標所在位置之後的 N 個字符。當 N 值爲負數時,刪除的則是光標之前的 |N| 個字符。
這裏需要對 Emacs 的光標作更多一些的介紹。光標,其形狀默認是一個矩形的小黑塊,它在自身停留的位置上恰好能完整覆蓋一個字符。這個小黑塊會不停地閃動着。當我們談及光標的位置時,實際上指的是這個小黑塊的左側邊界線的位置。這個位置,Emacs Lisp 語言將其稱爲點。緩衝區的起始位置,就是座標爲 1 的點。不過,有的時候,緩衝區的範圍會被人爲地縮小,此時它的起始位置就不再是 1,而是 (point-min)
。在 Emacs Lisp 程序中,使用 (point-min)
與 (point-max)
表示緩衝區的起點與終點是最穩妥的辦法。
馬克·吐溫說,哥倫布發現新大陸沒什麼了不起,他要是沒發現,那纔是真的見鬼了。上述的第一個小試驗可以證明馬克·吐溫的說法是正確的。第二個小試驗則可以證明……人類能夠造出原子彈,也沒什麼了不起,要是造不出來,那纔是真的見鬼了。
下一篇:無名