Difference between revisions of "Haskell mode for Emacs"
Jump to navigation
Jump to search
(mention C-c C-r) |
m |
||
(95 intermediate revisions by 30 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>. However, the released version (2.1) and the Debian package are both very old (Nov 2005). |
||
+ | [[Category: Pages to be removed]] |
||
− | ==Obtaining the CVS version== |
||
− | |||
− | <code>cvs -d :pserver:anoncvs@cvs.haskell.org:/cvs login # password 'cvs' </code> |
||
− | |||
− | <code>cvs -d :pserver:anoncvs@cvs.haskell.org:/cvs co fptools/CONTRIB/haskell-modes/emacs</code> |
||
− | |||
− | ==Minimal Setup== |
||
− | |||
− | Insert in your ~/.emacs or appropriate file: |
||
− | |||
− | <code> |
||
− | (add-to-list 'load-path "path/to/haskell-mode") |
||
− | </code> |
||
− | |||
− | <code>(load "haskell-site-file")</code> |
||
− | |||
− | <code>(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode) </code> |
||
− | |||
− | <code>(add-hook 'haskell-mode-hook 'turn-on-haskell-indent) |
||
− | </code> |
||
− | |||
− | <code>;; enable auto-mode selection:</code> |
||
− | |||
− | <code>(add-to-list 'auto-mode-alist '("\\.hs\\'" . 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 |
||
− | *<code>C-c C-.</code> aligns code over a region in a "sensible" fashion. |
||
− | |||
− | 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 could also achieve the same effect by selecting the region and typing <code>C-c C-.</code> |
||
− | |||
− | 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. Then, you can go on to type <code>C-c C-r</code> to reload the current module when you have made a change. |
||
− | |||
− | 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. |
||
− | |||
− | ===Xemacs=== |
||
− | 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. |
||
− | |||
− | === Hoogle lookup === |
||
− | This code adds hoogle lookup for emacs mode. If the current line contains a type signature, it is hoogled. Otherwise, the word at point is hoogled. |
||
− | <pre-lisp> |
||
− | (defun haskell-hoogle (query) |
||
− | "Hoogle search for QUERY via browse-url" |
||
− | (browse-url (concat "www.haskell.org/hoogle/?q=" query))) |
||
− | |||
− | (defun haskell-hoogle-point () |
||
− | "If point is at a type, hoogle for it. Else, hoogle for the word at point." |
||
− | (interactive) |
||
− | (if (save-excursion |
||
− | (beginning-of-line) |
||
− | (looking-at ".+::\\(.+\\)")) |
||
− | (haskell-hoogle (match-string 1)) |
||
− | (haskell-hoogle (haskell-doc-get-current-word)))) |
||
− | |||
− | (add-hook 'haskell-mode-hook |
||
− | (lambda () |
||
− | (local-set-key (kbd "C-c C-d h") 'haskell-hoogle-point))) |
||
− | |||
− | </pre-lisp> |
||
− | |||
− | === Using Rectangular region commands === |
||
− | |||
− | Emacs has a set of commands which operate on the region as if it were rectangular. This turns out to be extremely useful when dealing with whitespace sensitive languages. |
||
− | |||
− | <code>C-x r o</code> is "Open Rectangle". It will shift any text within the rectangle to the right side. |
||
− | |||
− | <code>C-x r d</code> is "Delete Rectangle". It will delete the contents of the rectangle and move anything on the right over. |
||
− | |||
− | <code>C-x r x</code> is "Copy Rectangle to Register". It will prompt you for a register number so it can save it for later. |
||
− | |||
− | <code>C-x r g</code> is "Insert register". This will insert the contents of the given register, overwriting whatever happens to be within the target rectangle. |
||
− | |||
− | As with all Emacs modifier combos, you can type <code>C-x r C-h</code> to find out what keys are bound beginning with the <code>C-x r</code> prefix. |
||
− | |||
− | === Aligning Code === |
||
− | |||
− | Emacs22 has a neat tool called: align-regexp. Select a region you want to align text within, M-x align-regexp, and type a regexp representing the alignment delimiter. |
||
− | |||
− | For example, I often line up my Haddock comments: |
||
− | |||
− | <haskell> |
||
− | f :: a -- ^ does a |
||
− | -> Foo b -- ^ and b |
||
− | -> c -- ^ to c |
||
− | </haskell> |
||
− | |||
− | Select the region, and let the regexp be: <code>--</code> |
||
− | |||
− | <haskell> |
||
− | f :: a -- ^ does a |
||
− | -> Foo b -- ^ and b |
||
− | -> c -- ^ to c |
||
− | </haskell> |
||
− | |||
− | Of course, this works for just about anything. Personally, I've globally bound it to <code>C-x a r</code>: |
||
− | |||
− | <code>(global-set-key (kbd "C-x a r") 'align-regexp)</code>. |
||
− | |||
− | [[Category:Development tools]] |
Latest revision as of 06:27, 8 June 2023
Redirect to: