Refactor String, use a common StringOps interface, hide std::string

This commit is contained in:
Maxime Coste 2015-03-10 19:33:46 +00:00
parent a0cf75ec39
commit 3c1a325b6f
24 changed files with 236 additions and 257 deletions

View File

@ -53,7 +53,7 @@ Buffer* create_buffer_from_data(StringView data, StringView name,
const char* pos = data.begin(); const char* pos = data.begin();
if (data.length() >= 3 and if (data.length() >= 3 and
data[0] == '\xEF' and data[1] == '\xBB' and data[2] == '\xBF') data[0_byte] == '\xEF' and data[1_byte] == '\xBB' and data[2_byte] == '\xBF')
{ {
bom = true; bom = true;
pos = data.begin() + 3; pos = data.begin() + 3;
@ -81,7 +81,7 @@ Buffer* create_buffer_from_data(StringView data, StringView name,
if (buffer) if (buffer)
buffer->reload(std::move(lines), fs_timestamp); buffer->reload(std::move(lines), fs_timestamp);
else else
buffer = new Buffer{name, flags, std::move(lines), fs_timestamp}; buffer = new Buffer{name.str(), flags, std::move(lines), fs_timestamp};
OptionManager& options = buffer->options(); OptionManager& options = buffer->options();
options.get_local_option("eolformat").set<String>(crlf ? "crlf" : "lf"); options.get_local_option("eolformat").set<String>(crlf ? "crlf" : "lf");

View File

@ -257,6 +257,11 @@ StringView Client::get_env_var(const String& name) const
return it->second; return it->second;
} }
StringView Client::get_env_var(StringView name) const
{
return get_env_var(name.str());
}
void Client::on_option_changed(const Option& option) void Client::on_option_changed(const Option& option)
{ {
if (option.name() == "ui_options") if (option.name() == "ui_options")

View File

@ -51,6 +51,7 @@ public:
void change_buffer(Buffer& buffer); void change_buffer(Buffer& buffer);
StringView get_env_var(const String& name) const; StringView get_env_var(const String& name) const;
StringView get_env_var(StringView name) const;
private: private:
void on_option_changed(const Option& option) override; void on_option_changed(const Option& option) override;

View File

@ -119,7 +119,7 @@ String get_until_delimiter(StringView base, ByteCount& pos,
} }
++pos; ++pos;
} }
return base.substr(start, pos - start); return base.substr(start, pos - start).str();
} }
struct unknown_expand : parse_error struct unknown_expand : parse_error
@ -313,7 +313,7 @@ String eval_token(const Token& token, Context& context,
return ShellManager::instance().eval(content, context, shell_params, return ShellManager::instance().eval(content, context, shell_params,
env_vars); env_vars);
case Token::Type::RegisterExpand: case Token::Type::RegisterExpand:
return context.main_sel_register_value(content); return context.main_sel_register_value(content).str();
case Token::Type::OptionExpand: case Token::Type::OptionExpand:
return context.options()[content].get_as_string(); return context.options()[content].get_as_string();
case Token::Type::ValExpand: case Token::Type::ValExpand:

View File

@ -47,7 +47,7 @@ Buffer* open_fifo(StringView name, StringView filename, bool scroll)
if (fd < 0) if (fd < 0)
throw runtime_error("unable to open " + filename); throw runtime_error("unable to open " + filename);
return create_fifo_buffer(name, fd, scroll); return create_fifo_buffer(name.str(), fd, scroll);
} }
const PerArgumentCommandCompleter filename_completer({ const PerArgumentCommandCompleter filename_completer({
@ -69,9 +69,9 @@ static CandidateList complete_buffer_name(StringView prefix, ByteCount cursor_po
StringView match_name = name; StringView match_name = name;
if (not include_dirs and buffer->flags() & Buffer::Flags::File) if (not include_dirs and buffer->flags() & Buffer::Flags::File)
{ {
ByteCount pos = name.find_last_of('/'); auto it = find(reversed(name), '/');
if (pos != (int)String::npos) if (it != name.rend())
match_name = name.substr(pos+1); match_name = StringView{it.base() + 2, name.end()};
} }
if (prefix_match(match_name, prefix)) if (prefix_match(match_name, prefix))
prefix_result.push_back(name); prefix_result.push_back(name);
@ -434,7 +434,7 @@ const CommandDesc namebuf_cmd = {
Completions complete_highlighter(const Context& context, Completions complete_highlighter(const Context& context,
StringView arg, ByteCount pos_in_token, bool only_group) StringView arg, ByteCount pos_in_token, bool only_group)
{ {
const bool shared = not arg.empty() and arg[0] == '/'; const bool shared = not arg.empty() and arg[0_byte] == '/';
if (shared) if (shared)
{ {
auto& group = DefinedHighlighters::instance(); auto& group = DefinedHighlighters::instance();
@ -480,7 +480,7 @@ Highlighter& get_highlighter(const Context& context, StringView path)
throw runtime_error("group path should not be empty"); throw runtime_error("group path should not be empty");
Highlighter* root = nullptr; Highlighter* root = nullptr;
if (path[0] == '/') if (path[0_byte] == '/')
{ {
root = &DefinedHighlighters::instance(); root = &DefinedHighlighters::instance();
path = path.substr(1_byte); path = path.substr(1_byte);
@ -603,12 +603,12 @@ const CommandDesc add_hook_cmd = {
if (regex_match(param.begin(), param.end(), regex)) if (regex_match(param.begin(), param.end(), regex))
CommandManager::instance().execute(command, context, {}, CommandManager::instance().execute(command, context, {},
{ { "hook_param", param } }); { { "hook_param", param.str() } });
}; };
StringView group; StringView group;
if (parser.has_option("group")) if (parser.has_option("group"))
group = parser.option_value("group"); group = parser.option_value("group");
get_scope(parser[0], context).hooks().add_hook(parser[1], group, hook_func); get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), hook_func);
} }
}; };
@ -866,7 +866,7 @@ const CommandDesc debug_cmd = {
{ {
size_t count = domain_allocated_bytes[domain]; size_t count = domain_allocated_bytes[domain];
total += count; total += count;
write_debug(" "_sv + domain_name((MemoryDomain)domain) + ": " + to_string(count)); write_debug(" "_str + domain_name((MemoryDomain)domain) + ": " + to_string(count));
} }
write_debug(" Total: " + to_string(total)); write_debug(" Total: " + to_string(total));
#if defined(__GLIBC__) || defined(__CYGWIN__) #if defined(__GLIBC__) || defined(__CYGWIN__)
@ -1254,7 +1254,7 @@ const CommandDesc prompt_cmd = {
{ {
if (params[1].length() != 1) if (params[1].length() != 1)
throw runtime_error("register name should be a single character"); throw runtime_error("register name should be a single character");
const char reg = params[1][0]; const char reg = params[1][0_byte];
const String& command = params[2]; const String& command = params[2];
String initstr; String initstr;
@ -1267,7 +1267,7 @@ const CommandDesc prompt_cmd = {
{ {
if (event != PromptEvent::Validate) if (event != PromptEvent::Validate)
return; return;
RegisterManager::instance()[reg] = ConstArrayView<String>(str); RegisterManager::instance()[reg] = ConstArrayView<String>(str.str());
CommandManager::instance().execute(command, context); CommandManager::instance().execute(command, context);
}); });
@ -1344,12 +1344,11 @@ const CommandDesc info_cmd = {
if (parser.has_option("anchor")) if (parser.has_option("anchor"))
{ {
auto anchor = parser.option_value("anchor"); auto anchor = parser.option_value("anchor");
size_t dot = anchor.find_first_of('.'); auto dot = find(anchor, '.');
if (dot == String::npos) if (dot == anchor.end())
throw runtime_error("expected <line>.<column> for anchor"); throw runtime_error("expected <line>.<column> for anchor");
ByteCount dotb = (int)dot; ByteCoord coord{str_to_int({anchor.begin(), dot})-1,
ByteCoord coord{str_to_int(anchor.substr(0, dotb))-1, str_to_int({dot+1, anchor.end()})-1};
str_to_int(anchor.substr(dotb+1))-1};
pos = context.window().display_position(coord); pos = context.window().display_position(coord);
style = InfoStyle::Inline; style = InfoStyle::Inline;
if (parser.has_option("placement")) if (parser.has_option("placement"))

View File

@ -49,7 +49,7 @@ void DisplayAtom::trim_begin(CharCount count)
m_begin = utf8::advance(m_buffer->iterator_at(m_begin), m_begin = utf8::advance(m_buffer->iterator_at(m_begin),
m_buffer->iterator_at(m_end), count).coord(); m_buffer->iterator_at(m_end), count).coord();
else else
m_text = m_text.substr(count); m_text = m_text.substr(count).str();
check_invariant(); check_invariant();
} }
@ -59,7 +59,7 @@ void DisplayAtom::trim_end(CharCount count)
m_end = utf8::advance(m_buffer->iterator_at(m_end), m_end = utf8::advance(m_buffer->iterator_at(m_end),
m_buffer->iterator_at(m_begin), -count).coord(); m_buffer->iterator_at(m_begin), -count).coord();
else else
m_text = m_text.substr(0, m_text.char_length() - count); m_text = m_text.substr(0, m_text.char_length() - count).str();
check_invariant(); check_invariant();
} }

View File

@ -26,8 +26,8 @@ namespace Kakoune
String parse_filename(StringView filename) String parse_filename(StringView filename)
{ {
if (filename.length() >= 1 and filename[0] == '~' and if (filename.length() >= 1 and filename[0_byte] == '~' and
(filename.length() == 1 or filename[1] == '/')) (filename.length() == 1 or filename[1_byte] == '/'))
return parse_filename("$HOME"_str + filename.substr(1_byte)); return parse_filename("$HOME"_str + filename.substr(1_byte));
ByteCount pos = 0; ByteCount pos = 0;
@ -90,7 +90,7 @@ String real_path(StringView filename)
auto it = find(existing.rbegin(), existing.rend(), '/'); auto it = find(existing.rbegin(), existing.rend(), '/');
if (it == existing.rend()) if (it == existing.rend())
return filename; return filename.str();
existing = StringView{existing.begin(), it.base()-1}; existing = StringView{existing.begin(), it.base()-1};
non_existing = StringView{it.base(), filename.end()}; non_existing = StringView{it.base(), filename.end()};
@ -105,7 +105,7 @@ String compact_path(StringView filename)
getcwd(cwd, 1024); getcwd(cwd, 1024);
String real_cwd = real_path(cwd) + "/"; String real_cwd = real_path(cwd) + "/";
if (prefix_match(real_filename, real_cwd)) if (prefix_match(real_filename, real_cwd))
return real_filename.substr(real_cwd.length()); return real_filename.substr(real_cwd.length()).str();
const char* home = getenv("HOME"); const char* home = getenv("HOME");
if (home) if (home)
@ -258,14 +258,14 @@ void write_buffer_to_backup_file(Buffer& buffer)
String find_file(StringView filename, ConstArrayView<String> paths) String find_file(StringView filename, ConstArrayView<String> paths)
{ {
struct stat buf; struct stat buf;
if (filename.length() > 1 and filename[0] == '/') if (filename.length() > 1 and filename[0_byte] == '/')
{ {
if (stat(filename.zstr(), &buf) == 0 and S_ISREG(buf.st_mode)) if (stat(filename.zstr(), &buf) == 0 and S_ISREG(buf.st_mode))
return filename.str(); return filename.str();
return ""; return "";
} }
if (filename.length() > 2 and if (filename.length() > 2 and
filename[0] == '~' and filename[1] == '/') filename[0_byte] == '~' and filename[1_byte] == '/')
{ {
String candidate = getenv("HOME") + filename.substr(1_byte).str(); String candidate = getenv("HOME") + filename.substr(1_byte).str();
if (stat(candidate.c_str(), &buf) == 0 and S_ISREG(buf.st_mode)) if (stat(candidate.c_str(), &buf) == 0 and S_ISREG(buf.st_mode))
@ -386,7 +386,7 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
Vector<String> res; Vector<String> res;
for (auto dir : split(getenv("PATH"), ':')) for (auto dir : split(getenv("PATH"), ':'))
{ {
String dirname = dir; String dirname = dir.str();
if (not dirname.empty() and dirname.back() != '/') if (not dirname.empty() and dirname.back() != '/')
dirname += '/'; dirname += '/';

View File

@ -264,9 +264,9 @@ public:
if (not regex_match(it->begin(), it->end(), res, face_spec_ex)) if (not regex_match(it->begin(), it->end(), res, face_spec_ex))
throw runtime_error("wrong face spec: '" + *it + throw runtime_error("wrong face spec: '" + *it +
"' expected <capture>:<facespec>"); "' expected <capture>:<facespec>");
get_face(res[2].str()); // throw if wrong face spec get_face({res[2].first, res[2].second}); // throw if wrong face spec
int capture = str_to_int(res[1].str()); int capture = str_to_int({res[1].first, res[1].second});
faces.emplace_back(capture, res[2].str()); faces.emplace_back(capture, String{res[2].first, res[2].second});
} }
String id = "hlregex'" + params[0] + "'"; String id = "hlregex'" + params[0] + "'";
@ -711,7 +711,8 @@ void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuf
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "U+" << std::hex << cp; oss << "U+" << std::hex << cp;
String str = oss.str(); const auto& stdstr = oss.str();
String str{stdstr.begin(), stdstr.end()};
if (it.coord() != atom_it->begin()) if (it.coord() != atom_it->begin())
atom_it = ++line.split(atom_it, it.coord()); atom_it = ++line.split(atom_it, it.coord());
if (next.coord() < atom_it->end()) if (next.coord() < atom_it->end())

View File

@ -51,7 +51,7 @@ void HookManager::run_hook(StringView hook_name,
for (auto& hook : hook_list_it->second) for (auto& hook : hook_list_it->second)
{ {
if (not hook.first.empty() and not disabled_hooks.empty() and if (not hook.first.empty() and not disabled_hooks.empty() and
regex_match(hook.first, disabled_hooks)) regex_match(hook.first.begin(), hook.first.end(), disabled_hooks))
continue; continue;
try try

View File

@ -65,7 +65,7 @@ public:
if (it != m_content.end()) if (it != m_content.end())
return it->second; return it->second;
append({ id, Value{} }); append({ id.str(), Value{} });
return (m_content.end()-1)->second; return (m_content.end()-1)->second;
} }

View File

@ -154,7 +154,7 @@ public:
if (m_params.reg != '"') if (m_params.reg != '"')
{ {
atoms.push_back({ "; reg=", Face(Colors::Yellow) }); atoms.push_back({ "; reg=", Face(Colors::Yellow) });
atoms.push_back({ StringView(m_params.reg), Face(Colors::Green) }); atoms.push_back({ StringView(m_params.reg).str(), Face(Colors::Green) });
} }
return atoms; return atoms;
} }
@ -325,12 +325,12 @@ public:
m_display_pos = m_cursor_pos + 1 - width; m_display_pos = m_cursor_pos + 1 - width;
if (m_cursor_pos == m_line.char_length()) if (m_cursor_pos == m_line.char_length())
return DisplayLine{{ {m_line.substr(m_display_pos, width-1), get_face("StatusLine")}, return DisplayLine{{ {m_line.substr(m_display_pos, width-1).str(), get_face("StatusLine")},
{" "_str, get_face("StatusCursor")} }}; {" "_str, get_face("StatusCursor")} }};
else else
return DisplayLine({ { m_line.substr(m_display_pos, m_cursor_pos - m_display_pos), get_face("StatusLine") }, return DisplayLine({ { m_line.substr(m_display_pos, m_cursor_pos - m_display_pos).str(), get_face("StatusLine") },
{ m_line.substr(m_cursor_pos,1), get_face("StatusCursor") }, { m_line.substr(m_cursor_pos,1).str(), get_face("StatusCursor") },
{ m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1), get_face("StatusLine") } }); { m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1).str(), get_face("StatusLine") } });
} }
private: private:
CharCount m_cursor_pos = 0; CharCount m_cursor_pos = 0;
@ -473,7 +473,7 @@ String common_prefix(ConstArrayView<String> strings)
while (common_len < len and str[common_len] == res[common_len]) while (common_len < len and str[common_len] == res[common_len])
++common_len; ++common_len;
if (common_len != res.length()) if (common_len != res.length())
res = res.substr(0, common_len); res = res.substr(0, common_len).str();
} }
return res; return res;
} }
@ -484,7 +484,7 @@ public:
Prompt(InputHandler& input_handler, StringView prompt, Prompt(InputHandler& input_handler, StringView prompt,
String initstr, Face face, Completer completer, String initstr, Face face, Completer completer,
PromptCallback callback) PromptCallback callback)
: InputMode(input_handler), m_prompt(prompt), m_prompt_face(face), : InputMode(input_handler), m_prompt(prompt.str()), m_prompt_face(face),
m_completer(completer), m_callback(callback), m_completer(completer), m_callback(callback),
m_autoshowcompl{context().options()["autoshowcompl"].get<bool>()} m_autoshowcompl{context().options()["autoshowcompl"].get<bool>()}
{ {
@ -600,7 +600,7 @@ public:
String prefix = common_prefix(candidates); String prefix = common_prefix(candidates);
if (m_completions.end - m_completions.start > prefix.length()) if (m_completions.end - m_completions.start > prefix.length())
prefix = line.substr(m_completions.start, prefix = line.substr(m_completions.start,
m_completions.end - m_completions.start); m_completions.end - m_completions.start).str();
if (not prefix.empty()) if (not prefix.empty())
{ {
@ -742,7 +742,7 @@ private:
History::iterator it; History::iterator it;
while ((it = find(history, entry)) != history.end()) while ((it = find(history, entry)) != history.end())
history.erase(it); history.erase(it);
history.push_back(entry); history.push_back(entry.str());
} }
}; };
UnorderedMap<String, Prompt::History, MemoryDomain::History> Prompt::ms_history; UnorderedMap<String, Prompt::History, MemoryDomain::History> Prompt::ms_history;

View File

@ -119,7 +119,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
ComplAndDescList result; ComplAndDescList result;
result.reserve(matches.size()); result.reserve(matches.size());
for (auto& m : matches) for (auto& m : matches)
result.emplace_back(m, ""); result.emplace_back(m.str(), "");
return { begin.coord(), cursor_pos, std::move(result), buffer.timestamp() }; return { begin.coord(), cursor_pos, std::move(result), buffer.timestamp() };
} }
@ -158,7 +158,7 @@ InsertCompletion complete_filename(const Buffer& buffer, ByteCoord cursor_pos,
if (not dir.empty() and dir.back() != '/') if (not dir.empty() and dir.back() != '/')
dir += '/'; dir += '/';
for (auto& filename : Kakoune::complete_filename(dir + prefix, Regex{})) for (auto& filename : Kakoune::complete_filename(dir + prefix, Regex{}))
res.emplace_back(filename.substr(dir.length()), ""); res.emplace_back(filename.substr(dir.length()).str(), "");
} }
} }
if (res.empty()) if (res.empty())
@ -178,16 +178,17 @@ InsertCompletion complete_option(const Buffer& buffer, ByteCoord cursor_pos,
MatchResults<String::const_iterator> match; MatchResults<String::const_iterator> match;
if (regex_match(desc.begin(), desc.end(), match, re)) if (regex_match(desc.begin(), desc.end(), match, re))
{ {
ByteCoord coord{ str_to_int(match[1].str()) - 1, str_to_int(match[2].str()) - 1 }; ByteCoord coord{ str_to_int({match[1].first, match[1].second}) - 1,
str_to_int({match[2].first, match[2].second}) - 1 };
if (not buffer.is_valid(coord)) if (not buffer.is_valid(coord))
return {}; return {};
auto end = coord; auto end = coord;
if (match[3].matched) if (match[3].matched)
{ {
ByteCount len = str_to_int(match[3].str()); ByteCount len = str_to_int({match[3].first, match[3].second});
end = buffer.advance(coord, len); end = buffer.advance(coord, len);
} }
size_t timestamp = (size_t)str_to_int(match[4].str()); size_t timestamp = (size_t)str_to_int({match[4].first, match[4].second});
auto changes = buffer.changes_since(timestamp); auto changes = buffer.changes_since(timestamp);
if (find_if(changes, [&](const Buffer::Change& change){ if (find_if(changes, [&](const Buffer::Change& change){
return change.begin < coord; return change.begin < coord;
@ -204,7 +205,7 @@ InsertCompletion complete_option(const Buffer& buffer, ByteCoord cursor_pos,
{ {
auto splitted = split(*it, '@'); auto splitted = split(*it, '@');
if (not splitted.empty() and prefix_match(splitted[0], prefix)) if (not splitted.empty() and prefix_match(splitted[0], prefix))
res.emplace_back(splitted[0], splitted.size() > 1 ? splitted[1] : ""); res.emplace_back(splitted[0].str(), splitted.size() > 1 ? splitted[1].str() : "");
} }
return { coord, end, std::move(res), timestamp }; return { coord, end, std::move(res), timestamp };
} }
@ -222,7 +223,7 @@ InsertCompletion complete_line(const Buffer& buffer, ByteCoord cursor_pos)
continue; continue;
ByteCount len = buffer[l].length(); ByteCount len = buffer[l].length();
if (len > cursor_pos.column and std::equal(prefix.begin(), prefix.end(), buffer[l].begin())) if (len > cursor_pos.column and std::equal(prefix.begin(), prefix.end(), buffer[l].begin()))
res.emplace_back(buffer[l].substr(0_byte, len-1), ""); res.emplace_back(buffer[l].substr(0_byte, len-1).str(), "");
} }
if (res.empty()) if (res.empty())
return {}; return {};

View File

@ -64,9 +64,9 @@ KeyList parse_keys(StringView str)
Key::Modifiers modifier = Key::Modifiers::None; Key::Modifiers modifier = Key::Modifiers::None;
StringView desc{it.base()+1, end_it.base()}; StringView desc{it.base()+1, end_it.base()};
if (desc.length() > 2 and desc[1] == '-') if (desc.length() > 2 and desc[1_byte] == '-')
{ {
switch(tolower(desc[0])) switch(tolower(desc[0_byte]))
{ {
case 'c': modifier = Key::Modifiers::Control; break; case 'c': modifier = Key::Modifiers::Control; break;
case 'a': modifier = Key::Modifiers::Alt; break; case 'a': modifier = Key::Modifiers::Alt; break;
@ -82,7 +82,7 @@ KeyList parse_keys(StringView str)
result.push_back(canonicalize_ifn({ modifier, name_it->key })); result.push_back(canonicalize_ifn({ modifier, name_it->key }));
else if (desc.char_length() == 1) else if (desc.char_length() == 1)
result.push_back(Key{ modifier, desc[0_char] }); result.push_back(Key{ modifier, desc[0_char] });
else if (tolower(desc[0]) == 'f' and desc.length() <= 3) else if (tolower(desc[0_byte]) == 'f' and desc.length() <= 3)
{ {
int val = str_to_int(desc.substr(1_byte)); int val = str_to_int(desc.substr(1_byte));
if (val >= 1 and val <= 12) if (val >= 1 and val <= 12)

View File

@ -37,10 +37,10 @@ void run_unit_tests();
String runtime_directory() String runtime_directory()
{ {
String bin_path = get_kak_binary_path(); String bin_path = get_kak_binary_path();
size_t last_slash = bin_path.find_last_of('/'); auto it = find(reversed(bin_path), '/');
if (last_slash == String::npos) if (it == bin_path.rend())
throw runtime_error("unable to determine runtime directory"); throw runtime_error("unable to determine runtime directory");
return bin_path.substr(0_byte, (int)last_slash) + "/../share/kak"; return StringView{bin_path.begin(), it.base()-1} + "/../share/kak";
} }
void register_env_vars() void register_env_vars()
@ -54,7 +54,7 @@ void register_env_vars()
{ return context.buffer().display_name(); } { return context.buffer().display_name(); }
}, { }, {
"buffile", "buffile",
[](StringView name, const Context& context) -> String [](StringView name, const Context& context)
{ return context.buffer().name(); } { return context.buffer().name(); }
}, { }, {
"buflist", "buflist",
@ -85,19 +85,19 @@ void register_env_vars()
{ return context.options()[name.substr(4_byte)].get_as_string(); } { return context.options()[name.substr(4_byte)].get_as_string(); }
}, { }, {
"reg_.+", "reg_.+",
[](StringView name, const Context& context) -> String [](StringView name, const Context& context)
{ return context.main_sel_register_value(name.substr(4_byte)); } { return context.main_sel_register_value(name.substr(4_byte)).str(); }
}, { }, {
"client_env_.+", "client_env_.+",
[](StringView name, const Context& context) -> String [](StringView name, const Context& context)
{ return context.client().get_env_var(name.substr(11_byte)); } { return context.client().get_env_var(name.substr(11_byte)).str(); }
}, { }, {
"session", "session",
[](StringView name, const Context& context) -> String [](StringView name, const Context& context)
{ return Server::instance().session(); } { return Server::instance().session(); }
}, { }, {
"client", "client",
[](StringView name, const Context& context) -> String [](StringView name, const Context& context)
{ return context.name(); } { return context.name(); }
}, { }, {
"cursor_line", "cursor_line",
@ -356,7 +356,7 @@ int run_server(StringView session, StringView init_command,
write_debug("*** This is the debug buffer, where debug info will be written ***"); write_debug("*** This is the debug buffer, where debug info will be written ***");
Server server(session.empty() ? to_string(getpid()) : String{session}); Server server(session.empty() ? to_string(getpid()) : session.str());
if (not ignore_kakrc) try if (not ignore_kakrc) try
{ {
@ -385,7 +385,7 @@ int run_server(StringView session, StringView init_command,
for (auto& file : reversed(files)) for (auto& file : reversed(files))
{ {
if (not create_buffer_from_file(file)) if (not create_buffer_from_file(file))
new Buffer(file, Buffer::Flags::New | Buffer::Flags::File); new Buffer(file.str(), Buffer::Flags::New | Buffer::Flags::File);
} }
} }
catch (Kakoune::runtime_error& error) catch (Kakoune::runtime_error& error)

View File

@ -591,7 +591,7 @@ void NCursesUI::menu_show(ConstArrayView<String> items,
const CharCount maxlen = min((int)maxsize.column-2, 200); const CharCount maxlen = min((int)maxsize.column-2, 200);
for (auto& item : items) for (auto& item : items)
{ {
m_items.push_back(item.substr(0_char, maxlen)); m_items.push_back(item.substr(0_char, maxlen).str());
longest = max(longest, m_items.back().char_length()); longest = max(longest, m_items.back().char_length());
} }
longest += 1; longest += 1;

View File

@ -375,7 +375,7 @@ void pipe(Context& context, NormalParams)
real_cmd = context.main_sel_register_value("|"); real_cmd = context.main_sel_register_value("|");
else else
{ {
RegisterManager::instance()['|'] = String{cmdline}; RegisterManager::instance()['|'] = cmdline.str();
real_cmd = cmdline; real_cmd = cmdline;
} }
@ -397,7 +397,7 @@ void pipe(Context& context, NormalParams)
{}, EnvVarMap{}); {}, EnvVarMap{});
if ((insert_eol or sel.max() == buffer.back_coord()) and if ((insert_eol or sel.max() == buffer.back_coord()) and
str.back() == '\n') str.back() == '\n')
str = str.substr(0, str.length()-1); str = str.substr(0, str.length()-1).str();
strings.push_back(std::move(str)); strings.push_back(std::move(str));
} }
ScopedEdition edition(context); ScopedEdition edition(context);
@ -428,7 +428,7 @@ void insert_output(Context& context, NormalParams)
real_cmd = context.main_sel_register_value("|"); real_cmd = context.main_sel_register_value("|");
else else
{ {
RegisterManager::instance()['|'] = String{cmdline}; RegisterManager::instance()['|'] = cmdline.str();
real_cmd = cmdline; real_cmd = cmdline;
} }
@ -617,7 +617,7 @@ void search(Context& context, NormalParams)
if (ex.empty()) if (ex.empty())
ex = Regex{context.main_sel_register_value("/").str()}; ex = Regex{context.main_sel_register_value("/").str()};
else if (event == PromptEvent::Validate) else if (event == PromptEvent::Validate)
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = ex.str();
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
select_next_match<direction, mode>(context.buffer(), context.selections(), ex); select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
}); });
@ -674,7 +674,7 @@ void select_regex(Context& context, NormalParams)
if (ex.empty()) if (ex.empty())
ex = Regex{context.main_sel_register_value("/").str()}; ex = Regex{context.main_sel_register_value("/").str()};
else if (event == PromptEvent::Validate) else if (event == PromptEvent::Validate)
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = ex.str();
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
select_all_matches(context.selections(), ex); select_all_matches(context.selections(), ex);
}); });
@ -686,7 +686,7 @@ void split_regex(Context& context, NormalParams)
if (ex.empty()) if (ex.empty())
ex = Regex{context.main_sel_register_value("/").str()}; ex = Regex{context.main_sel_register_value("/").str()};
else if (event == PromptEvent::Validate) else if (event == PromptEvent::Validate)
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = ex.str();
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
split_selections(context.selections(), ex); split_selections(context.selections(), ex);
}); });

View File

@ -14,8 +14,8 @@
namespace Kakoune namespace Kakoune
{ {
inline String option_to_string(StringView opt) { return opt; } inline String option_to_string(StringView opt) { return opt.str(); }
inline void option_from_string(StringView str, String& opt) { opt = str; } inline void option_from_string(StringView str, String& opt) { opt = str.str(); }
inline String option_to_string(int opt) { return to_string(opt); } inline String option_to_string(int opt) { return to_string(opt); }
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); } inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }

View File

@ -21,7 +21,7 @@ ParametersParser::ParametersParser(ParameterList params,
{ {
if (not only_pos and params[i] == "--") if (not only_pos and params[i] == "--")
only_pos = true; only_pos = true;
else if (not only_pos and params[i][0] == '-') else if (not only_pos and params[i][0_byte] == '-')
{ {
auto it = m_desc.switches.find(params[i].substr(1_byte)); auto it = m_desc.switches.find(params[i].substr(1_byte));
if (it == m_desc.switches.end()) if (it == m_desc.switches.end())
@ -30,7 +30,7 @@ ParametersParser::ParametersParser(ParameterList params,
if (it->second.takes_arg) if (it->second.takes_arg)
{ {
++i; ++i;
if (i == params.size() or params[i][0] == '-') if (i == params.size() or params[i][0_byte] == '-')
throw missing_option_value(it->first); throw missing_option_value(it->first);
} }
} }
@ -51,7 +51,7 @@ bool ParametersParser::has_option(const String& name) const
kak_assert(m_desc.switches.find(name) != m_desc.switches.end()); kak_assert(m_desc.switches.find(name) != m_desc.switches.end());
for (auto& param : m_params) for (auto& param : m_params)
{ {
if (param[0] == '-' and param.substr(1_byte) == name) if (param[0_byte] == '-' and param.substr(1_byte) == name)
return true; return true;
if (param == "--") if (param == "--")
@ -70,7 +70,7 @@ const String& ParametersParser::option_value(const String& name) const
for (size_t i = 0; i < m_params.size(); ++i) for (size_t i = 0; i < m_params.size(); ++i)
{ {
if (m_params[i][0] == '-' and m_params[i].substr(1_byte) == name) if (m_params[i][0_byte] == '-' and m_params[i].substr(1_byte) == name)
return m_params[i+1]; return m_params[i+1];
if (m_params[i] == "--") if (m_params[i] == "--")

View File

@ -7,7 +7,8 @@ namespace Kakoune
String option_to_string(const Regex& re) String option_to_string(const Regex& re)
{ {
return String{re.str()}; const auto& str = re.str();
return String{str.begin(), str.end()};
} }
void option_from_string(StringView str, Regex& re) void option_from_string(StringView str, Regex& re)

View File

@ -29,15 +29,27 @@ struct Regex : std::regex
bool operator==(const Regex& other) { return m_str == other.m_str; } bool operator==(const Regex& other) { return m_str == other.m_str; }
bool operator!=(const Regex& other) { return m_str != other.m_str; } bool operator!=(const Regex& other) { return m_str != other.m_str; }
StringView str() const { return m_str; } const String& str() const { return m_str; }
private: private:
String m_str; String m_str;
}; };
namespace regex_ns = std; namespace regex_ns = std;
#else #else
struct Regex : boost::regex
{
Regex() = default;
explicit Regex(StringView re, flag_type flags = ECMAScript)
: boost::regex(re.begin(), re.end(), flags) {}
template<typename Iterator>
Regex(Iterator begin, Iterator end, flag_type flags = ECMAScript)
: boost::regex(begin, end, flags) {}
String str() const { auto s = boost::regex::str(); return {s.begin(), s.end()}; }
};
namespace regex_ns = boost; namespace regex_ns = boost;
using Regex = boost::regex;
#endif #endif
template<typename Iterator> template<typename Iterator>

View File

@ -59,7 +59,7 @@ private:
Register& RegisterManager::operator[](StringView reg) Register& RegisterManager::operator[](StringView reg)
{ {
if (reg.length() == 1) if (reg.length() == 1)
return (*this)[reg[0]]; return (*this)[reg[0_byte]];
static const IdMap<Codepoint> reg_names = { static const IdMap<Codepoint> reg_names = {
{ "slash", '/' }, { "slash", '/' },

View File

@ -23,7 +23,7 @@ ShellManager::ShellManager()
new_path = path + ":"_str; new_path = path + ":"_str;
String kak_path = get_kak_binary_path(); String kak_path = get_kak_binary_path();
StringView kak_dir = kak_path.substr(0_byte, (int)kak_path.find_last_of('/')); StringView kak_dir{kak_path.begin(), find(reversed(kak_path), '/').base()-1};
new_path += kak_dir; new_path += kak_dir;
setenv("PATH", new_path.c_str(), 1); setenv("PATH", new_path.c_str(), 1);
} }
@ -111,7 +111,7 @@ String ShellManager::pipe(StringView input,
StringView name = StringView(match[1].first, match[1].second); StringView name = StringView(match[1].first, match[1].second);
kak_assert(name.length() > 0); kak_assert(name.length() > 0);
auto local_var = env_vars.find(name); auto local_var = env_vars.find(name.str());
if (local_var != env_vars.end()) if (local_var != env_vars.end())
setenv(("kak_" + name).c_str(), local_var->second.c_str(), 1); setenv(("kak_" + name).c_str(), local_var->second.c_str(), 1);
else else

View File

@ -9,11 +9,6 @@
namespace Kakoune namespace Kakoune
{ {
bool operator<(StringView lhs, StringView rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
Vector<String> split(StringView str, char separator, char escape) Vector<String> split(StringView str, char separator, char escape)
{ {
Vector<String> res; Vector<String> res;

View File

@ -14,56 +14,133 @@ namespace Kakoune
class StringView; class StringView;
using StringBase = std::basic_string<char, std::char_traits<char>, template<typename Type, typename CharType>
Allocator<char, MemoryDomain::String>>; class StringOps
constexpr ByteCount strlen(const char* s)
{
return *s == 0 ? 0 : strlen(s+1) + 1;
}
class String : public StringBase
{ {
public: public:
using value_type = CharType;
friend bool operator==(const Type& lhs, const Type& rhs)
{
return lhs.length() == rhs.length() and
std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
friend bool operator!=(const Type& lhs, const Type& rhs)
{
return lhs.length() != rhs.length() or
not std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
friend bool operator<(const Type& lhs, const Type& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end());
}
friend inline size_t hash_value(const Type& str)
{
return hash_data(str.data(), (int)str.length());
}
using iterator = CharType*;
using const_iterator = const CharType*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
[[gnu::always_inline]]
iterator begin() { return type().data(); }
[[gnu::always_inline]]
const_iterator begin() const { return type().data(); }
[[gnu::always_inline]]
iterator end() { return type().data() + (int)type().length(); }
[[gnu::always_inline]]
const_iterator end() const { return type().data() + (int)type().length(); }
reverse_iterator rbegin() { return reverse_iterator{end()}; }
const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; }
reverse_iterator rend() { return reverse_iterator{begin()}; }
const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; }
CharType& front() { return *type().data(); }
const CharType& front() const { return *type().data(); }
CharType& back() { return type().data()[(int)type().length() - 1]; }
const CharType& back() const { return type().data()[(int)type().length() - 1]; }
[[gnu::always_inline]]
CharType& operator[](ByteCount pos) { return type().data()[(int)pos]; }
[[gnu::always_inline]]
const CharType& operator[](ByteCount pos) const
{ return type().data()[(int)pos]; }
Codepoint operator[](CharCount pos) const
{ return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }
CharCount char_length() const { return utf8::distance(begin(), end()); }
[[gnu::always_inline]]
bool empty() const { return type().length() == 0_byte; }
ByteCount byte_count_to(CharCount count) const
{ return utf8::advance(begin(), end(), (int)count) - begin(); }
CharCount char_count_to(ByteCount count) const
{ return utf8::distance(begin(), begin() + (int)count); }
StringView substr(ByteCount from, ByteCount length = INT_MAX) const;
StringView substr(CharCount from, CharCount length = INT_MAX) const;
private:
Type& type() { return *static_cast<Type*>(this); }
const Type& type() const { return *static_cast<const Type*>(this); }
};
class String : public StringOps<String, char>
{
public:
using Content = std::basic_string<char, std::char_traits<char>,
Allocator<char, MemoryDomain::String>>;
String() {} String() {}
String(const char* content) : StringBase(content) {} String(const char* content) : m_data(content) {}
String(StringBase content) : StringBase(std::move(content)) {} String(Content content) : m_data(std::move(content)) {}
template<typename Char, typename Traits, typename Alloc> explicit String(char content, CharCount count = 1) : m_data((size_t)(int)count, content) {}
String(const std::basic_string<Char, Traits, Alloc>& content) : StringBase(content.begin(), content.end()) {}
explicit String(char content, CharCount count = 1) : StringBase((size_t)(int)count, content) {}
explicit String(Codepoint cp, CharCount count = 1) explicit String(Codepoint cp, CharCount count = 1)
{ {
while (count-- > 0) while (count-- > 0)
utf8::dump(back_inserter(*this), cp); utf8::dump(std::back_inserter(*this), cp);
} }
template<typename Iterator> template<typename Iterator>
String(Iterator begin, Iterator end) : StringBase(begin, end) {} String(Iterator begin, Iterator end) : m_data(begin, end) {}
StringBase& stdstr() { return *this; }
const StringBase& stdstr() const { return *this; }
[[gnu::always_inline]] [[gnu::always_inline]]
char operator[](ByteCount pos) const { return StringBase::operator[]((int)pos); } char* data() { return &m_data[0]; }
[[gnu::always_inline]]
char& operator[](ByteCount pos) { return StringBase::operator[]((int)pos); }
Codepoint operator[](CharCount pos) { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }
[[gnu::always_inline]] [[gnu::always_inline]]
ByteCount length() const { return ByteCount{(int)StringBase::length()}; } const char* data() const { return m_data.data(); }
CharCount char_length() const { return utf8::distance(begin(), end()); }
ByteCount byte_count_to(CharCount count) const { return utf8::advance(begin(), end(), (int)count) - begin(); }
CharCount char_count_to(ByteCount count) const { return utf8::distance(begin(), begin() + (int)count); }
String& operator+=(const String& other) { StringBase::operator+=(other); return *this; } [[gnu::always_inline]]
String& operator+=(const char* other) { StringBase::operator+=(other); return *this; } ByteCount length() const { return ByteCount{(int)m_data.length()}; }
String& operator+=(char other) { StringBase::operator+=(other); return *this; }
String& operator+=(Codepoint cp) { utf8::dump(back_inserter(*this), cp); return *this; }
StringView substr(ByteCount pos, ByteCount length = INT_MAX) const; [[gnu::always_inline]]
StringView substr(CharCount pos, CharCount length = INT_MAX) const; const char* c_str() const { return m_data.c_str(); }
void append(const char* data, ByteCount count) { m_data.append(data, (size_t)(int)count); }
void push_back(char c) { m_data.push_back(c); }
void resize(ByteCount size) { m_data.resize((size_t)(int)size); }
void reserve(ByteCount size) { m_data.reserve((size_t)(int)size); }
private:
Content m_data;
}; };
class StringView class StringView : public StringOps<StringView, const char>
{ {
public: public:
constexpr StringView() : m_data{nullptr}, m_length{0} {} constexpr StringView() : m_data{nullptr}, m_length{0} {}
@ -71,50 +148,17 @@ public:
: m_data{data}, m_length{length} {} : m_data{data}, m_length{length} {}
constexpr StringView(const char* data) : m_data{data}, m_length{strlen(data)} {} constexpr StringView(const char* data) : m_data{data}, m_length{strlen(data)} {}
constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {} constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {}
template<typename Char, typename Traits, typename Alloc> StringView(const String& str) : m_data{str.data()}, m_length{(int)str.length()} {}
StringView(const std::basic_string<Char, Traits, Alloc>& str) : m_data{str.data()}, m_length{(int)str.length()} {}
StringView(const char& c) : m_data(&c), m_length(1) {} StringView(const char& c) : m_data(&c), m_length(1) {}
friend bool operator==(StringView lhs, StringView rhs);
[[gnu::always_inline]] [[gnu::always_inline]]
const char* data() const { return m_data; } const char* data() const { return m_data; }
using iterator = const char*;
using reverse_iterator = std::reverse_iterator<const char*>;
[[gnu::always_inline]]
iterator begin() const { return m_data; }
[[gnu::always_inline]]
iterator end() const { return m_data + (int)m_length; }
reverse_iterator rbegin() const { return reverse_iterator{m_data + (int)m_length}; }
reverse_iterator rend() const { return reverse_iterator{m_data}; }
char front() const { return *m_data; }
char back() const { return m_data[(int)m_length - 1]; }
[[gnu::always_inline]]
char operator[](ByteCount pos) const { return m_data[(int)pos]; }
Codepoint operator[](CharCount pos) { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }
[[gnu::always_inline]] [[gnu::always_inline]]
ByteCount length() const { return m_length; } ByteCount length() const { return m_length; }
CharCount char_length() const { return utf8::distance(begin(), end()); }
[[gnu::always_inline]]
bool empty() { return m_length == 0_byte; }
ByteCount byte_count_to(CharCount count) const;
CharCount char_count_to(ByteCount count) const;
StringView substr(ByteCount from, ByteCount length = INT_MAX) const;
StringView substr(CharCount from, CharCount length = INT_MAX) const;
String str() const { return String{begin(), end()}; } String str() const { return String{begin(), end()}; }
operator String() const { return str(); } // to remove
struct ZeroTerminatedString struct ZeroTerminatedString
{ {
ZeroTerminatedString(const char* begin, const char* end) ZeroTerminatedString(const char* begin, const char* end)
@ -122,53 +166,37 @@ public:
if (*end == '\0') if (*end == '\0')
unowned = begin; unowned = begin;
else else
owned = StringBase(begin, end); owned = String::Content(begin, end);
} }
operator const char*() const { return unowned ? unowned : owned.c_str(); } operator const char*() const { return unowned ? unowned : owned.c_str(); }
private: private:
StringBase owned; String::Content owned;
const char* unowned = nullptr; const char* unowned = nullptr;
}; };
ZeroTerminatedString zstr() const { return ZeroTerminatedString{begin(), end()}; } ZeroTerminatedString zstr() const { return ZeroTerminatedString{begin(), end()}; }
private: private:
static constexpr ByteCount strlen(const char* s)
{
return *s == 0 ? 0 : strlen(s+1) + 1;
}
const char* m_data; const char* m_data;
ByteCount m_length; ByteCount m_length;
}; };
inline bool operator==(StringView lhs, StringView rhs) template<typename Type, typename CharType>
{ inline StringView StringOps<Type, CharType>::substr(ByteCount from, ByteCount length) const
return lhs.m_length == rhs.m_length and
std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
inline bool operator!=(StringView lhs, StringView rhs)
{
return not (lhs == rhs);
}
bool operator<(StringView lhs, StringView rhs);
inline ByteCount StringView::byte_count_to(CharCount count) const
{
return utf8::advance(begin(), end(), (int)count) - begin();
}
inline CharCount StringView::char_count_to(ByteCount count) const
{
return utf8::distance(begin(), begin() + (int)count);
}
inline StringView StringView::substr(ByteCount from, ByteCount length) const
{ {
if (length < 0) if (length < 0)
length = INT_MAX; length = INT_MAX;
return StringView{ m_data + (int)from, std::min(m_length - from, length) }; return StringView{ type().data() + (int)from, std::min(type().length() - from, length) };
} }
inline StringView StringView::substr(CharCount from, CharCount length) const template<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::substr(CharCount from, CharCount length) const
{ {
if (length < 0) if (length < 0)
length = INT_MAX; length = INT_MAX;
@ -176,70 +204,21 @@ inline StringView StringView::substr(CharCount from, CharCount length) const
return StringView{ beg, utf8::advance(beg, end(), length) }; return StringView{ beg, utf8::advance(beg, end(), length) };
} }
inline StringView String::substr(ByteCount pos, ByteCount length) const
{
return StringView{*this}.substr(pos, length);
}
inline StringView String::substr(CharCount pos, CharCount length) const
{
return StringView{*this}.substr(pos, length);
}
inline String& operator+=(String& lhs, StringView rhs) inline String& operator+=(String& lhs, StringView rhs)
{ {
lhs.append(rhs.data(), (size_t)(int)rhs.length()); lhs.append(rhs.data(), rhs.length());
return lhs; return lhs;
} }
inline String operator+(const String& lhs, const String& rhs)
{
String res = lhs;
res += rhs;
return res;
}
inline String operator+(StringView lhs, StringView rhs) inline String operator+(StringView lhs, StringView rhs)
{ {
String res{lhs.begin(), lhs.end()}; String res;
res.reserve((int)(lhs.length() + rhs.length()));
res += lhs;
res += rhs; res += rhs;
return res; return res;
} }
inline String operator+(const String& lhs, StringView rhs)
{
String res = lhs;
res += rhs;
return res;
}
inline String operator+(StringView lhs, const String& rhs)
{
String res{lhs.begin(), lhs.end()};
res.append(rhs);
return res;
}
inline String operator+(const char* lhs, StringView rhs)
{
return StringView{lhs} + rhs;
}
inline String operator+(StringView lhs, const char* rhs)
{
return lhs + StringView{rhs};
}
inline String operator+(const char* lhs, const String& rhs)
{
return StringView{lhs} + rhs;
}
inline String operator+(const String& lhs, const char* rhs)
{
return lhs + StringView{rhs};
}
Vector<String> split(StringView str, char separator, char escape); Vector<String> split(StringView str, char separator, char escape);
Vector<StringView> split(StringView str, char separator); Vector<StringView> split(StringView str, char separator);
@ -266,16 +245,11 @@ inline String operator"" _str(const char* str, size_t)
return String(str); return String(str);
} }
inline StringView operator"" _sv(const char* str, size_t len)
{
return StringView(str, (int)len);
}
inline String codepoint_to_str(Codepoint cp) inline String codepoint_to_str(Codepoint cp)
{ {
StringBase str; String str;
utf8::dump(back_inserter(str), cp); utf8::dump(std::back_inserter(str), cp);
return String(str); return str;
} }
int str_to_int(StringView str); int str_to_int(StringView str);
@ -301,16 +275,6 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0);
Vector<StringView> wrap_lines(StringView text, CharCount max_width); Vector<StringView> wrap_lines(StringView text, CharCount max_width);
inline size_t hash_value(const Kakoune::String& str)
{
return hash_data(str.data(), (int)str.length());
}
inline size_t hash_value(const Kakoune::StringView& str)
{
return hash_data(str.data(), (int)str.length());
}
} }
#endif // string_hh_INCLUDED #endif // string_hh_INCLUDED