Mercurial > hg
comparison mercurial/logcmdutil.py @ 36003:fcde8946c553
logcmdutil: hold makefilematcher/makehunksfilter() by changesetpriner (API)
This merges self.matchfn and self.show(matchfn) into self._makefilematcher,
and does the same for hunksfilter. Because changesetprinter seems to have
too many optional arguments, makefilematcher() and makehunksfilter() will
be packed into one object by later patch.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 21 Jan 2018 14:07:52 +0900 |
parents | f8ad57d24252 |
children | d4c210ee894f |
comparison
equal
deleted
inserted
replaced
36002:f8ad57d24252 | 36003:fcde8946c553 |
---|---|
133 return ' '.join(labels) | 133 return ' '.join(labels) |
134 | 134 |
135 class changesetprinter(object): | 135 class changesetprinter(object): |
136 '''show changeset information when templating not requested.''' | 136 '''show changeset information when templating not requested.''' |
137 | 137 |
138 def __init__(self, ui, repo, matchfn=None, diffopts=None, buffered=False): | 138 def __init__(self, ui, repo, makefilematcher=None, makehunksfilter=None, |
139 diffopts=None, buffered=False): | |
139 self.ui = ui | 140 self.ui = ui |
140 self.repo = repo | 141 self.repo = repo |
141 self.buffered = buffered | 142 self.buffered = buffered |
142 self.matchfn = matchfn | 143 self._makefilematcher = makefilematcher or (lambda ctx: None) |
144 self._makehunksfilter = makehunksfilter or (lambda ctx: None) | |
143 self.diffopts = diffopts or {} | 145 self.diffopts = diffopts or {} |
144 self.header = {} | 146 self.header = {} |
145 self.hunk = {} | 147 self.hunk = {} |
146 self.lastheader = None | 148 self.lastheader = None |
147 self.footer = None | 149 self.footer = None |
161 | 163 |
162 def close(self): | 164 def close(self): |
163 if self.footer: | 165 if self.footer: |
164 self.ui.write(self.footer) | 166 self.ui.write(self.footer) |
165 | 167 |
166 def show(self, ctx, copies=None, matchfn=None, hunksfilterfn=None, | 168 def show(self, ctx, copies=None, **props): |
167 **props): | |
168 props = pycompat.byteskwargs(props) | 169 props = pycompat.byteskwargs(props) |
169 if self.buffered: | 170 if self.buffered: |
170 self.ui.pushbuffer(labeled=True) | 171 self.ui.pushbuffer(labeled=True) |
171 self._show(ctx, copies, matchfn, hunksfilterfn, props) | 172 self._show(ctx, copies, props) |
172 self.hunk[ctx.rev()] = self.ui.popbuffer() | 173 self.hunk[ctx.rev()] = self.ui.popbuffer() |
173 else: | 174 else: |
174 self._show(ctx, copies, matchfn, hunksfilterfn, props) | 175 self._show(ctx, copies, props) |
175 | 176 |
176 def _show(self, ctx, copies, matchfn, hunksfilterfn, props): | 177 def _show(self, ctx, copies, props): |
177 '''show a single changeset or file revision''' | 178 '''show a single changeset or file revision''' |
178 changenode = ctx.node() | 179 changenode = ctx.node() |
179 rev = ctx.rev() | 180 rev = ctx.rev() |
180 | 181 |
181 if self.ui.quiet: | 182 if self.ui.quiet: |
262 else: | 263 else: |
263 self.ui.write(columns['summary'] % description.splitlines()[0], | 264 self.ui.write(columns['summary'] % description.splitlines()[0], |
264 label='log.summary') | 265 label='log.summary') |
265 self.ui.write("\n") | 266 self.ui.write("\n") |
266 | 267 |
267 self._showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn) | 268 self._showpatch(ctx) |
268 | 269 |
269 def _showobsfate(self, ctx): | 270 def _showobsfate(self, ctx): |
270 obsfate = templatekw.showobsfate(repo=self.repo, ctx=ctx, ui=self.ui) | 271 obsfate = templatekw.showobsfate(repo=self.repo, ctx=ctx, ui=self.ui) |
271 | 272 |
272 if obsfate: | 273 if obsfate: |
276 | 277 |
277 def _exthook(self, ctx): | 278 def _exthook(self, ctx): |
278 '''empty method used by extension as a hook point | 279 '''empty method used by extension as a hook point |
279 ''' | 280 ''' |
280 | 281 |
281 def _showpatch(self, ctx, matchfn, hunksfilterfn=None): | 282 def _showpatch(self, ctx): |
282 if not matchfn: | 283 matchfn = self._makefilematcher(ctx) |
283 matchfn = self.matchfn | 284 hunksfilterfn = self._makehunksfilter(ctx) |
284 if matchfn: | 285 if matchfn: |
285 stat = self.diffopts.get('stat') | 286 stat = self.diffopts.get('stat') |
286 diff = self.diffopts.get('patch') | 287 diff = self.diffopts.get('patch') |
287 diffopts = patch.diffallopts(self.ui, self.diffopts) | 288 diffopts = patch.diffallopts(self.ui, self.diffopts) |
288 node = ctx.node() | 289 node = ctx.node() |
301 self.ui.write("\n") | 302 self.ui.write("\n") |
302 | 303 |
303 class jsonchangeset(changesetprinter): | 304 class jsonchangeset(changesetprinter): |
304 '''format changeset information.''' | 305 '''format changeset information.''' |
305 | 306 |
306 def __init__(self, ui, repo, matchfn=None, diffopts=None, buffered=False): | 307 def __init__(self, ui, repo, makefilematcher=None, makehunksfilter=None, |
307 changesetprinter.__init__(self, ui, repo, matchfn, diffopts, buffered) | 308 diffopts=None, buffered=False): |
309 changesetprinter.__init__(self, ui, repo, makefilematcher, | |
310 makehunksfilter, diffopts, buffered) | |
308 self.cache = {} | 311 self.cache = {} |
309 self._first = True | 312 self._first = True |
310 | 313 |
311 def close(self): | 314 def close(self): |
312 if not self._first: | 315 if not self._first: |
313 self.ui.write("\n]\n") | 316 self.ui.write("\n]\n") |
314 else: | 317 else: |
315 self.ui.write("[]\n") | 318 self.ui.write("[]\n") |
316 | 319 |
317 def _show(self, ctx, copies, matchfn, hunksfilterfn, props): | 320 def _show(self, ctx, copies, props): |
318 '''show a single changeset or file revision''' | 321 '''show a single changeset or file revision''' |
319 rev = ctx.rev() | 322 rev = ctx.rev() |
320 if rev is None: | 323 if rev is None: |
321 jrev = jnode = 'null' | 324 jrev = jnode = 'null' |
322 else: | 325 else: |
377 if copies: | 380 if copies: |
378 self.ui.write((',\n "copies": {%s}') % | 381 self.ui.write((',\n "copies": {%s}') % |
379 ", ".join('"%s": "%s"' % (j(k), j(v)) | 382 ", ".join('"%s": "%s"' % (j(k), j(v)) |
380 for k, v in copies)) | 383 for k, v in copies)) |
381 | 384 |
382 matchfn = self.matchfn | 385 matchfn = self._makefilematcher(ctx) |
383 if matchfn: | 386 if matchfn: |
384 stat = self.diffopts.get('stat') | 387 stat = self.diffopts.get('stat') |
385 diff = self.diffopts.get('patch') | 388 diff = self.diffopts.get('patch') |
386 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True) | 389 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True) |
387 node, prev = ctx.node(), ctx.p1().node() | 390 node, prev = ctx.node(), ctx.p1().node() |
408 functions that use changesest_templater. | 411 functions that use changesest_templater. |
409 ''' | 412 ''' |
410 | 413 |
411 # Arguments before "buffered" used to be positional. Consider not | 414 # Arguments before "buffered" used to be positional. Consider not |
412 # adding/removing arguments before "buffered" to not break callers. | 415 # adding/removing arguments before "buffered" to not break callers. |
413 def __init__(self, ui, repo, tmplspec, matchfn=None, diffopts=None, | 416 def __init__(self, ui, repo, tmplspec, makefilematcher=None, |
414 buffered=False): | 417 makehunksfilter=None, diffopts=None, buffered=False): |
415 changesetprinter.__init__(self, ui, repo, matchfn, diffopts, buffered) | 418 changesetprinter.__init__(self, ui, repo, makefilematcher, |
419 makehunksfilter, diffopts, buffered) | |
416 tres = formatter.templateresources(ui, repo) | 420 tres = formatter.templateresources(ui, repo) |
417 self.t = formatter.loadtemplater(ui, tmplspec, | 421 self.t = formatter.loadtemplater(ui, tmplspec, |
418 defaults=templatekw.keywords, | 422 defaults=templatekw.keywords, |
419 resources=tres, | 423 resources=tres, |
420 cache=templatekw.defaulttempl) | 424 cache=templatekw.defaulttempl) |
453 if not self.footer: | 457 if not self.footer: |
454 self.footer = "" | 458 self.footer = "" |
455 self.footer += templater.stringify(self.t(self._parts['docfooter'])) | 459 self.footer += templater.stringify(self.t(self._parts['docfooter'])) |
456 return super(changesettemplater, self).close() | 460 return super(changesettemplater, self).close() |
457 | 461 |
458 def _show(self, ctx, copies, matchfn, hunksfilterfn, props): | 462 def _show(self, ctx, copies, props): |
459 '''show a single changeset or file revision''' | 463 '''show a single changeset or file revision''' |
460 props = props.copy() | 464 props = props.copy() |
461 props['ctx'] = ctx | 465 props['ctx'] = ctx |
462 props['index'] = index = next(self._counter) | 466 props['index'] = index = next(self._counter) |
463 props['revcache'] = {'copies': copies} | 467 props['revcache'] = {'copies': copies} |
480 self.ui.write(h) | 484 self.ui.write(h) |
481 | 485 |
482 # write changeset metadata, then patch if requested | 486 # write changeset metadata, then patch if requested |
483 key = self._parts[self._tref] | 487 key = self._parts[self._tref] |
484 self.ui.write(templater.stringify(self.t(key, **props))) | 488 self.ui.write(templater.stringify(self.t(key, **props))) |
485 self._showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn) | 489 self._showpatch(ctx) |
486 | 490 |
487 if self._parts['footer']: | 491 if self._parts['footer']: |
488 if not self.footer: | 492 if not self.footer: |
489 self.footer = templater.stringify( | 493 self.footer = templater.stringify( |
490 self.t(self._parts['footer'], **props)) | 494 self.t(self._parts['footer'], **props)) |
527 """Create a changesettemplater from a literal template 'tmpl' | 531 """Create a changesettemplater from a literal template 'tmpl' |
528 byte-string.""" | 532 byte-string.""" |
529 spec = templatespec(tmpl, None) | 533 spec = templatespec(tmpl, None) |
530 return changesettemplater(ui, repo, spec, buffered=buffered) | 534 return changesettemplater(ui, repo, spec, buffered=buffered) |
531 | 535 |
532 def changesetdisplayer(ui, repo, opts, buffered=False): | 536 def changesetdisplayer(ui, repo, opts, makefilematcher=None, |
537 makehunksfilter=None, buffered=False): | |
533 """show one changeset using template or regular display. | 538 """show one changeset using template or regular display. |
534 | 539 |
535 Display format will be the first non-empty hit of: | 540 Display format will be the first non-empty hit of: |
536 1. option 'template' | 541 1. option 'template' |
537 2. option 'style' | 542 2. option 'style' |
539 4. [ui] setting 'style' | 544 4. [ui] setting 'style' |
540 If all of these values are either the unset or the empty string, | 545 If all of these values are either the unset or the empty string, |
541 regular display via changesetprinter() is done. | 546 regular display via changesetprinter() is done. |
542 """ | 547 """ |
543 # options | 548 # options |
544 match = None | 549 if not makefilematcher and (opts.get('patch') or opts.get('stat')): |
545 if opts.get('patch') or opts.get('stat'): | 550 def makefilematcher(ctx): |
546 match = scmutil.matchall(repo) | 551 return scmutil.matchall(repo) |
547 | 552 |
553 postargs = (makefilematcher, makehunksfilter, opts, buffered) | |
548 if opts.get('template') == 'json': | 554 if opts.get('template') == 'json': |
549 return jsonchangeset(ui, repo, match, opts, buffered) | 555 return jsonchangeset(ui, repo, *postargs) |
550 | 556 |
551 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style')) | 557 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style')) |
552 | 558 |
553 if not spec.ref and not spec.tmpl and not spec.mapfile: | 559 if not spec.ref and not spec.tmpl and not spec.mapfile: |
554 return changesetprinter(ui, repo, match, opts, buffered) | 560 return changesetprinter(ui, repo, *postargs) |
555 | 561 |
556 return changesettemplater(ui, repo, spec, match, opts, buffered) | 562 return changesettemplater(ui, repo, spec, *postargs) |
557 | 563 |
558 def _makematcher(repo, revs, pats, opts): | 564 def _makematcher(repo, revs, pats, opts): |
559 """Build matcher and expanded patterns from log options | 565 """Build matcher and expanded patterns from log options |
560 | 566 |
561 If --follow, revs are the revisions to follow from. | 567 If --follow, revs are the revisions to follow from. |
859 def formatnode(repo, ctx): | 865 def formatnode(repo, ctx): |
860 props = {'ctx': ctx, 'repo': repo, 'revcache': {}} | 866 props = {'ctx': ctx, 'repo': repo, 'revcache': {}} |
861 return templ.render(props) | 867 return templ.render(props) |
862 return formatnode | 868 return formatnode |
863 | 869 |
864 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, | 870 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, props=None): |
865 filematcher=None, props=None): | |
866 props = props or {} | 871 props = props or {} |
867 formatnode = _graphnodeformatter(ui, displayer) | 872 formatnode = _graphnodeformatter(ui, displayer) |
868 state = graphmod.asciistate() | 873 state = graphmod.asciistate() |
869 styles = state['styles'] | 874 styles = state['styles'] |
870 | 875 |
895 copies = [] | 900 copies = [] |
896 for fn in ctx.files(): | 901 for fn in ctx.files(): |
897 rename = getrenamed(fn, ctx.rev()) | 902 rename = getrenamed(fn, ctx.rev()) |
898 if rename: | 903 if rename: |
899 copies.append((fn, rename[0])) | 904 copies.append((fn, rename[0])) |
900 revmatchfn = None | |
901 if filematcher is not None: | |
902 revmatchfn = filematcher(ctx) | |
903 edges = edgefn(type, char, state, rev, parents) | 905 edges = edgefn(type, char, state, rev, parents) |
904 firstedge = next(edges) | 906 firstedge = next(edges) |
905 width = firstedge[2] | 907 width = firstedge[2] |
906 displayer.show(ctx, copies=copies, matchfn=revmatchfn, | 908 displayer.show(ctx, copies=copies, |
907 _graphwidth=width, **pycompat.strkwargs(props)) | 909 _graphwidth=width, **pycompat.strkwargs(props)) |
908 lines = displayer.hunk.pop(rev).split('\n') | 910 lines = displayer.hunk.pop(rev).split('\n') |
909 if not lines[-1]: | 911 if not lines[-1]: |
910 del lines[-1] | 912 del lines[-1] |
911 displayer.flush(ctx) | 913 displayer.flush(ctx) |
924 if opts.get('rev'): | 926 if opts.get('rev'): |
925 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1 | 927 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1 |
926 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev) | 928 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev) |
927 | 929 |
928 ui.pager('log') | 930 ui.pager('log') |
929 displayer = changesetdisplayer(ui, repo, opts, buffered=True) | 931 displayer = changesetdisplayer(ui, repo, opts, makefilematcher=filematcher, |
930 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed, | 932 buffered=True) |
931 filematcher) | 933 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed) |
932 | 934 |
933 def checkunsupportedgraphflags(pats, opts): | 935 def checkunsupportedgraphflags(pats, opts): |
934 for op in ["newest_first"]: | 936 for op in ["newest_first"]: |
935 if op in opts and opts[op]: | 937 if op in opts and opts[op]: |
936 raise error.Abort(_("-G/--graph option is incompatible with --%s") | 938 raise error.Abort(_("-G/--graph option is incompatible with --%s") |