mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 21067e7cbe6d7a0f65ff5c317a96b5c337b0b3d8
commit | author | age
5cb5f7 1 ;;; smartparens-ruby.el --- Additional configuration for Ruby based modes.  -*- lexical-binding: t; -*-
C 2
3 ;; Copyright (C) 2013-2014 Jean-Louis Giordano
4
5 ;; Author: Jean-Louis Giordano <jean-louis@jawaninja.com>
6 ;; Maintainer: Matus Goljer <matus.goljer@gmail.com>
7 ;; Created: 16 June 2013
8 ;; Keywords: abbrev convenience editing
9 ;; URL: https://github.com/Fuco1/smartparens
10
11 ;; This file is not part of GNU Emacs.
12
13 ;;; License:
14
15 ;; This file is part of Smartparens.
16
17 ;; Smartparens is free software; you can redistribute it and/or modify
18 ;; it under the terms of the GNU General Public License as published by
19 ;; the Free Software Foundation, either version 3 of the License, or
20 ;; (at your option) any later version.
21
22 ;; Smartparens is distributed in the hope that it will be useful,
23 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 ;; GNU General Public License for more details.
26
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with Smartparens.  If not, see <http://www.gnu.org/licenses/>.
29
30 ;;; Commentary:
31
32 ;; This file provides some additional configuration for Ruby based
33 ;; modes.  To use it, simply add:
34 ;;
35 ;; (require 'smartparens-ruby)
36 ;;
37 ;; into your configuration.  You can use this in conjunction with the
38 ;; default config or your own configuration.
39 ;;
40
41 ;; If you have good ideas about what should be added please file an
42 ;; issue on the github tracker.
43
44 ;; For more info, see github readme at
45 ;; https://github.com/Fuco1/smartparens
46
47 ;;; Code:
48
49 (require 'smartparens)
50
51 (declare-function enh-ruby-forward-sexp "ruby")
52 (declare-function ruby-forward-sexp "ruby")
53 (declare-function enh-ruby-backward-sexp "ruby")
54 (declare-function ruby-backward-sexp "ruby")
55
56 (defun sp-ruby-forward-sexp ()
57   "Wrapper for `ruby-forward-sexp' based on `enh-ruby-mode'."
58   (interactive)
59   (if (boundp 'enh-ruby-forward-sexp)
60       (enh-ruby-forward-sexp)
61     (ruby-forward-sexp)))
62
63 (defun sp-ruby-backward-sexp ()
64   "Wrapper for `ruby-backward-sexp' based on `enh-ruby-mode'."
65   (interactive)
66   (if (boundp 'enh-ruby-backward-sexp)
67       (enh-ruby-backward-sexp)
68     (ruby-backward-sexp)))
69
70 (defun sp-ruby-maybe-one-space ()
71   "Turn whitespace around point to just one space."
72   (while (looking-back " " nil) (backward-char))
73   (when (or (looking-at-p " ")
74             (looking-at-p "}")
75             (looking-back "{" nil)
76             (and (looking-at-p "\\sw")
77                  (looking-back ":" nil)))
78     (save-excursion (just-one-space)))
79   (when (and (not (looking-back "^.?" nil))
80              (save-excursion
81                (backward-char 2)
82                (or (looking-at-p ".[^:] [.([,;]")
83                    (looking-at-p ".. ::")
84                    (looking-at-p ".[.@$] ")
85                    (looking-at-p ":: "))))
86     (delete-char 1)))
87
88 (defun sp-ruby-delete-indentation (&optional arg)
89   "Better way of joining ruby lines.
90
91 ARG is how many indentation to delete."
92   (delete-indentation arg)
93   (sp-ruby-maybe-one-space))
94
95 (defun sp-ruby-block-post-handler (id action context)
96   "Handler for ruby block-like insertions.
97 ID, ACTION, CONTEXT."
98   (when (equal action 'insert)
99     (save-excursion
100       (newline)
101       (indent-according-to-mode))
102     (indent-according-to-mode))
103   (sp-ruby-post-handler id action context))
104
105 (defun sp-ruby-def-post-handler (id action context)
106   "Handler for ruby def-like insertions.
107 ID, ACTION, CONTEXT."
108   (when (equal action 'insert)
109     (save-excursion
110       (insert "x")
111       (newline)
112       (indent-according-to-mode))
113     (delete-char 1))
114   (sp-ruby-post-handler id action context))
115
116 (defun sp-ruby-post-handler (_id action _context)
117   "Ruby post handler.
118 ID, ACTION, CONTEXT."
119   (-let (((&plist :arg arg :enc enc) sp-handler-context))
120     (when (equal action 'barf-backward)
121       (sp-ruby-delete-indentation 1)
122       (indent-according-to-mode)
123       (save-excursion
124         (sp-backward-sexp) ; move to begining of current sexp
125         (sp-backward-sexp arg)
126         (sp-ruby-maybe-one-space)))
127
128     (when (equal action 'barf-forward)
129       (sp-get enc
130         (let ((beg-line (line-number-at-pos :beg-in))
131               (end-line (line-number-at-pos :end-in)))
132           (sp-forward-sexp arg)
133           (sp-ruby-maybe-one-space)
134           (when (not (= (line-number-at-pos) beg-line))
135             (sp-ruby-delete-indentation -1))
136           (indent-according-to-mode))))))
137
138 (defun sp-ruby-pre-handler (_id action _context)
139   "Handler for ruby slurp and barf.
140 ID, ACTION, CONTEXT."
141   (let ((enc (plist-get sp-handler-context :enc)))
142     (sp-get enc
143       (let ((beg-line (line-number-at-pos :beg-in))
144             (end-line (line-number-at-pos :end-in)))
145
146         (when (equal action 'slurp-backward)
147           (save-excursion
148             (sp-forward-sexp)
149             (when (looking-at-p ";") (forward-char))
150             (sp-ruby-maybe-one-space)
151             (when (not (= (line-number-at-pos) end-line))
152               (sp-ruby-delete-indentation -1)))
153           (when (looking-at-p "::")
154             (while (and (looking-back "\\sw" nil)
155                         (--when-let (sp-get-symbol t)
156                           (sp-get it (goto-char :beg-prf))))))
157           (while (thing-at-point-looking-at "\\.[[:blank:]\n]*")
158             (sp-backward-sexp))
159           (when (looking-back "[@$:&?!]" nil)
160             (backward-char)
161             (when (looking-back "[@&:]" nil)
162               (backward-char)))
163           (just-one-space)
164           (save-excursion
165             (if (= (line-number-at-pos) end-line)
166                 (insert " ")
167               (newline))))
168
169         (when (equal action 'barf-backward)
170           ;; Barf whole method chains
171           (while (thing-at-point-looking-at "[(.:[][\n[:blank:]]*")
172             (sp-forward-sexp))
173           (if (looking-at-p " *$")
174               (newline)
175             (save-excursion (newline))))
176
177         (when (equal action 'slurp-forward)
178           (save-excursion
179             (sp-backward-sexp)
180             (when (looking-back "\." nil) (backward-char))
181             (sp-ruby-maybe-one-space)
182             (when (not (= (line-number-at-pos) beg-line))
183               (if (thing-at-point-looking-at "\\.[[:blank:]\n]*")
184                   (progn
185                     (forward-symbol -1)
186                     (sp-ruby-delete-indentation -1))
187                 (sp-ruby-delete-indentation))))
188           (while (looking-at-p "::") (sp-forward-symbol))
189           (when (looking-at-p "[?!;]") (forward-char))
190           (if (= (line-number-at-pos) beg-line)
191               (insert " ")
192             (newline)))
193
194         (when (equal action 'barf-forward)
195           (when (looking-back "\\." nil) (backward-char))
196           (when (looking-at-p "::")
197             (while (and (looking-back "\\sw" nil)
198                         (--when-let (sp-get-symbol t)
199                           (sp-get it (goto-char :beg-prf))))))
200           (if (= (line-number-at-pos) end-line)
201               (insert " ")
202             (if (looking-back "^[[:blank:]]*" nil)
203                 (save-excursion (newline))
204               (newline))))))))
205
206 (defun sp-ruby-inline-p (id)
207   "Test if ID is inline."
208   (save-excursion
209     (when (looking-back id nil)
210       (backward-word))
211     (when (not (or (looking-back "^[[:blank:]]*" nil)
212                    (looking-back "= *" nil)))
213       (or (save-excursion
214             (forward-symbol -1)
215             (forward-symbol 1)
216             (looking-at-p (concat " *" id)))
217           (save-excursion
218             ;; This does not seem to make emacs snapshot happy
219             (ignore-errors
220               (sp-ruby-backward-sexp)
221               (sp-ruby-forward-sexp)
222               (looking-at-p (concat "[^[:blank:]]* *" id))))))))
223
224 (defun sp-ruby-method-p (id)
225   "Test if ID is a method."
226   (save-excursion
227     (when (looking-back id nil)
228       (backward-word))
229     (and (looking-at-p id)
230          (or
231           ;; fix for def_foo
232           (looking-at-p (concat id "[_?!:]"))
233           ;; fix for foo_def
234           (looking-back "[_:@$.]" nil)
235           ;; fix for def for; end
236           (looking-back "def \\|class \\|module " nil)
237           ;; Check if multiline method call
238           ;; But beware of comments!
239           (and (looking-back "\\.[[:blank:]\n]*" nil)
240                (not (save-excursion
241                       (search-backward ".")
242                       (sp-point-in-comment))))))))
243
244 (defun sp-ruby-skip-inline-match-p (ms _mb _me)
245   "If non-nil, skip inline match.
246 MS, MB, ME."
247   (or (sp-ruby-method-p ms)
248       (sp-ruby-inline-p ms)))
249
250 (defun sp-ruby-skip-method-p (ms _mb _me)
251   "If non-nil, skip method.
252 MS, MB, ME."
253   (sp-ruby-method-p ms))
254
255 (defun sp-ruby-in-string-or-word-p (id action context)
256   "Test if point is inside string or word.
257 ID, ACTION, CONTEXT."
258   (or (sp-in-string-p id action context)
259       (and (looking-back id nil)
260            (not (looking-back (sp--strict-regexp-quote id) nil)))
261       (sp-ruby-method-p id)))
262
263 (defun sp-ruby-in-string-word-or-inline-p (id action context)
264   "Test if point is inside string, word or inline.
265 ID, ACTION, CONTEXT."
266   (or (sp-ruby-in-string-or-word-p id action context)
267       (and (looking-back id nil)
268            (sp-ruby-inline-p id))))
269
270 (defun sp-ruby-pre-pipe-handler (id action _context)
271   "Ruby pipe handler.
272 ID, ACTION, CONTEXT."
273   (when (equal action 'insert)
274     (save-excursion
275       (just-one-space))
276     (save-excursion
277       (search-backward id)
278       (just-one-space))))
279
280 (defun sp-ruby-should-insert-pipe-close (id action _context)
281   "Test whether to insert the closing pipe for a lambda-binding pipe pair.
282 ID, ACTION, CONTEXT"
283   (if (eq action 'insert)
284       (thing-at-point-looking-at
285        (rx-to-string `(and (or "do" "{") (* space) ,id)))
286     t))
287
288 (defun sp--ruby-skip-match (ms me mb)
289   "Ruby skip match.
290 MS, ME, MB."
291   (when (string= ms "end")
292     (or (sp-in-string-p ms me mb)
293         (sp-ruby-method-p "end"))))
294
295 (add-to-list 'sp-navigate-skip-match
296              '((ruby-mode enh-ruby-mode motion-mode) . sp--ruby-skip-match))
297
298 (dolist (mode '(ruby-mode motion-mode))
299   (add-to-list 'sp-sexp-suffix `(,mode syntax "")))
300
301 (sp-with-modes '(ruby-mode enh-ruby-mode motion-mode)
302   (sp-local-pair "do" "end"
303                  :when '(("SPC" "RET" "<evil-ret>"))
304                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
305                  :actions '(insert navigate)
306                  :pre-handlers '(sp-ruby-pre-handler)
307                  :post-handlers '(sp-ruby-block-post-handler)
308                  :skip-match 'sp-ruby-skip-method-p
309                  :suffix "")
310
311   (sp-local-pair "{" "}"
312                  :pre-handlers '(sp-ruby-pre-handler)
313                  :post-handlers '(sp-ruby-post-handler)
314                  :suffix "")
315
316   (sp-local-pair "begin" "end"
317                  :when '(("SPC" "RET" "<evil-ret>"))
318                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
319                  :actions '(insert navigate)
320                  :pre-handlers '(sp-ruby-pre-handler)
321                  :post-handlers '(sp-ruby-block-post-handler)
322                  :skip-match 'sp-ruby-skip-method-p
323                  :suffix "")
324
325   (sp-local-pair "def" "end"
326                  :when '(("SPC" "RET" "<evil-ret>"))
327                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
328                  :actions '(insert navigate)
329                  :pre-handlers '(sp-ruby-pre-handler)
330                  :post-handlers '(sp-ruby-def-post-handler)
331                  :skip-match 'sp-ruby-skip-method-p
332                  :suffix "")
333
334   (sp-local-pair "class" "end"
335                  :when '(("SPC" "RET" "<evil-ret>"))
336                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
337                  :actions '(insert navigate)
338                  :pre-handlers '(sp-ruby-pre-handler)
339                  :post-handlers '(sp-ruby-def-post-handler)
340                  :skip-match 'sp-ruby-skip-method-p
341                  :suffix "")
342
343   (sp-local-pair "module" "end"
344                  :when '(("SPC" "RET" "<evil-ret>"))
345                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
346                  :actions '(insert navigate)
347                  :pre-handlers '(sp-ruby-pre-handler)
348                  :post-handlers '(sp-ruby-def-post-handler)
349                  :skip-match 'sp-ruby-skip-method-p
350                  :suffix "")
351
352   (sp-local-pair "case" "end"
353                  :when '(("SPC" "RET" "<evil-ret>"))
354                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
355                  :actions '(insert navigate)
356                  :pre-handlers '(sp-ruby-pre-handler)
357                  :post-handlers '(sp-ruby-def-post-handler)
358                  :skip-match 'sp-ruby-skip-method-p
359                  :suffix "")
360
361   (sp-local-pair "for" "end"
362                  :when '(("SPC" "RET" "<evil-ret>"))
363                  :unless '(sp-ruby-in-string-or-word-p sp-in-comment-p)
364                  :actions '(insert navigate)
365                  :pre-handlers '(sp-ruby-pre-handler)
366                  :post-handlers '(sp-ruby-def-post-handler)
367                  :skip-match 'sp-ruby-skip-inline-match-p)
368
369   (sp-local-pair "if" "end"
370                  :when '(("SPC" "RET" "<evil-ret>"))
371                  :unless '(sp-ruby-in-string-word-or-inline-p sp-in-comment-p)
372                  :actions '(insert navigate)
373                  :pre-handlers '(sp-ruby-pre-handler)
374                  :post-handlers '(sp-ruby-def-post-handler)
375                  :skip-match 'sp-ruby-skip-inline-match-p
376                  :suffix "")
377
378   (sp-local-pair "unless" "end"
379                  :when '(("SPC" "RET" "<evil-ret>"))
380                  :unless '(sp-ruby-in-string-word-or-inline-p sp-in-comment-p)
381                  :actions '(insert navigate)
382                  :pre-handlers '(sp-ruby-pre-handler)
383                  :post-handlers '(sp-ruby-def-post-handler)
384                  :skip-match 'sp-ruby-skip-inline-match-p
385                  :suffix "")
386
387   (sp-local-pair "while" "end"
388                  :when '(("SPC" "RET" "<evil-ret>"))
389                  :unless '(sp-ruby-in-string-word-or-inline-p sp-in-comment-p)
390                  :actions '(insert navigate)
391                  :pre-handlers '(sp-ruby-pre-handler)
392                  :post-handlers '(sp-ruby-def-post-handler)
393                  :skip-match 'sp-ruby-skip-inline-match-p
394                  :suffix "")
395
396   (sp-local-pair "until" "end"
397                  :when '(("SPC" "RET" "<evil-ret>"))
398                  :unless '(sp-ruby-in-string-word-or-inline-p sp-in-comment-p)
399                  :actions '(insert navigate)
400                  :pre-handlers '(sp-ruby-pre-handler)
401                  :post-handlers '(sp-ruby-def-post-handler)
402                  :skip-match 'sp-ruby-skip-inline-match-p
403                  :suffix "")
404
405   (sp-local-pair "|" "|"
406                  :when '(sp-ruby-should-insert-pipe-close)
407                  :pre-handlers '(sp-ruby-pre-pipe-handler)
408                  :suffix ""))
409
410 (provide 'smartparens-ruby)
411
412 ;;; smartparens-ruby.el ends here