2525#include " MacUtils.h"
2626#include " Fonts.h"
2727#include " Processes.h"
28-
28+ # include < cctype >
2929#include < algorithm>
30+ #include < stack>
31+ #include < sstream>
3032
3133using namespace retro ;
3234
@@ -131,11 +133,13 @@ namespace
131133
132134Console::Console ()
133135{
136+ InitEscapeSequenceMap ();
134137}
135138
136139Console::Console (GrafPtr port, Rect r)
137140{
138141 Init (port, r);
142+ InitEscapeSequenceMap ();
139143}
140144
141145Console::~Console ()
@@ -283,30 +287,7 @@ bool Console::ProcessEscSequence(char c)
283287 sequenceState=State::noSequence; // Unrecognized sequence
284288 break ;
285289 case State::waitingForControlSequence:
286- sequenceState=State::waitingForM;
287- switch (c)
288- {
289- case ' 0' : // Normal character
290- currentAttr.reset ();
291- break ;
292- case ' 1' : // Bold
293- currentAttr.setBold (true );
294- break ;
295- case ' 3' : // Italic
296- currentAttr.setItalic (true );
297- break ;
298- case ' 4' : // Underline
299- currentAttr.setUnderline (true );
300- break ;
301- default :
302- sequenceState=State::noSequence; // Unrecognized sequence
303- }
304- break ;
305- case State::waitingForM:
306- if (c==' m' )
307- sequenceState=State::noSequence; // Normal end of sequence
308- else
309- sequenceState=State::noSequence; // Unrecognized sequence (but we end it anyway!)
290+ HandleControlSequence (c);
310291 break ;
311292 case State::waitingForOSCStart:
312293 if (c==' 0' )
@@ -318,21 +299,21 @@ bool Console::ProcessEscSequence(char c)
318299 if (c==' ;' )
319300 {
320301 sequenceState=State::inWindowName;
321- windowName= " " ;
302+ argument = " " ;
322303 }
323304 else
324305 sequenceState=State::noSequence; // Normal end of sequence
325306 break ;
326307 case State::inWindowName:
327308 if (c==BEL)
328309 {
329- setWindowName (std::move (windowName ));
310+ setWindowName (std::move (argument ));
330311 sequenceState=State::noSequence; // Normal end of sequence
331312 }
332313 else
333314 {
334- if (windowName .size () < MAX_LEN) // Ignore subsequent characters
335- windowName +=c;
315+ if (argument .size () < MAX_LEN) // Ignore subsequent characters
316+ argument +=c;
336317 }
337318 break ;
338319 default :
@@ -561,3 +542,171 @@ char Console::WaitNextChar()
561542{
562543 return 0 ;
563544}
545+
546+ // Map a letter to a function
547+ void Console::InitEscapeSequenceMap ()
548+ {
549+ escapeSequenceMap.insert ({' H' , [&](std::string args) { Console::SetCursorPosition (args); } });
550+ escapeSequenceMap.insert ({' J' , [&](std::string args) { EraseInDisplay (args); } });
551+ escapeSequenceMap.insert ({' m' , [&](std::string args) { SetDisplayAttributes (args); } });
552+ }
553+
554+ // turns an argument string into numbers
555+ // example: "12;13" would return a vector with numbers 12 and 13
556+ static std::vector<int > parseArguments (std::string str) {
557+ std::istringstream iss (str);
558+ std::string token;
559+ std::vector<int > numberVector;
560+ while (getline (iss, token, ' ;' ))
561+ {
562+ if (token == " " )
563+ {
564+ numberVector.push_back (1 );
565+ }
566+ else
567+ {
568+ numberVector.push_back (atoi (token.c_str ()));
569+ }
570+ }
571+
572+ while (numberVector.size () < 2 )
573+ numberVector.push_back (1 );
574+
575+ return numberVector;
576+ }
577+
578+ // Bound to ANSI escape code H
579+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
580+ // Section: Control Sequence Introducer commands
581+ // Name: Cursor Position
582+ void Console::SetCursorPosition (std::string args)
583+ {
584+ // possible formats the arguments can be in:
585+ // n -> (1,n)
586+ // n;m. -> (m,n)
587+ // n;m; -> (m,n)
588+ // n; -> (1,n)
589+ // ;m -> (m,1)
590+ // -> (1,1)
591+
592+ auto numberVector = parseArguments (args);
593+ cursorX = numberVector.at (1 );
594+ cursorY = numberVector.at (0 );
595+ Update ();
596+ }
597+
598+ // Bound to ANSI escape code J
599+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
600+ // Section: Control Sequence Introducer commands
601+ // Name: Erase in Display
602+ void Console::EraseInDisplay (std::string args)
603+ {
604+ int n;
605+ if (args == " " )
606+ n = 0 ;
607+ else
608+ n = atoi (args.c_str ());
609+
610+ switch (n) {
611+ case 0 : // clear from cursor to end of window
612+ ClearFromCursorToEndOfWindow ();
613+ break ;
614+
615+ case 1 : // clear from cursor to beginning of the window
616+ ClearFromTopOfWindowToCursor ();
617+ break ;
618+
619+ case 2 : // clear entire screen
620+ ClearWindow ();
621+ break ;
622+
623+ case 3 : // clear entire screen and delete all lines saved in the scrollback buffer
624+ ClearWindow ();
625+ break ;
626+ }
627+ }
628+
629+ // Sets attributes of characters
630+ // Note: only a few attributes are currently implemented
631+ // Bound to ANSI escape code m
632+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
633+ // Section: Select Graphic Rendition parameters
634+ void Console::SetDisplayAttributes (std::string args)
635+ {
636+ char c = args.c_str ()[0 ];
637+ switch (c)
638+ {
639+ case ' 0' : // Normal character
640+ currentAttr.reset ();
641+ break ;
642+ case ' 1' : // Bold
643+ currentAttr.setBold (true );
644+ break ;
645+ case ' 3' : // Italic
646+ currentAttr.setItalic (true );
647+ break ;
648+ case ' 4' : // Underline
649+ currentAttr.setUnderline (true );
650+ break ;
651+ }
652+ }
653+
654+ // Clears the window of all text
655+ void Console::ClearWindow ()
656+ {
657+ // Fill the buffer with blank spaces
658+ std::fill (chars.begin (), chars.end (), AttributedChar (' ' , currentAttr));
659+ std::fill (onscreen.begin (), onscreen.end (), AttributedChar (' ' , currentAttr));
660+
661+ // Erase the window
662+ EraseRect (&bounds);
663+ Update ();
664+ Draw (bounds);
665+ }
666+
667+ // Clears the window of text from the current cursor position to the bottom of the window
668+ void Console::ClearFromCursorToEndOfWindow ()
669+ {
670+ int newPosition = cursorY * cols + cursorX;
671+
672+ // Fill the buffer with blank spaces
673+ std::fill (chars.begin () + newPosition, chars.end (), AttributedChar (' ' , currentAttr));
674+ std::fill (onscreen.begin () + newPosition, onscreen.end (), AttributedChar (' ' , currentAttr));
675+
676+ // Erase the window
677+ EraseRect (&bounds);
678+ Update ();
679+ Draw (bounds);
680+ }
681+
682+ // Clears the window from the top to the current cursor position
683+ void Console::ClearFromTopOfWindowToCursor ()
684+ {
685+ int newPosition = cursorY * cols + cursorX;
686+
687+ // Fill the buffer with blank spaces
688+ std::fill (chars.begin (), chars.begin () + newPosition, AttributedChar (' ' , currentAttr));
689+ std::fill (onscreen.begin (), onscreen.begin () + newPosition, AttributedChar (' ' , currentAttr));
690+
691+ // Erase the window
692+ EraseRect (&bounds);
693+ Update ();
694+ Draw (bounds);
695+ }
696+
697+ // handles the waitingForControlSequence state
698+ void Console::HandleControlSequence (char c)
699+ {
700+ if (isalpha (c))
701+ {
702+ auto escFunc = escapeSequenceMap.at (c);
703+ escFunc (argument);
704+ sequenceState=State::noSequence;
705+ argument = " " ;
706+ }
707+
708+ else
709+ {
710+ argument = argument + c;
711+ }
712+ }
0 commit comments