yerba 0.2.2 → 0.3.0
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/README.md +78 -5
- data/ext/yerba/extconf.rb +17 -9
- data/ext/yerba/include/yerba.h +2 -1
- data/ext/yerba/yerba.c +8 -1
- data/lib/yerba/version.rb +1 -1
- data/lib/yerba.rb +7 -2
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +2 -2
- data/rust/src/commands/delete.rs +9 -4
- data/rust/src/commands/get.rs +56 -13
- data/rust/src/commands/insert.rs +8 -4
- data/rust/src/commands/mod.rs +72 -5
- data/rust/src/commands/move_item.rs +2 -1
- data/rust/src/commands/move_key.rs +2 -1
- data/rust/src/commands/remove.rs +8 -4
- data/rust/src/commands/rename.rs +8 -4
- data/rust/src/commands/selectors.rs +174 -0
- data/rust/src/commands/set.rs +33 -16
- data/rust/src/commands/sort.rs +477 -10
- data/rust/src/didyoumean.rs +55 -0
- data/rust/src/document.rs +118 -51
- data/rust/src/error.rs +12 -2
- data/rust/src/ffi.rs +8 -3
- data/rust/src/lib.rs +2 -1
- data/rust/src/main.rs +2 -0
- metadata +3 -1
data/rust/src/document.rs
CHANGED
|
@@ -53,7 +53,7 @@ impl SortField {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
#[derive(Debug)]
|
|
56
|
+
#[derive(Debug, Clone)]
|
|
57
57
|
pub enum InsertPosition {
|
|
58
58
|
At(usize),
|
|
59
59
|
Last,
|
|
@@ -169,6 +169,18 @@ impl Document {
|
|
|
169
169
|
.collect()
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
pub fn selectors(&self) -> Vec<String> {
|
|
173
|
+
let Some(value) = self.get_value("") else {
|
|
174
|
+
return Vec::new();
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
let mut selectors = Vec::new();
|
|
178
|
+
collect_selectors(&value, "", &mut selectors);
|
|
179
|
+
selectors.sort();
|
|
180
|
+
selectors.dedup();
|
|
181
|
+
selectors
|
|
182
|
+
}
|
|
183
|
+
|
|
172
184
|
fn evaluate_condition_on_node(&self, node: &SyntaxNode, condition: &str) -> bool {
|
|
173
185
|
let condition = condition.trim();
|
|
174
186
|
|
|
@@ -354,17 +366,35 @@ impl Document {
|
|
|
354
366
|
}
|
|
355
367
|
|
|
356
368
|
let scalar_token =
|
|
357
|
-
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::
|
|
369
|
+
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
358
370
|
|
|
359
371
|
let new_text = format_scalar_value(value, scalar_token.kind());
|
|
360
372
|
|
|
361
373
|
self.replace_token(&scalar_token, &new_text)
|
|
362
374
|
}
|
|
363
375
|
|
|
376
|
+
pub fn set_all(&mut self, dot_path: &str, value: &str) -> Result<(), YerbaError> {
|
|
377
|
+
let nodes = self.navigate_all(dot_path);
|
|
378
|
+
|
|
379
|
+
if nodes.is_empty() {
|
|
380
|
+
return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
for node in nodes.into_iter().rev() {
|
|
384
|
+
if let Some(scalar_token) = find_scalar_token(&node) {
|
|
385
|
+
let new_text = format_scalar_value(value, scalar_token.kind());
|
|
386
|
+
|
|
387
|
+
self.replace_token(&scalar_token, &new_text)?;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
Ok(())
|
|
392
|
+
}
|
|
393
|
+
|
|
364
394
|
pub fn set_scalar_style(&mut self, dot_path: &str, style: &QuoteStyle) -> Result<(), YerbaError> {
|
|
365
395
|
let current_node = self.navigate(dot_path)?;
|
|
366
396
|
let scalar_token =
|
|
367
|
-
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::
|
|
397
|
+
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
368
398
|
|
|
369
399
|
let current_kind = scalar_token.kind();
|
|
370
400
|
let target_kind = style.to_syntax_kind();
|
|
@@ -406,7 +436,7 @@ impl Document {
|
|
|
406
436
|
}
|
|
407
437
|
|
|
408
438
|
let scalar_token =
|
|
409
|
-
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::
|
|
439
|
+
find_scalar_token(¤t_node).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
410
440
|
|
|
411
441
|
self.replace_token(&scalar_token, value)
|
|
412
442
|
}
|
|
@@ -440,7 +470,7 @@ impl Document {
|
|
|
440
470
|
let entries: Vec<_> = sequence.entries().collect();
|
|
441
471
|
|
|
442
472
|
if entries.is_empty() {
|
|
443
|
-
return Err(YerbaError::
|
|
473
|
+
return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
|
|
444
474
|
}
|
|
445
475
|
|
|
446
476
|
let indent = entries
|
|
@@ -515,7 +545,7 @@ impl Document {
|
|
|
515
545
|
.map(|text| text == target_value)
|
|
516
546
|
.unwrap_or(false)
|
|
517
547
|
})
|
|
518
|
-
.ok_or_else(|| YerbaError::
|
|
548
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, target_value)))?;
|
|
519
549
|
|
|
520
550
|
let target_range = target_entry.syntax().text_range();
|
|
521
551
|
let replacement = format!("{}\n{}", new_item, indent);
|
|
@@ -534,7 +564,7 @@ impl Document {
|
|
|
534
564
|
.map(|text| text == target_value)
|
|
535
565
|
.unwrap_or(false)
|
|
536
566
|
})
|
|
537
|
-
.ok_or_else(|| YerbaError::
|
|
567
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, target_value)))?;
|
|
538
568
|
|
|
539
569
|
let new_text = format!("\n{}{}", indent, new_item);
|
|
540
570
|
|
|
@@ -545,7 +575,7 @@ impl Document {
|
|
|
545
575
|
let target_entry = entries
|
|
546
576
|
.iter()
|
|
547
577
|
.find(|entry| self.evaluate_condition_on_node(entry.syntax(), &condition))
|
|
548
|
-
.ok_or_else(|| YerbaError::
|
|
578
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} condition '{}'", dot_path, condition)))?;
|
|
549
579
|
|
|
550
580
|
let target_range = target_entry.syntax().text_range();
|
|
551
581
|
let replacement = format!("{}\n{}", new_item, indent);
|
|
@@ -558,7 +588,7 @@ impl Document {
|
|
|
558
588
|
let target_entry = entries
|
|
559
589
|
.iter()
|
|
560
590
|
.find(|entry| self.evaluate_condition_on_node(entry.syntax(), &condition))
|
|
561
|
-
.ok_or_else(|| YerbaError::
|
|
591
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} condition '{}'", dot_path, condition)))?;
|
|
562
592
|
|
|
563
593
|
let new_text = format!("\n{}{}", indent, new_item);
|
|
564
594
|
|
|
@@ -586,7 +616,7 @@ impl Document {
|
|
|
586
616
|
let map = current_node
|
|
587
617
|
.descendants()
|
|
588
618
|
.find_map(BlockMap::cast)
|
|
589
|
-
.ok_or_else(|| YerbaError::
|
|
619
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
590
620
|
|
|
591
621
|
let entries: Vec<_> = map.entries().collect();
|
|
592
622
|
|
|
@@ -638,7 +668,7 @@ impl Document {
|
|
|
638
668
|
|
|
639
669
|
InsertPosition::Before(target_key) => {
|
|
640
670
|
let target_entry = find_entry_by_key(&map, &target_key)
|
|
641
|
-
.ok_or_else(|| YerbaError::
|
|
671
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{}.{}", dot_path, target_key)))?;
|
|
642
672
|
|
|
643
673
|
let target_range = target_entry.syntax().text_range();
|
|
644
674
|
let replacement = format!("{}\n{}", new_entry_text, indent);
|
|
@@ -649,7 +679,7 @@ impl Document {
|
|
|
649
679
|
|
|
650
680
|
InsertPosition::After(target_key) => {
|
|
651
681
|
let target_entry = find_entry_by_key(&map, &target_key)
|
|
652
|
-
.ok_or_else(|| YerbaError::
|
|
682
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{}.{}", dot_path, target_key)))?;
|
|
653
683
|
|
|
654
684
|
let new_text = format!("\n{}{}", indent, new_entry_text);
|
|
655
685
|
|
|
@@ -711,17 +741,17 @@ impl Document {
|
|
|
711
741
|
let map = parent_node
|
|
712
742
|
.descendants()
|
|
713
743
|
.find_map(BlockMap::cast)
|
|
714
|
-
.ok_or_else(|| YerbaError::
|
|
744
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(source_path.to_string()))?;
|
|
715
745
|
|
|
716
746
|
let entry =
|
|
717
|
-
find_entry_by_key(&map, source_key).ok_or_else(|| YerbaError::
|
|
747
|
+
find_entry_by_key(&map, source_key).ok_or_else(|| YerbaError::SelectorNotFound(source_path.to_string()))?;
|
|
718
748
|
|
|
719
749
|
let key_node = entry
|
|
720
750
|
.key()
|
|
721
|
-
.ok_or_else(|| YerbaError::
|
|
751
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(source_path.to_string()))?;
|
|
722
752
|
|
|
723
753
|
let key_token =
|
|
724
|
-
find_scalar_token(key_node.syntax()).ok_or_else(|| YerbaError::
|
|
754
|
+
find_scalar_token(key_node.syntax()).ok_or_else(|| YerbaError::SelectorNotFound(source_path.to_string()))?;
|
|
725
755
|
|
|
726
756
|
let new_text = format_scalar_value(destination_key, key_token.kind());
|
|
727
757
|
|
|
@@ -729,7 +759,7 @@ impl Document {
|
|
|
729
759
|
} else {
|
|
730
760
|
let value = self
|
|
731
761
|
.get(source_path)
|
|
732
|
-
.ok_or_else(|| YerbaError::
|
|
762
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(source_path.to_string()))?;
|
|
733
763
|
|
|
734
764
|
self.delete(source_path)?;
|
|
735
765
|
self.insert_into(destination_path, &value, InsertPosition::Last)
|
|
@@ -745,9 +775,9 @@ impl Document {
|
|
|
745
775
|
let map = parent_node
|
|
746
776
|
.descendants()
|
|
747
777
|
.find_map(BlockMap::cast)
|
|
748
|
-
.ok_or_else(|| YerbaError::
|
|
778
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
749
779
|
|
|
750
|
-
let entry = find_entry_by_key(&map, last_key).ok_or_else(|| YerbaError::
|
|
780
|
+
let entry = find_entry_by_key(&map, last_key).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
751
781
|
|
|
752
782
|
self.remove_node(entry.syntax())
|
|
753
783
|
}
|
|
@@ -769,7 +799,7 @@ impl Document {
|
|
|
769
799
|
.map(|text| text == value)
|
|
770
800
|
.unwrap_or(false)
|
|
771
801
|
})
|
|
772
|
-
.ok_or_else(|| YerbaError::
|
|
802
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, value)))?;
|
|
773
803
|
|
|
774
804
|
self.remove_node(target_entry.syntax())
|
|
775
805
|
}
|
|
@@ -820,7 +850,7 @@ impl Document {
|
|
|
820
850
|
let map = current_node
|
|
821
851
|
.descendants()
|
|
822
852
|
.find_map(BlockMap::cast)
|
|
823
|
-
.ok_or_else(|| YerbaError::
|
|
853
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
824
854
|
|
|
825
855
|
let entries: Vec<_> = map.entries().collect();
|
|
826
856
|
|
|
@@ -833,7 +863,7 @@ impl Document {
|
|
|
833
863
|
let map = current_node
|
|
834
864
|
.descendants()
|
|
835
865
|
.find_map(BlockMap::cast)
|
|
836
|
-
.ok_or_else(|| YerbaError::
|
|
866
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
837
867
|
|
|
838
868
|
if let Ok(index) = reference.parse::<usize>() {
|
|
839
869
|
let length = map.entries().count();
|
|
@@ -856,7 +886,7 @@ impl Document {
|
|
|
856
886
|
.unwrap_or(false)
|
|
857
887
|
})
|
|
858
888
|
.map(|(index, _entry)| index)
|
|
859
|
-
.ok_or_else(|| YerbaError::
|
|
889
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} key '{}'", dot_path, reference)))
|
|
860
890
|
}
|
|
861
891
|
|
|
862
892
|
pub fn resolve_sequence_index(&self, dot_path: &str, reference: &str) -> Result<usize, YerbaError> {
|
|
@@ -883,7 +913,7 @@ impl Document {
|
|
|
883
913
|
.enumerate()
|
|
884
914
|
.find(|(_index, entry)| self.evaluate_condition_on_node(entry.syntax(), reference))
|
|
885
915
|
.map(|(index, _entry)| index)
|
|
886
|
-
.ok_or_else(|| YerbaError::
|
|
916
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} condition '{}'", dot_path, reference)));
|
|
887
917
|
}
|
|
888
918
|
|
|
889
919
|
sequence
|
|
@@ -897,7 +927,7 @@ impl Document {
|
|
|
897
927
|
.unwrap_or(false)
|
|
898
928
|
})
|
|
899
929
|
.map(|(index, _entry)| index)
|
|
900
|
-
.ok_or_else(|| YerbaError::
|
|
930
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, reference)))
|
|
901
931
|
}
|
|
902
932
|
|
|
903
933
|
pub fn validate_sort_keys(&self, dot_path: &str, key_order: &[&str]) -> Result<(), YerbaError> {
|
|
@@ -916,7 +946,7 @@ impl Document {
|
|
|
916
946
|
let map = current_node
|
|
917
947
|
.descendants()
|
|
918
948
|
.find_map(BlockMap::cast)
|
|
919
|
-
.ok_or_else(|| YerbaError::
|
|
949
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
920
950
|
|
|
921
951
|
let unknown_keys: Vec<String> = map
|
|
922
952
|
.entries()
|
|
@@ -947,7 +977,7 @@ impl Document {
|
|
|
947
977
|
let map = current_node
|
|
948
978
|
.descendants()
|
|
949
979
|
.find_map(BlockMap::cast)
|
|
950
|
-
.ok_or_else(|| YerbaError::
|
|
980
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
951
981
|
|
|
952
982
|
let entries: Vec<_> = map.entries().collect();
|
|
953
983
|
|
|
@@ -1000,7 +1030,7 @@ impl Document {
|
|
|
1000
1030
|
.unwrap_or_default();
|
|
1001
1031
|
|
|
1002
1032
|
let sorted_groups: Vec<EntryGroup> = keyed.into_iter().map(|(_, group)| group).collect();
|
|
1003
|
-
let map_text = rebuild_from_groups(&sorted_groups, &indent);
|
|
1033
|
+
let map_text = rebuild_from_groups(&sorted_groups, &indent, false);
|
|
1004
1034
|
|
|
1005
1035
|
self.apply_edit(range, &map_text)
|
|
1006
1036
|
}
|
|
@@ -1076,7 +1106,7 @@ impl Document {
|
|
|
1076
1106
|
.unwrap_or_default();
|
|
1077
1107
|
|
|
1078
1108
|
let sorted_groups: Vec<EntryGroup> = keyed.into_iter().map(|(_, group)| group).collect();
|
|
1079
|
-
let map_text = rebuild_from_groups(&sorted_groups, &indent);
|
|
1109
|
+
let map_text = rebuild_from_groups(&sorted_groups, &indent, false);
|
|
1080
1110
|
edits.push((group_range, map_text));
|
|
1081
1111
|
}
|
|
1082
1112
|
|
|
@@ -1226,7 +1256,7 @@ impl Document {
|
|
|
1226
1256
|
.unwrap_or_default();
|
|
1227
1257
|
|
|
1228
1258
|
let sorted_groups: Vec<EntryGroup> = sortable.into_iter().map(|(_, group)| group).collect();
|
|
1229
|
-
let sequence_text = rebuild_from_groups(&sorted_groups, &indent);
|
|
1259
|
+
let sequence_text = rebuild_from_groups(&sorted_groups, &indent, true);
|
|
1230
1260
|
|
|
1231
1261
|
self.apply_edit(range, &sequence_text)
|
|
1232
1262
|
}
|
|
@@ -1334,7 +1364,7 @@ impl Document {
|
|
|
1334
1364
|
.unwrap_or_default();
|
|
1335
1365
|
|
|
1336
1366
|
let sorted_groups: Vec<EntryGroup> = sortable.into_iter().map(|(_, group)| group).collect();
|
|
1337
|
-
let sequence_text = rebuild_from_groups(&sorted_groups, &indent);
|
|
1367
|
+
let sequence_text = rebuild_from_groups(&sorted_groups, &indent, true);
|
|
1338
1368
|
edits.push((group_range, sequence_text));
|
|
1339
1369
|
}
|
|
1340
1370
|
}
|
|
@@ -1664,12 +1694,12 @@ impl Document {
|
|
|
1664
1694
|
Self::validate_path(dot_path)?;
|
|
1665
1695
|
|
|
1666
1696
|
if dot_path.is_empty() {
|
|
1667
|
-
let root = Root::cast(self.root.clone()).ok_or_else(|| YerbaError::
|
|
1697
|
+
let root = Root::cast(self.root.clone()).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
1668
1698
|
|
|
1669
1699
|
let document = root
|
|
1670
1700
|
.documents()
|
|
1671
1701
|
.next()
|
|
1672
|
-
.ok_or_else(|| YerbaError::
|
|
1702
|
+
.ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
|
|
1673
1703
|
|
|
1674
1704
|
return Ok(document.syntax().clone());
|
|
1675
1705
|
}
|
|
@@ -1677,13 +1707,9 @@ impl Document {
|
|
|
1677
1707
|
let nodes = self.navigate_all(dot_path);
|
|
1678
1708
|
|
|
1679
1709
|
match nodes.len() {
|
|
1680
|
-
0 => Err(YerbaError::
|
|
1710
|
+
0 => Err(YerbaError::SelectorNotFound(dot_path.to_string())),
|
|
1681
1711
|
1 => Ok(nodes.into_iter().next().unwrap()),
|
|
1682
|
-
_ => Err(YerbaError::
|
|
1683
|
-
"{} (matched {} nodes, expected 1)",
|
|
1684
|
-
dot_path,
|
|
1685
|
-
nodes.len()
|
|
1686
|
-
))),
|
|
1712
|
+
_ => Err(YerbaError::AmbiguousSelector(dot_path.to_string(), nodes.len())),
|
|
1687
1713
|
}
|
|
1688
1714
|
}
|
|
1689
1715
|
|
|
@@ -1844,7 +1870,7 @@ impl Document {
|
|
|
1844
1870
|
.map(|entry| preceding_whitespace_indent(entry.syntax()))
|
|
1845
1871
|
.unwrap_or_default();
|
|
1846
1872
|
|
|
1847
|
-
let text = rebuild_from_groups(&reordered, &indent);
|
|
1873
|
+
let text = rebuild_from_groups(&reordered, &indent, true);
|
|
1848
1874
|
|
|
1849
1875
|
self.apply_edit(range, &text)
|
|
1850
1876
|
}
|
|
@@ -1871,6 +1897,36 @@ impl std::fmt::Display for Document {
|
|
|
1871
1897
|
}
|
|
1872
1898
|
}
|
|
1873
1899
|
|
|
1900
|
+
pub fn collect_selectors(value: &serde_yaml::Value, prefix: &str, selectors: &mut Vec<String>) {
|
|
1901
|
+
match value {
|
|
1902
|
+
serde_yaml::Value::Mapping(map) => {
|
|
1903
|
+
for (key, child) in map {
|
|
1904
|
+
if let serde_yaml::Value::String(key_string) = key {
|
|
1905
|
+
let selector = if prefix.is_empty() {
|
|
1906
|
+
key_string.clone()
|
|
1907
|
+
} else {
|
|
1908
|
+
format!("{}.{}", prefix, key_string)
|
|
1909
|
+
};
|
|
1910
|
+
|
|
1911
|
+
selectors.push(selector.clone());
|
|
1912
|
+
collect_selectors(child, &selector, selectors);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
serde_yaml::Value::Sequence(sequence) => {
|
|
1918
|
+
let bracket_prefix = format!("{}[]", prefix);
|
|
1919
|
+
selectors.push(bracket_prefix.clone());
|
|
1920
|
+
|
|
1921
|
+
for item in sequence {
|
|
1922
|
+
collect_selectors(item, &bracket_prefix, selectors);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
_ => {}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1874
1930
|
pub fn node_to_yaml_value(node: &SyntaxNode) -> serde_yaml::Value {
|
|
1875
1931
|
if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
|
|
1876
1932
|
let map_position = node
|
|
@@ -2178,8 +2234,7 @@ fn collect_preceding_sibling_comments(parent: &SyntaxNode) -> (String, Option<ro
|
|
|
2178
2234
|
Some(parent)
|
|
2179
2235
|
if parent.kind() == SyntaxKind::BLOCK
|
|
2180
2236
|
|| parent.kind() == SyntaxKind::DOCUMENT
|
|
2181
|
-
|| parent.kind() == SyntaxKind::BLOCK_MAP_VALUE
|
|
2182
|
-
|| parent.kind() == SyntaxKind::BLOCK_SEQ_ENTRY =>
|
|
2237
|
+
|| parent.kind() == SyntaxKind::BLOCK_MAP_VALUE =>
|
|
2183
2238
|
{
|
|
2184
2239
|
node = parent
|
|
2185
2240
|
}
|
|
@@ -2214,12 +2269,16 @@ fn collect_groups_with_range(parent: &SyntaxNode) -> (Vec<EntryGroup>, TextRange
|
|
|
2214
2269
|
(groups, range)
|
|
2215
2270
|
}
|
|
2216
2271
|
|
|
2217
|
-
fn rebuild_from_groups(groups: &[EntryGroup], indent: &str) -> String {
|
|
2218
|
-
let default_separator =
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2272
|
+
fn rebuild_from_groups(groups: &[EntryGroup], indent: &str, preserve_separators: bool) -> String {
|
|
2273
|
+
let default_separator = if preserve_separators {
|
|
2274
|
+
groups
|
|
2275
|
+
.iter()
|
|
2276
|
+
.find(|group| !group.separator.is_empty())
|
|
2277
|
+
.map(|group| group.separator.clone())
|
|
2278
|
+
.unwrap_or_else(|| "\n".to_string())
|
|
2279
|
+
} else {
|
|
2280
|
+
"\n".to_string()
|
|
2281
|
+
};
|
|
2223
2282
|
|
|
2224
2283
|
groups
|
|
2225
2284
|
.iter()
|
|
@@ -2227,10 +2286,18 @@ fn rebuild_from_groups(groups: &[EntryGroup], indent: &str) -> String {
|
|
|
2227
2286
|
.map(|(index, group)| {
|
|
2228
2287
|
if index == 0 {
|
|
2229
2288
|
group.full_text()
|
|
2230
|
-
} else if group.preceding.is_empty() {
|
|
2231
|
-
format!("{}{}{}", default_separator, indent, group.body)
|
|
2232
2289
|
} else {
|
|
2233
|
-
|
|
2290
|
+
let separator = if preserve_separators && !group.separator.is_empty() {
|
|
2291
|
+
&group.separator
|
|
2292
|
+
} else {
|
|
2293
|
+
&default_separator
|
|
2294
|
+
};
|
|
2295
|
+
|
|
2296
|
+
if group.preceding.is_empty() {
|
|
2297
|
+
format!("{}{}{}", separator, indent, group.body)
|
|
2298
|
+
} else {
|
|
2299
|
+
format!("{}{}\n{}{}", separator, group.preceding, indent, group.body)
|
|
2300
|
+
}
|
|
2234
2301
|
}
|
|
2235
2302
|
})
|
|
2236
2303
|
.collect()
|
data/rust/src/error.rs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
pub enum YerbaError {
|
|
3
3
|
ParseError(String),
|
|
4
4
|
IoError(std::io::Error),
|
|
5
|
-
|
|
5
|
+
SelectorNotFound(String),
|
|
6
|
+
AmbiguousSelector(String, usize),
|
|
6
7
|
NotASequence(String),
|
|
7
8
|
IndexOutOfBounds(usize, usize),
|
|
8
9
|
UnknownKeys(Vec<String>),
|
|
@@ -13,7 +14,16 @@ impl std::fmt::Display for YerbaError {
|
|
|
13
14
|
match self {
|
|
14
15
|
YerbaError::ParseError(msg) => write!(f, "parse error: {}", msg),
|
|
15
16
|
YerbaError::IoError(err) => write!(f, "io error: {}", err),
|
|
16
|
-
YerbaError::
|
|
17
|
+
YerbaError::SelectorNotFound(selector) => write!(f, "selector not found: {}", selector),
|
|
18
|
+
|
|
19
|
+
YerbaError::AmbiguousSelector(selector, count) => {
|
|
20
|
+
write!(
|
|
21
|
+
f,
|
|
22
|
+
"selector \"{}\" matched {} nodes (expected 1). Use --all to update all matches",
|
|
23
|
+
selector, count
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
YerbaError::NotASequence(path) => write!(f, "not a sequence: {}", path),
|
|
18
28
|
|
|
19
29
|
YerbaError::IndexOutOfBounds(index, length) => {
|
data/rust/src/ffi.rs
CHANGED
|
@@ -501,14 +501,19 @@ pub unsafe extern "C" fn yerba_document_set(
|
|
|
501
501
|
path: *const c_char,
|
|
502
502
|
value: *const c_char,
|
|
503
503
|
value_type: YerbaValueType,
|
|
504
|
+
all: bool,
|
|
504
505
|
) -> YerbaResult {
|
|
505
506
|
let document = &mut *document;
|
|
506
507
|
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
507
508
|
let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
|
|
508
509
|
|
|
509
|
-
let result =
|
|
510
|
-
|
|
511
|
-
|
|
510
|
+
let result = if all {
|
|
511
|
+
document.set_all(path_string, value_string)
|
|
512
|
+
} else {
|
|
513
|
+
match value_type {
|
|
514
|
+
YerbaValueType::String => document.set(path_string, value_string),
|
|
515
|
+
_ => document.set_plain(path_string, value_string),
|
|
516
|
+
}
|
|
512
517
|
};
|
|
513
518
|
|
|
514
519
|
match result {
|
data/rust/src/lib.rs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
pub mod didyoumean;
|
|
1
2
|
mod document;
|
|
2
3
|
mod error;
|
|
3
4
|
pub mod ffi;
|
|
@@ -8,7 +9,7 @@ mod syntax;
|
|
|
8
9
|
mod yaml_writer;
|
|
9
10
|
pub mod yerbafile;
|
|
10
11
|
|
|
11
|
-
pub use document::{Document, InsertPosition, SortField};
|
|
12
|
+
pub use document::{collect_selectors, Document, InsertPosition, SortField};
|
|
12
13
|
pub use error::YerbaError;
|
|
13
14
|
pub use quote_style::QuoteStyle;
|
|
14
15
|
pub use selector::Selector;
|
data/rust/src/main.rs
CHANGED
|
@@ -45,6 +45,8 @@ static HELP: LazyLock<String> = LazyLock::new(|| {
|
|
|
45
45
|
yerba move videos.yml "" ".id == talk-2" --after ".id == talk-1"
|
|
46
46
|
yerba sort-keys config.yml "database" "id,host,port,name"
|
|
47
47
|
yerba quote-style "data/**/*.yml" --values double
|
|
48
|
+
yerba sort videos.yml "[]" --by ".id" --order "talk-3,talk-1,talk-2"
|
|
49
|
+
yerba selectors videos.yml
|
|
48
50
|
"#})
|
|
49
51
|
});
|
|
50
52
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yerba
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -53,10 +53,12 @@ files:
|
|
|
53
53
|
- rust/src/commands/quote_style.rs
|
|
54
54
|
- rust/src/commands/remove.rs
|
|
55
55
|
- rust/src/commands/rename.rs
|
|
56
|
+
- rust/src/commands/selectors.rs
|
|
56
57
|
- rust/src/commands/set.rs
|
|
57
58
|
- rust/src/commands/sort.rs
|
|
58
59
|
- rust/src/commands/sort_keys.rs
|
|
59
60
|
- rust/src/commands/version.rs
|
|
61
|
+
- rust/src/didyoumean.rs
|
|
60
62
|
- rust/src/document.rs
|
|
61
63
|
- rust/src/error.rs
|
|
62
64
|
- rust/src/ffi.rs
|