Skip to content

Commit

Permalink
[vtbackend] Refactor Sequencer into SequenceBuilder to increase code …
Browse files Browse the repository at this point in the history
…share.

Also, SequenceBuilder is the way better and more intuitive name than Sequencer :)

Signed-off-by: Christian Parpart <[email protected]>
  • Loading branch information
christianparpart committed Jun 19, 2024
1 parent 8c6d981 commit 7d52144
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 653 deletions.
3 changes: 1 addition & 2 deletions src/vtbackend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ set(vtbackend_HEADERS
Screen.h
Selector.h
Sequence.h
Sequencer.h
SequenceBuilder.h
SixelParser.h
StatusLineBuilder.h
Terminal.h
Expand Down Expand Up @@ -67,7 +67,6 @@ set(vtbackend_SOURCES
Screen.cpp
Selector.cpp
Sequence.cpp
Sequencer.cpp
SixelParser.cpp
StatusLineBuilder.cpp
Terminal.cpp
Expand Down
2 changes: 0 additions & 2 deletions src/vtbackend/Metrics.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once

#include <vtbackend/Sequencer.h> // Sequence

#include <algorithm>
#include <map>
#include <string>
Expand Down
1 change: 1 addition & 0 deletions src/vtbackend/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vtbackend/VTType.h>
#include <vtbackend/VTWriter.h>
#include <vtbackend/logging.h>
#include <vtbackend/SixelParser.h>

#include <crispy/App.h>
#include <crispy/Comparison.h>
Expand Down
124 changes: 123 additions & 1 deletion src/vtbackend/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <vtbackend/Image.h>
#include <vtbackend/ScreenBase.h>
#include <vtbackend/ScreenEvents.h>
#include <vtbackend/Sequencer.h>
#include <vtbackend/VTType.h>
#include <vtbackend/cell/CellConcept.h>

Expand Down Expand Up @@ -39,9 +38,90 @@
namespace vtbackend
{

class SixelImageBuilder;
class Terminal;
struct Settings;

// {{{ TODO: move me somewhere more appropriate
// XTSMGRAPHICS (xterm extension)
// CSI ? Pi ; Pa ; Pv S
namespace XtSmGraphics
{
enum class Item
{
NumberOfColorRegisters = 1,
SixelGraphicsGeometry = 2,
ReGISGraphicsGeometry = 3,
};

enum class Action
{
Read = 1,
ResetToDefault = 2,
SetToValue = 3,
ReadLimit = 4
};

using Value = std::variant<std::monostate, unsigned, ImageSize>;
} // namespace XtSmGraphics

/// TBC - Tab Clear
///
/// This control function clears tab stops.
enum class HorizontalTabClear
{
/// Ps = 0 (default)
AllTabs,

/// Ps = 3
UnderCursor,
};

/// Input: CSI 16 t
///
/// Input: CSI 14 t (for text area size)
/// Input: CSI 14; 2 t (for full window size)
/// Output: CSI 14 ; width ; height ; t
enum class RequestPixelSize // TODO: rename RequestPixelSize to RequestArea?
{
CellArea,
TextArea,
WindowArea,
};

/// DECRQSS - Request Status String
enum class RequestStatusString
{
SGR,
DECSCL,
DECSCUSR,
DECSCA,
DECSTBM,
DECSLRM,
DECSLPP,
DECSCPP,
DECSNLS,
DECSASD,
DECSSDT,
};

inline std::string setDynamicColorValue(
RGBColor const& color) // TODO: yet another helper. maybe SemanticsUtils static class?
{
auto const r = static_cast<unsigned>(static_cast<float>(color.red) / 255.0f * 0xFFFF);

Check warning on line 111 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: variable name 'r' is too short, expected at least 3 characters [readability-identifier-length] ```cpp auto const r = static_cast<unsigned>(static_cast<float>(color.red) / 255.0f * 0xFFFF); ^ ```

Check warning on line 111 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] ```suggestion auto const r = static_cast<unsigned>(static_cast<float>(color.red) / 255.0F * 0xFFFF); ```
auto const g = static_cast<unsigned>(static_cast<float>(color.green) / 255.0f * 0xFFFF);

Check warning on line 112 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: variable name 'g' is too short, expected at least 3 characters [readability-identifier-length] ```cpp auto const g = static_cast<unsigned>(static_cast<float>(color.green) / 255.0f * 0xFFFF); ^ ```

Check warning on line 112 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] ```suggestion auto const g = static_cast<unsigned>(static_cast<float>(color.green) / 255.0F * 0xFFFF); ```
auto const b = static_cast<unsigned>(static_cast<float>(color.blue) / 255.0f * 0xFFFF);

Check warning on line 113 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: variable name 'b' is too short, expected at least 3 characters [readability-identifier-length] ```cpp auto const b = static_cast<unsigned>(static_cast<float>(color.blue) / 255.0f * 0xFFFF); ^ ```

Check warning on line 113 in src/vtbackend/Screen.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] ```suggestion auto const b = static_cast<unsigned>(static_cast<float>(color.blue) / 255.0F * 0xFFFF); ```
return fmt::format("rgb:{:04X}/{:04X}/{:04X}", r, g, b);
}

enum class ApplyResult
{
Ok,
Invalid,
Unsupported,
};
// }}}

/**
* Terminal Screen.
*
Expand Down Expand Up @@ -597,3 +677,45 @@ inline bool Screen<Cell>::isContiguousToCurrentLine(std::string_view continuatio
}

} // namespace vtbackend

// {{{ fmt formatter
template <>
struct fmt::formatter<vtbackend::RequestStatusString>: formatter<std::string_view>
{
auto format(vtbackend::RequestStatusString value,
format_context& ctx) noexcept -> format_context::iterator
{
string_view name;
switch (value)
{
case vtbackend::RequestStatusString::SGR: name = "SGR"; break;
case vtbackend::RequestStatusString::DECSCL: name = "DECSCL"; break;
case vtbackend::RequestStatusString::DECSCUSR: name = "DECSCUSR"; break;
case vtbackend::RequestStatusString::DECSCA: name = "DECSCA"; break;
case vtbackend::RequestStatusString::DECSTBM: name = "DECSTBM"; break;
case vtbackend::RequestStatusString::DECSLRM: name = "DECSLRM"; break;
case vtbackend::RequestStatusString::DECSLPP: name = "DECSLPP"; break;
case vtbackend::RequestStatusString::DECSCPP: name = "DECSCPP"; break;
case vtbackend::RequestStatusString::DECSNLS: name = "DECSNLS"; break;
case vtbackend::RequestStatusString::DECSASD: name = "DECSASD"; break;
case vtbackend::RequestStatusString::DECSSDT: name = "DECSSDT"; break;
}
return formatter<string_view>::format(name, ctx);
}
};

template <>
struct fmt::formatter<vtbackend::Sequence>
{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(vtbackend::Sequence const& seq, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), "{}", seq.text());
}
};
// }}}
10 changes: 10 additions & 0 deletions src/vtbackend/Sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <gsl/span>

#include <cassert>
#include <concepts>
#include <iterator>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -362,4 +363,13 @@ class SequenceHandler
virtual void writeTextEnd() = 0;
};

template <typename T>
concept SequenceHandlerConcept = requires(T t) {
{ t.executeControlCode('\x00') } -> std::same_as<void>;
{ t.processSequence(Sequence {}) } -> std::same_as<void>;
{ t.writeText(U'a') } -> std::same_as<void>;
{ t.writeText("a", size_t(1)) } -> std::same_as<void>;
{ t.writeTextEnd() } -> std::same_as<void>;
};

} // namespace vtbackend
197 changes: 197 additions & 0 deletions src/vtbackend/SequenceBuilder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once

#include <vtbackend/Sequence.h>
#include <vtbackend/SixelParser.h>
#include <vtbackend/logging.h>

#include <vtparser/Parser.h>
#include <vtparser/ParserExtension.h>

#include <concepts>
#include <memory>
#include <string_view>

namespace vtbackend
{

template <typename T>
concept InstructionCounterConcept = requires(T t, size_t n) {
{ t() } -> std::same_as<void>;
{ t(n) } -> std::same_as<void>;
};

struct NoOpInstructionCounter
{
void operator()(size_t /*increment*/ = 1) const noexcept {}
};

/// SequenceBuilder - The semantic VT analyzer layer.
///
/// SequenceBuilder implements the translation from VT parser events, forming a higher level Sequence,
/// that can be matched against FunctionDefinition objects and then handled on the currently active Screen.
template <SequenceHandlerConcept Handler, InstructionCounterConcept IncrementInstructionCounter>
class SequenceBuilder
{
public:
explicit SequenceBuilder(Handler handler, IncrementInstructionCounter incrementInstructionCounter):

Check warning on line 37 in src/vtbackend/SequenceBuilder.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: constructor does not initialize these fields: _incrementInstructionCounter, _handler [cppcoreguidelines-pro-type-member-init] src/vtbackend/SequenceBuilder.h:186: ```diff - IncrementInstructionCounter _incrementInstructionCounter; - Handler _handler; + IncrementInstructionCounter _incrementInstructionCounter{}; + Handler _handler{}; ```
_sequence {},
_parameterBuilder { _sequence.parameters() },
_incrementInstructionCounter { std::move(incrementInstructionCounter) },
_handler { std::move(handler) }
{
}

// {{{ ParserEvents interface
void error(std::string_view errorString)
{
if (vtParserLog)
vtParserLog()("Parser error: {}", errorString);

Check warning on line 49 in src/vtbackend/SequenceBuilder.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: statement should be inside braces [readability-braces-around-statements] ```suggestion if (vtParserLog) { vtParserLog()("Parser error: {}", errorString); } ```
}
void print(char32_t codepoint)
{
_incrementInstructionCounter();
_handler.writeText(codepoint);
}

size_t print(std::string_view chars, size_t cellCount)
{
assert(!chars.empty());

_incrementInstructionCounter(cellCount);
_handler.writeText(chars, cellCount);
return _handler.maxBulkTextSequenceWidth();
}

void printEnd() { _handler.writeTextEnd(); }

void execute(char controlCode) { _handler.executeControlCode(controlCode); }

void clear() noexcept
{
_sequence.clearExceptParameters();
_parameterBuilder.reset();
}

void collect(char ch) { _sequence.intermediateCharacters().push_back(ch); }

Check warning on line 76 in src/vtbackend/SequenceBuilder.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: parameter name 'ch' is too short, expected at least 3 characters [readability-identifier-length] ```cpp void collect(char ch) { _sequence.intermediateCharacters().push_back(ch); } ^ ```

void collectLeader(char leader) noexcept { _sequence.setLeader(leader); }

void param(char ch) noexcept

Check warning on line 80 in src/vtbackend/SequenceBuilder.h

View workflow job for this annotation

GitHub Actions / clang-tidy-review

clang-tidy

warning: parameter name 'ch' is too short, expected at least 3 characters [readability-identifier-length] ```cpp void param(char ch) noexcept ^ ```
{
switch (ch)
{
case ';': paramSeparator(); break;
case ':': paramSubSeparator(); break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': paramDigit(ch); break;
default: crispy::unreachable();
}
}

void paramDigit(char ch) noexcept
{
_parameterBuilder.multiplyBy10AndAdd(static_cast<uint8_t>(ch - '0'));
}

void paramSeparator() noexcept { _parameterBuilder.nextParameter(); }
void paramSubSeparator() noexcept { _parameterBuilder.nextSubParameter(); }

void dispatchESC(char finalChar)
{
_sequence.setCategory(FunctionCategory::ESC);
_sequence.setFinalChar(finalChar);
handleSequence();
}

void dispatchCSI(char finalChar)
{
_sequence.setCategory(FunctionCategory::CSI);
_sequence.setFinalChar(finalChar);
handleSequence();
}

void startOSC() { _sequence.setCategory(FunctionCategory::OSC); }

void putOSC(char ch)
{
if (_sequence.intermediateCharacters().size() + 1 < Sequence::MaxOscLength)
_sequence.intermediateCharacters().push_back(ch);
}

void dispatchOSC()
{
auto const [code, skipCount] = vtparser::extractCodePrefix(_sequence.intermediateCharacters());
_parameterBuilder.set(static_cast<Sequence::Parameter>(code));
_sequence.intermediateCharacters().erase(0, skipCount);
handleSequence();
clear();
}

void hook(char finalChar)
{
_incrementInstructionCounter();
_sequence.setCategory(FunctionCategory::DCS);
_sequence.setFinalChar(finalChar);

handleSequence();
}
void put(char ch)
{
if (_hookedParser)
_hookedParser->pass(ch);
}
void unhook()
{
if (_hookedParser)
{
_hookedParser->finalize();
_hookedParser.reset();
}
}
void startAPC() {}
void putAPC(char) {}
void dispatchAPC() {}
void startPM() {}
void putPM(char) {}
void dispatchPM() {}

void hookParser(std::unique_ptr<ParserExtension> parserExtension) noexcept
{
_hookedParser = std::move(parserExtension);
}

[[nodiscard]] size_t maxBulkTextSequenceWidth() const noexcept
{
return _handler.maxBulkTextSequenceWidth();
}
// }}}

private:
void handleSequence()
{
_parameterBuilder.fixiate();
_handler.processSequence(_sequence);
}

Sequence _sequence {};
SequenceParameterBuilder _parameterBuilder;
IncrementInstructionCounter _incrementInstructionCounter;
Handler _handler;

std::unique_ptr<ParserExtension> _hookedParser {};
};

template <SequenceHandlerConcept Handler, InstructionCounterConcept IncrementInstructionCounter>
SequenceBuilder(Handler&,
IncrementInstructionCounter) -> SequenceBuilder<Handler, IncrementInstructionCounter>;

} // namespace vtbackend
Loading

0 comments on commit 7d52144

Please sign in to comment.