1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
;; Halibut mode for emacs.
;;
;; Tested on GNU emacs 23.2.1.
(defun halibut-mode-font-lock-extend-region ()
(save-excursion
(let (new-beg new-end)
(goto-char font-lock-beg)
(if (re-search-backward "\n[ \t]*\n" nil 1)
(goto-char (match-end 0)))
(setq new-beg (point))
(goto-char font-lock-end)
(re-search-forward "\n[ \t]*\n" nil 1)
(setq new-end (point))
(if (and (= new-beg font-lock-beg) (= new-end font-lock-end))
nil ;; did nothing
(setq font-lock-beg new-beg)
(setq font-lock-end new-end)
t))))
(defun halibut-mode-match-braced-comment (limit)
;; Look for a braced Halibut comment, which starts with \#{ and ends
;; with } but has to skip over matching unescaped braces in between.
(if (not (search-forward "\\#{" limit t))
nil ;; didn't find the introducer string
(let ((start (match-beginning 0))
(depth 1))
(goto-char (match-end 0))
;; Repeatedly find the next unescaped brace and adjust depth.
(while (and (> depth 0)
(looking-at "\\([^\\\\{}]\\|\\\\.\\)*\\([{}]\\)")
(< (match-end 2) limit))
(setq depth (if (string= (match-string 2) "{") (1+ depth) (1- depth)))
(goto-char (match-end 2)))
;; If depth hit zero, we've stopped just after the closing
;; brace. If it didn't, we should stop at limit.
(if (> depth 0) (goto-char limit))
;; Now the string between 'start' and point is our match.
(set-match-data (list start (point)))
t)))
(defun halibut-mode-match-paragraph-comment (limit)
;; Look for a whole-paragraph Halibut comment, which starts with \#
;; and then something other than an open brace, and ends at the next
;; paragraph break.
(catch 'found-one
(while (search-forward "\\#" limit t)
(let ((start (match-beginning 0)))
;; For each \# we find, check to see if it's eligible.
(when (and
;; It must not be followed by {.
(not (looking-at "\\\\#{"))
;; It must be the first thing in its paragraph (either
;; because the chunk of whitespace immediately preceding it
;; contains more than one \n, or because that chunk of
;; whitespace terminates at the beginning of the file).
(let ((this-line (line-number-at-pos)))
(save-excursion
(goto-char start)
(skip-chars-backward "\n\t ")
(or (= (point) (point-min))
(< (line-number-at-pos) (1- this-line))))))
;; If those conditions are satisfied, we've found an
;; eligible \#. Search forward for the next paragraph end.
(if (re-search-forward "\n[ \t]*\n" nil 1)
(goto-char (match-beginning 0)))
;; Now the string between 'start' and point is our match.
(set-match-data (list start (point)))
;; Terminate the while loop.
(throw 'found-one t))))
;; The loop terminated without finding anything.
nil))
(defun halibut-mode-match-code-or-emphasis-line (char limit)
;; Look for a Halibut code line (starting with "\c " or containing
;; only "\c"). Either right here...
(if (and (= (current-column) 0) (looking-at (concat "\\\\" char "[ \n]")))
(let ((start (match-beginning 0)))
(end-of-line)
(set-match-data (list start (min limit (point))))
t)
;; ... or further down...
(if (re-search-forward (concat "\n\\\\" char "[ \n]") limit t)
(let ((start (1+ (match-beginning 0))))
(goto-char start)
(end-of-line)
(set-match-data (list start (min limit (point))))
t)
;; and if neither of those, we didn't find one.
nil)))
(defun halibut-mode-match-code-line (limit)
(halibut-mode-match-code-or-emphasis-line "c" limit))
(defun halibut-mode-match-emphasis-line (limit)
(halibut-mode-match-code-or-emphasis-line "e" limit))
(defconst halibut-font-lock-keywords
'((halibut-mode-match-braced-comment . font-lock-comment-face)
(halibut-mode-match-paragraph-comment . font-lock-comment-face)
(halibut-mode-match-code-line . font-lock-string-face)
(halibut-mode-match-emphasis-line . font-lock-preprocessor-face)
("\\\\\\([-{}_\\\\]\\|u[0-9a-fA-F]*\\|[A-Za-tv-z][0-9A-Za-z]*\\)" .
font-lock-keyword-face))
"Syntax highlighting for Halibut mode.")
;;;###autoload
(define-derived-mode halibut-mode fundamental-mode "Halibut"
"Major mode for editing Halibut documentation markup."
(setq font-lock-defaults '(halibut-font-lock-keywords t))
(add-hook 'font-lock-extend-region-functions 'halibut-mode-font-lock-extend-region))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.but\\'" . halibut-mode))
|