diff --git a/include/fmt/format.h b/include/fmt/format.h index 13e30f6b1fc2..94b07449626c 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2110,13 +2110,51 @@ FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, return write_int(out, make_write_int_arg(value, specs.sign()), specs); } +FMT_INLINE auto count_code_points_with_display_width_precision( + string_view s, size_t display_width_precision) -> size_t { + size_t display_width = 0; + size_t code_points = 0; + + // Iterate through the string to compute display width + for_each_codepoint(s, [&](uint32_t, string_view sv) { + // Compute the display width of the current code point + size_t cp_width = compute_width(sv); + if (display_width + cp_width > display_width_precision) { + return false; // Stop iteration when display width exceeds precision + } + + display_width += cp_width; + code_points++; + return true; + }); + + return code_points; +} + +template +FMT_CONSTEXPR auto handle_precision( + basic_string_view s, const Char* data, const format_specs& specs, + FMT_ENABLE_IF(std::is_same::value)) -> size_t { + auto code_points = count_code_points_with_display_width_precision( + to_string_view(data), to_unsigned(specs.precision)); + return code_point_index(s, to_unsigned(code_points)); +} + +template +FMT_CONSTEXPR auto handle_precision( + basic_string_view s, const Char*, const format_specs&, + FMT_ENABLE_IF(!std::is_same::value)) -> size_t { + return code_point_index(s, to_unsigned(s.size())); +} + template FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, const format_specs& specs) -> OutputIt { auto data = s.data(); auto size = s.size(); - if (specs.precision >= 0 && to_unsigned(specs.precision) < size) - size = code_point_index(s, to_unsigned(specs.precision)); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) { + size = handle_precision(s, data, specs); + } bool is_debug = specs.type() == presentation_type::debug; if (is_debug) {