Mercurial > public > mercurial-scm > hg
comparison mercurial/formatter.py @ 29836:18bac830eef3
formatter: factor out format*() functions to separate classes
New converter classes will be reused by a nested formatter. See the next
patch for details.
This change is also good in that the default values are defined uniquely
by the baseformatter.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Mon, 15 Aug 2016 13:51:14 +0900 |
parents | 4891f3b93182 |
children | 5b886289a1ca |
comparison
equal
deleted
inserted
replaced
29835:bff109e6398a | 29836:18bac830eef3 |
---|---|
23 util, | 23 util, |
24 ) | 24 ) |
25 | 25 |
26 pickle = util.pickle | 26 pickle = util.pickle |
27 | 27 |
28 class _nullconverter(object): | |
29 '''convert non-primitive data types to be processed by formatter''' | |
30 @staticmethod | |
31 def formatdate(date, fmt): | |
32 '''convert date tuple to appropriate format''' | |
33 return date | |
34 @staticmethod | |
35 def formatdict(data, key, value, fmt, sep): | |
36 '''convert dict or key-value pairs to appropriate dict format''' | |
37 # use plain dict instead of util.sortdict so that data can be | |
38 # serialized as a builtin dict in pickle output | |
39 return dict(data) | |
40 @staticmethod | |
41 def formatlist(data, name, fmt, sep): | |
42 '''convert iterable to appropriate list format''' | |
43 return list(data) | |
44 | |
28 class baseformatter(object): | 45 class baseformatter(object): |
29 def __init__(self, ui, topic, opts): | 46 def __init__(self, ui, topic, opts, converter): |
30 self._ui = ui | 47 self._ui = ui |
31 self._topic = topic | 48 self._topic = topic |
32 self._style = opts.get("style") | 49 self._style = opts.get("style") |
33 self._template = opts.get("template") | 50 self._template = opts.get("template") |
51 self._converter = converter | |
34 self._item = None | 52 self._item = None |
35 # function to convert node to string suitable for this output | 53 # function to convert node to string suitable for this output |
36 self.hexfunc = hex | 54 self.hexfunc = hex |
37 def __nonzero__(self): | 55 def __nonzero__(self): |
38 '''return False if we're not doing real templating so we can | 56 '''return False if we're not doing real templating so we can |
44 def startitem(self): | 62 def startitem(self): |
45 '''begin an item in the format list''' | 63 '''begin an item in the format list''' |
46 if self._item is not None: | 64 if self._item is not None: |
47 self._showitem() | 65 self._showitem() |
48 self._item = {} | 66 self._item = {} |
49 @staticmethod | 67 def formatdate(self, date, fmt='%a %b %d %H:%M:%S %Y %1%2'): |
50 def formatdate(date, fmt='%a %b %d %H:%M:%S %Y %1%2'): | |
51 '''convert date tuple to appropriate format''' | 68 '''convert date tuple to appropriate format''' |
52 return date | 69 return self._converter.formatdate(date, fmt) |
53 @staticmethod | 70 def formatdict(self, data, key='key', value='value', fmt='%s=%s', sep=' '): |
54 def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '): | |
55 '''convert dict or key-value pairs to appropriate dict format''' | 71 '''convert dict or key-value pairs to appropriate dict format''' |
56 # use plain dict instead of util.sortdict so that data can be | 72 return self._converter.formatdict(data, key, value, fmt, sep) |
57 # serialized as a builtin dict in pickle output | 73 def formatlist(self, data, name, fmt='%s', sep=' '): |
58 return dict(data) | |
59 @staticmethod | |
60 def formatlist(data, name, fmt='%s', sep=' '): | |
61 '''convert iterable to appropriate list format''' | 74 '''convert iterable to appropriate list format''' |
62 return list(data) | 75 # name is mandatory argument for now, but it could be optional if |
76 # we have default template keyword, e.g. {item} | |
77 return self._converter.formatlist(data, name, fmt, sep) | |
63 def data(self, **data): | 78 def data(self, **data): |
64 '''insert data into item that's not shown in default output''' | 79 '''insert data into item that's not shown in default output''' |
65 self._item.update(data) | 80 self._item.update(data) |
66 def write(self, fields, deftext, *fielddata, **opts): | 81 def write(self, fields, deftext, *fielddata, **opts): |
67 '''do default text output while assigning data to item''' | 82 '''do default text output while assigning data to item''' |
85 '''iterate key-value pairs in stable order''' | 100 '''iterate key-value pairs in stable order''' |
86 if isinstance(data, dict): | 101 if isinstance(data, dict): |
87 return sorted(data.iteritems()) | 102 return sorted(data.iteritems()) |
88 return data | 103 return data |
89 | 104 |
105 class _plainconverter(object): | |
106 '''convert non-primitive data types to text''' | |
107 @staticmethod | |
108 def formatdate(date, fmt): | |
109 '''stringify date tuple in the given format''' | |
110 return util.datestr(date, fmt) | |
111 @staticmethod | |
112 def formatdict(data, key, value, fmt, sep): | |
113 '''stringify key-value pairs separated by sep''' | |
114 return sep.join(fmt % (k, v) for k, v in _iteritems(data)) | |
115 @staticmethod | |
116 def formatlist(data, name, fmt, sep): | |
117 '''stringify iterable separated by sep''' | |
118 return sep.join(fmt % e for e in data) | |
119 | |
90 class plainformatter(baseformatter): | 120 class plainformatter(baseformatter): |
91 '''the default text output scheme''' | 121 '''the default text output scheme''' |
92 def __init__(self, ui, topic, opts): | 122 def __init__(self, ui, topic, opts): |
93 baseformatter.__init__(self, ui, topic, opts) | 123 baseformatter.__init__(self, ui, topic, opts, _plainconverter) |
94 if ui.debugflag: | 124 if ui.debugflag: |
95 self.hexfunc = hex | 125 self.hexfunc = hex |
96 else: | 126 else: |
97 self.hexfunc = short | 127 self.hexfunc = short |
98 def __nonzero__(self): | 128 def __nonzero__(self): |
99 return False | 129 return False |
100 def startitem(self): | 130 def startitem(self): |
101 pass | 131 pass |
102 @staticmethod | |
103 def formatdate(date, fmt='%a %b %d %H:%M:%S %Y %1%2'): | |
104 '''stringify date tuple in the given format''' | |
105 return util.datestr(date, fmt) | |
106 @staticmethod | |
107 def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '): | |
108 '''stringify key-value pairs separated by sep''' | |
109 return sep.join(fmt % (k, v) for k, v in _iteritems(data)) | |
110 @staticmethod | |
111 def formatlist(data, name, fmt='%s', sep=' '): | |
112 '''stringify iterable separated by sep''' | |
113 return sep.join(fmt % e for e in data) | |
114 def data(self, **data): | 132 def data(self, **data): |
115 pass | 133 pass |
116 def write(self, fields, deftext, *fielddata, **opts): | 134 def write(self, fields, deftext, *fielddata, **opts): |
117 self._ui.write(deftext % fielddata, **opts) | 135 self._ui.write(deftext % fielddata, **opts) |
118 def condwrite(self, cond, fields, deftext, *fielddata, **opts): | 136 def condwrite(self, cond, fields, deftext, *fielddata, **opts): |
124 def end(self): | 142 def end(self): |
125 pass | 143 pass |
126 | 144 |
127 class debugformatter(baseformatter): | 145 class debugformatter(baseformatter): |
128 def __init__(self, ui, topic, opts): | 146 def __init__(self, ui, topic, opts): |
129 baseformatter.__init__(self, ui, topic, opts) | 147 baseformatter.__init__(self, ui, topic, opts, _nullconverter) |
130 self._ui.write("%s = [\n" % self._topic) | 148 self._ui.write("%s = [\n" % self._topic) |
131 def _showitem(self): | 149 def _showitem(self): |
132 self._ui.write(" " + repr(self._item) + ",\n") | 150 self._ui.write(" " + repr(self._item) + ",\n") |
133 def end(self): | 151 def end(self): |
134 baseformatter.end(self) | 152 baseformatter.end(self) |
135 self._ui.write("]\n") | 153 self._ui.write("]\n") |
136 | 154 |
137 class pickleformatter(baseformatter): | 155 class pickleformatter(baseformatter): |
138 def __init__(self, ui, topic, opts): | 156 def __init__(self, ui, topic, opts): |
139 baseformatter.__init__(self, ui, topic, opts) | 157 baseformatter.__init__(self, ui, topic, opts, _nullconverter) |
140 self._data = [] | 158 self._data = [] |
141 def _showitem(self): | 159 def _showitem(self): |
142 self._data.append(self._item) | 160 self._data.append(self._item) |
143 def end(self): | 161 def end(self): |
144 baseformatter.end(self) | 162 baseformatter.end(self) |
162 else: | 180 else: |
163 return '"%s"' % encoding.jsonescape(v) | 181 return '"%s"' % encoding.jsonescape(v) |
164 | 182 |
165 class jsonformatter(baseformatter): | 183 class jsonformatter(baseformatter): |
166 def __init__(self, ui, topic, opts): | 184 def __init__(self, ui, topic, opts): |
167 baseformatter.__init__(self, ui, topic, opts) | 185 baseformatter.__init__(self, ui, topic, opts, _nullconverter) |
168 self._ui.write("[") | 186 self._ui.write("[") |
169 self._ui._first = True | 187 self._ui._first = True |
170 def _showitem(self): | 188 def _showitem(self): |
171 if self._ui._first: | 189 if self._ui._first: |
172 self._ui._first = False | 190 self._ui._first = False |
184 self._ui.write("\n }") | 202 self._ui.write("\n }") |
185 def end(self): | 203 def end(self): |
186 baseformatter.end(self) | 204 baseformatter.end(self) |
187 self._ui.write("\n]\n") | 205 self._ui.write("\n]\n") |
188 | 206 |
189 class templateformatter(baseformatter): | 207 class _templateconverter(object): |
190 def __init__(self, ui, topic, opts): | 208 '''convert non-primitive data types to be processed by templater''' |
191 baseformatter.__init__(self, ui, topic, opts) | 209 @staticmethod |
192 self._topic = topic | 210 def formatdate(date, fmt): |
193 self._t = gettemplater(ui, topic, opts.get('template', '')) | 211 '''return date tuple''' |
194 def _showitem(self): | 212 return date |
195 g = self._t(self._topic, ui=self._ui, **self._item) | 213 @staticmethod |
196 self._ui.write(templater.stringify(g)) | 214 def formatdict(data, key, value, fmt, sep): |
197 @staticmethod | |
198 def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '): | |
199 '''build object that can be evaluated as either plain string or dict''' | 215 '''build object that can be evaluated as either plain string or dict''' |
200 data = util.sortdict(_iteritems(data)) | 216 data = util.sortdict(_iteritems(data)) |
201 def f(): | 217 def f(): |
202 yield plainformatter.formatdict(data, key, value, fmt, sep) | 218 yield _plainconverter.formatdict(data, key, value, fmt, sep) |
203 return templatekw._hybrid(f(), data, lambda k: {key: k, value: data[k]}, | 219 return templatekw._hybrid(f(), data, lambda k: {key: k, value: data[k]}, |
204 lambda d: fmt % (d[key], d[value])) | 220 lambda d: fmt % (d[key], d[value])) |
205 @staticmethod | 221 @staticmethod |
206 def formatlist(data, name, fmt='%s', sep=' '): | 222 def formatlist(data, name, fmt, sep): |
207 '''build object that can be evaluated as either plain string or list''' | 223 '''build object that can be evaluated as either plain string or list''' |
208 # name is mandatory argument for now, but it could be optional if | |
209 # we have default template keyword, e.g. {item} | |
210 data = list(data) | 224 data = list(data) |
211 def f(): | 225 def f(): |
212 yield plainformatter.formatlist(data, name, fmt, sep) | 226 yield _plainconverter.formatlist(data, name, fmt, sep) |
213 return templatekw._hybrid(f(), data, lambda x: {name: x}, | 227 return templatekw._hybrid(f(), data, lambda x: {name: x}, |
214 lambda d: fmt % d[name]) | 228 lambda d: fmt % d[name]) |
229 | |
230 class templateformatter(baseformatter): | |
231 def __init__(self, ui, topic, opts): | |
232 baseformatter.__init__(self, ui, topic, opts, _templateconverter) | |
233 self._topic = topic | |
234 self._t = gettemplater(ui, topic, opts.get('template', '')) | |
235 def _showitem(self): | |
236 g = self._t(self._topic, ui=self._ui, **self._item) | |
237 self._ui.write(templater.stringify(g)) | |
215 | 238 |
216 def lookuptemplate(ui, topic, tmpl): | 239 def lookuptemplate(ui, topic, tmpl): |
217 # looks like a literal template? | 240 # looks like a literal template? |
218 if '{' in tmpl: | 241 if '{' in tmpl: |
219 return tmpl, None | 242 return tmpl, None |