aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/ast/edit_in_place.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src/ast/edit_in_place.rs')
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs130
1 files changed, 109 insertions, 21 deletions
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index ca777d057..14624c682 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -13,7 +13,7 @@ use crate::{
13 make, GenericParamsOwner, 13 make, GenericParamsOwner,
14 }, 14 },
15 ted::{self, Position}, 15 ted::{self, Position},
16 AstNode, AstToken, Direction, 16 AstNode, AstToken, Direction, SyntaxNode,
17}; 17};
18 18
19use super::NameOwner; 19use super::NameOwner;
@@ -297,7 +297,7 @@ impl ast::AssocItemList {
297 ), 297 ),
298 None => match self.l_curly_token() { 298 None => match self.l_curly_token() {
299 Some(l_curly) => { 299 Some(l_curly) => {
300 self.normalize_ws_between_braces(); 300 normalize_ws_between_braces(self.syntax());
301 (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n") 301 (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
302 } 302 }
303 None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), 303 None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"),
@@ -309,25 +309,6 @@ impl ast::AssocItemList {
309 ]; 309 ];
310 ted::insert_all(position, elements); 310 ted::insert_all(position, elements);
311 } 311 }
312
313 fn normalize_ws_between_braces(&self) -> Option<()> {
314 let l = self.l_curly_token()?;
315 let r = self.r_curly_token()?;
316 let indent = IndentLevel::from_node(self.syntax());
317
318 match l.next_sibling_or_token() {
319 Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
320 if ws.next_sibling_or_token()?.into_token()? == r {
321 ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent)));
322 }
323 }
324 Some(ws) if ws.kind() == T!['}'] => {
325 ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent)));
326 }
327 _ => (),
328 }
329 Some(())
330 }
331} 312}
332 313
333impl ast::Fn { 314impl ast::Fn {
@@ -346,6 +327,113 @@ impl ast::Fn {
346 } 327 }
347} 328}
348 329
330impl ast::MatchArm {
331 pub fn remove(&self) {
332 if let Some(sibling) = self.syntax().prev_sibling_or_token() {
333 if sibling.kind() == SyntaxKind::WHITESPACE {
334 ted::remove(sibling);
335 }
336 }
337 if let Some(sibling) = self.syntax().next_sibling_or_token() {
338 if sibling.kind() == T![,] {
339 ted::remove(sibling);
340 }
341 }
342 ted::remove(self.syntax());
343 }
344}
345
346impl ast::MatchArmList {
347 pub fn add_arm(&self, arm: ast::MatchArm) {
348 normalize_ws_between_braces(self.syntax());
349 let position = match self.arms().last() {
350 Some(last_arm) => {
351 let curly = last_arm
352 .syntax()
353 .siblings_with_tokens(Direction::Next)
354 .find(|it| it.kind() == T![,]);
355 Position::after(curly.unwrap_or_else(|| last_arm.syntax().clone().into()))
356 }
357 None => match self.l_curly_token() {
358 Some(it) => Position::after(it),
359 None => Position::last_child_of(self.syntax()),
360 },
361 };
362 let indent = IndentLevel::from_node(self.syntax()) + 1;
363 let elements = vec![
364 make::tokens::whitespace(&format!("\n{}", indent)).into(),
365 arm.syntax().clone().into(),
366 ];
367 ted::insert_all(position, elements);
368 }
369}
370
371impl ast::RecordExprFieldList {
372 pub fn add_field(&self, field: ast::RecordExprField) {
373 let is_multiline = self.syntax().text().contains_char('\n');
374 let whitespace = if is_multiline {
375 let indent = IndentLevel::from_node(self.syntax()) + 1;
376 make::tokens::whitespace(&format!("\n{}", indent))
377 } else {
378 make::tokens::single_space()
379 };
380
381 let position = match self.fields().last() {
382 Some(last_field) => {
383 let comma = match last_field
384 .syntax()
385 .siblings_with_tokens(Direction::Next)
386 .filter_map(|it| it.into_token())
387 .find(|it| it.kind() == T![,])
388 {
389 Some(it) => it,
390 None => {
391 let comma = ast::make::token(T![,]);
392 ted::insert(Position::after(last_field.syntax()), &comma);
393 comma
394 }
395 };
396 Position::after(comma)
397 }
398 None => match self.l_curly_token() {
399 Some(it) => Position::after(it),
400 None => Position::last_child_of(self.syntax()),
401 },
402 };
403
404 ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
405 if is_multiline {
406 ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
407 }
408 }
409}
410
411fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
412 let l = node
413 .children_with_tokens()
414 .filter_map(|it| it.into_token())
415 .find(|it| it.kind() == T!['{'])?;
416 let r = node
417 .children_with_tokens()
418 .filter_map(|it| it.into_token())
419 .find(|it| it.kind() == T!['}'])?;
420
421 let indent = IndentLevel::from_node(node);
422
423 match l.next_sibling_or_token() {
424 Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
425 if ws.next_sibling_or_token()?.into_token()? == r {
426 ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent)));
427 }
428 }
429 Some(ws) if ws.kind() == T!['}'] => {
430 ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent)));
431 }
432 _ => (),
433 }
434 Some(())
435}
436
349#[cfg(test)] 437#[cfg(test)]
350mod tests { 438mod tests {
351 use std::fmt; 439 use std::fmt;