[PATCH 8 of 8 techdocs] help: support loading sub-topics

Gregory Szorc gregory.szorc at gmail.com
Sun Dec 13 13:47:01 CST 2015


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1450034395 28800
#      Sun Dec 13 11:19:55 2015 -0800
# Node ID 6f49d08b3ad50763b0a98aa93f3d35ee9de566e8
# Parent  a1dac17af8e8022feb2125f1bf501309fbbf2805
help: support loading sub-topics

If a sub-topic/section is requested and the main topic corresponds to
a topic with sub-topics, we now look for and return content for a
sub-topic if found.

With this patch, `hg help internals.X` now works. hgweb does not yet
render sub-topics, however.

diff --git a/mercurial/help.py b/mercurial/help.py
--- a/mercurial/help.py
+++ b/mercurial/help.py
@@ -201,16 +201,21 @@ helptable = sorted([
      loaddoc('hgignore')),
     (["phases"], _("Working with Phases"), loaddoc('phases')),
     (['scripting'], _('Using Mercurial from scripts and automation'),
      loaddoc('scripting')),
     (['internals'], _("Technical implementation topics"),
      internalshelp),
 ])
 
+# Maps topics with sub-topics to a list of their sub-topics.
+subtopics = {
+    'internals': internalstable,
+}
+
 # Map topics to lists of callable taking the current topic help and
 # returning the updated version
 helphooks = {}
 
 def addtopichook(topic, rewriter):
     helphooks.setdefault(topic, []).append(rewriter)
 
 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
@@ -428,21 +433,29 @@ def help_(ui, name, unknowncmd=False, fu
                              'aliases and global options)\n') % name)
             else:
                 rst.append(_('\n(use "hg help -v%s" to show built-in aliases '
                              'and global options)\n')
                            % (name and " " + name or ""))
         return rst
 
     def helptopic(name, subtopic=None):
-        for names, header, doc in helptable:
-            if name in names:
-                break
-        else:
-            raise error.UnknownCommand(name)
+        # Look for sub-topic entry first.
+        header, doc = None, None
+        if subtopic and name in subtopics:
+            for names, header, doc in subtopics[name]:
+                if subtopic in names:
+                    break
+
+        if not header:
+            for names, header, doc in helptable:
+                if name in names:
+                    break
+            else:
+                raise error.UnknownCommand(name)
 
         rst = [minirst.section(header)]
 
         # description
         if not doc:
             rst.append("    %s\n" % _("(no help text available)"))
         if callable(doc):
             rst += ["    %s\n" % l for l in doc(ui).splitlines()]
diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -869,16 +869,161 @@ internals topic renders index of availab
 
   $ hg help internals
   Technical implementation topics
   """""""""""""""""""""""""""""""
   
        bundles       container for exchange of repository data
        changegroups  representation of revlog data
 
+sub-topics can be accessed
+
+  $ hg help internals.changegroups
+      Changegroups
+      ============
+  
+      Changegroups are representations of repository revlog data, specifically
+      the changelog, manifest, and filelogs.
+  
+      There are 2 versions of changegroups: "1" and "2". From a high-level, they
+      are almost exactly the same, with the only difference being a header on
+      entries in the changeset segment.
+  
+      Changegroups consists of 3 logical segments:
+  
+        +---------------------------------+
+        |           |          |          |
+        | changeset | manifest | filelogs |
+        |           |          |          |
+        +---------------------------------+
+  
+      The principle building block of each segment is a *chunk*. A *chunk* is a
+      framed piece of data:
+  
+        +---------------------------------------+
+        |           |                           |
+        |  length   |           data            |
+        | (32 bits) |       <length> bytes      |
+        |           |                           |
+        +---------------------------------------+
+  
+      Each chunk starts with a 32-bit big-endian signed integer indicating the
+      length of the raw data that follows.
+  
+      There is a special case chunk that has 0 length ("0x00000000"). We call
+      this an *empty chunk*.
+  
+      Delta Groups
+      ------------
+  
+      A *delta group* expresses the content of a revlog as a series of deltas,
+      or patches against previous revisions.
+  
+      Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
+      to signal the end of the delta group:
+  
+        +------------------------------------------------------------------------+
+        |                |             |               |             |           |
+        | chunk0 length  | chunk0 data | chunk1 length | chunk1 data |    0x0    |
+        |   (32 bits)    |  (various)  |   (32 bits)   |  (various)  | (32 bits) |
+        |                |             |               |             |           |
+        +------------------------------------------------------------+-----------+
+  
+      Each *chunk*'s data consists of the following:
+  
+        +-----------------------------------------+
+        |              |              |           |
+        | delta header | mdiff header |   delta   |
+        |  (various)   |  (12 bytes)  | (various) |
+        |              |              |           |
+        +-----------------------------------------+
+  
+      The *length* field is the byte length of the remaining 3 logical pieces of
+      data. The *delta* is a diff from an existing entry in the changelog.
+  
+      The *delta header* is different between versions "1" and "2" of the
+      changegroup format.
+  
+      Version 1:
+  
+        +------------------------------------------------------+
+        |            |             |             |             |
+        |    node    |   p1 node   |   p2 node   |  link node  |
+        | (20 bytes) |  (20 bytes) |  (20 bytes) |  (20 bytes) |
+        |            |             |             |             |
+        +------------------------------------------------------+
+  
+      Version 2:
+  
+        +------------------------------------------------------------------+
+        |            |             |             |            |            |
+        |    node    |   p1 node   |   p2 node   | base node  | link node  |
+        | (20 bytes) |  (20 bytes) |  (20 bytes) | (20 bytes) | (20 bytes) |
+        |            |             |             |            |            |
+        +------------------------------------------------------------------+
+  
+      The *mdiff header* consists of 3 32-bit big-endian signed integers
+      describing offsets at which to apply the following delta content:
+  
+        +-------------------------------------+
+        |           |            |            |
+        |  offset   | old length | new length |
+        | (32 bits) |  (32 bits) |  (32 bits) |
+        |           |            |            |
+        +-------------------------------------+
+  
+      In version 1, the delta is always applied against the previous node from
+      the changegroup or the first parent if this is the first entry in the
+      changegroup.
+  
+      In version 2, the delta base node is encoded in the entry in the
+      changegroup. This allows the delta to be expressed against any parent,
+      which can result in smaller deltas and more efficient encoding of data.
+  
+      Changeset Segment
+      -----------------
+  
+      The *changeset segment* consists of a single *delta group* holding
+      changelog data. It is followed by an *empty chunk* to denote the boundary
+      to the *manifests segment*.
+  
+      Manifest Segment
+      ----------------
+  
+      The *manifest segment* consists of a single *delta group* holding manifest
+      data. It is followed by an *empty chunk* to denote the boundary to the
+      *filelogs segment*.
+  
+      Filelogs Segment
+      ----------------
+  
+      The *filelogs* segment consists of multiple sub-segments, each
+      corresponding to an individual file whose data is being described:
+  
+        +--------------------------------------+
+        |          |          |          |     |
+        | filelog0 | filelog1 | filelog2 | ... |
+        |          |          |          |     |
+        +--------------------------------------+
+  
+      The final filelog sub-segment is followed by an *empty chunk* to denote
+      the end of the segment and the overall changegroup.
+  
+      Each filelog sub-segment consists of the following:
+  
+        +------------------------------------------+
+        |               |            |             |
+        | filename size |  filename  | delta group |
+        |   (32 bits)   |  (various) |  (various)  |
+        |               |            |             |
+        +------------------------------------------+
+  
+      That is, a *chunk* consisting of the filename (not terminated or padded)
+      followed by N chunks constituting the *delta group* for this file.
+
 Test list of commands with command with no help text
 
   $ hg help helpext
   helpext extension - no help text available
   
   list of commands:
   
    nohelp        (no help text available)


More information about the Mercurial-devel mailing list