1 ;;; smart-operator.el --- Insert operators with surrounding spaces smartly
3 ;; Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 William Xu
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 ;; This extension tries to insert operators with surrounding spaces smartly.
27 ;; e.g., `=' becomes ` = ', `+=' becomes ` += '. This is handy for writing
30 ;; To use, put this file to your load-path and the following to your
32 ;; (require 'smart-operator)
34 ;; Then `M-x smart-operator-mode' for toggling this minor mode.
38 ;; Nikolaj Schumacher <n_schumacher@web.de>, for suggesting
39 ;; reimplementing as a minor mode and providing an initial patch for
46 ;;; smart-operator minor mode
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-.)
67 "Keymap used my `smart-operator-mode'.")
69 (defvar smart-operator-double-space-docs t
70 "Enable double spacing of . in document lines - e,g, type '.' => get '. '")
72 (defvar smart-operator-docs t
73 "Enable smart-operator in strings and comments")
76 (define-minor-mode smart-operator-mode
77 "Insert operators with surrounding spaces smartly."
78 nil " _+_" smart-operator-mode-map)
81 (defun smart-operator-mode-on ()
82 "Turn on `smart-operator-mode'. "
83 (smart-operator-mode 1))
86 (defun smart-operator-self-insert-command (arg)
87 "Insert the entered operator plus surrounding spaces."
89 (smart-operator-insert (string last-command-event)))
91 (defvar smart-operator-list
92 '("=" "<" ">" "%" "+" "-" "*" "/" "&" "|" "!" ":" "?" "," "."))
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))
103 (smart-operator-insert-1 op only-where))))
105 (defun smart-operator-insert-1 (op &optional only-where)
106 "Insert operator OP with surrounding spaces.
107 e.g., `=' becomes ` = ', `+=' becomes ` += '.
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."
113 ((before) (insert " " op))
114 ((middle) (insert op))
115 ((after) (insert op " "))
117 (let ((begin? (bolp)))
118 (unless (or (looking-back (regexp-opt smart-operator-list)
119 (line-beginning-position))
124 (indent-according-to-mode))))))
126 (defun smart-operator-c-types ()
127 (concat c-primitive-type-key "?"))
129 (defun smart-operator-document-line? ()
130 (memq (syntax-ppss-context (syntax-ppss)) '(comment string)))
132 (defun smart-operator-lispy-mode? ()
133 (memq major-mode '(emacs-lisp-mode
135 lisp-interaction-mode
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."
147 (smart-operator-insert-1 op 'middle)
148 (smart-operator-insert-1 op 'after)))
150 (smart-operator-insert-1 op 'before))
152 (smart-operator-insert-1 op 'middle))))
157 (defun smart-operator-< ()
158 "See `smart-operator-insert'."
161 ((or (and c-buffer-is-cc-mode
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"
172 (line-beginning-position)))
173 (eq major-mode 'sgml-mode))
177 (smart-operator-insert "<"))))
179 (defun smart-operator-: ()
180 "See `smart-operator-insert'."
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 ":"))
189 (smart-operator-insert ":" 'after))))
191 (defun smart-operator-\, ()
192 "See `smart-operator-insert'."
194 (smart-operator-insert "," 'after))
196 (defun smart-operator-. ()
197 "See `smart-operator-insert'."
199 (cond ((and smart-operator-double-space-docs
200 (smart-operator-document-line?))
201 (smart-operator-insert "." 'after)
203 ((or (looking-back "[0-9]")
204 (or (and c-buffer-is-cc-mode
205 (looking-back "[a-z]"))
207 (memq major-mode '(python-mode ruby-mode))
208 (looking-back "[a-z\)]"))
210 (memq major-mode '(js-mode js2-mode))
211 (looking-back "[a-z\)$]"))))
213 ((memq major-mode '(cperl-mode perl-mode ruby-mode))
214 ;; Check for the .. range operator
215 (if (looking-back ".")
219 (smart-operator-insert "." 'after)
222 (defun smart-operator-& ()
223 "See `smart-operator-insert'."
225 (cond (c-buffer-is-cc-mode
227 ;; | char &a = b; // FIXME
228 ;; | void foo(const int& a);
233 (cond ((looking-back (concat (smart-operator-c-types) " *" ))
234 (smart-operator-insert "&" 'after))
235 ((looking-back "= *")
236 (smart-operator-insert "&" 'before))
238 (smart-operator-insert "&"))))
240 (smart-operator-insert "&"))))
242 (defun smart-operator-* ()
243 "See `smart-operator-insert'."
245 (cond (c-buffer-is-cc-mode
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))
264 (smart-operator-insert "*"))))
266 (smart-operator-insert "*"))))
268 (defun smart-operator-> ()
269 "See `smart-operator-insert'."
271 (cond ((and c-buffer-is-cc-mode (looking-back " - "))
275 (smart-operator-insert ">"))))
277 (defun smart-operator-+ ()
278 "See `smart-operator-insert'."
280 (cond ((and c-buffer-is-cc-mode (looking-back "\\+ *"))
281 (when (looking-back "[a-zA-Z0-9_] +\\+ *")
284 (delete-horizontal-space)))
285 (smart-operator-insert "+" 'middle)
286 (indent-according-to-mode))
288 (smart-operator-insert "+"))))
290 (defun smart-operator-- ()
291 "See `smart-operator-insert'."
293 (cond ((and c-buffer-is-cc-mode (looking-back "\\- *"))
294 (when (looking-back "[a-zA-Z0-9_] +\\- *")
297 (delete-horizontal-space)))
298 (smart-operator-insert "-" 'middle)
299 (indent-according-to-mode))
301 (smart-operator-insert "-"))))
303 (defun smart-operator-? ()
304 "See `smart-operator-insert'."
306 (cond (c-buffer-is-cc-mode
307 (smart-operator-insert "?"))
309 (smart-operator-insert "?" 'after))))
311 (defun smart-operator-% ()
312 "See `smart-operator-insert'."
314 (cond (c-buffer-is-cc-mode
317 ;; | printf("%d %d\n", a % b);
319 (if (and (looking-back "\".*")
320 (not (looking-back "\",.*")))
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?))
329 (smart-operator-insert "%"))))
331 (defun smart-operator-~ ()
332 "See `smart-operator-insert'."
334 ;; First class regex operator =~ langs
335 (cond ((memq major-mode '(ruby-mode perl-mode cperl-mode))
336 (if (looking-back "= ")
344 (defun smart-operator-/ ()
345 "See `smart-operator-insert'."
348 (cond ((and (eq 1 (line-number-at-pos))
350 (move-beginning-of-line nil)
354 (smart-operator-insert "/"))))
356 (provide 'smart-operator)
358 ;;; smart-operator.el ends here