Emacs and Go

With this stuff in ~/.emacs, you should get the following features:
  • (not really a feature) a strange delay the first time you open a Go file, while a bunch of dev tools get installed into GOPATH
  • With point on an identifier, M-. jumps to the identifier's definition (M-* returns to original point)
  • Gofmt and goimports get applied automatically when saving
  • Requires gocode goimports and godef
(setq-default indent-tabs-mode nil)

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives
             '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(when (< emacs-major-version 24)
  ;; compatibility libraries like cl-lib                                                                                                                                                                                        
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))
(add-to-list 'package-archives
             '("melpa" . "http://melpa.milkbox.net/packages/") t)
(package-initialize)

(define-key global-map (kbd "RET") 'newline-and-indent)

(setq package-list '(async auto-complete dash
  go-add-tags go-autocomplete go-errcheck go-mode go-playground
  go-rename gotest markdown-mode
  yaml-mode))
(dolist (package package-list)
  (unless (package-installed-p package)
    (message "installing %s..." package)
    (package-install package)))

(defun arvados-gopath ()
  (let ((bfn (buffer-file-name)))
    (setenv "GOPATH" 
            (with-temp-buffer
              (call-process "bash" nil t nil "-c" 
                            "gp=${GOPATH:-${HOME}/go}; d=${0}; while [[ ${d} != '' ]]; do if [[ -e ${d}/services/keep-web/. ]]; then gp=${d}/tmp/GOPATH; mkdir -p ${gp}/src/git.curoverse.com; ln -sfn ${d} ${gp}/src/git.curoverse.com/arvados.git; break; fi; d=${d%/*}; done; mkdir -p ${gp}; echo -n ${gp}" 
                            bfn)
              (buffer-substring (point-min) (point-max))))))

(defun go-mode-omnibus ()
  (let ((gopath (arvados-gopath)))
    (make-local-variable 'process-environment)
    (make-local-variable 'exec-path)
    (add-to-list 'exec-path (concat gopath "/bin"))
    (with-temp-buffer
      (call-process "bash" nil t t "-c" "([[ -x ${1}/bin/gocode ]] && ${1}/bin/goimports -srcdir / /dev/null) || go get -u -v golang.org/x/tools/cmd/... github.com/rogpeppe/godef github.com/nsf/gocode" "-" gopath))
    (auto-complete-mode 1)
                                        ; call gofmt before saving                                                                                                                                                              
    (add-hook 'before-save-hook 'gofmt-before-save)
    (setq gofmt-command "goimports")
                                        ; compile with go                                                                                                                                                                       
    (if (not (string-match "go" compile-command))
        (set (make-local-variable 'compile-command)
             "go build -v && go test -v && go vet"))
                                        ; godef-jump key bindings                                                                                                                                                               
    (local-set-key (kbd "M-.") 'godef-jump)
    (local-set-key (kbd "M-*") 'pop-tag-mark)))
(add-hook 'go-mode-hook 'go-mode-omnibus)