summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-06-14 13:23:46 +0200
committerOndřej Surý <ondrej@sury.org>2012-06-14 13:23:46 +0200
commit917c5fb8ec48e22459d77e3849e6d388f93d3260 (patch)
tree9c23734a6ffd4d2a8ac99502eda3cc812a8b130b /misc
parent0003ee229fd33ff46cb5f2fe1e35f5c0284debc4 (diff)
downloadgolang-917c5fb8ec48e22459d77e3849e6d388f93d3260.tar.gz
Imported Upstream version 1.0.2upstream/1.0.2
Diffstat (limited to 'misc')
-rw-r--r--misc/dashboard/godashboard/app.yaml15
-rw-r--r--misc/dashboard/godashboard/const.py7
-rw-r--r--misc/dashboard/godashboard/index.yaml51
-rw-r--r--misc/dashboard/godashboard/project-edit.html45
-rw-r--r--misc/dashboard/godashboard/project-notify.txt9
-rw-r--r--misc/dashboard/godashboard/project.html74
-rw-r--r--misc/dashboard/godashboard/project.py151
-rw-r--r--misc/dashboard/godashboard/static/favicon.icobin785 -> 0 bytes
-rw-r--r--misc/dashboard/godashboard/static/style.css136
-rw-r--r--misc/dashboard/godashboard/toutf8.py14
-rw-r--r--misc/emacs/go-mode.el151
11 files changed, 110 insertions, 543 deletions
diff --git a/misc/dashboard/godashboard/app.yaml b/misc/dashboard/godashboard/app.yaml
deleted file mode 100644
index ae2892497..000000000
--- a/misc/dashboard/godashboard/app.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-application: godashboard
-version: 9
-runtime: python
-api_version: 1
-
-handlers:
-- url: /favicon\.ico
- static_files: static/favicon.ico
- upload: static/favicon\.ico
-
-- url: /static
- static_dir: static
-
-- url: /(|project(|/login|/edit))
- script: project.py
diff --git a/misc/dashboard/godashboard/const.py b/misc/dashboard/godashboard/const.py
deleted file mode 100644
index d92d32aa9..000000000
--- a/misc/dashboard/godashboard/const.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright 2011 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-mail_from = "Go Dashboard <builder@golang.org>"
-mail_submit_to = "adg@golang.org"
-mail_submit_subject = "New Project Submitted"
diff --git a/misc/dashboard/godashboard/index.yaml b/misc/dashboard/godashboard/index.yaml
deleted file mode 100644
index f39299d5d..000000000
--- a/misc/dashboard/godashboard/index.yaml
+++ /dev/null
@@ -1,51 +0,0 @@
-indexes:
-
-- kind: BenchmarkResult
- ancestor: yes
- properties:
- - name: builder
- - name: __key__
- direction: desc
-
-- kind: BenchmarkResult
- ancestor: yes
- properties:
- - name: __key__
- direction: desc
-
-- kind: BenchmarkResults
- properties:
- - name: builder
- - name: benchmark
-
-- kind: Commit
- properties:
- - name: __key__
- direction: desc
-
-- kind: Commit
- ancestor: yes
- properties:
- - name: __key__
- direction: desc
-
-- kind: Project
- properties:
- - name: approved
- - name: category
- - name: name
-
-- kind: Project
- properties:
- - name: category
- - name: name
-
-# AUTOGENERATED
-
-# This index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run. If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED"). If you want to manage some indexes
-# manually, move them above the marker line. The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
diff --git a/misc/dashboard/godashboard/project-edit.html b/misc/dashboard/godashboard/project-edit.html
deleted file mode 100644
index 8ca5b22a3..000000000
--- a/misc/dashboard/godashboard/project-edit.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<html>
-<head>
-<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="http://www.google.com/jsapi"></script>
-<script>
-google.load("jquery", "1");
-google.load("jqueryui", "1.8.2");
-</script>
-</head>
-<body>
-<form action="/project/edit?orig_name={{p.name}}" method="POST">
-Name:<br/>
-<input type="text" name="name" value="{{p.name|escape}}"><br/>
-Description:<br/>
-<input type="text" name="descr" value="{{p.descr|escape}}"><br/>
-Category:<br/>
-<input type="text" id="cats" name="category" value="{{p.category|escape}}"><br/>
-Tags: (comma-separated)<br/>
-<input type="text" id="tags" name="tags" value="{{tags}}"><br/>
-Web URL:<br/>
-<input type="text" name="web_url" value="{{p.web_url|escape}}"><br/>
-Approved: <input type="checkbox" name="approved" value="1" {% if p.approved %}checked{% endif %}><br/>
-<br/>
-<input type="submit" name="do" value="Save">
-<input type="submit" name="do" value="Delete" onClick="javascript:return confirm('Delete this?');">
-</form>
-<script>
-var tags = [
-{% for t in taglist %}
- "{{t}}"{% if not forloop.last %},{% endif %}
-{% endfor %}
-];
-var cats = [
-{% for c in catlist %}
- "{{c}}"{% if not forloop.last %},{% endif %}
-{% endfor %}
-];
-
-google.setOnLoadCallback(function() {
- $('#tags').autocomplete({source:tags});
- $('#cats').autocomplete({source:cats});
-});
-</script>
-</body>
-</html>
diff --git a/misc/dashboard/godashboard/project-notify.txt b/misc/dashboard/godashboard/project-notify.txt
deleted file mode 100644
index f55bf6421..000000000
--- a/misc/dashboard/godashboard/project-notify.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-A new project has been submitted:
-
-Name: {{project.name}}
-Description: {{project.descr}}
-URL: {{project.web_url}}
-
-To edit/approve/delete:
-http://godashboard.appspot.com/project/edit?name={{project.name|toutf8|urlencode}}
-
diff --git a/misc/dashboard/godashboard/project.html b/misc/dashboard/godashboard/project.html
deleted file mode 100644
index 2d2429461..000000000
--- a/misc/dashboard/godashboard/project.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!DOCTYPE HTML>
-<html>
- <head>
- <title>Go Projects</title>
- <link rel="stylesheet" type="text/css" href="static/style.css">
- </head>
-
- <body>
- <ul class="menu"><li><a href="http://golang.org/">golang.org</a></li></ul>
- <h1>Go Projects</h1>
-
- <p>
- These are external projects and not endorsed or supported by the Go project.
- </p>
-
- <h2>Projects</h2>
-
- <div class="submit">
- <h3>Submit a Project</h3>
- <p>
- Using this form you can submit a project to be included in the list.
- </p>
- <form action="/project" method="POST">
- <table>
- <tr><td>Name:<td><input type="text" name="name">
- <tr><td>Description:<td><input type="text" name="descr">
- <tr><td>URL:<td><input type="text" name="web_url">
- <tr><td>&nbsp;<td><input type="submit" value="Send">
- {% if submitMsg %}
- <tr><td class="msg" colspan="2">{{ submitMsg }}</td></tr>
- {% endif %}
- </table>
- </form>
- </div>
-
- <p>
- Filter by tag:
- {% if tag %}
- <a href="/project">all</a>
- {% else %}
- <b>all</b>
- {% endif %}
- {% for t in tags %}
- {% ifequal t tag %}
- <b>{{t}}</b>
- {% else %}
- <a href="?tag={{t}}">{{t}}</a>
- {% endifequal %}
- {% endfor %}
- </p>
-
- {% for r in projects %}
- {% ifchanged r.category %}
- {% if not forloop.first %}
- </ul>
- {% endif %}
- <h3>{{r.category}}</h3>
- <ul>
- {% endifchanged %}
- <li{% if not r.approved %} class="unapproved"{% endif %}>
- {% if admin %}[<a href="/project/edit?name={{r.name}}">edit</a>]{% endif %}
- <a class="name" href="{{r.web_url}}">{{r.name}}</a> - {{r.descr}}
- {% for tag in r.tags %}
- <span class="tag">{{tag}}</span>
- {% endfor %}
- </li>
- {% if forloop.last %}
- </ul>
- {% endif %}
- {% endfor %}
- </ul>
-
- </body>
-</html>
diff --git a/misc/dashboard/godashboard/project.py b/misc/dashboard/godashboard/project.py
deleted file mode 100644
index b13599d5e..000000000
--- a/misc/dashboard/godashboard/project.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-from google.appengine.api import mail
-from google.appengine.api import memcache
-from google.appengine.api import users
-from google.appengine.ext import db
-from google.appengine.ext import webapp
-from google.appengine.ext.webapp import template
-from google.appengine.ext.webapp.util import run_wsgi_app
-import os
-import sets
-
-# local imports
-import toutf8
-import const
-
-template.register_template_library('toutf8')
-
-class Project(db.Model):
- name = db.StringProperty(indexed=True)
- descr = db.StringProperty()
- web_url = db.StringProperty()
- category = db.StringProperty(indexed=True)
- tags = db.ListProperty(str)
- approved = db.BooleanProperty(indexed=True)
-
-CacheTimeout = 3600
-
-class ProjectPage(webapp.RequestHandler):
-
- def get(self):
- admin = users.is_current_user_admin()
- if self.request.path == "/project/login":
- self.redirect(users.create_login_url("/project"))
- elif self.request.path == "/project/edit" and admin:
- self.edit()
- else:
- self.list()
-
- def post(self):
- if self.request.path == "/project/edit":
- self.edit(True)
- else:
- data = dict(map(lambda x: (x, self.request.get(x)), ["name","descr","web_url"]))
- if reduce(lambda x, y: x or not y, data.values(), False):
- data["submitMsg"] = "You must complete all the fields."
- self.list(data)
- return
- p = Project.get_by_key_name("proj-"+data["name"])
- if p is not None:
- data["submitMsg"] = "A project by this name already exists."
- self.list(data)
- return
- p = Project(key_name="proj-"+data["name"], **data)
- p.put()
-
- path = os.path.join(os.path.dirname(__file__), 'project-notify.txt')
- mail.send_mail(
- sender=const.mail_from,
- to=const.mail_submit_to,
- subject=const.mail_submit_subject,
- body=template.render(path, {'project': p}))
-
- self.list({"submitMsg": "Your project has been submitted."})
-
- def list(self, additional_data={}):
- cache_key = 'view-project-data'
- tag = self.request.get('tag', None)
- if tag:
- cache_key += '-'+tag
- data = memcache.get(cache_key)
- admin = users.is_current_user_admin()
- if admin or not data:
- projects = Project.all().order('category').order('name')
- if not admin:
- projects = projects.filter('approved =', True)
- projects = list(projects)
-
- tags = sets.Set()
- for p in projects:
- for t in p.tags:
- tags.add(t)
-
- if tag:
- projects = filter(lambda x: tag in x.tags, projects)
-
- data = {}
- data['tag'] = tag
- data['tags'] = tags
- data['projects'] = projects
- data['admin']= admin
- if not admin:
- memcache.set(cache_key, data, time=CacheTimeout)
-
- for k, v in additional_data.items():
- data[k] = v
-
- self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
- path = os.path.join(os.path.dirname(__file__), 'project.html')
- self.response.out.write(template.render(path, data))
-
- def edit(self, save=False):
- if save:
- name = self.request.get("orig_name")
- else:
- name = self.request.get("name")
-
- p = Project.get_by_key_name("proj-"+name)
- if not p:
- self.response.out.write("Couldn't find that Project.")
- return
-
- if save:
- if self.request.get("do") == "Delete":
- p.delete()
- else:
- for f in ['name', 'descr', 'web_url', 'category']:
- setattr(p, f, self.request.get(f, None))
- p.approved = self.request.get("approved") == "1"
- p.tags = filter(lambda x: x, self.request.get("tags", "").split(","))
- p.put()
- memcache.delete('view-project-data')
- self.redirect('/project')
- return
-
- # get all project categories and tags
- cats, tags = sets.Set(), sets.Set()
- for r in Project.all():
- cats.add(r.category)
- for t in r.tags:
- tags.add(t)
-
- self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
- path = os.path.join(os.path.dirname(__file__), 'project-edit.html')
- self.response.out.write(template.render(path, {
- "taglist": tags, "catlist": cats, "p": p, "tags": ",".join(p.tags) }))
-
- def redirect(self, url):
- self.response.set_status(302)
- self.response.headers.add_header("Location", url)
-
-def main():
- app = webapp.WSGIApplication([
- ('/.*', ProjectPage),
- ], debug=True)
- run_wsgi_app(app)
-
-if __name__ == '__main__':
- main()
diff --git a/misc/dashboard/godashboard/static/favicon.ico b/misc/dashboard/godashboard/static/favicon.ico
deleted file mode 100644
index 48854ff3b..000000000
--- a/misc/dashboard/godashboard/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/misc/dashboard/godashboard/static/style.css b/misc/dashboard/godashboard/static/style.css
deleted file mode 100644
index ad7038c3d..000000000
--- a/misc/dashboard/godashboard/static/style.css
+++ /dev/null
@@ -1,136 +0,0 @@
-body {
- font-family: sans-serif;
- margin: 0;
- padding: 0;
-}
-h1, h2, h3, ul.menu, table, p {
- padding: 0 0.5em;
-}
-h1, h2 {
- margin: 0;
- background: #eee;
-}
-h1 {
- border-bottom: 1px solid #ccc;
- font-size: 1em;
- padding: 0.5em;
- margin-bottom: 0.5em;
- text-align: right;
-}
-h2 {
- border-top: 1px solid #ccc;
- padding-left: 0.2em;
-}
-.submit {
- float: right;
- border: 1px solid #ccc;
- width: 350px;
- padding-bottom: 1em;
- margin: 0.5em;
- background: #eee;
-}
-.submit table {
- width: 100%;
-}
-.submit input[type=text] {
- width: 200px;
-}
-.submit .msg {
- text-align: center;
- color: red;
-}
-table.alternate {
- white-space: nowrap;
- margin: 0.5em 0;
-}
-table.alternate td,
-table.alternate th {
- padding: 0.1em 0.25em;
- font-size: small;
-}
-table.alternate tr td:last-child {
- padding-right: 0;
-}
-table.alternate tr:nth-child(2n) {
- background-color: #f0f0f0;
-}
-td.result {
- text-align: center;
-}
-span.hash {
- font-family: monospace;
- font-size: small;
- color: #aaa;
-}
-td.date {
- color: #aaa;
-}
-td.ok {
- text-align: center;
- color: #060;
- font-weight: bold;
-}
-td.ok a {
- cursor: help;
-}
-th {
- text-align: left;
-}
-th.builder {
- text-align: center;
- font-weight: bold;
-}
-a.fail {
- color: #F00;
-}
-a.fail:visited {
- color: #900;
-}
-ul.menu {
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-ul.menu li {
- float: left;
- display: block;
- font-size: 1em;
- padding: 0.5em;
- background: #EEF;
- margin-left: 0.5em;
- border-left: 1px solid #999;
- border-right: 1px solid #999;
-}
-div.paginate {
- padding: 0.5em;
-}
-div.paginate a {
- padding: 0.5em;
- margin-right: 0.5em;
- background: #eee;
- color: blue;
-}
-div.paginate a.inactive {
- color: #999;
-}
-td.time {
- font-family: monospace;
-}
-.notice {
- padding: 10px;
- margin: 10px;
- border: 2px solid #FF6;
- background: #900;
- color: white;
- text-align: center;
-}
-.notice a {
- color: #FF6;
-}
-.unapproved a.name {
- color: red;
-}
-.tag {
- font-size: 0.8em;
- color: #666;
-}
diff --git a/misc/dashboard/godashboard/toutf8.py b/misc/dashboard/godashboard/toutf8.py
deleted file mode 100644
index 544c681b6..000000000
--- a/misc/dashboard/godashboard/toutf8.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# This is a Django custom template filter to work around the
-# fact that GAE's urlencode filter doesn't handle unicode strings.
-
-from google.appengine.ext import webapp
-
-register = webapp.template.create_template_register()
-
-@register.filter
-def toutf8(value):
- return value.encode("utf-8")
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index 33ee7022f..214c19685 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -33,8 +33,8 @@
;; Operators (punctuation)
(modify-syntax-entry ?+ "." st)
(modify-syntax-entry ?- "." st)
- (modify-syntax-entry ?* "." st)
- (modify-syntax-entry ?/ "." st)
+ (modify-syntax-entry ?* ". 23" st) ; also part of comments
+ (modify-syntax-entry ?/ (if (featurep 'xemacs) ". 1456" ". 124b") st) ; ditto
(modify-syntax-entry ?% "." st)
(modify-syntax-entry ?& "." st)
(modify-syntax-entry ?| "." st)
@@ -50,6 +50,9 @@
(modify-syntax-entry ?` "." st)
(modify-syntax-entry ?\\ "." st)
+ ;; Newline is a comment-ender.
+ (modify-syntax-entry ?\n "> b" st)
+
st)
"Syntax table for Go mode.")
@@ -179,6 +182,10 @@ to and including character (1- go-mode-mark-comment-end)).")
marked from the beginning up to this point.")
(make-variable-buffer-local 'go-mode-mark-nesting-end)
+(defun go-mode-mark-clear-cs (b e l)
+ "An after-change-function that removes the go-mode-cs text property"
+ (remove-text-properties b e '(go-mode-cs)))
+
(defun go-mode-mark-clear-cache (b e)
"A before-change-function that clears the comment/string and
nesting caches from the modified point on."
@@ -243,8 +250,8 @@ comment or string."
(unless pos
(setq pos (point)))
- (when (> pos go-mode-mark-cs-end)
- (go-mode-mark-cs pos))
+ (when (>= pos go-mode-mark-cs-end)
+ (go-mode-mark-cs (1+ pos)))
(get-text-property pos 'go-mode-cs))
(defun go-mode-mark-cs (end)
@@ -435,7 +442,7 @@ if no further tokens of the type exist."
(when (search-forward "\n" (cdr cs) t)
(put-text-property
(car cs) (cdr cs) 'font-lock-multline t))
- (set-match-data (list (car cs) (cdr cs) (current-buffer)))
+ (set-match-data (list (car cs) (copy-marker (cdr cs))))
(goto-char (cdr cs))
(setq result t))
;; Wrong type. Look for next comment/string after this one.
@@ -545,8 +552,9 @@ token on the line."
(not (looking-at go-mode-non-terminating-keywords-regexp)))))))
(defun go-mode-whitespace-p (char)
- "Is char whitespace in the syntax table for go."
- (eq 32 (char-syntax char)))
+ "Is newline, or char whitespace in the syntax table for go."
+ (or (eq char ?\n)
+ (= (char-syntax char) ?\ )))
(defun go-mode-backward-skip-comments ()
"Skip backward over comments and whitespace."
@@ -589,7 +597,7 @@ indented one level."
(cond
((and cs (save-excursion
(goto-char (car cs))
- (looking-at "\\s\"")))
+ (looking-at "`")))
;; Inside a multi-line string. Don't mess with indentation.
nil)
(cs
@@ -698,13 +706,18 @@ functions, and some types. It also provides indentation that is
;; Remove stale text properties
(save-restriction
(widen)
- (remove-text-properties 1 (point-max)
- '(go-mode-cs nil go-mode-nesting nil)))
+ (let ((modified (buffer-modified-p)))
+ (remove-text-properties 1 (point-max)
+ '(go-mode-cs nil go-mode-nesting nil))
+ ;; remove-text-properties marks the buffer modified. undo that if it
+ ;; wasn't originally marked modified.
+ (set-buffer-modified-p modified)))
;; Reset the syntax mark caches
(setq go-mode-mark-cs-end 1
go-mode-mark-nesting-end 1)
(add-hook 'before-change-functions #'go-mode-mark-clear-cache nil t)
+ (add-hook 'after-change-functions #'go-mode-mark-clear-cs nil t)
;; Indentation
(set (make-local-variable 'indent-line-function)
@@ -716,7 +729,20 @@ functions, and some types. It also provides indentation that is
(set (make-local-variable 'comment-end) "")
;; Go style
- (setq indent-tabs-mode t))
+ (setq indent-tabs-mode t)
+
+ ;; Handle unit test failure output in compilation-mode
+ ;;
+ ;; Note the final t argument to add-to-list for append, ie put these at the
+ ;; *ends* of compilation-error-regexp-alist[-alist]. We want go-test to be
+ ;; handled first, otherwise other elements will match that don't work, and
+ ;; those alists are traversed in *reverse* order:
+ ;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html
+ (when (and (boundp 'compilation-error-regexp-alist)
+ (boundp 'compilation-error-regexp-alist-alist))
+ (add-to-list 'compilation-error-regexp-alist 'go-test t)
+ (add-to-list 'compilation-error-regexp-alist-alist
+ '(go-test . ("^\t+\\([^()\t\n]+\\):\\([0-9]+\\):? .*$" 1 2)) t)))
;;;###autoload
(add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode))
@@ -737,36 +763,79 @@ Replace the current buffer on success; display errors on failure."
(interactive)
(let ((currconf (current-window-configuration)))
- (let ((srcbuf (current-buffer)))
- (with-temp-buffer
- (let ((outbuf (current-buffer))
- (errbuf (get-buffer-create "*Gofmt Errors*"))
- (coding-system-for-read 'utf-8) ;; use utf-8 with subprocesses
- (coding-system-for-write 'utf-8))
- (with-current-buffer errbuf (erase-buffer))
- (with-current-buffer srcbuf
- (save-restriction
- (let (deactivate-mark)
- (widen)
- (if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt"
- outbuf nil errbuf))
- ;; restore window config
- ;; gofmt succeeded: replace the current buffer with outbuf,
- ;; restore the mark and point, and discard errbuf.
- (let ((old-mark (mark t)) (old-point (point)))
- (set-window-configuration currconf)
- (erase-buffer)
- (insert-buffer-substring outbuf)
- (goto-char (min old-point (point-max)))
- (if old-mark (push-mark (min old-mark (point-max)) t))
- (kill-buffer errbuf))
-
- ;; gofmt failed: display the errors
- (display-buffer errbuf)))))
-
- ;; Collapse any window opened on outbuf if shell-command-on-region
- ;; displayed it.
- (delete-windows-on outbuf))))))
+ (let ((srcbuf (current-buffer))
+ (filename buffer-file-name)
+ (patchbuf (get-buffer-create "*Gofmt patch*")))
+ (with-current-buffer patchbuf
+ (let ((errbuf (get-buffer-create "*Gofmt Errors*"))
+ (coding-system-for-read 'utf-8) ;; use utf-8 with subprocesses
+ (coding-system-for-write 'utf-8))
+ (with-current-buffer errbuf
+ (toggle-read-only 0)
+ (erase-buffer))
+ (with-current-buffer srcbuf
+ (save-restriction
+ (let (deactivate-mark)
+ (widen)
+ ; If this is a new file, diff-mode can't apply a
+ ; patch to a non-exisiting file, so replace the buffer
+ ; completely with the output of 'gofmt'.
+ ; If the file exists, patch it to keep the 'undo' list happy.
+ (let* ((newfile (not (file-exists-p filename)))
+ (flag (if newfile "" " -d")))
+ (if (= 0 (shell-command-on-region (point-min) (point-max)
+ (concat "gofmt" flag)
+ patchbuf nil errbuf))
+ ; gofmt succeeded: replace buffer or apply patch hunks.
+ (let ((old-point (point))
+ (old-mark (mark t)))
+ (kill-buffer errbuf)
+ (if newfile
+ ; New file, replace it (diff-mode won't work)
+ (gofmt-replace-buffer srcbuf patchbuf)
+ ; Existing file, patch it
+ (gofmt-apply-patch filename srcbuf patchbuf))
+ (goto-char (min old-point (point-max)))
+ ;; Restore the mark and point
+ (if old-mark (push-mark (min old-mark (point-max)) t))
+ (set-window-configuration currconf))
+
+ ;; gofmt failed: display the errors
+ (gofmt-process-errors filename errbuf))))))
+
+ ;; Collapse any window opened on outbuf if shell-command-on-region
+ ;; displayed it.
+ (delete-windows-on patchbuf)))
+ (kill-buffer patchbuf))))
+
+(defun gofmt-replace-buffer (srcbuf patchbuf)
+ (with-current-buffer srcbuf
+ (erase-buffer)
+ (insert-buffer-substring patchbuf)))
+
+(defconst gofmt-stdin-tag "<standard input>")
+
+(defun gofmt-apply-patch (filename srcbuf patchbuf)
+ (require 'diff-mode)
+ ;; apply all the patch hunks
+ (with-current-buffer patchbuf
+ (replace-regexp "^--- /tmp/gofmt[0-9]*" (concat "--- " filename)
+ nil (point-min) (point-max))
+ (condition-case nil
+ (while t
+ (diff-hunk-next)
+ (diff-apply-hunk))
+ ;; When there's no more hunks, diff-hunk-next signals an error, ignore it
+ (error nil))))
+
+(defun gofmt-process-errors (filename errbuf)
+ ;; Convert the gofmt stderr to something understood by the compilation mode.
+ (with-current-buffer errbuf
+ (beginning-of-buffer)
+ (insert "gofmt errors:\n")
+ (replace-string gofmt-stdin-tag (file-name-nondirectory filename) nil (point-min) (point-max))
+ (display-buffer errbuf)
+ (compilation-mode)))
;;;###autoload
(defun gofmt-before-save ()