Adding emacs stuff

This commit is contained in:
Hunter Haugen 2009-11-26 09:41:34 +05:30
parent 4cd060c128
commit 7a1b0e4178
31 changed files with 26489 additions and 3 deletions

183
.emacs Normal file
View file

@ -0,0 +1,183 @@
(mapcar (lambda (x) (add-to-list 'load-path (expand-file-name x)))
'("~/.emacs.d"
"/usr/share/emacs/site-lisp/clojure-mode"
"/usr/share/emacs/site-lisp/slime"
"/usr/share/emacs/site-lisp/swank-clojure"))
(defun require-all (packages)
(mapcar #'require packages))
(require-all '(
linum
ido
color-theme
gentooish
parenface
bar-cursor
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GLOBAL
(color-theme-initialize)
(if window-system
(color-theme-gentooish)
(color-theme-dark-laptop))
(bar-cursor-mode 1)
(tool-bar-mode 0)
(menu-bar-mode 0)
(global-linum-mode)
(setq linum-format "%3d ")
(setq-default indent-tabs-mode nil)
(setq indent-tabs-mode nil)
(winner-mode t)
(tooltip-mode nil)
(setq line-number-mode nil)
(setq column-number-mode nil)
(setq size-indication-mode nil)
(setq mode-line-position nil)
(ido-mode 1)
(global-set-key "\C-m" 'reindent-then-newline-and-indent) ;No tabs
(global-set-key "\C-a" 'beginning-of-line-text)
(defun indent-or-expand (arg)
"Either indent according to mode, or expand the word preceding
point."
(interactive "*P")
(if (and
(or (bobp) (= ?w (char-syntax (char-before))))
(or (eobp) (not (= ?w (char-syntax (char-after))))))
(dabbrev-expand arg)
(indent-according-to-mode)))
(global-set-key [C-tab] 'indent-according-to-mode)
;; Prevent Emacs from stupidly auto-changing my working directory
(defun find-file-save-default-directory ()
(interactive)
(setq saved-default-directory default-directory)
(ido-find-file)
(setq default-directory saved-default-directory))
(global-set-key "\C-x\C-f" 'find-file-save-default-directory)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Haskell mode
;;
(load "~/.emacs.d/haskell-mode/haskell-site-file")
(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Generic Lisp / Emacs Lisp
;; from http://www.emacswiki.org/emacs/AutoIndentation
(defadvice yank (after indent-region activate)
(if (member major-mode '(clojure-mode emacs-lisp-mode lisp-mode))
(let ((mark-even-if-inactive t))
(indent-region (region-beginning) (region-end) nil))))
(defun tab-fix ()
(local-set-key [tab] 'indent-or-expand))
(defun slime-tab-fix ()
(local-set-key [tab] 'slime-complete-symbol))
(add-hook 'emacs-lisp-mode-hook 'tab-fix)
(add-hook 'lisp-mode-hook 'slime-tab-fix)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Clojure / SLIME
(require 'swank-clojure-autoload)
(setq swank-clojure-binary "~/local/bin/clj-server")
(require-all '(
slime
clojure-mode
))
;(setq slime-net-coding-system 'utf-8-unix)
(setq auto-mode-alist
(cons '("\\.clj$" . clojure-mode)
auto-mode-alist))
;(set-language-environment "UTF-8")
;(setq slime-net-coding-system 'utf-8-unix)
;;(slime-setup '(slime-fancy))
(slime-setup)
(define-key clojure-mode-map (kbd "<tab>") 'indent-or-expand)
(add-hook 'slime-connected-hook 'slime-redirect-inferior-output)
(defun lisp-enable-paredit-hook () (paredit-mode 1))
(add-hook 'clojure-mode-hook 'lisp-enable-paredit-hook)
(defmacro defclojureface (name color desc &optional others)
`(defface ,name '((((class color)) (:foreground ,color ,@others))) ,desc :group 'faces))
(defclojureface clojure-parens "DimGrey" "Clojure parens")
(defclojureface clojure-braces "#49b2c7" "Clojure braces")
(defclojureface clojure-brackets "SteelBlue" "Clojure brackets")
(defclojureface clojure-keyword "khaki" "Clojure keywords")
(defclojureface clojure-namespace "#c476f1" "Clojure namespace")
(defclojureface clojure-java-call "#4bcf68" "Clojure Java calls")
(defclojureface clojure-special "#b8bb00" "Clojure special")
(defclojureface clojure-double-quote "#b8bb00" "Clojure special" (:background "unspecified"))
(defun tweak-clojure-syntax ()
(mapcar (lambda (x) (font-lock-add-keywords nil x))
'((("#?['`]*(\\|)" . 'clojure-parens))
(("#?\\^?{\\|}" . 'clojure-brackets))
(("\\[\\|\\]" . 'clojure-braces))
((":\\w+" . 'clojure-keyword))
(("#?\"" 0 'clojure-double-quote prepend))
(("nil\\|true\\|false\\|%[1-9]?" . 'clojure-special))
(("(\\(\\.[^ \n)]*\\|[^ \n)]+\\.\\|new\\)\\([ )\n]\\|$\\)" 1 'clojure-java-call))
)))
(add-hook 'clojure-mode-hook 'tweak-clojure-syntax)
;;(add-to-list 'slime-lisp-implementations '(sbcl ("/usr/bin/sbcl")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Custom
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(blink-cursor-mode nil)
'(case-fold-search t)
'(comint-scroll-to-bottom-on-input t)
'(fancy-splash-image "")
'(global-linum-mode t)
'(ido-decorations (quote ("" "" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
'(ido-everywhere t)
'(inhibit-startup-screen t)
'(line-number-mode nil)
'(lisp-loop-forms-indentation 6)
'(lisp-loop-keyword-indentation 6)
'(lisp-simple-loop-indentation 6)
'(mode-line-format (quote ("%e--[" mode-line-buffer-identification "]" (vc-mode vc-mode) " " mode-line-modes global-mode-string " %-")))
'(mode-line-in-non-selected-windows t)
'(mode-line-modes (quote ("%[" "(" (:propertize ("" mode-name)) ("" mode-line-process) (:propertize ("" minor-mode-alist)) "%n" ")" "%]")))
'(require-final-newline t)
'(savehist-mode t nil (savehist))
'(scroll-bar-mode nil)
'(scroll-conservatively 100000)
'(scroll-down-aggressively 0.0)
'(scroll-margin 0)
'(scroll-step 1)
'(scroll-up-aggressively 0.0)
'(show-paren-mode t nil (paren))
'(slime-compilation-finished-hook nil)
'(swank-clojure-extra-classpaths (quote ("/usr/share/emacs/site-lisp/swank-clojure/src/main/clojure"))))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(default ((t (:inherit nil :stipple nil :background "#171717" :foreground "#c0c0c0" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 90 :width normal :foundry "bitstream" :family "Bitstream Vera Sans Mono")))))

187
.emacs.d/bar-cursor.el Normal file
View file

@ -0,0 +1,187 @@
;;; @(#) bar-cursor.el -- package used to switch block cursor to a bar
;;; @(#) $Id: bar-cursor.el,v 1.1 2001/07/10 00:18:40 jcasa Exp $
;; This file is not part of Emacs
;; Copyright (C) 2001 by Joseph L. Casadonte Jr.
;; Author: Joe Casadonte (emacs@northbound-train.com)
;; Maintainer: Joe Casadonte (emacs@northbound-train.com)
;; Created: July 1, 2001
;; Keywords: bar cursor overwrite
;; Latest Version: http://www.northbound-train.com/emacs.html
;; COPYRIGHT NOTICE
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;
;; Simple package to convert the block cursor into a bar cursor. In
;; overwrite mode, the bar cursor changes back into a block cursor.
;; This is a quasi-minor mode, meaning that it can be turned on & off
;; easily though only globally (hence the quasi-)
;;; Installation:
;;
;; Put this file on your Emacs-Lisp load path and add the following to
;; your ~/.emacs startup file
;;
;; (require 'bar-cursor)
;; (bar-cursor-mode 1)
;;
;; To add a directory to your load-path, use something like the following:
;;
;; (add-to-list 'load-path (expand-file-name "/some/load/path"))
;;; Usage:
;;
;; M-x `bar-cursor-mode'
;; Toggles bar-cursor-mode on & off. Optional arg turns
;; bar-cursor-mode on iff arg is a positive integer.
;;; To Do:
;;
;; o Nothing, at the moment.
;;; Credits:
;;
;; The basis for this code comes from Steve Kemp by way of the
;; NTEmacs mailing list.
;;; Comments:
;;
;; Any comments, suggestions, bug reports or upgrade requests are welcome.
;; Please send them to Joe Casadonte (emacs@northbound-train.com).
;;
;; This version of bar-cursor was developed and tested with NTEmacs
;; 20.7.1 under Windows 2000 & NT 4.0 and Emacs 20.7.1 under Linux
;; (RH7). Please, let me know if it works with other OS and versions
;; of Emacs.
;;; Change Log:
;;
;; see http://www.northbound-train.com/emacs/bar-cursor.log
;;; **************************************************************************
;;; **************************************************************************
;;; **************************************************************************
;;; **************************************************************************
;;; **************************************************************************
;;; Code:
(eval-when-compile
;; silence the old byte-compiler
(defvar byte-compile-dynamic nil)
(set (make-local-variable 'byte-compile-dynamic) t))
;;; **************************************************************************
;;; ***** version related routines
;;; **************************************************************************
(defconst bar-cursor-version
"$Revision: 1.1 $"
"Version number for 'bar-cursor' package.")
;; ---------------------------------------------------------------------------
(defun bar-cursor-version-number ()
"Return 'bar-cursor' version number."
(string-match "[0123456789.]+" bar-cursor-version)
(match-string 0 bar-cursor-version))
;; ---------------------------------------------------------------------------
(defun bar-cursor-display-version ()
"Display 'bar-cursor' version."
(interactive)
(message "bar-cursor version <%s>." (bar-cursor-version-number)))
;;; **************************************************************************
;;; ***** real functions
;;; **************************************************************************
(defvar bar-cursor-mode nil "Non-nil if 'bar-cursor-mode' is enabled.")
;;; --------------------------------------------------------------------------
;;;###autoload
(defun bar-cursor-mode (&optional arg)
"Toggle use of 'bar-cursor-mode'.
This quasi-minor mode changes cursor to a bar cursor in insert mode,
and a block cursor in overwrite mode. It may only be turned on and
off globally, not on a per-buffer basis (hence the quasi- designation).
Optional ARG turns mode on iff ARG is a positive integer."
(interactive "P")
;; toggle on and off
(let ((old-mode bar-cursor-mode))
(setq bar-cursor-mode
(if arg (or (listp arg)
(> (prefix-numeric-value arg) 0))
(not bar-cursor-mode)))
(when (not (equal old-mode bar-cursor-mode))
;; enable/disable advice
(if bar-cursor-mode
(ad-enable-advice 'overwrite-mode 'after 'bar-cursor-overwrite-mode-ad)
(ad-disable-advice 'overwrite-mode 'after 'bar-cursor-overwrite-mode-ad))
(ad-activate 'overwrite-mode)
;; set the initial cursor type now
(bar-cursor-set-cursor)
;; add or remove to frame hook
(if bar-cursor-mode
(add-hook 'after-make-frame-functions 'bar-cursor-set-cursor)
(remove-hook 'after-make-frame-functions 'bar-cursor-set-cursor))
)))
;;;--------------------------------------------------------------------------
(defadvice overwrite-mode (after bar-cursor-overwrite-mode-ad disable)
"Advice that controls what type of cursor is displayed."
(bar-cursor-set-cursor))
;;;--------------------------------------------------------------------------
(defun bar-cursor-set-cursor-type (cursor &optional frame)
"Set the cursor-type for the named frame.
CURSOR is the name of the cursor to use (bar or block -- any others?).
FRAME is optional frame to set the cursor for; current frame is used
if not passed in."
(interactive)
(if (not frame)
(setq frame (selected-frame)))
;; Do the modification.
(modify-frame-parameters frame
(list (cons 'cursor-type cursor))))
;;; --------------------------------------------------------------------------
(defun bar-cursor-set-cursor (&optional frame)
"Set the cursor-type according to the insertion mode.
FRAME is optional frame to set the cursor for; current frame is used
if not passed in."
(if (and bar-cursor-mode (not overwrite-mode))
(bar-cursor-set-cursor-type 'bar frame)
(bar-cursor-set-cursor-type 'block frame)))
;;; **************************************************************************
;;; ***** we're done
;;; **************************************************************************
(provide 'bar-cursor)
;;; bar-cursor.el ends here
;;; **************************************************************************
;;;; ***** EOF ***** EOF ***** EOF ***** EOF ***** EOF *************

1666
.emacs.d/color-theme.el Normal file

File diff suppressed because it is too large Load diff

31
.emacs.d/gentooish.el Normal file
View file

@ -0,0 +1,31 @@
(require 'color-theme)
(defun color-theme-gentooish ()
"Mostly green and purple color theme"
(interactive)
(color-theme-install
'(color-theme-gentooish
((foreground-color . "#c0c0c0")
(background-color . "#171717")
(border-color . "black")
(cursor-color . "green")
(background-mode . dark))
(bold ((t (:foreground "white" :weight normal))))
(font-lock-builtin-face ((((class color) (min-colors 88) (background dark)) (:foreground "#c476f1"))))
(font-lock-comment-face ((((class color) (min-colors 88) (background dark)) (:foreground "grey30" :slant italic))))
(font-lock-function-name-face ((((class color) (min-colors 88) (background dark)) (:foreground "#4cbbd1"))))
(font-lock-keyword-face ((((class color) (min-colors 88) (background dark)) (:foreground "#9a383a"))))
(font-lock-string-face ((((class color) (min-colors 88) (background dark)) (:background "#0f291a" :foreground "#5dff9e"))))
(hi-blue ((((background dark)) (:background "grey20"))))
(ido-first-match ((t (:background "#361d45" :foreground "#cf7dff" :weight bold))))
(ido-only-match ((((class color)) (:background "#361d45" :foreground "#cf7dff" :weight bold))))
(ido-subdir ((((min-colors 88) (class color)) (:foreground "#7dcfff"))))
(linum ((t (:inherit shadow :background "grey12"))))
(minibuffer-prompt ((((background dark)) (:foreground "#863335"))))
(mode-line ((((class color) (min-colors 88)) (:background "#333333" :foreground "#ffffff" :box (:line-width -1 :color "#333333")))))
(mode-line-highlight ((((class color) (min-colors 88)) nil)))
(mode-line-inactive ((default (:inherit mode-line)) (((class color) (min-colors 88) (background dark)) (:foreground "#8b8b8b" :weight light))))
(show-paren-match ((((class color) (background dark)) (:background "#005500"))))
(tool-bar ((default (:foreground "black")) (((type x w32 ns) (class color)) (:background "grey75")))))))
(provide 'gentooish)

File diff suppressed because it is too large Load diff

104
.emacs.d/haskell-mode/NEWS Normal file
View file

@ -0,0 +1,104 @@
Changes since 2.5.1
* Parser corrections for haskell-indentation and haskell-decl-scan
* haskell-indentation: Pressing tab in the rightmost position now
moves to the leftmost, by default with a warning.
* Typo fix: One haskell-indentation variable had ended up in the
haskell-ntation customize group.
* haskell-hoogle aliased to hoogle, haskell-hayoo aliased to hayoo
* Courtesy of Alex Ott:
- Additional unicode symbols for font-lock-symbols: () == /= >= <= !! && || sqrt
- M-x haskell-hayoo search added, opens using browse-url
- Bug-fix for inferior-haskell-type
* If haskell-indentation errors out, it now fail-safes to inserting
a literal newline or deleting one character, for return and
backspace respectively.
Changes since 2.4:
* haskell-indentation, a new minor mode for indentation.
Changes since 2.3:
* Update license to GPLv3.
* New derived major mode for .hsc files.
* Removed the C-c C-r binding to reload a file. You can still call
inferior-haskell-reload-file (and/or bind it to your favorite key,
including C-c C-r) or you can now use C-u C-c C-l.
* C-c C-d looks up the symbol at point in the Haddock docs.
* Haddock comments are highlighted with font-lock-doc-face if it exists.
* Use `tex' rather than `latex' for haskell-literate.
* inf-haskell.el tries to find the root of the module hierarchy to determine
the root of a project (either by looking for a Cabal file or relying on
the `module' declaration line). If all works well, this will make C-c C-l
automatically switch to the root dir, so that dependencies in other
directories are automatically found. If it doesn't, complain and/or set
inferior-haskell-find-project-root to nil.
* The new command haskell-hoogle helps you query Hoogle from Emacs.
Changes since 2.2:
* Trivial support for Cabal package description files.
* Minor bug fixes.
Changes since 2.1:
* There are now commands to find type and info of identifiers by querying an
inferior haskell process. Available under C-c C-t, C-c C-i, and C-c M-.
* Indentation now looks back further, until a line that has no indentation.
To recover the earlier behavior of stopping at the first empty line
instead, configure haskell-indent-look-past-empty-line.
* inf-haskell can wait until a file load completes and jump directly to the
first error, like haskell-ghci and haskell-hugs used to do. See the var
inferior-haskell-wait-and-jump.
Changes since 2.0:
* inf-haskell uses ghci if hugs is absent.
* Fix up some binding conflicts (C-c C-o in haskell-doc)
* Many (hopefully minor) changes to the indentation.
* New symbols in haskell-font-lock-symbols-alist.
Changes since 1.45:
* keybindings C-c <char> have been replaced by C-c C-<char> so as not
to collide with minor modes.
* The following modules are now automatically activated without having to
add anything to haskell-mode-hook:
haskell-font-lock (just turn on global-font-lock-mode).
haskell-decl-scan (just bind `imenu' to some key).
* In recent Emacsen, haskell-doc hooks into eldoc-mode.
* haskell-hugs and haskell-ghci are superceded by inf-haskell.
* Indentation rules have been improved when using layout inside parens/braces.
* Symbols like -> and \ can be displayed as actual arrows and lambdas.
See haskell-font-lock-symbols.
* Tweaks to the font-lock settings. Among other things paren-matching
with things like \(x,y) should work correctly now.
* New maintainer <monnier@gnu.org>.
# arch-tag: e50204f2-98e4-438a-bcd1-a49afde5efa5

View file

@ -0,0 +1,108 @@
Haskell Mode for Emacs
----------------------
Version number: v2.6.4.
This is the Haskell mode package for Emacs. Its use should be mostly
self-explanatory if you're accustomed to Emacs.
When Emacs is started up, it normally runs a file called ~/.emacs located in
your home directory. This file should contain all of your personal
customisations written as a series of Elisp commands. In order to install
the Haskell mode, you have to tell Emacs where to find it. This is done by
adding some commands to the init file.
Installation
------------
- If you are using XEmacs, the haskell-mode package may be available for
installation through the XEmacs package UI.
- If you are using Debian, you may be able to install the package
haskell-mode with a command like "apt-get install haskell-mode".
Otherwise:
- Download and unpack the basic mode and modules into a suitable directory,
e.g. ~/lib/emacs/haskell-mode/ where ~ stands for your home directory.
- Assuming you have placed the basic mode haskell-mode.el and the modules
you want to use in the directory ~/lib/emacs/haskell-mode/, add the
following command to your init file (~/.emacs):
(load "~/lib/emacs/haskell-mode/haskell-site-file")
This only loads the bare-bones haskell-mode. To make it useful, you
need additional modules; you can use the haskell customize-group
to edit the Haskell mode hook or, if you prefer manual setup, try
adding the following lines according to which modules you want to use:
(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
Note that the three indentation modules are mutually exclusive - add at
most one. Note that the line of code for simple indentation is commented
out (using a preceeding ;) in preference for the more advanced
indentation module. Installation is now complete!
The other modules are automatically loaded when needed in the following way:
- Font locking: just turn it on via `global-font-lock-mode' or do
(add-hook 'haskell-mode-hook 'font-lock-mode)
- Declaration scanning: just use M-x imenu or bind `imenu' to a key. E.g.
(global-set-key [(control meta down-mouse-3)] 'imenu) or you can also add
it to the menubar with (add-hook 'haskell-mode-hook 'imenu-add-menubar-index)
- Interaction with inferior Haskell interpreter: just hit C-c C-z or C-c C-l.
Setup
-----
Normally, inf-haskell automatically finds ghci or hugs in your PATH, but if
that's not the case (common under Windows), or if you need to specify your
preference, just tell Emacs which executable to use with:
(setq haskell-program-name "/some/where/ghci.exe")
If you want to use different settings when you use Cygwin Emacs and NTEmacs,
you can test the value of `system-type':
(setq haskell-program-name
(if (eq system-type 'cygwin)
"/cygdrive/c/ghc/ghc-6.8.1/bin/ghcii.sh"
"c:/ghc/ghc-6.8.1/bin/ghci.exe"))
Note that Cygwin binaries tend to interact poorly with NTEmacs, especially
w.r.t signal-handling.
Customization
-------------
Most customizations are on the functionality of a particular module.
See the documentation of that module for information on its
customisation.
Known problems
--------------
It seems that some version of XEmacs come without the fsf-compat package
(which provides functions such as `line-end-position') and it seems that
even if your XEmacs does have the fsf-compat package installed it does not
autoload its part. Thus you may have to install the fsf-compat package and
add (require 'goto-addr) in your .emacs.
Support
-------
Any problems, do mail me <svein.ove@aas.no> and I will try my best
to help you!
<!-- arch-tag: 25fc8494-611d-459f-9919-579c97f6313e -->

View file

@ -0,0 +1,49 @@
-- Comments are coloured brightly and stand out clearly.
import qualified Foo as F hiding (toto)
import qualified Foo hiding (toto)
import qualified Foo as F (toto)
import Foo as F hiding (toto)
import Foo hiding (toto)
import Foo as F (toto)
hiding = 1
qualified = 3
as = 2
repeat :: a -> [a]
repeat xs = xs where xs = x:xs -- Keywords are also bright.
head :: [a] -> a
head (x:_) = x
head [] = error "PreludeList.head: empty list" -- Strings are coloured softly.
data Maybe a = Nothing | Just a -- Type constructors, data
deriving (Eq, Ord, Read, Show) -- constructors, class names
-- and module names are coloured
-- closer to ordinary code.
recognize +++ infix :: Operator Declarations
as `well` as = This Form
(+) and this one = as well
instance Show Toto where
fun1 arg1 = foo -- FIXME: `fun1' should be highlighted.
constStr = "hello \
\asdgfasgf\
\asf"
{-
map :: (a -> b) -> [a] -> [b] -- Commenting out large sections of
map f [] = [] -- code can be misleading. Coloured
map f (x:xs) = f x : map f xs -- comments reveal unused definitions.
-}
-- Note: the least significant bit is the first element of the list
bdigits :: Int -> [Int]
bdigits 0 = [0]
bdigits 1 = [1]
bdigits n | n>1 = n `mod` 2 :
-- arch-tag: a0d08cc2-4a81-4139-93bc-b3c6be0b5fb2

View file

@ -0,0 +1,47 @@
;;; haskell-c.el --- Major mode for *.hsc files
;; Copyright (C) 2007 Stefan Monnier
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;;; Code:
(require 'haskell-mode)
(require 'haskell-font-lock)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-c-mode))
(defvar haskell-c-font-lock-keywords
`(("^#[ \t]*[[:alnum:]]+" (0 font-lock-preprocessor-face))
,@haskell-font-lock-symbols))
;;;###autoload
(define-derived-mode haskell-c-mode haskell-mode "Haskell-C"
"Major mode for Haskell FFI files."
(set (make-local-variable 'font-lock-keywords)
(cons 'haskell-c-font-lock-keywords
(cdr font-lock-keywords))))
(provide 'haskell-c)
;; arch-tag: 51294c41-29f0-4599-9ce8-47fe2e7d3fd5
;;; haskell-c.el ends here

View file

@ -0,0 +1,182 @@
;;; haskell-cabal.el --- Support for Cabal packages
;; Copyright (C) 2007, 2008 Stefan Monnier
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; Todo:
;; - distinguish continued lines from indented lines.
;; - indent-line-function.
;; - outline-minor-mode.
;;; Code:
;; (defun haskell-cabal-extract-fields-from-doc ()
;; (require 'xml)
;; (require 'cl)
;; (let ((section (completing-read
;; "Section: "
;; '("general-fields" "library" "executable" "buildinfo"))))
;; (goto-char (point-min))
;; (search-forward (concat "<sect3 id=\"" section "\">")))
;; (let* ((xml (xml-parse-region
;; (progn (search-forward "<variablelist>") (match-beginning 0))
;; (progn (search-forward "</variablelist>") (point))))
;; (varlist (remove-if-not 'consp (cddar xml)))
;; (syms (mapcar (lambda (entry) (caddr (assq 'literal (assq 'term entry))))
;; varlist))
;; (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms)))
;; fields))
(eval-when-compile (require 'cl))
(defconst haskell-cabal-general-fields
;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields")
'("name" "version" "cabal-version" "license" "license-file" "copyright"
"author" "maintainer" "stability" "homepage" "package-url" "synopsis"
"description" "category" "tested-with" "build-depends" "data-files"
"extra-source-files" "extra-tmp-files"))
(defconst haskell-cabal-library-fields
;; Extracted with (haskell-cabal-extract-fields-from-doc "library")
'("exposed-modules"))
(defconst haskell-cabal-executable-fields
;; Extracted with (haskell-cabal-extract-fields-from-doc "executable")
'("executable" "main-is"))
(defconst haskell-cabal-buildinfo-fields
;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo")
'("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options"
"ghc-prof-options" "hugs-options" "nhc-options" "includes"
"install-includes" "include-dirs" "c-sources" "extra-libraries"
"extra-lib-dirs" "cc-options" "ld-options" "frameworks"))
(defvar haskell-cabal-mode-syntax-table
(let ((st (make-syntax-table)))
;; The comment syntax can't be described simply in syntax-table.
;; We could use font-lock-syntactic-keywords, but is it worth it?
;; (modify-syntax-entry ?- ". 12" st)
(modify-syntax-entry ?\n ">" st)
st))
(defvar haskell-cabal-font-lock-keywords
;; The comment syntax can't be described simply in syntax-table.
;; We could use font-lock-syntactic-keywords, but is it worth it?
'(("^[ \t]*--.*" . font-lock-comment-face)
("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face))
("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face))
("^\\(Executable\\)[ \t]+\\([^\n \t]*\\)"
(1 font-lock-keyword-face) (2 font-lock-function-name-face))
("^\\(Flag\\)[ \t]+\\([^\n \t]*\\)"
(1 font-lock-keyword-face) (2 font-lock-constant-face))
("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face))
("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)"
(2 font-lock-keyword-face))))
(defvar haskell-cabal-buffers nil
"List of Cabal buffers.")
;; (defsubst* inferior-haskell-string-prefix-p (str1 str2)
;; "Return non-nil if STR1 is a prefix of STR2"
;; (eq t (compare-strings str2 nil (length str1) str1 nil nil)))
(defun haskell-cabal-find-file ()
"Return a buffer visiting the cabal file of the current directory, or nil."
(catch 'found
;; ;; First look for it in haskell-cabal-buffers.
;; (dolist (buf haskell-cabal-buffers)
;; (if (inferior-haskell-string-prefix-p
;; (with-current-buffer buf default-directory) default-directory)
;; (throw 'found buf)))
;; Then look up the directory hierarchy.
(let ((user (nth 2 (file-attributes default-directory)))
;; Abbreviate, so as to stop when we cross ~/.
(root (abbreviate-file-name default-directory))
files)
(while (and root (equal user (nth 2 (file-attributes root))))
(if (setq files (directory-files root 'full "\\.cabal\\'"))
;; Avoid the .cabal directory.
(dolist (file files (throw 'found nil))
(unless (file-directory-p file)
(throw 'found (find-file-noselect file))))
(if (equal root
(setq root (file-name-directory
(directory-file-name root))))
(setq root nil))))
nil)))
(defun haskell-cabal-buffers-clean (&optional buffer)
(let ((bufs ()))
(dolist (buf haskell-cabal-buffers)
(if (and (buffer-live-p buf) (not (eq buf buffer))
(with-current-buffer buf (derived-mode-p 'haskell-cabal-mode)))
(push buf bufs)))
(setq haskell-cabal-buffers bufs)))
(defun haskell-cabal-unregister-buffer ()
(haskell-cabal-buffers-clean (current-buffer)))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
;;;###autoload
(define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal"
"Major mode for Cabal package description files."
(set (make-local-variable 'font-lock-defaults)
'(haskell-cabal-font-lock-keywords t t nil nil))
(add-to-list 'haskell-cabal-buffers (current-buffer))
(add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local)
(add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local)
(set (make-local-variable 'comment-start) "-- ")
(set (make-local-variable 'comment-start-skip) "\\(^[ \t]*\\)--[ \t]*")
(set (make-local-variable 'comment-end) "")
(set (make-local-variable 'comment-end-skip) "[ ]*\\(\\s>\\|\n\\)")
)
(defun haskell-cabal-get-setting (name)
(save-excursion
(let ((case-fold-search t))
(goto-char (point-min))
(when (re-search-forward
(concat "^" (regexp-quote name)
":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)")
nil t)
(let ((val (match-string 1))
(start 1))
(when (match-end 2) ;Multiple lines.
;; The documentation is not very precise about what to do about
;; the \n and the indentation: are they part of the value or
;; the encoding? I take the point of view that \n is part of
;; the value (so that values can span multiple lines as well),
;; and that only the first char in the indentation is part of
;; the encoding, the rest is part of the value (otherwise, lines
;; in the value cannot start with spaces or tabs).
(while (string-match "^[ \t]\\(?:\\.$\\)?" val start)
(setq start (1+ (match-beginning 0)))
(setq val (replace-match "" t t val))))
val)))))
(provide 'haskell-cabal)
;; arch-tag: d455f920-5e4d-42b6-a2c7-4a7e84a05c29
;;; haskell-cabal.el ends here

View file

@ -0,0 +1,698 @@
;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode
;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
;; Copyright (C) 1997-1998 Graeme E Moss
;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
;; Maintainer: Stefan Monnier <monnier@gnu.org>
;; Keywords: declarations menu files Haskell
;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; Top-level declarations are scanned and placed in a menu. Supports
;; full Latin1 Haskell 1.4 as well as literate scripts.
;;
;;
;; Installation:
;;
;; To turn declaration scanning on for all Haskell buffers under the
;; Haskell mode of Moss&Thorn, add this to .emacs:
;;
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
;;
;; Otherwise, call `turn-on-haskell-decl-scan'.
;;
;;
;; Customisation:
;;
;; None available so far.
;;
;;
;; History:
;;
;; If you have any problems or suggestions, after consulting the list
;; below, email gem@cs.york.ac.uk quoting the version of the library
;; you are using, the version of Emacs you are using, and a small
;; example of the problem or suggestion. Note that this library
;; requires a reasonably recent version of Emacs.
;;
;; Uses `imenu' under Emacs, and `func-menu' under XEmacs.
;;
;; Version 1.2:
;; Added support for LaTeX-style literate scripts.
;;
;; Version 1.1:
;; Use own syntax table. Fixed bug for very small buffers. Use
;; markers instead of pointers (markers move with the text).
;;
;; Version 1.0:
;; Brought over from Haskell mode v1.1.
;;
;;
;; Present Limitations/Future Work (contributions are most welcome!):
;;
;; . Declarations requiring information extending beyond starting line
;; don't get scanned properly, eg.
;; > class Eq a =>
;; > Test a
;;
;; . Comments placed in the midst of the first few lexemes of a
;; declaration will cause havoc, eg.
;; > infixWithComments :: Int -> Int -> Int
;; > x {-nastyComment-} `infixWithComments` y = x + y
;; but are not worth worrying about.
;;
;; . Would be nice to scan other top-level declarations such as
;; methods of a class, datatype field labels... any more?
;;
;; . Support for GreenCard?
;;
;; . Re-running (literate-)haskell-imenu should not cause the problems
;; that it does. The ability to turn off scanning would also be
;; useful. (Note that re-running (literate-)haskell-mode seems to
;; cause no problems.)
;;
;; . Inconsistency: we define the start of a declaration in `imenu' as
;; the start of the line the declaration starts on, but in
;; `func-menu' as the start of the name that the declaration is
;; given (eg. "class Eq a => Ord a ..." starts at "class" in `imenu'
;; but at "Ord" in `func-menu'). This avoids rescanning of the
;; buffer by the goto functions of `func-menu' but allows `imenu' to
;; have the better definition of the start of the declaration (IMO).
;;
;; . `func-menu' cannot cope well with spaces in declaration names.
;; This is unavoidable in "instance Eq Int" (changing the spaces to
;; underscores would cause rescans of the buffer). Note though that
;; `fume-prompt-function-goto' (usually bound to "C-c g") does cope
;; with spaces okay.
;;
;; . Would like to extend the goto functions given by `func-menu'
;; under XEmacs to Emacs. Would have to implement these
;; ourselves as `imenu' does not provide them.
;;
;; . `func-menu' uses its own syntax table when grabbing a declaration
;; name to lookup (why doesn't it use the syntax table of the
;; buffer?) so some declaration names will not be grabbed correctly,
;; eg. "fib'" will be grabbed as "fib" since "'" is not a word or
;; symbol constituent under the syntax table `func-menu' uses.
;; All functions/variables start with
;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'.
;; The imenu support is based on code taken from `hugs-mode',
;; thanks go to Chris Van Humbeeck.
;; Version.
;;; Code:
(require 'haskell-mode)
;;###autoload
;; As `cl' defines macros that `imenu' uses, we must require them at
;; compile time.
(eval-when-compile
(require 'cl)
(condition-case nil
(require 'imenu)
(error nil)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General declaration scanning functions.
(defalias 'haskell-ds-match-string
(if (fboundp 'match-string-no-properties)
'match-string-no-properties
(lambda (num)
"As `match-string' except that the string is stripped of properties."
(format "%s" (match-string num)))))
(defvar haskell-ds-start-keywords-re
(concat "\\(\\<"
"class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|"
"module\\|primitive\\|type\\|newtype"
"\\)\\>")
"Keywords that may start a declaration.")
(defvar haskell-ds-syntax-table
(let ((table (copy-syntax-table haskell-mode-syntax-table)))
(modify-syntax-entry ?\' "w" table)
(modify-syntax-entry ?_ "w" table)
(modify-syntax-entry ?\\ "_" table)
table)
"Syntax table used for Haskell declaration scanning.")
(defun haskell-ds-get-variable (prefix)
"Return variable involved in value binding or type signature.
Assumes point is looking at the regexp PREFIX followed by the
start of a declaration (perhaps in the middle of a series of
declarations concerning a single variable). Otherwise return nil.
Point is not changed."
;; I think I can now handle all declarations bar those with comments
;; nested before the second lexeme.
(save-excursion
(with-syntax-table haskell-ds-syntax-table
(if (looking-at prefix) (goto-char (match-end 0)))
;; Keyword.
(if (looking-at haskell-ds-start-keywords-re)
nil
(or ;; Parenthesized symbolic variable.
(and (looking-at "(\\(\\s_+\\))") (haskell-ds-match-string 1))
;; General case.
(if (looking-at
(if (eq ?\( (char-after))
;; Skip paranthesised expression.
(progn
(forward-sexp)
;; Repeating this code and avoiding moving point if
;; possible speeds things up.
"\\(\\'\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)")
"\\(\\sw+\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
(let ((match2 (haskell-ds-match-string 2)))
;; Weed out `::', `=' and `|' from potential infix
;; symbolic variable.
(if (member match2 '("::" "=" "|"))
;; Variable identifier.
(haskell-ds-match-string 1)
(if (eq (aref match2 0) ?\`)
;; Infix variable identifier.
(haskell-ds-match-string 3)
;; Infix symbolic variable.
match2))))
;; Variable identifier.
(and (looking-at "\\sw+") (haskell-ds-match-string 0)))))))
(defun haskell-ds-move-to-start-regexp (inc regexp)
"Move to beginning of line that succeeds/precedes (INC = 1/-1)
current line that starts with REGEXP and is not in `font-lock-comment-face'."
;; Making this defsubst instead of defun appears to have little or
;; no effect on efficiency. It is probably not called enough to do
;; so.
(while (and (= (forward-line inc) 0)
(or (not (looking-at regexp))
(eq (get-text-property (point) 'face)
'font-lock-comment-face)))))
(defun haskell-ds-move-to-start-regexp-skipping-comments (inc regexp)
"Like haskell-ds-move-to-start-regexp, but uses syntax-ppss to
skip comments"
(let (p)
(loop
do (setq p (point))
(haskell-ds-move-to-start-regexp inc regexp)
while (and (nth 4 (syntax-ppss))
(/= p (point))))))
(defvar literate-haskell-ds-line-prefix "> ?"
"Regexp matching start of a line of Bird-style literate code.
Current value is \"> \" as we assume top-level declarations start
at column 3. Must not contain the special \"^\" regexp as we may
not use the regexp at the start of a regexp string. Note this is
only for `imenu' support.")
(defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)"
"The regexp that starts a Haskell declaration.")
(defvar literate-haskell-ds-start-decl-re
(concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re)
"The regexp that starts a Bird-style literate Haskell declaration.")
(defun haskell-ds-move-to-decl (direction bird-literate fix)
"General function for moving to the start of a declaration,
either forwards or backwards from point, with normal or with Bird-style
literate scripts. If DIRECTION is t, then forward, else backward. If
BIRD-LITERATE is t, then treat as Bird-style literate scripts, else
normal scripts. Returns point if point is left at the start of a
declaration, and nil otherwise, ie. because point is at the beginning
or end of the buffer and no declaration starts there. If FIX is t,
then point does not move if already at the start of a declaration."
;; As `haskell-ds-get-variable' cannot separate an infix variable
;; identifier out of a value binding with non-alphanumeric first
;; argument, this function will treat such value bindings as
;; separate from the declarations surrounding it.
(let ( ;; The variable typed or bound in the current series of
;; declarations.
name
;; The variable typed or bound in the new declaration.
newname
;; Hack to solve hard problem for Bird-style literate scripts
;; that start with a declaration. We are in the abyss if
;; point is before start of this declaration.
abyss
(line-prefix (if bird-literate literate-haskell-ds-line-prefix ""))
;; The regexp to match for the start of a declaration.
(start-decl-re (if bird-literate
literate-haskell-ds-start-decl-re
haskell-ds-start-decl-re))
(increment (if direction 1 -1))
(bound (if direction (point-max) (point-min))))
;; Change syntax table.
(with-syntax-table haskell-ds-syntax-table
;; move to beginning of line that starts the "current
;; declaration" (dependent on DIRECTION and FIX), and then get
;; the variable typed or bound by this declaration, if any.
(let ( ;; Where point was at call of function.
(here (point))
;; Where the declaration on this line (if any) starts.
(start (progn
(beginning-of-line)
;; Checking the face to ensure a declaration starts
;; here seems to be the only addition to make this
;; module support LaTeX-style literate scripts.
(if (and (looking-at start-decl-re)
(not (eq (get-text-property (point) 'face)
'font-lock-comment-face)))
(match-beginning 1)))))
(if (and start
;; This complicated boolean determines whether we
;; should include the declaration that starts on the
;; current line as the "current declaration" or not.
(or (and (or (and direction (not fix))
(and (not direction) fix))
(>= here start))
(and (or (and direction fix)
(and (not direction) (not fix)))
(> here start))))
;; If so, we are already at start of the current line, so
;; do nothing.
()
;; If point was before start of a declaration on the first
;; line of the buffer (possible for Bird-style literate
;; scripts) then we are in the abyss.
(if (and start (bobp))
(setq abyss t)
;; Otherwise we move to the start of the first declaration
;; on a line preceeding the current one, skipping comments
(haskell-ds-move-to-start-regexp-skipping-comments -1 start-decl-re))))
;; If we are in the abyss, position and return as appropriate.
(if abyss
(if (not direction)
nil
(re-search-forward (concat "\\=" line-prefix) nil t)
(point))
;; Get the variable typed or bound by this declaration, if any.
(setq name (haskell-ds-get-variable line-prefix))
(if (not name)
;; If no such variable, stop at the start of this
;; declaration if moving backward, or move to the next
;; declaration if moving forward.
(if direction
(haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re))
;; If there is a variable, find the first
;; succeeding/preceeding declaration that does not type or
;; bind it. Check for reaching start/end of buffer and
;; comments.
(haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re)
(while (and (/= (point) bound)
(and (setq newname (haskell-ds-get-variable line-prefix))
(string= name newname)))
(setq name newname)
(haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re))
;; If we are going backward, and have either reached a new
;; declaration or the beginning of a buffer that does not
;; start with a declaration, move forward to start of next
;; declaration (which must exist). Otherwise, we are done.
(if (and (not direction)
(or (and (looking-at start-decl-re)
(not (string= name
;; Note we must not use
;; newname here as this may
;; not have been set if we
;; have reached the beginning
;; of the buffer.
(haskell-ds-get-variable
line-prefix))))
(and (not (looking-at start-decl-re))
(bobp))))
(haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re)))
;; Store whether we are at the start of a declaration or not.
;; Used to calculate final result.
(let ((at-start-decl (looking-at start-decl-re)))
;; If we are at the beginning of a line, move over
;; line-prefix, if present at point.
(if (bolp)
(re-search-forward (concat "\\=" line-prefix) (point-max) t))
;; Return point if at the start of a declaration and nil
;; otherwise.
(if at-start-decl (point) nil))))))
(defun haskell-ds-bird-p ()
(and (boundp 'haskell-literate) (eq haskell-literate 'bird)))
(defun haskell-ds-backward-decl ()
"Move point backward to the first character preceding the current
point that starts a top-level declaration. A series of declarations
concerning one variable is treated as one declaration by this
function. So, if point is within a top-level declaration then move it
to the start of that declaration. If point is already at the start of
a top-level declaration, then move it to the start of the preceding
declaration. Returns point if point is left at the start of a
declaration, and nil otherwise, ie. because point is at the beginning
of the buffer and no declaration starts there."
(interactive)
(haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil))
(defun haskell-ds-forward-decl ()
"As `haskell-ds-backward-decl' but forward."
(interactive)
(haskell-ds-move-to-decl t (haskell-ds-bird-p) nil))
(defun haskell-ds-generic-find-next-decl (bird-literate)
"Find the name, position and type of the declaration at or after point.
Return ((NAME . (START-POSITION . NAME-POSITION)) . TYPE)
if one exists and nil otherwise. The start-position is at the start
of the declaration, and the name-position is at the start of the name
of the declaration. The name is a string, the positions are buffer
positions and the type is one of the symbols \"variable\", \"datatype\",
\"class\", \"import\" and \"instance\"."
(let (;; The name, type and name-position of the declaration to
;; return.
name
type
name-pos
;; Buffer positions marking the start and end of the space
;; containing a declaration.
start
end)
;; Change to declaration scanning syntax.
(with-syntax-table haskell-ds-syntax-table
;; Stop when we are at the end of the buffer or when a valid
;; declaration is grabbed.
(while (not (or (eobp) name))
;; Move forward to next declaration at or after point.
(haskell-ds-move-to-decl t bird-literate t)
;; Start and end of search space is currently just the starting
;; line of the declaration.
(setq start (point)
end (line-end-position))
(cond
;; If the start of the top-level declaration does not begin
;; with a starting keyword, then (if legal) must be a type
;; signature or value binding, and the variable concerned is
;; grabbed.
((not (looking-at haskell-ds-start-keywords-re))
(setq name (haskell-ds-get-variable ""))
(if name
(progn
(setq type 'variable)
(re-search-forward (regexp-quote name) end t)
(setq name-pos (match-beginning 0)))))
;; User-defined datatype declaration.
((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t)
(re-search-forward "=>" end t)
(if (looking-at "[ \t]*\\(\\sw+\\)")
(progn
(setq name (haskell-ds-match-string 1))
(setq name-pos (match-beginning 1))
(setq type 'datatype))))
;; Class declaration.
((re-search-forward "\\=class\\>" end t)
(re-search-forward "=>" end t)
(if (looking-at "[ \t]*\\(\\sw+\\)")
(progn
(setq name (haskell-ds-match-string 1))
(setq name-pos (match-beginning 1))
(setq type 'class))))
;; Import declaration.
((looking-at "import[ \t]+\\(qualified[ \t]+\\)?\\(\\(?:\\sw\\|.\\)+\\)")
(setq name (haskell-ds-match-string 2))
(setq name-pos (match-beginning 2))
(setq type 'import))
;; Instance declaration.
((re-search-forward "\\=instance[ \t]+" end t)
(re-search-forward "=>[ \t]+" end t)
;; The instance "title" starts just after the `instance' (and
;; any context) and finishes just before the _first_ `where'
;; if one exists. This solution is ugly, but I can't find a
;; nicer one---a simple regexp will pick up the last `where',
;; which may be rare but nevertheless...
(setq name-pos (point))
(setq name (format "%s"
(buffer-substring
(point)
(progn
;; Look for a `where'.
(if (re-search-forward "\\<where\\>" end t)
;; Move back to just before the `where'.
(progn
(re-search-backward "\\s-where")
(point))
;; No `where' so move to last non-whitespace
;; before `end'.
(progn
(goto-char end)
(skip-chars-backward " \t")
(point)))))))
;; If we did not manage to extract a name, cancel this
;; declaration (eg. when line ends in "=> ").
(if (string-match "^[ \t]*$" name) (setq name nil))
(setq type 'instance)))
;; Move past start of current declaration.
(goto-char end))
;; If we have a valid declaration then return it, otherwise return
;; nil.
(if name
(cons (cons name (cons (copy-marker start t) (copy-marker name-pos t)))
type)
nil))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Declaration scanning via `imenu'.
(defun haskell-ds-create-imenu-index ()
"Function for finding `imenu' declarations in Haskell mode.
Finds all declarations (classes, variables, imports, instances and
datatypes) in a Haskell file for the `imenu' package."
;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'.
;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'.
(let* ((bird-literate (haskell-ds-bird-p))
(index-alist '())
(index-class-alist '()) ;; Classes
(index-var-alist '()) ;; Variables
(index-imp-alist '()) ;; Imports
(index-inst-alist '()) ;; Instances
(index-type-alist '()) ;; Datatypes
;; Variables for showing progress.
(bufname (buffer-name))
(divisor-of-progress (max 1 (/ (buffer-size) 100)))
;; The result we wish to return.
result)
(goto-char (point-min))
;; Loop forwards from the beginning of the buffer through the
;; starts of the top-level declarations.
(while (< (point) (point-max))
(message "Scanning declarations in %s... (%3d%%)" bufname
(/ (- (point) (point-min)) divisor-of-progress))
;; Grab the next declaration.
(setq result (haskell-ds-generic-find-next-decl bird-literate))
(if result
;; If valid, extract the components of the result.
(let* ((name-posns (car result))
(name (car name-posns))
(posns (cdr name-posns))
(start-pos (car posns))
(type (cdr result))
;; Place `(name . start-pos)' in the correct alist.
(sym (cdr (assq type
'((variable . index-var-alist)
(datatype . index-type-alist)
(class . index-class-alist)
(import . index-imp-alist)
(instance . index-inst-alist))))))
(set sym (cons (cons name start-pos) (symbol-value sym))))))
;; Now sort all the lists, label them, and place them in one list.
(message "Sorting declarations in %s..." bufname)
(and index-type-alist
(push (cons "Datatypes"
(sort index-type-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(and index-inst-alist
(push (cons "Instances"
(sort index-inst-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(and index-imp-alist
(push (cons "Imports"
(sort index-imp-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(and index-var-alist
(push (cons "Variables"
(sort index-var-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(and index-class-alist
(push (cons "Classes"
(sort index-class-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(message "Sorting declarations in %s...done" bufname)
;; Return the alist.
index-alist))
(defun haskell-ds-imenu-label-cmp (el1 el2)
"Predicate to compare labels in lists from `haskell-ds-create-imenu-index'."
(string< (car el1) (car el2)))
(defun haskell-ds-imenu ()
"Install `imenu' for Haskell scripts."
(setq imenu-create-index-function 'haskell-ds-create-imenu-index)
(if (fboundp 'imenu-add-to-menubar)
(imenu-add-to-menubar "Declarations")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Declaration scanning via `func-menu'.
(defun haskell-ds-func-menu-next (buffer)
"Non-literate Haskell version of `haskell-ds-generic-func-menu-next'."
(haskell-ds-generic-func-menu-next (haskell-ds-bird-p) buffer))
(defun haskell-ds-generic-func-menu-next (bird-literate buffer)
"Return `(name . pos)' of next declaration."
(set-buffer buffer)
(let ((result (haskell-ds-generic-find-next-decl bird-literate)))
(if result
(let* ((name-posns (car result))
(name (car name-posns))
(posns (cdr name-posns))
(name-pos (cdr posns))
;;(type (cdr result))
)
(cons ;(concat
;; func-menu has problems with spaces, and adding a
;; qualifying keyword will not allow the "goto fn"
;; functions to work properly. Sigh.
;; (cond
;; ((eq type 'variable) "")
;; ((eq type 'datatype) "datatype ")
;; ((eq type 'class) "class ")
;; ((eq type 'import) "import ")
;; ((eq type 'instance) "instance "))
name;)
name-pos))
nil)))
(defvar haskell-ds-func-menu-regexp
(concat "^" haskell-ds-start-decl-re)
"Regexp to match the start of a possible declaration.")
(defvar literate-haskell-ds-func-menu-regexp
(concat "^" literate-haskell-ds-start-decl-re)
"As `haskell-ds-func-menu-regexp' but for Bird-style literate scripts.")
(defvar fume-menubar-menu-name)
(defvar fume-function-name-regexp-alist)
(defvar fume-find-function-name-method-alist)
(defun haskell-ds-func-menu ()
"Use `func-menu' to establish declaration scanning for Haskell scripts."
(require 'func-menu)
(set (make-local-variable 'fume-menubar-menu-name) "Declarations")
(set (make-local-variable 'fume-function-name-regexp-alist)
(if (haskell-ds-bird-p)
'((haskell-mode . literate-haskell-ds-func-menu-regexp))
'((haskell-mode . haskell-ds-func-menu-regexp))))
(set (make-local-variable 'fume-find-function-name-method-alist)
'((haskell-mode . haskell-ds-func-menu-next)))
(fume-add-menubar-entry)
(local-set-key "\C-cl" 'fume-list-functions)
(local-set-key "\C-cg" 'fume-prompt-function-goto)
(local-set-key [(meta button1)] 'fume-mouse-function-goto))
;; The main functions to turn on declaration scanning.
(defun turn-on-haskell-decl-scan ()
(interactive)
"Unconditionally activate `haskell-decl-scan-mode'."
(haskell-decl-scan-mode 1))
(defvar haskell-decl-scan-mode nil)
(make-variable-buffer-local 'haskell-decl-scan-mode)
;;;###autoload
(defun haskell-decl-scan-mode (&optional arg)
"Minor mode for declaration scanning for Haskell mode.
Top-level declarations are scanned and listed in the menu item \"Declarations\".
Selecting an item from this menu will take point to the start of the
declaration.
\\[haskell-ds-forward-decl] and \\[haskell-ds-backward-decl] move forward and backward to the start of a declaration.
Under XEmacs, the following keys are also defined:
\\[fume-list-functions] lists the declarations of the current buffer,
\\[fume-prompt-function-goto] prompts for a declaration to move to, and
\\[fume-mouse-function-goto] moves to the declaration whose name is at point.
This may link with `haskell-doc' (only for Emacs currently).
For non-literate and LaTeX-style literate scripts, we assume the
common convention that top-level declarations start at the first
column. For Bird-style literate scripts, we assume the common
convention that top-level declarations start at the third column,
ie. after \"> \".
Anything in `font-lock-comment-face' is not considered for a
declaration. Therefore, using Haskell font locking with comments
coloured in `font-lock-comment-face' improves declaration scanning.
To turn on declaration scanning for all Haskell buffers, add this to
.emacs:
(add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
To turn declaration scanning on for the current buffer, call
`turn-on-haskell-decl-scan'.
Literate Haskell scripts are supported: If the value of
`haskell-literate' (automatically set by the Haskell mode of
Moss&Thorn) is `bird', a Bird-style literate script is assumed. If it
is nil or `tex', a non-literate or LaTeX-style literate script is
assumed, respectively.
Invokes `haskell-decl-scan-mode-hook'."
(interactive)
(if (boundp 'beginning-of-defun-function)
(if haskell-decl-scan-mode
(progn
(set (make-local-variable 'beginning-of-defun-function)
'haskell-ds-backward-decl)
(set (make-local-variable 'end-of-defun-function)
'haskell-ds-forward-decl))
(kill-local-variable 'beginning-of-defun-function)
(kill-local-variable 'end-of-defun-function))
(local-set-key "\M-\C-e"
(if haskell-decl-scan-mode 'haskell-ds-forward-decl))
(local-set-key "\M-\C-a"
(if haskell-decl-scan-mode 'haskell-ds-backward-decl)))
(if haskell-decl-scan-mode
(if (fboundp 'imenu)
(haskell-ds-imenu)
(haskell-ds-func-menu))
;; How can we cleanly remove that menus?
(local-set-key [menu-bar index] nil))
(run-hooks 'haskell-decl-scan-mode-hook))
;; Provide ourselves:
(provide 'haskell-decl-scan)
;; arch-tag: f4335fd8-4b6c-472e-9899-004d47d94818
;;; haskell-decl-scan.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,633 @@
;;; haskell-font-lock.el --- Font locking module for Haskell Mode
;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn
;; Authors: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and
;; Tommy Thorn <thorn@irisa.fr>
;; 2003 Dave Love <fx@gnu.org>
;; Keywords: faces files Haskell
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; To support fontification of standard Haskell keywords, symbols,
;; functions, etc. Supports full Haskell 1.4 as well as LaTeX- and
;; Bird-style literate scripts.
;;
;; Installation:
;;
;; To turn font locking on for all Haskell buffers under the Haskell
;; mode of Moss&Thorn, add this to .emacs:
;;
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
;;
;; Otherwise, call `turn-on-haskell-font-lock'.
;;
;;
;; Customisation:
;;
;; The colours and level of font locking may be customised. See the
;; documentation on `turn-on-haskell-font-lock' for more details.
;;
;;
;; History:
;;
;; If you have any problems or suggestions, after consulting the list
;; below, email gem@cs.york.ac.uk and thorn@irisa.fr quoting the
;; version of the mode you are using, the version of Emacs you are
;; using, and a small example of the problem or suggestion. Note that
;; this module requires a reasonably recent version of Emacs. It
;; requires Emacs 21 to cope with Unicode characters and to do proper
;; syntactic fontification.
;;
;; Version 1.3:
;; From Dave Love:
;; Support for proper behaviour (including with Unicode identifiers)
;; in Emacs 21 only hacked in messily to avoid disturbing the old
;; stuff. Needs integrating more cleanly. Allow literate comment
;; face to be customized. Some support for fontifying definitions.
;; (I'm not convinced the faces should be customizable -- fontlock
;; faces are normally expected to be consistent.)
;;
;; Version 1.2:
;; Added support for LaTeX-style literate scripts. Allow whitespace
;; after backslash to end a line for string continuations.
;;
;; Version 1.1:
;; Use own syntax table. Use backquote (neater). Stop ''' being
;; highlighted as quoted character. Fixed `\"' fontification bug
;; in comments.
;;
;; Version 1.0:
;; Brought over from Haskell mode v1.1.
;;
;; Present Limitations/Future Work (contributions are most welcome!):
;;
;; . Debatable whether `()' `[]' `(->)' `(,)' `(,,)' etc. should be
;; highlighted as constructors or not. Should the `->' in
;; `id :: a -> a' be considered a constructor or a keyword? If so,
;; how do we distinguish this from `\x -> x'? What about the `\'?
;;
;; . XEmacs can support both `--' comments and `{- -}' comments
;; simultaneously. If XEmacs is detected, this should be used.
;;
;; . Support for GreenCard?
;;
;; All functions/variables start with
;; `(turn-(on/off)-)haskell-font-lock' or `haskell-fl-'.
;;; Code:
(eval-when-compile
(require 'haskell-mode)
(require 'cl))
(require 'font-lock)
(defcustom haskell-font-lock-symbols nil
"Display \\ and -> and such using symbols in fonts.
This may sound like a neat trick, but be extra careful: it changes the
alignment and can thus lead to nasty surprises w.r.t layout.
If t, try to use whichever font is available. Otherwise you can
set it to a particular font of your preference among `japanese-jisx0208'
and `unicode'."
:group 'haskell
:type '(choice (const nil)
(const t)
(const unicode)
(const japanese-jisx0208)))
(defconst haskell-font-lock-symbols-alist
(append
;; Prefer single-width Unicode font for lambda.
(and (fboundp 'decode-char)
(memq haskell-font-lock-symbols '(t unicode))
(list (cons "\\" (decode-char 'ucs 955))))
;; The symbols can come from a JIS0208 font.
(and (fboundp 'make-char) (fboundp 'charsetp) (charsetp 'japanese-jisx0208)
(memq haskell-font-lock-symbols '(t japanese-jisx0208))
(list (cons "not" (make-char 'japanese-jisx0208 34 76))
(cons "\\" (make-char 'japanese-jisx0208 38 75))
(cons "->" (make-char 'japanese-jisx0208 34 42))
(cons "<-" (make-char 'japanese-jisx0208 34 43))
(cons "=>" (make-char 'japanese-jisx0208 34 77))
;; FIXME: I'd like to either use ∀ or ∃ depending on how the
;; `forall' keyword is used, but currently the rest of the
;; code assumes that such ambiguity doesn't happen :-(
(cons "forall" (make-char 'japanese-jisx0208 34 79))))
;; Or a unicode font.
(and (fboundp 'decode-char)
(memq haskell-font-lock-symbols '(t unicode))
(list (cons "not" (decode-char 'ucs 172))
(cons "->" (decode-char 'ucs 8594))
(cons "<-" (decode-char 'ucs 8592))
(cons "=>" (decode-char 'ucs 8658))
(cons "()" (decode-char 'ucs #X2205))
(cons "==" (decode-char 'ucs #X2261))
(cons "/=" (decode-char 'ucs #X2262))
(cons ">=" (decode-char 'ucs #X2265))
(cons "<=" (decode-char 'ucs #X2264))
(cons "!!" (decode-char 'ucs #X203C))
(cons "&&" (decode-char 'ucs #X2227))
(cons "||" (decode-char 'ucs #X2228))
(cons "sqrt" (decode-char 'ucs #X221A))
(cons "undefined" (decode-char 'ucs #X22A5))
(cons "pi" (decode-char 'ucs #X3C0))
(cons "~>" (decode-char 'ucs 8669)) ;; Omega language
;; (cons "~>" (decode-char 'ucs 8605)) ;; less desirable
(cons "-<" (decode-char 'ucs 8610)) ;; Paterson's arrow syntax
;; (cons "-<" (decode-char 'ucs 10521)) ;; nicer but uncommon
(cons "::" (decode-char 'ucs 8759))
(list "." (decode-char 'ucs 8728) ; (decode-char 'ucs 9675)
;; Need a predicate here to distinguish the . used by
;; forall <foo> . <bar>.
'haskell-font-lock-dot-is-not-composition)
(cons "forall" (decode-char 'ucs 8704)))))
"Alist mapping Haskell symbols to chars.
Each element has the form (STRING . CHAR) or (STRING CHAR PREDICATE).
STRING is the Haskell symbol.
CHAR is the character with which to represent this symbol.
PREDICATE if present is a function of one argument (the start position
of the symbol) which should return non-nil if this mapping should be disabled
at that position.")
(defun haskell-font-lock-dot-is-not-composition (start)
"Return non-nil if the \".\" at START is not a composition operator.
This is the case if the \".\" is part of a \"forall <tvar> . <type>\"."
(save-excursion
(goto-char start)
(re-search-backward "\\<forall\\>[^.\"]*\\="
(line-beginning-position) t)))
;; Use new vars for the font-lock faces. The indirection allows people to
;; use different faces than in other modes, as before.
(defvar haskell-keyword-face 'font-lock-keyword-face)
(defvar haskell-constructor-face 'font-lock-type-face)
;; This used to be `font-lock-variable-name-face' but it doesn't result in
;; a highlighting that's consistent with other modes (it's mostly used
;; for function defintions).
(defvar haskell-definition-face 'font-lock-function-name-face)
;; This is probably just wrong, but it used to use
;; `font-lock-function-name-face' with a result that was not consistent with
;; other major modes, so I just exchanged with `haskell-definition-face'.
(defvar haskell-operator-face 'font-lock-variable-name-face)
(defvar haskell-default-face nil)
(defvar haskell-literate-comment-face 'font-lock-doc-face
"Face with which to fontify literate comments.
Set to `default' to avoid fontification of them.")
(defconst haskell-emacs21-features (string-match "[[:alpha:]]" "x")
"Non-nil if we have regexp char classes.
Assume this means we have other useful features from Emacs 21.")
(defun haskell-font-lock-compose-symbol (alist)
"Compose a sequence of ascii chars into a symbol.
Regexp match data 0 points to the chars."
;; Check that the chars should really be composed into a symbol.
(let* ((start (match-beginning 0))
(end (match-end 0))
(syntaxes (cond
((eq (char-syntax (char-after start)) ?w) '(?w))
;; Special case for the . used for qualified names.
((and (eq (char-after start) ?\.) (= end (1+ start)))
'(?_ ?\\ ?w))
(t '(?_ ?\\))))
sym-data)
(if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
(memq (char-syntax (or (char-after end) ?\ )) syntaxes)
(memq (get-text-property start 'face)
'(font-lock-doc-face font-lock-string-face
font-lock-comment-face))
(and (consp (setq sym-data (cdr (assoc (match-string 0) alist))))
(let ((pred (cadr sym-data)))
(setq sym-data (car sym-data))
(funcall pred start))))
;; No composition for you. Let's actually remove any composition
;; we may have added earlier and which is now incorrect.
(remove-text-properties start end '(composition))
;; That's a symbol alright, so add the composition.
(compose-region start end sym-data)))
;; Return nil because we're not adding any face property.
nil)
(defun haskell-font-lock-symbols-keywords ()
(when (fboundp 'compose-region)
(let ((alist nil))
(dolist (x haskell-font-lock-symbols-alist)
(when (and (if (fboundp 'char-displayable-p)
(char-displayable-p (if (consp (cdr x)) (cadr x) (cdr x)))
t)
(not (assoc (car x) alist))) ;Not yet in alist.
(push x alist)))
(when alist
`((,(regexp-opt (mapcar 'car alist) t)
(0 (haskell-font-lock-compose-symbol ',alist)
;; In Emacs-21, if the `override' field is nil, the face
;; expressions is only evaluated if the text has currently
;; no face. So force evaluation by using `keep'.
keep)))))))
;; The font lock regular expressions.
(defun haskell-font-lock-keywords-create (literate)
"Create fontification definitions for Haskell scripts.
Returns keywords suitable for `font-lock-keywords'."
(let* (;; Bird-style literate scripts start a line of code with
;; "^>", otherwise a line of code starts with "^".
(line-prefix (if (eq literate 'bird) "^> ?" "^"))
;; Most names are borrowed from the lexical syntax of the Haskell
;; report.
;; Some of these definitions have been superseded by using the
;; syntax table instead.
;; (ASCsymbol "-!#$%&*+./<=>?@\\\\^|~")
;; Put the minus first to make it work in ranges.
;; (ISOsymbol "\241-\277\327\367")
(ISOlarge "\300-\326\330-\337")
(ISOsmall "\340-\366\370-\377")
(small
(if haskell-emacs21-features "[:lower:]" (concat "a-z" ISOsmall)))
(large
(if haskell-emacs21-features "[:upper:]" (concat "A-Z" ISOlarge)))
(alnum
(if haskell-emacs21-features "[:alnum:]" (concat small large "0-9")))
;; (symbol
;; (concat ASCsymbol ISOsymbol))
;; We allow _ as the first char to fit GHC
(varid (concat "\\b[" small "_][" alnum "'_]*\\b"))
(conid (concat "\\b[" large "][" alnum "'_]*\\b"))
(modid (concat "\\b" conid "\\(\\." conid "\\)*\\b"))
(qvarid (concat modid "\\." varid))
(qconid (concat modid "\\." conid))
(sym
;; We used to use the below for non-Emacs21, but I think the
;; regexp based on syntax works for other emacsen as well. -- Stef
;; (concat "[" symbol ":]+")
;; Add backslash to the symbol-syntax chars. This seems to
;; be thrown for some reason by backslash's escape syntax.
"\\(\\s_\\|\\\\\\)+")
;; Reserved operations
(reservedsym
(concat "\\S_"
;; (regexp-opt '(".." "::" "=" "\\" "|" "<-" "->"
;; "@" "~" "=>") t)
"\\(->\\|\\.\\.\\|::\\|<-\\|=>\\|[=@\\|~]\\)"
"\\S_"))
;; Reserved identifiers
(reservedid
(concat "\\<"
;; `as', `hiding', and `qualified' are part of the import
;; spec syntax, but they are not reserved.
;; `_' can go in here since it has temporary word syntax.
;; (regexp-opt
;; '("case" "class" "data" "default" "deriving" "do"
;; "else" "if" "import" "in" "infix" "infixl"
;; "infixr" "instance" "let" "module" "newtype" "of"
;; "then" "type" "where" "_") t)
"\\(_\\|c\\(ase\\|lass\\)\\|d\\(ata\\|e\\(fault\\|riving\\)\\|o\\)\\|else\\|i\\(mport\\|n\\(fix[lr]?\\|stance\\)\\|[fn]\\)\\|let\\|module\\|newtype\\|of\\|t\\(hen\\|ype\\)\\|where\\)"
"\\>"))
;; This unreadable regexp matches strings and character
;; constants. We need to do this with one regexp to handle
;; stuff like '"':"'". The regexp is the composition of
;; "([^"\\]|\\.)*" for strings and '([^\\]|\\.[^']*)' for
;; characters, allowing for string continuations.
;; Could probably be improved...
(string-and-char
(concat "\\(\\(\"\\|" line-prefix "[ \t]*\\\\\\)\\([^\"\\\\\n]\\|\\\\.\\)*\\(\"\\|\\\\[ \t]*$\\)\\|'\\([^'\\\\\n]\\|\\\\.[^'\n]*\\)'\\)"))
;; Top-level declarations
(topdecl-var
(concat line-prefix "\\(" varid "\\)\\s-*\\("
;; A toplevel declaration can be followed by a definition
;; (=), a type (::), a guard, or a pattern which can
;; either be a variable, a constructor, a parenthesized
;; thingy, or an integer or a string.
varid "\\|" conid "\\|::\\|=\\||\\|\\s(\\|[0-9\"']\\)"))
(topdecl-var2
(concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`"))
(topdecl-sym
(concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)"))
(topdecl-sym2 (concat line-prefix "(\\(" sym "\\))"))
keywords)
(setq keywords
`(;; NOTICE the ordering below is significant
;;
("^#.*$" 0 'font-lock-warning-face t)
,@(unless haskell-emacs21-features ;Supports nested comments?
;; Expensive.
`((,string-and-char 1 font-lock-string-face)))
;; This was originally at the very end (and needs to be after
;; all the comment/string/doc highlighting) but it seemed to
;; trigger a bug in Emacs-21.3 which caused the compositions to
;; be "randomly" dropped. Moving it earlier seemed to reduce
;; the occurrence of the bug.
,@(haskell-font-lock-symbols-keywords)
(,reservedid 1 (symbol-value 'haskell-keyword-face))
(,reservedsym 1 (symbol-value 'haskell-operator-face))
;; Special case for `as', `hiding', and `qualified', which are
;; keywords in import statements but are not otherwise reserved.
("\\<import[ \t]+\\(?:\\(qualified\\>\\)[ \t]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?"
(1 (symbol-value 'haskell-keyword-face) nil lax)
(2 (symbol-value 'haskell-keyword-face) nil lax)
(3 (symbol-value 'haskell-keyword-face) nil lax))
;; Toplevel Declarations.
;; Place them *before* generic id-and-op highlighting.
(,topdecl-var (1 (symbol-value 'haskell-definition-face)))
(,topdecl-var2 (2 (symbol-value 'haskell-definition-face)))
(,topdecl-sym (2 (symbol-value 'haskell-definition-face)))
(,topdecl-sym2 (1 (symbol-value 'haskell-definition-face)))
;; These four are debatable...
("(\\(,*\\|->\\))" 0 (symbol-value 'haskell-constructor-face))
("\\[\\]" 0 (symbol-value 'haskell-constructor-face))
;; Expensive.
(,qvarid 0 (symbol-value 'haskell-default-face))
(,qconid 0 (symbol-value 'haskell-constructor-face))
(,(concat "\`" varid "\`") 0 (symbol-value 'haskell-operator-face))
;; Expensive.
(,conid 0 (symbol-value 'haskell-constructor-face))
;; Very expensive.
(,sym 0 (if (eq (char-after (match-beginning 0)) ?:)
haskell-constructor-face
haskell-operator-face))))
(unless (boundp 'font-lock-syntactic-keywords)
(case literate
(bird
(setq keywords
`(("^[^>\n].*$" 0 haskell-comment-face t)
,@keywords
("^>" 0 haskell-default-face t))))
((latex tex)
(setq keywords
`((haskell-fl-latex-comments 0 'font-lock-comment-face t)
,@keywords)))))
keywords))
;; The next three aren't used in Emacs 21.
(defvar haskell-fl-latex-cache-pos nil
"Position of cache point used by `haskell-fl-latex-cache-in-comment'.
Should be at the start of a line.")
(defvar haskell-fl-latex-cache-in-comment nil
"If `haskell-fl-latex-cache-pos' is outside a
\\begin{code}..\\end{code} block (and therefore inside a comment),
this variable is set to t, otherwise nil.")
(defun haskell-fl-latex-comments (end)
"Sets `match-data' according to the region of the buffer before end
that should be commented under LaTeX-style literate scripts."
(let ((start (point)))
(if (= start end)
;; We're at the end. No more to fontify.
nil
(if (not (eq start haskell-fl-latex-cache-pos))
;; If the start position is not cached, calculate the state
;; of the start.
(progn
(setq haskell-fl-latex-cache-pos start)
;; If the previous \begin{code} or \end{code} is a
;; \begin{code}, then start is not in a comment, otherwise
;; it is in a comment.
(setq haskell-fl-latex-cache-in-comment
(if (and
(re-search-backward
"^\\(\\(\\\\begin{code}\\)\\|\\(\\\\end{code}\\)\\)$"
(point-min) t)
(match-end 2))
nil t))
;; Restore position.
(goto-char start)))
(if haskell-fl-latex-cache-in-comment
(progn
;; If start is inside a comment, search for next \begin{code}.
(re-search-forward "^\\\\begin{code}$" end 'move)
;; Mark start to end of \begin{code} (if present, till end
;; otherwise), as a comment.
(set-match-data (list start (point)))
;; Return point, as a normal regexp would.
(point))
;; If start is inside a code block, search for next \end{code}.
(if (re-search-forward "^\\\\end{code}$" end t)
;; If one found, mark it as a comment, otherwise finish.
(point))))))
(defconst haskell-basic-syntactic-keywords
'(;; Character constants (since apostrophe can't have string syntax).
;; Beware: do not match something like 's-}' or '\n"+' since the first '
;; might be inside a comment or a string.
;; This still gets fooled with "'"'"'"'"'"', but ... oh well.
("\\Sw\\('\\)\\([^\\'\n]\\|\\\\.[^\\'\n \"}]*\\)\\('\\)" (1 "|") (3 "|"))
;; The \ is not escaping in \(x,y) -> x + y.
("\\(\\\\\\)(" (1 "."))
;; The second \ in a gap does not quote the subsequent char.
;; It's probably not worth the trouble, tho.
;; ("^[ \t]*\\(\\\\\\)" (1 "."))
;; Deal with instances of `--' which don't form a comment.
("\\s_\\{3,\\}" (0 (if (string-match "\\`-*\\'" (match-string 0))
;; Sequence of hyphens. Do nothing in
;; case of things like `{---'.
nil
"_"))))) ; other symbol sequence
(defconst haskell-bird-syntactic-keywords
(cons '("^[^\n>]" (0 "<"))
haskell-basic-syntactic-keywords))
(defconst haskell-latex-syntactic-keywords
(append
'(("^\\\\begin{code}\\(\n\\)" 1 "!")
;; Note: buffer is widened during font-locking.
("\\`\\(.\\|\n\\)" (1 "!")) ; start comment at buffer start
("^\\(\\\\\\)end{code}$" 1 "!"))
haskell-basic-syntactic-keywords))
(defcustom haskell-font-lock-haddock (boundp 'font-lock-doc-face)
"If non-nil try to highlight Haddock comments specially."
:type 'boolean
:group 'haskell)
(defvar haskell-font-lock-seen-haddock nil)
(make-variable-buffer-local 'haskell-font-lock-seen-haddock)
(defun haskell-syntactic-face-function (state)
"`font-lock-syntactic-face-function' for Haskell."
(cond
((nth 3 state) font-lock-string-face) ; as normal
;; Else comment. If it's from syntax table, use default face.
((or (eq 'syntax-table (nth 7 state))
(and (eq haskell-literate 'bird)
(memq (char-before (nth 8 state)) '(nil ?\n))))
haskell-literate-comment-face)
;; Try and recognize Haddock comments. From what I gather from its
;; documentation, its comments can take the following forms:
;; a) {-| ... -}
;; b) {-^ ... -}
;; c) -- | ...
;; d) -- ^ ...
;; e) -- ...
;; Where `e' is the tricky one: it is only a Haddock comment if it
;; follows immediately another Haddock comment. Even an empty line
;; breaks such a sequence of Haddock comments. It is not clear if `e'
;; can follow any other case, so I interpreted it as following only cases
;; c,d,e (not a or b). In any case, this `e' is expensive since it
;; requires extra work for each and every non-Haddock comment, so I only
;; go through the more expensive check if we've already seen a Haddock
;; comment in the buffer.
((and haskell-font-lock-haddock
(save-excursion
(goto-char (nth 8 state))
(or (looking-at "\\(-- \\|{-\\)[|^]")
(and haskell-font-lock-seen-haddock
(looking-at "-- ")
(let ((doc nil)
pos)
(while (and (not doc)
(setq pos (line-beginning-position))
(forward-comment -1)
(eq (line-beginning-position 2) pos)
(looking-at "--\\( [|^]\\)?"))
(setq doc (match-beginning 1)))
doc)))))
(set (make-local-variable 'haskell-font-lock-seen-haddock) t)
font-lock-doc-face)
(t font-lock-comment-face)))
(defconst haskell-font-lock-keywords
(haskell-font-lock-keywords-create nil)
"Font lock definitions for non-literate Haskell.")
(defconst haskell-font-lock-bird-literate-keywords
(haskell-font-lock-keywords-create 'bird)
"Font lock definitions for Bird-style literate Haskell.")
(defconst haskell-font-lock-latex-literate-keywords
(haskell-font-lock-keywords-create 'latex)
"Font lock definitions for LaTeX-style literate Haskell.")
(defun haskell-font-lock-choose-keywords ()
(let ((literate (if (boundp 'haskell-literate) haskell-literate)))
(case literate
(bird haskell-font-lock-bird-literate-keywords)
((latex tex) haskell-font-lock-latex-literate-keywords)
(t haskell-font-lock-keywords))))
(defun haskell-font-lock-choose-syntactic-keywords ()
(let ((literate (if (boundp 'haskell-literate) haskell-literate)))
(case literate
(bird haskell-bird-syntactic-keywords)
((latex tex) haskell-latex-syntactic-keywords)
(t haskell-basic-syntactic-keywords))))
(defun haskell-font-lock-defaults-create ()
"Locally set `font-lock-defaults' for Haskell."
(set (make-local-variable 'font-lock-defaults)
'(haskell-font-lock-choose-keywords
nil nil ((?\' . "w") (?_ . "w")) nil
(font-lock-syntactic-keywords
. haskell-font-lock-choose-syntactic-keywords)
(font-lock-syntactic-face-function
. haskell-syntactic-face-function)
;; Get help from font-lock-syntactic-keywords.
(parse-sexp-lookup-properties . t))))
;; The main functions.
(defun turn-on-haskell-font-lock ()
"Turns on font locking in current buffer for Haskell 1.4 scripts.
Changes the current buffer's `font-lock-defaults', and adds the
following variables:
`haskell-keyword-face' for reserved keywords and syntax,
`haskell-constructor-face' for data- and type-constructors, class names,
and module names,
`haskell-operator-face' for symbolic and alphanumeric operators,
`haskell-default-face' for ordinary code.
The variables are initialised to the following font lock default faces:
`haskell-keyword-face' `font-lock-keyword-face'
`haskell-constructor-face' `font-lock-type-face'
`haskell-operator-face' `font-lock-function-name-face'
`haskell-default-face' <default face>
Two levels of fontification are defined: level one (the default)
and level two (more colour). The former does not colour operators.
Use the variable `font-lock-maximum-decoration' to choose
non-default levels of fontification. For example, adding this to
.emacs:
(setq font-lock-maximum-decoration '((haskell-mode . 2) (t . 0)))
uses level two fontification for `haskell-mode' and default level for
all other modes. See documentation on this variable for further
details.
To alter an attribute of a face, add a hook. For example, to change
the foreground colour of comments to brown, add the following line to
.emacs:
(add-hook 'haskell-font-lock-hook
(lambda ()
(set-face-foreground 'haskell-comment-face \"brown\")))
Note that the colours available vary from system to system. To see
what colours are available on your system, call
`list-colors-display' from emacs.
To turn font locking on for all Haskell buffers, add this to .emacs:
(add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
To turn font locking on for the current buffer, call
`turn-on-haskell-font-lock'. To turn font locking off in the current
buffer, call `turn-off-haskell-font-lock'.
Bird-style literate Haskell scripts are supported: If the value of
`haskell-literate-bird-style' (automatically set by the Haskell mode
of Moss&Thorn) is non-nil, a Bird-style literate script is assumed.
Invokes `haskell-font-lock-hook' if not nil."
(haskell-font-lock-defaults-create)
(run-hooks 'haskell-font-lock-hook)
(turn-on-font-lock))
(defun turn-off-haskell-font-lock ()
"Turns off font locking in current buffer."
(font-lock-mode -1))
;; Provide ourselves:
(provide 'haskell-font-lock)
;; arch-tag: 89fd122e-8378-4c7f-83a3-1f49a64e458d
;;; haskell-font-lock.el ends here

View file

@ -0,0 +1,332 @@
;;; haskell-ghci.el --- A GHCi interaction mode
;; Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Copyright (C) 2001 Chris Webb
;; Copyright (C) 1998, 1999 Guy Lapalme
;; Keywords: inferior mode, GHCi interaction mode, Haskell
;;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; To send a Haskell buffer to another buffer running a GHCi
;; interpreter.
;;
;; This mode is derived from version 1.1 of Guy Lapalme's
;; haskell-hugs.el, which can be obtained from:
;;
;; http://www.iro.umontreal.ca/~lapalme/Hugs-interaction.html
;;
;; This in turn was adapted from Chris Van Humbeeck's hugs-mode.el,
;; which can be obtained from:
;;
;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el
;;
;;
;; Installation:
;;
;; To use with Moss and Thorn's haskell-mode.el
;;
;; http://www.haskell.org/haskell-mode
;;
;; add this to .emacs:
;;
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-ghci)
;;
;;
;; Customisation:
;;
;; The name of the GHCi interpreter is in haskell-ghci-program-name.
;;
;; Arguments can be sent to the GHCi interpreter when it is started by
;; setting haskell-ghci-program-args (empty by default) to a list of
;; string args to pass it. This value can be set interactively by
;; calling C-c C-s with an argument (i.e. C-u C-c C-s).
;;
;; `haskell-ghci-hook' is invoked in the *ghci* buffer once GHCi is
;; started.
;;
;; All functions/variables start with `turn-{on,off}-haskell-ghci' or
;; `haskell-ghci-'.
;;; Code:
(defgroup haskell-ghci nil
"Major mode for interacting with an inferior GHCi session."
:group 'haskell
:prefix "haskell-ghci-")
(defun turn-on-haskell-ghci ()
"Turn on Haskell interaction mode with a GHCi interpreter running in an
another Emacs buffer named *ghci*.
Maps the following commands in the haskell keymap:
\\<haskell-mode-map>\\[haskell-ghci-start-process] to create the GHCi buffer and start a GHCi process in it.
\\[haskell-ghci-load-file] to save the current buffer and load it by sending the :load command to GHCi.
\\[haskell-ghci-reload-file] to send the :reload command to GHCi without saving the buffer.
\\[haskell-ghci-show-ghci-buffer] to show the GHCi buffer and go to it."
(local-set-key "\C-c\C-s" 'haskell-ghci-start-process)
(local-set-key "\C-c\C-l" 'haskell-ghci-load-file)
(local-set-key "\C-c\C-r" 'haskell-ghci-reload-file)
(local-set-key "\C-c\C-n" 'haskell-ghci-locate-next-error)
(local-set-key "\C-c\C-b" 'haskell-ghci-show-ghci-buffer))
(defun turn-off-haskell-ghci ()
"Turn off Haskell interaction mode with a GHCi interpreter within a buffer."
(local-unset-key "\C-c\C-s")
(local-unset-key "\C-c\C-l")
(local-unset-key "\C-c\C-r")
(local-unset-key "\C-c\C-b"))
(define-derived-mode haskell-ghci-mode comint-mode "Haskell GHCi"
"Major mode for interacting with an inferior GHCi session.
The commands available from within a Haskell script are:
\\<haskell-mode-map>\\[haskell-ghci-start-process] to create the GHCi buffer and start a GHCi process in it.
\\[haskell-ghci-load-file] to save the current buffer and load it by sending the :load command to GHCi.
\\[haskell-ghci-reload-file] to send the :reload command to GHCi without saving the buffer.
\\[haskell-ghci-show-ghci-buffer] to show the GHCi buffer and go to it.
\\<haskell-ghci-mode-map>Commands:
\\[comint-send-input] after end of GHCi output sends line as input to GHCi.
\\[comint-send-input] before end of GHCI output copies rest of line and sends it to GHCI as input.
\\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
\\[comint-interrupt-subjob] interrupts the comint or its current subjob if any.
\\[comint-stop-subjob] stops, likewise. \\[comint-quit-subjob] sends quit signal.")
;; GHCi interface:
(require 'comint)
(require 'shell)
(defvar haskell-ghci-process nil
"The active GHCi subprocess corresponding to current buffer.")
(defvar haskell-ghci-process-buffer nil
"*Buffer used for communication with GHCi subprocess for current buffer.")
(defcustom haskell-ghci-program-name "ghci"
"*The name of the GHCi interpreter program."
:type 'string
:group 'haskell-ghci)
(defcustom haskell-ghci-program-args nil
"*A list of string args to pass when starting the GHCi interpreter."
:type '(repeat string)
:group 'haskell-ghci)
(defvar haskell-ghci-load-end nil
"Position of the end of the last load command.")
(defvar haskell-ghci-error-pos nil
"Position of the end of the last load command.")
(defvar haskell-ghci-send-end nil
"Position of the end of the last send command.")
(defun haskell-ghci-start-process (arg)
"Start a GHCi process and invoke `haskell-ghci-hook' if not nil.
Prompt for a list of args if called with an argument."
(interactive "P")
(if arg
;; XXX [CDW] Fix to use more natural 'string' version of the
;; XXX arguments rather than a sexp.
(setq haskell-ghci-program-args
(read-minibuffer (format "List of args for %s:"
haskell-ghci-program-name)
(prin1-to-string haskell-ghci-program-args))))
;; Start the GHCi process in a new comint buffer.
(message "Starting GHCi process `%s'." haskell-ghci-program-name)
(setq haskell-ghci-process-buffer
(apply 'make-comint
"ghci" haskell-ghci-program-name nil
haskell-ghci-program-args))
(setq haskell-ghci-process
(get-buffer-process haskell-ghci-process-buffer))
;; Select GHCi buffer temporarily.
(set-buffer haskell-ghci-process-buffer)
(haskell-ghci-mode)
(make-local-variable 'shell-cd-regexp)
(make-local-variable 'shell-dirtrackp)
;; Track directory changes using the `:cd' command.
(setq shell-cd-regexp ":cd")
(setq shell-dirtrackp t)
(add-hook 'comint-input-filter-functions 'shell-directory-tracker nil 'local)
;; GHCi prompt should be of the form `ModuleName> '.
(setq comint-prompt-regexp "^\\*?[A-Z][\\._a-zA-Z0-9]*\\( \\*?[A-Z][\\._a-zA-Z0-9]*\\)*> ")
;; History syntax of comint conflicts with Haskell, e.g. !!, so better
;; turn it off.
(setq comint-input-autoexpand nil)
(run-hooks 'haskell-ghci-hook)
;; Clear message area.
(message ""))
(defun haskell-ghci-wait-for-output ()
"Wait until output arrives and go to the last input."
(while (progn
(goto-char comint-last-input-end)
(not (re-search-forward comint-prompt-regexp nil t)))
(accept-process-output haskell-ghci-process)))
(defun haskell-ghci-send (&rest string)
"Send `haskell-ghci-process' the arguments (one or more strings).
A newline is sent after the strings and they are inserted into the
current buffer after the last output."
(haskell-ghci-wait-for-output) ; wait for prompt
(goto-char (point-max)) ; position for this input
(apply 'insert string)
(comint-send-input)
(setq haskell-ghci-send-end (marker-position comint-last-input-end)))
(defun haskell-ghci-go (load-command cd)
"Save the current buffer and load its file into the GHCi process.
The first argument LOAD-COMMAND specifies how the file should be
loaded: as a new file (\":load \") or as a reload (\":reload \").
If the second argument CD is non-nil, change directory in the GHCi
process to the current buffer's directory before loading the file.
If the variable `haskell-ghci-command' is set then its value will be
sent to the GHCi process after the load command. This can be used for a
top-level expression to evaluate."
(hack-local-variables) ; in case they've changed
(save-buffer)
(let ((file (if (string-equal load-command ":load ")
(concat "\"" buffer-file-name "\"")
""))
(dir (expand-file-name default-directory))
(cmd (and (boundp 'haskell-ghci-command)
haskell-ghci-command
(if (stringp haskell-ghci-command)
haskell-ghci-command
(symbol-name haskell-ghci-command)))))
(if (and haskell-ghci-process-buffer
(eq (process-status haskell-ghci-process) 'run))
;; Ensure the GHCi buffer is selected.
(set-buffer haskell-ghci-process-buffer)
;; Start Haskell-GHCi process.
(haskell-ghci-start-process nil))
(if cd (haskell-ghci-send (concat ":cd " dir)))
;; Wait until output arrives and go to the last input.
(haskell-ghci-wait-for-output)
(haskell-ghci-send load-command file)
;; Error message search starts from last load command.
(setq haskell-ghci-load-end (marker-position comint-last-input-end))
(setq haskell-ghci-error-pos haskell-ghci-load-end)
(if cmd (haskell-ghci-send cmd))
;; Wait until output arrives and go to the last input.
(haskell-ghci-wait-for-output)))
(defun haskell-ghci-load-file (cd)
"Save a ghci buffer file and load its file.
If CD (prefix argument if interactive) is non-nil, change directory in
the GHCi process to the current buffer's directory before loading the
file. If there is an error, set the cursor at the error line otherwise
show the *ghci* buffer."
(interactive "P")
(haskell-ghci-gen-load-file ":load " cd))
(defun haskell-ghci-reload-file (cd)
"Save a ghci buffer file and load its file.
If CD (prefix argument if interactive) is non-nil, change the GHCi
process to the current buffer's directory before loading the file.
If there is an error, set the cursor at the error line otherwise show
the *ghci* buffer."
(interactive "P")
(haskell-ghci-gen-load-file ":reload " cd))
(defun haskell-ghci-gen-load-file (cmd cd)
"Save a ghci buffer file and load its file or reload depending on CMD.
If CD is non-nil, change the process to the current buffer's directory
before loading the file. If there is an error, set the cursor at the
error line otherwise show the *ghci* buffer."
;; Execute (re)load command.
(save-excursion (haskell-ghci-go cmd cd))
;; Show *ghci* buffer.
(pop-to-buffer haskell-ghci-process-buffer)
(goto-char haskell-ghci-load-end)
;; Did we finish loading without error?
(if (re-search-forward
"^Ok, modules loaded" nil t)
(progn (goto-char (point-max))
(recenter 2)
(message "There were no errors."))
;; Something went wrong. If possible, be helpful and pinpoint the
;; first error in the file whilst leaving the error visible in the
;; *ghci* buffer.
(goto-char haskell-ghci-load-end)
(haskell-ghci-locate-next-error)))
(defun haskell-ghci-locate-next-error ()
"Go to the next error shown in the *ghci* buffer."
(interactive)
(if (buffer-live-p haskell-ghci-process-buffer)
(progn (pop-to-buffer haskell-ghci-process-buffer)
(goto-char haskell-ghci-error-pos)
(if (re-search-forward
"^[^\/]*\\([^:\n]+\\):\\([0-9]+\\)" nil t)
(let ((efile (buffer-substring (match-beginning 1)
(match-end 1)))
(eline (string-to-int
(buffer-substring (match-beginning 2)
(match-end 2)))))
(recenter 2)
(setq haskell-ghci-error-pos (point))
(message "GHCi error on line %d of %s."
eline (file-name-nondirectory efile))
(if (file-exists-p efile)
(progn (find-file-other-window efile)
(goto-line eline)
(recenter))))
;; We got an error without a file and line number, so put the
;; point at end of the *ghci* buffer ready to deal with it.
(goto-char (point-max))
(recenter -2)
(message "No more errors found.")))
(message "No *ghci* buffer found.")))
(defun haskell-ghci-show-ghci-buffer ()
"Go to the *ghci* buffer."
(interactive)
(if (or (not haskell-ghci-process-buffer)
(not (buffer-live-p haskell-ghci-process-buffer)))
(haskell-ghci-start-process nil))
(pop-to-buffer haskell-ghci-process-buffer))
(provide 'haskell-ghci)
;; arch-tag: f0bade4b-288d-4329-9791-98c1e24167ac
;;; haskell-ghci.el ends here

View file

@ -0,0 +1,316 @@
;;; haskell-hugs.el --- simplistic interaction mode with a
;; Copyright 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Copyright 1998, 1999 Guy Lapalme
;; Hugs interpreter for Haskell developped by
;; The University of Nottingham and Yale University, 1994-1997.
;; Web: http://www.haskell.org/hugs.
;; In standard Emacs terminology, this would be called
;; inferior-hugs-mode
;; Keywords: Hugs inferior mode, Hugs interaction mode
;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-hugs.el?rev=HEAD
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; To send a Haskell buffer to another buffer running a Hugs interpreter
;; The functions are adapted from the Hugs Mode developed by
;; Chris Van Humbeeck <chris.vanhumbeeck@cs.kuleuven.ac.be>
;; which used to be available at:
;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el
;;
;; Installation:
;;
;; To use with the Haskell mode of
;; Moss&Thorn <http://www.haskell.org/haskell-mode>
;; add this to .emacs:
;;
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-hugs)
;;
;; Customisation:
;; The name of the hugs interpreter is in variable
;; haskell-hugs-program-name
;; Arguments can be sent to the Hugs interpreter when it is called
;; by setting the value of the variable
;; haskell-hugs-program-args
;; which by default contains '("+.") so that the progress of the
;; interpreter is visible without any "^H" in the *hugs* Emacs buffer.
;;
;; This value can be interactively by calling C-cC-s with an
;; argument.
;;
;; If the command does not seem to respond, see the
;; content of the `comint-prompt-regexp' variable
;; to check that it waits for the appropriate Hugs prompt
;; the current value is appropriate for Hugs 1.3 and 1.4
;;
;;
;; `haskell-hugs-hook' is invoked in the *hugs* once it is started.
;;
;;; All functions/variables start with
;;; `(turn-(on/off)-)haskell-hugs' or `haskell-hugs-'.
(defgroup haskell-hugs nil
"Major mode for interacting with an inferior Hugs session."
:group 'haskell
:prefix "haskell-hugs-")
(defun turn-on-haskell-hugs ()
"Turn on Haskell interaction mode with a Hugs interpreter running in an
another Emacs buffer named *hugs*.
Maps the followind commands in the haskell keymap.
\\[haskell-hugs-load-file]
to save the current buffer and load it by sending the :load command
to Hugs.
\\[haskell-hugs-reload-file]
to send the :reload command to Hugs without saving the buffer.
\\[haskell-hugs-show-hugs-buffer]
to show the Hugs buffer and go to it."
(local-set-key "\C-c\C-s" 'haskell-hugs-start-process)
(local-set-key "\C-c\C-l" 'haskell-hugs-load-file)
(local-set-key "\C-c\C-r" 'haskell-hugs-reload-file)
(local-set-key "\C-c\C-b" 'haskell-hugs-show-hugs-buffer))
(defun turn-off-haskell-hugs ()
"Turn off Haskell interaction mode with a Hugs interpreter within a buffer."
(local-unset-key "\C-c\C-s")
(local-unset-key "\C-c\C-l")
(local-unset-key "\C-c\C-r")
(local-unset-key "\C-c\C-b"))
(define-derived-mode haskell-hugs-mode comint-mode "Haskell Hugs"
;; called by haskell-hugs-start-process,
;; itself called by haskell-hugs-load-file
;; only when the file is loaded the first time
"Major mode for interacting with an inferior Hugs session.
The commands available from within a Haskell script are:
\\<haskell-mode-map>\\[haskell-hugs-load-file]
to save the current buffer and load it by sending the :load command
to Hugs.
\\[haskell-hugs-reload-file]
to send the :reload command to Hugs without saving the buffer.
\\[haskell-hugs-show-hugs-buffer]
to show the Hugs buffer and go to it.
\\<haskell-hugs-mode-map>
Commands:
Return at end of buffer sends line as input.
Return not at end copies rest of line to end and sends it.
\\[comint-kill-input] and \\[backward-kill-word] are kill commands,
imitating normal Unix input editing.
\\[comint-interrupt-subjob] interrupts the comint or its current
subjob if any.
\\[comint-stop-subjob] stops, likewise.
\\[comint-quit-subjob] sends quit signal."
)
;; Hugs-interface
(require 'comint)
(require 'shell)
(defvar haskell-hugs-process nil
"The active Hugs subprocess corresponding to current buffer.")
(defvar haskell-hugs-process-buffer nil
"*Buffer used for communication with Hugs subprocess for current buffer.")
(defcustom haskell-hugs-program-name "hugs"
"*The name of the command to start the Hugs interpreter."
:type 'string
:group 'haskell-hugs)
(defcustom haskell-hugs-program-args '("+.")
"*A list of string args to send to the hugs process."
:type '(repeat string)
:group 'haskell-hugs)
(defvar haskell-hugs-load-end nil
"Position of the end of the last load command.")
(defvar haskell-hugs-send-end nil
"Position of the end of the last send command.")
(defalias 'run-hugs 'haskell-hugs-start-process)
(defun haskell-hugs-start-process (arg)
"Start a Hugs process and invokes `haskell-hugs-hook' if not nil.
Prompts for a list of args if called with an argument."
(interactive "P")
(message "Starting `hugs-process' %s" haskell-hugs-program-name)
(if arg
(setq haskell-hugs-program-args
(read-minibuffer "List of args for Hugs:"
(prin1-to-string haskell-hugs-program-args))))
(setq haskell-hugs-process-buffer
(apply 'make-comint
"hugs" haskell-hugs-program-name nil
haskell-hugs-program-args))
(setq haskell-hugs-process
(get-buffer-process haskell-hugs-process-buffer))
;; Select Hugs buffer temporarily
(set-buffer haskell-hugs-process-buffer)
(haskell-hugs-mode)
(make-local-variable 'shell-cd-regexp)
(make-local-variable 'shell-dirtrackp)
(setq shell-cd-regexp ":cd")
(setq shell-dirtrackp t)
(add-hook 'comint-input-filter-functions 'shell-directory-tracker nil 'local)
; ? or module name in Hugs 1.4
(setq comint-prompt-regexp "^\? \\|^[A-Z][_a-zA-Z0-9\.]*> ")
;; comint's history syntax conflicts with Hugs syntax, eg. !!
(setq comint-input-autoexpand nil)
(run-hooks 'haskell-hugs-hook)
(message "")
)
(defun haskell-hugs-wait-for-output ()
"Wait until output arrives and go to the last input."
(while (progn
(goto-char comint-last-input-end)
(and
(not (re-search-forward comint-prompt-regexp nil t))
(accept-process-output haskell-hugs-process)))))
(defun haskell-hugs-send (&rest string)
"Send `haskell-hugs-process' the arguments (one or more strings).
A newline is sent after the strings and they are inserted into the
current buffer after the last output."
;; Wait until output arrives and go to the last input.
(haskell-hugs-wait-for-output)
;; Position for this input.
(goto-char (point-max))
(apply 'insert string)
(comint-send-input)
(setq haskell-hugs-send-end (marker-position comint-last-input-end)))
(defun haskell-hugs-go (load-command cd)
"Save the current buffer and load its file into the Hugs process.
The first argument LOAD-COMMAND specifies how the file should be
loaded: as a new file (\":load \") or as a reload (\":reload \").
If the second argument CD is non-nil, change the Haskell-Hugs process to the
current buffer's directory before loading the file.
If the variable `haskell-hugs-command' is set then its value will be sent to
the Hugs process after the load command. This can be used for a
top-level expression to evaluate."
(hack-local-variables) ;; In case they've changed
(save-buffer)
(let ((file (if (string-equal load-command ":load ")
(concat "\"" buffer-file-name "\"")
""))
(dir (expand-file-name default-directory))
(cmd (and (boundp 'haskell-hugs-command)
haskell-hugs-command
(if (stringp haskell-hugs-command)
haskell-hugs-command
(symbol-name haskell-hugs-command)))))
(if (and haskell-hugs-process-buffer
(eq (process-status haskell-hugs-process) 'run))
;; Ensure the Hugs buffer is selected.
(set-buffer haskell-hugs-process-buffer)
;; Start Haskell-Hugs process.
(haskell-hugs-start-process nil))
(if cd (haskell-hugs-send (concat ":cd " dir)))
;; Wait until output arrives and go to the last input.
(haskell-hugs-wait-for-output)
(haskell-hugs-send load-command file)
;; Error message search starts from last load command.
(setq haskell-hugs-load-end (marker-position comint-last-input-end))
(if cmd (haskell-hugs-send cmd))
;; Wait until output arrives and go to the last input.
(haskell-hugs-wait-for-output)))
(defun haskell-hugs-load-file (cd)
"Save a hugs buffer file and load its file.
If CD (prefix argument if interactive) is non-nil, change the Hugs
process to the current buffer's directory before loading the file.
If there is an error, set the cursor at the error line otherwise show
the Hugs buffer."
(interactive "P")
(haskell-hugs-gen-load-file ":load " cd)
)
(defun haskell-hugs-reload-file (cd)
"Save a hugs buffer file and load its file.
If CD (prefix argument if interactive) is non-nil, change the Hugs
process to the current buffer's directory before loading the file.
If there is an error, set the cursor at the error line otherwise show
the Hugs buffer."
(interactive "P")
(haskell-hugs-gen-load-file ":reload " cd)
)
(defun haskell-hugs-gen-load-file (cmd cd)
"Save a hugs buffer file and load its file or reload depending on CMD.
If CD is non-nil, change the process to the current buffer's directory
before loading the file. If there is an error, set the cursor at the
error line otherwise show the Hugs buffer."
(save-excursion (haskell-hugs-go cmd cd))
;; Ensure the Hugs buffer is selected.
(set-buffer haskell-hugs-process-buffer)
;; Error message search starts from last load command.
(goto-char haskell-hugs-load-end)
(if (re-search-forward
"^ERROR \"\\([^ ]*\\)\"\\( (line \\([0-9]*\\))\\|\\)" nil t)
(let ((efile (buffer-substring (match-beginning 1)
(match-end 1)))
(eline (if (match-beginning 3)
(string-to-int (buffer-substring (match-beginning 3)
(match-end 3)))))
(emesg (buffer-substring (1+ (point))
(save-excursion (end-of-line) (point)))))
(pop-to-buffer haskell-hugs-process-buffer) ; show *hugs* buffer
(goto-char (point-max))
(recenter)
(message "Hugs error %s %s"
(file-name-nondirectory efile) emesg)
(if (file-exists-p efile)
(progn (find-file-other-window efile)
(if eline (goto-line eline))
(recenter)))
)
(pop-to-buffer haskell-hugs-process-buffer) ; show *hugs* buffer
(goto-char (point-max))
(message "There were no errors.")
(recenter 2) ; show only the end...
)
)
(defun haskell-hugs-show-hugs-buffer ()
"Goes to the Hugs buffer."
(interactive)
(if (or (not haskell-hugs-process-buffer)
(not (buffer-live-p haskell-hugs-process-buffer)))
(haskell-hugs-start-process nil))
(pop-to-buffer haskell-hugs-process-buffer)
)
(provide 'haskell-hugs)
;; arch-tag: c2a621e9-d743-4361-a459-983fbf1d4589
;;; haskell-hugs.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,856 @@
;;; haskell-indentation.el -- indentation module for Haskell Mode
;; Copyright 2009 Kristof Bastiaensen
;; Author: 2009 Kristof Bastiaensen <kristof.bastiaensen@vleeuwen.org>
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Installation:
;;
;; To turn indentation on for all Haskell buffers under Haskell mode
;; <http://www.haskell.org/haskell-mode/> add this to .emacs:
;;
;; (add-hook haskell-mode-hook 'turn-on-haskell-indentation)
;;
;; Otherwise, call `haskell-indentation-mode'.
;;
;;; Code:
(defgroup haskell-indentation nil
"Haskell indentation."
:group 'haskell
:prefix "haskell-indentation-")
(defcustom haskell-indentation-cycle-warn t
"Warn before moving to the leftmost indentation, if you tab at the rightmost one."
:type 'boolean
:group 'haskell-indentation)
(defcustom haskell-indentation-layout-offset 2
"Extra indentation to add before expressions in a haskell layout list."
:type 'integer
:group 'haskell-indentation)
(defcustom haskell-indentation-starter-offset 1
"Extra indentation after an opening keyword (e.g. let)."
:type 'integer
:group 'haskell-indentation)
(defcustom haskell-indentation-left-offset 2
"Extra indentation after an indentation to the left (e.g. after do)."
:type 'integer
:group 'haskell-indentation)
(defcustom haskell-indentation-ifte-offset 2
"Extra indentation after the keywords `if' `then' or `else'."
:type 'integer
:group 'haskell-indentation)
(when (featurep 'xemacs)
(defun syntax-ppss (&rest pos)
(parse-partial-sexp (point-min) (or pos (point)))))
(defconst haskell-indentation-mode-map
(let ((keymap (make-sparse-keymap)))
(define-key keymap [?\r] 'haskell-newline-and-indent)
(define-key keymap [backspace] 'haskell-indentation-delete-backward-char)
(define-key keymap [?\C-d] 'haskell-indentation-delete-char)
keymap))
;;;###autoload
(define-minor-mode haskell-indentation-mode
"Haskell indentation mode that deals with the layout rule.
It rebinds RET, DEL and BACKSPACE, so that indentations can be
set and deleted as if they were real tabs. It supports
autofill-mode."
:lighter " Ind"
:keymap haskell-indentation-mode-map
(kill-local-variable 'indent-line-function)
(kill-local-variable 'normal-auto-fill-function)
(when haskell-indentation-mode
(setq max-lisp-eval-depth (max max-lisp-eval-depth 600)) ;; set a higher limit for recursion
(set (make-local-variable 'indent-line-function)
'haskell-indentation-indent-line)
(set (make-local-variable 'normal-auto-fill-function)
'haskell-indentation-auto-fill-function)
(set (make-local-variable 'haskell-indent-last-position)
nil)))
(defun turn-on-haskell-indentation ()
"Turn on the haskell-indentation minor mode"
(interactive)
(haskell-indentation-mode t))
(put 'parse-error
'error-conditions
'(error parse-error))
(put 'parse-error 'error-message "Parse error")
(defun parse-error (&rest args)
(signal 'parse-error (apply 'format args)))
(defmacro on-parse-error (except &rest body)
`(condition-case parse-error-string
(progn ,@body)
(parse-error
,except
(message "%s" (cdr parse-error-string)))))
(defun kill-indented-line (&optional arg)
"`kill-line' for indented text.
Preserves indentation and removes extra whitespace"
(interactive "P")
(let ((col (current-column))
(old-point (point)))
(cond ((or (and (numberp arg) (< arg 0))
(and (not (looking-at "[ \t]*$"))
(or (not (numberp arg)) (zerop arg))))
;use default behavior when calling with a negative argument
;or killing (once) from the middle of a line
(kill-line arg))
((and (skip-chars-backward " \t") ;always true
(bolp)
(save-excursion
(forward-line arg)
(not (looking-at "[ \t]*$"))))
; killing from an empty line:
; preserve indentation of the next line
(kill-region (point)
(save-excursion
(forward-line arg)
(point)))
(skip-chars-forward " \t")
(if (> (current-column) col)
(move-to-column col)))
(t ; killing from not empty line:
; kill all indentation
(goto-char old-point)
(kill-region (point)
(save-excursion
(forward-line arg)
(skip-chars-forward " \t")
(point)))))))
(defun haskell-indentation-auto-fill-function ()
(when (> (current-column) fill-column)
(while (> (current-column) fill-column)
(skip-syntax-backward "-")
(skip-syntax-backward "^-"))
(let ((auto-fill-function nil)
(indent (car (last (haskell-indentation-find-indentations)))))
(newline)
(indent-to indent)
(end-of-line))))
(defun haskell-indentation-reindent (col)
(beginning-of-line)
(delete-region (point)
(progn (skip-syntax-forward "-")
(point)))
(indent-to col))
(defun haskell-newline-and-indent ()
(interactive)
(on-parse-error (newline)
(let* ((cc (current-column))
(ci (current-indentation))
(indentations (haskell-indentation-find-indentations)))
(skip-syntax-forward "-")
(if (prog1 (and (eolp)
(not (= (current-column) ci)))
(newline))
(haskell-indentation-reindent
(max (haskell-indentation-butlast indentations)
(haskell-indentation-matching-indentation
ci indentations)))
(haskell-indentation-reindent (haskell-indentation-matching-indentation
cc indentations))))))
(defun haskell-indentation-one-indentation (col indentations)
(let* ((last-pair (last indentations)))
(cond ((null indentations)
col)
((null (cdr indentations))
(car indentations))
((<= col (car last-pair))
col)
(t (car last-pair)))))
(defun haskell-indentation-butlast (indentations)
(when (consp (cdr indentations))
(while (cddr indentations)
(setq indentations (cdr indentations))))
(car indentations))
(defun haskell-indentation-next-indentation (col indentations)
"Find the lefmost indentation which is greater than COL."
(catch 'return
(while indentations
(if (or (< col (car indentations))
(null (cdr indentations)))
(throw 'return (car indentations))
(setq indentations (cdr indentations))))
col))
(defun haskell-indentation-previous-indentation (col indentations)
"Find the rightmost indentation which is less than COL."
(and indentations
(> col (car indentations))
(catch 'return
(while indentations
(if (or (null (cdr indentations))
(<= col (cadr indentations)))
(throw 'return (car indentations))
(setq indentations (cdr indentations))))
col)))
(defun haskell-indentation-matching-indentation (col indentations)
"Find the leftmost indentation which is greater than or equal to COL."
(catch 'return
(while indentations
(if (or (<= col (car indentations))
(null (cdr indentations)))
(throw 'return (car indentations))
(setq indentations (cdr indentations))))
col))
(defun haskell-indentation-indent-line ()
(when (save-excursion
(beginning-of-line)
(not (nth 8 (syntax-ppss))))
(let ((ci (current-indentation))
(start-column (current-column)))
(cond ((> (current-column) ci)
(save-excursion
(move-to-column ci)
(haskell-indentation-reindent
(haskell-indentation-one-indentation
ci (haskell-indentation-find-indentations)))))
((= (current-column) ci)
(haskell-indentation-reindent
(haskell-indentation-next-indentation
ci (haskell-indentation-find-indentations))))
(t (move-to-column ci)
(haskell-indentation-reindent
(haskell-indentation-matching-indentation
ci (haskell-indentation-find-indentations)))))
(cond ((not (= (current-column) start-column))
(setq haskell-indent-last-position nil))
((not haskell-indentation-cycle-warn)
(haskell-indentation-reindent
(haskell-indentation-next-indentation
-1
(haskell-indentation-find-indentations))))
((not (eql (point) haskell-indent-last-position))
(message "Press TAB again to go to the leftmost indentation")
(setq haskell-indent-last-position (point)))
(t
(haskell-indentation-reindent
(haskell-indentation-next-indentation
-1
(haskell-indentation-find-indentations))))))))
(defun haskell-indentation-delete-backward-char (n)
(interactive "p")
(on-parse-error (backward-delete-char 1)
(cond
((and delete-selection-mode
mark-active
(not (= (point) (mark))))
(delete-region (mark) (point)))
((or (= (current-column) 0)
(> (current-column) (current-indentation))
(nth 8 (syntax-ppss)))
(delete-backward-char n))
(t (let* ((ci (current-indentation))
(pi (haskell-indentation-previous-indentation
ci (haskell-indentation-find-indentations))))
(save-excursion
(cond (pi
(move-to-column pi)
(delete-region (point)
(progn (move-to-column ci)
(point))))
(t
(beginning-of-line)
(delete-region (max (point-min) (- (point) 1))
(progn (move-to-column ci)
(point)))))))))))
(defun haskell-indentation-delete-char (n)
(interactive "p")
(on-parse-error (delete-char 1)
(cond
((and delete-selection-mode
mark-active
(not (= (point) (mark))))
(delete-region (mark) (point)))
((or (eolp)
(>= (current-column) (current-indentation))
(nth 8 (syntax-ppss)))
(delete-char n))
(t
(let* ((ci (current-indentation))
(pi (haskell-indentation-previous-indentation
ci (haskell-indentation-find-indentations))))
(save-excursion
(if (and pi (> pi (current-column)))
(move-to-column pi))
(delete-region (point)
(progn (move-to-column ci)
(point)))))))))
(defun haskell-indentation-goto-least-indentation ()
(beginning-of-line)
(catch 'return
(while (not (bobp))
(forward-comment (- (buffer-size)))
(beginning-of-line)
(let ((ps (nth 8 (syntax-ppss))))
(when ps ;; inside comment or string
(goto-char ps)))
(when (= 0 (current-indentation))
(throw 'return nil))))
(beginning-of-line)
(when (bobp)
(forward-comment (buffer-size))))
;; Dynamically scoped variables.
(defvar following-token)
(defvar current-token)
(defvar left-indent)
(defvar starter-indent)
(defvar current-indent)
(defvar layout-indent)
(defvar parse-line-number)
(defvar possible-indentations)
(defvar indentation-point)
(defun haskell-indentation-parse-to-indentations ()
(save-excursion
(skip-syntax-forward "-")
(let ((indentation-point (point))
(layout-indent 0)
(parse-line-number 0)
(current-indent haskell-indentation-layout-offset)
(starter-indent haskell-indentation-layout-offset)
(left-indent haskell-indentation-layout-offset)
(case-fold-search nil)
current-token
following-token
possible-indentations)
(haskell-indentation-goto-least-indentation)
(if (<= indentation-point (point))
'(0)
(setq current-token (haskell-indentation-peek-token))
(catch 'parse-end
(haskell-indentation-toplevel)
(when (not (equal current-token 'end-tokens))
(parse-error "illegal token: %s" current-token)))
possible-indentations))))
(defun haskell-indentation-find-indentations ()
(let ((ppss (syntax-ppss)))
(cond
((nth 3 ppss) '(0))
((nth 4 ppss)
(if (save-excursion
(and (skip-syntax-forward "-")
(eolp)
(not (> (forward-line 1) 0))
(not (nth 4 (syntax-ppss)))))
(haskell-indentation-parse-to-indentations)
'(0)))
(t
(haskell-indentation-parse-to-indentations)))))
(defconst haskell-indentation-toplevel-list
'(("module" . haskell-indentation-module)
("data" . haskell-indentation-data)
("type" . haskell-indentation-data)
("newtype" . haskell-indentation-data)
("class" . haskell-indentation-class-declaration)
("instance" . haskell-indentation-class-declaration )))
(defconst haskell-indentation-type-list
'(("::" . (lambda () (haskell-indentation-statement-right #'haskell-indentation-type)))
("(" . (lambda () (haskell-indentation-list #'haskell-indentation-type
")" "," nil)))
("[" . (lambda () (haskell-indentation-list #'haskell-indentation-type
"]" "," nil)))
("{" . (lambda () (haskell-indentation-list #'haskell-indentation-type
"}" "," nil)))))
(defconst haskell-indentation-expression-list
'(("data" . haskell-indentation-data)
("type" . haskell-indentation-data)
("newtype" . haskell-indentation-data)
("if" . (lambda () (haskell-indentation-phrase
'(haskell-indentation-expression
"then" haskell-indentation-expression
"else" haskell-indentation-expression))))
("let" . (lambda () (haskell-indentation-phrase
'(haskell-indentation-declaration-layout
"in" haskell-indentation-expression))))
("do" . (lambda () (haskell-indentation-with-starter
#'haskell-indentation-expression-layout nil)))
("case" . (lambda () (haskell-indentation-phrase
'(haskell-indentation-expression
"of" haskell-indentation-case-layout))))
("\\" . (lambda () (haskell-indentation-phrase
'(haskell-indentation-expression
"->" haskell-indentation-expression))))
("where" . (lambda () (haskell-indentation-with-starter
#'haskell-indentation-declaration-layout nil)))
("::" . (lambda () (haskell-indentation-statement-right #'haskell-indentation-type)))
("=" . (lambda () (haskell-indentation-statement-right #'haskell-indentation-expression)))
("<-" . (lambda () (haskell-indentation-statement-right #'haskell-indentation-expression)))
("(" . (lambda () (haskell-indentation-list #'haskell-indentation-expression
")" '(list "," "->") nil)))
("[" . (lambda () (haskell-indentation-list #'haskell-indentation-expression
"]" "," "|")))
("{" . (lambda () (haskell-indentation-list #'haskell-indentation-expression
"}" "," nil)))))
(defun haskell-indentation-expression-layout ()
(haskell-indentation-layout #'haskell-indentation-expression))
(defun haskell-indentation-declaration-layout ()
(haskell-indentation-layout #'haskell-indentation-declaration))
(defun haskell-indentation-case-layout ()
(haskell-indentation-layout #'haskell-indentation-case))
(defun haskell-indentation-fundep ()
(haskell-indentation-with-starter
(lambda () (haskell-indentation-separated
#'haskell-indentation-fundep1 "," nil))
nil))
(defun haskell-indentation-fundep1 ()
(let ((current-indent (current-column)))
(while (member current-token '(value "->"))
(haskell-indentation-read-next-token))
(when (and (equal current-token 'end-tokens)
(member following-token '(value "->")))
(haskell-indentation-add-indentation current-indent))))
(defun haskell-indentation-toplevel ()
(haskell-indentation-layout
(lambda ()
(let ((parser (assoc current-token haskell-indentation-toplevel-list)))
(if parser
(funcall (cdr parser))
(haskell-indentation-declaration))))))
(defun haskell-indentation-type ()
(let ((current-indent (current-column)))
(catch 'return
(while t
(cond
((member current-token '(value operator "->"))
(haskell-indentation-read-next-token))
((equal current-token 'end-tokens)
(when (member following-token
'(value operator no-following-token
"->" "(" "[" "{" "::"))
(haskell-indentation-add-indentation current-indent))
(throw 'return nil))
(t (let ((parser (assoc current-token haskell-indentation-type-list)))
(if (not parser)
(throw 'return nil)
(funcall (cdr parser))))))))))
(defun haskell-indentation-data ()
(haskell-indentation-with-starter
(lambda ()
(when (equal current-token "instance")
(haskell-indentation-read-next-token))
(haskell-indentation-type)
(cond ((equal current-token "=")
(haskell-indentation-with-starter
(lambda () (haskell-indentation-separated #'haskell-indentation-type "|" "deriving"))
nil))
((equal current-token "where")
(haskell-indentation-with-starter
#'haskell-indentation-expression-layout nil))))
nil))
(defun haskell-indentation-class-declaration ()
(haskell-indentation-with-starter
(lambda ()
(haskell-indentation-type)
(when (equal current-token "|")
(haskell-indentation-fundep))
(when (equal current-token "where")
(haskell-indentation-with-starter
#'haskell-indentation-expression-layout nil)))
nil))
(defun haskell-indentation-module ()
(haskell-indentation-with-starter
(lambda ()
(let ((current-indent (current-column)))
(haskell-indentation-read-next-token)
(when (equal current-token "(")
(haskell-indentation-list
#'haskell-indentation-module-export
")" "," nil))
(when (equal current-token 'end-tokens)
(haskell-indentation-add-indentation current-indent)
(throw 'parse-end nil))
(when (equal current-token "where")
(haskell-indentation-read-next-token)
(when (equal current-token 'end-tokens)
(haskell-indentation-add-layout-indent)
(throw 'parse-end nil))
(haskell-indentation-layout #'haskell-indentation-toplevel))))
nil))
(defun haskell-indentation-module-export ()
(cond ((equal current-token "module")
(let ((current-indent (current-column)))
(haskell-indentation-read-next-token)
(cond ((equal current-token 'end-tokens)
(haskell-indentation-add-indentation current-indent))
((equal current-token 'value)
(haskell-indentation-read-next-token)))))
(t (haskell-indentation-type))))
(defun haskell-indentation-list (parser end sep stmt-sep)
(haskell-indentation-with-starter
`(lambda () (haskell-indentation-separated #',parser
,sep
,stmt-sep))
end))
(defun haskell-indentation-with-starter (parser end)
(let ((starter-column (current-column))
(current-indent current-indent)
(left-indent (if (= (current-column) (current-indentation))
(current-column) left-indent)))
(haskell-indentation-read-next-token)
(when (equal current-token 'end-tokens)
(if (equal following-token end)
(haskell-indentation-add-indentation starter-column)
(haskell-indentation-add-indentation
(+ left-indent haskell-indentation-left-offset)))
(throw 'parse-end nil))
(let* ((current-indent (current-column))
(starter-indent (min starter-column current-indent))
(left-indent (if end (+ current-indent haskell-indentation-starter-offset)
left-indent)))
(funcall parser)
(cond ((equal current-token 'end-tokens)
(when (equal following-token end)
(haskell-indentation-add-indentation starter-indent))
(when end (throw 'parse-end nil))) ;; add no indentations
((equal current-token end)
(haskell-indentation-read-next-token)) ;; continue
(end (parse-error "Illegal token: %s" current-token))))))
(defun haskell-indentation-case ()
(haskell-indentation-expression)
(cond ((equal current-token 'end-tokens)
(haskell-indentation-add-indentation current-indent))
((equal current-token "|")
(haskell-indentation-with-starter
(lambda () (haskell-indentation-separated #'haskell-indentation-case "|" nil))
nil))
((equal current-token "->")
(haskell-indentation-statement-right #'haskell-indentation-expression))
;; otherwise fallthrough
))
(defun haskell-indentation-statement-right (parser)
(haskell-indentation-read-next-token)
(when (equal current-token 'end-tokens)
(haskell-indentation-add-indentation
(+ left-indent haskell-indentation-left-offset))
(throw 'parse-end nil))
(let ((current-indent (current-column)))
(funcall parser)))
(defun haskell-indentation-simple-declaration ()
(haskell-indentation-expression)
(cond ((equal current-token "=")
(haskell-indentation-statement-right #'haskell-indentation-expression))
((equal current-token "::")
(haskell-indentation-statement-right #'haskell-indentation-type))
((and (equal current-token 'end-tokens)
(equal following-token "="))
(haskell-indentation-add-indentation current-indent)
(throw 'parse-end nil))))
(defun haskell-indentation-declaration ()
(haskell-indentation-expression)
(cond ((equal current-token "|")
(haskell-indentation-with-starter
(lambda () (haskell-indentation-separated #'haskell-indentation-expression "," "|"))
nil))
((equal current-token 'end-tokens)
(when (member following-token '("|" "=" "::" ","))
(haskell-indentation-add-indentation current-indent)
(throw 'parse-end nil)))))
(defun haskell-indentation-layout (parser)
(if (equal current-token "{")
(haskell-indentation-list parser "}" ";" nil)
(haskell-indentation-implicit-layout-list parser)))
(defun haskell-indentation-expression-token (token)
(member token '("if" "let" "do" "case" "\\" "(" "[" "::"
value operator no-following-token)))
(defun haskell-indentation-expression ()
(let ((current-indent (current-column)))
(catch 'return
(while t
(cond
((member current-token '(value operator))
(haskell-indentation-read-next-token))
((equal current-token 'end-tokens)
(cond ((equal following-token "where")
(haskell-indentation-add-indentation
(+ left-indent haskell-indentation-left-offset)))
((haskell-indentation-expression-token following-token)
(haskell-indentation-add-indentation
current-indent)))
(throw 'return nil))
(t (let ((parser (assoc current-token haskell-indentation-expression-list)))
(when (null parser)
(throw 'return nil))
(funcall (cdr parser))
(when (and (equal current-token 'end-tokens)
(equal (car parser) "let")
(= haskell-indentation-layout-offset current-indent)
(haskell-indentation-expression-token following-token))
;; inside a layout, after a let construct
(haskell-indentation-add-layout-indent)
(throw 'parse-end nil))
(unless (member (car parser) '("(" "[" "{" "do" "case"))
(throw 'return nil)))))))))
(defun haskell-indentation-test-indentations ()
(interactive)
(let ((indentations (save-excursion (haskell-indentation-find-indentations)))
(str "")
(pos 0))
(while indentations
(when (>= (car indentations) pos)
(setq str (concat str (make-string (- (car indentations) pos) ?\ )
"|"))
(setq pos (+ 1 (car indentations))))
(setq indentations (cdr indentations)))
(end-of-line)
(newline)
(insert str)))
(defun haskell-indentation-separated (parser separator stmt-separator)
(catch 'return
(while t
(funcall parser)
(cond ((if (listp separator) (member current-token separator) (equal current-token separator))
(haskell-indentation-at-separator))
((equal current-token stmt-separator)
(setq starter-indent (current-column))
(haskell-indentation-at-separator))
((equal current-token 'end-tokens)
(cond ((or (equal following-token separator)
(equal following-token stmt-separator))
(haskell-indentation-add-indentation starter-indent)
(throw 'parse-end nil)))
(throw 'return nil))
(t (throw 'return nil))))))
(defun haskell-indentation-at-separator ()
(let ((separator-column
(and (= (current-column) (current-indentation))
(current-column))))
(haskell-indentation-read-next-token)
(cond ((eq current-token 'end-tokens)
(haskell-indentation-add-indentation current-indent)
(throw 'return nil))
(separator-column ;; on the beginning of the line
(setq current-indent (current-column))
(setq starter-indent separator-column)))))
(defun haskell-indentation-implicit-layout-list (parser)
(let* ((layout-indent (current-column))
(current-indent (current-column))
(left-indent (current-column)))
(catch 'return
(while t
(let ((left-indent left-indent))
(funcall parser))
(cond ((member current-token '(layout-next ";"))
(haskell-indentation-read-next-token))
((equal current-token 'end-tokens)
(when (or (haskell-indentation-expression-token following-token)
(equal following-token ";"))
(haskell-indentation-add-layout-indent))
(throw 'return nil))
(t (throw 'return nil))))))
;; put haskell-indentation-read-next-token outside the current-indent definition
;; so it will not return 'layout-end again
(when (eq current-token 'layout-end)
(haskell-indentation-read-next-token))) ;; leave layout at 'layout-end or illegal token
(defun haskell-indentation-phrase (phrase)
(haskell-indentation-with-starter
`(lambda () (haskell-indentation-phrase-rest ',phrase))
nil))
(defun haskell-indentation-phrase-rest (phrase)
(let ((starter-line parse-line-number))
(let ((current-indent (current-column)))
(funcall (car phrase)))
(cond
((equal current-token 'end-tokens)
(cond ((null (cdr phrase))) ;; fallthrough
((equal following-token (cadr phrase))
(haskell-indentation-add-indentation starter-indent)
(throw 'parse-end nil))
((equal (cadr phrase) "in")
(when (= left-indent layout-indent)
(haskell-indentation-add-layout-indent)
(throw 'parse-end nil)))
(t (throw 'parse-end nil))))
((null (cdr phrase)))
((equal (cadr phrase) current-token)
(let* ((on-new-line (= (current-column) (current-indentation)))
(lines-between (- parse-line-number starter-line))
(left-indent (if (<= lines-between 0)
left-indent
starter-indent)))
(haskell-indentation-read-next-token)
(when (equal current-token 'end-tokens)
(haskell-indentation-add-indentation
(cond ((member (cadr phrase) '("then" "else"))
(+ starter-indent haskell-indentation-ifte-offset))
((member (cadr phrase) '("in" "->"))
;; expression ending in another expression
(if on-new-line
(+ left-indent haskell-indentation-starter-offset)
left-indent))
(t (+ left-indent haskell-indentation-left-offset))))
(throw 'parse-end nil))
(haskell-indentation-phrase-rest (cddr phrase))))
((equal (cadr phrase) "in")) ;; fallthrough
(t (parse-error "Expecting %s" (cadr phrase))))))
(defun haskell-indentation-add-indentation (indent)
(haskell-indentation-push-indentation
(if (<= indent layout-indent)
(+ layout-indent haskell-indentation-layout-offset)
indent)))
(defun haskell-indentation-add-layout-indent ()
(haskell-indentation-push-indentation layout-indent))
(defun haskell-indentation-push-indentation (indent)
(when (or (null possible-indentations)
(< indent (car possible-indentations)))
(setq possible-indentations
(cons indent possible-indentations))))
(defun haskell-indentation-token-test ()
(let ((current-token nil)
(following-token nil)
(layout-indent 0)
(indentation-point (mark)))
(haskell-indentation-read-next-token)))
(defun haskell-indentation-read-next-token ()
(cond ((eq current-token 'end-tokens)
'end-tokens)
((eq current-token 'layout-end)
(cond ((> layout-indent (current-column))
'layout-end)
((= layout-indent (current-column))
(setq current-token 'layout-next))
((< layout-indent (current-column))
(setq current-token (haskell-indentation-peek-token)))))
((eq current-token 'layout-next)
(setq current-token (haskell-indentation-peek-token)))
((> layout-indent (current-column))
(setq current-token 'layout-end))
(t
(haskell-indentation-skip-token)
(if (>= (point) indentation-point)
(progn
(setq following-token
(if (= (point) indentation-point)
(haskell-indentation-peek-token)
'no-following-token))
(setq current-token 'end-tokens))
(when (= (current-column) (current-indentation))
;; on a new line
(setq current-indent (current-column))
(setq left-indent (current-column))
(setq parse-line-number (+ parse-line-number 1)))
(cond ((> layout-indent (current-column))
(setq current-token 'layout-end))
((= layout-indent (current-column))
(setq current-token 'layout-next))
(t (setq current-token (haskell-indentation-peek-token))))))))
(defun haskell-indentation-peek-token ()
(cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|do\\|case\\|of\\|where\\|module\\|deriving\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^A-Za-z']\\|$\\)")
(match-string 1))
((looking-at "[][(){}[,;]")
(match-string 0))
((looking-at "\\(\\\\\\|->\\|<-\\|::\\|=\\||\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)")
(match-string 1))
((looking-at"[-:!#$%&*+./<=>?@\\\\^|~`]" )
'operator)
(t 'value)))
(defun haskell-indentation-skip-token ()
"Skip to the next token."
(if (or (looking-at "'\\([^\\']\\|\\\\.\\)*'")
(looking-at "\"\\([^\\\"]\\|\\\\.\\)*\"")
(looking-at "[A-Z][A-Z_a-z0-9']*\\(\\.[A-Z_a-z][A-Z_a-z0-9']*\\)*") ; Allows hierarchical modules
(looking-at "[A-Z_a-z][A-Z_a-z0-9']*") ; Only unqualified vars can start with lowercase
(looking-at "[0-9][0-9oOxXeE+-]*")
(looking-at "[-:!#$%&*+./<=>?@\\\\^|~]+")
(looking-at "[](){}[,;]")
(looking-at "`[A-Za-z0-9']*`"))
(goto-char (match-end 0))
;; otherwise skip until space found
(skip-syntax-forward "^-"))
(forward-comment (buffer-size)))
(provide 'haskell-indentation)
;;; haskell-indentation.el ends here

View file

@ -0,0 +1,532 @@
;;; haskell-mode.el --- A Haskell editing mode -*-coding: iso-8859-1;-*-
;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc
;; Copyright (C) 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn
;; Authors: 1992 Simon Marlow
;; 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and
;; Tommy Thorn <thorn@irisa.fr>,
;; 2001-2002 Reuben Thomas (>=v1.4)
;; 2003 Dave Love <fx@gnu.org>
;; Keywords: faces files Haskell
;; Version: v2.6.4
;; URL: http://www.haskell.org/haskell-mode/
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; To provide a pleasant mode to browse and edit Haskell files, linking
;; into the following supported modules:
;;
;; `haskell-font-lock', Graeme E Moss and Tommy Thorn
;; Fontifies standard Haskell keywords, symbols, functions, etc.
;;
;; `haskell-decl-scan', Graeme E Moss
;; Scans top-level declarations, and places them in a menu.
;;
;; `haskell-doc', Hans-Wolfgang Loidl
;; Echoes types of functions or syntax of keywords when the cursor is idle.
;;
;; `haskell-indentation', Kristof Bastiaensen
;; Intelligent semi-automatic indentation, mark two.
;;
;; `haskell-indent', Guy Lapalme
;; Intelligent semi-automatic indentation.
;;
;; `haskell-simple-indent', Graeme E Moss and Heribert Schuetz
;; Simple indentation.
;;
;; `inf-haskell'
;; Interaction with an inferior Haskell process.
;; It replaces the previous two modules:
;; `haskell-hugs', Guy Lapalme
;; `haskell-ghci', Chris Web
;;
;;
;; This mode supports full Haskell 1.4 including literate scripts.
;; In some versions of (X)Emacs it may only support Latin-1, not Unicode.
;;
;; History:
;;
;; This mode is based on an editing mode by Simon Marlow 11/1/92
;; and heavily modified by Graeme E Moss and Tommy Thorn 7/11/98.
;;
;; If you have any problems or suggestions specific to a supported
;; module, consult that module for a list of known bugs, and an
;; author to contact via email. For general problems or suggestions,
;; consult the list below, then email gem@cs.york.ac.uk and
;; thorn@irisa.fr quoting the version of the mode you are using, the
;; version of Emacs you are using, and a small example of the problem
;; or suggestion.
;;
;; Version 1.5
;; Added autoload for haskell-indentation
;;
;; Version 1.43:
;; Various tweaks to doc strings and customization support from
;; Ville Skyttä <scop@xemacs.org>.
;;
;; Version 1.42:
;; Added autoload for GHCi inferior mode (thanks to Scott
;; Williams for the bug report and fix).
;;
;; Version 1.41:
;; Improved packaging, and made a couple more variables
;; interactively settable.
;;
;; Version 1.4:
;; Added GHCi mode from Chris Webb, and tidied up a little.
;;
;; Version 1.3:
;; The literate or non-literate style of a buffer is now indicated
;; by just the variable haskell-literate: nil, `bird', or `tex'.
;; For literate buffers with ambiguous style, the value of
;; haskell-literate-default is used.
;;
;; Version 1.2:
;; Separated off font locking, declaration scanning and simple
;; indentation, and made them separate modules. Modules can be
;; added easily now. Support for modules haskell-doc,
;; haskell-indent, and haskell-hugs. Literate and non-literate
;; modes integrated into one mode, and literate buffer indicated by
;; value of haskell-literate(-bird-style).
;;
;; Version 1.1:
;; Added support for declaration scanning under XEmacs via
;; func-menu. Moved operators to level two fontification.
;;
;; Version 1.0:
;; Added a nice indention support from Heribert Schuetz
;; <Heribert.Schuetz@informatik.uni-muenchen.de>:
;;
;; I have just hacked an Emacs Lisp function which you might prefer
;; to `indent-relative' in haskell-mode.el. See below. It is not
;; really Haskell-specific because it does not take into account
;; keywords like `do', `of', and `let' (where the layout rule
;; applies), but I already find it useful.
;;
;; Cleaned up the imenu support. Added support for literate scripts.
;;
;; Version 0.103 [HWL]:
;; From Hans Wolfgang Loidl <hwloidl@dcs.gla.ac.uk>:
;;
;; I (HWL) added imenu support by copying the appropriate functions
;; from hugs-mode. A menu-bar item "Declarations" is now added in
;; haskell mode. The new code, however, needs some clean-up.
;;
;; Version 0.102:
;;
;; Moved C-c C-c key binding to comment-region. Leave M-g M-g to do
;; the work. comment-start-skip is changed to comply with comment-start.
;;
;; Version 0.101:
;;
;; Altered indent-line-function to indent-relative.
;;
;; Version 0.100:
;;
;; First official release.
;; Present Limitations/Future Work (contributions are most welcome!):
;;
;; . Would like RET in Bird-style literate mode to add a ">" at the
;; start of a line when previous line starts with ">". Or would
;; "> " be better?
;;
;; . Support for GreenCard?
;;
;;; Code:
(eval-when-compile (require 'cl))
;; All functions/variables start with `(literate-)haskell-'.
;; Version of mode.
(defconst haskell-version "v2.6.4"
"`haskell-mode' version number.")
(defun haskell-version ()
"Echo the current version of `haskell-mode' in the minibuffer."
(interactive)
(message "Using haskell-mode version %s" haskell-version))
(defgroup haskell nil
"Major mode for editing Haskell programs."
:group 'languages
:prefix "haskell-")
;; Set load-path
;;;###autoload
(add-to-list 'load-path
(or (file-name-directory load-file-name) (car load-path)))
;; Set up autoloads for the modules we supply
(autoload 'turn-on-haskell-decl-scan "haskell-decl-scan"
"Turn on Haskell declaration scanning." t)
(autoload 'turn-on-haskell-doc-mode "haskell-doc"
"Turn on Haskell Doc minor mode." t)
(autoload 'turn-on-haskell-indentation "haskell-indentation"
"Turn on advanced Haskell indentation." t)
(autoload 'turn-on-haskell-indent "haskell-indent"
"Turn on Haskell indentation." t)
(autoload 'turn-on-haskell-simple-indent "haskell-simple-indent"
"Turn on simple Haskell indentation." t)
;; Functionality provided in other files.
(autoload 'haskell-ds-create-imenu-index "haskell-decl-scan")
(autoload 'haskell-font-lock-choose-keywords "haskell-font-lock")
(autoload 'haskell-doc-current-info "haskell-doc")
;; Obsolete functions.
(defun turn-on-haskell-font-lock ()
(turn-on-font-lock)
(message "turn-on-haskell-font-lock is obsolete. Use turn-on-font-lock instead."))
(defun turn-on-haskell-hugs () (message "haskell-hugs is obsolete."))
(defun turn-on-haskell-ghci () (message "haskell-ghci is obsolete."))
;; Are we looking at a literate script?
(defvar haskell-literate nil
"*If not nil, the current buffer contains a literate Haskell script.
Possible values are: `bird' and `tex', for Bird-style and LaTeX-style
literate scripts respectively. Set by `haskell-mode' and
`literate-haskell-mode'. For an ambiguous literate buffer -- ie. does
not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on
its own, nor does it contain \">\" at the start of a line -- the value
of `haskell-literate-default' is used.")
(make-variable-buffer-local 'haskell-literate)
(put 'haskell-literate 'safe-local-variable 'symbolp)
;; Default literate style for ambiguous literate buffers.
(defcustom haskell-literate-default 'bird
"Default value for `haskell-literate'.
Used if the style of a literate buffer is ambiguous. This variable should
be set to the preferred literate style."
:type '(choice (const bird) (const tex) (const nil)))
;; Mode maps.
(defvar haskell-mode-map
(let ((map (make-sparse-keymap)))
;; Bindings for the inferior haskell process:
;; (define-key map [?\M-C-x] 'inferior-haskell-send-defun)
;; (define-key map [?\C-x ?\C-e] 'inferior-haskell-send-last-sexp)
;; (define-key map [?\C-c ?\C-r] 'inferior-haskell-send-region)
(define-key map [?\C-c ?\C-z] 'switch-to-haskell)
(define-key map [?\C-c ?\C-l] 'inferior-haskell-load-file)
;; I think it makes sense to bind inferior-haskell-load-and-run to C-c
;; C-r, but since it used to be bound to `reload' until june 2007, I'm
;; going to leave it out for now.
;; (define-key map [?\C-c ?\C-r] 'inferior-haskell-load-and-run)
(define-key map [?\C-c ?\C-b] 'switch-to-haskell)
;; (define-key map [?\C-c ?\C-s] 'inferior-haskell-start-process)
;; That's what M-; is for.
;; (define-key map "\C-c\C-c" 'comment-region)
(define-key map (kbd "C-c C-t") 'inferior-haskell-type)
(define-key map (kbd "C-c C-i") 'inferior-haskell-info)
(define-key map (kbd "C-c M-.") 'inferior-haskell-find-definition)
(define-key map (kbd "C-c C-d") 'inferior-haskell-find-haddock)
(define-key map [remap delete-indentation] 'haskell-delete-indentation)
map)
"Keymap used in Haskell mode.")
(easy-menu-define haskell-mode-menu haskell-mode-map
"Menu for the Haskell major mode."
;; Suggestions from Pupeno <pupeno@pupeno.com>:
;; - choose the underlying interpreter
;; - look up docs
`("Haskell"
["Indent line" indent-according-to-mode]
["Indent region" indent-region mark-active]
["(Un)Comment region" comment-region mark-active]
"---"
["Start interpreter" switch-to-haskell]
["Load file" inferior-haskell-load-file]
"---"
,(if (default-boundp 'eldoc-documentation-function)
["Doc mode" eldoc-mode
:style toggle :selected (bound-and-true-p eldoc-mode)]
["Doc mode" haskell-doc-mode
:style toggle :selected (and (boundp 'haskell-doc-mode) haskell-doc-mode)])
["Customize" (customize-group 'haskell)]
))
;; Syntax table.
(defvar haskell-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?\ " " table)
(modify-syntax-entry ?\t " " table)
(modify-syntax-entry ?\" "\"" table)
(modify-syntax-entry ?\' "\'" table)
(modify-syntax-entry ?_ "w" table)
(modify-syntax-entry ?\( "()" table)
(modify-syntax-entry ?\) ")(" table)
(modify-syntax-entry ?\[ "(]" table)
(modify-syntax-entry ?\] ")[" table)
(cond ((featurep 'xemacs)
;; I don't know whether this is equivalent to the below
;; (modulo nesting). -- fx
(modify-syntax-entry ?{ "(}5" table)
(modify-syntax-entry ?} "){8" table)
(modify-syntax-entry ?- "_ 1267" table))
(t
;; In Emacs 21, the `n' indicates that they nest.
;; The `b' annotation is actually ignored because it's only
;; meaningful on the second char of a comment-starter, so
;; on Emacs 20 and before we get wrong results. --Stef
(modify-syntax-entry ?\{ "(}1nb" table)
(modify-syntax-entry ?\} "){4nb" table)
(modify-syntax-entry ?- "_ 123" table)))
(modify-syntax-entry ?\n ">" table)
(let (i lim)
(map-char-table
(lambda (k v)
(when (equal v '(1))
;; The current Emacs 22 codebase can pass either a char
;; or a char range.
(if (consp k)
(setq i (car k)
lim (cdr k))
(setq i k
lim k))
(while (<= i lim)
(when (> i 127)
(modify-syntax-entry i "_" table))
(setq i (1+ i)))))
(standard-syntax-table)))
(modify-syntax-entry ?\` "$`" table)
(modify-syntax-entry ?\\ "\\" table)
(mapc (lambda (x)
(modify-syntax-entry x "_" table))
;; Some of these are actually OK by default.
"!#$%&*+./:<=>?@^|~")
(unless (featurep 'mule)
;; Non-ASCII syntax should be OK, at least in Emacs.
(mapc (lambda (x)
(modify-syntax-entry x "_" table))
(concat "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿"
"×÷"))
(mapc (lambda (x)
(modify-syntax-entry x "w" table))
(concat "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ"
"ØÙÚÛÜÝÞß"
"àáâãäåæçèéêëìíîïðñòóôõö"
"øùúûüýþÿ")))
table)
"Syntax table used in Haskell mode.")
(defun haskell-ident-at-point ()
"Return the identifier under point, or nil if none found.
May return a qualified name."
(save-excursion
(let ((case-fold-search nil))
(multiple-value-bind (start end)
(if (looking-at "\\s_")
(values (progn (skip-syntax-backward "_") (point))
(progn (skip-syntax-forward "_") (point)))
(values
(progn (skip-syntax-backward "w'")
(skip-syntax-forward "'") (point))
(progn (skip-syntax-forward "w'") (point))))
;; If we're looking at a module ID that qualifies further IDs, add
;; those IDs.
(goto-char start)
(while (and (looking-at "[[:upper:]]") (eq (char-after end) ?.)
;; It's a module ID that qualifies further IDs.
(goto-char (1+ end))
(save-excursion
(when (not (zerop (skip-syntax-forward
(if (looking-at "\\s_") "_" "w'"))))
(setq end (point))))))
;; If we're looking at an ID that's itself qualified by previous
;; module IDs, add those too.
(goto-char start)
(if (eq (char-after) ?.) (forward-char 1)) ;Special case for "."
(while (and (eq (char-before) ?.)
(progn (forward-char -1)
(not (zerop (skip-syntax-backward "w'"))))
(skip-syntax-forward "'")
(looking-at "[[:upper:]]"))
(setq start (point)))
;; This is it.
(buffer-substring-no-properties start end)))))
(defun haskell-delete-indentation (&optional arg)
"Like `delete-indentation' but ignoring Bird-stlye \">\"."
(interactive "*P")
(let ((fill-prefix (or fill-prefix (if (eq haskell-literate 'bird) ">"))))
(delete-indentation arg)))
;; Various mode variables.
(defcustom haskell-mode-hook nil
"Hook run after entering Haskell mode. Do not select more than one of the three indentation modes."
:type 'hook
:options '(turn-on-haskell-indent turn-on-haskell-indentation turn-on-font-lock turn-on-eldoc-mode
turn-on-simple-indent turn-on-haskell-doc-mode imenu-add-menubar-index))
(defvar eldoc-print-current-symbol-info-function)
;; The main mode functions
;;;###autoload
(define-derived-mode haskell-mode fundamental-mode "Haskell"
"Major mode for editing Haskell programs.
Blank lines separate paragraphs, comments start with `-- '.
\\<haskell-mode-map>
Literate scripts are supported via `literate-haskell-mode'.
The variable `haskell-literate' indicates the style of the script in the
current buffer. See the documentation on this variable for more details.
Modules can hook in via `haskell-mode-hook'. The following modules
are supported with an `autoload' command:
`haskell-decl-scan', Graeme E Moss
Scans top-level declarations, and places them in a menu.
`haskell-doc', Hans-Wolfgang Loidl
Echoes types of functions or syntax of keywords when the cursor is idle.
`haskell-indentation', Kristof Bastiaensen
Intelligent semi-automatic indentation Mk2
`haskell-indent', Guy Lapalme
Intelligent semi-automatic indentation.
`haskell-simple-indent', Graeme E Moss and Heribert Schuetz
Simple indentation.
Module X is activated using the command `turn-on-X'. For example,
`haskell-indent' is activated using `turn-on-haskell-indent'.
For more information on a module, see the help for its `X-mode'
function. Some modules can be deactivated using `turn-off-X'. (Note
that `haskell-doc' is irregular in using `turn-(on/off)-haskell-doc-mode'.)
Use `haskell-version' to find out what version this is.
Invokes `haskell-mode-hook'."
(set (make-local-variable 'paragraph-start) (concat "^$\\|" page-delimiter))
(set (make-local-variable 'paragraph-separate) paragraph-start)
(set (make-local-variable 'comment-start) "-- ")
(set (make-local-variable 'comment-padding) 0)
(set (make-local-variable 'comment-start-skip) "[-{]-[ \t]*")
(set (make-local-variable 'comment-end) "")
(set (make-local-variable 'comment-end-skip) "[ \t]*\\(-}\\|\\s>\\)")
(set (make-local-variable 'parse-sexp-ignore-comments) t)
;; Set things up for eldoc-mode.
(set (make-local-variable 'eldoc-documentation-function)
'haskell-doc-current-info)
;; Set things up for imenu.
(set (make-local-variable 'imenu-create-index-function)
'haskell-ds-create-imenu-index)
;; Set things up for font-lock.
(set (make-local-variable 'font-lock-defaults)
'(haskell-font-lock-choose-keywords
nil nil ((?\' . "w") (?_ . "w")) nil
(font-lock-syntactic-keywords
. haskell-font-lock-choose-syntactic-keywords)
(font-lock-syntactic-face-function
. haskell-syntactic-face-function)
;; Get help from font-lock-syntactic-keywords.
(parse-sexp-lookup-properties . t)))
;; Haskell's layout rules mean that TABs have to be handled with extra care.
;; The safer option is to avoid TABs. The second best is to make sure
;; TABs stops are 8 chars apart, as mandated by the Haskell Report. --Stef
(set (make-local-variable 'indent-tabs-mode) nil)
(set (make-local-variable 'tab-width) 8)
(setq haskell-literate nil))
;;;###autoload
(define-derived-mode literate-haskell-mode haskell-mode "LitHaskell"
"As `haskell-mode' but for literate scripts."
(setq haskell-literate
(save-excursion
(goto-char (point-min))
(cond
((re-search-forward "^\\\\\\(begin\\|end\\){code}$" nil t) 'tex)
((re-search-forward "^>" nil t) 'bird)
(t haskell-literate-default))))
(if (eq haskell-literate 'bird)
;; fill-comment-paragraph isn't much use there, and even gets confused
;; by the syntax-table text-properties we add to mark the first char
;; of each line as a comment-starter.
(set (make-local-variable 'fill-paragraph-handle-comment) nil))
(set (make-local-variable 'mode-line-process)
'("/" (:eval (symbol-name haskell-literate)))))
;;;###autoload(add-to-list 'auto-mode-alist '("\\.\\(?:[gh]s\\|hi\\)\\'" . haskell-mode))
;;;###autoload(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode))
(defcustom haskell-hoogle-command
(if (executable-find "hoogle") "hoogle")
"Name of the command to use to query Hoogle.
If nil, use the Hoogle web-site."
:type '(choice (const :tag "Use Web-site" nil)
string))
;;;###autoload
(defun haskell-hoogle (query)
"Do a Hoogle search for QUERY."
(interactive
(let ((def (haskell-ident-at-point)))
(if (and def (symbolp def)) (setq def (symbol-name def)))
(list (read-string (if def
(format "Hoogle query (default %s): " def)
"Hoogle query: ")
nil nil def))))
(if (null haskell-hoogle-command)
(browse-url (format "http://haskell.org/hoogle/?q=%s" query))
(if (fboundp 'help-setup-xref)
(help-setup-xref (list 'haskell-hoogle query) (interactive-p)))
(with-output-to-temp-buffer
(if (fboundp 'help-buffer) (help-buffer) "*Help*")
(with-current-buffer standard-output
(start-process "hoogle" (current-buffer) haskell-hoogle-command
query)))))
;;;###autoload
(defalias 'hoogle 'haskell-hoogle)
;;;###autoload
(defun haskell-hayoo (query)
"Do a Hayoo search for QUERY."
(interactive
(let ((def (haskell-ident-at-point)))
(if (and def (symbolp def)) (setq def (symbol-name def)))
(list (read-string (if def
(format "Hayoo query (default %s): " def)
"Hayoo query: ")
nil nil def))))
(browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s" query)))
;;;###autoload
(defalias 'hayoo 'haskell-hayoo)
;; Provide ourselves:
(provide 'haskell-mode)
;; arch-tag: b2237ec0-ddb0-4c86-9339-52d410264980
;;; haskell-mode.el ends here

View file

@ -0,0 +1,154 @@
;;; haskell-simple-indent.el --- Simple indentation module for Haskell Mode
;; Copyright (C) 1998 Heribert Schuetz, Graeme E Moss
;; Authors:
;; 1998 Heribert Schuetz <Heribert.Schuetz@informatik.uni-muenchen.de> and
;; Graeme E Moss <gem@cs.york.ac.uk>
;; Keywords: indentation files Haskell
;; Version: 1.0
;; URL: http://www.cs.york.ac.uk/~gem/haskell-mode/simple-indent.html
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Purpose:
;;
;; To support simple indentation of Haskell scripts.
;;
;;
;; Installation:
;;
;; To bind TAB to the indentation command for all Haskell buffers, add
;; this to .emacs:
;;
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
;;
;; Otherwise, call `turn-on-haskell-simple-indent'.
;;
;;
;; Customisation:
;;
;; None supported.
;;
;;
;; History:
;;
;; If you have any problems or suggestions, after consulting the list
;; below, email gem@cs.york.ac.uk quoting the version of you are
;; using, the version of Emacs you are using, and a small example of
;; the problem or suggestion.
;;
;; Version 1.0:
;; Brought over from Haskell mode v1.1.
;;
;; Present Limitations/Future Work (contributions are most welcome!):
;;
;; (None so far.)
;;; Code:
;; All functions/variables start with
;; `(turn-(on/off)-)haskell-simple-indent'.
;; Version.
(defconst haskell-simple-indent-version "1.2"
"`haskell-simple-indent' version number.")
(defun haskell-simple-indent-version ()
"Echo the current version of `haskell-simple-indent' in the minibuffer."
(interactive)
(message "Using haskell-simple-indent version %s"
haskell-simple-indent-version))
;; Partly stolen from `indent-relative' in indent.el:
(defun haskell-simple-indent ()
"Space out to under next visible indent point.
Indent points are positions of non-whitespace following whitespace in
lines preceeding point. A position is visible if it is to the left of
the first non-whitespace of every nonblank line between the position and
the current line. If there is no visible indent point beyond the current
column, `tab-to-tab-stop' is done instead."
(interactive)
(let* ((start-column (current-column))
(invisible-from nil) ; `nil' means infinity here
(indent
(catch 'haskell-simple-indent-break
(save-excursion
(while (progn (beginning-of-line)
(not (bobp)))
(forward-line -1)
(if (not (looking-at "[ \t]*\n"))
(let ((this-indentation (current-indentation)))
(if (or (not invisible-from)
(< this-indentation invisible-from))
(if (> this-indentation start-column)
(setq invisible-from this-indentation)
(let ((end (line-beginning-position 2)))
(move-to-column start-column)
;; Is start-column inside a tab on this line?
(if (> (current-column) start-column)
(backward-char 1))
(or (looking-at "[ \t]")
(skip-chars-forward "^ \t" end))
(skip-chars-forward " \t" end)
(let ((col (current-column)))
(throw 'haskell-simple-indent-break
(if (or (= (point) end)
(and invisible-from
(> col invisible-from)))
invisible-from
col)))))))))))))
(if indent
(let ((opoint (point-marker)))
(indent-line-to indent)
(if (> opoint (point))
(goto-char opoint))
(set-marker opoint nil))
(tab-to-tab-stop))))
(defvar haskell-simple-indent-old)
;; The main functions.
(defun turn-on-haskell-simple-indent ()
"Set `indent-line-function' to a simple indentation function.
TAB will now move the cursor to the next indent point in the previous
nonblank line. An indent point is a non-whitespace character following
whitespace.
Runs `haskell-simple-indent-hook'.
Use `haskell-simple-indent-version' to find out what version this is."
(set (make-local-variable 'haskell-simple-indent-old) indent-line-function)
(set (make-local-variable 'indent-line-function) 'haskell-simple-indent)
(run-hooks 'haskell-simple-indent-hook))
(defun turn-off-haskell-simple-indent ()
"Return `indent-line-function' to original value.
I.e. the value before `turn-on-haskell-simple-indent' was called."
(when (local-variable-p 'haskell-simple-indent-old)
(setq indent-line-function haskell-simple-indent-old)
(kill-local-variable 'haskell-simple-indent-old)))
;; Provide ourselves:
(provide 'haskell-simple-indent)
;; arch-tag: 18a08122-723b-485e-b958-e1cf8218b816
;;; haskell-simple-indent.el ends here

View file

@ -0,0 +1,274 @@
;;;### (autoloads (haskell-c-mode) "haskell-c" "haskell-c.el" (19189
;;;;;; 21847))
;;; Generated autoloads from haskell-c.el
(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-c-mode))
(autoload 'haskell-c-mode "haskell-c" "\
Major mode for Haskell FFI files.
\(fn)" t nil)
;;;***
;;;### (autoloads (haskell-cabal-mode) "haskell-cabal" "haskell-cabal.el"
;;;;;; (19189 21847))
;;; Generated autoloads from haskell-cabal.el
(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
(autoload 'haskell-cabal-mode "haskell-cabal" "\
Major mode for Cabal package description files.
\(fn)" t nil)
;;;***
;;;### (autoloads (haskell-decl-scan-mode) "haskell-decl-scan" "haskell-decl-scan.el"
;;;;;; (19189 21847))
;;; Generated autoloads from haskell-decl-scan.el
(autoload 'haskell-decl-scan-mode "haskell-decl-scan" "\
Minor mode for declaration scanning for Haskell mode.
Top-level declarations are scanned and listed in the menu item \"Declarations\".
Selecting an item from this menu will take point to the start of the
declaration.
\\[haskell-ds-forward-decl] and \\[haskell-ds-backward-decl] move forward and backward to the start of a declaration.
Under XEmacs, the following keys are also defined:
\\[fume-list-functions] lists the declarations of the current buffer,
\\[fume-prompt-function-goto] prompts for a declaration to move to, and
\\[fume-mouse-function-goto] moves to the declaration whose name is at point.
This may link with `haskell-doc' (only for Emacs currently).
For non-literate and LaTeX-style literate scripts, we assume the
common convention that top-level declarations start at the first
column. For Bird-style literate scripts, we assume the common
convention that top-level declarations start at the third column,
ie. after \"> \".
Anything in `font-lock-comment-face' is not considered for a
declaration. Therefore, using Haskell font locking with comments
coloured in `font-lock-comment-face' improves declaration scanning.
To turn on declaration scanning for all Haskell buffers, add this to
.emacs:
(add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
To turn declaration scanning on for the current buffer, call
`turn-on-haskell-decl-scan'.
Literate Haskell scripts are supported: If the value of
`haskell-literate' (automatically set by the Haskell mode of
Moss&Thorn) is `bird', a Bird-style literate script is assumed. If it
is nil or `tex', a non-literate or LaTeX-style literate script is
assumed, respectively.
Invokes `haskell-decl-scan-mode-hook'.
\(fn &optional ARG)" t nil)
;;;***
;;;### (autoloads (haskell-doc-show-type haskell-doc-mode) "haskell-doc"
;;;;;; "haskell-doc.el" (19189 21847))
;;; Generated autoloads from haskell-doc.el
(autoload 'haskell-doc-mode "haskell-doc" "\
Enter `haskell-doc-mode' for showing fct types in the echo area.
See variable docstring.
\(fn &optional ARG)" t nil)
(defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode)
(autoload 'haskell-doc-show-type "haskell-doc" "\
Show the type of the function near point.
For the function under point, show the type in the echo area.
This information is extracted from the `haskell-doc-prelude-types' alist
of prelude functions and their types, or from the local functions in the
current buffer.
\(fn &optional SYM)" t nil)
;;;***
;;;### (autoloads (haskell-indent-mode) "haskell-indent" "haskell-indent.el"
;;;;;; (19189 21847))
;;; Generated autoloads from haskell-indent.el
(autoload 'haskell-indent-mode "haskell-indent" "\
``intelligent'' Haskell indentation mode that deals with
the layout rule of Haskell. \\[haskell-indent-cycle] starts the cycle
which proposes new possibilities as long as the TAB key is pressed.
Any other key or mouse click terminates the cycle and is interpreted
except for RET which merely exits the cycle.
Other special keys are:
\\[haskell-indent-insert-equal]
inserts an =
\\[haskell-indent-insert-guard]
inserts an |
\\[haskell-indent-insert-otherwise]
inserts an | otherwise =
these functions also align the guards and rhs of the current definition
\\[haskell-indent-insert-where]
inserts a where keyword
\\[haskell-indent-align-guards-and-rhs]
aligns the guards and rhs of the region
\\[haskell-indent-put-region-in-literate]
makes the region a piece of literate code in a literate script
Invokes `haskell-indent-hook' if not nil.
\(fn &optional ARG)" t nil)
;;;***
;;;### (autoloads (haskell-indentation-mode) "haskell-indentation"
;;;;;; "haskell-indentation.el" (19189 21847))
;;; Generated autoloads from haskell-indentation.el
(autoload 'haskell-indentation-mode "haskell-indentation" "\
Haskell indentation mode that deals with the layout rule.
It rebinds RET, DEL and BACKSPACE, so that indentations can be
set and deleted as if they were real tabs. It supports
autofill-mode.
\(fn &optional ARG)" t nil)
;;;***
;;;### (autoloads (haskell-hayoo haskell-hoogle literate-haskell-mode
;;;;;; haskell-mode) "haskell-mode" "haskell-mode.el" (19189 21847))
;;; Generated autoloads from haskell-mode.el
(add-to-list 'load-path (or (file-name-directory load-file-name) (car load-path)))
(autoload 'haskell-mode "haskell-mode" "\
Major mode for editing Haskell programs.
Blank lines separate paragraphs, comments start with `-- '.
\\<haskell-mode-map>
Literate scripts are supported via `literate-haskell-mode'.
The variable `haskell-literate' indicates the style of the script in the
current buffer. See the documentation on this variable for more details.
Modules can hook in via `haskell-mode-hook'. The following modules
are supported with an `autoload' command:
`haskell-decl-scan', Graeme E Moss
Scans top-level declarations, and places them in a menu.
`haskell-doc', Hans-Wolfgang Loidl
Echoes types of functions or syntax of keywords when the cursor is idle.
`haskell-indentation', Kristof Bastiaensen
Intelligent semi-automatic indentation Mk2
`haskell-indent', Guy Lapalme
Intelligent semi-automatic indentation.
`haskell-simple-indent', Graeme E Moss and Heribert Schuetz
Simple indentation.
Module X is activated using the command `turn-on-X'. For example,
`haskell-indent' is activated using `turn-on-haskell-indent'.
For more information on a module, see the help for its `X-mode'
function. Some modules can be deactivated using `turn-off-X'. (Note
that `haskell-doc' is irregular in using `turn-(on/off)-haskell-doc-mode'.)
Use `haskell-version' to find out what version this is.
Invokes `haskell-mode-hook'.
\(fn)" t nil)
(autoload 'literate-haskell-mode "haskell-mode" "\
As `haskell-mode' but for literate scripts.
\(fn)" t nil)
(add-to-list 'auto-mode-alist '("\\.\\(?:[gh]s\\|hi\\)\\'" . haskell-mode))
(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode))
(autoload 'haskell-hoogle "haskell-mode" "\
Do a Hoogle search for QUERY.
\(fn QUERY)" t nil)
(defalias 'hoogle 'haskell-hoogle)
(autoload 'haskell-hayoo "haskell-mode" "\
Do a Hayoo search for QUERY.
\(fn QUERY)" t nil)
(defalias 'hayoo 'haskell-hayoo)
;;;***
;;;### (autoloads (inferior-haskell-find-haddock inferior-haskell-find-definition
;;;;;; inferior-haskell-info inferior-haskell-type inferior-haskell-load-file
;;;;;; switch-to-haskell) "inf-haskell" "inf-haskell.el" (19189
;;;;;; 21847))
;;; Generated autoloads from inf-haskell.el
(defalias 'run-haskell 'switch-to-haskell)
(autoload 'switch-to-haskell "inf-haskell" "\
Show the inferior-haskell buffer. Start the process if needed.
\(fn &optional ARG)" t nil)
(autoload 'inferior-haskell-load-file "inf-haskell" "\
Pass the current buffer's file to the inferior haskell process.
If prefix arg \\[universal-argument] is given, just reload the previous file.
\(fn &optional RELOAD)" t nil)
(autoload 'inferior-haskell-type "inf-haskell" "\
Query the haskell process for the type of the given expression.
If optional argument `insert-value' is non-nil, insert the type above point
in the buffer. This can be done interactively with the \\[universal-argument] prefix.
The returned info is cached for reuse by `haskell-doc-mode'.
\(fn EXPR &optional INSERT-VALUE)" t nil)
(autoload 'inferior-haskell-info "inf-haskell" "\
Query the haskell process for the info of the given expression.
\(fn SYM)" t nil)
(autoload 'inferior-haskell-find-definition "inf-haskell" "\
Attempt to locate and jump to the definition of the given expression.
\(fn SYM)" t nil)
(autoload 'inferior-haskell-find-haddock "inf-haskell" "\
Find and open the Haddock documentation of SYM.
Make sure to load the file into GHCi or Hugs first by using C-c C-l.
Only works for functions in a package installed with ghc-pkg, or
whatever the value of `haskell-package-manager-name' is.
This function needs to find which package a given module belongs
to. In order to do this, it computes a module-to-package lookup
alist, which is expensive to compute (it takes upwards of five
seconds with more than about thirty installed packages). As a
result, we cache it across sessions using the cache file
referenced by `inferior-haskell-module-alist-file'. We test to
see if this is newer than `haskell-package-conf-file' every time
we load it.
\(fn SYM)" t nil)
;;;***
;;;### (autoloads nil nil ("haskell-font-lock.el" "haskell-ghci.el"
;;;;;; "haskell-hugs.el" "haskell-simple-indent.el") (19189 21847
;;;;;; 934450))
;;;***

View file

@ -0,0 +1,157 @@
-------------------------------------------------------------------------
-- Comments with allcaps `FIXME' indicate places where the indentation --
-- fails to find the correct indentation, whereas comments with --
-- lowercase `fixme' indicate places where impossible indentations --
-- are uselessly proposed. --
-------------------------------------------------------------------------
-- compute the list of binary digits corresponding to an integer
-- Note: the least significant bit is the first element of the list
bdigits :: Int -> [Int]
bdigits 0 = [0]
bdigits 1 = [1]
bdigits n | n>1 = n `mod` 2 :
bdigits (n `div` 2)
| otherwise = error "bdigits of a negative number"
-- compute the value of an integer given its list of binary digits
-- Note: the least significant bit is the first element of the list
bvalue :: [Int]->Int
bvalue [] = error "bvalue of []"
bvalue s = bval 1 s
where
bval e [] = 0
bval e [] = 0 -- fixme: can't align with `where'.
bval e (b:bs) | b==0 || b=="dd of " = b*e + bval (2*e) bs
| otherwise = error "ill digit" -- Spurious 3rd step.
foo
-- fixme: tab on the line above should insert `bvalue' at some point.
{- text
indentation
inside comments
-}
toto a = ( hello
, there -- indentation of leading , and ;
-- indentation of this comment.
, my friends )
lili x = do let ofs x = 1
print x
titi b =
let -- fixme: can't indent at column 0
x = let toto = 1
tata = 2 -- fixme: can't indent lower than `toto'.
in
toto in
do expr1
{- text
- indentation
- inside comments
-}
let foo s = let fro = 1
fri = 2 -- fixme: can't indent lower than `fro'.
in
hello
foo2 = bar2 -- fixme: can't align with arg `s' in foo.
foo1 = bar2 -- fixme: Can't be column 0.
expr2
tata c =
let bar = case foo -- fixme: can't be col 0.
of 1 -> blabla
2 -> blibli -- fixme: only one possible indentation here.
bar = case foo of
_ -> blabla
bar' = case foo
of _ -> blabla
toto -> plulu
turlu d = if test
then
ifturl
else
adfaf
turlu d = if test then
ifturl
else
sg
turly fg = toto
where
hello = 2
-- test from John Goerzen
x myVariableThing = case myVariablething of
Just z -> z
Nothing -> 0 -- fixme: "spurious" additional indents.
foo = let x = 1 in toto
titi -- FIXME
foo = let foo x y = toto
where
toto = 2
instance Show Toto where
foo x 4 = 50
data Toto = Foo
| Bar
deriving (Show) -- FIXME
foo = let toto x = do let bar = 2
return 1
in 3
eval env (Llambda x e) = -- FIXME: sole indentation is self???
Vfun (\v -> eval (\y -> if (x == y) then v else env y) -- FIXME
e) -- FIXME
foo = case findprop attr props of
Just x -> x
data T = T { granularity :: (Int, Int, Int, Int) -- FIXME: self indentation?
, items :: Map (Int, Int, Int, Int) [Item] }
foo = case foo of
[] ->
case bar of
[] ->
return ()
(x:xs) -> -- FIXME
bar = do toto
if titi
then tutu -- FIXME
else tata -- FIXME
insert :: Ord a => a -> b -> TreeMap a b -> TreeMap a b
insert x v Empty = Node 0 x v Empty Empty
insert x v (Node d x' v' t1 t2)
| x == x' = Node d x v t1 t2
| x < x' = Node ? x' v' (insert x v t1 Empty) t2
| -- FIXME: wrong indent *if at EOB*
tinsertb x v (Node x' v' d1 t1 d2 t2)
| x == x' = (1 + max d1 d2, Node x v d1 t1 d2 t2)
| x < x' =
case () of
_ | d1' <= d2 + 1 => (1 + max d1' d2, Node x' v' d1' t1' d2 t2)
-- d1' == d2 + 2: Need to rotate to rebalance. FIXME CRASH
else let (Node x'' v'' d1'' t1'' d2'' t2'') = t1'
test = if True then
toto
else if False then
tata -- FIXME
else -- FIXME
titi
-- arch-tag: de0069e3-c0a0-495c-b441-d4ff6e0509b1

View file

@ -0,0 +1,720 @@
;;; inf-haskell.el --- Interaction with an inferior Haskell process.
;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords: Haskell
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; The code is made of 2 parts: a major mode for the buffer that holds the
;; inferior process's session and a minor mode for use in source buffers.
;; Todo:
;; - Check out Shim for ideas.
;; - i-h-load-buffer and i-h-send-region.
;;; Code:
(require 'comint)
(require 'shell) ;For directory tracking.
(require 'compile)
(require 'haskell-mode)
(eval-when-compile (require 'cl))
;; XEmacs compatibility.
(unless (fboundp 'subst-char-in-string)
(defun subst-char-in-string (fromchar tochar string &optional inplace)
;; This is Haskell-mode, we don't want no stinkin' `aset'.
(apply 'string (mapcar (lambda (c) (if (eq c fromchar) tochar c)) string))))
(unless (fboundp 'make-temp-file)
(defun make-temp-file (prefix &optional dir-flag)
(catch 'done
(while t
(let ((f (make-temp-name (expand-file-name prefix (temp-directory)))))
(condition-case ()
(progn
(if dir-flag (make-directory f)
(write-region "" nil f nil 'silent nil))
(throw 'done f))
(file-already-exists t)))))))
(unless (fboundp 'replace-regexp-in-string)
(defun replace-regexp-in-string (regexp rep string)
(replace-in-string string regexp rep)))
;; Here I depart from the inferior-haskell- prefix.
;; Not sure if it's a good idea.
(defcustom haskell-program-name
;; Arbitrarily give preference to hugs over ghci.
(or (cond
((not (fboundp 'executable-find)) nil)
((executable-find "hugs") "hugs \"+.\"")
((executable-find "ghci") "ghci"))
"hugs \"+.\"")
"The name of the command to start the inferior Haskell process.
The command can include arguments."
;; Custom only supports the :options keyword for a few types, e.g. not
;; for string.
;; :options '("hugs \"+.\"" "ghci")
:group 'haskell
:type '(choice string (repeat string)))
(defconst inferior-haskell-info-xref-re
"\t-- Defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?$")
(defconst inferior-haskell-module-re
"\t-- Defined in \\(.+\\)$"
"Regular expression for matching module names in :info.")
(defconst inferior-haskell-error-regexp-alist
;; The format of error messages used by Hugs.
`(("^ERROR \"\\(.+?\\)\"\\(:\\| line \\)\\([0-9]+\\) - " 1 3)
;; Format of error messages used by GHCi.
("^\\(.+?\\):\\([0-9]+\\):\\(\\([0-9]+\\):\\)?\\( \\|\n *\\)\\(Warning\\)?"
1 2 4 ,@(if (fboundp 'compilation-fake-loc)
'((6) nil (5 '(face nil font-lock-multiline t)))))
;; Runtime exceptions, from ghci.
("^\\*\\*\\* Exception: \\(.+?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\)): .*"
1 ,@(if (fboundp 'compilation-fake-loc) '((2 . 4) (3 . 5)) '(2 3)))
;; GHCi uses two different forms for line/col ranges, depending on
;; whether it's all on the same line or not :-( In Emacs-23, I could use
;; explicitly numbered subgroups to merge the two patterns.
("^\\*\\*\\* Exception: \\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\): .*"
1 2 ,(if (fboundp 'compilation-fake-loc) '(3 . 4) 3))
;; Info messages. Not errors per se.
,@(when (fboundp 'compilation-fake-loc)
`(;; Other GHCi patterns used in type errors.
("^[ \t]+at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$"
1 2 (3 . 4) 0)
;; Foo.hs:318:80:
;; Ambiguous occurrence `Bar'
;; It could refer to either `Bar', defined at Zork.hs:311:5
;; or `Bar', imported from Bars at Frob.hs:32:0-16
;; (defined at Location.hs:97:5)
("[ (]defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\))?$" 1 2 3 0)
("imported from .* at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$"
1 2 (3 . 4) 0)
;; Info xrefs.
(,inferior-haskell-info-xref-re 1 2 (3 . 4) 0))))
"Regexps for error messages generated by inferior Haskell processes.
The format should be the same as for `compilation-error-regexp-alist'.")
(defcustom inferior-haskell-find-project-root t
"If non-nil, try and find the project root directory of this file.
This will either look for a Cabal file or a \"module\" statement in the file."
:type 'boolean)
(define-derived-mode inferior-haskell-mode comint-mode "Inf-Haskell"
"Major mode for interacting with an inferior Haskell process."
(set (make-local-variable 'comint-prompt-regexp)
"^\\*?[A-Z][\\._a-zA-Z0-9]*\\( \\*?[A-Z][\\._a-zA-Z0-9]*\\)*> ")
(set (make-local-variable 'comint-input-autoexpand) nil)
(add-hook 'comint-output-filter-functions 'inferior-haskell-spot-prompt nil t)
;; Setup directory tracking.
(set (make-local-variable 'shell-cd-regexp) ":cd")
(condition-case nil
(shell-dirtrack-mode 1)
(error ;The minor mode function may not exist or not accept an arg.
(set (make-local-variable 'shell-dirtrackp) t)
(add-hook 'comint-input-filter-functions 'shell-directory-tracker
nil 'local)))
;; Setup `compile' support so you can just use C-x ` and friends.
(set (make-local-variable 'compilation-error-regexp-alist)
inferior-haskell-error-regexp-alist)
(set (make-local-variable 'compilation-first-column) 0) ;GHCI counts from 0.
(if (and (not (boundp 'minor-mode-overriding-map-alist))
(fboundp 'compilation-shell-minor-mode))
;; If we can't remove compilation-minor-mode bindings, at least try to
;; use compilation-shell-minor-mode, so there are fewer
;; annoying bindings.
(compilation-shell-minor-mode 1)
;; Else just use compilation-minor-mode but without its bindings because
;; things like mouse-2 are simply too annoying.
(compilation-minor-mode 1)
(let ((map (make-sparse-keymap)))
(dolist (keys '([menu-bar] [follow-link]))
;; Preserve some of the bindings.
(define-key map keys (lookup-key compilation-minor-mode-map keys)))
(add-to-list 'minor-mode-overriding-map-alist
(cons 'compilation-minor-mode map)))))
(defun inferior-haskell-string-to-strings (string)
"Split the STRING into a list of strings."
(let ((i (string-match "[\"]" string)))
(if (null i) (split-string string) ; no quoting: easy
(append (unless (eq i 0) (split-string (substring string 0 i)))
(let ((rfs (read-from-string string i)))
(cons (car rfs)
(inferior-haskell-string-to-strings
(substring string (cdr rfs)))))))))
(defun inferior-haskell-command (arg)
(inferior-haskell-string-to-strings
(if (null arg) haskell-program-name
(read-string "Command to run haskell: " haskell-program-name))))
(defvar inferior-haskell-buffer nil
"The buffer in which the inferior process is running.")
(defun inferior-haskell-start-process (command)
"Start an inferior haskell process.
With universal prefix \\[universal-argument], prompts for a COMMAND,
otherwise uses `haskell-program-name'.
It runs the hook `inferior-haskell-hook' after starting the process and
setting up the inferior-haskell buffer."
(interactive (list (inferior-haskell-command current-prefix-arg)))
(setq inferior-haskell-buffer
(apply 'make-comint "haskell" (car command) nil (cdr command)))
(with-current-buffer inferior-haskell-buffer
(inferior-haskell-mode)
(run-hooks 'inferior-haskell-hook)))
(defun inferior-haskell-process (&optional arg)
(or (if (buffer-live-p inferior-haskell-buffer)
(get-buffer-process inferior-haskell-buffer))
(progn
(let ((current-prefix-arg arg))
(call-interactively 'inferior-haskell-start-process))
;; Try again.
(inferior-haskell-process arg))))
;;;###autoload
(defalias 'run-haskell 'switch-to-haskell)
;;;###autoload
(defun switch-to-haskell (&optional arg)
"Show the inferior-haskell buffer. Start the process if needed."
(interactive "P")
(let ((proc (inferior-haskell-process arg)))
(pop-to-buffer (process-buffer proc))))
(eval-when-compile
(unless (fboundp 'with-selected-window)
(defmacro with-selected-window (win &rest body)
`(save-selected-window
(select-window ,win)
,@body))))
(defcustom inferior-haskell-wait-and-jump nil
"If non-nil, wait for file loading to terminate and jump to the error."
:type 'boolean
:group 'haskell)
(defvar inferior-haskell-seen-prompt nil)
(make-variable-buffer-local 'inferior-haskell-seen-prompt)
(defun inferior-haskell-spot-prompt (string)
(let ((proc (get-buffer-process (current-buffer))))
(when proc
(save-excursion
(goto-char (process-mark proc))
(if (re-search-backward comint-prompt-regexp
(line-beginning-position) t)
(setq inferior-haskell-seen-prompt t))))))
(defun inferior-haskell-wait-for-prompt (proc &optional timeout)
"Wait until PROC sends us a prompt.
The process PROC should be associated to a comint buffer."
(with-current-buffer (process-buffer proc)
(while (progn
(goto-char comint-last-input-end)
(not (or inferior-haskell-seen-prompt
(setq inferior-haskell-seen-prompt
(re-search-forward comint-prompt-regexp nil t))
(not (accept-process-output proc timeout))))))
(unless inferior-haskell-seen-prompt
(error "Can't find the prompt."))))
(defvar inferior-haskell-cabal-buffer nil)
(defun inferior-haskell-cabal-of-buf (buf)
(require 'haskell-cabal)
(with-current-buffer buf
(or (and (buffer-live-p inferior-haskell-cabal-buffer)
inferior-haskell-cabal-buffer)
(and (not (local-variable-p 'inferior-haskell-cabal-buffer
;; XEmacs needs this argument.
(current-buffer)))
(set (make-local-variable 'inferior-haskell-cabal-buffer)
(haskell-cabal-find-file))))))
(defun inferior-haskell-find-project-root (buf)
(with-current-buffer buf
(let ((cabal (inferior-haskell-cabal-of-buf buf)))
(or (when cabal
(with-current-buffer cabal
(let ((hsd (haskell-cabal-get-setting "hs-source-dirs")))
(if (null hsd)
;; If there's a Cabal file with no Hs-Source-Dirs, then
;; just use the Cabal file's directory.
default-directory
;; If there is an HSD, then check that it's an existing
;; dir (otherwise, it may be a list of dirs and we don't
;; know what to do with those). If it doesn't exist, then
;; give up.
(if (file-directory-p hsd) (expand-file-name hsd))))))
;; If there's no Cabal file or it's not helpful, try to look for
;; a "module" statement and count the number of "." in the
;; module name.
(save-excursion
(goto-char (point-min))
(let ((case-fold-search nil))
(when (re-search-forward
"^module[ \t]+\\([^- \t\n]+\\.[^- \t\n]+\\)[ \t]+where\\>" nil t)
(let* ((dir default-directory)
(module (match-string 1))
(pos 0))
(while (string-match "\\." module pos)
(setq pos (match-end 0))
(setq dir (expand-file-name ".." dir)))
;; Let's check that the module name matches the file name,
;; otherwise the project root is probably not what we think.
(if (eq t (compare-strings
(file-name-sans-extension buffer-file-name)
nil nil
(expand-file-name
(replace-regexp-in-string "\\." "/" module)
dir)
nil nil t))
dir
;; If they're not equal, it means the local directory
;; hierarchy doesn't match the module name. This seems
;; odd, so let's warn the user about it. May help us
;; debug this code as well.
(message "Ignoring inconsistent `module' info: %s in %s"
module buffer-file-name)
nil)))))))))
;;;###autoload
(defun inferior-haskell-load-file (&optional reload)
"Pass the current buffer's file to the inferior haskell process.
If prefix arg \\[universal-argument] is given, just reload the previous file."
(interactive "P")
;; Save first, so we're sure that `buffer-file-name' is non-nil afterward.
(save-buffer)
(let ((buf (current-buffer))
(file buffer-file-name)
(proc (inferior-haskell-process)))
(with-current-buffer (process-buffer proc)
(compilation-forget-errors)
(let ((parsing-end (marker-position (process-mark proc)))
root)
;; Go to the root of the Cabal project, if applicable.
(when (and inferior-haskell-find-project-root
(setq root (inferior-haskell-find-project-root buf)))
;; Not sure if it's useful/needed and if it actually works.
(unless (equal default-directory root)
(setq default-directory root)
(inferior-haskell-send-command
proc (concat ":cd " default-directory)))
(setq file (file-relative-name file)))
(inferior-haskell-send-command
proc (if reload ":reload"
(concat ":load \""
;; Espace the backslashes that may occur in file names.
(replace-regexp-in-string "[\\\"]" "\\\\\&" file)
"\"")))
;; Move the parsing-end marker *after* sending the command so
;; that it doesn't point just to the insertion point.
;; Otherwise insertion may move the marker (if done with
;; insert-before-markers) and we'd then miss some errors.
(if (boundp 'compilation-parsing-end)
(if (markerp compilation-parsing-end)
(set-marker compilation-parsing-end parsing-end)
(setq compilation-parsing-end parsing-end))))
(with-selected-window (display-buffer (current-buffer))
(goto-char (point-max)))
;; Use compilation-auto-jump-to-first-error if available.
;; (if (and (boundp 'compilation-auto-jump-to-first-error)
;; compilation-auto-jump-to-first-error
;; (boundp 'compilation-auto-jump-to-next))
;; (setq compilation-auto-jump-to-next t)
(when inferior-haskell-wait-and-jump
(inferior-haskell-wait-for-prompt proc)
(ignore-errors ;Don't beep if there were no errors.
(next-error)))))) ;; )
(defvar inferior-haskell-run-command ":main")
(defun inferior-haskell-load-and-run (command)
"Pass the current buffer's file to haskell and then run a COMMAND."
(interactive
(list
(if (and inferior-haskell-run-command (not current-prefix-arg))
inferior-haskell-run-command
(read-string "Command to run: " nil nil inferior-haskell-run-command))))
(setq inferior-haskell-run-command command)
(let* ((inferior-haskell-errors nil)
(neh (lambda () (setq inferior-haskell-errors t))))
(unwind-protect
(let ((inferior-haskell-wait-and-jump t))
(add-hook 'next-error-hook neh)
(inferior-haskell-load-file))
(remove-hook 'next-error-hook neh))
(unless inferior-haskell-errors
(inferior-haskell-send-command (inferior-haskell-process) command)
(switch-to-haskell))))
(defun inferior-haskell-send-command (proc str)
(setq str (concat str "\n"))
(with-current-buffer (process-buffer proc)
(inferior-haskell-wait-for-prompt proc)
(goto-char (process-mark proc))
(insert-before-markers str)
(move-marker comint-last-input-end (point))
(setq inferior-haskell-seen-prompt nil)
(comint-send-string proc str)))
(defun inferior-haskell-reload-file ()
"Tell the inferior haskell process to reread the current buffer's file."
(interactive)
(inferior-haskell-load-file 'reload))
;;;###autoload
(defun inferior-haskell-type (expr &optional insert-value)
"Query the haskell process for the type of the given expression.
If optional argument `insert-value' is non-nil, insert the type above point
in the buffer. This can be done interactively with the \\[universal-argument] prefix.
The returned info is cached for reuse by `haskell-doc-mode'."
(interactive
(let ((sym (haskell-ident-at-point)))
(list (read-string (if (> (length sym) 0)
(format "Show type of (default %s): " sym)
"Show type of: ")
nil nil sym)
current-prefix-arg)))
(if (string-match "\\`\\s_+\\'" expr) (setq expr (concat "(" expr ")")))
(let* ((proc (inferior-haskell-process))
(type
(with-current-buffer (process-buffer proc)
(let ((parsing-end ; Remember previous spot.
(marker-position (process-mark proc))))
(inferior-haskell-send-command proc (concat ":type " expr))
;; Find new point.
(inferior-haskell-wait-for-prompt proc)
(goto-char (point-max))
;; Back up to the previous end-of-line.
(end-of-line 0)
;; Extract the type output
(buffer-substring-no-properties
(save-excursion (goto-char parsing-end)
(line-beginning-position 2))
(point))))))
(if (not (string-match (concat "^\\(" (regexp-quote expr) "[ \t\n]+::[ \t\n]*\\(.\\|\n\\)*\\)")
type))
(error "No type info: %s" type)
(progn
(setf type (match-string 1 type))
;; Cache for reuse by haskell-doc.
(when (and (boundp 'haskell-doc-mode) haskell-doc-mode
(boundp 'haskell-doc-user-defined-ids)
;; Haskell-doc only works for idents, not arbitrary expr.
(string-match "\\`(?\\(\\s_+\\|\\(\\sw\\|\\s'\\)+\\)?[ \t]*::[ \t]*"
type))
(let ((sym (match-string 1 type)))
(setq haskell-doc-user-defined-ids
(cons (cons sym (substring type (match-end 0)))
(delq (assoc sym haskell-doc-user-defined-ids)
haskell-doc-user-defined-ids)))))
(if (interactive-p) (message "%s" type))
(when insert-value
(beginning-of-line)
(insert type "\n"))
type))))
;;;###autoload
(defun inferior-haskell-info (sym)
"Query the haskell process for the info of the given expression."
(interactive
(let ((sym (haskell-ident-at-point)))
(list (read-string (if (> (length sym) 0)
(format "Show info of (default %s): " sym)
"Show info of: ")
nil nil sym))))
(let ((proc (inferior-haskell-process)))
(with-current-buffer (process-buffer proc)
(let ((parsing-end ; Remember previous spot.
(marker-position (process-mark proc))))
(inferior-haskell-send-command proc (concat ":info " sym))
;; Find new point.
(inferior-haskell-wait-for-prompt proc)
(goto-char (point-max))
;; Move to previous end-of-line
(end-of-line 0)
(let ((result
(buffer-substring-no-properties
(save-excursion (goto-char parsing-end)
(line-beginning-position 2))
(point))))
;; Move back to end of process buffer
(goto-char (point-max))
(if (interactive-p) (message "%s" result))
result)))))
;;;###autoload
(defun inferior-haskell-find-definition (sym)
"Attempt to locate and jump to the definition of the given expression."
(interactive
(let ((sym (haskell-ident-at-point)))
(list (read-string (if (> (length sym) 0)
(format "Find definition of (default %s): " sym)
"Find definition of: ")
nil nil sym))))
(let ((info (inferior-haskell-info sym)))
(if (not (string-match inferior-haskell-info-xref-re info))
(error "No source information available")
(let ((file (match-string-no-properties 1 info))
(line (string-to-number
(match-string-no-properties 2 info)))
(col (string-to-number
(match-string-no-properties 3 info))))
(when file
(with-current-buffer (process-buffer (inferior-haskell-process))
;; The file name is relative to the process's cwd.
(setq file (expand-file-name file)))
;; Push current location marker on the ring used by `find-tag'
(require 'etags)
(ring-insert find-tag-marker-ring (point-marker))
(pop-to-buffer (find-file-noselect file))
(when line
(goto-line line)
(when col (move-to-column col))))))))
;;; Functions to find the documentation of a given function.
;;
;; TODO for this section:
;;
;; * Support fetching of local Haddock docs pulled directly from source files.
;; * Display docs locally? w3m?
(defcustom inferior-haskell-use-web-docs
'fallback
"Whether to use the online documentation. Possible values:
`never', meaning always use local documentation, unless the local
file doesn't exist, when do nothing, `fallback', which means only
use the online documentation when the local file doesn't exist,
or `always', meaning always use the online documentation,
regardless of existance of local files. Default is `fallback'."
:group 'haskell
:type '(choice (const :tag "Never" never)
(const :tag "As fallback" fallback)
(const :tag "Always" always)))
(defcustom inferior-haskell-web-docs-base
"http://haskell.org/ghc/docs/latest/html/libraries/"
"The base URL of the online libraries documentation. This will
only be used if the value of `inferior-haskell-use-web-docs' is
`always' or `fallback'."
:group 'haskell
:type 'string)
(defcustom haskell-package-manager-name "ghc-pkg"
"Name of the program to consult regarding package details."
:group 'haskell
:type 'string)
(defcustom haskell-package-conf-file
(condition-case nil
(with-temp-buffer
(call-process "ghc" nil t nil "--print-libdir")
(expand-file-name "package.conf"
(buffer-substring (point-min) (1- (point-max)))))
;; Don't use `ignore-errors' because this form is not byte-compiled :-(
(error nil))
"Where the package configuration file for the package manager resides.
By default this is set to `ghc --print-libdir`/package.conf."
:group 'haskell
:type 'string)
(defun inferior-haskell-get-module (sym)
"Fetch the module in which SYM is defined."
(let ((info (inferior-haskell-info sym)))
(unless (string-match inferior-haskell-module-re info)
(error
"No documentation information available. Did you forget to C-c C-l?"))
(match-string-no-properties 1 info)))
(defun inferior-haskell-query-ghc-pkg (&rest args)
"Send ARGS to ghc-pkg, or whatever the value of
`haskell-package-manager' is. Insert the output into the current
buffer."
(apply 'call-process haskell-package-manager-name nil t nil args))
(defun inferior-haskell-get-package-list ()
"Get the list of packages from ghc-pkg, or whatever
`haskell-package-manager-name' is."
(with-temp-buffer
(inferior-haskell-query-ghc-pkg "--simple-output" "list")
(split-string (buffer-substring (point-min) (point-max)))))
(defun inferior-haskell-compute-module-alist ()
"Compute a list mapping modules to package names and haddock URLs using ghc-pkg."
(message "Generating module alist...")
(let ((module-alist ()))
(with-temp-buffer
(dolist (package (inferior-haskell-get-package-list))
(erase-buffer)
(inferior-haskell-query-ghc-pkg "describe" package)
(let ((package-w/o-version
(replace-regexp-in-string "[-.0-9]*\\'" "" package))
;; Find the Haddock documentation URL for this package
(haddock
(progn
(goto-char (point-min))
(when (re-search-forward "haddock-html:[ \t]+\\(.*[^ \t\n]\\)"
nil t)
(match-string 1)))))
;; Fetch the list of exposed modules for this package
(goto-char (point-min))
(when (re-search-forward "^exposed-modules:\\(.*\\(\n[ \t].*\\)*\\)"
nil t)
(dolist (module (split-string (match-string 1)))
(push (list module package-w/o-version haddock)
module-alist)))))
(message "Generating module alist... done")
module-alist)))
(defcustom inferior-haskell-module-alist-file
;; (expand-file-name "~/.inf-haskell-module-alist")
(expand-file-name (concat "inf-haskell-module-alist-"
(number-to-string (user-uid)))
(if (fboundp 'temp-directory)
(temp-directory)
temporary-file-directory))
"Where to save the module -> package lookup table.
Set this to `nil' to never cache to a file."
:group 'haskell
:type '(choice (const :tag "Don't cache to file" nil) string))
(defvar inferior-haskell-module-alist nil
"Association list of modules to their packages.
Each element is of the form (MODULE PACKAGE HADDOCK), where
MODULE is the name of a module,
PACKAGE is the package it belongs to, and
HADDOCK is the path to that package's Haddock documentation.
This is calculated on-demand using `inferior-haskell-compute-module-alist'.
It's also cached in the file `inferior-haskell-module-alist-file',
so that it can be obtained more quickly next time.")
(defun inferior-haskell-module-alist ()
"Get the module alist from cache or ghc-pkg's info."
(or
;; If we already have computed the alist, use it...
inferior-haskell-module-alist
(setq inferior-haskell-module-alist
(or
;; ...otherwise try to read it from the cache file...
(and
inferior-haskell-module-alist-file
(file-readable-p inferior-haskell-module-alist-file)
(file-newer-than-file-p inferior-haskell-module-alist-file
haskell-package-conf-file)
(with-temp-buffer
(insert-file-contents inferior-haskell-module-alist-file)
(goto-char (point-min))
(prog1 (read (current-buffer))
(message "Read module alist from file cache."))))
;; ...or generate it again and save it in a file for later.
(let ((alist (inferior-haskell-compute-module-alist)))
(when inferior-haskell-module-alist-file
(with-temp-buffer
(print alist (current-buffer))
;; Do the write to a temp file first, then rename it.
;; This makes it more atomic, and suffers from fewer security
;; holes related to race conditions if the file is in /tmp.
(let ((tmp (make-temp-file inferior-haskell-module-alist-file)))
(write-region (point-min) (point-max) tmp)
(rename-file tmp inferior-haskell-module-alist-file
'ok-if-already-exists))))
alist)))))
(defvar inferior-haskell-ghc-internal-ident-alist
;; FIXME: Fill this table, ideally semi-automatically.
'(("GHC.Base.return" . "Control.Monad.return")
("GHC.List" . "Data.List")))
(defun inferior-haskell-map-internal-ghc-ident (ident)
"Try to translate some internal GHC identifier to its alter ego in haskell docs."
(let ((head ident)
(tail "")
remapped)
(while (and (not
(setq remapped
(cdr (assoc head
inferior-haskell-ghc-internal-ident-alist))))
(string-match "\\.[^.]+\\'" head))
(setq tail (concat (match-string 0 head) tail))
(setq head (substring head 0 (match-beginning 0))))
(concat (or remapped head) tail)))
;;;###autoload
(defun inferior-haskell-find-haddock (sym)
"Find and open the Haddock documentation of SYM.
Make sure to load the file into GHCi or Hugs first by using C-c C-l.
Only works for functions in a package installed with ghc-pkg, or
whatever the value of `haskell-package-manager-name' is.
This function needs to find which package a given module belongs
to. In order to do this, it computes a module-to-package lookup
alist, which is expensive to compute (it takes upwards of five
seconds with more than about thirty installed packages). As a
result, we cache it across sessions using the cache file
referenced by `inferior-haskell-module-alist-file'. We test to
see if this is newer than `haskell-package-conf-file' every time
we load it."
(interactive
(let ((sym (haskell-ident-at-point)))
(list (read-string (if (> (length sym) 0)
(format "Find documentation of (default %s): " sym)
"Find documentation of: ")
nil nil sym))))
(setq sym (inferior-haskell-map-internal-ghc-ident sym))
(let* (;; Find the module and look it up in the alist
(module (inferior-haskell-get-module sym))
(alist-record (assoc module (inferior-haskell-module-alist)))
(package (nth 1 alist-record))
(file-name (concat (subst-char-in-string ?. ?- module) ".html"))
(local-path (concat (nth 2 alist-record) "/" file-name))
(url (if (or (eq inferior-haskell-use-web-docs 'always)
(and (not (file-exists-p local-path))
(eq inferior-haskell-use-web-docs 'fallback)))
(concat inferior-haskell-web-docs-base package "/" file-name
;; Jump to the symbol anchor within Haddock.
"#v:" sym)
(and (file-exists-p local-path)
(concat "file://" local-path)))))
(if url (browse-url url) (error "Local file doesn't exist."))))
(provide 'inf-haskell)
;; arch-tag: 61804287-63dd-4052-bc0e-90f691b34b40
;;; inf-haskell.el ends here

View file

@ -0,0 +1,157 @@
;;; highlight-parentheses.el --- highlight surrounding parentheses
;;
;; Copyright (C) 2007, 2009 Nikolaj Schumacher
;;
;; Author: Nikolaj Schumacher <bugs * nschum de>
;; Version: 1.0.1
;; Keywords: faces, matching
;; URL: http://nschum.de/src/emacs/highlight-parentheses/
;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
;;
;; This file is NOT part of GNU Emacs.
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 2
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;; Add the following to your .emacs file:
;; (require 'highlight-parentheses)
;;
;; Enable `highlight-parentheses-mode'.
;;
;;; Change Log:
;;
;; 2009-03-19 (1.0.1)
;; Added setter for color variables.
;;
;; 2007-07-30 (1.0)
;; Added background highlighting and faces.
;;
;; 2007-05-15 (0.9.1)
;; Support for defcustom.
;;
;; 2007-04-26 (0.9)
;; Initial Release.
;;
;;; Code:
(eval-when-compile (require 'cl))
(defgroup highlight-parentheses nil
"Highlight surrounding parentheses"
:group 'faces
:group 'matching)
(defun hl-paren-set (variable value)
(set variable value)
(when (fboundp 'hl-paren-color-update)
(hl-paren-color-update)))
(defcustom hl-paren-colors
'("firebrick1" "IndianRed1" "IndianRed3" "IndianRed4")
"*List of colors for the highlighted parentheses.
The list starts with the the inside parentheses and moves outwards."
:type '(repeat color)
:set 'hl-paren-set
:group 'highlight-parentheses)
(defcustom hl-paren-background-colors nil
"*List of colors for the background highlighted parentheses.
The list starts with the the inside parentheses and moves outwards."
:type '(repeat color)
:set 'hl-paren-set
:group 'highlight-parentheses)
(defface hl-paren-face nil
"*Face used for highlighting parentheses.
Color attributes might be overriden by `hl-paren-colors' and
`hl-paren-background-colors'."
:group 'highlight-parentheses)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar hl-paren-overlays nil
"This buffers currently active overlays.")
(make-variable-buffer-local 'hl-paren-overlays)
(defvar hl-paren-last-point 0
"The last point for which parentheses were highlighted.
This is used to prevent analyzing the same context over and over.")
(make-variable-buffer-local 'hl-paren-last-point)
(defun hl-paren-highlight ()
"Highlight the parentheses around point."
(unless (= (point) hl-paren-last-point)
(setq hl-paren-last-point (point))
(let ((overlays hl-paren-overlays)
pos1 pos2
(pos (point)))
(save-excursion
(condition-case err
(while (and (setq pos1 (cadr (syntax-ppss pos1)))
(cddr overlays))
(move-overlay (pop overlays) pos1 (1+ pos1))
(when (setq pos2 (scan-sexps pos1 1))
(move-overlay (pop overlays) (1- pos2) pos2)
))
(error nil))
(goto-char pos))
(dolist (ov overlays)
(move-overlay ov 1 1)))))
;;;###autoload
(define-minor-mode highlight-parentheses-mode
"Minor mode to highlight the surrounding parentheses."
nil " hl-p" nil
(if highlight-parentheses-mode
(progn
(hl-paren-create-overlays)
(add-hook 'post-command-hook 'hl-paren-highlight nil t))
(mapc 'delete-overlay hl-paren-overlays)
(kill-local-variable 'hl-paren-overlays)
(kill-local-variable 'hl-paren-point)
(remove-hook 'post-command-hook 'hl-paren-highlight t)))
;;; overlays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun hl-paren-create-overlays ()
(let ((fg hl-paren-colors)
(bg hl-paren-background-colors)
attributes)
(while (or fg bg)
(setq attributes (face-attr-construct 'hl-paren-face))
(when (car fg)
(setq attributes (plist-put attributes :foreground (car fg))))
(pop fg)
(when (car bg)
(setq attributes (plist-put attributes :background (car bg))))
(pop bg)
(dotimes (i 2) ;; front and back
(push (make-overlay 0 0) hl-paren-overlays)
(overlay-put (car hl-paren-overlays) 'face attributes)))
(setq hl-paren-overlays (nreverse hl-paren-overlays))))
(defun hl-paren-color-update ()
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when hl-paren-overlays
(mapc 'delete-overlay hl-paren-overlays)
(setq hl-paren-overlays nil)
(hl-paren-create-overlays)
(let ((hl-paren-last-point -1)) ;; force update
(hl-paren-highlight))))))
(provide 'highlight-parentheses)
;;; highlight-parentheses.el ends here

8
.emacs.d/history Normal file
View file

@ -0,0 +1,8 @@
;; -*- mode: emacs-lisp; coding: utf-8-unix -*-
;; Minibuffer history file, automatically generated by `savehist'.
(setq savehist-minibuffer-history-variables '(ido-buffer-history extended-command-history yes-or-no-p-history ido-file-history))
(setq ido-buffer-history '("2" "ha" "Tu" "Me"))
(setq extended-command-history '("menu-bar-mode" "make-frame" "auto-fill-mode" "text-mode" "slime" "imenu" "slime" "slime-abort-connection" "slime" "slime-abort-connection" "slime" "slime-abort-connection" "slime"))
(setq yes-or-no-p-history '("yes" "yse" "yes"))
(setq ido-file-history '("2." "ha" "eu" "Scripts/" "2." "ha" "eu" "Scripts/" "some.hs" "xmonad.hs" ".xmonad/" "xmonad.hs" ".xmonad/" ".emacs" "n" "de" "src/" "vim" "Downloads/"))

265
.emacs.d/line-num.el Normal file
View file

@ -0,0 +1,265 @@
;;; line-num.el --- Display line numbers in left-margin of buffer.
;;
;; Filename: line-num.el
;; Description: Display line numbers in left-margin of buffer.
;; Author: (Darryl Okahata) darrylo@hpsrdmo, Drew Adams
;; Maintainer: Drew Adams
;; Copyright (C) 1999-2009, Drew Adams, all rights reserved.
;; Copyright (C) 1989, Hewlett-Packard, all rights reserved.
;; Created: Wed Mar 31 16:18:24 1999
;; Version: 21.0
;; Last-Updated: Sat Dec 27 10:09:30 2008 (-0800)
;; By: dradams
;; Update #: 206
;; URL: http://www.emacswiki.org/cgi-bin/wiki/line-num.el
;; Keywords: local
;; Compatibility: GNU Emacs 20.x, GNU Emacs 21.x, GNU Emacs 22.x
;;
;; Features that might be required by this library:
;;
;; None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; Display line numbers in left-margin of buffer.
;;
;; New functions defined here:
;;
;; `display-line-numbers', `toggle-line-numbers-display',
;; `turn-on-line-numbers-display', `turn-off-line-numbers-display'.
;;
;; NOTE: `setnu.el' now provides similar, but generally better,
;; functionality.
;;
;; Original author was Darryl Okahata darrylo@hpsrdmo: The copy on
;; which the current (Adams) modifications were made was obtained from
;; Rick Kunin (rickk@sperdk).
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;; 2004/11/26 dadams
;; Replaced decf with setq...1+.
;; turn-off-line-numbers-display: Error if not displaying line #s.
;; Removed calls to `fit-frame' (and require of fit-frame.el).
;; 2000/11/01 dadams
;; 1. Added: toggle-line-numbers-display, turn-on-line-numbers-display,
;; turn-off-line-numbers-display.
;; 2. Added global vars: displaying-line-numbers-p,
;; display-line-numbers-format-string, display-line-numbers-first-line,
;; display-line-numbers-count, display-line-numbers-buffer-name,
;; display-line-numbers-modified-p.
;; 1999/04/14 dadams
;; Commented out assignment to unused free var: insert-end.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:
;;>> Problem: Tabs at beginning of lines
(and (< emacs-major-version 20) (eval-when-compile (require 'cl))) ;; when, unless
;;;;;;;;;;;;;
;;;###autoload
(defun display-line-numbers ()
"Temporarily display line numbers in left margin of current buffer."
(interactive)
(or (eq (current-buffer) (window-buffer (selected-window)))
(error "Current buffer, %s, is not the selected window's buffer"
(buffer-name)))
(let ((buffer-read-only nil)
(modified (buffer-modified-p))
(name buffer-file-name)
(point (point-marker))
format-string
line-number
(count 0)
nlines
first-line)
(save-restriction
(widen)
(save-excursion
(setq first-line (window-start (selected-window)))
(goto-char first-line)
(setq line-number (1+ (count-lines (point-min) (point))))
(move-to-window-line -1)
(beginning-of-line)
(setq nlines (count-lines first-line (point)))
(let ((max (+ line-number nlines)))
(setq format-string (cond ((< max 100) "%2d ")
((< max 1000) "%3d ")
((< max 10000) "%4d ")
(t "%7d "))))))
(save-excursion
(unwind-protect
(progn
(goto-char first-line)
;; defeat file locking... don't try this at home, kids!
(setq buffer-file-name nil)
(while (<= count nlines)
(insert-before-markers (format format-string line-number))
;;;(setq insert-end (point)) THIS VAR IS FREE - AND UNUSED!
(setq line-number (1+ line-number))
(setq count (1+ count))
(forward-line 1))
(set-window-start (selected-window) first-line)
(goto-char point)
(set-buffer-modified-p modified)
(message "<<< Press SPACE to continue >>>")
(let ((char (read-char)))
(or (eql char ?\ )
(setq unread-command-events (list char))))
)
(goto-char first-line)
(let ((n (1+ (- (aref format-string 1) ?0))))
(while (> count 0)
(setq count (1- count))
(delete-char n)
(forward-line 1)))
(setq buffer-file-name name)
(set-buffer-modified-p modified)))))
;;;-----------------------------------------------------------------
(defvar displaying-line-numbers-p nil)
(make-variable-buffer-local 'displaying-line-numbers-p)
(defvar display-line-numbers-format-string nil)
(make-variable-buffer-local 'display-line-numbers-format-string)
(defvar display-line-numbers-first-line nil)
(make-variable-buffer-local 'display-line-numbers-first-line)
(defvar display-line-numbers-count 0)
(make-variable-buffer-local 'display-line-numbers-count)
(defvar display-line-numbers-buffer-name nil)
(make-variable-buffer-local 'display-line-numbers-buffer-name)
(defvar display-line-numbers-modified-p nil)
(make-variable-buffer-local 'display-line-numbers-modified-p)
;;;###autoload
(defun toggle-line-numbers-display (arg)
"Display/clear line numbers in left margin of current buffer.
With prefix ARG, just number lines in current window, not all lines in
buffer."
(interactive "P")
(if displaying-line-numbers-p
(turn-off-line-numbers-display)
(turn-on-line-numbers-display arg)))
;;;###autoload
(defun turn-on-line-numbers-display (arg)
"Display line numbers in left margin of current buffer.
With prefix ARG, just number lines in current window, not all lines in
buffer."
(interactive "P")
(or (eq (current-buffer) (window-buffer (selected-window)))
(error "Current buffer, %s, is not the selected window's buffer"
(buffer-name)))
(let ((buffer-read-only nil)
(point (point-marker))
line-number
nlines)
(setq display-line-numbers-buffer-name buffer-file-name)
(setq display-line-numbers-modified-p (buffer-modified-p))
(save-restriction
(widen)
(save-excursion
(setq display-line-numbers-first-line
(if arg
(window-start (selected-window))
(point-min)))
(goto-char display-line-numbers-first-line)
(setq line-number (1+ (count-lines (point-min) (point))))
(if arg
(move-to-window-line -1)
(goto-char (point-max)))
(beginning-of-line)
(setq nlines (count-lines display-line-numbers-first-line (point)))
(let ((max (+ line-number nlines)))
(setq display-line-numbers-format-string (cond ((< max 100) "%2d ")
((< max 1000) "%3d ")
((< max 10000) "%4d ")
(t "%7d "))))))
(save-excursion
(condition-case nil
(progn
(goto-char display-line-numbers-first-line)
(setq buffer-file-name nil) ; To prevent saving with line numbers etc.
(setq displaying-line-numbers-p t)
(while (<= display-line-numbers-count nlines)
(insert-before-markers
(format display-line-numbers-format-string line-number))
(setq line-number (1+ line-number))
(setq display-line-numbers-count (1+ display-line-numbers-count))
(forward-line 1))
(when arg
(set-window-start (selected-window) display-line-numbers-first-line))
(goto-char point)
(set-buffer-modified-p display-line-numbers-modified-p))
(error
(progn
(goto-char display-line-numbers-first-line)
(let ((n (1+ (- (aref display-line-numbers-format-string 1) ?0))))
(while (> display-line-numbers-count 0)
(setq display-line-numbers-count (1- display-line-numbers-count))
(delete-char n)
(forward-line 1)))
(setq buffer-file-name display-line-numbers-buffer-name)
(set-buffer-modified-p display-line-numbers-modified-p)
(setq displaying-line-numbers-p nil))))))
(let ((curr-line (count-lines (window-start) (point))))
(when (> curr-line 0) (setq curr-line (1+ curr-line)))
(recenter curr-line)))
;;;###autoload
(defun turn-off-line-numbers-display ()
"Clear displayed line numbers from left margin of current buffer."
(interactive)
(unless (eq (current-buffer) (window-buffer (selected-window)))
(error "Current buffer, `%s', is not the selected window's buffer"
(buffer-name)))
(unless displaying-line-numbers-p
(error "Not displaying line numbers in buffer `%s'" (buffer-name)))
(let ((buffer-read-only nil))
(save-excursion
(when (boundp 'display-line-numbers-buffer-name)
(setq buffer-file-name display-line-numbers-buffer-name))
(goto-char display-line-numbers-first-line)
(let ((n (1+ (- (aref display-line-numbers-format-string 1) ?0))))
(while (> display-line-numbers-count 0)
(setq display-line-numbers-count (1- display-line-numbers-count))
(delete-char n)
(forward-line 1)))
(when (boundp 'display-line-numbers-modified-p)
(set-buffer-modified-p display-line-numbers-modified-p))
(setq displaying-line-numbers-p nil))))
;;;;;;;;;;;;;;;;;;;;;;;
(provide 'line-num)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; line-num.el ends here

196
.emacs.d/linum.el Normal file
View file

@ -0,0 +1,196 @@
;;; linum.el --- Display line numbers to the left of buffers
;; Copyright (C) 2007 Markus Triska
;; Author: Markus Triska <markus.triska@gmx.at>
;; Keywords: convenience
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; Display line numbers for the current buffer. Copy linum.el to your
;; load-path and add to your .emacs:
;; (require 'linum)
;; Then toggle display of line numbers with M-x linum-mode. To enable
;; line numbering in all buffers, use M-x global-linum-mode.
;;; Code:
(defconst linum-version "0.9wx")
(defvar linum-overlays nil "Overlays used in this buffer.")
(defvar linum-available nil "Overlays available for reuse.")
(defvar linum-before-numbering-hook nil
"Functions run in each buffer before line numbering starts.")
(mapc #'make-variable-buffer-local '(linum-overlays linum-available))
(defgroup linum nil
"Show line numbers to the left of buffers"
:group 'convenience)
;;;###autoload
(defcustom linum-format 'dynamic
"Format used to display line numbers. Either a format string
like \"%7d\", 'dynamic to adapt the width as needed, or a
function that is called with a line number as its argument and
should evaluate to a string to be shown on that line. See also
`linum-before-numbering-hook'."
:group 'linum
:type 'sexp)
(defface linum
'((t :inherit shadow))
"Face for displaying line numbers in the display margin."
:group 'linum)
(defcustom linum-eager t
"Whether line numbers should be updated after each command.
The conservative setting `nil' might miss some buffer changes,
and you have to scroll or press C-l to update the numbers."
:group 'linum
:type 'boolean)
(defcustom linum-delay t
"Whether updates should be delayed to give Emacs a chance for
other changes."
:group 'linum
:type 'boolean)
;;;###autoload
(define-minor-mode linum-mode
"Toggle display of line numbers in the left marginal area."
:lighter "" ; for desktop.el
(if linum-mode
(progn
(if linum-eager
(add-hook 'post-command-hook (if linum-delay
'linum-schedule
'linum-update-current) nil t)
(add-hook 'after-change-functions 'linum-after-change nil t))
(add-hook 'window-scroll-functions 'linum-after-scroll nil t)
;; mistake in Emacs: window-size-change-functions cannot be local
(add-hook 'window-size-change-functions 'linum-after-size)
(add-hook 'change-major-mode-hook 'linum-delete-overlays nil t)
(add-hook 'window-configuration-change-hook
'linum-after-config nil t)
(linum-update-current))
(remove-hook 'post-command-hook 'linum-update-current t)
(remove-hook 'post-command-hook 'linum-schedule t)
(remove-hook 'window-size-change-functions 'linum-after-size)
(remove-hook 'window-scroll-functions 'linum-after-scroll t)
(remove-hook 'after-change-functions 'linum-after-change t)
(remove-hook 'window-configuration-change-hook 'linum-after-config t)
(remove-hook 'change-major-mode-hook 'linum-delete-overlays t)
(linum-delete-overlays)))
;;;###autoload
(define-globalized-minor-mode global-linum-mode linum-mode linum-on)
(defun linum-on ()
(unless (minibufferp)
(linum-mode 1)))
(defun linum-delete-overlays ()
"Delete all overlays displaying line numbers for this buffer."
(mapc #'delete-overlay linum-overlays)
(setq linum-overlays nil)
(dolist (w (get-buffer-window-list (current-buffer) nil t))
(set-window-margins w 0)))
(defun linum-update-current ()
"Update line numbers for the current buffer."
(linum-update (current-buffer)))
(defun linum-update (buffer)
"Update line numbers for all windows displaying BUFFER."
(with-current-buffer buffer
(when linum-mode
(setq linum-available linum-overlays)
(setq linum-overlays nil)
(save-excursion
(mapc #'linum-update-window
(get-buffer-window-list buffer nil 'visible)))
(mapc #'delete-overlay linum-available)
(setq linum-available nil))))
(defun linum-update-window (win)
"Update line numbers for the portion visible in window WIN."
(goto-char (window-start win))
(let ((line (line-number-at-pos))
(limit (1+ (window-end win t)))
(fmt (cond ((stringp linum-format) linum-format)
((eq linum-format 'dynamic)
(let ((w (length (number-to-string
(count-lines (point-min) (point-max))))))
(concat "%" (number-to-string w) "d ")))))
(width 0)
visited
ov)
(run-hooks 'linum-before-numbering-hook)
;; Create an overlay (or reuse an existing one) for each
;; line visible in this window, if necessary.
(while (and (not (eobp)) (< (point) limit))
(setq visited nil)
(dolist (o (overlays-in (point) (point)))
(when (eq (overlay-get o 'linum-line) line)
(unless (memq o linum-overlays)
(push o linum-overlays))
(setq linum-available (delete o linum-available))
(setq visited t)))
(let ((str (if fmt
(propertize (format fmt line) 'face 'linum)
(funcall linum-format line))))
(setq width (max width (length str)))
(unless visited
(if (null linum-available)
(setq ov (make-overlay (point) (point)))
(setq ov (pop linum-available))
(move-overlay ov (point) (point)))
(push ov linum-overlays)
(setq str (propertize " " 'display `((margin left-margin) ,str)))
(overlay-put ov 'before-string str)
(overlay-put ov 'linum-line line)))
(forward-line)
(setq line (1+ line)))
(set-window-margins win width)))
(defun linum-after-change (beg end len)
;; update overlays on deletions, and after newlines are inserted
(when (or (= beg end)
(= end (point-max))
;; TODO: use string-match-p with CVS or new release
(string-match "\n" (buffer-substring-no-properties beg end)))
(linum-update-current)))
(defun linum-after-scroll (win start)
(linum-update (window-buffer win)))
(defun linum-after-size (frame)
(linum-after-config))
(defun linum-schedule ()
;; schedule an update; the delay gives Emacs a chance for display changes
(run-with-idle-timer 0 nil #'linum-update-current))
(defun linum-after-config ()
(walk-windows (lambda (w) (linum-update (window-buffer))) nil 'visible))
(provide 'linum)
;;; linum.el ends here

38
.emacs.d/parenface.el Normal file
View file

@ -0,0 +1,38 @@
;;; parenface.el --- Provide a face for parens in lisp modes.
;; By Dave Pearson <davep@davep.org>
;; $Revision: 1.1 $
;; Add a paren-face to emacs and add support for it to the various lisp modes.
;;
;; Based on some code that Boris Schaefer <boris@uncommon-sense.net> posted
;; to comp.lang.scheme in message <87hf8g9nw5.fsf@qiwi.uncommon-sense.net>.
(defvar paren-face 'paren-face)
(defface paren-face
'((((class color))
(:foreground "DimGray")))
"Face for displaying a paren."
:group 'faces)
(defmacro paren-face-add-support (keywords)
"Generate a lambda expression for use in a hook."
`(lambda ()
(let* ((regexp "(\\|)")
(match (assoc regexp ,keywords)))
(unless (eq (cdr match) paren-face)
(setq ,keywords (append (list (cons regexp paren-face)) ,keywords))))))
;; Keep the compiler quiet.
(eval-when-compile
(defvar scheme-font-lock-keywords-2 nil)
(defvar lisp-font-lock-keywords-2 nil))
(add-hook 'scheme-mode-hook (paren-face-add-support scheme-font-lock-keywords-2))
(add-hook 'lisp-mode-hook (paren-face-add-support lisp-font-lock-keywords-2))
(add-hook 'emacs-lisp-mode-hook (paren-face-add-support lisp-font-lock-keywords-2))
(add-hook 'lisp-interaction-mode-hook (paren-face-add-support lisp-font-lock-keywords-2))
(provide 'parenface)
;; parenface.el ends here

View file

@ -0,0 +1,22 @@
(eval-when-compile
(require 'color-theme))
(defun color-theme-example ()
"Example theme. Carbon copy of color-theme-gnome contributed by Jonadab."
(interactive)
(color-theme-install
'(color-theme-example
((foreground-color . "wheat")
(background-color . "darkslategrey")
(background-mode . dark))
(default ((t (nil))))
(region ((t (:foreground "cyan" :background "dark cyan"))))
(underline ((t (:foreground "yellow" :underline t))))
(modeline ((t (:foreground "dark cyan" :background "wheat"))))
(modeline-buffer-id ((t (:foreground "dark cyan" :background "wheat"))))
(modeline-mousable ((t (:foreground "dark cyan" :background "wheat"))))
(modeline-mousable-minor-mode ((t (:foreground "dark cyan" :background "wheat"))))
(italic ((t (:foreground "dark red" :italic t))))
(bold-italic ((t (:foreground "dark red" :bold t :italic t))))
(font-lock-comment-face ((t (:foreground "Firebrick"))))
(bold ((t (:bold)))))))

File diff suppressed because it is too large Load diff

19
.vimrc
View file

@ -15,7 +15,7 @@ set encoding=utf-8
" Turn off the menubar so we don't get key accelerators with Meta. " Turn off the menubar so we don't get key accelerators with Meta.
" Don't include the toolbar " Don't include the toolbar
set guioptions=aegiLt set guioptions=aegiLt
colorscheme inkpot "colorscheme ir_black
set fenc=utf-8 set fenc=utf-8
if exists('&t_SI') if exists('&t_SI')
@ -111,8 +111,15 @@ elseif has("gui_running")
endif endif
" Try to load a nice colourscheme " Try to load a nice colourscheme
set t_Co=256 if ! has("gui_running")
color inkpot set t_Co=256
colors inkpot
else
colors ir_black
endif
" set background=light gives a different style, feel free to choose between them.
set background=dark
"colors peaksea
" No icky toolbar, menu or scrollbars in the GUI " No icky toolbar, menu or scrollbars in the GUI
"if has('gui') "if has('gui')
@ -651,6 +658,12 @@ if has("eval")
let ruby_operators=1 let ruby_operators=1
let ruby_space_errors=1 let ruby_space_errors=1
" clojure options
let g:clj_want_gorilla = 1
let g:clj_highlight_builtins = 1
let g:clj_highlight_contrib = 1
let g:clj_paren_rainbow = 1
" php specific options " php specific options
let php_sql_query=1 let php_sql_query=1
let php_htmlInStrings=1 let php_htmlInStrings=1

View file

@ -161,6 +161,7 @@ mManageHook = composeAll
, className =? "googleearth" --> doFloat , className =? "googleearth" --> doFloat
, className =? "Pidgin" --> doFloat , className =? "Pidgin" --> doFloat
, className =? "mangclient" --> doFloat , className =? "mangclient" --> doFloat
, className =? "Emacs" --> doFloat
, className =? "CellWriter" --> doFloat , className =? "CellWriter" --> doFloat
, className =? "Gvba" --> doFloat , className =? "Gvba" --> doFloat
, className =? "Cellwriter" --> doIgnore , className =? "Cellwriter" --> doIgnore