From d40eacf12edfbd3e73404263fd35a1c9ed57951b Mon Sep 17 00:00:00 2001 From: DarwinNE Date: Tue, 14 Jan 2020 22:46:05 +0100 Subject: [PATCH 1/5] Implement sequence to change the window name. --- Console/ConsoleTest.cc | 3 +- Console/retro/Console.cc | 76 +++++++++++++++++++++++++++++++--- Console/retro/Console.h | 9 ++++ Console/retro/ConsoleWindow.cc | 1 + Console/retro/ConsoleWindow.h | 2 +- 5 files changed, 84 insertions(+), 7 deletions(-) diff --git a/Console/ConsoleTest.cc b/Console/ConsoleTest.cc index b32da0ea83..82faadf9bd 100644 --- a/Console/ConsoleTest.cc +++ b/Console/ConsoleTest.cc @@ -9,7 +9,8 @@ namespace retro int main() { retro::InitConsole(); - std::string out = "Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; + std::string out = "\033]0;Hello world win\007Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; + //std::string out = "Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; retro::Console::currentInstance->write(out.data(), out.size()); std::string in; diff --git a/Console/retro/Console.cc b/Console/retro/Console.cc index 6024a8bcc0..db7ca63be8 100644 --- a/Console/retro/Console.cc +++ b/Console/retro/Console.cc @@ -265,15 +265,80 @@ void Console::ScrollUp(short n) dirtyRect.bottom = dirtyRect.bottom > 0 ? dirtyRect.bottom - 1 : 0; } -void Console::ProcessEscSequence(char c) +void Console::ProcessOSCseq(char c) { switch(sequenceStep) { - case 0: - if(c=='[') - ++sequenceStep; - else + case 1: + if(c!='0') // The only recognized sequence is OSC 0; + { + OSCseq=false; + sequenceStep=0; + return; + } + ++sequenceStep; + break; + case 2: + if(c!=';') // The only recognized sequence is OSC 0; + { + OSCseq=false; + sequenceStep=0; + return; + } + ++sequenceStep; + windowName=" "; + break; + default: + if(c==BEL) // The BEL character ends the sequence. + { + windowName[0]=windowName.length(); + SetWTitle(win, (ConstStringPtr)windowName.c_str()); + OSCseq=false; isProcessingEscSequence=false; + sequenceStep=0; + } + else + { + windowName+=c; + ++sequenceStep; + } + } +} + +void Console::ProcessEscSequence(char c) +{ + if(sequenceStep>0 && OSCseq) + { + ProcessOSCseq(c); + //sequenceStep=0; + //isProcessingEscSequence=false; + return; + } + if(sequenceStep>MAX_LEN) + { + // Sequence is too long! + sequenceStep=0; + isProcessingEscSequence=false; + return; + } + + switch(sequenceStep) + { + case 0: + if(c=='[') // Control Sequence Introducer + { + OSCseq=false; + ++sequenceStep; + } + else if(c==']') // Operating System Command + { + OSCseq=true; + ++sequenceStep; + } + else + { + isProcessingEscSequence=false; + } break; case 1: ++sequenceStep; @@ -305,6 +370,7 @@ void Console::ProcessEscSequence(char c) break; default: sequenceStep=0; + isProcessingEscSequence=false; } } diff --git a/Console/retro/Console.h b/Console/retro/Console.h index cc5df88403..6c08d6abd5 100644 --- a/Console/retro/Console.h +++ b/Console/retro/Console.h @@ -27,6 +27,9 @@ #include #include +#define BEL 7 +#define MAX_LEN 250 + namespace retro { class Attributes @@ -86,6 +89,10 @@ namespace retro void Idle(); bool IsEOF() const { return eof; } + protected: + std::string windowName; + WindowPtr win; + private: GrafPtr consolePort = nullptr; Rect bounds; @@ -94,6 +101,7 @@ namespace retro std::vector chars, onscreen; bool isProcessingEscSequence; int sequenceStep; + bool OSCseq; short cellSizeX; short cellSizeY; @@ -118,6 +126,7 @@ namespace retro void DrawCells(short x1, short x2, short y, bool erase = true); void ScrollUp(short n = 1); void ProcessEscSequence(char c); + void ProcessOSCseq(char c); void SetAttributes(Attributes aa); void InvalidateCursor(); diff --git a/Console/retro/ConsoleWindow.cc b/Console/retro/ConsoleWindow.cc index 5740ede97f..db71f55258 100644 --- a/Console/retro/ConsoleWindow.cc +++ b/Console/retro/ConsoleWindow.cc @@ -36,6 +36,7 @@ ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) { GrafPtr port; //Retro68 Improved Console + windowName="Retro68 Console"; win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0); #if !TARGET_API_MAC_CARBON diff --git a/Console/retro/ConsoleWindow.h b/Console/retro/ConsoleWindow.h index e3d71c33bd..1b787dc769 100644 --- a/Console/retro/ConsoleWindow.h +++ b/Console/retro/ConsoleWindow.h @@ -35,7 +35,7 @@ namespace retro ConsoleWindow(Rect r, ConstStr255Param title); ~ConsoleWindow(); private: - WindowPtr win; + //WindowPtr win; virtual char WaitNextChar(); }; From 9cf5c41ad7a4627ed32af8080d306098156ced2e Mon Sep 17 00:00:00 2001 From: DarwinNE Date: Thu, 16 Jan 2020 00:01:26 +0100 Subject: [PATCH 2/5] Add a virtual function to the Console class so that it does not need to keep track of the window. --- Console/retro/Console.cc | 5 ++--- Console/retro/Console.h | 7 ++++--- Console/retro/ConsoleWindow.cc | 13 +++++++++++-- Console/retro/ConsoleWindow.h | 4 +++- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Console/retro/Console.cc b/Console/retro/Console.cc index db7ca63be8..f934146055 100644 --- a/Console/retro/Console.cc +++ b/Console/retro/Console.cc @@ -286,13 +286,12 @@ void Console::ProcessOSCseq(char c) return; } ++sequenceStep; - windowName=" "; + windowName=""; break; default: if(c==BEL) // The BEL character ends the sequence. { - windowName[0]=windowName.length(); - SetWTitle(win, (ConstStringPtr)windowName.c_str()); + setWindowName(windowName); OSCseq=false; isProcessingEscSequence=false; sequenceStep=0; diff --git a/Console/retro/Console.h b/Console/retro/Console.h index 6c08d6abd5..c30e7cb7b3 100644 --- a/Console/retro/Console.h +++ b/Console/retro/Console.h @@ -86,14 +86,15 @@ namespace retro short GetRows() const { return rows; } short GetCols() const { return cols; } + virtual void setWindowName(std::string newName) {}; + + void Idle(); bool IsEOF() const { return eof; } - protected: - std::string windowName; - WindowPtr win; private: + std::string windowName; GrafPtr consolePort = nullptr; Rect bounds; Attributes currentAttr; diff --git a/Console/retro/ConsoleWindow.cc b/Console/retro/ConsoleWindow.cc index db71f55258..5ff92023ba 100644 --- a/Console/retro/ConsoleWindow.cc +++ b/Console/retro/ConsoleWindow.cc @@ -36,8 +36,9 @@ ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) { GrafPtr port; //Retro68 Improved Console - windowName="Retro68 Console"; - win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0); + win = NewWindow(NULL, &r, "\p", true, 0, (WindowPtr)-1, true, 0); + setWindowName("Retro68 Console"); + #if !TARGET_API_MAC_CARBON port = win; @@ -64,6 +65,14 @@ ConsoleWindow::~ConsoleWindow() DisposeWindow(win); } +void ConsoleWindow::setWindowName(std::string newName) +{ + newName=" "+newName; // Convert into Pascal string + newName[0]=newName.length(); + SetWTitle(win, (ConstStringPtr)newName.c_str()); +} + + char ConsoleWindow::WaitNextChar() { EventRecord event; diff --git a/Console/retro/ConsoleWindow.h b/Console/retro/ConsoleWindow.h index 1b787dc769..7756beff83 100644 --- a/Console/retro/ConsoleWindow.h +++ b/Console/retro/ConsoleWindow.h @@ -34,8 +34,10 @@ namespace retro public: ConsoleWindow(Rect r, ConstStr255Param title); ~ConsoleWindow(); + void setWindowName(std::string newName); + private: - //WindowPtr win; + WindowPtr win; virtual char WaitNextChar(); }; From 5f30a05a3437c8dd1383d5c38f2df606a4dc578f Mon Sep 17 00:00:00 2001 From: DarwinNE Date: Thu, 16 Jan 2020 00:11:56 +0100 Subject: [PATCH 3/5] Slightly better strategy to convert C strings to Pascal-style ones. --- Console/ConsoleTest.cc | 2 +- Console/retro/Console.cc | 6 +++--- Console/retro/ConsoleWindow.cc | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Console/ConsoleTest.cc b/Console/ConsoleTest.cc index 82faadf9bd..7d02558f4b 100644 --- a/Console/ConsoleTest.cc +++ b/Console/ConsoleTest.cc @@ -12,7 +12,7 @@ int main() std::string out = "\033]0;Hello world win\007Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; //std::string out = "Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; retro::Console::currentInstance->write(out.data(), out.size()); - + std::string in; do { diff --git a/Console/retro/Console.cc b/Console/retro/Console.cc index f934146055..9fea2fb5f2 100644 --- a/Console/retro/Console.cc +++ b/Console/retro/Console.cc @@ -270,7 +270,7 @@ void Console::ProcessOSCseq(char c) switch(sequenceStep) { case 1: - if(c!='0') // The only recognized sequence is OSC 0; + if(c!='0') // The only recognized sequence is OSC 0; { OSCseq=false; sequenceStep=0; @@ -279,7 +279,7 @@ void Console::ProcessOSCseq(char c) ++sequenceStep; break; case 2: - if(c!=';') // The only recognized sequence is OSC 0; + if(c!=';') // The only recognized sequence is OSC 0; { OSCseq=false; sequenceStep=0; @@ -333,7 +333,7 @@ void Console::ProcessEscSequence(char c) { OSCseq=true; ++sequenceStep; - } + } else { isProcessingEscSequence=false; diff --git a/Console/retro/ConsoleWindow.cc b/Console/retro/ConsoleWindow.cc index 5ff92023ba..367d00c45f 100644 --- a/Console/retro/ConsoleWindow.cc +++ b/Console/retro/ConsoleWindow.cc @@ -24,6 +24,7 @@ #include "ConsoleWindow.h" #include "Events.h" #include +#include using namespace retro; @@ -67,9 +68,20 @@ ConsoleWindow::~ConsoleWindow() void ConsoleWindow::setWindowName(std::string newName) { - newName=" "+newName; // Convert into Pascal string - newName[0]=newName.length(); - SetWTitle(win, (ConstStringPtr)newName.c_str()); + Str255 pname; +#if TARGET_API_MAC_CARBON + // Carbon has the new, sane version. + c2pstrcpy(pname,newName.c_str()); +#else + // It is also availble in various glue code libraries and + // in some versions of InterfaceLib, but it's confusing. + // Using the inplace variant, c2pstr, isn't much better than + // doing things by hand: + strncpy((char *)&pname[1],newName.c_str(),255); + pname[0] = newName.length(); +#endif + + SetWTitle(win, pname); } From 46a380b89ae7ec50d728b65df37c37479f127b4f Mon Sep 17 00:00:00 2001 From: DarwinNE Date: Sat, 18 Jan 2020 00:33:55 +0100 Subject: [PATCH 4/5] Implement suggestions from the code review of the pull request #103. --- Console/ConsoleTest.cc | 2 +- Console/readme.txt | 15 ++-- Console/retro/Console.cc | 142 +++++++++++++-------------------- Console/retro/Console.h | 23 +++--- Console/retro/ConsoleWindow.cc | 5 +- 5 files changed, 78 insertions(+), 109 deletions(-) diff --git a/Console/ConsoleTest.cc b/Console/ConsoleTest.cc index 7d02558f4b..ce8fa7e896 100644 --- a/Console/ConsoleTest.cc +++ b/Console/ConsoleTest.cc @@ -10,7 +10,7 @@ int main() { retro::InitConsole(); std::string out = "\033]0;Hello world win\007Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; - //std::string out = "Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n"; + retro::Console::currentInstance->write(out.data(), out.size()); std::string in; diff --git a/Console/readme.txt b/Console/readme.txt index 6abd8b4d30..b3ddcdcb95 100644 --- a/Console/readme.txt +++ b/Console/readme.txt @@ -1,17 +1,18 @@ - IConsole + Console -This is a slightly improved version of Retro68's Console library, offering a -support for a subset of ANSI control sequences. +This library provides a simple console library, offering a limited support for ANSI control sequences. Here is a list of the supported sequences and their meaning: -ESC[0m Reset all text style -ESC[1m Bold font (*) -ESC[3m Italic font -ESC[4m Underline font +ESC[0m Reset all text style +ESC[1m Bold font (*) +ESC[3m Italic font +ESC[4m Underline font +ESC]0;NewnameBEL Set the window title to "Newname" (**) NOTES: (*) Obtained with bold + condense style together, so that the character grid remains regular (this way, the width of bold characters remains the same as regular ones). +(**) BEL is ASCII character 7. diff --git a/Console/retro/Console.cc b/Console/retro/Console.cc index 9fea2fb5f2..cb11ced0a8 100644 --- a/Console/retro/Console.cc +++ b/Console/retro/Console.cc @@ -30,6 +30,9 @@ using namespace retro; +const char BEL = 7; +const char MAX_LEN = 250; + Console *Console::currentInstance = NULL; Attributes::Attributes(void) @@ -162,7 +165,7 @@ void Console::Init(GrafPtr port, Rect r) onscreen = chars; cursorX = cursorY = 0; - isProcessingEscSequence=false; + sequenceState=State::noSequence; } void Console::SetAttributes(Attributes aa) @@ -265,82 +268,22 @@ void Console::ScrollUp(short n) dirtyRect.bottom = dirtyRect.bottom > 0 ? dirtyRect.bottom - 1 : 0; } -void Console::ProcessOSCseq(char c) +bool Console::ProcessEscSequence(char c) { - switch(sequenceStep) + switch(sequenceState) { - case 1: - if(c!='0') // The only recognized sequence is OSC 0; - { - OSCseq=false; - sequenceStep=0; - return; - } - ++sequenceStep; - break; - case 2: - if(c!=';') // The only recognized sequence is OSC 0; - { - OSCseq=false; - sequenceStep=0; - return; - } - ++sequenceStep; - windowName=""; - break; - default: - if(c==BEL) // The BEL character ends the sequence. - { - setWindowName(windowName); - OSCseq=false; - isProcessingEscSequence=false; - sequenceStep=0; - } + case State::noSequence: + return false; // Break is not needed there. + case State::waitingForSequenceStart: + if(c=='[') + sequenceState=State::waitingForControlSequence; + else if(c==']') + sequenceState=State::waitingForOSCStart; else - { - windowName+=c; - ++sequenceStep; - } - } -} - -void Console::ProcessEscSequence(char c) -{ - if(sequenceStep>0 && OSCseq) - { - ProcessOSCseq(c); - //sequenceStep=0; - //isProcessingEscSequence=false; - return; - } - if(sequenceStep>MAX_LEN) - { - // Sequence is too long! - sequenceStep=0; - isProcessingEscSequence=false; - return; - } - - switch(sequenceStep) - { - case 0: - if(c=='[') // Control Sequence Introducer - { - OSCseq=false; - ++sequenceStep; - } - else if(c==']') // Operating System Command - { - OSCseq=true; - ++sequenceStep; - } - else - { - isProcessingEscSequence=false; - } + sequenceState=State::noSequence; // Unrecognized sequence break; - case 1: - ++sequenceStep; + case State::waitingForControlSequence: + sequenceState=State::waitingForM; switch(c) { case '0': // Normal character @@ -356,36 +299,61 @@ void Console::ProcessEscSequence(char c) currentAttr.setUnderline(true); break; default: - isProcessingEscSequence=false; + sequenceState=State::noSequence; // Unrecognized sequence } break; - case 2: + case State::waitingForM: if(c=='m') - isProcessingEscSequence=false; - else if(c==';') - sequenceStep=1; + sequenceState=State::noSequence; // Normal end of sequence else - isProcessingEscSequence=false; + sequenceState=State::noSequence; // Unrecognized sequence (but we end it anyway!) + break; + case State::waitingForOSCStart: + if(c=='0') + sequenceState=State::waitingForSemicolon; + else + sequenceState=State::noSequence; // Normal end of sequence + break; + case State::waitingForSemicolon: + if(c==';') + { + sequenceState=State::inWindowName; + windowName=""; + } + else + sequenceState=State::noSequence; // Normal end of sequence + break; + case State::inWindowName: + if(c==BEL) + { + setWindowName(std::move(windowName)); + sequenceState=State::noSequence; // Normal end of sequence + } + else + { + if(windowName.size() < MAX_LEN) + windowName+=c; + } break; default: - sequenceStep=0; - isProcessingEscSequence=false; + sequenceState=State::noSequence; + break; } + return true; } void Console::PutCharNoUpdate(char c) { - if(isProcessingEscSequence) - { - ProcessEscSequence(c); + if(ProcessEscSequence(c)) return; - } + InvalidateCursor(); switch(c) { case '\033': // Begin of an ANSI escape sequence - isProcessingEscSequence=true; - sequenceStep=0; + //isProcessingEscSequence=true; + //sequenceStep=0; + sequenceState=State::waitingForSequenceStart; break; case '\r': cursorX = 0; diff --git a/Console/retro/Console.h b/Console/retro/Console.h index c30e7cb7b3..7ace8b3500 100644 --- a/Console/retro/Console.h +++ b/Console/retro/Console.h @@ -27,9 +27,6 @@ #include #include -#define BEL 7 -#define MAX_LEN 250 - namespace retro { class Attributes @@ -62,8 +59,16 @@ namespace retro AttributedChar(char cc, Attributes aa) {c=cc; attrs=aa;} }; -// inline bool operator==(const Attributes& lhs, const Attributes& rhs); -// inline bool operator!=(const Attributes& lhs, const Attributes& rhs); + enum class State + { + noSequence, + waitingForSequenceStart, + waitingForControlSequence, + waitingForM, + waitingForOSCStart, + waitingForSemicolon, + inWindowName + }; class Console { @@ -94,15 +99,14 @@ namespace retro bool IsEOF() const { return eof; } private: + + State sequenceState; std::string windowName; GrafPtr consolePort = nullptr; Rect bounds; Attributes currentAttr; std::vector chars, onscreen; - bool isProcessingEscSequence; - int sequenceStep; - bool OSCseq; short cellSizeX; short cellSizeY; @@ -126,8 +130,7 @@ namespace retro void DrawCell(short x, short y, bool erase = true); void DrawCells(short x1, short x2, short y, bool erase = true); void ScrollUp(short n = 1); - void ProcessEscSequence(char c); - void ProcessOSCseq(char c); + bool ProcessEscSequence(char c); void SetAttributes(Attributes aa); void InvalidateCursor(); diff --git a/Console/retro/ConsoleWindow.cc b/Console/retro/ConsoleWindow.cc index 367d00c45f..cc29e6f262 100644 --- a/Console/retro/ConsoleWindow.cc +++ b/Console/retro/ConsoleWindow.cc @@ -36,10 +36,7 @@ namespace ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) { GrafPtr port; - //Retro68 Improved Console - win = NewWindow(NULL, &r, "\p", true, 0, (WindowPtr)-1, true, 0); - setWindowName("Retro68 Console"); - + win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0); #if !TARGET_API_MAC_CARBON port = win; From 812831c24f964b9e5f4b7c8338a88c52df6f9e70 Mon Sep 17 00:00:00 2001 From: DarwinNE Date: Sun, 19 Jan 2020 00:38:33 +0100 Subject: [PATCH 5/5] Correct a missing header that would have made impossible to compile the code with Carbon. Remove commented out code. --- Console/retro/Console.cc | 4 +--- Console/retro/ConsoleWindow.cc | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Console/retro/Console.cc b/Console/retro/Console.cc index cb11ced0a8..4328964d58 100644 --- a/Console/retro/Console.cc +++ b/Console/retro/Console.cc @@ -331,7 +331,7 @@ bool Console::ProcessEscSequence(char c) } else { - if(windowName.size() < MAX_LEN) + if(windowName.size() < MAX_LEN) // Ignore subsequent characters windowName+=c; } break; @@ -351,8 +351,6 @@ void Console::PutCharNoUpdate(char c) switch(c) { case '\033': // Begin of an ANSI escape sequence - //isProcessingEscSequence=true; - //sequenceStep=0; sequenceState=State::waitingForSequenceStart; break; case '\r': diff --git a/Console/retro/ConsoleWindow.cc b/Console/retro/ConsoleWindow.cc index cc29e6f262..41effd229a 100644 --- a/Console/retro/ConsoleWindow.cc +++ b/Console/retro/ConsoleWindow.cc @@ -25,6 +25,7 @@ #include "Events.h" #include #include +#include using namespace retro;