Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Utkarsh-khambra committed Jan 29, 2023
1 parent 1a7ae70 commit 9aec7ad
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/contour/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,7 @@ void loadConfigFromFile(Config& _config, FileSystem::path const& _fileName)
}

tryLoadValue(usedKeys, doc, "reflow_on_resize", _config.reflowOnResize);
tryLoadValue(usedKeys, doc, "expand_tabs", _config.expandTabs);

if (auto profiles = doc["profiles"]; profiles)
{
Expand Down
1 change: 1 addition & 0 deletions src/contour/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ struct Config
size_t ptyBufferObjectSize = 1024lu * 1024lu;

bool reflowOnResize = true;
bool expandTabs = false;

std::unordered_map<std::string, terminal::ColorPalette> colorschemes;
std::unordered_map<std::string, TerminalProfile> profiles;
Expand Down
1 change: 1 addition & 0 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ namespace
settings.primaryScreen.allowReflowOnResize = config.reflowOnResize;
settings.highlightDoubleClickedWord = profile.highlightDoubleClickedWord;
settings.highlightTimeout = profile.highlightTimeout;
settings.expandTabs = config.expandTabs;

return settings;
}
Expand Down
1 change: 1 addition & 0 deletions src/vtbackend/CellFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class CellFlags : uint32_t
Overline = (1 << 14),
RapidBlinking = (1 << 15),
CharacterProtected = (1 << 16), // Character is protected by selective erase operations.
Tab = (1 << 17), // Cell is part of tab character.
};

constexpr CellFlags& operator|=(CellFlags& a, CellFlags b) noexcept
Expand Down
3 changes: 1 addition & 2 deletions src/vtbackend/Grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,8 +798,7 @@ CellLocation Grid<Cell>::resize(PageSize newSize, CellLocation currentCursorPos,
flushLogicalLine();
if (line.isTrivialBuffer())
{
auto& buffer = line.trivialBuffer();
buffer.displayWidth = newColumnCount;
line.trivialBuffer().resize(newColumnCount);
grownLines.emplace_back(line);
}
else
Expand Down
30 changes: 26 additions & 4 deletions src/vtbackend/Line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ typename Line<Cell>::InflatedBuffer Line<Cell>::reflow(ColumnCount newColumnCoun
{
switch (crispy::strongCompare(newColumnCount, ColumnCount::cast_from(trivialBuffer().text.size())))
{
case Comparison::Greater: trivialBuffer().displayWidth = newColumnCount; return {};
case Comparison::Greater: trivialBuffer().resize(newColumnCount); return {};
case Comparison::Equal: return {};
case Comparison::Less:;
}
Expand Down Expand Up @@ -99,8 +99,7 @@ inline void Line<Cell>::resize(ColumnCount count)
{
if (isTrivialBuffer())
{
TrivialBuffer& buffer = trivialBuffer();
buffer.displayWidth = count;
trivialBuffer().resize(count);
return;
}
}
Expand Down Expand Up @@ -168,7 +167,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
auto lastChar = char32_t { 0 };
auto utf8DecoderState = unicode::utf8_decoder_state {};
auto gapPending = 0;

size_t cellNr = 0;
for (char const ch: input.text.view())
{
unicode::ConvertResult const r = unicode::from_utf8(utf8DecoderState, static_cast<uint8_t>(ch));
Expand All @@ -189,6 +188,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
columns.emplace_back(Cell {});
columns.back().setHyperlink(input.hyperlink);
columns.back().write(input.textAttributes, nextChar, static_cast<uint8_t>(charWidth));
columns.back().setTab(input.tabstops[cellNr]);
gapPending = charWidth - 1;
}
else
Expand All @@ -207,6 +207,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
}
}
lastChar = nextChar;
++cellNr;
}

while (gapPending > 0)
Expand All @@ -218,10 +219,31 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
assert(columns.size() == unbox<size_t>(input.usedColumns));

while (columns.size() < unbox<size_t>(input.displayWidth))
{
columns.emplace_back(Cell { input.fillAttributes });
columns.back().setTab(input.tabstops[cellNr]);
++cellNr;
}

return columns;
}

template <typename Cell>
void Line<Cell>::setTab(ColumnOffset start, ColumnCount n, bool tab)
{
if (isInflatedBuffer())
{
for (; n > ColumnCount(0); --n)
useCellAt(start++).setTab(tab);
}
else
{
auto& buffer = trivialBuffer();
for (; n > ColumnCount(0); --n)
buffer.tabstops[(start++).as<size_t>()] = true;
// assert(false);
}
}
} // end namespace terminal

#include <vtbackend/cell/CompactCell.h>
Expand Down
19 changes: 18 additions & 1 deletion src/vtbackend/Line.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,20 @@ struct TrivialLineBuffer

ColumnCount usedColumns {};
crispy::BufferFragment<char> text {};

std::vector<bool> tabstops = std::vector<bool>(displayWidth.value, false);
void reset(GraphicsAttributes attributes) noexcept
{
textAttributes = attributes;
fillAttributes = attributes;
hyperlink = {};
usedColumns = {};
text.reset();
tabstops.clear();
}
void resize(ColumnCount count)
{
displayWidth = count;
tabstops.resize(count.as<size_t>());
}
};

Expand Down Expand Up @@ -233,6 +239,15 @@ class Line
return inflatedBuffer().at(unbox<size_t>(column)).empty();
}

[[nodiscard]] bool hasTabstop(ColumnOffset column) const noexcept
{
Require(ColumnOffset(0) <= column);
Require(column <= ColumnOffset::cast_from(size()));
if (isInflatedBuffer())
return cells()[column.as<size_t>()].isTab();
return trivialBuffer().tabstops[column.as<size_t>()];
}

[[nodiscard]] uint8_t cellWidthAt(ColumnOffset column) const noexcept
{
#if 0 // TODO: This optimization - but only when we return actual widths and not always 1.
Expand All @@ -257,6 +272,8 @@ class Line
[[nodiscard]] bool wrappable() const noexcept { return isFlagEnabled(LineFlags::Wrappable); }
void setWrappable(bool enable) { setFlag(LineFlags::Wrappable, enable); }

void setTab(ColumnOffset start, ColumnCount n, bool tab);

[[nodiscard]] LineFlags wrappableFlag() const noexcept
{
return wrappable() ? LineFlags::Wrappable : LineFlags::None;
Expand Down
10 changes: 6 additions & 4 deletions src/vtbackend/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ using std::vector;
namespace terminal
{

auto constexpr inline TabWidth = ColumnCount(8);

auto const inline VTCaptureBufferLog = logstore::Category("vt.ext.capturebuffer",
"Capture Buffer debug logging.",
logstore::Category::State::Disabled,
Expand Down Expand Up @@ -1464,9 +1462,12 @@ void Screen<Cell>::moveCursorToNextTab()
++i;

auto const currentCursorColumn = logicalCursorPosition().column;

if (i < _state.tabs.size())
moveCursorForward(boxed_cast<ColumnCount>(_state.tabs[i] - currentCursorColumn));
{
auto const cursorMoveAmount = boxed_cast<ColumnCount>(_state.tabs[i] - currentCursorColumn);
currentLine().setTab(currentCursorColumn, cursorMoveAmount, true);
moveCursorForward(cursorMoveAmount);
}
else if (realCursorPosition().column < margin().horizontal.to)
moveCursorForward(boxed_cast<ColumnCount>(margin().horizontal.to - currentCursorColumn));
else
Expand All @@ -1480,6 +1481,7 @@ void Screen<Cell>::moveCursorToNextTab()
auto const n =
min((TabWidth - boxed_cast<ColumnCount>(_cursor.position.column) % TabWidth),
_settings.pageSize.columns - boxed_cast<ColumnCount>(logicalCursorPosition().column));
currentLine().setTab(logicalCursorPosition().column, n, true);
moveCursorForward(n);
}
else
Expand Down
5 changes: 5 additions & 0 deletions src/vtbackend/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class ScreenBase: public SequenceHandler
[[nodiscard]] virtual Margin& margin() noexcept = 0;
[[nodiscard]] virtual bool contains(CellLocation coord) const noexcept = 0;
[[nodiscard]] virtual bool isCellEmpty(CellLocation position) const noexcept = 0;
[[nodiscard]] virtual bool hasTabstop(CellLocation position) const noexcept = 0;
[[nodiscard]] virtual bool compareCellTextAt(CellLocation position, char codepoint) const noexcept = 0;
[[nodiscard]] virtual std::string cellTextAt(CellLocation position) const noexcept = 0;
[[nodiscard]] virtual std::string lineTextAt(LineOffset line) const noexcept = 0;
Expand Down Expand Up @@ -509,6 +510,10 @@ class Screen final: public ScreenBase, public capabilities::StaticDatabase
return _grid.lineAt(position.line).cellEmptyAt(position.column);
}

[[nodiscard]] bool hasTabstop(CellLocation position) const noexcept override
{
return _grid.lineAt(position.line).hasTabstop(position.column);
}
[[nodiscard]] bool compareCellTextAt(CellLocation position, char codepoint) const noexcept override
{
auto const& cell = _grid.lineAt(position.line).inflatedBuffer().at(position.column.as<size_t>());
Expand Down
1 change: 1 addition & 0 deletions src/vtbackend/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct Settings
std::chrono::milliseconds highlightTimeout = std::chrono::milliseconds { 150 };
bool highlightDoubleClickedWord = true;
// TODO: ^^^ make also use of it. probably rename to how VScode has named it.
bool expandTabs = false;

struct PrimaryScreen
{
Expand Down
65 changes: 56 additions & 9 deletions src/vtbackend/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#include <utility>
#include <variant>

#include "fmt/core.h"

using crispy::Size;

using namespace std;
Expand All @@ -48,7 +50,7 @@ using std::move;

namespace terminal
{

// inline constexpr auto TabWidth = ColumnCount(8);
namespace // {{{ helpers
{
constexpr size_t MaxColorPaletteSaveStackSize = 10;
Expand Down Expand Up @@ -786,7 +788,27 @@ bool Terminal::sendMouseMoveEvent(Modifier modifier,
{
if (currentScreen().isCellEmpty(relativePos) && !currentScreen().compareCellTextAt(relativePos, 0x20))
{
relativePos.column = ColumnOffset { 0 } + *(_settings.pageSize.columns - 1);
if (currentScreen().hasTabstop(relativePos))
{
if (!_state.tabs.empty())
{
auto tab = std::upper_bound(_state.tabs.begin(), _state.tabs.end(), relativePos.column);
relativePos.column = (tab == _state.tabs.end())
? ColumnOffset::cast_from(_settings.pageSize.columns - 1)
: *tab - 1;
}
else
{
auto const n =
min((TabWidth - boxed_cast<ColumnCount>(relativePos.column) % TabWidth - 1),
_settings.pageSize.columns - boxed_cast<ColumnCount>(relativePos.column));
relativePos.column += n;
}
}
else
{
relativePos.column = ColumnOffset::cast_from(_settings.pageSize.columns - 1);
}
}
changed = true;
selector()->extend(relativePos);
Expand Down Expand Up @@ -1124,26 +1146,51 @@ namespace
Terminal const& term;
ColumnOffset rightPage;
ColumnOffset lastColumn {};
LineOffset lastLine {};
string text {};
string currentLine {};

void operator()(CellLocation pos, Cell const& cell)
{
auto const isNewLine = pos.column < lastColumn || (pos.column == lastColumn && !text.empty());
auto const isNewLine = lastLine < pos.line && !text.empty();
bool const touchesRightPage = term.isSelected({ pos.line, rightPage });
if (isNewLine && (!term.isLineWrapped(pos.line) || !touchesRightPage))
if (isNewLine && !term.isLineWrapped(pos.line))
{
// TODO: handle logical line in word-selection (don't include LF in wrapped lines)
trimSpaceRight(currentLine);
text += currentLine;
text += '\n';
currentLine.clear();
}
if (cell.empty())
currentLine += ' ';
else
currentLine += cell.toUtf8();
lastColumn = pos.column;
if (cell.isTab())
{
if (term.settings().expandTabs)
currentLine += ' ';
else if (lastColumn < pos.column)
{
auto const& tabs = term.state().tabs;
if (!tabs.empty())
{
auto itr = std::lower_bound(tabs.begin(), tabs.end(), pos.column);
if (itr != tabs.end())
{
pos.column = *itr;
}
else
{
assert(false);
}
}
else
{
pos.column += TabWidth - boxed_cast<ColumnCount>(pos.column) % TabWidth;
}
currentLine += '\t';
}
}
currentLine += cell.toUtf8();
lastColumn = lastColumn < pos.column ? pos.column : lastColumn;
lastLine = pos.line;
}

std::string finish()
Expand Down
2 changes: 2 additions & 0 deletions src/vtbackend/Terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
namespace terminal
{

constexpr static inline auto TabWidth = ColumnCount(8);

template <typename Cell>
CRISPY_REQUIRES(CellConcept<Cell>)
class Screen;
Expand Down
3 changes: 3 additions & 0 deletions src/vtbackend/cell/CellConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ concept CellConcept = requires(T t, T const& u)

{ u.hyperlink() } -> std::same_as<HyperlinkId>;
t.setHyperlink(HyperlinkId{});

t.setTab(bool{});
{ u.isTab() } noexcept -> std::same_as<bool>;
};


Expand Down
14 changes: 14 additions & 0 deletions src/vtbackend/cell/CompactCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class CRISPY_PACKED CompactCell
void setForegroundColor(Color color) noexcept;
[[nodiscard]] Color backgroundColor() const noexcept;
void setBackgroundColor(Color color) noexcept;
void setTab(bool tab) noexcept;

[[nodiscard]] std::shared_ptr<ImageFragment> imageFragment() const noexcept;
void setImageFragment(std::shared_ptr<RasterizedImage> rasterizedImage, CellLocation offset);
Expand All @@ -139,6 +140,7 @@ class CRISPY_PACKED CompactCell
void setHyperlink(HyperlinkId hyperlink);

[[nodiscard]] bool empty() const noexcept;
[[nodiscard]] bool isTab() const noexcept;

void setGraphicsRendition(GraphicsRendition sgr) noexcept;

Expand Down Expand Up @@ -408,6 +410,14 @@ inline void CompactCell::setBackgroundColor(Color color) noexcept
_backgroundColor = color;
}

inline void CompactCell::setTab(bool tab) noexcept
{
if (tab)
extra().flags |= CellFlags::Tab;
else
extra().flags &= ~CellFlags::Tab;
}

inline Color CompactCell::underlineColor() const noexcept
{
if (!_extra)
Expand Down Expand Up @@ -460,6 +470,10 @@ inline bool CompactCell::empty() const noexcept
return CellUtil::empty(*this);
}

inline bool CompactCell::isTab() const noexcept
{
return _extra && _extra->flags & CellFlags::Tab;
}
inline void CompactCell::setGraphicsRendition(GraphicsRendition sgr) noexcept
{
CellUtil::applyGraphicsRendition(sgr, *this);
Expand Down
Loading

0 comments on commit 9aec7ad

Please sign in to comment.