Skip to content

Commit 661b9d0

Browse files
committed
Get type information from ghci in interaction-mode
See also #432, this makes haskell's eldoc support somewhat more complete and precise.
1 parent 12da44f commit 661b9d0

File tree

1 file changed

+71
-2
lines changed

1 file changed

+71
-2
lines changed

haskell-doc.el

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8 -*-
1+
;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8; lexical-binding: t -*-
22

33
;; Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
44
;; Copyright (C) 1997 Hans-Wolfgang Loidl
@@ -343,6 +343,8 @@
343343
;;@subsection Emacs portability
344344

345345
(require 'haskell-mode)
346+
(require 'haskell-process)
347+
(require 'haskell)
346348
(require 'inf-haskell)
347349
(require 'imenu)
348350

@@ -1519,7 +1521,14 @@ This function is run by an idle timer to print the type
15191521
(defun haskell-doc-current-info ()
15201522
"Return the info about symbol at point.
15211523
Meant for `eldoc-documentation-function'."
1522-
(haskell-doc-sym-doc (haskell-ident-at-point)))
1524+
;; There are a number of possible documentation functions.
1525+
;; Some of them are asynchronous.
1526+
(let ((msg (or
1527+
(when (and (require 'eldoc nil t) ; FIXME eldoc required?
1528+
(fboundp #'eldoc-print-current-symbol-info))
1529+
(haskell-doc-current-info--interaction))
1530+
(haskell-doc-sym-doc (haskell-ident-at-point)))))
1531+
(unless (symbolp msg) msg)))
15231532

15241533

15251534
;;@node Mouse interface, Print fctsym, Top level function, top
@@ -1583,6 +1592,66 @@ current buffer."
15831592
(let ((message-log-max nil))
15841593
(message "%s" doc)))))))
15851594

1595+
(defvar haskell-doc-current-info--interaction-last nil
1596+
"If non-nil, a previous eldoc message from an async call, that
1597+
hasn't been displayed yet.")
1598+
1599+
(defun haskell-doc-current-info--interaction ()
1600+
"Asynchronous call to `haskell-process-get-type', suitable for
1601+
use in the eldoc function `haskell-doc-current-info'."
1602+
;; Return nil if nothing is available, or 'async if something might
1603+
;; be available, but asynchronously later. This will call
1604+
;; `eldoc-print-current-symbol-info' later.
1605+
(let (sym prev-message)
1606+
(cond
1607+
((setq prev-message haskell-doc-current-info--interaction-last)
1608+
(setq haskell-doc-current-info--interaction-last nil)
1609+
(cdr prev-message))
1610+
((setq sym
1611+
(if (use-region-p)
1612+
(buffer-substring-no-properties
1613+
(region-beginning) (region-end))
1614+
(thing-at-point 'symbol 'no-properties)))
1615+
(haskell-process-get-type
1616+
sym (lambda (response)
1617+
(setq haskell-doc-current-info--interaction-last
1618+
(cons 'async response))
1619+
(when (fboundp #'eldoc-print-current-symbol-info) ; FIXME eldoc required?
1620+
(eldoc-print-current-symbol-info))))
1621+
'async))))
1622+
1623+
(defun haskell-process-get-type (expr-string &optional callback)
1624+
"Asynchronously get the type of a given string.
1625+
1626+
EXPR-STRING should be an expression passed to :type in ghci.
1627+
1628+
CALLBACK will be called with a formatted type string."
1629+
(let ((process (haskell-process))
1630+
;; Avoid passing bad strings to ghci
1631+
(expr-okay (not (string-match-p "\n" expr-string)))
1632+
(ghci-command (concat ":type " expr-string)))
1633+
(when (and process expr-okay)
1634+
(haskell-process-queue-command
1635+
(haskell-process)
1636+
(make-haskell-command
1637+
:go (lambda (_) (haskell-process-send-string process ghci-command))
1638+
:complete
1639+
(lambda (_ response)
1640+
;; Responses with empty first line are likely errors
1641+
(if (string-match-p (rx string-start line-end) response)
1642+
(setq response nil)
1643+
;; Remove a newline at the end
1644+
(setq response (replace-regexp-in-string "\n\\'" "" response))
1645+
;; Propertize for eldoc
1646+
(save-match-data
1647+
(when (string-match " :: " response)
1648+
;; Highlight type
1649+
(let ((name (substring response 0 (match-end 0)))
1650+
(type (propertize
1651+
(substring response (match-end 0))
1652+
'face 'eldoc-highlight-function-argument)))
1653+
(setq response (concat name type))))))
1654+
(when callback (funcall callback response))))))))
15861655

15871656
(defun haskell-doc-sym-doc (sym)
15881657
"Show the type of the function near point.

0 commit comments

Comments
 (0)