Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_assists/src/assist_context.rs')
-rw-r--r--crates/ide_assists/src/assist_context.rs30
1 files changed, 26 insertions, 4 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index 671a945a44..d6fd27efac 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -14,7 +14,7 @@ use ide_db::{
};
use syntax::{
algo::{self, find_node_at_offset, find_node_at_range},
- AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
+ AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
SyntaxToken, TextRange, TextSize, TokenAtOffset,
};
use text_edit::{TextEdit, TextEditBuilder};
@@ -57,6 +57,7 @@ pub(crate) struct AssistContext<'a> {
pub(crate) config: &'a AssistConfig,
pub(crate) sema: Semantics<'a, RootDatabase>,
pub(crate) frange: FileRange,
+ trimmed_range: TextRange,
source_file: SourceFile,
}
@@ -67,7 +68,20 @@ impl<'a> AssistContext<'a> {
frange: FileRange,
) -> AssistContext<'a> {
let source_file = sema.parse(frange.file_id);
- AssistContext { config, sema, frange, source_file }
+
+ let start = frange.range.start();
+ let end = frange.range.end();
+ let left = source_file.syntax().token_at_offset(start);
+ let right = source_file.syntax().token_at_offset(end);
+ let left =
+ left.right_biased().and_then(|t| algo::skip_whitespace_token(t, Direction::Next));
+ let right =
+ right.left_biased().and_then(|t| algo::skip_whitespace_token(t, Direction::Prev));
+ let left = left.map(|t| t.text_range().start()).unwrap_or(start).clamp(start, end);
+ let right = right.map(|t| t.text_range().end()).unwrap_or(end).clamp(start, end);
+ let trimmed_range = TextRange::new(left, right);
+
+ AssistContext { config, sema, frange, source_file, trimmed_range }
}
pub(crate) fn db(&self) -> &RootDatabase {
@@ -79,6 +93,12 @@ impl<'a> AssistContext<'a> {
self.frange.range.start()
}
+ /// Returns the selected range trimmed for whitespace tokens, that is the range will be snapped
+ /// to the nearest enclosed token.
+ pub(crate) fn selection_trimmed(&self) -> TextRange {
+ self.trimmed_range
+ }
+
pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
self.source_file.syntax().token_at_offset(self.offset())
}
@@ -92,13 +112,15 @@ impl<'a> AssistContext<'a> {
find_node_at_offset(self.source_file.syntax(), self.offset())
}
pub(crate) fn find_node_at_range<N: AstNode>(&self) -> Option<N> {
- find_node_at_range(self.source_file.syntax(), self.frange.range)
+ find_node_at_range(self.source_file.syntax(), self.trimmed_range)
}
pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> {
self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset())
}
+ /// Returns the element covered by the selection range, this excludes trailing whitespace in the selection.
pub(crate) fn covering_element(&self) -> SyntaxElement {
- self.source_file.syntax().covering_element(self.frange.range)
+ self.source_file.syntax().covering_element(self.selection_trimmed())
+ // self.source_file.syntax().covering_element(self.frange.range)
}
}