feat(lsp): Implement textDocument/documentSymbol (#9981)

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
This commit is contained in:
Jean Pierre 2021-04-19 20:29:27 -05:00 committed by GitHub
parent 6d404ec54b
commit 2079da0f1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 563 additions and 2 deletions

View file

@ -718,6 +718,49 @@ impl Inner {
self.performance.measure(mark);
}
async fn document_symbol(
&self,
params: DocumentSymbolParams,
) -> LspResult<Option<DocumentSymbolResponse>> {
if !self.enabled() {
return Ok(None);
}
let mark = self.performance.mark("selection_range");
let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
} else {
return Err(LspError::invalid_params(format!(
"An unexpected specifier ({}) was provided.",
specifier
)));
};
let req = tsc::RequestMethod::GetNavigationTree(specifier);
let navigation_tree: tsc::NavigationTree = self
.ts_server
.request(self.snapshot(), req)
.await
.map_err(|err| {
error!("Failed to request to tsserver {}", err);
LspError::invalid_request()
})?;
let response = if let Some(child_items) = navigation_tree.child_items {
let mut document_symbols = Vec::<DocumentSymbol>::new();
for item in child_items {
item.collect_document_symbols(&line_index, &mut document_symbols);
}
Some(DocumentSymbolResponse::Nested(document_symbols))
} else {
None
};
self.performance.measure(mark);
Ok(response)
}
async fn formatting(
&self,
params: DocumentFormattingParams,
@ -2165,6 +2208,13 @@ impl lspower::LanguageServer for LanguageServer {
self.0.lock().await.did_change_watched_files(params).await
}
async fn document_symbol(
&self,
params: DocumentSymbolParams,
) -> LspResult<Option<DocumentSymbolResponse>> {
self.0.lock().await.document_symbol(params).await
}
async fn formatting(
&self,
params: DocumentFormattingParams,
@ -3406,6 +3456,410 @@ mod tests {
);
}
#[tokio::test]
async fn test_document_symbol() {
let mut harness = LspTestHarness::new(vec![
(
LspFixture::Path("initialize_request.json"),
LspResponse::RequestAny,
),
(
LspFixture::Path("initialized_notification.json"),
LspResponse::None,
),
(
LspFixture::Path("document_symbol_did_open_notification.json"),
LspResponse::None,
),
(
LspFixture::Path("document_symbol_request.json"),
LspResponse::Request(
2,
json!([
{
"name": "bar",
"kind": 13,
"range": {
"start": {
"line": 17,
"character": 4
},
"end": {
"line": 17,
"character": 26
}
},
"selectionRange": {
"start": {
"line": 17,
"character": 4
},
"end": {
"line": 17,
"character": 7
}
}
},
{
"name": "Bar",
"kind": 5,
"range": {
"start": {
"line": 4,
"character": 0
},
"end": {
"line": 13,
"character": 1
}
},
"selectionRange": {
"start": {
"line": 4,
"character": 6
},
"end": {
"line": 4,
"character": 9
}
},
"children": [
{
"name": "constructor",
"kind": 9,
"range": {
"start": {
"line": 5,
"character": 2
},
"end": {
"line": 5,
"character": 35
}
},
"selectionRange": {
"start": {
"line": 5,
"character": 2
},
"end": {
"line": 5,
"character": 35
}
}
},
{
"name": "baz",
"kind": 6,
"tags": [
1
],
"range": {
"start": {
"line": 8,
"character": 2
},
"end": {
"line": 8,
"character": 25
}
},
"selectionRange": {
"start": {
"line": 8,
"character": 2
},
"end": {
"line": 8,
"character": 5
}
}
},
{
"name": "foo",
"kind": 6,
"range": {
"start": {
"line": 6,
"character": 2
},
"end": {
"line": 6,
"character": 24
}
},
"selectionRange": {
"start": {
"line": 6,
"character": 2
},
"end": {
"line": 6,
"character": 5
}
}
},
{
"name": "getStaticBar",
"kind": 6,
"range": {
"start": {
"line": 12,
"character": 2
},
"end": {
"line": 12,
"character": 57
}
},
"selectionRange": {
"start": {
"line": 12,
"character": 17
},
"end": {
"line": 12,
"character": 29
}
}
},
{
"name": "staticBar",
"kind": 7,
"range": {
"start": {
"line": 11,
"character": 2
},
"end": {
"line": 11,
"character": 32
}
},
"selectionRange": {
"start": {
"line": 11,
"character": 9
},
"end": {
"line": 11,
"character": 18
}
}
},
{
"name": "value",
"kind": 7,
"range": {
"start": {
"line": 9,
"character": 2
},
"end": {
"line": 9,
"character": 35
}
},
"selectionRange": {
"start": {
"line": 9,
"character": 6
},
"end": {
"line": 9,
"character": 11
}
}
},
{
"name": "value",
"kind": 7,
"range": {
"start": {
"line": 10,
"character": 2
},
"end": {
"line": 10,
"character": 42
}
},
"selectionRange": {
"start": {
"line": 10,
"character": 6
},
"end": {
"line": 10,
"character": 11
}
}
},
{
"name": "x",
"kind": 7,
"range": {
"start": {
"line": 5,
"character": 14
},
"end": {
"line": 5,
"character": 30
}
},
"selectionRange": {
"start": {
"line": 5,
"character": 21
},
"end": {
"line": 5,
"character": 22
}
}
}
]
},
{
"name": "IFoo",
"kind": 11,
"range": {
"start": {
"line": 0,
"character": 0
},
"end": {
"line": 2,
"character": 1
}
},
"selectionRange": {
"start": {
"line": 0,
"character": 10
},
"end": {
"line": 0,
"character": 14
}
},
"children": [
{
"name": "foo",
"kind": 6,
"range": {
"start": {
"line": 1,
"character": 2
},
"end": {
"line": 1,
"character": 17
}
},
"selectionRange": {
"start": {
"line": 1,
"character": 2
},
"end": {
"line": 1,
"character": 5
}
}
}
]
},
{
"name": "Values",
"kind": 10,
"range": {
"start": {
"line": 15,
"character": 0
},
"end": {
"line": 15,
"character": 30
}
},
"selectionRange": {
"start": {
"line": 15,
"character": 5
},
"end": {
"line": 15,
"character": 11
}
},
"children": [
{
"name": "value1",
"kind": 13,
"range": {
"start": {
"line": 15,
"character": 14
},
"end": {
"line": 15,
"character": 20
}
},
"selectionRange": {
"start": {
"line": 15,
"character": 14
},
"end": {
"line": 15,
"character": 20
}
}
},
{
"name": "value2",
"kind": 13,
"range": {
"start": {
"line": 15,
"character": 22
},
"end": {
"line": 15,
"character": 28
}
},
"selectionRange": {
"start": {
"line": 15,
"character": 22
},
"end": {
"line": 15,
"character": 28
}
}
}
]
}
]),
),
),
(
LspFixture::Path("shutdown_request.json"),
LspResponse::Request(3, json!(null)),
),
(
LspFixture::Path("exit_notification.json"),
LspResponse::None,
),
]);
harness.run().await;
}
#[tokio::test]
async fn test_folding_range() {
let mut harness = LspTestHarness::new(vec![