-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontentreplace.py
142 lines (127 loc) · 4.03 KB
/
contentreplace.py
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import argparse
import codecs
import pyperclip
import re
import sys
from voussoirkit import betterhelp
from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import spinal
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'contentreplace')
def contentreplace(file, replace_from, replace_to, autoyes=False, do_regex=False):
file = pathclass.Path(file)
content = file.read('r', encoding='utf-8')
if do_regex:
occurances = len(re.findall(replace_from, content, flags=re.MULTILINE))
else:
occurances = content.count(replace_from)
print(f'{file.absolute_path}: Found {occurances} occurences.')
if occurances == 0:
return
if not (autoyes or interactive.getpermission('Replace?')):
return
if do_regex:
content = re.sub(replace_from, replace_to, content, flags=re.MULTILINE)
else:
content = content.replace(replace_from, replace_to)
file.write('w', content, encoding='utf-8')
@pipeable.ctrlc_return1
def contentreplace_argparse(args):
files = spinal.walk(
glob_filenames=args.filename_glob,
recurse=args.recurse,
)
if args.clip_prompt:
replace_from = input('Ready from')
if not replace_from:
replace_from = pyperclip.paste()
replace_to = input('Ready to')
if not replace_to:
replace_to = pyperclip.paste()
else:
if args.do_regex:
replace_from = args.replace_from
replace_to = args.replace_to
else:
replace_from = codecs.decode(args.replace_from, 'unicode_escape')
replace_to = codecs.decode(args.replace_to, 'unicode_escape')
for file in files:
try:
contentreplace(
file,
replace_from,
replace_to,
autoyes=args.autoyes,
do_regex=args.do_regex,
)
except UnicodeDecodeError:
log.error('%s encountered unicode decode error.', file.absolute_path)
return 0
@vlogging.main_decorator
def main(argv):
parser = argparse.ArgumentParser(
description='''
find-and-replace en masse
''',
)
parser.add_argument(
'filename_glob',
help='''
A glob pattern that targets the files of interest.
''',
)
parser.add_argument(
'replace_from',
help='''
String to be replaced. You can use backslash-escaped symbols like
\\n for newline.
''',
)
parser.add_argument(
'replace_to',
help='''
String with which to replace. Can use backslash-escaped symbols.
''',
)
parser.add_argument(
'--yes',
dest='autoyes',
action='store_true',
help='''
If provided, replacements will occur automatically without prompting.
''',
)
parser.add_argument(
'--recurse',
action='store_true',
help='''
If provided, we will recurse into subdirectories and look for glob matches
there too. If not provided, only files in the cwd are affected.
''',
)
parser.add_argument(
'--regex',
dest='do_regex',
action='store_true',
help='''
If provided, the given replace_from, replace_to will be treated as regex
strings. If not provided, we use regular str.replace.
''',
)
parser.add_argument(
'--clip_prompt',
'--clip-prompt',
action='store_true',
help='''
If you want to do contentreplace with unicode that is difficult to enter
into your terminal, or multi-line strings that don't work as command line
arguments, this option might help you. The program will wait for you to put
the text of interest into your clipboard and press Enter.
''',
)
parser.set_defaults(func=contentreplace_argparse)
return betterhelp.go(parser, argv)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))