From a4635a199bc446bd103aa5821e57dc19b8a15751 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Jan 2019 18:59:17 +0300 Subject: more enterprisey assists API --- crates/ra_editor/src/assists.rs | 155 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 2 deletions(-) (limited to 'crates/ra_editor/src/assists.rs') diff --git a/crates/ra_editor/src/assists.rs b/crates/ra_editor/src/assists.rs index b6e6dd628..cc40ee4c8 100644 --- a/crates/ra_editor/src/assists.rs +++ b/crates/ra_editor/src/assists.rs @@ -9,8 +9,13 @@ mod add_impl; mod introduce_variable; mod change_visibility; -use ra_text_edit::TextEdit; -use ra_syntax::{Direction, SyntaxNodeRef, TextUnit}; +use ra_text_edit::{TextEdit, TextEditBuilder}; +use ra_syntax::{ + Direction, SyntaxNodeRef, TextUnit, TextRange,SourceFileNode, AstNode, + algo::{find_leaf_at_offset, find_covering_node, LeafAtOffset}, +}; + +use crate::find_node_at_offset; pub use self::{ flip_comma::flip_comma, @@ -20,6 +25,21 @@ pub use self::{ change_visibility::change_visibility, }; +/// Return all the assists applicable at the given position. +pub fn assists(file: &SourceFileNode, range: TextRange) -> Vec { + let ctx = AssistCtx::new(file, range); + [ + flip_comma, + add_derive, + add_impl, + introduce_variable, + change_visibility, + ] + .iter() + .filter_map(|&assist| ctx.clone().apply(assist)) + .collect() +} + #[derive(Debug)] pub struct LocalEdit { pub label: String, @@ -32,3 +52,134 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option { + source_file: &'a SourceFileNode, + range: TextRange, + should_compute_edit: bool, +} + +#[derive(Debug)] +pub enum Assist { + Applicable, + Edit(LocalEdit), +} + +#[derive(Default)] +struct AssistBuilder { + edit: TextEditBuilder, + cursor_position: Option, +} + +impl<'a> AssistCtx<'a> { + pub fn new(source_file: &'a SourceFileNode, range: TextRange) -> AssistCtx { + AssistCtx { + source_file, + range, + should_compute_edit: false, + } + } + + pub fn apply(mut self, assist: fn(AssistCtx) -> Option) -> Option { + self.should_compute_edit = true; + match assist(self) { + None => None, + Some(Assist::Edit(e)) => Some(e), + Some(Assist::Applicable) => unreachable!(), + } + } + + pub fn check(mut self, assist: fn(AssistCtx) -> Option) -> bool { + self.should_compute_edit = false; + match assist(self) { + None => false, + Some(Assist::Edit(_)) => unreachable!(), + Some(Assist::Applicable) => true, + } + } + + fn build(self, label: impl Into, f: impl FnOnce(&mut AssistBuilder)) -> Option { + if !self.should_compute_edit { + return Some(Assist::Applicable); + } + let mut edit = AssistBuilder::default(); + f(&mut edit); + Some(Assist::Edit(LocalEdit { + label: label.into(), + edit: edit.edit.finish(), + cursor_position: edit.cursor_position, + })) + } + + pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset> { + find_leaf_at_offset(self.source_file.syntax(), self.range.start()) + } + pub(crate) fn node_at_offset>(&self) -> Option { + find_node_at_offset(self.source_file.syntax(), self.range.start()) + } + pub(crate) fn covering_node(&self) -> SyntaxNodeRef<'a> { + find_covering_node(self.source_file.syntax(), self.range) + } +} + +impl AssistBuilder { + fn replace(&mut self, range: TextRange, replace_with: impl Into) { + self.edit.replace(range, replace_with.into()) + } + #[allow(unused)] + fn delete(&mut self, range: TextRange) { + self.edit.delete(range) + } + fn insert(&mut self, offset: TextUnit, text: impl Into) { + self.edit.insert(offset, text.into()) + } + fn set_cursor(&mut self, offset: TextUnit) { + self.cursor_position = Some(offset) + } +} + +#[cfg(test)] +fn check_assist(assist: fn(AssistCtx) -> Option, before: &str, after: &str) { + crate::test_utils::check_action(before, after, |file, off| { + let range = TextRange::offset_len(off, 0.into()); + AssistCtx::new(file, range).apply(assist) + }) +} + +#[cfg(test)] +fn check_assist_range(assist: fn(AssistCtx) -> Option, before: &str, after: &str) { + crate::test_utils::check_action_range(before, after, |file, range| { + AssistCtx::new(file, range).apply(assist) + }) +} -- cgit v1.2.3