Skip to content

Commit fc34a63

Browse files
WIP
1 parent 1a7ae70 commit fc34a63

File tree

9 files changed

+120
-12
lines changed

9 files changed

+120
-12
lines changed

src/vtbackend/CellFlags.h

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum class CellFlags : uint32_t
4444
Overline = (1 << 14),
4545
RapidBlinking = (1 << 15),
4646
CharacterProtected = (1 << 16), // Character is protected by selective erase operations.
47+
Tab = (1 << 17), // Cell is part of tab character.
4748
};
4849

4950
constexpr CellFlags& operator|=(CellFlags& a, CellFlags b) noexcept

src/vtbackend/Line.cpp

+25-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ inline void Line<Cell>::resize(ColumnCount count)
101101
{
102102
TrivialBuffer& buffer = trivialBuffer();
103103
buffer.displayWidth = count;
104+
buffer.tabstops.resize(count.as<size_t>());
104105
return;
105106
}
106107
}
@@ -168,7 +169,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
168169
auto lastChar = char32_t { 0 };
169170
auto utf8DecoderState = unicode::utf8_decoder_state {};
170171
auto gapPending = 0;
171-
172+
size_t cellNr = 0;
172173
for (char const ch: input.text.view())
173174
{
174175
unicode::ConvertResult const r = unicode::from_utf8(utf8DecoderState, static_cast<uint8_t>(ch));
@@ -189,6 +190,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
189190
columns.emplace_back(Cell {});
190191
columns.back().setHyperlink(input.hyperlink);
191192
columns.back().write(input.textAttributes, nextChar, static_cast<uint8_t>(charWidth));
193+
columns.back().setTab(input.tabstops[cellNr]);
192194
gapPending = charWidth - 1;
193195
}
194196
else
@@ -207,6 +209,7 @@ InflatedLineBuffer<Cell> inflate(TrivialLineBuffer const& input)
207209
}
208210
}
209211
lastChar = nextChar;
212+
++cellNr;
210213
}
211214

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

220223
while (columns.size() < unbox<size_t>(input.displayWidth))
224+
{
221225
columns.emplace_back(Cell { input.fillAttributes });
226+
columns.back().setTab(input.tabstops[cellNr]);
227+
++cellNr;
228+
}
222229

223230
return columns;
224231
}
232+
233+
template <typename Cell>
234+
void Line<Cell>::setTab(ColumnOffset start, ColumnCount n, bool tab)
235+
{
236+
if (isInflatedBuffer())
237+
{
238+
for (; n > ColumnCount(0); --n)
239+
useCellAt(start++).setTab(tab);
240+
}
241+
else
242+
{
243+
auto& buffer = trivialBuffer();
244+
for (; n > ColumnCount(0); --n)
245+
buffer.tabstops[(start++).as<size_t>()] = true;
246+
// assert(false);
247+
}
248+
}
225249
} // end namespace terminal
226250

227251
#include <vtbackend/cell/CompactCell.h>

src/vtbackend/Line.h

+25-2
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ struct TrivialLineBuffer
6363

6464
ColumnCount usedColumns {};
6565
crispy::BufferFragment<char> text {};
66-
66+
std::vector<bool> tabstops = std::vector<bool>(displayWidth.value, false);
6767
void reset(GraphicsAttributes attributes) noexcept
6868
{
6969
textAttributes = attributes;
7070
fillAttributes = attributes;
7171
hyperlink = {};
7272
usedColumns = {};
7373
text.reset();
74+
tabstops.clear();
7475
}
7576
};
7677

@@ -233,6 +234,15 @@ class Line
233234
return inflatedBuffer().at(unbox<size_t>(column)).empty();
234235
}
235236

237+
[[nodiscard]] bool hasTabstop(ColumnOffset column) const noexcept
238+
{
239+
Require(ColumnOffset(0) <= column);
240+
Require(column <= ColumnOffset::cast_from(size()));
241+
if (isInflatedBuffer())
242+
return cells()[column.as<size_t>()].isTab();
243+
return trivialBuffer().tabstops[column.as<size_t>()];
244+
}
245+
236246
[[nodiscard]] uint8_t cellWidthAt(ColumnOffset column) const noexcept
237247
{
238248
#if 0 // TODO: This optimization - but only when we return actual widths and not always 1.
@@ -257,6 +267,8 @@ class Line
257267
[[nodiscard]] bool wrappable() const noexcept { return isFlagEnabled(LineFlags::Wrappable); }
258268
void setWrappable(bool enable) { setFlag(LineFlags::Wrappable, enable); }
259269

270+
void setTab(ColumnOffset start, ColumnCount n, bool tab);
271+
260272
[[nodiscard]] LineFlags wrappableFlag() const noexcept
261273
{
262274
return wrappable() ? LineFlags::Wrappable : LineFlags::None;
@@ -315,7 +327,18 @@ class Line
315327
return !std::holds_alternative<TrivialBuffer>(storage_);
316328
}
317329

318-
void setBuffer(Storage buffer) noexcept { storage_ = std::move(buffer); }
330+
void setBuffer(Storage buffer) noexcept
331+
{
332+
if (isTrivialBuffer())
333+
std::get<TrivialBuffer>(buffer).tabstops = std::move(trivialBuffer().tabstops);
334+
else
335+
{
336+
size_t cellNr = 0;
337+
for (auto const& cell: cells())
338+
std::get<TrivialBuffer>(buffer).tabstops[cellNr++] = cell.isTab();
339+
}
340+
storage_ = std::move(buffer);
341+
}
319342

320343
// Tests if the given text can be matched in this line at the exact given start column.
321344
[[nodiscard]] bool matchTextAt(std::u32string_view text, ColumnOffset startColumn) const noexcept

src/vtbackend/Screen.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ using std::vector;
8686
namespace terminal
8787
{
8888

89-
auto constexpr inline TabWidth = ColumnCount(8);
89+
extern auto const TabWidth = ColumnCount(8);
9090

9191
auto const inline VTCaptureBufferLog = logstore::Category("vt.ext.capturebuffer",
9292
"Capture Buffer debug logging.",
@@ -1464,9 +1464,12 @@ void Screen<Cell>::moveCursorToNextTab()
14641464
++i;
14651465

14661466
auto const currentCursorColumn = logicalCursorPosition().column;
1467-
1467+
auto const cursorMoveAmount = boxed_cast<ColumnCount>(_state.tabs[i] - currentCursorColumn);
14681468
if (i < _state.tabs.size())
1469-
moveCursorForward(boxed_cast<ColumnCount>(_state.tabs[i] - currentCursorColumn));
1469+
{
1470+
currentLine().setTab(currentCursorColumn, cursorMoveAmount, true);
1471+
moveCursorForward(cursorMoveAmount);
1472+
}
14701473
else if (realCursorPosition().column < margin().horizontal.to)
14711474
moveCursorForward(boxed_cast<ColumnCount>(margin().horizontal.to - currentCursorColumn));
14721475
else
@@ -1480,6 +1483,7 @@ void Screen<Cell>::moveCursorToNextTab()
14801483
auto const n =
14811484
min((TabWidth - boxed_cast<ColumnCount>(_cursor.position.column) % TabWidth),
14821485
_settings.pageSize.columns - boxed_cast<ColumnCount>(logicalCursorPosition().column));
1486+
currentLine().setTab(logicalCursorPosition().column, n, true);
14831487
moveCursorForward(n);
14841488
}
14851489
else

src/vtbackend/Screen.h

+5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class ScreenBase: public SequenceHandler
7373
[[nodiscard]] virtual Margin& margin() noexcept = 0;
7474
[[nodiscard]] virtual bool contains(CellLocation coord) const noexcept = 0;
7575
[[nodiscard]] virtual bool isCellEmpty(CellLocation position) const noexcept = 0;
76+
[[nodiscard]] virtual bool hasTabstop(CellLocation position) const noexcept = 0;
7677
[[nodiscard]] virtual bool compareCellTextAt(CellLocation position, char codepoint) const noexcept = 0;
7778
[[nodiscard]] virtual std::string cellTextAt(CellLocation position) const noexcept = 0;
7879
[[nodiscard]] virtual std::string lineTextAt(LineOffset line) const noexcept = 0;
@@ -509,6 +510,10 @@ class Screen final: public ScreenBase, public capabilities::StaticDatabase
509510
return _grid.lineAt(position.line).cellEmptyAt(position.column);
510511
}
511512

513+
[[nodiscard]] bool hasTabstop(CellLocation position) const noexcept override
514+
{
515+
return _grid.lineAt(position.line).hasTabstop(position.column);
516+
}
512517
[[nodiscard]] bool compareCellTextAt(CellLocation position, char codepoint) const noexcept override
513518
{
514519
auto const& cell = _grid.lineAt(position.line).inflatedBuffer().at(position.column.as<size_t>());

src/vtbackend/Terminal.cpp

+30-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include <utility>
3939
#include <variant>
4040

41+
#include "fmt/core.h"
42+
4143
using crispy::Size;
4244

4345
using namespace std;
@@ -48,7 +50,8 @@ using std::move;
4850

4951
namespace terminal
5052
{
51-
53+
// inline constexpr auto TabWidth = ColumnCount(8);
54+
extern const ColumnCount TabWidth;
5255
namespace // {{{ helpers
5356
{
5457
constexpr size_t MaxColorPaletteSaveStackSize = 10;
@@ -786,7 +789,28 @@ bool Terminal::sendMouseMoveEvent(Modifier modifier,
786789
{
787790
if (currentScreen().isCellEmpty(relativePos) && !currentScreen().compareCellTextAt(relativePos, 0x20))
788791
{
789-
relativePos.column = ColumnOffset { 0 } + *(_settings.pageSize.columns - 1);
792+
if (currentScreen().hasTabstop(relativePos))
793+
{
794+
if (!_state.tabs.empty())
795+
{
796+
auto tab = std::upper_bound(_state.tabs.begin(), _state.tabs.end(), relativePos.column);
797+
relativePos.column = (tab == _state.tabs.end())
798+
? ColumnOffset::cast_from(_settings.pageSize.columns - 1)
799+
: *tab;
800+
}
801+
else
802+
{
803+
auto const n =
804+
min((TabWidth - boxed_cast<ColumnCount>(relativePos.column) % TabWidth),
805+
_settings.pageSize.columns - boxed_cast<ColumnCount>(relativePos.column));
806+
relativePos.column += n;
807+
}
808+
}
809+
else
810+
{
811+
fmt::print("Why here?\n");
812+
relativePos.column = ColumnOffset::cast_from(_settings.pageSize.columns - 1);
813+
}
790814
}
791815
changed = true;
792816
selector()->extend(relativePos);
@@ -1139,10 +1163,11 @@ namespace
11391163
text += '\n';
11401164
currentLine.clear();
11411165
}
1142-
if (cell.empty())
1166+
if (cell.isTab())
1167+
{
11431168
currentLine += ' ';
1144-
else
1145-
currentLine += cell.toUtf8();
1169+
}
1170+
currentLine += cell.toUtf8();
11461171
lastColumn = pos.column;
11471172
}
11481173

src/vtbackend/cell/CellConcept.h

+3
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ concept CellConcept = requires(T t, T const& u)
9999

100100
{ u.hyperlink() } -> std::same_as<HyperlinkId>;
101101
t.setHyperlink(HyperlinkId{});
102+
103+
t.setTab(bool{});
104+
{ u.isTab() } noexcept -> std::same_as<bool>;
102105
};
103106

104107

src/vtbackend/cell/CompactCell.h

+14
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class CRISPY_PACKED CompactCell
127127
void setForegroundColor(Color color) noexcept;
128128
[[nodiscard]] Color backgroundColor() const noexcept;
129129
void setBackgroundColor(Color color) noexcept;
130+
void setTab(bool tab) noexcept;
130131

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

141142
[[nodiscard]] bool empty() const noexcept;
143+
[[nodiscard]] bool isTab() const noexcept;
142144

143145
void setGraphicsRendition(GraphicsRendition sgr) noexcept;
144146

@@ -408,6 +410,14 @@ inline void CompactCell::setBackgroundColor(Color color) noexcept
408410
_backgroundColor = color;
409411
}
410412

413+
inline void CompactCell::setTab(bool tab) noexcept
414+
{
415+
if (tab)
416+
extra().flags |= CellFlags::Tab;
417+
else
418+
extra().flags &= ~CellFlags::Tab;
419+
}
420+
411421
inline Color CompactCell::underlineColor() const noexcept
412422
{
413423
if (!_extra)
@@ -460,6 +470,10 @@ inline bool CompactCell::empty() const noexcept
460470
return CellUtil::empty(*this);
461471
}
462472

473+
inline bool CompactCell::isTab() const noexcept
474+
{
475+
return _extra && _extra->flags & CellFlags::Tab;
476+
}
463477
inline void CompactCell::setGraphicsRendition(GraphicsRendition sgr) noexcept
464478
{
465479
CellUtil::applyGraphicsRendition(sgr, *this);

src/vtbackend/cell/SimpleCell.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class SimpleCell
7373
void setForegroundColor(Color color) noexcept;
7474
void setBackgroundColor(Color color) noexcept;
7575
void setUnderlineColor(Color color) noexcept;
76+
void setTab(bool tab) noexcept;
7677
[[nodiscard]] Color foregroundColor() const noexcept;
7778
[[nodiscard]] Color backgroundColor() const noexcept;
7879
[[nodiscard]] Color underlineColor() const noexcept;
@@ -84,6 +85,7 @@ class SimpleCell
8485
void setHyperlink(HyperlinkId hyperlink) noexcept;
8586

8687
[[nodiscard]] bool empty() const noexcept { return CellUtil::empty(*this); }
88+
[[nodiscard]] bool isTab() const noexcept { return _flags & CellFlags::Tab; }
8789

8890
private:
8991
std::u32string _codepoints {};
@@ -123,7 +125,6 @@ inline void SimpleCell::write(GraphicsAttributes sgr, char32_t codepoint, uint8_
123125
_graphicsAttributes = sgr;
124126
_codepoints.clear();
125127
_codepoints.push_back(codepoint);
126-
127128
_width = width;
128129
}
129130

@@ -238,6 +239,14 @@ inline void SimpleCell::setUnderlineColor(Color color) noexcept
238239
_graphicsAttributes.underlineColor = color;
239240
}
240241

242+
inline void SimpleCell::setTab(bool tab) noexcept
243+
{
244+
if (tab)
245+
_flags |= CellFlags::Tab;
246+
else
247+
_flags &= ~CellFlags::Tab;
248+
}
249+
241250
inline Color SimpleCell::foregroundColor() const noexcept
242251
{
243252
return _graphicsAttributes.foregroundColor;

0 commit comments

Comments
 (0)