##// END OF EJS Templates
templater: introduce filter() function to remove empty items from list...
Yuya Nishihara -
r38467:dae829b4 default
parent child Browse files
Show More
@@ -727,6 +727,10 b' class sessionvars(templateutil.wrapped):'
727 727 def getmax(self, context, mapping):
728 728 raise error.ParseError(_('not comparable'))
729 729
730 def filter(self, context, mapping, select):
731 # implement if necessary
732 raise error.ParseError(_('not filterable'))
733
730 734 def itermaps(self, context):
731 735 separator = self._start
732 736 for key, value in sorted(self._vars.iteritems()):
@@ -166,6 +166,17 b' def fill(context, mapping, args):'
166 166
167 167 return templatefilters.fill(text, width, initindent, hangindent)
168 168
169 @templatefunc('filter(iterable)')
170 def filter_(context, mapping, args):
171 """Remove empty elements from a list or a dict."""
172 if len(args) != 1:
173 # i18n: "filter" is a keyword
174 raise error.ParseError(_("filter expects one argument"))
175 iterable = evalwrapped(context, mapping, args[0])
176 def select(w):
177 return w.tobool(context, mapping)
178 return iterable.filter(context, mapping, select)
179
169 180 @templatefunc('formatnode(node)', requires={'ui'})
170 181 def formatnode(context, mapping, args):
171 182 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
@@ -63,6 +63,14 b' class wrapped(object):'
63 63 value depending on the self type"""
64 64
65 65 @abc.abstractmethod
66 def filter(self, context, mapping, select):
67 """Return new container of the same type which includes only the
68 selected elements
69
70 select() takes each item as a wrapped object and returns True/False.
71 """
72
73 @abc.abstractmethod
66 74 def itermaps(self, context):
67 75 """Yield each template mapping"""
68 76
@@ -130,6 +138,10 b' class wrappedbytes(wrapped):'
130 138 raise error.ParseError(_('empty string'))
131 139 return func(pycompat.iterbytestr(self._value))
132 140
141 def filter(self, context, mapping, select):
142 raise error.ParseError(_('%r is not filterable')
143 % pycompat.bytestr(self._value))
144
133 145 def itermaps(self, context):
134 146 raise error.ParseError(_('%r is not iterable of mappings')
135 147 % pycompat.bytestr(self._value))
@@ -164,6 +176,9 b' class wrappedvalue(wrapped):'
164 176 def getmax(self, context, mapping):
165 177 raise error.ParseError(_("%r is not iterable") % self._value)
166 178
179 def filter(self, context, mapping, select):
180 raise error.ParseError(_("%r is not iterable") % self._value)
181
167 182 def itermaps(self, context):
168 183 raise error.ParseError(_('%r is not iterable of mappings')
169 184 % self._value)
@@ -208,6 +223,9 b' class date(mappable, wrapped):'
208 223 def getmax(self, context, mapping):
209 224 raise error.ParseError(_('date is not iterable'))
210 225
226 def filter(self, context, mapping, select):
227 raise error.ParseError(_('date is not iterable'))
228
211 229 def join(self, context, mapping, sep):
212 230 raise error.ParseError(_("date is not iterable"))
213 231
@@ -273,6 +291,14 b' class hybrid(wrapped):'
273 291 return val
274 292 return hybriditem(None, key, val, self._makemap)
275 293
294 def filter(self, context, mapping, select):
295 if util.safehasattr(self._values, 'get'):
296 values = {k: v for k, v in self._values.iteritems()
297 if select(self._wrapvalue(k, v))}
298 else:
299 values = [v for v in self._values if select(self._wrapvalue(v, v))]
300 return hybrid(None, values, self._makemap, self._joinfmt, self._keytype)
301
276 302 def itermaps(self, context):
277 303 makemap = self._makemap
278 304 for x in self._values:
@@ -336,6 +362,10 b' class hybriditem(mappable, wrapped):'
336 362 w = makewrapped(context, mapping, self._value)
337 363 return w.getmax(context, mapping)
338 364
365 def filter(self, context, mapping, select):
366 w = makewrapped(context, mapping, self._value)
367 return w.filter(context, mapping, select)
368
339 369 def join(self, context, mapping, sep):
340 370 w = makewrapped(context, mapping, self._value)
341 371 return w.join(context, mapping, sep)
@@ -384,6 +414,9 b' class _mappingsequence(wrapped):'
384 414 def getmax(self, context, mapping):
385 415 raise error.ParseError(_('not comparable'))
386 416
417 def filter(self, context, mapping, select):
418 raise error.ParseError(_('not filterable without template'))
419
387 420 def join(self, context, mapping, sep):
388 421 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
389 422 if self._name:
@@ -472,6 +505,17 b' class mappedgenerator(wrapped):'
472 505 raise error.ParseError(_('empty sequence'))
473 506 return func(xs)
474 507
508 @staticmethod
509 def _filteredgen(context, mapping, make, args, select):
510 for x in make(context, *args):
511 s = stringify(context, mapping, x)
512 if select(wrappedbytes(s)):
513 yield s
514
515 def filter(self, context, mapping, select):
516 args = (mapping, self._make, self._args, select)
517 return mappedgenerator(self._filteredgen, args)
518
475 519 def itermaps(self, context):
476 520 raise error.ParseError(_('list of strings is not mappable'))
477 521
@@ -435,6 +435,48 b' latesttag() function:'
435 435
436 436 $ cd ..
437 437
438 Test filter() empty values:
439
440 $ hg log -R a -r 1 -T '{filter(desc|splitlines) % "{line}\n"}'
441 other 1
442 other 2
443 other 3
444 $ hg log -R a -r 0 -T '{filter(dict(a=0, b=1) % "{ifeq(key, "a", "{value}\n")}")}'
445 0
446
447 0 should not be falsy
448
449 $ hg log -R a -r 0 -T '{filter(revset("0:2"))}\n'
450 0 1 2
451
452 Test filter() shouldn't crash:
453
454 $ hg log -R a -r 0 -T '{filter(extras)}\n'
455 branch=default
456 $ hg log -R a -r 0 -T '{filter(files)}\n'
457 a
458
459 Test filter() unsupported arguments:
460
461 $ hg log -R a -r 0 -T '{filter()}\n'
462 hg: parse error: filter expects one argument
463 [255]
464 $ hg log -R a -r 0 -T '{filter(date)}\n'
465 hg: parse error: date is not iterable
466 [255]
467 $ hg log -R a -r 0 -T '{filter(rev)}\n'
468 hg: parse error: 0 is not iterable
469 [255]
470 $ hg log -R a -r 0 -T '{filter(desc|firstline)}\n'
471 hg: parse error: 'line 1' is not filterable
472 [255]
473 $ hg log -R a -r 0 -T '{filter(manifest)}\n'
474 hg: parse error: '0:a0c8bcbbb45c' is not filterable
475 [255]
476 $ hg log -R a -r 0 -T '{filter(succsandmarkers)}\n'
477 hg: parse error: not filterable without template
478 [255]
479
438 480 Test manifest/get() can be join()-ed as string, though it's silly:
439 481
440 482 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
General Comments 0
You need to be logged in to leave comments. Login now