logging works ( but it's buggy 😭 )

This commit is contained in:
FantasyPvP
2024-12-05 01:42:50 +00:00
parent ad8496ca68
commit 3f35a00526
12 changed files with 786 additions and 44 deletions
View File
+270
View File
@@ -0,0 +1,270 @@
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
ADDED
ADDED
ADDED
ADDED
ADDED
ADDED
ADDED
ADDED
ADDED
ADDED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
REMOVED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
UNMODIFIED
+11 -4
View File
@@ -96,7 +96,6 @@ String_t str_from_file(FILE* file) {
return string;
}
int str_to_file(String_t* self, FILE* file) {
char* data = to_chars(self);
@@ -108,16 +107,24 @@ int str_to_file(String_t* self, FILE* file) {
return 0;
}
String_t str_clone(String_t* self) {
String_t clone;
clone.size = self->size;
clone.capacity = self->capacity;
clone.data = (char*)malloc(clone.capacity);
clone.data = (char*)calloc(clone.capacity, sizeof(char));
memcpy(clone.data, self->data, clone.capacity);
return clone;
}
String_t* str_clone_all(String_t* strings, int len) {
String_t* clones = (String_t*)calloc(len, sizeof(String_t));
for (int i = 0; i < len; i++) {
clones[i] = str_clone(&strings[i]);
}
return clones;
}
char str_pop(String_t* self) {
if (self->size == 0) {
return '\0';
@@ -244,4 +251,4 @@ String_t str_slice(String_t* s, int start, int end) {
s2.data[i] = s->data[start + i];
}
return s2;
}
}
+3 -1
View File
@@ -70,7 +70,9 @@ String_t str_new();
* This allocates new memory that must be freed
* @param self Pointer to the String_t to clone
*/
String_t str_clone();
String_t str_clone(String_t* self);
String_t* str_clone_all(String_t* strings, int len);
/**
* Creates a new string containing a slice of an existing string.
+191 -30
View File
@@ -1,6 +1,8 @@
#include <stdbool.h>
#include <stdlib.h>
#include "dynstr.h"
#include "log.h"
#include "state.h"
#include <ncurses.h>
#define min(x, y) ((x) < (y) ? (x) : (y))
@@ -15,9 +17,13 @@ typedef struct {
uint32_t x_offset;
bool unsaved_changes;
bool editmode;
String_t* buffer;
String_t* original;
String_t filename;
String_t* buffer;
// variables needed for the changelog functionality
int original_len; // length of the original buffer
String_t* original; // original buffer
StateArray diff; // changelog
} Editor;
void add_toolbar(Editor* self) {
@@ -46,6 +52,23 @@ void add_toolbar(Editor* self) {
attroff(COLOR_PAIR(1));
}
void refresh_cursor(Editor* self) {
int max_x,max_y;
getmaxyx(stdscr, max_y, max_x);
// Clamp cursor position to screen bounds
int cursor_y = min(
max(self->buffer_line - self->y_offset, 0),
max_y - 1
);
int cursor_x = min(
max(self->buffer_col - self->x_offset + 5, 5),
max_x - 1
);
move(cursor_y, cursor_x);
}
void refresh_buffer(Editor* self) {
move(0, 0);
@@ -99,41 +122,42 @@ void refresh_buffer(Editor* self) {
}
add_toolbar(self);
refresh_cursor(self);
}
// Ensure cursor position is valid
int cursor_y = self->buffer_line - self->y_offset;
int cursor_x = self->buffer_col - self->x_offset + 5;
// Clamp cursor position to screen bounds
cursor_y = min(max(cursor_y, 0), max_y - 1);
cursor_x = min(max(cursor_x, 5), max_x - 1);
move(cursor_y, cursor_x);
}
void move_cursor_on_screen(Editor* editor, int x, int y) {
void move_cursor_on_screen(Editor* self, int x, int y) {
bool offset_changed = false;
int max_x, max_y;
getmaxyx(stdscr, max_y, max_x);
max_y--; // Reserve bottom line for toolbar
max_x -= 5; // Account for line number margin
// Adjust x_offset if cursor would be off screen
if (x + 5 >= max_x + editor->x_offset) {
editor->x_offset = x - max_x + 6;
// Adjust x_offset if cursor would be off screen
if (x + 5 >= max_x + self->x_offset) {
self->x_offset = x - max_x + 6;
offset_changed = true;
}
if (x < editor->x_offset) {
editor->x_offset = x;
if (x < self->x_offset) {
self->x_offset = x;
offset_changed = true;
}
// Adjust y_offset if cursor would be off screen
if (y >= max_y + editor->y_offset) {
editor->y_offset = y - max_y + 1;
if (y >= max_y + self->y_offset) {
self->y_offset = y - max_y + 1;
offset_changed = true;
}
if (y < editor->y_offset) {
editor->y_offset = y;
if (y < self->y_offset) {
self->y_offset = y;
offset_changed = true;
}
if (offset_changed) {
refresh_buffer(self);
} else {
refresh_cursor(self);
}
refresh_buffer(editor);
}
void switch_mode(Editor* self) {
@@ -144,7 +168,7 @@ void switch_mode(Editor* self) {
void newline(Editor* self) {
move(self->buffer_line, 0);
char line_no[6];
snprintf(line_no, 6, "%-6d", self->buffer_line + 1);
snprintf(line_no, 6, "%-5d", self->buffer_line + 1);
// add the line number
attron(COLOR_PAIR(1));
@@ -166,9 +190,13 @@ Editor editor_from(String_t input_string, String_t filename) {
int linenum = 0;
e.buffer = str_lines(&input_string, &linenum);
e.original = str_clone_all(e.buffer, linenum);
e.lines = (uint32_t)linenum;
e.original_len = linenum;
e.capacity = e.lines;
e.diff = arr_init(e.lines);
str_dealloc(&input_string);
refresh_buffer(&e);
@@ -179,22 +207,129 @@ Editor new_editor(String_t filename) {
return editor_from(str_new(), filename);
}
int print_diff(Editor* self) {
char buffer[512];
String_t log_string = str_new();
int original_offset;
int modified_offset;
for (size_t i = 0; i < self->diff.size; i++) {
LineState state = self->diff.data[i];
switch (state) {
// case UNMODIFIED:
// original_offset = arr_original_offset(&self->diff, i);
// snprintf(
// buffer,
// 512,
// "UNMODIFIED %s \n",
// to_chars(&self->buffer[original_offset + i])
// );
// str_push_str(&log_string, buffer);
// break;
case MODIFIED:
original_offset = arr_original_offset(&self->diff, i);
modified_offset = arr_modified_offset(&self->diff, i);
snprintf(
buffer,
512,
"MODIFIED %-6d | %s\n -> %-6d | %s \n",
original_offset + i + 1,
to_chars(&self->original[original_offset + i]),
modified_offset + i + 1,
to_chars(&self->buffer[modified_offset + i])
);
str_push_str(&log_string, buffer);
break;
case REMOVED:
original_offset = arr_original_offset(&self->diff, i);
snprintf(
buffer,
512,
"REMOVED %-6d | %s \n",
original_offset + i + 1,
to_chars(&self->original[original_offset + i])
);
str_push_str(&log_string, buffer);
break;
case ADDED:
modified_offset = arr_modified_offset(&self->diff, i);
snprintf(
buffer,
512,
"ADDED %-6d | %s \n",
modified_offset + i + 1,
to_chars(&self->buffer[modified_offset + i])
);
str_push_str(&log_string, buffer);
break;
default:
break;
}
}
if (write_log(&log_string) == -1) {
fprintf(stderr, "Error writing log\n");
return -1;
}
str_dealloc(&log_string);
}
int save_file(Editor* self) {
String_t log_string = str_new();
char log_message[64];
char* name = to_chars(&self->filename);
FILE* file = fopen(name, "w");
if (file == NULL) {
fprintf(stderr, "Error: Could not open file %s\n", name);
return -1;
}
// writes the content line by line to the file
FILE* file = fopen(name, "w");
for (size_t i = 0; i < self->lines; i++) {
if (str_to_file(&self->buffer[i], file) == -1) {
free(name);
fprintf(stderr, "Error writing to file\n");
return -1;
}
}
arr_print(&self->diff);
print_diff(self);
free(name);
fclose(file);
for (size_t i = 0; i < self->original_len; i++) {
str_dealloc(&self->original[i]);
}
free(self->original);
self->original = str_clone_all(self->buffer, self->lines);
snprintf(log_message, 64, "Edited file [%s]\n", to_chars(&self->filename));
str_push_str(&log_string, log_message);
self->original_len = self->lines;
snprintf(log_message, 64, "Old Length: [%d] New Length: [%d]\n", self->original_len, self->lines);
str_push_str(&log_string, log_message);
// log messages
if (write_log(&log_string) == -1) {
fprintf(stderr, "Error writing log\n");
return -1;
}
printf("wrote log");
str_dealloc(&log_string);
arr_dealloc(&self->diff);
self->diff = arr_init(self->lines);
return 0;
}
@@ -235,7 +370,6 @@ void delchar(Editor* self) {
self->unsaved_changes = true;
if (self->buffer_col == str_len(&self->buffer[self->buffer_line])) {
if (self->buffer_line +1 == self->lines) {
return;
}
@@ -245,7 +379,13 @@ void delchar(Editor* self) {
String_t old_next_line = self->buffer[self->buffer_line + 1];
// assign the new line
self->buffer[self->buffer_line] = str_merge(&self->buffer[self->buffer_line], &self->buffer[self->buffer_line + 1]);
self->buffer[self->buffer_line] = str_merge(&old_curr_line, &old_next_line);
if (arr_get(&self->diff, self->buffer_line + 1) == ADDED) {
arr_remove(&self->diff, self->buffer_line + 1);
} else {
arr_set(&self->diff, self->buffer_line + 1, REMOVED);
}
// deallocate the memory for the old lines
str_dealloc(&old_curr_line);
@@ -261,6 +401,8 @@ void delchar(Editor* self) {
refresh_buffer(self);
} else {
// removes the character from the current line
arr_set(&self->diff, self->buffer_line, MODIFIED);
str_remove(&self->buffer[self->buffer_line], self->buffer_col);
delch();
}
@@ -278,6 +420,9 @@ void pressed_enter(Editor* self) {
}
self->buffer = (String_t*)realloc(self->buffer, sizeof(String_t) * (self->capacity));
// logs the change of adding a new line
arr_insert(&self->diff, self->buffer_line + 1, ADDED);
if (self->buffer_line == self->lines -1) {
// if at end of file add an empty line
self->buffer[self->lines - 1] = str_new();
@@ -314,6 +459,12 @@ void addchar(Editor* self, char c) {
if (self->buffer_line == self->lines) {
// if we are at the end of the file then we need to add a new line
if (arr_get(&self->diff, self->buffer_line) == REMOVED) {
arr_set(&self->diff, self->buffer_line, MODIFIED);
} else {
arr_insert(&self->diff, self->buffer_line, ADDED);
}
newline(self);
// reallocate self->buffer to be 1 larger
@@ -327,6 +478,10 @@ void addchar(Editor* self, char c) {
// allocate the memory space for the new line and add it to the buffer
self->buffer[self->buffer_line] = str_new();
} else {
if (arr_get(&self->diff, self->buffer_line) == UNMODIFIED) {
arr_set(&self->diff, self->buffer_line, MODIFIED);
}
}
insch(c);
@@ -339,6 +494,12 @@ void shutdown_editor(Editor* self) {
for (size_t i = 0; i < self->capacity; i++) {
str_dealloc(&self->buffer[i]);
}
str_dealloc(&self->filename);
free(self->buffer);
for (size_t i = 0; i < self->original_len; i++) {
str_dealloc(&self->original[i]);
}
free(self->original);
str_dealloc(&self->filename);
}
+8 -3
View File
@@ -1,4 +1,5 @@
#include "dynstr.h"
#include "state.h"
#include <stdint.h>
/**
@@ -6,7 +7,7 @@
* cursor position, and various editor settings.
*/
typedef struct {
uint32_t lines;
uint32_t lines;
uint32_t capacity;
uint32_t buffer_line;
uint32_t buffer_col;
@@ -14,9 +15,13 @@ typedef struct {
uint32_t x_offset;
bool unsaved_changes;
bool editmode;
String_t* buffer;
String_t* original;
String_t filename;
String_t* buffer;
// variables needed for the changelog functionality
int original_len; // length of the original buffer
String_t* original; // original buffer
StateArray diff; // changelog
} Editor;
/**
+7 -3
View File
@@ -1,14 +1,18 @@
#include "dynstr.h"
int write_log(String_t* string, int lines) {
int write_log(String_t* string) {
FILE* file = fopen("log.txt", "a");
int numlines;
String_t* lines = str_lines(string, &numlines);
for (int i = 0; i < lines; i++) {
str_to_file(&string[i], file);
for (int i = 0; i < numlines; i++) {
str_to_file(&lines[i], file);
}
fclose(file);
return 0;
}
+1 -1
View File
@@ -8,5 +8,5 @@
* @return 0 on success, -1 on error
* @note This function frees the string passed to it!
*/
int write_log(String_t* string, int lines);
int write_log(String_t* string);
+27
View File
@@ -0,0 +1,27 @@
REMOVED 16 |
REMOVED 17 |
REMOVED 18 | modifie
REMOVED 19 |
REMOVED 20 |
ADDED 35 | } AND modified a line.
ADDED 36 |
ADDED 37 |
ADDED 38 | added some lines
ADDED 39 |
ADDED 40 |
ADDED 41 |
ADDED 42 |
ADDED 43 |
ADDED 44 |
REMOVED 40 | } AND modified a line.
REMOVED 41 |
REMOVED 42 |
REMOVED 43 | added some lines
REMOVED 44 |
REMOVED 45 |
REMOVED 46 |
REMOVED 47 |
REMOVED 48 |
REMOVED 49 |
REMOVED 50 |
REMOVED 51 |
+3 -2
View File
@@ -211,7 +211,7 @@ int main(int argc, char* argv[]) {
if (argc == 3) {
switch (cmd) {
case CMD_OPEN:
sprintf(log_fmt_string, "Edited File [%s]", argv[2]);
sprintf(log_fmt_string, "Opened File [%s]", argv[2]);
open_editor(argv[2]);
break;
case CMD_RM:
@@ -263,7 +263,8 @@ int main(int argc, char* argv[]) {
// log output of command
if (log_fmt_string[0] != '\0') {
String_t str = str_from_chars(log_fmt_string);
write_log(&str, 1);
write_log(&str);
str_dealloc(&str);
}
return 0;
+150
View File
@@ -0,0 +1,150 @@
/// dynamic array class
/// written by: Harry Irving
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef enum LineState {
UNMODIFIED,
MODIFIED,
ADDED,
REMOVED,
} LineState;
typedef struct {
uint32_t size; // Current number of elements
uint32_t capacity; // Total capacity allocated
LineState* data; // Array of LineState values
} StateArray;
StateArray arr_init(int capacity) {
StateArray arr;
arr.size = capacity;
arr.capacity = capacity;
arr.data = (LineState*)calloc(capacity, sizeof(LineState));
// Initialize all elements to UNMODIFIED
for (int i = 0; i < capacity; i++) {
arr.data[i] = UNMODIFIED;
}
return arr;
}
void arr_print(StateArray* self) {
FILE* log_file = fopen("diff.txt", "w");
if (log_file == NULL) {
fprintf(stderr, "Error: Could not open log file\n");
}
for (int i = 0; i < self->size; i++) {
switch (self->data[i]) {
case UNMODIFIED:
fwrite("UNMODIFIED\n", sizeof(char), strlen("UNMODIFIED\n"), log_file);
break;
case MODIFIED:
fwrite("MODIFIED\n", sizeof(char), strlen("MODIFIED\n"), log_file);
break;
case ADDED:
fwrite("ADDED\n", sizeof(char), strlen("ADDED\n"), log_file);
break;
case REMOVED:
fwrite("REMOVED\n", sizeof(char), strlen("REMOVED\n"), log_file);
break;
}
}
fclose(log_file);
}
int arr_added_or_removed_before(StateArray* self, int index) {
int count = 0;
for (int i = 0; i < index; i++) {
if (self->data[i] == ADDED || self->data[i] == REMOVED) {
if (self->data[i] == REMOVED) {
index++;
}
count++;
}
}
return count;
}
void arr_set(StateArray* self, int index, LineState state) {
int offset = arr_added_or_removed_before(self, index);
self->data[index] = state;
}
LineState arr_remove(StateArray* self, int index) {
int offset = arr_added_or_removed_before(self, index);
if (index >= self->size) {
return -1;
}
LineState removed = self->data[index];
// Shift remaining elements left
for (int i = index; i < self->size - 1; i++) {
self->data[i] = self->data[i + 1];
}
self->size--;
return removed;
}
int arr_insert(StateArray* self, int index, LineState state) {
int offset = arr_added_or_removed_before(self, index);
if (index > self->size) {
return -1;
}
self->size++;
// Grow array if needed
if (self->size > self->capacity) {
self->capacity = (self->size) * sizeof(LineState);
self->data = (LineState*)realloc(self->data, self->capacity * sizeof(LineState));
}
// Shift elements right to make room
for (int i = self->size - 1; i > index; i--) {
self->data[i] = self->data[i - 1];
}
self->data[index] = state;
return 0;
}
LineState arr_get(StateArray* self, int index) {
int offset = arr_added_or_removed_before(self, index);
return self->data[index];
}
int arr_original_offset(StateArray* self, int index) {
int offset = 0;
for (int i = 0; i < index; i++) {
if (self->data[i] == ADDED) {
offset--;
}
}
return offset;
}
int arr_modified_offset(StateArray* self, int index) {
int offset = 0;
for (int i = 0; i < index; i++) {
if (self->data[i] == REMOVED) {
offset--;
}
}
return offset;
}
int arr_dealloc(StateArray* self) {
free(self->data);
self->data = NULL;
self->size = 0;
self->capacity = 0;
return 0;
}
+115
View File
@@ -0,0 +1,115 @@
#ifndef STATEARR_H
#define STATEARR_H
#include <stdint.h>
typedef enum LineState {
UNMODIFIED,
MODIFIED,
ADDED,
REMOVED,
} LineState;
/**
* Dynamic array structure for storing LineState values
*/
typedef struct {
uint32_t size; // Current number of elements
uint32_t capacity; // Total capacity allocated
LineState* data; // Array of LineState values
} StateArray;
void arr_print(StateArray* self);
/**
* Creates a new StateArray with the specified initial capacity
*
* All elements will have a default value of UNMODIFIED
*
* @param capacity Initial capacity in number of elements
* @return A new StateArray structure with allocated memory
*/
StateArray arr_init(int capacity);
/**
* Sets a LineState value at the specified index
* Does not perform bounds checking
*
* @param self Pointer to the StateArray to modify
* @param index Position to set the value
* @param state The LineState value to set
*/
void arr_set(StateArray* self, int index, LineState state);
/**
* Removes a LineState value at the specified index
* Shifts remaining elements left to fill the gap
*
* @param self Pointer to the StateArray to modify
* @param index Position of value to remove
* @return The LineState value that was removed
*/
LineState arr_remove(StateArray* self, int index);
/**
* Inserts a LineState value at the specified index
* Shifts existing elements right to make room
* Automatically reallocates if more capacity is needed
*
* @param self Pointer to the StateArray to modify
* @param index Position to insert the value
* @param state The LineState value to insert
* @return 0 on success, -1 if index is out of bounds
*/
int arr_insert(StateArray* self, int index, LineState state);
/**
* Gets the LineState value at the specified index
* Does not perform bounds checking
*
* @param self Pointer to the StateArray to read from
* @param index Position to get the value from
* @return The LineState value at the specified index
*/
LineState arr_get(StateArray* self, int index);
/**
* Deallocates memory used by the StateArray
* Must be called when the array is no longer needed
*
* @param self Pointer to the StateArray to deallocate
* @return 0 on success
*/
int arr_dealloc(StateArray* self);
/**
* Calculates the offset needed to map from state array index to original buffer index
* by counting ADDED lines before the given index
*
* @param self Pointer to the StateArray
* @param index The index in the state array
* @return The negative offset (number of ADDED lines before index)
*/
int arr_original_offset(StateArray* self, int index);
/**
* Calculates the offset needed to map from state array index to modified buffer index
* by counting REMOVED lines before the given index
*
* @param self Pointer to the StateArray
* @param index The index in the state array
* @return The negative offset (number of REMOVED lines before index)
*/
int arr_modified_offset(StateArray* self, int index);
/**
* Counts the number of lines that have been either added or removed
* Does not count lines that have been modified
*
* @param self Pointer to the StateArray to analyze
* @param index The index to count up to.
* @return The count of lines marked as either ADDED or REMOVED
*/
int arr_added_or_removed_before(StateArray* self, int index);
#endif