diff options
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | jet.c | 118 | ||||
-rw-r--r-- | jet.cpp | 123 | ||||
-rw-r--r-- | page.c | 93 | ||||
-rw-r--r-- | page.cpp | 88 | ||||
-rw-r--r-- | point.c | 123 | ||||
-rw-r--r-- | point.cpp | 112 | ||||
-rw-r--r-- | test/page.cpp (renamed from test/page.c) | 22 | ||||
-rw-r--r-- | test/point.cpp (renamed from test/point.c) | 24 |
9 files changed, 352 insertions, 363 deletions
@@ -1,10 +1,10 @@ FLAGS=-ggdb -O0 -fno-builtin -Wall -lcurses -jet: Makefile *.c - gcc $(FLAGS) jet.c -o jet +jet: Makefile *.cpp + g++ $(FLAGS) jet.cpp -o jet -page: Makefile page.c test/page.c - gcc $(FLAGS) test/page.c -o page +page: Makefile page.cpp test/page.cpp + g++ $(FLAGS) test/page.cpp -o page -point: Makefile page.c point.c test/point.c - gcc $(FLAGS) test/point.c -o point +point: Makefile page.cpp point.cpp test/point.cpp + g++ $(FLAGS) test/point.cpp -o point @@ -1,118 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <curses.h> -#include "page.c" -#include "point.c" - -#define NORMAL_MODE 0 -#define INSERT_MODE 1 - -struct buffer { - char *name; - struct point start; - struct point cursor; -}; - -struct buffer *new_buffer(char *name) { - struct buffer *result = calloc(1, sizeof(struct buffer)); - result->name = name; - result->start.page = new_page(); - result->cursor = result->start; - return result; -} - -int main(int argc, char *argv[]) { - initscr(); - cbreak(); - noecho(); - intrflush(stdscr, FALSE); - keypad(stdscr, TRUE); - - struct buffer *buffer = new_buffer("test"); - struct point window_start = buffer->start; - - if (argc > 1) { - FILE *f = fopen(argv[1], "r"); - char c; - while ((c = fgetc(f)) != EOF) { - insert_at_point(&buffer->cursor, c); - } - buffer->cursor = buffer->start; - fclose(f); - } - - int window_height, window_width; - getmaxyx(stdscr, window_height, window_width); - - int mode = NORMAL_MODE; - - int quit = 0; - while (!quit) { - clear(); - - int x = -1, y = -1; - struct point window_end = window_start; - while (element(&window_end) && getcury(stdscr) < window_height - 1) { - if (same_point(&window_end, &buffer->cursor)) { - getyx(stdscr, y, x); - } - addch(element(&window_end)); - move_point_forward(&window_end); - } - if (x > -1 && y > -1) { - move(y, x); - } - - int input = getch(); - - if (mode == NORMAL_MODE) { - switch (input) { - case '': - quit = 1; - break; - case 'i': - mode = INSERT_MODE; - break; - case 'k': - prev_line(&buffer->cursor, window_width); - if (y <= 0) { - prev_line(&window_start, window_width); - } - break; - case 'j': - next_line(&buffer->cursor, window_width); - if (y >= window_height - 2) { - next_line(&window_start, window_width); - } - break; - case 'h': - move_point_backward(&buffer->cursor); - break; - case 'l': - move_point_forward(&buffer->cursor); - break; - } - } else { - switch (input) { - case '': - mode = NORMAL_MODE; - break; - case KEY_BACKSPACE: - delete_at_point(&buffer->cursor); - break; - default: - insert_at_point(&buffer->cursor, input); - } - } - if (element(&buffer->cursor) == 0) { - move_point_backward(&buffer->cursor); - } - } - - endwin(); - return 0; -} @@ -0,0 +1,123 @@ +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <curses.h> +#include "page.cpp" +#include "point.cpp" + +#define NORMAL_MODE 0 +#define INSERT_MODE 1 + +struct Buffer { + const char *name; + Point start; + Point cursor; + + Buffer(const char *name) : name(name), start(new Page()), cursor(start) {} + + void prev_line(int window_width) { + cursor--; + cursor--; + cursor.rseek('\n', window_width - 2); + if (cursor.element() == '\n') { + cursor++; + } + } + + void next_line(int window_width) { + cursor.seek('\n', window_width); + if (cursor.element() == '\n') { + cursor++; + } + } + +}; + +int main(int argc, char *argv[]) { + initscr(); + cbreak(); + noecho(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + Buffer buffer = Buffer("test"); + Point window_start = buffer.start; + + if (argc > 1) { + FILE *f = fopen(argv[1], "r"); + char c; + while ((c = fgetc(f)) != EOF) { + buffer.cursor.push(c); + } + buffer.cursor = buffer.start; + fclose(f); + } + + int window_height, window_width; + getmaxyx(stdscr, window_height, window_width); + + int mode = NORMAL_MODE; + + int quit = 0; + while (!quit) { + clear(); + + int x = -1, y = -1; + Point window_end = window_start; + while (window_end.element() && getcury(stdscr) < window_height - 1) { + if (window_end == buffer.cursor) { + getyx(stdscr, y, x); + } + addch(window_end.element()); + window_end++; + } + if (x > -1 && y > -1) { + move(y, x); + } + + int input = getch(); + + if (mode == NORMAL_MODE) { + switch (input) { + case '': + quit = 1; + break; + case 'i': + mode = INSERT_MODE; + break; + case 'k': + buffer.prev_line(window_width); + break; + case 'j': + buffer.next_line(window_width); + break; + case 'h': + buffer.cursor--; + break; + case 'l': + buffer.cursor++; + break; + } + } else { + switch (input) { + case '': + mode = NORMAL_MODE; + break; + case KEY_BACKSPACE: + buffer.cursor.pop(); + break; + default: + buffer.cursor.push(input); + } + } + if (buffer.cursor.element() == 0) { + buffer.cursor--; + } + } + + endwin(); + return 0; +} @@ -1,93 +0,0 @@ -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -struct page { - uint8_t *elements; - struct page *next; - struct page *prev; - uint16_t gap_start; - uint16_t gap_end; - uint16_t element_count; -}; - -struct page *new_page() { - struct page *result = malloc(sizeof(struct page)); - result->elements = malloc(PAGE_SIZE); - result->gap_start = 0; - result->gap_end = PAGE_SIZE; - result->next = 0; - result->prev = 0; - return result; -} - -void split_page(struct page *back) { - struct page *front = new_page(); - - memcpy(front->elements, back->elements + PAGE_SIZE / 2, PAGE_SIZE / 2); - - front->gap_start = PAGE_SIZE / 2; - front->gap_end = PAGE_SIZE; - front->element_count = PAGE_SIZE / 2; - - back->gap_start = PAGE_SIZE / 2; - back->gap_end = PAGE_SIZE; - back->element_count = PAGE_SIZE / 2; - - if (back->next) { - back->next->prev = front; - } - front->next = back->next; - front->prev = back; - back->next = front; -} - -void copy_page(struct page *dest, struct page *src) { - memcpy(dest->elements, src->elements, PAGE_SIZE); - dest->gap_start = src->gap_start; - dest->gap_end = src->gap_end; - dest->element_count = src->element_count; -} - -void free_page(struct page *page) { - if (page->prev) { - page->prev->next = page->next; - } - if (page->next) { - page->next->prev = page->prev; - } - free(page->elements); - free(page); -} - -void move_gap_forward(struct page *page) { - assert(page->gap_end < PAGE_SIZE); - page->elements[page->gap_start] = page->elements[page->gap_end]; - page->gap_start++; - page->gap_end++; -} - -void move_gap_backward(struct page *page) { - assert(page->gap_start > 0); - page->gap_end--; - page->gap_start--; - page->elements[page->gap_end] = page->elements[page->gap_start]; -} - -void insert_at_gap(struct page *page, uint8_t c) { - assert(page->element_count < PAGE_SIZE); - page->elements[page->gap_start] = c; - page->gap_start++; - page->element_count++; -} - -void delete_at_gap(struct page *page) { - assert(page->gap_start > 0); - page->gap_start--; - page->element_count--; -} diff --git a/page.cpp b/page.cpp new file mode 100644 index 0000000..7f56fc9 --- /dev/null +++ b/page.cpp @@ -0,0 +1,88 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +struct Page { + uint8_t *elements; + Page *next; + Page *prev; + uint16_t gap_start; + uint16_t gap_end; + uint16_t element_count; + + Page() { + elements = new uint8_t[PAGE_SIZE]; + gap_start = 0; + gap_end = PAGE_SIZE; + element_count = 0; + next = nullptr; + prev = nullptr; + } + + ~Page() { + if (prev) prev->next = next; + if (next) next->prev = prev; + delete[] elements; + } + + void split() { + Page *front = new Page(); + + memcpy(front->elements, elements + PAGE_SIZE / 2, PAGE_SIZE / 2); + + front->gap_start = PAGE_SIZE / 2; + front->gap_end = PAGE_SIZE; + front->element_count = PAGE_SIZE / 2; + + gap_start = PAGE_SIZE / 2; + gap_end = PAGE_SIZE; + element_count = PAGE_SIZE / 2; + + if (next) { + next->prev = front; + } + front->next = next; + front->prev = this; + next = front; + } + + void copy_to(Page *dest) { + memcpy(dest->elements, elements, PAGE_SIZE); + dest->gap_start = gap_start; + dest->gap_end = gap_end; + dest->element_count = element_count; + } + + void operator++(int) { + assert(gap_end < PAGE_SIZE); + elements[gap_start] = elements[gap_end]; + gap_start++; + gap_end++; + } + + void operator--(int) { + assert(gap_start > 0); + gap_end--; + gap_start--; + elements[gap_end] = elements[gap_start]; + } + + void push(uint8_t c) { + assert(element_count < PAGE_SIZE); + elements[gap_start] = c; + gap_start++; + element_count++; + } + + void pop() { + assert(gap_start > 0); + gap_start--; + element_count--; + } + +}; diff --git a/point.c b/point.c deleted file mode 100644 index 515d73d..0000000 --- a/point.c +++ /dev/null @@ -1,123 +0,0 @@ -#include <stdint.h> -#include <stdbool.h> - -struct point { - struct page *page; - uint16_t index; -}; - -uint16_t index_to_offset(struct point *point) { - if (point->index < point->page->gap_start) { - return point->index; - } else { - return point->index + (point->page->gap_end - point->page->gap_start); - } -} - -bool same_point(struct point *a, struct point *b) { - return a->page == b->page && a->index == b->index; -} - -uint8_t element(struct point *point) { - if (point->index == point->page->element_count) { - return !point->page->next ? 0 : point->page->next->elements[0]; - } else { - return point->page->elements[index_to_offset(point)]; - } -} - -void move_point_forward(struct point *point) { - if (point->index < point->page->element_count) { - point->index++; - } else if (point->page->next) { - point->index = 1; - point->page = point->page->next; - } -} - -void move_point_backward(struct point *point) { - if (point->index > 1) { - point->index--; - } else if (point->page->prev) { - point->page = point->page->prev; - point->index = point->page->element_count; - } else { - point->index = 0; - } -} - -uint64_t seek(struct point *point, uint8_t c, int limit) { - uint64_t travel_distance = 0; - while (element(point) && element(point) != c && travel_distance < limit) { - move_point_forward(point); - travel_distance++; - } - return travel_distance; -} - -uint64_t rseek(struct point *point, uint8_t c, int limit) { - uint64_t travel_distance = 0; - while (point->index != 0 && element(point) != c && travel_distance < limit) { - move_point_backward(point); - travel_distance++; - } - return travel_distance; -} - -void prev_line(struct point *point, int window_width) { - move_point_backward(point); - move_point_backward(point); - rseek(point, '\n', window_width - 2); - if (element(point) == '\n') { - move_point_forward(point); - } -} - -void next_line(struct point *point, int window_width) { - seek(point, '\n', window_width); - if (element(point) == '\n') { - move_point_forward(point); - } -} - -void align_gap(struct point *point) { - while (point->page->gap_end < index_to_offset(point)) { - move_gap_forward(point->page); - } - while (point->page->gap_end > index_to_offset(point)) { - move_gap_backward(point->page); - } -} - -void insert_at_point(struct point *point, uint8_t c) { - if (point->page->gap_start == point->page->gap_end) { - split_page(point->page); - if (point->index >= PAGE_SIZE / 2) { - point->page = point->page->next; - point->index -= PAGE_SIZE / 2; - } - } - align_gap(point); - insert_at_gap(point->page, c); - move_point_forward(point); -} - -void delete_at_point(struct point *point) { - if (point->page->element_count == 1 && point->index == 1) { - if (point->page->prev) { - move_point_backward(point); - free_page(point->page->next); - } else if (point->page->next) { - copy_page(point->page, point->page->next); - free_page(point->page->next); - point->index = 0; - } else { - delete_at_gap(point->page); - point->index = 0; - } - } else if (point->index > 0) { - align_gap(point); - delete_at_gap(point->page); - move_point_backward(point); - } -} diff --git a/point.cpp b/point.cpp new file mode 100644 index 0000000..e31f5de --- /dev/null +++ b/point.cpp @@ -0,0 +1,112 @@ +#include <stdint.h> +#include <stdbool.h> + +struct Point { + Page *page; + uint16_t index; + + Point() : page(nullptr), index(0) {} + Point(Page *page) : page(page), index(0) {} + Point(const Point& p) : page(p.page), index(p.index) {} + + uint16_t index_to_offset() { + if (index < page->gap_start) { + return index; + } else { + return index + (page->gap_end - page->gap_start); + } + } + + bool operator==(Point p) { + return page == p.page && index == p.index; + } + + uint8_t element() { + if (index == page->element_count) { + return !page->next ? 0 : page->next->elements[0]; + } else { + return page->elements[index_to_offset()]; + } + } + + void operator++(int) { + if (index < page->element_count) { + index++; + } else if (page->next) { + index = 1; + page = page->next; + } + } + + void operator--(int) { + if (index > 1) { + index--; + } else if (page->prev) { + page = page->prev; + index = page->element_count; + } else { + index = 0; + } + } + + uint64_t seek(uint8_t c, uint64_t limit) { + uint64_t travel_distance = 0; + while (element() && element() != c && travel_distance < limit) { + (*this)++; + travel_distance++; + } + return travel_distance; + } + + uint64_t rseek(uint8_t c, uint64_t limit) { + uint64_t travel_distance = 0; + while (index != 0 && element() != c && travel_distance < limit) { + (*this)--; + travel_distance++; + } + return travel_distance; + } + + void align_gap() { + while (page->gap_end < index_to_offset()) { + (*page)++; + } + while (page->gap_end > index_to_offset()) { + (*page)--; + } + } + + void push(uint8_t c) { + if (page->gap_start == page->gap_end) { + page->split(); + if (index >= PAGE_SIZE / 2) { + page = page->next; + index -= PAGE_SIZE / 2; + } + } + align_gap(); + page->push(c); + (*this)++; + } + + void pop() { + if (page->element_count == 1 && index == 1) { + if (page->prev) { + (*this)--; + delete page->next; + } else if (page->next) { + page->next->copy_to(page); + delete page->next; + index = 0; + } else { + page->pop(); + index = 0; + } + } else if (index > 0) { + align_gap(); + page->pop(); + (*this)--; + } + } + +}; diff --git a/test/page.c b/test/page.cpp index f558fc6..d0a4d54 100644 --- a/test/page.c +++ b/test/page.cpp @@ -1,11 +1,11 @@ #include <curses.h> #define PAGE_SIZE 32 -#include "../page.c" +#include "../page.cpp" int main() { int exit = 0; - struct page *page = new_page(); + Page page = Page(); initscr(); cbreak(); @@ -17,29 +17,29 @@ int main() { while (!exit) { clear(); - for (int i = 0; i < page->gap_start; i++) { - addch(page->elements[i]); + for (int i = 0; i < page.gap_start; i++) { + addch(page.elements[i]); } - for (int i = page->gap_start; i < page->gap_end; i++) { + for (int i = page.gap_start; i < page.gap_end; i++) { addch('.'); } - for (int i = page->gap_end; i < PAGE_SIZE; i++) { - addch(page->elements[i]); + for (int i = page.gap_end; i < PAGE_SIZE; i++) { + addch(page.elements[i]); } int input = getch(); switch (input) { case KEY_LEFT: - move_gap_backward(page); + page--; break; case KEY_RIGHT: - move_gap_forward(page); + page++; break; case KEY_BACKSPACE: - delete_at_gap(page); + page.pop(); break; default: - insert_at_gap(page, input); + page.push(input); } } diff --git a/test/point.c b/test/point.cpp index 0902f47..edf4492 100644 --- a/test/point.c +++ b/test/point.cpp @@ -1,13 +1,13 @@ #include <curses.h> #define PAGE_SIZE 16 -#include "../page.c" -#include "../point.c" +#include "../page.cpp" +#include "../point.cpp" int main() { int exit = 0; - struct page *page = new_page(); - struct point point = {page, 0}; + Page *page = new Page(); + Point point = Point(page); initscr(); start_color(); @@ -29,9 +29,9 @@ int main() { while (!exit) { clear(); - struct page *iter = page; + Page *iter = page; while (iter) { - if (iter == point.page) { + if (iter == point.page && iter->gap_end == point.index_to_offset()) { attron(COLOR_PAIR(1)); } else { attron(COLOR_PAIR(2)); @@ -56,18 +56,18 @@ int main() { exit = 1; break; case KEY_LEFT: - move_point_backward(&point); - align_gap(&point); + point--; + point.align_gap(); break; case KEY_RIGHT: - move_point_forward(&point); - align_gap(&point); + point++; + point.align_gap(); break; case KEY_BACKSPACE: - delete_at_point(&point); + point.pop(); break; default: - insert_at_point(&point, input); + point.push(input); } } |