Skip to content

Commit

Permalink
[Fix #425] Fix delayed hooks.
Browse files Browse the repository at this point in the history
Introduced sp-state to properly track the state changes sp needs.
  • Loading branch information
Fuco1 committed May 10, 2016
1 parent 3edcfcc commit 954f791
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 6 deletions.
35 changes: 29 additions & 6 deletions smartparens.el
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,22 @@ Maximum length of opening or closing pair is
"Symbol holding the last successful operation.")
(make-variable-buffer-local 'sp-last-operation)

(cl-defstruct sp-state
"Smartparens state for the current buffer."
;; A "counter" to track delayed hook. When a pair is inserted, a
;; cons of the form (:next . pair) is stored. On the next
;; (immediately after insertion) invocation of post-command-hook, it
;; is changed to (:this . pair). When the `car' is :this, the
;; post-command-hook checks the delayed hooks for `pair' and
;; executes them, then reset the "counter".
delayed-hook
;; TODO
delayed-insertion)

(defvar sp-state nil
"Smartparens state for the current buffer.")
(make-variable-buffer-local 'sp-state)

;; TODO: get rid of this
(defvar sp-previous-point -1
"Location of point before last command.
Expand Down Expand Up @@ -646,6 +662,8 @@ after the smartparens indicator in the mode list."
(defun sp--init ()
"Initialize the buffer local pair bindings and other buffer
local variables that depend on the active `major-mode'."
;; setup local state
(setq sp-state (make-sp-state))
;; setup local pair replacements
(sp--update-local-pairs)
;; set the escape char
Expand Down Expand Up @@ -2674,18 +2692,22 @@ see `sp-pair' for description."
(setq sp-previous-point (point)))

;; Here we run the delayed hooks. See issue #80
(when (and (not (eq sp-last-operation 'sp-insert-pair))
sp-last-inserted-pair)
(let ((hooks (sp-get-pair sp-last-inserted-pair :post-handlers-cond)))
(cond
((eq (car-safe (sp-state-delayed-hook sp-state)) :next)
(setf (car (sp-state-delayed-hook sp-state)) :this))
((eq (car-safe (sp-state-delayed-hook sp-state)) :this)
(let* ((pair (cdr (sp-state-delayed-hook sp-state)))
(hooks (sp-get-pair pair :post-handlers-cond)))
(--each hooks
(let ((fun (car it))
(conds (cdr it)))
(when (or (--any? (eq this-command it) conds)
(--any? (equal (single-key-description last-command-event) it) conds))
(sp--run-function-or-insertion
fun sp-last-inserted-pair 'insert
(sp--get-handler-context :post-handlers))))))
(setq sp-last-inserted-pair nil))
fun pair 'insert
(sp--get-handler-context :post-handlers)))))
(setf (sp-state-delayed-hook sp-state) nil)
(setq sp-last-inserted-pair nil))))

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

(defun sp--wrap-repeat-last (active-pair)
Expand Down
70 changes: 70 additions & 0 deletions test/smartparens-delayed-hook-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
(ert-deftest sp-test-delayed-hook-should-trigger-on-RET ()
(cl-flet ((sp-test-insert-space
(&rest _)
(insert " ")))
(let ((sp-pairs '((emacs-lisp-mode
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
:post-handlers ((sp-test-insert-space "RET")))))))
(sp-test-with-temp-elisp-buffer ""
(execute-kbd-macro "(")
(execute-kbd-macro (kbd "RET"))
(insert "|")
(should (equal (buffer-string) "(
|)"))))))

(ert-deftest sp-test-delayed-hook-should-not-trigger-on-a ()
(cl-flet ((sp-test-insert-space
(&rest _)
(insert " ")))
(let ((sp-pairs '((emacs-lisp-mode
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
:post-handlers ((sp-test-insert-space "RET")))))))
(sp-test-with-temp-elisp-buffer ""
(execute-kbd-macro "(")
(execute-kbd-macro (kbd "a"))
(insert "|")
(should (equal (buffer-string) "(a|)"))))))

(ert-deftest sp-test-delayed-hook-should-trigger-on-my/newline ()
(cl-letf (((symbol-function 'my/test-newline)
(lambda (&rest _)
(interactive)
(insert "\n")))
((symbol-function 'sp-test-insert-space)
(lambda (&rest _)
(insert " "))))
(let ((sp-pairs '((emacs-lisp-mode
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
:post-handlers ((sp-test-insert-space my/test-newline)))))))
(sp-test-with-temp-elisp-buffer ""
(execute-kbd-macro "(")
(setq this-command 'my/test-newline)
(call-interactively 'my/test-newline)
(run-hooks 'post-command-hook)
(insert "|")
(should (equal (buffer-string) "(
|)"))))))

(ert-deftest sp-test-delayed-hook-should-not-trigger-on-newline ()
(cl-letf (((symbol-function 'my/test-newline)
(lambda (&rest _)
(interactive)
(insert "\n")))
((symbol-function 'newline)
(lambda (&rest _)
(interactive)
(insert "\n")))
((symbol-function 'sp-test-insert-space)
(lambda (&rest _)
(insert " "))))
(let ((sp-pairs '((emacs-lisp-mode
(:open "(" :close ")" :actions (insert wrap autoskip navigate)
:post-handlers ((sp-test-insert-space my/test-newline)))))))
(sp-test-with-temp-elisp-buffer ""
(execute-kbd-macro "(")
(setq this-command 'newline)
(call-interactively 'newline)
(run-hooks 'post-command-hook)
(insert "|")
(should (equal (buffer-string) "(
|)"))))))

0 comments on commit 954f791

Please sign in to comment.