#ifndef string_utils_hh_INCLUDED #define string_utils_hh_INCLUDED #include "string.hh" #include "enum.hh" #include "vector.hh" #include "ranges.hh" #include "optional.hh" #include "utils.hh" namespace Kakoune { String trim_indent(StringView str); String escape(StringView str, StringView characters, char escape); String unescape(StringView str, StringView characters, char escape); template String unescape(StringView str) { const char to_escape[2] = { character, escape }; return unescape(str, {to_escape, 2}, escape); } String indent(StringView str, StringView indent = " "); String replace(StringView str, StringView substr, StringView replacement); String left_pad(StringView str, ColumnCount size, Codepoint c = ' '); String right_pad(StringView str, ColumnCount size, Codepoint c = ' '); template String join(const Container& container, char joiner, bool esc_joiner = true) { const char to_escape[2] = { joiner, '\\' }; String res; for (const auto& str : container) { if (not res.empty()) res += joiner; res += esc_joiner ? escape(str, {to_escape, 2}, '\\') : str; } return res; } template String join(const Container& container, StringView joiner) { String res; for (const auto& str : container) { if (not res.empty()) res += joiner; res += str; } return res; } inline bool prefix_match(StringView str, StringView prefix) { return str.substr(0_byte, prefix.length()) == prefix; } bool subsequence_match(StringView str, StringView subseq); String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col = 0); struct WrapView { struct Iterator : std::iterator { Iterator(StringView text, ColumnCount max_width); Iterator& operator++(); Iterator operator++(int) { auto copy = *this; ++(*this); return copy; } bool operator==(Iterator other) const { return m_remaining == other.m_remaining and m_current == other.m_current; } bool operator!=(Iterator other) const { return not (*this == other); } StringView operator*() { return m_current; } private: StringView m_current; StringView m_remaining; ColumnCount m_max_width; }; Iterator begin() const { return {text, max_width}; } Iterator end() const { return {{}, 1}; } StringView text; ColumnCount max_width; }; inline auto wrap_at(ColumnCount max_width) { return make_view_factory([=](StringView text) { return WrapView{text, max_width}; }); } int str_to_int(StringView str); // throws on error Optional str_to_int_ifp(StringView str); template struct InplaceString { static_assert(N < 256, "InplaceString cannot handle sizes >= 256"); constexpr operator StringView() const { return {m_data, ByteCount{m_length}}; } operator String() const { return {m_data, ByteCount{m_length}}; } unsigned char m_length; char m_data[N]; }; struct Hex { size_t val; }; constexpr Hex hex(size_t val) { return {val}; } InplaceString<15> to_string(int val); InplaceString<15> to_string(unsigned val); InplaceString<23> to_string(long int val); InplaceString<23> to_string(unsigned long val); InplaceString<23> to_string(long long int val); InplaceString<23> to_string(Hex val); InplaceString<23> to_string(float val); InplaceString<7> to_string(Codepoint c); template decltype(auto) to_string(const StronglyTypedNumber& val) { return to_string((ValueType)val); } namespace detail { template requires std::is_convertible_v StringView format_param(const T& val) { return val; } template requires (not std::is_convertible_v) decltype(auto) format_param(const T& val) { return to_string(val); } } String format(StringView fmt, ArrayView params); template String format(StringView fmt, Types&&... params) { return format(fmt, ArrayView{detail::format_param(std::forward(params))...}); } StringView format_to(ArrayView buffer, StringView fmt, ArrayView params); template StringView format_to(ArrayView buffer, StringView fmt, Types&&... params) { return format_to(buffer, fmt, ArrayView{detail::format_param(std::forward(params))...}); } void format_with(FunctionRef append, StringView fmt, ArrayView params); template void format_with(FunctionRef append, StringView fmt, Types&&... params) { return format_with(append, fmt, ArrayView{detail::format_param(std::forward(params))...}); } String double_up(StringView s, StringView characters); inline String quote(StringView s) { return format("'{}'", double_up(s, "'")); } inline String shell_quote(StringView s) { return format("'{}'", replace(s, "'", R"('\'')")); } enum class Quoting { Raw, Kakoune, Shell }; constexpr auto enum_desc(Meta::Type) { return make_array>({ { Quoting::Raw, "raw" }, { Quoting::Kakoune, "kakoune" }, { Quoting::Shell, "shell" } }); } inline auto quoter(Quoting quoting) { switch (quoting) { case Quoting::Kakoune: return "e; case Quoting::Shell: return &shell_quote; case Quoting::Raw: default: return +[](StringView s) { return s.str(); }; } } inline String option_to_string(StringView opt, Quoting quoting) { return quoter(quoting)(opt); } inline Vector option_to_strings(StringView opt) { return {opt.str()}; } inline String option_from_string(Meta::Type, StringView str) { return str.str(); } inline bool option_add(String& opt, StringView val) { opt += val; return not val.empty(); } } #endif // string_utils_hh_INCLUDED