/src/haskell/haskell-font-lock.el

http://github.com/kjhealy/emacs-starter-kit · Emacs Lisp · 633 lines · 349 code · 69 blank · 215 comment · 22 complexity · 749276ef7a5c8cf9937d860a16337935 MD5 · raw file

  1. ;;; haskell-font-lock.el --- Font locking module for Haskell Mode
  2. ;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
  3. ;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn
  4. ;; Authors: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and
  5. ;; Tommy Thorn <thorn@irisa.fr>
  6. ;; 2003 Dave Love <fx@gnu.org>
  7. ;; Keywords: faces files Haskell
  8. ;; This file is not part of GNU Emacs.
  9. ;; This file is free software; you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation; either version 3, or (at your option)
  12. ;; any later version.
  13. ;; This file is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  19. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. ;; Boston, MA 02111-1307, USA.
  21. ;;; Commentary:
  22. ;; Purpose:
  23. ;;
  24. ;; To support fontification of standard Haskell keywords, symbols,
  25. ;; functions, etc. Supports full Haskell 1.4 as well as LaTeX- and
  26. ;; Bird-style literate scripts.
  27. ;;
  28. ;; Installation:
  29. ;;
  30. ;; To turn font locking on for all Haskell buffers under the Haskell
  31. ;; mode of Moss&Thorn, add this to .emacs:
  32. ;;
  33. ;; (add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
  34. ;;
  35. ;; Otherwise, call `turn-on-haskell-font-lock'.
  36. ;;
  37. ;;
  38. ;; Customisation:
  39. ;;
  40. ;; The colours and level of font locking may be customised. See the
  41. ;; documentation on `turn-on-haskell-font-lock' for more details.
  42. ;;
  43. ;;
  44. ;; History:
  45. ;;
  46. ;; If you have any problems or suggestions, after consulting the list
  47. ;; below, email gem@cs.york.ac.uk and thorn@irisa.fr quoting the
  48. ;; version of the mode you are using, the version of Emacs you are
  49. ;; using, and a small example of the problem or suggestion. Note that
  50. ;; this module requires a reasonably recent version of Emacs. It
  51. ;; requires Emacs 21 to cope with Unicode characters and to do proper
  52. ;; syntactic fontification.
  53. ;;
  54. ;; Version 1.3:
  55. ;; From Dave Love:
  56. ;; Support for proper behaviour (including with Unicode identifiers)
  57. ;; in Emacs 21 only hacked in messily to avoid disturbing the old
  58. ;; stuff. Needs integrating more cleanly. Allow literate comment
  59. ;; face to be customized. Some support for fontifying definitions.
  60. ;; (I'm not convinced the faces should be customizable -- fontlock
  61. ;; faces are normally expected to be consistent.)
  62. ;;
  63. ;; Version 1.2:
  64. ;; Added support for LaTeX-style literate scripts. Allow whitespace
  65. ;; after backslash to end a line for string continuations.
  66. ;;
  67. ;; Version 1.1:
  68. ;; Use own syntax table. Use backquote (neater). Stop ''' being
  69. ;; highlighted as quoted character. Fixed `\"' fontification bug
  70. ;; in comments.
  71. ;;
  72. ;; Version 1.0:
  73. ;; Brought over from Haskell mode v1.1.
  74. ;;
  75. ;; Present Limitations/Future Work (contributions are most welcome!):
  76. ;;
  77. ;; . Debatable whether `()' `[]' `(->)' `(,)' `(,,)' etc. should be
  78. ;; highlighted as constructors or not. Should the `->' in
  79. ;; `id :: a -> a' be considered a constructor or a keyword? If so,
  80. ;; how do we distinguish this from `\x -> x'? What about the `\'?
  81. ;;
  82. ;; . XEmacs can support both `--' comments and `{- -}' comments
  83. ;; simultaneously. If XEmacs is detected, this should be used.
  84. ;;
  85. ;; . Support for GreenCard?
  86. ;;
  87. ;; All functions/variables start with
  88. ;; `(turn-(on/off)-)haskell-font-lock' or `haskell-fl-'.
  89. ;;; Code:
  90. (eval-when-compile
  91. (require 'haskell-mode)
  92. (require 'cl))
  93. (require 'font-lock)
  94. (defcustom haskell-font-lock-symbols nil
  95. "Display \\ and -> and such using symbols in fonts.
  96. This may sound like a neat trick, but be extra careful: it changes the
  97. alignment and can thus lead to nasty surprises w.r.t layout.
  98. If t, try to use whichever font is available. Otherwise you can
  99. set it to a particular font of your preference among `japanese-jisx0208'
  100. and `unicode'."
  101. :group 'haskell
  102. :type '(choice (const nil)
  103. (const t)
  104. (const unicode)
  105. (const japanese-jisx0208)))
  106. (defconst haskell-font-lock-symbols-alist
  107. (append
  108. ;; Prefer single-width Unicode font for lambda.
  109. (and (fboundp 'decode-char)
  110. (memq haskell-font-lock-symbols '(t unicode))
  111. (list (cons "\\" (decode-char 'ucs 955))))
  112. ;; The symbols can come from a JIS0208 font.
  113. (and (fboundp 'make-char) (fboundp 'charsetp) (charsetp 'japanese-jisx0208)
  114. (memq haskell-font-lock-symbols '(t japanese-jisx0208))
  115. (list (cons "not" (make-char 'japanese-jisx0208 34 76))
  116. (cons "\\" (make-char 'japanese-jisx0208 38 75))
  117. (cons "->" (make-char 'japanese-jisx0208 34 42))
  118. (cons "<-" (make-char 'japanese-jisx0208 34 43))
  119. (cons "=>" (make-char 'japanese-jisx0208 34 77))
  120. ;; FIXME: I'd like to either use ? or ? depending on how the
  121. ;; `forall' keyword is used, but currently the rest of the
  122. ;; code assumes that such ambiguity doesn't happen :-(
  123. (cons "forall" (make-char 'japanese-jisx0208 34 79))))
  124. ;; Or a unicode font.
  125. (and (fboundp 'decode-char)
  126. (memq haskell-font-lock-symbols '(t unicode))
  127. (list (cons "not" (decode-char 'ucs 172))
  128. (cons "->" (decode-char 'ucs 8594))
  129. (cons "<-" (decode-char 'ucs 8592))
  130. (cons "=>" (decode-char 'ucs 8658))
  131. (cons "()" (decode-char 'ucs #X2205))
  132. (cons "==" (decode-char 'ucs #X2261))
  133. (cons "/=" (decode-char 'ucs #X2262))
  134. (cons ">=" (decode-char 'ucs #X2265))
  135. (cons "<=" (decode-char 'ucs #X2264))
  136. (cons "!!" (decode-char 'ucs #X203C))
  137. (cons "&&" (decode-char 'ucs #X2227))
  138. (cons "||" (decode-char 'ucs #X2228))
  139. (cons "sqrt" (decode-char 'ucs #X221A))
  140. (cons "undefined" (decode-char 'ucs #X22A5))
  141. (cons "pi" (decode-char 'ucs #X3C0))
  142. (cons "~>" (decode-char 'ucs 8669)) ;; Omega language
  143. ;; (cons "~>" (decode-char 'ucs 8605)) ;; less desirable
  144. (cons "-<" (decode-char 'ucs 8610)) ;; Paterson's arrow syntax
  145. ;; (cons "-<" (decode-char 'ucs 10521)) ;; nicer but uncommon
  146. (cons "::" (decode-char 'ucs 8759))
  147. (list "." (decode-char 'ucs 8728) ; (decode-char 'ucs 9675)
  148. ;; Need a predicate here to distinguish the . used by
  149. ;; forall <foo> . <bar>.
  150. 'haskell-font-lock-dot-is-not-composition)
  151. (cons "forall" (decode-char 'ucs 8704)))))
  152. "Alist mapping Haskell symbols to chars.
  153. Each element has the form (STRING . CHAR) or (STRING CHAR PREDICATE).
  154. STRING is the Haskell symbol.
  155. CHAR is the character with which to represent this symbol.
  156. PREDICATE if present is a function of one argument (the start position
  157. of the symbol) which should return non-nil if this mapping should be disabled
  158. at that position.")
  159. (defun haskell-font-lock-dot-is-not-composition (start)
  160. "Return non-nil if the \".\" at START is not a composition operator.
  161. This is the case if the \".\" is part of a \"forall <tvar> . <type>\"."
  162. (save-excursion
  163. (goto-char start)
  164. (re-search-backward "\\<forall\\>[^.\"]*\\="
  165. (line-beginning-position) t)))
  166. ;; Use new vars for the font-lock faces. The indirection allows people to
  167. ;; use different faces than in other modes, as before.
  168. (defvar haskell-keyword-face 'font-lock-keyword-face)
  169. (defvar haskell-constructor-face 'font-lock-type-face)
  170. ;; This used to be `font-lock-variable-name-face' but it doesn't result in
  171. ;; a highlighting that's consistent with other modes (it's mostly used
  172. ;; for function defintions).
  173. (defvar haskell-definition-face 'font-lock-function-name-face)
  174. ;; This is probably just wrong, but it used to use
  175. ;; `font-lock-function-name-face' with a result that was not consistent with
  176. ;; other major modes, so I just exchanged with `haskell-definition-face'.
  177. (defvar haskell-operator-face 'font-lock-variable-name-face)
  178. (defvar haskell-default-face nil)
  179. (defvar haskell-literate-comment-face 'font-lock-doc-face
  180. "Face with which to fontify literate comments.
  181. Set to `default' to avoid fontification of them.")
  182. (defconst haskell-emacs21-features (string-match "[[:alpha:]]" "x")
  183. "Non-nil if we have regexp char classes.
  184. Assume this means we have other useful features from Emacs 21.")
  185. (defun haskell-font-lock-compose-symbol (alist)
  186. "Compose a sequence of ascii chars into a symbol.
  187. Regexp match data 0 points to the chars."
  188. ;; Check that the chars should really be composed into a symbol.
  189. (let* ((start (match-beginning 0))
  190. (end (match-end 0))
  191. (syntaxes (cond
  192. ((eq (char-syntax (char-after start)) ?w) '(?w))
  193. ;; Special case for the . used for qualified names.
  194. ((and (eq (char-after start) ?\.) (= end (1+ start)))
  195. '(?_ ?\\ ?w))
  196. (t '(?_ ?\\))))
  197. sym-data)
  198. (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
  199. (memq (char-syntax (or (char-after end) ?\ )) syntaxes)
  200. (memq (get-text-property start 'face)
  201. '(font-lock-doc-face font-lock-string-face
  202. font-lock-comment-face))
  203. (and (consp (setq sym-data (cdr (assoc (match-string 0) alist))))
  204. (let ((pred (cadr sym-data)))
  205. (setq sym-data (car sym-data))
  206. (funcall pred start))))
  207. ;; No composition for you. Let's actually remove any composition
  208. ;; we may have added earlier and which is now incorrect.
  209. (remove-text-properties start end '(composition))
  210. ;; That's a symbol alright, so add the composition.
  211. (compose-region start end sym-data)))
  212. ;; Return nil because we're not adding any face property.
  213. nil)
  214. (unless (fboundp 'char-displayable-p)
  215. (require 'latin1-disp nil t))
  216. (defun haskell-font-lock-symbols-keywords ()
  217. (when (fboundp 'compose-region)
  218. (let ((alist nil))
  219. (dolist (x haskell-font-lock-symbols-alist)
  220. (when (and (if (fboundp 'char-displayable-p)
  221. (char-displayable-p (if (consp (cdr x)) (cadr x) (cdr x)))
  222. (if (fboundp 'latin1-char-displayable-p)
  223. (latin1-char-displayable-p (if (consp (cdr x))
  224. (cadr x)
  225. (cdr x)))
  226. t))
  227. (not (assoc (car x) alist))) ;Not yet in alist.
  228. (push x alist)))
  229. (when alist
  230. `((,(regexp-opt (mapcar 'car alist) t)
  231. (0 (haskell-font-lock-compose-symbol ',alist)
  232. ;; In Emacs-21, if the `override' field is nil, the face
  233. ;; expressions is only evaluated if the text has currently
  234. ;; no face. So force evaluation by using `keep'.
  235. keep)))))))
  236. ;; The font lock regular expressions.
  237. (defun haskell-font-lock-keywords-create (literate)
  238. "Create fontification definitions for Haskell scripts.
  239. Returns keywords suitable for `font-lock-keywords'."
  240. (let* (;; Bird-style literate scripts start a line of code with
  241. ;; "^>", otherwise a line of code starts with "^".
  242. (line-prefix (if (eq literate 'bird) "^> ?" "^"))
  243. ;; Most names are borrowed from the lexical syntax of the Haskell
  244. ;; report.
  245. ;; Some of these definitions have been superseded by using the
  246. ;; syntax table instead.
  247. ;; (ASCsymbol "-!#$%&*+./<=>?@\\\\^|~")
  248. ;; Put the minus first to make it work in ranges.
  249. ;; We allow _ as the first char to fit GHC
  250. (varid "\\b[[:lower:]_][[:alnum:]'_]*\\b")
  251. (conid "\\b[[:upper:]][[:alnum:]'_]*\\b")
  252. (modid (concat "\\b" conid "\\(\\." conid "\\)*\\b"))
  253. (qvarid (concat modid "\\." varid))
  254. (qconid (concat modid "\\." conid))
  255. (sym
  256. ;; We used to use the below for non-Emacs21, but I think the
  257. ;; regexp based on syntax works for other emacsen as well. -- Stef
  258. ;; (concat "[" symbol ":]+")
  259. ;; Add backslash to the symbol-syntax chars. This seems to
  260. ;; be thrown for some reason by backslash's escape syntax.
  261. "\\(\\s_\\|\\\\\\)+")
  262. ;; Reserved operations
  263. (reservedsym
  264. (concat "\\S_"
  265. ;; (regexp-opt '(".." "::" "=" "\\" "|" "<-" "->"
  266. ;; "@" "~" "=>") t)
  267. "\\(->\\|\\.\\.\\|::\\|?\\|<-\\|=>\\|[=@\\|~]\\)"
  268. "\\S_"))
  269. ;; Reserved identifiers
  270. (reservedid
  271. (concat "\\<"
  272. ;; `as', `hiding', and `qualified' are part of the import
  273. ;; spec syntax, but they are not reserved.
  274. ;; `_' can go in here since it has temporary word syntax.
  275. ;; (regexp-opt
  276. ;; '("case" "class" "data" "default" "deriving" "do"
  277. ;; "else" "if" "import" "in" "infix" "infixl"
  278. ;; "infixr" "instance" "let" "module" "newtype" "of"
  279. ;; "then" "type" "where" "_") t)
  280. "\\(_\\|c\\(ase\\|lass\\)\\|d\\(ata\\|e\\(fault\\|riving\\)\\|o\\)\\|else\\|i\\(mport\\|n\\(fix[lr]?\\|stance\\)\\|[fn]\\)\\|let\\|module\\|newtype\\|of\\|t\\(hen\\|ype\\)\\|where\\)"
  281. "\\>"))
  282. ;; This unreadable regexp matches strings and character
  283. ;; constants. We need to do this with one regexp to handle
  284. ;; stuff like '"':"'". The regexp is the composition of
  285. ;; "([^"\\]|\\.)*" for strings and '([^\\]|\\.[^']*)' for
  286. ;; characters, allowing for string continuations.
  287. ;; Could probably be improved...
  288. (string-and-char
  289. (concat "\\(\\(\"\\|" line-prefix "[ \t]*\\\\\\)\\([^\"\\\\\n]\\|\\\\.\\)*\\(\"\\|\\\\[ \t]*$\\)\\|'\\([^'\\\\\n]\\|\\\\.[^'\n]*\\)'\\)"))
  290. ;; Top-level declarations
  291. (topdecl-var
  292. (concat line-prefix "\\(" varid "\\)\\s-*\\("
  293. ;; A toplevel declaration can be followed by a definition
  294. ;; (=), a type (::) or (?), a guard, or a pattern which can
  295. ;; either be a variable, a constructor, a parenthesized
  296. ;; thingy, or an integer or a string.
  297. varid "\\|" conid "\\|::\\|?\\|=\\||\\|\\s(\\|[0-9\"']\\)"))
  298. (topdecl-var2
  299. (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`"))
  300. (topdecl-sym
  301. (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)"))
  302. (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))"))
  303. keywords)
  304. (setq keywords
  305. `(;; NOTICE the ordering below is significant
  306. ;;
  307. ("^#.*$" 0 'font-lock-warning-face t)
  308. ,@(unless haskell-emacs21-features ;Supports nested comments?
  309. ;; Expensive.
  310. `((,string-and-char 1 font-lock-string-face)))
  311. ;; This was originally at the very end (and needs to be after
  312. ;; all the comment/string/doc highlighting) but it seemed to
  313. ;; trigger a bug in Emacs-21.3 which caused the compositions to
  314. ;; be "randomly" dropped. Moving it earlier seemed to reduce
  315. ;; the occurrence of the bug.
  316. ,@(haskell-font-lock-symbols-keywords)
  317. (,reservedid 1 (symbol-value 'haskell-keyword-face))
  318. (,reservedsym 1 (symbol-value 'haskell-operator-face))
  319. ;; Special case for `as', `hiding', and `qualified', which are
  320. ;; keywords in import statements but are not otherwise reserved.
  321. ("\\<import[ \t]+\\(?:\\(qualified\\>\\)[ \t]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?"
  322. (1 (symbol-value 'haskell-keyword-face) nil lax)
  323. (2 (symbol-value 'haskell-keyword-face) nil lax)
  324. (3 (symbol-value 'haskell-keyword-face) nil lax))
  325. ;; Toplevel Declarations.
  326. ;; Place them *before* generic id-and-op highlighting.
  327. (,topdecl-var (1 (symbol-value 'haskell-definition-face)))
  328. (,topdecl-var2 (2 (symbol-value 'haskell-definition-face)))
  329. (,topdecl-sym (2 (symbol-value 'haskell-definition-face)))
  330. (,topdecl-sym2 (1 (symbol-value 'haskell-definition-face)))
  331. ;; These four are debatable...
  332. ("(\\(,*\\|->\\))" 0 (symbol-value 'haskell-constructor-face))
  333. ("\\[\\]" 0 (symbol-value 'haskell-constructor-face))
  334. ;; Expensive.
  335. (,qvarid 0 (symbol-value 'haskell-default-face))
  336. (,qconid 0 (symbol-value 'haskell-constructor-face))
  337. (,(concat "\`" varid "\`") 0 (symbol-value 'haskell-operator-face))
  338. ;; Expensive.
  339. (,conid 0 (symbol-value 'haskell-constructor-face))
  340. ;; Very expensive.
  341. (,sym 0 (if (eq (char-after (match-beginning 0)) ?:)
  342. haskell-constructor-face
  343. haskell-operator-face))))
  344. (unless (boundp 'font-lock-syntactic-keywords)
  345. (case literate
  346. (bird
  347. (setq keywords
  348. `(("^[^>\n].*$" 0 haskell-comment-face t)
  349. ,@keywords
  350. ("^>" 0 haskell-default-face t))))
  351. ((latex tex)
  352. (setq keywords
  353. `((haskell-fl-latex-comments 0 'font-lock-comment-face t)
  354. ,@keywords)))))
  355. keywords))
  356. ;; The next three aren't used in Emacs 21.
  357. (defvar haskell-fl-latex-cache-pos nil
  358. "Position of cache point used by `haskell-fl-latex-cache-in-comment'.
  359. Should be at the start of a line.")
  360. (defvar haskell-fl-latex-cache-in-comment nil
  361. "If `haskell-fl-latex-cache-pos' is outside a
  362. \\begin{code}..\\end{code} block (and therefore inside a comment),
  363. this variable is set to t, otherwise nil.")
  364. (defun haskell-fl-latex-comments (end)
  365. "Sets `match-data' according to the region of the buffer before end
  366. that should be commented under LaTeX-style literate scripts."
  367. (let ((start (point)))
  368. (if (= start end)
  369. ;; We're at the end. No more to fontify.
  370. nil
  371. (if (not (eq start haskell-fl-latex-cache-pos))
  372. ;; If the start position is not cached, calculate the state
  373. ;; of the start.
  374. (progn
  375. (setq haskell-fl-latex-cache-pos start)
  376. ;; If the previous \begin{code} or \end{code} is a
  377. ;; \begin{code}, then start is not in a comment, otherwise
  378. ;; it is in a comment.
  379. (setq haskell-fl-latex-cache-in-comment
  380. (if (and
  381. (re-search-backward
  382. "^\\(\\(\\\\begin{code}\\)\\|\\(\\\\end{code}\\)\\)$"
  383. (point-min) t)
  384. (match-end 2))
  385. nil t))
  386. ;; Restore position.
  387. (goto-char start)))
  388. (if haskell-fl-latex-cache-in-comment
  389. (progn
  390. ;; If start is inside a comment, search for next \begin{code}.
  391. (re-search-forward "^\\\\begin{code}$" end 'move)
  392. ;; Mark start to end of \begin{code} (if present, till end
  393. ;; otherwise), as a comment.
  394. (set-match-data (list start (point)))
  395. ;; Return point, as a normal regexp would.
  396. (point))
  397. ;; If start is inside a code block, search for next \end{code}.
  398. (if (re-search-forward "^\\\\end{code}$" end t)
  399. ;; If one found, mark it as a comment, otherwise finish.
  400. (point))))))
  401. (defconst haskell-basic-syntactic-keywords
  402. '(;; Character constants (since apostrophe can't have string syntax).
  403. ;; Beware: do not match something like 's-}' or '\n"+' since the first '
  404. ;; might be inside a comment or a string.
  405. ;; This still gets fooled with "'"'"'"'"'"', but ... oh well.
  406. ("\\Sw\\('\\)\\([^\\'\n]\\|\\\\.[^\\'\n \"}]*\\)\\('\\)" (1 "|") (3 "|"))
  407. ;; The \ is not escaping in \(x,y) -> x + y.
  408. ("\\(\\\\\\)(" (1 "."))
  409. ;; The second \ in a gap does not quote the subsequent char.
  410. ;; It's probably not worth the trouble, tho.
  411. ;; ("^[ \t]*\\(\\\\\\)" (1 "."))
  412. ;; Deal with instances of `--' which don't form a comment
  413. ("\\s_\\{3,\\}" (0 (cond ((nth 4 (syntax-ppss))
  414. ;; There are no such instances inside an existing comment
  415. nil)
  416. ((string-match "\\`-*\\'" (match-string 0))
  417. ;; Sequence of hyphens. Do nothing in
  418. ;; case of things like `{---'.
  419. nil)
  420. (t "_")))) ; other symbol sequence
  421. ))
  422. (defconst haskell-bird-syntactic-keywords
  423. (cons '("^[^\n>]" (0 "<"))
  424. haskell-basic-syntactic-keywords))
  425. (defconst haskell-latex-syntactic-keywords
  426. (append
  427. '(("^\\\\begin{code}\\(\n\\)" 1 "!")
  428. ;; Note: buffer is widened during font-locking.
  429. ("\\`\\(.\\|\n\\)" (1 "!")) ; start comment at buffer start
  430. ("^\\(\\\\\\)end{code}$" 1 "!"))
  431. haskell-basic-syntactic-keywords))
  432. (defcustom haskell-font-lock-haddock (boundp 'font-lock-doc-face)
  433. "If non-nil try to highlight Haddock comments specially."
  434. :type 'boolean
  435. :group 'haskell)
  436. (defvar haskell-font-lock-seen-haddock nil)
  437. (make-variable-buffer-local 'haskell-font-lock-seen-haddock)
  438. (defun haskell-syntactic-face-function (state)
  439. "`font-lock-syntactic-face-function' for Haskell."
  440. (cond
  441. ((nth 3 state) font-lock-string-face) ; as normal
  442. ;; Else comment. If it's from syntax table, use default face.
  443. ((or (eq 'syntax-table (nth 7 state))
  444. (and (eq haskell-literate 'bird)
  445. (memq (char-before (nth 8 state)) '(nil ?\n))))
  446. haskell-literate-comment-face)
  447. ;; Try and recognize Haddock comments. From what I gather from its
  448. ;; documentation, its comments can take the following forms:
  449. ;; a) {-| ... -}
  450. ;; b) {-^ ... -}
  451. ;; c) -- | ...
  452. ;; d) -- ^ ...
  453. ;; e) -- ...
  454. ;; Where `e' is the tricky one: it is only a Haddock comment if it
  455. ;; follows immediately another Haddock comment. Even an empty line
  456. ;; breaks such a sequence of Haddock comments. It is not clear if `e'
  457. ;; can follow any other case, so I interpreted it as following only cases
  458. ;; c,d,e (not a or b). In any case, this `e' is expensive since it
  459. ;; requires extra work for each and every non-Haddock comment, so I only
  460. ;; go through the more expensive check if we've already seen a Haddock
  461. ;; comment in the buffer.
  462. ((and haskell-font-lock-haddock
  463. (save-excursion
  464. (goto-char (nth 8 state))
  465. (or (looking-at "\\(-- \\|{-\\)[|^]")
  466. (and haskell-font-lock-seen-haddock
  467. (looking-at "-- ")
  468. (let ((doc nil)
  469. pos)
  470. (while (and (not doc)
  471. (setq pos (line-beginning-position))
  472. (forward-comment -1)
  473. (eq (line-beginning-position 2) pos)
  474. (looking-at "--\\( [|^]\\)?"))
  475. (setq doc (match-beginning 1)))
  476. doc)))))
  477. (set (make-local-variable 'haskell-font-lock-seen-haddock) t)
  478. font-lock-doc-face)
  479. (t font-lock-comment-face)))
  480. (defconst haskell-font-lock-keywords
  481. (haskell-font-lock-keywords-create nil)
  482. "Font lock definitions for non-literate Haskell.")
  483. (defconst haskell-font-lock-bird-literate-keywords
  484. (haskell-font-lock-keywords-create 'bird)
  485. "Font lock definitions for Bird-style literate Haskell.")
  486. (defconst haskell-font-lock-latex-literate-keywords
  487. (haskell-font-lock-keywords-create 'latex)
  488. "Font lock definitions for LaTeX-style literate Haskell.")
  489. (defun haskell-font-lock-choose-keywords ()
  490. (let ((literate (if (boundp 'haskell-literate) haskell-literate)))
  491. (case literate
  492. (bird haskell-font-lock-bird-literate-keywords)
  493. ((latex tex) haskell-font-lock-latex-literate-keywords)
  494. (t haskell-font-lock-keywords))))
  495. (defun haskell-font-lock-choose-syntactic-keywords ()
  496. (let ((literate (if (boundp 'haskell-literate) haskell-literate)))
  497. (case literate
  498. (bird haskell-bird-syntactic-keywords)
  499. ((latex tex) haskell-latex-syntactic-keywords)
  500. (t haskell-basic-syntactic-keywords))))
  501. (defun haskell-font-lock-defaults-create ()
  502. "Locally set `font-lock-defaults' for Haskell."
  503. (set (make-local-variable 'font-lock-defaults)
  504. '(haskell-font-lock-choose-keywords
  505. nil nil ((?\' . "w") (?_ . "w")) nil
  506. (font-lock-syntactic-keywords
  507. . haskell-font-lock-choose-syntactic-keywords)
  508. (font-lock-syntactic-face-function
  509. . haskell-syntactic-face-function)
  510. ;; Get help from font-lock-syntactic-keywords.
  511. (parse-sexp-lookup-properties . t))))
  512. ;; The main functions.
  513. (defun turn-on-haskell-font-lock ()
  514. "Turns on font locking in current buffer for Haskell 1.4 scripts.
  515. Changes the current buffer's `font-lock-defaults', and adds the
  516. following variables:
  517. `haskell-keyword-face' for reserved keywords and syntax,
  518. `haskell-constructor-face' for data- and type-constructors, class names,
  519. and module names,
  520. `haskell-operator-face' for symbolic and alphanumeric operators,
  521. `haskell-default-face' for ordinary code.
  522. The variables are initialised to the following font lock default faces:
  523. `haskell-keyword-face' `font-lock-keyword-face'
  524. `haskell-constructor-face' `font-lock-type-face'
  525. `haskell-operator-face' `font-lock-function-name-face'
  526. `haskell-default-face' <default face>
  527. Two levels of fontification are defined: level one (the default)
  528. and level two (more colour). The former does not colour operators.
  529. Use the variable `font-lock-maximum-decoration' to choose
  530. non-default levels of fontification. For example, adding this to
  531. .emacs:
  532. (setq font-lock-maximum-decoration '((haskell-mode . 2) (t . 0)))
  533. uses level two fontification for `haskell-mode' and default level for
  534. all other modes. See documentation on this variable for further
  535. details.
  536. To alter an attribute of a face, add a hook. For example, to change
  537. the foreground colour of comments to brown, add the following line to
  538. .emacs:
  539. (add-hook 'haskell-font-lock-hook
  540. (lambda ()
  541. (set-face-foreground 'haskell-comment-face \"brown\")))
  542. Note that the colours available vary from system to system. To see
  543. what colours are available on your system, call
  544. `list-colors-display' from emacs.
  545. To turn font locking on for all Haskell buffers, add this to .emacs:
  546. (add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
  547. To turn font locking on for the current buffer, call
  548. `turn-on-haskell-font-lock'. To turn font locking off in the current
  549. buffer, call `turn-off-haskell-font-lock'.
  550. Bird-style literate Haskell scripts are supported: If the value of
  551. `haskell-literate-bird-style' (automatically set by the Haskell mode
  552. of Moss&Thorn) is non-nil, a Bird-style literate script is assumed.
  553. Invokes `haskell-font-lock-hook' if not nil."
  554. (haskell-font-lock-defaults-create)
  555. (run-hooks 'haskell-font-lock-hook)
  556. (turn-on-font-lock))
  557. (defun turn-off-haskell-font-lock ()
  558. "Turns off font locking in current buffer."
  559. (font-lock-mode -1))
  560. ;; Provide ourselves:
  561. (provide 'haskell-font-lock)
  562. ;; arch-tag: 89fd122e-8378-4c7f-83a3-1f49a64e458d
  563. ;;; haskell-font-lock.el ends here