From 9d5e9326266d6b064c6d0f5d78ba2fae4d78e8fb Mon Sep 17 00:00:00 2001 From: Alex Zatelepin Date: Mon, 21 Oct 2019 02:04:55 +0300 Subject: fixup folding ranges for "lineFoldingOnly" clients #2033 --- crates/ra_lsp_server/src/conv.rs | 63 +++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-) (limited to 'crates/ra_lsp_server/src/conv.rs') diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 1318a1738..173580dee 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -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, + } } } } -- cgit v1.2.3