Skip to content

editor: reduce input latency in large documents - #13

Merged
oligo merged 5 commits into
oligo:mainfrom
qianniancn:fix/editor-input-performance
Jul 20, 2026
Merged

editor: reduce input latency in large documents#13
oligo merged 5 commits into
oligo:mainfrom
qianniancn:fix/editor-input-performance

Conversation

@qianniancn

@qianniancn qianniancn commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Typing and backspace in large documents were still doing work for every unchanged paragraph. Paragraph layout is now reused without allocating a string per line, and the example app defers syntax and diff refreshes until after input processing.

This also fixes a few input edge cases:

  • close active IME undo groups on focus changes or SetText
  • emit one ChangeEvent per EditEvent
  • keep auto-inserted closing brackets aligned after edits
  • return io.EOF for invalid rune offsets

BenchmarkDeleteBackwardLargeDocument with 5,000 lines:

d0c7656    79.75 ms/op    21.24 MB/op    285,083 allocs/op
this branch 1.03 ms/op     6.6 KB/op          49 allocs/op

BenchmarkTextInputLargeDocument on this branch:

0.98 ms/op    7.1 KB/op    83 allocs/op

Tested with:

go test -count=1 ./...
go vet ./internal/buffer ./internal/layout

@oligo oligo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, thanks! Please see my comments inline.

Comment thread editor.go

sc := e.text.Replace(start, end, s)
newEnd := start + sc
if len(e.autoInsertions) > 0 && (start != end || sc != 0) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enables the auto-inserted pairs to be deleted even if there's insertion before them, right? This changes the editor behaviour which I think should be documented in your PR.

The auto-insertion behaviour was aligned with vscode. While I think the new feature is smarter, but sometimes it may be not desired.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right. The marker now moves when text is inserted before the pair,
so the pair can still be skipped or deleted later.

I added a test for this in b65ee58. I'll also mention it in the PR description.

Comment thread event.go Outdated
e.updateSnippet(gtx, ke.Start, ke.End)
case key.EditEvent:
e.onTextInput(ke)
if e.text.Changed() {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to emit events for every edit? If the editor receives 2 edit events in a frame, that would be 2 change events, and downstream code will have to run the event callback twice for no benefit. The old code handles this in a debounced way. Did I missed something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I misunderstood the existing batching behavior. I reverted that
change in b65ee58. Edit events in the same frame are coalesced again, and the
test now covers that.

@qianniancn

Copy link
Copy Markdown
Contributor Author

Auto-inserted pairs remain tracked when edits before them move their offsets.

@oligo
oligo merged commit 0083ce1 into oligo:main Jul 20, 2026
1 check passed
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.

2 participants