diff --git a/Emulator/Headless.cpp b/Emulator/Headless.cpp index 5f9a2c304..55d39cdd0 100644 --- a/Emulator/Headless.cpp +++ b/Emulator/Headless.cpp @@ -285,7 +285,7 @@ Headless::execScript() // Launch the emulator thread vamiga.launch(this, vamiga::process); - // Execute scripts + // Execute script barrier.lock(); vamiga.retroShell.execScript(script); barrier.lock(); diff --git a/Emulator/Headless.h b/Emulator/Headless.h index 9bc3a85ac..9815d3695 100644 --- a/Emulator/Headless.h +++ b/Emulator/Headless.h @@ -417,11 +417,10 @@ static const char *script[] = { "server gdb", "server gdb set PORT 8000", "server gdb set VERBOSE true", - "server gdb set VERBOSE false" -}; + "server gdb set VERBOSE false", -/* -static const char *debugScript[] = { + // Enter debugger + ".", "", "break", @@ -531,6 +530,5 @@ static const char *debugScript[] = { "i host", "i server" }; -*/ } diff --git a/Emulator/Misc/RetroShell/CommandConsole.cpp b/Emulator/Misc/RetroShell/CommandConsole.cpp index 21ef7edda..9f977df4a 100644 --- a/Emulator/Misc/RetroShell/CommandConsole.cpp +++ b/Emulator/Misc/RetroShell/CommandConsole.cpp @@ -135,7 +135,7 @@ Console::initCommands(Command &root) auto stream = std::ifstream(argv.front()); if (!stream.is_open()) throw Error(ERROR_FILE_NOT_FOUND, argv.front()); - asyncExecScript(stream); + retroShell.asyncExecScript(stream); }); root.add({"wait"}, {Arg::value, Arg::seconds}, diff --git a/Emulator/Misc/RetroShell/Console.cpp b/Emulator/Misc/RetroShell/Console.cpp index e54815323..184a66d45 100644 --- a/Emulator/Misc/RetroShell/Console.cpp +++ b/Emulator/Misc/RetroShell/Console.cpp @@ -30,7 +30,7 @@ Console::_initialize() history.push_back( { "", 0 } ); // Print the startup message and the input prompt - asyncExec("welcome"); + // retroShell.asyncExec("welcome"); } Console& @@ -160,6 +160,18 @@ Console::clear() needsDisplay(); } +bool +Console::isEmpty() +{ + return storage.isCleared(); +} + +bool +Console::lastLineIsEmpty() +{ + return storage.lastLineIsEmpty(); +} + void Console::printState() { @@ -254,7 +266,7 @@ Console::press(RetroShellKey key, bool shift) if (tabPressed) { // TAB was pressed twice - asyncExec("help \"" + input + "\""); + retroShell.asyncExec("help \"" + input + "\""); } else { @@ -339,7 +351,8 @@ Console::pressReturn(bool shift) if (shift) { // Switch the interpreter - retroShell.switchConsole(); + // retroShell.switchConsole(); + retroShell.asyncExec("."); } else { @@ -352,7 +365,7 @@ Console::pressReturn(bool shift) ipos = (isize)history.size() - 1; // Feed the command into the command queue - asyncExec(input); + retroShell.asyncExec(input); // Clear the input line input = ""; @@ -523,124 +536,6 @@ Console::getRoot() return root; } -void -Console::asyncExec(const string &command) -{ - // Feed the command into the command queue - commands.push_back({ 0, command}); - emulator.put(Cmd(CMD_RSH_EXECUTE)); -} - -void -Console::exec() -{ - SYNCHRONIZED - - // Only proceed if there is anything to process - if (commands.empty()) return; - - std::pair cmd; - - try { - - while (!commands.empty()) { - - cmd = commands.front(); - commands.erase(commands.begin()); - exec(cmd); - } - msgQueue.put(MSG_RSH_EXEC); - - } catch (ScriptInterruption &) { - - msgQueue.put(MSG_RSH_WAIT); - - } catch (...) { - - // Remove all remaining commands - commands = { }; - - msgQueue.put(MSG_RSH_ERROR); - } - - // Print prompt - *this << getPrompt(); -} - -void -Console::exec(QueuedCmd cmd) -{ - auto line = cmd.first; - auto command = cmd.second; - - try { - - // Print the command if it comes from a script - if (line) *this << command << '\n'; - - // Call the interpreter - exec(command); - - } catch (ScriptInterruption &) { - - // Rethrow the exception - throw; - - } catch (std::exception &err) { - - // Print error message - describe(err, line, command); - - // Rethrow the exception if the command is not prefixed with 'try' - if (command.rfind("try", 0)) throw; - } -} - -void -Console::asyncExecScript(std::stringstream &ss) -{ - SYNCHRONIZED - - std::string line; - isize nr = 1; - - while (std::getline(ss, line)) { - - commands.push_back({ nr++, line }); - } - - emulator.put(Cmd(CMD_RSH_EXECUTE)); -} - -void -Console::asyncExecScript(const std::ifstream &fs) -{ - std::stringstream ss; - ss << fs.rdbuf(); - asyncExecScript(ss); -} - -void -Console::asyncExecScript(const string &contents) -{ - std::stringstream ss; - ss << contents; - asyncExecScript(ss); -} - -void -Console::abortScript() -{ - { SYNCHRONIZED - - if (!commands.empty()) { - - commands.clear(); - agnus.cancel(); - } - } -} - void Console::exec(const string& userInput, bool verbose) { diff --git a/Emulator/Misc/RetroShell/Console.h b/Emulator/Misc/RetroShell/Console.h index c5f138beb..8291e61f2 100644 --- a/Emulator/Misc/RetroShell/Console.h +++ b/Emulator/Misc/RetroShell/Console.h @@ -35,6 +35,7 @@ struct ScriptInterruption: util::Exception { class Console : public SubComponent { + friend class RetroShell; friend class RshServer; friend class Interpreter; @@ -88,9 +89,6 @@ class Console : public SubComponent { // Input line string input; - // Command queue (stores all pending commands) - std::vector commands; - // Cursor position isize cursor = 0; @@ -184,6 +182,12 @@ class Console : public SubComponent { // Clears the console window void clear(); + // Returns true if the console is cleared + bool isEmpty(); + + // Returns true if the last line contains no text + bool lastLineIsEmpty(); + // Prints the welcome message virtual void welcome() = 0; @@ -282,31 +286,6 @@ class Console : public SubComponent { // Returns the root node of the currently active instruction tree Command &getRoot(); - - // - // Executing commands - // - -public: - - // Adds a command to the list of pending commands - void asyncExec(const string &command); - - // Adds the commands of a shell script to the list of pending commands - void asyncExecScript(std::stringstream &ss) throws; - void asyncExecScript(const std::ifstream &fs) throws; - void asyncExecScript(const string &contents) throws; - // void asyncExecScript(const class MediaFile &script) throws; - - // Aborts the execution of a script - void abortScript(); - - // Executes all pending commands - void exec() throws; - - // Executes a single pending command - void exec(QueuedCmd cmd) throws; - protected: // Executes a single command diff --git a/Emulator/Misc/RetroShell/DebugConsole.cpp b/Emulator/Misc/RetroShell/DebugConsole.cpp index 16e5228eb..7f1d351d4 100644 --- a/Emulator/Misc/RetroShell/DebugConsole.cpp +++ b/Emulator/Misc/RetroShell/DebugConsole.cpp @@ -18,7 +18,7 @@ namespace vamiga { void DebugConsole::_pause() { - asyncExec("state"); + retroShell.asyncExec("state"); } string diff --git a/Emulator/Misc/RetroShell/RetroShell.cpp b/Emulator/Misc/RetroShell/RetroShell.cpp index 64de5663c..5bd52cbed 100644 --- a/Emulator/Misc/RetroShell/RetroShell.cpp +++ b/Emulator/Misc/RetroShell/RetroShell.cpp @@ -30,26 +30,162 @@ RetroShell::RetroShell(Amiga& ref) : SubComponent(ref) void RetroShell::_initialize() { - + enterCommander(); } void RetroShell::switchConsole() { - if (inCommandShell()) { + inCommandShell() ? enterDebugger() : enterCommander(); +} + +void +RetroShell::enterDebugger() +{ + // Assign the new console + current = &debugger; + + // Enter tracking mode + emulator.trackOn(1); + msgQueue.put(MSG_RSH_DEBUGGER, true); + + // Print the welcome message if entered the first time + if (current->isEmpty()) asyncExec("welcome"); + // if (current->isEmpty()) current->welcome(); +} - current = &debugger; - emulator.trackOn(1); - msgQueue.put(MSG_RSH_DEBUGGER, true); +void +RetroShell::enterCommander() +{ + // Assign the new console + current = &commander; - } else { + // Leave tracking mode + emulator.trackOff(1); + msgQueue.put(MSG_RSH_DEBUGGER, false); + + // Print the welcome message if entered the first time + if (current->isEmpty()) asyncExec("welcome"); + // if (current->isEmpty()) current->welcome(); +} + +void +RetroShell::asyncExec(const string &command) +{ + // Feed the command into the command queue + commands.push_back({ 0, command}); + emulator.put(Cmd(CMD_RSH_EXECUTE)); +} + +void +RetroShell::asyncExecScript(std::stringstream &ss) +{ + SYNCHRONIZED - current = &commander; - emulator.trackOff(1); - msgQueue.put(MSG_RSH_DEBUGGER, false); + std::string line; + isize nr = 1; + + while (std::getline(ss, line)) { + + commands.push_back({ nr++, line }); } + + emulator.put(Cmd(CMD_RSH_EXECUTE)); +} + +void +RetroShell::asyncExecScript(const std::ifstream &fs) +{ + std::stringstream ss; + ss << fs.rdbuf(); + asyncExecScript(ss); +} + +void +RetroShell::asyncExecScript(const string &contents) +{ + std::stringstream ss; + ss << contents; + asyncExecScript(ss); } +void +RetroShell::abortScript() +{ + { SYNCHRONIZED + + if (!commands.empty()) { + + commands.clear(); + agnus.cancel(); + } + } +} + +void +RetroShell::exec() +{ + SYNCHRONIZED + + // Only proceed if there is anything to process + if (commands.empty()) return; + + std::pair cmd; + + try { + + while (!commands.empty()) { + + cmd = commands.front(); + commands.erase(commands.begin()); + exec(cmd); + } + msgQueue.put(MSG_RSH_EXEC); + + } catch (ScriptInterruption &) { + + msgQueue.put(MSG_RSH_WAIT); + + } catch (...) { + + // Remove all remaining commands + commands = { }; + + msgQueue.put(MSG_RSH_ERROR); + } + + // Print prompt + if (current->lastLineIsEmpty()) *this << current->getPrompt(); +} + +void +RetroShell::exec(QueuedCmd cmd) +{ + auto line = cmd.first; + auto command = cmd.second; + + try { + + // Print the command if it comes from a script + if (line) *this << command << '\n'; + + // Call the interpreter + current->exec(command); + + } catch (ScriptInterruption &) { + + // Rethrow the exception + throw; + + } catch (std::exception &err) { + + // Print error message + current->describe(err, line, command); + + // Rethrow the exception if the command is not prefixed with 'try' + if (command.rfind("try", 0)) throw; + } +} RetroShell & RetroShell::operator<<(char value) @@ -147,41 +283,33 @@ RetroShell::press(const string &s) void RetroShell::setStream(std::ostream &os) { - current->setStream(os); -} - -void -RetroShell::exec() -{ - // Only proceed of the shell does not process a 'wait' command - if (agnus.hasEvent()) return; - - commander.exec(); - debugger.exec(); + // current->setStream(os); + commander.setStream(os); + debugger.setStream(os); } void RetroShell::exec(const string &command) { - current->asyncExec(command); + asyncExec(command); } void RetroShell::execScript(std::stringstream &ss) { - current->asyncExecScript(ss); + asyncExecScript(ss); } void RetroShell::execScript(const std::ifstream &fs) { - current->asyncExecScript(fs); + asyncExecScript(fs); } void RetroShell::execScript(const string &contents) { - current->asyncExecScript(contents); + asyncExecScript(contents); } void diff --git a/Emulator/Misc/RetroShell/RetroShell.h b/Emulator/Misc/RetroShell/RetroShell.h index 012040277..bbb5a77df 100644 --- a/Emulator/Misc/RetroShell/RetroShell.h +++ b/Emulator/Misc/RetroShell/RetroShell.h @@ -62,6 +62,9 @@ class RetroShell : public SubComponent { private: + // Command queue (stores all pending commands) + std::vector commands; + // The currently active console Console *current = &commander; @@ -116,7 +119,33 @@ class RetroShell : public SubComponent { // void switchConsole(); + void enterDebugger(); + void enterCommander(); + + + // + // Executing commands + // + +public: + + // Adds a command to the list of pending commands + void asyncExec(const string &command); + + // Adds the commands of a shell script to the list of pending commands + void asyncExecScript(std::stringstream &ss) throws; + void asyncExecScript(const std::ifstream &fs) throws; + void asyncExecScript(const string &contents) throws; + + // Aborts the execution of a script + void abortScript(); + + // Executes all pending commands + void exec() throws; + // Executes a single pending command + void exec(QueuedCmd cmd) throws; + // // Bridge functions @@ -138,7 +167,6 @@ class RetroShell : public SubComponent { void press(char c); void press(const string &s); void setStream(std::ostream &os); - void exec(); void exec(const string &command); void execScript(std::stringstream &ss); void execScript(const std::ifstream &fs); diff --git a/Emulator/Misc/RetroShell/TextStorage.cpp b/Emulator/Misc/RetroShell/TextStorage.cpp index 6ae3d6283..dc8674175 100644 --- a/Emulator/Misc/RetroShell/TextStorage.cpp +++ b/Emulator/Misc/RetroShell/TextStorage.cpp @@ -47,6 +47,18 @@ TextStorage::clear() storage.push_back(""); } +bool +TextStorage::isCleared() +{ + return storage.size() == 1 && storage[0].size() == 0; +} + +bool +TextStorage::lastLineIsEmpty() +{ + return storage.back().empty(); +} + void TextStorage::append(const string &line) { diff --git a/Emulator/Misc/RetroShell/TextStorage.h b/Emulator/Misc/RetroShell/TextStorage.h index 7737b751f..fc0c222b1 100644 --- a/Emulator/Misc/RetroShell/TextStorage.h +++ b/Emulator/Misc/RetroShell/TextStorage.h @@ -55,7 +55,13 @@ class TextStorage { // Initializes the storage with a single empty line void clear(); - + + // Returns true if the console is cleared + bool isCleared(); + + // Returns true if the last line contains no text + bool lastLineIsEmpty(); + private: // Appends a new line diff --git a/Emulator/config.cpp b/Emulator/config.cpp index 42caefe6a..fce3f8840 100644 --- a/Emulator/config.cpp +++ b/Emulator/config.cpp @@ -132,7 +132,7 @@ debugflag IMG_DEBUG = 0; // Other components debugflag RTC_DEBUG = 0; debugflag KBD_DEBUG = 0; -debugflag KEY_DEBUG = 1; +debugflag KEY_DEBUG = 0; // Misc debugflag REC_DEBUG = 0;