summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-08-06 14:07:53 -0400
committerpommicket <pommicket@gmail.com>2023-08-06 14:07:53 -0400
commit52da64686fb506372fa09ab562915f895cd88cb9 (patch)
tree24c2ca40227ddc0ad92adced2432930d4beed729
parentb4e2b3d2407cbad54169da707f72595246e4794a (diff)
util cleanup
-rw-r--r--buffer.c14
-rw-r--r--find.c19
-rw-r--r--gl.c8
-rw-r--r--ide-autocomplete.c24
-rw-r--r--ide-rename-symbol.c4
-rw-r--r--main.c20
-rw-r--r--menu.c16
-rw-r--r--node.c11
-rw-r--r--os-posix.c4
-rw-r--r--os-win.c7
-rw-r--r--os.h10
-rw-r--r--ted-internal.h2
-rw-r--r--text.c4
-rw-r--r--ui.c38
-rw-r--r--util.c200
-rw-r--r--util.h226
16 files changed, 214 insertions, 393 deletions
diff --git a/buffer.c b/buffer.c
index 65461e7..36f094d 100644
--- a/buffer.c
+++ b/buffer.c
@@ -956,7 +956,7 @@ vec2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos) {
Font *font = buffer_font(buffer);
float x = (float)((double)xoff - buffer->scroll_x * text_font_char_width(font, ' ')) + buffer->x1;
float y = (float)((double)line - buffer->scroll_y) * text_font_char_height(font) + buffer->y1;
- return Vec2(x, y);
+ return (vec2){x, y};
}
bool buffer_pixels_to_pos(TextBuffer *buffer, vec2 pixel_coords, BufferPos *pos) {
@@ -992,7 +992,7 @@ bool buffer_clip_rect(TextBuffer *buffer, Rect *r) {
float x1, y1, x2, y2;
rect_coords(*r, &x1, &y1, &x2, &y2);
if (x1 > buffer->x2 || y1 > buffer->y2 || x2 < buffer->x1 || y2 < buffer->y1) {
- r->pos = r->size = Vec2(0, 0);
+ *r = (Rect){0};
return false;
}
if (x1 < buffer->x1) x1 = buffer->x1;
@@ -3062,7 +3062,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
x1 += line_number_width;
x1 += 2; // a little bit of padding
// line separating line numbers from text
- gl_geometry_rect(rect(Vec2(x1, y1), Vec2(border_thickness, y2 - y1)), colors[COLOR_LINE_NUMBERS_SEPARATOR]);
+ gl_geometry_rect(rect_xywh(x1, y1, border_thickness, y2 - y1), colors[COLOR_LINE_NUMBERS_SEPARATOR]);
x1 += border_thickness;
}
@@ -3099,10 +3099,10 @@ void buffer_render(TextBuffer *buffer, Rect r) {
// get screen coordinates of cursor
vec2 cursor_display_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos);
// the rectangle that the cursor is rendered as
- Rect cursor_rect = rect(cursor_display_pos, Vec2(settings->cursor_width, char_height));
+ Rect cursor_rect = rect(cursor_display_pos, (vec2){settings->cursor_width, char_height});
if (!buffer->is_line_buffer) { // highlight line cursor is on
- Rect hl_rect = rect(Vec2(x1, cursor_display_pos.y), Vec2(x2-x1-1, char_height));
+ Rect hl_rect = rect_xywh(x1, cursor_display_pos.y, x2-x1-1, char_height);
buffer_clip_rect(buffer, &hl_rect);
gl_geometry_rect(hl_rect, colors[COLOR_CURSOR_LINE_BG]);
}
@@ -3142,7 +3142,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
vec2 hl_p1 = buffer_pos_to_pixels(buffer, p1);
Rect hl_rect = rect(
hl_p1,
- Vec2((float)highlight_width, char_height)
+ (vec2){(float)highlight_width, char_height}
);
buffer_clip_rect(buffer, &hl_rect);
gl_geometry_rect(hl_rect, colors[buffer->view_only ? COLOR_VIEW_ONLY_SELECTION_BG : COLOR_SELECTION_BG]);
@@ -3242,7 +3242,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
char32_t c = buffer_pos_move_to_matching_bracket(buffer, &pos);
if (c) {
vec2 gl_pos = buffer_pos_to_pixels(buffer, pos);
- Rect hl_rect = rect(gl_pos, Vec2(text_font_char_width(font, c), char_height));
+ Rect hl_rect = rect(gl_pos, (vec2){text_font_char_width(font, c), char_height});
if (buffer_clip_rect(buffer, &hl_rect)) {
gl_geometry_rect(hl_rect, colors[COLOR_MATCHING_BRACKET_HL]);
}
diff --git a/find.c b/find.c
index 759cd05..de5ec15 100644
--- a/find.c
+++ b/find.c
@@ -337,7 +337,7 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) {
gl_geometry_rect(menu_bounds, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(menu_bounds, border_thickness, colors[COLOR_BORDER]);
- menu_bounds = rect_shrink(menu_bounds, border_thickness);
+ rect_shrink(&menu_bounds, border_thickness);
float x1, y1, x2, y2;
rect_coords(menu_bounds, &x1, &y1, &x2, &y2);
@@ -357,15 +357,15 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) {
float x = x1, y = y2 - prev_size.y;
// compute positions of buttons
- Rect button_prev = rect(Vec2(x, y), prev_size);
+ Rect button_prev = rect((vec2){x, y}, prev_size);
x += button_prev.size.x + padding;
- Rect button_next = rect(Vec2(x, y), next_size);
+ Rect button_next = rect((vec2){x, y}, next_size);
x += button_next.size.x + padding;
- Rect button_replace = rect(Vec2(x, y), replace_size);
+ Rect button_replace = rect((vec2){x, y}, replace_size);
x += button_replace.size.x + padding;
- Rect button_replace_find = rect(Vec2(x, y), replace_find_size);
+ Rect button_replace_find = rect((vec2){x, y}, replace_find_size);
x += button_replace_find.size.x + padding;
- Rect button_replace_all = rect(Vec2(x, y), replace_all_size);
+ Rect button_replace_all = rect((vec2){x, y}, replace_all_size);
x += button_replace_all.size.x + padding;
@@ -402,7 +402,8 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) {
Rect find_buffer_bounds = rect4(x1 + text_width + padding, y1, x2 - padding, y1 + line_buffer_height);
- Rect replace_buffer_bounds = rect_translate(find_buffer_bounds, Vec2(0, line_buffer_height + padding));
+ Rect replace_buffer_bounds = find_buffer_bounds;
+ replace_buffer_bounds.pos.y += line_buffer_height + padding;
button_render(ted, button_prev, prev_text, colors[COLOR_TEXT]);
@@ -440,8 +441,8 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) {
text_render(font_bold);
x = x1;
- x += checkbox_frame(ted, &ted->find_case_sensitive, "Case sensitive", Vec2(x, y1)).x + 2*padding;
- x += checkbox_frame(ted, &ted->find_regex, "Regular expression", Vec2(x, y1)).x + 2*padding;
+ x += checkbox_frame(ted, &ted->find_case_sensitive, "Case sensitive", (vec2){x, y1}).x + 2*padding;
+ x += checkbox_frame(ted, &ted->find_regex, "Regular expression", (vec2){x, y1}).x + 2*padding;
buffer_render(find_buffer, find_buffer_bounds);
if (replace) buffer_render(replace_buffer, replace_buffer_bounds);
diff --git a/gl.c b/gl.c
index 64c3220..bf03250 100644
--- a/gl.c
+++ b/gl.c
@@ -234,10 +234,10 @@ void gl_geometry_rect(Rect r, u32 color_rgba) {
return;
vec4 color = rgba_u32_to_vec4(color_rgba);
- vec2 p1 = r.pos;
- vec2 p2 = vec2_add(r.pos, Vec2(0, r.size.y));
- vec2 p3 = vec2_add(r.pos, Vec2(r.size.x, r.size.y));
- vec2 p4 = vec2_add(r.pos, Vec2(r.size.x, 0));
+ vec2 p1 = {rect_x1(r), rect_y1(r)};
+ vec2 p2 = {rect_x1(r), rect_y2(r)};
+ vec2 p3 = {rect_x2(r), rect_y2(r)};
+ vec2 p4 = {rect_x2(r), rect_y1(r)};
GLSimpleTriangle triangle = {
{p1, color},
diff --git a/ide-autocomplete.c b/ide-autocomplete.c
index ec6c83f..42183ff 100644
--- a/ide-autocomplete.c
+++ b/ide-autocomplete.c
@@ -610,7 +610,7 @@ void autocomplete_frame(Ted *ted) {
else
start_y += char_height; // put menu below cursor
{
- Rect menu_rect = rect(Vec2(x, start_y), Vec2(menu_width, menu_height));
+ Rect menu_rect = rect_xywh(x, start_y, menu_width, menu_height);
gl_geometry_rect(menu_rect, colors[COLOR_AUTOCOMPLETE_BG]);
gl_geometry_rect_border(menu_rect, 1, colors[COLOR_AUTOCOMPLETE_BORDER]);
ac->rect = menu_rect;
@@ -622,7 +622,7 @@ void autocomplete_frame(Ted *ted) {
if (ncompletions) {
assert(ac->cursor >= 0 && ac->cursor < (i32)ncompletions);
// highlight cursor entry
- Rect r = rect(Vec2(x, start_y + (float)(ac->cursor - scroll) * char_height), Vec2(menu_width, char_height));
+ Rect r = rect_xywh(x, start_y + (float)(ac->cursor - scroll) * char_height, menu_width, char_height);
if (rect_contains_point(ac->rect, rect_center(r))) {
gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
document = &ac->completions[ac->suggested[ac->cursor]];
@@ -631,7 +631,7 @@ void autocomplete_frame(Ted *ted) {
if (mouse_entry >= 0 && mouse_entry < (i32)ncompletions
&& rect_contains_point(ac->rect, ted->mouse_pos)) {
// highlight moused over entry
- Rect r = rect(Vec2(x, start_y + (float)(mouse_entry - scroll) * char_height), Vec2(menu_width, char_height));
+ Rect r = rect_xywh(x, start_y + (float)(mouse_entry - scroll) * char_height, menu_width, char_height);
gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
ted->cursor = ted->cursor_hand;
document = &ac->completions[ac->suggested[mouse_entry]];
@@ -656,7 +656,7 @@ void autocomplete_frame(Ted *ted) {
float doc_x = open_left ? ac->rect.pos.x - doc_width - padding
: ac->rect.pos.x + ac->rect.size.x + padding;
float doc_y = ac->rect.pos.y;
- Rect r = rect(Vec2(doc_x, doc_y), Vec2(doc_width, doc_height));
+ Rect r = rect_xywh(doc_x, doc_y, doc_width, doc_height);
gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_BG]);
gl_geometry_rect_border(r, border_thickness, colors[COLOR_AUTOCOMPLETE_BORDER]);
@@ -699,8 +699,8 @@ void autocomplete_frame(Ted *ted) {
state.x = x; state.y = y;
if (i != ncompletions_visible-1) {
- gl_geometry_rect(rect(Vec2(x, y + char_height),
- Vec2(menu_width, border_thickness)),
+ gl_geometry_rect(rect_xywh(x, y + char_height,
+ menu_width, border_thickness),
colors[COLOR_AUTOCOMPLETE_BORDER]);
}
@@ -715,7 +715,7 @@ void autocomplete_frame(Ted *ted) {
state.x += padding;
text_utf8_with_state(font, &state, icon_text);
state.x += padding;
- gl_geometry_rect(rect(Vec2((float)state.x, (float)state.y), Vec2(border_thickness, char_height)),
+ gl_geometry_rect(rect_xywh((float)state.x, (float)state.y, border_thickness, char_height),
colors[COLOR_AUTOCOMPLETE_BORDER]);
state.x += padding;
@@ -753,9 +753,13 @@ void autocomplete_frame(Ted *ted) {
}
if (completion->deprecated) {
- gl_geometry_rect(rect(Vec2(label_x, y + (char_height - border_thickness) * 0.5f),
- Vec2((float)state.x - label_x, 1)),
- colors[label_color]);
+ gl_geometry_rect(
+ rect_xywh(
+ label_x, y + (char_height - border_thickness) * 0.5f,
+ (float)state.x - label_x, 1
+ ),
+ colors[label_color]
+ );
}
y += char_height;
diff --git a/ide-rename-symbol.c b/ide-rename-symbol.c
index 7d1e2ad..6f320ae 100644
--- a/ide-rename-symbol.c
+++ b/ide-rename-symbol.c
@@ -98,10 +98,10 @@ static void rename_symbol_menu_render(Ted *ted) {
gl_geometry_rect(bounds, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]);
gl_geometry_draw();
- bounds = rect_shrink(bounds, padding);
+ rect_shrink(&bounds, padding);
const char *text = "Rename symbol to...";
text_utf8(ted->font_bold, text, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]);
- bounds = rect_shrink_left(bounds, text_get_size_vec2(ted->font_bold, text).x + padding);
+ rect_shrink_left(&bounds, text_get_size_vec2(ted->font_bold, text).x + padding);
text_render(ted->font_bold);
buffer_render(&ted->line_buffer, bounds);
diff --git a/main.c b/main.c
index fcc3c01..bc8f7be 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,6 @@
/*
+TODO:
+ - remove rect_translate?
FUTURE FEATURES:
- autodetect indentation (tabs vs spaces)
- robust find (results shouldn't move around when you type things)
@@ -89,8 +91,8 @@ static Rect message_box_rect(Ted *ted) {
float padding = settings->padding;
float window_width = ted->window_width, window_height = ted->window_height;
float char_height = text_font_char_height(font);
- return rect_centered(Vec2(window_width * 0.5f, window_height * 0.9f),
- Vec2(ted_get_menu_width(ted), 3 * char_height + 2 * padding));
+ return rect_centered((vec2){window_width * 0.5f, window_height * 0.9f},
+ (vec2){ted_get_menu_width(ted), 3 * char_height + 2 * padding});
}
#if DEBUG
@@ -602,7 +604,7 @@ int main(int argc, char **argv) {
{ // get mouse position
int mouse_x = 0, mouse_y = 0;
ted->mouse_state = SDL_GetMouseState(&mouse_x, &mouse_y);
- ted->mouse_pos = Vec2((float)mouse_x, (float)mouse_y);
+ ted->mouse_pos = (vec2){(float)mouse_x, (float)mouse_y};
}
for (size_t i = 0; i < arr_count(ted->mouse_clicks); ++i)
@@ -663,7 +665,7 @@ int main(int argc, char **argv) {
if (button >= arr_count(ted->mouse_clicks)) break;
- vec2 pos = Vec2(x, y);
+ vec2 pos = {x, y};
bool add = true;
if (*ted->message_shown) {
if (rect_contains_point(message_box_rect(ted), pos)) {
@@ -715,7 +717,7 @@ int main(int argc, char **argv) {
Uint8 button = event.button.button;
if (button >= arr_count(ted->mouse_releases)) break;
- vec2 pos = Vec2((float)event.button.x, (float)event.button.y);
+ vec2 pos = {(float)event.button.x, (float)event.button.y};
MouseRelease release = {
.pos = pos
};
@@ -732,7 +734,7 @@ int main(int argc, char **argv) {
BufferPos pos = {0};
// drag to select
// we don't check the return value here, because it's okay to drag off the screen.
- buffer_pixels_to_pos(ted->drag_buffer, Vec2(x, y), &pos);
+ buffer_pixels_to_pos(ted->drag_buffer, (vec2){x, y}, &pos);
buffer_select_to_pos(ted->drag_buffer, pos);
}
hover_reset_timer(ted);
@@ -784,7 +786,7 @@ int main(int argc, char **argv) {
{
int mx = 0, my = 0;
ted->mouse_state = SDL_GetMouseState(&mx, &my);
- ted->mouse_pos = Vec2((float)mx, (float)my);
+ ted->mouse_pos = (vec2){(float)mx, (float)my};
}
// default to arrow cursor
ted->cursor = ted->cursor_arrow;
@@ -1102,8 +1104,8 @@ int main(int argc, char **argv) {
const char *text = "Recording macro...";
vec2 size = text_get_size_vec2(font_bold, text);
Rect r = {
- .pos = vec2_sub(Vec2(window_width - 3 * padding, window_height - 3 * padding), size),
- .size = vec2_add(size, Vec2(padding, padding)),
+ .pos = vec2_sub((vec2){window_width - 3 * padding, window_height - 3 * padding}, size),
+ .size = vec2_add(size, (vec2){padding, padding}),
};
gl_geometry_rect(r, bg_color);
Rect full_screen = {
diff --git a/menu.c b/menu.c
index b658086..d74762f 100644
--- a/menu.c
+++ b/menu.c
@@ -64,7 +64,7 @@ void menu_open_with_context(Ted *ted, const char *menu_name, void *context) {
ted->menu_context = context;
TextBuffer *prev_buf = ted->prev_active_buffer = ted->active_buffer;
if (prev_buf)
- ted->prev_active_buffer_scroll = Vec2d(prev_buf->scroll_x, prev_buf->scroll_y);
+ ted->prev_active_buffer_scroll = (dvec2) {prev_buf->scroll_x, prev_buf->scroll_y};
ted_switch_to_buffer(ted, NULL);
*ted->warn_overwrite = 0; // clear warn_overwrite
@@ -102,9 +102,9 @@ Rect selection_menu_render_bg(Ted *ted) {
const float padding = settings->padding;
const u32 *colors = settings->colors;
const float window_width = ted->window_width, window_height = ted->window_height;
- Rect bounds = rect(
- Vec2(window_width * 0.5f - 0.5f * menu_width, padding),
- Vec2(menu_width, window_height - 2 * padding)
+ Rect bounds = rect_xywh(
+ window_width * 0.5f - 0.5f * menu_width, padding,
+ menu_width, window_height - 2 * padding
);
float x1, y1, x2, y2;
@@ -128,7 +128,7 @@ void menu_render(Ted *ted) {
const float window_width = ted->window_width, window_height = ted->window_height;
const MenuInfo *info = &ted->all_menus[ted->menu_open_idx];
// render backdrop
- gl_geometry_rect(rect(Vec2(0, 0), Vec2(window_width, window_height)), colors[COLOR_MENU_BACKDROP]);
+ gl_geometry_rect(rect_xywh(0, 0, window_width, window_height), colors[COLOR_MENU_BACKDROP]);
gl_geometry_draw();
if (info->render)
@@ -477,7 +477,7 @@ static void goto_line_menu_render(Ted *ted) {
Font *font_bold = ted->font_bold;
float menu_height = ted_line_buffer_height(ted) + 2 * padding;
- Rect r = rect(Vec2(padding, window_height - menu_height - padding), Vec2(window_width - 2 * padding, menu_height));
+ Rect r = rect_xywh(padding, window_height - menu_height - padding, window_width - 2 * padding, menu_height);
gl_geometry_rect(r, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(r, settings->border_thickness, colors[COLOR_BORDER]);
const char *text = "Go to line...";
@@ -535,10 +535,10 @@ static void shell_menu_render(Ted *ted) {
gl_geometry_rect(bounds, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]);
gl_geometry_draw();
- bounds = rect_shrink(bounds, padding);
+ rect_shrink(&bounds, padding);
const char *text = "Run";
text_utf8(ted->font_bold, text, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]);
- bounds = rect_shrink_left(bounds, text_get_size_vec2(ted->font_bold, text).x + padding);
+ rect_shrink_left(&bounds, text_get_size_vec2(ted->font_bold, text).x + padding);
text_render(ted->font_bold);
buffer_render(&ted->line_buffer, bounds);
}
diff --git a/node.c b/node.c
index c44f1ad..6acbfa8 100644
--- a/node.c
+++ b/node.c
@@ -295,7 +295,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
TextBuffer *buffer = &ted->buffers[node->tabs[i]];
char tab_title[256];
const char *filename = buffer_display_filename(buffer);
- Rect tab_rect = rect(Vec2(r.pos.x + tab_width * i, r.pos.y), Vec2(tab_width, tab_bar_height));
+ Rect tab_rect = rect_xywh(r.pos.x + tab_width * i, r.pos.y, tab_width, tab_bar_height);
if (i > 0) {
// make sure tab borders overlap (i.e. don't double the border thickness between tabs)
@@ -310,7 +310,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
// tab border
gl_geometry_rect_border(tab_rect, border_thickness, colors[COLOR_BORDER]);
- tab_rect = rect_shrink(tab_rect, border_thickness);
+ rect_shrink(&tab_rect, border_thickness);
// tab title
{
@@ -343,7 +343,8 @@ void node_frame(Ted *ted, Node *node, Rect r) {
u16 buffer_index = node->tabs[node->active_tab];
TextBuffer *buffer = &ted->buffers[buffer_index];
assert(ted->buffers_used[buffer_index]);
- Rect buffer_rect = rect_translate(r, Vec2(0, tab_bar_height));
+ Rect buffer_rect = r;
+ buffer_rect.pos.y += tab_bar_height;
// make sure buffer border and tab border overlap
buffer_rect.pos.y -= border_thickness;
@@ -378,13 +379,13 @@ void node_frame(Ted *ted, Node *node, Rect r) {
r1.size.y = split_pos - padding;
r2.pos.y += split_pos + padding;
r2.size.y = r.size.y - split_pos - padding;
- r_between = rect(Vec2(r.pos.x, r.pos.y + split_pos - padding), Vec2(r.size.x, 2 * padding));
+ r_between = rect_xywh(r.pos.x, r.pos.y + split_pos - padding, r.size.x, 2 * padding);
} else {
float split_pos = r.size.x * node->split_pos;
r1.size.x = split_pos - padding;
r2.pos.x += split_pos + padding;
r2.size.x = r.size.x - split_pos - padding;
- r_between = rect(Vec2(r.pos.x + split_pos - padding, r.pos.y), Vec2(2 * padding, r.size.y));
+ r_between = rect_xywh(r.pos.x + split_pos - padding, r.pos.y, 2 * padding, r.size.y);
}
if (rect_contains_point(r_between, ted->mouse_pos)) {
ted->cursor = resize_cursor;
diff --git a/os-posix.c b/os-posix.c
index 4485845..a620523 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -408,3 +408,7 @@ bool open_with_default_application(const char *path) {
return true;
}
}
+
+bool change_directory(const char *path) {
+ return chdir(path) == 0;
+}
diff --git a/os-win.c b/os-win.c
index 7d335c7..8d751ff 100644
--- a/os-win.c
+++ b/os-win.c
@@ -414,5 +414,10 @@ int process_check_status(Process **pprocess, ProcessExitInfo *info) {
bool open_with_default_application(const char *path) {
- todo
+ todo ShellExecuteW?
+}
+
+
+bool change_directory(const char *path) {
+ return _chdir(path) == 0;
}
diff --git a/os.h b/os.h
index 3542ffe..5af1dca 100644
--- a/os.h
+++ b/os.h
@@ -54,6 +54,12 @@ struct timespec time_get(void);
/// sleep for a certain number of nanoseconds
void time_sleep_ns(u64 ns);
+/// runs xdg-open or equivalent on the given path, which can be a URL.
+///
+/// returns `true` on success.
+bool open_with_default_application(const char *path);
+/// equivalent to POSIX function chdir, but returns `true` on success and `false` on failure.
+bool change_directory(const char *path);
/// free the entries generated by fs_list_directory.
static void fs_dir_entries_free(FsDirectoryEntry **entries) {
@@ -155,10 +161,6 @@ int process_check_status(Process **process, ProcessExitInfo *info);
/// `*process` will be set to NULL.
void process_kill(Process **process);
-/// runs xdg-open or equivalent on the given path, which can be a URL.
-///
-/// returns `true` on success.
-bool open_with_default_application(const char *path);
#endif // OS_H_
diff --git a/ted-internal.h b/ted-internal.h
index b2f54bf..40d87f8 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -508,7 +508,7 @@ struct Ted {
u32 build_error;
/// used by menus to keep track of the scroll position so we can return to it.
- vec2d prev_active_buffer_scroll;
+ dvec2 prev_active_buffer_scroll;
SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_wait,
*cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move;
diff --git a/text.c b/text.c
index d939dbc..ba9212f 100644
--- a/text.c
+++ b/text.c
@@ -489,10 +489,10 @@ static vec2 text_render_utf8_internal(Font *font, const char *text, double x, do
render_state.y = y;
rgba_u32_to_floats(color, render_state.color);
text_utf8_with_state(font, &render_state, text);
- return Vec2(
+ return (vec2){
maxf(0.0f, (float)(render_state.x_largest - x)),
maxf(0.0f, (float)(render_state.y_largest - y))
- );
+ };
}
void text_utf8(Font *font, const char *text, double x, double y, u32 color) {
diff --git a/ui.c b/ui.c
index df6ab9c..2374377 100644
--- a/ui.c
+++ b/ui.c
@@ -43,10 +43,10 @@ static void selector_scroll_to_cursor(Ted *ted, Selector *s) {
static bool selector_entry_pos(Ted *ted, const Selector *s, u32 i, Rect *r) {
Rect bounds = s->bounds;
float char_height = text_font_char_height(ted->font);
- *r = rect(Vec2(bounds.pos.x, selector_entries_start_y(ted, s)
+ *r = rect_xywh(bounds.pos.x, selector_entries_start_y(ted, s)
- char_height * s->scroll
- + char_height * (float)i),
- Vec2(bounds.size.x, char_height));
+ + char_height * (float)i,
+ bounds.size.x, char_height);
return rect_clip_to_rect(r, bounds);
}
@@ -498,7 +498,7 @@ void file_selector_render(Ted *ted, FileSelector *fs) {
if (*fs->title) {
text_utf8(font_bold, fs->title, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]);
- bounds = rect_shrink_top(bounds, text_font_char_height(font_bold) * 0.75f + padding);
+ rect_shrink_top(&bounds, text_font_char_height(font_bold) * 0.75f + padding);
}
// current working directory
@@ -518,7 +518,7 @@ void file_selector_render(Ted *ted, FileSelector *fs) {
state.max_x = rect_x2(bounds);
text_utf8_with_state(font, &state, fs->cwd);
- bounds = rect_shrink_top(bounds, char_height + padding);
+ rect_shrink_top(&bounds, char_height + padding);
}
// render selector
@@ -577,23 +577,23 @@ bool button_update(Ted *ted, Rect button) {
static void popup_get_rects(Ted const *ted, u32 options, Rect *popup, Rect *button_yes, Rect *button_no, Rect *button_cancel) {
float window_width = ted->window_width, window_height = ted->window_height;
- *popup = rect_centered(Vec2(window_width * 0.5f, window_height * 0.5f), Vec2(300, 200));
+ *popup = rect_centered((vec2){window_width * 0.5f, window_height * 0.5f}, (vec2){300, 200});
float button_height = 30;
u16 nbuttons = util_popcount(options);
float button_width = popup->size.x / nbuttons;
- popup->size = vec2_clamp(popup->size, Vec2(0, 0), Vec2(window_width, window_height));
- Rect r = rect(Vec2(popup->pos.x, rect_y2(*popup) - button_height), Vec2(button_width, button_height));
+ popup->size = vec2_clamp(popup->size, (vec2){0, 0}, (vec2){window_width, window_height});
+ Rect r = rect_xywh(popup->pos.x, rect_y2(*popup) - button_height, button_width, button_height);
if (options & POPUP_YES) {
*button_yes = r;
- r = rect_translate(r, Vec2(button_width, 0));
+ r.pos.x += button_width;
}
if (options & POPUP_NO) {
*button_no = r;
- r = rect_translate(r, Vec2(button_width, 0));
+ r.pos.x += button_width;
}
if (options & POPUP_CANCEL) {
*button_cancel = r;
- r = rect_translate(r, Vec2(button_width, 0));
+ r.pos.x += button_width;
}
}
@@ -629,7 +629,7 @@ void popup_render(Ted *ted, u32 options, const char *title, const char *body) {
gl_geometry_rect(r, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(r, border_thickness, colors[COLOR_BORDER]);
// line separating text from body
- gl_geometry_rect(rect(Vec2(r.pos.x, y + char_height_bold), Vec2(r.size.x, border_thickness)), colors[COLOR_BORDER]);
+ gl_geometry_rect(rect_xywh(r.pos.x, y + char_height_bold, r.size.x, border_thickness), colors[COLOR_BORDER]);
if (options & POPUP_YES) button_render(ted, button_yes, "Yes", colors[COLOR_YES]);
if (options & POPUP_NO) button_render(ted, button_no, "No", colors[COLOR_NO]);
@@ -638,7 +638,7 @@ void popup_render(Ted *ted, u32 options, const char *title, const char *body) {
// title text
vec2 title_size = {0};
text_get_size(font_bold, title, &title_size.x, &title_size.y);
- vec2 title_pos = vec2_sub(Vec2(window_width * 0.5f, y), Vec2(title_size.x * 0.5f, 0));
+ vec2 title_pos = {(window_width - title_size.x) * 0.5f, y};
text_utf8(font_bold, title, title_pos.x, title_pos.y, colors[COLOR_TEXT]);
text_render(font_bold);
@@ -668,23 +668,25 @@ vec2 checkbox_frame(Ted *ted, bool *value, const char *label, vec2 pos) {
float padding = settings->padding;
float border_thickness = settings->border_thickness;
- Rect checkbox_rect = rect(pos, Vec2(checkbox_size, checkbox_size));
+ Rect checkbox_rect = rect(pos, (vec2){checkbox_size, checkbox_size});
if (ted_clicked_in_rect(ted, checkbox_rect)) {
*value = !*value;
}
- checkbox_rect.pos = vec2_add(checkbox_rect.pos, Vec2(0.5f, 0.5f));
+ checkbox_rect.pos = vec2_add(checkbox_rect.pos, (vec2){0.5f, 0.5f});
gl_geometry_rect_border(checkbox_rect, border_thickness, colors[COLOR_TEXT]);
if (*value) {
- gl_geometry_rect(rect_shrink(checkbox_rect, border_thickness + 2), colors[COLOR_TEXT]);
+ Rect r = checkbox_rect;
+ rect_shrink(&r, border_thickness + 2);
+ gl_geometry_rect(r, colors[COLOR_TEXT]);
}
- vec2 text_pos = vec2_add(pos, Vec2(checkbox_size + padding * 0.5f, 0));
+ vec2 text_pos = vec2_add(pos, (vec2){checkbox_size + padding * 0.5f, 0});
vec2 size = text_get_size_vec2(font, label);
text_utf8(font, label, text_pos.x, text_pos.y, colors[COLOR_TEXT]);
gl_geometry_draw();
text_render(font);
- return vec2_add(size, Vec2(checkbox_size + padding * 0.5f, 0));
+ return vec2_add(size, (vec2){checkbox_size + padding * 0.5f, 0});
}
diff --git a/util.c b/util.c
index a16f7a5..8ba700c 100644
--- a/util.c
+++ b/util.c
@@ -412,6 +412,7 @@ bool path_is_absolute(const char *path) {
void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size) {
assert(abspath_size);
assert(dir[0]);
+ assert(path_is_absolute(dir));
abspath[0] = '\0';
if (path_is_absolute(relpath)) {
@@ -478,14 +479,6 @@ bool paths_eq(const char *path1, const char *path2) {
#endif
}
-void change_directory(const char *path) {
-#if _WIN32
- _chdir(path);
-#else
- chdir(path);
-#endif
-}
-
bool copy_file(const char *src, const char *dst) {
bool success = false;
FILE *src_file = fopen(src, "rb");
@@ -512,19 +505,10 @@ bool copy_file(const char *src, const char *dst) {
#define MATH_GL 1
#endif
-float degrees(float r) {
- return r * (180.0f / PIf);
-}
-float radians(float r) {
- return r * (PIf / 180.f);
-}
-
-// map x from the interval [0, 1] to the interval [a, b]. does NOT clamp.
float lerpf(float x, float a, float b) {
return x * (b-a) + a;
}
-// opposite of lerp; map x from the interval [a, b] to the interval [0, 1]. does NOT clamp.
float normf(float x, float a, float b) {
return (x-a) / (b-a);
}
@@ -644,11 +628,13 @@ i64 max_i64(i64 a, i64 b) {
}
i64 mod_i64(i64 a, i64 b) {
+ assert(b > 0);
i64 ret = a % b;
if (ret < 0) ret += b;
return ret;
}
i32 mod_i32(i32 a, i32 b) {
+ assert(b > 0);
i32 ret = a % b;
if (ret < 0) ret += b;
return ret;
@@ -670,139 +656,67 @@ float sgnf(float x) {
return 0;
}
-float smoothstepf(float x) {
- if (x <= 0) return 0;
- if (x >= 1) return 1;
- return x * x * (3 - 2 * x);
-}
-
-float randf(void) {
- return (float)rand() / (float)((ulong)RAND_MAX + 1);
-}
-
-u32 rand_u32(void) {
- return ((u32)rand() & 0xfff)
- | ((u32)rand() & 0xfff) << 12
- | ((u32)rand() & 0xff) << 24;
-}
-
-float rand_uniform(float from, float to) {
- return lerpf(randf(), from, to);
-}
-
-float sigmoidf(float x) {
- return 1.0f / (1.0f + expf(-x));
-}
-
-// returns ⌈x/y⌉ (x/y rounded up)
-i32 ceildivi32(i32 x, i32 y) {
- if (y < 0) {
- // negating both operands doesn't change the answer
- x = -x;
- y = -y;
- }
- if (x < 0) {
- // truncation is the same as ceiling for negative numbers
- return x / y;
- } else {
- return (x + (y-1)) / y;
- }
-}
-
-vec2 Vec2(float x, float y) {
- vec2 v;
- v.x = x;
- v.y = y;
- return v;
-}
-
vec2 vec2_add(vec2 a, vec2 b) {
- return Vec2(a.x + b.x, a.y + b.y);
+ return (vec2){a.x + b.x, a.y + b.y};
}
vec2 vec2_add_const(vec2 a, float c) {
- return Vec2(a.x + c, a.y + c);
+ return (vec2){a.x + c, a.y + c};
}
vec2 vec2_sub(vec2 a, vec2 b) {
- return Vec2(a.x - b.x, a.y - b.y);
+ return (vec2){a.x - b.x, a.y - b.y};
}
vec2 vec2_scale(vec2 v, float s) {
- return Vec2(v.x * s, v.y * s);
+ return (vec2){v.x * s, v.y * s};
}
vec2 vec2_mul(vec2 a, vec2 b) {
- return Vec2(a.x * b.x, a.y * b.y);
+ return (vec2){a.x * b.x, a.y * b.y};
}
vec2 vec2_clamp(vec2 x, vec2 a, vec2 b) {
- return Vec2(clampf(x.x, a.x, b.x), clampf(x.y, a.y, b.y));
+ return (vec2){clampf(x.x, a.x, b.x), clampf(x.y, a.y, b.y)};
}
float vec2_dot(vec2 a, vec2 b) {
return a.x * b.x + a.y * b.y;
}
-float vec2_len(vec2 v) {
+float vec2_norm(vec2 v) {
return sqrtf(vec2_dot(v, v));
}
vec2 vec2_lerp(float x, vec2 a, vec2 b) {
- return Vec2(lerpf(x, a.x, b.x), lerpf(x, a.y, b.y));
+ return (vec2){lerpf(x, a.x, b.x), lerpf(x, a.y, b.y)};
}
// rotate v theta radians counterclockwise
vec2 vec2_rotate(vec2 v, float theta) {
float c = cosf(theta), s = sinf(theta);
- return Vec2(
+ return (vec2){
c * v.x - s * v.y,
s * v.x + c * v.y
- );
+ };
}
vec2 vec2_normalize(vec2 v) {
- float len = vec2_len(v);
+ float len = vec2_norm(v);
float mul = len == 0.0f ? 1.0f : 1.0f/len;
return vec2_scale(v, mul);
}
-float vec2_dist(vec2 a, vec2 b) {
- return vec2_len(vec2_sub(a, b));
-}
-
-float vec2_dist_squared(vec2 a, vec2 b) {
- vec2 diff = vec2_sub(a, b);
- return vec2_dot(diff, diff);
+float vec2_distance(vec2 a, vec2 b) {
+ return vec2_norm(vec2_sub(a, b));
}
void vec2_print(vec2 v) {
printf("(%f, %f)\n", v.x, v.y);
}
-vec2 vec2_rand_unit(void) {
- float theta = rand_uniform(0, TAUf);
- return Vec2(cosf(theta), sinf(theta));
-}
-
vec2 vec2_polar(float r, float theta) {
- return Vec2(r * cosf(theta), r * sinf(theta));
-}
-
-vec4 Vec4(float x, float y, float z, float w) {
- vec4 v;
- v.x = x;
- v.y = y;
- v.z = z;
- v.w = w;
- return v;
-}
-
-vec2d Vec2d(double x, double y) {
- return (vec2d) {
- .x = x,
- .y = y
- };
+ return (vec2){r * cosf(theta), r * sinf(theta)};
}
void rgba_u32_to_floats(u32 rgba, float floats[4]) {
@@ -815,7 +729,7 @@ void rgba_u32_to_floats(u32 rgba, float floats[4]) {
vec4 rgba_u32_to_vec4(u32 rgba) {
float c[4];
rgba_u32_to_floats(rgba, c);
- return Vec4(c[0], c[1], c[2], c[3]);
+ return (vec4){c[0], c[1], c[2], c[3]};
}
u32 rgba_vec4_to_u32(vec4 color) {
@@ -825,12 +739,6 @@ u32 rgba_vec4_to_u32(vec4 color) {
| (u32)(color.w * 255);
}
-// returns average of red green and blue components of color
-float rgba_brightness(u32 color) {
- u8 r = (u8)(color >> 24), g = (u8)(color >> 16), b = (u8)(color >> 8);
- return ((float)r+(float)g+(float)b) * (1.0f / 3);
-}
-
bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point) {
float x1 = pos.x, y1 = pos.y, x2 = pos.x + size.x, y2 = pos.y + size.y,
x = point.x, y = point.y;
@@ -858,13 +766,13 @@ Rect rect_endpoints(vec2 e1, vec2 e2) {
Rect rect4(float x1, float y1, float x2, float y2) {
assert(x2 >= x1);
assert(y2 >= y1);
- return rect(Vec2(x1,y1), Vec2(x2-x1, y2-y1));
+ return rect_xywh(x1, y1, x2-x1, y2-y1);
}
Rect rect_xywh(float x, float y, float w, float h) {
assert(w >= 0);
assert(h >= 0);
- return rect(Vec2(x, y), Vec2(w, h));
+ return rect((vec2){x, y}, (vec2){w, h});
}
Rect rect_centered(vec2 center, vec2 size) {
@@ -925,51 +833,45 @@ bool rect_clip_to_rect(Rect *clipped, Rect clipper) {
return clipped->size.x > 0 && clipped->size.y > 0;
}
-Rect rect_shrink(Rect r, float amount) {
- r.pos.x += amount;
- r.pos.y += amount;
- r.size.x -= 2 * amount;
- r.size.y -= 2 * amount;
- r.size.x = maxf(r.size.x, 0);
- r.size.y = maxf(r.size.y, 0);
- return r;
+void rect_shrink(Rect *r, float amount) {
+ r->pos.x += amount;
+ r->pos.y += amount;
+ r->size.x -= 2 * amount;
+ r->size.y -= 2 * amount;
+ r->size.x = maxf(r->size.x, 0);
+ r->size.y = maxf(r->size.y, 0);
}
-Rect rect_shrink_left(Rect r, float amount) {
- r.pos.x += amount;
- r.size.x -= amount;
- r.size.x = maxf(r.size.x, 0);
- return r;
+void rect_shrink_left(Rect *r, float amount) {
+ r->pos.x += amount;
+ r->size.x -= amount;
+ r->size.x = maxf(r->size.x, 0);
}
-Rect rect_shrink_top(Rect r, float amount) {
- r.pos.y += amount;
- r.size.y -= amount;
- r.size.y = maxf(r.size.y, 0);
- return r;
+void rect_shrink_top(Rect *r, float amount) {
+ r->pos.y += amount;
+ r->size.y -= amount;
+ r->size.y = maxf(r->size.y, 0);
}
-Rect rect_shrink_right(Rect r, float amount) {
- r.size.x -= amount;
- r.size.x = maxf(r.size.x, 0);
- return r;
+void rect_shrink_right(Rect *r, float amount) {
+ r->size.x -= amount;
+ r->size.x = maxf(r->size.x, 0);
}
-Rect rect_shrink_bottom(Rect r, float amount) {
- r.size.y -= amount;
- r.size.y = maxf(r.size.y, 0);
- return r;
+void rect_shrink_bottom(Rect *r, float amount) {
+ r->size.y -= amount;
+ r->size.y = maxf(r->size.y, 0);
}
-Rect rect_grow(Rect r, float amount) {
- r.pos.x -= amount;
- r.pos.y -= amount;
- r.size.x += 2 * amount;
- r.size.y += 2 * amount;
- return r;
+void rect_grow(Rect *r, float amount) {
+ r->pos.x -= amount;
+ r->pos.y -= amount;
+ r->size.x += 2 * amount;
+ r->size.y += 2 * amount;
}
-vec4 color_rgba_to_hsva(vec4 rgba) {
+static vec4 color_rgba_to_hsva(vec4 rgba) {
float R = rgba.x, G = rgba.y, B = rgba.z, A = rgba.w;
float M = maxf(R, maxf(G, B));
float m = minf(R, minf(G, B));
@@ -986,10 +888,10 @@ vec4 color_rgba_to_hsva(vec4 rgba) {
H *= 60;
float V = M;
float S = V == 0 ? 0 : C / V;
- return Vec4(H, S, V, A);
+ return (vec4){H, S, V, A};
}
-vec4 color_hsva_to_rgba(vec4 hsva) {
+static vec4 color_hsva_to_rgba(vec4 hsva) {
float H = hsva.x, S = hsva.y, V = hsva.z, A = hsva.w;
H /= 60;
float C = S * V;
@@ -1012,7 +914,7 @@ vec4 color_hsva_to_rgba(vec4 hsva) {
R += m;
G += m;
B += m;
- return Vec4(R, G, B, A);
+ return (vec4){R, G, B, A};
}
u32 color_interpolate(float x, u32 color1, u32 color2) {
@@ -1041,7 +943,7 @@ u32 color_interpolate(float x, u32 color1, u32 color2) {
}
h_out = fmodf(h_out, 360);
- vec4 c_out = Vec4(h_out, s_out, v_out, a_out);
+ vec4 c_out = (vec4){h_out, s_out, v_out, a_out};
c_out = color_hsva_to_rgba(c_out);
return rgba_vec4_to_u32(c_out);
}
diff --git a/util.h b/util.h
index aba98bc..6e243d8 100644
--- a/util.h
+++ b/util.h
@@ -20,13 +20,6 @@
#define PIf 3.14159265358979f
-#define HALF_PIf 1.5707963267948966f
-#define TAUf 6.283185307179586f
-#define SQRT2f 1.4142135623730951f
-#define HALF_SQRT2f 0.7071067811865476f
-#define SQRT3f 1.7320508075688772f
-#define HALF_SQRT3f 0.8660254037844386f
-
typedef struct {
float x, y;
@@ -36,7 +29,7 @@ typedef struct {
} vec4;
typedef struct {
double x, y;
-} vec2d;
+} dvec2;
typedef struct {
vec2 pos, size;
@@ -49,19 +42,27 @@ typedef struct {
} String32;
-/// ctype functions for 32-bit chars.
+/// `isword` for 32-bit chars.
bool is32_word(char32_t c);
+/// `isspace` for 32-bit chars.
bool is32_space(char32_t c);
+/// `isalpha` for 32-bit chars.
bool is32_alpha(char32_t c);
+/// `isalnum` for 32-bit chars.
bool is32_alnum(char32_t c);
+/// `isdigit` for 32-bit chars.
bool is32_digit(char32_t c);
+/// `isgraph` for 32-bit chars.
bool is32_graph(char32_t c);
+/// cross-platform `isatty`
bool is_a_tty(FILE *out);
-/// terminal colors. if `out` is a TTY, these will return the appropriate escape sequences.
-/// if `out` is not a TTY, these will return "".
+/// returns terminal escape sequence for italics, or `""` if `out` is not a TTY.
const char *term_italics(FILE *out);
+/// returns terminal escape sequence for bold, or `""` if `out` is not a TTY.
const char *term_bold(FILE *out);
+/// returns terminal escape sequence for yellow, or `""` if `out` is not a TTY.
const char *term_yellow(FILE *out);
+/// returns terminal escape sequence to clear, or `""` if `out` is not a TTY.
const char *term_clear(FILE *out);
/// number of 1 bits in x.
u8 util_popcount(u64 x);
@@ -119,6 +120,7 @@ bool streq_case_insensitive(const char *a, const char *b);
/// function to be passed into qsort for case insensitive sorting
int str_qsort_case_insensitive_cmp(const void *av, const void *bv);
/// the actual file name part of the path; get rid of the containing directory.
+///
/// NOTE: the returned string is part of path, so you don't need to free it or anything.
const char *path_filename(const char *path);
/// is this an absolute path?
@@ -126,12 +128,11 @@ bool path_is_absolute(const char *path);
/// assuming `dir` is an absolute path, returns the absolute path of `relpath`, relative to `dir`.
void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size);
/// returns true if the paths are the same.
-/// handles the fact that paths are case insensitive on windows and that \ is the same as /.
+///
+/// handles the fact that paths are case insensitive on windows and that `\\` is the same as `/`.
/// a symbolic link is considered different from the file it points to, as are two hard
/// links to the same file.
bool paths_eq(const char *path1, const char *path2);
-/// equivalent to POSIX function chdir.
-void change_directory(const char *path);
/// copy file from src to dest
/// returns true on success
bool copy_file(const char *src, const char *dst);
@@ -139,44 +140,68 @@ bool copy_file(const char *src, const char *dst);
void qsort_with_context(void *base, size_t nmemb, size_t size,
int (*compar)(void *, const void *, const void *),
void *arg);
-float degrees(float r);
-float radians(float r);
+/// map x from the interval [0, 1] to the interval [a, b]. does NOT clamp.
+///
+/// note that the order is different from the usual convention because i like this order better.
float lerpf(float x, float a, float b);
+/// opposite of lerp; map x from the interval [a, b] to the interval [0, 1]. does NOT clamp.
float normf(float x, float a, float b);
+/// clamp `x` to the range [a, b].
float clampf(float x, float a, float b);
+/// clamp `x` to the range [a, b].
double clampd(double x, double a, double b);
+/// clamp `x` to the range [a, b].
int clampi(int x, int a, int b);
+/// clamp `x` to the range [a, b].
i16 clamp_i16(i16 x, i16 a, i16 b);
+/// clamp `x` to the range [a, b].
u16 clamp_u16(u16 x, u16 a, u16 b);
+/// clamp `x` to the range [a, b].
i32 clamp_i32(i32 x, i32 a, i32 b);
+/// clamp `x` to the range [a, b].
u32 clamp_u32(u32 x, u32 a, u32 b);
+/// number of digits in the decimal representation `x`
u8 ndigits_u64(u64 x);
+/// linearly remap `x` from the interval [`from_a`, `from_b`] to the interval [`to_a`, `to_b`]
float remapf(float x, float from_a, float from_b, float to_a, float to_b);
+/// minimum of `a` and `b`
float minf(float a, float b);
float maxf(float a, float b);
double maxd(double a, double b);
+/// minimum of `a` and `b`
double mind(double a, double b);
+/// minimum of `a` and `b`
u32 min_u32(u32 a, u32 b);
+/// maximum of `a` and `b`
u32 max_u32(u32 a, u32 b);
+/// set `a` to the minimum of `a` and `b` and `b` to the maximum.
void sort2_u32(u32 *a, u32 *b);
+/// minimum of `a` and `b`
i32 min_i32(i32 a, i32 b);
+/// maximum of `a` and `b`
i32 max_i32(i32 a, i32 b);
+/// minimum of `a` and `b`
u64 min_u64(u64 a, u64 b);
+/// maximum of `a` and `b`
u64 max_u64(u64 a, u64 b);
+/// minimum of `a` and `b`
i64 min_i64(i64 a, i64 b);
+/// maximum of `a` and `b`
i64 max_i64(i64 a, i64 b);
+/// returns `a` modulo `b`. for `b > 0`, this will be between `0` and `b - 1`.
+///
+/// if `b <= 0`, the return value is unspecified.
i64 mod_i64(i64 a, i64 b);
+/// returns `a` modulo `b`. for `b > 0`, this will be between `0` and `b - 1`.
+///
+/// if `b <= 0`, the return value is unspecified.
i32 mod_i32(i32 a, i32 b);
+/// absolute value
i64 abs_i64(i64 x);
+/// `-1` if `x < 0`, `0` if `x == 0`, and `1` if `x > 0`
i64 sgn_i64(i64 x);
+/// `-1` if `x < 0`, `0` if `x == 0`, and `1` if `x > 0`
float sgnf(float x);
-float smoothstepf(float x);
-float randf(void);
-u32 rand_u32(void);
-float rand_uniform(float from, float to);
-float sigmoidf(float x);
-i32 ceildivi32(i32 x, i32 y);
-vec2 Vec2(float x, float y);
vec2 vec2_add(vec2 a, vec2 b);
vec2 vec2_add_const(vec2 a, float c);
vec2 vec2_sub(vec2 a, vec2 b);
@@ -184,20 +209,16 @@ vec2 vec2_scale(vec2 v, float s);
vec2 vec2_mul(vec2 a, vec2 b);
vec2 vec2_clamp(vec2 x, vec2 a, vec2 b);
float vec2_dot(vec2 a, vec2 b);
-float vec2_len(vec2 v);
+float vec2_norm(vec2 v);
vec2 vec2_lerp(float x, vec2 a, vec2 b);
vec2 vec2_rotate(vec2 v, float theta);
vec2 vec2_normalize(vec2 v);
-float vec2_dist(vec2 a, vec2 b);
-float vec2_dist_squared(vec2 a, vec2 b);
+float vec2_distance(vec2 a, vec2 b);
void vec2_print(vec2 v);
-vec2 vec2_rand_unit(void);
vec2 vec2_polar(float r, float theta);
-vec4 Vec4(float x, float y, float z, float w);
void rgba_u32_to_floats(u32 rgba, float floats[4]);
vec4 rgba_u32_to_vec4(u32 rgba);
u32 rgba_vec4_to_u32(vec4 color);
-float rgba_brightness(u32 color);
bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point);
bool centered_rect_contains_point(vec2 center, vec2 size, vec2 point);
Rect rect(vec2 pos, vec2 size);
@@ -209,150 +230,27 @@ vec2 rect_center(Rect r);
bool rect_contains_point(Rect r, vec2 point);
Rect rect_translate(Rect r, vec2 by);
void rect_coords(Rect r, float *x1, float *y1, float *x2, float *y2);
-void rect_print(Rect r);
-float rects_intersect(Rect r1, Rect r2);
-bool rect_clip_to_rect(Rect *clipped, Rect clipper);
-/// removes `amount` from all sides of r
-Rect rect_shrink(Rect r, float amount);
-/// removes `amount` from the left side of r
-Rect rect_shrink_left(Rect r, float amount);
-/// removes `amount` from the top side of r
-Rect rect_shrink_top(Rect r, float amount);
-/// removes `amount` from the right side of r
-Rect rect_shrink_right(Rect r, float amount);
-/// removes `amount` from the bottom side of r
-Rect rect_shrink_bottom(Rect r, float amount);
-/// adds `amount` to all sides of r
-Rect rect_grow(Rect r, float amount);
-vec4 color_rgba_to_hsva(vec4 rgba);
-vec4 color_hsva_to_rgba(vec4 hsva);
-u32 color_interpolate(float x, u32 color1, u32 color2);
-int timespec_cmp(struct timespec a, struct timespec b);
-bool timespec_eq(struct timespec a, struct timespec b);
-struct timespec timespec_max(struct timespec a, struct timespec b);
-double timespec_to_seconds(struct timespec ts);
-bool is32_word(char32_t c);
-bool is32_space(char32_t c);
-bool is32_alpha(char32_t c);
-bool is32_alnum(char32_t c);
-bool is32_digit(char32_t c);
-bool is32_graph(char32_t c);
-bool is_a_tty(FILE *out);
-const char *term_italics(FILE *out);
-const char *term_bold(FILE *out);
-const char *term_yellow(FILE *out);
-const char *term_clear(FILE *out);
-u8 util_popcount(u64 x);
-u8 util_count_leading_zeroes32(u32 x);
-bool util_is_power_of_2(u64 x);
-char32_t *util_mem32chr(char32_t *s, char32_t c, size_t n);
-const char32_t *util_mem32chr_const(const char32_t *s, char32_t c, size_t n);
-bool str_has_prefix(const char *str, const char *prefix);
-bool str_has_path_prefix(const char *path, const char *prefix);
-bool streq(const char *a, const char *b);
-size_t strn_len(const char *src, size_t n);
-char *strn_dup(const char *src, size_t n);
-char *str_dup(const char *src);
-void strn_cat(char *dst, size_t dst_sz, const char *src, size_t src_len);
-void str_cat(char *dst, size_t dst_sz, const char *src);
-void strn_cpy(char *dst, size_t dst_sz, const char *src, size_t src_len);
-void str_cpy(char *dst, size_t dst_sz, const char *src);
-char *a_sprintf(const char *fmt, ...);
-char *strstr_case_insensitive(const char *haystack, const char *needle);
-void print_bytes(const u8 *bytes, size_t n);
-int strcmp_case_insensitive(const char *a, const char *b);
-int str_qsort_case_insensitive_cmp(const void *av, const void *bv);
-int qsort_with_context_cmp(const void *a, const void *b, void *context);
-const char *path_filename(const char *path);
-bool path_is_absolute(const char *path);
-void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size);
-bool paths_eq(const char *path1, const char *path2);
-void change_directory(const char *path);
-bool copy_file(const char *src, const char *dst);
-float degrees(float r);
-float radians(float r);
-float lerpf(float x, float a, float b);
-float normf(float x, float a, float b);
-float clampf(float x, float a, float b);
-int clampi(int x, int a, int b);
-i16 clamp_i16(i16 x, i16 a, i16 b);
-u16 clamp_u16(u16 x, u16 a, u16 b);
-i32 clamp_i32(i32 x, i32 a, i32 b);
-u32 clamp_u32(u32 x, u32 a, u32 b);
-u8 ndigits_u64(u64 x);
-float remapf(float x, float from_a, float from_b, float to_a, float to_b);
-float minf(float a, float b);
-float maxf(float a, float b);
-double maxd(double a, double b);
-double mind(double a, double b);
-u32 min_u32(u32 a, u32 b);
-u32 max_u32(u32 a, u32 b);
-void sort2_u32(u32 *a, u32 *b);
-i32 min_i32(i32 a, i32 b);
-i32 max_i32(i32 a, i32 b);
-u64 min_u64(u64 a, u64 b);
-u64 max_u64(u64 a, u64 b);
-i64 min_i64(i64 a, i64 b);
-i64 max_i64(i64 a, i64 b);
-i64 mod_i64(i64 a, i64 b);
-i32 mod_i32(i32 a, i32 b);
-i64 abs_i64(i64 x);
-i64 sgn_i64(i64 x);
-float sgnf(float x);
-float smoothstepf(float x);
-float randf(void);
-float rand_gauss(void);
-u32 rand_u32(void);
-float rand_uniform(float from, float to);
-float sigmoidf(float x);
-i32 ceildivi32(i32 x, i32 y);
-vec2 Vec2(float x, float y);
-vec2 vec2_add(vec2 a, vec2 b);
-vec2 vec2_add_const(vec2 a, float c);
-vec2 vec2_sub(vec2 a, vec2 b);
-vec2 vec2_scale(vec2 v, float s);
-vec2 vec2_mul(vec2 a, vec2 b);
-vec2 vec2_clamp(vec2 x, vec2 a, vec2 b);
-float vec2_dot(vec2 a, vec2 b);
-float vec2_len(vec2 v);
-vec2 vec2_lerp(float x, vec2 a, vec2 b);
-vec2 vec2_rotate(vec2 v, float theta);
-vec2 vec2_normalize(vec2 v);
-float vec2_dist(vec2 a, vec2 b);
-float vec2_dist_squared(vec2 a, vec2 b);
-void vec2_print(vec2 v);
-vec2 vec2_rand_unit(void);
-vec2 vec2_polar(float r, float theta);
-vec4 Vec4(float x, float y, float z, float w);
-vec2d Vec2d(double x, double y);
-void rgba_u32_to_floats(u32 rgba, float floats[4]);
-vec4 rgba_u32_to_vec4(u32 rgba);
-u32 rgba_vec4_to_u32(vec4 color);
-float rgba_brightness(u32 color);
-bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point);
-bool centered_rect_contains_point(vec2 center, vec2 size, vec2 point);
-Rect rect(vec2 pos, vec2 size);
-Rect rect_endpoints(vec2 e1, vec2 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(vec2 center, vec2 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);
-vec2 rect_center(Rect r);
-bool rect_contains_point(Rect r, vec2 point);
-Rect rect_translate(Rect r, vec2 by);
-void rect_coords(Rect r, float *x1, float *y1, float *x2, float *y2);
void rect_print(Rect r);
float rects_intersect(Rect r1, Rect r2);
bool rect_clip_to_rect(Rect *clipped, Rect clipper);
-Rect rect_shrink(Rect r, float amount);
-Rect rect_grow(Rect r, float amount);
-vec4 color_rgba_to_hsva(vec4 rgba);
-vec4 color_hsva_to_rgba(vec4 hsva);
+/// removes `amount` from all sides of r
+void rect_shrink(Rect *r, float amount);
+/// removes `amount` from the left side of r
+void rect_shrink_left(Rect *r, float amount);
+/// removes `amount` from the top side of r
+void rect_shrink_top(Rect *r, float amount);
+/// removes `amount` from the right side of r
+void rect_shrink_right(Rect *r, float amount);
+/// removes `amount` from the bottom side of r
+void rect_shrink_bottom(Rect *r, float amount);
+/// adds `amount` to all sides of r
+void rect_grow(Rect *r, float amount);
u32 color_interpolate(float x, u32 color1, u32 color2);
int timespec_cmp(struct timespec a, struct timespec b);
bool timespec_eq(struct timespec a, struct timespec b);