diff --git a/internal/lsp/diff/diff.go b/internal/lsp/diff/diff.go index 2aad5138ce..5536c3b895 100644 --- a/internal/lsp/diff/diff.go +++ b/internal/lsp/diff/diff.go @@ -83,7 +83,9 @@ func prepareEdits(before string, edits []TextEdit) (*span.TokenConverter, []Text for i, edit := range edits { edit.Span, _ = edit.Span.WithAll(c) copied[i] = edit - partial = partial || edit.Span.Start().Column() > 1 || edit.Span.End().Column() > 1 + partial = partial || + edit.Span.Start().Offset() >= len(before) || + edit.Span.Start().Column() > 1 || edit.Span.End().Column() > 1 } SortTextEdits(copied) return c, copied, partial @@ -127,6 +129,19 @@ func addEdit(before string, edits []TextEdit, edit TextEdit) []TextEdit { edit.Span = span.New(edit.Span.URI(), start, end) edit.NewText = before[start.Offset():start.Offset()+delta] + edit.NewText } + if start.Offset() >= len(before) && start.Line() > 1 && before[len(before)-1] != '\n' { + // after end of file that does not end in eol, so join to last line of file + // to do this we need to know where the start of the last line was + eol := strings.LastIndex(before, "\n") + if eol < 0 { + // file is one non terminated line + eol = 0 + } + delta := len(before) - eol + start = span.NewPoint(start.Line()-1, 1, start.Offset()-delta) + edit.Span = span.New(edit.Span.URI(), start, end) + edit.NewText = before[start.Offset():start.Offset()+delta] + edit.NewText + } if end.Column() > 1 { remains := before[end.Offset():] eol := strings.IndexRune(remains, '\n') diff --git a/internal/lsp/diff/difftest/difftest.go b/internal/lsp/diff/difftest/difftest.go index 9a8f187ad8..297515f9ec 100644 --- a/internal/lsp/diff/difftest/difftest.go +++ b/internal/lsp/diff/difftest/difftest.go @@ -114,6 +114,31 @@ var TestCases = []struct { \ No newline at end of file `[1:], Edits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "B"}}, +}, { + Name: "add_end", + In: "A", + Out: "AB", + Unified: UnifiedPrefix + ` +@@ -1 +1 @@ +-A +\ No newline at end of file ++AB +\ No newline at end of file +`[1:], + Edits: []diff.TextEdit{{Span: newSpan(1, 1), NewText: "B"}}, + LineEdits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "AB"}}, +}, { + Name: "add_newline", + In: "A", + Out: "A\n", + Unified: UnifiedPrefix + ` +@@ -1 +1 @@ +-A +\ No newline at end of file ++A +`[1:], + Edits: []diff.TextEdit{{Span: newSpan(1, 1), NewText: "\n"}}, + LineEdits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "A\n"}}, }, { Name: "delete_front", In: "A\nB\nC\nA\nB\nB\nA\n",