-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve behavior of folding feature (#918)
Do not fold the entire structure but the contents inside. See #915.
Showing
12 changed files
with
268 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "folding" | ||
version = "0.0.0" | ||
license.workspace = true | ||
authors.workspace = true | ||
edition.workspace = true | ||
rust-version.workspace = true | ||
|
||
[dependencies] | ||
base-db = { path = "../base-db" } | ||
rowan = "0.15.11" | ||
syntax = { path = "../syntax" } | ||
|
||
[dev-dependencies] | ||
expect-test = "1.4.1" | ||
test-utils = { path = "../test-utils" } | ||
|
||
[lib] | ||
doctest = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use base_db::{Document, DocumentData}; | ||
use rowan::{ast::AstNode, TextRange}; | ||
use syntax::{ | ||
bibtex::{self, HasDelims, HasName}, | ||
latex, | ||
}; | ||
|
||
#[derive(Debug)] | ||
pub struct FoldingRange { | ||
pub range: TextRange, | ||
pub kind: FoldingRangeKind, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] | ||
pub enum FoldingRangeKind { | ||
Section, | ||
Environment, | ||
Entry, | ||
} | ||
|
||
pub fn find_all(document: &Document) -> Vec<FoldingRange> { | ||
let mut builder = FoldingBuilder::default(); | ||
|
||
if let DocumentData::Tex(data) = &document.data { | ||
for node in data.root_node().descendants() { | ||
if let Some(section) = latex::Section::cast(node.clone()) { | ||
builder.fold_section(§ion); | ||
} else if let Some(item) = latex::EnumItem::cast(node.clone()) { | ||
builder.fold_enum_item(&item); | ||
} else if let Some(env) = latex::Environment::cast(node) { | ||
builder.fold_environment(env); | ||
} | ||
} | ||
} else if let DocumentData::Bib(data) = &document.data { | ||
for node in data.root_node().descendants() { | ||
if let Some(entry) = bibtex::Entry::cast(node.clone()) { | ||
builder.fold_entry(&entry); | ||
} else if let Some(string) = bibtex::StringDef::cast(node) { | ||
builder.fold_entry(&string); | ||
} | ||
} | ||
} | ||
|
||
builder.ranges | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
struct FoldingBuilder { | ||
ranges: Vec<FoldingRange>, | ||
} | ||
|
||
impl FoldingBuilder { | ||
fn fold_section(&mut self, section: &latex::Section) -> Option<()> { | ||
let start = section | ||
.name() | ||
.map(|name| latex::small_range(&name).end()) | ||
.or_else(|| section.command().map(|cmd| cmd.text_range().end()))?; | ||
let end = section.syntax().text_range().end(); | ||
|
||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
kind: FoldingRangeKind::Section, | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_enum_item(&mut self, item: &latex::EnumItem) -> Option<()> { | ||
let start = item | ||
.label() | ||
.map(|label| latex::small_range(&label).end()) | ||
.or_else(|| item.command().map(|cmd| cmd.text_range().end()))?; | ||
|
||
let end = item.syntax().text_range().end(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
kind: FoldingRangeKind::Section, | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_environment(&mut self, env: latex::Environment) -> Option<()> { | ||
let start = latex::small_range(&env.begin()?).end(); | ||
let end = latex::small_range(&env.end()?).start(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
kind: FoldingRangeKind::Environment, | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_entry(&mut self, entry: &(impl HasName + HasDelims)) -> Option<()> { | ||
let start = entry.name_token()?.text_range().end(); | ||
let end = entry.right_delim_token()?.text_range().start(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
kind: FoldingRangeKind::Entry, | ||
}); | ||
|
||
Some(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
use expect_test::{expect, Expect}; | ||
|
||
fn check(input: &str, expect: Expect) { | ||
let fixture = test_utils::fixture::Fixture::parse(input); | ||
let workspace = &fixture.workspace; | ||
let document = workspace.lookup(&fixture.documents[0].uri).unwrap(); | ||
let data = crate::find_all(document); | ||
expect.assert_debug_eq(&data); | ||
} | ||
|
||
#[test] | ||
fn test_latex() { | ||
check( | ||
r#" | ||
%! main.tex | ||
\begin{document} | ||
\section{Foo} | ||
foo | ||
\subsection{Bar} | ||
bar | ||
\section{Baz} | ||
baz | ||
\section{Qux} | ||
\end{document} | ||
|"#, | ||
expect![[r#" | ||
[ | ||
FoldingRange { | ||
range: 16..116, | ||
kind: Environment, | ||
}, | ||
FoldingRange { | ||
range: 34..76, | ||
kind: Section, | ||
}, | ||
FoldingRange { | ||
range: 63..76, | ||
kind: Section, | ||
}, | ||
FoldingRange { | ||
range: 89..102, | ||
kind: Section, | ||
}, | ||
FoldingRange { | ||
range: 115..116, | ||
kind: Section, | ||
}, | ||
] | ||
"#]], | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_bibtex() { | ||
check( | ||
r#" | ||
%! main.bib | ||
some junk | ||
here | ||
@article{foo, | ||
author = {bar}, | ||
title = {baz} | ||
} | ||
@string{foo = "bar"} | ||
@comment{foo, | ||
author = {bar}, | ||
title = {baz} | ||
} | ||
@preamble{"foo"} | ||
|"#, | ||
expect![[r#" | ||
[ | ||
FoldingRange { | ||
range: 28..68, | ||
kind: Entry, | ||
}, | ||
FoldingRange { | ||
range: 82..90, | ||
kind: Entry, | ||
}, | ||
] | ||
"#]], | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,44 @@ | ||
use base_db::{DocumentData, Workspace}; | ||
use lsp_types::{FoldingRange, FoldingRangeKind, Range, Url}; | ||
use rowan::ast::AstNode; | ||
use syntax::{bibtex, latex}; | ||
use base_db::Workspace; | ||
use folding::FoldingRangeKind; | ||
use lsp_types::{ClientCapabilities, Url}; | ||
|
||
use crate::util::line_index_ext::LineIndexExt; | ||
|
||
pub fn find_all(workspace: &Workspace, uri: &Url) -> Option<Vec<FoldingRange>> { | ||
pub fn find_all( | ||
workspace: &Workspace, | ||
uri: &Url, | ||
capabilities: &ClientCapabilities, | ||
) -> Option<Vec<serde_json::Value>> { | ||
let custom_kinds = capabilities | ||
.text_document | ||
.as_ref() | ||
.and_then(|cap| cap.folding_range.as_ref()) | ||
.and_then(|cap| cap.folding_range_kind.as_ref()) | ||
.and_then(|cap| cap.value_set.as_ref()) | ||
.is_some(); | ||
|
||
let document = workspace.lookup(uri)?; | ||
let line_index = &document.line_index; | ||
let foldings = match &document.data { | ||
DocumentData::Tex(data) => { | ||
let mut results = Vec::new(); | ||
for node in data.root_node().descendants() { | ||
if let Some(folding) = latex::Environment::cast(node.clone()) | ||
.map(|node| latex::small_range(&node)) | ||
.or_else(|| { | ||
latex::Section::cast(node.clone()).map(|node| latex::small_range(&node)) | ||
}) | ||
.or_else(|| latex::EnumItem::cast(node).map(|node| latex::small_range(&node))) | ||
.map(|node| line_index.line_col_lsp_range(node)) | ||
.map(create_range) | ||
{ | ||
results.push(folding); | ||
} | ||
} | ||
let foldings = folding::find_all(document).into_iter().map(|folding| { | ||
let range = document.line_index.line_col_lsp_range(folding.range); | ||
|
||
results | ||
} | ||
DocumentData::Bib(data) => { | ||
let root = data.root_node(); | ||
root.descendants() | ||
.filter(|node| { | ||
matches!( | ||
node.kind(), | ||
bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY | ||
) | ||
}) | ||
.map(|node| create_range(line_index.line_col_lsp_range(node.text_range()))) | ||
.collect() | ||
} | ||
DocumentData::Aux(_) | ||
| DocumentData::Log(_) | ||
| DocumentData::Root | ||
| DocumentData::Tectonic => { | ||
return None; | ||
} | ||
}; | ||
let kind = if custom_kinds { | ||
Some(match folding.kind { | ||
FoldingRangeKind::Section => "section", | ||
FoldingRangeKind::Environment => "environment", | ||
FoldingRangeKind::Entry => "entry", | ||
}) | ||
} else { | ||
None | ||
}; | ||
|
||
Some(foldings) | ||
} | ||
serde_json::json!({ | ||
"startLine": range.start.line, | ||
"startCharacter": range.start.character, | ||
"endLine": range.end.line, | ||
"endCharacter": range.end.character, | ||
"kind": kind, | ||
}) | ||
}); | ||
|
||
fn create_range(range: Range) -> FoldingRange { | ||
FoldingRange { | ||
start_line: range.start.line, | ||
start_character: Some(range.start.character), | ||
end_line: range.end.line, | ||
end_character: Some(range.end.character), | ||
collapsed_text: None, | ||
kind: Some(FoldingRangeKind::Region), | ||
} | ||
Some(foldings.collect()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
27 changes: 0 additions & 27 deletions
27
...s/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__bibtex.snap
This file was deleted.
Oops, something went wrong.
41 changes: 0 additions & 41 deletions
41
...es/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__latex.snap
This file was deleted.
Oops, something went wrong.