Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/templatefuncs.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | d783f945a701 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
48 # dict of template built-in functions | 48 # dict of template built-in functions |
49 funcs = {} | 49 funcs = {} |
50 templatefunc = registrar.templatefunc(funcs) | 50 templatefunc = registrar.templatefunc(funcs) |
51 | 51 |
52 | 52 |
53 @templatefunc('date(date[, fmt])') | 53 @templatefunc(b'date(date[, fmt])') |
54 def date(context, mapping, args): | 54 def date(context, mapping, args): |
55 """Format a date. See :hg:`help dates` for formatting | 55 """Format a date. See :hg:`help dates` for formatting |
56 strings. The default is a Unix date format, including the timezone: | 56 strings. The default is a Unix date format, including the timezone: |
57 "Mon Sep 04 15:13:13 2006 0700".""" | 57 "Mon Sep 04 15:13:13 2006 0700".""" |
58 if not (1 <= len(args) <= 2): | 58 if not (1 <= len(args) <= 2): |
59 # i18n: "date" is a keyword | 59 # i18n: "date" is a keyword |
60 raise error.ParseError(_("date expects one or two arguments")) | 60 raise error.ParseError(_(b"date expects one or two arguments")) |
61 | 61 |
62 date = evaldate( | 62 date = evaldate( |
63 context, | 63 context, |
64 mapping, | 64 mapping, |
65 args[0], | 65 args[0], |
66 # i18n: "date" is a keyword | 66 # i18n: "date" is a keyword |
67 _("date expects a date information"), | 67 _(b"date expects a date information"), |
68 ) | 68 ) |
69 fmt = None | 69 fmt = None |
70 if len(args) == 2: | 70 if len(args) == 2: |
71 fmt = evalstring(context, mapping, args[1]) | 71 fmt = evalstring(context, mapping, args[1]) |
72 if fmt is None: | 72 if fmt is None: |
73 return dateutil.datestr(date) | 73 return dateutil.datestr(date) |
74 else: | 74 else: |
75 return dateutil.datestr(date, fmt) | 75 return dateutil.datestr(date, fmt) |
76 | 76 |
77 | 77 |
78 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs') | 78 @templatefunc(b'dict([[key=]value...])', argspec=b'*args **kwargs') |
79 def dict_(context, mapping, args): | 79 def dict_(context, mapping, args): |
80 """Construct a dict from key-value pairs. A key may be omitted if | 80 """Construct a dict from key-value pairs. A key may be omitted if |
81 a value expression can provide an unambiguous name.""" | 81 a value expression can provide an unambiguous name.""" |
82 data = util.sortdict() | 82 data = util.sortdict() |
83 | 83 |
84 for v in args['args']: | 84 for v in args[b'args']: |
85 k = templateutil.findsymbolicname(v) | 85 k = templateutil.findsymbolicname(v) |
86 if not k: | 86 if not k: |
87 raise error.ParseError(_('dict key cannot be inferred')) | 87 raise error.ParseError(_(b'dict key cannot be inferred')) |
88 if k in data or k in args['kwargs']: | 88 if k in data or k in args[b'kwargs']: |
89 raise error.ParseError(_("duplicated dict key '%s' inferred") % k) | 89 raise error.ParseError(_(b"duplicated dict key '%s' inferred") % k) |
90 data[k] = evalfuncarg(context, mapping, v) | 90 data[k] = evalfuncarg(context, mapping, v) |
91 | 91 |
92 data.update( | 92 data.update( |
93 (k, evalfuncarg(context, mapping, v)) | 93 (k, evalfuncarg(context, mapping, v)) |
94 for k, v in args['kwargs'].iteritems() | 94 for k, v in args[b'kwargs'].iteritems() |
95 ) | 95 ) |
96 return templateutil.hybriddict(data) | 96 return templateutil.hybriddict(data) |
97 | 97 |
98 | 98 |
99 @templatefunc( | 99 @templatefunc( |
100 'diff([includepattern [, excludepattern]])', requires={'ctx', 'ui'} | 100 b'diff([includepattern [, excludepattern]])', requires={b'ctx', b'ui'} |
101 ) | 101 ) |
102 def diff(context, mapping, args): | 102 def diff(context, mapping, args): |
103 """Show a diff, optionally | 103 """Show a diff, optionally |
104 specifying files to include or exclude.""" | 104 specifying files to include or exclude.""" |
105 if len(args) > 2: | 105 if len(args) > 2: |
106 # i18n: "diff" is a keyword | 106 # i18n: "diff" is a keyword |
107 raise error.ParseError(_("diff expects zero, one, or two arguments")) | 107 raise error.ParseError(_(b"diff expects zero, one, or two arguments")) |
108 | 108 |
109 def getpatterns(i): | 109 def getpatterns(i): |
110 if i < len(args): | 110 if i < len(args): |
111 s = evalstring(context, mapping, args[i]).strip() | 111 s = evalstring(context, mapping, args[i]).strip() |
112 if s: | 112 if s: |
113 return [s] | 113 return [s] |
114 return [] | 114 return [] |
115 | 115 |
116 ctx = context.resource(mapping, 'ctx') | 116 ctx = context.resource(mapping, b'ctx') |
117 ui = context.resource(mapping, 'ui') | 117 ui = context.resource(mapping, b'ui') |
118 diffopts = diffutil.diffallopts(ui) | 118 diffopts = diffutil.diffallopts(ui) |
119 chunks = ctx.diff( | 119 chunks = ctx.diff( |
120 match=ctx.match([], getpatterns(0), getpatterns(1)), opts=diffopts | 120 match=ctx.match([], getpatterns(0), getpatterns(1)), opts=diffopts |
121 ) | 121 ) |
122 | 122 |
123 return ''.join(chunks) | 123 return b''.join(chunks) |
124 | 124 |
125 | 125 |
126 @templatefunc('extdata(source)', argspec='source', requires={'ctx', 'cache'}) | 126 @templatefunc( |
127 b'extdata(source)', argspec=b'source', requires={b'ctx', b'cache'} | |
128 ) | |
127 def extdata(context, mapping, args): | 129 def extdata(context, mapping, args): |
128 """Show a text read from the specified extdata source. (EXPERIMENTAL)""" | 130 """Show a text read from the specified extdata source. (EXPERIMENTAL)""" |
129 if 'source' not in args: | 131 if b'source' not in args: |
130 # i18n: "extdata" is a keyword | 132 # i18n: "extdata" is a keyword |
131 raise error.ParseError(_('extdata expects one argument')) | 133 raise error.ParseError(_(b'extdata expects one argument')) |
132 | 134 |
133 source = evalstring(context, mapping, args['source']) | 135 source = evalstring(context, mapping, args[b'source']) |
134 if not source: | 136 if not source: |
135 sym = templateutil.findsymbolicname(args['source']) | 137 sym = templateutil.findsymbolicname(args[b'source']) |
136 if sym: | 138 if sym: |
137 raise error.ParseError( | 139 raise error.ParseError( |
138 _('empty data source specified'), | 140 _(b'empty data source specified'), |
139 hint=_("did you mean extdata('%s')?") % sym, | 141 hint=_(b"did you mean extdata('%s')?") % sym, |
140 ) | 142 ) |
141 else: | 143 else: |
142 raise error.ParseError(_('empty data source specified')) | 144 raise error.ParseError(_(b'empty data source specified')) |
143 cache = context.resource(mapping, 'cache').setdefault('extdata', {}) | 145 cache = context.resource(mapping, b'cache').setdefault(b'extdata', {}) |
144 ctx = context.resource(mapping, 'ctx') | 146 ctx = context.resource(mapping, b'ctx') |
145 if source in cache: | 147 if source in cache: |
146 data = cache[source] | 148 data = cache[source] |
147 else: | 149 else: |
148 data = cache[source] = scmutil.extdatasource(ctx.repo(), source) | 150 data = cache[source] = scmutil.extdatasource(ctx.repo(), source) |
149 return data.get(ctx.rev(), '') | 151 return data.get(ctx.rev(), b'') |
150 | 152 |
151 | 153 |
152 @templatefunc('files(pattern)', requires={'ctx'}) | 154 @templatefunc(b'files(pattern)', requires={b'ctx'}) |
153 def files(context, mapping, args): | 155 def files(context, mapping, args): |
154 """All files of the current changeset matching the pattern. See | 156 """All files of the current changeset matching the pattern. See |
155 :hg:`help patterns`.""" | 157 :hg:`help patterns`.""" |
156 if not len(args) == 1: | 158 if not len(args) == 1: |
157 # i18n: "files" is a keyword | 159 # i18n: "files" is a keyword |
158 raise error.ParseError(_("files expects one argument")) | 160 raise error.ParseError(_(b"files expects one argument")) |
159 | 161 |
160 raw = evalstring(context, mapping, args[0]) | 162 raw = evalstring(context, mapping, args[0]) |
161 ctx = context.resource(mapping, 'ctx') | 163 ctx = context.resource(mapping, b'ctx') |
162 m = ctx.match([raw]) | 164 m = ctx.match([raw]) |
163 files = list(ctx.matches(m)) | 165 files = list(ctx.matches(m)) |
164 return templateutil.compatfileslist(context, mapping, "file", files) | 166 return templateutil.compatfileslist(context, mapping, b"file", files) |
165 | 167 |
166 | 168 |
167 @templatefunc('fill(text[, width[, initialident[, hangindent]]])') | 169 @templatefunc(b'fill(text[, width[, initialident[, hangindent]]])') |
168 def fill(context, mapping, args): | 170 def fill(context, mapping, args): |
169 """Fill many | 171 """Fill many |
170 paragraphs with optional indentation. See the "fill" filter.""" | 172 paragraphs with optional indentation. See the "fill" filter.""" |
171 if not (1 <= len(args) <= 4): | 173 if not (1 <= len(args) <= 4): |
172 # i18n: "fill" is a keyword | 174 # i18n: "fill" is a keyword |
173 raise error.ParseError(_("fill expects one to four arguments")) | 175 raise error.ParseError(_(b"fill expects one to four arguments")) |
174 | 176 |
175 text = evalstring(context, mapping, args[0]) | 177 text = evalstring(context, mapping, args[0]) |
176 width = 76 | 178 width = 76 |
177 initindent = '' | 179 initindent = b'' |
178 hangindent = '' | 180 hangindent = b'' |
179 if 2 <= len(args) <= 4: | 181 if 2 <= len(args) <= 4: |
180 width = evalinteger( | 182 width = evalinteger( |
181 context, | 183 context, |
182 mapping, | 184 mapping, |
183 args[1], | 185 args[1], |
184 # i18n: "fill" is a keyword | 186 # i18n: "fill" is a keyword |
185 _("fill expects an integer width"), | 187 _(b"fill expects an integer width"), |
186 ) | 188 ) |
187 try: | 189 try: |
188 initindent = evalstring(context, mapping, args[2]) | 190 initindent = evalstring(context, mapping, args[2]) |
189 hangindent = evalstring(context, mapping, args[3]) | 191 hangindent = evalstring(context, mapping, args[3]) |
190 except IndexError: | 192 except IndexError: |
191 pass | 193 pass |
192 | 194 |
193 return templatefilters.fill(text, width, initindent, hangindent) | 195 return templatefilters.fill(text, width, initindent, hangindent) |
194 | 196 |
195 | 197 |
196 @templatefunc('filter(iterable[, expr])') | 198 @templatefunc(b'filter(iterable[, expr])') |
197 def filter_(context, mapping, args): | 199 def filter_(context, mapping, args): |
198 """Remove empty elements from a list or a dict. If expr specified, it's | 200 """Remove empty elements from a list or a dict. If expr specified, it's |
199 applied to each element to test emptiness.""" | 201 applied to each element to test emptiness.""" |
200 if not (1 <= len(args) <= 2): | 202 if not (1 <= len(args) <= 2): |
201 # i18n: "filter" is a keyword | 203 # i18n: "filter" is a keyword |
202 raise error.ParseError(_("filter expects one or two arguments")) | 204 raise error.ParseError(_(b"filter expects one or two arguments")) |
203 iterable = evalwrapped(context, mapping, args[0]) | 205 iterable = evalwrapped(context, mapping, args[0]) |
204 if len(args) == 1: | 206 if len(args) == 1: |
205 | 207 |
206 def select(w): | 208 def select(w): |
207 return w.tobool(context, mapping) | 209 return w.tobool(context, mapping) |
208 | 210 |
209 else: | 211 else: |
210 | 212 |
211 def select(w): | 213 def select(w): |
212 if not isinstance(w, templateutil.mappable): | 214 if not isinstance(w, templateutil.mappable): |
213 raise error.ParseError(_("not filterable by expression")) | 215 raise error.ParseError(_(b"not filterable by expression")) |
214 lm = context.overlaymap(mapping, w.tomap(context)) | 216 lm = context.overlaymap(mapping, w.tomap(context)) |
215 return evalboolean(context, lm, args[1]) | 217 return evalboolean(context, lm, args[1]) |
216 | 218 |
217 return iterable.filter(context, mapping, select) | 219 return iterable.filter(context, mapping, select) |
218 | 220 |
219 | 221 |
220 @templatefunc('formatnode(node)', requires={'ui'}) | 222 @templatefunc(b'formatnode(node)', requires={b'ui'}) |
221 def formatnode(context, mapping, args): | 223 def formatnode(context, mapping, args): |
222 """Obtain the preferred form of a changeset hash. (DEPRECATED)""" | 224 """Obtain the preferred form of a changeset hash. (DEPRECATED)""" |
223 if len(args) != 1: | 225 if len(args) != 1: |
224 # i18n: "formatnode" is a keyword | 226 # i18n: "formatnode" is a keyword |
225 raise error.ParseError(_("formatnode expects one argument")) | 227 raise error.ParseError(_(b"formatnode expects one argument")) |
226 | 228 |
227 ui = context.resource(mapping, 'ui') | 229 ui = context.resource(mapping, b'ui') |
228 node = evalstring(context, mapping, args[0]) | 230 node = evalstring(context, mapping, args[0]) |
229 if ui.debugflag: | 231 if ui.debugflag: |
230 return node | 232 return node |
231 return templatefilters.short(node) | 233 return templatefilters.short(node) |
232 | 234 |
233 | 235 |
234 @templatefunc('mailmap(author)', requires={'repo', 'cache'}) | 236 @templatefunc(b'mailmap(author)', requires={b'repo', b'cache'}) |
235 def mailmap(context, mapping, args): | 237 def mailmap(context, mapping, args): |
236 """Return the author, updated according to the value | 238 """Return the author, updated according to the value |
237 set in the .mailmap file""" | 239 set in the .mailmap file""" |
238 if len(args) != 1: | 240 if len(args) != 1: |
239 raise error.ParseError(_("mailmap expects one argument")) | 241 raise error.ParseError(_(b"mailmap expects one argument")) |
240 | 242 |
241 author = evalstring(context, mapping, args[0]) | 243 author = evalstring(context, mapping, args[0]) |
242 | 244 |
243 cache = context.resource(mapping, 'cache') | 245 cache = context.resource(mapping, b'cache') |
244 repo = context.resource(mapping, 'repo') | 246 repo = context.resource(mapping, b'repo') |
245 | 247 |
246 if 'mailmap' not in cache: | 248 if b'mailmap' not in cache: |
247 data = repo.wvfs.tryread('.mailmap') | 249 data = repo.wvfs.tryread(b'.mailmap') |
248 cache['mailmap'] = stringutil.parsemailmap(data) | 250 cache[b'mailmap'] = stringutil.parsemailmap(data) |
249 | 251 |
250 return stringutil.mapname(cache['mailmap'], author) | 252 return stringutil.mapname(cache[b'mailmap'], author) |
251 | 253 |
252 | 254 |
253 @templatefunc( | 255 @templatefunc( |
254 'pad(text, width[, fillchar=\' \'[, left=False[, truncate=False]]])', | 256 b'pad(text, width[, fillchar=\' \'[, left=False[, truncate=False]]])', |
255 argspec='text width fillchar left truncate', | 257 argspec=b'text width fillchar left truncate', |
256 ) | 258 ) |
257 def pad(context, mapping, args): | 259 def pad(context, mapping, args): |
258 """Pad text with a | 260 """Pad text with a |
259 fill character.""" | 261 fill character.""" |
260 if 'text' not in args or 'width' not in args: | 262 if b'text' not in args or b'width' not in args: |
261 # i18n: "pad" is a keyword | 263 # i18n: "pad" is a keyword |
262 raise error.ParseError(_("pad() expects two to four arguments")) | 264 raise error.ParseError(_(b"pad() expects two to four arguments")) |
263 | 265 |
264 width = evalinteger( | 266 width = evalinteger( |
265 context, | 267 context, |
266 mapping, | 268 mapping, |
267 args['width'], | 269 args[b'width'], |
268 # i18n: "pad" is a keyword | 270 # i18n: "pad" is a keyword |
269 _("pad() expects an integer width"), | 271 _(b"pad() expects an integer width"), |
270 ) | 272 ) |
271 | 273 |
272 text = evalstring(context, mapping, args['text']) | 274 text = evalstring(context, mapping, args[b'text']) |
273 | 275 |
274 truncate = False | 276 truncate = False |
275 left = False | 277 left = False |
276 fillchar = ' ' | 278 fillchar = b' ' |
277 if 'fillchar' in args: | 279 if b'fillchar' in args: |
278 fillchar = evalstring(context, mapping, args['fillchar']) | 280 fillchar = evalstring(context, mapping, args[b'fillchar']) |
279 if len(color.stripeffects(fillchar)) != 1: | 281 if len(color.stripeffects(fillchar)) != 1: |
280 # i18n: "pad" is a keyword | 282 # i18n: "pad" is a keyword |
281 raise error.ParseError(_("pad() expects a single fill character")) | 283 raise error.ParseError(_(b"pad() expects a single fill character")) |
282 if 'left' in args: | 284 if b'left' in args: |
283 left = evalboolean(context, mapping, args['left']) | 285 left = evalboolean(context, mapping, args[b'left']) |
284 if 'truncate' in args: | 286 if b'truncate' in args: |
285 truncate = evalboolean(context, mapping, args['truncate']) | 287 truncate = evalboolean(context, mapping, args[b'truncate']) |
286 | 288 |
287 fillwidth = width - encoding.colwidth(color.stripeffects(text)) | 289 fillwidth = width - encoding.colwidth(color.stripeffects(text)) |
288 if fillwidth < 0 and truncate: | 290 if fillwidth < 0 and truncate: |
289 return encoding.trim(color.stripeffects(text), width, leftside=left) | 291 return encoding.trim(color.stripeffects(text), width, leftside=left) |
290 if fillwidth <= 0: | 292 if fillwidth <= 0: |
293 return fillchar * fillwidth + text | 295 return fillchar * fillwidth + text |
294 else: | 296 else: |
295 return text + fillchar * fillwidth | 297 return text + fillchar * fillwidth |
296 | 298 |
297 | 299 |
298 @templatefunc('indent(text, indentchars[, firstline])') | 300 @templatefunc(b'indent(text, indentchars[, firstline])') |
299 def indent(context, mapping, args): | 301 def indent(context, mapping, args): |
300 """Indents all non-empty lines | 302 """Indents all non-empty lines |
301 with the characters given in the indentchars string. An optional | 303 with the characters given in the indentchars string. An optional |
302 third parameter will override the indent for the first line only | 304 third parameter will override the indent for the first line only |
303 if present.""" | 305 if present.""" |
304 if not (2 <= len(args) <= 3): | 306 if not (2 <= len(args) <= 3): |
305 # i18n: "indent" is a keyword | 307 # i18n: "indent" is a keyword |
306 raise error.ParseError(_("indent() expects two or three arguments")) | 308 raise error.ParseError(_(b"indent() expects two or three arguments")) |
307 | 309 |
308 text = evalstring(context, mapping, args[0]) | 310 text = evalstring(context, mapping, args[0]) |
309 indent = evalstring(context, mapping, args[1]) | 311 indent = evalstring(context, mapping, args[1]) |
310 | 312 |
311 if len(args) == 3: | 313 if len(args) == 3: |
315 | 317 |
316 # the indent function doesn't indent the first line, so we do it here | 318 # the indent function doesn't indent the first line, so we do it here |
317 return templatefilters.indent(firstline + text, indent) | 319 return templatefilters.indent(firstline + text, indent) |
318 | 320 |
319 | 321 |
320 @templatefunc('get(dict, key)') | 322 @templatefunc(b'get(dict, key)') |
321 def get(context, mapping, args): | 323 def get(context, mapping, args): |
322 """Get an attribute/key from an object. Some keywords | 324 """Get an attribute/key from an object. Some keywords |
323 are complex types. This function allows you to obtain the value of an | 325 are complex types. This function allows you to obtain the value of an |
324 attribute on these types.""" | 326 attribute on these types.""" |
325 if len(args) != 2: | 327 if len(args) != 2: |
326 # i18n: "get" is a keyword | 328 # i18n: "get" is a keyword |
327 raise error.ParseError(_("get() expects two arguments")) | 329 raise error.ParseError(_(b"get() expects two arguments")) |
328 | 330 |
329 dictarg = evalwrapped(context, mapping, args[0]) | 331 dictarg = evalwrapped(context, mapping, args[0]) |
330 key = evalrawexp(context, mapping, args[1]) | 332 key = evalrawexp(context, mapping, args[1]) |
331 try: | 333 try: |
332 return dictarg.getmember(context, mapping, key) | 334 return dictarg.getmember(context, mapping, key) |
333 except error.ParseError as err: | 335 except error.ParseError as err: |
334 # i18n: "get" is a keyword | 336 # i18n: "get" is a keyword |
335 hint = _("get() expects a dict as first argument") | 337 hint = _(b"get() expects a dict as first argument") |
336 raise error.ParseError(bytes(err), hint=hint) | 338 raise error.ParseError(bytes(err), hint=hint) |
337 | 339 |
338 | 340 |
339 @templatefunc('config(section, name[, default])', requires={'ui'}) | 341 @templatefunc(b'config(section, name[, default])', requires={b'ui'}) |
340 def config(context, mapping, args): | 342 def config(context, mapping, args): |
341 """Returns the requested hgrc config option as a string.""" | 343 """Returns the requested hgrc config option as a string.""" |
342 fn = context.resource(mapping, 'ui').config | 344 fn = context.resource(mapping, b'ui').config |
343 return _config(context, mapping, args, fn, evalstring) | 345 return _config(context, mapping, args, fn, evalstring) |
344 | 346 |
345 | 347 |
346 @templatefunc('configbool(section, name[, default])', requires={'ui'}) | 348 @templatefunc(b'configbool(section, name[, default])', requires={b'ui'}) |
347 def configbool(context, mapping, args): | 349 def configbool(context, mapping, args): |
348 """Returns the requested hgrc config option as a boolean.""" | 350 """Returns the requested hgrc config option as a boolean.""" |
349 fn = context.resource(mapping, 'ui').configbool | 351 fn = context.resource(mapping, b'ui').configbool |
350 return _config(context, mapping, args, fn, evalboolean) | 352 return _config(context, mapping, args, fn, evalboolean) |
351 | 353 |
352 | 354 |
353 @templatefunc('configint(section, name[, default])', requires={'ui'}) | 355 @templatefunc(b'configint(section, name[, default])', requires={b'ui'}) |
354 def configint(context, mapping, args): | 356 def configint(context, mapping, args): |
355 """Returns the requested hgrc config option as an integer.""" | 357 """Returns the requested hgrc config option as an integer.""" |
356 fn = context.resource(mapping, 'ui').configint | 358 fn = context.resource(mapping, b'ui').configint |
357 return _config(context, mapping, args, fn, evalinteger) | 359 return _config(context, mapping, args, fn, evalinteger) |
358 | 360 |
359 | 361 |
360 def _config(context, mapping, args, configfn, defaultfn): | 362 def _config(context, mapping, args, configfn, defaultfn): |
361 if not (2 <= len(args) <= 3): | 363 if not (2 <= len(args) <= 3): |
362 raise error.ParseError(_("config expects two or three arguments")) | 364 raise error.ParseError(_(b"config expects two or three arguments")) |
363 | 365 |
364 # The config option can come from any section, though we specifically | 366 # The config option can come from any section, though we specifically |
365 # reserve the [templateconfig] section for dynamically defining options | 367 # reserve the [templateconfig] section for dynamically defining options |
366 # for this function without also requiring an extension. | 368 # for this function without also requiring an extension. |
367 section = evalstringliteral(context, mapping, args[0]) | 369 section = evalstringliteral(context, mapping, args[0]) |
371 return configfn(section, name, default) | 373 return configfn(section, name, default) |
372 else: | 374 else: |
373 return configfn(section, name) | 375 return configfn(section, name) |
374 | 376 |
375 | 377 |
376 @templatefunc('if(expr, then[, else])') | 378 @templatefunc(b'if(expr, then[, else])') |
377 def if_(context, mapping, args): | 379 def if_(context, mapping, args): |
378 """Conditionally execute based on the result of | 380 """Conditionally execute based on the result of |
379 an expression.""" | 381 an expression.""" |
380 if not (2 <= len(args) <= 3): | 382 if not (2 <= len(args) <= 3): |
381 # i18n: "if" is a keyword | 383 # i18n: "if" is a keyword |
382 raise error.ParseError(_("if expects two or three arguments")) | 384 raise error.ParseError(_(b"if expects two or three arguments")) |
383 | 385 |
384 test = evalboolean(context, mapping, args[0]) | 386 test = evalboolean(context, mapping, args[0]) |
385 if test: | 387 if test: |
386 return evalrawexp(context, mapping, args[1]) | 388 return evalrawexp(context, mapping, args[1]) |
387 elif len(args) == 3: | 389 elif len(args) == 3: |
388 return evalrawexp(context, mapping, args[2]) | 390 return evalrawexp(context, mapping, args[2]) |
389 | 391 |
390 | 392 |
391 @templatefunc('ifcontains(needle, haystack, then[, else])') | 393 @templatefunc(b'ifcontains(needle, haystack, then[, else])') |
392 def ifcontains(context, mapping, args): | 394 def ifcontains(context, mapping, args): |
393 """Conditionally execute based | 395 """Conditionally execute based |
394 on whether the item "needle" is in "haystack".""" | 396 on whether the item "needle" is in "haystack".""" |
395 if not (3 <= len(args) <= 4): | 397 if not (3 <= len(args) <= 4): |
396 # i18n: "ifcontains" is a keyword | 398 # i18n: "ifcontains" is a keyword |
397 raise error.ParseError(_("ifcontains expects three or four arguments")) | 399 raise error.ParseError(_(b"ifcontains expects three or four arguments")) |
398 | 400 |
399 haystack = evalwrapped(context, mapping, args[1]) | 401 haystack = evalwrapped(context, mapping, args[1]) |
400 try: | 402 try: |
401 needle = evalrawexp(context, mapping, args[0]) | 403 needle = evalrawexp(context, mapping, args[0]) |
402 found = haystack.contains(context, mapping, needle) | 404 found = haystack.contains(context, mapping, needle) |
407 return evalrawexp(context, mapping, args[2]) | 409 return evalrawexp(context, mapping, args[2]) |
408 elif len(args) == 4: | 410 elif len(args) == 4: |
409 return evalrawexp(context, mapping, args[3]) | 411 return evalrawexp(context, mapping, args[3]) |
410 | 412 |
411 | 413 |
412 @templatefunc('ifeq(expr1, expr2, then[, else])') | 414 @templatefunc(b'ifeq(expr1, expr2, then[, else])') |
413 def ifeq(context, mapping, args): | 415 def ifeq(context, mapping, args): |
414 """Conditionally execute based on | 416 """Conditionally execute based on |
415 whether 2 items are equivalent.""" | 417 whether 2 items are equivalent.""" |
416 if not (3 <= len(args) <= 4): | 418 if not (3 <= len(args) <= 4): |
417 # i18n: "ifeq" is a keyword | 419 # i18n: "ifeq" is a keyword |
418 raise error.ParseError(_("ifeq expects three or four arguments")) | 420 raise error.ParseError(_(b"ifeq expects three or four arguments")) |
419 | 421 |
420 test = evalstring(context, mapping, args[0]) | 422 test = evalstring(context, mapping, args[0]) |
421 match = evalstring(context, mapping, args[1]) | 423 match = evalstring(context, mapping, args[1]) |
422 if test == match: | 424 if test == match: |
423 return evalrawexp(context, mapping, args[2]) | 425 return evalrawexp(context, mapping, args[2]) |
424 elif len(args) == 4: | 426 elif len(args) == 4: |
425 return evalrawexp(context, mapping, args[3]) | 427 return evalrawexp(context, mapping, args[3]) |
426 | 428 |
427 | 429 |
428 @templatefunc('join(list, sep)') | 430 @templatefunc(b'join(list, sep)') |
429 def join(context, mapping, args): | 431 def join(context, mapping, args): |
430 """Join items in a list with a delimiter.""" | 432 """Join items in a list with a delimiter.""" |
431 if not (1 <= len(args) <= 2): | 433 if not (1 <= len(args) <= 2): |
432 # i18n: "join" is a keyword | 434 # i18n: "join" is a keyword |
433 raise error.ParseError(_("join expects one or two arguments")) | 435 raise error.ParseError(_(b"join expects one or two arguments")) |
434 | 436 |
435 joinset = evalwrapped(context, mapping, args[0]) | 437 joinset = evalwrapped(context, mapping, args[0]) |
436 joiner = " " | 438 joiner = b" " |
437 if len(args) > 1: | 439 if len(args) > 1: |
438 joiner = evalstring(context, mapping, args[1]) | 440 joiner = evalstring(context, mapping, args[1]) |
439 return joinset.join(context, mapping, joiner) | 441 return joinset.join(context, mapping, joiner) |
440 | 442 |
441 | 443 |
442 @templatefunc('label(label, expr)', requires={'ui'}) | 444 @templatefunc(b'label(label, expr)', requires={b'ui'}) |
443 def label(context, mapping, args): | 445 def label(context, mapping, args): |
444 """Apply a label to generated content. Content with | 446 """Apply a label to generated content. Content with |
445 a label applied can result in additional post-processing, such as | 447 a label applied can result in additional post-processing, such as |
446 automatic colorization.""" | 448 automatic colorization.""" |
447 if len(args) != 2: | 449 if len(args) != 2: |
448 # i18n: "label" is a keyword | 450 # i18n: "label" is a keyword |
449 raise error.ParseError(_("label expects two arguments")) | 451 raise error.ParseError(_(b"label expects two arguments")) |
450 | 452 |
451 ui = context.resource(mapping, 'ui') | 453 ui = context.resource(mapping, b'ui') |
452 thing = evalstring(context, mapping, args[1]) | 454 thing = evalstring(context, mapping, args[1]) |
453 # preserve unknown symbol as literal so effects like 'red', 'bold', | 455 # preserve unknown symbol as literal so effects like 'red', 'bold', |
454 # etc. don't need to be quoted | 456 # etc. don't need to be quoted |
455 label = evalstringliteral(context, mapping, args[0]) | 457 label = evalstringliteral(context, mapping, args[0]) |
456 | 458 |
457 return ui.label(thing, label) | 459 return ui.label(thing, label) |
458 | 460 |
459 | 461 |
460 @templatefunc('latesttag([pattern])') | 462 @templatefunc(b'latesttag([pattern])') |
461 def latesttag(context, mapping, args): | 463 def latesttag(context, mapping, args): |
462 """The global tags matching the given pattern on the | 464 """The global tags matching the given pattern on the |
463 most recent globally tagged ancestor of this changeset. | 465 most recent globally tagged ancestor of this changeset. |
464 If no such tags exist, the "{tag}" template resolves to | 466 If no such tags exist, the "{tag}" template resolves to |
465 the string "null". See :hg:`help revisions.patterns` for the pattern | 467 the string "null". See :hg:`help revisions.patterns` for the pattern |
466 syntax. | 468 syntax. |
467 """ | 469 """ |
468 if len(args) > 1: | 470 if len(args) > 1: |
469 # i18n: "latesttag" is a keyword | 471 # i18n: "latesttag" is a keyword |
470 raise error.ParseError(_("latesttag expects at most one argument")) | 472 raise error.ParseError(_(b"latesttag expects at most one argument")) |
471 | 473 |
472 pattern = None | 474 pattern = None |
473 if len(args) == 1: | 475 if len(args) == 1: |
474 pattern = evalstring(context, mapping, args[0]) | 476 pattern = evalstring(context, mapping, args[0]) |
475 return templatekw.showlatesttags(context, mapping, pattern) | 477 return templatekw.showlatesttags(context, mapping, pattern) |
476 | 478 |
477 | 479 |
478 @templatefunc('localdate(date[, tz])') | 480 @templatefunc(b'localdate(date[, tz])') |
479 def localdate(context, mapping, args): | 481 def localdate(context, mapping, args): |
480 """Converts a date to the specified timezone. | 482 """Converts a date to the specified timezone. |
481 The default is local date.""" | 483 The default is local date.""" |
482 if not (1 <= len(args) <= 2): | 484 if not (1 <= len(args) <= 2): |
483 # i18n: "localdate" is a keyword | 485 # i18n: "localdate" is a keyword |
484 raise error.ParseError(_("localdate expects one or two arguments")) | 486 raise error.ParseError(_(b"localdate expects one or two arguments")) |
485 | 487 |
486 date = evaldate( | 488 date = evaldate( |
487 context, | 489 context, |
488 mapping, | 490 mapping, |
489 args[0], | 491 args[0], |
490 # i18n: "localdate" is a keyword | 492 # i18n: "localdate" is a keyword |
491 _("localdate expects a date information"), | 493 _(b"localdate expects a date information"), |
492 ) | 494 ) |
493 if len(args) >= 2: | 495 if len(args) >= 2: |
494 tzoffset = None | 496 tzoffset = None |
495 tz = evalfuncarg(context, mapping, args[1]) | 497 tz = evalfuncarg(context, mapping, args[1]) |
496 if isinstance(tz, bytes): | 498 if isinstance(tz, bytes): |
500 if tzoffset is None: | 502 if tzoffset is None: |
501 try: | 503 try: |
502 tzoffset = int(tz) | 504 tzoffset = int(tz) |
503 except (TypeError, ValueError): | 505 except (TypeError, ValueError): |
504 # i18n: "localdate" is a keyword | 506 # i18n: "localdate" is a keyword |
505 raise error.ParseError(_("localdate expects a timezone")) | 507 raise error.ParseError(_(b"localdate expects a timezone")) |
506 else: | 508 else: |
507 tzoffset = dateutil.makedate()[1] | 509 tzoffset = dateutil.makedate()[1] |
508 return templateutil.date((date[0], tzoffset)) | 510 return templateutil.date((date[0], tzoffset)) |
509 | 511 |
510 | 512 |
511 @templatefunc('max(iterable)') | 513 @templatefunc(b'max(iterable)') |
512 def max_(context, mapping, args, **kwargs): | 514 def max_(context, mapping, args, **kwargs): |
513 """Return the max of an iterable""" | 515 """Return the max of an iterable""" |
514 if len(args) != 1: | 516 if len(args) != 1: |
515 # i18n: "max" is a keyword | 517 # i18n: "max" is a keyword |
516 raise error.ParseError(_("max expects one argument")) | 518 raise error.ParseError(_(b"max expects one argument")) |
517 | 519 |
518 iterable = evalwrapped(context, mapping, args[0]) | 520 iterable = evalwrapped(context, mapping, args[0]) |
519 try: | 521 try: |
520 return iterable.getmax(context, mapping) | 522 return iterable.getmax(context, mapping) |
521 except error.ParseError as err: | 523 except error.ParseError as err: |
522 # i18n: "max" is a keyword | 524 # i18n: "max" is a keyword |
523 hint = _("max first argument should be an iterable") | 525 hint = _(b"max first argument should be an iterable") |
524 raise error.ParseError(bytes(err), hint=hint) | 526 raise error.ParseError(bytes(err), hint=hint) |
525 | 527 |
526 | 528 |
527 @templatefunc('min(iterable)') | 529 @templatefunc(b'min(iterable)') |
528 def min_(context, mapping, args, **kwargs): | 530 def min_(context, mapping, args, **kwargs): |
529 """Return the min of an iterable""" | 531 """Return the min of an iterable""" |
530 if len(args) != 1: | 532 if len(args) != 1: |
531 # i18n: "min" is a keyword | 533 # i18n: "min" is a keyword |
532 raise error.ParseError(_("min expects one argument")) | 534 raise error.ParseError(_(b"min expects one argument")) |
533 | 535 |
534 iterable = evalwrapped(context, mapping, args[0]) | 536 iterable = evalwrapped(context, mapping, args[0]) |
535 try: | 537 try: |
536 return iterable.getmin(context, mapping) | 538 return iterable.getmin(context, mapping) |
537 except error.ParseError as err: | 539 except error.ParseError as err: |
538 # i18n: "min" is a keyword | 540 # i18n: "min" is a keyword |
539 hint = _("min first argument should be an iterable") | 541 hint = _(b"min first argument should be an iterable") |
540 raise error.ParseError(bytes(err), hint=hint) | 542 raise error.ParseError(bytes(err), hint=hint) |
541 | 543 |
542 | 544 |
543 @templatefunc('mod(a, b)') | 545 @templatefunc(b'mod(a, b)') |
544 def mod(context, mapping, args): | 546 def mod(context, mapping, args): |
545 """Calculate a mod b such that a / b + a mod b == a""" | 547 """Calculate a mod b such that a / b + a mod b == a""" |
546 if not len(args) == 2: | 548 if not len(args) == 2: |
547 # i18n: "mod" is a keyword | 549 # i18n: "mod" is a keyword |
548 raise error.ParseError(_("mod expects two arguments")) | 550 raise error.ParseError(_(b"mod expects two arguments")) |
549 | 551 |
550 func = lambda a, b: a % b | 552 func = lambda a, b: a % b |
551 return templateutil.runarithmetic( | 553 return templateutil.runarithmetic( |
552 context, mapping, (func, args[0], args[1]) | 554 context, mapping, (func, args[0], args[1]) |
553 ) | 555 ) |
554 | 556 |
555 | 557 |
556 @templatefunc('obsfateoperations(markers)') | 558 @templatefunc(b'obsfateoperations(markers)') |
557 def obsfateoperations(context, mapping, args): | 559 def obsfateoperations(context, mapping, args): |
558 """Compute obsfate related information based on markers (EXPERIMENTAL)""" | 560 """Compute obsfate related information based on markers (EXPERIMENTAL)""" |
559 if len(args) != 1: | 561 if len(args) != 1: |
560 # i18n: "obsfateoperations" is a keyword | 562 # i18n: "obsfateoperations" is a keyword |
561 raise error.ParseError(_("obsfateoperations expects one argument")) | 563 raise error.ParseError(_(b"obsfateoperations expects one argument")) |
562 | 564 |
563 markers = evalfuncarg(context, mapping, args[0]) | 565 markers = evalfuncarg(context, mapping, args[0]) |
564 | 566 |
565 try: | 567 try: |
566 data = obsutil.markersoperations(markers) | 568 data = obsutil.markersoperations(markers) |
567 return templateutil.hybridlist(data, name='operation') | 569 return templateutil.hybridlist(data, name=b'operation') |
568 except (TypeError, KeyError): | 570 except (TypeError, KeyError): |
569 # i18n: "obsfateoperations" is a keyword | 571 # i18n: "obsfateoperations" is a keyword |
570 errmsg = _("obsfateoperations first argument should be an iterable") | 572 errmsg = _(b"obsfateoperations first argument should be an iterable") |
571 raise error.ParseError(errmsg) | 573 raise error.ParseError(errmsg) |
572 | 574 |
573 | 575 |
574 @templatefunc('obsfatedate(markers)') | 576 @templatefunc(b'obsfatedate(markers)') |
575 def obsfatedate(context, mapping, args): | 577 def obsfatedate(context, mapping, args): |
576 """Compute obsfate related information based on markers (EXPERIMENTAL)""" | 578 """Compute obsfate related information based on markers (EXPERIMENTAL)""" |
577 if len(args) != 1: | 579 if len(args) != 1: |
578 # i18n: "obsfatedate" is a keyword | 580 # i18n: "obsfatedate" is a keyword |
579 raise error.ParseError(_("obsfatedate expects one argument")) | 581 raise error.ParseError(_(b"obsfatedate expects one argument")) |
580 | 582 |
581 markers = evalfuncarg(context, mapping, args[0]) | 583 markers = evalfuncarg(context, mapping, args[0]) |
582 | 584 |
583 try: | 585 try: |
584 # TODO: maybe this has to be a wrapped list of date wrappers? | 586 # TODO: maybe this has to be a wrapped list of date wrappers? |
585 data = obsutil.markersdates(markers) | 587 data = obsutil.markersdates(markers) |
586 return templateutil.hybridlist(data, name='date', fmt='%d %d') | 588 return templateutil.hybridlist(data, name=b'date', fmt=b'%d %d') |
587 except (TypeError, KeyError): | 589 except (TypeError, KeyError): |
588 # i18n: "obsfatedate" is a keyword | 590 # i18n: "obsfatedate" is a keyword |
589 errmsg = _("obsfatedate first argument should be an iterable") | 591 errmsg = _(b"obsfatedate first argument should be an iterable") |
590 raise error.ParseError(errmsg) | 592 raise error.ParseError(errmsg) |
591 | 593 |
592 | 594 |
593 @templatefunc('obsfateusers(markers)') | 595 @templatefunc(b'obsfateusers(markers)') |
594 def obsfateusers(context, mapping, args): | 596 def obsfateusers(context, mapping, args): |
595 """Compute obsfate related information based on markers (EXPERIMENTAL)""" | 597 """Compute obsfate related information based on markers (EXPERIMENTAL)""" |
596 if len(args) != 1: | 598 if len(args) != 1: |
597 # i18n: "obsfateusers" is a keyword | 599 # i18n: "obsfateusers" is a keyword |
598 raise error.ParseError(_("obsfateusers expects one argument")) | 600 raise error.ParseError(_(b"obsfateusers expects one argument")) |
599 | 601 |
600 markers = evalfuncarg(context, mapping, args[0]) | 602 markers = evalfuncarg(context, mapping, args[0]) |
601 | 603 |
602 try: | 604 try: |
603 data = obsutil.markersusers(markers) | 605 data = obsutil.markersusers(markers) |
604 return templateutil.hybridlist(data, name='user') | 606 return templateutil.hybridlist(data, name=b'user') |
605 except (TypeError, KeyError, ValueError): | 607 except (TypeError, KeyError, ValueError): |
606 # i18n: "obsfateusers" is a keyword | 608 # i18n: "obsfateusers" is a keyword |
607 msg = _( | 609 msg = _( |
608 "obsfateusers first argument should be an iterable of " "obsmakers" | 610 b"obsfateusers first argument should be an iterable of " |
611 b"obsmakers" | |
609 ) | 612 ) |
610 raise error.ParseError(msg) | 613 raise error.ParseError(msg) |
611 | 614 |
612 | 615 |
613 @templatefunc('obsfateverb(successors, markers)') | 616 @templatefunc(b'obsfateverb(successors, markers)') |
614 def obsfateverb(context, mapping, args): | 617 def obsfateverb(context, mapping, args): |
615 """Compute obsfate related information based on successors (EXPERIMENTAL)""" | 618 """Compute obsfate related information based on successors (EXPERIMENTAL)""" |
616 if len(args) != 2: | 619 if len(args) != 2: |
617 # i18n: "obsfateverb" is a keyword | 620 # i18n: "obsfateverb" is a keyword |
618 raise error.ParseError(_("obsfateverb expects two arguments")) | 621 raise error.ParseError(_(b"obsfateverb expects two arguments")) |
619 | 622 |
620 successors = evalfuncarg(context, mapping, args[0]) | 623 successors = evalfuncarg(context, mapping, args[0]) |
621 markers = evalfuncarg(context, mapping, args[1]) | 624 markers = evalfuncarg(context, mapping, args[1]) |
622 | 625 |
623 try: | 626 try: |
624 return obsutil.obsfateverb(successors, markers) | 627 return obsutil.obsfateverb(successors, markers) |
625 except TypeError: | 628 except TypeError: |
626 # i18n: "obsfateverb" is a keyword | 629 # i18n: "obsfateverb" is a keyword |
627 errmsg = _("obsfateverb first argument should be countable") | 630 errmsg = _(b"obsfateverb first argument should be countable") |
628 raise error.ParseError(errmsg) | 631 raise error.ParseError(errmsg) |
629 | 632 |
630 | 633 |
631 @templatefunc('relpath(path)', requires={'repo'}) | 634 @templatefunc(b'relpath(path)', requires={b'repo'}) |
632 def relpath(context, mapping, args): | 635 def relpath(context, mapping, args): |
633 """Convert a repository-absolute path into a filesystem path relative to | 636 """Convert a repository-absolute path into a filesystem path relative to |
634 the current working directory.""" | 637 the current working directory.""" |
635 if len(args) != 1: | 638 if len(args) != 1: |
636 # i18n: "relpath" is a keyword | 639 # i18n: "relpath" is a keyword |
637 raise error.ParseError(_("relpath expects one argument")) | 640 raise error.ParseError(_(b"relpath expects one argument")) |
638 | 641 |
639 repo = context.resource(mapping, 'repo') | 642 repo = context.resource(mapping, b'repo') |
640 path = evalstring(context, mapping, args[0]) | 643 path = evalstring(context, mapping, args[0]) |
641 return repo.pathto(path) | 644 return repo.pathto(path) |
642 | 645 |
643 | 646 |
644 @templatefunc('revset(query[, formatargs...])', requires={'repo', 'cache'}) | 647 @templatefunc(b'revset(query[, formatargs...])', requires={b'repo', b'cache'}) |
645 def revset(context, mapping, args): | 648 def revset(context, mapping, args): |
646 """Execute a revision set query. See | 649 """Execute a revision set query. See |
647 :hg:`help revset`.""" | 650 :hg:`help revset`.""" |
648 if not len(args) > 0: | 651 if not len(args) > 0: |
649 # i18n: "revset" is a keyword | 652 # i18n: "revset" is a keyword |
650 raise error.ParseError(_("revset expects one or more arguments")) | 653 raise error.ParseError(_(b"revset expects one or more arguments")) |
651 | 654 |
652 raw = evalstring(context, mapping, args[0]) | 655 raw = evalstring(context, mapping, args[0]) |
653 repo = context.resource(mapping, 'repo') | 656 repo = context.resource(mapping, b'repo') |
654 | 657 |
655 def query(expr): | 658 def query(expr): |
656 m = revsetmod.match(repo.ui, expr, lookup=revsetmod.lookupfn(repo)) | 659 m = revsetmod.match(repo.ui, expr, lookup=revsetmod.lookupfn(repo)) |
657 return m(repo) | 660 return m(repo) |
658 | 661 |
659 if len(args) > 1: | 662 if len(args) > 1: |
660 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]] | 663 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]] |
661 revs = query(revsetlang.formatspec(raw, *formatargs)) | 664 revs = query(revsetlang.formatspec(raw, *formatargs)) |
662 else: | 665 else: |
663 cache = context.resource(mapping, 'cache') | 666 cache = context.resource(mapping, b'cache') |
664 revsetcache = cache.setdefault("revsetcache", {}) | 667 revsetcache = cache.setdefault(b"revsetcache", {}) |
665 if raw in revsetcache: | 668 if raw in revsetcache: |
666 revs = revsetcache[raw] | 669 revs = revsetcache[raw] |
667 else: | 670 else: |
668 revs = query(raw) | 671 revs = query(raw) |
669 revsetcache[raw] = revs | 672 revsetcache[raw] = revs |
670 return templatekw.showrevslist(context, mapping, "revision", revs) | 673 return templatekw.showrevslist(context, mapping, b"revision", revs) |
671 | 674 |
672 | 675 |
673 @templatefunc('rstdoc(text, style)') | 676 @templatefunc(b'rstdoc(text, style)') |
674 def rstdoc(context, mapping, args): | 677 def rstdoc(context, mapping, args): |
675 """Format reStructuredText.""" | 678 """Format reStructuredText.""" |
676 if len(args) != 2: | 679 if len(args) != 2: |
677 # i18n: "rstdoc" is a keyword | 680 # i18n: "rstdoc" is a keyword |
678 raise error.ParseError(_("rstdoc expects two arguments")) | 681 raise error.ParseError(_(b"rstdoc expects two arguments")) |
679 | 682 |
680 text = evalstring(context, mapping, args[0]) | 683 text = evalstring(context, mapping, args[0]) |
681 style = evalstring(context, mapping, args[1]) | 684 style = evalstring(context, mapping, args[1]) |
682 | 685 |
683 return minirst.format(text, style=style, keep=['verbose']) | 686 return minirst.format(text, style=style, keep=[b'verbose']) |
684 | 687 |
685 | 688 |
686 @templatefunc('search(pattern, text)') | 689 @templatefunc(b'search(pattern, text)') |
687 def search(context, mapping, args): | 690 def search(context, mapping, args): |
688 """Look for the first text matching the regular expression pattern. | 691 """Look for the first text matching the regular expression pattern. |
689 Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template.""" | 692 Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template.""" |
690 if len(args) != 2: | 693 if len(args) != 2: |
691 # i18n: "search" is a keyword | 694 # i18n: "search" is a keyword |
705 if badgroups: | 708 if badgroups: |
706 raise error.ParseError( | 709 raise error.ParseError( |
707 # i18n: "search" is a keyword | 710 # i18n: "search" is a keyword |
708 _(b'invalid group %(group)s in search pattern: %(pat)s') | 711 _(b'invalid group %(group)s in search pattern: %(pat)s') |
709 % { | 712 % { |
710 b'group': b', '.join("'%s'" % g for g in sorted(badgroups)), | 713 b'group': b', '.join(b"'%s'" % g for g in sorted(badgroups)), |
711 b'pat': pat, | 714 b'pat': pat, |
712 } | 715 } |
713 ) | 716 ) |
714 | 717 |
715 match = patre.search(src) | 718 match = patre.search(src) |
720 lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1)) | 723 lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1)) |
721 lm.update(pycompat.byteskwargs(match.groupdict())) | 724 lm.update(pycompat.byteskwargs(match.groupdict())) |
722 return templateutil.mappingdict(lm, tmpl=b'{0}') | 725 return templateutil.mappingdict(lm, tmpl=b'{0}') |
723 | 726 |
724 | 727 |
725 @templatefunc('separate(sep, args...)', argspec='sep *args') | 728 @templatefunc(b'separate(sep, args...)', argspec=b'sep *args') |
726 def separate(context, mapping, args): | 729 def separate(context, mapping, args): |
727 """Add a separator between non-empty arguments.""" | 730 """Add a separator between non-empty arguments.""" |
728 if 'sep' not in args: | 731 if b'sep' not in args: |
729 # i18n: "separate" is a keyword | 732 # i18n: "separate" is a keyword |
730 raise error.ParseError(_("separate expects at least one argument")) | 733 raise error.ParseError(_(b"separate expects at least one argument")) |
731 | 734 |
732 sep = evalstring(context, mapping, args['sep']) | 735 sep = evalstring(context, mapping, args[b'sep']) |
733 first = True | 736 first = True |
734 for arg in args['args']: | 737 for arg in args[b'args']: |
735 argstr = evalstring(context, mapping, arg) | 738 argstr = evalstring(context, mapping, arg) |
736 if not argstr: | 739 if not argstr: |
737 continue | 740 continue |
738 if first: | 741 if first: |
739 first = False | 742 first = False |
740 else: | 743 else: |
741 yield sep | 744 yield sep |
742 yield argstr | 745 yield argstr |
743 | 746 |
744 | 747 |
745 @templatefunc('shortest(node, minlength=4)', requires={'repo', 'cache'}) | 748 @templatefunc(b'shortest(node, minlength=4)', requires={b'repo', b'cache'}) |
746 def shortest(context, mapping, args): | 749 def shortest(context, mapping, args): |
747 """Obtain the shortest representation of | 750 """Obtain the shortest representation of |
748 a node.""" | 751 a node.""" |
749 if not (1 <= len(args) <= 2): | 752 if not (1 <= len(args) <= 2): |
750 # i18n: "shortest" is a keyword | 753 # i18n: "shortest" is a keyword |
751 raise error.ParseError(_("shortest() expects one or two arguments")) | 754 raise error.ParseError(_(b"shortest() expects one or two arguments")) |
752 | 755 |
753 hexnode = evalstring(context, mapping, args[0]) | 756 hexnode = evalstring(context, mapping, args[0]) |
754 | 757 |
755 minlength = 4 | 758 minlength = 4 |
756 if len(args) > 1: | 759 if len(args) > 1: |
757 minlength = evalinteger( | 760 minlength = evalinteger( |
758 context, | 761 context, |
759 mapping, | 762 mapping, |
760 args[1], | 763 args[1], |
761 # i18n: "shortest" is a keyword | 764 # i18n: "shortest" is a keyword |
762 _("shortest() expects an integer minlength"), | 765 _(b"shortest() expects an integer minlength"), |
763 ) | 766 ) |
764 | 767 |
765 repo = context.resource(mapping, 'repo') | 768 repo = context.resource(mapping, b'repo') |
766 if len(hexnode) > 40: | 769 if len(hexnode) > 40: |
767 return hexnode | 770 return hexnode |
768 elif len(hexnode) == 40: | 771 elif len(hexnode) == 40: |
769 try: | 772 try: |
770 node = bin(hexnode) | 773 node = bin(hexnode) |
777 node = wdirid | 780 node = wdirid |
778 except error.LookupError: | 781 except error.LookupError: |
779 return hexnode | 782 return hexnode |
780 if not node: | 783 if not node: |
781 return hexnode | 784 return hexnode |
782 cache = context.resource(mapping, 'cache') | 785 cache = context.resource(mapping, b'cache') |
783 try: | 786 try: |
784 return scmutil.shortesthexnodeidprefix(repo, node, minlength, cache) | 787 return scmutil.shortesthexnodeidprefix(repo, node, minlength, cache) |
785 except error.RepoLookupError: | 788 except error.RepoLookupError: |
786 return hexnode | 789 return hexnode |
787 | 790 |
788 | 791 |
789 @templatefunc('strip(text[, chars])') | 792 @templatefunc(b'strip(text[, chars])') |
790 def strip(context, mapping, args): | 793 def strip(context, mapping, args): |
791 """Strip characters from a string. By default, | 794 """Strip characters from a string. By default, |
792 strips all leading and trailing whitespace.""" | 795 strips all leading and trailing whitespace.""" |
793 if not (1 <= len(args) <= 2): | 796 if not (1 <= len(args) <= 2): |
794 # i18n: "strip" is a keyword | 797 # i18n: "strip" is a keyword |
795 raise error.ParseError(_("strip expects one or two arguments")) | 798 raise error.ParseError(_(b"strip expects one or two arguments")) |
796 | 799 |
797 text = evalstring(context, mapping, args[0]) | 800 text = evalstring(context, mapping, args[0]) |
798 if len(args) == 2: | 801 if len(args) == 2: |
799 chars = evalstring(context, mapping, args[1]) | 802 chars = evalstring(context, mapping, args[1]) |
800 return text.strip(chars) | 803 return text.strip(chars) |
801 return text.strip() | 804 return text.strip() |
802 | 805 |
803 | 806 |
804 @templatefunc('sub(pattern, replacement, expression)') | 807 @templatefunc(b'sub(pattern, replacement, expression)') |
805 def sub(context, mapping, args): | 808 def sub(context, mapping, args): |
806 """Perform text substitution | 809 """Perform text substitution |
807 using regular expressions.""" | 810 using regular expressions.""" |
808 if len(args) != 3: | 811 if len(args) != 3: |
809 # i18n: "sub" is a keyword | 812 # i18n: "sub" is a keyword |
810 raise error.ParseError(_("sub expects three arguments")) | 813 raise error.ParseError(_(b"sub expects three arguments")) |
811 | 814 |
812 pat = evalstring(context, mapping, args[0]) | 815 pat = evalstring(context, mapping, args[0]) |
813 rpl = evalstring(context, mapping, args[1]) | 816 rpl = evalstring(context, mapping, args[1]) |
814 src = evalstring(context, mapping, args[2]) | 817 src = evalstring(context, mapping, args[2]) |
815 try: | 818 try: |
816 patre = re.compile(pat) | 819 patre = re.compile(pat) |
817 except re.error: | 820 except re.error: |
818 # i18n: "sub" is a keyword | 821 # i18n: "sub" is a keyword |
819 raise error.ParseError(_("sub got an invalid pattern: %s") % pat) | 822 raise error.ParseError(_(b"sub got an invalid pattern: %s") % pat) |
820 try: | 823 try: |
821 yield patre.sub(rpl, src) | 824 yield patre.sub(rpl, src) |
822 except re.error: | 825 except re.error: |
823 # i18n: "sub" is a keyword | 826 # i18n: "sub" is a keyword |
824 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl) | 827 raise error.ParseError(_(b"sub got an invalid replacement: %s") % rpl) |
825 | 828 |
826 | 829 |
827 @templatefunc('startswith(pattern, text)') | 830 @templatefunc(b'startswith(pattern, text)') |
828 def startswith(context, mapping, args): | 831 def startswith(context, mapping, args): |
829 """Returns the value from the "text" argument | 832 """Returns the value from the "text" argument |
830 if it begins with the content from the "pattern" argument.""" | 833 if it begins with the content from the "pattern" argument.""" |
831 if len(args) != 2: | 834 if len(args) != 2: |
832 # i18n: "startswith" is a keyword | 835 # i18n: "startswith" is a keyword |
833 raise error.ParseError(_("startswith expects two arguments")) | 836 raise error.ParseError(_(b"startswith expects two arguments")) |
834 | 837 |
835 patn = evalstring(context, mapping, args[0]) | 838 patn = evalstring(context, mapping, args[0]) |
836 text = evalstring(context, mapping, args[1]) | 839 text = evalstring(context, mapping, args[1]) |
837 if text.startswith(patn): | 840 if text.startswith(patn): |
838 return text | 841 return text |
839 return '' | 842 return b'' |
840 | 843 |
841 | 844 |
842 @templatefunc('word(number, text[, separator])') | 845 @templatefunc(b'word(number, text[, separator])') |
843 def word(context, mapping, args): | 846 def word(context, mapping, args): |
844 """Return the nth word from a string.""" | 847 """Return the nth word from a string.""" |
845 if not (2 <= len(args) <= 3): | 848 if not (2 <= len(args) <= 3): |
846 # i18n: "word" is a keyword | 849 # i18n: "word" is a keyword |
847 raise error.ParseError( | 850 raise error.ParseError( |
848 _("word expects two or three arguments, got %d") % len(args) | 851 _(b"word expects two or three arguments, got %d") % len(args) |
849 ) | 852 ) |
850 | 853 |
851 num = evalinteger( | 854 num = evalinteger( |
852 context, | 855 context, |
853 mapping, | 856 mapping, |
854 args[0], | 857 args[0], |
855 # i18n: "word" is a keyword | 858 # i18n: "word" is a keyword |
856 _("word expects an integer index"), | 859 _(b"word expects an integer index"), |
857 ) | 860 ) |
858 text = evalstring(context, mapping, args[1]) | 861 text = evalstring(context, mapping, args[1]) |
859 if len(args) == 3: | 862 if len(args) == 3: |
860 splitter = evalstring(context, mapping, args[2]) | 863 splitter = evalstring(context, mapping, args[2]) |
861 else: | 864 else: |
862 splitter = None | 865 splitter = None |
863 | 866 |
864 tokens = text.split(splitter) | 867 tokens = text.split(splitter) |
865 if num >= len(tokens) or num < -len(tokens): | 868 if num >= len(tokens) or num < -len(tokens): |
866 return '' | 869 return b'' |
867 else: | 870 else: |
868 return tokens[num] | 871 return tokens[num] |
869 | 872 |
870 | 873 |
871 def loadfunction(ui, extname, registrarobj): | 874 def loadfunction(ui, extname, registrarobj): |