diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-03-17 23:37:31 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-03-17 23:37:31 -0400 |
| commit | 451634ae23418b65945a9d9a3b1d895023940c18 (patch) | |
| tree | 7d0c2dc1aec246e671c20c85844ce1e78d6c5d89 /stdlib | |
| parent | f6eda4cf855fdf613cbcde0b073adfde43b354e7 (diff) | |
Add text width support and have that work for padding
Diffstat (limited to 'stdlib')
| -rw-r--r-- | stdlib/text.c | 50 | ||||
| -rw-r--r-- | stdlib/text.h | 7 |
2 files changed, 41 insertions, 16 deletions
diff --git a/stdlib/text.c b/stdlib/text.c index adbac3f0..9abab57b 100644 --- a/stdlib/text.c +++ b/stdlib/text.c @@ -66,6 +66,7 @@ #include <unictype.h> #include <unigbrk.h> #include <uniname.h> +#include <uniwidth.h> #include "arrays.h" #include "integers.h" @@ -512,45 +513,68 @@ public Text_t Text$repeat(Text_t text, Int_t count) return ret; } -static Text_t Text$repeat_to_length(Text_t to_repeat, int64_t length) +public Int_t Text$width(Text_t text, Text_t language) { - if (length <= 0) + int width = u8_strwidth((const uint8_t*)Text$as_c_string(text), Text$as_c_string(language)); + return Int$from_int32(width); +} + +static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_t language) +{ + if (target_width <= 0) return EMPTY_TEXT; + const char *lang_str = Text$as_c_string(language); + int64_t width = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(to_repeat), lang_str); Text_t repeated = EMPTY_TEXT; - while (repeated.length + to_repeat.length <= length) + int64_t repeated_width = 0; + while (repeated_width + width <= target_width) { repeated = concat2(repeated, to_repeat); + repeated_width += width; + } - if (repeated.length < length) - repeated = concat2(repeated, Text$slice(to_repeat, I_small(1), I(length - repeated.length))); + if (repeated_width < target_width) { + for (int64_t i = 0; repeated_width < target_width && i < to_repeat.length; i++) { + Text_t c = Text$slice(to_repeat, I_small(i+1), I_small(i+1)); + int64_t w = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(c), lang_str); + if (repeated_width + w > target_width) { + repeated = concat2(repeated, Text$repeat(Text(" "), I(target_width - repeated_width))); + repeated_width = target_width; + break; + } + repeated = concat2(repeated, c); + repeated_width += w; + } + } - assert(repeated.length == length); return repeated; } -public Text_t Text$left_pad(Text_t text, Int_t count, Text_t padding) +public Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { if (padding.length == 0) fail("Cannot pad with an empty text!"); - return concat2(Text$repeat_to_length(padding, Int64$from_int(count, false) - text.length), text); + int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); + return concat2(Text$repeat_to_width(padding, needed, language), text); } -public Text_t Text$right_pad(Text_t text, Int_t count, Text_t padding) +public Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { if (padding.length == 0) fail("Cannot pad with an empty text!"); - return concat2(text, Text$repeat_to_length(padding, Int64$from_int(count, false) - text.length)); + int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); + return concat2(text, Text$repeat_to_width(padding, needed, language)); } -public Text_t Text$middle_pad(Text_t text, Int_t count, Text_t padding) +public Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { if (padding.length == 0) fail("Cannot pad with an empty text!"); - int64_t needed = Int64$from_int(count, false) - text.length; - return Texts(Text$repeat_to_length(padding, needed/2), text, Text$repeat_to_length(padding, (needed+1)/2)); + int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); + return Texts(Text$repeat_to_width(padding, needed/2, language), text, Text$repeat_to_width(padding, (needed+1)/2, language)); } public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) diff --git a/stdlib/text.h b/stdlib/text.h index 9923403c..e2b0984b 100644 --- a/stdlib/text.h +++ b/stdlib/text.h @@ -68,9 +68,10 @@ Array_t Text$lines(Text_t text); Closure_t Text$by_line(Text_t text); Text_t Text$join(Text_t glue, Array_t pieces); Text_t Text$repeat(Text_t text, Int_t count); -Text_t Text$left_pad(Text_t text, Int_t count, Text_t padding); -Text_t Text$right_pad(Text_t text, Int_t count, Text_t padding); -Text_t Text$middle_pad(Text_t text, Int_t count, Text_t padding); +Int_t Text$width(Text_t text, Text_t language); +Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language); +Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language); +Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language); int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index); uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index); void Text$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *); |
