/
reformat.go
117 lines (93 loc) · 2.6 KB
/
reformat.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package langserver
import (
"context"
"encoding/json"
"fmt"
"github.com/thought-machine/please/tools/build_langserver/lsp"
"github.com/bazelbuild/buildtools/build"
"github.com/sourcegraph/jsonrpc2"
)
const reformatMethod = "textDocument/formatting"
func (h *LsHandler) handleReformatting(ctx context.Context, req *jsonrpc2.Request) (result interface{}, err error) {
if req.Params == nil {
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeInvalidParams}
}
var params lsp.DocumentFormattingParams
if err := json.Unmarshal(*req.Params, ¶ms); err != nil {
return nil, err
}
documentURI, err := getURIAndHandleErrors(params.TextDocument.URI, reformatMethod)
if err != nil {
return nil, err
}
h.mu.Lock()
defer h.mu.Unlock()
edits, err := h.getFormatEdits(documentURI)
if err != nil {
log.Warning("error occurred when formatting file: %s, skipping", err)
}
log.Info("formatting document with edits: %s", edits)
return edits, err
}
func (h *LsHandler) getFormatEdits(uri lsp.DocumentURI) ([]*lsp.TextEdit, error) {
filePath, err := GetPathFromURL(uri, "file")
if err != nil {
return nil, err
}
doc, ok := h.workspace.documents[uri]
if !ok {
return nil, fmt.Errorf("document not opened: %s", uri)
}
content := JoinLines(doc.textInEdit, true)
bytecontent := []byte(content)
var f *build.File
if h.analyzer.IsBuildFile(uri) {
f, err = build.ParseBuild(filePath, bytecontent)
if err != nil {
return nil, err
}
} else {
f, err = build.ParseDefault(filePath, bytecontent)
if err != nil {
return nil, err
}
}
reformatted := build.Format(f)
return getEdits(content, string(reformatted)), nil
}
func getEdits(before string, after string) []*lsp.TextEdit {
beforeLines := SplitLines(before, true)
afterLines := SplitLines(after, true)
var edits []*lsp.TextEdit
for i, line := range afterLines {
eRange := lsp.Range{
Start: lsp.Position{
Line: i,
Character: 0,
},
End: lsp.Position{
Line: i,
Character: 0,
},
}
if i <= len(beforeLines)-1 {
if line == beforeLines[i] {
continue
}
if i < len(beforeLines)-1 {
eRange.End.Line = i + 1
} else if beforeLines[i] != "" {
// This is to ensure the original line gets overridden if there is no newline after:
// usually if the last line is new line, it gets formatted correctly with startline:currentline, endline:currline + 1
// however this does not apply we want to format the last line
eRange.End.Character = len(beforeLines[i]) - 1
}
}
edit := &lsp.TextEdit{
Range: eRange,
NewText: line,
}
edits = append(edits, edit)
}
return edits
}