##// END OF EJS Templates
formatter: add function to convert list to appropriate format (issue5217)...
Yuya Nishihara -
r29676:c3a9cd78 default
parent child Browse files
Show More
@@ -1,224 +1,243 b''
1 1 # formatter.py - generic output formatting for mercurial
2 2 #
3 3 # Copyright 2012 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import os
11 11
12 12 from .i18n import _
13 13 from .node import (
14 14 hex,
15 15 short,
16 16 )
17 17
18 18 from . import (
19 19 encoding,
20 20 error,
21 templatekw,
21 22 templater,
22 23 util,
23 24 )
24 25
25 26 pickle = util.pickle
26 27
27 28 class baseformatter(object):
28 29 def __init__(self, ui, topic, opts):
29 30 self._ui = ui
30 31 self._topic = topic
31 32 self._style = opts.get("style")
32 33 self._template = opts.get("template")
33 34 self._item = None
34 35 # function to convert node to string suitable for this output
35 36 self.hexfunc = hex
36 37 def __nonzero__(self):
37 38 '''return False if we're not doing real templating so we can
38 39 skip extra work'''
39 40 return True
40 41 def _showitem(self):
41 42 '''show a formatted item once all data is collected'''
42 43 pass
43 44 def startitem(self):
44 45 '''begin an item in the format list'''
45 46 if self._item is not None:
46 47 self._showitem()
47 48 self._item = {}
49 @staticmethod
50 def formatlist(data, name, fmt='%s', sep=' '):
51 '''convert iterable to appropriate list format'''
52 return list(data)
48 53 def data(self, **data):
49 54 '''insert data into item that's not shown in default output'''
50 55 self._item.update(data)
51 56 def write(self, fields, deftext, *fielddata, **opts):
52 57 '''do default text output while assigning data to item'''
53 58 fieldkeys = fields.split()
54 59 assert len(fieldkeys) == len(fielddata)
55 60 self._item.update(zip(fieldkeys, fielddata))
56 61 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
57 62 '''do conditional write (primarily for plain formatter)'''
58 63 fieldkeys = fields.split()
59 64 assert len(fieldkeys) == len(fielddata)
60 65 self._item.update(zip(fieldkeys, fielddata))
61 66 def plain(self, text, **opts):
62 67 '''show raw text for non-templated mode'''
63 68 pass
64 69 def end(self):
65 70 '''end output for the formatter'''
66 71 if self._item is not None:
67 72 self._showitem()
68 73
69 74 class plainformatter(baseformatter):
70 75 '''the default text output scheme'''
71 76 def __init__(self, ui, topic, opts):
72 77 baseformatter.__init__(self, ui, topic, opts)
73 78 if ui.debugflag:
74 79 self.hexfunc = hex
75 80 else:
76 81 self.hexfunc = short
77 82 def __nonzero__(self):
78 83 return False
79 84 def startitem(self):
80 85 pass
86 @staticmethod
87 def formatlist(data, name, fmt='%s', sep=' '):
88 '''stringify iterable separated by sep'''
89 return sep.join(fmt % e for e in data)
81 90 def data(self, **data):
82 91 pass
83 92 def write(self, fields, deftext, *fielddata, **opts):
84 93 self._ui.write(deftext % fielddata, **opts)
85 94 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
86 95 '''do conditional write'''
87 96 if cond:
88 97 self._ui.write(deftext % fielddata, **opts)
89 98 def plain(self, text, **opts):
90 99 self._ui.write(text, **opts)
91 100 def end(self):
92 101 pass
93 102
94 103 class debugformatter(baseformatter):
95 104 def __init__(self, ui, topic, opts):
96 105 baseformatter.__init__(self, ui, topic, opts)
97 106 self._ui.write("%s = [\n" % self._topic)
98 107 def _showitem(self):
99 108 self._ui.write(" " + repr(self._item) + ",\n")
100 109 def end(self):
101 110 baseformatter.end(self)
102 111 self._ui.write("]\n")
103 112
104 113 class pickleformatter(baseformatter):
105 114 def __init__(self, ui, topic, opts):
106 115 baseformatter.__init__(self, ui, topic, opts)
107 116 self._data = []
108 117 def _showitem(self):
109 118 self._data.append(self._item)
110 119 def end(self):
111 120 baseformatter.end(self)
112 121 self._ui.write(pickle.dumps(self._data))
113 122
114 123 def _jsonifyobj(v):
115 if isinstance(v, tuple):
124 if isinstance(v, (list, tuple)):
116 125 return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']'
117 126 elif v is None:
118 127 return 'null'
119 128 elif v is True:
120 129 return 'true'
121 130 elif v is False:
122 131 return 'false'
123 132 elif isinstance(v, (int, float)):
124 133 return str(v)
125 134 else:
126 135 return '"%s"' % encoding.jsonescape(v)
127 136
128 137 class jsonformatter(baseformatter):
129 138 def __init__(self, ui, topic, opts):
130 139 baseformatter.__init__(self, ui, topic, opts)
131 140 self._ui.write("[")
132 141 self._ui._first = True
133 142 def _showitem(self):
134 143 if self._ui._first:
135 144 self._ui._first = False
136 145 else:
137 146 self._ui.write(",")
138 147
139 148 self._ui.write("\n {\n")
140 149 first = True
141 150 for k, v in sorted(self._item.items()):
142 151 if first:
143 152 first = False
144 153 else:
145 154 self._ui.write(",\n")
146 155 self._ui.write(' "%s": %s' % (k, _jsonifyobj(v)))
147 156 self._ui.write("\n }")
148 157 def end(self):
149 158 baseformatter.end(self)
150 159 self._ui.write("\n]\n")
151 160
152 161 class templateformatter(baseformatter):
153 162 def __init__(self, ui, topic, opts):
154 163 baseformatter.__init__(self, ui, topic, opts)
155 164 self._topic = topic
156 165 self._t = gettemplater(ui, topic, opts.get('template', ''))
157 166 def _showitem(self):
158 167 g = self._t(self._topic, ui=self._ui, **self._item)
159 168 self._ui.write(templater.stringify(g))
169 @staticmethod
170 def formatlist(data, name, fmt='%s', sep=' '):
171 '''build object that can be evaluated as either plain string or list'''
172 # name is mandatory argument for now, but it could be optional if
173 # we have default template keyword, e.g. {item}
174 data = list(data)
175 def f():
176 yield plainformatter.formatlist(data, name, fmt, sep)
177 return templatekw._hybrid(f(), data, lambda x: {name: x},
178 lambda d: fmt % d[name])
160 179
161 180 def lookuptemplate(ui, topic, tmpl):
162 181 # looks like a literal template?
163 182 if '{' in tmpl:
164 183 return tmpl, None
165 184
166 185 # perhaps a stock style?
167 186 if not os.path.split(tmpl)[0]:
168 187 mapname = (templater.templatepath('map-cmdline.' + tmpl)
169 188 or templater.templatepath(tmpl))
170 189 if mapname and os.path.isfile(mapname):
171 190 return None, mapname
172 191
173 192 # perhaps it's a reference to [templates]
174 193 t = ui.config('templates', tmpl)
175 194 if t:
176 195 return templater.unquotestring(t), None
177 196
178 197 if tmpl == 'list':
179 198 ui.write(_("available styles: %s\n") % templater.stylelist())
180 199 raise error.Abort(_("specify a template"))
181 200
182 201 # perhaps it's a path to a map or a template
183 202 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
184 203 # is it a mapfile for a style?
185 204 if os.path.basename(tmpl).startswith("map-"):
186 205 return None, os.path.realpath(tmpl)
187 206 tmpl = open(tmpl).read()
188 207 return tmpl, None
189 208
190 209 # constant string?
191 210 return tmpl, None
192 211
193 212 def gettemplater(ui, topic, spec):
194 213 tmpl, mapfile = lookuptemplate(ui, topic, spec)
195 214 assert not (tmpl and mapfile)
196 215 if mapfile:
197 216 return templater.templater.frommapfile(mapfile)
198 217 return maketemplater(ui, topic, tmpl)
199 218
200 219 def maketemplater(ui, topic, tmpl, filters=None, cache=None):
201 220 """Create a templater from a string template 'tmpl'"""
202 221 aliases = ui.configitems('templatealias')
203 222 t = templater.templater(filters=filters, cache=cache, aliases=aliases)
204 223 if tmpl:
205 224 t.cache[topic] = tmpl
206 225 return t
207 226
208 227 def formatter(ui, topic, opts):
209 228 template = opts.get("template", "")
210 229 if template == "json":
211 230 return jsonformatter(ui, topic, opts)
212 231 elif template == "pickle":
213 232 return pickleformatter(ui, topic, opts)
214 233 elif template == "debug":
215 234 return debugformatter(ui, topic, opts)
216 235 elif template != "":
217 236 return templateformatter(ui, topic, opts)
218 237 # developer config: ui.formatdebug
219 238 elif ui.configbool('ui', 'formatdebug'):
220 239 return debugformatter(ui, topic, opts)
221 240 # deprecated config: ui.formatjson
222 241 elif ui.configbool('ui', 'formatjson'):
223 242 return jsonformatter(ui, topic, opts)
224 243 return plainformatter(ui, topic, opts)
General Comments 0
You need to be logged in to leave comments. Login now