X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fchat.cpp;h=2f65e68b35b7c9d7459274e2337ddd58b74c3240;hb=8c1871fa2c066a2086988684256da97bd0f4ab6f;hp=b78b90145f2588e57d2de19fd5ad16cd2ba8e937;hpb=daefd0ab367605eabe1a293dd7f6a50964bb3801;p=minetest.git diff --git a/src/chat.cpp b/src/chat.cpp index b78b90145..2f65e68b3 100644 --- a/src/chat.cpp +++ b/src/chat.cpp @@ -18,38 +18,31 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "chat.h" -#include "debug.h" -#include "strfnd.h" + +#include #include #include + +#include "config.h" +#include "debug.h" +#include "util/strfnd.h" #include "util/string.h" #include "util/numeric.h" ChatBuffer::ChatBuffer(u32 scrollback): - m_scrollback(scrollback), - m_unformatted(), - m_cols(0), - m_rows(0), - m_scroll(0), - m_formatted(), - m_empty_formatted_line() + m_scrollback(scrollback) { if (m_scrollback == 0) m_scrollback = 1; m_empty_formatted_line.first = true; } -ChatBuffer::~ChatBuffer() -{ -} - -void ChatBuffer::addLine(std::wstring name, std::wstring text) +void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text) { ChatLine line(name, text); m_unformatted.push_back(line); - if (m_rows > 0) - { + if (m_rows > 0) { // m_formatted is valid and must be kept valid bool scrolled_at_bottom = (m_scroll == getBottomScrollPos()); u32 num_added = formatChatLine(line, m_cols, m_formatted); @@ -58,8 +51,7 @@ void ChatBuffer::addLine(std::wstring name, std::wstring text) } // Limit number of lines by m_scrollback - if (m_unformatted.size() > m_scrollback) - { + if (m_unformatted.size() > m_scrollback) { deleteOldest(m_unformatted.size() - m_scrollback); } } @@ -76,27 +68,23 @@ u32 ChatBuffer::getLineCount() const return m_unformatted.size(); } -u32 ChatBuffer::getScrollback() const -{ - return m_scrollback; -} - const ChatLine& ChatBuffer::getLine(u32 index) const { - assert(index < getLineCount()); + assert(index < getLineCount()); // pre-condition return m_unformatted[index]; } void ChatBuffer::step(f32 dtime) { - for (u32 i = 0; i < m_unformatted.size(); ++i) - { - m_unformatted[i].age += dtime; + for (ChatLine &line : m_unformatted) { + line.age += dtime; } } void ChatBuffer::deleteOldest(u32 count) { + bool at_bottom = (m_scroll == getBottomScrollPos()); + u32 del_unformatted = 0; u32 del_formatted = 0; @@ -107,7 +95,8 @@ void ChatBuffer::deleteOldest(u32 count) // keep m_formatted in sync if (del_formatted < m_formatted.size()) { - assert(m_formatted[del_formatted].first); + + sanity_check(m_formatted[del_formatted].first); ++del_formatted; while (del_formatted < m_formatted.size() && !m_formatted[del_formatted].first) @@ -119,6 +108,11 @@ void ChatBuffer::deleteOldest(u32 count) m_unformatted.erase(m_unformatted.begin(), m_unformatted.begin() + del_unformatted); m_formatted.erase(m_formatted.begin(), m_formatted.begin() + del_formatted); + + if (at_bottom) + m_scroll = getBottomScrollPos(); + else + scrollAbsolute(m_scroll - del_formatted); } void ChatBuffer::deleteByAge(f32 maxAge) @@ -129,14 +123,14 @@ void ChatBuffer::deleteByAge(f32 maxAge) deleteOldest(count); } -u32 ChatBuffer::getColumns() const +u32 ChatBuffer::getRows() const { - return m_cols; + return m_rows; } -u32 ChatBuffer::getRows() const +void ChatBuffer::scrollTop() { - return m_rows; + m_scroll = getTopScrollPos(); } void ChatBuffer::reformat(u32 cols, u32 rows) @@ -200,8 +194,8 @@ const ChatFormattedLine& ChatBuffer::getFormattedLine(u32 row) const s32 index = m_scroll + (s32) row; if (index >= 0 && index < (s32) m_formatted.size()) return m_formatted[index]; - else - return m_empty_formatted_line; + + return m_empty_formatted_line; } void ChatBuffer::scroll(s32 rows) @@ -226,11 +220,6 @@ void ChatBuffer::scrollBottom() m_scroll = getBottomScrollPos(); } -void ChatBuffer::scrollTop() -{ - m_scroll = getTopScrollPos(); -} - u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols, std::vector& destination) const { @@ -243,8 +232,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols, u32 hanging_indentation = 0; // Format the sender name and produce fragments - if (!line.name.empty()) - { + if (!line.name.empty()) { temp_frag.text = L"<"; temp_frag.column = 0; //temp_frag.bold = 0; @@ -259,22 +247,20 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols, next_frags.push_back(temp_frag); } + std::wstring name_sanitized = line.name.c_str(); + // Choose an indentation level - if (line.name.empty()) - { + if (line.name.empty()) { // Server messages hanging_indentation = 0; - } - else if (line.name.size() + 3 <= cols/2) - { + } else if (name_sanitized.size() + 3 <= cols/2) { // Names shorter than about half the console width hanging_indentation = line.name.size() + 3; - } - else - { + } else { // Very long names hanging_indentation = 2; } + //EnrichedString line_text(line.text); next_line.first = true; bool text_processing = false; @@ -330,7 +316,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols, while (frag_length < remaining_in_input && frag_length < remaining_in_output) { - if (isspace(line.text[in_pos + frag_length])) + if (iswspace(line.text.getString()[in_pos + frag_length])) space_pos = frag_length; ++frag_length; } @@ -362,10 +348,11 @@ s32 ChatBuffer::getTopScrollPos() const s32 rows = (s32) m_rows; if (rows == 0) return 0; - else if (formatted_count <= rows) + + if (formatted_count <= rows) return formatted_count - rows; - else - return 0; + + return 0; } s32 ChatBuffer::getBottomScrollPos() const @@ -374,27 +361,21 @@ s32 ChatBuffer::getBottomScrollPos() const s32 rows = (s32) m_rows; if (rows == 0) return 0; - else - return formatted_count - rows; -} - + return formatted_count - rows; +} -ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit): - m_prompt(prompt), - m_line(L""), - m_history(), - m_history_index(0), - m_history_limit(history_limit), - m_cols(0), - m_view(0), - m_cursor(0), - m_nick_completion_start(0), - m_nick_completion_end(0) +void ChatBuffer::resize(u32 scrollback) { + m_scrollback = scrollback; + if (m_unformatted.size() > m_scrollback) + deleteOldest(m_unformatted.size() - m_scrollback); } -ChatPrompt::~ChatPrompt() + +ChatPrompt::ChatPrompt(const std::wstring &prompt, u32 history_limit): + m_prompt(prompt), + m_history_limit(history_limit) { } @@ -416,20 +397,19 @@ void ChatPrompt::input(const std::wstring &str) m_nick_completion_end = 0; } -std::wstring ChatPrompt::submit() +void ChatPrompt::addToHistory(const std::wstring &line) { - std::wstring line = m_line; - m_line.clear(); - if (!line.empty()) + if (!line.empty() && + (m_history.size() == 0 || m_history.back() != line)) { + // Remove all duplicates + m_history.erase(std::remove(m_history.begin(), m_history.end(), + line), m_history.end()); + // Push unique line m_history.push_back(line); + } if (m_history.size() > m_history_limit) m_history.erase(m_history.begin()); m_history_index = m_history.size(); - m_view = 0; - m_cursor = 0; - m_nick_completion_start = 0; - m_nick_completion_end = 0; - return line; } void ChatPrompt::clear() @@ -441,13 +421,15 @@ void ChatPrompt::clear() m_nick_completion_end = 0; } -void ChatPrompt::replace(std::wstring line) +std::wstring ChatPrompt::replace(const std::wstring &line) { + std::wstring old_line = m_line; m_line = line; m_view = m_cursor = line.size(); clampView(); m_nick_completion_start = 0; m_nick_completion_end = 0; + return old_line; } void ChatPrompt::historyPrev() @@ -491,9 +473,9 @@ void ChatPrompt::nickCompletion(const std::list& names, bool backwa { // no previous nick completion is active prefix_start = prefix_end = m_cursor; - while (prefix_start > 0 && !isspace(m_line[prefix_start-1])) + while (prefix_start > 0 && !iswspace(m_line[prefix_start-1])) --prefix_start; - while (prefix_end < m_line.size() && !isspace(m_line[prefix_end])) + while (prefix_end < m_line.size() && !iswspace(m_line[prefix_end])) ++prefix_end; if (prefix_start == prefix_end) return; @@ -502,18 +484,15 @@ void ChatPrompt::nickCompletion(const std::list& names, bool backwa // find all names that start with the selected prefix std::vector completions; - for (std::list::const_iterator - i = names.begin(); - i != names.end(); ++i) - { - if (str_starts_with(narrow_to_wide(*i), prefix, true)) - { - std::wstring completion = narrow_to_wide(*i); + for (const std::string &name : names) { + if (str_starts_with(narrow_to_wide(name), prefix, true)) { + std::wstring completion = narrow_to_wide(name); if (prefix_start == 0) - completion += L":"; + completion += L": "; completions.push_back(completion); } } + if (completions.empty()) return; @@ -522,7 +501,7 @@ void ChatPrompt::nickCompletion(const std::list& names, bool backwa u32 replacement_index = 0; if (!initial) { - while (word_end < m_line.size() && !isspace(m_line[word_end])) + while (word_end < m_line.size() && !iswspace(m_line[word_end])) ++word_end; std::wstring word = m_line.substr(prefix_start, word_end - prefix_start); @@ -540,8 +519,8 @@ void ChatPrompt::nickCompletion(const std::list& names, bool backwa } } } - std::wstring replacement = completions[replacement_index] + L" "; - if (word_end < m_line.size() && isspace(word_end)) + std::wstring replacement = completions[replacement_index]; + if (word_end < m_line.size() && iswspace(m_line[word_end])) ++word_end; // replace existing word with replacement word, @@ -589,54 +568,60 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco s32 length = m_line.size(); s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1; - if (scope == CURSOROP_SCOPE_CHARACTER) - { + switch (scope) { + case CURSOROP_SCOPE_CHARACTER: new_cursor += increment; - } - else if (scope == CURSOROP_SCOPE_WORD) - { - if (increment > 0) - { + break; + case CURSOROP_SCOPE_WORD: + if (dir == CURSOROP_DIR_RIGHT) { // skip one word to the right - while (new_cursor < length && isspace(m_line[new_cursor])) + while (new_cursor < length && iswspace(m_line[new_cursor])) new_cursor++; - while (new_cursor < length && !isspace(m_line[new_cursor])) + while (new_cursor < length && !iswspace(m_line[new_cursor])) new_cursor++; - while (new_cursor < length && isspace(m_line[new_cursor])) + while (new_cursor < length && iswspace(m_line[new_cursor])) new_cursor++; - } - else - { + } else { // skip one word to the left - while (new_cursor >= 1 && isspace(m_line[new_cursor - 1])) + while (new_cursor >= 1 && iswspace(m_line[new_cursor - 1])) new_cursor--; - while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1])) + while (new_cursor >= 1 && !iswspace(m_line[new_cursor - 1])) new_cursor--; } - } - else if (scope == CURSOROP_SCOPE_LINE) - { + break; + case CURSOROP_SCOPE_LINE: new_cursor += increment * length; + break; + case CURSOROP_SCOPE_SELECTION: + break; } new_cursor = MYMAX(MYMIN(new_cursor, length), 0); - if (op == CURSOROP_MOVE) - { + switch (op) { + case CURSOROP_MOVE: m_cursor = new_cursor; - } - else if (op == CURSOROP_DELETE) - { - if (new_cursor < old_cursor) - { - m_line.erase(new_cursor, old_cursor - new_cursor); - m_cursor = new_cursor; + m_cursor_len = 0; + break; + case CURSOROP_DELETE: + if (m_cursor_len > 0) { // Delete selected text first + m_line.erase(m_cursor, m_cursor_len); + } else { + m_cursor = MYMIN(new_cursor, old_cursor); + m_line.erase(m_cursor, abs(new_cursor - old_cursor)); } - else if (new_cursor > old_cursor) - { - m_line.erase(old_cursor, new_cursor - old_cursor); - m_cursor = old_cursor; + m_cursor_len = 0; + break; + case CURSOROP_SELECT: + if (scope == CURSOROP_SCOPE_LINE) { + m_cursor = 0; + m_cursor_len = length; + } else { + m_cursor = MYMIN(new_cursor, old_cursor); + m_cursor_len += abs(new_cursor - old_cursor); + m_cursor_len = MYMIN(m_cursor_len, length - m_cursor); } + break; } clampView(); @@ -670,15 +655,12 @@ ChatBackend::ChatBackend(): { } -ChatBackend::~ChatBackend() -{ -} - -void ChatBackend::addMessage(std::wstring name, std::wstring text) +void ChatBackend::addMessage(const std::wstring &name, std::wstring text) { // Note: A message may consist of multiple lines, for example the MOTD. + text = translate_string(text); WStrfnd fnd(text); - while (!fnd.atend()) + while (!fnd.at_end()) { std::wstring line = fnd.next(L"\n"); m_console_buffer.addLine(name, line); @@ -719,19 +701,21 @@ ChatBuffer& ChatBackend::getRecentBuffer() return m_recent_buffer; } -std::wstring ChatBackend::getRecentChat() +EnrichedString ChatBackend::getRecentChat() const { - std::wostringstream stream; - for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i) - { + EnrichedString result; + for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i) { const ChatLine& line = m_recent_buffer.getLine(i); if (i != 0) - stream << L"\n"; - if (!line.name.empty()) - stream << L"<" << line.name << L"> "; - stream << line.text; + result += L"\n"; + if (!line.name.empty()) { + result += L"<"; + result += line.name; + result += L"> "; + } + result += line.text; } - return stream.str(); + return result; } ChatPrompt& ChatBackend::getPrompt() @@ -754,6 +738,14 @@ void ChatBackend::clearRecentChat() m_recent_buffer.clear(); } + +void ChatBackend::applySettings() +{ + u32 recent_lines = g_settings->getU32("recent_chat_messages"); + recent_lines = rangelim(recent_lines, 2, 20); + m_recent_buffer.resize(recent_lines); +} + void ChatBackend::step(float dtime) { m_recent_buffer.step(dtime); @@ -774,5 +766,5 @@ void ChatBackend::scrollPageDown() void ChatBackend::scrollPageUp() { - m_console_buffer.scroll(-m_console_buffer.getRows()); + m_console_buffer.scroll(-(s32)m_console_buffer.getRows()); }