Toying with event recording to see if it can be used for testing

This commit is contained in:
Krzosa Karol
2024-06-29 07:35:22 +02:00
parent 2807573012
commit 0d3cb029d8
5 changed files with 246 additions and 161 deletions

View File

@@ -227,6 +227,9 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
Scratch scratch((Arena *)buffer->allocator.object);
Assert(buffer->data[0]);
Assert(buffer->allocator.proc);
Assert(buffer->lines.len);
// Figure out how much we insert and how much we delete so
// we can resize buffers properly if necessary
@@ -356,13 +359,22 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
}
buffer->lines.add({base_index, base_index + string.len});
}
Assert(buffer->data[0]);
Assert(buffer->allocator.proc);
Assert(buffer->lines.len);
}
void InitBuffer(Buffer *buffer) {
Scratch scratch;
Array<Edit> edits = {};
AddEdit(&edits, {}, "");
ApplyEdits(buffer, edits);
void InitBuffer(Allocator allocator, Buffer *buffer, int64_t _size = 4096) {
int64_t size = AlignUp(_size, 4096);
buffer->allocator = allocator;
for (int i = 0; i < 2; i += 1) {
buffer->data[i] = AllocArray(allocator, char, size);
Assert(buffer->data[i]);
}
buffer->cap = size;
buffer->lines.allocator = allocator;
buffer->lines.add({});
}
String CopyNullTerminated(Allocator allocator, Buffer &buffer, Range range) {
@@ -569,3 +581,29 @@ int64_t Seek(Buffer &buffer, int64_t pos, int64_t direction = ITERATE_FORWARD) {
}
return result;
}
int64_t MoveRight(Buffer &buffer, int64_t pos) {
pos = pos + 1;
pos = AdjustUTF8Pos(buffer, pos);
Assert(pos >= 0 && pos <= buffer.len);
return pos;
}
int64_t MoveLeft(Buffer &buffer, int64_t pos) {
pos = pos - 1;
pos = AdjustUTF8Pos(buffer, pos, -1);
Assert(pos >= 0 && pos <= buffer.len);
return pos;
}
int64_t MoveDown(Buffer &buffer, int64_t pos) {
LineAndColumn info = FindLineAndColumn(buffer, pos);
int64_t new_pos = FindPos(buffer, info.line.number + 1, info.column);
return new_pos;
}
int64_t MoveUp(Buffer &buffer, int64_t pos) {
LineAndColumn info = FindLineAndColumn(buffer, pos);
int64_t new_pos = FindPos(buffer, info.line.number - 1, info.column);
return new_pos;
}

View File

@@ -0,0 +1,133 @@
bool EventRecording = false;
bool EventPlaying = false;
AutomationEventList EventList;
Array<AutomationEventList> EventsToPlay;
unsigned int frameCounter;
unsigned int playFrameCounter;
unsigned int currentPlayFrame;
void InitEventRecording() {
EventList = LoadAutomationEventList(0);
SetAutomationEventList(&EventList);
}
void StartNextEvent() {
Assert(EventPlaying);
if (EventsToPlay.len > 0) {
AutomationEventList event = EventsToPlay.pop();
EventList = event;
SetAutomationEventList(&EventList);
} else {
EventPlaying = false;
SetTargetFPS(60);
}
currentPlayFrame = 0;
playFrameCounter = -1;
}
void UpdateEventRecording() {
if (IsKeyPressed(KEY_F5)) {
if (EventRecording) {
Scratch scratch;
EventRecording = false;
StopAutomationEventRecording();
int random_value = GetRandomValue(0, INT_MAX);
String path = Format(scratch, "%d.rae", random_value);
if (!IsKeyDown(KEY_LEFT_CONTROL)) {
ExportAutomationEventList(EventList, path.data);
}
} else {
SetAutomationEventBaseFrame(0);
StartAutomationEventRecording();
EventRecording = true;
}
}
if (IsKeyPressed(KEY_F8)) {
if (!EventPlaying) {
FilePathList list = LoadDirectoryFiles(".");
for (unsigned int i = 0; i < list.count; i += 1) {
String path = list.paths[i];
if (EndsWith(path, "rae")) {
AutomationEventList rae = LoadAutomationEventList(path.data);
EventsToPlay.add(rae);
}
}
UnloadDirectoryFiles(list);
EventPlaying = true;
SetTargetFPS(3000);
StartNextEvent();
}
}
if (EventPlaying) {
// NOTE: Multiple events could be executed in a single frame
while (playFrameCounter == EventList.events[currentPlayFrame].frame) {
TraceLog(LOG_INFO, "PLAYING: PlayFrameCount: %i | currentPlayFrame: %i | Event Frame: %i, param: %i",
playFrameCounter, currentPlayFrame, EventList.events[currentPlayFrame].frame, EventList.events[currentPlayFrame].params[0]);
PlayAutomationEvent(EventList.events[currentPlayFrame]);
currentPlayFrame++;
if (currentPlayFrame == EventList.count) {
StartNextEvent();
break;
}
}
playFrameCounter++;
}
}
void EventRecording_SimulateGetCharPressed(Window *focused_window) {
if (!EventPlaying) return;
Scratch scratch;
for (int i = KEY_A; i <= KEY_Z; i += 1) {
bool press = IsKeyPressed(i) || IsKeyPressedRepeat(i);
if (press) {
String string = "?";
int offset = 32;
if (IsKeyDown(KEY_LEFT_SHIFT)) offset = 0;
UTF8Result utf8 = UTF32ToUTF8((uint32_t)i + offset);
if (utf8.error == 0) {
string = {(char *)utf8.out_str, (int64_t)utf8.len};
}
BeforeEdit(focused_window);
Array<Edit> edits = {scratch};
For(focused_window->cursors) {
AddEdit(&edits, it.range, string);
}
ApplyEdits(&focused_window->buffer, edits);
AfterEdit(focused_window, edits);
}
}
}
void EventRecording_Draw() {
if (EventRecording) Assert(EventPlaying == false);
if (EventPlaying) Assert(EventRecording == false);
Rect2 screen = GetScreenRect();
Color color = {};
Rect2 l = CutLeft(&screen, 4);
Rect2 r = CutRight(&screen, 4);
Rect2 t = CutTop(&screen, 4);
Rect2 b = CutBottom(&screen, 4);
if (EventPlaying) {
color = BLUE;
}
if (EventRecording) {
color = RED;
}
DrawRectangleRec(ToRectangle(l), color);
DrawRectangleRec(ToRectangle(r), color);
DrawRectangleRec(ToRectangle(t), color);
DrawRectangleRec(ToRectangle(b), color);
}

View File

@@ -240,3 +240,53 @@ Array<LayoutColumn> CalculateVisibleColumns(Arena *arena, Window &window) {
}
return r;
}
void BeforeEdit(Window *window) {
// Merge cursors that overlap, this needs to be handled before any edits to
// make sure overlapping edits won't happen.
for (int64_t cursor_i = 0; cursor_i < window->cursors.len; cursor_i += 1) {
Cursor &cursor = window->cursors[cursor_i];
IterRemove(window->cursors) {
IterRemovePrepare(window->cursors);
if (&cursor == &it) continue;
if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) {
remove_item = true;
cursor.range.max = it.range.max;
break;
}
}
}
}
void AfterEdit(Window *window, Array<Edit> edits) {
// Offset all cursors by edits
ForItem(edit, edits) {
int64_t remove_size = GetRangeSize(edit.range);
int64_t insert_size = edit.string.len;
int64_t offset = insert_size - remove_size;
ForItem(cursor, window->cursors) {
if (edit.range.min == cursor.range.min) {
if (GetRangeSize(edit.range)) {
cursor.range.min += edit.string.len;
} else {
cursor.range.min += offset;
}
cursor.range.max = cursor.range.min;
} else if (edit.range.min <= cursor.range.min) {
if (GetRangeSize(edit.range)) {
cursor.range.min += edit.string.len;
}
cursor.range.min += offset;
cursor.range.max = cursor.range.min;
}
}
}
// Make sure all cursors are in range
For(window->cursors) it.range = Clamp(window->buffer, it.range);
Clear(&window->layout_arena);
window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing);
}

View File

@@ -8,96 +8,8 @@
#include "rect2.cpp"
#include "buffer.cpp"
#include "layout.cpp"
Rect2 GetScreenRect() {
Rect2 result = {
{ 0, 0},
{(float)GetRenderWidth(), (float)GetRenderHeight()}
};
return result;
}
int64_t MoveRight(Buffer &buffer, int64_t pos) {
pos = pos + 1;
pos = AdjustUTF8Pos(buffer, pos);
Assert(pos >= 0 && pos <= buffer.len);
return pos;
}
int64_t MoveLeft(Buffer &buffer, int64_t pos) {
pos = pos - 1;
pos = AdjustUTF8Pos(buffer, pos, -1);
Assert(pos >= 0 && pos <= buffer.len);
return pos;
}
// @todo: when at the end of line, it resets to first position on next line
int64_t MoveDown(Buffer &buffer, int64_t pos) {
LineAndColumn info = FindLineAndColumn(buffer, pos);
int64_t new_pos = FindPos(buffer, info.line.number + 1, info.column);
return new_pos;
}
int64_t MoveUp(Buffer &buffer, int64_t pos) {
LineAndColumn info = FindLineAndColumn(buffer, pos);
int64_t new_pos = FindPos(buffer, info.line.number - 1, info.column);
return new_pos;
}
bool AreEqual(float a, float b, float epsilon = 0.001f) {
bool result = (a - epsilon < b && a + epsilon > b);
return result;
}
void BeforeEdit(Window *window) {
// Merge cursors that overlap, this needs to be handled before any edits to
// make sure overlapping edits won't happen.
for (int64_t cursor_i = 0; cursor_i < window->cursors.len; cursor_i += 1) {
Cursor &cursor = window->cursors[cursor_i];
IterRemove(window->cursors) {
IterRemovePrepare(window->cursors);
if (&cursor == &it) continue;
if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) {
remove_item = true;
cursor.range.max = it.range.max;
break;
}
}
}
}
void AfterEdit(Window *window, Array<Edit> edits) {
// Offset all cursors by edits
ForItem(edit, edits) {
int64_t remove_size = GetRangeSize(edit.range);
int64_t insert_size = edit.string.len;
int64_t offset = insert_size - remove_size;
ForItem(cursor, window->cursors) {
if (edit.range.min == cursor.range.min) {
if (GetRangeSize(edit.range)) {
cursor.range.min += edit.string.len;
} else {
cursor.range.min += offset;
}
cursor.range.max = cursor.range.min;
} else if (edit.range.min <= cursor.range.min) {
if (GetRangeSize(edit.range)) {
cursor.range.min += edit.string.len;
}
cursor.range.min += offset;
cursor.range.max = cursor.range.min;
}
}
}
// Make sure all cursors are in range
For(window->cursors) it.range = Clamp(window->buffer, it.range);
Clear(&window->layout_arena);
window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing);
}
#include "utils.cpp"
#include "event_recording.cpp"
Arena PermArena;
Arena FrameArena;
@@ -126,68 +38,6 @@ void Dbg_Draw() {
}
}
bool EventRecording = false;
bool EventPlaying = false;
AutomationEventList EventList;
void InitEventRecording() {
EventList = LoadAutomationEventList(0);
SetAutomationEventList(&EventList);
EventList = LoadAutomationEventList("automation.rae");
EventPlaying = true;
}
int ModifiedGetCharPressed() {
static int i;
int result = GetCharPressed();
if (EventPlaying && (i % 2) == 0) {
result = 'a';
}
i += 1;
return result;
}
void UpdateEventRecording() {
static unsigned int frameCounter;
static unsigned int playFrameCounter;
static unsigned int currentPlayFrame;
if (IsKeyPressed(KEY_F5)) {
if (EventRecording) {
StopAutomationEventRecording();
ExportAutomationEventList(EventList, "automation.rae");
EventRecording = false;
} else {
SetAutomationEventBaseFrame(0);
StartAutomationEventRecording();
EventRecording = true;
}
}
if (EventPlaying) {
// NOTE: Multiple events could be executed in a single frame
while (playFrameCounter == EventList.events[currentPlayFrame].frame) {
TraceLog(LOG_INFO, "PLAYING: PlayFrameCount: %i | currentPlayFrame: %i | Event Frame: %i, param: %i",
playFrameCounter, currentPlayFrame, EventList.events[currentPlayFrame].frame, EventList.events[currentPlayFrame].params[0]);
PlayAutomationEvent(EventList.events[currentPlayFrame]);
currentPlayFrame++;
if (currentPlayFrame == EventList.count) {
EventPlaying = false;
currentPlayFrame = 0;
playFrameCounter = 0;
TraceLog(LOG_INFO, "FINISH PLAYING!");
break;
}
}
playFrameCounter++;
}
}
int main() {
InitScratch();
InitWindow(800, 600, "Hello");
@@ -210,7 +60,7 @@ int main() {
window.font_spacing;
InitArena(&window.layout_arena);
InitBuffer(&window.buffer);
InitBuffer(GetSystemAllocator(), &window.buffer);
if (1) {
// Array<Edit> edits = {FrameArena};
// AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: 1"));
@@ -475,7 +325,7 @@ int main() {
}
}
if (IsKeyPressed(KEY_ENTER)) {
if (IsKeyPressed(KEY_ENTER) || IsKeyPressedRepeat(KEY_ENTER)) {
if (IsKeyDown(KEY_LEFT_CONTROL)) {
For(focused_window->cursors) {
int64_t front = GetFront(it);
@@ -493,7 +343,7 @@ int main() {
// Handle user input
for (;;) {
int c = ModifiedGetCharPressed();
int c = GetCharPressed();
if (!c) break;
String string = "?";
@@ -510,6 +360,7 @@ int main() {
ApplyEdits(&focused_window->buffer, edits);
AfterEdit(focused_window, edits);
}
EventRecording_SimulateGetCharPressed(focused_window);
}
BeginDrawing();
@@ -654,6 +505,7 @@ int main() {
}
Dbg_Draw();
EventRecording_Draw();
EndDrawing();
}
}

12
src/text_editor/utils.cpp Normal file
View File

@@ -0,0 +1,12 @@
Rect2 GetScreenRect() {
Rect2 result = {
{ 0, 0},
{(float)GetRenderWidth(), (float)GetRenderHeight()}
};
return result;
}
bool AreEqual(float a, float b, float epsilon = 0.001f) {
bool result = (a - epsilon < b && a + epsilon > b);
return result;
}