Mercurial > hg
comparison mercurial/context.py @ 36918:5d3abd6a5b25
dagop: extract core algorithm of annotate() from context.py
See the previous patch for why.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Wed, 28 Feb 2018 15:19:47 -0500 |
parents | 7affcabf561e |
children | b235bde38a83 |
comparison
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: |