#pragma once #include #include #include #include #include namespace roro::files { // A text file of any size, shown a screen at a time (F1, Q134): only the part on screen is read, // through `read`, about a kilobyte at once. Lines wrap at spaces, `cols` characters wide. Going // back a line means finding where the paragraph before started and wrapping it again, so a file // reads the same whichever way it was scrolled. class TextPager { public: // Reads up to `len` bytes at `offset`; returns how many it got. using ReadAt = std::function; TextPager(ReadAt read, uint32_t size, int cols, int rows); void toStart() { top_ = 0; } void toEnd(); // the last line at the bottom of the screen void down(int lines = 1); void up(int lines = 1); std::vector lines(); // what's on screen: tabs as spaces, control characters as dots uint32_t top() const { return top_; } uint32_t size() const { return size_; } bool atEnd(); // the file's last line is on screen int percent() const { return size_ ? static_cast(static_cast(top_) * 100 / size_) : 0; } private: static constexpr size_t kBlock = 1024; // read at once static constexpr uint32_t kLookBack = 1024; // how far back a paragraph's start is looked for const uint8_t* bytes(uint32_t at, size_t& len); // what's cached from `at` on int byteAt(uint32_t at); // -1 past the end uint32_t nextLine(uint32_t at, std::string* text); // where the line after the one at `at` starts uint32_t lineBefore(uint32_t at); ReadAt read_; uint32_t size_; int cols_, rows_; uint32_t top_ = 0; std::vector cache_; uint32_t cacheAt_ = 0; }; } // namespace roro::files