Skip to content

表格末尾列双击选中内容编辑会串到下一行 #42

Closed

Description

@ryan-cine

在 md 表格中,选中末尾列双击全选后编辑,光标和编辑内容会串到下一行首列开头,同时无法撤销改动。希望能够优化,感谢。

Activity

  1. added
    bugSomething isn't working
    plannedAccepted, on the roadmap
    on Sep 13, 2026
  2. Systemofdumb commented on Sep 14, 2026

    @Systemofdumb
    Contributor

    I think I have the exact gesture, and it is worth separating from the version it landed in — this predates v0.9.0, so the tabs merge is not the cause.

    The gesture is a triple-click, not a double-click

    There are two selection states in a cell, and they behave differently:

    gesture selection result of typing
    double-click "Test" — end = #text:4 replaces the cell text, table intact
    triple-click "Test\n" — end = P:0 cell boundary destroyed

    The triple-click selection includes a trailing newline and its end anchor sits outside the text node, in the following block. Replacing it therefore eats the cell separator along with the text.

    Starting from:

    | Test | Test-2 |
    | --- | --- |
    | Test-3 | Test-4 |

    triple-click Test, type Wrong:

    before: [["Test","Test-2"],["Test-3","Test-4"]]
    after : [["WrongTest-2"],["Test-3","Test-4"]]      cell count changed
    

    Row 1 is left with a single cell while row 2 still has two — a malformed table, which is also why undo cannot put it back cleanly. The original report is the same thing seen from the last column, where the next cell in document order is the next row's first column, exactly as described.

    It is not from the tabs merge

    Same script, same build process, against v0.8.1 — byte-identical:

    v0.8.1   triple click   sel="Test\n" end=P:0
             after=[["WrongTest-2"],["Test-3","Test-4"]]   cellCountChanged=true
    

    The issue was filed about an hour after v0.9.0 shipped, so the tabs merge is an understandable first suspect — it is not this. For what it is worth, the tabs PR touched no kernel files at all, and the only kernel lines in any of my merged PRs are the two matchesLetterKey shortcut tests.

    Suggested framing

    The selection endpoint is the thing: a triple-click inside a cell resolves to a range whose end is a block boundary rather than the cell's text end, and the replace path then removes the boundary. Anchoring the replacement to the cell's own text extent would leave the grid intact.

    Measured in WebKit via Playwright against the built static export; only macOS was exercised.

    Unrelated but found alongside it: ⌘A with the caret in a table selects everything except the table when the table is the document's first block. That one is new in v0.9.0 — filed separately as #43 so it does not get tangled with this.

  3. Systemofdumb commented on Sep 16, 2026

    @Systemofdumb
    Contributor

    fcfbfed fixes the reported gesture — I re-measured it on WebKit and a triple-click now selects "Test" with end = #text:4, replacing the cell cleanly with the grid intact.

    The corruption underneath it is still reachable from the keyboard, though. Double-click a word in a cell, extend with Shift+Right or Shift+Down, type:

    dblclick + Shift+Right      sel="Test\n"    -> [["WrongTest-2"],["Test-3","Test-4"]]
    dblclick + Shift+Right x2   sel="Test\nT"   -> [["Wrongest-2"],["Test-3","Test-4"]]
    dblclick + Shift+Down       sel="Test\n"    -> [["WrongTest-2"],["Test-3","Test-4"]]
    

    Same outcome as the original report: row one keeps a single cell while row two still has two.

    Not a regression from the fix — it behaves identically on v0.9.0 and v0.8.1. The triple-click was one entry point to it; the boundary-crossing replace is the thing itself, and handleMouseDown_ can only close the mouse route.

    Opened #44 with a fix at the edit layer: applySelectEdit_ clamps a cross-cell selection to the cell it starts in, so the | separator is never inside the replaced span. Paragraph merges are untouched — between paragraphs that merge is the correct outcome, which is why the guard is scoped to cells.

    It ships scripts/verify-table-cell-guard, and the part worth mentioning: with the clamp disabled 5 of its 9 assertions fail, including the exact | WrongTest-2 | collapse. The harness sets the cursor pair directly rather than through setSelection, because setSelection refuses a range straddling the separator (applied:false, reason:"invalid") — which is precisely why only a DOM selection could ever reach this, and why it never showed up in a headless suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplannedAccepted, on the roadmap

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions