Difference between revisions of "Haskell mode for Emacs"

From HaskellWiki
Jump to navigation Jump to search
(HaWiki conversion / add XEmacs fixes)
 
(Redirect to Emacs which will be part of a series of pages.)
(102 intermediate revisions by 29 users not shown)
Line 1: Line 1:
  +
#REDIRECT[[Emacs]]
haskell-mode is a major mode for Emacs and XEmacs specifically for writing Haskell code. You can get HaskellMode from the web page: http://www.haskell.org/haskell-mode/ or on Debian you can type <code>apt-get install haskell-mode</code>.
 
==Tips and use==
 
Handy keybindings in haskell-mode. See the documentation <code>C-h m</code> for more information:
 
*<code>C-c C-=</code> inserts an = sign and lines up type signatures and other pattern matches nicely.
 
*<code>C-c C-|</code> inserts a guard
 
*<code>C-c C-o</code> inserts a guard <hask>| otherwise =</hask> and lines up existing guards
 
*<code>C-c C-w</code> inserts a where keyword
 
 
Here's an example for <code>C-c C-=</code>. Put your cursor after myInt and hit <code>C-c C-=</code>
 
<haskell>
 
blah :: Int -> Int
 
blah myInt
 
</haskell>
 
note how the function signature is reindented to match the column of the = sign.
 
<haskell>
 
blah :: Int -> Int
 
blah myInt =
 
</haskell>
 
 
You can also use Haskell-Mode to load Emacs buffers with Haskell code in either Hugs or GHC. To load something in Hugs or ghci, type <code>C-c C-l</code> to load the file.
 
 
If you have imenu (standard in Emacs and available as a package in XEmacs), you can use <code>M-x imenu</code> to jump to any definition in the file. A good keybinding for it is:
 
<pre-lisp>
 
(global-set-key [(control meta down-mouse-3)] 'imenu)
 
</pre-lisp>
 
If you don't have imenu but have func-menu you can do
 
<pre-lisp>
 
(add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
 
</pre-lisp>
 
after which some keybindings will be available, such as:
 
*<code>C-c l</code> fume-list-functions - quickly jump to a function definition in this file.
 
 
== Questions ==
 
* haddock integration with haskell-doc.el ?
 
 
== Bugs ==
 
* Debian maintains a list of bugs for haskell-mode [http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=haskell-mode here].
 
* haskell-mode does not check for unsent input at a ghci prompt before sending a <code>:load myfilename</code> command to ghci.
 
 
On some the linux systems with XEmacs, admittedly, only verified on Ubuntu and Debian), there is a system function missing that interferes with automatic indenting. Secondly, there seems to be an issue with setting the <code-lisp>haskell-default-face</code-lisp> to <code-lisp>nil</code-lisp>.
 
 
===line-end-position===
 
 
To fix this, find where the haskell mode package is installed on your system. (Usually <code>/usr/share/emacs/site-lisp/haskell-mode</code>). Edit the file <code>haskell-indent.el</code> and add the lines:
 
<pre-lisp>
 
(eval-and-compile
 
 
;; If `line-end-position' isn't available provide one.
 
(unless (fboundp 'line-end-position)
 
(defun line-end-position (&optional n)
 
"Return the `point' of the end of the current line."
 
(save-excursion
 
(end-of-line n)
 
(point)))))
 
</pre-lisp>
 
right after the comments at the top. That should fix the issue.
 
 
===haskell-default-face===
 
 
This one shows up when typing in code (at various spots - most often when typing a qualified function, such as <hask>List.map</hask>.)
 
 
To fix this one, edit the file <code>haskell-font-lock.el</code>. Look for the line that says:
 
<pre-lisp>
 
(defvar haskell-default-face nil)
 
</pre-lisp>
 
and change this to
 
<pre-lisp>
 
(defvar haskell-default-face 'default)
 
</pre-lisp>
 
In my version, this is line 168.
 
 
Then, look for the line that says:
 
<pre-lisp>
 
(,qvarid 0 haskell-default-face)
 
</pre-lisp>
 
and change it to
 
<pre-lisp>
 
(,qvarid 0 (symbol-value 'haskell-default-face))
 
</pre-lisp>
 
 
For me, this is line 326 of the file.
 
YMMV - hope this helps.
 
 
 
 
 
== Tricks and Tweaks ==
 
 
=== Automatic Unit Testing ===
 
Here's a cute trick I've evolved:
 
 
I'm a great fan of [[unit test first]], as described by eXtremeProgramming on TheOriginalWiki.
 
 
With the code below, I can press F12 and immediately run all of my unit tests, and immediately see whether they all passed or not.
 
I've put all of my unit tests into their own file with a main function that runs the tests and gives an exitcode according to the test results. I've specified that the compile-command for that file compiles and runs the file.
 
 
This elisp code will run the <code>compile</code> command from the F12 key in emacs. The output will popup a new window twelve lines tall. If the compilation is successful (exitcode zero) the window goes away. If the exitcode is 1 or greater, the window stays so you can see the output.
 
<pre-lisp>
 
(require 'compile)
 
 
;; this means hitting the compile button always saves the buffer
 
;; having to separately hit C-x C-s is a waste of time
 
(setq mode-compile-always-save-buffer-p t)
 
;; make the compile window stick at 12 lines tall
 
(setq compilation-window-height 12)
 
 
;; from enberg on #emacs
 
;; if the compilation has a zero exit code,
 
;; the windows disappears after two seconds
 
;; otherwise it stays
 
(setq compilation-finish-function
 
(lambda (buf str)
 
(unless (string-match "exited abnormally" str)
 
;;no errors, make the compilation window go away in a few seconds
 
(run-at-time
 
"2 sec" nil 'delete-windows-on
 
(get-buffer-create "*compilation*"))
 
(message "No Compilation Errors!"))))
 
 
 
;; one-button testing, tada!
 
(global-set-key [f12] 'compile)
 
</pre-lisp>
 
 
 
This Haskell code has some Emacs local variable settings at the bottom specifying what the compile-command should be for this buffer.
 
<haskell>
 
import HUnit
 
import System
 
 
myTestList =
 
TestList [
 
"add numbers" ~: 5 ~=? (3 + 2)
 
,"add numbers" ~: 5 ~=? (3 + 3)
 
]
 
 
h = runTestTT myTestList
 
 
main = do c <- h
 
putStr $ show c
 
let errs = errors c
 
fails = failures c
 
System.exitWith (codeGet errs fails)
 
 
codeGet errs fails
 
| fails > 0 = ExitFailure 2
 
| errs > 0 = ExitFailure 1
 
| otherwise = ExitSuccess
 
 
-- Local Variables:
 
-- compile-command: "ghc --make -o Test_Demo -i/home/shae/src/haskell/libraries/ HUnitDemo.hs && ./Test_Demo"
 
-- End:
 
</haskell>
 
 
 
If you have any questions, ideas, or suggestions for this code, the maintainer would love to hear them.
 
 
[[Category:Development tools]]
 

Revision as of 10:01, 18 May 2012

Redirect to: