summaryrefslogtreecommitdiff
path: root/support/emacs
diff options
context:
space:
mode:
authorschinz <schinz@epfl.ch>2003-03-17 09:21:17 +0000
committerschinz <schinz@epfl.ch>2003-03-17 09:21:17 +0000
commit16e81343bac1158a731a37a0459ce603e524a8a3 (patch)
treea403db45f9bea650f9967b6f46a86d4e27b41ebc /support/emacs
parent7b6238d54b9d9c2104c9adbb13a4718ea74eb9c7 (diff)
downloadscala-16e81343bac1158a731a37a0459ce603e524a8a3.tar.gz
scala-16e81343bac1158a731a37a0459ce603e524a8a3.tar.bz2
scala-16e81343bac1158a731a37a0459ce603e524a8a3.zip
*** empty log message ***
Diffstat (limited to 'support/emacs')
-rw-r--r--support/emacs/inferior-scala-mode.el115
-rw-r--r--support/emacs/scala-mode-auto.el47
-rw-r--r--support/emacs/scala-mode.el647
3 files changed, 809 insertions, 0 deletions
diff --git a/support/emacs/inferior-scala-mode.el b/support/emacs/inferior-scala-mode.el
new file mode 100644
index 0000000000..d97a5d14c3
--- /dev/null
+++ b/support/emacs/inferior-scala-mode.el
@@ -0,0 +1,115 @@
+;;; inferior-scala-mode.el - Interaction with a Scala interpreter.
+;;; $Id$
+
+(require 'comint)
+
+(defgroup inferior-scala
+ nil
+ "Mode to interact with a Scala interpreter."
+ :group 'scala
+ :tag "Inferior Scala")
+
+(defcustom scala-default-interpreter "siris -emacs"
+ "Name of the interpreter to use by default."
+ :type 'string
+ :group 'inferior-scala)
+
+(defvar scala-interpreter scala-default-interpreter
+ "The interpreter that `run-scala' should run.
+If you want to change the defaut value, don't change that variable
+but customize `scala-default-interpreter' instead.")
+
+(defconst scala-inf-buffer-name "*inferior-scala*")
+
+(define-derived-mode inferior-scala-mode comint-mode "Inferior Scala"
+ "Major mode for interacting with a Scala interpreter.
+
+\\{inferior-scala-mode-map\\}"
+ (define-key inferior-scala-mode-map [(meta return)] 'comint-accumulate)
+
+ ;; Comint configuration
+ (make-local-variable 'comint-input-sender)
+ (setq comint-input-sender 'scala-input-sender))
+
+(defun scala-input-sender (proc string)
+ (comint-send-string proc string)
+ (comint-send-string proc "\nemacs:end\n"))
+
+;;;###autoload
+(defun scala-interpreter-running-p-1 ()
+ ;; True iff a Scala interpreter is currently running in a buffer.
+ (comint-check-proc scala-inf-buffer-name))
+
+(defun scala-check-interpreter-running ()
+ (unless (scala-interpreter-running-p-1)
+ (error "Scala interpreter not running")))
+
+;;;###autoload
+(defun run-scala (cmd-line)
+ "Run a Scala interpreter in an Emacs buffer"
+ (interactive (list (if current-prefix-arg
+ (read-string "Scala interpreter: " scala-interpreter)
+ scala-interpreter)))
+ (unless (scala-interpreter-running-p-1)
+ (setq scala-interpreter cmd-line)
+ (let ((cmd/args (split-string cmd-line)))
+ (set-buffer
+ (apply 'make-comint "inferior-scala" (car cmd/args) nil (cdr cmd/args))))
+ (inferior-scala-mode)
+ (pop-to-buffer scala-inf-buffer-name)))
+
+(defun scala-send-string (str &rest args)
+ ;; Send string to interpreter
+ (comint-send-string scala-inf-buffer-name (apply 'format str args))
+ (comint-send-string scala-inf-buffer-name "\nemacs:end\n"))
+
+;;;###autoload
+(defun scala-switch-to-interpreter ()
+ "Switch to buffer containing the interpreter"
+ (interactive)
+ (scala-check-interpreter-running)
+ (switch-to-buffer scala-inf-buffer-name))
+
+(defvar scala-tmp-file nil)
+
+;;;###autoload
+(defun scala-eval-region (start end)
+ "Send current region to Scala interpreter."
+ (interactive "r")
+ (scala-check-interpreter-running)
+ (if scala-tmp-file
+ (delete-file scala-tmp-file)
+ (setq scala-tmp-file (make-temp-file "scala_tmp")))
+ (write-region start end scala-tmp-file nil 'quiet)
+ (scala-send-string ":l %s" scala-tmp-file))
+
+;;;###autoload
+(defun scala-eval-buffer ()
+ "Send whole buffer to Scala interpreter."
+ (interactive)
+ (scala-eval-region (point-min) (point-max)))
+
+(defvar scala-prev-l/c-dir/file nil
+ "Caches the last (directory . file) pair.
+Caches the last pair used in the last scala-load-file.
+Used for determining the default in the next one.")
+
+;;;###autoload
+(defun scala-load-file (file-name)
+ "Load a file in the Scala interpreter."
+ (interactive (comint-get-source "Load Scala file: " scala-prev-l/c-dir/file
+ '(scala-mode) t))
+ (scala-check-interpreter-running)
+ (comint-check-source file-name)
+ (setq scala-prev-l/c-dir/file (cons (file-name-directory file-name)
+ (file-name-nondirectory file-name)))
+ (scala-send-string ":l %s" file-name))
+
+;;;###autoload
+(defun scala-quit-interpreter ()
+ "Quit Scala interpreter."
+ (interactive)
+ (scala-check-interpreter-running)
+ (scala-send-string "\n:q"))
+
+(provide 'inferior-scala-mode)
diff --git a/support/emacs/scala-mode-auto.el b/support/emacs/scala-mode-auto.el
new file mode 100644
index 0000000000..d3af11415d
--- /dev/null
+++ b/support/emacs/scala-mode-auto.el
@@ -0,0 +1,47 @@
+;;; scala-mode-auto.el - Provides autoload definitions for scala-mode.
+;;; $Id$
+
+(add-to-list 'auto-mode-alist '("\\.scala\\'" . scala-mode))
+
+
+;;;### (autoloads (scala-mode) "scala-mode" "scala-mode.el" (15703
+;;;;;; 49825))
+;;; Generated autoloads from scala-mode.el
+
+(autoload (quote scala-mode) "scala-mode" "\
+Major mode for editing Scala code.
+
+When started, run `scala-mode-hook'.
+
+\\{scala-mode-map}" t nil)
+
+;;;***
+
+;;;### (autoloads (scala-quit-interpreter scala-load-file scala-eval-buffer
+;;;;;; scala-eval-region scala-switch-to-interpreter run-scala scala-interpreter-running-p-1)
+;;;;;; "inferior-scala-mode" "inferior-scala-mode.el" (15703 53506))
+;;; Generated autoloads from inferior-scala-mode.el
+
+(autoload (quote scala-interpreter-running-p-1) "inferior-scala-mode" nil nil nil)
+
+(autoload (quote run-scala) "inferior-scala-mode" "\
+Run a Scala interpreter in an Emacs buffer" t nil)
+
+(autoload (quote scala-switch-to-interpreter) "inferior-scala-mode" "\
+Switch to buffer containing the interpreter" t nil)
+
+(autoload (quote scala-eval-region) "inferior-scala-mode" "\
+Send current region to Scala interpreter." t nil)
+
+(autoload (quote scala-eval-buffer) "inferior-scala-mode" "\
+Send whole buffer to Scala interpreter." t nil)
+
+(autoload (quote scala-load-file) "inferior-scala-mode" "\
+Load a file in the Scala interpreter." t nil)
+
+(autoload (quote scala-quit-interpreter) "inferior-scala-mode" "\
+Quit Scala interpreter." t nil)
+
+;;;***
+
+(provide 'scala-mode-auto)
diff --git a/support/emacs/scala-mode.el b/support/emacs/scala-mode.el
new file mode 100644
index 0000000000..b29f22051e
--- /dev/null
+++ b/support/emacs/scala-mode.el
@@ -0,0 +1,647 @@
+;;; scala.el - Major mode for editing Scala code.
+;;; $Id$
+
+;;; TODO
+
+(require 'easymenu)
+(require 'newcomment)
+(require 'cl)
+(require 'regexp-opt)
+
+(defconst scala-mode-version "0.2 ($Revision$)")
+(defconst scala-bug-e-mail "Michel.Schinz@epfl.ch")
+(defconst scala-web-url "http://lampwww.epfl.ch/scala/")
+
+;; Customization
+
+(defgroup scala
+ nil
+ "Mode to edit Scala code."
+ :group 'languages)
+
+(defcustom scala-indent-step 2
+ "Indentation step."
+ :type 'integer
+ :group 'scala)
+
+(defconst scala-number-re
+ "[[:digit:]]+\\(\\.[[:digit:]]+\\)?\\([eE][+-]?[[:digit:]]+\\)?[fl]?"
+ "Regular expression matching a Scala number (integer or float).")
+
+(defconst scala-string-re
+ "\"\\([^\"\\\\]\\|\\\\\.\\)*\""
+ "Regular expression matching a Scala string literal.")
+
+(defconst scala-char-re
+ "'\\([^'\\\\]\\|\\\\.\\)*\'"
+ "Regular expression matching a Scala character literal.")
+
+(defconst scala-literal-re
+ (concat "\\(" "\\(" scala-number-re "\\)"
+ "\\|" "\\(" scala-string-re "\\)"
+ "\\|" "\\(" scala-char-re "\\)" "\\)")
+ "Regular expression matching any Scala literal.")
+
+(defconst scala-most-special-chars (mapcar 'identity "<>+-*/|@#%&!?$^'`~\\")
+ "List of almost all Scala special characters.
+Not included in this list are the special characters which are
+reserved keywords when used alone.")
+
+(defconst scala-all-special-chars (append (mapcar 'identity ":;,=")
+ scala-most-special-chars)
+ "List of all Scala special characters.")
+
+(defconst scala-most-special-char-re
+ (regexp-opt-charset scala-most-special-chars)
+ "Regular expression matching a single Scala special character")
+
+(defconst scala-all-special-char-re
+ (regexp-opt-charset scala-all-special-chars)
+ "Regular expression matching a single Scala special character")
+
+(defconst scala-keywords-re
+ (regexp-opt '("abstract" "as" "case" "class" "def" "do" "else"
+ "extends" "final" "for" "if" "import" "is"
+ "let" "module" "new" "override" "outer"
+ "package" "private" "protected" "qualified"
+ "trait" "type" "val" "var" "with" "yield"
+ "null" "this" "super")
+ 'words))
+
+(defconst scala-constants-re
+ (regexp-opt '("true" "false" ) 'words))
+
+(defconst scala-special-ident-re
+ (concat "\\(" scala-most-special-char-re "+"
+ "\\|" scala-all-special-char-re "\\{2,\\}"
+ "\\)"))
+
+(defconst scala-ident-re
+ (let* ((varid-re "[[:alnum:]]+")
+ (id-re (concat "\\(" varid-re "\\|" scala-special-ident-re "\\)")))
+ (concat id-re
+ "\\(" "_+" "\\(" id-re "\\)?" "\\)*"))
+ "Regular expression matching a Scala identifier.")
+
+(defconst scala-var-ident-re
+ (concat "[[:lower:]][[:alnum:]]*" "\\(_" scala-ident-re "\\)*")
+ "Relgular expression matching a Scala 'variable' identifier.")
+
+(defconst scala-qual-ident-re
+ (concat scala-ident-re "\\(" "\\." scala-ident-re "\\)*"))
+
+(defconst scala-capitalized-ident-re
+ (concat "\\(\\)\\([[:upper:]]" scala-ident-re "\\)"))
+
+(defconst scala-expr-start-re
+ (concat
+ (regexp-opt '("if" "else" "for" "do" "yield") 'words) "\\|"
+ (regexp-opt '("=" "=>") t)))
+
+(defconst scala-expr-starter
+ (mapcar (lambda (pair) (cons (car pair) (concat "\\<" (cdr pair) "\\>")))
+ '(("else" . "if")
+ ("yield" . "for")
+ ("do" . "for")
+ ("extends" . "class")
+ ("with" . "class")
+ ("=>" . "case"))))
+
+(defconst scala-expr-middle-re
+ (regexp-opt (mapcar #'car scala-expr-starter) 'words))
+
+(defconst scala-compound-expr-re
+ "\\<else\\s +if\\>")
+
+(defun scala-special-char-p (char)
+ (and char
+ (string-match scala-all-special-char-re (string char))))
+
+(defun scala-looking-at-special-identifier (regexp)
+ (and (not (scala-special-char-p (char-before)))
+ (looking-at regexp)
+ (not (scala-special-char-p (char-after (match-end 0))))))
+
+(defconst scala-comment-begin-or-end-re
+ (concat "\\(" "^/\\*.*" "\\|" "^//.*" "\\|" ".*\\*/$" "\\)"))
+
+(defun scala-search-special-identifier-forward (limit)
+ (ignore-errors
+ (while (and (search-forward-regexp scala-special-ident-re limit)
+ (save-match-data
+ (string-match scala-comment-begin-or-end-re
+ (match-string-no-properties 0)))))
+ t))
+
+;; Movement
+
+(defun scala-forward-spaces (&optional limit)
+ (if limit
+ (save-restriction
+ (narrow-to-region (point) limit)
+ (forward-comment 100000))
+ (forward-comment 100000)))
+
+(defun scala-backward-spaces ()
+ (forward-comment -100000))
+
+(defun scala-looking-at-backward (re)
+ (save-excursion
+ (when (= 0 (skip-syntax-backward "w_")) (backward-char))
+ (looking-at re)))
+
+(defmacro scala-point-after (&rest body)
+ `(save-excursion
+ ,@body
+ (point)))
+
+(defmacro scala-move-if (&rest body)
+ (let ((pt-sym (make-symbol "point"))
+ (res-sym (make-symbol "result")))
+ `(let ((,pt-sym (point))
+ (,res-sym ,(cons 'progn body)))
+ (unless ,res-sym (goto-char ,pt-sym))
+ ,res-sym)))
+
+(defun scala-forward-ident ()
+ ;; Move forward over an identifier.
+ (scala-forward-spaces)
+ (if (looking-at scala-ident-re)
+ (goto-char (match-end 0))
+ (forward-char))
+ t)
+
+(defun scala-backward-ident ()
+ ;; Move backward over an identifier.
+ (scala-backward-spaces)
+ (if (scala-looking-at-backward scala-ident-re)
+ (goto-char (match-beginning 0))
+ (backward-char))
+ t)
+
+(defun scala-forward-qual-ident ()
+ ;; Move forward over a qualifier identifier.
+ (scala-forward-spaces)
+ (if (looking-at scala-qual-ident-re)
+ (goto-char (match-end 0))
+ (forward-char))
+ t)
+
+(defun scala-backward-qual-ident ()
+ ;; Move backward over a qualifier identifier.
+ (scala-backward-spaces)
+ (if (scala-looking-at-backward scala-qual-ident-re)
+ (goto-char (match-beginning 0))
+ (backward-char))
+ t)
+
+(defun scala-forward-simple-type ()
+ ;; Move forward over a simple type (as defined by the grammar).
+ ;; Works only when point is at the beginning of a simple type
+ ;; (modulo initial spaces/comments).
+ (cond ((eobp) nil)
+ ((= (char-syntax (char-after)) ?\()
+ ;; Tuple or function type.
+ (forward-sexp)
+ (scala-forward-spaces)
+ (when (looking-at "\\sw\\|(") (scala-forward-type)))
+ (t
+ ;; Type designator
+ (scala-forward-qual-ident)
+ (scala-forward-spaces)
+ (when (and (not (eobp)) (= (char-after) ?\[))
+ ;; Type arguments
+ (forward-sexp))))
+ t)
+
+(defun scala-forward-type ()
+ ;; Move forward over a type.
+ ;; Works only when point is at the beginning of a type (modulo
+ ;; initial spaces/comments).
+ (scala-forward-spaces)
+ (when (looking-at "\\<class\\>") (forward-word 1) (scala-forward-spaces))
+ (scala-forward-simple-type)
+ (while (looking-at "\\s *\\<with\\>\\s *")
+ (goto-char (match-end 0))
+ (if (and (not (eobp)) (= (char-after) ?\{))
+ (forward-sexp) ;skip refinement
+ (scala-forward-simple-type)))
+ t)
+
+(defun scala-forward-literal ()
+ ;; Move forward over an integer, float, character or string literal.
+ (scala-forward-spaces)
+ (when (looking-at scala-literal-re)
+ (goto-char (match-end 0)))
+ t)
+
+;;; Indentation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scala-parse-partial-sexp ()
+ (parse-partial-sexp (point-min) (point)))
+
+(defun scala-in-comment-p ()
+ "Return t iff the point is inside a comment."
+ ;; The two branches of the "if" below do not have the same behaviour
+ ;; when the point is on the comment beginning/ending character(s).
+ (if font-lock-mode
+ (eq (get-text-property (point) 'face) 'font-lock-comment-face)
+ (save-excursion (comment-beginning))))
+
+(defun scala-in-string-p ()
+ "Return t iff the point is inside a string."
+ (if font-lock-mode
+ (eq (get-text-property (point) 'face) 'font-lock-string-face)
+ (let ((limit (point)))
+ (beginning-of-line)
+ (loop while (search-forward-regexp "\\(^\\|[^\\\\]\\)\"" limit 'move)
+ count (not (scala-in-comment-p)) into quotes
+ finally return (oddp quotes)))))
+
+(defun scala-indentation ()
+ "Return the suggested indentation for the current line."
+ (save-excursion
+ (beginning-of-line)
+ (or (scala-indentation-from-following)
+ (scala-indentation-from-preceding)
+ (scala-indentation-from-block)
+ 0)))
+
+(defun scala-block-indentation ()
+ (let ((block-start-eol (scala-point-after (end-of-line)))
+ (block-after-spc (scala-point-after (scala-forward-spaces))))
+ (if (> block-after-spc block-start-eol)
+ (+ (current-indentation) scala-indent-step)
+ (current-column))))
+
+(defun scala-indentation-from-following ()
+ ;; Return suggested indentation based on the following part of the
+ ;; current expression. Return nil if indentation cannot be guessed.
+ (save-excursion
+ (scala-forward-spaces (scala-point-after (end-of-line)))
+ (cond
+ ((eobp) nil)
+ ((= (char-syntax (char-after)) ?\))
+ (let ((parse-sexp-ignore-comments t))
+ (goto-char (1+ (scan-sexps (1+ (point)) -1))))
+ (- (scala-block-indentation) scala-indent-step))
+ ((looking-at scala-expr-middle-re)
+ ;; [...] this is a somewhat of a hack.
+ (let ((matching-kw (cdr (assoc (match-string-no-properties 0)
+ scala-expr-starter))))
+ (while (and (search-backward-regexp matching-kw nil t)
+ (or (scala-in-comment-p) (scala-in-string-p)))))
+ (scala-move-if (backward-word 1)
+ (looking-at scala-compound-expr-re))
+ (current-column)))))
+
+(defun scala-indentation-from-preceding ()
+ ;; Return suggested indentation based on the preceding part of the
+ ;; current expression. Return nil if indentation cannot be guessed.
+ (save-excursion
+ (scala-backward-spaces)
+ (when (and (not (bobp))
+ (or (eq (char-syntax (char-before)) ?\()
+ (progn
+ (when (eq (char-before) ?\))
+ (backward-sexp)
+ (scala-backward-spaces))
+ (scala-looking-at-backward scala-expr-start-re))))
+ (+ (current-indentation) scala-indent-step))))
+
+(defun scala-indentation-from-block ()
+ ;; Return suggested indentation based on the current block.
+ (save-excursion
+ (let* ((state (scala-parse-partial-sexp))
+ (block-start (nth 1 state)))
+ (if (not block-start)
+ 0
+ (goto-char (1+ block-start))
+ (scala-block-indentation)))))
+
+(defun scala-indent-line-to (column)
+ "Indent current line to COLUMN and perhaps move point.
+The point is moved iff it is currently in the indentation, in which
+case it is brought to the end of that indentation. Otherwise it does
+not move."
+ (if (<= (current-column) (current-indentation))
+ (indent-line-to column)
+ (save-excursion (indent-line-to column))))
+
+(defun scala-indent-line ()
+ "Indent current line as smartly as possible.
+When called repeatedly, indent each time one stop further on the right."
+ (interactive)
+ (if (or (eq last-command this-command)
+ (eq last-command 'scala-undent-line))
+ (scala-indent-line-to (+ (current-indentation) scala-indent-step))
+ (let ((indentation (scala-indentation)))
+ (scala-indent-line-to indentation))))
+
+(defun scala-undent-line ()
+ "Indent line to previous tab stop."
+ (interactive)
+ (scala-indent-line-to (max 0 (- (current-indentation) scala-indent-step))))
+
+(defun scala-electric-brace ()
+ "Insert a brace, and if alone on a non-comment line, reindent."
+ (interactive)
+ (let ((on-empty-line-p (save-excursion
+ (beginning-of-line)
+ (looking-at "^\\s *$"))))
+ (call-interactively 'self-insert-command)
+ (when on-empty-line-p (scala-indent-line))))
+
+;;; Syntax highlighting
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scala-mark-borders (funs)
+ (loop for (fun . flag) in funs
+ if flag collect (point-marker)
+ while (funcall fun)
+ if flag collect (point-marker)))
+
+(defun scala-make-match (funs)
+ (let ((start-mark (point-marker))
+ (markers (scala-mark-borders funs))
+ (end-mark (point-marker)))
+ (cons start-mark (cons end-mark markers))))
+
+(defconst scala-binding-end-re
+ (regexp-opt '(":" "=" "=>" ";" "<-")))
+
+(defun scala-match-and-skip-binding (limit)
+ (skip-chars-forward " ()")
+ (and (not (or (looking-at "\\<\\(extends\\|with\\)\\>\\|{")
+ (scala-looking-at-special-identifier scala-binding-end-re)))
+ (ignore-errors
+ (save-restriction
+ (narrow-to-region (point-min) limit)
+ (let ((matches (scala-make-match
+ '((scala-forward-ident . t)
+ ((lambda ()
+ (scala-forward-spaces)
+ (when (scala-looking-at-special-identifier ":")
+ (forward-char)
+ (scala-forward-spaces)
+ t)) . nil)
+ (scala-forward-type . t)))))
+ (when (looking-at "\\s *,") (goto-char (match-end 0)))
+ (set-match-data matches)
+ t)))))
+
+(defun scala-match-and-skip-ident (limit)
+ (scala-forward-spaces)
+ (when (and (not (looking-at scala-keywords-re))
+ (looking-at scala-qual-ident-re))
+ (goto-char (match-end 0))
+ t))
+
+(defun scala-match-and-skip-type-args (limit)
+ (when (looking-at (concat "[[,]\\s *\\(" scala-ident-re "\\)?\\]?"))
+ (goto-char (match-end 0))
+ t))
+
+(defun scala-match-and-skip-result-type (limit)
+ (when (looking-at "\\s *:\\s *")
+ (goto-char (match-end 0))
+ (set-match-data (list (point-marker)
+ (progn (scala-forward-type) (point-marker))))
+ t))
+
+(defconst scala-pattern-end-re
+ (regexp-opt '("if" "case" "class") 'words))
+
+(defconst scala-pattern-end-special-re
+ (regexp-opt '( "=>" "=" "<-") t))
+
+(defun scala-match-and-skip-pattern (limit)
+ (while (progn
+ (skip-chars-forward "()[], ")
+ (and (not (or (looking-at scala-pattern-end-re)
+ (scala-looking-at-special-identifier
+ scala-pattern-end-special-re)))
+ (looking-at scala-literal-re)))
+ (goto-char (match-end 0)))
+ (and (not (or (looking-at scala-pattern-end-re)
+ (scala-looking-at-special-identifier scala-pattern-end-special-re)))
+ (let ((case-fold-search nil))
+ (cond ((looking-at scala-capitalized-ident-re)
+ (goto-char (match-end 0)))
+ ((scala-match-and-skip-binding limit) t)))))
+
+(defvar scala-font-lock-keywords
+ `(;; keywords
+ (,scala-keywords-re
+ 1 font-lock-keyword-face nil)
+
+ ;; constants
+ (,scala-constants-re
+ 0 ,(if (boundp 'font-lock-constant-face)
+ 'font-lock-constant-face
+ 'font-lock-keyword-face)
+ nil)
+
+ ;; modules
+ (,(concat "\\<module\\>\\s *\\(" scala-ident-re "\\)")
+ (1 font-lock-variable-name-face nil))
+
+ ;; type definitions
+ (,(concat "\\<type\\>\\s *\\(" scala-ident-re "\\)")
+ (1 font-lock-type-face nil))
+
+ ;; variables
+ ("\\<var\\>"
+ (scala-match-and-skip-binding (goto-char (match-end 0))
+ nil
+ (1 font-lock-variable-name-face nil)
+ (2 font-lock-type-face nil t)))
+
+ ;; functions
+ (,(concat "\\(^\\|[^(,]\\)\\s *\\<def\\>" "\\s *" "\\(" scala-ident-re "\\)\\s *")
+ (2 font-lock-function-name-face nil)
+ (scala-match-and-skip-type-args (goto-char (match-end 0)) nil
+ (1 font-lock-type-face nil t))
+ (scala-match-and-skip-binding nil nil
+ (1 font-lock-variable-name-face nil)
+ (2 font-lock-type-face nil t))
+ (scala-match-and-skip-result-type nil nil
+ (0 font-lock-type-face nil)))
+
+ ;; class definitions
+ ("\\<class\\|trait\\>"
+ (scala-match-and-skip-ident (goto-char (match-end 0)) nil
+ (1 font-lock-type-face nil))
+ (scala-match-and-skip-type-args nil nil
+ (1 font-lock-type-face nil t))
+ (scala-match-and-skip-binding nil nil
+ (1 font-lock-variable-name-face nil)
+ (2 font-lock-type-face nil t)))
+
+ ;; "extends" and "with" clauses
+ ("\\<extends\\|with\\>\\s *[^{]"
+ (scala-match-and-skip-ident (goto-char (1- (match-end 0))) nil
+ (0 font-lock-type-face nil))
+ (scala-match-and-skip-type-args nil nil
+ (1 font-lock-type-face nil t)))
+
+ ;; patterns
+ ("\\<\\(case\\|val\\)\\>\\s *"
+ (scala-match-and-skip-pattern (goto-char (match-end 0)) nil
+ (1 font-lock-variable-name-face nil)
+ (2 font-lock-type-face nil t)))))
+
+
+(defvar scala-font-lock-syntactic-keywords
+ '((scala-search-special-identifier-forward (0 "w" nil t))))
+
+;; Bug reporting
+
+(defun scala-report-bug ()
+ "Report a bug to the author of the Scala mode via e-mail.
+The package used to edit and send the e-mail is the one selected
+through `mail-user-agent'."
+ (interactive)
+ (require 'reporter)
+ (let ((reporter-prompt-for-summary-p t))
+ (reporter-submit-bug-report
+ scala-bug-e-mail
+ (concat "Scala mode v" scala-mode-version)
+ '(scala-indent-step))))
+
+;; Customization
+
+(defun scala-customize ()
+ "Customize Scala mode using the Customize package."
+ (interactive)
+ (customize-group 'scala))
+
+(defun scala-interpreter-running-p ()
+ "True iff a Scala interpreter is currently running in a buffer."
+ ;; The following makes sure that we do not autoload
+ ;; inferior-scala-mode just to check if the interpreter is running.
+ (and (fboundp 'inferior-scala-mode)
+ (let ((ism-def (symbol-function 'inferior-scala-mode)))
+ (not (and (consp ism-def) (eq (car ism-def) 'autoload))))
+ (scala-interpreter-running-p-1)))
+
+(defun scala-browse-web-site ()
+ "Browse the Scala home-page"
+ (interactive)
+ (require 'browse-url)
+ (browse-url scala-web-url))
+
+;;; Mode
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;###autoload
+(define-derived-mode scala-mode fundamental-mode "Scala"
+ "Major mode for editing Scala code.
+
+When started, run `scala-mode-hook'.
+
+\\{scala-mode-map}"
+ ;; Font lock
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults
+ `(scala-font-lock-keywords
+ nil
+ nil
+ ((?\_ . "w"))
+ nil
+ (font-lock-syntactic-keywords . ,scala-font-lock-syntactic-keywords)
+ (parse-sexp-lookup-properties . t)))
+
+ ;; Paragraph separation
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat "^\\s *$\\|" 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)
+
+ ;; Comment handling
+ (make-local-variable 'comment-start)
+ (setq comment-start "// ")
+ (make-local-variable 'comment-end)
+ (setq comment-end "")
+ (make-local-variable 'comment-multi-line)
+ (setq comment-multi-line nil)
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "/\\*+ *\\|//+ *")
+ (make-local-variable 'comment-end-skip)
+ (setq comment-end-skip " *\\*+/\\| *")
+
+ ;; Misc
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function #'scala-indent-line)
+ (make-local-variable 'require-final-newline)
+ (setq require-final-newline t))
+
+
+;; Keymap
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-key scala-mode-map [tab] 'scala-indent-line)
+(define-key scala-mode-map [(control tab)] 'scala-undent-line)
+(define-key scala-mode-map [backspace] 'backward-delete-char-untabify)
+
+(define-key scala-mode-map [(control c)(control l)] 'scala-load-file)
+(define-key scala-mode-map [(control c)(control r)] 'scala-eval-region)
+(define-key scala-mode-map [(control c)(control b)] 'scala-eval-buffer)
+
+(define-key scala-mode-map "}" 'scala-electric-brace)
+
+(easy-menu-define scala-menu-bar scala-mode-map "Scala menu"
+ '("Scala"
+ ["Run interpreter..."
+ run-scala (not (scala-interpreter-running-p))]
+ ["Quit interpreter"
+ scala-quit-interpreter (scala-interpreter-running-p)]
+ ["Load file in interpreter..."
+ scala-load-file (scala-interpreter-running-p)]
+ ["Switch to interpreter"
+ scala-switch-to-interpreter (scala-interpreter-running-p)]
+ ["Evaluate region"
+ scala-eval-region (and (scala-interpreter-running-p)
+ mark-active)]
+ ["Evaluate buffer"
+ scala-eval-buffer (scala-interpreter-running-p)]
+ "---"
+ ["Browse Scala Web site..."
+ scala-browse-web-site t]
+ ["Customize..."
+ scala-customize t]
+ ["Report bug..."
+ scala-report-bug t]))
+
+;; Syntax tables
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; strings and character literals
+(modify-syntax-entry ?\" "\"" scala-mode-syntax-table)
+(modify-syntax-entry ?\' "\"" scala-mode-syntax-table)
+
+;; different kinds of "parenthesis"
+(modify-syntax-entry ?\( "()" scala-mode-syntax-table)
+(modify-syntax-entry ?\[ "(]" scala-mode-syntax-table)
+(modify-syntax-entry ?\{ "(}" scala-mode-syntax-table)
+(modify-syntax-entry ?\) ")(" scala-mode-syntax-table)
+(modify-syntax-entry ?\] ")[" scala-mode-syntax-table)
+(modify-syntax-entry ?\} "){" scala-mode-syntax-table)
+
+;; special characters
+(modify-syntax-entry ?\_ "_" scala-mode-syntax-table)
+
+(dolist (char scala-all-special-chars)
+ (modify-syntax-entry char "." scala-mode-syntax-table))
+(modify-syntax-entry ?\. "." scala-mode-syntax-table)
+
+;; comments
+(modify-syntax-entry ?\/ ". 124b" scala-mode-syntax-table)
+(modify-syntax-entry ?\* ". 23" scala-mode-syntax-table)
+(modify-syntax-entry ?\n "> b" scala-mode-syntax-table)
+(modify-syntax-entry ?\r "> b" scala-mode-syntax-table)
+
+(provide 'scala-mode)