28using std::string_view;
35 : line(
std::move(line_))
42 chunks.emplace_back(Chunk{rgb, line.size()});
43 line.append(text.data(), text.size());
53 assert(i < chunks.size());
59 assert(i < chunks.size());
60 auto pos = chunks[i].pos;
61 auto len = ((i + 1) == chunks.size())
63 : chunks[i + 1].pos - pos;
64 return string_view(line).substr(pos, len);
69static constexpr const char*
const PROMPT_NEW =
"> ";
70static constexpr const char*
const PROMPT_CONT =
"| ";
71static constexpr const char*
const PROMPT_BUSY =
"*busy*";
77 : commandController(commandController_)
78 , eventDistributor(eventDistributor_)
81 commandController,
"console",
82 "turns console display on/off", false,
Setting::DONT_SAVE)
84 commandController,
"console_history_size",
85 "amount of commands kept in console history", 100, 0, 10000)
86 , removeDoublesSetting(
87 commandController,
"console_remove_doubles",
88 "don't add the command to history if it's the same as the previous one",
91 , history(
std::
max(1, historySizeSetting.getInt()))
94 newLineConsole(prompt);
101 print(
string(fullVersion.size(),
'-'));
103 "General information about openMSX is available at "
104 "http://openmsx.org.\n"
106 "Type 'help' to see a list of available commands "
107 "(use <PgUp>/<PgDn> to scroll).\n"
108 "Or read the Console Command Reference in the manual.\n"
127void CommandConsole::saveHistory()
130 std::ofstream outputFile;
135 "Error while saving the console history.");
137 for (
auto& s : history) {
138 outputFile << s <<
'\n';
140 }
catch (FileException&
e) {
145void CommandConsole::loadHistory()
148 std::ifstream inputFile(
150 resolveCreate(
"history.txt").c_str());
153 getline(inputFile, line);
154 putCommandHistory(line);
156 }
catch (FileException&) {
163 auto xPosition = narrow<int>(cursorPosition %
getColumns());
164 auto num = lines[0].numChars() /
getColumns();
165 auto yPosition = narrow<int>(num - (cursorPosition /
getColumns()));
166 return {xPosition, yPosition};
169int CommandConsole::signalEvent(
const Event& event)
180 if (!executingCommand) {
181 if (handleEvent(keyEvent)) {
200bool CommandConsole::handleEvent(
const KeyEvent& keyEvent)
202 auto keyCode = keyEvent.getKeyCode();
213 cursorPosition = unsigned(prompt.size());
216 cursorPosition = unsigned(lines[0].numChars());
251 cursorPosition = unsigned(prompt.size());
254 cursorPosition = unsigned(lines[0].numChars());
262 deleteToStartOfWord();
307 cursorPosition = unsigned(prompt.size());
310 if (cursorPosition > prompt.size()) {
315 if (cursorPosition < lines[0].numChars()) {
321 scroll(narrow<int>(lines.size()));
323 cursorPosition = unsigned(prompt.size());
328 scroll(-narrow<int>(lines.size()));
330 cursorPosition = unsigned(lines[0].numChars());
337 auto unicode = keyEvent.getUnicode();
365 if (unicode >= 0x20) {
373void CommandConsole::output(string_view text)
378unsigned CommandConsole::getOutputColumns()
const
383void CommandConsole::print(string_view text,
unsigned rgb)
386 auto pos = text.find(
'\n');
387 newLineConsole(ConsoleLine(
string(text.substr(0, pos)), rgb));
388 if (pos == string_view::npos)
return;
389 text = text.substr(pos + 1);
390 if (text.empty())
return;
394void CommandConsole::newLineConsole(
string line)
396 newLineConsole(ConsoleLine(std::move(line)));
399void CommandConsole::newLineConsole(ConsoleLine line)
401 if (lines.isFull()) {
404 ConsoleLine tmp = std::move(lines[0]);
405 lines[0] = std::move(line);
406 lines.addFront(std::move(tmp));
409void CommandConsole::putCommandHistory(
const string& command)
411 if (command.empty())
return;
413 (history.
back() == command)) {
420void CommandConsole::commandExecute()
423 string cmd0 = lines[0].str().substr(prompt.size());
424 putCommandHistory(cmd0);
428 newLineConsole(lines[0]);
429 if (commandController.
isComplete(commandBuffer)) {
434 prompt = PROMPT_BUSY;
442 if (!result.empty()) {
445 }
catch (CommandException&
e) {
446 print(
e.getMessage(), 0xff0000);
448 commandBuffer.clear();
451 prompt = PROMPT_CONT;
456ConsoleLine CommandConsole::highLight(string_view line)
459 result.addChunk(prompt, 0xffffff);
463 assert(colors.size() == line.size());
466 while (pos != colors.size()) {
467 char col = colors[pos];
468 unsigned pos2 = pos++;
469 while ((pos != colors.size()) && (colors[pos] == col)) {
475 case 'E':
return 0xff0000;
476 case 'c':
return 0x5c5cff;
477 case 'v':
return 0x00ffff;
478 case 'l':
return 0xff00ff;
479 case 'p':
return 0xcdcd00;
480 case 'o':
return 0x00cdcd;
481 default:
return 0xffffff;
484 result.addChunk(line.substr(pos2, pos - pos2), rgb);
489void CommandConsole::putPrompt()
491 commandScrollBack = unsigned(history.
size());
493 lines[0] = highLight(currentLine);
494 cursorPosition = unsigned(prompt.size());
497void CommandConsole::tabCompletion()
500 auto pl = unsigned(prompt.size());
505 currentLine = newFront + back;
506 lines[0] = highLight(currentLine);
509void CommandConsole::scroll(
int delta)
511 consoleScrollBack =
std::max(
std::min(consoleScrollBack + delta,
int(lines.size()) -
int(rows)), 0);
527static std::tuple<std::string::const_iterator, std::string::const_iterator, unsigned>
528 getStartOfWord(
const std::string& line,
unsigned cursorPos,
size_t promptSize)
531 auto prompt =
begin + narrow<ptrdiff_t>(promptSize);
537 while (pos > prompt) {
540 if (*pos2 !=
one_of(
' ',
'\t'))
break;
545 while (pos > prompt) {
548 if (*pos2 ==
one_of(
' ',
'\t'))
break;
561static std::tuple<std::string::const_iterator, std::string::const_iterator, unsigned>
562 getEndOfWord(
const std::string& line,
unsigned cursorPos)
571 while ((pos <
end) && (*pos ==
one_of(
' ',
'\t'))) {
576 while ((pos <
end) && (*pos !=
one_of(
' ',
'\t'))) {
583void CommandConsole::gotoStartOfWord()
585 auto [
begin,
end,
distance] = getStartOfWord(lines[0].str(), cursorPosition, prompt.size());
589void CommandConsole::deleteToStartOfWord()
592 currentLine = lines[0].str();
593 auto [
begin,
end,
distance] = getStartOfWord(currentLine, cursorPosition, prompt.size());
595 currentLine.erase(0, prompt.size());
596 lines[0] = highLight(currentLine);
600void CommandConsole::gotoEndOfWord()
606void CommandConsole::deleteToEndOfWord()
609 currentLine = lines[0].str();
612 currentLine.erase(0, prompt.size());
613 lines[0] = highLight(currentLine);
616void CommandConsole::prevCommand()
619 if (history.
empty()) {
623 unsigned tmp = commandScrollBack;
624 while ((tmp != 0) && !match) {
626 match = history[tmp].starts_with(currentLine);
629 commandScrollBack = tmp;
630 lines[0] = highLight(history[commandScrollBack]);
631 cursorPosition = unsigned(lines[0].numChars());
635void CommandConsole::nextCommand()
638 if (commandScrollBack == history.
size()) {
642 auto tmp = commandScrollBack;
643 while ((++tmp != history.
size()) && !match) {
644 match = history[tmp].starts_with(currentLine);
648 commandScrollBack = tmp;
649 lines[0] = highLight(history[commandScrollBack]);
651 commandScrollBack = unsigned(history.
size());
652 lines[0] = highLight(currentLine);
654 cursorPosition = unsigned(lines[0].numChars());
657void CommandConsole::clearCommand()
660 commandBuffer.clear();
663 lines[0] = highLight(currentLine);
664 cursorPosition = unsigned(prompt.size());
667void CommandConsole::clearHistory()
670 while (lines.size() > 1) {
675void CommandConsole::backspace()
678 if (cursorPosition > prompt.size()) {
679 currentLine = lines[0].str();
680 auto b =
begin(currentLine);
684 currentLine.erase(b,
e);
685 currentLine.erase(0, prompt.size());
686 lines[0] = highLight(currentLine);
691void CommandConsole::delete_key()
694 if (lines[0].numChars() > cursorPosition) {
695 currentLine = lines[0].str();
696 auto b =
begin(currentLine);
700 currentLine.erase(b,
e);
701 currentLine.erase(0, prompt.size());
702 lines[0] = highLight(currentLine);
706void CommandConsole::normalKey(uint32_t chr)
710 currentLine = lines[0].str();
711 auto pos =
begin(currentLine);
714 currentLine.erase(0, prompt.size());
715 lines[0] = highLight(currentLine);
719void CommandConsole::resetScrollBack()
721 consoleScrollBack = 0;
724static std::vector<std::string_view> splitLines(std::string_view str)
735 std::vector<std::string_view> result;
737 auto pos = str.find_first_of(
'\n');
738 if (pos == std::string_view::npos)
break;
739 result.push_back(str.substr(0, pos));
740 str = str.substr(pos + 1);
742 result.push_back(str);
746void CommandConsole::paste()
749 if (text.empty())
return;
750 auto pastedLines = splitLines(text);
751 assert(!pastedLines.empty());
754 std::string_view prefix = lines[0].str();
755 prefix.remove_prefix(prompt.size());
756 auto append = [&](std::string_view suffix) {
757 if (prefix.empty()) {
758 lines[0] = highLight(suffix);
760 lines[0] = highLight(
tmpStrCat(prefix, suffix));
770 append(pastedLines.back());
771 cursorPosition = unsigned(lines[0].numChars());
Assign new value to some variable and restore the original value when this object goes out of scope.
std::string getColors() const
Ouput: a string of equal length of the input command where each character indicates the type of the c...
bool getBoolean() const noexcept
void printWarning(std::string_view message)
CommandConsole(GlobalCommandController &commandController, EventDistributor &eventDistributor, Display &display)
gl::ivec2 getCursorPosition() const
unsigned getColumns() const
static void setOutput(InterpreterOutput *output_)
std::string_view chunkText(size_t i) const
Get the text for the i-th chunk.
ConsoleLine()=default
Construct empty line.
size_t numChars() const
Get the number of UTF8 characters in this line.
uint32_t chunkColor(size_t i) const
Get the color for the i-th chunk.
void addChunk(std::string_view text, uint32_t rgb)
Append a chunk with a (different) color.
Represents the output window/screen of openMSX.
VideoSystem & getVideoSystem()
void repaintDelayed(uint64_t delta)
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
Interpreter & getInterpreter() override
std::string tabCompletion(std::string_view command)
Complete the given command.
CliComm & getCliComm() override
TclObject executeCommand(zstring_view command, CliConnection *connection=nullptr) override
Execute the given command.
bool isComplete(zstring_view command)
Returns true iff the command is complete (all braces, quotes etc.
void setOutput(InterpreterOutput *output_)
TclParser parse(std::string_view command)
zstring_view getString() const
static std::string full()
virtual std::string getClipboardText()=0
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
void openOfStream(std::ofstream &stream, zstring_view filename)
Open an ofstream in a platform-independent manner.
This file implemented 3 utility functions:
auto visit(Visitor &&visitor, const Event &event)
FileContext userFileContext(string_view savePath)
std::string_view substr(std::string_view utf8, std::string_view::size_type first=0, std::string_view::size_type len=std::string_view::npos)
void advance(octet_iterator &it, distance_type n)
size_t size(std::string_view utf8)
uint32_t next(octet_iterator &it)
octet_iterator append(uint32_t cp, octet_iterator result)
uint32_t prior(octet_iterator &it)
auto distance(octet_iterator first, octet_iterator last)
constexpr bool is_pua(uint32_t cp)
constexpr auto drop_back(Range &&range, size_t n)
TemporaryString tmpStrCat(Ts &&... ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)