about summary refs log tree commit diff
path: root/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el
diff options
context:
space:
mode:
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el')
-rw-r--r--configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el711
1 files changed, 711 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el
new file mode 100644
index 0000000000..8360c7dd06
--- /dev/null
+++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el
@@ -0,0 +1,711 @@
+;;; haskell-font-lock.el --- Font locking module for Haskell Mode -*- lexical-binding: t -*-
+
+;; Copyright 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+;; Copyright 1997-1998  Graeme E Moss, and Tommy Thorn
+
+;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
+;;         1997-1998 Tommy Thorn <thorn@irisa.fr>
+;;         2003      Dave Love <fx@gnu.org>
+;; Keywords: faces files Haskell
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'haskell-compat)
+(require 'haskell-lexeme)
+(require 'font-lock)
+
+;;;###autoload
+(defgroup haskell-appearance nil
+  "Haskell Appearance."
+  :group 'haskell)
+
+
+(defcustom haskell-font-lock-symbols nil
+  "Display \\ and -> and such using symbols in fonts.
+
+This may sound like a neat trick, but be extra careful: it changes the
+alignment and can thus lead to nasty surprises with regards to layout."
+  :group 'haskell-appearance
+  :type 'boolean)
+
+(defcustom haskell-font-lock-symbols-alist
+  '(("\\" . "λ")
+    ("not" . "¬")
+    ("->" . "→")
+    ("<-" . "←")
+    ("=>" . "⇒")
+    ("()" . "∅")
+    ("==" . "≡")
+    ("/=" . "≢")
+    (">=" . "≥")
+    ("<=" . "≤")
+    ("!!" . "‼")
+    ("&&" . "∧")
+    ("||" . "∨")
+    ("sqrt" . "√")
+    ("undefined" . "⊥")
+    ("pi" . "π")
+    ("~>" . "⇝") ;; Omega language
+    ;; ("~>" "↝") ;; less desirable
+    ("-<" . "↢") ;; Paterson's arrow syntax
+    ;; ("-<" "⤙") ;; nicer but uncommon
+    ("::" . "∷")
+    ("." "∘" ; "○"
+     ;; Need a predicate here to distinguish the . used by
+     ;; forall <foo> . <bar>.
+     haskell-font-lock-dot-is-not-composition)
+    ("forall" . "∀"))
+  "Alist mapping Haskell symbols to chars.
+
+Each element has the form (STRING . COMPONENTS) or (STRING
+COMPONENTS PREDICATE).
+
+STRING is the Haskell symbol.
+COMPONENTS is a representation specification suitable as an argument to
+`compose-region'.
+PREDICATE if present is a function of one argument (the start position
+of the symbol) which should return non-nil if this mapping should
+be disabled at that position."
+  :type '(alist string string)
+  :group 'haskell-appearance)
+
+(defcustom haskell-font-lock-keywords
+  ;; `as', `hiding', and `qualified' are part of the import
+  ;; spec syntax, but they are not reserved.
+  ;; `_' can go in here since it has temporary word syntax.
+  '("case" "class" "data" "default" "deriving" "do"
+    "else" "if" "import" "in" "infix" "infixl"
+    "infixr" "instance" "let" "module" "mdo" "newtype" "of"
+    "rec" "pattern" "proc" "signature" "then" "type" "where" "_")
+  "Identifiers treated as reserved keywords in Haskell."
+  :group 'haskell-appearance
+  :type '(repeat string))
+
+
+(defun haskell-font-lock-dot-is-not-composition (start)
+  "Return non-nil if the \".\" at START is not a composition operator.
+This is the case if the \".\" is part of a \"forall <tvar> . <type>\"."
+  (save-excursion
+    (goto-char start)
+    (or (re-search-backward "\\<forall\\>[^.\"]*\\="
+                            (line-beginning-position) t)
+        (not (or
+              (string= " " (string (char-after start)))
+              (null (char-before start))
+              (string= " " (string (char-before start))))))))
+
+(defvar haskell-yesod-parse-routes-mode-keywords
+  '(("^\\([^ \t\n]+\\)\\(?:[ \t]+\\([^ \t\n]+\\)\\)?"
+     (1 'font-lock-string-face)
+     (2 'haskell-constructor-face nil lax))))
+
+(define-derived-mode haskell-yesod-parse-routes-mode text-mode "Yesod parseRoutes mode"
+  "Mode for parseRoutes from Yesod."
+  (setq-local font-lock-defaults '(haskell-yesod-parse-routes-mode-keywords t t nil nil)))
+
+(defcustom haskell-font-lock-quasi-quote-modes
+  `(("hsx" . xml-mode)
+    ("hamlet" . shakespeare-hamlet-mode)
+    ("shamlet" . shakespeare-hamlet-mode)
+    ("whamlet" . shakespeare-hamlet-mode)
+    ("xmlQQ" . xml-mode)
+    ("xml" . xml-mode)
+    ("cmd" . shell-mode)
+    ("sh_" . shell-mode)
+    ("jmacro" . javascript-mode)
+    ("jmacroE" . javascript-mode)
+    ("r" . ess-mode)
+    ("rChan" . ess-mode)
+    ("sql" . sql-mode)
+    ("json" . json-mode)
+    ("aesonQQ" . json-mode)
+    ("parseRoutes" . haskell-yesod-parse-routes-mode))
+  "Mapping from quasi quoter token to fontification mode.
+
+If a quasi quote is seen in Haskell code its contents will have
+font faces assigned as if respective mode was enabled."
+  :group 'haskell-appearance
+  :type '(repeat (cons string symbol)))
+
+;;;###autoload
+(defface haskell-keyword-face
+  '((t :inherit font-lock-keyword-face))
+  "Face used to highlight Haskell keywords."
+  :group 'haskell-appearance)
+
+;;;###autoload
+(defface haskell-type-face
+  '((t :inherit font-lock-type-face))
+  "Face used to highlight Haskell types"
+  :group 'haskell-appearance)
+
+;;;###autoload
+(defface haskell-constructor-face
+  '((t :inherit font-lock-type-face))
+  "Face used to highlight Haskell constructors."
+  :group 'haskell-appearance)
+
+;; This used to be `font-lock-variable-name-face' but it doesn't result in
+;; a highlighting that's consistent with other modes (it's mostly used
+;; for function defintions).
+(defface haskell-definition-face
+  '((t :inherit font-lock-function-name-face))
+  "Face used to highlight Haskell definitions."
+  :group 'haskell-appearance)
+
+;; This is probably just wrong, but it used to use
+;; `font-lock-function-name-face' with a result that was not consistent with
+;; other major modes, so I just exchanged with `haskell-definition-face'.
+;;;###autoload
+(defface haskell-operator-face
+  '((t :inherit font-lock-variable-name-face))
+  "Face used to highlight Haskell operators."
+  :group 'haskell-appearance)
+
+;;;###autoload
+(defface haskell-pragma-face
+  '((t :inherit font-lock-preprocessor-face))
+  "Face used to highlight Haskell pragmas ({-# ... #-})."
+  :group 'haskell-appearance)
+
+;;;###autoload
+(defface haskell-liquid-haskell-annotation-face
+  '((t :inherit haskell-pragma-face))
+  "Face used to highlight LiquidHaskell annotations ({-@ ... @-})."
+  :group 'haskell-appearance)
+
+;;;###autoload
+(defface haskell-literate-comment-face
+  '((t :inherit font-lock-doc-face))
+  "Face with which to fontify literate comments.
+Inherit from `default' to avoid fontification of them."
+  :group 'haskell-appearance)
+
+(defface haskell-quasi-quote-face
+  '((t :inherit font-lock-string-face))
+  "Generic face for quasiquotes.
+
+Some quote types are fontified according to other mode defined in
+`haskell-font-lock-quasi-quote-modes'."
+  :group 'haskell-appearance)
+
+(defun haskell-font-lock-compose-symbol (alist)
+  "Compose a sequence of ascii chars into a symbol.
+Regexp match data 0 points to the chars."
+  ;; Check that the chars should really be composed into a symbol.
+  (let* ((start (match-beginning 0))
+         (end (match-end 0))
+         (syntaxes (cond
+                    ((eq (char-syntax (char-after start)) ?w) '(?w))
+                    ((eq (char-syntax (char-after start)) ?.) '(?.))
+                    ;; Special case for the . used for qualified names.
+                    ((and (eq (char-after start) ?\.) (= end (1+ start)))
+                     '(?_ ?\\ ?w))
+                    (t '(?_ ?\\))))
+         sym-data)
+    (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
+            (memq (char-syntax (or (char-after end) ?\ )) syntaxes)
+            (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))
+            (and (consp (setq sym-data (cdr (assoc (match-string 0) alist))))
+                 (let ((pred (cadr sym-data)))
+                   (setq sym-data (car sym-data))
+                   (funcall pred start))))
+        ;; No composition for you.  Let's actually remove any composition
+        ;; we may have added earlier and which is now incorrect.
+        (remove-text-properties start end '(composition))
+      ;; That's a symbol alright, so add the composition.
+      (compose-region start end sym-data)))
+  ;; Return nil because we're not adding any face property.
+  nil)
+
+(defun haskell-font-lock-symbols-keywords ()
+  (when (and haskell-font-lock-symbols
+             haskell-font-lock-symbols-alist)
+    `((,(regexp-opt (mapcar 'car haskell-font-lock-symbols-alist) t)
+       (0 (haskell-font-lock-compose-symbol ',haskell-font-lock-symbols-alist)
+          ;; In Emacs-21, if the `override' field is nil, the face
+          ;; expressions is only evaluated if the text has currently
+          ;; no face.  So force evaluation by using `keep'.
+          keep)))))
+
+(defun haskell-font-lock--forward-type (&optional ignore)
+  "Find where does this type declaration end.
+
+Moves the point to the end of type declaration. It should be
+invoked with point just after one of type introducing keywords
+like ::, class, instance, data, newtype, type."
+  (interactive)
+  (let ((cont t)
+        (end (point))
+        (token nil)
+        ;; we are starting right after ::
+        (last-token-was-operator t)
+        (last-token-was-newline nil)
+        (open-parens 0))
+    (while cont
+      (setq token (haskell-lexeme-looking-at-token 'newline))
+
+      (cond
+       ((null token)
+        (setq cont nil))
+       ((member token '(newline))
+        (setq last-token-was-newline (not last-token-was-operator))
+        (setq end (match-end 0))
+        (goto-char (match-end 0)))
+       ((member (match-string-no-properties 0)
+                    '(")" "]" "}"))
+        (setq open-parens (1- open-parens))
+        (if (< open-parens 0)
+            ;; unmatched closing parenthesis closes type declaration
+            (setq cont nil)
+          (setq end (match-end 0))
+          (goto-char end))
+        (setq last-token-was-newline nil))
+       ((and (member (match-string-no-properties 0)
+                     '("," ";" "|"))
+             (not (member (match-string-no-properties 0) ignore)))
+        (if (equal 0 open-parens)
+            (setq cont nil)
+          (setq last-token-was-operator t)
+          (setq end (match-end 0))
+          (goto-char end))
+        (setq last-token-was-newline nil))
+       ((and (or (member (match-string-no-properties 0)
+                         '("<-" "=" "←"))
+                 (member (match-string-no-properties 0) haskell-font-lock-keywords))
+             (not (member (match-string-no-properties 0) ignore)))
+        (setq cont nil)
+        (setq last-token-was-newline nil))
+       ((member (match-string-no-properties 0)
+                '("(" "[" "{"))
+        (if last-token-was-newline
+            (setq cont nil)
+          (setq open-parens (1+ open-parens))
+          (setq end (match-end 0))
+          (goto-char end)
+          (setq last-token-was-newline nil)))
+       ((member token '(qsymid char string number template-haskell-quote template-haskell-quasi-quote))
+        (setq last-token-was-operator (member (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1)))
+                                              '(varsym consym)))
+        (if (and (not last-token-was-operator) last-token-was-newline)
+            (setq cont nil)
+
+          (goto-char (match-end 0))
+          (setq end (point)))
+        (setq last-token-was-newline nil))
+       ((member token '(comment nested-comment literate-comment))
+        (goto-char (match-end 0))
+        (setq end (point)))
+       (t
+        (goto-char (match-end 0))
+        (setq end (point))
+        (setq last-token-was-newline nil))))
+    (goto-char end)))
+
+
+(defun haskell-font-lock--select-face-on-type-or-constructor ()
+  "Private function used to select either type or constructor face
+on an uppercase identifier."
+  (cl-case (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1)))
+    (varid (let ((word (match-string-no-properties 0)))
+             (cond
+              ((member word haskell-font-lock-keywords)
+               ;; Note: keywords parse as keywords only when not qualified.
+               ;; GHC parses Control.let as a single but illegal lexeme.
+               (when (member word '("class" "instance" "type" "data" "newtype"))
+                 (save-excursion
+                   (goto-char (match-end 0))
+                   (save-match-data
+                     (haskell-font-lock--forward-type
+                      (cond
+                       ((member word '("class" "instance"))
+                        '("|"))
+                       ((member word '("type"))
+                        ;; Need to support 'type instance'
+                        '("=" "instance")))))
+                   (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t))))
+               'haskell-keyword-face)
+              ((member word '("forall"))
+               (when (get-text-property (match-beginning 0) 'haskell-type)
+                 'haskell-keyword-face)))))
+    (conid (if (get-text-property (match-beginning 0) 'haskell-type)
+               'haskell-type-face
+             'haskell-constructor-face))
+    (varsym (unless (and (member (match-string 0) '("-" "+" "."))
+                         (equal (string-to-syntax "w") (syntax-after (match-beginning 0))))
+              ;; We need to protect against the case of
+              ;; plus, minus or dot inside a floating
+              ;; point number.
+              'haskell-operator-face))
+    (consym (if (not (member (match-string 1) '("::" "∷")))
+                (if (get-text-property (match-beginning 0) 'haskell-type)
+                    'haskell-type-face
+                  'haskell-constructor-face)
+              (save-excursion
+                (goto-char (match-end 0))
+                (save-match-data
+                  (haskell-font-lock--forward-type))
+                (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t)))
+              'haskell-operator-face))))
+
+(defun haskell-font-lock--put-face-on-type-or-constructor ()
+  "Private function used to put either type or constructor face
+on an uppercase identifier."
+  (let ((face (haskell-font-lock--select-face-on-type-or-constructor)))
+    (when (and face
+               (not (text-property-not-all (match-beginning 0) (match-end 0) 'face nil)))
+      (put-text-property (match-beginning 0) (match-end 0) 'face face))))
+
+
+(defun haskell-font-lock-keywords ()
+  ;; this has to be a function because it depends on global value of
+  ;; `haskell-font-lock-symbols'
+  "Generate font lock eywords."
+  (let* (;; Bird-style literate scripts start a line of code with
+         ;; "^>", otherwise a line of code starts with "^".
+         (line-prefix "^\\(?:> ?\\)?")
+
+         (varid "[[:lower:]_][[:alnum:]'_]*")
+         ;; We allow ' preceding conids because of DataKinds/PolyKinds
+         (conid "'?[[:upper:]][[:alnum:]'_]*")
+         (sym "\\s.+")
+
+         ;; Top-level declarations
+         (topdecl-var
+          (concat line-prefix "\\(" varid "\\(?:\\s-*,\\s-*" varid "\\)*" "\\)"
+                  ;; optionally allow for a single newline after identifier
+                  "\\(\\s-+\\|\\s-*[\n]\\s-+\\)"
+                  ;; A toplevel declaration can be followed by a definition
+                  ;; (=), a type (::) or (∷), a guard, or a pattern which can
+                  ;; either be a variable, a constructor, a parenthesized
+                  ;; thingy, or an integer or a string.
+                  "\\(" varid "\\|" conid "\\|::\\|∷\\|=\\||\\|\\s(\\|[0-9\"']\\)"))
+         (topdecl-var2
+          (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`"))
+         (topdecl-bangpat
+          (concat line-prefix "\\(" varid "\\)\\s-*!"))
+         (topdecl-sym
+          (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)"))
+         (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))"))
+
+         keywords)
+
+    (setq keywords
+          `(;; NOTICE the ordering below is significant
+            ;;
+            ("^#\\(?:[^\\\n]\\|\\\\\\(?:.\\|\n\\|\\'\\)\\)*\\(?:\n\\|\\'\\)" 0 'font-lock-preprocessor-face t)
+
+            ,@(haskell-font-lock-symbols-keywords)
+
+            ;; Special case for `as', `hiding', `safe' and `qualified', which are
+            ;; keywords in import statements but are not otherwise reserved.
+            ("\\<import[ \t]+\\(?:\\(safe\\>\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?\\(?:\"[^\"]*\"[\t ]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?"
+             (1 'haskell-keyword-face nil lax)
+             (2 'haskell-keyword-face nil lax)
+             (3 'haskell-keyword-face nil lax)
+             (4 'haskell-keyword-face nil lax))
+
+            ;; Special case for `foreign import'
+            ;; keywords in foreign import statements but are not otherwise reserved.
+            ("\\<\\(foreign\\)[ \t]+\\(import\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?\\(?:\\(safe\\|unsafe\\|interruptible\\)[ \t]+\\)?"
+             (1 'haskell-keyword-face nil lax)
+             (2 'haskell-keyword-face nil lax)
+             (3 'haskell-keyword-face nil lax)
+             (4 'haskell-keyword-face nil lax))
+
+            ;; Special case for `foreign export'
+            ;; keywords in foreign export statements but are not otherwise reserved.
+            ("\\<\\(foreign\\)[ \t]+\\(export\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?"
+             (1 'haskell-keyword-face nil lax)
+             (2 'haskell-keyword-face nil lax)
+             (3 'haskell-keyword-face nil lax))
+
+            ;; Special case for `type family' and `data family'.
+            ;; `family' is only reserved in these contexts.
+            ("\\<\\(type\\|data\\)[ \t]+\\(family\\>\\)"
+             (1 'haskell-keyword-face nil lax)
+             (2 'haskell-keyword-face nil lax))
+
+            ;; Special case for `type role'
+            ;; `role' is only reserved in this context.
+            ("\\<\\(type\\)[ \t]+\\(role\\>\\)"
+             (1 'haskell-keyword-face nil lax)
+             (2 'haskell-keyword-face nil lax))
+
+            ;; Toplevel Declarations.
+            ;; Place them *before* generic id-and-op highlighting.
+            (,topdecl-var  (1 (unless (member (match-string 1) haskell-font-lock-keywords)
+                                'haskell-definition-face)))
+            (,topdecl-var2 (2 (unless (member (match-string 2) haskell-font-lock-keywords)
+                                'haskell-definition-face)))
+            (,topdecl-bangpat  (1 (unless (member (match-string 1) haskell-font-lock-keywords)
+                                'haskell-definition-face)))
+            (,topdecl-sym  (2 (unless (member (match-string 2) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`"))
+                                'haskell-definition-face)))
+            (,topdecl-sym2 (1 (unless (member (match-string 1) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`"))
+                                'haskell-definition-face)))
+
+            ;; These four are debatable...
+            ("(\\(,*\\|->\\))" 0 'haskell-constructor-face)
+            ("\\[\\]" 0 'haskell-constructor-face)
+
+            ("`"
+             (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))
+                    (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss)
+                                        'syntax-table)
+                  (when (save-excursion
+                          (goto-char (match-beginning 0))
+                          (haskell-lexeme-looking-at-backtick))
+                    (goto-char (match-end 0))
+                    (unless (text-property-not-all (match-beginning 1) (match-end 1) 'face nil)
+                      (put-text-property (match-beginning 1) (match-end 1) 'face 'haskell-operator-face))
+                    (unless (text-property-not-all (match-beginning 2) (match-end 2) 'face nil)
+                      (put-text-property (match-beginning 2) (match-end 2) 'face 'haskell-operator-face))
+                    (unless (text-property-not-all (match-beginning 4) (match-end 4) 'face nil)
+                      (put-text-property (match-beginning 4) (match-end 4) 'face 'haskell-operator-face))
+                    (add-text-properties
+                     (match-beginning 0) (match-end 0)
+                     '(font-lock-fontified t fontified t font-lock-multiline t))))))
+
+            (,haskell-lexeme-idsym-first-char
+             (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))
+                    (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss)
+                                        'syntax-table)
+                  (when (save-excursion
+                          (goto-char (match-beginning 0))
+                          (haskell-lexeme-looking-at-qidsym))
+                    (goto-char (match-end 0))
+                    ;; note that we have to put face ourselves here because font-lock
+                    ;; will use match data from the original matcher
+                    (haskell-font-lock--put-face-on-type-or-constructor)))))))
+    keywords))
+
+
+(defun haskell-font-lock-fontify-block (lang-mode start end)
+  "Fontify a block as LANG-MODE."
+  (let ((string (buffer-substring-no-properties start end))
+        (modified (buffer-modified-p))
+        (org-buffer (current-buffer)) pos next)
+    (remove-text-properties start end '(face nil))
+    (with-current-buffer
+        (get-buffer-create
+         (concat " haskell-font-lock-fontify-block:" (symbol-name lang-mode)))
+      (delete-region (point-min) (point-max))
+      (insert string " ") ;; so there's a final property change
+      (cl-letf (((symbol-function 'message)
+                 (lambda (_fmt &rest _args))))
+        ;; silence messages
+        (unless (eq major-mode lang-mode) (funcall lang-mode))
+        (font-lock-ensure))
+      (setq pos (point-min))
+      (while (setq next (next-single-property-change pos 'face))
+        (put-text-property
+         (+ start (1- pos)) (1- (+ start next)) 'face
+         (or (get-text-property pos 'face) 'default) org-buffer)
+        (setq pos next))
+      (unless (equal pos (point-max))
+        (put-text-property
+         (+ start (1- pos)) (1- (+ start (point-max))) 'face
+         'default org-buffer)))
+    (add-text-properties
+     start end
+     '(font-lock-fontified t fontified t font-lock-multiline t))
+    (set-buffer-modified-p modified)))
+
+(defun haskell-syntactic-face-function (state)
+  "`font-lock-syntactic-face-function' for Haskell."
+  (cond
+   ((nth 3 state)
+    (if (equal ?| (nth 3 state))
+        ;; find out what kind of QuasiQuote is this
+        (let* ((qqname (save-excursion
+                        (goto-char (nth 8 state))
+                        (skip-syntax-backward "w._")
+                        (buffer-substring-no-properties (point) (nth 8 state))))
+               (lang-mode (cdr (assoc qqname haskell-font-lock-quasi-quote-modes))))
+
+          (if (and lang-mode
+                   (fboundp lang-mode))
+              (save-excursion
+                ;; find the end of the QuasiQuote
+                (parse-partial-sexp (point) (point-max) nil nil state
+                                    'syntax-table)
+                (haskell-font-lock-fontify-block lang-mode (1+ (nth 8 state)) (1- (point)))
+                ;; must return nil here so that it is not fontified again as string
+                nil)
+            ;; fontify normally as string because lang-mode is not present
+            'haskell-quasi-quote-face))
+      (save-excursion
+        (let
+            ((state2
+              (parse-partial-sexp (point) (point-max) nil nil state
+                                  'syntax-table))
+             (end-of-string (point)))
+
+          (put-text-property (nth 8 state) (point)
+                             'face 'font-lock-string-face)
+
+
+          (if (or (equal t (nth 3 state)) (nth 3 state2))
+              ;; This is an unterminated string constant, use warning
+              ;; face for the opening quote.
+              (put-text-property (nth 8 state) (1+ (nth 8 state))
+                                 'face 'font-lock-warning-face))
+
+          (goto-char (1+ (nth 8 state)))
+          (while (re-search-forward "\\\\" end-of-string t)
+
+            (goto-char (1- (point)))
+
+            (if (looking-at haskell-lexeme-string-literal-inside-item)
+                (goto-char (match-end 0))
+
+              ;; We are looking at an unacceptable escape
+              ;; sequence. Use warning face to highlight that.
+              (put-text-property (point) (1+ (point))
+                                 'face 'font-lock-warning-face)
+              (goto-char (1+ (point)))))))
+      ;; must return nil here so that it is not fontified again as string
+      nil))
+   ;; Detect literate comment lines starting with syntax class '<'
+   ((save-excursion
+      (goto-char (nth 8 state))
+      (equal (string-to-syntax "<") (syntax-after (point))))
+    'haskell-literate-comment-face)
+   ;; Detect pragmas. A pragma is enclosed in special comment
+   ;; delimiters {-# .. #-}.
+   ((save-excursion
+      (goto-char (nth 8 state))
+      (and (looking-at-p "{-#")
+           (forward-comment 1)
+           (goto-char (- (point) 3))
+           (looking-at-p "#-}")))
+    'haskell-pragma-face)
+   ;; Detect Liquid Haskell annotations enclosed in special comment
+   ;; delimiters {-@ .. @-}.
+   ((save-excursion
+      (goto-char (nth 8 state))
+      (and (looking-at-p "{-@")
+           (forward-comment 1)
+           (goto-char (- (point) 3))
+           (looking-at-p "@-}")))
+    'haskell-liquid-haskell-annotation-face)
+   ;; Haddock comment start with either "-- [|^*$]" or "{- ?[|^*$]"
+   ;; (note space optional for nested comments and mandatory for
+   ;; double dash comments).
+   ;;
+   ;; Haddock comment will also continue on next line, provided:
+   ;; - current line is a double dash haddock comment
+   ;; - next line is also double dash comment
+   ;; - there is only whitespace between
+   ;;
+   ;; We recognize double dash haddock comments by property
+   ;; 'font-lock-doc-face attached to newline. In case of {- -}
+   ;; comments newline is outside of comment.
+   ((save-excursion
+      (goto-char (nth 8 state))
+      (or (looking-at-p "\\(?:{- ?\\|-- \\)[|^*$]")
+          (and (looking-at-p "--")            ; are we at double dash comment
+               (forward-line -1)              ; this is nil on first line
+               (eq (get-text-property (line-end-position) 'face)
+                   'font-lock-doc-face)       ; is a doc face
+               (forward-line)
+               (skip-syntax-forward "-")      ; see if there is only whitespace
+               (eq (point) (nth 8 state)))))  ; we are back in position
+    ;; Here we look inside the comment to see if there are substrings
+    ;; worth marking inside we try to emulate as much of haddock as
+    ;; possible.  First we add comment face all over the comment, then
+    ;; we add special features.
+    (let ((beg (nth 8 state))
+          (end (save-excursion
+                 (parse-partial-sexp (point) (point-max) nil nil state
+                                     'syntax-table)
+                 (point)))
+          (emphasis-open-point nil)
+          (strong-open-point nil))
+      (put-text-property beg end 'face 'font-lock-doc-face)
+
+      (when (fboundp 'add-face-text-property)
+        ;; `add-face-text-property' is not defined in Emacs 23
+
+        ;; iterate over chars, take escaped chars unconditionally
+        ;; mark when a construct is opened, close and face it when
+        ;; it is closed
+
+        (save-excursion
+          (while (< (point) end)
+            (if (looking-at "__\\|\\\\.\\|\\\n\\|[/]")
+                (progn
+                  (cond
+                   ((equal (match-string 0) "/")
+                    (if emphasis-open-point
+                        (progn
+                          (add-face-text-property emphasis-open-point (match-end 0)
+                                                  '(:slant italic))
+                          (setq emphasis-open-point nil))
+                      (setq emphasis-open-point (point))))
+                   ((equal (match-string 0) "__")
+                    (if strong-open-point
+                        (progn
+                          (add-face-text-property strong-open-point (match-end 0)
+                                                  '(:weight bold))
+                          (setq strong-open-point nil))
+                      (setq strong-open-point (point))))
+                   (t
+                    ;; this is a backslash escape sequence, skip over it
+                    ))
+                  (goto-char (match-end 0)))
+              ;; skip chars that are not interesting
+              (goto-char (1+ (point)))
+              (skip-chars-forward "^_\\\\/" end))))))
+    nil)
+   (t 'font-lock-comment-face)))
+
+(defun haskell-font-lock-defaults-create ()
+  "Locally set `font-lock-defaults' for Haskell."
+  (setq-local font-lock-defaults
+              '((haskell-font-lock-keywords)
+                nil nil nil nil
+                (font-lock-syntactic-face-function
+                 . haskell-syntactic-face-function)
+                ;; Get help from font-lock-syntactic-keywords.
+                (parse-sexp-lookup-properties . t)
+                (font-lock-extra-managed-props . (composition)))))
+
+(defun haskell-fontify-as-mode (text mode)
+  "Fontify TEXT as MODE, returning the fontified text."
+  (with-temp-buffer
+    (funcall mode)
+    (insert text)
+    (if (fboundp 'font-lock-ensure)
+        (font-lock-ensure)
+      (with-no-warnings (font-lock-fontify-buffer)))
+    (buffer-substring (point-min) (point-max))))
+
+;; Provide ourselves:
+
+(provide 'haskell-font-lock)
+
+;; Local Variables:
+;; coding: utf-8-unix
+;; tab-width: 8
+;; End:
+
+;;; haskell-font-lock.el ends here