Skip to content

Commit f7cf9cf

Browse files
committed
Support full complexity of backtick syntax
1 parent 262a27a commit f7cf9cf

File tree

4 files changed

+111
-2
lines changed

4 files changed

+111
-2
lines changed

haskell-font-lock.el

+15-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,21 @@ on an uppercase identifier."
455455
("(\\(,*\\|->\\))" 0 'haskell-constructor-face)
456456
("\\[\\]" 0 'haskell-constructor-face)
457457

458-
(,(concat "`" haskell-lexeme-qid-or-qsym "`") 0 'haskell-operator-face)
458+
("`"
459+
(0 (unless (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))
460+
(when (save-excursion
461+
(goto-char (match-beginning 0))
462+
(haskell-lexeme-looking-at-backtick))
463+
(goto-char (match-end 0))
464+
(unless (text-property-not-all (match-beginning 1) (match-end 1) 'face nil)
465+
(put-text-property (match-beginning 1) (match-end 1) 'face 'haskell-operator-face))
466+
(unless (text-property-not-all (match-beginning 2) (match-end 2) 'face nil)
467+
(put-text-property (match-beginning 2) (match-end 2) 'face 'haskell-operator-face))
468+
(unless (text-property-not-all (match-beginning 4) (match-end 4) 'face nil)
469+
(put-text-property (match-beginning 4) (match-end 4) 'face 'haskell-operator-face))
470+
(add-text-properties
471+
(match-beginning 0) (match-end 0)
472+
'(font-lock-fontified t fontified t font-lock-multiline t))))))
459473

460474
(,haskell-lexeme-idsym-first-char
461475
(0 (unless (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))

haskell-lexeme.el

+44
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,50 @@ the unqualified part (if any)."
130130
nil nil))
131131
'qprefix)))))
132132

133+
(defun haskell-lexeme-looking-at-backtick ()
134+
"Non-nil when point is just in front of an identifier quoted with backticks.
135+
136+
When match is successful, match-data will contain:
137+
(match-text 1) - opening backtick
138+
(match-text 2) - whole qualified identifier
139+
(match-text 3) - unqualified part of identifier
140+
(match-text 4) - closing backtick"
141+
(let ((begin (point))
142+
(match-data-old (match-data))
143+
first-backtick-start
144+
last-backtick-start
145+
qid-start
146+
id-start
147+
id-end
148+
result)
149+
(save-excursion
150+
(when (looking-at "`")
151+
(setq first-backtick-start (match-beginning 0))
152+
(goto-char (match-end 0))
153+
(forward-comment (buffer-size))
154+
(when (haskell-lexeme-looking-at-qidsym)
155+
(setq qid-start (match-beginning 0))
156+
(setq id-start (match-beginning 1))
157+
(setq id-end (match-end 1))
158+
(goto-char (match-end 0))
159+
(forward-comment (buffer-size))
160+
(when (looking-at "`")
161+
(setq last-backtick-start (match-beginning 0))
162+
(set-match-data
163+
(mapcar
164+
(lambda (p)
165+
(set-marker (make-marker) p))
166+
(list
167+
first-backtick-start (1+ last-backtick-start)
168+
first-backtick-start (1+ first-backtick-start)
169+
qid-start id-end
170+
id-start id-end
171+
last-backtick-start (1+ last-backtick-start))))
172+
(setq result t)))))
173+
(unless result
174+
(set-match-data match-data-old))
175+
result))
176+
133177
(defconst haskell-lexeme-qid
134178
(rx-to-string `(: (regexp "'*")
135179
(regexp ,haskell-lexeme-modid-opt-prefix)

tests/haskell-font-lock-tests.el

+32
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,38 @@
111111

112112
("<=<" "." haskell-operator-face))))
113113

114+
(ert-deftest haskell-syntactic-test-18 ()
115+
"Backtick operators"
116+
(check-properties
117+
'(" `fmap1`"
118+
" ` fmap2 `"
119+
" ` {- C1 -} M.fmap3 {- C2 -} `")
120+
'(("`" t haskell-operator-face)
121+
("fmap1" t haskell-operator-face)
122+
("`" t haskell-operator-face)
123+
124+
("`" t haskell-operator-face)
125+
("fmap2" t haskell-operator-face)
126+
("`" t haskell-operator-face)
127+
128+
("`" t haskell-operator-face)
129+
("C1" t font-lock-comment-face)
130+
("fmap3" t haskell-operator-face)
131+
("C2" t font-lock-comment-face)
132+
("`" t haskell-operator-face))))
133+
134+
(ert-deftest haskell-syntactic-test-18a-multiline ()
135+
"Backtick operators multiline"
136+
;; strangely thins works in interactive session
137+
:expected-result :failed
138+
(check-properties
139+
'(" `"
140+
" fmap "
141+
" `")
142+
'(("`" t haskell-operator-face)
143+
("fmap" t haskell-operator-face)
144+
("`" t haskell-operator-face))))
145+
114146
(ert-deftest haskell-syntactic-test-9a ()
115147
"Syntax for hierarchical modules when on the first line."
116148
;; note that quite many things here are not consistent but for now

tests/haskell-lexeme-tests.el

+20-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ buffer."
6363
(insert "\n"))
6464
(insert lines-or-contents))
6565

66+
(when (fboundp 'jit-lock-debug-mode)
67+
;; to see stack traces from inside font-lock
68+
(jit-lock-debug-mode))
69+
70+
;; Note that all of this should work both in haskell-mode and
71+
;; outside of it. Currently we test only haskell-mode setup.
72+
(if literate
73+
(literate-haskell-mode)
74+
(haskell-mode))
75+
6676
(font-lock-fontify-buffer)
6777

6878
;; here we check only if tokenization did not end in exception thrown
@@ -314,7 +324,7 @@ buffer."
314324
(check-lexemes-nocheck
315325
(concat "x = " "\""
316326
(let ((result "\\x01\\&,..\\NUL"))
317-
(dotimes (i 17)
327+
(dotimes (i 10)
318328
(setq result (concat result result)))
319329
result)
320330
"\"")))
@@ -348,3 +358,12 @@ buffer."
348358
(setq result (concat result result)))
349359
result)
350360
"++")))
361+
362+
(ert-deftest haskell-lexeme-big-09-backticks-long-id()
363+
(check-lexemes-nocheck
364+
(concat "x = `"
365+
(let ((result "xx"))
366+
(dotimes (i 20)
367+
(setq result (concat result result)))
368+
result)
369+
"id`")))

0 commit comments

Comments
 (0)