/** * @file EscapeSequence.cpp * @author apio (cloudapio.eu) * @brief ANSI escape sequence parsing. * * @copyright Copyright (c) 2023, the Luna authors. * */ #include #include #include #include EscapeSequenceParser::EscapeSequenceParser(u8 begin) { switch (begin) { case 0x1b: m_sequence_type = SequenceType::ESC; break; case 0x9b: m_sequence_type = SequenceType::CSI; break; case 0x90: m_sequence_type = SequenceType::DCS; break; case 0x9d: m_sequence_type = SequenceType::OSC; break; default: fail("Unrecognized escape sequence type"); } } Result EscapeSequenceParser::advance(u8 byte) { switch (m_sequence_type) { case SequenceType::ESC: { switch (byte) { case '[': { m_sequence_type = SequenceType::CSI; return false; }; case 'P': { m_sequence_type = SequenceType::DCS; return false; }; case ']': { m_sequence_type = SequenceType::OSC; return false; }; case '7': { m_escape_code = EscapeCode::SaveCursor; m_valid = true; return true; }; case '8': { m_escape_code = EscapeCode::RestoreCursor; m_valid = true; return true; }; default: { m_valid = false; return true; } } }; break; case SequenceType::CSI: { if (_isdigit(byte)) { m_parsing_parameter = true; TRY(m_parameter.try_append(byte)); return false; } if (!m_parsing_parameter && byte == ';') { TRY(m_parameters.try_append(0)); return false; } if (m_parsing_parameter) { TRY(m_parameter.try_append(0)); int value = static_cast(parse_unsigned_integer((const char*)m_parameter.data(), nullptr, 10)); m_parameter.clear(); TRY(m_parameters.try_append(value)); } switch (byte) { case 'A': { m_escape_code = EscapeCode::CursorUp; m_valid = true; return true; }; case 'B': { m_escape_code = EscapeCode::CursorDown; m_valid = true; return true; }; case 'C': { m_escape_code = EscapeCode::CursorForward; m_valid = true; return true; }; case 'D': { m_escape_code = EscapeCode::CursorBack; m_valid = true; return true; }; case 'E': { m_escape_code = EscapeCode::CursorNextLine; m_valid = true; return true; }; case 'F': { m_escape_code = EscapeCode::CursorPreviousLine; m_valid = true; return true; }; case 'G': { m_escape_code = EscapeCode::CursorHorizontalAbsolute; m_valid = true; return true; }; case 'H': { m_escape_code = EscapeCode::SetCursorPosition; m_valid = true; return true; }; case 'm': { m_escape_code = EscapeCode::SelectGraphicRendition; m_valid = true; return true; }; case ';': { return false; }; default: { m_valid = false; return true; } } }; break; case SequenceType::DCS: todo(); case SequenceType::OSC: todo(); default: todo(); } }