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