Skip to content

Commit

Permalink
WIP: Implementing DECSASD, DECSSDT: status (line) display.
Browse files Browse the repository at this point in the history
  • Loading branch information
christianparpart committed Jun 6, 2022
1 parent 503f506 commit f16d796
Show file tree
Hide file tree
Showing 23 changed files with 459 additions and 72 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
- `<S-K>` and `<S-J>` don't just move the cursor up/down but also move the terminal's viewport respectively.
- and more...
- Adds specialized PTY implementation for Linux operating system utilizing OS-specific kernel APIs.
- Adds basic support for Indicator status line and their VT sequences `DECSASD` and `DECSSDT`, and `DECRQSS` has been adapted (#687).
- Adds configuration option `profiles.*.status_line.display` to be either `none` or `indicator` to reflect the initial state of the status line.
- Changes CLI syntax for `contour parser-table` to `contour generate parser-table`.

### 0.3.1 (2022-05-01)
Expand Down
1 change: 1 addition & 0 deletions src/contour/Actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ optional<Action> fromString(string const& _name)
mapAction<actions::SendChars>("SendChars"),
mapAction<actions::ToggleAllKeyMaps>("ToggleAllKeyMaps"),
mapAction<actions::ToggleFullscreen>("ToggleFullscreen"),
mapAction<actions::ToggleStatusLine>("ToggleStatusLine"),
mapAction<actions::ToggleTitleBar>("ToggleTitleBar"),
mapAction<actions::ViNormalMode>("ViNormalMode"),
mapAction<actions::WriteScreen>("WriteScreen"),
Expand Down
3 changes: 3 additions & 0 deletions src/contour/Actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct ScrollUp{};
struct SendChars{ std::string chars; };
struct ToggleAllKeyMaps{};
struct ToggleFullscreen{};
struct ToggleStatusLine{};
struct ToggleTitleBar{};
struct ViNormalMode{};
struct WriteScreen{ std::string chars; }; // "\033[2J\033[3J"
Expand Down Expand Up @@ -98,6 +99,7 @@ using Action = std::variant<CancelSelection,
SendChars,
ToggleAllKeyMaps,
ToggleFullscreen,
ToggleStatusLine,
ToggleTitleBar,
ViNormalMode,
WriteScreen>;
Expand Down Expand Up @@ -159,6 +161,7 @@ DECLARE_ACTION_FMT(ScrollUp)
DECLARE_ACTION_FMT(SendChars)
DECLARE_ACTION_FMT(ToggleAllKeyMaps)
DECLARE_ACTION_FMT(ToggleFullscreen)
DECLARE_ACTION_FMT(ToggleStatusLine)
DECLARE_ACTION_FMT(ToggleTitleBar)
DECLARE_ACTION_FMT(ViNormalMode)
DECLARE_ACTION_FMT(WriteScreen)
Expand Down
5 changes: 5 additions & 0 deletions src/contour/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,11 @@ TerminalProfile loadTerminalProfile(UsedKeys& _usedKeys,
}
}

if (auto statusLine = _profile["status_line"])
{
// TODO(pr)
}

return profile;
}

Expand Down
14 changes: 12 additions & 2 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ void TerminalSession::onSelectionCompleted()
}
}

void TerminalSession::resizeWindow(LineCount _lines, ColumnCount _columns)
void TerminalSession::requestWindowResize(LineCount _lines, ColumnCount _columns)
{
if (!display_)
return;
Expand All @@ -428,7 +428,7 @@ void TerminalSession::resizeWindow(LineCount _lines, ColumnCount _columns)
display_->post([this, _lines, _columns]() { display_->resizeWindow(_lines, _columns); });
}

void TerminalSession::resizeWindow(Width _width, Height _height)
void TerminalSession::requestWindowResize(Width _width, Height _height)
{
if (!display_)
return;
Expand Down Expand Up @@ -867,6 +867,16 @@ bool TerminalSession::operator()(actions::ToggleFullscreen)
return true;
}

bool TerminalSession::operator()(actions::ToggleStatusLine)
{
auto const _l = scoped_lock { terminal_ };
if (terminal().state().statusDisplayType != StatusDisplayType::Indicator)
terminal().setStatusDisplay(StatusDisplayType::Indicator);
else
terminal().setStatusDisplay(StatusDisplayType::None);
return true;
}

bool TerminalSession::operator()(actions::ToggleTitleBar)
{
if (display_)
Expand Down
5 changes: 3 additions & 2 deletions src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class TerminalSession: public QObject, public terminal::Terminal::Events
void onClosed() override;
void pasteFromClipboard(unsigned count) override;
void onSelectionCompleted() override;
void resizeWindow(terminal::LineCount, terminal::ColumnCount) override;
void resizeWindow(terminal::Width, terminal::Height) override;
void requestWindowResize(terminal::LineCount, terminal::ColumnCount) override;
void requestWindowResize(terminal::Width, terminal::Height) override;
void setWindowTitle(std::string_view _title) override;
void setTerminalProfile(std::string const& _configProfileName) override;
void discardImage(terminal::Image const&) override;
Expand Down Expand Up @@ -162,6 +162,7 @@ class TerminalSession: public QObject, public terminal::Terminal::Events
bool operator()(actions::SendChars const& _event);
bool operator()(actions::ToggleAllKeyMaps);
bool operator()(actions::ToggleFullscreen);
bool operator()(actions::ToggleStatusLine);
bool operator()(actions::ToggleTitleBar);
bool operator()(actions::ViNormalMode);
bool operator()(actions::WriteScreen const& _event);
Expand Down
8 changes: 8 additions & 0 deletions src/contour/contour.yml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ profiles:
blinking: false
blinking_interval: 500

status_line:
# Either none or indicator.
# This only reflects the initial state of the status line, as it can
# be changed at any time during runtime by the user or by an application.
display: none

# Background configuration
background:
# Background opacity to use. A value of 1.0 means fully opaque whereas 0.0 means fully
Expand Down Expand Up @@ -533,6 +539,7 @@ color_schemes:
# - SendChars Writes given characters in `chars` member to the applications input.
# - ToggleAllKeyMaps Disables/enables responding to all keybinds (this keybind will be preserved when disabling all others).
# - ToggleFullScreen Enables/disables full screen mode.
# - ToggleStatusLine Shows/hides the VT320 compatible Indicator status line.
# - ToggleTitleBar Shows/Hides titlebar
# - ViNormalMode Enters Vi-like normal mode. The cursor can then be moved via h/j/k/l movements and text can be selected via v, yanked via y, and clipboard pasted via p.
# - WriteScreen Writes VT sequence in `chars` member to the screen (bypassing the application).
Expand Down Expand Up @@ -574,3 +581,4 @@ input_mapping:
- { mods: [Shift], mouse: WheelDown, action: ScrollPageDown }
- { mods: [Shift], mouse: WheelUp, action: ScrollPageUp }
- { mods: [Control, Alt], key: O, action: OpenFileManager }
- { mods: [Control, Alt], key: '.', action: ToggleStatusLine }
6 changes: 6 additions & 0 deletions src/crispy/BufferObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <iterator>
#include <list>
#include <memory>
#include <mutex>
#include <string_view>

#define BUFFER_OBJECT_INLINE 1
Expand Down Expand Up @@ -100,6 +101,9 @@ class BufferObject: public std::enable_shared_from_this<BufferObject>

void clear() noexcept;

void lock() { mutex_.lock(); }
void unlock() { mutex_.unlock(); }

private:
#if !defined(BUFFER_OBJECT_INLINE)
char* data_;
Expand All @@ -108,6 +112,8 @@ class BufferObject: public std::enable_shared_from_this<BufferObject>
char* end_;

friend class BufferFragment;

std::mutex mutex_;
};

/**
Expand Down
9 changes: 7 additions & 2 deletions src/terminal/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ constexpr inline auto XTSHIFTESCAPE=detail::CSI('>', 0, 1, std::nullopt, 's', VT
constexpr inline auto XTVERSION = detail::CSI('>', 0, 1, std::nullopt, 'q', VTType::VT525 /*Xterm*/, "XTVERSION", "Query terminal name and version");
constexpr inline auto CAPTURE = detail::CSI('>', 0, 2, std::nullopt, 't', VTType::VT525 /*Extension*/, "CAPTURE", "Report screen buffer capture.");

constexpr inline auto DECSSDT = detail::CSI(std::nullopt, 0, 1, '$', '~', VTType::VT320, "DECSSDT", "Select Status Display (Line) Type");
constexpr inline auto DECSASD = detail::CSI(std::nullopt, 0, 1, '$', '}', VTType::VT420, "DECSASD", "Select Active Status Display");

// DCS functions
constexpr inline auto STP = detail::DCS(std::nullopt, 0, 0, '$', 'p', VTType::VT525, "STP", "Set Terminal Profile");
constexpr inline auto DECRQSS = detail::DCS(std::nullopt, 0, 0, '$', 'q', VTType::VT420, "DECRQSS", "Request Status String");
Expand Down Expand Up @@ -447,22 +450,24 @@ inline auto const& functions() noexcept
DCH,
DECCARA,
DECCRA,
DECDC,
DECERA,
DECFRA,
DECDC,
DECIC,
DECMODERESTORE,
DECMODESAVE,
DECRM,
DECRQM,
DECRQM_ANSI,
DECRQPSR,
DECSASD,
DECSCL,
DECSCPP,
DECSCUSR,
DECSLRM,
DECSM,
DECSNLS,
DECSSDT,
DECSTBM,
DECSTR,
DECXCPR,
Expand All @@ -486,8 +491,8 @@ inline auto const& functions() noexcept
TBC,
VPA,
WINMANIP,
XTSMGRAPHICS,
XTSHIFTESCAPE,
XTSMGRAPHICS,
XTVERSION,

// DCS
Expand Down
18 changes: 11 additions & 7 deletions src/terminal/RenderBufferBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,18 @@ namespace
} // namespace

template <typename Cell>
RenderBufferBuilder<Cell>::RenderBufferBuilder(Terminal const& _terminal, RenderBuffer& _output):
RenderBufferBuilder<Cell>::RenderBufferBuilder(Terminal const& _terminal,
RenderBuffer& _output,
LineOffset base,
bool theReverseVideo):
output { _output },
terminal { _terminal },
cursorPosition { _terminal.inputHandler().mode() == ViMode::Insert
? _terminal.realCursorPosition()
: _terminal.state().viCommands.cursorPosition }
: _terminal.state().viCommands.cursorPosition },
baseLine { base },
reverseVideo { theReverseVideo }
{
output.clear();
output.frameID = _terminal.lastFrameID();
output.cursor = renderCursor();
}
Expand Down Expand Up @@ -275,7 +279,7 @@ void RenderBufferBuilder<Cell>::renderTrivialLine(TriviallyStyledLineBuffer cons
fg,
bg,
lineBuffer.attributes.underlineColor,
lineOffset,
baseLine + lineOffset,
columnOffset));

columnOffset += ColumnOffset::cast_from(width);
Expand All @@ -301,7 +305,7 @@ void RenderBufferBuilder<Cell>::renderTrivialLine(TriviallyStyledLineBuffer cons
fg,
bg,
lineBuffer.attributes.underlineColor,
lineOffset,
baseLine + lineOffset,
columnOffset));
}
// }}}
Expand Down Expand Up @@ -355,7 +359,7 @@ void RenderBufferBuilder<Cell>::renderCell(Cell const& screenCell, LineOffset _l
screenCell,
fg,
bg,
_line,
baseLine + _line,
_column));
output.cells.back().groupStart = true;
}
Expand All @@ -373,7 +377,7 @@ void RenderBufferBuilder<Cell>::renderCell(Cell const& screenCell, LineOffset _l
screenCell,
fg,
bg,
_line,
baseLine + _line,
_column));

if (isNewLine)
Expand Down
5 changes: 3 additions & 2 deletions src/terminal/RenderBufferBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ template <typename Cell>
class RenderBufferBuilder
{
public:
RenderBufferBuilder(Terminal const& terminal, RenderBuffer& output);
RenderBufferBuilder(Terminal const& terminal, RenderBuffer& output, LineOffset base, bool reverseVideo);

/// Renders a single grid cell.
/// This call is guaranteed to be invoked sequencially, from top line
Expand Down Expand Up @@ -87,8 +87,9 @@ class RenderBufferBuilder
RenderBuffer& output;
Terminal const& terminal;
CellLocation cursorPosition;
LineOffset baseLine;
bool reverseVideo;

bool reverseVideo = terminal.isModeEnabled(terminal::DECMode::ReverseVideo);
int prevWidth = 0;
bool prevHasCursor = false;
State state = State::Gap;
Expand Down
58 changes: 53 additions & 5 deletions src/terminal/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,18 @@ void Screen<Cell, TheScreenType>::writeText(string_view _chars, size_t cellCount
writeTextInternal(static_cast<char32_t>(ch));
}

template <typename Cell, ScreenType TheScreenType>
void Screen<Cell, TheScreenType>::writeTextFromExternal(std::string_view _chars)
{
#if defined(LIBTERMINAL_LOG_TRACE)
if (VTTraceSequenceLog)
VTTraceSequenceLog()("external text: \"{}\"", _chars);
#endif

for (char const ch: _chars)
writeTextInternal(static_cast<char32_t>(ch));
}

template <typename Cell, ScreenType TheScreenType>
void Screen<Cell, TheScreenType>::crlfIfWrapPending()
{
Expand Down Expand Up @@ -1800,6 +1812,21 @@ void Screen<Cell, TheScreenType>::requestStatusString(RequestStatusString _value
case RequestStatusString::DECSCA: // TODO
errorlog()(fmt::format("Requesting device status for {} not implemented yet.", _value));
break;
case RequestStatusString::DECSASD:
switch (_state.activeStatusDisplay)
{
case ActiveStatusDisplay::Main: return "0$}";
case ActiveStatusDisplay::StatusLine: return "1$}";
}
break;
case RequestStatusString::DECSSDT:
switch (_state.statusDisplayType)
{
case StatusDisplayType::None: return "0$~";
case StatusDisplayType::Indicator: return "1$~";
case StatusDisplayType::HostWritable: return "2$~";
}
break;
}
return nullopt;
}(_value);
Expand Down Expand Up @@ -2799,11 +2826,11 @@ namespace impl
switch (_seq.param(0))
{
case 4: // resize in pixel units
terminal.resizeWindow(ImageSize { Width(_seq.param(2)), Height(_seq.param(1)) });
terminal.requestWindowResize(ImageSize { Width(_seq.param(2)), Height(_seq.param(1)) });
break;
case 8: // resize in cell units
terminal.resizeWindow(PageSize { LineCount::cast_from(_seq.param(1)),
ColumnCount::cast_from(_seq.param(2)) });
terminal.requestWindowResize(PageSize { LineCount::cast_from(_seq.param(1)),
ColumnCount::cast_from(_seq.param(2)) });
break;
case 22: terminal.saveWindowTitle(); break;
case 23: terminal.restoreWindowTitle(); break;
Expand All @@ -2819,7 +2846,7 @@ namespace impl
case 8:
// this means, resize to full display size
// TODO: just create a dedicated callback for fulscreen resize!
terminal.resizeWindow(ImageSize {});
terminal.requestWindowResize(ImageSize {});
break;
case 14:
if (_seq.parameterCount() == 2 && _seq.param(1) == 2)
Expand Down Expand Up @@ -3261,6 +3288,26 @@ ApplyResult Screen<Cell, TheScreenType>::apply(FunctionDefinition const& functio
case XTVERSION:
_terminal.reply(fmt::format("\033P>|{} {}\033\\", LIBTERMINAL_NAME, LIBTERMINAL_VERSION_STRING));
return ApplyResult::Ok;
case DECSSDT: {
// Changes the status line display type.
switch (seq.param_or(0, 0))
{
case 0: _terminal.setStatusDisplay(StatusDisplayType::None); break;
case 1: _terminal.setStatusDisplay(StatusDisplayType::Indicator); break;
case 2: _terminal.setStatusDisplay(StatusDisplayType::HostWritable); break;
default: return ApplyResult::Invalid;
}
break;
}
case DECSASD:
// Selects whether the terminal sends data to the main display or the status line.
switch (seq.param_or(0, 0))
{
case 0: _terminal.setActiveStatusDisplay(ActiveStatusDisplay::Main); break;
case 1: _terminal.setActiveStatusDisplay(ActiveStatusDisplay::StatusLine); break;
default: return ApplyResult::Invalid;
}
break;

// OSC
case SETTITLE:
Expand Down Expand Up @@ -3404,11 +3451,12 @@ unique_ptr<ParserExtension> Screen<Cell, TheScreenType>::hookDECRQSS(Sequence co
{
return make_unique<SimpleStringCollector>([this](string_view const& _data) {
auto const s = [](string_view _dataString) -> optional<RequestStatusString> {
auto const mappings = array<pair<string_view, RequestStatusString>, 9> {
auto const mappings = array<pair<string_view, RequestStatusString>, 11> {
pair { "m", RequestStatusString::SGR }, pair { "\"p", RequestStatusString::DECSCL },
pair { " q", RequestStatusString::DECSCUSR }, pair { "\"q", RequestStatusString::DECSCA },
pair { "r", RequestStatusString::DECSTBM }, pair { "s", RequestStatusString::DECSLRM },
pair { "t", RequestStatusString::DECSLPP }, pair { "$|", RequestStatusString::DECSCPP },
pair { "$}", RequestStatusString::DECSASD }, pair { "$~", RequestStatusString::DECSSDT },
pair { "*|", RequestStatusString::DECSNLS }
};
for (auto const& mapping: mappings)
Expand Down
Loading

0 comments on commit f16d796

Please sign in to comment.