]> code.delx.au - gnu-emacs-elpa/blob - packages/smart-operator/smart-operator.el
Add smart-operator.
[gnu-emacs-elpa] / packages / smart-operator / smart-operator.el
1 ;;; smart-operator.el --- Insert operators with surrounding spaces smartly
2
3 ;; Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 William Xu
4
5 ;; Author: William Xu <william.xwl@gmail.com>
6 ;; Version: 4.0
7 ;; Url: http://xwl.appspot.com/ref/smart-operator.el
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13
14 ;; This program is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with EMMS; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Commentary:
25
26 ;; This extension tries to insert operators with surrounding spaces smartly.
27 ;; e.g., `=' becomes ` = ', `+=' becomes ` += '. This is handy for writing
28 ;; C-style sources.
29
30 ;; To use, put this file to your load-path and the following to your
31 ;; ~/.emacs:
32 ;; (require 'smart-operator)
33 ;;
34 ;; Then `M-x smart-operator-mode' for toggling this minor mode.
35
36 ;;; Acknowledgements
37
38 ;; Nikolaj Schumacher <n_schumacher@web.de>, for suggesting
39 ;; reimplementing as a minor mode and providing an initial patch for
40 ;; that.
41
42 ;;; Code:
43
44 (require 'cc-mode)
45
46 ;;; smart-operator minor mode
47
48 (defvar smart-operator-mode-map
49 (let ((keymap (make-sparse-keymap)))
50 (define-key keymap "=" 'smart-operator-self-insert-command)
51 (define-key keymap "<" 'smart-operator-<)
52 (define-key keymap ">" 'smart-operator->)
53 (define-key keymap "%" 'smart-operator-%)
54 (define-key keymap "+" 'smart-operator-+)
55 (define-key keymap "-" 'smart-operator--)
56 (define-key keymap "*" 'smart-operator-*)
57 (define-key keymap "/" 'smart-operator-/)
58 (define-key keymap "&" 'smart-operator-&)
59 (define-key keymap "|" 'smart-operator-self-insert-command)
60 ;; (define-key keymap "!" 'smart-operator-self-insert-command)
61 (define-key keymap ":" 'smart-operator-:)
62 (define-key keymap "?" 'smart-operator-?)
63 (define-key keymap "," 'smart-operator-\,)
64 (define-key keymap "~" 'smart-operator-~)
65 (define-key keymap "." 'smart-operator-.)
66 keymap)
67 "Keymap used my `smart-operator-mode'.")
68
69 (defvar smart-operator-double-space-docs t
70 "Enable double spacing of . in document lines - e,g, type '.' => get '. '")
71
72 (defvar smart-operator-docs t
73 "Enable smart-operator in strings and comments")
74
75 ;;;###autoload
76 (define-minor-mode smart-operator-mode
77 "Insert operators with surrounding spaces smartly."
78 nil " _+_" smart-operator-mode-map)
79
80 ;;;###autoload
81 (defun smart-operator-mode-on ()
82 "Turn on `smart-operator-mode'. "
83 (smart-operator-mode 1))
84
85 ;;;###autoload
86 (defun smart-operator-self-insert-command (arg)
87 "Insert the entered operator plus surrounding spaces."
88 (interactive "p")
89 (smart-operator-insert (string last-command-event)))
90
91 (defvar smart-operator-list
92 '("=" "<" ">" "%" "+" "-" "*" "/" "&" "|" "!" ":" "?" "," "."))
93
94 (defun smart-operator-insert (op &optional only-where)
95 "See `smart-operator-insert-1'."
96 (delete-horizontal-space)
97 (cond ((and (smart-operator-lispy-mode?)
98 (not (smart-operator-document-line?)))
99 (smart-operator-lispy op))
100 ((not smart-operator-docs)
101 (smart-operator-insert-1 op 'middle))
102 (t
103 (smart-operator-insert-1 op only-where))))
104
105 (defun smart-operator-insert-1 (op &optional only-where)
106 "Insert operator OP with surrounding spaces.
107 e.g., `=' becomes ` = ', `+=' becomes ` += '.
108
109 When `only-where' is 'after, we will insert space at back only;
110 when `only-where' is 'before, we will insert space at front only;
111 when `only-where' is 'middle, we will not insert space."
112 (case only-where
113 ((before) (insert " " op))
114 ((middle) (insert op))
115 ((after) (insert op " "))
116 (t
117 (let ((begin? (bolp)))
118 (unless (or (looking-back (regexp-opt smart-operator-list)
119 (line-beginning-position))
120 begin?)
121 (insert " "))
122 (insert op " ")
123 (when begin?
124 (indent-according-to-mode))))))
125
126 (defun smart-operator-c-types ()
127 (concat c-primitive-type-key "?"))
128
129 (defun smart-operator-document-line? ()
130 (memq (syntax-ppss-context (syntax-ppss)) '(comment string)))
131
132 (defun smart-operator-lispy-mode? ()
133 (memq major-mode '(emacs-lisp-mode
134 lisp-mode
135 lisp-interaction-mode
136 scheme-mode)))
137
138 (defun smart-operator-lispy (op)
139 "We're in a Lisp-ish mode, so let's look for parenthesis.
140 Meanwhile, if not found after ( operators are more likely to be function names,
141 so let's not get too insert-happy."
142 (cond
143 ((save-excursion
144 (backward-char 1)
145 (looking-at "("))
146 (if (equal op ",")
147 (smart-operator-insert-1 op 'middle)
148 (smart-operator-insert-1 op 'after)))
149 ((equal op ",")
150 (smart-operator-insert-1 op 'before))
151 (t
152 (smart-operator-insert-1 op 'middle))))
153
154 \f
155 ;;; Fine Tunings
156
157 (defun smart-operator-< ()
158 "See `smart-operator-insert'."
159 (interactive)
160 (cond
161 ((or (and c-buffer-is-cc-mode
162 (looking-back
163 (concat "\\("
164 (regexp-opt
165 '("#include" "vector" "deque" "list" "map" "stack"
166 "multimap" "set" "hash_map" "iterator" "template"
167 "pair" "auto_ptr" "static_cast"
168 "dynmaic_cast" "const_cast" "reintepret_cast"
169
170 "#import"))
171 "\\)\\ *")
172 (line-beginning-position)))
173 (eq major-mode 'sgml-mode))
174 (insert "<>")
175 (backward-char))
176 (t
177 (smart-operator-insert "<"))))
178
179 (defun smart-operator-: ()
180 "See `smart-operator-insert'."
181 (interactive)
182 (cond (c-buffer-is-cc-mode
183 (if (looking-back "\\?.+")
184 (smart-operator-insert ":")
185 (smart-operator-insert ":" 'middle)))
186 ((memq major-mode '(haskell-mode))
187 (smart-operator-insert ":"))
188 (t
189 (smart-operator-insert ":" 'after))))
190
191 (defun smart-operator-\, ()
192 "See `smart-operator-insert'."
193 (interactive)
194 (smart-operator-insert "," 'after))
195
196 (defun smart-operator-. ()
197 "See `smart-operator-insert'."
198 (interactive)
199 (cond ((and smart-operator-double-space-docs
200 (smart-operator-document-line?))
201 (smart-operator-insert "." 'after)
202 (insert " "))
203 ((or (looking-back "[0-9]")
204 (or (and c-buffer-is-cc-mode
205 (looking-back "[a-z]"))
206 (and
207 (memq major-mode '(python-mode ruby-mode))
208 (looking-back "[a-z\)]"))
209 (and
210 (memq major-mode '(js-mode js2-mode))
211 (looking-back "[a-z\)$]"))))
212 (insert "."))
213 ((memq major-mode '(cperl-mode perl-mode ruby-mode))
214 ;; Check for the .. range operator
215 (if (looking-back ".")
216 (insert ".")
217 (insert " . ")))
218 (t
219 (smart-operator-insert "." 'after)
220 (insert " "))))
221
222 (defun smart-operator-& ()
223 "See `smart-operator-insert'."
224 (interactive)
225 (cond (c-buffer-is-cc-mode
226 ;; ,----[ cases ]
227 ;; | char &a = b; // FIXME
228 ;; | void foo(const int& a);
229 ;; | char *a = &b;
230 ;; | int c = a & b;
231 ;; | a && b;
232 ;; `----
233 (cond ((looking-back (concat (smart-operator-c-types) " *" ))
234 (smart-operator-insert "&" 'after))
235 ((looking-back "= *")
236 (smart-operator-insert "&" 'before))
237 (t
238 (smart-operator-insert "&"))))
239 (t
240 (smart-operator-insert "&"))))
241
242 (defun smart-operator-* ()
243 "See `smart-operator-insert'."
244 (interactive)
245 (cond (c-buffer-is-cc-mode
246 ;; ,----
247 ;; | a * b;
248 ;; | char *a;
249 ;; | char **b;
250 ;; | (*a)->func();
251 ;; | *p++;
252 ;; | *a = *b;
253 ;; `----
254 (cond ((looking-back (concat (smart-operator-c-types) " *" ))
255 (smart-operator-insert "*" 'before))
256 ((looking-back "\\* *")
257 (smart-operator-insert "*" 'middle))
258 ((looking-back "^[ (]*")
259 (smart-operator-insert "*" 'middle)
260 (indent-according-to-mode))
261 ((looking-back "= *")
262 (smart-operator-insert "*" 'before))
263 (t
264 (smart-operator-insert "*"))))
265 (t
266 (smart-operator-insert "*"))))
267
268 (defun smart-operator-> ()
269 "See `smart-operator-insert'."
270 (interactive)
271 (cond ((and c-buffer-is-cc-mode (looking-back " - "))
272 (delete-char -3)
273 (insert "->"))
274 (t
275 (smart-operator-insert ">"))))
276
277 (defun smart-operator-+ ()
278 "See `smart-operator-insert'."
279 (interactive)
280 (cond ((and c-buffer-is-cc-mode (looking-back "\\+ *"))
281 (when (looking-back "[a-zA-Z0-9_] +\\+ *")
282 (save-excursion
283 (backward-char 2)
284 (delete-horizontal-space)))
285 (smart-operator-insert "+" 'middle)
286 (indent-according-to-mode))
287 (t
288 (smart-operator-insert "+"))))
289
290 (defun smart-operator-- ()
291 "See `smart-operator-insert'."
292 (interactive)
293 (cond ((and c-buffer-is-cc-mode (looking-back "\\- *"))
294 (when (looking-back "[a-zA-Z0-9_] +\\- *")
295 (save-excursion
296 (backward-char 2)
297 (delete-horizontal-space)))
298 (smart-operator-insert "-" 'middle)
299 (indent-according-to-mode))
300 (t
301 (smart-operator-insert "-"))))
302
303 (defun smart-operator-? ()
304 "See `smart-operator-insert'."
305 (interactive)
306 (cond (c-buffer-is-cc-mode
307 (smart-operator-insert "?"))
308 (t
309 (smart-operator-insert "?" 'after))))
310
311 (defun smart-operator-% ()
312 "See `smart-operator-insert'."
313 (interactive)
314 (cond (c-buffer-is-cc-mode
315 ;; ,----
316 ;; | a % b;
317 ;; | printf("%d %d\n", a % b);
318 ;; `----
319 (if (and (looking-back "\".*")
320 (not (looking-back "\",.*")))
321 (insert "%")
322 (smart-operator-insert "%")))
323 ;; If this is a comment or string, we most likely
324 ;; want no spaces - probably string formatting
325 ((and (memq major-mode '(python-mode))
326 (smart-operator-document-line?))
327 (insert "%"))
328 (t
329 (smart-operator-insert "%"))))
330
331 (defun smart-operator-~ ()
332 "See `smart-operator-insert'."
333 (interactive)
334 ;; First class regex operator =~ langs
335 (cond ((memq major-mode '(ruby-mode perl-mode cperl-mode))
336 (if (looking-back "= ")
337 (progn
338 (delete-char -2)
339 (insert "=~ "))
340 (insert "~")))
341 (t
342 (insert "~"))))
343
344 (defun smart-operator-/ ()
345 "See `smart-operator-insert'."
346 (interactive)
347 ;; *nix shebangs #!
348 (cond ((and (eq 1 (line-number-at-pos))
349 (save-excursion
350 (move-beginning-of-line nil)
351 (looking-at "#!")))
352 (insert "/"))
353 (t
354 (smart-operator-insert "/"))))
355
356 (provide 'smart-operator)
357
358 ;;; smart-operator.el ends here