1 ;;; smart-operator.el --- Insert operators with surrounding spaces smartly
3 ;; Copyright (C) 2004, 2005, 2007-2012 Free Software Foundation, Inc.
5 ;; Author: William Xu <william.xwl@gmail.com>
7 ;; Url: http://xwl.appspot.com/ref/smart-operator.el
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)
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.
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.
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.
31 ;; Type `M-x smart-operator-mode' to toggle this minor mode.
35 ;; Nikolaj Schumacher <n_schumacher@web.de>, for suggesting
36 ;; reimplementing as a minor mode and providing an initial patch for
43 ;;; smart-operator minor mode
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-.)
64 "Keymap used my `smart-operator-mode'.")
66 (defvar smart-operator-double-space-docs t
67 "Enable double spacing of . in document lines - e,g, type '.' => get '. '")
69 (defvar smart-operator-docs t
70 "Enable smart-operator in strings and comments")
73 (define-minor-mode smart-operator-mode
74 "Insert operators with surrounding spaces smartly."
75 nil " _+_" smart-operator-mode-map)
78 (defun smart-operator-mode-on ()
79 "Turn on `smart-operator-mode'. "
80 (smart-operator-mode 1))
83 (defun smart-operator-self-insert-command (arg)
84 "Insert the entered operator plus surrounding spaces."
86 (smart-operator-insert (string last-command-event)))
88 (defvar smart-operator-list
89 '("=" "<" ">" "%" "+" "-" "*" "/" "&" "|" "!" ":" "?" "," "."))
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))
100 (smart-operator-insert-1 op only-where))))
102 (defun smart-operator-insert-1 (op &optional only-where)
103 "Insert operator OP with surrounding spaces.
104 e.g., `=' becomes ` = ', `+=' becomes ` += '.
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."
110 ((before) (insert " " op))
111 ((middle) (insert op))
112 ((after) (insert op " "))
114 (let ((begin? (bolp)))
115 (unless (or (looking-back (regexp-opt smart-operator-list)
116 (line-beginning-position))
121 (indent-according-to-mode))))))
123 (defun smart-operator-c-types ()
124 (concat c-primitive-type-key "?"))
126 (defun smart-operator-document-line? ()
127 (memq (syntax-ppss-context (syntax-ppss)) '(comment string)))
129 (defun smart-operator-lispy-mode? ()
130 (memq major-mode '(emacs-lisp-mode
132 lisp-interaction-mode
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."
144 (smart-operator-insert-1 op 'middle)
145 (smart-operator-insert-1 op 'after)))
147 (smart-operator-insert-1 op 'before))
149 (smart-operator-insert-1 op 'middle))))
154 (defun smart-operator-< ()
155 "See `smart-operator-insert'."
158 ((or (and c-buffer-is-cc-mode
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"
169 (line-beginning-position)))
170 (eq major-mode 'sgml-mode))
174 (smart-operator-insert "<"))))
176 (defun smart-operator-: ()
177 "See `smart-operator-insert'."
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 ":"))
186 (smart-operator-insert ":" 'after))))
188 (defun smart-operator-\, ()
189 "See `smart-operator-insert'."
191 (smart-operator-insert "," 'after))
193 (defun smart-operator-. ()
194 "See `smart-operator-insert'."
196 (cond ((and smart-operator-double-space-docs
197 (smart-operator-document-line?))
198 (smart-operator-insert "." 'after)
200 ((or (looking-back "[0-9]")
201 (or (and c-buffer-is-cc-mode
202 (looking-back "[a-z]"))
204 (memq major-mode '(python-mode ruby-mode))
205 (looking-back "[a-z\)]"))
207 (memq major-mode '(js-mode js2-mode))
208 (looking-back "[a-z\)$]"))))
210 ((memq major-mode '(cperl-mode perl-mode ruby-mode))
211 ;; Check for the .. range operator
212 (if (looking-back ".")
216 (smart-operator-insert "." 'after)
219 (defun smart-operator-& ()
220 "See `smart-operator-insert'."
222 (cond (c-buffer-is-cc-mode
224 ;; | char &a = b; // FIXME
225 ;; | void foo(const int& a);
230 (cond ((looking-back (concat (smart-operator-c-types) " *" ))
231 (smart-operator-insert "&" 'after))
232 ((looking-back "= *")
233 (smart-operator-insert "&" 'before))
235 (smart-operator-insert "&"))))
237 (smart-operator-insert "&"))))
239 (defun smart-operator-* ()
240 "See `smart-operator-insert'."
242 (cond (c-buffer-is-cc-mode
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))
261 (smart-operator-insert "*"))))
263 (smart-operator-insert "*"))))
265 (defun smart-operator-> ()
266 "See `smart-operator-insert'."
268 (cond ((and c-buffer-is-cc-mode (looking-back " - "))
272 (smart-operator-insert ">"))))
274 (defun smart-operator-+ ()
275 "See `smart-operator-insert'."
277 (cond ((and c-buffer-is-cc-mode (looking-back "\\+ *"))
278 (when (looking-back "[a-zA-Z0-9_] +\\+ *")
281 (delete-horizontal-space)))
282 (smart-operator-insert "+" 'middle)
283 (indent-according-to-mode))
285 (smart-operator-insert "+"))))
287 (defun smart-operator-- ()
288 "See `smart-operator-insert'."
290 (cond ((and c-buffer-is-cc-mode (looking-back "\\- *"))
291 (when (looking-back "[a-zA-Z0-9_] +\\- *")
294 (delete-horizontal-space)))
295 (smart-operator-insert "-" 'middle)
296 (indent-according-to-mode))
298 (smart-operator-insert "-"))))
300 (defun smart-operator-? ()
301 "See `smart-operator-insert'."
303 (cond (c-buffer-is-cc-mode
304 (smart-operator-insert "?"))
306 (smart-operator-insert "?" 'after))))
308 (defun smart-operator-% ()
309 "See `smart-operator-insert'."
311 (cond (c-buffer-is-cc-mode
314 ;; | printf("%d %d\n", a % b);
316 (if (and (looking-back "\".*")
317 (not (looking-back "\",.*")))
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?))
326 (smart-operator-insert "%"))))
328 (defun smart-operator-~ ()
329 "See `smart-operator-insert'."
331 ;; First class regex operator =~ langs
332 (cond ((memq major-mode '(ruby-mode perl-mode cperl-mode))
333 (if (looking-back "= ")
341 (defun smart-operator-/ ()
342 "See `smart-operator-insert'."
345 (cond ((and (eq 1 (line-number-at-pos))
347 (move-beginning-of-line nil)
351 (smart-operator-insert "/"))))
353 (provide 'smart-operator)
355 ;;; smart-operator.el ends here