;; haskell-c2hs.el --- -*- lexical-binding: t; -*- ;; Copyright (C) 2016 Sergey Vinokurov ;; ;; Author: Sergey Vinokurov ;; Created: Monday, 7 March 2016 ;; This program 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 of the License, or ;; (at your option) any later version. ;; This program 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 . ;;; Commentary: ;; This mode is mostly intended for highlighting {#...#} hooks. ;; ;; Quick setup: ;; (autoload 'haskell-c2hs-mode "haskell-c2hs-mode" nil t) ;; (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) ;; (require 'haskell-mode) (require 'haskell-font-lock) (require 'haskell-utils) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) (defface haskell-c2hs-hook-pair-face '((t (:inherit 'font-lock-preprocessor-face))) "Face for highlighting {#...#} pairs." :group 'haskell) (defface haskell-c2hs-hook-name-face '((t (:inherit 'font-lock-keyword-face))) "Face for highlighting c2hs hook names." :group 'haskell) (defvar haskell-c2hs-font-lock-keywords `((,(eval-when-compile (let* ((ws '(any ?\s ?\t ?\n ?\r)) (anychar '(or (not (any ?#)) (seq "#" (not (any ?\}))))) (any-nonquote '(or (not (any ?# ?\")) (seq "#" (not (any ?\} ?\"))))) (cid '(seq (any (?a . ?z) (?A . ?Z) ?_) (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_)))) (hsid-type '(seq (? "'") (any (?A . ?Z)) (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_ ?')))) (equals-str-val `(seq (* ,ws) "=" (* ,ws) "\"" (* ,any-nonquote) "\""))) (eval `(rx (seq (group-n 1 "{#") (* ,ws) (or (seq (group-n 2 "import" (opt (+ ,ws) "qualified")) (+ ,ws)) (seq (group-n 2 "context") (opt (+ ,ws) (group-n 3 "lib") ,equals-str-val) (opt (+ ,ws) (group-n 4 "prefix") ,equals-str-val) (opt (+ ,ws) (group-n 5 "add" (+ ,ws) "prefix") ,equals-str-val)) (seq (group-n 2 "type") (+ ,ws) ,cid) (seq (group-n 2 "sizeof") (+ ,ws) ,cid) (seq (group-n 2 "enum" (+ ,ws) "define") (+ ,ws) ,cid) ;; TODO: vanilla enum fontification is incomplete (seq (group-n 2 "enum") (+ ,ws) ,cid (opt (+ ,ws) (group-n 3 "as"))) ;; TODO: fun hook highlighting is incompelete (seq (group-n 2 (or "call" "fun") (opt (+ ,ws) "pure") (opt (+ ,ws) "unsafe")) (+ ,ws) ,cid (opt (+ ,ws) (group-n 3 "as") (opt (+ ,ws) (group-n 8 "^")))) (group-n 2 "get") (group-n 2 "set") (seq (group-n 2 "pointer") (or (seq (* ,ws) (group-n 3 "*") (* ,ws)) (+ ,ws)) ,cid (opt (+ ,ws) (group-n 4 "as") (+ ,ws) ,hsid-type) (opt (+ ,ws) (group-n 5 (or "foreign" "stable"))) (opt (or (seq (+ ,ws) (group-n 6 "newtype")) (seq (* ,ws) "->" (* ,ws) ,hsid-type))) (opt (+ ,ws) (group-n 7 "nocode"))) (group-n 2 "class") (group-n 2 "alignof") (group-n 2 "offsetof") (seq (group-n 2 "const") (+ ,ws) ,cid) (seq (group-n 2 "typedef") (+ ,ws) ,cid (+ ,ws) ,hsid-type) (group-n 2 "nonGNU") ;; TODO: default hook not implemented ) (* ,anychar) (group-n 9 "#}")))))) ;; Override highlighting for pairs in order to always distinguish them. (1 'haskell-c2hs-hook-pair-face t) (2 'haskell-c2hs-hook-name-face) ;; Make matches lax, i.e. do not signal error if nothing ;; matched. (3 'haskell-c2hs-hook-name-face nil t) (4 'haskell-c2hs-hook-name-face nil t) (5 'haskell-c2hs-hook-name-face nil t) (6 'haskell-c2hs-hook-name-face nil t) (7 'haskell-c2hs-hook-name-face nil t) (8 'font-lock-negation-char-face nil t) ;; Override highlighting for pairs in order to always distinguish them. (9 'haskell-c2hs-hook-pair-face t)) ,@(haskell-font-lock-keywords))) ;;;###autoload (define-derived-mode haskell-c2hs-mode haskell-mode "C2HS" "Mode for editing *.chs files of the c2hs haskell tool." (setq-local font-lock-defaults (cons 'haskell-c2hs-font-lock-keywords (cdr font-lock-defaults)))) (provide 'haskell-c2hs) ;; haskell-c2hs.el ends here