Skip to content

Fix horizontal relocation (scrolling) not respecting selections - #3826

Open
masmu wants to merge 2 commits into
micro-editor:masterfrom
masmu:bug/horizontal-relocate-doesnt-respect-selections
Open

masmu wants to merge 2 commits into
micro-editor:masterfrom
masmu:bug/horizontal-relocate-doesnt-respect-selections

Conversation

@masmu

@masmu masmu commented Aug 7, 2025 •

Copy link
Copy Markdown
Contributor

Currently there is no logic to handle horizontal scrolling when text is selected. The current code only takes the cursor position into account. This only affects buffers where the softwrap option is disabled.

How to reproduce:

PLUGIN_VERSION = "2.0.0"
PLUGIN_NAME = "bug_horizontal_relocate_doesnt_respect_selections"

local micro = import("micro")
local buffer = import("micro/buffer")
local config = import("micro/config")
local util = import("micro/util")

local TEST_STRING1 = [[
//        1         2         3         4         5         6         7         8         9
//23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
    scrollbarWidth := 0
	scrollbarWidth := 0
	if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height && w.Width > 0 {
		scrollbarWidth = 1
	}]]

local TEST_STRING2 = [[
//        1         2         3         4         5         6         7         8         9
//23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
// ThisIsAVeryLongLineSoLongActuallyItsNotGonnaFitIntoOneBufSplit
	// >>> ThisIsAVeryLongLineSoLongActuallyItsNotGonnaFitIntoOneBufSplit]]

function postinit()
    local bp = micro.CurPane()
    if bp.Buf:Size() > 0 then
        return
    end
    bp.Buf.settings["softwrap"] = false
    bp.Buf.settings["tabsize"] = 4
    micro.Log("tabsize", bp.Buf.settings["tabsize"])
    micro.Log("softwrap", bp.Buf.settings["softwrap"])
    testCase1a()
    -- testCase2()
end

function resizePane(bp, size)
    -- bp:ResizePane(size, true)
    bp:ResizePane(size)
end

function testCase1a()
    local bp = micro.CurPane()
    local cursor = bp.Buf:GetActiveCursor()
    bp.Buf:Insert(-cursor.Loc, TEST_STRING1)

    local unusedBuf, err = buffer.NewBufferFromFile("")
    local unusedBp = bp:VSplitIndex(unusedBuf, true)
    resizePane(bp, 60)

    local tab = bp:Tab()
    tab:SetActive(bp:ID() - 1)

    -- select "Width"
    local loc = buffer.Loc(10, 3)
    cursor:GotoLoc(loc)
    bp:SelectSubWordRight()
end

function testCase2()
    local bp = micro.CurPane()
    local cursor = bp.Buf:GetActiveCursor()
    bp.Buf:Insert(-cursor.Loc, TEST_STRING2)

    local unusedBuf, err = buffer.NewBufferFromFile("")
    local unusedBp = bp:VSplitIndex(unusedBuf, true)
    resizePane(bp, 60)

    local tab = bp:Tab()
    tab:SetActive(bp:ID() - 1)

    -- select "ThisIsAVeryLongLineSoLongActuallyItsNotGonnaFitIntoOneBufSplit"
    local loc = buffer.Loc(3, 2)
    cursor:GotoLoc(loc)
    bp:SelectWordRight()
end

function onTriggerBug(bp)
    micro.Log("onTriggerBug")
    local bp = micro.CurPane()
    local cursor = bp.Buf:GetActiveCursor()
    if cursor:HasSelection() == false then
        return false
    end
    local selectedText = util.String(cursor:GetSelection())
    bp.Buf.LastSearch = selectedText
    bp:FindNext()
end

Bind onTriggerBug to see the effect.

Actual behavior:
You cannot see the selected subword Width every time you trigger onTriggerBug.

Expectation:
The selected text should be visible at all times.

masmu added 2 commits November 6, 2026 11:33
Currently there is no logic to handle horizontal scrolling when text
is selected. The current code only takes the cursor position into
account. This only affects buffers where the softwrap option is
disabled.

Relocate() computes the StartCol values that keep the cursor's rune
visible and the values that make the whole selection visible, and
uses their intersection. If the two cannot be combined, because the
selection is wider than the window or the cursor is outside the
selection, the cursor wins: Relocate() must always keep the cursor
in view. The view is then moved as little as possible.

See micro-editor#3826
Tests for the horizontal part of BufWindow.Relocate() with softwrap
off, which previously had no test coverage. They cover the cursor
alone, selections that fit in the window, selections that extend
past the window away from the cursor, selections wider than the
window, reversed and multi-line selections, tabs, double-width runes,
a one column window and an empty line.

The predicates shared by all cases state the contract of Relocate():
the cursor stays visible, a selection that fits the window becomes
fully visible, and a view that already shows the relevant content is
not scrolled.
@masmu
masmu force-pushed the bug/horizontal-relocate-doesnt-respect-selections branch from d3d120a to 3f3fde1 Compare November 6, 2026 11:58
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.

1 participant