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