[PATCH 2 of 3] context: add a `blockancestors(fromline, toline)` method to filectx

Yuya Nishihara yuya at tcha.org
Wed Nov 30 10:04:02 EST 2016


On Mon, 28 Nov 2016 10:54:15 +0100, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde <denis at laxalde.org>
> # Date 1480086869 -3600
> #      Fri Nov 25 16:14:29 2016 +0100
> # Node ID 6dd93ae7b35002531308444c87dcf47beb773648
> # Parent  0cf70234a38e47a3f7107611885368db9d52f574
> # EXP-Topic linerange-log/revset
> context: add a `blockancestors(fromline, toline)` method to filectx
> 
> This yields filectx instances obtained by walking through ancestors by
> only keeping changesets touching the file within specified `linerange =
> (fromline, toline)`. It only follows first parent, since this yields weird
> results in case of merge (might be improved later).
> 
> Matching revisions are found by inspecting the result of `mdiff.allblocks()`,
> filtered by `mdiff.blocksinrange()`, to find out if there are blocks of type
> "!" within specified line range.
> 
> diff --git a/mercurial/context.py b/mercurial/context.py
> --- a/mercurial/context.py
> +++ b/mercurial/context.py
> @@ -1153,6 +1153,40 @@ class filectx(basefilectx):
>          return [filectx(self._repo, self._path, fileid=x,
>                          filelog=self._filelog) for x in c]
>  
> +    def blockancestors(self, fromline, toline):
> +        """Yield ancestors of this filectx with respect to the block of lines
> +        in `linerange = (lowerbound, upperbound)`.
> +        """

Nit: Perhaps this could be a module-level function since it doesn't depend on
the internals of filectx.

> +        def changesrange(fctx1, fctx2, linerange2):
> +            """Return `(diffinrange, linerange1)` where `diffinrange` is True
> +            if diff from fctx2 to fctx1 has changes in linerange2 and
> +            `linerange1` is the new line range for fctx1.
> +            """
> +            diffopts = patch.diffopts(self._repo.ui)

Is it intended to take all diff options such as ignorews?

> +            blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts)
> +            blocks = mdiff.blocksinrange(blocks, linerange2)
> +            # consume blocks to find out linerange1 and whether there's some
> +            # diff in linerange2.
> +            diffinrange = False
> +            while True:
> +                try:
> +                    _, stype = next(blocks)
> +                    if diffinrange:
> +                        continue
> +                    diffinrange = stype == '!'
> +                except StopIteration as exc:
> +                    linerange1 = exc.args[0]
> +                    break
> +            return diffinrange, linerange1
> +
> +        c, linerange2 = self, (fromline, toline)
> +        for p in self.ancestors(followfirst=True):  # TODO handle followfirst
> +            inrangep, linerange1 = changesrange(p, c, linerange2)
> +            if inrangep:
> +                yield c
> +            c, linerange2 = p, linerange1

> +        yield c  # XXX should we?

Maybe yes, considering there's a diff between null and c.


More information about the Mercurial-devel mailing list