commit e9e7126b6ab59ab16e34c2a05f1c85e06397dd1a
parent 6bb06d32ebffb4dadf4a8ff4002bc4a5f58ea9e4
Author: rexim <reximkut@gmail.com>
Date: Thu, 9 Feb 2023 13:01:19 +0700
Go inside folders
Diffstat:
8 files changed, 148 insertions(+), 18 deletions(-)
diff --git a/src/common.c b/src/common.c
@@ -8,6 +8,9 @@
# include <minirent.h>
#else
# include <dirent.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
#endif // _WIN32
#include "common.h"
@@ -124,3 +127,21 @@ Vec4f hex_to_vec4f(uint32_t color)
result.w = a/255.0f;
return result;
}
+
+Errno type_of_file(const char *file_path, File_Type *ft)
+{
+#ifdef _WIN32
+#error "TODO: type_of_file() is not implemented for Windows"
+#else
+ struct stat sb = {0};
+ if (stat(file_path, &sb) < 0) return errno;
+ if (S_ISREG(sb.st_mode)) {
+ *ft = FT_REGULAR;
+ } else if (S_ISDIR(sb.st_mode)) {
+ *ft = FT_DIRECTORY;
+ } else {
+ *ft = FT_OTHER;
+ }
+#endif
+ return 0;
+}
diff --git a/src/common.h b/src/common.h
@@ -68,10 +68,11 @@ typedef struct {
} String_Builder;
#define sb_append_buf da_append_many
-#define sb_append_cstr(sb, cstr) \
- do { \
- size_t n = strlen(cstr); \
- da_append_many(sb, cstr, n); \
+#define sb_append_cstr(sb, cstr) \
+ do { \
+ const char *s = (cstr); \
+ size_t n = strlen(s); \
+ da_append_many(sb, s, n); \
} while (0)
#define sb_append_null(sb) da_append_many(sb, "", 1)
@@ -81,6 +82,13 @@ typedef struct {
size_t capacity;
} Files;
+typedef enum {
+ FT_REGULAR,
+ FT_DIRECTORY,
+ FT_OTHER,
+} File_Type;
+
+Errno type_of_file(const char *file_path, File_Type *ft);
Errno read_entire_file(const char *file_path, String_Builder *sb);
Errno write_entire_file(const char *file_path, const char *buf, size_t buf_size);
Errno read_entire_dir(const char *dir_path, Files *files);
diff --git a/src/editor.c b/src/editor.c
@@ -53,6 +53,8 @@ Errno editor_save(const Editor *e)
Errno editor_load_from_file(Editor *e, const char *file_path)
{
+ printf("Loading %s\n", file_path);
+
e->data.count = 0;
Errno err = read_entire_file(file_path, &e->data);
if (err != 0) return err;
@@ -308,20 +310,26 @@ void editor_render(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer
// Update camera
{
- float target_scale = 3.0f;
if (max_line_len > 1000.0f) {
max_line_len = 1000.0f;
}
- if (max_line_len > 0.0f) {
- target_scale = SCREEN_WIDTH / max_line_len;
- }
+
+ // TODO: SCREEN_WIDTH has to be variable cause window my resize
+ float target_scale = SCREEN_WIDTH / max_line_len;
+
+ Vec2f target = cursor_pos;
+ float offset = 0.0f;
if (target_scale > 3.0f) {
target_scale = 3.0f;
+ } else {
+ offset = cursor_pos.x - SCREEN_WIDTH/sr->camera_scale;
+ if (offset < 0.0f) offset = 0.0f;
+ target = vec2f(SCREEN_WIDTH/sr->camera_scale + offset, cursor_pos.y);
}
sr->camera_vel = vec2f_mul(
- vec2f_sub(cursor_pos, sr->camera_pos),
+ vec2f_sub(target, sr->camera_pos),
vec2fs(2.0f));
sr->camera_scale_vel = (target_scale - sr->camera_scale) * 2.0f;
diff --git a/src/file_browser.c b/src/file_browser.c
@@ -17,6 +17,39 @@ Errno fb_open_dir(File_Browser *fb, const char *dir_path)
return err;
}
qsort(fb->files.items, fb->files.count, sizeof(*fb->files.items), file_cmp);
+
+ fb->dir_path.count = 0;
+ sb_append_cstr(&fb->dir_path, dir_path);
+ sb_append_null(&fb->dir_path);
+
+ return 0;
+}
+
+Errno fb_change_dir(File_Browser *fb)
+{
+ assert(fb->dir_path.count > 0 && "You need to call fb_open_dir() before fb_change_dir()");
+ assert(fb->dir_path.items[fb->dir_path.count - 1] == '\0');
+
+ if (fb->cursor >= fb->files.count) return 0;
+
+ const char *dir_name = fb->files.items[fb->cursor];
+
+ fb->dir_path.count -= 1;
+
+ // TODO: fb_change_dir() does not support .. and . properly
+ sb_append_cstr(&fb->dir_path, "/");
+ sb_append_cstr(&fb->dir_path, dir_name);
+ sb_append_null(&fb->dir_path);
+
+ fb->files.count = 0;
+ fb->cursor = 0;
+ Errno err = read_entire_dir(fb->dir_path.items, &fb->files);
+
+ if (err != 0) {
+ return err;
+ }
+ qsort(fb->files.items, fb->files.count, sizeof(*fb->files.items), file_cmp);
+
return 0;
}
@@ -81,3 +114,19 @@ void fb_render(const File_Browser *fb, SDL_Window *window, Free_Glyph_Atlas *atl
sr->camera_scale = sr->camera_scale + sr->camera_scale_vel * DELTA_TIME;
}
}
+
+const char *fb_file_path(File_Browser *fb)
+{
+ assert(fb->dir_path.count > 0 && "You need to call fb_open_dir() before fb_file_path()");
+ assert(fb->dir_path.items[fb->dir_path.count - 1] == '\0');
+
+ if (fb->cursor >= fb->files.count) return NULL;
+
+ fb->file_path.count = 0;
+ sb_append_buf(&fb->file_path, fb->dir_path.items, fb->dir_path.count - 1);
+ sb_append_buf(&fb->file_path, "/", 1);
+ sb_append_cstr(&fb->file_path, fb->files.items[fb->cursor]);
+ sb_append_null(&fb->file_path);
+
+ return fb->file_path.items;
+}
diff --git a/src/file_browser.h b/src/file_browser.h
@@ -9,9 +9,13 @@
typedef struct {
Files files;
size_t cursor;
+ String_Builder dir_path;
+ String_Builder file_path;
} File_Browser;
Errno fb_open_dir(File_Browser *fb, const char *dir_path);
+Errno fb_change_dir(File_Browser *fb);
void fb_render(const File_Browser *fb, SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr);
+const char *fb_file_path(File_Browser *fb);
#endif // FILE_BROWSER_H_
diff --git a/src/main.c b/src/main.c
@@ -50,7 +50,7 @@ static Editor editor = {0};
static File_Browser fb = {0};
// TODO: display errors reported via flash_error right in the text editor window somehow
-#define flash_error(...) fprintf(stderr, __VA_ARGS__)
+#define flash_error(...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while(0)
int main(int argc, char **argv)
{
@@ -197,16 +197,42 @@ int main(int argc, char **argv)
break;
case SDLK_RETURN: {
- if (fb.cursor < fb.files.count) {
- // TODO: go inside folders
- const char *file_path = fb.files.items[fb.cursor];
- // TODO: before opening a new file make sure you don't have unsaved changes
- // And if you do, annoy the user about it. (just like all the other editors do)
- err = editor_load_from_file(&editor, file_path);
+ const char *file_path = fb_file_path(&fb);
+ if (file_path) {
+ File_Type ft;
+ err = type_of_file(file_path, &ft);
if (err != 0) {
- flash_error("Could not open file %s: %s", file_path, strerror(err));
+ flash_error("Could not determine type of file %s: %s", file_path, strerror(err));
} else {
- file_browser = false;
+ switch (ft) {
+ case FT_DIRECTORY: {
+ err = fb_change_dir(&fb);
+ if (err != 0) {
+ flash_error("Could not change directory to %s: %s", file_path, strerror(err));
+ }
+ }
+ break;
+
+ case FT_REGULAR: {
+ // TODO: before opening a new file make sure you don't have unsaved changes
+ // And if you do, annoy the user about it. (just like all the other editors do)
+ err = editor_load_from_file(&editor, file_path);
+ if (err != 0) {
+ flash_error("Could not open file %s: %s", file_path, strerror(err));
+ } else {
+ file_browser = false;
+ }
+ }
+ break;
+
+ case FT_OTHER: {
+ flash_error("%s is neither a regular file nor a directory. We can't open it.", file_path);
+ }
+ break;
+
+ default:
+ UNREACHABLE("unknown File_Type");
+ }
}
}
}
@@ -335,3 +361,7 @@ int main(int argc, char **argv)
return 0;
}
+
+// TODO: ability to search within file browser
+// Very useful when you have a lot of files
+// TODO: ability to search with the text editor
diff --git a/src/simple_renderer.c b/src/simple_renderer.c
@@ -208,8 +208,14 @@ void simple_renderer_init(Simple_Renderer *sr)
// simple_renderer_vertex() for a potentially large amount of verticies in the first place.
void simple_renderer_vertex(Simple_Renderer *sr, Vec2f p, Vec4f c, Vec2f uv)
{
+#if 1
// TODO: flush the renderer on vertex buffer overflow instead firing the assert
+ if (sr->verticies_count >= SIMPLE_VERTICIES_CAP) simple_renderer_flush(sr);
+#else
+ // NOTE: it is better to just crash the app in this case until the culling described
+ // above is sorted out.
assert(sr->verticies_count < SIMPLE_VERTICIES_CAP);
+#endif
Simple_Vertex *last = &sr->verticies[sr->verticies_count];
last->position = p;
last->color = c;
diff --git a/src/simple_renderer.h b/src/simple_renderer.h
@@ -1,6 +1,8 @@
#ifndef SIMPLE_RENDERER_H_
#define SIMPLE_RENDERER_H_
+#include <assert.h>
+
#define GLEW_STATIC
#include <GL/glew.h>
@@ -31,6 +33,8 @@ typedef struct {
#define SIMPLE_VERTICIES_CAP (3*640*1000)
+static_assert(SIMPLE_VERTICIES_CAP%3 == 0, "Simple renderer vertex capacity must be divisible by 3. We are rendring triangles after all.");
+
typedef enum {
SHADER_FOR_COLOR = 0,
SHADER_FOR_IMAGE,