branch: elpa/smartparens commit 0fe32ac56da6d8e725850e9c438904db24be0bb9 Author: Matus Goljer <matus.gol...@gmail.com> Commit: Matus Goljer <matus.gol...@gmail.com>
feat(lisp): insert space before opening paren after slurping This prevents some weirdly formatted code like (foo)(bar) becomnig (foo(bar)) instead of (foo (bar)) Fixes #781 --- smartparens-config.el | 12 ++++++++++ smartparens.el | 12 +++++++--- test/smartparens-elisp-test.el | 51 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/smartparens-config.el b/smartparens-config.el index c639e5e998..8709c52085 100644 --- a/smartparens-config.el +++ b/smartparens-config.el @@ -70,9 +70,21 @@ ID, ACTION, CONTEXT." ;; do not consider punctuation (not (looking-at "[?.,;!]")))))))) +(defun sp-lisp-insert-space-after-slurp (_id action _context) + (-let (((&plist :ok-orig :next-thing) sp-handler-context)) + (when (and (eq action 'slurp-forward) + (sp-get ok-orig (/= :beg-in :end-in))) + (save-excursion + (sp-get ok-orig (goto-char :end-in)) + (skip-syntax-backward " ") + (unless (looking-at-p (rx (or whitespace eol))) + (insert " ")))))) + ;; emacs is lisp hacking environment, so we set up some most common ;; lisp modes too (sp-with-modes sp-lisp-modes + (sp-local-pair "(" nil :post-handlers '(:add sp-lisp-insert-space-after-slurp)) + (sp-local-pair "[" nil :post-handlers '(:add sp-lisp-insert-space-after-slurp)) ;; disable ', it's the quote character! (sp-local-pair "'" nil :actions nil)) diff --git a/smartparens.el b/smartparens.el index f625190765..e10585f8ba 100644 --- a/smartparens.el +++ b/smartparens.el @@ -7362,7 +7362,12 @@ Examples: (let ((n (abs (prefix-numeric-value arg))) (enc (sp-get-enclosing-sexp)) (in-comment (sp-point-in-comment)) - next-thing ok) + next-thing ok + ;; At some places we mutate the value of `ok' + ;; destructively (updating the end). The original value + ;; is useful in the handlers for manipulating the + ;; surroundings, so we copy it here. + ok-orig) (when enc (save-excursion (if (sp--raw-argument-p arg) @@ -7387,6 +7392,7 @@ Examples: (goto-char (sp-get next-thing :end-suf)) (setq ok next-thing) (setq next-thing (sp-get-thing nil))) + (setq ok-orig (copy-sequence ok)) ;; do not allow slurping into a different context from ;; inside a comment (if (and in-comment @@ -7427,14 +7433,14 @@ Examples: (insert " ")))) (sp--run-hook-with-args (sp-get enc :op) :pre-handlers 'slurp-forward - (list :arg arg :enc enc :ok ok :next-thing next-thing)) + (list :arg arg :enc enc :ok ok :ok-orig ok-orig :next-thing next-thing)) (sp-get ok (insert :cl :suffix)) (sp--indent-region (sp-get ok :beg-prf) (point)) ;; HACK: update the "enc" data structure if ok==enc (when (= (sp-get enc :beg) (sp-get ok :beg)) (plist-put enc :end (point))) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'slurp-forward - (list :arg arg :enc enc :ok ok :next-thing next-thing))) + (list :arg arg :enc enc :ok ok :ok-orig ok-orig :next-thing next-thing))) (setq n (1- n))) (sp-message :cant-slurp) (setq n -1)))))))) diff --git a/test/smartparens-elisp-test.el b/test/smartparens-elisp-test.el index 9e1036e2df..334725c7c0 100644 --- a/test/smartparens-elisp-test.el +++ b/test/smartparens-elisp-test.el @@ -25,3 +25,54 @@ punctuation was considered invalid." (sp-backward-delete-char) (sp-backward-delete-char) (sp-buffer-equals ";; `a-symbol-name'? I|"))) + +(prog1 "#781" + (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-paren-no-space () + (sp-test-with-temp-elisp-buffer "(foo|)(bar)" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| (bar))") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(foo|) (bar)") + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| (bar))"))) + + (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-paren-space () + (sp-test-with-temp-elisp-buffer "(foo|) (bar)" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| (bar))") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(foo|) (bar)") + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| (bar))"))) + + (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-symbol-no-space () + (sp-test-with-temp-elisp-buffer "(foo|)bar" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| bar)") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(foo|) bar") + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| bar)"))) + + (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-symbol-space () + (sp-test-with-temp-elisp-buffer "(foo|) bar" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| bar)") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(foo|) bar") + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo| bar)"))) + + (ert-deftest sp-test-slurp-insert-space-for-style--no-extra-space-from-empty-sexp () + (sp-test-with-temp-elisp-buffer "(|)foo" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(|foo)") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(|)foo"))) + + (ert-deftest sp-test-slurp-insert-space-for-style--next-on-new-line () + (sp-test-with-temp-elisp-buffer "(foo|)\n(bar)" + (call-interactively 'sp-forward-slurp-sexp) + (sp-buffer-equals "(foo|\n (bar))") + (call-interactively 'sp-forward-barf-sexp) + (sp-buffer-equals "(foo|)\n(bar)"))))