1
0
Fork 0

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

pull/10820/head
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. * 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 * @param item The current indexed item to return. This function can, and most
* likely will, alter item, to skip empty items in the arrays. * 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 */ /* First, try clients */
if (*item < MAX_CLIENT_SLOTS) { if (*item < MAX_CLIENT_SLOTS) {
/* Skip inactive clients */ /* Skip inactive clients */
for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) { for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) {
*item = ci->index; *item = ci->index;
return ci->client_name.c_str(); return ci->client_name;
} }
*item = MAX_CLIENT_SLOTS; *item = MAX_CLIENT_SLOTS;
} }
@ -346,12 +344,11 @@ struct NetworkChatWindow : public Window {
for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) { for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) {
/* Get the town-name via the string-system */ /* Get the town-name via the string-system */
SetDParam(0, t->index); SetDParam(0, t->index);
GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer)); return GetString(STR_TOWN_NAME);
return &chat_tab_temp_buffer[0];
} }
} }
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 * 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. * 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, ' '); auto it = buf.find_last_of(' ');
if (p == nullptr) return buf; if (it == std::string_view::npos) return buf;
*p = '\0'; std::string_view res = buf.substr(it + 1);
return p + 1; buf.remove_suffix(res.size() + 1);
return res;
} }
/** /**
@ -373,46 +371,44 @@ struct NetworkChatWindow : public Window {
*/ */
void ChatTabCompletion() void ChatTabCompletion()
{ {
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH]; static std::string _chat_tab_completion_buf;
assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf));
Textbuf *tb = &this->message_editbox.text; Textbuf *tb = &this->message_editbox.text;
size_t len, tb_len; uint item = 0;
uint item;
char *tb_buf, *pre_buf;
const char *cur_name;
bool second_scan = false; 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); std::optional<std::string> cur_item;
tb_len = strlen(tb_buf); while ((cur_item = ChatTabCompletionNextItem(&item)).has_value()) {
std::string_view cur_name = cur_item.value();
while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) {
item++; item++;
if (_chat_tab_completion_active) { if (_chat_tab_completion_active) {
/* We are pressing TAB again on the same name, is there another name /* We are pressing TAB again on the same name, is there another name
* that starts with this? */ * that starts with this? */
if (!second_scan) { if (!second_scan) {
size_t offset; std::string_view view;
size_t length;
/* If we are completing at the begin of the line, skip the ': ' we added */ /* If we are completing at the begin of the line, skip the ': ' we added */
if (tb_buf == pre_buf) { if (begin_of_line) {
offset = 0; view = std::string_view(tb->buf, (tb->bytes - 1) - 2);
length = (tb->bytes - 1) - 2;
} else { } else {
/* Else, find the place we are completing at */ /* Else, find the place we are completing at */
offset = strlen(pre_buf) + 1; size_t offset = pre_buf.size() + 1;
length = (tb->bytes - 1) - offset; view = std::string_view(tb->buf + offset, (tb->bytes - 1) - offset);
} }
/* Compare if we have a match */ /* 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; continue;
} }
@ -420,21 +416,19 @@ struct NetworkChatWindow : public Window {
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */ /* Now any match we make on _chat_tab_completion_buf after this, is perfect */
} }
len = strlen(cur_name); if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) {
if (tb_len < len && StrStartsWith(cur_name, tb_buf)) {
/* Save the data it was before completion */ /* 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; _chat_tab_completion_active = true;
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ /* 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)); this->message_editbox.text.Assign(fmt::format("{}: ", cur_name));
} else { } else {
this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name)); this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name));
} }
this->SetDirty(); this->SetDirty();
free(pre_buf);
return; return;
} }
} }
@ -446,7 +440,6 @@ struct NetworkChatWindow : public Window {
this->SetDirty(); this->SetDirty();
} }
free(pre_buf);
} }
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override