Mercurial > hg
changeset 15528:a84698badf0b
annotate: support diff whitespace filtering flags (issue3030)
splitblock() was added to handle blocks returned by bdiff.blocks() which differ
only by blank lines but are not made only of blank lines. I do not know exactly
how it could happen but mdiff.blocks() threshold behaviour makes me think it
can if those blocks are made of very popular lines mixed with popular blank
lines. If it is proven to be wrong, the function can be dropped.
The first implementation made annotate share diff configuration entries. But it
looks like users will user -w/b for annotate but not for diff, on both the
command line and hgweb. Since the latter cannot use command line entries, we
introduce a new [annotate] section duplicating the diff whitespace options.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Fri, 18 Nov 2011 12:04:31 +0100 |
parents | 9926aab3d0b5 |
children | b35cf47286a6 |
files | mercurial/commands.py mercurial/context.py mercurial/help/config.txt mercurial/hgweb/webcommands.py mercurial/mdiff.py mercurial/patch.py tests/test-annotate.t tests/test-debugcomplete.t |
diffstat | 8 files changed, 132 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/commands.py Fri Nov 18 12:04:31 2011 +0100 @@ -106,15 +106,19 @@ ('', 'nodates', None, _('omit dates from diff headers')) ] -diffopts2 = [ - ('p', 'show-function', None, _('show which function each change is in')), - ('', 'reverse', None, _('produce a diff that undoes the changes')), +diffwsopts = [ ('w', 'ignore-all-space', None, _('ignore white space when comparing lines')), ('b', 'ignore-space-change', None, _('ignore changes in the amount of white space')), ('B', 'ignore-blank-lines', None, _('ignore changes whose lines are all blank')), + ] + +diffopts2 = [ + ('p', 'show-function', None, _('show which function each change is in')), + ('', 'reverse', None, _('produce a diff that undoes the changes')), + ] + diffwsopts + [ ('U', 'unified', '', _('number of lines of context to show'), _('NUM')), ('', 'stat', None, _('output diffstat-style summary of changes')), @@ -215,7 +219,7 @@ ('n', 'number', None, _('list the revision number (default)')), ('c', 'changeset', None, _('list the changeset')), ('l', 'line-number', None, _('show line number at the first appearance')) - ] + walkopts, + ] + diffwsopts + walkopts, _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')) def annotate(ui, repo, *pats, **opts): """show changeset information by line for each file @@ -270,13 +274,15 @@ m = scmutil.match(ctx, pats, opts) m.bad = bad follow = not opts.get('no_follow') + diffopts = patch.diffopts(ui, opts, section='annotate') for abs in ctx.walk(m): fctx = ctx[abs] if not opts.get('text') and util.binary(fctx.data()): ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) continue - lines = fctx.annotate(follow=follow, linenumber=linenumber) + lines = fctx.annotate(follow=follow, linenumber=linenumber, + diffopts=diffopts) pieces = [] for f, sep in funcmap:
--- a/mercurial/context.py Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/context.py Fri Nov 18 12:04:31 2011 +0100 @@ -7,7 +7,7 @@ from node import nullid, nullrev, short, hex from i18n import _ -import ancestor, bdiff, error, util, scmutil, subrepo, patch, encoding +import ancestor, mdiff, error, util, scmutil, subrepo, patch, encoding import match as matchmod import os, errno, stat @@ -433,7 +433,7 @@ return [filectx(self._repo, self._path, fileid=x, filelog=self._filelog) for x in c] - def annotate(self, follow=False, linenumber=None): + def annotate(self, follow=False, linenumber=None, diffopts=None): '''returns a list of tuples of (ctx, line) for each line in the file, where ctx is the filectx of the node where that line was last changed. @@ -460,8 +460,13 @@ without_linenumber) def pair(parent, child): - for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]): - child[0][b1:b2] = parent[0][a1:a2] + blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts, + refine=True) + for (a1, a2, b1, b2), t in blocks: + # Changed blocks ('!') or blocks made only of blank lines ('~') + # belong to the child. + if t == '=': + child[0][b1:b2] = parent[0][a1:a2] return child getlog = util.lrucachefunc(lambda x: self._repo.file(x))
--- a/mercurial/help/config.txt Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/help/config.txt Fri Nov 18 12:04:31 2011 +0100 @@ -227,6 +227,24 @@ processed before shell aliases and will thus not be passed to aliases. + +``annotate`` +"""""""" + +Settings used when displaying file annotations. All values are +Booleans and default to False. See ``diff`` section for related +options for the diff command. + +``ignorews`` + Ignore white space when comparing lines. + +``ignorewsamount`` + Ignore changes in the amount of white space. + +``ignoreblanklines`` + Ignore changes whose lines are all blank. + + ``auth`` """""""" @@ -364,8 +382,9 @@ ``diff`` """""""" -Settings used when displaying diffs. Everything except for ``unified`` is a -Boolean and defaults to False. +Settings used when displaying diffs. Everything except for ``unified`` +is a Boolean and defaults to False. See ``annotate`` section for +related options for the annotate command. ``git`` Use git extended diff format.
--- a/mercurial/hgweb/webcommands.py Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/hgweb/webcommands.py Fri Nov 18 12:04:31 2011 +0100 @@ -12,7 +12,7 @@ from mercurial.util import binary from common import paritygen, staticfile, get_contact, ErrorResponse from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND -from mercurial import graphmod +from mercurial import graphmod, patch from mercurial import help as helpmod from mercurial.i18n import _ @@ -576,6 +576,7 @@ fctx = webutil.filectx(web.repo, req) f = fctx.path() parity = paritygen(web.stripecount) + diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate') def annotate(**map): last = None @@ -585,7 +586,8 @@ lines = enumerate([((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)]) else: - lines = enumerate(fctx.annotate(follow=True, linenumber=True)) + lines = enumerate(fctx.annotate(follow=True, linenumber=True, + diffopts=diffopts)) for lineno, ((f, targetline), l) in lines: fnode = f.filenode()
--- a/mercurial/mdiff.py Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/mdiff.py Fri Nov 18 12:04:31 2011 +0100 @@ -75,11 +75,38 @@ text = re.sub('\n+', '\n', text).strip('\n') return text -def allblocks(text1, text2, opts=None, lines1=None, lines2=None): +def splitblock(base1, lines1, base2, lines2, opts): + # The input lines matches except for interwoven blank lines. We + # transform it into a sequence of matching blocks and blank blocks. + lines1 = [(wsclean(opts, l) and 1 or 0) for l in lines1] + lines2 = [(wsclean(opts, l) and 1 or 0) for l in lines2] + s1, e1 = 0, len(lines1) + s2, e2 = 0, len(lines2) + while s1 < e1 or s2 < e2: + i1, i2, btype = s1, s2, '=' + if (i1 >= e1 or lines1[i1] == 0 + or i2 >= e2 or lines2[i2] == 0): + # Consume the block of blank lines + btype = '~' + while i1 < e1 and lines1[i1] == 0: + i1 += 1 + while i2 < e2 and lines2[i2] == 0: + i2 += 1 + else: + # Consume the matching lines + while i1 < e1 and lines1[i1] == 1 and lines2[i2] == 1: + i1 += 1 + i2 += 1 + yield [base1 + s1, base1 + i1, base2 + s2, base2 + i2], btype + s1 = i1 + s2 = i2 + +def allblocks(text1, text2, opts=None, lines1=None, lines2=None, refine=False): """Return (block, type) tuples, where block is an mdiff.blocks line entry. type is '=' for blocks matching exactly one another (bdiff blocks), '!' for non-matching blocks and '~' for blocks - matching only after having filtered blank lines. + matching only after having filtered blank lines. If refine is True, + then '~' blocks are refined and are only made of blank lines. line1 and line2 are text1 and text2 split with splitnewlines() if they are already available. """
--- a/mercurial/patch.py Sun Nov 20 19:14:36 2011 +0100 +++ b/mercurial/patch.py Fri Nov 18 12:04:31 2011 +0100 @@ -1527,10 +1527,10 @@ class GitDiffRequired(Exception): pass -def diffopts(ui, opts=None, untrusted=False): +def diffopts(ui, opts=None, untrusted=False, section='diff'): def get(key, name=None, getter=ui.configbool): return ((opts and opts.get(key)) or - getter('diff', name or key, None, untrusted=untrusted)) + getter(section, name or key, None, untrusted=untrusted)) return mdiff.diffopts( text=opts and opts.get('text'), git=get('git'),
--- a/tests/test-annotate.t Sun Nov 20 19:14:36 2011 +0100 +++ b/tests/test-annotate.t Fri Nov 18 12:04:31 2011 +0100 @@ -2,7 +2,8 @@ init - $ hg init + $ hg init repo + $ cd repo commit @@ -253,3 +254,56 @@ $ hg ann nosuchfile abort: nosuchfile: no such file in rev e9e6b4fa872f [255] + +Test annotate with whitespace options + + $ cd .. + $ hg init repo-ws + $ cd repo-ws + $ cat > a <<EOF + > aa + > + > b b + > EOF + $ hg ci -Am "adda" + adding a + $ cat > a <<EOF + > a a + > + > + > b b + > EOF + $ hg ci -m "changea" + +Annotate with no option + + $ hg annotate a + 1: a a + 0: + 1: + 1: b b + +Annotate with --ignore-space-change + + $ hg annotate --ignore-space-change a + 1: a a + 1: + 0: + 0: b b + +Annotate with --ignore-all-space + + $ hg annotate --ignore-all-space a + 0: a a + 0: + 1: + 0: b b + +Annotate with --ignore-blank-lines (similar to no options case) + + $ hg annotate --ignore-blank-lines a + 1: a a + 0: + 1: + 1: b b +
--- a/tests/test-debugcomplete.t Sun Nov 20 19:14:36 2011 +0100 +++ b/tests/test-debugcomplete.t Fri Nov 18 12:04:31 2011 +0100 @@ -189,7 +189,7 @@ Show all commands + options $ hg debugcommands add: include, exclude, subrepos, dry-run - annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude + annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure commit: addremove, close-branch, include, exclude, message, logfile, date, user, subrepos diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos