Progress bar for Notepad IO (#1322)

This commit is contained in:
Kyle Reed 2023-07-30 00:36:57 -07:00 committed by GitHub
parent 0a3aa706ef
commit 411f6c0a34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 3 deletions

View File

@ -474,7 +474,13 @@ void TextEditorView::open_file(const fs::path& path) {
path_ = {};
file_dirty_ = false;
has_temp_file_ = false;
auto result = FileWrapper::open(path);
auto result = FileWrapper::open(
path, false, [](uint32_t value, uint32_t total) {
Painter p;
auto percent = (value * 100) / total;
auto width = (percent * screen_width) / 100;
p.draw_hline({0, 16}, width, Color::yellow());
});
if (!result) {
nav_.display_modal("Read Error", "Cannot open file:\n" + result.error().what());
@ -582,6 +588,10 @@ void TextEditorView::prepare_for_write() {
if (has_temp_file_)
return;
// TODO: This would be nice to have but it causes a stack overflow in an ISR?
// Painter p;
// p.draw_string({2, 48}, Styles::yellow, "Creating temporary file...");
// Copy to temp file on write.
has_temp_file_ = true;
delete_temp_file(path_);

View File

@ -26,6 +26,7 @@
#include "file.hpp"
#include "optional.hpp"
#include <functional>
#include <memory>
#include <string_view>
@ -75,6 +76,8 @@ class BufferWrapper {
}
virtual ~BufferWrapper() {}
std::function<void(Size, Size)> on_read_progress{};
/* Prevent copies */
BufferWrapper(const BufferWrapper&) = delete;
BufferWrapper& operator=(const BufferWrapper&) = delete;
@ -234,13 +237,23 @@ class BufferWrapper {
line_count_ = start_line_;
Offset offset = start_offset_;
// Report progress every N lines.
constexpr auto report_interval = 100u;
auto result = next_newline(offset);
auto next_report = report_interval;
while (result) {
++line_count_;
if (newlines_.size() < max_newlines)
newlines_.push_back(*result);
offset = *result + 1;
if (on_read_progress && line_count_ > next_report) {
on_read_progress(offset, size());
next_report = line_count_ + report_interval;
}
result = next_newline(offset);
}
}
@ -397,6 +410,9 @@ class BufferWrapper {
// Number of bytes left to shift.
Offset remaining = size() - src;
Offset offset = size();
Size report_total = remaining;
Size report_interval = report_total / 8;
Size next_report = remaining - report_interval;
while (remaining > 0) {
offset -= std::min(remaining, buffer_size);
@ -413,6 +429,11 @@ class BufferWrapper {
break;
remaining -= *result;
if (on_read_progress && remaining <= next_report) {
on_read_progress(report_total - remaining, report_total);
next_report = remaining > report_interval ? remaining - report_interval : 0;
}
}
}
@ -424,6 +445,9 @@ class BufferWrapper {
char buffer[buffer_size];
auto offset = src;
Size report_total = size();
Size report_interval = report_total / 8;
Size next_report = offset + report_interval;
while (true) {
wrapped_->seek(offset);
@ -438,6 +462,11 @@ class BufferWrapper {
break;
offset += *result;
if (on_read_progress && offset >= next_report) {
on_read_progress(offset, report_total);
next_report = offset + report_interval;
}
}
// Delete the extra bytes at the end of the file.
@ -463,13 +492,19 @@ class FileWrapper : public BufferWrapper<File, 64> {
template <typename T>
using Result = File::Result<T>;
using Error = File::Error;
static Result<std::unique_ptr<FileWrapper>> open(const std::filesystem::path& path, bool create = false) {
static Result<std::unique_ptr<FileWrapper>> open(
const std::filesystem::path& path,
bool create = false,
std::function<void(Size, Size)> on_read_progress = nullptr) {
auto fw = std::unique_ptr<FileWrapper>(new FileWrapper());
auto error = fw->file_.open(path, /*read_only*/ false, create);
if (error)
return *error;
if (on_read_progress)
fw->on_read_progress = on_read_progress;
fw->initialize();
return fw;
}

View File

@ -435,4 +435,29 @@ SCENARIO("Delete line.") {
}
}
SCENARIO("It calls on_read_progress while reading.") {
GIVEN("A file larger than internal buffer_size (512)") {
std::string content = std::string(599, 'a');
content.push_back('x');
MockFile f{content};
auto w = wrap_buffer(f);
auto init_line_count = w.line_count();
auto init_size = w.size();
auto called = false;
w.on_read_progress = [&called](auto, auto) {
called = true;
};
WHEN("Replacing range with larger size") {
w.replace_range({0, 2}, "bbb");
THEN("callback should be called.") {
CHECK(called);
}
}
}
}
TEST_SUITE_END();