aboutsummaryrefslogtreecommitdiff
path: root/elisp
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-05-27 20:00:10 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-05-27 20:00:10 +0000
commit6bb637f647598002be3c8acfaf3b396966d3e581 (patch)
treeead65d2b207e8874684c558d4127e93a346ddc7d /elisp
parente3b13bbba66a92a75ac73d3ab50bca45d69c7c0d (diff)
downloadmailfromd-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.el306
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
155block constructs. Return the indentation of the line, or 0
156if 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
173block 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 ()