Skip to content
This repository
Newer
Older
100644 608 lines (544 sloc) 26.229 kb
44188717 » monnier
2004-11-24 New file.
1 ;;; inf-haskell.el --- Interaction with an inferior Haskell process.
2
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
3 ;; Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
44188717 » monnier
2004-11-24 New file.
4
5 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
6 ;; Keywords: Haskell
7
8 ;; This file is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
30d658f0 » monnier
2007-07-30 (displayed-month): Remove declaration since it's not used here.
10 ;; the Free Software Foundation; either version 3, or (at your option)
44188717 » monnier
2004-11-24 New file.
11 ;; any later version.
12
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
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
22
23 ;;; Commentary:
24
25 ;; The code is made of 2 parts: a major mode for the buffer that holds the
225a7c54 » monnier
2005-01-26 (inferior-haskell-load-file): Quote file name.
26 ;; inferior process's session and a minor mode for use in source buffers.
44188717 » monnier
2004-11-24 New file.
27
3e6c2e07 » monnier
2007-08-29 *** empty log message ***
28 ;; Todo:
29
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
30 ;; - i-h-load-buffer and i-h-send-region.
3e6c2e07 » monnier
2007-08-29 *** empty log message ***
31 ;; - Obey the Hs-Source-Dirs setting in the Cabal file.
32 ;; - If there's no Cabal file, look for a "module" line at the beginning of
33 ;; the file to determine how many times to "cd .." in order to get to the
34 ;; root of the project (count the number of "." in the module name).
35
44188717 » monnier
2004-11-24 New file.
36 ;;; Code:
37
38 (require 'comint)
39 (require 'shell) ;For directory tracking.
40 (require 'compile)
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
41 (require 'haskell-mode)
74104803 » monnier
2006-05-18 (inferior-haskell-wait-for-prompt): New fun, extracted
42 (eval-when-compile (require 'cl))
44188717 » monnier
2004-11-24 New file.
43
44 ;; Here I depart from the inferior-haskell- prefix.
45 ;; Not sure if it's a good idea.
27cc26c3 » monnier
2004-12-10 (haskell-program-name): Use ghci if hugs is absent.
46 (defcustom haskell-program-name
47 ;; Arbitrarily give preference to hugs over ghci.
48 (or (cond
49 ((not (fboundp 'executable-find)) nil)
50 ((executable-find "hugs") "hugs \"+.\"")
51 ((executable-find "ghci") "ghci"))
52 "hugs \"+.\"")
44188717 » monnier
2004-11-24 New file.
53 "The name of the command to start the inferior Haskell process.
54 The command can include arguments."
8b661ca0 » monnier
2005-07-18 (haskell-program-name): Fix defcustom delcaration.
55 ;; Custom only supports the :options keyword for a few types, e.g. not
56 ;; for string.
57 ;; :options '("hugs \"+.\"" "ghci")
44188717 » monnier
2004-11-24 New file.
58 :group 'haskell
59 :type '(choice string (repeat string)))
60
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
61 (defconst inferior-haskell-info-xref-re
62 "\t-- Defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)$")
63
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
64 (defconst inferior-haskell-module-re
65 "\t-- Defined in \\(.+\\)$"
66 "Regular expression for matching module names in :info.")
67
44188717 » monnier
2004-11-24 New file.
68 (defconst inferior-haskell-error-regexp-alist
69 ;; The format of error messages used by Hugs.
e19bf495 » monnier
2005-11-14 (inferior-haskell-error-regexp-alist): Fix GHCi regexp, support warni…
70 `(("^ERROR \"\\(.+?\\)\"\\(:\\| line \\)\\([0-9]+\\) - " 1 3)
44188717 » monnier
2004-11-24 New file.
71 ;; Format of error messages used by GHCi.
a9fe15bb » monnier
2007-06-12 (inferior-haskell-error-regexp-alist): Be more careful
72 ("^\\(.+?\\):\\([0-9]+\\):\\(\\([0-9]+\\):\\)?\\( \\|\n *\\)\\(Warning\\)?"
73 1 2 4 ,@(if (fboundp 'compilation-fake-loc)
74 '((6) nil (5 '(face nil font-lock-multiline t)))))
5a72afa0 » monnier
2007-06-07 (inferior-haskell-error-regexp-alist): Add entries for GHCI's excepti…
75 ;; Runtime exceptions, from ghci.
76 ("^\\*\\*\\* Exception: \\(.+?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\)): .*"
77 1 ,@(if (fboundp 'compilation-fake-loc) '((2 . 4) (3 . 5)) '(2 3)))
a9fe15bb » monnier
2007-06-12 (inferior-haskell-error-regexp-alist): Be more careful
78 ;; GHCi uses two different forms for line/col ranges, depending on
ff46f40a » monnier
2007-06-26 (inferior-haskell-error-regexp-alist):
79 ;; whether it's all on the same line or not :-( In Emacs-23, I could use
80 ;; explicitly numbered subgroups to merge the two patterns.
5a72afa0 » monnier
2007-06-07 (inferior-haskell-error-regexp-alist): Add entries for GHCI's excepti…
81 ("^\\*\\*\\* Exception: \\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\): .*"
82 1 2 ,(if (fboundp 'compilation-fake-loc) '(3 . 4) 3))
a9fe15bb » monnier
2007-06-12 (inferior-haskell-error-regexp-alist): Be more careful
83 ;; Info messages. Not errors per se.
ff46f40a » monnier
2007-06-26 (inferior-haskell-error-regexp-alist):
84 ,@(when (fboundp 'compilation-fake-loc)
85 `(;; Other GHCi patterns used in type errors.
86 ("^[ \t]+at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$"
87 1 2 (3 . 4) 0)
88 ;; Foo.hs:318:80:
89 ;; Ambiguous occurrence `Bar'
90 ;; It could refer to either `Bar', defined at Zork.hs:311:5
91 ;; or `Bar', imported from Bars at Frob.hs:32:0-16
92 ;; (defined at Location.hs:97:5)
93 ("[ (]defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\))?$" 1 2 3 0)
94 ("imported from .* at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$"
95 1 2 (3 . 4) 0)
96 ;; Info xrefs.
97 (,inferior-haskell-info-xref-re 1 2 3 0))))
44188717 » monnier
2004-11-24 New file.
98 "Regexps for error messages generated by inferior Haskell processes.
99 The format should be the same as for `compilation-error-regexp-alist'.")
100
c7c62784 » monnier
2007-05-08 (inferior-haskell-use-cabal): New custom var.
101 (defcustom inferior-haskell-use-cabal t
102 "If non-nil, try and find a Cabal file to get the project root directory."
103 :type 'boolean)
104
44188717 » monnier
2004-11-24 New file.
105 (define-derived-mode inferior-haskell-mode comint-mode "Inf-Haskell"
106 "Major mode for interacting with an inferior Haskell process."
107 (set (make-local-variable 'comint-prompt-regexp)
108 "^\\*?[A-Z][\\._a-zA-Z0-9]*\\( \\*?[A-Z][\\._a-zA-Z0-9]*\\)*> ")
109 (set (make-local-variable 'comint-input-autoexpand) nil)
110
111 ;; Setup directory tracking.
112 (set (make-local-variable 'shell-cd-regexp) ":cd")
bbbe0544 » monnier
2006-05-17 (inferior-haskell-mode): Use shell-dirtrack-mode if possible.
113 (condition-case nil
114 (shell-dirtrack-mode 1)
115 (error ;The minor mode function may not exist or not accept an arg.
116 (set (make-local-variable 'shell-dirtrackp) t)
117 (add-hook 'comint-input-filter-functions 'shell-directory-tracker
118 nil 'local)))
44188717 » monnier
2004-11-24 New file.
119
120 ;; Setup `compile' support so you can just use C-x ` and friends.
121 (set (make-local-variable 'compilation-error-regexp-alist)
122 inferior-haskell-error-regexp-alist)
5a72afa0 » monnier
2007-06-07 (inferior-haskell-error-regexp-alist): Add entries for GHCI's excepti…
123 (set (make-local-variable 'compilation-first-column) 0) ;GHCI counts from 0.
bfd15e13 » monnier
2005-11-04 (inferior-haskell-mode): Hide compilation-mode bindings.
124 (if (and (not (boundp 'minor-mode-overriding-map-alist))
125 (fboundp 'compilation-shell-minor-mode))
126 ;; If we can't remove compilation-minor-mode bindings, at least try to
127 ;; use compilation-shell-minor-mode, so there are fewer
128 ;; annoying bindings.
129 (compilation-shell-minor-mode 1)
130 ;; Else just use compilation-minor-mode but without its bindings because
131 ;; things like mouse-2 are simply too annoying.
132 (compilation-minor-mode 1)
133 (let ((map (make-sparse-keymap)))
134 (dolist (keys '([menu-bar] [follow-link]))
135 ;; Preserve some of the bindings.
136 (define-key map keys (lookup-key compilation-minor-mode-map keys)))
137 (add-to-list 'minor-mode-overriding-map-alist
138 (cons 'compilation-minor-mode map)))))
44188717 » monnier
2004-11-24 New file.
139
6784a8b0 » monnier
2007-05-08 (inferior-haskell-string-to-strings): Remove `separator' argument. Ca…
140 (defun inferior-haskell-string-to-strings (string)
141 "Split the STRING into a list of strings."
142 (let ((i (string-match "[\"]" string)))
143 (if (null i) (split-string string) ; no quoting: easy
144 (append (unless (eq i 0) (split-string (substring string 0 i)))
44188717 » monnier
2004-11-24 New file.
145 (let ((rfs (read-from-string string i)))
146 (cons (car rfs)
147 (inferior-haskell-string-to-strings
6784a8b0 » monnier
2007-05-08 (inferior-haskell-string-to-strings): Remove `separator' argument. Ca…
148 (substring string (cdr rfs)))))))))
44188717 » monnier
2004-11-24 New file.
149
150 (defun inferior-haskell-command (arg)
151 (inferior-haskell-string-to-strings
152 (if (null arg) haskell-program-name
6dd0f3a0 » monnier
2005-11-11 (inferior-haskell-command): Provide a default.
153 (read-string "Command to run haskell: " haskell-program-name))))
44188717 » monnier
2004-11-24 New file.
154
155 (defvar inferior-haskell-buffer nil
156 "The buffer in which the inferior process is running.")
157
158 (defun inferior-haskell-start-process (command)
159 "Start an inferior haskell process.
6784a8b0 » monnier
2007-05-08 (inferior-haskell-string-to-strings): Remove `separator' argument. Ca…
160 With universal prefix \\[universal-argument], prompts for a COMMAND,
44188717 » monnier
2004-11-24 New file.
161 otherwise uses `haskell-program-name'.
162 It runs the hook `inferior-haskell-hook' after starting the process and
163 setting up the inferior-haskell buffer."
164 (interactive (list (inferior-haskell-command current-prefix-arg)))
165 (setq inferior-haskell-buffer
166 (apply 'make-comint "haskell" (car command) nil (cdr command)))
167 (with-current-buffer inferior-haskell-buffer
168 (inferior-haskell-mode)
169 (run-hooks 'inferior-haskell-hook)))
170
171 (defun inferior-haskell-process (&optional arg)
172 (or (if (buffer-live-p inferior-haskell-buffer)
173 (get-buffer-process inferior-haskell-buffer))
174 (progn
175 (let ((current-prefix-arg arg))
176 (call-interactively 'inferior-haskell-start-process))
177 ;; Try again.
178 (inferior-haskell-process arg))))
179
180 ;;;###autoload
181 (defalias 'run-haskell 'switch-to-haskell)
182 ;;;###autoload
183 (defun switch-to-haskell (&optional arg)
184 "Show the inferior-haskell buffer. Start the process if needed."
185 (interactive "P")
186 (let ((proc (inferior-haskell-process arg)))
187 (pop-to-buffer (process-buffer proc))))
188
ce51306a » monnier
2007-02-14 (with-selected-window): Define while compiling.
189 (eval-when-compile
190 (unless (fboundp 'with-selected-window)
191 (defmacro with-selected-window (win &rest body)
192 `(save-selected-window
193 (select-window ,win)
194 ,@body))))
6dd0f3a0 » monnier
2005-11-11 (inferior-haskell-command): Provide a default.
195
74104803 » monnier
2006-05-18 (inferior-haskell-wait-for-prompt): New fun, extracted
196 (defcustom inferior-haskell-wait-and-jump nil
197 "If non-nil, wait for file loading to terminate and jump to the error."
198 :type 'boolean
199 :group 'haskell)
200
201 (defun inferior-haskell-wait-for-prompt (proc)
202 "Wait until PROC sends us a prompt.
203 The process PROC should be associated to a comint buffer."
204 (with-current-buffer (process-buffer proc)
205 (while (progn
206 (goto-char comint-last-input-end)
207 (and (not (re-search-forward comint-prompt-regexp nil t))
208 (accept-process-output proc))))))
209
c7c62784 » monnier
2007-05-08 (inferior-haskell-use-cabal): New custom var.
210 (defvar inferior-haskell-cabal-buffer nil)
211
212 (defun inferior-haskell-cabal-of-buf (buf)
213 (require 'haskell-cabal)
214 (with-current-buffer buf
215 (or inferior-haskell-cabal-buffer
216 (and (not (local-variable-p 'inferior-haskell-cabal-buffer))
217 (set (make-local-variable 'inferior-haskell-cabal-buffer)
218 (haskell-cabal-find-file))))))
219
44188717 » monnier
2004-11-24 New file.
220 ;;;###autoload
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
221 (defun inferior-haskell-load-file (&optional reload)
44188717 » monnier
2004-11-24 New file.
222 "Pass the current buffer's file to the inferior haskell process."
223 (interactive)
2eaced43 » monnier
2007-05-03 (inferior-haskell-load-file): Save buffer before using buffer-file-name.
224 ;; Save first, so we're sure that `buffer-file-name' is non-nil afterward.
225 (save-buffer)
c7c62784 » monnier
2007-05-08 (inferior-haskell-use-cabal): New custom var.
226 (let ((buf (current-buffer))
227 (file buffer-file-name)
44188717 » monnier
2004-11-24 New file.
228 (proc (inferior-haskell-process)))
229 (with-current-buffer (process-buffer proc)
230 (compilation-forget-errors)
c7c62784 » monnier
2007-05-08 (inferior-haskell-use-cabal): New custom var.
231 (let ((parsing-end (marker-position (process-mark proc)))
232 cabal)
233 ;; Go to the root of the Cabal project, if applicable.
234 (when (and inferior-haskell-use-cabal
235 (setq cabal (inferior-haskell-cabal-of-buf buf)))
236 ;; Not sure if it's useful/needed and if it actually works.
237 (unless (equal default-directory
238 (with-current-buffer cabal default-directory))
239 (setq default-directory
240 (with-current-buffer cabal default-directory))
241 (inferior-haskell-send-command
242 proc (concat ":cd " default-directory)))
243 (setq file (file-relative-name file)))
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
244 (inferior-haskell-send-command
245 proc (if reload ":reload" (concat ":load \"" file "\"")))
30d658f0 » monnier
2007-07-30 (displayed-month): Remove declaration since it's not used here.
246 ;; Move the parsing-end marker *after* sending the command so
d8a5cc86 » monnier
2005-11-20 (inferior-haskell-load-file): Fix the compilation-parsing-end fiddlin…
247 ;; that it doesn't point just to the insertion point.
248 ;; Otherwise insertion may move the marker (if done with
249 ;; insert-before-markers) and we'd then miss some errors.
250 (if (boundp 'compilation-parsing-end)
251 (if (markerp compilation-parsing-end)
252 (set-marker compilation-parsing-end parsing-end)
253 (setq compilation-parsing-end parsing-end))))
1cda3842 » monnier
2006-10-19 (inferior-haskell-load-file): Simplify and make more
254 (with-selected-window (display-buffer (current-buffer))
74104803 » monnier
2006-05-18 (inferior-haskell-wait-for-prompt): New fun, extracted
255 (goto-char (point-max)))
30d658f0 » monnier
2007-07-30 (displayed-month): Remove declaration since it's not used here.
256 ;; Use compilation-auto-jump-to-first-error if available.
257 ;; (if (and (boundp 'compilation-auto-jump-to-first-error)
258 ;; compilation-auto-jump-to-first-error
259 ;; (boundp 'compilation-auto-jump-to-next))
260 ;; (setq compilation-auto-jump-to-next t)
261 (when inferior-haskell-wait-and-jump
262 (inferior-haskell-wait-for-prompt proc)
263 (ignore-errors ;Don't beep if there were no errors.
264 (next-error)))))) ;; )
8512ba1e » monnier
2004-11-25 (inferior-haskell-mode): Typo.
265
3afdf6bc » monnier
2007-06-29 (inferior-haskell-run-command): New var.
266 (defvar inferior-haskell-run-command ":main")
267
268 (defun inferior-haskell-load-and-run (command)
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
269 "Pass the current buffer's file to haskell and then run a COMMAND."
3afdf6bc » monnier
2007-06-29 (inferior-haskell-run-command): New var.
270 (interactive
271 (list
272 (if (and inferior-haskell-run-command (not current-prefix-arg))
273 inferior-haskell-run-command
274 (read-string "Command to run: " nil nil inferior-haskell-run-command))))
275 (setq inferior-haskell-run-command command)
f818e57a » monnier
2007-06-30 Removed support for :reload (e.g. removed the C-c C-r binding).
276 (inferior-haskell-load-file)
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
277 ;; FIXME: if the :load encountered errors, we should not `run'.
3afdf6bc » monnier
2007-06-29 (inferior-haskell-run-command): New var.
278 (inferior-haskell-send-command (inferior-haskell-process) command))
279
8512ba1e » monnier
2004-11-25 (inferior-haskell-mode): Typo.
280 (defun inferior-haskell-send-command (proc str)
281 (setq str (concat str "\n"))
282 (with-current-buffer (process-buffer proc)
74104803 » monnier
2006-05-18 (inferior-haskell-wait-for-prompt): New fun, extracted
283 (inferior-haskell-wait-for-prompt proc)
8512ba1e » monnier
2004-11-25 (inferior-haskell-mode): Typo.
284 (goto-char (process-mark proc))
285 (insert-before-markers str)
286 (move-marker comint-last-input-end (point))
287 (comint-send-string proc str)))
44188717 » monnier
2004-11-24 New file.
288
9ed46b19 » monnier
2007-08-29 (inferior-haskell-load-file): Re-add the `reload' arg.
289 (defun inferior-haskell-reload-file ()
290 "Tell the inferior haskell process to reread the current buffer's file."
291 (interactive)
292 (inferior-haskell-load-file 'reload))
293
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
294 ;;;###autoload
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
295 (defun inferior-haskell-type (expr &optional insert-value)
296 "Query the haskell process for the type of the given expression.
297 If optional argument `insert-value' is non-nil, insert the type above point
298 in the buffer. This can be done interactively with the \\[universal-argument] prefix.
299 The returned info is cached for reuse by `haskell-doc-mode'."
300 (interactive
301 (let ((sym (haskell-ident-at-point)))
302 (list (read-string (if (> (length sym) 0)
303 (format "Show type of (default %s): " sym)
304 "Show type of: ")
305 nil nil sym)
306 current-prefix-arg)))
307 (if (string-match "\\`\\s_+\\'" expr) (setq expr (concat "(" expr ")")))
308 (let* ((proc (inferior-haskell-process))
309 (type
310 (with-current-buffer (process-buffer proc)
311 (let ((parsing-end ; Remember previous spot.
312 (marker-position (process-mark proc))))
313 (inferior-haskell-send-command proc (concat ":type " expr))
314 ;; Find new point.
315 (goto-char (point-max))
316 (inferior-haskell-wait-for-prompt proc)
317 ;; Back up to the previous end-of-line.
318 (end-of-line 0)
319 ;; Extract the type output
320 (buffer-substring-no-properties
321 (save-excursion (goto-char parsing-end)
322 (line-beginning-position 2))
323 (point))))))
324 (if (not (string-match (concat "\\`" (regexp-quote expr) "[ \t]+::[ \t]*")
325 type))
326 (error "No type info: %s" type)
327
328 ;; Cache for reuse by haskell-doc.
329 (when (and (boundp 'haskell-doc-mode) haskell-doc-mode
330 (boundp 'haskell-doc-user-defined-ids)
331 ;; Haskell-doc only works for idents, not arbitrary expr.
332 (string-match "\\`(?\\(\\s_+\\|\\(\\sw\\|\\s'\\)+\\)?[ \t]*::[ \t]*"
333 type))
334 (let ((sym (match-string 1 type)))
335 (setq haskell-doc-user-defined-ids
336 (cons (cons sym (substring type (match-end 0)))
337 (remove-if (lambda (item) (equal (car item) sym))
338 haskell-doc-user-defined-ids)))))
339
011c5029 » monnier
2007-07-31 (inferior-haskell-type): Fix call to message.
340 (if (interactive-p) (message "%s" type))
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
341 (when insert-value
342 (beginning-of-line)
343 (insert type "\n"))
344 type)))
345
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
346 ;;;###autoload
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
347 (defun inferior-haskell-info (sym)
348 "Query the haskell process for the info of the given expression."
349 (interactive
350 (let ((sym (haskell-ident-at-point)))
351 (list (read-string (if (> (length sym) 0)
352 (format "Show info of (default %s): " sym)
353 "Show info of: ")
354 nil nil sym))))
355 (let ((proc (inferior-haskell-process)))
356 (with-current-buffer (process-buffer proc)
357 (let ((parsing-end ; Remember previous spot.
358 (marker-position (process-mark proc))))
359 (inferior-haskell-send-command proc (concat ":info " sym))
360 ;; Find new point.
361 (goto-char (point-max))
362 (inferior-haskell-wait-for-prompt proc)
363 ;; Move to previous end-of-line
364 (end-of-line 0)
365 (let ((result
366 (buffer-substring-no-properties
367 (save-excursion (goto-char parsing-end)
368 (line-beginning-position 2))
369 (point))))
370 ;; Move back to end of process buffer
371 (goto-char (point-max))
372 (if (interactive-p) (message "%s" result))
373 result)))))
374
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
375 ;;;###autoload
36dd8bd9 » monnier
2007-02-09 (inferior-haskell-info-xref-re): New cst.
376 (defun inferior-haskell-find-definition (sym)
377 "Attempt to locate and jump to the definition of the given expression."
378 (interactive
379 (let ((sym (haskell-ident-at-point)))
380 (list (read-string (if (> (length sym) 0)
381 (format "Find definition of (default %s): " sym)
382 "Find definition of: ")
383 nil nil sym))))
384 (let ((info (inferior-haskell-info sym)))
385 (if (not (string-match inferior-haskell-info-xref-re info))
386 (error "No source information available")
387 (let ((file (match-string-no-properties 1 info))
388 (line (string-to-number
389 (match-string-no-properties 2 info)))
390 (col (string-to-number
391 (match-string-no-properties 3 info))))
392 (when file
393 ;; Push current location marker on the ring used by `find-tag'
394 (require 'etags)
395 (ring-insert find-tag-marker-ring (point-marker))
396 (pop-to-buffer (find-file-noselect file))
397 (when line
398 (goto-line line)
399 (when col (move-to-column col))))))))
400
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
401 ;;; Functions to find the documentation of a given function.
402 ;;
403 ;; TODO for this section:
404 ;;
405 ;; * Support fetching of local Haddock docs pulled directly from source files.
406 ;; * Display docs locally? w3m?
407
408 (defcustom inferior-haskell-use-web-docs
409 'fallback
410 "Whether to use the online documentation. Possible values:
411 `never', meaning always use local documentation, unless the local
412 file doesn't exist, when do nothing, `fallback', which means only
413 use the online documentation when the local file doesn't exist,
414 or `always', meaning always use the online documentation,
415 regardless of existance of local files. Default is `fallback'."
416 :group 'haskell
417 :type '(choice (const :tag "Never" never)
418 (const :tag "As fallback" fallback)
419 (const :tag "Always" always)))
420
421 (defcustom inferior-haskell-web-docs-base
422 "http://haskell.org/ghc/docs/latest/html/libraries/"
423 "The base URL of the online libraries documentation. This will
424 only be used if the value of `inferior-haskell-use-web-docs' is
425 `always' or `fallback'."
426 :group 'haskell
427 :type 'string)
428
429 (defcustom haskell-package-manager-name "ghc-pkg"
430 "Name of the program to consult regarding package details."
431 :group 'haskell
432 :type 'string)
433
434 (defcustom haskell-package-conf-file
435 (ignore-errors
436 (with-temp-buffer
437 (call-process "ghc" nil t nil "--print-libdir")
438 (expand-file-name "package.conf"
439 (buffer-substring (point-min) (1- (point-max))))))
440 "Where the package configuration file for the package manager resides.
441 By default this is set to `ghc --print-libdir`/package.conf."
442 :group 'haskell
443 :type 'string)
444
445 (defun inferior-haskell-get-module (sym)
446 "Fetch the module in which SYM is defined."
447 (let ((info (inferior-haskell-info sym)))
448 (unless (string-match inferior-haskell-module-re info)
449 (error
450 "No documentation information available. Did you forget to C-c C-l?"))
451 (match-string-no-properties 1 info)))
452
453 (defun inferior-haskell-query-ghc-pkg (&rest args)
454 "Send ARGS to ghc-pkg, or whatever the value of
455 `haskell-package-manager' is. Insert the output into the current
456 buffer."
457 (apply 'call-process haskell-package-manager-name nil t nil args))
458
459 (defun inferior-haskell-get-package-list ()
460 "Get the list of packages from ghc-pkg, or whatever
461 `haskell-package-manager-name' is."
462 (with-temp-buffer
463 (inferior-haskell-query-ghc-pkg "--simple-output" "list")
464 (split-string (buffer-substring (point-min) (point-max)))))
465
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
466 (defun inferior-haskell-compute-module-alist ()
467 "Compute a list mapping modules to package names and haddock URLs using ghc-pkg."
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
468 (message "Generating module alist...")
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
469 (let ((module-alist ()))
470 (with-temp-buffer
471 (dolist (package (inferior-haskell-get-package-list))
472 (erase-buffer)
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
473 (inferior-haskell-query-ghc-pkg "describe" package)
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
474
475 (let ((package-w/o-version
476 (replace-regexp-in-string "[-.0-9]*\\'" "" package))
477 ;; Find the Haddock documentation URL for this package
478 (haddock
479 (progn
480 (goto-char (point-min))
bf802671 » monnier
2007-06-29 (inferior-haskell-compute-module-alist): Fix regexps.
481 (when (re-search-forward "haddock-html:[ \t]+\\(.*[^ \t\n]\\)"
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
482 nil t)
483 (match-string 1)))))
484
485 ;; Fetch the list of exposed modules for this package
486 (goto-char (point-min))
bf802671 » monnier
2007-06-29 (inferior-haskell-compute-module-alist): Fix regexps.
487 (when (re-search-forward "^exposed-modules:\\(.*\\(\n[ \t].*\\)*\\)"
488 nil t)
489 (dolist (module (split-string (match-string 1)))
490 (push (list module package-w/o-version haddock)
491 module-alist)))))
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
492
493 (message "Generating module alist... done")
494 module-alist)))
495
496
497 (defcustom inferior-haskell-module-alist-file
498 ;; (expand-file-name "~/.inf-haskell-module-alist")
bf802671 » monnier
2007-06-29 (inferior-haskell-compute-module-alist): Fix regexps.
499 (expand-file-name (concat "inf-haskell-module-alist-"
500 (number-to-string (user-uid)))
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
501 temporary-file-directory)
502 "Where to save the module -> package lookup table.
503 Set this to `nil' to never cache to a file."
504 :group 'haskell
505 :type '(choice (const :tag "Don't cache to file" nil) string))
506
507 (defvar inferior-haskell-module-alist nil
508 "Association list of modules to their packages.
509 Each element is of the form (MODULE PACKAGE HADDOCK), where
510 MODULE is the name of a module,
511 PACKAGE is the package it belongs to, and
512 HADDOCK is the path to that package's Haddock documentation.
513
514 This is calculated on-demand using `inferior-haskell-compute-module-alist'.
515 It's also cached in the file `inferior-haskell-module-alist-file',
516 so that it can be obtained more quickly next time.")
517
518 (defun inferior-haskell-module-alist ()
519 "Get the module alist from cache or ghc-pkg's info."
520 (or
521 ;; If we already have computed the alist, use it...
522 inferior-haskell-module-alist
523 (setq inferior-haskell-module-alist
524 (or
525 ;; ...otherwise try to read it from the cache file...
526 (and
527 inferior-haskell-module-alist-file
528 (file-readable-p inferior-haskell-module-alist-file)
529 (file-newer-than-file-p inferior-haskell-module-alist-file
530 haskell-package-conf-file)
531 (with-temp-buffer
532 (insert-file-contents inferior-haskell-module-alist-file)
533 (goto-char (point-min))
534 (prog1 (read (current-buffer))
535 (message "Read module alist from file cache."))))
536
537 ;; ...or generate it again and save it in a file for later.
538 (let ((alist (inferior-haskell-compute-module-alist)))
539 (when inferior-haskell-module-alist-file
540 (print alist (current-buffer))
541 ;; Do the write to a temp file first, then rename it.
542 ;; This makes it more atomic, and suffers from fewer security
543 ;; holes related to race conditions if the file is in /tmp.
544 (let ((tmp (make-temp-file inferior-haskell-module-alist-file)))
545 (write-region (point-min) (point-max) tmp)
546 (rename-file tmp inferior-haskell-module-alist-file
547 'ok-if-already-exists)))
548 alist)))))
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
549
3afdf6bc » monnier
2007-06-29 (inferior-haskell-run-command): New var.
550 (defvar inferior-haskell-ghc-internal-ident-alist
551 ;; FIXME: Fill this table, ideally semi-automatically.
552 '(("GHC.Base.return" . "Control.Monad.return")
553 ("GHC.List" . "Data.List")))
554
555 (defun inferior-haskell-map-internal-ghc-ident (ident)
556 "Try to translate some internal GHC identifier to its alter ego in haskell docs."
557 (let ((head ident)
558 (tail "")
559 remapped)
560 (while (and (not
561 (setq remapped
562 (cdr (assoc head
563 inferior-haskell-ghc-internal-ident-alist))))
564 (string-match "\\.[^.]+\\'" head))
565 (setq tail (concat (match-string 0 head) tail))
566 (setq head (substring head 0 (match-beginning 0))))
567 (concat (or remapped head) tail)))
568
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
569 ;;;###autoload
570 (defun inferior-haskell-find-haddock (sym)
571 "Find and open the Haddock documentation of SYM.
572 Make sure to load the file into GHCi or Hugs first by using C-c C-l.
573 Only works for functions in a package installed with ghc-pkg, or
574 whatever the value of `haskell-package-manager-name' is.
575
576 This function needs to find which package a given module belongs
577 to. In order to do this, it computes a module-to-package lookup
578 alist, which is expensive to compute (it takes upwards of five
579 seconds with more than about thirty installed packages). As a
580 result, we cache it across sessions using the cache file
581 referenced by `inferior-haskell-module-alist-file'. We test to
582 see if this is newer than `haskell-package-conf-file' every time
583 we load it."
584 (interactive
585 (let ((sym (haskell-ident-at-point)))
586 (list (read-string (if (> (length sym) 0)
587 (format "Find documentation of (default %s): " sym)
588 "Find documentation of: ")
589 nil nil sym))))
3afdf6bc » monnier
2007-06-29 (inferior-haskell-run-command): New var.
590 (setq sym (inferior-haskell-map-internal-ghc-ident sym))
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
591 (let* (;; Find the module and look it up in the alist
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
592 (module (inferior-haskell-get-module sym))
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
593 (alist-record (assoc module (inferior-haskell-module-alist)))
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
594 (package (nth 1 alist-record))
595 (file-name (concat (subst-char-in-string ?. ?- module) ".html"))
596 (local-path (concat (nth 2 alist-record) "/" file-name))
597 (url (if (or (eq inferior-haskell-use-web-docs 'always)
598 (and (not (file-exists-p local-path))
599 (eq inferior-haskell-use-web-docs 'fallback)))
600 (concat inferior-haskell-web-docs-base package "/" file-name)
b74e553f » monnier
2007-06-29 (inferior-haskell-module-alist-file): Use a file in /tmp rather than ~/.
601 (and (file-exists-p local-path)
c5f1425d » monnier
2007-06-29 (inferior-haskell-module-alist-file)
602 (concat "file://" local-path)))))
603 (if url (browse-url url) (error "Local file doesn't exist."))))
604
44188717 » monnier
2004-11-24 New file.
605 (provide 'inf-haskell)
bfd15e13 » monnier
2005-11-04 (inferior-haskell-mode): Hide compilation-mode bindings.
606
607 ;; arch-tag: 61804287-63dd-4052-bc0e-90f691b34b40
44188717 » monnier
2004-11-24 New file.
608 ;;; inf-haskell.el ends here
Something went wrong with that request. Please try again.