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