|
1 """ |
|
2 Runs through a reST file looking for old-style literals, and helps replace them |
|
3 with new-style references. |
|
4 """ |
|
5 |
|
6 import re |
|
7 import sys |
|
8 import shelve |
|
9 |
|
10 refre = re.compile(r'``([^`\s]+?)``') |
|
11 |
|
12 ROLES = ( |
|
13 'attr', |
|
14 'class', |
|
15 "djadmin", |
|
16 'data', |
|
17 'exc', |
|
18 'file', |
|
19 'func', |
|
20 'lookup', |
|
21 'meth', |
|
22 'mod' , |
|
23 "djadminopt", |
|
24 "ref", |
|
25 "setting", |
|
26 "term", |
|
27 "tfilter", |
|
28 "ttag", |
|
29 |
|
30 # special |
|
31 "skip" |
|
32 ) |
|
33 |
|
34 ALWAYS_SKIP = [ |
|
35 "NULL", |
|
36 "True", |
|
37 "False", |
|
38 ] |
|
39 |
|
40 def fixliterals(fname): |
|
41 data = open(fname).read() |
|
42 |
|
43 last = 0 |
|
44 new = [] |
|
45 storage = shelve.open("/tmp/literals_to_xref.shelve") |
|
46 lastvalues = storage.get("lastvalues", {}) |
|
47 |
|
48 for m in refre.finditer(data): |
|
49 |
|
50 new.append(data[last:m.start()]) |
|
51 last = m.end() |
|
52 |
|
53 line_start = data.rfind("\n", 0, m.start()) |
|
54 line_end = data.find("\n", m.end()) |
|
55 prev_start = data.rfind("\n", 0, line_start) |
|
56 next_end = data.find("\n", line_end + 1) |
|
57 |
|
58 # Skip always-skip stuff |
|
59 if m.group(1) in ALWAYS_SKIP: |
|
60 new.append(m.group(0)) |
|
61 continue |
|
62 |
|
63 # skip when the next line is a title |
|
64 next_line = data[m.end():next_end].strip() |
|
65 if next_line[0] in "!-/:-@[-`{-~" and all(c == next_line[0] for c in next_line): |
|
66 new.append(m.group(0)) |
|
67 continue |
|
68 |
|
69 sys.stdout.write("\n"+"-"*80+"\n") |
|
70 sys.stdout.write(data[prev_start+1:m.start()]) |
|
71 sys.stdout.write(colorize(m.group(0), fg="red")) |
|
72 sys.stdout.write(data[m.end():next_end]) |
|
73 sys.stdout.write("\n\n") |
|
74 |
|
75 replace_type = None |
|
76 while replace_type is None: |
|
77 replace_type = raw_input( |
|
78 colorize("Replace role: ", fg="yellow") |
|
79 ).strip().lower() |
|
80 if replace_type and replace_type not in ROLES: |
|
81 replace_type = None |
|
82 |
|
83 if replace_type == "": |
|
84 new.append(m.group(0)) |
|
85 continue |
|
86 |
|
87 if replace_type == "skip": |
|
88 new.append(m.group(0)) |
|
89 ALWAYS_SKIP.append(m.group(1)) |
|
90 continue |
|
91 |
|
92 default = lastvalues.get(m.group(1), m.group(1)) |
|
93 if default.endswith("()") and replace_type in ("class", "func", "meth"): |
|
94 default = default[:-2] |
|
95 replace_value = raw_input( |
|
96 colorize("Text <target> [", fg="yellow") + default + colorize("]: ", fg="yellow") |
|
97 ).strip() |
|
98 if not replace_value: |
|
99 replace_value = default |
|
100 new.append(":%s:`%s`" % (replace_type, replace_value)) |
|
101 lastvalues[m.group(1)] = replace_value |
|
102 |
|
103 new.append(data[last:]) |
|
104 open(fname, "w").write("".join(new)) |
|
105 |
|
106 storage["lastvalues"] = lastvalues |
|
107 storage.close() |
|
108 |
|
109 # |
|
110 # The following is taken from django.utils.termcolors and is copied here to |
|
111 # avoid the dependancy. |
|
112 # |
|
113 |
|
114 |
|
115 def colorize(text='', opts=(), **kwargs): |
|
116 """ |
|
117 Returns your text, enclosed in ANSI graphics codes. |
|
118 |
|
119 Depends on the keyword arguments 'fg' and 'bg', and the contents of |
|
120 the opts tuple/list. |
|
121 |
|
122 Returns the RESET code if no parameters are given. |
|
123 |
|
124 Valid colors: |
|
125 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white' |
|
126 |
|
127 Valid options: |
|
128 'bold' |
|
129 'underscore' |
|
130 'blink' |
|
131 'reverse' |
|
132 'conceal' |
|
133 'noreset' - string will not be auto-terminated with the RESET code |
|
134 |
|
135 Examples: |
|
136 colorize('hello', fg='red', bg='blue', opts=('blink',)) |
|
137 colorize() |
|
138 colorize('goodbye', opts=('underscore',)) |
|
139 print colorize('first line', fg='red', opts=('noreset',)) |
|
140 print 'this should be red too' |
|
141 print colorize('and so should this') |
|
142 print 'this should not be red' |
|
143 """ |
|
144 color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white') |
|
145 foreground = dict([(color_names[x], '3%s' % x) for x in range(8)]) |
|
146 background = dict([(color_names[x], '4%s' % x) for x in range(8)]) |
|
147 |
|
148 RESET = '0' |
|
149 opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'} |
|
150 |
|
151 text = str(text) |
|
152 code_list = [] |
|
153 if text == '' and len(opts) == 1 and opts[0] == 'reset': |
|
154 return '\x1b[%sm' % RESET |
|
155 for k, v in kwargs.iteritems(): |
|
156 if k == 'fg': |
|
157 code_list.append(foreground[v]) |
|
158 elif k == 'bg': |
|
159 code_list.append(background[v]) |
|
160 for o in opts: |
|
161 if o in opt_dict: |
|
162 code_list.append(opt_dict[o]) |
|
163 if 'noreset' not in opts: |
|
164 text = text + '\x1b[%sm' % RESET |
|
165 return ('\x1b[%sm' % ';'.join(code_list)) + text |
|
166 |
|
167 if __name__ == '__main__': |
|
168 try: |
|
169 fixliterals(sys.argv[1]) |
|
170 except (KeyboardInterrupt, SystemExit): |
|
171 print |