diff options
Diffstat (limited to 'support/emacs')
-rw-r--r-- | support/emacs/inferior-scala-mode.el | 115 | ||||
-rw-r--r-- | support/emacs/scala-mode-auto.el | 47 | ||||
-rw-r--r-- | support/emacs/scala-mode.el | 647 |
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) |