hgext3rd/topic/__init__.py
branchmercurial-4.5
changeset 4075 dc247e648f43
parent 4073 d54a4b9c1d01
child 4078 da6ce6d446b9
--- a/hgext3rd/topic/__init__.py	Tue Aug 28 11:24:50 2018 +0200
+++ b/hgext3rd/topic/__init__.py	Mon Sep 03 22:05:12 2018 +0200
@@ -29,8 +29,10 @@
 your current topic.
 
 Topic is offering you aliases reference to changeset in your current topic
-stack as 't#'. For example, 't1' refers to the root of your stack, 't2' to the
-second commits, etc. The 'hg stack' command show these number.
+stack as 's#'. For example, 's1' refers to the root of your stack, 's2' to the
+second commits, etc. The 'hg stack' command show these number. 's0' can be used
+to refer to the parent of the topic root. Updating using `hg up s0` will keep
+the topic active.
 
 Push behavior will change a bit with topic. When pushing to a publishing
 repository the changesets will turn public and the topic data on them will fade
@@ -132,7 +134,6 @@
     registrar,
     scmutil,
     templatefilters,
-    templatekw,
     util,
 )
 
@@ -149,13 +150,8 @@
     topicmap,
 )
 
-if util.safehasattr(registrar, 'command'):
-    commandfunc = registrar.command
-else: # compat with hg < 4.3
-    commandfunc = cmdutil.command
-
 cmdtable = {}
-command = commandfunc(cmdtable)
+command = registrar.command(cmdtable)
 colortable = {'topic.active': 'green',
               'topic.list.troubledcount': 'red',
               'topic.list.headcount.multiple': 'yellow',
@@ -181,7 +177,7 @@
               'topic.active': 'green',
              }
 
-__version__ = '0.10.1.dev'
+__version__ = '0.11.0.dev'
 
 testedwith = '4.3.3 4.4.2 4.5.2 4.6.2 4.7'
 minimumhgversion = '4.3'
@@ -231,6 +227,8 @@
                       default=None,
             )
 
+templatekeyword = registrar.templatekeyword()
+
 def _contexttopic(self, force=False):
     if not (force or self.mutable()):
         return ''
@@ -240,8 +238,8 @@
 def _contexttopicidx(self):
     topic = self.topic()
     if not topic:
-        # XXX we might want to include t0 here,
-        # however t0 is related to  'currenttopic' which has no place here.
+        # XXX we might want to include s0 here,
+        # however s0 is related to  'currenttopic' which has no place here.
         return None
     revlist = stack.stack(self._repo, topic=topic)
     try:
@@ -257,12 +255,23 @@
         return None
 context.basectx.topicidx = _contexttopicidx
 
+stackrev = re.compile(r'^s\d+$')
 topicrev = re.compile(r'^t\d+$')
 branchrev = re.compile(r'^b\d+$')
 
 def _namemap(repo, name):
     revs = None
-    if topicrev.match(name):
+    if stackrev.match(name):
+        idx = int(name[1:])
+        tname = topic = repo.currenttopic
+        if topic:
+            ttype = 'topic'
+            revs = list(stack.stack(repo, topic=topic))
+        else:
+            ttype = 'branch'
+            tname = branch = repo[None].branch()
+            revs = list(stack.stack(repo, branch=branch))
+    elif topicrev.match(name):
         idx = int(name[1:])
         ttype = 'topic'
         tname = topic = repo.currenttopic
@@ -279,9 +288,12 @@
         try:
             r = revs[idx]
         except IndexError:
-            msg = _('cannot resolve "%s": %s "%s" has only %d changesets')
+            if ttype == 'topic':
+                msg = _('cannot resolve "%s": %s "%s" has only %d changesets')
+            elif ttype == 'branch':
+                msg = _('cannot resolve "%s": %s "%s" has only %d non-public changesets')
             raise error.Abort(msg % (name, ttype, tname, len(revs) - 1))
-        # b0 or t0 can be None
+        # b0 or t0 or s0 can be None
         if r == -1 and idx == 0:
             msg = _('the %s "%s" has no %s')
             raise error.Abort(msg % (ttype, tname, name))
@@ -323,7 +335,7 @@
 
     extensions.wrapfunction(cmdutil, 'buildcommittext', committextwrap)
     extensions.wrapfunction(merge, 'update', mergeupdatewrap)
-    # We need to check whether t0 or b0 is passed to override the default update
+    # We need to check whether t0 or b0 or s0 is passed to override the default update
     # behaviour of changing topic and I can't find a better way
     # to do that as scmutil.revsingle returns the rev number and hence we can't
     # plug into logic for this into mergemod.update().
@@ -338,7 +350,6 @@
 
     cmdutil.summaryhooks.add('topic', summaryhook)
 
-    templatekw.keywords['topic'] = topickw
     # Wrap workingctx extra to return the topic name
     extensions.wrapfunction(context.workingctx, '__init__', wrapinit)
     # Wrap changelog.add to drop empty topic
@@ -510,9 +521,11 @@
             'topics', 'topic', namemap=_namemap, nodemap=_nodemap,
             listnames=lambda repo: repo.topics))
 
-def topickw(**args):
+@templatekeyword('topic', requires={'ctx'})
+def topickw(context, mapping):
     """:topic: String. The topic of the changeset"""
-    return args['ctx'].topic()
+    ctx = context.resource(mapping, 'ctx')
+    return ctx.topic()
 
 def wrapinit(orig, self, repo, *args, **kwargs):
     orig(self, repo, *args, **kwargs)
@@ -647,9 +660,9 @@
 
     ct = repo.currenttopic
     if clear:
-        empty = stack.stack(repo, topic=ct).changesetcount == 0
-        if empty:
-            if ct:
+        if ct:
+            empty = stack.stack(repo, topic=ct).changesetcount == 0
+            if empty:
                 ui.status(_('clearing empty topic "%s"\n') % ct)
         return _changecurrenttopic(repo, None)
 
@@ -1152,7 +1165,6 @@
         # rebased commit. We have explicitly stored in config if rebase is
         # running.
         ot = repo.currenttopic
-        empty = stack.stack(repo, topic=ot).changesetcount == 0
         if repo.ui.hasconfig('experimental', 'topicrebase'):
             isrebase = True
         if repo.ui.configbool('_internal', 'keep-topic'):
@@ -1166,8 +1178,10 @@
                 f.write(t)
             if t and t != ot:
                 repo.ui.status(_("switching to topic %s\n") % t)
-            if ot and not t and empty:
-                repo.ui.status(_('clearing empty topic "%s"\n') % ot)
+            if ot and not t:
+                empty = stack.stack(repo, topic=ot).changesetcount == 0
+                if empty:
+                    repo.ui.status(_('clearing empty topic "%s"\n') % ot)
         elif ist0:
             repo.ui.status(_("preserving the current topic '%s'\n") % ot)
         return ret
@@ -1176,7 +1190,7 @@
 
 def checkt0(orig, ui, repo, node=None, rev=None, *args, **kwargs):
 
-    thezeros = set(['t0', 'b0'])
+    thezeros = set(['t0', 'b0', 's0'])
     backup = repo.ui.backupconfig('_internal', 'keep-topic')
     try:
         if node in thezeros or rev in thezeros: