diff --git a/.vscode/settings.json b/.vscode/settings.json index a8195b9..ea95eb7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,8 @@ "format": "c", "initializer_list": "c", "vector": "c", - "__bit_reference": "c" + "__bit_reference": "c", + "source_location": "c", + "stdbool.h": "c" } } \ No newline at end of file diff --git a/final/binary b/final/binary index 72a7733..71919e9 100755 Binary files a/final/binary and b/final/binary differ diff --git a/final/dynstr.c b/final/dynstr.c index 1823e5c..2ffb31b 100644 --- a/final/dynstr.c +++ b/final/dynstr.c @@ -156,10 +156,35 @@ String_t* str_split(String_t* self, int* res_len, char c) { return elements; } +String_t str_merge(String_t* s1, String_t* s2) { + String_t s; + s.size = s1->size + s2->size; + s.capacity = s.size; + s.data = (char*)calloc(s.size, sizeof(char)); + for (int i = 0; i < s1->size; i++) { + s.data[i] = s1->data[i]; + } + for (int i = 0; i < s2->size; i++) { + s.data[s1->size + i] = s2->data[i]; + } + return s; +} + String_t* str_lines(String_t* self, int* numlines) { return str_split(self, numlines, '\n'); } +String_t str_slice(String_t* s, int start, int end) { + String_t s2; + s2.size = end - start; + s2.capacity = s2.size; + s2.data = (char*)calloc(s2.size, sizeof(char)); + for (int i = 0; i < s2.size; i++) { + s2.data[i] = s->data[start + i]; + } + return s2; +} + int str_len(String_t* s) { return s->size; } diff --git a/final/dynstr.h b/final/dynstr.h index 6f86e5b..a4f4018 100644 --- a/final/dynstr.h +++ b/final/dynstr.h @@ -13,10 +13,14 @@ String_t str_from_chars(char* string); String_t str_from_slice(char* string, int len); +String_t str_merge(String_t* s1, String_t* s2); + String_t str_new(); String_t* str_lines(String_t* self, int* numlines); +String_t str_slice(String_t* s, int start, int end); + // String_t* str_split(String_t* self, int* res_len, char c); void str_push(String_t* s, char c); diff --git a/final/editor.c b/final/editor.c index 5f782d7..d1d5ea2 100644 --- a/final/editor.c +++ b/final/editor.c @@ -5,104 +5,196 @@ typedef struct { uint32_t lines; - uint32_t screen_line; - uint32_t screen_col; + uint32_t buffer_line; + uint32_t buffer_col; + uint32_t y_offset; + uint32_t x_offset; bool editmode; String_t* buffer; } Editor; -Editor editor_from(char* input_string) { - Editor e; - e.lines = 0; - e.screen_line = 0; - e.screen_col = 0; - e.editmode = false; +void add_toolbar(Editor* self) { + int max_x, max_y; + getmaxyx(stdscr, max_y, max_x); - int linenum = 0; - String_t lines = str_from_chars(input_string); - e.buffer = str_lines(&lines, &linenum); - e.lines = (size_t)linenum; - str_dealloc(&lines); - - for (size_t i = 0; i < e.lines; i++) { + move(max_y - 1, 0); + char mode[8]; + snprintf(mode, 9, "[%6s]", self->editmode ? "Insert" : "Normal"); + addstr(mode); +} + +void refresh_buffer(Editor* self) { + + move(0, 0); + + clear(); + + // get the screen size so we can figure out where to place characters + int max_x, max_y; + getmaxyx(stdscr, max_y, max_x); + + for (size_t i = self->y_offset; i < self->lines && i < self->y_offset + max_y; i++) { + // for (size_t i = 0; i < self->lines; i++) { // adding the line number char line_no[5]; snprintf(line_no, 5, "%-5d", i + 1); // adding the line of text to the buffer addstr(line_no); addch(' '); - addstr(to_chars(&e.buffer[i])); + addstr(to_chars(&self->buffer[i])); addstr("\n"); } + + add_toolbar(self); + + move(self->buffer_line, self->buffer_col + 5); +} + +void move_cursor_on_screen(Editor* editor, int x, int y) { + int newx = x + 5; // account for the line number + + move(y, newx); +} + +void switch_mode(Editor* self) { + self->editmode = !self->editmode; + refresh_buffer(self); +} + +void newline(Editor* self) { + move(self->buffer_line, 0); + char line_no[5]; + snprintf(line_no, 5, "%-5d", self->buffer_line + 1); + // adding the line of text to the buffer + addstr(line_no); + addch(' '); + move(self->buffer_line, self->buffer_col + 5); +} + +Editor editor_from(String_t input_string) { + Editor e; + e.lines = 0; + e.buffer_line = 0; + e.buffer_col = 0; + e.y_offset = 0; + e.x_offset = 0; + e.editmode = false; + + int linenum = 0; + e.buffer = str_lines(&input_string, &linenum); + e.lines = (size_t)linenum; + str_dealloc(&input_string); + + refresh_buffer(&e); return e; } Editor new_editor() { - return editor_from(""); + return editor_from(str_new()); } void move_cursor(Editor* self, int x, int y) { if (y != 0 - && (int)(self->screen_line) + y >= 0 - && self->screen_line + y <= self->lines) + && (int)(self->buffer_line) + y >= 0 + && self->buffer_line + y <= self->lines) { - self->screen_line += y; - int line_width = str_len(&self->buffer[self->screen_line]); - if (self->screen_col > line_width) { - self->screen_col = line_width; + // move the cursor up or down + self->buffer_line += y; + int line_width = str_len(&self->buffer[self->buffer_line]); + if (self->buffer_col > line_width) { + self->buffer_col = line_width; } - } else if ((int)(self->screen_col) + x < 0) { - if ((int)self->screen_line - 1 >= 0) { - self->screen_line -= 1; - self->screen_col = str_len(&self->buffer[self->screen_line]); + } else if ((int)(self->buffer_col) + x < 0) { + // moving the cursor off the left hand side of the line + if ((int)self->buffer_line > 0) { + self->buffer_line -= 1; + self->buffer_col = str_len(&self->buffer[self->buffer_line]); } - } else if (self->screen_col + x > str_len(&self->buffer[self->screen_line])) { - if (self->screen_line + 1 <= self->lines) { - self->screen_col = 0; - self->screen_line += 1; + } else if (self->buffer_col + x > str_len(&self->buffer[self->buffer_line])) { + // moving the cursor off the right hand side of the line + if (self->buffer_line < self->lines) { + self->buffer_col = 0; + self->buffer_line += 1; } } else if (x != 0) { - self->screen_col += x; + // moving the cursor left or right in any other case + self->buffer_col += x; } - move(self->screen_line, self->screen_col + 5); + move_cursor_on_screen(self, self->buffer_col, self->buffer_line); } void delchar(Editor* self) { - str_remove(&self->buffer[self->screen_line], self->screen_col); - delch(); + if (self->buffer_col == str_len(&self->buffer[self->buffer_line])) { + + if (self->buffer_line +1 == self->lines) { + return; + } + + self->buffer[self->buffer_line] = str_merge(&self->buffer[self->buffer_line], &self->buffer[self->buffer_line + 1]); + + for (size_t i = self->buffer_line + 2; i < self->lines; i++) { + self->buffer[i - 1] = self->buffer[i]; + } + + self->buffer[self->lines - 1] = str_new(); + self->lines--; + refresh_buffer(self); + } else { + // removes the character from the current line + str_remove(&self->buffer[self->buffer_line], self->buffer_col); + delch(); + } + } void pressed_enter(Editor* self) { + // allocate memory immediately since we know a new line is being added + self->lines++; + self->buffer = realloc(self->buffer, sizeof(String_t) * (self->lines)); + + if (self->buffer_line == self->lines -1) { + // if at end of file add an empty line + self->buffer[self->lines - 1] = str_new(); + } else { + // else shift each line downwards including everything past the cursor on the current line + for (size_t i = self->lines - 1; i > self->buffer_line + 1; i--) { + self->buffer[i] = self->buffer[i - 1]; + } + + self->buffer[self->buffer_line + 1] = str_slice( + &self->buffer[self->buffer_line], + self->buffer_col, + str_len(&self->buffer[self->buffer_line]) + ); + + self->buffer[self->buffer_line] = str_slice( + &self->buffer[self->buffer_line], + 0, + self->buffer_col + ); + } + // refresh the screen with the new data + refresh_buffer(self); move_cursor(self, 1, 0); } +// inserts a character at the cursor void addchar(Editor* self, char c) { - if (self->screen_line == self->lines) { - move(self->screen_line, 0); - char line_no[5]; - snprintf(line_no, 5, "%-5d", self->screen_line + 1); - // adding the line of text to the buffer - addstr(line_no); - addch(' '); - move(self->screen_line, self->screen_col + 5); + if (self->buffer_line == self->lines) { + // if we are at the end of the file then we need to add a new line + newline(self); - fprintf(stderr, "buffer full\n"); // reallocate self->buffer to be 1 larger self->lines++; - self->buffer = realloc(self->buffer, sizeof(String_t) * (self->lines + 1)); + self->buffer = realloc(self->buffer, sizeof(String_t) * (self->lines)); // allocate the memory space for the new line and add it to the buffer - self->buffer[self->screen_line] = str_new(); - for (size_t i = 0; i < self->lines; i++) { - fprintf(stderr, "size: %d\n", (&self->buffer[i])->size); - } - - fprintf(stderr, "ok!"); + self->buffer[self->buffer_line] = str_new(); } insch(c); // insert the character into the string at the given index - str_insert(&self->buffer[self->screen_line], self->screen_col, c); + str_insert(&self->buffer[self->buffer_line], self->buffer_col, c); move_cursor(self, 1, 0); } diff --git a/final/editor.h b/final/editor.h index fadee90..5eb7ed1 100644 --- a/final/editor.h +++ b/final/editor.h @@ -3,19 +3,22 @@ typedef struct { uint32_t lines; - uint32_t screen_line; - uint32_t screen_col; + uint32_t buffer_line; + uint32_t buffer_col; + uint32_t y_offset; + uint32_t x_offset; bool editmode; String_t* buffer; } Editor; Editor new_editor(); -Editor editor_from(char* input_string); +Editor editor_from(String_t input_string); void move_cursor(Editor* self, int x, int y); void delchar(Editor* self); void addchar(Editor* self, char c); void pressed_enter(Editor* self); +void switch_mode(Editor* self); String_t* to_string(Editor* self); diff --git a/final/log.txt b/final/log.txt index ca0ed9d..50edf5f 100644 --- a/final/log.txt +++ b/final/log.txt @@ -1,19 +1 @@ -buffer full -size: 25 -size: 23 -size: 25 -size: 0 -ok!buffer full -size: 25 -size: 23 -size: 30 -size: 4 -size: 0 -ok!buffer full -size: 25 -size: 23 -size: 30 -size: 4 -size: 1 -size: 0 -ok! \ No newline at end of file +Fatal glibc error: malloc.c:2599 (sysmalloc): assertion failed: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0) diff --git a/final/main.c b/final/main.c index 2894162..c4d5dd3 100644 --- a/final/main.c +++ b/final/main.c @@ -22,16 +22,40 @@ int open_editor() { int max_y, max_x; getmaxyx(stdscr, max_y, max_x); - Editor editor = editor_from("this is some text to edit\nthis is the second line\nand this is the third lol"); - move(0, 5); + FILE* file = fopen("somecode.c", "r"); + if (file == NULL) { + endwin(); + printf("Failed to open file\n"); + return 1; + } + + String_t text = str_new(); + + // read from file char by char + + while (true) { + char line[1024]; + if (fgets(line, 1024, file) == NULL) { + break; + } + String_t new_text = str_from_chars(line); + text = str_merge(&text, &new_text); + str_dealloc(&new_text); + } + + fclose(file); + + Editor editor = editor_from(text); + move(0, 5); + while (true) { refresh(); int c = getch(); if (editor.editmode == true) { switch (c) { case 27: - editor.editmode = false; + switch_mode(&editor); break; case KEY_BACKSPACE: move_cursor(&editor, -1, 0); @@ -40,10 +64,8 @@ int open_editor() { case KEY_DC: delchar(&editor); break; - case KEY_ENTER: - //pressed_enter(&editor); - move_cursor(&editor, 1, 0); - //TODO: next line + case '\n': + pressed_enter(&editor); break; case KEY_UP: move_cursor(&editor, 0, -1); @@ -58,6 +80,7 @@ int open_editor() { move_cursor(&editor, 1, 0); break; default: + fprintf(stderr, "%d\n", c); addchar(&editor, c); break; } @@ -67,7 +90,7 @@ int open_editor() { endwin(); return 0; case 'i': - editor.editmode = true; + switch_mode(&editor); break; case 'w': // TODO: write function to save the data to a file diff --git a/final/somecode.c b/final/somecode.c new file mode 100644 index 0000000..2ffb31b --- /dev/null +++ b/final/somecode.c @@ -0,0 +1,213 @@ +/// dynamic array class +/// written by: Harry Irving + +#include +#include +#include +#include +#include + +typedef struct { + uint32_t size, capacity; + char* data; +} String_t; + +String_t str_with_capacity(int capacity) { + String_t s; + + /// allocate memory for 'capacity' chars + s.data = (char*)calloc(capacity, sizeof(char)); + + s.size = 0; + s.capacity = capacity; + + return s; +} + +String_t str_from_chars(const char* string) { + String_t s; + + s.data = (char*)calloc(strlen(string), sizeof(char)); + strcpy(s.data, string); + s.size = strlen(string); + s.capacity = strlen(string); + return s; +} + +String_t str_from_slice(const char* string, int len) { + String_t s; + + s.data = (char*)calloc(len, sizeof(char)); + strncpy(s.data, string, len); + s.size = len; + s.capacity = len; + return s; +} + +String_t str_new() { + return str_with_capacity(1); +} + +int str_dealloc(String_t* self) { + free(self->data); + return 0; +} + +int str_push(String_t* self, char c) { + // check size < capacity + if (self->size < self->capacity) { + self->data[self->size] = c; + self->size++; + return 0; + } + + // reallocate to add capacity for an extra char + int newcap = self->capacity + sizeof(char); + self->data = (char*)realloc(self->data, newcap); + self->data[self->size] = c; + self->size++; + self->capacity = newcap; + return 0; +} + +char str_pop(String_t* self) { + if (self->size == 0) { + return '\0'; + } + self->size--; + char c = self->data[self->size]; + return c; +} + +int str_insert(String_t* self, int index, char c) { + if (index > self->size) { + return -1; + } + self->size++; + for (int i = self->size - 1; i > index; i--) { + self->data[i] = self->data[i - 1]; + } + self->data[index] = c; + return 0; +} + +int str_remove(String_t* self, int index) { + if (index >= self->size) { + return -1; + } + self->size--; + for (int i = index; i < self->size; i++) { + self->data[i] = self->data[i + 1]; + } + return 0; +} + +/// splits a string into an array of strings based on a delimiter +String_t* str_split(String_t* self, int* res_len, char c) { + + char* string = self->data; + String_t* elements = NULL; + + // find the number of lines in the file + + bool flag = false; + *res_len = 0; + for (int i = 0; i < strlen(string); i++) { + if (string[i] == c) { + if (flag) { + (*res_len)++; + flag = false; + } + } else { + flag = true; + } + } + if (flag) { + (*res_len)++; + } + + // allocate memory for an array of pointers to each line + elements = (String_t*)malloc((*res_len) * sizeof(String_t)); + + int i = 0; + flag = false; + char* start = string; + char* end = string; + + while (*end != '\0') { + if (*end == c) { + if (flag) { + elements[i] = str_from_slice(start, end - start); + i++; + } + end++; + start = end; + flag = false; + } else { + end++; + flag = true; + } + } if (flag) { + elements[i] = str_from_slice(start, end - start); + } + + + // returns an array of String_t + return elements; +} + +String_t str_merge(String_t* s1, String_t* s2) { + String_t s; + s.size = s1->size + s2->size; + s.capacity = s.size; + s.data = (char*)calloc(s.size, sizeof(char)); + for (int i = 0; i < s1->size; i++) { + s.data[i] = s1->data[i]; + } + for (int i = 0; i < s2->size; i++) { + s.data[s1->size + i] = s2->data[i]; + } + return s; +} + +String_t* str_lines(String_t* self, int* numlines) { + return str_split(self, numlines, '\n'); +} + +String_t str_slice(String_t* s, int start, int end) { + String_t s2; + s2.size = end - start; + s2.capacity = s2.size; + s2.data = (char*)calloc(s2.size, sizeof(char)); + for (int i = 0; i < s2.size; i++) { + s2.data[i] = s->data[start + i]; + } + return s2; +} + +int str_len(String_t* s) { + return s->size; +} + +char* to_chars(String_t* s) { + return s->data; +} + +// int main() { +// String_t s = str_from_chars("hello\nworld\neeeee\notherline\n"); + +// str_remove(&s, 10); +// str_insert(&s, 10, 'h'); + +// printf("%s\n", to_chars(&s)); + +// int linen = 0; +// String_t* lines = str_lines(&s, &linen); +// for (int i=0; i < linen; i++) { +// printf("%s", to_chars(&lines[i])); +// } + +// str_dealloc(&s); + +// return 0; +// }