summaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-11-27 09:40:03 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-11-27 09:40:03 -0500
commitcac24ffa13dc969244fb171b9aad565311c69f16 (patch)
tree45d8f353a5b0968ea0ea9eecc297b11749c117b6 /buffer.c
parent370b74e5335745ea01fc7bb6d5425360d26ca0ce (diff)
scrolling working
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c115
1 files changed, 82 insertions, 33 deletions
diff --git a/buffer.c b/buffer.c
index f98e3f3..f06ca00 100644
--- a/buffer.c
+++ b/buffer.c
@@ -21,16 +21,17 @@ typedef struct {
} TextBlock;
typedef struct {
- u32 nblocks; // number of text blocks
double scroll_x, scroll_y; // number of characters scrolled in the x/y direction
- TextBlock *blocks;
Font *font;
+ u8 tab_width;
float x1, y1, x2, y2;
+ u32 nblocks; // number of text blocks
+ TextBlock *blocks;
} TextBuffer;
// Returns a new block added at index `where`,
// or NULL if there's not enough memory.
-static TextBlock *text_buffer_add_block(TextBuffer *buffer, u32 where) {
+static TextBlock *buffer_add_block(TextBuffer *buffer, u32 where) {
// make sure we can actually allocate enough memory for the contents of the block
// before doing anything
char *block_contents = calloc(1, TEXT_BLOCK_MAX_SIZE);
@@ -63,12 +64,13 @@ static TextBlock *text_buffer_add_block(TextBuffer *buffer, u32 where) {
return block;
}
-void text_buffer_create(TextBuffer *buffer, Font *font) {
+void buffer_create(TextBuffer *buffer, Font *font) {
util_zero_memory(buffer, sizeof *buffer);
buffer->font = font;
+ buffer->tab_width = 4;
}
-Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) {
+Status buffer_load_file(TextBuffer *buffer, FILE *fp) {
char block_contents[TEXT_BLOCK_DEFAULT_SIZE];
size_t bytes_read;
// @TODO: @TODO: IMPORTANT! make this work if buffer already has a file
@@ -77,7 +79,7 @@ Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) {
do {
bytes_read = fread(block_contents, 1, sizeof block_contents, fp);
if (bytes_read > 0) {
- TextBlock *block = text_buffer_add_block(buffer, buffer->nblocks);
+ TextBlock *block = buffer_add_block(buffer, buffer->nblocks);
if (!block) {
return false;
}
@@ -90,8 +92,8 @@ Status text_buffer_load_file(TextBuffer *buffer, FILE *fp) {
return true;
}
-static void text_buffer_print_internal(TextBuffer *buffer, bool debug) {
- printf("\033[2J\033[;H");
+static void buffer_print_internal(TextBuffer *buffer, bool debug) {
+ printf("\033[2J\033[;H"); // clear terminal screen
TextBlock *blocks = buffer->blocks;
u32 nblocks = buffer->nblocks;
@@ -105,17 +107,17 @@ static void text_buffer_print_internal(TextBuffer *buffer, bool debug) {
}
// print the contents of a buffer to stdout
-void text_buffer_print(TextBuffer *buffer) {
- text_buffer_print_internal(buffer, false);
+void buffer_print(TextBuffer *buffer) {
+ buffer_print_internal(buffer, false);
}
// print the contents of a buffer to stdout, along with debugging information
-void text_buffer_print_debug(TextBuffer *buffer) {
- text_buffer_print_internal(buffer, true);
+void buffer_print_debug(TextBuffer *buffer) {
+ buffer_print_internal(buffer, true);
}
// Does not free the pointer `buffer` (buffer might not have even been allocated with malloc)
-void text_buffer_free(TextBuffer *buffer) {
+void buffer_free(TextBuffer *buffer) {
TextBlock *blocks = buffer->blocks;
u32 nblocks = buffer->nblocks;
for (u32 i = 0; i < nblocks; ++i) {
@@ -124,30 +126,87 @@ void text_buffer_free(TextBuffer *buffer) {
free(blocks);
}
+// returns the number of lines of text in the buffer into *lines (if not NULL),
+// and the number of columns of text, i.e. the length of the longest line, into *cols (if not NULL)
+static void buffer_text_dimensions(TextBuffer *buffer, u64 *lines, u64 *cols) {
+ u64 nlines = 1;
+ u64 maxcol = 0;
+ u64 col = 0;
+ for (u32 i = 0; i < buffer->nblocks; ++i) {
+ TextBlock *block = &buffer->blocks[i];
+ for (char *p = block->contents, *end = p + block->len; p != end; ++p) {
+ switch (*p) {
+ case '\n':
+ ++nlines;
+ col = 0;
+ break;
+ case '\r': break;
+ case '\t':
+ do
+ ++col;
+ while (col % buffer->tab_width);
+ break;
+ default:
+ ++col;
+ break;
+ }
+ if (col > maxcol)
+ maxcol = col;
+ }
+ }
+ if (lines) *lines = nlines;
+ if (cols) *cols = maxcol;
+}
+
+
+// returns the number of rows of text that can fit in the buffer, rounded down.
+int buffer_display_rows(TextBuffer *buffer) {
+ return (int)((buffer->y2 - buffer->y1) / text_font_char_height(buffer->font));
+}
+
+// returns the number of columns of text that can fit in the buffer, rounded down.
+int buffer_display_cols(TextBuffer *buffer) {
+ return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer->font));
+}
// make sure we don't scroll too far
-static void text_buffer_correct_scroll(TextBuffer *buffer) {
+static void buffer_correct_scroll(TextBuffer *buffer) {
if (buffer->scroll_x < 0)
buffer->scroll_x = 0;
if (buffer->scroll_y < 0)
buffer->scroll_y = 0;
- // @TODO: maximum scroll_x and scroll_y
+ u64 nlines, ncols;
+ buffer_text_dimensions(buffer, &nlines, &ncols);
+ double max_scroll_x = (double)ncols - buffer_display_cols(buffer);
+ double max_scroll_y = (double)nlines - buffer_display_rows(buffer);
+ if (max_scroll_x <= 0) {
+ buffer->scroll_x = 0;
+ } else if (buffer->scroll_x > max_scroll_x) {
+ buffer->scroll_x = max_scroll_x;
+ }
+
+ if (max_scroll_y <= 0) {
+ buffer->scroll_y = 0;
+ } else if (buffer->scroll_y > max_scroll_y) {
+ buffer->scroll_y = max_scroll_y;
+ }
}
-void text_buffer_scroll(TextBuffer *buffer, double dx, double dy) {
+void buffer_scroll(TextBuffer *buffer, double dx, double dy) {
buffer->scroll_x += dx;
buffer->scroll_y += dy;
- text_buffer_correct_scroll(buffer);
+ buffer_correct_scroll(buffer);
}
// Render the text buffer in the given rectangle
// NOTE: also corrects scroll
-void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
+void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2;
Font *font = buffer->font;
mbstate_t mbstate = {0};
- uint nblocks = buffer->nblocks;
+ u32 nblocks = buffer->nblocks;
TextBlock *blocks = buffer->blocks;
- float char_height = text_font_char_height(font);
+ float char_width = text_font_char_width(font),
+ char_height = text_font_char_height(font);
glColor3f(0.5f,0.5f,0.5f);
glBegin(GL_LINE_STRIP);
glVertex2f(x1,y1);
@@ -161,7 +220,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float
text_chars_begin(font);
// what x coordinate to start rendering the text from
- float render_start_x = x1 - (float)buffer->scroll_x * char_height;
+ float render_start_x = x1 - (float)buffer->scroll_x * char_width;
u32 column = 0;
@@ -174,7 +233,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float
// @TODO: make this better (we should figure out where to start rendering, etc.)
text_state.y -= (float)buffer->scroll_y * char_height;
- for (uint block_idx = 0; block_idx < nblocks; ++block_idx) {
+ for (u32 block_idx = 0; block_idx < nblocks; ++block_idx) {
TextBlock *block = &blocks[block_idx];
char *p = block->contents, *end = p + block->len;
while (p != end) {
@@ -208,7 +267,7 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float
do {
text_render_char(font, L' ', &text_state);
++column;
- } while (column % 4);
+ } while (column % buffer->tab_width);
break;
default:
text_render_char(font, c, &text_state);
@@ -219,13 +278,3 @@ void text_buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float
}
text_chars_end(font);
}
-
-// returns the number of rows of text that can fit in the buffer, rounded down.
-int text_buffer_num_rows(TextBuffer *buffer) {
- return (int)((buffer->y2 - buffer->y1) / text_font_char_height(buffer->font));
-}
-
-// returns the number of columns of text that can fit in the buffer, rounded down.
-int text_buffer_num_cols(TextBuffer *buffer) {
- return (int)((buffer->x2 - buffer->x1) / text_font_char_width(buffer->font));
-}