29 using std::string_view;
36 : line(std::move(line_))
43 chunks.emplace_back(rgb, line.size());
44 line.append(text.data(), text.size());
54 assert(i < chunks.size());
55 return chunks[i].first;
60 assert(i < chunks.size());
61 auto pos = chunks[i].second;
62 auto len = ((i + 1) == chunks.size())
64 : chunks[i + 1].second - pos;
65 return string_view(line).substr(pos, len);
78 : commandController(commandController_)
79 , eventDistributor(eventDistributor_)
82 commandController,
"console",
83 "turns console display on/off", false,
Setting::DONT_SAVE)
85 commandController,
"console_history_size",
86 "amount of commands kept in console history", 100, 0, 10000)
87 , removeDoublesSetting(
88 commandController,
"console_remove_doubles",
89 "don't add the command to history if it's the same as the previous one",
91 , history(std::
max(1, historySizeSetting.getInt()))
92 , executingCommand(false)
96 newLineConsole(prompt);
103 print(
string(fullVersion.size(),
'-'));
105 "General information about openMSX is available at "
106 "http://openmsx.org.\n"
108 "Type 'help' to see a list of available commands "
109 "(use <PgUp>/<PgDn> to scroll).\n"
110 "Or read the Console Command Reference in the manual.\n"
129 void CommandConsole::saveHistory()
132 std::ofstream outputfile;
137 "Error while saving the console history.");
139 for (
auto& s : history) {
140 outputfile << s <<
'\n';
142 }
catch (FileException& e) {
147 void CommandConsole::loadHistory()
150 std::ifstream inputfile(
152 resolveCreate(
"history.txt").c_str());
155 getline(inputfile, line);
156 putCommandHistory(line);
158 }
catch (FileException&) {
165 int xPosition = cursorPosition %
getColumns();
166 auto num = lines[0].numChars() /
getColumns();
167 int yPosition = unsigned(num - (cursorPosition /
getColumns()));
168 return {xPosition, yPosition};
171 int CommandConsole::signalEvent(
const std::shared_ptr<const Event>& event) noexcept
173 if (!consoleSetting.getBoolean())
return 0;
174 const auto& keyEvent = checked_cast<const KeyEvent&>(*event);
182 if (!executingCommand) {
183 if (handleEvent(keyEvent)) {
185 display.repaintDelayed(40000);
201 bool CommandConsole::handleEvent(
const KeyEvent& keyEvent)
203 auto keyCode = keyEvent.getKeyCode();
214 cursorPosition = unsigned(prompt.size());
217 cursorPosition = unsigned(lines[0].numChars());
235 scroll(max<int>(
getRows() - 1, 1));
238 scroll(-max<int>(
getRows() - 1, 1));
252 cursorPosition = unsigned(prompt.size());
255 cursorPosition = unsigned(lines[0].numChars());
263 deleteToStartOfWord();
308 cursorPosition = unsigned(prompt.size());
311 if (cursorPosition > prompt.size()) {
316 if (cursorPosition < lines[0].numChars()) {
322 scroll(lines.size());
324 cursorPosition = unsigned(prompt.size());
329 scroll(-lines.size());
331 cursorPosition = unsigned(lines[0].numChars());
338 auto unicode = keyEvent.getUnicode();
366 if (unicode >= 0x20) {
374 void CommandConsole::output(string_view text)
379 unsigned CommandConsole::getOutputColumns()
const
384 void CommandConsole::print(string_view text,
unsigned rgb)
387 auto pos = text.find(
'\n');
388 newLineConsole(ConsoleLine(
string(text.substr(0, pos)), rgb));
389 if (pos == string_view::npos)
return;
390 text = text.substr(pos + 1);
391 if (text.empty())
return;
395 void CommandConsole::newLineConsole(
string line)
397 newLineConsole(ConsoleLine(std::move(line)));
400 void CommandConsole::newLineConsole(ConsoleLine line)
402 if (lines.isFull()) {
405 ConsoleLine tmp = std::move(lines[0]);
406 lines[0] = std::move(line);
407 lines.addFront(std::move(tmp));
410 void CommandConsole::putCommandHistory(
const string& command)
412 if (command.empty())
return;
414 (history.
back() == command)) {
421 void CommandConsole::commandExecute()
424 string cmd0 = lines[0].str().substr(prompt.size());
425 putCommandHistory(cmd0);
429 newLineConsole(lines[0]);
430 if (commandController.
isComplete(commandBuffer)) {
443 if (!result.empty()) {
446 }
catch (CommandException& e) {
447 print(e.getMessage(), 0xff0000);
449 commandBuffer.clear();
457 ConsoleLine CommandConsole::highLight(string_view line)
460 result.addChunk(prompt, 0xffffff);
464 assert(colors.size() == line.size());
467 while (pos != colors.size()) {
468 char col = colors[pos];
469 unsigned pos2 = pos++;
470 while ((pos != colors.size()) && (colors[pos] == col)) {
476 case 'E':
return 0xff0000;
477 case 'c':
return 0x5c5cff;
478 case 'v':
return 0x00ffff;
479 case 'l':
return 0xff00ff;
480 case 'p':
return 0xcdcd00;
481 case 'o':
return 0x00cdcd;
482 default:
return 0xffffff;
485 result.addChunk(line.substr(pos2, pos - pos2), rgb);
490 void CommandConsole::putPrompt()
492 commandScrollBack = unsigned(history.
size());
494 lines[0] = highLight(currentLine);
495 cursorPosition = unsigned(prompt.size());
498 void CommandConsole::tabCompletion()
501 auto pl = unsigned(prompt.size());
506 currentLine = newFront + back;
507 lines[0] = highLight(currentLine);
510 void CommandConsole::scroll(
int delta)
512 consoleScrollBack =
max(
min(consoleScrollBack + delta,
int(lines.size()) -
int(rows)), 0);
528 static std::tuple<std::string::const_iterator, std::string::const_iterator, unsigned>
529 getStartOfWord(
const std::string& line,
unsigned cursorPos,
size_t promptSize)
532 auto prompt =
begin + promptSize;
538 while (pos > prompt) {
541 if (*pos2 !=
one_of(
' ',
'\t'))
break;
546 while (pos > prompt) {
549 if (*pos2 ==
one_of(
' ',
'\t'))
break;
562 static std::tuple<std::string::const_iterator, std::string::const_iterator, unsigned>
563 getEndOfWord(
const std::string& line,
unsigned cursorPos)
572 while ((pos <
end) && (*pos ==
one_of(
' ',
'\t'))) {
577 while ((pos <
end) && (*pos !=
one_of(
' ',
'\t'))) {
584 void CommandConsole::gotoStartOfWord()
586 auto [
begin,
end,
distance] = getStartOfWord(lines[0].str(), cursorPosition, prompt.size());
590 void CommandConsole::deleteToStartOfWord()
593 currentLine = lines[0].str();
594 auto [
begin,
end,
distance] = getStartOfWord(currentLine, cursorPosition, prompt.size());
596 currentLine.erase(0, prompt.size());
597 lines[0] = highLight(currentLine);
601 void CommandConsole::gotoEndOfWord()
607 void CommandConsole::deleteToEndOfWord()
610 currentLine = lines[0].str();
613 currentLine.erase(0, prompt.size());
614 lines[0] = highLight(currentLine);
617 void CommandConsole::prevCommand()
620 if (history.
empty()) {
624 unsigned tmp = commandScrollBack;
625 while ((tmp != 0) && !match) {
630 commandScrollBack = tmp;
631 lines[0] = highLight(history[commandScrollBack]);
632 cursorPosition = unsigned(lines[0].numChars());
636 void CommandConsole::nextCommand()
639 if (commandScrollBack == history.
size()) {
643 auto tmp = commandScrollBack;
644 while ((++tmp != history.
size()) && !match) {
649 commandScrollBack = tmp;
650 lines[0] = highLight(history[commandScrollBack]);
652 commandScrollBack = unsigned(history.
size());
653 lines[0] = highLight(currentLine);
655 cursorPosition = unsigned(lines[0].numChars());
658 void CommandConsole::clearCommand()
661 commandBuffer.clear();
664 lines[0] = highLight(currentLine);
665 cursorPosition = unsigned(prompt.size());
668 void CommandConsole::clearHistory()
671 while (lines.size() > 1) {
676 void CommandConsole::backspace()
679 if (cursorPosition > prompt.size()) {
680 currentLine = lines[0].str();
681 auto b =
begin(currentLine);
685 currentLine.erase(b, e);
686 currentLine.erase(0, prompt.size());
687 lines[0] = highLight(currentLine);
692 void CommandConsole::delete_key()
695 if (lines[0].numChars() > cursorPosition) {
696 currentLine = lines[0].str();
697 auto b =
begin(currentLine);
701 currentLine.erase(b, e);
702 currentLine.erase(0, prompt.size());
703 lines[0] = highLight(currentLine);
707 void CommandConsole::normalKey(uint32_t chr)
711 currentLine = lines[0].str();
712 auto pos =
begin(currentLine);
715 currentLine.erase(0, prompt.size());
716 lines[0] = highLight(currentLine);
720 void CommandConsole::resetScrollBack()
722 consoleScrollBack = 0;
725 static std::vector<std::string_view> splitLines(std::string_view str)
736 std::vector<std::string_view> result;
738 auto pos = str.find_first_of(
'\n');
739 if (pos == std::string_view::npos)
break;
740 result.push_back(str.substr(0, pos));
741 str = str.substr(pos + 1);
743 result.push_back(str);
747 void CommandConsole::paste()
750 if (text.empty())
return;
751 auto pastedLines = splitLines(text);
752 assert(!pastedLines.empty());
755 std::string_view prefix = lines[0].str();
756 prefix.remove_prefix(prompt.size());
757 auto append = [&](std::string_view suffix) {
758 if (prefix.empty()) {
759 lines[0] = highLight(suffix);
761 lines[0] = highLight(
tmpStrCat(prefix, suffix));
771 append(pastedLines.back());
772 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...
void push_back(const T &t)
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 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
bool startsWith(string_view total, string_view part)
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:
constexpr const char *const PROMPT_BUSY
constexpr const char *const PROMPT_CONT
constexpr const char *const PROMPT_NEW
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)