internal: add add_tabstop_{before,after}_token

This commit is contained in:
DropDemBits 2023-06-24 20:31:44 -04:00
parent db0add1ce9
commit 4de7cbe04c
No known key found for this signature in database
GPG Key ID: 7FE02A6C1EDFA075

View File

@ -9,7 +9,10 @@ use crate::SnippetCap;
use base_db::{AnchoredPathBuf, FileId}; use base_db::{AnchoredPathBuf, FileId};
use nohash_hasher::IntMap; use nohash_hasher::IntMap;
use stdx::never; use stdx::never;
use syntax::{algo, ast, ted, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; use syntax::{
algo, ast, ted, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
TextSize,
};
use text_edit::{TextEdit, TextEditBuilder}; use text_edit::{TextEdit, TextEditBuilder};
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
@ -237,19 +240,31 @@ impl SourceChangeBuilder {
/// Adds a tabstop snippet to place the cursor before `node` /// Adds a tabstop snippet to place the cursor before `node`
pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) { pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) {
assert!(node.syntax().parent().is_some()); assert!(node.syntax().parent().is_some());
self.add_snippet(PlaceSnippet::Before(node.syntax().clone())); self.add_snippet(PlaceSnippet::Before(node.syntax().clone().into()));
} }
/// Adds a tabstop snippet to place the cursor after `node` /// Adds a tabstop snippet to place the cursor after `node`
pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) { pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) {
assert!(node.syntax().parent().is_some()); assert!(node.syntax().parent().is_some());
self.add_snippet(PlaceSnippet::After(node.syntax().clone())); self.add_snippet(PlaceSnippet::After(node.syntax().clone().into()));
}
/// Adds a tabstop snippet to place the cursor before `token`
pub fn add_tabstop_before_token(&mut self, _cap: SnippetCap, token: SyntaxToken) {
assert!(token.parent().is_some());
self.add_snippet(PlaceSnippet::Before(token.clone().into()));
}
/// Adds a tabstop snippet to place the cursor after `token`
pub fn add_tabstop_after_token(&mut self, _cap: SnippetCap, token: SyntaxToken) {
assert!(token.parent().is_some());
self.add_snippet(PlaceSnippet::After(token.clone().into()));
} }
/// Adds a snippet to move the cursor selected over `node` /// Adds a snippet to move the cursor selected over `node`
pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) { pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) {
assert!(node.syntax().parent().is_some()); assert!(node.syntax().parent().is_some());
self.add_snippet(PlaceSnippet::Over(node.syntax().clone())) self.add_snippet(PlaceSnippet::Over(node.syntax().clone().into()))
} }
fn add_snippet(&mut self, snippet: PlaceSnippet) { fn add_snippet(&mut self, snippet: PlaceSnippet) {
@ -282,38 +297,40 @@ impl From<FileSystemEdit> for SourceChange {
} }
enum PlaceSnippet { enum PlaceSnippet {
/// Place a tabstop before a node /// Place a tabstop before an element
Before(SyntaxNode), Before(SyntaxElement),
/// Place a tabstop before a node /// Place a tabstop before an element
After(SyntaxNode), After(SyntaxElement),
/// Place a placeholder snippet in place of the node /// Place a placeholder snippet in place of the element
Over(SyntaxNode), Over(SyntaxElement),
} }
impl PlaceSnippet { impl PlaceSnippet {
/// Places the snippet before or over a node with the given tab stop index /// Places the snippet before or over an element with the given tab stop index
fn place(self, order: usize) { fn place(self, order: usize) {
// ensure the target node is still attached // ensure the target element is still attached
match &self { match &self {
PlaceSnippet::Before(node) | PlaceSnippet::After(node) | PlaceSnippet::Over(node) => { PlaceSnippet::Before(element)
// node should still be in the tree, but if it isn't | PlaceSnippet::After(element)
| PlaceSnippet::Over(element) => {
// element should still be in the tree, but if it isn't
// then it's okay to just ignore this place // then it's okay to just ignore this place
if stdx::never!(node.parent().is_none()) { if stdx::never!(element.parent().is_none()) {
return; return;
} }
} }
} }
match self { match self {
PlaceSnippet::Before(node) => { PlaceSnippet::Before(element) => {
ted::insert_raw(ted::Position::before(&node), Self::make_tab_stop(order)); ted::insert_raw(ted::Position::before(&element), Self::make_tab_stop(order));
} }
PlaceSnippet::After(node) => { PlaceSnippet::After(element) => {
ted::insert_raw(ted::Position::after(&node), Self::make_tab_stop(order)); ted::insert_raw(ted::Position::after(&element), Self::make_tab_stop(order));
} }
PlaceSnippet::Over(node) => { PlaceSnippet::Over(element) => {
let position = ted::Position::before(&node); let position = ted::Position::before(&element);
node.detach(); element.detach();
let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}")) let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}"))
.syntax_node() .syntax_node()
@ -321,7 +338,7 @@ impl PlaceSnippet {
let placeholder = let placeholder =
snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap(); snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap();
ted::replace(placeholder.syntax(), node); ted::replace(placeholder.syntax(), element);
ted::insert_raw(position, snippet); ted::insert_raw(position, snippet);
} }