Skip to content

Commit

Permalink
grid wip
Browse files Browse the repository at this point in the history
  • Loading branch information
christianparpart committed Aug 9, 2021
1 parent 75e4ae7 commit ad396d0
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 89 deletions.
79 changes: 64 additions & 15 deletions src/terminal/Grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <algorithm>
#include <iostream>
#include <optional>
#include <ostream>
#include <sstream>
#include <sstream>
#include <tuple>
#include <utility>
Expand All @@ -33,6 +35,7 @@ using crispy::Comparison;
using gsl::span;

using std::back_inserter;
using std::ostream;
using std::copy_n;
using std::fill_n;
using std::fill;
Expand Down Expand Up @@ -130,8 +133,8 @@ Grid::Grid(PageSize _screenSize, bool _reflowOnResize, LineCount _maxHistoryLine
maxHistoryLineCount_{ _maxHistoryLineCount },
buffer_{createBuffer(_screenSize, _maxHistoryLineCount)},
lines_{createLines(buffer_, _screenSize, _maxHistoryLineCount, _reflowOnResize, {})},
mainPageTopLineIndex_{0},
linesUsed_{_screenSize.lines}
zeroOffset_{0},
linesUsed_{_screenSize.lines.as<size_t>()}
{
}

Expand Down Expand Up @@ -540,7 +543,7 @@ Coordinate Grid::resize(PageSize _newSize, Coordinate _currentCursorPos)

void Grid::appendNewLines(LineCount _count, GraphicsAttributes _attr)
{
auto const wrappable = lines_[*linesUsed_].wrappableFlag() == Line::Flags::Wrappable;
auto const wrappable = lines_[linesUsed_].wrappableFlag() == Line::Flags::Wrappable;

for (auto i = LineOffset(0); i < _count.as<LineOffset>(); ++i)
{
Expand All @@ -550,24 +553,34 @@ void Grid::appendNewLines(LineCount _count, GraphicsAttributes _attr)
line.setWrappable(wrappable);
}

mainPageTopLineIndex_ += _count.as<LineOffset>();
linesUsed_ = (linesUsed_ + *_count) % lineCapacity();

//mainPageTopLineIndex_ += _count.as<LineOffset>();
}

void Grid::clearHistory()
{
linesUsed_ = screenSize_.lines;
zeroOffset_ = (zeroOffset_ + linesUsed_ - *screenSize_.lines) % lineCapacity();
linesUsed_ = screenSize_.lines.as<size_t>();
}

void Grid::clampHistory()
{
linesUsed_ = screenSize_.lines;
linesUsed_ = screenSize_.lines.as<size_t>();
}

void Grid::scrollUpUninitialized(LineCount _n)
{
mainPageTopLineIndex_ += _n.as<LineOffset>();
mainPageTopLineIndex_ %= LineOffset::cast_from(lines_.size());
linesUsed_ = min(linesUsed_ + _n, LineCount::cast_from(lines_.size()));
if (linesUsed_ < lines_.size())
linesUsed_ = min(linesUsed_ + _n.as<size_t>(), lines_.size());
else
{
buffer_.rotate_left(_n.as<size_t>() * screenSize_.columns.as<size_t>());
zeroOffset_ = (zeroOffset_ + linesUsed() + _n.as<size_t>()) % lineCapacity();
// mainPageTopLineIndex_ += _n.as<LineOffset>();
// if (mainPageTopLineIndex_.as<size_t>() > lines_.size())
// mainPageTopLineIndex_ = LineOffset::cast_from(mainPageTopLineIndex_.as<size_t>() - lines_.size());
}
}

void Grid::scrollUp(LineCount _n, GraphicsAttributes const& _defaultAttributes, Margin const& _margin)
Expand All @@ -582,14 +595,17 @@ void Grid::scrollUp(LineCount _n, GraphicsAttributes const& _defaultAttributes,
// Margin spans full page.
if (auto const n = min(_n, screenSize_.lines); *n > 0)
{
auto const wrappable = lines_[*linesUsed_].wrappableFlag() == Line::Flags::Wrappable;
auto const baseLineOffset = mainPageTopLineIndex_
+ screenSize_.lines.as<LineOffset>();
// newZero := (zero + n) % cap
auto const wrappable = lines_[linesUsed_].wrappableFlag() == Line::Flags::Wrappable;
auto const baseLineOffset = zeroOffset_ + *screenSize_.lines;

for (auto const i: ranges::views::iota(0u, n.as<size_t>()))
resetLine(baseLineOffset + LineOffset::cast_from(i), _defaultAttributes);
resetLine(LineOffset::cast_from(baseLineOffset + i), _defaultAttributes);

scrollUpUninitialized(n);
zeroOffset_ = (zeroOffset_ + *n) % lineCapacity();
if (linesUsed() < lineCapacity())
linesUsed_ = min(linesUsed_ + *n, lineCapacity());
//scrollUpUninitialized(n);
}
return;
}
Expand Down Expand Up @@ -737,7 +753,7 @@ string Grid::renderAllText() const
);

int columnIndex = 0;
for (auto line = LineOffset(0); line < linesUsed_.as<LineOffset>(); ++line)
for (auto line = LineOffset(0); line < linesUsed().as<LineOffset>(); ++line)
{
auto lineStart = lines_[realLineOffset(line).as<size_t>()].begin_offset();
auto const lineEnd = lineStart + lineLength(line).as<size_t>();
Expand Down Expand Up @@ -777,4 +793,37 @@ string Grid::renderMainPageText() const
}
// }}}

ostream& dumpGrid(std::ostream& os, Grid const& grid)
{
string text;
for (Cell const& cell: grid.buffer())
if (cell.codepointCount())
text += cell.toUtf8();
else
text += ' ';
os << fmt::format("raw buffer: '{}'\n", text);
os << fmt::format("main page top index: {}, lines: {}/{} + {}\n",
grid.baseline(),
grid.historyLineCount(),
grid.maxHistoryLineCount(), grid.screenSize().lines);

for (auto const row: ranges::views::iota(-grid.historyLineCount().as<int>(), grid.screenSize().lines.as<int>()))
{
terminal::Line const& lineAttribs = grid.lineAt(LineOffset(row));

os << fmt::format("[{}] \"{}\" | {}\n",
row, grid.renderTextLine(LineOffset::cast_from(row)),
lineAttribs.flags());
}

return os;
}

string dumpGrid(Grid const& grid)
{
std::stringstream sstr;
dumpGrid(sstr, grid);
return sstr.str();
}

}
87 changes: 38 additions & 49 deletions src/terminal/Grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@
#include <terminal/Image.h>
#include <terminal/primitives.h>

#include <crispy/algorithm.h>
#include <crispy/indexed.h>
#include <crispy/point.h>
#include <crispy/range.h>
#include <crispy/size.h>
#include <crispy/span.h>
#include <crispy/times.h>
#include <crispy/ring.h>
#include <crispy/utils.h>

#include <unicode/grapheme_segmenter.h>
Expand All @@ -39,6 +33,8 @@
#include <gsl/span>
#include <gsl/span_ext>

#include <range/v3/view/iota.hpp>

#include <algorithm>
#include <array>
#include <deque>
Expand Down Expand Up @@ -471,7 +467,7 @@ inline bool operator==(Cell const& a, Cell const& b) noexcept
if (!(a.attributes() == b.attributes()))
return false;

for (auto const i : crispy::times(a.codepointCount()))
for (auto const i: ranges::views::iota(a.codepointCount()))
if (a.codepoint(i) != b.codepoint(i))
return false;

Expand All @@ -480,7 +476,7 @@ inline bool operator==(Cell const& a, Cell const& b) noexcept

// }}}

using GridBuffer = std::vector<Cell>;
using GridBuffer = crispy::Ring<Cell>;

class Line // {{{
{
Expand Down Expand Up @@ -582,7 +578,7 @@ constexpr bool operator&(Line::Flags a, Line::Flags b) noexcept
}
// }}}

using Lines = std::vector<Line>;
using Lines = crispy::Ring<Line>;

/**
* Manages the screen grid buffer (main screen + scrollback history).
Expand Down Expand Up @@ -635,16 +631,6 @@ class Grid
/// @returns updated cursor position.
Coordinate resize(PageSize _screenSize, Coordinate _currentCursorPos);

LineOffset scrollTopOffset() const noexcept
{
return -(linesUsed_ - screenSize_.lines).as<LineOffset>();
}

LineCount historyLineCount() const noexcept
{
return linesUsed_ - screenSize_.lines;
}

// }}}

// {{{ Line API
Expand All @@ -659,8 +645,7 @@ class Grid
gsl::span<Cell> lineBuffer(LineOffset _line) noexcept
{
auto const width = screenSize_.columns.as<size_t>();
auto const lineOffset = realLineOffset(_line).as<size_t>();
Cell* start = buffer_.data() + lineOffset * width;
Cell* start = &buffer_[_line.as<size_t>() * width];
return gsl::make_span(start, width);
}

Expand Down Expand Up @@ -772,20 +757,29 @@ class Grid

// }}}

/// Converts a relative line number into an absolute line number.
int toAbsoluteLine(int _relativeLine) const noexcept;
size_t lineCapacity() const noexcept { return lines_.size(); }

/// Returns the maximum number of lines this grid can hold.
size_t linesAvailable() const noexcept { return maxLines_; }

/// Returns the number of lines used, i.e. scrollback lines plus main page lines.
size_t linesUsed() const noexcept { return lines_.size(); }

LineOffset realLineOffset(LineOffset p) const noexcept
LineOffset mainPageTopOffset() const noexcept
{
return (mainPageTopLineIndex_.as<LineOffset>() + p)
% LineOffset::cast_from(lines_.size());
return LineOffset::cast_from(lines_.size()) - screenSize_.lines.as<LineOffset>();
}

/// Translates relative line offset into an absolute offset into the buffer.
size_t toBufferOffset(LineOffset p) const noexcept
LineOffset realLineOffset(LineOffset p) const noexcept { return p; }

LineCount historyLineCount() const noexcept
{
return LineCount::cast_from(linesUsed() - *screenSize_.lines);
}

LineOffset scrollTopOffset() const noexcept
{
auto const lineNr = (mainPageTopLineIndex_.as<LineOffset>() + p).as<size_t>() % lines_.size();
return lineNr * screenSize_.columns.as<size_t>();
return - historyLineCount().as<LineOffset>();
}

private:
Expand All @@ -801,34 +795,34 @@ class Grid
LineCount maxHistoryLineCount_;

GridBuffer buffer_;

Lines lines_;
LineOffset mainPageTopLineIndex_; //!< index to first line in the ring buffer.
LineCount linesUsed_; //!< number of lines used in the scrollback ring buffer.
// XXX ^^^ do we want/need you?
size_t maxLines_;
};

std::ostream& dumpGrid(std::ostream& os, Grid const& grid);
std::string dumpGrid(Grid const& grid);

// {{{ inlines
template <typename RendererT>
inline void Grid::render(RendererT && _render, ScrollOffset _scrollOffset) const
{
assert(!_scrollOffset || _scrollOffset.as<LineCount>() <= historyLineCount());

auto const scrollOffset = -_scrollOffset.as<LineOffset>();
auto const topLeftOffset = realLineOffset(scrollOffset).as<size_t>() * screenSize_.columns.as<size_t>();
auto const topLeftOffset = mainPageTopOffset().as<long>()
- _scrollOffset.as<long>() * screenSize_.columns.as<long>();
auto const bottomRightOffset = topLeftOffset + *screenSize_.columns * *screenSize_.lines;
auto const pageCellCount = screenSize_.lines.as<size_t>() * screenSize_.columns.as<size_t>();

assert(bottomRightOffset >= pageCellCount);

auto a = buffer_.data() + topLeftOffset;
auto b = buffer_.data() + bottomRightOffset;
auto k = 0ul;
auto a = std::next(buffer_.begin(), topLeftOffset);
auto b = std::next(buffer_.begin(), bottomRightOffset);
auto k = 0l;
while (a != b)
{
_render(*a++,
LineOffset(k / screenSize_.columns.as<size_t>()),
ColumnOffset(k % screenSize_.columns.as<size_t>()));
LineOffset::cast_from(k / *screenSize_.columns),
ColumnOffset::cast_from(k % *screenSize_.columns));
k++;
}
}
Expand All @@ -844,11 +838,6 @@ inline Line const& Grid::lineAt(LineOffset _line) const noexcept
return const_cast<Grid&>(*this).lineAt(_line);
}

inline int Grid::toAbsoluteLine(int _relativeLine) const noexcept
{
return *historyLineCount() + _relativeLine;
}

inline Cell& Grid::at(LineOffset _line, ColumnOffset _column) noexcept
{
Expects(ColumnOffset(0) <= _column);
Expand All @@ -865,8 +854,8 @@ inline Cell const& Grid::at(LineOffset _line, ColumnOffset _column) const noexce

inline gsl::span<Line> Grid::lines(LineOffset _start, LineCount _count)
{
assert(crispy::ascending(LineOffset{0}, _start, boxed_cast<LineOffset>(linesUsed_)) && "Absolute scroll offset must not be negative or overflowing.");
assert(_start.as<LineCount>() + _count.as<LineCount>() <= linesUsed_ && "Absolute scroll offset must not be negative or overflowing.");
assert(crispy::ascending(size_t{0}, _start.as<size_t>(), linesUsed_) && "Absolute scroll offset must not be negative or overflowing.");
assert(*_start + *_count <= linesUsed_ && "Absolute scroll offset must not be negative or overflowing.");

return gsl::span<Line>{
lines_.data() + _start.as<size_t>(),
Expand Down
7 changes: 5 additions & 2 deletions src/terminal/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,8 @@ void Screen::writeText(std::string_view _chars)
{
bool const cursorInsideMargin = isModeEnabled(DECMode::LeftRightMargin) && isCursorInsideMargins();
auto const cellsAvailable = cursorInsideMargin
? *(margin_.horizontal.to - cursor_.position.column) - 1
: *size_.columns - *cursor_.position.column - 1;
? *(margin_.horizontal.to - cursor_.position.column)
: *size_.columns - *cursor_.position.column;
auto const n = min(size_t(cellsAvailable), charsLeft);
for (size_t k = 0; k < n && i != e; ++k)
{
Expand Down Expand Up @@ -588,7 +588,10 @@ void Screen::writeText(std::string_view _chars)
}
++i;
}
charsLeft -= n;
linefeed(margin_.horizontal.from);
std::cout << fmt::format("line written\n");
std::cout << dumpGrid(grid());
}

// TODO: Call this but with range range of point.
Expand Down
Loading

0 comments on commit ad396d0

Please sign in to comment.