##// 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 def getmax(self, context, mapping):
727 def getmax(self, context, mapping):
728 raise error.ParseError(_('not comparable'))
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 def itermaps(self, context):
734 def itermaps(self, context):
731 separator = self._start
735 separator = self._start
732 for key, value in sorted(self._vars.iteritems()):
736 for key, value in sorted(self._vars.iteritems()):
@@ -166,6 +166,17 b' def fill(context, mapping, args):'
166
166
167 return templatefilters.fill(text, width, initindent, hangindent)
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 @templatefunc('formatnode(node)', requires={'ui'})
180 @templatefunc('formatnode(node)', requires={'ui'})
170 def formatnode(context, mapping, args):
181 def formatnode(context, mapping, args):
171 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
182 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
@@ -63,6 +63,14 b' class wrapped(object):'
63 value depending on the self type"""
63 value depending on the self type"""
64
64
65 @abc.abstractmethod
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 def itermaps(self, context):
74 def itermaps(self, context):
67 """Yield each template mapping"""
75 """Yield each template mapping"""
68
76
@@ -130,6 +138,10 b' class wrappedbytes(wrapped):'
130 raise error.ParseError(_('empty string'))
138 raise error.ParseError(_('empty string'))
131 return func(pycompat.iterbytestr(self._value))
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 def itermaps(self, context):
145 def itermaps(self, context):
134 raise error.ParseError(_('%r is not iterable of mappings')
146 raise error.ParseError(_('%r is not iterable of mappings')
135 % pycompat.bytestr(self._value))
147 % pycompat.bytestr(self._value))
@@ -164,6 +176,9 b' class wrappedvalue(wrapped):'
164 def getmax(self, context, mapping):
176 def getmax(self, context, mapping):
165 raise error.ParseError(_("%r is not iterable") % self._value)
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 def itermaps(self, context):
182 def itermaps(self, context):
168 raise error.ParseError(_('%r is not iterable of mappings')
183 raise error.ParseError(_('%r is not iterable of mappings')
169 % self._value)
184 % self._value)
@@ -208,6 +223,9 b' class date(mappable, wrapped):'
208 def getmax(self, context, mapping):
223 def getmax(self, context, mapping):
209 raise error.ParseError(_('date is not iterable'))
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 def join(self, context, mapping, sep):
229 def join(self, context, mapping, sep):
212 raise error.ParseError(_("date is not iterable"))
230 raise error.ParseError(_("date is not iterable"))
213
231
@@ -273,6 +291,14 b' class hybrid(wrapped):'
273 return val
291 return val
274 return hybriditem(None, key, val, self._makemap)
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 def itermaps(self, context):
302 def itermaps(self, context):
277 makemap = self._makemap
303 makemap = self._makemap
278 for x in self._values:
304 for x in self._values:
@@ -336,6 +362,10 b' class hybriditem(mappable, wrapped):'
336 w = makewrapped(context, mapping, self._value)
362 w = makewrapped(context, mapping, self._value)
337 return w.getmax(context, mapping)
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 def join(self, context, mapping, sep):
369 def join(self, context, mapping, sep):
340 w = makewrapped(context, mapping, self._value)
370 w = makewrapped(context, mapping, self._value)
341 return w.join(context, mapping, sep)
371 return w.join(context, mapping, sep)
@@ -384,6 +414,9 b' class _mappingsequence(wrapped):'
384 def getmax(self, context, mapping):
414 def getmax(self, context, mapping):
385 raise error.ParseError(_('not comparable'))
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 def join(self, context, mapping, sep):
420 def join(self, context, mapping, sep):
388 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
421 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
389 if self._name:
422 if self._name:
@@ -472,6 +505,17 b' class mappedgenerator(wrapped):'
472 raise error.ParseError(_('empty sequence'))
505 raise error.ParseError(_('empty sequence'))
473 return func(xs)
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 def itermaps(self, context):
519 def itermaps(self, context):
476 raise error.ParseError(_('list of strings is not mappable'))
520 raise error.ParseError(_('list of strings is not mappable'))
477
521
@@ -435,6 +435,48 b' latesttag() function:'
435
435
436 $ cd ..
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 Test manifest/get() can be join()-ed as string, though it's silly:
480 Test manifest/get() can be join()-ed as string, though it's silly:
439
481
440 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
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