ghc-mod/elisp/ghc-check.el
Kazu Yamamoto 0564042b48 adding ghc-check.el finally.
Still developping.
2014-03-19 15:03:03 +09:00

136 lines
3.9 KiB
EmacsLisp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; ghc-check.el
;;;
;; Author: Kazu Yamamoto <Kazu@Mew.org>
;; Created: Mar 9, 2014
;;; Code:
(require 'ghc-func)
(defvar-local ghc-check-running nil)
(defvar-local ghc-check-process-name nil)
(defvar-local ghc-check-original-buffer nil)
(defvar-local ghc-check-original-file nil)
(defun ghc-check-get-process-name ()
(let ((file (buffer-file-name)))
(with-temp-buffer
(ghc-call-process ghc-module-command nil t nil "debug" file)
(goto-char (point-min))
(when (re-search-forward "^Root directory: +\\(.*\\)$" nil t)
(match-string-no-properties 1)))))
(defun ghc-check-syntax ()
(unless ghc-check-process-name
(setq ghc-check-process-name (ghc-check-get-process-name)))
(if (null ghc-check-process-name)
(message "Can't check")
(let* ((cbuf (current-buffer))
(name ghc-check-process-name)
(buf (get-buffer-create (concat " ghc-modi:" name)))
(file (buffer-file-name))
(cpro (get-process name)))
(with-current-buffer buf
(unless ghc-check-running
(setq ghc-check-running t)
(setq ghc-check-original-buffer cbuf)
(setq ghc-check-original-file file)
(erase-buffer)
(let ((pro (ghc-check-get-process cpro name buf)))
(process-send-string pro (concat file "\n"))))))))
(defun ghc-check-get-process (cpro name buf)
(cond
((not cpro)
(ghc-check-start-process name buf))
((not (eq (process-status cpro) 'run))
(delete-process cpro)
(ghc-check-start-process name buf))
(t cpro)))
(defun ghc-check-start-process (name buf)
(let ((pro (start-file-process name buf "ghc-modi")))
(set-process-filter pro 'ghc-check-process-filter)
(set-process-sentinel pro 'ghc-check-process-sentinel)
(set-process-query-on-exit-flag pro nil)
pro))
(ghc-defstruct hilit-info file line col msg)
(defun ghc-check-process-filter (process string)
(with-current-buffer (process-buffer process)
(goto-char (point-max))
(insert string)
(forward-line -1)
(cond
((looking-at "^NG$")
(setq ghc-check-running nil)
(message "An error happens"))
((looking-at "^OK$")
(goto-char (point-min))
(let ((regex "^\\(.*\\):\\([0-9]+\\):\\([0-9]+\\): *\\(.+\\)")
info infos)
(while (re-search-forward regex nil t)
(setq info (ghc-make-hilit-info
:file (match-string 1)
:line (string-to-number (match-string 2))
:col (string-to-number (match-string 3))
:msg (match-string 4)))
(setq infos (cons info infos)))
(setq infos (nreverse infos))
(cond
(infos
(ghc-check-highlight-original-buffer ghc-check-original-buffer infos))
(t
(message "No changes")))
(setq ghc-check-running nil))))))
(defun ghc-check-process-sentinel ()
)
(defun ghc-check-highlight-original-buffer (buf infos)
(message "%s" infos)
(with-current-buffer buf
(remove-overlays (point-min) (point-max) 'ghc-check t)
(save-excursion
(goto-char (point-min))
(dolist (info infos)
(let ((line (ghc-hilit-info-get-line info))
(msg (ghc-hilit-info-get-msg info))
beg end ovl)
(goto-line line)
(while (eq (char-after) 32) (forward-char))
(setq beg (point))
(forward-line)
(setq end (1- (point)))
(setq ovl (make-overlay beg end))
(overlay-put ovl 'ghc-check t)
(overlay-put ovl 'ghc-msg msg) ;; should be list
(let ((face (if (string-match "^Error" msg)
'ghc-face-error
'ghc-face-warn)))
(overlay-put ovl 'face face)))))))
;; stolen from flymake.el
(defface ghc-face-error
'((((supports :underline (:style wave)))
:underline (:style wave :color "Red1"))
(t
:inherit error))
"Face used for marking error lines."
:group 'ghc)
(defface ghc-face-warn
'((((supports :underline (:style wave)))
:underline (:style wave :color "DarkOrange"))
(t
:inherit warning))
"Face used for marking warning lines."
:group 'ghc)
(provide 'ghc-check)