Codechange: replace C-style (stredup) chat completion with std::string_view

This commit is contained in:
Rubidium 2023-05-13 08:58:24 +02:00 committed by rubidium42
parent e1b653137f
commit a372c59483
1 changed files with 33 additions and 40 deletions

View File

@ -323,18 +323,16 @@ struct NetworkChatWindow : public Window {
* Find the next item of the list of things that can be auto-completed.
* @param item The current indexed item to return. This function can, and most
* likely will, alter item, to skip empty items in the arrays.
* @return Returns the char that matched to the index.
* @return Returns the view that matched to the index.
*/
const char *ChatTabCompletionNextItem(uint *item)
std::optional<std::string> ChatTabCompletionNextItem(uint *item)
{
static char chat_tab_temp_buffer[64];
/* First, try clients */
if (*item < MAX_CLIENT_SLOTS) {
/* Skip inactive clients */
for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) {
*item = ci->index;
return ci->client_name.c_str();
return ci->client_name;
}
*item = MAX_CLIENT_SLOTS;
}
@ -346,12 +344,11 @@ struct NetworkChatWindow : public Window {
for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) {
/* Get the town-name via the string-system */
SetDParam(0, t->index);
GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer));
return &chat_tab_temp_buffer[0];
return GetString(STR_TOWN_NAME);
}
}
return nullptr;
return std::nullopt;
}
/**
@ -359,13 +356,14 @@ struct NetworkChatWindow : public Window {
* the word right from that as to complete. It also writes a \0 at the
* position of the space (if any). If nothing found, buf is returned.
*/
static char *ChatTabCompletionFindText(char *buf)
static std::string_view ChatTabCompletionFindText(std::string_view &buf)
{
char *p = strrchr(buf, ' ');
if (p == nullptr) return buf;
auto it = buf.find_last_of(' ');
if (it == std::string_view::npos) return buf;
*p = '\0';
return p + 1;
std::string_view res = buf.substr(it + 1);
buf.remove_suffix(res.size() + 1);
return res;
}
/**
@ -373,46 +371,44 @@ struct NetworkChatWindow : public Window {
*/
void ChatTabCompletion()
{
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH];
assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf));
static std::string _chat_tab_completion_buf;
Textbuf *tb = &this->message_editbox.text;
size_t len, tb_len;
uint item;
char *tb_buf, *pre_buf;
const char *cur_name;
uint item = 0;
bool second_scan = false;
item = 0;
/* Create views, so we do not need to copy the data for now. */
std::string_view pre_buf = _chat_tab_completion_active ? std::string_view(_chat_tab_completion_buf) : std::string_view(tb->buf);
std::string_view tb_buf = ChatTabCompletionFindText(pre_buf);
/* Copy the buffer so we can modify it without damaging the real data */
pre_buf = (_chat_tab_completion_active) ? stredup(_chat_tab_completion_buf) : stredup(tb->buf);
/*
* Comparing pointers of the data, as both "Hi:<tab>" and "Hi: Hi:<tab>" will result in
* tb_buf and pre_buf being "Hi:", which would be equal in content but not in context.
*/
bool begin_of_line = tb_buf.data() == pre_buf.data();
tb_buf = ChatTabCompletionFindText(pre_buf);
tb_len = strlen(tb_buf);
while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) {
std::optional<std::string> cur_item;
while ((cur_item = ChatTabCompletionNextItem(&item)).has_value()) {
std::string_view cur_name = cur_item.value();
item++;
if (_chat_tab_completion_active) {
/* We are pressing TAB again on the same name, is there another name
* that starts with this? */
if (!second_scan) {
size_t offset;
size_t length;
std::string_view view;
/* If we are completing at the begin of the line, skip the ': ' we added */
if (tb_buf == pre_buf) {
offset = 0;
length = (tb->bytes - 1) - 2;
if (begin_of_line) {
view = std::string_view(tb->buf, (tb->bytes - 1) - 2);
} else {
/* Else, find the place we are completing at */
offset = strlen(pre_buf) + 1;
length = (tb->bytes - 1) - offset;
size_t offset = pre_buf.size() + 1;
view = std::string_view(tb->buf + offset, (tb->bytes - 1) - offset);
}
/* Compare if we have a match */
if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
if (cur_name == view) second_scan = true;
continue;
}
@ -420,21 +416,19 @@ struct NetworkChatWindow : public Window {
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
}
len = strlen(cur_name);
if (tb_len < len && StrStartsWith(cur_name, tb_buf)) {
if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) {
/* Save the data it was before completion */
if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf);
if (!second_scan) _chat_tab_completion_buf = tb->buf;
_chat_tab_completion_active = true;
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
if (pre_buf == tb_buf) {
if (begin_of_line) {
this->message_editbox.text.Assign(fmt::format("{}: ", cur_name));
} else {
this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name));
}
this->SetDirty();
free(pre_buf);
return;
}
}
@ -446,7 +440,6 @@ struct NetworkChatWindow : public Window {
this->SetDirty();
}
free(pre_buf);
}
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override