# HG changeset patch # User Matt Mackall # Date 1163446017 21600 # Node ID b984dcb1df71fe36a45a8d234c8a816a28d60160 # Parent b7547efe78fbb43a1393b4892b6675c3ba7d32ad Refactor log ui buffering and patch display diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -9,7 +9,7 @@ from demandload import demandload from node import * from i18n import gettext as _ demandload(globals(), 'os sys') -demandload(globals(), 'mdiff util templater cStringIO') +demandload(globals(), 'mdiff util templater cStringIO patch') revrangesep = ':' @@ -196,15 +196,63 @@ def addremove(repo, pats=[], opts={}, wl if not dry_run: repo.copy(old, new, wlock=wlock) +class uibuffer(object): + # Implement and delegate some ui protocol. Save hunks of + # output for later display in the desired order. + def __init__(self, ui): + self.ui = ui + self.hunk = {} + self.header = {} + self.quiet = ui.quiet + self.verbose = ui.verbose + self.debugflag = ui.debugflag + self.lastheader = None + def note(self, *args): + if self.verbose: + self.write(*args) + def status(self, *args): + if not self.quiet: + self.write(*args) + def debug(self, *args): + if self.debugflag: + self.write(*args) + def write(self, *args): + self.hunk.setdefault(self.rev, []).extend(args) + def write_header(self, *args): + self.header.setdefault(self.rev, []).extend(args) + def mark(self, rev): + self.rev = rev + def flush(self, rev): + if rev in self.header: + h = "".join(self.header[rev]) + if h != self.lastheader: + self.lastheader = h + self.ui.write(h) + del self.header[rev] + if rev in self.hunk: + self.ui.write("".join(self.hunk[rev])) + del self.hunk[rev] + return 1 + return 0 + class changeset_printer(object): '''show changeset information when templating not requested.''' - def __init__(self, ui, repo): + def __init__(self, ui, repo, patch, buffered): self.ui = ui self.repo = repo + self.buffered = buffered + self.patch = patch + if buffered: + self.ui = uibuffer(ui) + + def flush(self, rev): + return self.ui.flush(rev) def show(self, rev=0, changenode=None, brinfo=None, copies=None): '''show a single changeset or file revision''' + if self.buffered: + self.ui.mark(rev) log = self.repo.changelog if changenode is None: changenode = log.node(rev) @@ -280,17 +328,23 @@ class changeset_printer(object): description.splitlines()[0]) self.ui.write("\n") -class changeset_templater(object): + self.showpatch(changenode) + + def showpatch(self, node): + if self.patch: + prev = self.repo.changelog.parents(node)[0] + patch.diff(self.repo, prev, node, fp=self.ui) + self.ui.write("\n") + +class changeset_templater(changeset_printer): '''format changeset information.''' - def __init__(self, ui, repo, mapfile, dest=None): + def __init__(self, ui, repo, patch, mapfile, buffered): + changeset_printer.__init__(self, ui, repo, patch, buffered) self.t = templater.templater(mapfile, templater.common_filters, cache={'parent': '{rev}:{node|short} ', 'manifest': '{rev}:{node|short}', 'filecopy': '{name} ({source})'}) - self.ui = ui - self.dest = dest - self.repo = repo def use_template(self, t): '''set template string to use''' @@ -298,6 +352,8 @@ class changeset_templater(object): def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props): '''show a single changeset or file revision''' + if self.buffered: + self.ui.mark(rev) log = self.repo.changelog if changenode is None: changenode = log.node(rev) @@ -440,7 +496,6 @@ class changeset_templater(object): props.update(defprops) try: - dest = self.dest or self.ui if self.ui.debugflag and 'header_debug' in self.t: key = 'header_debug' elif self.ui.quiet and 'header_quiet' in self.t: @@ -452,7 +507,11 @@ class changeset_templater(object): else: key = '' if key: - dest.write_header(templater.stringify(self.t(key, **props))) + h = templater.stringify(self.t(key, **props)) + if self.buffered: + self.ui.write_header(h) + else: + self.ui.write(h) if self.ui.debugflag and 'changeset_debug' in self.t: key = 'changeset_debug' elif self.ui.quiet and 'changeset_quiet' in self.t: @@ -461,7 +520,8 @@ class changeset_templater(object): key = 'changeset_verbose' else: key = 'changeset' - dest.write(templater.stringify(self.t(key, **props))) + self.ui.write(templater.stringify(self.t(key, **props))) + self.showpatch(changenode) except KeyError, inst: raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile, inst.args[0])) @@ -482,7 +542,7 @@ class stringio(object): def __getattr__(self, key): return getattr(self.fp, key) -def show_changeset(ui, repo, opts): +def show_changeset(ui, repo, opts, buffered=False): """show one changeset using template or regular display. Display format will be the first non-empty hit of: @@ -494,6 +554,7 @@ def show_changeset(ui, repo, opts): regular display via changeset_printer() is done. """ # options + patch = opts.get('patch') tmpl = opts.get('template') mapfile = None if tmpl: @@ -515,10 +576,10 @@ def show_changeset(ui, repo, opts): or templater.templatepath(mapfile)) if mapname: mapfile = mapname try: - t = changeset_templater(ui, repo, mapfile) + t = changeset_templater(ui, repo, patch, mapfile, buffered) except SyntaxError, inst: raise util.Abort(inst.args[0]) if tmpl: t.use_template(tmpl) return t - return changeset_printer(ui, repo) + return changeset_printer(ui, repo, patch, buffered) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -1592,10 +1592,6 @@ def incoming(ui, repo, source="default", if opts['no_merges'] and len(parents) == 2: continue displayer.show(changenode=n) - if opts['patch']: - prev = (parents and parents[0]) or nullid - patch.diff(other, prev, n, fp=repo.ui) - ui.write("\n") finally: if hasattr(other, 'close'): other.close() @@ -1672,35 +1668,6 @@ def log(ui, repo, *pats, **opts): commit. When the -v/--verbose switch is used, the list of changed files and full commit message is shown. """ - class dui(object): - # Implement and delegate some ui protocol. Save hunks of - # output for later display in the desired order. - def __init__(self, ui): - self.ui = ui - self.hunk = {} - self.header = {} - self.quiet = ui.quiet - self.verbose = ui.verbose - self.debugflag = ui.debugflag - def bump(self, rev): - self.rev = rev - self.hunk[rev] = [] - self.header[rev] = [] - def note(self, *args): - if self.verbose: - self.write(*args) - def status(self, *args): - if not self.quiet: - self.write(*args) - def write(self, *args): - self.hunk[self.rev].extend(args) - def write_header(self, *args): - self.header[self.rev].extend(args) - def debug(self, *args): - if self.debugflag: - self.write(*args) - def __getattr__(self, key): - return getattr(self.ui, key) getchange = util.cachefunc(lambda r:repo.changectx(r).changeset()) changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts) @@ -1755,13 +1722,9 @@ def log(ui, repo, *pats, **opts): return ncache[fn].get(dcache[1][fn]) return None - displayer = cmdutil.show_changeset(ui, repo, opts) + displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True) for st, rev, fns in changeiter: - if st == 'window': - du = dui(ui) - displayer.ui = du - elif st == 'add': - du.bump(rev) + if st == 'add': changenode = repo.changelog.node(rev) parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev] @@ -1794,21 +1757,10 @@ def log(ui, repo, *pats, **opts): if rename: copies.append((fn, rename[0])) displayer.show(rev, changenode, brinfo=br, copies=copies) - if opts['patch']: - if parents: - prev = parents[0] - else: - prev = nullrev - prev = repo.changelog.node(prev) - patch.diff(repo, prev, changenode, match=matchfn, fp=du) - du.write("\n\n") elif st == 'iter': if count == limit: break - if du.header[rev]: - ui.write_header(*du.header[rev]) - if du.hunk[rev]: + if displayer.flush(rev): count += 1 - ui.write(*du.hunk[rev]) def manifest(ui, repo, rev=None): """output the latest or given revision of the project manifest @@ -1897,10 +1849,6 @@ def outgoing(ui, repo, dest=None, **opts if opts['no_merges'] and len(parents) == 2: continue displayer.show(changenode=n) - if opts['patch']: - prev = (parents and parents[0]) or nullid - patch.diff(repo, prev, n) - ui.write("\n") def parents(ui, repo, file_=None, rev=None, branches=None, **opts): """show the parents of the working dir or revision @@ -2560,8 +2508,6 @@ def tip(ui, repo, **opts): "please use 'hg branches' instead\n")) br = repo.branchlookup([n]) cmdutil.show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) - if opts['patch']: - patch.diff(repo, repo.changelog.parents(n)[0], n) def unbundle(ui, repo, fname, **opts): """apply a changegroup file diff --git a/tests/test-remove.out b/tests/test-remove.out --- a/tests/test-remove.out +++ b/tests/test-remove.out @@ -37,7 +37,6 @@ diff -r 000000000000 -r 8ba83d44753d foo @@ -0,0 +1,1 @@ +a - changeset: 1:a1fce69c50d9 tag: tip user: test @@ -50,7 +49,6 @@ diff -r 8ba83d44753d -r a1fce69c50d9 foo @@ -1,1 +0,0 @@ -a - not removing a: file has been marked for add (use -f to force removal) adding a adding b