Skip to content

Commit

Permalink
Improve videodump performance and add new block script type
Browse files Browse the repository at this point in the history
  • Loading branch information
mls-m5 committed Nov 4, 2023
1 parent 30f90ca commit dd69b83
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 255 deletions.
7 changes: 7 additions & 0 deletions data/example_playback_scripts/script1.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@

// block 5
void print() {
std::cout << "this is a block\n";
}
// end

int main() {
1-2: std::cout << "hello, world\n";
2: std::cout << "hello there\n";
Expand Down
2 changes: 1 addition & 1 deletion lib/matrix-screen
Submodule matrix-screen updated 1 files
+1 −1 lib/sdlpp
245 changes: 1 addition & 244 deletions src/codeplayback/codeplayback.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@

#include "edit.h"
#include "files/config.h"
#include "files/file.h"
#include "playbacksettings.h"
#include "sdlpp/image.hpp"
#include "syntax/basichighligting.h"
#include "text/bufferedit.h"
#include "text/cursorops.h"
#include "text/fstring.h"
#include "text/utf8char.h"
#include "videodump.h"
#include "views/editor.h"
#include "views/iwindow.h"
Expand Down Expand Up @@ -87,247 +85,6 @@ struct PlaybackWindow : public Window {
void draw(IScreen &) override {}
};

BufferEdit createEdit(Buffer &buffer, FString textA, FString textB) {
auto edit = BufferEdit{
.from = textA,
.to = textB,
.position = {buffer, 0, 0},
};
edit.trim();
return edit;
}

/// Creates smaller edits (single characters) that looks more like written text
std::vector<BufferEdit> splitEdit(const BufferEdit &old) {
auto ret = std::vector<BufferEdit>{};

{
// Note that the first edit just removes the text
ret.push_back(BufferEdit{
.from = old.from,
.to = {},
.position = old.position,
});
}

auto position = old.position;
for (auto c : old.to) {
ret.push_back({
.from = "",
.to = FString{1, c},
.position = position,
});

if (c == '\n') {
position.x(0);
position.y(position.y() + 1);
}
else {
position.x(position.x() + 1);
}
}

return ret;
}

// Struct that extract the numbers that is put before a line or after
struct FrameNumLineDescription {

bool tryPrefix(const std::string fullLine) {
auto line = fullLine;
std::string beginStr = std::string{};
while (!line.empty() && std::isdigit(line.front())) {
beginStr += line.front();
line.erase(0, 1);
}

if (line.empty() || (line.front() != '-' && line.front() != ':')) {
begin = -1;
end = std::numeric_limits<int>::max();
this->line = fullLine;
return false;
}

begin = std::stoi(beginStr);
end = std::numeric_limits<int>::max();

if (line.front() == ':') {
this->line = line.substr(1);
return true;
}

std::string endStr;
// line.front must be '-'
line.erase(0, 1); // remove '-'
while (!line.empty() && std::isdigit(line.front())) {
endStr += line.front();
line.erase(0, 1);
}

if (line.empty() || line.front() != ':') {
begin = -1;
end = std::numeric_limits<int>::max();
this->line = fullLine;
return false;
}

line.erase(0, 1); // Remove ':'

end = stoi(endStr);
this->line = line;
return true;
}

/// For formating sake i sometimes comment out some of the versions
/// so that you could run clang-format on the file without it being messed
/// up, but then you need to remove the comment
/// This function only removes comments that has only spaces (indentation)
/// before them
std::string removeInitialComment(const std::string &line) {
// Regex pattern to match lines that start with spaces followed by a
// comment
std::regex commentRegex(R"_(^(\s*)//\s*(.*))_");

std::smatch match;
if (std::regex_search(line, match, commentRegex)) {
auto res = match[1].str() + match[2].str();

auto m2 = match[2].str();
if (!m2.empty() && m2.front() == '$') {
m2.erase(0, 1);
return match[1].str() + m2;
}

return res;
}
return line;
}

bool tryComments(const std::string &line) {
// Regex for range number
std::regex rangeRegex(R"(\s*//\s*(\d+)-(\d+)\s*$)");
// Regex for single number
std::regex singleRegex(R"(\s*//\s*(\d+)\s*$)");

std::smatch match;
if (std::regex_search(line, match, rangeRegex)) {
begin = std::stoi(match[1]);
end = std::stoi(match[2]);
this->line = removeInitialComment(line.substr(0, match.position()));
return true;
}
else if (std::regex_search(line, match, singleRegex)) {
begin = std::stoi(match[1]);
this->line = removeInitialComment(line.substr(0, match.position()));
return true;
}
this->line = line;
return false;
}

FrameNumLineDescription(const std::string &fullLine) {
if (tryPrefix(fullLine)) {
return;
}

tryComments(fullLine);
}

std::string line; // The line without the line
int begin = -1;
int end = std::numeric_limits<int>::max();

bool isInside(int i) const {
return i >= begin && i < end;
}

operator bool() const {
return begin >= 0;
}

bool hasEnd() const {
return end < std::numeric_limits<int>::max();
}
};

std::string extractSingleFrame(
const std::vector<FrameNumLineDescription> &descriptions, int frameNum) {
auto res = std::ostringstream{};

for (auto &d : descriptions) {
if (d.isInside(frameNum)) {
res << d.line << "\n";
}
}

return res.str();
}

std::vector<FrameNumLineDescription> streamToDescriptions(std::istream &ss) {
auto descriptions = std::vector<FrameNumLineDescription>{};

int isHead = 2; // 2 = Comments at beginning of file, 1 = spaces after this
for (std::string line; std::getline(ss, line);) {
if (isHead == 2) {
if (line.rfind("//", 0) == 0) {
continue;
}
isHead = 1;
}
if (isHead == 1) {
if (line.empty()) {
continue;
}

isHead = 0;
}
auto descriptor = FrameNumLineDescription{line};
descriptions.push_back(std::move(descriptor));
}

return descriptions;
}

std::vector<BufferEdit> descriptionsToBufferEdit(
Buffer &buffer, const std::vector<FrameNumLineDescription> &descriptions) {
int max = 0;
for (auto &d : descriptions) {
if (d.hasEnd()) {
max = std::max(d.end, max);
}
max = std::max(d.begin + 1, max);
}

auto ret = std::vector<BufferEdit>{};
auto lastFrame = std::string{};
for (int i = 0; i < max; ++i) {
auto newFrame = extractSingleFrame(descriptions, i);
ret.push_back(createEdit(buffer, lastFrame, newFrame));
lastFrame = newFrame;
}

return ret;
}

std::vector<BufferEdit> extractEditsFromString(Buffer &buffer, std::string in) {
auto descriptions = [&] {
auto ss = std::istringstream{std::move(in)};
return streamToDescriptions(ss);
}();

return descriptionsToBufferEdit(buffer, descriptions);
}

std::vector<BufferEdit> loadEditsFromFile(Buffer &buffer,
std::filesystem::path path) {
auto descriptions = [&] {
auto file = std::ifstream{path};
return streamToDescriptions(file);
}();

return descriptionsToBufferEdit(buffer, descriptions);
}

int main(int argc, char *argv[]) {
const auto settings = CodePlaybackSettings{argc, argv};

Expand Down
Loading

0 comments on commit dd69b83

Please sign in to comment.