28
28
29
29
(require 'cl-lib )
30
30
(require 'haskell-compat )
31
+ (require 'haskell-lexeme )
31
32
(require 'font-lock )
32
33
34
+ ;;;### autoload
35
+ (defgroup haskell-appearance nil
36
+ " Haskell Appearance."
37
+ :group 'haskell )
38
+
39
+
33
40
(defcustom haskell-font-lock-symbols nil
34
41
" Display \\ and -> and such using symbols in fonts.
35
42
36
43
This may sound like a neat trick, but be extra careful: it changes the
37
44
alignment and can thus lead to nasty surprises with regards to layout."
38
- :group 'haskell
45
+ :group 'haskell-appearance
39
46
:type 'boolean )
40
47
41
48
(defcustom haskell-font-lock-symbols-alist
@@ -77,7 +84,7 @@ PREDICATE if present is a function of one argument (the start position
77
84
of the symbol) which should return non-nil if this mapping should
78
85
be disabled at that position."
79
86
:type '(alist string string)
80
- :group 'haskell )
87
+ :group 'haskell-appearance )
81
88
82
89
(defun haskell-font-lock-dot-is-not-composition (start )
83
90
" Return non-nil if the \" .\" at START is not a composition operator.
@@ -107,28 +114,28 @@ This is the case if the \".\" is part of a \"forall <tvar> . <type>\"."
107
114
108
115
If a quasi quote is seen in Haskell code its contents will have
109
116
font faces assigned as if respective mode was enabled."
110
- :group 'haskell
117
+ :group 'haskell-appearance
111
118
:type '(repeat (cons string symbol)))
112
119
113
120
;;;### autoload
114
121
(defface haskell-keyword-face
115
122
'((t :inherit font-lock-keyword-face ))
116
123
" Face used to highlight Haskell keywords."
117
- :group 'haskell )
124
+ :group 'haskell-appearance )
118
125
119
126
;;;### autoload
120
127
(defface haskell-constructor-face
121
128
'((t :inherit font-lock-type-face ))
122
129
" Face used to highlight Haskell constructors."
123
- :group 'haskell )
130
+ :group 'haskell-appearance )
124
131
125
132
; ; This used to be `font-lock-variable-name-face' but it doesn't result in
126
133
; ; a highlighting that's consistent with other modes (it's mostly used
127
134
; ; for function defintions).
128
135
(defface haskell-definition-face
129
136
'((t :inherit font-lock-function-name-face ))
130
137
" Face used to highlight Haskell definitions."
131
- :group 'haskell )
138
+ :group 'haskell-appearance )
132
139
133
140
; ; This is probably just wrong, but it used to use
134
141
; ; `font-lock-function-name-face' with a result that was not consistent with
@@ -137,28 +144,28 @@ font faces assigned as if respective mode was enabled."
137
144
(defface haskell-operator-face
138
145
'((t :inherit font-lock-variable-name-face ))
139
146
" Face used to highlight Haskell operators."
140
- :group 'haskell )
147
+ :group 'haskell-appearance )
141
148
142
149
;;;### autoload
143
150
(defface haskell-pragma-face
144
151
'((t :inherit font-lock-preprocessor-face ))
145
152
" Face used to highlight Haskell pragmas."
146
- :group 'haskell )
153
+ :group 'haskell-appearance )
147
154
148
155
;;;### autoload
149
156
(defface haskell-literate-comment-face
150
157
'((t :inherit font-lock-doc-face ))
151
158
" Face with which to fontify literate comments.
152
159
Inherit from `default' to avoid fontification of them."
153
- :group 'haskell )
160
+ :group 'haskell-appearance )
154
161
155
162
(defface haskell-quasi-quote-face
156
163
'((t :inherit font-lock-string-face ))
157
164
" Generic face for quasiquotes.
158
165
159
166
Some quote types are fontified according to other mode defined in
160
167
`haskell-font-lock-quasi-quote-modes' ."
161
- :group 'haskell )
168
+ :group 'haskell-appearance )
162
169
163
170
(defun haskell-font-lock-compose-symbol (alist )
164
171
" Compose a sequence of ascii chars into a symbol.
@@ -199,13 +206,13 @@ Regexp match data 0 points to the chars."
199
206
; ; no face. So force evaluation by using `keep' .
200
207
keep)))))
201
208
202
- ; ; The font lock regular expressions.
203
- ( defun haskell-font-lock-keywords-create ( literate )
204
- " Create fontification definitions for Haskell scripts.
205
- Returns keywords suitable for ` font- lock-keywords' ."
209
+ ( defun haskell- font- lock-keywords ()
210
+ ; ; this has to be a function because it depends on global value of
211
+ ; ; `haskell-font-lock-symbols'
212
+ " Generate font lock eywords ."
206
213
(let* (; ; Bird-style literate scripts start a line of code with
207
214
; ; "^>", otherwise a line of code starts with "^".
208
- (line-prefix ( if ( eq literate 'bird ) " ^ > ?" " ^ " ) )
215
+ (line-prefix " ^ \\ (?: > ?\\ )? " )
209
216
210
217
(varid " \\ b[[:lower:]_][[:alnum:]'_]*\\ b" )
211
218
; ; We allow ' preceding conids because of DataKinds/PolyKinds
@@ -233,8 +240,7 @@ Returns keywords suitable for `font-lock-keywords'."
233
240
(topdecl-var
234
241
(concat line-prefix " \\ (" varid " \\ (?:\\ s-*,\\ s-*" varid " \\ )*" " \\ )\\ s-*"
235
242
; ; optionally allow for a single newline after identifier
236
- ; ; NOTE: not supported for bird-style .lhs files
237
- (if (eq literate 'bird ) nil " \\ ([\n ]\\ s-+\\ )?" )
243
+ " \\ ([\n ]\\ s-+\\ )?"
238
244
; ; A toplevel declaration can be followed by a definition
239
245
; ; (=), a type (::) or (∷), a guard, or a pattern which can
240
246
; ; either be a variable, a constructor, a parenthesized
@@ -323,90 +329,6 @@ Returns keywords suitable for `font-lock-keywords'."
323
329
'haskell-operator-face ))))
324
330
keywords))
325
331
326
- (defconst haskell-basic-syntactic-keywords
327
- '(; ; Character constants (since apostrophe can't have string syntax).
328
- ; ; Beware: do not match something like 's-}' or '\n"+' since the first '
329
- ; ; might be inside a comment or a string.
330
- ; ; This still gets fooled with "'"'"'"'"'"', but ... oh well.
331
- (" \\ Sw\\ ('\\ )\\ ([^\\ '\n ]\\ |\\\\ .[^\\ '\n \" }]*\\ )\\ ('\\ )" (1 " \" " ) (3 " \" " ))
332
- ; ; Deal with instances of `--' which don't form a comment
333
- (" [!#$%&*+./:<=>?@^|~\\ ]*--[!#$%&*+./:<=>?@^|~\\ -]*" (0 (cond ((or (nth 3 (syntax-ppss )) (numberp (nth 4 (syntax-ppss ))))
334
- ; ; There are no such instances inside
335
- ; ; nestable comments or strings
336
- nil )
337
- ((string-match " \\ `-*\\' " (match-string 0 ))
338
- ; ; Sequence of hyphens. Do nothing in
339
- ; ; case of things like `{---' .
340
- nil )
341
- ((string-match " \\ `[^-]+--.*" (match-string 0 ))
342
- ; ; Extra characters before comment starts
343
- " ." )
344
- (t " ." )))) ; other symbol sequence
345
-
346
- ; ; Implement Haskell Report 'escape' and 'gap' rules. Backslash
347
- ; ; inside of a string is escaping unless it is preceeded by
348
- ; ; another escaping backslash. There can be whitespace between
349
- ; ; those two.
350
- ; ;
351
- ; ; Backslashes outside of string never escape.
352
- ; ;
353
- ; ; Note that (> 0 (skip-syntax-backward ".")) this skips over *escaping*
354
- ; ; backslashes only.
355
- (" \\\\ " (0 (when (save-excursion (and (nth 3 (syntax-ppss ))
356
- (goto-char (match-beginning 0 ))
357
- (skip-syntax-backward " ->" )
358
- (or (not (eq ?\\ (char-before )))
359
- (> 0 (skip-syntax-backward " ." )))))
360
- " \\ " )))
361
-
362
- ; ; QuasiQuotes syntax: [quoter| string |], quoter is unqualified
363
- ; ; name, no spaces, string is arbitrary (including newlines),
364
- ; ; finishes at the first occurence of |], no escaping is provided.
365
- ; ;
366
- ; ; The quoter cannot be "e", "t", "d", or "p", since those overlap
367
- ; ; with Template Haskell quotations.
368
- ; ;
369
- ; ; QuasiQuotes opens only when outside of a string or a comment
370
- ; ; and closes only when inside a quasiquote.
371
- ; ;
372
- ; ; (syntax-ppss) returns list with two interesting elements:
373
- ; ; nth 3. non-nil if inside a string. (it is the character that will
374
- ; ; terminate the string, or t if the string should be terminated
375
- ; ; by a generic string delimiter.)
376
- ; ; nth 4. nil if outside a comment, t if inside a non-nestable comment,
377
- ; ; else an integer (the current comment nesting).
378
- ; ;
379
- ; ; Note also that we need to do in in a single pass, hence a regex
380
- ; ; that covers both the opening and the ending of a quasiquote.
381
-
382
- (" \\ (\\ [[[:alnum:]]+\\ )?\\ (|\\ )\\ (]\\ )?"
383
- (2 (save-excursion
384
- (goto-char (match-beginning 0 ))
385
- (if (eq ?\[ (char-after ))
386
- ; ; opening case
387
- (unless (or (nth 3 (syntax-ppss ))
388
- (nth 4 (syntax-ppss ))
389
- (member (match-string 1 )
390
- '(" [e" " [t" " [d" " [p" )))
391
- " \" " )
392
- ; ; closing case
393
- (when (and (eq ?| (nth 3 (syntax-ppss )))
394
- (equal " ]" (match-string 3 ))
395
- )
396
- " \" " )))))
397
- ))
398
-
399
- (defconst haskell-bird-syntactic-keywords
400
- (cons '(" ^[^\n >]" (0 " <" ))
401
- haskell-basic-syntactic-keywords))
402
-
403
- (defconst haskell-latex-syntactic-keywords
404
- (append
405
- '((" ^\\\\ begin{code}\\ (\n \\ )" 1 " !" )
406
- ; ; Note: buffer is widened during font-locking.
407
- (" \\ `\\ (.\\ |\n \\ )" (1 " !" )) ; start comment at buffer start
408
- (" ^\\ (\\\\\\ )end{code}$" 1 " !" ))
409
- haskell-basic-syntactic-keywords))
410
332
411
333
(defun haskell-font-lock-fontify-block (lang-mode start end )
412
334
" Fontify a block as LANG-MODE."
@@ -455,20 +377,51 @@ Returns keywords suitable for `font-lock-keywords'."
455
377
nil )
456
378
; ; fontify normally as string because lang-mode is not present
457
379
'haskell-quasi-quote-face ))
458
- 'font-lock-string-face ))
459
- ; ; Else comment. If it's from syntax table, use default face.
460
- ((or (eq 'syntax-table (nth 7 state))
461
- (and (eq haskell-literate 'bird )
462
- (memq (char-before (nth 8 state)) '(nil ?\n ))))
380
+ (save-excursion
381
+ (let
382
+ ((state2
383
+ (parse-partial-sexp (point ) (point-max ) nil nil state
384
+ 'syntax-table ))
385
+ (end-of-string (point )))
386
+
387
+ (put-text-property (nth 8 state) (point )
388
+ 'face 'font-lock-string-face )
389
+
390
+
391
+ (if (or (equal t (nth 3 state)) (nth 3 state2))
392
+ ; ; This is an unterminated string constant, use warning
393
+ ; ; face for the opening quote.
394
+ (put-text-property (nth 8 state) (1+ (nth 8 state))
395
+ 'face 'font-lock-warning-face ))
396
+
397
+ (goto-char (1+ (nth 8 state)))
398
+ (while (re-search-forward " \\\\ " end-of-string t )
399
+
400
+ (goto-char (1- (point )))
401
+
402
+ (if (looking-at haskell-lexeme-string-literal-inside-item)
403
+ (goto-char (match-end 0 ))
404
+
405
+ ; ; We are looking at an unacceptable escape
406
+ ; ; sequence. Use warning face to highlight that.
407
+ (put-text-property (point ) (1+ (point ))
408
+ 'face 'font-lock-warning-face )
409
+ (goto-char (1+ (point )))))))
410
+ ; ; must return nil here so that it is not fontified again as string
411
+ nil ))
412
+ ; ; Detect literate comment lines starting with syntax class '<'
413
+ ((save-excursion
414
+ (goto-char (nth 8 state))
415
+ (equal (string-to-syntax " <" ) (syntax-after (point ))))
463
416
'haskell-literate-comment-face )
464
417
; ; Detect pragmas. A pragma is enclosed in special comment
465
418
; ; delimeters {-# .. #-}.
466
419
((save-excursion
467
420
(goto-char (nth 8 state))
468
- (and (looking-at " {-#" )
421
+ (and (looking-at-p " {-#" )
469
422
(forward-comment 1 )
470
423
(goto-char (- (point ) 3 ))
471
- (looking-at " #-}" )))
424
+ (looking-at-p " #-}" )))
472
425
'haskell-pragma-face )
473
426
; ; Haddock comment start with either "-- [|^*$]" or "{- ?[|^*$]"
474
427
; ; (note space optional for nested comments and mandatory for
@@ -484,8 +437,8 @@ Returns keywords suitable for `font-lock-keywords'."
484
437
; ; comments newline is outside of comment.
485
438
((save-excursion
486
439
(goto-char (nth 8 state))
487
- (or (looking-at " \\ (?:{- ?\\ |-- \\ )[|^*$]" )
488
- (and (looking-at " --" ) ; are we at double dash comment
440
+ (or (looking-at-p " \\ (?:{- ?\\ |-- \\ )[|^*$]" )
441
+ (and (looking-at-p " --" ) ; are we at double dash comment
489
442
(forward-line -1 ) ; this is nil on first line
490
443
(eq (get-text-property (line-end-position ) 'face )
491
444
'font-lock-doc-face ) ; is a doc face
@@ -495,40 +448,11 @@ Returns keywords suitable for `font-lock-keywords'."
495
448
'font-lock-doc-face )
496
449
(t 'font-lock-comment-face )))
497
450
498
- (defconst haskell-font-lock-keywords
499
- (haskell-font-lock-keywords-create nil )
500
- " Font lock definitions for non-literate Haskell." )
501
-
502
- (defconst haskell-font-lock-bird-literate-keywords
503
- (haskell-font-lock-keywords-create 'bird )
504
- " Font lock definitions for Bird-style literate Haskell." )
505
-
506
- (defconst haskell-font-lock-latex-literate-keywords
507
- (haskell-font-lock-keywords-create 'latex )
508
- " Font lock definitions for LaTeX-style literate Haskell." )
509
-
510
- ;;;### autoload
511
- (defun haskell-font-lock-choose-keywords ()
512
- (let ((literate (if (boundp 'haskell-literate ) haskell-literate)))
513
- (cl-case literate
514
- (bird haskell-font-lock-bird-literate-keywords)
515
- ((latex tex) haskell-font-lock-latex-literate-keywords)
516
- (t haskell-font-lock-keywords))))
517
-
518
- (defun haskell-font-lock-choose-syntactic-keywords ()
519
- (let ((literate (if (boundp 'haskell-literate ) haskell-literate)))
520
- (cl-case literate
521
- (bird haskell-bird-syntactic-keywords)
522
- ((latex tex) haskell-latex-syntactic-keywords)
523
- (t haskell-basic-syntactic-keywords))))
524
-
525
451
(defun haskell-font-lock-defaults-create ()
526
452
" Locally set `font-lock-defaults' for Haskell."
527
453
(set (make-local-variable 'font-lock-defaults )
528
- '(haskell-font-lock-choose-keywords
529
- nil nil ((?\' . " w" ) (?_ . " w" )) nil
530
- (font-lock-syntactic-keywords
531
- . haskell-font-lock-choose-syntactic-keywords)
454
+ '((haskell-font-lock-keywords)
455
+ nil nil nil nil
532
456
(font-lock-syntactic-face-function
533
457
. haskell-syntactic-face-function)
534
458
; ; Get help from font-lock-syntactic-keywords.
0 commit comments