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 |
diffopts |
|
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, |
|
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 |
|
|
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`` |
|
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( |
|
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