Skip to content

Commit 954f791

Browse files
committed
[Fix #425] Fix delayed hooks.
Introduced sp-state to properly track the state changes sp needs.
1 parent 3edcfcc commit 954f791

File tree

2 files changed

+99
-6
lines changed

2 files changed

+99
-6
lines changed

smartparens.el

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,22 @@ Maximum length of opening or closing pair is
355355
"Symbol holding the last successful operation.")
356356
(make-variable-buffer-local 'sp-last-operation)
357357

358+
(cl-defstruct sp-state
359+
"Smartparens state for the current buffer."
360+
;; A "counter" to track delayed hook. When a pair is inserted, a
361+
;; cons of the form (:next . pair) is stored. On the next
362+
;; (immediately after insertion) invocation of post-command-hook, it
363+
;; is changed to (:this . pair). When the `car' is :this, the
364+
;; post-command-hook checks the delayed hooks for `pair' and
365+
;; executes them, then reset the "counter".
366+
delayed-hook
367+
;; TODO
368+
delayed-insertion)
369+
370+
(defvar sp-state nil
371+
"Smartparens state for the current buffer.")
372+
(make-variable-buffer-local 'sp-state)
373+
358374
;; TODO: get rid of this
359375
(defvar sp-previous-point -1
360376
"Location of point before last command.
@@ -646,6 +662,8 @@ after the smartparens indicator in the mode list."
646662
(defun sp--init ()
647663
"Initialize the buffer local pair bindings and other buffer
648664
local variables that depend on the active `major-mode'."
665+
;; setup local state
666+
(setq sp-state (make-sp-state))
649667
;; setup local pair replacements
650668
(sp--update-local-pairs)
651669
;; set the escape char
@@ -2674,18 +2692,22 @@ see `sp-pair' for description."
26742692
(setq sp-previous-point (point)))
26752693

26762694
;; Here we run the delayed hooks. See issue #80
2677-
(when (and (not (eq sp-last-operation 'sp-insert-pair))
2678-
sp-last-inserted-pair)
2679-
(let ((hooks (sp-get-pair sp-last-inserted-pair :post-handlers-cond)))
2695+
(cond
2696+
((eq (car-safe (sp-state-delayed-hook sp-state)) :next)
2697+
(setf (car (sp-state-delayed-hook sp-state)) :this))
2698+
((eq (car-safe (sp-state-delayed-hook sp-state)) :this)
2699+
(let* ((pair (cdr (sp-state-delayed-hook sp-state)))
2700+
(hooks (sp-get-pair pair :post-handlers-cond)))
26802701
(--each hooks
26812702
(let ((fun (car it))
26822703
(conds (cdr it)))
26832704
(when (or (--any? (eq this-command it) conds)
26842705
(--any? (equal (single-key-description last-command-event) it) conds))
26852706
(sp--run-function-or-insertion
2686-
fun sp-last-inserted-pair 'insert
2687-
(sp--get-handler-context :post-handlers))))))
2688-
(setq sp-last-inserted-pair nil))
2707+
fun pair 'insert
2708+
(sp--get-handler-context :post-handlers)))))
2709+
(setf (sp-state-delayed-hook sp-state) nil)
2710+
(setq sp-last-inserted-pair nil))))
26892711

26902712
;; Here we run the delayed insertion. Some details in issue #113
26912713
(when (and (not (eq sp-last-operation 'sp-insert-pair-delayed))
@@ -3284,6 +3306,7 @@ default."
32843306
(push nil buffer-undo-list))
32853307
(sp--run-hook-with-args open-pair :post-handlers 'insert)
32863308
(setq sp-last-inserted-pair open-pair)
3309+
(setf (sp-state-delayed-hook sp-state) (cons :next open-pair))
32873310
(setq sp-last-operation 'sp-insert-pair)))))
32883311

32893312
(defun sp--wrap-repeat-last (active-pair)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
(ert-deftest sp-test-delayed-hook-should-trigger-on-RET ()
2+
(cl-flet ((sp-test-insert-space
3+
(&rest _)
4+
(insert " ")))
5+
(let ((sp-pairs '((emacs-lisp-mode
6+
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
7+
:post-handlers ((sp-test-insert-space "RET")))))))
8+
(sp-test-with-temp-elisp-buffer ""
9+
(execute-kbd-macro "(")
10+
(execute-kbd-macro (kbd "RET"))
11+
(insert "|")
12+
(should (equal (buffer-string) "(
13+
|)"))))))
14+
15+
(ert-deftest sp-test-delayed-hook-should-not-trigger-on-a ()
16+
(cl-flet ((sp-test-insert-space
17+
(&rest _)
18+
(insert " ")))
19+
(let ((sp-pairs '((emacs-lisp-mode
20+
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
21+
:post-handlers ((sp-test-insert-space "RET")))))))
22+
(sp-test-with-temp-elisp-buffer ""
23+
(execute-kbd-macro "(")
24+
(execute-kbd-macro (kbd "a"))
25+
(insert "|")
26+
(should (equal (buffer-string) "(a|)"))))))
27+
28+
(ert-deftest sp-test-delayed-hook-should-trigger-on-my/newline ()
29+
(cl-letf (((symbol-function 'my/test-newline)
30+
(lambda (&rest _)
31+
(interactive)
32+
(insert "\n")))
33+
((symbol-function 'sp-test-insert-space)
34+
(lambda (&rest _)
35+
(insert " "))))
36+
(let ((sp-pairs '((emacs-lisp-mode
37+
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
38+
:post-handlers ((sp-test-insert-space my/test-newline)))))))
39+
(sp-test-with-temp-elisp-buffer ""
40+
(execute-kbd-macro "(")
41+
(setq this-command 'my/test-newline)
42+
(call-interactively 'my/test-newline)
43+
(run-hooks 'post-command-hook)
44+
(insert "|")
45+
(should (equal (buffer-string) "(
46+
|)"))))))
47+
48+
(ert-deftest sp-test-delayed-hook-should-not-trigger-on-newline ()
49+
(cl-letf (((symbol-function 'my/test-newline)
50+
(lambda (&rest _)
51+
(interactive)
52+
(insert "\n")))
53+
((symbol-function 'newline)
54+
(lambda (&rest _)
55+
(interactive)
56+
(insert "\n")))
57+
((symbol-function 'sp-test-insert-space)
58+
(lambda (&rest _)
59+
(insert " "))))
60+
(let ((sp-pairs '((emacs-lisp-mode
61+
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
62+
:post-handlers ((sp-test-insert-space my/test-newline)))))))
63+
(sp-test-with-temp-elisp-buffer ""
64+
(execute-kbd-macro "(")
65+
(setq this-command 'newline)
66+
(call-interactively 'newline)
67+
(run-hooks 'post-command-hook)
68+
(insert "|")
69+
(should (equal (buffer-string) "(
70+
|)"))))))

0 commit comments

Comments
 (0)