@@ -123,6 +123,12 @@ font faces assigned as if respective mode was enabled."
123
123
" Face used to highlight Haskell keywords."
124
124
:group 'haskell-appearance )
125
125
126
+ ;;;### autoload
127
+ (defface haskell-type-face
128
+ '((t :inherit font-lock-function-name-face ))
129
+ " Face used to highlight Haskell types"
130
+ :group 'haskell-appearance )
131
+
126
132
;;;### autoload
127
133
(defface haskell-constructor-face
128
134
'((t :inherit font-lock-type-face ))
@@ -206,6 +212,117 @@ Regexp match data 0 points to the chars."
206
212
; ; no face. So force evaluation by using `keep' .
207
213
keep)))))
208
214
215
+ (defconst haskell-font-lock--reverved-ids
216
+ ; ; `as' , `hiding' , and `qualified' are part of the import
217
+ ; ; spec syntax, but they are not reserved.
218
+ ; ; `_' can go in here since it has temporary word syntax.
219
+ '(" case" " class" " data" " default" " deriving" " do"
220
+ " else" " if" " import" " in" " infix" " infixl"
221
+ " infixr" " instance" " let" " module" " mdo" " newtype" " of"
222
+ " rec" " proc" " then" " type" " where" " _" )
223
+ " Identifiers treated as reserved keywords in Haskell." )
224
+
225
+ (defun haskell-font-lock--forward-type (&optional ignore )
226
+ " Find where does this type declaration end.
227
+
228
+ Moves the point to the end of type declaration. It should be
229
+ invoked with point just after one of type introducing keywords
230
+ like ::, class, instance, data, newtype, type."
231
+ (interactive )
232
+ (let ((cont t )
233
+ (end (point ))
234
+ (token nil )
235
+ ; ; we are starting right after ::
236
+ (last-token-was-operator t )
237
+ (last-token-was-newline nil ))
238
+ (while cont
239
+ (setq token (haskell-lexeme-looking-at-token 'newline ))
240
+
241
+ (cond
242
+ ((null token)
243
+ (setq cont nil ))
244
+ ((member token '(newline ))
245
+ (setq last-token-was-newline (not last-token-was-operator))
246
+ (setq end (match-end 0 ))
247
+ (goto-char (match-end 0 )))
248
+ ((and (or (member (match-string-no-properties 0 )
249
+ '(" <-" " =" " <-" " ←" " ," " ;"
250
+ " )" " ]" " }" " |" ))
251
+ (member (match-string-no-properties 0 ) haskell-font-lock--reverved-ids))
252
+ (not (member (match-string-no-properties 0 ) ignore)))
253
+ (setq cont nil )
254
+ (setq last-token-was-newline nil ))
255
+ ((member (match-string-no-properties 0 )
256
+ '(" (" " [" " {" ))
257
+ (if last-token-was-newline
258
+ (setq cont nil )
259
+ (goto-char (match-beginning 0 ))
260
+ (condition-case err
261
+ (forward-sexp )
262
+ (scan-error (goto-char (nth 3 err))))
263
+ (setq end (point ))
264
+ (setq last-token-was-newline nil )))
265
+ ((member token '(qsymid char string number template-haskell-quote template-haskell-quasi-quote))
266
+ (setq last-token-was-operator (member (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1 )))
267
+ '(varsym consym)))
268
+ (if (and (not last-token-was-operator) last-token-was-newline)
269
+ (setq cont nil )
270
+
271
+ (goto-char (match-end 0 ))
272
+ (setq end (point )))
273
+ (setq last-token-was-newline nil ))
274
+ ((member token '(comment nested-comment literate-comment))
275
+ (goto-char (match-end 0 ))
276
+ (setq end (point )))
277
+ (t
278
+ (goto-char (match-end 0 ))
279
+ (setq end (point ))
280
+ (setq last-token-was-newline nil ))))
281
+ (goto-char end)))
282
+
283
+
284
+ (defun haskell-font-lock--put-face-on-type-or-constructor ()
285
+ " Private function used to put either type or constructor face
286
+ on an uppercase identifier."
287
+ (cl-case (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1 )))
288
+ (varid (when (member (match-string 0 ) haskell-font-lock--reverved-ids)
289
+ ; ; Note: keywords parse as keywords only when not qualified.
290
+ ; ; GHC parses Control.let as a single but illegal lexeme.
291
+ (when (member (match-string 0 ) '(" class" " instance" " type" " data" " newtype" ))
292
+ (save-excursion
293
+ (goto-char (match-end 0 ))
294
+ (save-match-data
295
+ (haskell-font-lock--forward-type
296
+ (cond
297
+ ((member (match-string 0 ) '(" class" " instance" ))
298
+ '(" |" ))
299
+ ((member (match-string 0 ) '(" type" ))
300
+ ; ; Need to support 'type instance'
301
+ '(" =" " instance" )))))
302
+ (add-text-properties (match-end 0 ) (point ) '(font-lock-multiline t haskell-type t ))))
303
+ 'haskell-keyword-face ))
304
+ (conid (if (get-text-property (match-beginning 0 ) 'haskell-type )
305
+ 'haskell-type-face
306
+ 'haskell-constructor-face ))
307
+ (varsym (when (and (not (member (match-string 0 ) '(" -" " +" " ." )))
308
+ (not (save-excursion
309
+ (goto-char (match-beginning 1 ))
310
+ (looking-at-p " \\ sw" ))))
311
+ ; ; We need to protect against the case of
312
+ ; ; plus, minus or dot inside a floating
313
+ ; ; point number.
314
+ 'haskell-operator-face ))
315
+ (consym (if (not (member (match-string 1 ) '(" ::" " ∷" )))
316
+ (if (get-text-property (match-beginning 0 ) 'haskell-type )
317
+ 'haskell-type-face
318
+ 'haskell-constructor-face )
319
+ (save-excursion
320
+ (goto-char (match-end 0 ))
321
+ (save-match-data
322
+ (haskell-font-lock--forward-type))
323
+ (add-text-properties (match-end 0 ) (point ) '(font-lock-multiline t haskell-type t )))
324
+ 'haskell-operator-face ))))
325
+
209
326
(defun haskell-font-lock-keywords ()
210
327
; ; this has to be a function because it depends on global value of
211
328
; ; `haskell-font-lock-symbols'
@@ -218,14 +335,6 @@ Regexp match data 0 points to the chars."
218
335
; ; We allow ' preceding conids because of DataKinds/PolyKinds
219
336
(conid " \\ b'?[[:upper:]][[:alnum:]'_]*\\ b" )
220
337
(sym " \\ s.+" )
221
- (reservedids
222
- ; ; `as' , `hiding' , and `qualified' are part of the import
223
- ; ; spec syntax, but they are not reserved.
224
- ; ; `_' can go in here since it has temporary word syntax.
225
- '(" case" " class" " data" " default" " deriving" " do"
226
- " else" " if" " import" " in" " infix" " infixl"
227
- " infixr" " instance" " let" " module" " mdo" " newtype" " of"
228
- " rec" " proc" " then" " type" " where" " _" ))
229
338
230
339
; ; Top-level declarations
231
340
(topdecl-var
@@ -291,11 +400,11 @@ Regexp match data 0 points to the chars."
291
400
292
401
; ; Toplevel Declarations.
293
402
; ; Place them *before* generic id-and-op highlighting.
294
- (, topdecl-var (1 (unless (member (match-string 1 ) ' , reservedids )
403
+ (, topdecl-var (1 (unless (member (match-string 1 ) haskell-font-lock--reverved-ids )
295
404
'haskell-definition-face )))
296
- (, topdecl-var2 (2 (unless (member (match-string 2 ) ' , reservedids )
405
+ (, topdecl-var2 (2 (unless (member (match-string 2 ) haskell-font-lock--reverved-ids )
297
406
'haskell-definition-face )))
298
- (, topdecl-bangpat (1 (unless (member (match-string 1 ) ' , reservedids )
407
+ (, topdecl-bangpat (1 (unless (member (match-string 1 ) haskell-font-lock--reverved-ids )
299
408
'haskell-definition-face )))
300
409
(, topdecl-sym (2 (unless (member (match-string 2 ) '(" \\ " " =" " ->" " →" " <-" " ←" " ::" " ∷" " ," " ;" " `" ))
301
410
'haskell-definition-face )))
@@ -309,23 +418,7 @@ Regexp match data 0 points to the chars."
309
418
(,(concat " `" haskell-lexeme-qid-or-qsym " `" ) 0 'haskell-operator-face )
310
419
311
420
(, haskell-lexeme-qid-or-qsym
312
- 0 (cl-case (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1 )))
313
- (varid (when (member (match-string 0 ) ', reservedids )
314
- ; ; Note: keywords parse as keywords only when not qualified.
315
- ; ; GHC parses Control.let as a single but illegal lexeme.
316
- 'haskell-keyword-face ))
317
- (conid 'haskell-constructor-face )
318
- (varsym (when (and (not (member (match-string 0 ) '(" -" " +" " ." )))
319
- (not (save-excursion
320
- (goto-char (match-beginning 1 ))
321
- (looking-at-p " \\ sw" ))))
322
- ; ; We need to protect against the case of
323
- ; ; plus, minus or dot inside a floating
324
- ; ; point number.
325
- 'haskell-operator-face ))
326
- (consym (if (not (member (match-string 1 ) '(" ::" " ∷" )))
327
- 'haskell-constructor-face
328
- 'haskell-operator-face ))))))
421
+ (0 (haskell-font-lock--put-face-on-type-or-constructor)))))
329
422
keywords))
330
423
331
424
0 commit comments