Commit: 400dd63d5a02cf6426bc56279de1017eb4cc017a
Parent: 21b5b3ee81f2061fa0184037cfc9768c560613e2
Author: Randy Palamar
Date: Mon, 8 Jul 2024 20:54:46 -0600
add initial test program and fix 1 bug
On initial start up the framebuffer would only get allocated if
the window resizes. This is fine in my setup with a tiling wm but
it would have immediately crashed in a floating wm.
Diffstat:
M | build.sh | | | 5 | +++++ |
M | main.c | | | 15 | --------------- |
A | test.c | | | 94 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | util.c | | | 12 | ++++++++++++ |
M | util.h | | | 8 | ++++++++ |
M | vtgl.c | | | 7 | ++++++- |
6 files changed, 125 insertions(+), 16 deletions(-)
diff --git a/build.sh b/build.sh
@@ -12,7 +12,12 @@ cflags="$cflags -D_DEBUG -Wno-unused-function -Wno-undefined-internal"
libcflags="$cflags -fPIC -Wno-unused-function"
libldflags="$ldflags -shared"
+testcflags="-march=native -ggdb -O0 -Wall $(pkg-config --cflags freetype2)"
+testcflags="$testcflags -D_DEBUG -Wno-unused-function -Wno-undefined-internal"
+testldflags="-lfreetype"
+
if ! [ -s "./config.h" ]; then cp ./config.def.h ./config.h; fi
cc $libcflags vtgl.c -o vtgl.so $libldflags
cc $cflags -o vtgl main.c $ldflags
+cc $testcflags -o test test.c $testldflags
diff --git a/main.c b/main.c
@@ -6,9 +6,6 @@
#include "util.h"
-#define BACKLOG_SIZE (16 * MEGABYTE)
-#define BACKLOG_LINES (1024UL)
-
#ifndef _DEBUG
static void do_debug(GLCtx *gl) { }
#include "vtgl.c"
@@ -264,18 +261,6 @@ check_shaders(GLCtx *gl, Arena a)
}
}
-static void
-line_buf_alloc(LineBuf *lb, Arena *a, u8 *start_position, CellStyle state, size capacity)
-{
- lb->cap = capacity;
- lb->filled = 0;
- lb->widx = 0;
- lb->buf = alloc(a, Line, capacity);
- lb->buf[0].start = start_position;
- lb->buf[0].end = start_position;
- lb->buf[0].cursor_state = state;
-}
-
i32
main(void)
{
diff --git a/test.c b/test.c
@@ -0,0 +1,94 @@
+/* NOTE: stubs for stuff we aren't testing */
+typedef void *GLFWwindow;
+static void glfwSetWindowTitle(GLFWwindow *w, const char *s) {};
+static const char *glfwGetWindowTitle(GLFWwindow *w) { return "test"; };
+
+#include "util.h"
+
+#define ESC(a) "\x1B"#a
+#define CSI(a) ESC([a)
+
+struct test_result { b32 status; const char *info; };
+#define TEST_FN(name) struct test_result name(Term *term, Arena arena)
+typedef TEST_FN(Test_Fn);
+
+static size
+copy_into_ringbuf(RingBuf *rb, s8 raw)
+{
+ ASSERT(raw.len < rb->cap);
+ for (size i = 0; i < raw.len; i++)
+ rb->buf[rb->widx + i] = raw.data[i];
+
+ rb->widx += raw.len;
+ rb->filled += raw.len;
+
+ CLAMP(rb->filled, 0, rb->cap);
+ if (rb->widx >= rb->cap)
+ rb->widx -= rb->cap;
+
+ ASSERT(rb->filled >= 0);
+ ASSERT(rb->widx >= 0 && rb->widx < rb->cap);
+ return raw.len;
+}
+
+static s8
+launder_static_string(Term *term, s8 static_str)
+{
+ term->unprocessed_bytes += copy_into_ringbuf(&term->log, static_str);
+ s8 raw = {
+ .len = term->unprocessed_bytes,
+ .data = term->log.buf + (term->log.widx - term->unprocessed_bytes)
+ };
+ return raw;
+}
+
+static TEST_FN(test_cursor_movement)
+{
+ struct test_result result = {.info = __FUNCTION__};
+
+ s8 raw = launder_static_string(term, s8(CSI(17;2H)));
+ split_raw_input_to_lines(term, raw);
+ blit_lines(term, arena);
+
+ raw = launder_static_string(term, s8(CSI(7G)));
+ split_raw_input_to_lines(term, raw);
+ blit_lines(term, arena);
+
+ result.status = term->cursor.row == 16 && term->cursor.col == 6;
+
+ return result;
+}
+
+static Test_Fn *tests[] = {
+ test_cursor_movement,
+};
+
+static u32 failure_count;
+
+int
+main(void)
+{
+ Arena memory = os_new_arena(16 * MEGABYTE);
+ Term term = {0};
+
+ cursor_reset(&term);
+
+ os_alloc_ring_buffer(&term.log, BACKLOG_SIZE);
+ line_buf_alloc(&term.log_lines, &memory, term.log.buf, term.cursor.state, BACKLOG_LINES);
+
+ /* TODO: should probably be some odd size */
+ term.size = (uv2){.w = 80, .h = 24};
+ os_alloc_framebuffer(&term.fb, term.size.h, term.size.w);
+
+ for (u32 i = 0; i < ARRAY_COUNT(tests); i++) {
+ cursor_reset(&term);
+ struct test_result result = tests[i](&term, memory);
+ if (result.status == 0) {
+ failure_count++;
+ printf("TEST FAILED: [%u/%lu] %s\n", i, ARRAY_COUNT(tests), result.info);
+ }
+ }
+ printf("FINISHED: [%lu/%lu] Succeeded\n", ARRAY_COUNT(tests) - failure_count,
+ ARRAY_COUNT(tests));
+ return 0;
+}
diff --git a/util.c b/util.c
@@ -38,6 +38,18 @@ alloc_(Arena *a, size len, size align, size count)
return mem_clear(p, 0, count * len);
}
+static void
+line_buf_alloc(LineBuf *lb, Arena *a, u8 *start_position, CellStyle state, size capacity)
+{
+ lb->cap = capacity;
+ lb->filled = 0;
+ lb->widx = 0;
+ lb->buf = alloc(a, Line, capacity);
+ lb->buf[0].start = start_position;
+ lb->buf[0].end = start_position;
+ lb->buf[0].cursor_state = state;
+}
+
static s8
s8alloc(Arena *a, size len)
{
diff --git a/util.h b/util.h
@@ -5,6 +5,10 @@
#include <stdint.h>
#include <stddef.h>
+#ifndef asm
+#define asm __asm__
+#endif
+
#ifdef _DEBUG
#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0)
#define DEBUG_EXPORT
@@ -30,6 +34,9 @@
/* NOTE: GLFW does not sequentially number keys so switch statement will never be optimized */
#define ENCODE_KEY(action, mod, key) (((action) << 24) | ((mod) << 16) | ((key) & 0xFFFF))
+#define BACKLOG_SIZE (16 * MEGABYTE)
+#define BACKLOG_LINES (1024UL)
+
typedef float f32;
typedef double f64;
typedef uint8_t u8;
@@ -158,6 +165,7 @@ typedef struct {
X(vertscale)
enum gl_flags {
+ NEEDS_RESIZE = 1 << 0,
UPDATE_RENDER_UNIFORMS = 1 << 29,
UPDATE_POST_UNIFORMS = 1 << 30,
};
diff --git a/vtgl.c b/vtgl.c
@@ -58,6 +58,7 @@ resize(Term *t)
v2 ws = t->gl.window_size;
os_alloc_framebuffer(&t->fb, t->size.h, t->size.w);
os_set_term_size(t->child, t->size.h, t->size.w, ws.w, ws.h);
+ t->gl.flags &= ~NEEDS_RESIZE;
}
static void
@@ -289,7 +290,7 @@ fb_callback(GLFWwindow *win, i32 w, i32 h)
set_projection_matrix(&t->gl);
- resize(t);
+ t->gl.flags |= NEEDS_RESIZE;
}
static void
@@ -376,6 +377,10 @@ do_terminal(Term *t, Arena a)
{
static f32 last_frame_time;
f32 frame_start_time = (f32)glfwGetTime();
+
+ if (t->gl.flags & NEEDS_RESIZE)
+ resize(t);
+
if (t->gl.flags & UPDATE_RENDER_UNIFORMS)
update_uniforms(t, SHADER_RENDER);
if (t->gl.flags & UPDATE_POST_UNIFORMS)