Adding emacs stuff
This commit is contained in:
parent
4cd060c128
commit
7a1b0e4178
31 changed files with 26489 additions and 3 deletions
183
.emacs
Normal file
183
.emacs
Normal 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
187
.emacs.d/bar-cursor.el
Normal 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
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
31
.emacs.d/gentooish.el
Normal 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)
|
||||||
1505
.emacs.d/haskell-mode/ChangeLog
Normal file
1505
.emacs.d/haskell-mode/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
104
.emacs.d/haskell-mode/NEWS
Normal file
104
.emacs.d/haskell-mode/NEWS
Normal 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
|
||||||
108
.emacs.d/haskell-mode/README
Normal file
108
.emacs.d/haskell-mode/README
Normal 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 -->
|
||||||
49
.emacs.d/haskell-mode/fontlock.hs
Normal file
49
.emacs.d/haskell-mode/fontlock.hs
Normal 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
|
||||||
47
.emacs.d/haskell-mode/haskell-c.el
Normal file
47
.emacs.d/haskell-mode/haskell-c.el
Normal 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
|
||||||
182
.emacs.d/haskell-mode/haskell-cabal.el
Normal file
182
.emacs.d/haskell-mode/haskell-cabal.el
Normal 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
|
||||||
698
.emacs.d/haskell-mode/haskell-decl-scan.el
Normal file
698
.emacs.d/haskell-mode/haskell-decl-scan.el
Normal 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
|
||||||
1932
.emacs.d/haskell-mode/haskell-doc.el
Normal file
1932
.emacs.d/haskell-mode/haskell-doc.el
Normal file
File diff suppressed because it is too large
Load diff
633
.emacs.d/haskell-mode/haskell-font-lock.el
Normal file
633
.emacs.d/haskell-mode/haskell-font-lock.el
Normal 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
|
||||||
332
.emacs.d/haskell-mode/haskell-ghci.el
Normal file
332
.emacs.d/haskell-mode/haskell-ghci.el
Normal 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
|
||||||
316
.emacs.d/haskell-mode/haskell-hugs.el
Normal file
316
.emacs.d/haskell-mode/haskell-hugs.el
Normal 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
|
||||||
1581
.emacs.d/haskell-mode/haskell-indent.el
Normal file
1581
.emacs.d/haskell-mode/haskell-indent.el
Normal file
File diff suppressed because it is too large
Load diff
856
.emacs.d/haskell-mode/haskell-indentation.el
Normal file
856
.emacs.d/haskell-mode/haskell-indentation.el
Normal 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
|
||||||
532
.emacs.d/haskell-mode/haskell-mode.el
Normal file
532
.emacs.d/haskell-mode/haskell-mode.el
Normal 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
|
||||||
154
.emacs.d/haskell-mode/haskell-simple-indent.el
Normal file
154
.emacs.d/haskell-mode/haskell-simple-indent.el
Normal 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
|
||||||
274
.emacs.d/haskell-mode/haskell-site-file.el
Normal file
274
.emacs.d/haskell-mode/haskell-site-file.el
Normal 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))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
157
.emacs.d/haskell-mode/indent.hs
Normal file
157
.emacs.d/haskell-mode/indent.hs
Normal 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
|
||||||
720
.emacs.d/haskell-mode/inf-haskell.el
Normal file
720
.emacs.d/haskell-mode/inf-haskell.el
Normal 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
|
||||||
157
.emacs.d/highlight-parenthesis.el
Normal file
157
.emacs.d/highlight-parenthesis.el
Normal 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
8
.emacs.d/history
Normal 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
265
.emacs.d/line-num.el
Normal 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
196
.emacs.d/linum.el
Normal 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
38
.emacs.d/parenface.el
Normal 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
|
||||||
22
.emacs.d/themes/color-theme-example.el
Normal file
22
.emacs.d/themes/color-theme-example.el
Normal 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)))))))
|
||||||
13539
.emacs.d/themes/color-theme-library.el
Normal file
13539
.emacs.d/themes/color-theme-library.el
Normal file
File diff suppressed because it is too large
Load diff
17
.vimrc
17
.vimrc
|
|
@ -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
|
||||||
|
if ! has("gui_running")
|
||||||
set t_Co=256
|
set t_Co=256
|
||||||
color inkpot
|
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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue