Patchwork templater: add intersperse() template function

login
register
mail settings
Submitter via Mercurial-devel
Date May 3, 2016, 4:58 p.m.
Message ID <d88e385e84ca345474c1.1462294726@martinvonz.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/14871/
State Changes Requested
Headers show

Comments

via Mercurial-devel - May 3, 2016, 4:58 p.m.
# HG changeset patch
# User Martin von Zweigbergk <martinvonz@google.com>
# Date 1462294194 25200
#      Tue May 03 09:49:54 2016 -0700
# Branch stable
# Node ID d88e385e84ca345474c177932e605c79a487a8d4
# Parent  61463b8fcef871ff3efff53945df4671c71c4e31
templater: add intersperse() template function

A pretty common pattern in templates is adding conditional separators
like so:

  {node}{if(bookmarks, " {bookmarks}")}{if(tags, " {tags}")}

With this patch, the above can be simplified to:

  {intersperse(" ", node, bookmarks, tags)}
timeless - May 3, 2016, 7:31 p.m.
i like this

On Tue, May 3, 2016 at 12:58 PM, Martin von Zweigbergk via
Mercurial-devel <mercurial-devel@mercurial-scm.org> wrote:
> # HG changeset patch
> # User Martin von Zweigbergk <martinvonz@google.com>
> # Date 1462294194 25200
> #      Tue May 03 09:49:54 2016 -0700
> # Branch stable
> # Node ID d88e385e84ca345474c177932e605c79a487a8d4
> # Parent  61463b8fcef871ff3efff53945df4671c71c4e31
> templater: add intersperse() template function
>
> A pretty common pattern in templates is adding conditional separators
> like so:
>
>   {node}{if(bookmarks, " {bookmarks}")}{if(tags, " {tags}")}
>
> With this patch, the above can be simplified to:
>
>   {intersperse(" ", node, bookmarks, tags)}
>
> diff -r 61463b8fcef8 -r d88e385e84ca mercurial/templater.py
> --- a/mercurial/templater.py    Sun May 01 14:36:12 2016 -0500
> +++ b/mercurial/templater.py    Tue May 03 09:49:54 2016 -0700
> @@ -621,6 +621,26 @@
>              yield joiner
>          yield x
>
> +@templatefunc('intersperse(sep, args)')
> +def intersperse(context, mapping, args):
> +    """Add a separator between non-empty arguments."""
> +    if not args:
> +        # i18n: "intersperse" is a keyword
> +        raise error.ParseError(_("intersperse expects at least one argument"))
> +
> +    joiner = evalstring(context, mapping, args[0])
> +
> +    first = True
> +    for x in args[1:]:
> +        argstr = evalstring(context, mapping, x)
> +        if not argstr:
> +            continue
> +        if first:
> +            first = False
> +        else:
> +            yield joiner
> +        yield argstr
> +
>  @templatefunc('label(label, expr)')
>  def label(context, mapping, args):
>      """Apply a label to generated content. Content with
> diff -r 61463b8fcef8 -r d88e385e84ca tests/test-command-template.t
> --- a/tests/test-command-template.t     Sun May 01 14:36:12 2016 -0500
> +++ b/tests/test-command-template.t     Tue May 03 09:49:54 2016 -0700
> @@ -3320,6 +3320,15 @@
>    hg: parse error: pad() expects an integer width
>    [255]
>
> +Test intersperse function
> +
> +  $ hg log -r 0 -T '{intersperse("-", "", "a", "b", "", "", "c", "")}\n'
> +  a-b-c
> +  $ hg log -r 0 -T '{intersperse(" ", "{rev}:{node|short}", author|user, branch)}\n'
> +  0:f7769ec2ab97 test default
> +  $ hg log -r 0 --color=always -T '{intersperse(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
> +  a \x1b[0;31mb\x1b[0m c d (esc)
> +
>  Test ifcontains function
>
>    $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Matt Mackall - May 3, 2016, 8:12 p.m.
On Tue, 2016-05-03 at 09:58 -0700, Martin von Zweigbergk via Mercurial-devel
wrote:
> # HG changeset patch
> # User Martin von Zweigbergk <martinvonz@google.com>
> # Date 1462294194 25200
> #      Tue May 03 09:49:54 2016 -0700
> # Branch stable
> # Node ID d88e385e84ca345474c177932e605c79a487a8d4
> # Parent  61463b8fcef871ff3efff53945df4671c71c4e31
> templater: add intersperse() template function
> 
> A pretty common pattern in templates is adding conditional separators
> like so:
> 
>   {node}{if(bookmarks, " {bookmarks}")}{if(tags, " {tags}")}
> 
> With this patch, the above can be simplified to:
> 
>   {intersperse(" ", node, bookmarks, tags)}

This is very similar to the existing join function:

 join(list, sep)

It's unfortunate that we didn't make that:

 join(sep, list)

Because then it would be natural to have a second form of join:

 join(sep, a, b, c, ..)

However, the current behavior of join doesn't notice empty args (it works like
Python's join).

So how would you feel about a new function separate():

 separate(sep, list) -> put a separator between non-empty elements of list
 separate(sep, a, b, c...) -> put a separator between non-empty arguments

-- 
Mathematics is the supreme nostalgia of our time.
via Mercurial-devel - May 3, 2016, 8:19 p.m.
On Tue, May 3, 2016 at 1:12 PM, Matt Mackall <mpm@selenic.com> wrote:
> On Tue, 2016-05-03 at 09:58 -0700, Martin von Zweigbergk via Mercurial-devel
> wrote:
>> # HG changeset patch
>> # User Martin von Zweigbergk <martinvonz@google.com>
>> # Date 1462294194 25200
>> #      Tue May 03 09:49:54 2016 -0700
>> # Branch stable
>> # Node ID d88e385e84ca345474c177932e605c79a487a8d4
>> # Parent  61463b8fcef871ff3efff53945df4671c71c4e31
>> templater: add intersperse() template function
>>
>> A pretty common pattern in templates is adding conditional separators
>> like so:
>>
>>   {node}{if(bookmarks, " {bookmarks}")}{if(tags, " {tags}")}
>>
>> With this patch, the above can be simplified to:
>>
>>   {intersperse(" ", node, bookmarks, tags)}
>
> This is very similar to the existing join function:
>
>  join(list, sep)
>
> It's unfortunate that we didn't make that:
>
>  join(sep, list)
>
> Because then it would be natural to have a second form of join:
>
>  join(sep, a, b, c, ..)
>
> However, the current behavior of join doesn't notice empty args (it works like
> Python's join).
>
> So how would you feel about a new function separate():
>
>  separate(sep, list) -> put a separator between non-empty elements of list
>  separate(sep, a, b, c...) -> put a separator between non-empty arguments

Both new name and list support sounds fine to me. I'll prepare a V2.

Patch

diff -r 61463b8fcef8 -r d88e385e84ca mercurial/templater.py
--- a/mercurial/templater.py	Sun May 01 14:36:12 2016 -0500
+++ b/mercurial/templater.py	Tue May 03 09:49:54 2016 -0700
@@ -621,6 +621,26 @@ 
             yield joiner
         yield x
 
+@templatefunc('intersperse(sep, args)')
+def intersperse(context, mapping, args):
+    """Add a separator between non-empty arguments."""
+    if not args:
+        # i18n: "intersperse" is a keyword
+        raise error.ParseError(_("intersperse expects at least one argument"))
+
+    joiner = evalstring(context, mapping, args[0])
+
+    first = True
+    for x in args[1:]:
+        argstr = evalstring(context, mapping, x)
+        if not argstr:
+            continue
+        if first:
+            first = False
+        else:
+            yield joiner
+        yield argstr
+
 @templatefunc('label(label, expr)')
 def label(context, mapping, args):
     """Apply a label to generated content. Content with
diff -r 61463b8fcef8 -r d88e385e84ca tests/test-command-template.t
--- a/tests/test-command-template.t	Sun May 01 14:36:12 2016 -0500
+++ b/tests/test-command-template.t	Tue May 03 09:49:54 2016 -0700
@@ -3320,6 +3320,15 @@ 
   hg: parse error: pad() expects an integer width
   [255]
 
+Test intersperse function
+
+  $ hg log -r 0 -T '{intersperse("-", "", "a", "b", "", "", "c", "")}\n'
+  a-b-c
+  $ hg log -r 0 -T '{intersperse(" ", "{rev}:{node|short}", author|user, branch)}\n'
+  0:f7769ec2ab97 test default
+  $ hg log -r 0 --color=always -T '{intersperse(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
+  a \x1b[0;31mb\x1b[0m c d (esc)
+
 Test ifcontains function
 
   $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'