-
Notifications
You must be signed in to change notification settings - Fork 211
/
go-rename.el
110 lines (93 loc) · 3.94 KB
/
go-rename.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
;;; go-rename.el --- Integration of the 'gorename' tool into Emacs.
;; Copyright 2014 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.
;; Version: 0.1
;; Package-Requires: ((go-mode "1.3.1"))
;; Keywords: tools
;;; Commentary:
;; To install:
;; % go get golang.org/x/tools/cmd/gorename
;; % go build golang.org/x/tools/cmd/gorename
;; % mv gorename $HOME/bin/ # or elsewhere on $PATH
;; The go-rename-command variable can be customized to specify an
;; alternative location for the installed command.
;;; Code:
(require 'cl-lib)
(require 'compile)
(require 'go-mode)
(require 'thingatpt)
(defgroup go-rename nil
"Options specific to the Go rename."
:group 'go)
(defcustom go-rename-command "gorename"
"The `gorename' command; by the default, $PATH is searched."
:type 'string
:group 'go-rename)
;;;###autoload
(defun go-rename (new-name &optional force)
"Rename the entity denoted by the identifier at point, using
the `gorename' tool. With FORCE, call `gorename' with the
`-force' flag."
(interactive (list
(if (and buffer-file-name (not (buffer-modified-p)))
(read-string "New name: " (thing-at-point 'symbol)))
current-prefix-arg))
(if (not buffer-file-name)
(error "Cannot use go-rename on a buffer without a file name"))
;; It's not sufficient to save the current buffer if modified,
;; since if gofmt-before-save is on the before-save-hook,
;; saving will disturb the selected region.
(if (buffer-modified-p)
(error "Please save the current buffer before invoking go-rename"))
;; Prompt-save all other modified Go buffers, since they might get written.
(save-some-buffers nil #'(lambda ()
(and (buffer-file-name)
(string= (file-name-extension (buffer-file-name)) ".go"))))
(let* ((posflag (format "-offset=%s:#%d"
buffer-file-name
(1- (position-bytes (point)))))
(env-vars (go-root-and-paths))
(goroot-env (concat "GOROOT=" (car env-vars)))
(gopath-env (concat "GOPATH=" (mapconcat #'identity (cdr env-vars) ":")))
success)
(with-current-buffer (get-buffer-create "*go-rename*")
(setq buffer-read-only nil)
(erase-buffer)
(let ((args (append (list go-rename-command nil t nil posflag "-to" new-name) (if force '("-force")))))
;; Log the command to *Messages*, for debugging.
(message "Command: %s:" args)
(message "Running gorename...")
;; Use dynamic binding to modify/restore the environment
(setq success (zerop (let ((process-environment (cl-list* goroot-env gopath-env process-environment)))
(apply #'call-process args))))
(insert "\n")
(compilation-mode)
(setq compilation-error-screen-columns nil)
;; On success, print the one-line result in the message bar,
;; and hide the *go-rename* buffer.
(if success
(progn
(message "%s" (go--buffer-string-no-trailing-space))
(gofmt--kill-error-buffer (current-buffer)))
;; failure
(let ((w (display-buffer (current-buffer))))
(message "gorename exited")
(set-window-point w (point-min)))))))
;; Reload the modified files, saving line/col.
;; (Don't restore the point since the text has changed.)
;;
;; TODO(adonovan): should we also do this for all other files
;; that were updated (the tool can print them)?
(let ((line (line-number-at-pos))
(col (current-column)))
(revert-buffer t t t) ; safe, because we just saved it
(goto-char (point-min))
(forward-line (1- line))
(forward-char col)))
(defun go--buffer-string-no-trailing-space ()
(replace-regexp-in-string "[\t\n ]*\\'"
""
(buffer-substring (point-min) (point-max))))
(provide 'go-rename)
;;; go-rename.el ends here