diff --git a/doc/haskell-mode.texi b/doc/haskell-mode.texi index a76854fa2..f1a5fe814 100644 --- a/doc/haskell-mode.texi +++ b/doc/haskell-mode.texi @@ -730,6 +730,21 @@ associated with at most one GHCi session, so when you call no session associated yet, you're asked which GHCi session to create or associate with. +@section Goto Error + +In a Haskell source buffer associated with a GHCi session, errors that +prevent the file from loading are highlighted with +@code{haskell-error-face}. You can move between these error lines with + +@table @kbd +@item M-n +is bound to @code{haskell-goto-next-error} +@item M-p +is bound to @code{haskell-goto-prev-error} +@item C-c M-p +is bound to @code{haskell-goto-first-error} +@end table + @section Using GHCi-ng Put @code{:set +c} in your @code{.ghci} or run it in the REPL. Then use diff --git a/haskell-load.el b/haskell-load.el index dc2647b64..4bd622d21 100644 --- a/haskell-load.el +++ b/haskell-load.el @@ -346,6 +346,12 @@ correspondingly-named overlay properties of OVL." (t (message "No further notes from Haskell compiler.")))) +(defun haskell-goto-first-error () + (interactive) + (haskell-goto-error-overlay + (first-overlay-in-if 'haskell-check-overlay-p + (buffer-end 0) (buffer-end 1)))) + (defun haskell-goto-prev-error () (interactive) (haskell-goto-error-overlay diff --git a/haskell.el b/haskell.el index d8d424dfc..cbf5c816f 100644 --- a/haskell.el +++ b/haskell.el @@ -54,6 +54,7 @@ (define-key map [?\C-c ?\C-z] 'haskell-interactive-switch) (define-key map (kbd "M-n") 'haskell-goto-next-error) (define-key map (kbd "M-p") 'haskell-goto-prev-error) + (define-key map (kbd "C-c M-p") 'haskell-goto-first-error) map) "Keymap for using haskell-interactive-mode.") diff --git a/tests/haskell-load-tests.el b/tests/haskell-load-tests.el new file mode 100644 index 000000000..227f2e180 --- /dev/null +++ b/tests/haskell-load-tests.el @@ -0,0 +1,85 @@ +;;; haskell-load-tests.el + +;;; Code: + +(require 'ert) +(require 'haskell-test-utils) + +(require 'haskell-load) + +(defun insert-errors () + (insert "import Control.Applicativ\nimport Data.Mayb\nimport Data.String") + (goto-char 1) + (let ((applicativ (progn + (search-forward "Control.Applicativ") + (make-overlay (match-beginning 0) (match-end 0))))) + (overlay-put applicativ 'haskell-check t) + (overlay-put applicativ 'haskell-msg-type 'error) + (overlay-put applicativ 'haskell-msg "Could not find module ‘Control.Applicativ’\n Perhaps you meant Control.Applicative (from base-4.8.1.0)\n Use -v to see a list of the files searched for.")) + (let ((mayb (progn + (search-forward "Data.Mayb") + (make-overlay (match-beginning 0) (match-end 0))))) + (overlay-put mayb 'haskell-check t) + (overlay-put mayb 'haskell-msg-type 'error) + (overlay-put mayb 'haskell-msg "Could not find module ‘Data.Mayb’\n Perhaps you meant\n Data.Maybe (from base-4.8.1.0)\n Data.Map (from containers-0.5.6.2@conta_LKCPrTJwOTOLk4OU37YmeN)\n Use -v to see a list of the files searched for.")) + (goto-char 1)) + +(ert-deftest goto-first-error-before () + (with-temp-switch-to-buffer + (insert-errors) + (haskell-goto-first-error) + (should (looking-at-p "Control.Applicativ")))) + +(ert-deftest goto-first-error-after () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "Data.String") + (haskell-goto-first-error) + (should (looking-at-p "Control.Applicativ")))) + +(ert-deftest goto-first-error-between () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "import Data.Mayb") + (haskell-goto-first-error) + (should (looking-at-p "Control.Applicativ")))) + +(ert-deftest goto-next-error-before () + (with-temp-switch-to-buffer + (insert-errors) + (haskell-goto-next-error) + (should (looking-at-p "Control.Applicativ")))) + +(ert-deftest goto-next-error-between () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "import" nil nil 2) + (haskell-goto-next-error) + (should (looking-at-p "Data.Mayb")))) + +(ert-deftest goto-next-error-after () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "import" nil nil 3) + (haskell-goto-next-error) + (should (looking-at-p " Data.String")))) + +(ert-deftest goto-prev-error-before () + (with-temp-switch-to-buffer + (insert-errors) + (haskell-goto-prev-error) + (should (looking-at-p "import Control.Applicativ")))) + +(ert-deftest goto-prev-error-between () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "import" nil nil 2) + (haskell-goto-prev-error) + (should (looking-at-p "Control.Applicativ")))) + +(ert-deftest goto-prev-error-after () + (with-temp-switch-to-buffer + (insert-errors) + (search-forward "import Data.String") + (haskell-goto-prev-error) + (should (looking-at-p "Data.Mayb"))))