mirror of
https://github.com/denoland/deno.git
synced 2025-08-03 10:33:54 +00:00
feat(lsp): implement textDocument/foldingRange (#9900)
Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
This commit is contained in:
parent
f50385b2a5
commit
035f7b0ca0
9 changed files with 274 additions and 2 deletions
|
@ -228,6 +228,25 @@ impl Inner {
|
|||
maybe_line_index
|
||||
}
|
||||
|
||||
// TODO(@kitsonk) we really should find a better way to just return the
|
||||
// content as a `&str`, or be able to get the byte at a particular offset
|
||||
// which is all that this API that is consuming it is trying to do at the
|
||||
// moment
|
||||
/// Searches already cached assets and documents and returns its text
|
||||
/// content. If not found, `None` is returned.
|
||||
fn get_text_content(&self, specifier: &ModuleSpecifier) -> Option<String> {
|
||||
if specifier.scheme() == "asset" {
|
||||
self
|
||||
.assets
|
||||
.get(specifier)
|
||||
.map(|o| o.clone().map(|a| a.text))?
|
||||
} else if self.documents.contains_key(specifier) {
|
||||
self.documents.content(specifier).unwrap()
|
||||
} else {
|
||||
self.sources.get_source(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_navigation_tree(
|
||||
&mut self,
|
||||
specifier: &ModuleSpecifier,
|
||||
|
@ -1515,6 +1534,63 @@ impl Inner {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
async fn folding_range(
|
||||
&self,
|
||||
params: FoldingRangeParams,
|
||||
) -> LspResult<Option<Vec<FoldingRange>>> {
|
||||
if !self.enabled() {
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("folding_range");
|
||||
let specifier = self.url_map.normalize_url(¶ms.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::GetOutliningSpans(specifier.clone());
|
||||
let outlining_spans: Vec<tsc::OutliningSpan> = self
|
||||
.ts_server
|
||||
.request(self.snapshot(), req)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Failed to request to tsserver {}", err);
|
||||
LspError::invalid_request()
|
||||
})?;
|
||||
|
||||
let response = if !outlining_spans.is_empty() {
|
||||
let text_content =
|
||||
self.get_text_content(&specifier).ok_or_else(|| {
|
||||
LspError::invalid_params(format!(
|
||||
"An unexpected specifier ({}) was provided.",
|
||||
specifier
|
||||
))
|
||||
})?;
|
||||
Some(
|
||||
outlining_spans
|
||||
.iter()
|
||||
.map(|span| {
|
||||
span.to_folding_range(
|
||||
&line_index,
|
||||
text_content.as_str().as_bytes(),
|
||||
self.config.client_capabilities.line_folding_only,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<FoldingRange>>(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.performance.measure(mark);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn rename(
|
||||
&mut self,
|
||||
params: RenameParams,
|
||||
|
@ -1840,6 +1916,13 @@ impl lspower::LanguageServer for LanguageServer {
|
|||
self.0.lock().await.goto_implementation(params).await
|
||||
}
|
||||
|
||||
async fn folding_range(
|
||||
&self,
|
||||
params: FoldingRangeParams,
|
||||
) -> LspResult<Option<Vec<FoldingRange>>> {
|
||||
self.0.lock().await.folding_range(params).await
|
||||
}
|
||||
|
||||
async fn rename(
|
||||
&self,
|
||||
params: RenameParams,
|
||||
|
@ -2425,6 +2508,54 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_folding_range() {
|
||||
let mut harness = LspTestHarness::new(vec![
|
||||
("initialize_request.json", LspResponse::RequestAny),
|
||||
("initialized_notification.json", LspResponse::None),
|
||||
(
|
||||
"folding_range_did_open_notification.json",
|
||||
LspResponse::None,
|
||||
),
|
||||
(
|
||||
"folding_range_request.json",
|
||||
LspResponse::Request(
|
||||
2,
|
||||
json!([
|
||||
{
|
||||
"startLine": 0,
|
||||
"endLine": 12,
|
||||
"kind": "region"
|
||||
},
|
||||
{
|
||||
"startLine": 1,
|
||||
"endLine": 3,
|
||||
"kind": "comment"
|
||||
},
|
||||
{
|
||||
"startLine": 4,
|
||||
"endLine": 10
|
||||
},
|
||||
{
|
||||
"startLine": 5,
|
||||
"endLine": 9
|
||||
},
|
||||
{
|
||||
"startLine": 6,
|
||||
"endLine": 7
|
||||
}
|
||||
]),
|
||||
),
|
||||
),
|
||||
(
|
||||
"shutdown_request.json",
|
||||
LspResponse::Request(3, json!(null)),
|
||||
),
|
||||
("exit_notification.json", LspResponse::None),
|
||||
]);
|
||||
harness.run().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rename() {
|
||||
let mut harness = LspTestHarness::new(vec![
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue