mercurial/context.py
changeset 36918 5d3abd6a5b25
parent 36917 7affcabf561e
child 37065 b235bde38a83
equal deleted inserted replaced
36917:7affcabf561e 36918:5d3abd6a5b25
    30     dagop,
    30     dagop,
    31     encoding,
    31     encoding,
    32     error,
    32     error,
    33     fileset,
    33     fileset,
    34     match as matchmod,
    34     match as matchmod,
    35     mdiff,
       
    36     obsolete as obsmod,
    35     obsolete as obsmod,
    37     obsutil,
    36     obsutil,
    38     patch,
    37     patch,
    39     pathutil,
    38     pathutil,
    40     phases,
    39     phases,
   974         in the file, where ctx is the filectx of the node where
   973         in the file, where ctx is the filectx of the node where
   975         that line was last changed; if linenumber parameter is true, number is
   974         that line was last changed; if linenumber parameter is true, number is
   976         the line number at the first appearance in the managed file, otherwise,
   975         the line number at the first appearance in the managed file, otherwise,
   977         number has a fixed value of False.
   976         number has a fixed value of False.
   978         '''
   977         '''
   979         annotateline = dagop.annotateline
       
   980         _annotatepair = dagop._annotatepair
       
   981 
       
   982         def lines(text):
       
   983             if text.endswith("\n"):
       
   984                 return text.count("\n")
       
   985             return text.count("\n") + int(bool(text))
       
   986 
       
   987         if linenumber:
       
   988             def decorate(text, rev):
       
   989                 return ([annotateline(fctx=rev, lineno=i)
       
   990                          for i in xrange(1, lines(text) + 1)], text)
       
   991         else:
       
   992             def decorate(text, rev):
       
   993                 return ([annotateline(fctx=rev)] * lines(text), text)
       
   994 
       
   995         getlog = util.lrucachefunc(lambda x: self._repo.file(x))
   978         getlog = util.lrucachefunc(lambda x: self._repo.file(x))
   996 
   979 
   997         def parents(f):
   980         def parents(f):
   998             # Cut _descendantrev here to mitigate the penalty of lazy linkrev
   981             # Cut _descendantrev here to mitigate the penalty of lazy linkrev
   999             # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
   982             # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
  1025                                   inclusive=True)
  1008                                   inclusive=True)
  1026             else:
  1009             else:
  1027                 ac = cl.ancestors([base.rev()], inclusive=True)
  1010                 ac = cl.ancestors([base.rev()], inclusive=True)
  1028             base._ancestrycontext = ac
  1011             base._ancestrycontext = ac
  1029 
  1012 
  1030         # This algorithm would prefer to be recursive, but Python is a
  1013         return dagop.annotate(base, parents, linenumber=linenumber,
  1031         # bit recursion-hostile. Instead we do an iterative
  1014                               skiprevs=skiprevs, diffopts=diffopts)
  1032         # depth-first search.
       
  1033 
       
  1034         # 1st DFS pre-calculates pcache and needed
       
  1035         visit = [base]
       
  1036         pcache = {}
       
  1037         needed = {base: 1}
       
  1038         while visit:
       
  1039             f = visit.pop()
       
  1040             if f in pcache:
       
  1041                 continue
       
  1042             pl = parents(f)
       
  1043             pcache[f] = pl
       
  1044             for p in pl:
       
  1045                 needed[p] = needed.get(p, 0) + 1
       
  1046                 if p not in pcache:
       
  1047                     visit.append(p)
       
  1048 
       
  1049         # 2nd DFS does the actual annotate
       
  1050         visit[:] = [base]
       
  1051         hist = {}
       
  1052         while visit:
       
  1053             f = visit[-1]
       
  1054             if f in hist:
       
  1055                 visit.pop()
       
  1056                 continue
       
  1057 
       
  1058             ready = True
       
  1059             pl = pcache[f]
       
  1060             for p in pl:
       
  1061                 if p not in hist:
       
  1062                     ready = False
       
  1063                     visit.append(p)
       
  1064             if ready:
       
  1065                 visit.pop()
       
  1066                 curr = decorate(f.data(), f)
       
  1067                 skipchild = False
       
  1068                 if skiprevs is not None:
       
  1069                     skipchild = f._changeid in skiprevs
       
  1070                 curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild,
       
  1071                                      diffopts)
       
  1072                 for p in pl:
       
  1073                     if needed[p] == 1:
       
  1074                         del hist[p]
       
  1075                         del needed[p]
       
  1076                     else:
       
  1077                         needed[p] -= 1
       
  1078 
       
  1079                 hist[f] = curr
       
  1080                 del pcache[f]
       
  1081 
       
  1082         lineattrs, text = hist[base]
       
  1083         return pycompat.ziplist(lineattrs, mdiff.splitnewlines(text))
       
  1084 
  1015 
  1085     def ancestors(self, followfirst=False):
  1016     def ancestors(self, followfirst=False):
  1086         visit = {}
  1017         visit = {}
  1087         c = self
  1018         c = self
  1088         if followfirst:
  1019         if followfirst: