PageRenderTime 45ms CodeModel.GetById 18ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/vendor/haskell-mode/haskell-cabal.el

http://github.com/rejeep/emacs
Emacs Lisp | 183 lines | 87 code | 28 blank | 68 comment | 1 complexity | a4ed4316e6c8346d104682c32ac81437 MD5 | raw file
  1;;; haskell-cabal.el --- Support for Cabal packages
  2
  3;; Copyright (C) 2007, 2008  Stefan Monnier
  4
  5;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
  6
  7;; This file is free software; you can redistribute it and/or modify
  8;; it under the terms of the GNU General Public License as published by
  9;; the Free Software Foundation; either version 3, or (at your option)
 10;; any later version.
 11
 12;; This file is distributed in the hope that it will be useful,
 13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15;; GNU General Public License for more details.
 16
 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
 19;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 20;; Boston, MA 02110-1301, USA.
 21
 22;;; Commentary:
 23
 24;; Todo:
 25
 26;; - distinguish continued lines from indented lines.
 27;; - indent-line-function.
 28;; - outline-minor-mode.
 29
 30;;; Code:
 31
 32;; (defun haskell-cabal-extract-fields-from-doc ()
 33;;   (require 'xml)
 34;;   (require 'cl)
 35;;   (let ((section (completing-read
 36;;                   "Section: "
 37;;                   '("general-fields" "library" "executable" "buildinfo"))))
 38;;     (goto-char (point-min))
 39;;     (search-forward (concat "<sect3 id=\"" section "\">")))
 40;;   (let* ((xml (xml-parse-region
 41;;                (progn (search-forward "<variablelist>") (match-beginning 0))
 42;;                (progn (search-forward "</variablelist>") (point))))
 43;;          (varlist (remove-if-not 'consp (cddar xml)))
 44;;          (syms (mapcar (lambda (entry) (caddr (assq 'literal (assq 'term entry))))
 45;;                        varlist))
 46;;          (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms)))
 47;;     fields))
 48
 49(eval-when-compile (require 'cl))
 50
 51(defconst haskell-cabal-general-fields
 52  ;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields")
 53  '("name" "version" "cabal-version" "license" "license-file" "copyright"
 54    "author" "maintainer" "stability" "homepage" "package-url" "synopsis"
 55    "description" "category" "tested-with" "build-depends" "data-files"
 56    "extra-source-files" "extra-tmp-files"))
 57
 58(defconst haskell-cabal-library-fields
 59  ;; Extracted with (haskell-cabal-extract-fields-from-doc "library")
 60  '("exposed-modules"))
 61
 62(defconst haskell-cabal-executable-fields
 63  ;; Extracted with (haskell-cabal-extract-fields-from-doc "executable")
 64  '("executable" "main-is"))
 65
 66(defconst haskell-cabal-buildinfo-fields
 67  ;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo")
 68  '("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options"
 69    "ghc-prof-options" "hugs-options" "nhc-options" "includes"
 70    "install-includes" "include-dirs" "c-sources" "extra-libraries"
 71    "extra-lib-dirs" "cc-options" "ld-options" "frameworks"))
 72
 73(defvar haskell-cabal-mode-syntax-table
 74  (let ((st (make-syntax-table)))
 75    ;; The comment syntax can't be described simply in syntax-table.
 76    ;; We could use font-lock-syntactic-keywords, but is it worth it?
 77    ;; (modify-syntax-entry ?-  ". 12" st)
 78    (modify-syntax-entry ?\n ">" st)
 79    st))
 80
 81(defvar haskell-cabal-font-lock-keywords
 82  ;; The comment syntax can't be described simply in syntax-table.
 83  ;; We could use font-lock-syntactic-keywords, but is it worth it?
 84  '(("^[ \t]*--.*" . font-lock-comment-face)
 85    ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face))
 86    ("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face))
 87    ("^\\(Executable\\)[ \t]+\\([^\n \t]*\\)"
 88     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
 89    ("^\\(Flag\\)[ \t]+\\([^\n \t]*\\)"
 90     (1 font-lock-keyword-face) (2 font-lock-constant-face))
 91    ("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face))
 92    ("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)"
 93     (2 font-lock-keyword-face))))
 94
 95(defvar haskell-cabal-buffers nil
 96  "List of Cabal buffers.")
 97
 98;; (defsubst* inferior-haskell-string-prefix-p (str1 str2)
 99;;   "Return non-nil if STR1 is a prefix of STR2"
100;;   (eq t (compare-strings str2 nil (length str1) str1 nil nil)))
101
102(defun haskell-cabal-find-file ()
103  "Return a buffer visiting the cabal file of the current directory, or nil."
104  (catch 'found
105    ;; ;; First look for it in haskell-cabal-buffers.
106    ;; (dolist (buf haskell-cabal-buffers)
107    ;;   (if (inferior-haskell-string-prefix-p
108    ;;        (with-current-buffer buf default-directory) default-directory)
109    ;;       (throw 'found buf)))
110    ;; Then look up the directory hierarchy.
111    (let ((user (nth 2 (file-attributes default-directory)))
112          ;; Abbreviate, so as to stop when we cross ~/.
113          (root (abbreviate-file-name default-directory))
114          files)
115      (while (and root (equal user (nth 2 (file-attributes root))))
116        (if (setq files (directory-files root 'full "\\.cabal\\'"))
117            ;; Avoid the .cabal directory.
118            (dolist (file files (throw 'found nil))
119              (unless (file-directory-p file)
120                (throw 'found (find-file-noselect file))))
121          (if (equal root
122                     (setq root (file-name-directory
123                                 (directory-file-name root))))
124              (setq root nil))))
125      nil)))
126
127(autoload 'derived-mode-p "derived")	; Emacs 21
128
129(defun haskell-cabal-buffers-clean (&optional buffer)
130  (let ((bufs ()))
131    (dolist (buf haskell-cabal-buffers)
132      (if (and (buffer-live-p buf) (not (eq buf buffer))
133               (with-current-buffer buf (derived-mode-p 'haskell-cabal-mode)))
134          (push buf bufs)))
135    (setq haskell-cabal-buffers bufs)))
136
137(defun haskell-cabal-unregister-buffer ()
138  (haskell-cabal-buffers-clean (current-buffer)))
139
140;;;###autoload
141(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
142
143;;;###autoload
144(define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal"
145  "Major mode for Cabal package description files."
146  (set (make-local-variable 'font-lock-defaults)
147       '(haskell-cabal-font-lock-keywords t t nil nil))
148  (add-to-list 'haskell-cabal-buffers (current-buffer))
149  (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local)
150  (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local)
151  (set (make-local-variable 'comment-start) "-- ")
152  (set (make-local-variable 'comment-start-skip) "\\(^[ \t]*\\)--[ \t]*")
153  (set (make-local-variable 'comment-end) "")
154  (set (make-local-variable 'comment-end-skip) "[ 	]*\\(\\s>\\|\n\\)")
155)
156
157(defun haskell-cabal-get-setting (name)
158  (save-excursion
159    (let ((case-fold-search t))
160      (goto-char (point-min))
161      (when (re-search-forward
162             (concat "^" (regexp-quote name)
163                     ":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)")
164             nil t)
165        (let ((val (match-string 1))
166              (start 1))
167          (when (match-end 2)             ;Multiple lines.
168            ;; The documentation is not very precise about what to do about
169            ;; the \n and the indentation: are they part of the value or
170            ;; the encoding?  I take the point of view that \n is part of
171            ;; the value (so that values can span multiple lines as well),
172            ;; and that only the first char in the indentation is part of
173            ;; the encoding, the rest is part of the value (otherwise, lines
174            ;; in the value cannot start with spaces or tabs).
175            (while (string-match "^[ \t]\\(?:\\.$\\)?" val start)
176              (setq start (1+ (match-beginning 0)))
177              (setq val (replace-match "" t t val))))
178          val)))))
179
180(provide 'haskell-cabal)
181
182;; arch-tag: d455f920-5e4d-42b6-a2c7-4a7e84a05c29
183;;; haskell-cabal.el ends here