headson 0.6.5__tar.gz → 0.6.6__tar.gz
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.
Potentially problematic release.
This version of headson might be problematic. Click here for more details.
- {headson-0.6.5 → headson-0.6.6}/Cargo.lock +1 -1
- {headson-0.6.5 → headson-0.6.6}/Cargo.toml +1 -1
- {headson-0.6.5 → headson-0.6.6}/PKG-INFO +22 -2
- {headson-0.6.5 → headson-0.6.6}/README.md +21 -1
- {headson-0.6.5 → headson-0.6.6}/pyproject.toml +1 -1
- {headson-0.6.5 → headson-0.6.6}/python/Cargo.lock +2 -2
- {headson-0.6.5 → headson-0.6.6}/python/Cargo.toml +1 -1
- {headson-0.6.5 → headson-0.6.6}/src/lib.rs +14 -3
- {headson-0.6.5 → headson-0.6.6}/src/main.rs +54 -23
- {headson-0.6.5 → headson-0.6.6}/src/order/build.rs +1 -1
- {headson-0.6.5 → headson-0.6.6}/src/utils/measure.rs +20 -12
- {headson-0.6.5 → headson-0.6.6}/docs/assets/algorithm.svg +0 -0
- {headson-0.6.5 → headson-0.6.6}/docs/assets/logo.png +0 -0
- {headson-0.6.5 → headson-0.6.6}/docs/assets/logo.svg +0 -0
- {headson-0.6.5 → headson-0.6.6}/docs/assets/tapes/demo.gif +0 -0
- {headson-0.6.5 → headson-0.6.6}/python/README.md +0 -0
- {headson-0.6.5 → headson-0.6.6}/python/headson/__init__.py +0 -0
- {headson-0.6.5 → headson-0.6.6}/python/src/lib.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/format.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/builder.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/samplers/default.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/samplers/head.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/samplers/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/json/samplers/tail.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/text/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/formats/yaml/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/ingest/sampling/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/order/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/order/scoring.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/order/snapshots/headson__order__build__tests__order_empty_array_order.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/order/snapshots/headson__order__build__tests__order_single_string_array_order.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/order/types.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/color.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/fileset.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/output.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__arena_render_empty.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__arena_render_empty_yaml.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__arena_render_single.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__arena_render_single_yaml.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_internal_gaps_yaml.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_js_head.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_js_tail.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_pseudo_head.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_pseudo_tail.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_yaml_head.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__array_omitted_yaml_tail.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__inline_open_array_in_object_json.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/snapshots/headson__serialization__tests__inline_open_array_in_object_yaml.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/core.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/js.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/json.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/pseudo.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/text.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/templates/yaml.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/serialization/types.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/snapshots/headson__order__tests__order_empty_array_order.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/snapshots/headson__order__tests__order_single_string_array_order.snap +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/graph.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/json.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/mod.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/search.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/text.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/src/utils/tree_arena.rs +0 -0
- {headson-0.6.5 → headson-0.6.6}/tests/fixtures/json/JSONTestSuite/LICENSE +0 -0
- {headson-0.6.5 → headson-0.6.6}/tests/fixtures/json/JSONTestSuite/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: headson
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.6
|
|
4
4
|
Classifier: Programming Language :: Python
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -70,7 +70,8 @@ If you’re comfortable with tools like `head` and `tail`, use `headson` when yo
|
|
|
70
70
|
|
|
71
71
|
Common flags:
|
|
72
72
|
|
|
73
|
-
- `-c, --bytes <BYTES>`: per‑file output budget. For multiple inputs, default total budget is `<BYTES> * number_of_inputs`.
|
|
73
|
+
- `-c, --bytes <BYTES>`: per‑file output budget (bytes). For multiple inputs, default total budget is `<BYTES> * number_of_inputs`.
|
|
74
|
+
- `-u, --chars <CHARS>`: per‑file output budget (Unicode code points). Behaves like `--bytes` but counts characters instead of bytes.
|
|
74
75
|
- `-C, --global-bytes <BYTES>`: total output budget across all inputs. With `--bytes`, the effective total is the smaller of the two.
|
|
75
76
|
- `-f, --format <auto|json|yaml|text>`: output format (default: `auto`).
|
|
76
77
|
- Auto: stdin → JSON family; filesets → per‑file based on extension (`.json` → JSON family, `.yaml`/`.yml` → YAML, unknown → Text).
|
|
@@ -97,6 +98,25 @@ Notes:
|
|
|
97
98
|
- Directories and binary files are ignored; a notice is printed to stderr for each. Stdin reads the stream as‑is.
|
|
98
99
|
- Head vs Tail sampling: these options bias which part of arrays are kept before rendering. Display styles may still insert internal gap markers to honor very small budgets; strict JSON stays unannotated.
|
|
99
100
|
|
|
101
|
+
## Budget Modes
|
|
102
|
+
|
|
103
|
+
- Bytes (`-c/--bytes`, `-C/--global-bytes`)
|
|
104
|
+
- Measures UTF‑8 bytes in the output.
|
|
105
|
+
- Default per‑file budget is 500 bytes when neither `--lines` nor `--chars` is provided.
|
|
106
|
+
- Multiple inputs: total default budget is `<BYTES> * number_of_inputs`; `--global-bytes` caps the total.
|
|
107
|
+
|
|
108
|
+
- Characters (`-u/--chars`)
|
|
109
|
+
- Measures Unicode code points (not grapheme clusters).
|
|
110
|
+
|
|
111
|
+
- Lines (`-n/--lines`, `-N/--global-lines`)
|
|
112
|
+
- Caps the number of lines in the output.
|
|
113
|
+
- Incompatible with `--no-newline`.
|
|
114
|
+
- Multiple inputs: defaults to `<LINES> * number_of_inputs`; `--global-lines` caps the total.
|
|
115
|
+
|
|
116
|
+
- Interactions and precedence
|
|
117
|
+
- All active budgets are enforced simultaneously. The render must satisfy all of: bytes (if set), chars (if set), and lines (if set). The strictest cap wins.
|
|
118
|
+
- When only lines are specified, no implicit byte cap applies. When neither lines nor chars are specified, a 500‑byte default applies.
|
|
119
|
+
|
|
100
120
|
Quick one‑liners:
|
|
101
121
|
|
|
102
122
|
- Peek a big JSON stream (keeps structure):
|
|
@@ -56,7 +56,8 @@ If you’re comfortable with tools like `head` and `tail`, use `headson` when yo
|
|
|
56
56
|
|
|
57
57
|
Common flags:
|
|
58
58
|
|
|
59
|
-
- `-c, --bytes <BYTES>`: per‑file output budget. For multiple inputs, default total budget is `<BYTES> * number_of_inputs`.
|
|
59
|
+
- `-c, --bytes <BYTES>`: per‑file output budget (bytes). For multiple inputs, default total budget is `<BYTES> * number_of_inputs`.
|
|
60
|
+
- `-u, --chars <CHARS>`: per‑file output budget (Unicode code points). Behaves like `--bytes` but counts characters instead of bytes.
|
|
60
61
|
- `-C, --global-bytes <BYTES>`: total output budget across all inputs. With `--bytes`, the effective total is the smaller of the two.
|
|
61
62
|
- `-f, --format <auto|json|yaml|text>`: output format (default: `auto`).
|
|
62
63
|
- Auto: stdin → JSON family; filesets → per‑file based on extension (`.json` → JSON family, `.yaml`/`.yml` → YAML, unknown → Text).
|
|
@@ -83,6 +84,25 @@ Notes:
|
|
|
83
84
|
- Directories and binary files are ignored; a notice is printed to stderr for each. Stdin reads the stream as‑is.
|
|
84
85
|
- Head vs Tail sampling: these options bias which part of arrays are kept before rendering. Display styles may still insert internal gap markers to honor very small budgets; strict JSON stays unannotated.
|
|
85
86
|
|
|
87
|
+
## Budget Modes
|
|
88
|
+
|
|
89
|
+
- Bytes (`-c/--bytes`, `-C/--global-bytes`)
|
|
90
|
+
- Measures UTF‑8 bytes in the output.
|
|
91
|
+
- Default per‑file budget is 500 bytes when neither `--lines` nor `--chars` is provided.
|
|
92
|
+
- Multiple inputs: total default budget is `<BYTES> * number_of_inputs`; `--global-bytes` caps the total.
|
|
93
|
+
|
|
94
|
+
- Characters (`-u/--chars`)
|
|
95
|
+
- Measures Unicode code points (not grapheme clusters).
|
|
96
|
+
|
|
97
|
+
- Lines (`-n/--lines`, `-N/--global-lines`)
|
|
98
|
+
- Caps the number of lines in the output.
|
|
99
|
+
- Incompatible with `--no-newline`.
|
|
100
|
+
- Multiple inputs: defaults to `<LINES> * number_of_inputs`; `--global-lines` caps the total.
|
|
101
|
+
|
|
102
|
+
- Interactions and precedence
|
|
103
|
+
- All active budgets are enforced simultaneously. The render must satisfy all of: bytes (if set), chars (if set), and lines (if set). The strictest cap wins.
|
|
104
|
+
- When only lines are specified, no implicit byte cap applies. When neither lines nor chars are specified, a 500‑byte default applies.
|
|
105
|
+
|
|
86
106
|
Quick one‑liners:
|
|
87
107
|
|
|
88
108
|
- Peek a big JSON stream (keeps structure):
|
|
@@ -214,7 +214,7 @@ dependencies = [
|
|
|
214
214
|
|
|
215
215
|
[[package]]
|
|
216
216
|
name = "headson"
|
|
217
|
-
version = "0.6.
|
|
217
|
+
version = "0.6.6"
|
|
218
218
|
dependencies = [
|
|
219
219
|
"anyhow",
|
|
220
220
|
"clap",
|
|
@@ -228,7 +228,7 @@ dependencies = [
|
|
|
228
228
|
|
|
229
229
|
[[package]]
|
|
230
230
|
name = "headson-python"
|
|
231
|
-
version = "0.6.
|
|
231
|
+
version = "0.6.6"
|
|
232
232
|
dependencies = [
|
|
233
233
|
"anyhow",
|
|
234
234
|
"headson",
|
|
@@ -38,6 +38,7 @@ pub use serialization::types::{
|
|
|
38
38
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
|
39
39
|
pub struct Budgets {
|
|
40
40
|
pub byte_budget: Option<usize>,
|
|
41
|
+
pub char_budget: Option<usize>,
|
|
41
42
|
pub line_budget: Option<usize>,
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -54,6 +55,7 @@ pub fn headson(
|
|
|
54
55
|
config,
|
|
55
56
|
Budgets {
|
|
56
57
|
byte_budget: Some(budget),
|
|
58
|
+
char_budget: None,
|
|
57
59
|
line_budget: None,
|
|
58
60
|
},
|
|
59
61
|
);
|
|
@@ -73,6 +75,7 @@ pub fn headson_many(
|
|
|
73
75
|
config,
|
|
74
76
|
Budgets {
|
|
75
77
|
byte_budget: Some(budget),
|
|
78
|
+
char_budget: None,
|
|
76
79
|
line_budget: None,
|
|
77
80
|
},
|
|
78
81
|
);
|
|
@@ -93,6 +96,7 @@ pub fn headson_yaml(
|
|
|
93
96
|
config,
|
|
94
97
|
Budgets {
|
|
95
98
|
byte_budget: Some(budget),
|
|
99
|
+
char_budget: None,
|
|
96
100
|
line_budget: None,
|
|
97
101
|
},
|
|
98
102
|
);
|
|
@@ -113,6 +117,7 @@ pub fn headson_many_yaml(
|
|
|
113
117
|
config,
|
|
114
118
|
Budgets {
|
|
115
119
|
byte_budget: Some(budget),
|
|
120
|
+
char_budget: None,
|
|
116
121
|
line_budget: None,
|
|
117
122
|
},
|
|
118
123
|
);
|
|
@@ -133,6 +138,7 @@ pub fn headson_text(
|
|
|
133
138
|
config,
|
|
134
139
|
Budgets {
|
|
135
140
|
byte_budget: Some(budget),
|
|
141
|
+
char_budget: None,
|
|
136
142
|
line_budget: None,
|
|
137
143
|
},
|
|
138
144
|
);
|
|
@@ -153,6 +159,7 @@ pub fn headson_many_text(
|
|
|
153
159
|
config,
|
|
154
160
|
Budgets {
|
|
155
161
|
byte_budget: Some(budget),
|
|
162
|
+
char_budget: None,
|
|
156
163
|
line_budget: None,
|
|
157
164
|
},
|
|
158
165
|
);
|
|
@@ -201,10 +208,14 @@ fn find_largest_render_under_budgets(
|
|
|
201
208
|
render_set_id = render_set_id.wrapping_add(1).max(1);
|
|
202
209
|
// Measure output using a unified stats helper and enforce
|
|
203
210
|
// all provided caps (chars and/or lines).
|
|
204
|
-
let stats = crate::utils::measure::count_output_stats(
|
|
205
|
-
|
|
211
|
+
let stats = crate::utils::measure::count_output_stats(
|
|
212
|
+
&s,
|
|
213
|
+
budgets.char_budget.is_some(),
|
|
214
|
+
);
|
|
215
|
+
let fits_bytes = budgets.byte_budget.is_none_or(|c| stats.bytes <= c);
|
|
216
|
+
let fits_chars = budgets.char_budget.is_none_or(|c| stats.chars <= c);
|
|
206
217
|
let fits_lines = budgets.line_budget.is_none_or(|l| stats.lines <= l);
|
|
207
|
-
if fits_chars && fits_lines {
|
|
218
|
+
if fits_bytes && fits_chars && fits_lines {
|
|
208
219
|
best_k = Some(mid);
|
|
209
220
|
true
|
|
210
221
|
} else {
|
|
@@ -23,6 +23,13 @@ type IgnoreNotices = Vec<String>;
|
|
|
23
23
|
struct Cli {
|
|
24
24
|
#[arg(short = 'c', long = "bytes")]
|
|
25
25
|
bytes: Option<usize>,
|
|
26
|
+
#[arg(
|
|
27
|
+
short = 'u',
|
|
28
|
+
long = "chars",
|
|
29
|
+
value_name = "CHARS",
|
|
30
|
+
help = "Per-file Unicode character budget (adds up across files if no global chars limit)"
|
|
31
|
+
)]
|
|
32
|
+
chars: Option<usize>,
|
|
26
33
|
#[arg(
|
|
27
34
|
short = 'n',
|
|
28
35
|
long = "lines",
|
|
@@ -53,7 +60,8 @@ struct Cli {
|
|
|
53
60
|
#[arg(
|
|
54
61
|
long = "no-newline",
|
|
55
62
|
default_value_t = false,
|
|
56
|
-
|
|
63
|
+
conflicts_with_all = ["lines", "global_lines"],
|
|
64
|
+
help = "Do not add newlines in the output. Incompatible with --lines/--global-lines."
|
|
57
65
|
)]
|
|
58
66
|
no_newline: bool,
|
|
59
67
|
#[arg(
|
|
@@ -170,21 +178,28 @@ fn main() -> Result<()> {
|
|
|
170
178
|
|
|
171
179
|
// Build budgets from CLI flags. If only line caps are provided, avoid imposing
|
|
172
180
|
// the default byte cap; keep the 500-byte default only when neither lines nor
|
|
173
|
-
// bytes are specified. If any byte-related flag is present, enforce bytes.
|
|
181
|
+
// chars nor bytes are specified. If any byte-related flag is present, enforce bytes.
|
|
174
182
|
fn make_budgets(
|
|
175
183
|
cli: &Cli,
|
|
176
184
|
eff_bytes: usize,
|
|
177
185
|
eff_lines: Option<usize>,
|
|
186
|
+
eff_chars: Option<usize>,
|
|
178
187
|
) -> headson::Budgets {
|
|
179
|
-
let
|
|
188
|
+
let any_bytes = cli.bytes.is_some() || cli.global_bytes.is_some();
|
|
189
|
+
let any_lines = cli.lines.is_some() || cli.global_lines.is_some();
|
|
190
|
+
let any_chars = cli.chars.is_some();
|
|
191
|
+
|
|
192
|
+
// Apply default 500-byte only when no explicit budgets provided.
|
|
193
|
+
let byte_budget = if any_bytes {
|
|
180
194
|
Some(eff_bytes)
|
|
181
|
-
} else if
|
|
195
|
+
} else if any_lines || any_chars {
|
|
182
196
|
None
|
|
183
197
|
} else {
|
|
184
198
|
Some(eff_bytes)
|
|
185
199
|
};
|
|
186
200
|
headson::Budgets {
|
|
187
201
|
byte_budget,
|
|
202
|
+
char_budget: if any_chars { eff_chars } else { None },
|
|
188
203
|
line_budget: eff_lines,
|
|
189
204
|
}
|
|
190
205
|
}
|
|
@@ -198,6 +213,10 @@ fn compute_effective_bytes(cli: &Cli, input_count: usize) -> usize {
|
|
|
198
213
|
}
|
|
199
214
|
}
|
|
200
215
|
|
|
216
|
+
fn compute_effective_chars(cli: &Cli, input_count: usize) -> Option<usize> {
|
|
217
|
+
cli.chars.map(|n| n.saturating_mul(input_count))
|
|
218
|
+
}
|
|
219
|
+
|
|
201
220
|
fn compute_effective_lines(cli: &Cli, input_count: usize) -> Option<usize> {
|
|
202
221
|
match (cli.global_lines, cli.lines) {
|
|
203
222
|
(Some(g), Some(n)) => Some(g.min(n.saturating_mul(input_count))),
|
|
@@ -209,18 +228,19 @@ fn compute_effective_lines(cli: &Cli, input_count: usize) -> Option<usize> {
|
|
|
209
228
|
|
|
210
229
|
fn compute_priority(
|
|
211
230
|
cli: &Cli,
|
|
212
|
-
|
|
231
|
+
effective_bytes: usize,
|
|
232
|
+
effective_chars: Option<usize>,
|
|
213
233
|
input_count: usize,
|
|
214
234
|
) -> headson::PriorityConfig {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
235
|
+
// Choose a unit for heuristics: prefer bytes if present; else chars if present; else default bytes.
|
|
236
|
+
let chosen_global = if cli.bytes.is_some() || cli.global_bytes.is_some() {
|
|
237
|
+
effective_bytes
|
|
238
|
+
} else if let Some(c) = effective_chars {
|
|
239
|
+
c
|
|
240
|
+
} else {
|
|
241
|
+
effective_bytes
|
|
242
|
+
};
|
|
243
|
+
let per_file_for_priority = (chosen_global / input_count.max(1)).max(1);
|
|
224
244
|
get_priority_config(per_file_for_priority, cli)
|
|
225
245
|
}
|
|
226
246
|
|
|
@@ -274,14 +294,18 @@ fn run_from_stdin(
|
|
|
274
294
|
let input_bytes = read_stdin()?;
|
|
275
295
|
let input_count = 1usize;
|
|
276
296
|
let eff = compute_effective_bytes(cli, input_count);
|
|
297
|
+
let eff_chars = compute_effective_chars(cli, input_count);
|
|
277
298
|
let eff_lines = compute_effective_lines(cli, input_count);
|
|
278
|
-
let prio = compute_priority(cli, eff, input_count);
|
|
299
|
+
let prio = compute_priority(cli, eff, eff_chars, input_count);
|
|
279
300
|
let mut cfg = render_cfg.clone();
|
|
280
301
|
// Resolve effective output template for stdin:
|
|
281
302
|
cfg.template = resolve_effective_template_for_stdin(cli.format, cfg.style);
|
|
282
|
-
let budgets = make_budgets(cli, eff, eff_lines);
|
|
303
|
+
let budgets = make_budgets(cli, eff, eff_lines, eff_chars);
|
|
283
304
|
// Enable free string prefix when in line-only mode
|
|
284
|
-
if budgets.byte_budget.is_none()
|
|
305
|
+
if budgets.byte_budget.is_none()
|
|
306
|
+
&& budgets.char_budget.is_none()
|
|
307
|
+
&& budgets.line_budget.is_some()
|
|
308
|
+
{
|
|
285
309
|
cfg.string_free_prefix_graphemes = Some(40);
|
|
286
310
|
}
|
|
287
311
|
match cli.input_format {
|
|
@@ -315,15 +339,19 @@ fn run_from_paths(
|
|
|
315
339
|
let included = entries.len();
|
|
316
340
|
let input_count = included.max(1);
|
|
317
341
|
let eff = compute_effective_bytes(cli, input_count);
|
|
342
|
+
let eff_chars = compute_effective_chars(cli, input_count);
|
|
318
343
|
let eff_lines = compute_effective_lines(cli, input_count);
|
|
319
|
-
let prio = compute_priority(cli, eff, input_count);
|
|
344
|
+
let prio = compute_priority(cli, eff, eff_chars, input_count);
|
|
320
345
|
if cli.inputs.len() > 1 {
|
|
321
346
|
let chosen_input = choose_input_format_fileset(cli, &entries);
|
|
322
347
|
let mut cfg = render_cfg.clone();
|
|
323
348
|
// For filesets: if format=auto, enable per-file template selection.
|
|
324
349
|
cfg.template = effective_fileset_template(cli, cfg.style);
|
|
325
|
-
let budgets = make_budgets(cli, eff, eff_lines);
|
|
326
|
-
if budgets.byte_budget.is_none()
|
|
350
|
+
let budgets = make_budgets(cli, eff, eff_lines, eff_chars);
|
|
351
|
+
if budgets.byte_budget.is_none()
|
|
352
|
+
&& budgets.char_budget.is_none()
|
|
353
|
+
&& budgets.line_budget.is_some()
|
|
354
|
+
{
|
|
327
355
|
cfg.string_free_prefix_graphemes = Some(40);
|
|
328
356
|
}
|
|
329
357
|
let out = match chosen_input {
|
|
@@ -361,8 +389,11 @@ fn run_from_paths(
|
|
|
361
389
|
cfg.template = resolve_effective_template_for_single(
|
|
362
390
|
cli.format, cfg.style, &lower,
|
|
363
391
|
);
|
|
364
|
-
let budgets = make_budgets(cli, eff, eff_lines);
|
|
365
|
-
if budgets.byte_budget.is_none()
|
|
392
|
+
let budgets = make_budgets(cli, eff, eff_lines, eff_chars);
|
|
393
|
+
if budgets.byte_budget.is_none()
|
|
394
|
+
&& budgets.char_budget.is_none()
|
|
395
|
+
&& budgets.line_budget.is_some()
|
|
396
|
+
{
|
|
366
397
|
cfg.string_free_prefix_graphemes = Some(40);
|
|
367
398
|
}
|
|
368
399
|
let out = match chosen_input {
|
|
@@ -496,7 +527,7 @@ fn get_priority_config(
|
|
|
496
527
|
per_file_budget: usize,
|
|
497
528
|
cli: &Cli,
|
|
498
529
|
) -> headson::PriorityConfig {
|
|
499
|
-
// Detect line-only mode: lines flag present and no explicit bytes flags.
|
|
530
|
+
// Detect line-only mode: lines flag present and no explicit bytes/chars flags.
|
|
500
531
|
let line_only = (cli.lines.is_some() || cli.global_lines.is_some())
|
|
501
532
|
&& cli.bytes.is_none()
|
|
502
533
|
&& cli.global_bytes.is_none();
|
|
@@ -14,7 +14,7 @@ struct Entry {
|
|
|
14
14
|
priority_index: usize,
|
|
15
15
|
depth: usize,
|
|
16
16
|
// When present, we can read kind from the arena (parsed JSON) node.
|
|
17
|
-
// When None, this is a synthetic entry (
|
|
17
|
+
// When None, this is a synthetic entry (used for string grapheme entries).
|
|
18
18
|
arena_index: Option<usize>,
|
|
19
19
|
}
|
|
20
20
|
impl PartialEq for Entry {
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
2
2
|
pub(crate) struct OutputStats {
|
|
3
3
|
pub bytes: usize,
|
|
4
|
+
pub chars: usize,
|
|
4
5
|
pub lines: usize,
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/// - Otherwise, lines = number of line break sequences + 1.
|
|
12
|
-
/// - A CRLF pair counts as a single line break.
|
|
13
|
-
pub(crate) fn count_output_stats(s: &str) -> OutputStats {
|
|
14
|
-
let bytes = s.len();
|
|
15
|
-
if bytes == 0 {
|
|
16
|
-
return OutputStats { bytes, lines: 0 };
|
|
8
|
+
#[inline]
|
|
9
|
+
fn count_lines_from_bytes(b: &[u8]) -> usize {
|
|
10
|
+
if b.is_empty() {
|
|
11
|
+
return 0;
|
|
17
12
|
}
|
|
18
|
-
let b = s.as_bytes();
|
|
19
13
|
let mut i = 0usize;
|
|
20
14
|
let mut breaks = 0usize;
|
|
21
15
|
while i < b.len() {
|
|
@@ -35,8 +29,22 @@ pub(crate) fn count_output_stats(s: &str) -> OutputStats {
|
|
|
35
29
|
_ => i += 1,
|
|
36
30
|
}
|
|
37
31
|
}
|
|
32
|
+
breaks + 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Count bytes and logical lines in a string, normalizing CRLF/CR/LF.
|
|
36
|
+
///
|
|
37
|
+
/// Rules:
|
|
38
|
+
/// - An empty string has 0 lines.
|
|
39
|
+
/// - Otherwise, lines = number of line break sequences + 1.
|
|
40
|
+
/// - A CRLF pair counts as a single line break.
|
|
41
|
+
pub(crate) fn count_output_stats(s: &str, want_chars: bool) -> OutputStats {
|
|
42
|
+
let bytes = s.len();
|
|
43
|
+
let chars = if want_chars { s.chars().count() } else { 0 };
|
|
44
|
+
let lines = count_lines_from_bytes(s.as_bytes());
|
|
38
45
|
OutputStats {
|
|
39
46
|
bytes,
|
|
40
|
-
|
|
47
|
+
chars,
|
|
48
|
+
lines,
|
|
41
49
|
}
|
|
42
50
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{headson-0.6.5 → headson-0.6.6}/src/snapshots/headson__order__tests__order_empty_array_order.snap
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|