aboutsummaryrefslogtreecommitdiffstats
path: root/support/emacs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2010-12-01 02:10:27 +0000
committerDavid Robillard <d@drobilla.net>2010-12-01 02:10:27 +0000
commit5b9b071a8b59e6d66cc71c3c06a12bea3a0cebb7 (patch)
tree4a47e1ac3e9a9e1c4aef1c7b9f259ef4fa2fd678 /support/emacs
parent0e77ece68cc136ff294f0b272634e520c477143b (diff)
downloadresp-5b9b071a8b59e6d66cc71c3c06a12bea3a0cebb7.tar.gz
resp-5b9b071a8b59e6d66cc71c3c06a12bea3a0cebb7.tar.bz2
resp-5b9b071a8b59e6d66cc71c3c06a12bea3a0cebb7.zip
Add basic emacs resp-mode (modified from scheme.el).
git-svn-id: http://svn.drobilla.net/resp/resp@273 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'support/emacs')
-rw-r--r--support/emacs/resp.el391
1 files changed, 391 insertions, 0 deletions
diff --git a/support/emacs/resp.el b/support/emacs/resp.el
new file mode 100644
index 0000000..d3a6301
--- /dev/null
+++ b/support/emacs/resp.el
@@ -0,0 +1,391 @@
+;;; resp.el --- Resp editing mode
+
+;; Copyright (C) 1986, 1987, 1988, 1997, 1998, 2001, 2002, 2003, 2004, 2005,
+;; 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+;; Based on resp.el
+
+;; Author: Bill Rozas <jinx@martigny.ai.mit.edu>
+;; Adapted-by: Dave Love <d.love@dl.ac.uk>
+;; Adapted-by: David Robillard <d@drobilla.net>
+;; Keywords: languages, lisp, resp, resp
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The major mode for editing Resp-type Lisp code, very similar to
+;; the Lisp mode documented in the Emacs manual.
+
+;;; Code:
+
+(require 'lisp-mode)
+
+(defvar resp-mode-syntax-table
+ (let ((st (make-syntax-table))
+ (i 0))
+
+ ;; Default is atom-constituent.
+ (while (< i 256)
+ (modify-syntax-entry i "_ " st)
+ (setq i (1+ i)))
+
+ ;; Word components.
+ (setq i ?0)
+ (while (<= i ?9)
+ (modify-syntax-entry i "w " st)
+ (setq i (1+ i)))
+ (setq i ?A)
+ (while (<= i ?Z)
+ (modify-syntax-entry i "w " st)
+ (setq i (1+ i)))
+ (setq i ?a)
+ (while (<= i ?z)
+ (modify-syntax-entry i "w " st)
+ (setq i (1+ i)))
+
+ ;; Whitespace
+ (modify-syntax-entry ?\t " " st)
+ (modify-syntax-entry ?\n "> " st)
+ (modify-syntax-entry ?\f " " st)
+ (modify-syntax-entry ?\r " " st)
+ (modify-syntax-entry ?\s " " st)
+
+ ;; These characters are delimiters but otherwise undefined.
+ ;; Brackets and braces balance for editing convenience.
+ (modify-syntax-entry ?\[ "(] " st)
+ (modify-syntax-entry ?\] ")[ " st)
+ (modify-syntax-entry ?{ "(} " st)
+ (modify-syntax-entry ?} "){ " st)
+
+ ;; Other atom delimiters
+ (modify-syntax-entry ?\( "() " st)
+ (modify-syntax-entry ?\) ")( " st)
+ ;; It's used for single-line comments as well as for #;(...) sexp-comments.
+ (modify-syntax-entry ?\; "< 2 " st)
+ (modify-syntax-entry ?\" "\" " st)
+ (modify-syntax-entry ?' "' " st)
+ (modify-syntax-entry ?` "' " st)
+
+ ;; Special characters
+ (modify-syntax-entry ?, "' " st)
+ (modify-syntax-entry ?@ "' " st)
+ (modify-syntax-entry ?# "' 14b" st)
+ (modify-syntax-entry ?\\ "\\ " st)
+ st))
+
+(defvar resp-mode-abbrev-table nil)
+(define-abbrev-table 'resp-mode-abbrev-table ())
+
+(defvar resp-imenu-generic-expression
+ '((nil "^(def\\(\\|-type\\)\\s-+(?\\(\\sw+\\)" 2))
+ "Imenu generic expression for Resp mode. See `imenu-generic-expression'.")
+
+(defun resp-mode-variables ()
+ (set-syntax-table resp-mode-syntax-table)
+ (setq local-abbrev-table resp-mode-abbrev-table)
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat "$\\|" page-delimiter))
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate paragraph-start)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+ (make-local-variable 'fill-paragraph-function)
+ (setq fill-paragraph-function 'lisp-fill-paragraph)
+ ;; Adaptive fill mode gets in the way of auto-fill,
+ ;; and should make no difference for explicit fill
+ ;; because lisp-fill-paragraph should do the job.
+ (make-local-variable 'adaptive-fill-mode)
+ (setq adaptive-fill-mode nil)
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'lisp-indent-line)
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (setq parse-sexp-ignore-comments t)
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp ";;; \\|(....")
+ (make-local-variable 'comment-start)
+ (setq comment-start ";")
+ (set (make-local-variable 'comment-add) 1)
+ (make-local-variable 'comment-start-skip)
+ ;; Look within the line for a ; following an even number of backslashes
+ ;; after either a non-backslash or the line beginning.
+ (setq comment-start-skip "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+[ \t]*")
+ (set (make-local-variable 'font-lock-comment-start-skip) ";+ *")
+ (make-local-variable 'comment-column)
+ (setq comment-column 40)
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (setq parse-sexp-ignore-comments t)
+ (make-local-variable 'lisp-indent-function)
+ (setq lisp-indent-function 'resp-indent-function)
+ (setq mode-line-process '("" resp-mode-line-process))
+ (set (make-local-variable 'imenu-case-fold-search) t)
+ (setq imenu-generic-expression resp-imenu-generic-expression)
+ (set (make-local-variable 'imenu-syntax-alist)
+ '(("+-*/.<>=?!$%_&~^:" . "w")))
+ (set (make-local-variable 'font-lock-defaults)
+ '((resp-font-lock-keywords
+ resp-font-lock-keywords-1 resp-font-lock-keywords-2)
+ nil t (("+-*/.<>=!?$%_&~^:" . "w") (?#. "w 14"))
+ beginning-of-defun
+ (font-lock-mark-block-function . mark-defun)
+ (font-lock-syntactic-face-function
+ . resp-font-lock-syntactic-face-function)
+ (parse-sexp-lookup-properties . t)
+ (font-lock-extra-managed-props syntax-table)))
+ (set (make-local-variable 'lisp-doc-string-elt-property)
+ 'resp-doc-string-elt))
+
+(defvar resp-mode-line-process "")
+
+(defvar resp-mode-map
+ (let ((smap (make-sparse-keymap))
+ (map (make-sparse-keymap "Resp")))
+ (set-keymap-parent smap lisp-mode-shared-map)
+ (define-key smap [menu-bar resp] (cons "Resp" map))
+ (define-key map [run-resp] '("Run Inferior Resp" . run-resp))
+ (define-key map [uncomment-region]
+ '("Uncomment Out Region" . (lambda (beg end)
+ (interactive "r")
+ (comment-region beg end '(4)))))
+ (define-key map [comment-region] '("Comment Out Region" . comment-region))
+ (define-key map [indent-region] '("Indent Region" . indent-region))
+ (define-key map [indent-line] '("Indent Line" . lisp-indent-line))
+ (put 'comment-region 'menu-enable 'mark-active)
+ (put 'uncomment-region 'menu-enable 'mark-active)
+ (put 'indent-region 'menu-enable 'mark-active)
+ smap)
+ "Keymap for Resp mode.
+All commands in `lisp-mode-shared-map' are inherited by this map.")
+
+
+;;;###autoload
+(defun resp-mode ()
+ "Major mode for editing Resp code.
+Editing commands are similar to those of `lisp-mode'.
+
+Commands:
+Delete converts tabs to spaces as it moves back.
+Blank lines separate paragraphs. Semicolons start comments.
+\\{resp-mode-map}
+Entry to this mode calls the value of `resp-mode-hook'
+if that value is non-nil."
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map resp-mode-map)
+ (setq major-mode 'resp-mode)
+ (setq mode-name "Resp")
+ (resp-mode-variables)
+ (run-mode-hooks 'resp-mode-hook))
+
+(defgroup resp nil
+ "Editing Resp code."
+ :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
+ :group 'lisp)
+
+(defcustom resp-mode-hook nil
+ "Normal hook run when entering `resp-mode'.
+See `run-hooks'."
+ :type 'hook
+ :group 'resp)
+
+;; This is shared by cmuresp and xresp.
+(defcustom resp-program-name "resp"
+ "*Program invoked by the `run-resp' command."
+ :type 'string
+ :group 'resp)
+
+(defconst resp-font-lock-keywords-1
+ (eval-when-compile
+ (list
+ ;;
+ ;; Declarations. Hannes Haug <hannes.haug@student.uni-tuebingen.de> says
+ ;; this works for SOS, STklos, SCOOPS, Meroon and Tiny CLOS.
+ (list (concat "(\\(def\\*?\\("
+ ;; Function names.
+ "\\(\\|-public\\|-method\\|-generic\\(-procedure\\)?\\)\\|"
+ ;; Macro names, as variable names. A bit dubious, this.
+ "\\(-syntax\\|-macro\\)\\|"
+ ;; Class names.
+ "\\(-class\\|-type\\)\\|"
+ ;; Guile modules.
+ "\\|-module"
+ "\\)\\)\\>"
+ ;; Any whitespace and declared object.
+ "[ \t]*(?"
+ "\\(\\sw+\\)?")
+ '(1 font-lock-keyword-face)
+ '(6 (cond ((match-beginning 3) font-lock-function-name-face)
+ ((match-beginning 5) font-lock-variable-name-face)
+ (t font-lock-type-face))
+ nil t))
+ ))
+ "Subdued expressions to highlight in Resp modes.")
+
+(defconst resp-font-lock-keywords-2
+ (append resp-font-lock-keywords-1
+ (eval-when-compile
+ (list
+ ;;
+ ;; Control structures.
+ (cons
+ (concat
+ "(" (regexp-opt
+ '("begin" "call-with-current-continuation" "call/cc"
+ "call-with-input-file" "call-with-output-file" "case" "cond"
+ "do" "else" "for-each" "if" "lambda" "fn" "match"
+ "let" "let*" "let-syntax" "letrec" "letrec-syntax"
+ ;; SRFI 11 usage comes up often enough.
+ "let-values" "let*-values"
+ ;; Hannes Haug <hannes.haug@student.uni-tuebingen.de> wants:
+ "and" "or" "delay" "force"
+ ;; Stefan Monnier <stefan.monnier@epfl.ch> says don't bother:
+ ;;"quasiquote" "quote" "unquote" "unquote-splicing"
+ "map" "syntax" "syntax-rules") t)
+ "\\>") 1)
+ ;;
+ ;; Named let
+ '("(let\\s-+\\(\\sw+\\)"
+ (1 font-lock-function-name-face))
+ ;;
+ ;; David Fox <fox@graphics.cs.nyu.edu> for SOS/STklos class specifiers.
+ '("\\<<\\sw+>\\>" . font-lock-type-face)
+ ;;
+ ;; Resp `:' and `#:' keywords as builtins.
+ '("\\<#?:\\sw+\\>" . font-lock-builtin-face)
+ ;;
+ )))
+ "Gaudy expressions to highlight in Resp modes.")
+
+(defvar resp-font-lock-keywords resp-font-lock-keywords-1
+ "Default expressions to highlight in Resp modes.")
+
+(defconst resp-sexp-comment-syntax-table
+ (let ((st (make-syntax-table resp-mode-syntax-table)))
+ (modify-syntax-entry ?\; "." st)
+ (modify-syntax-entry ?\n " " st)
+ (modify-syntax-entry ?# "'" st)
+ st))
+
+(put 'lambda 'resp-doc-string-elt 2)
+;; Docstring's pos in a `define' depends on whether it's a var or fun def.
+(put 'define 'resp-doc-string-elt
+ (lambda ()
+ ;; The function is called with point right after "define".
+ (forward-comment (point-max))
+ (if (eq (char-after) ?\() 2 0)))
+
+(defun resp-font-lock-syntactic-face-function (state)
+ (when (and (null (nth 3 state))
+ (eq (char-after (nth 8 state)) ?#)
+ (eq (char-after (1+ (nth 8 state))) ?\;))
+ ;; It's a sexp-comment. Tell parse-partial-sexp where it ends.
+ (save-excursion
+ (let ((pos (point))
+ (end
+ (condition-case err
+ (let ((parse-sexp-lookup-properties nil))
+ (goto-char (+ 2 (nth 8 state)))
+ ;; FIXME: this doesn't handle the case where the sexp
+ ;; itself contains a #; comment.
+ (forward-sexp 1)
+ (point))
+ (scan-error (nth 2 err)))))
+ (when (< pos (- end 2))
+ (put-text-property pos (- end 2)
+ 'syntax-table resp-sexp-comment-syntax-table))
+ (put-text-property (- end 1) end 'syntax-table '(12)))))
+ ;; Choose the face to use.
+ (lisp-font-lock-syntactic-face-function state))
+
+
+(defvar calculate-lisp-indent-last-sexp)
+
+;; Copied from lisp-indent-function, but with gets of
+;; resp-indent-{function,hook}.
+(defun resp-indent-function (indent-point state)
+ (let ((normal-indent (current-column)))
+ (goto-char (1+ (elt state 1)))
+ (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
+ (if (and (elt state 2)
+ (not (looking-at "\\sw\\|\\s_")))
+ ;; car of form doesn't seem to be a symbol
+ (progn
+ (if (not (> (save-excursion (forward-line 1) (point))
+ calculate-lisp-indent-last-sexp))
+ (progn (goto-char calculate-lisp-indent-last-sexp)
+ (beginning-of-line)
+ (parse-partial-sexp (point)
+ calculate-lisp-indent-last-sexp 0 t)))
+ ;; Indent under the list or under the first sexp on the same
+ ;; line as calculate-lisp-indent-last-sexp. Note that first
+ ;; thing on that line has to be complete sexp since we are
+ ;; inside the innermost containing sexp.
+ (backward-prefix-chars)
+ (current-column))
+ (let ((function (buffer-substring (point)
+ (progn (forward-sexp 1) (point))))
+ method)
+ (setq method (or (get (intern-soft function) 'resp-indent-function)
+ (get (intern-soft function) 'resp-indent-hook)))
+ (cond ((or (eq method 'defun)
+ (and (null method)
+ (> (length function) 3)
+ (string-match "\\`def" function)))
+ (lisp-indent-defform state indent-point))
+ ((integerp method)
+ (lisp-indent-specform method state
+ indent-point normal-indent))
+ (method
+ (funcall method state indent-point normal-indent)))))))
+
+
+;;; Let is different in Resp
+
+(defun would-be-symbol (string)
+ (not (string-equal (substring string 0 1) "(")))
+
+(defun next-sexp-as-string ()
+ ;; Assumes that it is protected by a save-excursion
+ (forward-sexp 1)
+ (let ((the-end (point)))
+ (backward-sexp 1)
+ (buffer-substring (point) the-end)))
+
+;; This is correct but too slow.
+;; The one below works almost always.
+;;(defun resp-let-indent (state indent-point)
+;; (if (would-be-symbol (next-sexp-as-string))
+;; (resp-indent-specform 2 state indent-point)
+;; (resp-indent-specform 1 state indent-point)))
+
+(defun resp-let-indent (state indent-point normal-indent)
+ (skip-chars-forward " \t")
+ (if (looking-at "[-a-zA-Z0-9+*/?!@$%^&_:~]")
+ (lisp-indent-specform 2 state indent-point normal-indent)
+ (lisp-indent-specform 1 state indent-point normal-indent)))
+
+;; (put 'begin 'resp-indent-function 0), say, causes begin to be indented
+;; like defun if the first form is placed on the next line, otherwise
+;; it is indented like any other form (i.e. forms line up under first).
+
+(put 'def 'resp-indent-function 1)
+(put 'match 'resp-indent-function 1)
+(put 'fn 'resp-indent-function 1)
+
+
+(provide 'resp)
+
+;;; resp.el ends here