branch: elpa/haskell-tng-mode commit 249f507226495142591020e6a7c55a8f4dc75730 Author: Tseen She <ts33n....@gmail.com> Commit: Tseen She <ts33n....@gmail.com>
support whitespace gaps --- haskell-tng-rx.el | 8 ++------ haskell-tng-syntax.el | 37 +++++++++++++++++++++++-------------- test/haskell-tng-lexer-test.el | 36 ++++++++++++++++++++++++------------ test/src/medley.hs | 5 +++++ test/src/medley.hs.faceup | 5 +++++ test/src/medley.hs.insert.indent | 10 ++++++++++ test/src/medley.hs.layout | 5 +++++ test/src/medley.hs.lexer | 5 +++++ test/src/medley.hs.syntax | 5 +++++ 9 files changed, 84 insertions(+), 32 deletions(-) diff --git a/haskell-tng-rx.el b/haskell-tng-rx.el index aafface..2ca0858 100644 --- a/haskell-tng-rx.el +++ b/haskell-tng-rx.el @@ -58,13 +58,9 @@ give false positives." `(| `(: line-start (group (| ,haskell-tng:rx:varid (: "(" (+? (syntax symbol)) ")"))) symbol-end)) -;; note that \n has syntax `comment-end' (defconst haskell-tng:rx:newline - '(| (syntax comment-end) - (: symbol-start - "--" - (+ (not (syntax comment-end))) - (syntax comment-end))) + '(| ?\n + (: symbol-start "--" (+ (not (any ?\n))) ?\n)) "Newline or line comment.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/haskell-tng-syntax.el b/haskell-tng-syntax.el index 05adb1d..22f3635 100644 --- a/haskell-tng-syntax.el +++ b/haskell-tng-syntax.el @@ -108,17 +108,20 @@ module or qualifier, then it is punctuation." This needs to run before `haskell-tng:syntax:escapes' or string detection will not work correctly. -There is an expected false positive: an operator uses \ as its -final character and is called with a literal string or char as -the 2nd parameter with no whitespace." +There is an expected false positive: an operator has an odd +number of \ as its final characters and is called with a literal +string or char as the 2nd parameter and no whitespace." (goto-char start) (while (re-search-forward - (rx "\\" (| (syntax string-quote) - (syntax character-quote))) + (rx "\\" (syntax string-quote)) end t) (let* ((escape (match-beginning 0)) (before (haskell-tng:syntax:count-escapes escape))) - (when (cl-evenp before) + (when (and + (cl-evenp before) ;; makes sure it's a real escape + (not (looking-back ;; and not a whitespace gap terminal + (rx "\\" (+ (| space ?\n)) "\\" (syntax string-quote)) + (point-min)))) (put-text-property escape (1+ escape) 'syntax-table '(9)))))) (defun haskell-tng:syntax:count-escapes (pos) @@ -133,14 +136,20 @@ Even means the next char is not escaped." ;; TODO does this pull its weight? (slow, requires a ppss) (goto-char start) (while (re-search-forward (rx "\\") end t) - (let ((escape (match-beginning 0))) - (when (/= 9 (car (syntax-after escape))) ;; already calculated - (let ((before (haskell-tng:syntax:count-escapes escape))) - (when (and (cl-evenp before) (nth 3 (syntax-ppss))) - (put-text-property escape (1+ escape) 'syntax-table '(9))))) - (when (= 9 (car (syntax-after escape))) - ;; next char is escaped, so no need to check it - (forward-char 1))))) + (unless + ;; \...whitespace...\ is not escaped + ;; it is tempting to skip ahead here, but it can go beyond `end' + (or + (looking-at (rx (+ (| space ?\n)) "\\")) + (looking-back (rx "\\" (+ (| space ?\n)) "\\") (point-min))) + (let ((escape (match-beginning 0))) + (when (/= 9 (car (syntax-after escape))) ;; already calculated + (let ((before (haskell-tng:syntax:count-escapes escape))) + (when (and (cl-evenp before) (nth 3 (syntax-ppss))) + (put-text-property escape (1+ escape) 'syntax-table '(9))))) + (when (= 9 (car (syntax-after escape))) + ;; next char is escaped, so no need to check it + (forward-char 1)))))) (provide 'haskell-tng-syntax) ;;; haskell-tng-syntax.el ends here diff --git a/test/haskell-tng-lexer-test.el b/test/haskell-tng-lexer-test.el index a7724a6..c3080a1 100644 --- a/test/haskell-tng-lexer-test.el +++ b/test/haskell-tng-lexer-test.el @@ -98,8 +98,11 @@ "»") ((looking-at (rx (| (syntax string-quote) (syntax string-delimiter)))) - (forward-sexp 1) - "§") + (let ((start (point))) + (forward-sexp 1) + (if (= (line-number-at-pos start) + (line-number-at-pos (point))) + "§" "§§"))) (t (error "Unknown token: '%s' with '%S'" (string (char-after)) (syntax-after (point))))))) @@ -119,8 +122,11 @@ ((looking-back (rx (| (syntax string-quote) (syntax string-delimiter))) (- (point) 1)) - (backward-sexp 1) - "§") + (let ((start (point))) + (backward-sexp 1) + (if (= (line-number-at-pos start) + (line-number-at-pos (point))) + "§" "§§"))) (t (error "Unknown token: '%s' with '%S'" (string (char-before)) (progn @@ -140,14 +146,20 @@ When called interactively, shows the tokens in a buffer." (token (if reverse (haskell-tng-lexer-test:indent-backward-token) (haskell-tng-lexer-test:indent-forward-token)))) - (let ((line-diff (- (line-number-at-pos (point)) - (line-number-at-pos start)))) - (unless (= line-diff 0) - (setq lines (append (-repeat (abs line-diff) nil) lines)))) - (if (and (not token) (if reverse (bobp) (eobp))) - (setq quit 't) - (unless (s-blank? token) - (push token (car lines)))))) + (let* ((line-diff (- (line-number-at-pos (point)) + (line-number-at-pos start))) + (multiline (/= line-diff 0)) + (string-hack (and (not reverse) + multiline + (equal "§§" token)))) + (when string-hack + (push token (car lines))) + (unless (not multiline) + (setq lines (append (-repeat (abs line-diff) nil) lines))) + (if (and (not token) (if reverse (bobp) (eobp))) + (setq quit 't) + (unless (or (s-blank? token) string-hack) + (push token (car lines))))))) (if reverse lines (reverse (--map (reverse it) lines))))) diff --git a/test/src/medley.hs b/test/src/medley.hs index a1bf069..534bbae 100644 --- a/test/src/medley.hs +++ b/test/src/medley.hs @@ -39,6 +39,11 @@ chars = ['c', '\n', '\''] strings = ["", "\"\"", "\n\\ ", "\\"] -- knownWrongEscape = "foo"\\"bar" +multiline1 = "\ + \ " +multiline2 = "\ + \" + difficult = foo' 'a' 2 foo = "wobble (wibble)" diff --git a/test/src/medley.hs.faceup b/test/src/medley.hs.faceup index a37b9ae..9b34d03 100644 --- a/test/src/medley.hs.faceup +++ b/test/src/medley.hs.faceup @@ -39,6 +39,11 @@ «:haskell-tng:toplevel:strings» «:haskell-tng:keyword:=» «:haskell-tng:keyword:[»«s:""»«:haskell-tng:keyword:,» «s:"\"\""»«:haskell-tng:keyword:,» «s:"\n\\ "»«:haskell-tng:keyword:,» «s:"\\"»«:haskell-tng:keyword:]» «m:-- »«x:knownWrongEscape = "foo"\\"bar" » +«:haskell-tng:toplevel:multiline1» «:haskell-tng:keyword:=» «s:"\ + \ "» +«:haskell-tng:toplevel:multiline2» «:haskell-tng:keyword:=» «s:"\ + \"» + «:haskell-tng:toplevel:difficult» «:haskell-tng:keyword:=» foo' «s:'a'» 2 «:haskell-tng:toplevel:foo» «:haskell-tng:keyword:=» «s:"wobble (wibble)"» diff --git a/test/src/medley.hs.insert.indent b/test/src/medley.hs.insert.indent index 18c90b0..62d2a89 100644 --- a/test/src/medley.hs.insert.indent +++ b/test/src/medley.hs.insert.indent @@ -80,6 +80,16 @@ strings = ["", "\"\"", "\n\\ ", "\\"] 1 v v +multiline1 = "\ +v 1 + \ " +v 1 +multiline2 = "\ +v 1 + \" +1 2 v + +v 1 difficult = foo' 'a' 2 1 v diff --git a/test/src/medley.hs.layout b/test/src/medley.hs.layout index 7e0ca87..4027728 100644 --- a/test/src/medley.hs.layout +++ b/test/src/medley.hs.layout @@ -39,6 +39,11 @@ module Foo.Bar.Main ;strings = ["", "\"\"", "\n\\ ", "\\"] -- knownWrongEscape = "foo"\\"bar" +;multiline1 = "\ + \ " +;multiline2 = "\ + \" + ;difficult = foo' 'a' 2 ;foo = "wobble (wibble)" diff --git a/test/src/medley.hs.lexer b/test/src/medley.hs.lexer index ccc6cf4..e7e7c4d 100644 --- a/test/src/medley.hs.lexer +++ b/test/src/medley.hs.lexer @@ -39,6 +39,11 @@ VARID , VARID , VARID » ; VARID = « § , § , § , § » +; VARID = §§ + +; VARID = §§ + + ; VARID = VARID § 2 ; VARID = § diff --git a/test/src/medley.hs.syntax b/test/src/medley.hs.syntax index be0ca4a..67fd841 100644 --- a/test/src/medley.hs.syntax +++ b/test/src/medley.hs.syntax @@ -39,6 +39,11 @@ wwwww _ ("w". "\w". "\w")> wwwwwww _ ("". "\"\"". "\w\_ ". "\_")> __ wwwwwwwwwwwwwwww _ "www"__"www"> > +wwwwwwwwww _ "_> + _ "> +wwwwwwwwww _ "_> + _"> +> wwwwwwwww _ wwww "w" w> > www _ "wwwwww (wwwwww)">