##// END OF EJS Templates
annotate: support diff whitespace filtering flags (issue3030)...
Patrick Mezard -
r15528:a84698ba default
parent child Browse files
Show More
@@ -106,15 +106,19 b' diffopts = ['
106 ('', 'nodates', None, _('omit dates from diff headers'))
106 ('', 'nodates', None, _('omit dates from diff headers'))
107 ]
107 ]
108
108
109 diffopts2 = [
109 diffwsopts = [
110 ('p', 'show-function', None, _('show which function each change is in')),
111 ('', 'reverse', None, _('produce a diff that undoes the changes')),
112 ('w', 'ignore-all-space', None,
110 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
111 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
112 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
113 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
114 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
115 _('ignore changes whose lines are all blank')),
116 ]
117
118 diffopts2 = [
119 ('p', 'show-function', None, _('show which function each change is in')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ] + diffwsopts + [
118 ('U', 'unified', '',
122 ('U', 'unified', '',
119 _('number of lines of context to show'), _('NUM')),
123 _('number of lines of context to show'), _('NUM')),
120 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
@@ -215,7 +219,7 b' def addremove(ui, repo, *pats, **opts):'
215 ('n', 'number', None, _('list the revision number (default)')),
219 ('n', 'number', None, _('list the revision number (default)')),
216 ('c', 'changeset', None, _('list the changeset')),
220 ('c', 'changeset', None, _('list the changeset')),
217 ('l', 'line-number', None, _('show line number at the first appearance'))
221 ('l', 'line-number', None, _('show line number at the first appearance'))
218 ] + walkopts,
222 ] + diffwsopts + walkopts,
219 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
223 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
220 def annotate(ui, repo, *pats, **opts):
224 def annotate(ui, repo, *pats, **opts):
221 """show changeset information by line for each file
225 """show changeset information by line for each file
@@ -270,13 +274,15 b' def annotate(ui, repo, *pats, **opts):'
270 m = scmutil.match(ctx, pats, opts)
274 m = scmutil.match(ctx, pats, opts)
271 m.bad = bad
275 m.bad = bad
272 follow = not opts.get('no_follow')
276 follow = not opts.get('no_follow')
277 diffopts = patch.diffopts(ui, opts, section='annotate')
273 for abs in ctx.walk(m):
278 for abs in ctx.walk(m):
274 fctx = ctx[abs]
279 fctx = ctx[abs]
275 if not opts.get('text') and util.binary(fctx.data()):
280 if not opts.get('text') and util.binary(fctx.data()):
276 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
281 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
277 continue
282 continue
278
283
279 lines = fctx.annotate(follow=follow, linenumber=linenumber)
284 lines = fctx.annotate(follow=follow, linenumber=linenumber,
285 diffopts=diffopts)
280 pieces = []
286 pieces = []
281
287
282 for f, sep in funcmap:
288 for f, sep in funcmap:
@@ -7,7 +7,7 b''
7
7
8 from node import nullid, nullrev, short, hex
8 from node import nullid, nullrev, short, hex
9 from i18n import _
9 from i18n import _
10 import ancestor, bdiff, error, util, scmutil, subrepo, patch, encoding
10 import ancestor, mdiff, error, util, scmutil, subrepo, patch, encoding
11 import match as matchmod
11 import match as matchmod
12 import os, errno, stat
12 import os, errno, stat
13
13
@@ -433,7 +433,7 b' class filectx(object):'
433 return [filectx(self._repo, self._path, fileid=x,
433 return [filectx(self._repo, self._path, fileid=x,
434 filelog=self._filelog) for x in c]
434 filelog=self._filelog) for x in c]
435
435
436 def annotate(self, follow=False, linenumber=None):
436 def annotate(self, follow=False, linenumber=None, diffopts=None):
437 '''returns a list of tuples of (ctx, line) for each line
437 '''returns a list of tuples of (ctx, line) for each line
438 in the file, where ctx is the filectx of the node where
438 in the file, where ctx is the filectx of the node where
439 that line was last changed.
439 that line was last changed.
@@ -460,8 +460,13 b' class filectx(object):'
460 without_linenumber)
460 without_linenumber)
461
461
462 def pair(parent, child):
462 def pair(parent, child):
463 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
463 blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts,
464 child[0][b1:b2] = parent[0][a1:a2]
464 refine=True)
465 for (a1, a2, b1, b2), t in blocks:
466 # Changed blocks ('!') or blocks made only of blank lines ('~')
467 # belong to the child.
468 if t == '=':
469 child[0][b1:b2] = parent[0][a1:a2]
465 return child
470 return child
466
471
467 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
472 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
@@ -227,6 +227,24 b' echo foo`` call above, ``$HG_ARGS`` woul'
227 processed before shell aliases and will thus not be passed to
227 processed before shell aliases and will thus not be passed to
228 aliases.
228 aliases.
229
229
230
231 ``annotate``
232 """"""""
233
234 Settings used when displaying file annotations. All values are
235 Booleans and default to False. See ``diff`` section for related
236 options for the diff command.
237
238 ``ignorews``
239 Ignore white space when comparing lines.
240
241 ``ignorewsamount``
242 Ignore changes in the amount of white space.
243
244 ``ignoreblanklines``
245 Ignore changes whose lines are all blank.
246
247
230 ``auth``
248 ``auth``
231 """"""""
249 """"""""
232
250
@@ -364,8 +382,9 b' to the aliases of the commands defined.'
364 ``diff``
382 ``diff``
365 """"""""
383 """"""""
366
384
367 Settings used when displaying diffs. Everything except for ``unified`` is a
385 Settings used when displaying diffs. Everything except for ``unified``
368 Boolean and defaults to False.
386 is a Boolean and defaults to False. See ``annotate`` section for
387 related options for the annotate command.
369
388
370 ``git``
389 ``git``
371 Use git extended diff format.
390 Use git extended diff format.
@@ -12,7 +12,7 b' from mercurial.node import short, hex'
12 from mercurial.util import binary
12 from mercurial.util import binary
13 from common import paritygen, staticfile, get_contact, ErrorResponse
13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod
15 from mercurial import graphmod, patch
16 from mercurial import help as helpmod
16 from mercurial import help as helpmod
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18
18
@@ -576,6 +576,7 b' def annotate(web, req, tmpl):'
576 fctx = webutil.filectx(web.repo, req)
576 fctx = webutil.filectx(web.repo, req)
577 f = fctx.path()
577 f = fctx.path()
578 parity = paritygen(web.stripecount)
578 parity = paritygen(web.stripecount)
579 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
579
580
580 def annotate(**map):
581 def annotate(**map):
581 last = None
582 last = None
@@ -585,7 +586,8 b' def annotate(web, req, tmpl):'
585 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
586 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
586 '(binary:%s)' % mt)])
587 '(binary:%s)' % mt)])
587 else:
588 else:
588 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
589 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
590 diffopts=diffopts))
589 for lineno, ((f, targetline), l) in lines:
591 for lineno, ((f, targetline), l) in lines:
590 fnode = f.filenode()
592 fnode = f.filenode()
591
593
@@ -75,11 +75,38 b' def wsclean(opts, text, blank=True):'
75 text = re.sub('\n+', '\n', text).strip('\n')
75 text = re.sub('\n+', '\n', text).strip('\n')
76 return text
76 return text
77
77
78 def allblocks(text1, text2, opts=None, lines1=None, lines2=None):
78 def splitblock(base1, lines1, base2, lines2, opts):
79 # The input lines matches except for interwoven blank lines. We
80 # transform it into a sequence of matching blocks and blank blocks.
81 lines1 = [(wsclean(opts, l) and 1 or 0) for l in lines1]
82 lines2 = [(wsclean(opts, l) and 1 or 0) for l in lines2]
83 s1, e1 = 0, len(lines1)
84 s2, e2 = 0, len(lines2)
85 while s1 < e1 or s2 < e2:
86 i1, i2, btype = s1, s2, '='
87 if (i1 >= e1 or lines1[i1] == 0
88 or i2 >= e2 or lines2[i2] == 0):
89 # Consume the block of blank lines
90 btype = '~'
91 while i1 < e1 and lines1[i1] == 0:
92 i1 += 1
93 while i2 < e2 and lines2[i2] == 0:
94 i2 += 1
95 else:
96 # Consume the matching lines
97 while i1 < e1 and lines1[i1] == 1 and lines2[i2] == 1:
98 i1 += 1
99 i2 += 1
100 yield [base1 + s1, base1 + i1, base2 + s2, base2 + i2], btype
101 s1 = i1
102 s2 = i2
103
104 def allblocks(text1, text2, opts=None, lines1=None, lines2=None, refine=False):
79 """Return (block, type) tuples, where block is an mdiff.blocks
105 """Return (block, type) tuples, where block is an mdiff.blocks
80 line entry. type is '=' for blocks matching exactly one another
106 line entry. type is '=' for blocks matching exactly one another
81 (bdiff blocks), '!' for non-matching blocks and '~' for blocks
107 (bdiff blocks), '!' for non-matching blocks and '~' for blocks
82 matching only after having filtered blank lines.
108 matching only after having filtered blank lines. If refine is True,
109 then '~' blocks are refined and are only made of blank lines.
83 line1 and line2 are text1 and text2 split with splitnewlines() if
110 line1 and line2 are text1 and text2 split with splitnewlines() if
84 they are already available.
111 they are already available.
85 """
112 """
@@ -1527,10 +1527,10 b' def b85diff(to, tn):'
1527 class GitDiffRequired(Exception):
1527 class GitDiffRequired(Exception):
1528 pass
1528 pass
1529
1529
1530 def diffopts(ui, opts=None, untrusted=False):
1530 def diffopts(ui, opts=None, untrusted=False, section='diff'):
1531 def get(key, name=None, getter=ui.configbool):
1531 def get(key, name=None, getter=ui.configbool):
1532 return ((opts and opts.get(key)) or
1532 return ((opts and opts.get(key)) or
1533 getter('diff', name or key, None, untrusted=untrusted))
1533 getter(section, name or key, None, untrusted=untrusted))
1534 return mdiff.diffopts(
1534 return mdiff.diffopts(
1535 text=opts and opts.get('text'),
1535 text=opts and opts.get('text'),
1536 git=get('git'),
1536 git=get('git'),
@@ -2,7 +2,8 b''
2
2
3 init
3 init
4
4
5 $ hg init
5 $ hg init repo
6 $ cd repo
6
7
7 commit
8 commit
8
9
@@ -253,3 +254,56 b' missing file'
253 $ hg ann nosuchfile
254 $ hg ann nosuchfile
254 abort: nosuchfile: no such file in rev e9e6b4fa872f
255 abort: nosuchfile: no such file in rev e9e6b4fa872f
255 [255]
256 [255]
257
258 Test annotate with whitespace options
259
260 $ cd ..
261 $ hg init repo-ws
262 $ cd repo-ws
263 $ cat > a <<EOF
264 > aa
265 >
266 > b b
267 > EOF
268 $ hg ci -Am "adda"
269 adding a
270 $ cat > a <<EOF
271 > a a
272 >
273 >
274 > b b
275 > EOF
276 $ hg ci -m "changea"
277
278 Annotate with no option
279
280 $ hg annotate a
281 1: a a
282 0:
283 1:
284 1: b b
285
286 Annotate with --ignore-space-change
287
288 $ hg annotate --ignore-space-change a
289 1: a a
290 1:
291 0:
292 0: b b
293
294 Annotate with --ignore-all-space
295
296 $ hg annotate --ignore-all-space a
297 0: a a
298 0:
299 1:
300 0: b b
301
302 Annotate with --ignore-blank-lines (similar to no options case)
303
304 $ hg annotate --ignore-blank-lines a
305 1: a a
306 0:
307 1:
308 1: b b
309
@@ -189,7 +189,7 b' Show an error if we use --options with a'
189 Show all commands + options
189 Show all commands + options
190 $ hg debugcommands
190 $ hg debugcommands
191 add: include, exclude, subrepos, dry-run
191 add: include, exclude, subrepos, dry-run
192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user, subrepos
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user, subrepos
195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
General Comments 0
You need to be logged in to leave comments. Login now