diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-05-27 20:00:10 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-05-27 20:00:10 +0000 |
commit | 6bb637f647598002be3c8acfaf3b396966d3e581 (patch) | |
tree | ead65d2b207e8874684c558d4127e93a346ddc7d /elisp | |
parent | e3b13bbba66a92a75ac73d3ab50bca45d69c7c0d (diff) | |
download | mailfromd-6bb637f647598002be3c8acfaf3b396966d3e581.tar.gz mailfromd-6bb637f647598002be3c8acfaf3b396966d3e581.tar.bz2 |
Improve mfl-mode
git-svn-id: file:///svnroot/mailfromd/trunk@1479 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'elisp')
-rw-r--r-- | elisp/mfl-mode.el | 306 |
1 files changed, 285 insertions, 21 deletions
diff --git a/elisp/mfl-mode.el b/elisp/mfl-mode.el index 5c66edc6..aadcab08 100644 --- a/elisp/mfl-mode.el +++ b/elisp/mfl-mode.el | |||
@@ -29,6 +29,12 @@ | |||
29 | ;; Install the file mfl-mode.elc (and, optionally, mfl-mode.el) to | 29 | ;; Install the file mfl-mode.elc (and, optionally, mfl-mode.el) to |
30 | ;; any directory in your Emacs load-path. | 30 | ;; any directory in your Emacs load-path. |
31 | 31 | ||
32 | ;; Customization: | ||
33 | ;; To your .emacs or site-start.el add: | ||
34 | ;; (autoload 'mfl-mode "mfl-mode") | ||
35 | ;; (setq auto-mode-alist (append auto-mode-alist | ||
36 | ;; '(("\\.mf$" . mfl-mode)))) | ||
37 | |||
32 | (eval-when-compile | 38 | (eval-when-compile |
33 | ;; We use functions from these modules | 39 | ;; We use functions from these modules |
34 | (mapcar 'require '(font-lock))) | 40 | (mapcar 'require '(font-lock))) |
@@ -51,12 +57,232 @@ | |||
51 | (modify-syntax-entry ?\/ ". 14" mfl-mode-syntax-table) | 57 | (modify-syntax-entry ?\/ ". 14" mfl-mode-syntax-table) |
52 | (modify-syntax-entry ?\* ". 23" mfl-mode-syntax-table)) | 58 | (modify-syntax-entry ?\* ". 23" mfl-mode-syntax-table)) |
53 | 59 | ||
54 | (defvar mfl-mode-map (make-sparse-keymap) | 60 | (defvar mfl-mode-map nil |
55 | "Keymap used in MFL mode.") | 61 | "Keymap used in MFL mode.") |
56 | 62 | ||
57 | ;(define-key mfl-mode-map [menu-bar] (make-sparse-keymap)) | 63 | (unless mfl-mode-map |
58 | ;(define-key cflow-mode-map [menu-bar MFL] | 64 | (setq mfl-mode-map (make-sparse-keymap)) |
59 | ; (cons "MFL" (make-sparse-keymap "MFL"))) | 65 | (define-key mfl-mode-map "\t" 'mfl-indent-line) |
66 | (define-key mfl-mode-map "\r" 'mfl-newline-and-indent) | ||
67 | (define-key mfl-mode-map "\C-c\C-c" 'mfl-check-syntax) | ||
68 | (define-key mfl-mode-map "\C-\M-a" 'beginning-of-defun) | ||
69 | (define-key mfl-mode-map "\C-\M-e" 'end-of-defun) | ||
70 | |||
71 | (define-key mfl-mode-map [menu-bar] (make-sparse-keymap)) | ||
72 | (define-key mfl-mode-map [menu-bar MFL] | ||
73 | (cons "MFL" mfl-mode-map)) | ||
74 | (define-key mfl-mode-map [mfl-check-syntax] | ||
75 | '("Check syntax" . mfl-check-syntax)) | ||
76 | (define-key mfl-mode-map [beginning-of-defun] | ||
77 | '("Beginning of definition" . beginning-of-defun)) | ||
78 | (define-key mfl-mode-map [end-of-defun] | ||
79 | '("End of definition" . beginning-of-defun))) | ||
80 | |||
81 | |||
82 | |||
83 | (defgroup mfl nil | ||
84 | "MFL programming utilities" | ||
85 | :group 'unix | ||
86 | :group 'languages) | ||
87 | |||
88 | (defgroup mfl nil | ||
89 | "MFL script mode" | ||
90 | :group 'mfl | ||
91 | :prefix "mfl-") | ||
92 | |||
93 | (defgroup mfl-lint nil | ||
94 | "Variables controlling invocation of mailfromd in `lint' mode. | ||
95 | " | ||
96 | :group 'mfl) | ||
97 | |||
98 | (defcustom mfl-mailfromd-command "mailfromd" | ||
99 | "*The default mailfromd command line (without --lint option)" | ||
100 | :type 'string | ||
101 | :group 'mfl-lint) | ||
102 | |||
103 | (defcustom mfl-include-path nil | ||
104 | "*Additional include directories" | ||
105 | :type '(repeat string) | ||
106 | :group 'mfl-lint) | ||
107 | |||
108 | (defgroup mfl-indentation nil | ||
109 | "Variables controlling indentation in MFL scripts. | ||
110 | " | ||
111 | :group 'mfl) | ||
112 | |||
113 | (defcustom mfl-basic-offset 2 | ||
114 | "*The default indentation increment." | ||
115 | :type 'integer | ||
116 | :group 'mfl-indentation) | ||
117 | |||
118 | (defcustom mfl-case-line-offset 0 | ||
119 | "*The default indentation increment for `when' and `case' lines." | ||
120 | :type 'integer | ||
121 | :group 'mfl-indentation) | ||
122 | |||
123 | (defun mfl-find-comment-start () | ||
124 | "Find the beginning of a multiline comment the point is in." | ||
125 | (while (not (or (bobp) (looking-at ".*/\\*"))) | ||
126 | (forward-line -1))) | ||
127 | |||
128 | (defun mfl-next-line-indentation () | ||
129 | "Guess and return the indentation of the next line." | ||
130 | (save-excursion | ||
131 | (beginning-of-line) | ||
132 | (cond | ||
133 | ((not (eolp)) | ||
134 | (skip-chars-forward " \t") | ||
135 | (cond | ||
136 | ((looking-at (regexp-opt '("do" "if" "else" "elif") 'words)) | ||
137 | (+ (current-indentation) mfl-basic-offset)) | ||
138 | ((looking-at ".*/\\*") | ||
139 | (+ (current-indentation) | ||
140 | (- (match-end 0) (match-beginning 0)) 1)) ; FIXME: customization | ||
141 | ((looking-at ".*\\*/\\s *$") | ||
142 | (mfl-find-comment-start) | ||
143 | (forward-line -1) | ||
144 | (current-indentation)) | ||
145 | ((looking-at ".*:[ \t]*$") | ||
146 | (+ (current-indentation) mfl-basic-offset)) | ||
147 | (t | ||
148 | (current-indentation)))) | ||
149 | (t | ||
150 | (forward-line -1) | ||
151 | (mfl-next-line-indentation))))) | ||
152 | |||
153 | (defun mfl-find-line-indentation (regexp) | ||
154 | "Move backwards to the line containing "REGEXP", skipping over | ||
155 | block constructs. Return the indentation of the line, or 0 | ||
156 | if no matching line was found." | ||
157 | (catch 'found | ||
158 | (while (not (bobp)) | ||
159 | (forward-line -1) | ||
160 | (beginning-of-line) | ||
161 | (skip-chars-forward " \t") | ||
162 | (cond | ||
163 | ((looking-at regexp) | ||
164 | (throw 'found (current-indentation))) | ||
165 | ((looking-at "\\<done\\>") | ||
166 | (mfl-find-line-indent "\\<do\\>")) | ||
167 | ((looking-at "\\<fi\\>") | ||
168 | (mfl-find-line-indent "\\<if\\>")))) | ||
169 | 0)) | ||
170 | |||
171 | (defun mfl-find-line-forward (regexp) | ||
172 | "Move forward to the line containing "REGEXP", skipping over | ||
173 | block constructs. Return t if the line was found, nil otherwise." | ||
174 | (catch 'found | ||
175 | (while (not (eobp)) | ||
176 | (forward-line 1) | ||
177 | (beginning-of-line) | ||
178 | (skip-chars-forward " \t") | ||
179 | (cond | ||
180 | ((looking-at regexp) | ||
181 | (throw 'found t)) | ||
182 | ((looking-at "\\<do\\>") | ||
183 | (mfl-find-line-forward "\\<done\\>")) | ||
184 | ((looking-at "\\<if\\>") | ||
185 | (mfl-find-line-forward "\\<fi\\>")))) | ||
186 | nil)) | ||
187 | |||
188 | (defun mfl-compute-line-indentation () | ||
189 | "Compute the indentation of the current line." | ||
190 | (save-excursion | ||
191 | (beginning-of-line) | ||
192 | (skip-chars-forward " \t") | ||
193 | (cond | ||
194 | ((looking-at (regexp-opt '("else" "elif" "fi") 'words)) | ||
195 | (mfl-find-line-indentation (regexp-opt '("if" "elif") 'words))) | ||
196 | ((looking-at "\\<done\\>") | ||
197 | ; FIXME: Continuation lines are not properly handled | ||
198 | (mfl-find-line-indentation ".*\\<do\\>")) | ||
199 | ((looking-at "\\<when\\>") | ||
200 | (+ (mfl-find-line-indentation "\\<on\\>") | ||
201 | mfl-case-line-offset)) | ||
202 | ((looking-at (regexp-opt '("case" "default") 'words)) | ||
203 | (+ (mfl-find-line-indentation "\\<switch\\>") | ||
204 | mfl-case-line-offset)) | ||
205 | (t | ||
206 | (forward-line -1) | ||
207 | (mfl-next-line-indentation))))) | ||
208 | |||
209 | (defun mfl-indent-line () | ||
210 | "Indent the current line." | ||
211 | (interactive "*") | ||
212 | (let ((start-of-line (save-excursion | ||
213 | (beginning-of-line) | ||
214 | (skip-chars-forward " \t") | ||
215 | (point))) | ||
216 | (shift-amt (mfl-compute-line-indentation))) | ||
217 | (if (not (= shift-amt (current-indentation))) | ||
218 | (let ((off (- (point) start-of-line))) | ||
219 | (beginning-of-line) | ||
220 | (delete-region (point) start-of-line) | ||
221 | (indent-to shift-amt) | ||
222 | (if (>= off 0) | ||
223 | (goto-char (+ (point) off)) | ||
224 | (beginning-of-line)))))) | ||
225 | |||
226 | (defun mfl-newline-and-indent () | ||
227 | "Indent the current line, insert a newline, and then indent again." | ||
228 | (interactive "*") | ||
229 | (mfl-indent-line) | ||
230 | (newline-and-indent)) | ||
231 | |||
232 | |||
233 | (defun mfl-check-syntax () | ||
234 | "Checks the syntax of the current MFL buffer." | ||
235 | (interactive "*") | ||
236 | (compile (concat | ||
237 | mfl-mailfromd-command | ||
238 | " --lint" | ||
239 | (if mfl-include-path | ||
240 | (apply 'concat (mapcar (lambda (x) (concat " -I" x)) | ||
241 | mfl-include-path)) | ||
242 | "") | ||
243 | " " | ||
244 | (buffer-file-name)))) | ||
245 | |||
246 | |||
247 | |||
248 | (defun mfl-at-beginning-of-defun-p () | ||
249 | "Return true if the point is at the beginning of a defun" | ||
250 | (or (looking-at "[ \t]*prog [a-z]+") | ||
251 | (looking-at (concat "[ \t]*" | ||
252 | (regexp-opt '("begin" "end") 'words))) | ||
253 | (looking-at "[ \t]*func\\s +[a-zA-Z_][a-zA-Z0-9_]*\\s *("))) | ||
254 | |||
255 | (defun mfl-search-next-defun () | ||