2010-01-06 05:38:06 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; ghc-comp.el
|
|
|
|
;;;
|
|
|
|
|
|
|
|
;; Author: Kazu Yamamoto <Kazu@Mew.org>
|
|
|
|
;; Created: Sep 25, 2009
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
(require 'ghc-func)
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Customize Variables
|
|
|
|
;;;
|
|
|
|
|
2010-06-14 03:03:14 +00:00
|
|
|
(defvar ghc-idle-timer-interval 30
|
|
|
|
"*Period of idele timer in second. When timeout, the names of
|
|
|
|
unloaded modules are loaded")
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Constants
|
|
|
|
;;;
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
;; must be sorted
|
2010-06-14 03:03:14 +00:00
|
|
|
(defconst ghc-reserved-keyword-for-bol '("class" "data" "default" "import" "infix" "infixl" "infixr" "instance" "main" "module" "newtype" "type"))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
;; must be sorted
|
2010-06-14 03:03:14 +00:00
|
|
|
(defconst ghc-reserved-keyword '("case" "deriving" "do" "else" "if" "in" "let" "module" "of" "then" "where"))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
2010-03-10 06:33:18 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Local Variables
|
|
|
|
;;;
|
|
|
|
|
|
|
|
(defvar ghc-window-configuration nil)
|
|
|
|
|
|
|
|
(mapc 'make-variable-buffer-local
|
|
|
|
'(ghc-window-configuration))
|
|
|
|
|
2010-01-06 05:38:06 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Initializer
|
|
|
|
;;;
|
|
|
|
|
|
|
|
(defvar ghc-module-names nil) ;; completion for "import"
|
|
|
|
(defvar ghc-merged-keyword nil) ;; completion for type/func/...
|
2010-04-02 06:37:04 +00:00
|
|
|
(defvar ghc-language-extensions nil)
|
2010-01-06 05:38:06 +00:00
|
|
|
|
2010-06-14 03:03:14 +00:00
|
|
|
(defconst ghc-keyword-prefix "ghc-keyword-")
|
2010-01-06 05:38:06 +00:00
|
|
|
(defvar ghc-keyword-Prelude nil)
|
|
|
|
(defvar ghc-loaded-module nil)
|
|
|
|
|
|
|
|
(defun ghc-comp-init ()
|
2010-05-04 03:49:22 +00:00
|
|
|
(let* ((syms '(ghc-module-names
|
|
|
|
ghc-language-extensions
|
|
|
|
ghc-keyword-Prelude))
|
2010-05-04 08:52:16 +00:00
|
|
|
(vals (ghc-boot (length syms))))
|
2010-05-04 03:49:22 +00:00
|
|
|
(ghc-set syms vals))
|
2010-05-04 07:35:40 +00:00
|
|
|
(ghc-add ghc-module-names "qualified")
|
|
|
|
(ghc-add ghc-module-names "hiding")
|
|
|
|
(ghc-add ghc-language-extensions "LANGUAGE")
|
2010-05-04 08:52:16 +00:00
|
|
|
(ghc-merge-keywords '("Prelude"))
|
2010-01-06 05:38:06 +00:00
|
|
|
(run-with-idle-timer ghc-idle-timer-interval 'repeat 'ghc-idle-timer))
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Executing command
|
|
|
|
;;;
|
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
(defun ghc-boot (n)
|
2010-01-07 01:51:05 +00:00
|
|
|
(if (not (ghc-which ghc-module-command))
|
|
|
|
(message "%s not found" ghc-module-command)
|
2010-05-04 08:52:16 +00:00
|
|
|
(ghc-read-lisp-list
|
2010-01-06 05:38:06 +00:00
|
|
|
(lambda ()
|
2010-05-04 08:52:16 +00:00
|
|
|
(message "Initializing...")
|
|
|
|
(call-process ghc-module-command nil t nil "-l" "boot")
|
|
|
|
(message "Initializing...done"))
|
|
|
|
n)))
|
|
|
|
|
|
|
|
(defun ghc-load-modules (mods)
|
|
|
|
(if (not (ghc-which ghc-module-command))
|
|
|
|
(message "%s not found" ghc-module-command)
|
|
|
|
(ghc-read-lisp-list
|
|
|
|
(lambda ()
|
|
|
|
(message "Loading names...")
|
|
|
|
(apply 'call-process ghc-module-command nil t nil
|
|
|
|
(cons "-l" (cons "browse" mods)))
|
|
|
|
(message "Loading names...done"))
|
|
|
|
(length mods))))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Completion
|
|
|
|
;;;
|
|
|
|
|
|
|
|
(defvar ghc-completion-buffer-name "*Completions*")
|
|
|
|
|
|
|
|
(defun ghc-complete ()
|
|
|
|
(interactive)
|
|
|
|
(if (ghc-should-scroll)
|
|
|
|
(ghc-scroll-completion-buffer)
|
|
|
|
(ghc-try-complete)))
|
|
|
|
|
|
|
|
(defun ghc-should-scroll ()
|
|
|
|
(let ((window (ghc-completion-window)))
|
|
|
|
(and (eq last-command this-command)
|
|
|
|
window (window-live-p window) (window-buffer window)
|
|
|
|
(buffer-name (window-buffer window)))))
|
|
|
|
|
|
|
|
(defun ghc-scroll-completion-buffer ()
|
|
|
|
(let ((window (ghc-completion-window)))
|
|
|
|
(with-current-buffer (window-buffer window)
|
|
|
|
(if (pos-visible-in-window-p (point-max) window)
|
|
|
|
(set-window-start window (point-min))
|
|
|
|
(save-selected-window
|
|
|
|
(select-window window)
|
|
|
|
(scroll-up))))))
|
|
|
|
|
|
|
|
(defun ghc-completion-window ()
|
|
|
|
(get-buffer-window ghc-completion-buffer-name 0))
|
|
|
|
|
|
|
|
(defun ghc-try-complete ()
|
|
|
|
(let* ((end (point))
|
|
|
|
(symbols (ghc-select-completion-symbol))
|
|
|
|
(beg (ghc-completion-start-point))
|
|
|
|
(pattern (buffer-substring-no-properties beg end))
|
|
|
|
(completion (try-completion pattern symbols)))
|
|
|
|
(cond
|
|
|
|
((eq completion t) ;; completed
|
|
|
|
) ;; do nothing
|
|
|
|
((null completion) ;; no completions
|
|
|
|
(ding))
|
|
|
|
((not (string= pattern completion)) ;; ???
|
|
|
|
(delete-region beg end)
|
|
|
|
(insert completion)
|
2010-03-10 06:33:18 +00:00
|
|
|
(ghc-reset-window-configuration))
|
2010-01-06 05:38:06 +00:00
|
|
|
(t ;; multiple completions
|
|
|
|
(let* ((list0 (all-completions pattern symbols))
|
|
|
|
(list (sort list0 'string<)))
|
2010-03-10 06:33:18 +00:00
|
|
|
(if (= (length list) 1)
|
|
|
|
(ghc-reset-window-configuration)
|
|
|
|
(ghc-save-window-configuration)
|
|
|
|
(with-output-to-temp-buffer ghc-completion-buffer-name
|
|
|
|
(display-completion-list list pattern))))))))
|
|
|
|
|
|
|
|
(defun ghc-save-window-configuration ()
|
|
|
|
(unless (get-buffer-window ghc-completion-buffer-name)
|
|
|
|
(setq ghc-window-configuration (current-window-configuration))))
|
|
|
|
|
|
|
|
(defun ghc-reset-window-configuration ()
|
|
|
|
(when ghc-window-configuration
|
|
|
|
(set-window-configuration ghc-window-configuration)
|
|
|
|
(setq ghc-window-configuration nil)))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
2010-07-16 10:02:23 +00:00
|
|
|
(defun ghc-module-completion-p ()
|
|
|
|
(or (minibufferp)
|
2010-08-03 03:26:25 +00:00
|
|
|
(let ((end (point)))
|
|
|
|
(save-excursion
|
|
|
|
(beginning-of-line)
|
|
|
|
(and (looking-at "import ")
|
|
|
|
(not (search-forward "(" end t)))))
|
2010-07-16 10:02:23 +00:00
|
|
|
(save-excursion
|
|
|
|
(beginning-of-line)
|
2010-08-03 03:26:25 +00:00
|
|
|
(looking-at " +module "))))
|
2010-07-16 10:02:23 +00:00
|
|
|
|
2010-01-06 05:38:06 +00:00
|
|
|
(defun ghc-select-completion-symbol ()
|
|
|
|
(cond
|
2010-07-16 10:02:23 +00:00
|
|
|
((ghc-module-completion-p)
|
2010-01-06 05:38:06 +00:00
|
|
|
ghc-module-names)
|
2010-04-02 06:37:04 +00:00
|
|
|
((save-excursion
|
|
|
|
(beginning-of-line)
|
|
|
|
(looking-at "{-#"))
|
|
|
|
ghc-language-extensions)
|
2010-01-06 05:38:06 +00:00
|
|
|
((or (bolp)
|
|
|
|
(let ((end (point)))
|
|
|
|
(save-excursion
|
|
|
|
(beginning-of-line)
|
|
|
|
(not (search-forward " " end t)))))
|
|
|
|
ghc-reserved-keyword-for-bol)
|
|
|
|
(t ghc-merged-keyword)))
|
|
|
|
|
|
|
|
(defun ghc-completion-start-point ()
|
|
|
|
(save-excursion
|
2010-06-27 12:35:49 +00:00
|
|
|
(let ((beg (save-excursion (beginning-of-line) (point)))
|
2010-07-16 10:02:23 +00:00
|
|
|
(regex (if (ghc-module-completion-p) "[ (,`]" "[ (,`.]")))
|
2010-06-27 12:35:49 +00:00
|
|
|
(if (re-search-backward regex beg t)
|
2010-01-06 05:38:06 +00:00
|
|
|
(1+ (point))
|
|
|
|
beg))))
|
|
|
|
|
2010-01-06 05:39:30 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Loading keywords
|
|
|
|
;;;
|
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
(add-hook 'find-file-hook 'ghc-import-module)
|
2010-03-10 06:54:27 +00:00
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
(defun ghc-import-module ()
|
2010-03-10 06:54:27 +00:00
|
|
|
(interactive)
|
|
|
|
(when (eq major-mode 'haskell-mode)
|
2010-05-04 08:52:16 +00:00
|
|
|
(ghc-load-module-buffer)))
|
|
|
|
|
|
|
|
(defun ghc-unloaded-modules (mods)
|
|
|
|
(ghc-filter (lambda (mod)
|
|
|
|
(and (member mod ghc-module-names)
|
|
|
|
(not (member mod ghc-loaded-module))))
|
|
|
|
mods))
|
|
|
|
|
|
|
|
(defun ghc-load-module-all-buffers ()
|
|
|
|
(ghc-load-merge-modules (ghc-gather-import-modules-all-buffers)))
|
|
|
|
|
|
|
|
(defun ghc-load-module-buffer ()
|
|
|
|
(ghc-load-merge-modules (ghc-gather-import-modules-buffer)))
|
|
|
|
|
|
|
|
(defun ghc-load-merge-modules (mods)
|
|
|
|
(let* ((umods (ghc-unloaded-modules mods))
|
|
|
|
(syms (mapcar 'ghc-module-symbol umods))
|
|
|
|
(names (ghc-load-modules umods)))
|
|
|
|
(ghc-set syms names)
|
|
|
|
(ghc-merge-keywords umods)))
|
|
|
|
|
|
|
|
(defun ghc-merge-keywords (mods)
|
|
|
|
(setq ghc-loaded-module (append mods ghc-loaded-module))
|
2010-01-06 05:39:30 +00:00
|
|
|
(let* ((modkeys (mapcar 'ghc-module-keyword ghc-loaded-module))
|
|
|
|
(keywords (cons ghc-reserved-keyword modkeys))
|
|
|
|
(uniq-sorted (sort (ghc-uniq-lol keywords) 'string<)))
|
|
|
|
(setq ghc-merged-keyword uniq-sorted)))
|
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
(defun ghc-module-symbol (mod)
|
|
|
|
(intern (concat ghc-keyword-prefix mod)))
|
|
|
|
|
|
|
|
(defun ghc-module-keyword (mod)
|
|
|
|
(symbol-value (ghc-module-symbol mod)))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(defun ghc-gather-import-modules-all-buffers ()
|
2010-01-06 05:38:06 +00:00
|
|
|
(let ((bufs (mapcar 'buffer-name (buffer-list)))
|
|
|
|
ret)
|
|
|
|
(save-excursion
|
2010-05-04 08:52:16 +00:00
|
|
|
(dolist (buf bufs (ghc-uniq-lol ret))
|
2010-01-06 05:38:06 +00:00
|
|
|
(when (string-match "\\.hs$" buf)
|
|
|
|
(set-buffer buf)
|
2010-05-04 08:52:16 +00:00
|
|
|
(ghc-add ret (ghc-gather-import-modules-buffer)))))))
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
(defun ghc-gather-import-modules-buffer ()
|
|
|
|
(let (ret)
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (point-min))
|
2010-05-04 08:52:16 +00:00
|
|
|
(while (re-search-forward "^import\\( *qualified\\)? +\\([^\n ]+\\)" nil t)
|
|
|
|
(ghc-add ret (match-string-no-properties 2))
|
2010-01-06 05:38:06 +00:00
|
|
|
(forward-line)))
|
|
|
|
ret))
|
|
|
|
|
2010-05-04 08:52:16 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;
|
|
|
|
;;; Background Idle Timer
|
|
|
|
;;;
|
|
|
|
|
|
|
|
(defalias 'ghc-idle-timer 'ghc-load-module-all-buffer)
|
|
|
|
|
|
|
|
(defun ghc-load-module-all-buffer () nil)
|
2010-01-06 05:38:06 +00:00
|
|
|
|
|
|
|
(provide 'ghc-comp)
|