internal/lsp: fix formatting bug that keeps adding extra newlines
If a file ends with an empty newline, go/token treats the newline as the
final character of the previous line. VSCode, however, treats this as a
final line with no characters. We handle this by determining if the file
we are formatting ends with a newline character and updating the
protocol ranges accordingly.
Change-Id: Id8be0fd776ae65c8f0f937f3e718825e407cb217
Reviewed-on: https://go-review.googlesource.com/c/150338
Reviewed-by: Ian Cottrell <iancottrell@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/internal/lsp/server.go b/internal/lsp/server.go
index ad51fa4..5c9b4f2 100644
--- a/internal/lsp/server.go
+++ b/internal/lsp/server.go
@@ -277,21 +277,36 @@
} else {
r = fromProtocolRange(tok, *rng)
}
+ content, err := f.Read()
+ if err != nil {
+ return nil, err
+ }
edits, err := source.Format(ctx, f, r)
if err != nil {
return nil, err
}
- return toProtocolEdits(tok, edits), nil
+ return toProtocolEdits(tok, content, edits), nil
}
-func toProtocolEdits(f *token.File, edits []source.TextEdit) []protocol.TextEdit {
+func toProtocolEdits(tok *token.File, content []byte, edits []source.TextEdit) []protocol.TextEdit {
if edits == nil {
return nil
}
+ // When a file ends with an empty line, the newline character is counted
+ // as part of the previous line. This causes the formatter to insert
+ // another unnecessary newline on each formatting. We handle this case by
+ // checking if the file already ends with a newline character.
+ hasExtraNewline := content[len(content)-1] == '\n'
result := make([]protocol.TextEdit, len(edits))
for i, edit := range edits {
+ rng := toProtocolRange(tok, edit.Range)
+ // If the edit ends at the end of the file, add the extra line.
+ if hasExtraNewline && tok.Offset(edit.Range.End) == len(content) {
+ rng.End.Line++
+ rng.End.Character = 0
+ }
result[i] = protocol.TextEdit{
- Range: toProtocolRange(f, edit.Range),
+ Range: rng,
NewText: edit.NewText,
}
}