summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-01-02 13:36:38 -0500
committerpommicket <pommicket@gmail.com>2023-01-02 13:36:38 -0500
commitc0d0117a963cf8e4dfb28b919087d8a8ecbbca6e (patch)
tree0c412921f82f141cf733e8de4b4b02152446dba5
parent1dc24e79ec7cf80e06b9c4e7cc55e18857b624c1 (diff)
fix up restructuring
-rw-r--r--base.h3
-rw-r--r--gl.c76
-rw-r--r--ide-autocomplete.c8
-rw-r--r--lsp.h2
-rw-r--r--main.c24
-rw-r--r--os-posix.c17
-rw-r--r--os.h9
-rw-r--r--ted.c23
-rw-r--r--ted.h104
-rw-r--r--text.c2
-rw-r--r--text.h1
-rw-r--r--util.h6
12 files changed, 155 insertions, 120 deletions
diff --git a/base.h b/base.h
index 92ea4ae..f775bd5 100644
--- a/base.h
+++ b/base.h
@@ -32,11 +32,14 @@
#include <stdbool.h>
#include <inttypes.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <float.h>
#include <limits.h>
#include <assert.h>
+#include <time.h>
#if __linux__ || _WIN32
#include <uchar.h>
#else
diff --git a/gl.c b/gl.c
index 1063c96..65f474d 100644
--- a/gl.c
+++ b/gl.c
@@ -1,6 +1,10 @@
#include "ted.h"
#include "lib/glcorearb.h"
+float gl_window_width, gl_window_height;
+int gl_version_major, gl_version_minor;
+
+
#if DEBUG
unsigned char *stbi_load(const char *filename, int *x, int *y, int *comp, int req_comp);
#else
@@ -10,66 +14,10 @@ no_warn_start
no_warn_end
#endif
-// macro trickery to avoid having to write everything twice
-#define gl_for_each_proc(do)\
- do(DRAWARRAYS, DrawArrays)\
- do(GENTEXTURES, GenTextures)\
- do(DELETETEXTURES, DeleteTextures)\
- do(GENERATEMIPMAP, GenerateMipmap)\
- do(TEXIMAGE2D, TexImage2D)\
- do(BINDTEXTURE, BindTexture)\
- do(TEXPARAMETERI, TexParameteri)\
- do(GETERROR, GetError)\
- do(GETINTEGERV, GetIntegerv)\
- do(ENABLE, Enable)\
- do(DISABLE, Disable)\
- do(BLENDFUNC, BlendFunc)\
- do(VIEWPORT, Viewport)\
- do(CLEARCOLOR, ClearColor)\
- do(CLEAR, Clear)\
- do(FINISH, Finish)\
- do(CREATESHADER, CreateShader)\
- do(DELETESHADER, DeleteShader)\
- do(CREATEPROGRAM, CreateProgram)\
- do(SHADERSOURCE, ShaderSource)\
- do(GETSHADERIV, GetShaderiv)\
- do(GETSHADERINFOLOG, GetShaderInfoLog)\
- do(COMPILESHADER, CompileShader)\
- do(CREATEPROGRAM, CreateProgram)\
- do(DELETEPROGRAM, DeleteProgram)\
- do(ATTACHSHADER, AttachShader)\
- do(LINKPROGRAM, LinkProgram)\
- do(GETPROGRAMIV, GetProgramiv)\
- do(GETPROGRAMINFOLOG, GetProgramInfoLog)\
- do(USEPROGRAM, UseProgram)\
- do(GETATTRIBLOCATION, GetAttribLocation)\
- do(GETUNIFORMLOCATION, GetUniformLocation)\
- do(GENBUFFERS, GenBuffers)\
- do(DELETEBUFFERS, DeleteBuffers)\
- do(BINDBUFFER, BindBuffer)\
- do(BUFFERDATA, BufferData)\
- do(VERTEXATTRIBPOINTER, VertexAttribPointer)\
- do(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray)\
- do(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray)\
- do(GENVERTEXARRAYS, GenVertexArrays)\
- do(DELETEVERTEXARRAYS, DeleteVertexArrays)\
- do(BINDVERTEXARRAY, BindVertexArray)\
- do(ACTIVETEXTURE, ActiveTexture)\
- do(UNIFORM1F, Uniform1f)\
- do(UNIFORM2F, Uniform2f)\
- do(UNIFORM3F, Uniform3f)\
- do(UNIFORM4F, Uniform4f)\
- do(UNIFORM1I, Uniform1i)\
- do(UNIFORM2I, Uniform2i)\
- do(UNIFORM3I, Uniform3i)\
- do(UNIFORM4I, Uniform4i)\
- do(UNIFORMMATRIX4FV, UniformMatrix4fv)\
- do(DEBUGMESSAGECALLBACK, DebugMessageCallback)\
- do(DEBUGMESSAGECONTROL, DebugMessageControl)\
-
-#define gl_declare_proc(upper, lower) static PFNGL##upper##PROC gl##lower;
-gl_for_each_proc(gl_declare_proc)
-#undef gl_declare_proc
+
+#define gl_define_proc(upper, lower) PFNGL##upper##PROC gl##lower;
+gl_for_each_proc(gl_define_proc)
+#undef gl_define_proc
GlRcSAB *gl_rc_sab_new(GLuint shader, GLuint array, GLuint buffer) {
GlRcSAB *s = calloc(1, sizeof *s);
@@ -121,11 +69,7 @@ void gl_rc_texture_decref(GlRcTexture **pt) {
*pt = NULL;
}
-// set by main()
-static int gl_version_major;
-static int gl_version_minor;
-
-static void gl_get_procs(void) {
+void gl_get_procs(void) {
#define gl_get_proc(upper, lower) gl##lower = (PFNGL##upper##PROC)SDL_GL_GetProcAddress("gl" #lower);
#if __GNUC__ && !__clang__
#pragma GCC diagnostic push
@@ -283,8 +227,6 @@ void gl_geometry_init(void) {
glGenVertexArrays(1, &gl_geometry_vao);
}
-static float gl_window_width, gl_window_height;
-
void gl_geometry_rect(Rect r, u32 color_rgba) {
v4 color = rgba_u32_to_v4(color_rgba);
diff --git a/ide-autocomplete.c b/ide-autocomplete.c
index ed9617d..a9056f0 100644
--- a/ide-autocomplete.c
+++ b/ide-autocomplete.c
@@ -240,7 +240,7 @@ static SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind) {
}
-static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) {
+void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) {
const LSPRequest *request = &response->request;
if (request->type != LSP_REQUEST_COMPLETION)
return;
@@ -288,9 +288,7 @@ static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *respo
}
}
-// open autocomplete
-// trigger should either be a character (e.g. '.') or one of the TRIGGER_* constants.
-static void autocomplete_open(Ted *ted, uint32_t trigger) {
+void autocomplete_open(Ted *ted, uint32_t trigger) {
Autocomplete *ac = &ted->autocomplete;
if (ac->open) return;
if (!ted->active_buffer) return;
@@ -342,7 +340,7 @@ static char symbol_kind_icon(SymbolKind k) {
return ' ';
}
-static void autocomplete_frame(Ted *ted) {
+void autocomplete_frame(Ted *ted) {
Autocomplete *ac = &ted->autocomplete;
if (!ac->open) return;
diff --git a/lsp.h b/lsp.h
index 6623300..7803ea1 100644
--- a/lsp.h
+++ b/lsp.h
@@ -494,7 +494,7 @@ typedef struct LSP {
// The server process
// thread-safety: created in lsp_create, then only accessed by the communication thread
- Process process;
+ Process *process;
SDL_mutex *document_mutex;
// for our purposes, folders are "documents"
diff --git a/main.c b/main.c
index 9433c4d..f8e07d7 100644
--- a/main.c
+++ b/main.c
@@ -54,19 +54,11 @@ FUTURE FEATURES:
- LSP request timeout
*/
-#include "base.h"
-no_warn_start
-#if _WIN32
-#include <SDL.h>
-#else
-#if DEBUG || __TINYC__ // speed up compile time on debug, also tcc doesn't have immintrin.h
-#define SDL_DISABLE_IMMINTRIN_H
-#endif
-#include <SDL2/SDL.h>
-#endif
-no_warn_end
+#include "ted.h"
+
#include <locale.h>
#include <wctype.h>
+#include <signal.h>
#if __linux__
#include <execinfo.h>
#endif
@@ -78,6 +70,13 @@ no_warn_end
#pragma comment(lib, "shell32.lib")
#endif
+
+#if !defined ONE_SOURCE && !defined DEBUG
+ #define ONE_SOURCE 1
+#endif
+
+#if ONE_SOURCE
+
#include "util.c"
#if _WIN32
@@ -114,12 +113,15 @@ no_warn_end
#include "lsp-write.c"
#include "lsp-parse.c"
+#endif // ONE_SOURCE
+
#if PROFILE
#define PROFILE_TIME(var) double var = time_get_seconds();
#else
#define PROFILE_TIME(var)
#endif
+
static Rect error_box_rect(Ted *ted) {
Font *font = ted->font;
const Settings *settings = ted_active_settings(ted);
diff --git a/os-posix.c b/os-posix.c
index 4e9e402..5b37268 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -153,19 +153,19 @@ static void set_nonblocking(int fd) {
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}
-bool process_run_ex(Process *proc, const char *command, const ProcessSettings *settings) {
- memset(proc, 0, sizeof *proc);
+Process *process_run_ex(const char *command, const ProcessSettings *settings) {
+ Process *proc = calloc(1, sizeof *proc);
int stdin_pipe[2] = {0}, stdout_pipe[2] = {0}, stderr_pipe[2] = {0};
if (pipe(stdin_pipe) != 0) {
strbuf_printf(proc->error, "%s", strerror(errno));
- return false;
+ return proc;
}
if (pipe(stdout_pipe) != 0) {
strbuf_printf(proc->error, "%s", strerror(errno));
close(stdin_pipe[0]);
close(stdin_pipe[1]);
- return false;
+ return proc;
}
if (settings->separate_stderr) {
if (pipe(stderr_pipe) != 0) {
@@ -174,7 +174,7 @@ bool process_run_ex(Process *proc, const char *command, const ProcessSettings *s
close(stdin_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
- return false;
+ return proc;
}
}
@@ -232,14 +232,13 @@ bool process_run_ex(Process *proc, const char *command, const ProcessSettings *s
if (stderr_pipe[0])
proc->stderr_pipe = stderr_pipe[0];
proc->stdin_pipe = stdin_pipe[1];
- success = true;
}
- return success;
+ return proc;
}
-bool process_run(Process *proc, const char *command) {
+Process *process_run(const char *command) {
const ProcessSettings settings = {0};
- return process_run_ex(proc, command, &settings);
+ return process_run_ex(command, &settings);
}
diff --git a/os.h b/os.h
index 6b1e3a5..37b7128 100644
--- a/os.h
+++ b/os.h
@@ -89,11 +89,11 @@ typedef struct {
// get process ID of this process
int process_get_id(void);
-// execute the given command (like if it was passed to system()).
-// returns false on failure
-bool process_run_ex(Process *proc, const char *command, const ProcessSettings *props);
+// execute the given command (like if it was passed to system()), creating a new Process object.
+// returns a valid process object on failure, but it will have an error, according to process_geterr
+Process *process_run_ex(const char *command, const ProcessSettings *props);
// like process_run_ex, but with the default settings
-bool process_run(Process *process, const char *command);
+Process *process_run(const char *command);
// returns the error last error produced, or NULL if there was no error.
const char *process_geterr(Process *process);
// write to stdin
@@ -119,6 +119,7 @@ long long process_read_stderr(Process *process, char *data, size_t size);
// If message is not NULL, it will be set to a description of what happened (e.g. "exited successfully")
int process_check_status(Process *process, char *message, size_t message_size);
// kills process if still running
+// this also frees any resources used by `process`.
void process_kill(Process *process);
#endif // OS_H_
diff --git a/ted.c b/ted.c
index ef91745..647b48b 100644
--- a/ted.c
+++ b/ted.c
@@ -1,10 +1,6 @@
#include "ted.h"
-// this is a macro so we get -Wformat warnings
-#define ted_seterr(ted, ...) \
- snprintf((ted)->error, sizeof (ted)->error - 1, __VA_ARGS__)
-
-static void die(const char *fmt, ...) {
+void die(const char *fmt, ...) {
char buf[256] = {0};
va_list args;
@@ -188,7 +184,7 @@ static bool ted_is_regular_buffer(Ted *ted, TextBuffer *buffer) {
}
// Check the various places a file could be, and return the full path.
-static Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz) {
+Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz) {
if (ted->search_start_cwd && fs_file_exists(name)) {
// check in start_cwd
path_full(ted->start_cwd, name, out, outsz);
@@ -231,8 +227,7 @@ static void ted_load_font(Ted *ted, const char *filename, Font **out) {
}
-// Load all the fonts ted will use.
-static void ted_load_fonts(Ted *ted) {
+void ted_load_fonts(Ted *ted) {
ted_load_font(ted, "assets/font.ttf", &ted->font);
ted_load_font(ted, "assets/font-bold.ttf", &ted->font_bold);
}
@@ -389,9 +384,7 @@ static TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path) {
return NULL;
}
-
-// Returns true on success
-static bool ted_open_file(Ted *ted, const char *filename) {
+Status ted_open_file(Ted *ted, const char *filename) {
char path[TED_PATH_MAX];
ted_path_full(ted, filename, path, sizeof path);
@@ -422,7 +415,7 @@ static bool ted_open_file(Ted *ted, const char *filename) {
}
}
-static bool ted_new_file(Ted *ted, const char *filename) {
+Status ted_new_file(Ted *ted, const char *filename) {
u16 buffer_idx, tab_idx;
char path[TED_PATH_MAX];
if (filename)
@@ -446,10 +439,8 @@ static bool ted_new_file(Ted *ted, const char *filename) {
}
-// save all changes to all buffers with unsaved changes.
-// returns true if all buffers were saved successfully
-static bool ted_save_all(Ted *ted) {
- bool success = true;
+Status ted_save_all(Ted *ted) {
+ Status success = true;
bool *buffers_used = ted->buffers_used;
for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
if (buffers_used[i]) {
diff --git a/ted.h b/ted.h
index 7c50ac2..9c7305f 100644
--- a/ted.h
+++ b/ted.h
@@ -1,14 +1,26 @@
#ifndef TED_H_
#define TED_H_
+#include "base.h"
+no_warn_start
+#if _WIN32
+ #include <SDL.h>
+#else
+ #if DEBUG || __TINYC__ // speed up compile time on debug, also tcc doesn't have immintrin.h
+ #define SDL_DISABLE_IMMINTRIN_H
+ #endif
+ #include <SDL2/SDL.h>
+#endif
+no_warn_end
#include "util.h"
+#include "os.h"
#include "unicode.h"
#include "ds.h"
#include "lsp.h"
-#include "base.h"
#include "text.h"
#include "colors.h"
#include "command.h"
+#include "lib/glcorearb.h"
#define TED_VERSION "2.0"
#define TED_VERSION_FULL "ted v. " TED_VERSION
@@ -21,10 +33,6 @@
// max number of LSPs running at once
#define TED_LSP_MAX 200
-typedef u32 GLuint;
-typedef i32 GLint;
-typedef unsigned GLenum;
-
// these all say "CPP" but really they're C/C++
enum {
SYNTAX_STATE_CPP_MULTI_LINE_COMMENT = 0x1u, // are we in a multi-line comment? (delineated by /* */)
@@ -575,7 +583,7 @@ typedef struct Ted {
double last_save_time; // last time a save command was executed. used for bg-shaders.
- Process build_process;
+ Process *build_process;
// When we read the stdout from the build process, the tail end of the read could be an
// incomplete UTF-8 code point. This is where we store that "tail end" until more
// data is available. (This is up to 3 bytes, null terminated)
@@ -811,6 +819,72 @@ void find_open(Ted *ted, bool replace);
void find_close(Ted *ted);
// === gl.c ===
+extern float gl_window_width, gl_window_height;
+// set by main()
+extern int gl_version_major, gl_version_minor;
+
+// macro trickery to avoid having to write everything multiple times
+#define gl_for_each_proc(do)\
+ do(DRAWARRAYS, DrawArrays)\
+ do(GENTEXTURES, GenTextures)\
+ do(DELETETEXTURES, DeleteTextures)\
+ do(GENERATEMIPMAP, GenerateMipmap)\
+ do(TEXIMAGE2D, TexImage2D)\
+ do(BINDTEXTURE, BindTexture)\
+ do(TEXPARAMETERI, TexParameteri)\
+ do(GETERROR, GetError)\
+ do(GETINTEGERV, GetIntegerv)\
+ do(ENABLE, Enable)\
+ do(DISABLE, Disable)\
+ do(BLENDFUNC, BlendFunc)\
+ do(VIEWPORT, Viewport)\
+ do(CLEARCOLOR, ClearColor)\
+ do(CLEAR, Clear)\
+ do(FINISH, Finish)\
+ do(CREATESHADER, CreateShader)\
+ do(DELETESHADER, DeleteShader)\
+ do(CREATEPROGRAM, CreateProgram)\
+ do(SHADERSOURCE, ShaderSource)\
+ do(GETSHADERIV, GetShaderiv)\
+ do(GETSHADERINFOLOG, GetShaderInfoLog)\
+ do(COMPILESHADER, CompileShader)\
+ do(CREATEPROGRAM, CreateProgram)\
+ do(DELETEPROGRAM, DeleteProgram)\
+ do(ATTACHSHADER, AttachShader)\
+ do(LINKPROGRAM, LinkProgram)\
+ do(GETPROGRAMIV, GetProgramiv)\
+ do(GETPROGRAMINFOLOG, GetProgramInfoLog)\
+ do(USEPROGRAM, UseProgram)\
+ do(GETATTRIBLOCATION, GetAttribLocation)\
+ do(GETUNIFORMLOCATION, GetUniformLocation)\
+ do(GENBUFFERS, GenBuffers)\
+ do(DELETEBUFFERS, DeleteBuffers)\
+ do(BINDBUFFER, BindBuffer)\
+ do(BUFFERDATA, BufferData)\
+ do(VERTEXATTRIBPOINTER, VertexAttribPointer)\
+ do(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray)\
+ do(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray)\
+ do(GENVERTEXARRAYS, GenVertexArrays)\
+ do(DELETEVERTEXARRAYS, DeleteVertexArrays)\
+ do(BINDVERTEXARRAY, BindVertexArray)\
+ do(ACTIVETEXTURE, ActiveTexture)\
+ do(UNIFORM1F, Uniform1f)\
+ do(UNIFORM2F, Uniform2f)\
+ do(UNIFORM3F, Uniform3f)\
+ do(UNIFORM4F, Uniform4f)\
+ do(UNIFORM1I, Uniform1i)\
+ do(UNIFORM2I, Uniform2i)\
+ do(UNIFORM3I, Uniform3i)\
+ do(UNIFORM4I, Uniform4i)\
+ do(UNIFORMMATRIX4FV, UniformMatrix4fv)\
+ do(DEBUGMESSAGECALLBACK, DebugMessageCallback)\
+ do(DEBUGMESSAGECONTROL, DebugMessageControl)\
+
+#define gl_declare_proc(upper, lower) extern PFNGL##upper##PROC gl##lower;
+gl_for_each_proc(gl_declare_proc)
+#undef gl_declare_proc
+
+void gl_get_procs(void);
GlRcSAB *gl_rc_sab_new(GLuint shader, GLuint array, GLuint buffer);
void gl_rc_sab_incref(GlRcSAB *s);
void gl_rc_sab_decref(GlRcSAB **ps);
@@ -831,12 +905,17 @@ void gl_geometry_draw(void);
GLuint gl_load_texture_from_image(const char *path);
// === ide-autocomplete.c ===
+// open autocomplete
+// trigger should either be a character (e.g. '.') or one of the TRIGGER_* constants.
+void autocomplete_open(Ted *ted, uint32_t trigger);
+void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response);
void autocomplete_select_cursor_completion(Ted *ted);
void autocomplete_scroll(Ted *ted, i32 by);
void autocomplete_next(Ted *ted);
void autocomplete_prev(Ted *ted);
void autocomplete_close(Ted *ted);
void autocomplete_update_suggested(Ted *ted);
+void autocomplete_frame(Ted *ted);
// === ide-definitions.c ===
// go to the definition of `name`.
@@ -844,10 +923,12 @@ void autocomplete_update_suggested(Ted *ted);
// Note: the document position is required for LSP requests because of overloading (where the name
// alone isn't sufficient)
void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos);
+void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response);
void definitions_selector_open(Ted *ted);
void definitions_selector_update(Ted *ted);
void definitions_selector_render(Ted *ted, Rect bounds);
void definitions_selector_close(Ted *ted);
+void definitions_frame(Ted *ted);
// === ide-highlights.c ===
void highlights_close(Ted *ted);
@@ -936,9 +1017,16 @@ bool tag_goto(Ted *ted, const char *tag);
SymbolInfo *tags_get_symbols(Ted *ted);
// === ted.c ===
+#define ted_seterr(ted, ...) \
+ snprintf((ted)->error, sizeof (ted)->error - 1, __VA_ARGS__)
+// for fatal errors
+void die(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
+Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz);
void ted_seterr_to_buferr(Ted *ted, TextBuffer *buffer);
bool ted_haserr(Ted *ted);
const char *ted_geterr(Ted *ted);
+// Load all the fonts ted will use.
+void ted_load_fonts(Ted *ted);
void ted_clearerr(Ted *ted);
char *ted_get_root_dir_of(Ted *ted, const char *path);
char *ted_get_root_dir(Ted *ted);
@@ -949,6 +1037,10 @@ LSP *ted_get_lsp_by_id(Ted *ted, LSPID id);
LSP *ted_get_lsp(Ted *ted, const char *path, Language language);
LSP *ted_active_lsp(Ted *ted);
u32 ted_color(Ted *ted, ColorSetting color);
+Status ted_open_file(Ted *ted, const char *filename);
+Status ted_new_file(Ted *ted, const char *filename);
+// save all changes to all buffers with unsaved changes.
+Status ted_save_all(Ted *ted);
// sets the active buffer to this buffer, and updates active_node, etc. accordingly
// you can pass NULL to buffer to make it so no buffer is active.
void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer);
diff --git a/text.c b/text.c
index 291e047..94dd8c7 100644
--- a/text.c
+++ b/text.c
@@ -90,7 +90,7 @@ static GLuint text_v_pos, text_v_color, text_v_tex_coord;
static GLint text_u_sampler;
static GLint text_u_window_size;
-static bool text_init(void) {
+bool text_init(void) {
const char *vshader_code = "attribute vec4 v_color;\n\
attribute vec2 v_pos;\n\
attribute vec2 v_tex_coord;\n\
diff --git a/text.h b/text.h
index dbfb82c..0074448 100644
--- a/text.h
+++ b/text.h
@@ -41,6 +41,7 @@ typedef enum {
ANCHOR_BOTTOM_RIGHT,
} Anchor;
+bool text_init(void);
bool text_has_err(void);
// Get the current error. Errors will NOT be overwritten with newer errors.
const char *text_get_err(void);
diff --git a/util.h b/util.h
index a71a961..99d8128 100644
--- a/util.h
+++ b/util.h
@@ -406,6 +406,12 @@ Rect rect_endpoints(v2 e1, v2 e2);
Rect rect4(float x1, float y1, float x2, float y2);
Rect rect_xywh(float x, float y, float w, float h);
Rect rect_centered(v2 center, v2 size);
+float rect_x1(Rect r);
+float rect_y1(Rect r);
+float rect_x2(Rect r);
+float rect_y2(Rect r);
+float rect_xmid(Rect r);
+float rect_ymid(Rect r);
v2 rect_center(Rect r);
bool rect_contains_point(Rect r, v2 point);
Rect rect_translate(Rect r, v2 by);