Add basic annotation support
authormpm@selenic.com
Tue, 17 May 2005 01:12:30 -0800
changeset 79 837d473d54d5
parent 78 85f1f87dc8ff
child 80 5b7a444c794a
Add basic annotation support filelog.annotate() will get the change number on each line. Singed-Off-by: Christopher Li<hg@chrisli.org>
hg
mercurial/hg.py
--- a/hg	Tue May 17 01:07:57 2005 -0800
+++ b/hg	Tue May 17 01:12:30 2005 -0800
@@ -199,6 +199,21 @@
 
     diff(args, *revs)
 
+elif cmd == "annotate":
+    aoptions = {}
+    opts = [('r', 'revision', '', 'revision')]
+    args = fancyopts.fancyopts(args, opts, aoptions,
+                               'hg annotate [-r id] [files]')
+    if args:
+        node = repo.current
+        if aoptions['revision']:
+            node = repo.changelog.lookup(aoptions['revision'])
+        change = repo.changelog.read(node)
+        mmap = repo.manifest.read(change[0])
+        for f in args:
+            for n, l in repo.file(f).annotate(mmap[f]):
+                sys.stdout.write("%s: %s"%(n, l))
+
 elif cmd == "export":
     node = repo.lookup(args[0])
     prev, other = repo.changelog.parents(node)
--- a/mercurial/hg.py	Tue May 17 01:07:57 2005 -0800
+++ b/mercurial/hg.py	Tue May 17 01:12:30 2005 -0800
@@ -10,6 +10,7 @@
 from mercurial import byterange
 from mercurial.transaction import *
 from mercurial.revlog import *
+from difflib import SequenceMatcher
 
 class filelog(revlog):
     def __init__(self, opener, path):
@@ -65,6 +66,32 @@
         (o, n) = self.mergedag(other, transaction, linkseq)
         return self.resolvedag(o, n, transaction, link)
 
+    def annotate(self, node):
+        revs = []
+        while node != nullid:
+            revs.append(node)
+            node = self.parents(node)[0]
+        revs.reverse()
+        prev = []
+        annotate = []
+        for node in revs:
+            curr = self.read(node).splitlines(1)
+            linkrev = self.linkrev(node)
+            sm = SequenceMatcher(None, prev, curr)
+            offset = 0
+            for o, m, n, s, t in sm.get_opcodes():
+                if o in ('insert','replace'):
+                    annotate[m+offset:n+offset] = \
+                        [ (linkrev, l) for l in curr[s:t]]
+                    if o == 'insert':
+                        offset += m-n
+                elif o == 'delete':
+                    del annotate[m+offset:n+offset]
+                    offset -= m-n
+            assert len(annotate) == len(curr)
+            prev = curr
+        return annotate
+
 class manifest(revlog):
     def __init__(self, opener):
         self.mapcache = None