pubnix/lib/neovision/src/ansi.cpp

219 lines
4.9 KiB
C++

#include <cwctype>
#include <string>
#include <vector>
#include "neovision/ansi.h"
namespace neovision {
namespace ansi {
// AnsiParser ------------------------------------------------------------------
std::wstring AnsiParser::ControlPortion() const
{
return m_controlPortion;
}
std::vector<std::wstring> AnsiParser::CsiParameters() const
{
return m_csiParameters;
}
std::wstring AnsiParser::CsiPortion() const
{
return m_csiPortion;
}
std::wstring AnsiParser::EscapePortion() const
{
return m_escapePortion;
}
bool AnsiParser::Parse(wchar_t c)
{
m_processedChars += c;
if (m_state == ParseState::None) ParseNoneState(c);
if (m_state == ParseState::Control)
{
ParseControlState(c);
}
else if (m_state == ParseState::Escape)
{
ParseEscapeState(c);
}
else if (m_state == ParseState::Csi)
{
ParseCsiState(c);
}
if (m_state == ParseState::Error) return false;
if (m_state == ParseState::None) return false;
return true;
}
void AnsiParser::ParseNoneState(wchar_t c)
{
const std::wstring cwstr{c};
if (ControlCharacters.count(cwstr))
{
m_state = ParseState::Control;
}
else
{
m_state = ParseState::Error;
}
}
void AnsiParser::ParseControlState(wchar_t c)
{
const std::wstring cwstr{c};
if (ControlCharacters.count(cwstr))
{
m_controlPortion += cwstr;
if (cwstr == ControlCharacter::CSI)
m_state = ParseState::Csi;
else if (cwstr == ControlCharacter::ESC)
m_state = ParseState::Escape;
else
m_state = ParseState::None;
return;
}
else
{
m_state = ParseState::Error;
}
}
void AnsiParser::ParseEscapeState(wchar_t c)
{
m_escapePortion += c;
if (EscapeSequences.count(m_escapePortion))
{
if (m_escapePortion == EscapeSequence::CSI)
m_state = ParseState::Csi;
else if (m_escapePortion == EscapeSequence::CSSI)
m_state = ParseState::Cssi;
}
else
{
// Longest possible escape sequence start is 2 characters.
if (m_escapePortion.length() > 2) m_state = ParseState::Error;
}
}
void AnsiParser::ParseCsiState(wchar_t c)
{
const std::wstring cwstr{c};
m_csiPortion += cwstr;
if (CsiSequences.count(cwstr))
{
// If c is a csi sequence char, that would mark the end of the sequence.
if (!m_parameterBuffer.empty())
{
m_csiParameters.emplace_back(m_parameterBuffer);
m_parameterBuffer.clear();
}
m_state = ParseState::None;
}
else
{
/* Characters in the range of 0x30-0x3f are part of a parameter.
If the character is a semi-colon, then we're starting the next
parameter. */
if (c == L';')
{
m_csiParameters.emplace_back(m_parameterBuffer);
m_parameterBuffer.clear();
}
else if ((c >= 0x30) && (c <= 0x3f))
{
m_parameterBuffer += c;
}
else
{
m_state = ParseState::Error;
}
}
}
std::wstring AnsiParser::PmPortion() const
{
return m_pmPortion;
}
std::wstring AnsiParser::ProcessedCharacters() const
{
return m_processedChars;
}
void AnsiParser::Reset()
{
m_controlPortion.clear();
m_escapePortion.clear();
m_csiPortion.clear();
m_csiParameters.clear();
m_csiParameterBuffer.clear();
m_cssiPortion.clear();
m_parameterBuffer.clear();
m_pmPortion.clear();
m_processedChars.clear();
m_state = ParseState::None;
}
AnsiParser::ParseState AnsiParser::State() const
{
return m_state;
}
// Functions -------------------------------------------------------------------
std::wstring MakeEscapeSequence(const std::wstring& sequence)
{
return ControlCharacter::ESC + sequence;
}
std::wstring MakeCssiSequence(const wchar_t sequence)
{
return MakeEscapeSequence(EscapeSequence::CSSI + sequence);
}
std::wstring MakeCsiSequence(const std::vector<std::wstring>& sequenceItems)
{
std::wstring result;
if (!sequenceItems.empty())
{
for (const std::wstring& item: sequenceItems)
{
result += item + L";";
}
result.pop_back();
}
return MakeEscapeSequence(EscapeSequence::CSI + result);
}
std::wstring MakeDecPmSequence(const std::wstring& sequence, const std::wstring& suffix)
{
return MakeCsiSequence({
std::wstring{CsiSequence::DECPM},
sequence,
suffix
});
}
std::wstring MakeSgrSequence(const std::vector<std::wstring>& sequenceItems)
{
std::wstring result;
if (!sequenceItems.empty())
{
for (const std::wstring& item: sequenceItems)
{
result += item + L";";
}
result.pop_back();
}
result += CsiSequence::SGR;
return MakeCsiSequence({result});
}
} // namespace ansi
} // namespace neovision