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.
- checksums.yaml +4 -4
- data/exe/arm-linux-gnu/yerba +0 -0
- data/lib/yerba/3.2/yerba.so +0 -0
- data/lib/yerba/3.3/yerba.so +0 -0
- data/lib/yerba/3.4/yerba.so +0 -0
- data/lib/yerba/4.0/yerba.so +0 -0
- data/lib/yerba/version.rb +1 -1
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/document/condition.rs +4 -4
- data/rust/src/document/delete.rs +8 -31
- data/rust/src/document/get.rs +10 -16
- data/rust/src/document/insert.rs +50 -144
- data/rust/src/document/mod.rs +80 -79
- data/rust/src/document/schema.rs +1 -1
- data/rust/src/document/set.rs +42 -38
- data/rust/src/document/sort.rs +150 -310
- data/rust/src/document/style.rs +78 -308
- data/rust/src/document/unique.rs +4 -5
- data/rust/src/selector.rs +3 -3
- data/rust/src/syntax.rs +63 -47
- metadata +2 -2
data/rust/src/document/mod.rs
CHANGED
|
@@ -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,
|
|
38
|
-
|
|
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.
|
|
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.
|
|
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()
|
|
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
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
let end: usize = range.end().into();
|
|
429
|
+
self.apply_edits(vec![(range, replacement.to_string())])
|
|
430
|
+
}
|
|
418
431
|
|
|
419
|
-
|
|
420
|
-
|
|
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
|
-
|
|
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
|
|
449
|
-
let duplicate_line = source
|
|
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
|
-
|
|
524
|
-
|
|
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
|
-
|
|
539
|
-
let
|
|
558
|
+
Some(FirstCollection::Map(map)) => {
|
|
559
|
+
let mut mapping = yaml_serde::Mapping::new();
|
|
540
560
|
|
|
541
|
-
|
|
542
|
-
.
|
|
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
|
-
|
|
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
|
-
|
|
550
|
-
|
|
569
|
+
mapping.insert(yaml_serde::Value::String(key), value);
|
|
570
|
+
}
|
|
551
571
|
|
|
552
|
-
|
|
553
|
-
|
|
572
|
+
return yaml_serde::Value::Mapping(mapping);
|
|
573
|
+
}
|
|
554
574
|
|
|
555
|
-
|
|
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
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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)]
|
data/rust/src/document/schema.rs
CHANGED
data/rust/src/document/set.rs
CHANGED
|
@@ -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
|
|
9
|
-
|
|
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
|
-
|
|
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(¤t_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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
68
|
-
|
|
69
|
-
|
|
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
|
}
|