x/tools/tour: support for golang.org/x/tools/imports.

This adds a new toggle, which, when enabled, uses goimports instead of
gofmt to format and auto-add imports on "format" requests.

Fixes #17886.

Change-Id: I7909e38c4001a372250667ef53a8af42717de200
Reviewed-on: https://go-review.googlesource.com/33202
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Run-TryBot: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/gotour/fmt.go b/gotour/fmt.go
index 8aa3f6f..0a0be16 100644
--- a/gotour/fmt.go
+++ b/gotour/fmt.go
@@ -12,6 +12,8 @@
 	"go/printer"
 	"go/token"
 	"net/http"
+
+	"golang.org/x/tools/imports"
 )
 
 func init() {
@@ -25,7 +27,15 @@
 
 func fmtHandler(w http.ResponseWriter, r *http.Request) {
 	resp := new(fmtResponse)
-	body, err := gofmt(r.FormValue("body"))
+	var body string
+	var err error
+	if r.FormValue("imports") == "true" {
+		var b []byte
+		b, err = imports.Process("prog.go", []byte(r.FormValue("body")), nil)
+		body = string(b)
+	} else {
+		body, err = gofmt(r.FormValue("body"))
+	}
 	if err != nil {
 		resp.Error = err.Error()
 	} else {
diff --git a/static/css/app.css b/static/css/app.css
index ef74c36..1e0f1d8 100755
--- a/static/css/app.css
+++ b/static/css/app.css
@@ -199,6 +199,12 @@
 .menu-button.active {
     background: #fff;
 }
+.menu-button[imports-checkbox]:after {
+    content: ' off';
+}
+.menu-button[imports-checkbox].active:after {
+    content: ' on';
+}
 .menu-button[syntax-checkbox]:after {
     content: ' off';
 }
@@ -243,6 +249,9 @@
     padding-left: 30px;
     background: #fafafa;
 }
+#explorer .imports-checkbox {
+    float: right;
+}
 #explorer .menu-button.active {
     cursor: default;
 }
diff --git a/static/js/controllers.js b/static/js/controllers.js
index 157881e..e035544 100755
--- a/static/js/controllers.js
+++ b/static/js/controllers.js
@@ -96,7 +96,7 @@
 
         $scope.format = function() {
             log('info', i18n.l('waiting'));
-            fmt(file().Content).then(
+            fmt(file().Content, editor.imports).then(
                 function(data) {
                     if (data.data.Error !== '') {
                         log('stderr', data.data.Error);
diff --git a/static/js/directives.js b/static/js/directives.js
index 3740246..d7eb9bc 100755
--- a/static/js/directives.js
+++ b/static/js/directives.js
@@ -48,6 +48,19 @@
     };
 }).
 
+// imports-checkbox activates and deactivates
+directive('importsCheckbox', ['editor',
+    function(editor) {
+        return function(scope, elm) {
+            elm.click(function() {
+                editor.toggleImports();
+                scope.$digest();
+            });
+            scope.editor = editor;
+        };
+    }
+]).
+
 // syntax-checkbox activates and deactivates
 directive('syntaxCheckbox', ['editor',
     function(editor) {
diff --git a/static/js/services.js b/static/js/services.js
index 1152da6..dd4563f 100755
--- a/static/js/services.js
+++ b/static/js/services.js
@@ -61,9 +61,10 @@
 // Formatting code
 factory('fmt', ['$http',
     function($http) {
-        return function(body) {
+        return function(body, imports) {
             var params = $.param({
-                'body': body
+                'body': body,
+                'imports': imports,
             });
             var headers = {
                 'Content-Type': 'application/x-www-form-urlencoded'
@@ -104,6 +105,11 @@
 factory('editor', ['$window', 'storage',
     function(win, storage) {
         var ctx = {
+            imports: storage.get('imports') === 'true',
+            toggleImports: function() {
+                ctx.imports = !ctx.imports;
+                storage.set('imports', ctx.imports);
+            },
             syntax: storage.get('syntax') === 'true',
             toggleSyntax: function() {
                 ctx.syntax = !ctx.syntax;
diff --git a/static/partials/editor.html b/static/partials/editor.html
index 536fb15..15b6e20 100644
--- a/static/partials/editor.html
+++ b/static/partials/editor.html
@@ -17,6 +17,7 @@
             <div id="explorer" ng-class="{hidden: toc.lessons[lessonId].Pages[curPage-1].Files.length==0}">
                 <a class="menu-button" ng-repeat="f in toc.lessons[lessonId].Pages[curPage-1].Files" ng-click="openFile($index)" ng-class="{active: $index==curFile}">{{f.Name}}</a>
                 <a syntax-checkbox ng-class="{active: editor.syntax}" class="menu-button syntax-checkbox">Syntax</a>
+                <a imports-checkbox ng-class="{active: editor.imports}" class="menu-button imports-checkbox">Imports</a>
             </div>
 
             <div class="relative-content" ng-class="{hidden: toc.lessons[lessonId].Pages[curPage-1].Files.length==0}">