yerba 0.7.2-arm-linux-gnu → 0.7.3-arm-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,8 +34,9 @@ use crate::error::YerbaError;
34
34
  use crate::QuoteStyle;
35
35
 
36
36
  use crate::syntax::{
37
- dedent_block_scalar, extract_scalar, extract_scalar_text, find_entry_by_key, find_scalar_token, format_scalar_value, is_map_key, is_yaml_non_string,
38
- preceding_whitespace_indent, preceding_whitespace_token, removal_range, unescape_double_quoted, unescape_single_quoted, ScalarValue,
37
+ column_at, dedent_block_scalar, extract_scalar, extract_scalar_text, find_block_map, find_block_sequence, find_entry_by_key, find_scalar_token,
38
+ first_collection, format_scalar_value, is_map_key, is_yaml_non_string, line_at, line_start_at, preceding_whitespace_indent, preceding_whitespace_token,
39
+ raw_scalar_value, removal_range, FirstCollection, ScalarValue,
39
40
  };
40
41
 
41
42
  #[derive(Debug, Clone)]
@@ -148,13 +149,13 @@ impl Document {
148
149
  .as_ref()
149
150
  .ok_or_else(|| YerbaError::IoError(std::io::Error::new(std::io::ErrorKind::NotFound, "no file path associated with this document")))?;
150
151
 
151
- fs::write(path, self.to_string())?;
152
+ fs::write(path, self.source_text())?;
152
153
 
153
154
  Ok(())
154
155
  }
155
156
 
156
157
  pub fn save_to(&self, path: impl AsRef<Path>) -> Result<(), YerbaError> {
157
- fs::write(path, self.to_string())?;
158
+ fs::write(path, self.source_text())?;
158
159
 
159
160
  Ok(())
160
161
  }
@@ -208,7 +209,7 @@ impl Document {
208
209
  let mut current_nodes: Vec<Option<SyntaxNode>> = vec![Some(document.syntax().clone())];
209
210
 
210
211
  if parsed.is_empty() {
211
- if let Some(sequence) = document.syntax().descendants().find_map(BlockSeq::cast) {
212
+ if let Some(sequence) = find_block_sequence(document.syntax()) {
212
213
  current_nodes = sequence.entries().map(|entry| Some(entry.syntax().clone())).collect();
213
214
  }
214
215
 
@@ -296,7 +297,20 @@ impl Document {
296
297
  }
297
298
 
298
299
  fn insert_after_node(&mut self, node: &SyntaxNode, text: &str) -> Result<(), YerbaError> {
299
- let position = node.text_range().end();
300
+ let end: usize = node.text_range().end().into();
301
+ let source = self.source_text();
302
+
303
+ let rest = &source[end..];
304
+ let line_end = rest.find('\n').unwrap_or(rest.len());
305
+ let trailing = &rest[..line_end];
306
+
307
+ let position = if let Some(comment_start) = trailing.find('#') {
308
+ let _ = comment_start;
309
+ rowan::TextSize::from((end + line_end) as u32)
310
+ } else {
311
+ node.text_range().end()
312
+ };
313
+
300
314
  let range = TextRange::new(position, position);
301
315
 
302
316
  self.apply_edit(range, text)
@@ -412,15 +426,37 @@ impl Document {
412
426
  }
413
427
 
414
428
  fn apply_edit(&mut self, range: TextRange, replacement: &str) -> Result<(), YerbaError> {
415
- let source = self.root.text().to_string();
416
- let start: usize = range.start().into();
417
- let end: usize = range.end().into();
429
+ self.apply_edits(vec![(range, replacement.to_string())])
430
+ }
418
431
 
419
- let mut new_source = source;
420
- new_source.replace_range(start..end, replacement);
432
+ fn apply_edits(&mut self, mut edits: Vec<(TextRange, String)>) -> Result<(), YerbaError> {
433
+ if edits.is_empty() {
434
+ return Ok(());
435
+ }
436
+
437
+ edits.sort_by_key(|(range, _)| std::cmp::Reverse(range.start()));
438
+
439
+ let mut new_source = self.source_text();
440
+
441
+ for (range, replacement) in edits {
442
+ let start: usize = range.start().into();
443
+ let end: usize = range.end().into();
444
+
445
+ new_source.replace_range(start..end, &replacement);
446
+ }
421
447
 
448
+ self.reparse(&new_source)
449
+ }
450
+
451
+ fn source_text(&self) -> String {
452
+ self.root.text().to_string()
453
+ }
454
+
455
+ fn reparse(&mut self, new_source: &str) -> Result<(), YerbaError> {
456
+ let document = Self::parse(new_source)?;
422
457
  let path = self.path.take();
423
- *self = Self::parse(&new_source)?;
458
+
459
+ *self = document;
424
460
  self.path = path;
425
461
 
426
462
  Ok(())
@@ -445,8 +481,8 @@ fn check_duplicate_keys(root: &SyntaxNode) -> Result<(), YerbaError> {
445
481
 
446
482
  if let Some(&first_offset) = seen.get(&key_text) {
447
483
  let source = root.text().to_string();
448
- let first_line = source[..first_offset.into()].matches('\n').count() + 1;
449
- let duplicate_line = source[..usize::from(offset)].matches('\n').count() + 1;
484
+ let first_line = line_at(&source, first_offset.into());
485
+ let duplicate_line = line_at(&source, offset.into());
450
486
  let line_content = source.lines().nth(duplicate_line - 1).unwrap_or("").to_string();
451
487
 
452
488
  return Err(YerbaError::DuplicateKey {
@@ -471,21 +507,13 @@ pub(crate) fn compute_location(source: &str, start_offset: usize, end_offset: us
471
507
  let start = start_offset.min(source.len());
472
508
  let end = end_offset.min(source.len());
473
509
 
474
- let before_start = &source[..start];
475
- let start_line = before_start.chars().filter(|c| *c == '\n').count() + 1;
476
- let start_column = start - before_start.rfind('\n').map(|p| p + 1).unwrap_or(0);
477
-
478
- let before_end = &source[..end];
479
- let end_line = before_end.chars().filter(|c| *c == '\n').count() + 1;
480
- let end_column = end - before_end.rfind('\n').map(|p| p + 1).unwrap_or(0);
481
-
482
510
  Location {
483
511
  start_offset: start,
484
512
  end_offset: end,
485
- start_line,
486
- start_column,
487
- end_line,
488
- end_column,
513
+ start_line: line_at(source, start),
514
+ start_column: column_at(source, start),
515
+ end_line: line_at(source, end),
516
+ end_column: column_at(source, end),
489
517
  }
490
518
  }
491
519
 
@@ -520,39 +548,31 @@ pub fn collect_selectors(value: &yaml_serde::Value, prefix: &str, selectors: &mu
520
548
  }
521
549
 
522
550
  pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> yaml_serde::Value {
523
- if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
524
- let map_position = node.descendants().find_map(BlockMap::cast).map(|map| map.syntax().text_range().start());
525
-
526
- let sequence_position = sequence.syntax().text_range().start();
527
-
528
- if map_position.is_none() || sequence_position <= map_position.unwrap() {
551
+ match first_collection(node) {
552
+ Some(FirstCollection::Sequence(sequence)) => {
529
553
  let values: Vec<yaml_serde::Value> = sequence.entries().map(|entry| node_to_yaml_value(entry.syntax())).collect();
530
554
 
531
555
  return yaml_serde::Value::Sequence(values);
532
556
  }
533
- }
534
-
535
- if let Some(map) = node.descendants().find_map(BlockMap::cast) {
536
- let mut mapping = yaml_serde::Mapping::new();
537
557
 
538
- for entry in map.entries() {
539
- let key = entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())).unwrap_or_default();
558
+ Some(FirstCollection::Map(map)) => {
559
+ let mut mapping = yaml_serde::Mapping::new();
540
560
 
541
- let value = entry
542
- .value()
543
- .map(|value_node| node_to_yaml_value(value_node.syntax()))
544
- .unwrap_or(yaml_serde::Value::Null);
561
+ for entry in map.entries() {
562
+ let key = entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())).unwrap_or_default();
545
563
 
546
- mapping.insert(yaml_serde::Value::String(key), value);
547
- }
564
+ let value = entry
565
+ .value()
566
+ .map(|value_node| node_to_yaml_value(value_node.syntax()))
567
+ .unwrap_or(yaml_serde::Value::Null);
548
568
 
549
- return yaml_serde::Value::Mapping(mapping);
550
- }
569
+ mapping.insert(yaml_serde::Value::String(key), value);
570
+ }
551
571
 
552
- if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
553
- let values: Vec<yaml_serde::Value> = sequence.entries().map(|entry| node_to_yaml_value(entry.syntax())).collect();
572
+ return yaml_serde::Value::Mapping(mapping);
573
+ }
554
574
 
555
- return yaml_serde::Value::Sequence(values);
575
+ None => {}
556
576
  }
557
577
 
558
578
  if let Some(block_scalar) = node.descendants().find(|child| child.kind() == SyntaxKind::BLOCK_SCALAR) {
@@ -608,17 +628,13 @@ pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> yaml_serde::Value {
608
628
  }
609
629
 
610
630
  pub(crate) fn parse_condition(condition: &str) -> Option<(String, &str, String)> {
611
- let (left, operator, right) = if let Some(index) = condition.find(" not_contains ") {
612
- (condition[..index].trim(), "not_contains", condition[index + 14..].trim())
613
- } else if let Some(index) = condition.find(" contains ") {
614
- (condition[..index].trim(), "contains", condition[index + 10..].trim())
615
- } else if let Some(index) = condition.find("!=") {
616
- (condition[..index].trim(), "!=", condition[index + 2..].trim())
617
- } else if let Some(index) = condition.find("==") {
618
- (condition[..index].trim(), "==", condition[index + 2..].trim())
619
- } else {
620
- return None;
621
- };
631
+ const OPERATORS: [(&str, &str); 4] = [(" not_contains ", "not_contains"), (" contains ", "contains"), ("!=", "!="), ("==", "==")];
632
+
633
+ let (left, operator, right) = OPERATORS.iter().find_map(|(pattern, operator)| {
634
+ condition
635
+ .find(pattern)
636
+ .map(|index| (condition[..index].trim(), *operator, condition[index + pattern.len()..].trim()))
637
+ })?;
622
638
 
623
639
  let right = right
624
640
  .trim_start_matches('"')
@@ -654,7 +670,7 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
654
670
 
655
671
  match segment {
656
672
  SelectorSegment::AllItems => {
657
- if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
673
+ if let Some(sequence) = find_block_sequence(node) {
658
674
  sequence.entries().map(|entry| entry.syntax().clone()).collect()
659
675
  } else {
660
676
  Vec::new()
@@ -662,7 +678,7 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
662
678
  }
663
679
 
664
680
  SelectorSegment::Index(index) => {
665
- if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
681
+ if let Some(sequence) = find_block_sequence(node) {
666
682
  sequence.entries().nth(*index).map(|entry| vec![entry.syntax().clone()]).unwrap_or_default()
667
683
  } else {
668
684
  Vec::new()
@@ -670,7 +686,7 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
670
686
  }
671
687
 
672
688
  SelectorSegment::Key(key) => {
673
- if let Some(map) = node.descendants().find_map(BlockMap::cast) {
689
+ if let Some(map) = find_block_map(node) {
674
690
  if let Some(entry) = find_entry_by_key(&map, key) {
675
691
  if let Some(value) = entry.value() {
676
692
  return vec![value.syntax().clone()];
@@ -685,23 +701,8 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
685
701
 
686
702
  pub(crate) fn navigate_from_node(node: &SyntaxNode, path: &str) -> Vec<SyntaxNode> {
687
703
  let parsed = crate::selector::Selector::parse(path);
688
- let mut current_nodes = vec![node.clone()];
689
-
690
- for segment in parsed.segments() {
691
- let mut next_nodes = Vec::new();
692
704
 
693
- for current in &current_nodes {
694
- next_nodes.extend(resolve_segment(current, segment));
695
- }
696
-
697
- current_nodes = next_nodes;
698
-
699
- if current_nodes.is_empty() {
700
- break;
701
- }
702
- }
703
-
704
- current_nodes
705
+ navigate_remaining(node, parsed.segments())
705
706
  }
706
707
 
707
708
  #[derive(Debug, Clone)]
@@ -31,7 +31,7 @@ impl Document {
31
31
  crate::schema::validate_value(&value, schema)
32
32
  };
33
33
 
34
- let source = self.to_string();
34
+ let source = self.source_text();
35
35
 
36
36
  for error in &mut errors {
37
37
  if !error.path.is_empty() {
@@ -5,17 +5,10 @@ impl Document {
5
5
  let current_node = self.navigate(dot_path)?;
6
6
 
7
7
  if let Some(block_scalar) = current_node.descendants().find(|node| node.kind() == SyntaxKind::BLOCK_SCALAR) {
8
- let new_text = if value.is_empty() {
9
- "\"\"".to_string()
10
- } else if value.contains('\n') {
11
- format!("|-\n {}", value.replace('\n', "\n "))
12
- } else {
13
- format!("\"{}\"", value.replace('"', "\\\""))
14
- };
8
+ let source = self.source_text();
9
+ let new_text = Self::block_scalar_replacement(&source, &block_scalar, value);
15
10
 
16
- let range = block_scalar.text_range();
17
-
18
- return self.apply_edit(range, &new_text);
11
+ return self.apply_edit(block_scalar.text_range(), &new_text);
19
12
  }
20
13
 
21
14
  let scalar_token = find_scalar_token(&current_node).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
@@ -32,25 +25,18 @@ impl Document {
32
25
  return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
33
26
  }
34
27
 
35
- for node in nodes.into_iter().rev() {
36
- if let Some(block_scalar) = node.descendants().find(|child| child.kind() == SyntaxKind::BLOCK_SCALAR) {
37
- let new_text = if value.is_empty() {
38
- "\"\"".to_string()
39
- } else if value.contains('\n') {
40
- format!("|-\n {}", value.replace('\n', "\n "))
41
- } else {
42
- format!("\"{}\"", value.replace('"', "\\\""))
43
- };
28
+ let source = self.source_text();
29
+ let mut edits: Vec<(TextRange, String)> = Vec::new();
44
30
 
45
- self.apply_edit(block_scalar.text_range(), &new_text)?;
31
+ for node in nodes {
32
+ if let Some(block_scalar) = node.descendants().find(|child| child.kind() == SyntaxKind::BLOCK_SCALAR) {
33
+ edits.push((block_scalar.text_range(), Self::block_scalar_replacement(&source, &block_scalar, value)));
46
34
  } else if let Some(scalar_token) = find_scalar_token(&node) {
47
- let new_text = format_scalar_value(value, scalar_token.kind());
48
-
49
- self.replace_token(&scalar_token, &new_text)?;
35
+ edits.push((scalar_token.text_range(), format_scalar_value(value, scalar_token.kind())));
50
36
  }
51
37
  }
52
38
 
53
- Ok(())
39
+ self.apply_edits(edits)
54
40
  }
55
41
 
56
42
  pub fn set_scalar_style(&mut self, dot_path: &str, style: &QuoteStyle) -> Result<(), YerbaError> {
@@ -64,20 +50,9 @@ impl Document {
64
50
  return Ok(());
65
51
  }
66
52
 
67
- let raw_value = match current_kind {
68
- SyntaxKind::DOUBLE_QUOTED_SCALAR => {
69
- let text = scalar_token.text();
70
- unescape_double_quoted(&text[1..text.len() - 1])
71
- }
72
-
73
- SyntaxKind::SINGLE_QUOTED_SCALAR => {
74
- let text = scalar_token.text();
75
- unescape_single_quoted(&text[1..text.len() - 1])
76
- }
77
-
78
- SyntaxKind::PLAIN_SCALAR => scalar_token.text().to_string(),
79
-
80
- _ => return Ok(()),
53
+ let raw_value = match raw_scalar_value(&scalar_token) {
54
+ Some(value) => value,
55
+ None => return Ok(()),
81
56
  };
82
57
 
83
58
  let new_text = format_scalar_value(&raw_value, target_kind);
@@ -97,4 +72,33 @@ impl Document {
97
72
 
98
73
  self.replace_token(&scalar_token, value)
99
74
  }
75
+
76
+ fn block_scalar_replacement(source: &str, block_scalar: &SyntaxNode, value: &str) -> String {
77
+ if value.is_empty() {
78
+ return "\"\"".to_string();
79
+ }
80
+
81
+ if !value.contains('\n') {
82
+ return format!("\"{}\"", value.replace('"', "\\\""));
83
+ }
84
+
85
+ let offset: usize = block_scalar.text_range().start().into();
86
+ let line_start = line_start_at(source, offset);
87
+ let key_indent = source[line_start..offset].len() - source[line_start..offset].trim_start().len();
88
+ let indent = " ".repeat(key_indent + 2);
89
+
90
+ let indented_lines: Vec<String> = value
91
+ .split('\n')
92
+ .enumerate()
93
+ .map(|(index, line)| {
94
+ if line.is_empty() && index > 0 {
95
+ String::new()
96
+ } else {
97
+ format!("{}{}", indent, line)
98
+ }
99
+ })
100
+ .collect();
101
+
102
+ format!("|-\n{}", indented_lines.join("\n"))
103
+ }
100
104
  }