fix(vscode): apply next edit insertions safely at eof

This commit is contained in:
kiloconnect[bot]
2026-05-27 11:08:12 +00:00
parent 50a91dccbc
commit 7834aeb2b3
3 changed files with 49 additions and 4 deletions
@@ -1,5 +1,6 @@
import * as vscode from "vscode"
import { nesLog } from "./log"
import { planInsertion } from "./pendingEdit"
const PENDING_CONTEXT_KEY = "kilo-code.nextEdit.hasPendingSuggestion"
const CHAIN_DELAY_MS = 60
@@ -20,7 +21,7 @@ export type PendingNextEdit =
| {
kind: "insert"
document: vscode.TextDocument
/** Existing line BEFORE which the new content will be inserted. */
/** Existing line before insertion, or `lineCount` when appending at EOF. */
diffStartLine: number
/** Same as diffStartLine for hint/jump-target purposes. */
diffEndLine: number
@@ -192,9 +193,13 @@ export class NextEditSuggestionManager implements vscode.Disposable {
nesLog(`document drifted since suggestion was made — dropping insert at line ${p.diffStartLine}`)
return
}
const pos = new vscode.Position(p.diffStartLine, 0)
ok = await editor.edit((b) => b.insert(pos, p.replacement))
nesLog(`applied insert at line ${pos.line} (${p.replacement.length} chars, ok=${ok})`)
const edit = planInsertion(p, {
lineCount: editor.document.lineCount,
end: (line) => editor.document.lineAt(line).range.end.character,
})
const pos = new vscode.Position(edit.line, edit.character)
ok = await editor.edit((b) => b.insert(pos, edit.text))
nesLog(`applied insert at line ${pos.line} (${edit.text.length} chars, ok=${ok})`)
} else {
const range = new vscode.Range(
new vscode.Position(p.diffStartLine, 0),
@@ -0,0 +1,18 @@
type Input = {
diffStartLine: number
replacement: string
}
type Document = {
lineCount: number
end(line: number): number
}
export function planInsertion(input: Input, document: Document) {
if (input.diffStartLine < document.lineCount) {
return { line: input.diffStartLine, character: 0, text: input.replacement }
}
const line = Math.max(0, document.lineCount - 1)
const text = input.replacement.endsWith("\n") ? input.replacement.slice(0, -1) : input.replacement
return { line, character: document.end(line), text: `\n${text}` }
}
@@ -0,0 +1,22 @@
import { describe, expect, it } from "bun:test"
import { planInsertion } from "../../src/services/autocomplete/next-edit/pendingEdit"
describe("planInsertion", () => {
it("appends after the final unterminated line at EOF", () => {
const edit = planInsertion(
{ diffStartLine: 2, replacement: "third\n" },
{ lineCount: 2, end: (line) => [5, 6][line] },
)
expect(edit).toEqual({ line: 1, character: 6, text: "\nthird" })
})
it("keeps insertion-before-line semantics for a trailing empty line", () => {
const edit = planInsertion(
{ diffStartLine: 1, replacement: "second\n" },
{ lineCount: 2, end: (line) => [5, 0][line] },
)
expect(edit).toEqual({ line: 1, character: 0, text: "second\n" })
})
})