fixup folding ranges for "lineFoldingOnly" clients #2033

This commit is contained in:
Alex Zatelepin 2019-10-21 02:04:55 +03:00
parent 6b9bd7bdd2
commit 9d5e932626
4 changed files with 74 additions and 24 deletions

View File

@ -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,
}
}
}
}

View File

@ -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,
)
};

View File

@ -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)
}

View File

@ -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