ghc-comp.el 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;;
  3. ;;; ghc-comp.el
  4. ;;;
  5. ;; Author: Kazu Yamamoto <Kazu@Mew.org>
  6. ;; Created: Sep 25, 2009
  7. ;;; Code:
  8. (require 'ghc-func)
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10. ;;;
  11. ;;; Customize Variables
  12. ;;;
  13. (defvar ghc-idle-timer-interval 30
  14. "*Period of idele timer in second. When timeout, the names of
  15. unloaded modules are loaded")
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17. ;;;
  18. ;;; Constants
  19. ;;;
  20. ;; must be sorted
  21. (defconst ghc-reserved-keyword-for-bol '("class" "data" "default" "import" "infix" "infixl" "infixr" "instance" "main" "module" "newtype" "type"))
  22. ;; must be sorted
  23. (defconst ghc-reserved-keyword '("case" "deriving" "do" "else" "if" "in" "let" "module" "of" "then" "where"))
  24. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  25. ;;;
  26. ;;; Local Variables
  27. ;;;
  28. (defvar ghc-window-configuration nil)
  29. (mapc 'make-variable-buffer-local
  30. '(ghc-window-configuration))
  31. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  32. ;;;
  33. ;;; Initializer
  34. ;;;
  35. (defvar ghc-module-names nil) ;; completion for "import"
  36. (defvar ghc-merged-keyword nil) ;; completion for type/func/...
  37. (defvar ghc-language-extensions nil)
  38. (defvar ghc-option-flags nil)
  39. (defvar ghc-pragma-names '("LANGUAGE" "OPTIONS_GHC"))
  40. (defconst ghc-keyword-prefix "ghc-keyword-")
  41. (defvar ghc-keyword-Prelude nil)
  42. (defvar ghc-keyword-Control.Applicative nil)
  43. (defvar ghc-keyword-Control.Monad nil)
  44. (defvar ghc-keyword-Control.Exception nil)
  45. (defvar ghc-keyword-Data.Char nil)
  46. (defvar ghc-keyword-Data.List nil)
  47. (defvar ghc-keyword-Data.Maybe nil)
  48. (defvar ghc-keyword-System.IO nil)
  49. (defvar ghc-loaded-module nil)
  50. (defun ghc-comp-init ()
  51. (add-hook 'find-file-hook 'ghc-import-module)
  52. (let* ((syms '(ghc-module-names
  53. ghc-language-extensions
  54. ghc-option-flags
  55. ghc-keyword-Prelude
  56. ghc-keyword-Control.Applicative
  57. ghc-keyword-Control.Monad
  58. ghc-keyword-Control.Exception
  59. ghc-keyword-Data.Char
  60. ghc-keyword-Data.List
  61. ghc-keyword-Data.Maybe
  62. ghc-keyword-System.IO))
  63. (vals (ghc-boot (length syms))))
  64. (ghc-set syms vals))
  65. (ghc-add ghc-module-names "qualified")
  66. (ghc-add ghc-module-names "hiding")
  67. (ghc-merge-keywords '("Prelude"
  68. "Control.Applicative"
  69. "Control.Monad"
  70. "Control.Exception"
  71. "Data.Char"
  72. "Data.List"
  73. "Data.Maybe"
  74. "System.IO"))
  75. (run-with-idle-timer ghc-idle-timer-interval 'repeat 'ghc-idle-timer))
  76. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  77. ;;;
  78. ;;; Executing command
  79. ;;;
  80. (defun ghc-boot (n)
  81. (if (not (executable-find ghc-module-command))
  82. (message "%s not found" ghc-module-command)
  83. (ghc-read-lisp-list
  84. (lambda ()
  85. (message "Initializing...")
  86. (call-process ghc-module-command nil t nil "-l" "boot")
  87. (message "Initializing...done"))
  88. n)))
  89. (defun ghc-load-modules (mods)
  90. (if (not (executable-find ghc-module-command))
  91. (message "%s not found" ghc-module-command)
  92. (ghc-read-lisp-list
  93. (lambda ()
  94. (message "Loading names...")
  95. (apply 'call-process ghc-module-command nil '(t nil) nil
  96. `(,@(ghc-make-ghc-options) "-l" "browse" ,@mods))
  97. (message "Loading names...done"))
  98. (length mods))))
  99. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  100. ;;;
  101. ;;; Completion
  102. ;;;
  103. (defvar ghc-completion-buffer-name "*Completions*")
  104. (defun ghc-complete ()
  105. (interactive)
  106. (if (ghc-should-scroll)
  107. (ghc-scroll-completion-buffer)
  108. (ghc-try-complete)))
  109. (defun ghc-should-scroll ()
  110. (let ((window (ghc-completion-window)))
  111. (and (eq last-command this-command)
  112. window (window-live-p window) (window-buffer window)
  113. (buffer-name (window-buffer window)))))
  114. (defun ghc-scroll-completion-buffer ()
  115. (let ((window (ghc-completion-window)))
  116. (with-current-buffer (window-buffer window)
  117. (if (pos-visible-in-window-p (point-max) window)
  118. (set-window-start window (point-min))
  119. (save-selected-window
  120. (select-window window)
  121. (scroll-up))))))
  122. (defun ghc-completion-window ()
  123. (get-buffer-window ghc-completion-buffer-name 0))
  124. (defun ghc-try-complete ()
  125. (let* ((end (point))
  126. (symbols (ghc-select-completion-symbol))
  127. (beg (ghc-completion-start-point))
  128. (pattern (buffer-substring-no-properties beg end))
  129. (completion (try-completion pattern symbols)))
  130. (cond
  131. ((eq completion t) ;; completed
  132. ) ;; do nothing
  133. ((null completion) ;; no completions
  134. (ding))
  135. ((not (string= pattern completion)) ;; ???
  136. (delete-region beg end)
  137. (insert completion)
  138. (ghc-reset-window-configuration))
  139. (t ;; multiple completions
  140. (let* ((list0 (all-completions pattern symbols))
  141. (list (sort list0 'string<)))
  142. (if (= (length list) 1)
  143. (ghc-reset-window-configuration)
  144. (ghc-save-window-configuration)
  145. (with-output-to-temp-buffer ghc-completion-buffer-name
  146. (display-completion-list list pattern))))))))
  147. (defun ghc-save-window-configuration ()
  148. (unless (get-buffer-window ghc-completion-buffer-name)
  149. (setq ghc-window-configuration (current-window-configuration))))
  150. (defun ghc-reset-window-configuration ()
  151. (when ghc-window-configuration
  152. (set-window-configuration ghc-window-configuration)
  153. (setq ghc-window-configuration nil)))
  154. (defun ghc-module-completion-p ()
  155. (or (minibufferp)
  156. (let ((end (point)))
  157. (save-excursion
  158. (beginning-of-line)
  159. (and (looking-at "import ")
  160. (not (search-forward "(" end t)))))
  161. (save-excursion
  162. (beginning-of-line)
  163. (looking-at " +module "))))
  164. (defun ghc-select-completion-symbol ()
  165. (cond
  166. ((ghc-module-completion-p)
  167. ghc-module-names)
  168. ((save-excursion
  169. (beginning-of-line)
  170. (looking-at "{-# LANGUAGE "))
  171. ghc-language-extensions)
  172. ((save-excursion
  173. (beginning-of-line)
  174. (looking-at "{-# OPTIONS_GHC "))
  175. ghc-option-flags)
  176. ((save-excursion
  177. (beginning-of-line)
  178. (looking-at "{-# "))
  179. ghc-pragma-names)
  180. ((or (bolp)
  181. (let ((end (point)))
  182. (save-excursion
  183. (beginning-of-line)
  184. (not (search-forward " " end t)))))
  185. ghc-reserved-keyword-for-bol)
  186. (t ghc-merged-keyword)))
  187. (defun ghc-completion-start-point ()
  188. (save-excursion
  189. (let ((beg (save-excursion (beginning-of-line) (point)))
  190. (regex (if (ghc-module-completion-p) "[ (,`]" "[ (,`.]")))
  191. (if (re-search-backward regex beg t)
  192. (1+ (point))
  193. beg))))
  194. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  195. ;;;
  196. ;;; Loading keywords
  197. ;;;
  198. (defun ghc-import-module ()
  199. (interactive)
  200. (when (eq major-mode 'haskell-mode)
  201. (ghc-load-module-buffer)))
  202. (defun ghc-unloaded-modules (mods)
  203. (ghc-filter (lambda (mod)
  204. (and (member mod ghc-module-names)
  205. (not (member mod ghc-loaded-module))))
  206. mods))
  207. (defun ghc-load-module-all-buffers ()
  208. (ghc-load-merge-modules (ghc-gather-import-modules-all-buffers)))
  209. (defun ghc-load-module-buffer ()
  210. (ghc-load-merge-modules (ghc-gather-import-modules-buffer)))
  211. (defun ghc-load-merge-modules (mods)
  212. (let* ((umods (ghc-unloaded-modules mods))
  213. (syms (mapcar 'ghc-module-symbol umods))
  214. (names (ghc-load-modules umods)))
  215. (ghc-set syms names)
  216. (ghc-merge-keywords umods)))
  217. (defun ghc-merge-keywords (mods)
  218. (setq ghc-loaded-module (append mods ghc-loaded-module))
  219. (let* ((modkeys (mapcar 'ghc-module-keyword ghc-loaded-module))
  220. (keywords (cons ghc-reserved-keyword modkeys))
  221. (uniq-sorted (sort (ghc-uniq-lol keywords) 'string<)))
  222. (setq ghc-merged-keyword uniq-sorted)))
  223. (defun ghc-module-symbol (mod)
  224. (intern (concat ghc-keyword-prefix mod)))
  225. (defun ghc-module-keyword (mod)
  226. (symbol-value (ghc-module-symbol mod)))
  227. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. (ghc-defstruct buffer name file)
  229. (defun ghc-buffer-name-file (buf)
  230. (ghc-make-buffer (buffer-name buf) (buffer-file-name buf)))
  231. (defun ghc-gather-import-modules-all-buffers ()
  232. (let ((bufs (mapcar 'ghc-buffer-name-file (buffer-list)))
  233. ret file)
  234. (save-excursion
  235. (dolist (buf bufs (ghc-uniq-lol ret))
  236. (setq file (ghc-buffer-get-file buf))
  237. (when (and file (string-match "\\.hs$" file))
  238. (set-buffer (ghc-buffer-get-name buf))
  239. (ghc-add ret (ghc-gather-import-modules-buffer)))))))
  240. (defun ghc-gather-import-modules-buffer ()
  241. (let (ret)
  242. (save-excursion
  243. (goto-char (point-min))
  244. (while (re-search-forward "^import\\( *qualified\\)? +\\([^\n ]+\\)" nil t)
  245. (ghc-add ret (match-string-no-properties 2))
  246. (forward-line)))
  247. ret))
  248. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  249. ;;;
  250. ;;; Background Idle Timer
  251. ;;;
  252. (defalias 'ghc-idle-timer 'ghc-load-module-all-buffer)
  253. (defun ghc-load-module-all-buffer () nil)
  254. (provide 'ghc-comp)