yerba 0.8.0 → 0.8.1
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/lib/yerba/version.rb +1 -1
- data/rust/Cargo.toml +15 -6
- data/rust/src/commands/blank_lines.rs +2 -2
- data/rust/src/commands/directives.rs +4 -4
- data/rust/src/commands/get.rs +7 -10
- data/rust/src/commands/init.rs +4 -4
- data/rust/src/commands/insert.rs +6 -6
- data/rust/src/commands/location.rs +2 -2
- data/rust/src/commands/mate.rs +7 -7
- data/rust/src/commands/mod.rs +119 -90
- data/rust/src/commands/move_key.rs +9 -6
- data/rust/src/commands/quote_style.rs +4 -5
- data/rust/src/commands/schema.rs +6 -6
- data/rust/src/commands/selectors.rs +2 -2
- data/rust/src/commands/set.rs +3 -2
- data/rust/src/commands/sort.rs +36 -42
- data/rust/src/commands/sort_keys.rs +2 -2
- data/rust/src/commands/ui.rs +157 -0
- data/rust/src/commands/unique.rs +7 -7
- data/rust/src/commands/version.rs +13 -3
- data/rust/src/document/insert.rs +4 -0
- data/rust/src/document/mod.rs +7 -3
- data/rust/src/document/set.rs +10 -2
- data/rust/src/error.rs +3 -0
- data/rust/src/ffi.rs +5 -0
- data/rust/src/lib.rs +9 -1
- data/rust/src/quote_style.rs +12 -11
- data/rust/src/syntax.rs +132 -1
- data/rust/src/yaml_writer.rs +4 -4
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a769e82895bc0bea8b8e25391f39cdbf8e915a46d524efd05af951738b4b046a
|
|
4
|
+
data.tar.gz: 83d41f698f888f6065729b8adb5e6646e14b9832871eafde6af2fa60bfd4b862
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64e3fe5431316bc5faf03187419f234f52c9d8f04710d06afdd6bf13dc5342a80dadae3a4345ee610f4f307976d45520f0cc6b4bcc7a7959e21a9902ae071343
|
|
7
|
+
data.tar.gz: 3f12d6fa79ed13905bca60481eb3a87caffa46fd8205b6a9d56a8fcf250ce708698e218a4cec7126294940eb6ce8f44e02abf445144c12b9f39ad16f417a1da7
|
data/lib/yerba/version.rb
CHANGED
data/rust/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "yerba"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Marco Roth <marco.roth@intergga.ch>"]
|
|
6
6
|
description = "YAML Editing and Refactoring with Better Accuracy"
|
|
@@ -18,21 +18,30 @@ crate-type = ["cdylib", "staticlib", "rlib"]
|
|
|
18
18
|
[[bin]]
|
|
19
19
|
name = "yerba"
|
|
20
20
|
path = "src/main.rs"
|
|
21
|
+
required-features = ["cli"]
|
|
22
|
+
|
|
23
|
+
[features]
|
|
24
|
+
default = ["cli"]
|
|
25
|
+
cli = ["dep:clap", "dep:indoc", "dep:anstyle-query", "glob", "schema"]
|
|
26
|
+
glob = ["dep:glob", "dep:rayon"]
|
|
27
|
+
schema = ["dep:jsonschema"]
|
|
21
28
|
|
|
22
29
|
[dependencies]
|
|
23
30
|
yaml_parser = "0.3"
|
|
24
31
|
rowan = "0.16"
|
|
25
|
-
glob = "0.3"
|
|
32
|
+
glob = { version = "0.3", optional = true }
|
|
26
33
|
serde = { version = "1", features = ["derive"] }
|
|
27
34
|
yaml_serde = "0.10"
|
|
28
35
|
serde_json = { version = "1", features = ["preserve_order"] }
|
|
29
|
-
clap = { version = "4", features = ["derive"] }
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
clap = { version = "4", features = ["derive"], optional = true }
|
|
37
|
+
anstyle-query = { version = "1", optional = true }
|
|
38
|
+
indoc = { version = "2", optional = true }
|
|
39
|
+
rayon = { version = "1", optional = true }
|
|
40
|
+
jsonschema = { version = "0.29", default-features = false, optional = true }
|
|
33
41
|
|
|
34
42
|
[build-dependencies]
|
|
35
43
|
cbindgen = "0.28"
|
|
36
44
|
|
|
37
45
|
[dev-dependencies]
|
|
46
|
+
indoc = "2"
|
|
38
47
|
tempfile = "3"
|
|
@@ -37,9 +37,9 @@ impl Args {
|
|
|
37
37
|
} else if let Ok(count) = self.first.parse::<usize>() {
|
|
38
38
|
("", count)
|
|
39
39
|
} else {
|
|
40
|
-
use super::
|
|
40
|
+
use super::ui;
|
|
41
41
|
|
|
42
|
-
eprintln!("{
|
|
42
|
+
eprintln!("{} expected a number for blank line count, got '{}'", ui::failure("Error:"), self.first);
|
|
43
43
|
|
|
44
44
|
std::process::exit(1);
|
|
45
45
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use super::ui;
|
|
1
2
|
use std::sync::LazyLock;
|
|
2
3
|
|
|
3
4
|
use indoc::indoc;
|
|
@@ -35,14 +36,13 @@ pub struct Args {
|
|
|
35
36
|
impl Args {
|
|
36
37
|
pub fn run(self) {
|
|
37
38
|
if !self.ensure && !self.remove {
|
|
38
|
-
use super::
|
|
39
|
-
eprintln!("{
|
|
39
|
+
use super::ui;
|
|
40
|
+
eprintln!("{} specify --ensure or --remove", ui::failure("Error:"));
|
|
40
41
|
std::process::exit(1);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
if self.ensure && self.remove {
|
|
44
|
-
|
|
45
|
-
eprintln!("{RED}Error:{RESET} --ensure and --remove are mutually exclusive");
|
|
45
|
+
eprintln!("{} --ensure and --remove are mutually exclusive", ui::failure("Error:"));
|
|
46
46
|
std::process::exit(1);
|
|
47
47
|
}
|
|
48
48
|
|
data/rust/src/commands/get.rs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use super::ui;
|
|
1
2
|
use std::process;
|
|
2
3
|
use std::sync::LazyLock;
|
|
3
4
|
|
|
@@ -64,9 +65,9 @@ impl Args {
|
|
|
64
65
|
|
|
65
66
|
if let Some(condition) = &normalized_condition {
|
|
66
67
|
if let Err(error) = yerba::validate_item_condition(condition) {
|
|
67
|
-
use super::
|
|
68
|
+
use super::ui;
|
|
68
69
|
|
|
69
|
-
eprintln!("{
|
|
70
|
+
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
70
71
|
|
|
71
72
|
process::exit(1);
|
|
72
73
|
}
|
|
@@ -85,9 +86,7 @@ impl Args {
|
|
|
85
86
|
continue;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
eprintln!("{RED}Error:{RESET} selector \"{}\" not found in {}", self.selector, self.file);
|
|
89
|
+
eprintln!("{} selector \"{}\" not found in {}", ui::failure("Error:"), self.selector, self.file);
|
|
91
90
|
|
|
92
91
|
show_similar_selectors(&self.file, &document, &self.selector);
|
|
93
92
|
process::exit(1);
|
|
@@ -110,8 +109,7 @@ impl Args {
|
|
|
110
109
|
break;
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
eprintln!("{RED}Error:{RESET} select field \"{}\" not found in {}", field.trim(), self.file);
|
|
112
|
+
eprintln!("{} select field \"{}\" not found in {}", ui::failure("Error:"), field.trim(), self.file);
|
|
115
113
|
show_similar_selectors(&self.file, &document, &full_selector);
|
|
116
114
|
process::exit(1);
|
|
117
115
|
}
|
|
@@ -190,10 +188,9 @@ impl Args {
|
|
|
190
188
|
}
|
|
191
189
|
|
|
192
190
|
if is_glob && all_results.is_empty() && normalized_condition.is_none() {
|
|
193
|
-
use super::color::*;
|
|
194
|
-
|
|
195
191
|
eprintln!(
|
|
196
|
-
"{
|
|
192
|
+
"{} selector \"{}\" not found in any of the {} files matching \"{}\"",
|
|
193
|
+
ui::failure("Error:"),
|
|
197
194
|
self.selector,
|
|
198
195
|
files.len(),
|
|
199
196
|
self.file
|
data/rust/src/commands/init.rs
CHANGED
|
@@ -3,13 +3,13 @@ use std::process;
|
|
|
3
3
|
|
|
4
4
|
use indoc::indoc;
|
|
5
5
|
|
|
6
|
-
use super::
|
|
6
|
+
use super::ui;
|
|
7
7
|
|
|
8
8
|
pub fn run() {
|
|
9
9
|
let filename = "Yerbafile";
|
|
10
10
|
|
|
11
11
|
if Path::new(filename).exists() {
|
|
12
|
-
eprintln!("🧉 {
|
|
12
|
+
eprintln!("🧉 {}", ui::pending("Yerbafile already exists."));
|
|
13
13
|
process::exit(1);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -81,9 +81,9 @@ pub fn run() {
|
|
|
81
81
|
"#};
|
|
82
82
|
|
|
83
83
|
std::fs::write(filename, content).unwrap_or_else(|error| {
|
|
84
|
-
eprintln!("{
|
|
84
|
+
eprintln!("{} writing Yerbafile: {}", ui::failure("Error:"), error);
|
|
85
85
|
process::exit(1);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
eprintln!("🧉 {
|
|
88
|
+
eprintln!("🧉 {}", ui::success("Created Yerbafile"));
|
|
89
89
|
}
|
data/rust/src/commands/insert.rs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use super::ui;
|
|
1
2
|
use std::sync::LazyLock;
|
|
2
3
|
|
|
3
4
|
use indoc::indoc;
|
|
@@ -28,6 +29,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
28
29
|
pub struct Args {
|
|
29
30
|
file: String,
|
|
30
31
|
selector: String,
|
|
32
|
+
#[arg(allow_hyphen_values = true)]
|
|
31
33
|
value: Option<String>,
|
|
32
34
|
#[arg(long, help = "Read value from a file (use - for stdin)")]
|
|
33
35
|
from: Option<String>,
|
|
@@ -49,8 +51,8 @@ impl Args {
|
|
|
49
51
|
let mut buffer = String::new();
|
|
50
52
|
|
|
51
53
|
std::io::stdin().read_to_string(&mut buffer).unwrap_or_else(|error| {
|
|
52
|
-
use super::
|
|
53
|
-
eprintln!("{
|
|
54
|
+
use super::ui;
|
|
55
|
+
eprintln!("{} reading stdin: {}", ui::failure("Error:"), error);
|
|
54
56
|
|
|
55
57
|
std::process::exit(1);
|
|
56
58
|
});
|
|
@@ -59,8 +61,7 @@ impl Args {
|
|
|
59
61
|
} else {
|
|
60
62
|
std::fs::read_to_string(&from_path)
|
|
61
63
|
.unwrap_or_else(|error| {
|
|
62
|
-
|
|
63
|
-
eprintln!("{RED}Error:{RESET} reading {}: {}", from_path, error);
|
|
64
|
+
eprintln!("{} reading {}: {}", ui::failure("Error:"), from_path, error);
|
|
64
65
|
std::process::exit(1);
|
|
65
66
|
})
|
|
66
67
|
.trim()
|
|
@@ -69,8 +70,7 @@ impl Args {
|
|
|
69
70
|
} else if let Some(val) = self.value {
|
|
70
71
|
val
|
|
71
72
|
} else {
|
|
72
|
-
|
|
73
|
-
eprintln!("{RED}Error:{RESET} either a value argument or --from is required");
|
|
73
|
+
eprintln!("{} either a value argument or --from is required", ui::failure("Error:"));
|
|
74
74
|
|
|
75
75
|
std::process::exit(1);
|
|
76
76
|
};
|
|
@@ -28,13 +28,13 @@ pub struct Args {
|
|
|
28
28
|
|
|
29
29
|
impl Args {
|
|
30
30
|
pub fn run(self) {
|
|
31
|
-
use super::
|
|
31
|
+
use super::ui;
|
|
32
32
|
|
|
33
33
|
let document = parse_file(&self.file);
|
|
34
34
|
let info = document.get_node_info(&self.selector);
|
|
35
35
|
|
|
36
36
|
if info.location.start_line == 0 && info.location.end_line == 0 {
|
|
37
|
-
eprintln!("{
|
|
37
|
+
eprintln!("{} selector \"{}\" not found in {}", ui::failure("Error:"), self.selector, self.file);
|
|
38
38
|
|
|
39
39
|
super::show_similar_selectors(&self.file, &document, &self.selector);
|
|
40
40
|
process::exit(1);
|
data/rust/src/commands/mate.rs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
use super::
|
|
1
|
+
use super::ui;
|
|
2
2
|
|
|
3
3
|
pub fn run() {
|
|
4
|
-
let g =
|
|
5
|
-
let b =
|
|
6
|
-
let d =
|
|
7
|
-
let i =
|
|
8
|
-
let y =
|
|
9
|
-
let r =
|
|
4
|
+
let g = ui::raw::green();
|
|
5
|
+
let b = ui::raw::bold();
|
|
6
|
+
let d = ui::raw::dim();
|
|
7
|
+
let i = ui::raw::italic();
|
|
8
|
+
let y = ui::raw::yellow();
|
|
9
|
+
let r = ui::raw::reset();
|
|
10
10
|
let hr = format!(" {d}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}{r}");
|
|
11
11
|
|
|
12
12
|
println!();
|
data/rust/src/commands/mod.rs
CHANGED
|
@@ -18,6 +18,7 @@ pub mod selectors;
|
|
|
18
18
|
pub mod set;
|
|
19
19
|
pub mod sort;
|
|
20
20
|
pub mod sort_keys;
|
|
21
|
+
pub mod ui;
|
|
21
22
|
pub mod unique;
|
|
22
23
|
pub mod version;
|
|
23
24
|
|
|
@@ -30,56 +31,15 @@ pub(crate) fn is_github_actions() -> bool {
|
|
|
30
31
|
std::env::var("GITHUB_ACTIONS").is_ok()
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
pub(crate)
|
|
34
|
-
|
|
35
|
-
pub const RED: &str = "\x1b[31m";
|
|
36
|
-
pub const YELLOW: &str = "\x1b[33m";
|
|
37
|
-
pub const DIM: &str = "\x1b[2m";
|
|
38
|
-
pub const BOLD: &str = "\x1b[1m";
|
|
39
|
-
pub const RESET: &str = "\x1b[0m";
|
|
34
|
+
pub(crate) fn pluralize(count: usize, singular: &str, plural: &str) -> String {
|
|
35
|
+
format!("{} {}", count, if count == 1 { singular } else { plural })
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
// Compile-time ANSI macros for use in concat!() / clap attributes (used in main.rs)
|
|
43
|
-
#[allow(unused_macros)]
|
|
44
|
-
macro_rules! h {
|
|
45
|
-
() => {
|
|
46
|
-
"\x1b[1;32m"
|
|
47
|
-
};
|
|
48
|
-
} // header (bold green)
|
|
49
|
-
#[allow(unused_macros)]
|
|
50
|
-
macro_rules! b {
|
|
51
|
-
() => {
|
|
52
|
-
"\x1b[1m"
|
|
53
|
-
};
|
|
54
|
-
} // bold
|
|
55
|
-
#[allow(unused_macros)]
|
|
56
|
-
macro_rules! c {
|
|
57
|
-
() => {
|
|
58
|
-
"\x1b[36m"
|
|
59
|
-
};
|
|
60
|
-
} // cyan
|
|
61
|
-
#[allow(unused_macros)]
|
|
62
|
-
macro_rules! d {
|
|
63
|
-
() => {
|
|
64
|
-
"\x1b[2m"
|
|
65
|
-
};
|
|
66
|
-
} // dim
|
|
67
|
-
#[allow(unused_macros)]
|
|
68
|
-
macro_rules! r {
|
|
69
|
-
() => {
|
|
70
|
-
"\x1b[0m"
|
|
71
|
-
};
|
|
72
|
-
} // reset
|
|
73
|
-
#[allow(unused_imports)]
|
|
74
|
-
pub(crate) use {b, c, d, h, r};
|
|
75
|
-
|
|
76
38
|
pub(crate) fn colorize_examples(input: &str) -> String {
|
|
77
39
|
colorize_help(&format!("Examples:\n{}", input.trim()))
|
|
78
40
|
}
|
|
79
41
|
|
|
80
42
|
pub(crate) fn colorize_help(input: &str) -> String {
|
|
81
|
-
use color::*;
|
|
82
|
-
|
|
83
43
|
let mut output = String::new();
|
|
84
44
|
|
|
85
45
|
for line in input.lines() {
|
|
@@ -91,7 +51,7 @@ pub(crate) fn colorize_help(input: &str) -> String {
|
|
|
91
51
|
}
|
|
92
52
|
|
|
93
53
|
if trimmed.ends_with(':') && !trimmed.contains(' ') {
|
|
94
|
-
output.push_str(&format!("{
|
|
54
|
+
output.push_str(&format!("{}\n", ui::success(trimmed)));
|
|
95
55
|
continue;
|
|
96
56
|
}
|
|
97
57
|
|
|
@@ -100,11 +60,11 @@ pub(crate) fn colorize_help(input: &str) -> String {
|
|
|
100
60
|
|
|
101
61
|
match (parts.next(), parts.next(), parts.next()) {
|
|
102
62
|
(Some(cmd), Some(sub), Some(rest)) => {
|
|
103
|
-
output.push_str(&format!(" {
|
|
63
|
+
output.push_str(&format!(" {} {} {}\n", ui::strong(cmd), ui::muted(sub), rest));
|
|
104
64
|
}
|
|
105
65
|
|
|
106
66
|
(Some(cmd), Some(sub), None) => {
|
|
107
|
-
output.push_str(&format!(" {
|
|
67
|
+
output.push_str(&format!(" {} {}\n", ui::strong(cmd), ui::muted(sub)));
|
|
108
68
|
}
|
|
109
69
|
|
|
110
70
|
_ => {
|
|
@@ -134,9 +94,14 @@ pub(crate) fn colorize_help(input: &str) -> String {
|
|
|
134
94
|
}
|
|
135
95
|
|
|
136
96
|
if columns.len() == 3 {
|
|
137
|
-
output.push_str(&format!(
|
|
97
|
+
output.push_str(&format!(
|
|
98
|
+
" {} {:<21} {}\n",
|
|
99
|
+
ui::muted(format!("{:<20}", columns[0])),
|
|
100
|
+
columns[1],
|
|
101
|
+
ui::subtle(columns[2])
|
|
102
|
+
));
|
|
138
103
|
} else if columns.len() == 2 {
|
|
139
|
-
output.push_str(&format!("
|
|
104
|
+
output.push_str(&format!(" {} {}\n", ui::muted(format!("{:<20}", columns[0])), columns[1]));
|
|
140
105
|
} else {
|
|
141
106
|
output.push_str(&format!(" {trimmed}\n"));
|
|
142
107
|
}
|
|
@@ -204,19 +169,35 @@ impl Command {
|
|
|
204
169
|
}
|
|
205
170
|
|
|
206
171
|
pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
207
|
-
use color::*;
|
|
208
|
-
|
|
209
172
|
let yerbafile_path = yerba::Yerbafile::find().unwrap_or_else(|| {
|
|
210
|
-
eprintln!(
|
|
173
|
+
eprintln!(
|
|
174
|
+
"{} No Yerbafile found. Run {} to create one.",
|
|
175
|
+
ui::failure(ui::glyph::FAIL),
|
|
176
|
+
ui::strong("yerba init")
|
|
177
|
+
);
|
|
211
178
|
process::exit(1);
|
|
212
179
|
});
|
|
213
180
|
|
|
214
181
|
let yerbafile = yerba::Yerbafile::load(&yerbafile_path).unwrap_or_else(|error| {
|
|
215
|
-
eprintln!(
|
|
182
|
+
eprintln!(
|
|
183
|
+
"{} {}",
|
|
184
|
+
ui::failure(ui::glyph::FAIL),
|
|
185
|
+
ui::strong(format!("Could not read {}", yerbafile_path.display()))
|
|
186
|
+
);
|
|
187
|
+
eprintln!(" {}", error);
|
|
216
188
|
process::exit(1);
|
|
217
189
|
});
|
|
218
190
|
|
|
219
|
-
eprintln!("
|
|
191
|
+
eprintln!("{}", ui::banner());
|
|
192
|
+
|
|
193
|
+
eprintln!(
|
|
194
|
+
"{}{} {}\n",
|
|
195
|
+
ui::INDENT,
|
|
196
|
+
ui::strong("Using Yerbafile rules"),
|
|
197
|
+
ui::subtle(format!("(from {})", yerbafile_path.display()))
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
let started = std::time::Instant::now();
|
|
220
201
|
|
|
221
202
|
let results = if files.is_empty() {
|
|
222
203
|
yerbafile.apply(write)
|
|
@@ -224,6 +205,8 @@ pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
|
224
205
|
files.iter().flat_map(|file| yerbafile.apply_file(file, write)).collect()
|
|
225
206
|
};
|
|
226
207
|
|
|
208
|
+
let elapsed = started.elapsed();
|
|
209
|
+
|
|
227
210
|
let mut has_changes = false;
|
|
228
211
|
let mut has_errors = false;
|
|
229
212
|
|
|
@@ -231,7 +214,8 @@ pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
|
231
214
|
|
|
232
215
|
for result in &results {
|
|
233
216
|
if let Some(error) = &result.error {
|
|
234
|
-
eprintln!(" {
|
|
217
|
+
eprintln!(" {} {}", ui::failure(ui::glyph::FAIL), ui::strong(&result.file));
|
|
218
|
+
eprintln!(" {}", ui::muted(error));
|
|
235
219
|
|
|
236
220
|
if github {
|
|
237
221
|
use yerba::error::GitHubAnnotations;
|
|
@@ -244,12 +228,15 @@ pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
|
244
228
|
has_errors = true;
|
|
245
229
|
} else if result.changed {
|
|
246
230
|
if write {
|
|
247
|
-
eprintln!(" {
|
|
231
|
+
eprintln!(" {} {}", ui::success(ui::glyph::OK), result.file);
|
|
248
232
|
} else {
|
|
249
|
-
eprintln!(" {
|
|
233
|
+
eprintln!(" {} {}", ui::pending(ui::glyph::PENDING), result.file);
|
|
250
234
|
|
|
251
235
|
if github {
|
|
252
|
-
eprintln!(
|
|
236
|
+
eprintln!(
|
|
237
|
+
"::error file={}::File does not match Yerbafile rules. Run `yerba apply` to update it.",
|
|
238
|
+
result.file
|
|
239
|
+
);
|
|
253
240
|
}
|
|
254
241
|
}
|
|
255
242
|
|
|
@@ -257,19 +244,70 @@ pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
|
257
244
|
}
|
|
258
245
|
}
|
|
259
246
|
|
|
260
|
-
|
|
261
|
-
|
|
247
|
+
let changed = results.iter().filter(|result| result.error.is_none() && result.changed).count();
|
|
248
|
+
let seen: std::collections::HashSet<&String> = results.iter().map(|result| &result.file).collect();
|
|
249
|
+
let rules = yerbafile.rules.len() + usize::from(!yerbafile.pipeline.is_empty());
|
|
250
|
+
let steps = yerbafile.pipeline.len() + yerbafile.rules.iter().map(|rule| rule.pipeline.len()).sum::<usize>();
|
|
251
|
+
|
|
252
|
+
if seen.is_empty() {
|
|
253
|
+
eprintln!(
|
|
254
|
+
"{} {} {}",
|
|
255
|
+
ui::pending(ui::glyph::PENDING),
|
|
256
|
+
ui::pending("No files matched."),
|
|
257
|
+
ui::subtle("Check the `files:` patterns in your Yerbafile.")
|
|
258
|
+
);
|
|
259
|
+
} else if !has_changes && !has_errors {
|
|
260
|
+
eprintln!("{} {}", ui::success(ui::glyph::OK), ui::success("Everything's up to date."));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if write && has_changes {
|
|
264
|
+
eprintln!(
|
|
265
|
+
"\n{} {}",
|
|
266
|
+
ui::success(ui::glyph::OK),
|
|
267
|
+
ui::success(format!("Freshly brewed {}.", pluralize(changed, "file", "files")))
|
|
268
|
+
);
|
|
262
269
|
}
|
|
263
270
|
|
|
264
271
|
if !write && has_changes {
|
|
265
|
-
|
|
272
|
+
let command = if files.is_empty() {
|
|
273
|
+
"yerba apply".to_string()
|
|
274
|
+
} else {
|
|
275
|
+
format!("yerba apply {}", files.join(" "))
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
eprintln!(
|
|
279
|
+
"\n{} {} {}",
|
|
280
|
+
ui::pending(ui::glyph::PENDING),
|
|
281
|
+
ui::pending(format!("{} out of date.", pluralize(changed, "file", "files"))),
|
|
282
|
+
ui::subtle(format!("Run {} to update {}.", command, if changed == 1 { "it" } else { "them" }))
|
|
283
|
+
);
|
|
266
284
|
}
|
|
267
285
|
|
|
268
|
-
|
|
286
|
+
eprintln!(
|
|
287
|
+
"{}{}",
|
|
288
|
+
ui::STATUS_INDENT,
|
|
289
|
+
ui::subtle(format!(
|
|
290
|
+
"{} · {} · {} · {}",
|
|
291
|
+
pluralize(seen.len(), "file", "files"),
|
|
292
|
+
pluralize(rules, "rule", "rules"),
|
|
293
|
+
pluralize(steps, "step", "steps"),
|
|
294
|
+
format_duration(elapsed)
|
|
295
|
+
))
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
if has_errors || (!write && has_changes) {
|
|
269
299
|
process::exit(1);
|
|
270
300
|
}
|
|
271
301
|
}
|
|
272
302
|
|
|
303
|
+
fn format_duration(elapsed: std::time::Duration) -> String {
|
|
304
|
+
if elapsed.as_secs() == 0 {
|
|
305
|
+
format!("{}ms", elapsed.as_millis())
|
|
306
|
+
} else {
|
|
307
|
+
format!("{:.1}s", elapsed.as_secs_f64())
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
273
311
|
pub(crate) fn resolve_move_indexes(
|
|
274
312
|
document: &yerba::Document,
|
|
275
313
|
path: &str,
|
|
@@ -279,10 +317,8 @@ pub(crate) fn resolve_move_indexes(
|
|
|
279
317
|
to: Option<usize>,
|
|
280
318
|
resolve: impl Fn(&yerba::Document, &str, &str) -> Result<usize, yerba::YerbaError>,
|
|
281
319
|
) -> (usize, usize) {
|
|
282
|
-
use color::*;
|
|
283
|
-
|
|
284
320
|
let from_index = resolve(document, path, item).unwrap_or_else(|error| {
|
|
285
|
-
eprintln!("{
|
|
321
|
+
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
286
322
|
process::exit(1);
|
|
287
323
|
});
|
|
288
324
|
|
|
@@ -290,7 +326,7 @@ pub(crate) fn resolve_move_indexes(
|
|
|
290
326
|
index
|
|
291
327
|
} else if let Some(target) = &before {
|
|
292
328
|
let target_index = resolve(document, path, target).unwrap_or_else(|error| {
|
|
293
|
-
eprintln!("{
|
|
329
|
+
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
294
330
|
process::exit(1);
|
|
295
331
|
});
|
|
296
332
|
|
|
@@ -301,7 +337,7 @@ pub(crate) fn resolve_move_indexes(
|
|
|
301
337
|
}
|
|
302
338
|
} else if let Some(target) = &after {
|
|
303
339
|
let target_index = resolve(document, path, target).unwrap_or_else(|error| {
|
|
304
|
-
eprintln!("{
|
|
340
|
+
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
305
341
|
process::exit(1);
|
|
306
342
|
});
|
|
307
343
|
|
|
@@ -311,7 +347,7 @@ pub(crate) fn resolve_move_indexes(
|
|
|
311
347
|
target_index + 1
|
|
312
348
|
}
|
|
313
349
|
} else {
|
|
314
|
-
eprintln!("{
|
|
350
|
+
eprintln!("{} specify --before, --after, or --to", ui::failure("Error:"));
|
|
315
351
|
process::exit(1);
|
|
316
352
|
};
|
|
317
353
|
|
|
@@ -319,12 +355,10 @@ pub(crate) fn resolve_move_indexes(
|
|
|
319
355
|
}
|
|
320
356
|
|
|
321
357
|
pub(crate) fn resolve_files(pattern: &str) -> Vec<String> {
|
|
322
|
-
use color::*;
|
|
323
|
-
|
|
324
358
|
if pattern.contains('*') || pattern.contains('?') || pattern.contains('[') {
|
|
325
359
|
let paths: Vec<String> = glob::glob(pattern)
|
|
326
360
|
.unwrap_or_else(|error| {
|
|
327
|
-
eprintln!("{
|
|
361
|
+
eprintln!("{} invalid glob pattern '{}': {}", ui::failure("Error:"), pattern, error);
|
|
328
362
|
process::exit(1);
|
|
329
363
|
})
|
|
330
364
|
.filter_map(|entry| entry.ok())
|
|
@@ -332,7 +366,7 @@ pub(crate) fn resolve_files(pattern: &str) -> Vec<String> {
|
|
|
332
366
|
.collect();
|
|
333
367
|
|
|
334
368
|
if paths.is_empty() {
|
|
335
|
-
eprintln!("{
|
|
369
|
+
eprintln!("{} no files matched pattern: {}", ui::failure("Error:"), pattern);
|
|
336
370
|
process::exit(1);
|
|
337
371
|
}
|
|
338
372
|
|
|
@@ -343,18 +377,16 @@ pub(crate) fn resolve_files(pattern: &str) -> Vec<String> {
|
|
|
343
377
|
}
|
|
344
378
|
|
|
345
379
|
pub(crate) fn parse_file(file: &str) -> yerba::Document {
|
|
346
|
-
use color::*;
|
|
347
|
-
|
|
348
380
|
yerba::parse_file(file).unwrap_or_else(|error| {
|
|
349
381
|
match &error {
|
|
350
382
|
yerba::YerbaError::IoError(io_error) => match io_error.kind() {
|
|
351
|
-
std::io::ErrorKind::NotFound => eprintln!("{
|
|
383
|
+
std::io::ErrorKind::NotFound => eprintln!("{} file not found: {}", ui::failure("Error:"), file),
|
|
352
384
|
std::io::ErrorKind::PermissionDenied => {
|
|
353
|
-
eprintln!("{
|
|
385
|
+
eprintln!("{} permission denied: {}", ui::failure("Error:"), file)
|
|
354
386
|
}
|
|
355
|
-
_ => eprintln!("{
|
|
387
|
+
_ => eprintln!("{} reading {}: {}", ui::failure("Error:"), file, io_error),
|
|
356
388
|
},
|
|
357
|
-
_ => eprintln!("{
|
|
389
|
+
_ => eprintln!("{} parsing {}: {}", ui::failure("Error:"), file, error),
|
|
358
390
|
}
|
|
359
391
|
|
|
360
392
|
process::exit(1);
|
|
@@ -366,21 +398,19 @@ pub(crate) fn run_op(display_file: &str, document: &yerba::Document, result: Res
|
|
|
366
398
|
}
|
|
367
399
|
|
|
368
400
|
pub(crate) fn run_op_with_hint(display_file: &str, document: &yerba::Document, result: Result<(), yerba::YerbaError>, hint: Option<&str>) {
|
|
369
|
-
use color::*;
|
|
370
|
-
|
|
371
401
|
if let Err(error) = result {
|
|
372
402
|
if let yerba::YerbaError::SelectorNotFound(selector) = &error {
|
|
373
|
-
eprintln!("{
|
|
403
|
+
eprintln!("{} selector \"{selector}\" not found in {display_file}", ui::failure("Error:"));
|
|
374
404
|
|
|
375
405
|
show_similar_selectors(display_file, document, selector);
|
|
376
406
|
} else {
|
|
377
|
-
eprintln!("{
|
|
407
|
+
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
378
408
|
}
|
|
379
409
|
|
|
380
410
|
if let Some(hint) = hint {
|
|
381
411
|
if matches!(error, yerba::YerbaError::SelectorNotFound(_)) {
|
|
382
412
|
eprintln!();
|
|
383
|
-
eprintln!(" {
|
|
413
|
+
eprintln!(" {}", ui::subtle(format!("Hint: {}", hint)));
|
|
384
414
|
}
|
|
385
415
|
}
|
|
386
416
|
|
|
@@ -389,7 +419,6 @@ pub(crate) fn run_op_with_hint(display_file: &str, document: &yerba::Document, r
|
|
|
389
419
|
}
|
|
390
420
|
|
|
391
421
|
pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document, invalid_path: &str) {
|
|
392
|
-
use color::*;
|
|
393
422
|
use yerba::didyoumean::didyoumean_ranked;
|
|
394
423
|
|
|
395
424
|
let selectors = document.selectors();
|
|
@@ -405,19 +434,19 @@ pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document, inv
|
|
|
405
434
|
eprintln!();
|
|
406
435
|
|
|
407
436
|
if close.is_empty() {
|
|
408
|
-
eprintln!(" {
|
|
437
|
+
eprintln!(" {}", ui::strong(format!("Available selectors in {}:", file)));
|
|
409
438
|
|
|
410
439
|
for selector in selectors.iter().take(10) {
|
|
411
|
-
eprintln!(" {
|
|
440
|
+
eprintln!(" {}", ui::subtle(selector));
|
|
412
441
|
}
|
|
413
442
|
|
|
414
443
|
if selectors.len() > 10 {
|
|
415
|
-
eprintln!(" {
|
|
444
|
+
eprintln!(" {}", ui::subtle(format!("... and {} more", selectors.len() - 10)));
|
|
416
445
|
}
|
|
417
446
|
} else if close.len() == 1 {
|
|
418
|
-
eprintln!(" {
|
|
447
|
+
eprintln!(" {} {}", ui::strong("Did you mean this selector?"), close[0]);
|
|
419
448
|
} else {
|
|
420
|
-
eprintln!(" {
|
|
449
|
+
eprintln!(" {}", ui::strong("Did you mean one of these selectors?"));
|
|
421
450
|
|
|
422
451
|
for selector in close.iter().take(5) {
|
|
423
452
|
eprintln!(" {selector}");
|
|
@@ -425,8 +454,8 @@ pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document, inv
|
|
|
425
454
|
}
|
|
426
455
|
|
|
427
456
|
eprintln!();
|
|
428
|
-
eprintln!(" {
|
|
429
|
-
eprintln!(" yerba selectors \"{file}\"
|
|
457
|
+
eprintln!(" {}", ui::strong("To see all valid selectors, run:"));
|
|
458
|
+
eprintln!(" yerba selectors \"{file}\"");
|
|
430
459
|
}
|
|
431
460
|
|
|
432
461
|
pub(crate) fn output(file: &str, document: &yerba::Document, dry_run: bool) {
|