Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ jobs:
# test tries to retrieve non-existent node
# TestParser_NodeFieldsConsistency:
# Vars.Content only includes name, not whole body
# TestCollector_CollectByTreeSitter_Java
# JDTLS download was rate-limited on github actions
SKIPPED_TESTS: >-
TestPatcher|TestCases|Test_goParser_ParseNode|TestParser_NodeFieldsConsistency|TestRustLSP
TestPatcher|TestCases|Test_goParser_ParseNode|TestParser_NodeFieldsConsistency|TestRustLSP|TestCollector_CollectByTreeSitter_Java

steps:
- name: Checkout code
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
DIFFJSON_IGNORE: >
['id']
['Path']
['ToolVersion']
['Modules']['a.b/c']['Dependencies']['a.b/c']
['Modules']['a.b/c/cmdx']['Dependencies']['a.b/c/cmdx']
steps:
Expand Down
12 changes: 8 additions & 4 deletions lang/lsp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func NewLSPClient(repo string, openfile string, wait time.Duration, opts ClientO
return nil, err
}

cli, err := initLSPClient(context.Background(), svr, NewURI(repo), opts.Verbose, opts.InitializationOptions)
cli, err := initLSPClient(context.Background(), svr, NewURI(repo), opts.Verbose, opts.Language, opts.InitializationOptions)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -122,7 +122,7 @@ func (c *LSPClient) InitFiles() {
}
}

func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir DocumentURI, verbose bool, InitializationOptions interface{}) (*LSPClient, error) {
func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir DocumentURI, verbose bool, language uniast.Language, InitializationOptions interface{}) (*LSPClient, error) {
h := newLSPHandler()
stream := jsonrpc2.NewBufferedStream(svr, jsonrpc2.VSCodeObjectCodec{})
conn := jsonrpc2.NewConn(ctx, stream, h)
Expand All @@ -141,8 +141,12 @@ func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir DocumentURI,
"dynamicRegistration": true,
},
},
"documentSymbol": map[string]interface{}{
"hierarchicalDocumentSymbolSupport": true,
"textDocument": map[string]interface{}{
"documentSymbol": map[string]interface{}{
// Java uses tree-sitter instead of hierarchical symbols
// Golang stays the same as older versions. ABCoder do not use gopls, so don't play with it.
"hierarchicalDocumentSymbolSupport": (language != uniast.Java && language != uniast.Golang),
},
},
}

Expand Down
8 changes: 7 additions & 1 deletion lang/lsp/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,18 @@ type DocumentSymbol struct {
Name string `json:"name"`
Kind SymbolKind `json:"kind"`
Tags []json.RawMessage `json:"tags"`
Location Location `json:"location"`
Children []*DocumentSymbol `json:"children"`
Text string `json:"text"`
Tokens []Token `json:"tokens"`
Node *sitter.Node `json:"-"`
Role SymbolRole `json:"-"`

// Older LSPs might return SymbolInformation[] which have `Location`.
// Newer LSPs return DocumentSymbol[] which have `Range` and `SelectionRange`.
// ABCoder uses `Location`, and converts `Range` to `Location` when needed.
Location Location `json:"location"`
Range *Range `json:"range"`
SelectionRange *Range `json:"selectionRange"`
}

type TextDocumentPositionParams struct {
Expand Down
47 changes: 43 additions & 4 deletions lang/lsp/lsp_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,44 @@ func (cli *LSPClient) DidOpen(ctx context.Context, file DocumentURI) (*TextDocum
return f, nil
}

func flattenDocumentSymbols(symbols []*DocumentSymbol, uri DocumentURI) []*DocumentSymbol {
var result []*DocumentSymbol
for _, sym := range symbols {
var location Location
if sym.Range != nil {
location = Location{
URI: uri,
Range: *sym.Range,
}
} else {
location = sym.Location
}
flatSymbol := DocumentSymbol{
// copy
Name: sym.Name,
Kind: sym.Kind,
Tags: sym.Tags,
Text: sym.Text,
Tokens: sym.Tokens,
Node: sym.Node,
Children: sym.Children,
// new
Location: location,
// empty
Role: 0,
Range: nil,
SelectionRange: nil,
}
result = append(result, &flatSymbol)

if len(sym.Children) > 0 {
childSymbols := flattenDocumentSymbols(sym.Children, uri)
result = append(result, childSymbols...)
}
}
return result
}

func (cli *LSPClient) DocumentSymbols(ctx context.Context, file DocumentURI) (map[Range]*DocumentSymbol, error) {
// open file first
f, err := cli.DidOpen(ctx, file)
Expand All @@ -78,14 +116,15 @@ func (cli *LSPClient) DocumentSymbols(ctx context.Context, file DocumentURI) (ma
URI: uri,
},
}
var resp []DocumentSymbol
var resp []*DocumentSymbol
if err := cli.Call(ctx, "textDocument/documentSymbol", req, &resp); err != nil {
return nil, err
}
respFlatten := flattenDocumentSymbols(resp, file)
// cache symbols
f.Symbols = make(map[Range]*DocumentSymbol, len(resp))
for i := range resp {
s := &resp[i]
f.Symbols = make(map[Range]*DocumentSymbol, len(respFlatten))
for i := range respFlatten {
s := respFlatten[i]
f.Symbols[s.Location.Range] = s
}
return f.Symbols, nil
Expand Down
2 changes: 1 addition & 1 deletion lang/python/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func CheckPythonVersion() error {

func InstallLanguageServer() (string, error) {
if out, err := exec.Command("pylsp", "--version").CombinedOutput(); err == nil {
log.Info("pylsp already installed: %v", out)
log.Info("pylsp already installed: %v", string(out))
return lspName, nil
}
if err := CheckPythonVersion(); err != nil {
Expand Down
Loading