branch: elpa/julia-mode commit b295e36721718ceef309d9eaaf968925b31d7045 Merge: a4eeb6c 13a3c53 Author: Tamas K. Papp <tkp...@gmail.com> Commit: GitHub <nore...@github.com>
Merge pull request #133 from non-Jedi/triple-quote-cmd Apply proper syntax to triple-quoted cmds --- julia-mode-tests.el | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ julia-mode.el | 49 +++++++++++++++++++++++++++++++------------- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/julia-mode-tests.el b/julia-mode-tests.el index 8aa8355..94d46bb 100644 --- a/julia-mode-tests.el +++ b/julia-mode-tests.el @@ -532,6 +532,56 @@ end") (julia--should-font-lock string 74 font-lock-type-face) ; B )) +(ert-deftest julia--test-single-quote-string-font-lock () + "Test that single quoted strings are font-locked correctly even with escapes." + ;; Issue #15 + (let ((s1 "\"a\\\"b\"c")) + (julia--should-font-lock s1 2 font-lock-string-face) + (julia--should-font-lock s1 5 font-lock-string-face) + (julia--should-font-lock s1 7 nil))) + +(ert-deftest julia--test-triple-quote-string-font-lock () + "Test that triple quoted strings are font-locked correctly even with escapes." + ;; Issue #15 + (let ((s1 "\"\"\"a\\\"\\\"\"b\"\"\"d") + (s2 "\"\"\"a\\\"\"\"b\"\"\"d") + (s3 "\"\"\"a```b\"\"\"d") + (s4 "\\\"\"\"a\\\"\"\"b\"\"\"d") + (s5 "\"\"\"a\\\"\"\"\"b")) + (julia--should-font-lock s1 4 font-lock-string-face) + (julia--should-font-lock s1 10 font-lock-string-face) + (julia--should-font-lock s1 14 nil) + (julia--should-font-lock s2 4 font-lock-string-face) + (julia--should-font-lock s2 9 font-lock-string-face) + (julia--should-font-lock s2 13 nil) + (julia--should-font-lock s3 4 font-lock-string-face) + (julia--should-font-lock s3 8 font-lock-string-face) + (julia--should-font-lock s3 12 nil) + (julia--should-font-lock s4 5 font-lock-string-face) + (julia--should-font-lock s4 10 font-lock-string-face) + (julia--should-font-lock s4 14 nil) + (julia--should-font-lock s5 4 font-lock-string-face) + (julia--should-font-lock s5 10 nil))) + +(ert-deftest julia--test-triple-quote-cmd-font-lock () + "Test that triple-quoted cmds are font-locked correctly even with escapes." + (let ((s1 "```a\\`\\``b```d") + (s2 "```a\\```b```d") + (s3 "```a\"\"\"b```d") + (s4 "\\```a\\```b```d")) + (julia--should-font-lock s1 4 font-lock-string-face) + (julia--should-font-lock s1 10 font-lock-string-face) + (julia--should-font-lock s1 14 nil) + (julia--should-font-lock s2 4 font-lock-string-face) + (julia--should-font-lock s2 9 font-lock-string-face) + (julia--should-font-lock s2 13 nil) + (julia--should-font-lock s3 4 font-lock-string-face) + (julia--should-font-lock s3 8 font-lock-string-face) + (julia--should-font-lock s3 12 nil) + (julia--should-font-lock s4 5 font-lock-string-face) + (julia--should-font-lock s4 10 font-lock-string-face) + (julia--should-font-lock s4 14 nil))) + (ert-deftest julia--test-ccall-font-lock () (let ((s1 "t = ccall(:clock, Int32, ())")) (julia--should-font-lock s1 5 font-lock-builtin-face) @@ -703,6 +753,14 @@ hello world ;; instead of 1. (should (= 1 (nth 8 (syntax-ppss 5)))))) +(ert-deftest julia--test-triple-quoted-cmd-syntax () + (with-temp-buffer + (julia-mode) + (insert "``` +hello world +```") + (should (= 1 (nth 8 (syntax-ppss 5)))))) + (ert-deftest julia--test-backslash-syntax () (with-temp-buffer (julia-mode) diff --git a/julia-mode.el b/julia-mode.el index 155df80..dedf966 100644 --- a/julia-mode.el +++ b/julia-mode.el @@ -113,9 +113,8 @@ (syntax whitespace) bol) (group "'") - (group - (or (repeat 0 8 (not (any "'"))) (not (any "\\")) - "\\\\")) + (or (repeat 0 8 (not (any "'"))) (not (any "\\")) + "\\\\") (group "'")))) (defconst julia-hanging-operator-regexp @@ -306,22 +305,44 @@ (defconst julia-syntax-propertize-function (syntax-propertize-rules ;; triple-quoted strings are a single string rather than 3 - ((rx (group ?\") ?\" (group ?\")) - ;; First " starts a string if not already inside a string (or comment) - (1 (let ((ppss (save-excursion (syntax-ppss (match-beginning 0))))) - (unless (or (nth 3 ppss) (nth 4 ppss)) - (string-to-syntax "|")))) - ;; Last " ends a string if already inside a string - (2 (and (nth 3 (save-excursion (syntax-ppss (match-beginning 0)))) - (string-to-syntax "|")))) + ("\"\"\"" + (0 (ignore (julia-syntax-stringify)))) + ;; same with triple-quoted backticks + ("```" + (0 (ignore (julia-syntax-stringify)))) ;; backslash acts as an operator if it's not inside a string ("\\\\" (0 (unless (nth 3 (save-excursion (syntax-ppss (match-beginning 0)))) (string-to-syntax ".")))) (julia-char-regex - (1 "\"") ; Treat ' as a string delimiter. - (2 ".") ; Don't highlight anything between. - (3 "\"")))) ; Treat the last " in """ as a string delimiter. + ;; treat ' in 'c' as string-delimiter + (1 "\"") + (2 "\"")))) + +(defun julia-syntax-stringify () + "Put `syntax-table' property correctly on triple-quoted strings and cmds." + (let* ((ppss (save-excursion (syntax-ppss (match-beginning 0)))) + (string-open (and (not (nth 4 ppss)) (nth 8 ppss)))) + (cond + ;; this set of quotes delimit the start of string/cmd + ((not string-open) + (put-text-property (match-beginning 0) (1+ (match-beginning 0)) + 'syntax-table (string-to-syntax "|"))) + ;; this set of quotes closes the current string/cmd + ((and + ;; check that """ closes """ and ``` closes ``` + (eq (char-before) (char-after string-open)) + ;; check that triple quote isn't escaped by odd number of backslashes + (let ((i 0)) + (while (and (< (point-min) (- (match-beginning 0) i)) + (eq (char-before (- (match-beginning 0) i)) ?\\)) + (setq i (1+ i))) + (cl-evenp i))) + (put-text-property (1- (match-end 0)) (match-end 0) + 'syntax-table (string-to-syntax "|"))) + ;; Put point after (match-beginning 0) to account for possibility + ;; of overlapping triple-quotes with first escaped + ((backward-char 2))))) (defun julia-in-comment (&optional syntax-ppss) "Return non-nil if point is inside a comment using SYNTAX-PPSS.