-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathrename-identifier
executable file
·78 lines (71 loc) · 2.81 KB
/
rename-identifier
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
#!/bin/bash
# This came from Gary Bernhardt's dotfiles:
#
# https://github.com/garybernhardt/dotfiles
# This script efficiently bulk-renames identifiers, with confirmation of each
# change. For example, to rename the User class to Person in all files in app
# and lib, do:
#
# rename-identifier User Person {app,lib}/**/*.rb
#
# The arguments are:
#
# 1) The old (current) identifier
# 2) The new identifier (to rename the old one to)
# 3) The files to look in (in the example above, a standard shell glob is
# used).
#
# The script will collect all of the given files that contain the old
# identifier, then open them all in a vim instance. Vim will have two new keys
# mapped:
#
# <leader>j to do a global search and replace from the old to the new
# identifier. This uses :s///c, so it will individually confirm each change.
#
# <leader>k to write the current file and delete the buffer (going to the
# next file). This is for when you're doing renaming in the current file.
#
# For both file searching and vim replacing, word boundaries are used. So, if
# you're replacing "User", and you have a file with the string "Users" but not
# "User", that file won't be matched. If a file containing "Users" also matches
# "User", the vim search/replace still won't hit the "Users" token.
#
# A typical session will look like this (assuming <leader> is ","):
#
# # Run script
# ,j # Trigger rename process in first file
# y # Replace first identifier found
# n # Don't replace second identifier
# # No more matches are found, so Vim drops us back in normal mode
# ,k # Write file and go to the next one
# ,j # Trigger rename process in second file
# # Etc.
#
# This is much more efficient than clumsily typing the ack, then the ":%s",
# then repeatedly saying ":w" to write, ":bd" to close the buffer, ":<up>" to
# recall the search and replace command, etc.
#
# Notes:
#
# Sometimes you need to manually adjust something (e.g., things don't line up
# after an identifier change). That's easy, though: just cancel the
# search/replace with <esc>, make your change, and hit <leader>j to start the
# search/replace over again. This is why there are two maps instead of one.
#
# Despite its name, this isn't limited to single-identifier renames. It will
# happily rename "Day::Range" to "DayRange", behaving as you'd expect, since
# it's simply adding word boundaries to both sides of the string.
set -e
if [ $# -lt 3 ]; then
echo "usage: $(basename $0) old_identifier new_identifier paths ..." >&2
echo "example: rename-identifier User Person {app,lib}/**/*.rb" >&2
exit 1
fi
old=$1
new=$2
shift; shift
files=$*
files=$(ack -l '\b'$old'\b' $files)
leader_j='nnoremap <leader>j :%s/\<'$old'\>/'$new'/gc<cr>'
leader_k='nnoremap <leader>k :update\|:bd<cr>'
vim -c "$leader_j" -c "$leader_k" $files