branch: elpa/scala-mode
commit 74e51944b4b1cd5e1fe445ccc94573d11314df29
Author: Heikki Vesalainen <heikkivesalai...@yahoo.com>
Commit: Heikki Vesalainen <heikkivesalai...@yahoo.com>

    sbt support for scala-mode2
---
 README.md          |  22 ++++++++++
 scala-mode2-sbt.el | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scala-mode2.el     |   1 +
 3 files changed, 142 insertions(+)

diff --git a/README.md b/README.md
index 2189b32..04f6a69 100644
--- a/README.md
+++ b/README.md
@@ -293,6 +293,28 @@ The commands *forward-sexp* and *backward-sexp* ( 
**M-C-f**, **M-C-b**
 ) motion commands will move over reserved words, literals, ids and
 lists.
 
+# sbt support
+
+To compile your code using sbt, you can use the sbt support.
+
+To begin with, configure *scala-sbt:sbt-command*. The default is
+`sbt`, which is expected to be found on PATH or in your sbt project
+root.
+
+Before you can compile using sbt, you must start it with the
+*scala-sbt:start* command. For this to work, run the command from a
+buffer that is within your project tree.
+
+After you have your sbt running, you can either switch to the `*sbt*`
+buffer to interact with it, or send compile commands using the
+*scala-sbt:command* command. The latter will always clear the `*sbt*`
+buffer and reset errors before running the command.
+
+In you scala buffer, you can use the normal error-navigation commands
+(*next-error*, **C-x \`**, *previous-error*) and in the *sbt* buffer
+you can use the commands from the *compilation-mode* (see **C-h-f
+compilation-mode** for help).
+
 ## Keymap and other commands
 
 For the sake of customizability, scala-mode does not alter the default
diff --git a/scala-mode2-sbt.el b/scala-mode2-sbt.el
new file mode 100644
index 0000000..9bac026
--- /dev/null
+++ b/scala-mode2-sbt.el
@@ -0,0 +1,119 @@
+;;; scala-mode-lib.el - Major mode for editing scala, common functions
+;;; Copyright (c) 2012 Heikki Vesalainen
+;;; For information on the License, see the LICENSE file
+
+(require 'comint)
+
+(defcustom scala-sbt:sbt-command "sbt"
+  "The name of the sbt script to run. This must be either a
+command on path or in the sbt root."
+  :type 'string
+  :group 'scala)
+
+(defcustom scala-sbt:default-command "test:compile"
+  "The default command to run with scala-sbt:command."
+  :type 'string
+  :group 'scala)
+
+(defvar scala-sbt:previous-command scala-sbt:default-command)
+
+(defun scala-sbt:find-root-impl (name-or-pred &optional dir best-root)
+  (when (null dir) (setq dir default-directory))
+  (let ((parent (if (string-match locate-dominating-stop-dir-regexp dir) nil
+                  (file-name-directory (directory-file-name dir)))))
+    (cond ((or (null parent)
+               (equal dir parent))
+           best-root)
+          ((if (stringp name-or-pred)
+               (file-exists-p (expand-file-name name-or-pred dir))
+             (funcall name-or-pred dir))
+           (scala-sbt:find-root-impl name-or-pred parent dir))
+          ('t
+           (scala-sbt:find-root-impl name-or-pred parent best-root)))))
+
+(defun scala-sbt:find-root ()
+  "Starting from the current default-directory, find the top-most
+parent directory that is an sbt root. An sbt root directory is
+identified by the following rules:
+
+  - a directory containing a 'project/build.properties' in it.
+
+  - a directory that contains a file matching one of the patterns
+    '*.sbt' or 'project/*.scala' file in it.
+
+The first rule is applied first and the second is used only if it
+fails to find the sbt root."
+  (or
+   (scala-sbt:find-root-impl "project/build.properties")
+   (scala-sbt:find-root-impl 
+    (lambda (dir) 
+      (or (directory-files dir nil ".+\\.sbt$")
+          (and (file-exists-p (concat dir "project"))
+               (directory-files (concat dir "project") nil ".+\\.scala$")))))))
+
+(defun scala-sbt:start () 
+  "Start sbt in a buffer called *sbt*, stops any existing sbt
+running in the same buffer."
+  (interactive)
+  (let ((project-root (scala-sbt:find-root))
+        (compilation-buffer-name-function (lambda (m) "*sbt*")))
+    (when (null project-root)
+      (error "Could not find project root, type `C-h f scala-sbt:find-root` 
for help."))
+
+    (when (not (or (executable-find scala-sbt:sbt-command)
+                   (file-executable-p (concat project-root 
scala-sbt:sbt-command))))
+      (error "Could not find %s in %s or on PATH" scala-sbt:sbt-command 
project-root))
+                    
+    ;; kill existing sbt
+    (when (get-buffer "*sbt*") (kill-buffer "*sbt*"))
+
+    ;; start new sbt
+    (with-current-buffer (get-buffer-create "*sbt*")
+      (display-buffer (current-buffer))
+      (buffer-disable-undo)
+      (cd project-root)
+      (comint-mode)
+      (compilation-shell-minor-mode)
+      (setq compilation-error-regexp-alist            
+            `((,(rx line-start
+                    ?[ (or (group "error") (group "warn") (group "info")) ?]
+                    " " (group (1+ (not (any ": "))))
+                    ?: (group (1+ digit)) ?:)
+               4 5 nil (2 . 3))))
+                    
+      (comint-exec (current-buffer) "sbt" scala-sbt:sbt-command nil nil))))
+
+(defun scala-sbt:command (&optional command)
+  "Send a command to the sbt running in the '*sbt*'
+buffer. Prompts for the command to send when in interactive
+mode.
+
+This command does the following:
+  - displays the buffer without moving focus to it
+  - erases the buffer
+  - forgets about compilation errors
+
+The command is most usefull for running a compilation command
+that outputs errors."
+  (interactive)
+
+  (when (not (get-buffer "*sbt*"))
+    (message "Running scala-sbt:start ...")
+    (scala-sbt:start)
+    (sit-for 5))
+  
+  (when (null command)
+    (setq command (read-string (format "Command to run (default %s): " 
+                                       scala-sbt:previous-command) 
+                               nil nil scala-sbt:previous-command)))
+
+  (save-some-buffers)
+  (let ((buffer (get-buffer "*sbt*")))
+    (with-current-buffer buffer
+      (display-buffer (current-buffer))
+      (compilation-forget-errors)
+      (erase-buffer)
+      (comint-send-string buffer (concat "\n" command "\n")))
+    (setq scala-sbt:previous-command command)))
+
+(provide 'scala-mode2-sbt)
diff --git a/scala-mode2.el b/scala-mode2.el
index 42f3b40..174c7c7 100644
--- a/scala-mode2.el
+++ b/scala-mode2.el
@@ -11,6 +11,7 @@
 (require 'scala-mode2-indent)
 (require 'scala-mode2-fontlock)
 (require 'scala-mode2-map)
+(require 'scala-mode2-sbt)
 
 ;; Tested only for emacs 24
 (unless (<= 24 emacs-major-version)

Reply via email to