Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/terminal/adapter/ITermDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Microsoft::Console::VirtualTerminal
class Microsoft::Console::VirtualTerminal::ITermDispatch
{
public:
using StringHandler = std::function<bool(const wchar_t)>;
using StringHandler = std::function<bool(std::wstring_view)>;

enum class OptionalFeature
{
Expand Down
150 changes: 77 additions & 73 deletions src/terminal/adapter/MacroBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,92 +113,96 @@ bool MacroBuffer::InitParser(const size_t macroId, const DispatchTypes::MacroDel
return false;
}

bool MacroBuffer::ParseDefinition(const wchar_t ch)
bool MacroBuffer::ParseDefinition(const std::wstring_view str)
{
// Once we receive an ESC, that marks the end of the definition, but if
// an unterminated repeat is still pending, we should apply that now.
if (ch == AsciiChars::ESC)
for (const auto ch : str)
{
if (_repeatPending && !_applyPendingRepeat())
// Once we receive an ESC, that marks the end of the definition, but if
// an unterminated repeat is still pending, we should apply that now.
if (ch == AsciiChars::ESC)
{
_deleteMacro(_activeMacro());
if (_repeatPending && !_applyPendingRepeat())
{
_deleteMacro(_activeMacro());
}
return false;
}
return false;
}

// Any other control characters are just ignored.
if (ch < L' ')
{
return true;
}

// For "text encoded" macros, we'll always be in the ExpectingText state.
// For "hex encoded" macros, we'll typically be alternating between the
// ExpectingHexDigit and ExpectingSecondHexDigit states as we parse the two
// digits of each hex pair. But we also need to deal with repeat sequences,
// which start with `!`, followed by a numeric repeat count, and then a
// range of hex pairs between two `;` characters. When parsing the repeat
// count, we use the ExpectingRepeatCount state, but when parsing the hex
// pairs of the repeat, we just use the regular ExpectingHexDigit states.

auto success = true;
switch (_parseState)
{
case State::ExpectingText:
success = _appendToActiveMacro(ch);
break;
case State::ExpectingHexDigit:
if (_decodeHexDigit(ch))
// Any other control characters are just ignored.
if (ch < L' ')
{
_parseState = State::ExpectingSecondHexDigit;
}
else if (ch == L'!' && !_repeatPending)
{
_parseState = State::ExpectingRepeatCount;
_repeatCount = 0;
}
else if (ch == L';' && _repeatPending)
{
success = _applyPendingRepeat();
}
else
{
success = false;
}
break;
case State::ExpectingSecondHexDigit:
success = _decodeHexDigit(ch) && _appendToActiveMacro(_decodedChar);
_decodedChar = 0;
_parseState = State::ExpectingHexDigit;
break;
case State::ExpectingRepeatCount:
if (ch >= L'0' && ch <= L'9')
{
_repeatCount = _repeatCount * 10 + (ch - L'0');
_repeatCount = std::min<size_t>(_repeatCount, MAX_PARAMETER_VALUE);
return true;
}
else if (ch == L';')

// For "text encoded" macros, we'll always be in the ExpectingText state.
// For "hex encoded" macros, we'll typically be alternating between the
// ExpectingHexDigit and ExpectingSecondHexDigit states as we parse the two
// digits of each hex pair. But we also need to deal with repeat sequences,
// which start with `!`, followed by a numeric repeat count, and then a
// range of hex pairs between two `;` characters. When parsing the repeat
// count, we use the ExpectingRepeatCount state, but when parsing the hex
// pairs of the repeat, we just use the regular ExpectingHexDigit states.

auto success = true;
switch (_parseState)
{
_repeatPending = true;
_repeatStart = _activeMacro().length();
case State::ExpectingText:
success = _appendToActiveMacro(ch);
break;
case State::ExpectingHexDigit:
if (_decodeHexDigit(ch))
{
_parseState = State::ExpectingSecondHexDigit;
}
else if (ch == L'!' && !_repeatPending)
{
_parseState = State::ExpectingRepeatCount;
_repeatCount = 0;
}
else if (ch == L';' && _repeatPending)
{
success = _applyPendingRepeat();
}
else
{
success = false;
}
break;
case State::ExpectingSecondHexDigit:
success = _decodeHexDigit(ch) && _appendToActiveMacro(_decodedChar);
_decodedChar = 0;
_parseState = State::ExpectingHexDigit;
}
else
{
break;
case State::ExpectingRepeatCount:
if (ch >= L'0' && ch <= L'9')
{
_repeatCount = _repeatCount * 10 + (ch - L'0');
_repeatCount = std::min<size_t>(_repeatCount, MAX_PARAMETER_VALUE);
}
else if (ch == L';')
{
_repeatPending = true;
_repeatStart = _activeMacro().length();
_parseState = State::ExpectingHexDigit;
}
else
{
success = false;
}
break;
default:
success = false;
break;
}
break;
default:
success = false;
break;
}

// If there is an error in the definition, clear everything received so far.
if (!success)
{
_deleteMacro(_activeMacro());
// If there is an error in the definition, clear everything received so far.
if (!success)
{
_deleteMacro(_activeMacro());
return false;
}
}
return success;
return true;
}

bool MacroBuffer::_decodeHexDigit(const wchar_t ch) noexcept
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/MacroBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace Microsoft::Console::VirtualTerminal
void InvokeMacro(const size_t macroId, StateMachine& stateMachine);
void ClearMacrosIfInUse();
bool InitParser(const size_t macroId, const DispatchTypes::MacroDeleteControl deleteControl, const DispatchTypes::MacroEncoding encoding);
bool ParseDefinition(const wchar_t ch);
bool ParseDefinition(std::wstring_view str);

private:
bool _decodeHexDigit(const wchar_t ch) noexcept;
Expand Down
22 changes: 15 additions & 7 deletions src/terminal/adapter/SixelParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ size_t SixelParser::MaxColorsForLevel(const VTInt conformanceLevel) noexcept
}
}

SixelParser::SixelParser(AdaptDispatch& dispatcher, const StateMachine& stateMachine, const VTInt conformanceLevel) noexcept :
SixelParser::SixelParser(AdaptDispatch& dispatcher, const VTInt conformanceLevel) noexcept :
_dispatcher{ dispatcher },
_stateMachine{ stateMachine },
_conformanceLevel{ conformanceLevel },
_cellSize{ CellSizeForLevel(conformanceLevel) },
_maxColors{ MaxColorsForLevel(conformanceLevel) }
Expand Down Expand Up @@ -80,7 +79,7 @@ void SixelParser::SetDisplayMode(const bool enabled) noexcept
}
}

std::function<bool(wchar_t)> SixelParser::DefineImage(const VTInt macroParameter, const DispatchTypes::SixelBackground backgroundSelect, const VTParameter backgroundColor)
std::function<bool(std::wstring_view)> SixelParser::DefineImage(const VTInt macroParameter, const DispatchTypes::SixelBackground backgroundSelect, const VTParameter backgroundColor)
{
if (_initTextBufferBoundaries())
{
Expand All @@ -89,8 +88,17 @@ std::function<bool(wchar_t)> SixelParser::DefineImage(const VTInt macroParameter
_initImageBuffer();
_state = States::Normal;
_parameters.clear();
return [&](const auto ch) {
_parseCommandChar(ch);
return [&](const std::wstring_view str) {
auto it = str.begin();
const auto end = str.end();

while (it != end)
{
const auto ch = *it++;
_isProcessingLastCharacter = it == end;
_parseCommandChar(ch);
}

return true;
};
}
Expand Down Expand Up @@ -554,7 +562,7 @@ void SixelParser::_defineColor(const size_t colorNumber, const COLORREF color)
// If some image content has already been defined at this point, and
// we're processing the last character in the packet, this is likely an
// attempt to animate the palette, so we should flush the image.
if (_imageWidth > 0 && _stateMachine.IsProcessingLastCharacter())
if (_imageWidth > 0 && _isProcessingLastCharacter)
{
_maybeFlushImageBuffer();
}
Expand Down Expand Up @@ -876,7 +884,7 @@ void SixelParser::_maybeFlushImageBuffer(const bool endOfSequence)
const auto currentTime = steady_clock::now();
const auto timeSinceLastFlush = duration_cast<milliseconds>(currentTime - _lastFlushTime);
const auto linesSinceLastFlush = _imageLineCount - _lastFlushLine;
if (endOfSequence || timeSinceLastFlush > 500ms || (linesSinceLastFlush <= 1 && _stateMachine.IsProcessingLastCharacter()))
if (endOfSequence || timeSinceLastFlush > 500ms || (linesSinceLastFlush <= 1 && _isProcessingLastCharacter))
{
_lastFlushTime = currentTime;
_lastFlushLine = _imageLineCount;
Expand Down
7 changes: 3 additions & 4 deletions src/terminal/adapter/SixelParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace Microsoft::Console::VirtualTerminal
{
class AdaptDispatch;
class Page;
class StateMachine;

class SixelParser
{
Expand All @@ -31,10 +30,10 @@ namespace Microsoft::Console::VirtualTerminal
static til::size CellSizeForLevel(const VTInt conformanceLevel = DefaultConformance) noexcept;
static size_t MaxColorsForLevel(const VTInt conformanceLevel = DefaultConformance) noexcept;

SixelParser(AdaptDispatch& dispatcher, const StateMachine& stateMachine, const VTInt conformanceLevel = DefaultConformance) noexcept;
SixelParser(AdaptDispatch& dispatcher, const VTInt conformanceLevel = DefaultConformance) noexcept;
void SoftReset();
void SetDisplayMode(const bool enabled) noexcept;
std::function<bool(wchar_t)> DefineImage(const VTInt macroParameter, const DispatchTypes::SixelBackground backgroundSelect, const VTParameter backgroundColor);
std::function<bool(std::wstring_view)> DefineImage(const VTInt macroParameter, const DispatchTypes::SixelBackground backgroundSelect, const VTParameter backgroundColor);

private:
// NB: If we want to support more than 256 colors, we'll also need to
Expand All @@ -49,7 +48,6 @@ namespace Microsoft::Console::VirtualTerminal
};

AdaptDispatch& _dispatcher;
const StateMachine& _stateMachine;
const VTInt _conformanceLevel;

void _parseCommandChar(const wchar_t ch);
Expand Down Expand Up @@ -106,6 +104,7 @@ namespace Microsoft::Console::VirtualTerminal
size_t _colorsAvailable = 0;
IndexedPixel _foregroundPixel = {};
bool _colorTableChanged = false;
bool _isProcessingLastCharacter = false;

void _initImageBuffer();
void _resizeImageBuffer(const til::CoordType requiredHeight);
Expand Down
Loading
Loading