From 5cb0cc903f64607a07b4cb3129f28e2cc072f5d7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 5 Apr 2014 00:31:02 +0100 Subject: [PATCH] Improve on previous quote autopairing change * lisp/elec-pair.el: (electric-pair--syntax-ppss): When inside comments parse from comment beginning. (electric-pair--balance-info): Fix typo in comment. (electric-pair--in-unterminated-string-p): Delete. (electric-pair--unbalanced-strings-p): New function. (electric-pair-string-bound-function): New var. (electric-pair-inhibit-if-helps-balance): Decide quote pairing according to `electric-pair--in-unterminated-string-p' * test/automated/electric-tests.el (define-electric-pair-test): Don't overtest.. (inhibit-in-mismatched-string-inside-ruby-comments): New test. (inhibit-in-mismatched-string-inside-c-comments): New test. --- lisp/ChangeLog | 12 +++++++ lisp/elec-pair.el | 55 +++++++++++++++++++++----------- test/ChangeLog | 7 ++++ test/automated/electric-tests.el | 44 ++++++++++++++++++++++++- 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 418a586b22..170fcd2892 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,15 @@ +2014-04-04 João Távora + + * elec-pair.el: + (electric-pair--syntax-ppss): When inside comments parse from + comment beginning. + (electric-pair--balance-info): Fix typo in comment. + (electric-pair--in-unterminated-string-p): Delete. + (electric-pair--unbalanced-strings-p): New function. + (electric-pair-string-bound-function): New var. + (electric-pair-inhibit-if-helps-balance): Decide quote pairing + according to `electric-pair--in-unterminated-string-p' + 2014-04-04 Stefan Monnier * textmodes/reftex-parse.el (reftex--index-tags): Rename `index-tags'. diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el index 2d7060eb27..73eabdf51c 100644 --- a/lisp/elec-pair.el +++ b/lisp/elec-pair.el @@ -257,11 +257,19 @@ when to fallback to `parse-partial-sexp'." (let* ((pos (or pos (point))) (where (or where '(string comment))) (quick-ppss (syntax-ppss)) - (quick-ppss-at-pos (syntax-ppss pos))) - (if (or (and (nth 3 quick-ppss) (memq 'string where)) - (and (nth 4 quick-ppss) (memq 'comment where))) + (quick-ppss-at-pos (syntax-ppss pos)) + (in-string (and (nth 3 quick-ppss-at-pos) (memq 'string where))) + (in-comment (and (nth 4 quick-ppss-at-pos) (memq 'comment where))) + (s-or-c-start (cond (in-string + (1+ (nth 8 quick-ppss))) + (in-comment + (goto-char (nth 8 quick-ppss)) + (forward-comment (- (point-max))) + (skip-syntax-forward " >!") + (point))))) + (if s-or-c-start (with-syntax-table electric-pair-text-syntax-table - (parse-partial-sexp (1+ (nth 8 quick-ppss)) pos)) + (parse-partial-sexp s-or-c-start pos)) ;; HACK! cc-mode apparently has some `syntax-ppss' bugs (if (memq major-mode '(c-mode c++ mode)) (parse-partial-sexp (point-min) pos) @@ -351,7 +359,7 @@ If point is not enclosed by any lists, return ((t) . (t))." (scan-error (cond ((or ;; some error happened and it is not of the "ended - ;; prematurely" kind"... + ;; prematurely" kind... (not (string-match "ends prematurely" (nth 1 err))) ;; ... or we were in a comment and just came out of ;; it. @@ -364,18 +372,29 @@ If point is not enclosed by any lists, return ((t) . (t))." (funcall ended-prematurely-fn))))))) (cons innermost outermost))) -(defun electric-pair--in-unterminated-string-p (char) - "Return non-nil if inside unterminated string started by CHAR" - (let* ((ppss (syntax-ppss)) - (relevant-ppss (if (nth 4 ppss) ; in comment - (electric-pair--syntax-ppss) - ppss)) +(defvar electric-pair-string-bound-function 'point-max + "Next buffer position where strings are syntatically unexpected. +Value is a function called with no arguments and returning a +buffer position. Major modes should set this variable +buffer-locally if they experience slowness with +`electric-pair-mode' when pairing quotes.") + +(defun electric-pair--unbalanced-strings-p (char) + "Return non-nil if there are unbalanced strings started by CHAR." + (let* ((selector-ppss (syntax-ppss)) + (relevant-ppss (save-excursion + (if (nth 4 selector-ppss) ; comment + (electric-pair--syntax-ppss + (progn + (goto-char (nth 8 selector-ppss)) + (forward-comment (point-max)) + (skip-syntax-backward " >!") + (point))) + (syntax-ppss + (funcall electric-pair-string-bound-function))))) (string-delim (nth 3 relevant-ppss))) - (and (or (eq t string-delim) - (eq char string-delim)) - (condition-case nil (progn (scan-sexps (nth 8 relevant-ppss) 1) - nil) - (scan-error t))))) + (or (eq t string-delim) + (eq char string-delim)))) (defun electric-pair--inside-string-p (char) "Return non-nil if point is inside a string started by CHAR. @@ -408,9 +427,7 @@ happened." (t (eq (cdr outermost) pair))))) ((eq syntax ?\") - (save-excursion - (goto-char (point-max)) - (electric-pair--in-unterminated-string-p char))))) + (electric-pair--unbalanced-strings-p char)))) (insert-char char))))) (defun electric-pair-skip-if-helps-balance (char) diff --git a/test/ChangeLog b/test/ChangeLog index be845db162..4b1e352051 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,10 @@ +2014-04-04 João Távora + + * automated/electric-tests.el (define-electric-pair-test): Don't + overtest.. + (inhibit-in-mismatched-string-inside-ruby-comments): New test. + (inhibit-in-mismatched-string-inside-c-comments): New test. + 2014-04-02 João Távora * automated/electric-tests.el (inhibit-if-strings-mismatched): diff --git a/test/automated/electric-tests.el b/test/automated/electric-tests.el index c43b87f3f8..9f0973e16b 100644 --- a/test/automated/electric-tests.el +++ b/test/automated/electric-tests.el @@ -141,7 +141,7 @@ Should %s \"%s\" and point at %d" expected-string expected-point bindings - (modes '(quote (emacs-lisp-mode ruby-mode c++-mode))) + (modes '(quote (ruby-mode c++-mode))) (test-in-comments t) (test-in-strings t) (test-in-code t) @@ -303,6 +303,48 @@ Should %s \"%s\" and point at %d" :bindings `((electric-pair-text-syntax-table . ,prog-mode-syntax-table))) +(define-electric-pair-test inhibit-in-mismatched-string-inside-ruby-comments + "foo\"\" +# +# \"bar\" +# \" \" +# \" +# +baz\"\"" + "\"" + :modes '(ruby-mode) + :test-in-strings nil + :test-in-comments nil + :expected-point 19 + :expected-string + "foo\"\" +# +# \"bar\"\" +# \" \" +# \" +# +baz\"\"" + :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar"))) + +(define-electric-pair-test inhibit-in-mismatched-string-inside-c-comments + "foo\"\"/* + \"bar\" + \" \" + \" +*/baz\"\"" + "\"" + :modes '(c-mode) + :test-in-strings nil + :test-in-comments nil + :expected-point 18 + :expected-string + "foo\"\"/* + \"bar\"\" + \" \" + \" +*/baz\"\"" + :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar"))) + ;;; More quotes, but now don't bind `electric-pair-text-syntax-table' ;;; to `prog-mode-syntax-table'. Use the defaults for -- 2.20.1