Skip to content

Commit fbfe8e3

Browse files
committed
feat: use embedded prettyunits for bytes and numbers
1 parent 678bd39 commit fbfe8e3

File tree

2 files changed

+130
-15
lines changed

2 files changed

+130
-15
lines changed

R/numbers.R

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
2+
format_num <- local({
3+
4+
pretty_num <- function(number, style = c("default", "nopad", "6")) {
5+
6+
style <- switch(
7+
match.arg(style),
8+
"default" = pretty_num_default,
9+
"nopad" = pretty_num_nopad,
10+
"6" = pretty_num_6
11+
)
12+
13+
style(number)
14+
}
15+
16+
compute_num <- function(number, smallest_prefix = "y") {
17+
prefixes0 <- c("y","z","a","f","p","n","u","m","", "k", "M", "G", "T", "P", "E", "Z", "Y")
18+
zeroshif0 <- 9L
19+
20+
stopifnot(
21+
is.numeric(number),
22+
is.character(smallest_prefix),
23+
length(smallest_prefix) == 1,
24+
!is.na(smallest_prefix),
25+
smallest_prefix %in% prefixes0
26+
)
27+
28+
limits <- c(999950 * 1000 ^ (seq_len(length(prefixes0)) - (zeroshif0 + 1L)))
29+
nrow <- length(limits)
30+
low <- match(smallest_prefix, prefixes0)
31+
zeroshift <- zeroshif0 + 1L - low
32+
prefixes <- prefixes0[low:length(prefixes0)]
33+
limits <- limits[low:nrow]
34+
nrow <- nrow - low + 1
35+
36+
neg <- number < 0 & !is.na(number)
37+
number <- abs(number)
38+
mat <- matrix(
39+
rep(number, each = nrow),
40+
nrow = nrow,
41+
ncol = length(number)
42+
)
43+
mat2 <- matrix(mat < limits, nrow = nrow, ncol = length(number))
44+
exponent <- nrow - colSums(mat2) - (zeroshift - 1L)
45+
in_range <- function(exponent) {
46+
max(min(exponent, nrow - zeroshift, na.rm = FALSE), 1L - zeroshift, na.rm = TRUE)
47+
}
48+
if (length(exponent)) {
49+
exponent <- sapply(exponent, in_range)
50+
}
51+
res <- number / 1000 ^ exponent
52+
prefix <- prefixes[exponent + zeroshift]
53+
54+
## Zero number
55+
res[number == 0] <- 0
56+
prefix[number == 0] <- prefixes[zeroshift]
57+
58+
## NA and NaN number
59+
res[is.na(number)] <- NA_real_
60+
res[is.nan(number)] <- NaN
61+
prefix[is.na(number)] <- "" # prefixes0[low] is meaningless # Includes NaN as well
62+
63+
data.frame(
64+
stringsAsFactors = FALSE,
65+
amount = res,
66+
prefix = prefix,
67+
negative = neg
68+
)
69+
}
70+
71+
pretty_num_default <- function(number) {
72+
szs <- compute_num(number)
73+
amt <- szs$amount
74+
sep <- " "
75+
76+
## String. For fractions we always show two fraction digits
77+
res <- character(length(amt))
78+
int <- is.na(amt) | abs(amt - as.integer(amt)) <= .Machine$double.eps
79+
res[int] <- format(
80+
ifelse(szs$negative[int], -1, 1) * amt[int],
81+
scientific = FALSE
82+
)
83+
res[!int] <- sprintf("%.2f", ifelse(szs$negative[!int], -1, 1) * amt[!int])
84+
85+
format(paste(res, szs$prefix, sep = sep), justify = "right")
86+
}
87+
88+
pretty_num_nopad <- function(number) {
89+
sub("^\\s+", "", pretty_num_default(number))
90+
}
91+
92+
pretty_num_6 <- function(number) {
93+
szs <- compute_num(number, smallest_prefix = "y")
94+
amt <- round(szs$amount, 2)
95+
sep <- " "
96+
97+
na <- is.na(amt)
98+
nan <- is.nan(amt)
99+
neg <- !na & !nan & szs$negative
100+
l10p <- !na & !nan & !neg & amt < 10
101+
l100p <- !na & !nan & !neg & amt >= 10 & amt < 100
102+
b100p <- !na & !nan & !neg & amt >= 100
103+
l10n <- !na & !nan & neg & amt < 10
104+
l100n <- !na & !nan & neg & amt >= 10 & amt < 100
105+
b100n <- !na & !nan & neg & amt >= 100
106+
107+
famt <- character(length(amt))
108+
famt[na] <- " NA"
109+
famt[nan] <- " NaN"
110+
famt[l10p] <- sprintf("%.2f", amt[l10p])
111+
famt[l100p] <- sprintf("%.1f", amt[l100p])
112+
famt[b100p] <- sprintf(" %.0f", amt[b100p])
113+
famt[l10n] <- sprintf("-%.1f", amt[l10n])
114+
famt[l100n] <- sprintf(" -%.0f", amt[l100n])
115+
famt[b100n] <- sprintf("-%.0f", amt[b100n])
116+
117+
sub(" $", " ", paste0(famt, sep, szs$prefix))
118+
}
119+
120+
structure(
121+
list(
122+
.internal = environment(),
123+
pretty_num = pretty_num,
124+
compute_num = compute_num
125+
),
126+
class = c("standalone_num", "standalone")
127+
)
128+
})

R/themes.R

+2-15
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,10 @@ builtin_theme <- function(dark = getOption("cli.theme_dark", "auto")) {
254254
span.or = list("vec-sep2" = " or ", "vec-last" = ", or "),
255255
span.timestamp = list(before = "[", after = "]", color = "grey"),
256256
span.bytes = list(
257-
transform = function(x) format_pretty(x, "bytes")
257+
transform = function(x) format_bytes$pretty_bytes(x)
258258
),
259259
span.num = list(
260-
transform = function(x) format_pretty(x, "num")
260+
transform = function(x) format_num$pretty_num(x)
261261
)
262262
)
263263
}
@@ -386,19 +386,6 @@ format_code <- function(dark) {
386386
}
387387
}
388388

389-
format_pretty <- function(x, type = c("num", "bytes")) {
390-
if (!requireNamespace("prettyunits", quietly = TRUE)) {
391-
throw(cli_error(
392-
"{.pgk prettyunits} is required for formatting numbers and bytes."
393-
))
394-
}
395-
type <- match.arg(type)
396-
switch(type,
397-
num = prettyunits::pretty_num(x),
398-
bytes = prettyunits::pretty_bytes(x)
399-
)
400-
}
401-
402389
theme_create <- function(theme) {
403390
mtheme <- theme
404391
mtheme[] <- lapply(mtheme, create_formatter)

0 commit comments

Comments
 (0)