elisp--实现一个emacs mode

前言

接触Emacs编辑器有几年了,一直是编程的不二之选,日常也用Org-Mode来写笔记和博客,对Elisp有点兴趣,但没有怎么学。

一个简单例子

建立一个最简单的hello-mode.el,只提供一个功能,就是按快捷键插入字符串 =Hello,World!=:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(define-derived-mode hello-mode outline-mode "Hello"
"Hello mode is a test mode of emacs")

(defvar hello-mode-map)

(defun say-hello ()
"Just display message 'Hello,World!'"
(interactive)
(message "Hello,World!")
(insert "Hello,World!"))

(define-key hello-mode-map "\C-h" 'say-hello)

(provide 'hello)

在 =~/.emacs= 文件里面配置下,以 =.tks= 结尾文件就当使用 =hello-mode=:

1
2
3
4
5
6
(add-to-list 'load-path "/path/to/hello-mode.el/")

(setq auto-mode-alist
(cons '("\\.tks" . hello-mode) auto-mode-alist))

(require 'hello)

打开一个.tks文件的时候,自动进入 =Hello mode=, 按快捷键 =^C h= 插入字符串 =Hello,World!=.

基础

定义变量

1
(setq my-name "Bastien")

insert

1
(insert "Hello!")

切换缓冲区

1
(switch-to-buffer-other-window "*test*")

progn

1
2
3
(progn
(switch-to-buffer-other-window "*test*")
(hello "you"))

清空缓冲区

1
(erase-buffer)

format

1
(format "Hello %s!\n" "visitor")

get input

1
(read-from-minibuffer "Enter your name: ")

replace

1
2
3
4
5
6
(defun replace-hello-by-bonjour ()
(switch-to-buffer-other-window "*test*")
(goto-char (point-min))
(while (search-forward "Hello" nil t)
(replace-match "Bonjour"))
(other-window 1))

color

1
2
3
4
5
6
7
8
(defun boldify-names ()
(switch-to-buffer-other-window "*test*")
(goto-char (point-min))
(while (re-search-forward "Bonjour \\(.+\\)!" nil t)
(add-text-properties (match-beginning 1)
(match-end 1)
(list 'face 'bold)))
(other-window 1))

依赖其它软件包

1
2
3
4
5
6
(eval-when-compile
(require 'cl)
(require 'gnus-sum))

(require 'calendar)
(require 'format-spec)

定义变量

1
2
3
4
(defvar org-inhibit-highlight-removal nil) ; dynamically scoped param
(defvar org-table-formula-constants-local nil
"Local version of `org-table-formula-constants'.")
(make-variable-buffer-local 'org-table-formula-constants-local)

定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(declare-function org-inlinetask-at-task-p "org-inlinetask" ())

(defun org-babel-do-load-languages (sym value)
"Load the languages defined in `org-babel-load-languages'."
(set-default sym value)
(mapc (lambda (pair)
(let ((active (cdr pair)) (lang (symbol-name (car pair))))
(if active
(progn
(require (intern (concat "ob-" lang))))
(progn
(funcall 'fmakunbound
(intern (concat "org-babel-execute:" lang)))
(funcall 'fmakunbound
(intern (concat "org-babel-expand-body:" lang)))))))
org-babel-load-languages))

defcustom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
(defcustom org-babel-load-languages '((emacs-lisp . t))
"Languages which can be evaluated in Org-mode buffers.
This list can be used to load support for any of the languages
below, note that each language will depend on a different set of
system executables and/or Emacs modes. When a language is
\"loaded\", then code blocks in that language can be evaluated
with `org-babel-execute-src-block' bound by default to C-c
C-c (note the `org-babel-no-eval-on-ctrl-c-ctrl-c' variable can
be set to remove code block evaluation from the C-c C-c
keybinding. By default only Emacs Lisp (which has no
requirements) is loaded."
:group 'org-babel
:set 'org-babel-do-load-languages
:version "24.1"
:type '(alist :tag "Babel Languages"
:key-type
(choice
(const :tag "Awk" awk)
(const :tag "C" C)
(const :tag "R" R)
(const :tag "Asymptote" asymptote)
(const :tag "Calc" calc)
(const :tag "Clojure" clojure)
(const :tag "CSS" css)
(const :tag "Ditaa" ditaa)
(const :tag "Dot" dot)
(const :tag "Emacs Lisp" emacs-lisp)
(const :tag "Fortran" fortran)
(const :tag "Gnuplot" gnuplot)
(const :tag "Haskell" haskell)
(const :tag "Java" java)
(const :tag "Javascript" js)
(const :tag "Latex" latex)
(const :tag "Ledger" ledger)
(const :tag "Lilypond" lilypond)
(const :tag "Maxima" maxima)
(const :tag "Matlab" matlab)
(const :tag "Mscgen" mscgen)
(const :tag "Ocaml" ocaml)
(const :tag "Octave" octave)
(const :tag "Org" org)
(const :tag "Perl" perl)
(const :tag "Pico Lisp" picolisp)
(const :tag "PlantUML" plantuml)
(const :tag "Python" python)
(const :tag "Ruby" ruby)
(const :tag "Sass" sass)
(const :tag "Scheme" scheme)
(const :tag "Screen" screen)
(const :tag "Shell Script" sh)
(const :tag "Shen" shen)
(const :tag "Sql" sql)
(const :tag "Sqlite" sqlite))
:value-type (boolean :tag "Activate" :value t)))

defconst

1
2
(defconst org-version "7.8.11"
"The version number of the file org.el.")

defgroup

1
2
3
4
5
(defgroup org nil
"Outline-based notes management and organizer."
:tag "Org"
:group 'outlines
:group 'calendar)

when

1
2
3
(when (org-bound-and-true-p org-modules)
(let ((a (member 'org-infojs org-modules)))
(and a (setcar a 'org-jsinfo))))

key map

1
(define-key org-mode-map "\C-a" 'org-beginning-of-line)

defadvice

define-derived-mode

1
2
(define-derived-mode org-mode outline-mode "Org"
"Outline-based notes management and organizer, alias")

finish

1
2
3
4
5
6
7
;;;; Finish up

(provide 'org)

(run-hooks 'org-load-hook)

;;; org.el ends here

资料