annotate: limit output to range of lines
authorZeger Van de Vannet <zeger@vandevan.net>
Wed, 14 Feb 2024 08:14:46 +0100
changeset 51398 e9304c39e075
parent 51397 b01e7d97e167
child 51400 e2dfa403452d
annotate: limit output to range of lines
mercurial/commands.py
tests/test-annotate.t
tests/test-completion.t
--- a/mercurial/commands.py	Mon Feb 12 20:01:27 2024 +0000
+++ b/mercurial/commands.py	Wed Feb 14 08:14:46 2024 +0100
@@ -371,6 +371,13 @@
             _(b'revset to not display (EXPERIMENTAL)'),
             _(b'REV'),
         ),
+        (
+            b'L',
+            b'line-range',
+            [],
+            _(b'follow line range of specified file (EXPERIMENTAL)'),
+            _(b'FILE,RANGE'),
+        ),
     ]
     + diffwsopts
     + walkopts
@@ -399,6 +406,13 @@
 
     .. container:: verbose
 
+       Use -L/--line-range FILE,M:N options to filter the output to the lines
+       from M to N in FILE. This option is incompatible with --no-follow and
+       cannot be combined with file pattern arguments. When combined with --rev
+       the line ranges refer to the state of the file at the requested revision.
+
+    .. container:: verbose
+
       Template:
 
       The following keywords are supported in addition to the common template
@@ -419,7 +433,20 @@
     Returns 0 on success.
     """
     opts = pycompat.byteskwargs(opts)
-    if not pats:
+
+    linerange = opts.get(b'line_range')
+
+    if linerange and opts.get(b'no_follow'):
+        raise error.InputError(
+            _(b'--line-range is incompatible with --no-follow')
+        )
+
+    if pats and linerange:
+        raise error.InputError(
+            _(b'cannot combine filename or pattern and --line-range')
+        )
+
+    if not pats and not linerange:
         raise error.InputError(
             _(b'at least one filename or pattern is required')
         )
@@ -450,6 +477,12 @@
         repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
     ctx = logcmdutil.revsingle(repo, rev)
 
+    if not pats:
+        pats = [
+            fname
+            for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
+        ]
+
     ui.pager(b'annotate')
     rootfm = ui.formatter(b'annotate', opts)
     if ui.debugflag:
@@ -554,6 +587,16 @@
         lines = fctx.annotate(
             follow=follow, skiprevs=skiprevs, diffopts=diffopts
         )
+        if linerange:
+            _fname, (line_start, line_end) = list(
+                logcmdutil._parselinerangeopt(repo, opts)
+            )[0]
+            lines = [
+                line
+                for no, line in enumerate(lines)
+                if line_start <= no < line_end
+            ]
+
         if not lines:
             fm.end()
             continue
@@ -1359,7 +1402,6 @@
             repo.dirstate.setbranch(label, repo.currenttransaction())
             ui.status(_(b'reset working directory to branch %s\n') % label)
         elif label:
-
             scmutil.checknewlabel(repo, label, b'branch')
             if revs:
                 return cmdutil.changebranch(ui, repo, revs, label, **opts)
--- a/tests/test-annotate.t	Mon Feb 12 20:01:27 2024 +0000
+++ b/tests/test-annotate.t	Wed Feb 14 08:14:46 2024 +0100
@@ -430,6 +430,69 @@
   1:2: a
   1:3: a
 
+annotate line-range
+
+  $ hg annotate -l -L b,8:10
+   8: 8: more
+   9: 9: more
+  10:10: more
+
+annotate line-range beyond last line
+
+  $ hg annotate -l -L b,8:13
+   8: 8: more
+   9: 9: more
+  10:10: more
+
+annotate line-range before first line
+
+  $ hg annotate -l -L b,0:2
+  hg: parse error: fromline must be strictly positive
+  [10]
+
+annotate line-range with --rev
+  $ hg annotate -l -L b,5:7
+  4:5: c
+  3:5: b5
+  7:7: d
+  $ sed 's/d/x/' b > b.new
+  $ mv b.new b
+  $ hg annotate --rev 'wdir()' -l -L b,5:7
+   4 :5: c
+   3 :5: b5
+  10+:7: x
+  $ hg annotate -l -L b,5:7
+  4:5: c
+  3:5: b5
+  7:7: d
+  $ hg revert --no-backup b
+  $ hg annotate --rev 3 -l b
+  0:1: a
+  1:2: a
+  1:3: a
+  3:4: b4
+  3:5: b5
+  3:6: b6
+  $ hg annotate --rev 3 -l -L b,5:7
+  3:5: b5
+  3:6: b6
+
+annotate line-range invalid combination of options
+
+  $ hg annotate --no-follow -L b,5:7
+  abort: --line-range is incompatible with --no-follow
+  [10]
+  $ hg annotate -L b,5:7 a
+  abort: cannot combine filename or pattern and --line-range
+  [10]
+
+annote line-range with glob patterns
+
+  $ hg annotate -l -L glob:b*,5:7
+  4:5: c
+  3:5: b5
+  7:7: d
+
 Issue589: "undelete" sequence leads to crash
 
 annotate was crashing when trying to --follow something
--- a/tests/test-completion.t	Mon Feb 12 20:01:27 2024 +0000
+++ b/tests/test-completion.t	Wed Feb 14 08:14:46 2024 +0100
@@ -260,7 +260,7 @@
   add: include, exclude, subrepos, dry-run
   addremove: similarity, subrepos, include, exclude, dry-run
   admin::verify: check, option
-  annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
+  annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, line-range, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
   archive: no-decode, prefix, rev, type, subrepos, include, exclude
   backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
   bisect: reset, good, bad, skip, extend, command, noupdate