Skip to content

Commit 1ed28e8

Browse files
committed
og_image: Improve releases and lines of code formatting
1 parent 42a14bd commit 1ed28e8

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed

crates/crates_io_og_image/src/formatting.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,51 @@ pub fn format_bytes(bytes: u32) -> String {
5050
}
5151
}
5252

53+
/// Formats a number with "k" and "M" suffixes for thousands and millions.
54+
///
55+
/// The function follows these rules:
56+
/// - Uses suffixes: none, k, and M
57+
/// - Switches from no suffix to k at 1500
58+
/// - Switches from k to M at 1500 * 1000
59+
/// - Limits the number to a maximum of 4 characters by adjusting decimal places
60+
///
61+
/// # Arguments
62+
///
63+
/// * `number` - The number to format
64+
///
65+
/// # Returns
66+
///
67+
/// A formatted string representing the number with appropriate suffixes
68+
pub fn format_number(number: u32) -> String {
69+
const THRESHOLD: f64 = 1500.;
70+
const UNITS: &[&str] = &["", "k", "M"];
71+
72+
let mut value = number as f64;
73+
let mut unit_index = 0;
74+
75+
// Keep dividing by 1000 until value is below threshold or we've reached the last unit
76+
while value >= THRESHOLD && unit_index < UNITS.len() - 1 {
77+
value /= 1000.0;
78+
unit_index += 1;
79+
}
80+
81+
let unit = UNITS[unit_index];
82+
83+
// Special case for numbers without suffix - no decimal places
84+
if unit_index == 0 {
85+
return format!("{}", number);
86+
}
87+
88+
// For k and M, format with appropriate decimal places
89+
90+
// Determine number of decimal places to keep number under 4 chars
91+
if value < 10.0 {
92+
format!("{:.1}{}", value, unit)
93+
} else {
94+
format!("{:.0}{}", value, unit)
95+
}
96+
}
97+
5398
#[cfg(test)]
5499
mod tests {
55100
use super::*;
@@ -81,4 +126,32 @@ mod tests {
81126
assert_eq!(format_bytes(104857600), "100 MB");
82127
assert_eq!(format_bytes(1073741824), "1024 MB");
83128
}
129+
130+
#[test]
131+
fn test_format_number() {
132+
// Test numbers without suffix (below 1500)
133+
assert_eq!(format_number(0), "0");
134+
assert_eq!(format_number(1), "1");
135+
assert_eq!(format_number(1000), "1000");
136+
assert_eq!(format_number(1499), "1499");
137+
138+
// Test numbers with k suffix (1500 to 1500 * 1000)
139+
assert_eq!(format_number(1500), "1.5k");
140+
assert_eq!(format_number(2000), "2.0k");
141+
assert_eq!(format_number(5000), "5.0k");
142+
assert_eq!(format_number(10000), "10k");
143+
assert_eq!(format_number(50000), "50k");
144+
assert_eq!(format_number(100000), "100k");
145+
assert_eq!(format_number(500000), "500k");
146+
assert_eq!(format_number(999999), "1000k");
147+
148+
// Test numbers with M suffix (above 1500 * 1000)
149+
assert_eq!(format_number(1500000), "1.5M");
150+
assert_eq!(format_number(2000000), "2.0M");
151+
assert_eq!(format_number(5000000), "5.0M");
152+
assert_eq!(format_number(10000000), "10M");
153+
assert_eq!(format_number(50000000), "50M");
154+
assert_eq!(format_number(100000000), "100M");
155+
assert_eq!(format_number(1000000000), "1000M");
156+
}
84157
}

crates/crates_io_og_image/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
mod formatting;
44

5-
use crate::formatting::format_bytes;
5+
use crate::formatting::{format_bytes, format_number};
66
use anyhow::{Context, anyhow};
77
use bytes::Bytes;
88
use crates_io_env_vars::var;
@@ -29,6 +29,9 @@ static TEMPLATE_ENV: LazyLock<Environment<'_>> = LazyLock::new(|| {
2929
// Add custom filter for formatting byte sizes
3030
env.add_filter("format_bytes", format_bytes);
3131

32+
// Add custom filter for formatting numbers with k/M suffixes
33+
env.add_filter("format_number", format_number);
34+
3235
let template_str = include_str!("../templates/og-image.typ.j2");
3336
env.add_template("og-image.typ", template_str).unwrap();
3437
env

crates/crates_io_og_image/src/snapshots/crates_io_og_image__tests__generated_template.typ.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ expression: template_content
279279
render-metadata("Releases", "15", "tag")
280280
render-metadata("Latest", truncate_to_width("v2.1.0", maxWidth: 80pt), "code-branch")
281281
render-metadata("License", truncate_to_width("MIT OR Apache-2.0", maxWidth: 100pt), "scale-balanced")
282-
render-metadata("SLoC", "5500", "code")
282+
render-metadata("SLoC", "5.5k", "code")
283283
render-metadata("Size", "125 kB", "weight-hanging")
284284
})
285285
)

crates/crates_io_og_image/templates/og-image.typ.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,11 @@
274274

275275
place(bottom + left, float: true,
276276
stack(dir: ltr, {
277-
render-metadata("Releases", "{{ data.releases }}", "tag")
277+
render-metadata("Releases", "{{ data.releases | format_number }}", "tag")
278278
render-metadata("Latest", truncate_to_width("{{ data.version | typst_escape }}", maxWidth: 80pt), "code-branch")
279279
render-metadata("License", truncate_to_width("{{ data.license | typst_escape }}", maxWidth: 100pt), "scale-balanced")
280280
{%- if data.lines_of_code %}
281-
render-metadata("SLoC", "{{ data.lines_of_code }}", "code")
281+
render-metadata("SLoC", "{{ data.lines_of_code | format_number }}", "code")
282282
{%- endif %}
283283
render-metadata("Size", "{{ data.crate_size | format_bytes }}", "weight-hanging")
284284
})

0 commit comments

Comments
 (0)