[vim/vim] getregionpos() is slow when only the region bounds are needed (PR #21209)

3 views
Skip to first unread message

Volodymyr Chernetskyi

unread,
Sep 2, 2026, 2:06:12 PM (2 days ago) Sep 2
to vim/vim, Subscribed

Problem

getregionpos() returns a pair of positions for every line of the region, so
obtaining just the outer endpoints costs O(lines).

Solution

Add a bounds item to {opts} defaulting to false. When it is set, only the
first and the last line of the region are visited and the result is a single
pair:

[[{start_pos}, {end_pos}]]

{start_pos} is the start position on the first line and {end_pos} the end
position on the last line, so with the same {opts} this is equivalent to
taking the outer positions of the full result:

let full = getregionpos(pos1, pos2, opts)
let bounds = [[full[0][0], full[-1][1]]]

That equivalence is the whole specification, so the existing corners are
reproduced:

  • The two positions come from different lines, so they describe a diagonal of
    the region and not its shape. For a blockwise region they are the start of
    the first line and the end of the last line, not the corners of the block.
  • If the first line is empty and eol is false, {start_pos} has a col of
    0 while {end_pos} may not.
  • Error behaviour is untouched, and positions in two different buffers still
    return an empty list rather than a pair.

Numbers

Measured on a 100000 line buffer, macOS arm64, -O2:

region type full result bounds
charwise 45.6 ms 0.003 ms
linewise 41.0 ms 0.003 ms
blockwise 42.9 ms 0.003 ms

The normal per-line path is unaffected by the refactor.

Tests

Test_visual_getregionpos_bounds() in src/testdir/test_visual.vim asserts
explicit expected pairs for the interesting shapes — the blockwise diagonal,
an empty first line with and without eol, multibyte and combining
characters, tabs, v:maxcol, a region within one line, and reversed
arguments — and then checks over 6144 generated cases that bounds equals
[[full[0][0], full[-1][1]]] for every combination of region type, eol,
exclusive, 'selection' and 'virtualedit'. It also covers the unchanged
error cases and the different-buffer empty list.

During development the same equivalence was checked over 3888000 cases with no
mismatches; the committed matrix is the small readable subset of that.

AI Disclosure

This change was prepared with AI assistance.

Context

Neovim intends to port this afterwards, see
neovim/neovim#41448.


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/21209

Commit Summary

  • f696429 getregionpos() cannot compute the segment of a single line
  • ab3fd51 getregionpos() is slow when only the region bounds are needed

File Changes

(3 files)

Patch Links:


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/21209@github.com>

Reply all
Reply to author
Forward
0 new messages