Patchwork [2,of,2] cmdutil: make commit message shown in text editor customizable by template

login
register
mail settings
Submitter Katsunori FUJIWARA
Date July 14, 2014, 4:31 p.m.
Message ID <7392ce1e88463adeafc6.1405355479@feefifofum>
Download mbox | patch
Permalink /patch/5163/
State Superseded
Headers show

Comments

Katsunori FUJIWARA - July 14, 2014, 4:31 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1405353550 -32400
#      Tue Jul 15 00:59:10 2014 +0900
# Node ID 7392ce1e88463adeafc6416f976c9589ed9eed43
# Parent  f5df6f7bf9a04559b31df62592244209d90e79ab
cmdutil: make commit message shown in text editor customizable by template

This patch makes commit message shown in text editor customizable by
template. For example, this can advertise:

  - sample commit messages for routine works,
  - points to call attention before commit,
  - message of the day, and so on

In addition to pre-defined template keywords, this patch adds commit
log specific ones below:

  - subrepos:
      List of strings. Updated subrepositories in the changeset.

  - currentbookmark:
      String. The active bookmark associated with the changeset, if exists.

  - extramsg:
      String: Extra message instead of 'Leave message empty to abort
      commit.', if specified. This is specific for MQ commands, which
      use default message (e.g. '[mq]: PATCHNAME') if commit message
      is empty.

For example, the editor shows as same text as one shown before this
patch, with the configuration below.

  [committemplate]
  changeset = {desc}\n\n
      HG: Enter commit message.  Lines beginning with 'HG:' are removed.
      HG: {if(extramsg, extramsg, "Leave message empty to abort commit.")}
      HG: --
      HG: user: {author}\n{ifeq(p2rev, "-1", "",
     "HG: branch merge\n")
     }HG: branch '{branch}'\n{if(currentbookmark,
     "HG: bookmark '{currentbookmark}'\n")  }{subrepos %
     "HG: subrepo {subrepo}\n"              }{file_adds %
     "HG: added {file}\n"                   }{file_mods %
     "HG: changed {file}\n"                 }{file_dels %
     "HG: removed {file}\n"                 }{if(files, "",
     "HG: no files changed\n")}

This patch still uses old implementation "buildcommittext" in default
for safety, because some problematic encodings (CP932/Shift-JIS, for
example) use backslash (0x5c) in multibyte character sequence, even
though it has special meaning also for template.

Customized commit log is used for commands below:

  - backout
  - commit
  - fetch (for merge commit)
  - graft
  - histedit (for 'fold', 'mess' and 'edit')
  - import
  - qfold, qnew, qrefresh (of mq)
  - rebase
  - shelve
  - sign (of gpg)
  - tag
  - transplant
Katsunori FUJIWARA - July 14, 2014, 4:38 p.m.
At Tue, 15 Jul 2014 01:31:19 +0900,
FUJIWARA Katsunori wrote:
> 
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> # Date 1405353550 -32400
> #      Tue Jul 15 00:59:10 2014 +0900
> # Node ID 7392ce1e88463adeafc6416f976c9589ed9eed43
> # Parent  f5df6f7bf9a04559b31df62592244209d90e79ab
> cmdutil: make commit message shown in text editor customizable by template

For convenience, I'm also planning to post 2 more additional
series below (maybe after 3.1 release).

  1. allow selective customization for each commit actions

     for example:

       - advertise specific message "A" at commit for tag creation,
       - advertise specific message "B" at commit for tag removal, but
       - show default commit message (= no advertisement) at other
         commit actions

  2. add 'diff' template keyword to show diff at commit

     this can stop repetition of Q&A below, without decreasing
     usability for any users :-)

       Q. Mercurial should (be able to) show diff in the commit
          message shown in text editor at commit, shouldn't it ?

       A. it is not acceptable, because it may show too much
          information and decrease visibility easily


> This patch makes commit message shown in text editor customizable by
> template. For example, this can advertise:
> 
>   - sample commit messages for routine works,
>   - points to call attention before commit,
>   - message of the day, and so on
> 
> In addition to pre-defined template keywords, this patch adds commit
> log specific ones below:
> 
>   - subrepos:
>       List of strings. Updated subrepositories in the changeset.
> 
>   - currentbookmark:
>       String. The active bookmark associated with the changeset, if exists.
> 
>   - extramsg:
>       String: Extra message instead of 'Leave message empty to abort
>       commit.', if specified. This is specific for MQ commands, which
>       use default message (e.g. '[mq]: PATCHNAME') if commit message
>       is empty.
> 
> For example, the editor shows as same text as one shown before this
> patch, with the configuration below.
> 
>   [committemplate]
>   changeset = {desc}\n\n
>       HG: Enter commit message.  Lines beginning with 'HG:' are removed.
>       HG: {if(extramsg, extramsg, "Leave message empty to abort commit.")}
>       HG: --
>       HG: user: {author}\n{ifeq(p2rev, "-1", "",
>      "HG: branch merge\n")
>      }HG: branch '{branch}'\n{if(currentbookmark,
>      "HG: bookmark '{currentbookmark}'\n")  }{subrepos %
>      "HG: subrepo {subrepo}\n"              }{file_adds %
>      "HG: added {file}\n"                   }{file_mods %
>      "HG: changed {file}\n"                 }{file_dels %
>      "HG: removed {file}\n"                 }{if(files, "",
>      "HG: no files changed\n")}
> 
> This patch still uses old implementation "buildcommittext" in default
> for safety, because some problematic encodings (CP932/Shift-JIS, for
> example) use backslash (0x5c) in multibyte character sequence, even
> though it has special meaning also for template.
> 
> Customized commit log is used for commands below:
> 
>   - backout
>   - commit
>   - fetch (for merge commit)
>   - graft
>   - histedit (for 'fold', 'mess' and 'edit')
>   - import
>   - qfold, qnew, qrefresh (of mq)
>   - rebase
>   - shelve
>   - sign (of gpg)
>   - tag
>   - transplant
> 
> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -2170,7 +2170,11 @@
>      return commitforceeditor(repo, ctx, subs)
>  
>  def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None):
> -    committext = buildcommittext(repo, ctx, subs, extramsg)
> +    tmpl = repo.ui.config('committemplate', 'changeset')
> +    if tmpl:
> +        committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
> +    else:
> +        committext = buildcommittext(repo, ctx, subs, extramsg)
>  
>      # run editor in the repository root
>      olddir = os.getcwd()
> @@ -2186,6 +2190,37 @@
>  
>      return text
>  
> +def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
> +    ui = repo.ui
> +    tmpl, mapfile = gettemplate(ui, tmpl, None)
> +
> +    try:
> +        t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
> +    except SyntaxError, inst:
> +        raise util.Abort(inst.args[0])
> +
> +    props = {}
> +
> +    def subrepos(**args):
> +        return templatekw.showlist('subrepo', subs, **args)
> +    props['subrepos'] = subrepos
> +
> +    def currentbookmark(**args):
> +        if bookmarks.iscurrent(repo): # delay examination
> +            return repo._bookmarkcurrent
> +        else:
> +            return ''
> +    props['currentbookmark'] = currentbookmark
> +
> +    if extramsg:
> +        props['extramsg'] = extramsg
> +    else:
> +        props['extramsg'] = ''
> +
> +    ui.pushbuffer()
> +    t.show(ctx, **props)
> +    return ui.popbuffer()
> +
>  def buildcommittext(repo, ctx, subs, extramsg):
>      edittext = []
>      modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
> diff --git a/tests/test-commit.t b/tests/test-commit.t
> --- a/tests/test-commit.t
> +++ b/tests/test-commit.t
> @@ -354,6 +354,50 @@
>    
>    test saving last-message.txt
>  
> +test that '[committemplate] changeset' definition and commit log
> +specific template keywords work well
> +
> +  $ cat >> .hg/hgrc <<EOF
> +  > [committemplate]
> +  > changeset = HG: this is customized commit template
> +  >     HG: 'extramsg' should be empty
> +  >     {extramsg}\n{if(currentbookmark,
> +  >    "HG: bookmark '{currentbookmark}' is activated\n",
> +  >    "HG: no bookmark is activated\n")}{subrepos %
> +  >    "HG: subrepo '{subrepo}' is changed\n"}
> +  > EOF
> +
> +  $ hg init sub2
> +  $ echo a > sub2/a
> +  $ hg -R sub2 add sub2/a
> +  $ echo 'sub2 = sub2' >> .hgsub
> +
> +  $ HGEDITOR=cat hg commit -S -q
> +  HG: this is customized commit template
> +  HG: 'extramsg' should be empty
> +  
> +  HG: bookmark 'currentbookmark' is activated
> +  HG: subrepo 'sub' is changed
> +  HG: subrepo 'sub2' is changed
> +  abort: empty commit message
> +  [255]
> +
> +  $ hg bookmark --inactive currentbookmark
> +  $ hg forget .hgsub
> +  $ HGEDITOR=cat hg commit -q
> +  HG: this is customized commit template
> +  HG: 'extramsg' should be empty
> +  
> +  HG: no bookmark is activated
> +  abort: empty commit message
> +  [255]
> +
> +  $ cat >> .hg/hgrc <<EOF
> +  > # disable customizing for subsequent tests
> +  > [committemplate]
> +  > changeset =
> +  > EOF
> +
>    $ cd ..
>  
>  
> diff --git a/tests/test-mq-qrefresh-replace-log-message.t b/tests/test-mq-qrefresh-replace-log-message.t
> --- a/tests/test-mq-qrefresh-replace-log-message.t
> +++ b/tests/test-mq-qrefresh-replace-log-message.t
> @@ -26,10 +26,28 @@
>    First commit message
>  
>  Testing changing message with -m
> -(this tests also that '--edit' can be used with '--message')
> +(this tests also that '--edit' can be used with '--message', and
> +that '[committemplate] changeset' definition and commit log specific
> +template keyword 'extramsg' work well)
> +
> +  $ cat >> .hg/hgrc <<EOF
> +  > [committemplate]
> +  > changeset = HG: this is customized commit template
> +  >     {desc}\n\n
> +  >     HG: Enter commit message.  Lines beginning with 'HG:' are removed.
> +  >     HG: {extramsg}
> +  >     HG: --
> +  >     HG: user: {author}
> +  >     HG: branch '{branch}'\n{file_adds %
> +  >    "HG: added {file}\n"     }{file_mods %
> +  >    "HG: changed {file}\n"   }{file_dels %
> +  >    "HG: removed {file}\n"   }{if(files, "",
> +  >    "HG: no files changed\n")}
> +  > EOF
>  
>    $ echo bbbb > file
>    $ HGEDITOR=cat hg qrefresh -m "Second commit message" -e
> +  HG: this is customized commit template
>    Second commit message
>    
>    
> @@ -40,6 +58,12 @@
>    HG: branch 'default'
>    HG: added file
>  
> +  $ cat >> .hg/hgrc <<EOF
> +  > # disable customizing for subsequent tests
> +  > [committemplate]
> +  > changeset =
> +  > EOF
> +
>  Should display 'Second commit message'
>  
>    $ hg log -l1 --template "{desc}\n"
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
> 

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy@lares.dti.ne.jp
Matt Mackall - July 14, 2014, 10:44 p.m.
On Tue, 2014-07-15 at 01:31 +0900, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> # Date 1405353550 -32400
> #      Tue Jul 15 00:59:10 2014 +0900
> # Node ID 7392ce1e88463adeafc6416f976c9589ed9eed43
> # Parent  f5df6f7bf9a04559b31df62592244209d90e79ab
> cmdutil: make commit message shown in text editor customizable by template
> 
> This patch makes commit message shown in text editor customizable by
> template. For example, this can advertise:
> 
>   - sample commit messages for routine works,
>   - points to call attention before commit,
>   - message of the day, and so on
> 
> In addition to pre-defined template keywords, this patch adds commit
> log specific ones below:
> 
>   - subrepos:
>       List of strings. Updated subrepositories in the changeset.
> 
>   - currentbookmark:
>       String. The active bookmark associated with the changeset, if exists.
> 
>   - extramsg:
>       String: Extra message instead of 'Leave message empty to abort
>       commit.', if specified. This is specific for MQ commands, which
>       use default message (e.g. '[mq]: PATCHNAME') if commit message
>       is empty.

I assume you've just temporarily forgotten I reject patches with
multiple features on principle. The first two look like they belong in
the core templates.

> For example, the editor shows as same text as one shown before this
> patch, with the configuration below.
> 
>   [committemplate]
>   changeset = {desc}\n\n
>       HG: Enter commit message.  Lines beginning with 'HG:' are removed.
>       HG: {if(extramsg, extramsg, "Leave message empty to abort commit.")}
>       HG: --
>       HG: user: {author}\n{ifeq(p2rev, "-1", "",
>      "HG: branch merge\n")
>      }HG: branch '{branch}'\n{if(currentbookmark,
>      "HG: bookmark '{currentbookmark}'\n")  }{subrepos %
>      "HG: subrepo {subrepo}\n"              }{file_adds %
>      "HG: added {file}\n"                   }{file_mods %
>      "HG: changed {file}\n"                 }{file_dels %
>      "HG: removed {file}\n"                 }{if(files, "",
>      "HG: no files changed\n")}

These are great docs, too bad they're in the commit message.

> This patch still uses old implementation "buildcommittext" in default
> for safety, because some problematic encodings (CP932/Shift-JIS, for
> example) use backslash (0x5c) in multibyte character sequence, even
> though it has special meaning also for template.

Can you be more specific?
Katsunori FUJIWARA - July 15, 2014, 1:40 p.m.
At Mon, 14 Jul 2014 17:44:05 -0500,
Matt Mackall wrote:
> 
> On Tue, 2014-07-15 at 01:31 +0900, FUJIWARA Katsunori wrote:
> > # HG changeset patch
> > # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> > # Date 1405353550 -32400
> > #      Tue Jul 15 00:59:10 2014 +0900
> > # Node ID 7392ce1e88463adeafc6416f976c9589ed9eed43
> > # Parent  f5df6f7bf9a04559b31df62592244209d90e79ab
> > cmdutil: make commit message shown in text editor customizable by template
> > 
> > This patch makes commit message shown in text editor customizable by
> > template. For example, this can advertise:
> > 
> >   - sample commit messages for routine works,
> >   - points to call attention before commit,
> >   - message of the day, and so on
> > 
> > In addition to pre-defined template keywords, this patch adds commit
> > log specific ones below:
> > 
> >   - subrepos:
> >       List of strings. Updated subrepositories in the changeset.
> > 
> >   - currentbookmark:
> >       String. The active bookmark associated with the changeset, if exists.
> > 
> >   - extramsg:
> >       String: Extra message instead of 'Leave message empty to abort
> >       commit.', if specified. This is specific for MQ commands, which
> >       use default message (e.g. '[mq]: PATCHNAME') if commit message
> >       is empty.
> 
> I assume you've just temporarily forgotten I reject patches with
> multiple features on principle. The first two look like they belong in
> the core templates.

Oops ! 'extramsg' made me mis-recognize generality of other two
keywords. I'll send them in separated patches.

> > For example, the editor shows as same text as one shown before this
> > patch, with the configuration below.
> > 
> >   [committemplate]
> >   changeset = {desc}\n\n
> >       HG: Enter commit message.  Lines beginning with 'HG:' are removed.
> >       HG: {if(extramsg, extramsg, "Leave message empty to abort commit.")}
> >       HG: --
> >       HG: user: {author}\n{ifeq(p2rev, "-1", "",
> >      "HG: branch merge\n")
> >      }HG: branch '{branch}'\n{if(currentbookmark,
> >      "HG: bookmark '{currentbookmark}'\n")  }{subrepos %
> >      "HG: subrepo {subrepo}\n"              }{file_adds %
> >      "HG: added {file}\n"                   }{file_mods %
> >      "HG: changed {file}\n"                 }{file_dels %
> >      "HG: removed {file}\n"                 }{if(files, "",
> >      "HG: no files changed\n")}
> 
> These are great docs, too bad they're in the commit message.

I'll put them into 'hg help config'

> > This patch still uses old implementation "buildcommittext" in default
> > for safety, because some problematic encodings (CP932/Shift-JIS, for
> > example) use backslash (0x5c) in multibyte character sequence, even
> > though it has special meaning also for template.
> 
> Can you be more specific?

I'll describe more detailed explanation about it.

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy@lares.dti.ne.jp

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2170,7 +2170,11 @@ 
     return commitforceeditor(repo, ctx, subs)
 
 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None):
-    committext = buildcommittext(repo, ctx, subs, extramsg)
+    tmpl = repo.ui.config('committemplate', 'changeset')
+    if tmpl:
+        committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
+    else:
+        committext = buildcommittext(repo, ctx, subs, extramsg)
 
     # run editor in the repository root
     olddir = os.getcwd()
@@ -2186,6 +2190,37 @@ 
 
     return text
 
+def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
+    ui = repo.ui
+    tmpl, mapfile = gettemplate(ui, tmpl, None)
+
+    try:
+        t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
+    except SyntaxError, inst:
+        raise util.Abort(inst.args[0])
+
+    props = {}
+
+    def subrepos(**args):
+        return templatekw.showlist('subrepo', subs, **args)
+    props['subrepos'] = subrepos
+
+    def currentbookmark(**args):
+        if bookmarks.iscurrent(repo): # delay examination
+            return repo._bookmarkcurrent
+        else:
+            return ''
+    props['currentbookmark'] = currentbookmark
+
+    if extramsg:
+        props['extramsg'] = extramsg
+    else:
+        props['extramsg'] = ''
+
+    ui.pushbuffer()
+    t.show(ctx, **props)
+    return ui.popbuffer()
+
 def buildcommittext(repo, ctx, subs, extramsg):
     edittext = []
     modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
diff --git a/tests/test-commit.t b/tests/test-commit.t
--- a/tests/test-commit.t
+++ b/tests/test-commit.t
@@ -354,6 +354,50 @@ 
   
   test saving last-message.txt
 
+test that '[committemplate] changeset' definition and commit log
+specific template keywords work well
+
+  $ cat >> .hg/hgrc <<EOF
+  > [committemplate]
+  > changeset = HG: this is customized commit template
+  >     HG: 'extramsg' should be empty
+  >     {extramsg}\n{if(currentbookmark,
+  >    "HG: bookmark '{currentbookmark}' is activated\n",
+  >    "HG: no bookmark is activated\n")}{subrepos %
+  >    "HG: subrepo '{subrepo}' is changed\n"}
+  > EOF
+
+  $ hg init sub2
+  $ echo a > sub2/a
+  $ hg -R sub2 add sub2/a
+  $ echo 'sub2 = sub2' >> .hgsub
+
+  $ HGEDITOR=cat hg commit -S -q
+  HG: this is customized commit template
+  HG: 'extramsg' should be empty
+  
+  HG: bookmark 'currentbookmark' is activated
+  HG: subrepo 'sub' is changed
+  HG: subrepo 'sub2' is changed
+  abort: empty commit message
+  [255]
+
+  $ hg bookmark --inactive currentbookmark
+  $ hg forget .hgsub
+  $ HGEDITOR=cat hg commit -q
+  HG: this is customized commit template
+  HG: 'extramsg' should be empty
+  
+  HG: no bookmark is activated
+  abort: empty commit message
+  [255]
+
+  $ cat >> .hg/hgrc <<EOF
+  > # disable customizing for subsequent tests
+  > [committemplate]
+  > changeset =
+  > EOF
+
   $ cd ..
 
 
diff --git a/tests/test-mq-qrefresh-replace-log-message.t b/tests/test-mq-qrefresh-replace-log-message.t
--- a/tests/test-mq-qrefresh-replace-log-message.t
+++ b/tests/test-mq-qrefresh-replace-log-message.t
@@ -26,10 +26,28 @@ 
   First commit message
 
 Testing changing message with -m
-(this tests also that '--edit' can be used with '--message')
+(this tests also that '--edit' can be used with '--message', and
+that '[committemplate] changeset' definition and commit log specific
+template keyword 'extramsg' work well)
+
+  $ cat >> .hg/hgrc <<EOF
+  > [committemplate]
+  > changeset = HG: this is customized commit template
+  >     {desc}\n\n
+  >     HG: Enter commit message.  Lines beginning with 'HG:' are removed.
+  >     HG: {extramsg}
+  >     HG: --
+  >     HG: user: {author}
+  >     HG: branch '{branch}'\n{file_adds %
+  >    "HG: added {file}\n"     }{file_mods %
+  >    "HG: changed {file}\n"   }{file_dels %
+  >    "HG: removed {file}\n"   }{if(files, "",
+  >    "HG: no files changed\n")}
+  > EOF
 
   $ echo bbbb > file
   $ HGEDITOR=cat hg qrefresh -m "Second commit message" -e
+  HG: this is customized commit template
   Second commit message
   
   
@@ -40,6 +58,12 @@ 
   HG: branch 'default'
   HG: added file
 
+  $ cat >> .hg/hgrc <<EOF
+  > # disable customizing for subsequent tests
+  > [committemplate]
+  > changeset =
+  > EOF
+
 Should display 'Second commit message'
 
   $ hg log -l1 --template "{desc}\n"