summaryrefslogtreecommitdiff
path: root/src/string_utils.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/string_utils.hh')
-rw-r--r--src/string_utils.hh115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/string_utils.hh b/src/string_utils.hh
new file mode 100644
index 00000000..7263c6f6
--- /dev/null
+++ b/src/string_utils.hh
@@ -0,0 +1,115 @@
+#ifndef string_utils_hh_INCLUDED
+#define string_utils_hh_INCLUDED
+
+#include "string.hh"
+#include "vector.hh"
+#include "optional.hh"
+
+namespace Kakoune
+{
+
+Vector<String> split(StringView str, char separator, char escape);
+Vector<StringView> split(StringView str, char separator);
+
+StringView trim_whitespaces(StringView str);
+
+String escape(StringView str, StringView characters, char escape);
+String unescape(StringView str, StringView characters, char escape);
+
+String indent(StringView str, StringView indent = " ");
+
+String replace(StringView str, StringView substr, StringView replacement);
+
+template<typename Container>
+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;
+}
+
+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);
+
+Vector<StringView> wrap_lines(StringView text, ColumnCount max_width);
+
+int str_to_int(StringView str); // throws on error
+Optional<int> str_to_int_ifp(StringView str);
+
+inline String option_to_string(StringView opt) { return opt.str(); }
+inline void option_from_string(StringView str, String& opt) { opt = str.str(); }
+inline bool option_add(String& opt, StringView val) { opt += val; return not val.empty(); }
+
+template<size_t N>
+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<23> to_string(long int val);
+InplaceString<23> to_string(size_t 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<typename RealType, typename ValueType>
+decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
+{
+ return to_string((ValueType)val);
+}
+
+namespace detail
+{
+
+template<typename T> constexpr bool is_string = std::is_convertible<T, StringView>::value;
+
+template<typename T, class = std::enable_if_t<not is_string<T>>>
+decltype(auto) format_param(const T& val) { return to_string(val); }
+
+template<typename T, class = std::enable_if_t<is_string<T>>>
+StringView format_param(const T& val) { return val; }
+
+}
+
+String format(StringView fmt, ArrayView<const StringView> params);
+
+template<typename... Types>
+String format(StringView fmt, Types&&... params)
+{
+ return format(fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
+}
+
+StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params);
+
+template<typename... Types>
+StringView format_to(ArrayView<char> buffer, StringView fmt, Types&&... params)
+{
+ return format_to(buffer, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
+}
+
+}
+
+#endif // string_utils_hh_INCLUDED