fixup folding ranges for "lineFoldingOnly" clients #2033
This commit is contained in:
parent
6b9bd7bdd2
commit
9d5e932626
@ -227,22 +227,57 @@ impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit {
|
||||
}
|
||||
}
|
||||
|
||||
impl ConvWith<&LineIndex> for Fold {
|
||||
pub(crate) struct FoldConvCtx<'a> {
|
||||
pub(crate) text: &'a str,
|
||||
pub(crate) line_index: &'a LineIndex,
|
||||
pub(crate) line_folding_only: bool,
|
||||
}
|
||||
|
||||
impl ConvWith<&FoldConvCtx<'_>> for Fold {
|
||||
type Output = lsp_types::FoldingRange;
|
||||
|
||||
fn conv_with(self, line_index: &LineIndex) -> lsp_types::FoldingRange {
|
||||
let range = self.range.conv_with(&line_index);
|
||||
lsp_types::FoldingRange {
|
||||
start_line: range.start.line,
|
||||
start_character: Some(range.start.character),
|
||||
end_line: range.end.line,
|
||||
end_character: Some(range.end.character),
|
||||
kind: match self.kind {
|
||||
FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
|
||||
FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
|
||||
FoldKind::Mods => None,
|
||||
FoldKind::Block => None,
|
||||
},
|
||||
fn conv_with(self, ctx: &FoldConvCtx) -> lsp_types::FoldingRange {
|
||||
let kind = match self.kind {
|
||||
FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
|
||||
FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
|
||||
FoldKind::Mods => None,
|
||||
FoldKind::Block => None,
|
||||
};
|
||||
|
||||
let range = self.range.conv_with(&ctx.line_index);
|
||||
|
||||
if ctx.line_folding_only {
|
||||
// Clients with line_folding_only == true (such as VSCode) will fold the whole end line
|
||||
// even if it contains text not in the folding range. To prevent that we exclude
|
||||
// range.end.line from the folding region if there is more text after range.end
|
||||
// on the same line.
|
||||
let has_more_text_on_end_line = ctx.text
|
||||
[TextRange::from_to(self.range.end(), TextUnit::of_str(ctx.text))]
|
||||
.chars()
|
||||
.take_while(|it| *it != '\n')
|
||||
.any(|it| !it.is_whitespace());
|
||||
|
||||
let end_line = if has_more_text_on_end_line {
|
||||
range.end.line.saturating_sub(1)
|
||||
} else {
|
||||
range.end.line
|
||||
};
|
||||
|
||||
lsp_types::FoldingRange {
|
||||
start_line: range.start.line,
|
||||
start_character: None,
|
||||
end_line,
|
||||
end_character: None,
|
||||
kind,
|
||||
}
|
||||
} else {
|
||||
lsp_types::FoldingRange {
|
||||
start_line: range.start.line,
|
||||
start_character: Some(range.start.character),
|
||||
end_line: range.end.line,
|
||||
end_character: Some(range.end.character),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,21 @@ pub fn main_loop(
|
||||
connection.sender.send(request.into()).unwrap();
|
||||
}
|
||||
|
||||
let options = {
|
||||
let text_document_caps = client_caps.text_document.as_ref();
|
||||
Options {
|
||||
publish_decorations: config.publish_decorations,
|
||||
supports_location_link: text_document_caps
|
||||
.and_then(|it| it.definition)
|
||||
.and_then(|it| it.link_support)
|
||||
.unwrap_or(false),
|
||||
line_folding_only: text_document_caps
|
||||
.and_then(|it| it.folding_range.as_ref())
|
||||
.and_then(|it| it.line_folding_only)
|
||||
.unwrap_or(false),
|
||||
}
|
||||
};
|
||||
|
||||
let feature_flags = {
|
||||
let mut ff = FeatureFlags::default();
|
||||
for (flag, value) in config.feature_flags {
|
||||
@ -133,14 +148,7 @@ pub fn main_loop(
|
||||
config.lru_capacity,
|
||||
&globs,
|
||||
Watch(!config.use_client_watching),
|
||||
Options {
|
||||
publish_decorations: config.publish_decorations,
|
||||
supports_location_link: client_caps
|
||||
.text_document
|
||||
.and_then(|it| it.definition)
|
||||
.and_then(|it| it.link_support)
|
||||
.unwrap_or(false),
|
||||
},
|
||||
options,
|
||||
feature_flags,
|
||||
)
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ use serde_json::to_value;
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::{runnable_args, CargoTargetSpec},
|
||||
conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith, TryConvWithToVec},
|
||||
conv::{to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, TryConvWithToVec},
|
||||
req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind},
|
||||
world::WorldSnapshot,
|
||||
LspError, Result,
|
||||
@ -383,8 +383,14 @@ pub fn handle_folding_range(
|
||||
) -> Result<Option<Vec<FoldingRange>>> {
|
||||
let file_id = params.text_document.try_conv_with(&world)?;
|
||||
let folds = world.analysis().folding_ranges(file_id)?;
|
||||
let text = world.analysis().file_text(file_id)?;
|
||||
let line_index = world.analysis().file_line_index(file_id)?;
|
||||
let res = Some(folds.into_iter().map_conv_with(&*line_index).collect());
|
||||
let ctx = FoldConvCtx {
|
||||
text: &text,
|
||||
line_index: &line_index,
|
||||
line_folding_only: world.options.line_folding_only,
|
||||
};
|
||||
let res = Some(folds.into_iter().map_conv_with(&ctx).collect());
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use crate::{
|
||||
pub struct Options {
|
||||
pub publish_decorations: bool,
|
||||
pub supports_location_link: bool,
|
||||
pub line_folding_only: bool,
|
||||
}
|
||||
|
||||
/// `WorldState` is the primary mutable state of the language server
|
||||
|
Loading…
x
Reference in New Issue
Block a user