Skip to content

fix: fix selected-text dedenting in characterwise and blockwise modes - #1453

Open
pilgrimlyieu wants to merge 5 commits into
L3MON4D3:masterfrom
pilgrimlyieu:fix/select
Open

pilgrimlyieu wants to merge 5 commits into
L3MON4D3:masterfrom
pilgrimlyieu:fix/select

Conversation

@pilgrimlyieu

@pilgrimlyieu pilgrimlyieu commented Sep 18, 2026

Copy link
Copy Markdown

This PR is drafted with the help of Codex and I've reviewed and tested.

Fix #1452: LS_SELECT_DEDENT can delete whitespace inside a characterwise selection, and blockwise dedenting can depend on which corner started the selection. This series fixes those behaviors in two independently selectable patches.

Recommended submission: take A and B. The internal refactor R is an optional follow-up; neither correctness fix requires it. A and B can also be submitted separately if smaller PRs are preferred.

A. Preserve characterwise selected text

With ls.cut_keys mapped to <F5> in Visual mode, select the following text with gg^vjj$<F5>:

    first
      keep    gap
    last

The middle line currently becomes " keepgap". The expected dedented selection is:

{ "first", "  keep    gap", "last" }

The characterwise path uses unanchored substitutions. Its first-line branch also reconstructs text from the entire source line, which can include text beyond a single-line selection. Adding ^ to the substitutions alone would leave that second problem unresolved.

A removes only the overlap between the common indentation and each selected chunk. This handles partial first and last lines, single-line selections, and a selection consisting entirely of whitespace inside the line body. It reuses the existing minimum-indentation calculation and leaves the hook structure intact.

The production diff is 6 (+) 14 (-), confined to the characterwise branch of select.lua.

B. Normalize block selection columns before dedenting

For the same source text, gg01l<C-v>2j6l and gg07l<C-v>2j6h select the same rectangle from different corners. Pressing <F5> should produce the same dedented result. The old code assumes that the column of '< is the left edge, although the marks are ordered by buffer position and that endpoint can be on the right.

B uses the smaller of the two recorded byte columns in blockwise mode. Its production diff is 4 (+).

R. Optional internal refactor

R groups the operation's register and selection metadata into pending_yank, centralizes text conversion in dedent_selection, and leaves post_yank to read, restore, transform, and publish. This makes state ownership and cleanup easier to follow. Its production diff is 48 (+) 70 (-), primarily reorganization.

R is not necessary to fix #1452 so it can be reverted if needed. A+B pass all related tests (2 failed in master too in my local) and reported cases. The same suite passes with R applied. The existing public mappings, pre_yank/post_yank protocol, selected-text variables, and linewise TM_SELECTED_TEXT behavior are preserved.

Trim the indentation overlapping each selected chunk. Preserve interior
whitespace and the bounds of single-line and partially indented selections.
This fixes the characterwise part of L3MON4D3#1452 without changing block handling
or reorganizing the selection hooks.
Use the smaller recorded byte column for blockwise selections so the
reported space-indented rectangle dedents consistently in every direction.
Keep get_min_indent, its byte-length comparison, the strict indentation
boundary, and the existing anchored prefix substitution unchanged.
Group register and selection metadata into a single pending_yank snapshot.
Move text transformation into dedent_selection and leave post_yank to read,
restore, transform, and publish. Release the complete snapshot after use.
Precompute the literal prefix for linewise and blockwise selections while
preserving the existing byte-based indentation rules.

This optional cleanup follows both correctness fixes and is not needed
to obtain their behavior.
Add four focused regressions for interior whitespace, single-line bounds,
selected indentation, and selected interior spaces.
Add regression exercising the same rectangle in all four directions.
pilgrimlyieu added a commit to pilgrimlyieu/nvim that referenced this pull request Sep 18, 2026
1. LuaSnip snippets 继承触发点的缩进,因此若片段中有静态缩进与多行的 VISUAL 选中内容,只有第一行会有静态缩进。
    - 解决方法:加入了 `indented_visual` 工具函数继承完整的缩进,包含 snippets 模板中的静态缩进。
2. 去除选中行的共同缩进。这应该符合绝大多数情况预期,因此没有提供额外方法。
    - 不过 `LS_SELECT_DEDENT` 有问题亟待修复:L3MON4D3/LuaSnip#1453
3. LazyVim 默认启用 LuaSnip 的 history 选项,导致 snippet 生命周期过长,无法在 snippet 结束后自动清理。
    - 解决方法:手动恢复 LuaSnip 默认值
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LS_SELECT_DEDENT removes interior whitespace from characterwise selections

1 participant