Skip to content

Commit 57d23fa

Browse files
committed
Implement path normalization for file browser
1 parent f75ebd3 commit 57d23fa

File tree

5 files changed

+422
-4
lines changed

5 files changed

+422
-4
lines changed

src/common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "common.h"
1717
#define ARENA_IMPLEMENTATION
1818
#include "./arena.h"
19+
#define SV_IMPLEMENTATION
20+
#include "sv.h"
1921

2022
static Arena temporary_arena = {0};
2123

src/common.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ typedef int Errno;
3232

3333
#define DA_INIT_CAP 256
3434

35+
#define da_last(da) (assert((da)->count > 0), (da)->items[(da)->count - 1])
36+
37+
#define da_move(dst, src) \
38+
do { \
39+
free((dst)->items); \
40+
(dst)->items = (src).items; \
41+
(dst)->count = (src).count; \
42+
(dst)->capacity = (src).capacity; \
43+
} while (0)
44+
3545
#define da_append(da, item) \
3646
do { \
3747
if ((da)->count >= (da)->capacity) { \
@@ -68,6 +78,9 @@ typedef struct {
6878
size_t capacity;
6979
} String_Builder;
7080

81+
#define SB_Fmt "%.*s"
82+
#define SB_Arg(sb) (int) (sb).count, (sb).items
83+
7184
#define sb_append_buf da_append_many
7285
#define sb_append_cstr(sb, cstr) \
7386
do { \
@@ -77,6 +90,8 @@ typedef struct {
7790
} while (0)
7891
#define sb_append_null(sb) da_append_many(sb, "", 1)
7992

93+
#define sb_to_sv(sb) sv_from_parts((sb).items, (sb).count)
94+
8095
typedef struct {
8196
const char **items;
8297
size_t count;

src/file_browser.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <string.h>
22
#include "file_browser.h"
3+
#include "sv.h"
34

45
static int file_cmp(const void *ap, const void *bp)
56
{
@@ -25,6 +26,76 @@ Errno fb_open_dir(File_Browser *fb, const char *dir_path)
2526
return 0;
2627
}
2728

29+
#define PATH_SEP "/"
30+
#define PATH_EMPTY ""
31+
#define PATH_DOT "."
32+
#define PATH_DOTDOT ".."
33+
34+
typedef struct {
35+
String_View *items;
36+
size_t count;
37+
size_t capacity;
38+
} Comps;
39+
40+
void normpath(String_View path, String_Builder *result)
41+
{
42+
size_t original_sb_size = result->count;
43+
44+
if (path.count == 0) {
45+
sb_append_cstr(result, PATH_DOT);
46+
return;
47+
}
48+
49+
int initial_slashes = 0;
50+
while (path.count > 0 && *path.data == *PATH_SEP) {
51+
initial_slashes += 1;
52+
sv_chop_left(&path, 1);
53+
}
54+
if (initial_slashes > 2) {
55+
initial_slashes = 1;
56+
}
57+
58+
Comps new_comps = {0};
59+
60+
while (path.count > 0) {
61+
String_View comp = sv_chop_by_delim(&path, '/');
62+
if (comp.count == 0 || sv_eq(comp, SV(PATH_DOT))) {
63+
continue;
64+
}
65+
if (!sv_eq(comp, SV(PATH_DOTDOT))) {
66+
da_append(&new_comps, comp);
67+
continue;
68+
}
69+
if (initial_slashes == 0 && new_comps.count == 0) {
70+
da_append(&new_comps, comp);
71+
continue;
72+
}
73+
if (new_comps.count > 0 && sv_eq(da_last(&new_comps), SV(PATH_DOTDOT))) {
74+
da_append(&new_comps, comp);
75+
continue;
76+
}
77+
if (new_comps.count > 0) {
78+
new_comps.count -= 1;
79+
continue;
80+
}
81+
}
82+
83+
for (int i = 0; i < initial_slashes; ++i) {
84+
sb_append_cstr(result, PATH_SEP);
85+
}
86+
87+
for (size_t i = 0; i < new_comps.count; ++i) {
88+
if (i > 0) sb_append_cstr(result, PATH_SEP);
89+
sb_append_buf(result, new_comps.items[i].data, new_comps.items[i].count);
90+
}
91+
92+
if (original_sb_size == result->count) {
93+
sb_append_cstr(result, PATH_DOT);
94+
}
95+
96+
free(new_comps.items);
97+
}
98+
2899
Errno fb_change_dir(File_Browser *fb)
29100
{
30101
assert(fb->dir_path.count > 0 && "You need to call fb_open_dir() before fb_change_dir()");
@@ -36,11 +107,17 @@ Errno fb_change_dir(File_Browser *fb)
36107

37108
fb->dir_path.count -= 1;
38109

39-
// TODO: fb_change_dir() does not support .. and . properly
110+
// TODO: fb->dir_path grows indefinitely if we hit the root
40111
sb_append_cstr(&fb->dir_path, "/");
41112
sb_append_cstr(&fb->dir_path, dir_name);
113+
114+
String_Builder result = {0};
115+
normpath(sb_to_sv(fb->dir_path), &result);
116+
da_move(&fb->dir_path, result);
42117
sb_append_null(&fb->dir_path);
43118

119+
printf("Changed dir to %s\n", fb->dir_path.items);
120+
44121
fb->files.count = 0;
45122
fb->cursor = 0;
46123
Errno err = read_entire_dir(fb->dir_path.items, &fb->files);

src/main.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "./simple_renderer.h"
2121
#include "./common.h"
2222
#include "./lexer.h"
23+
#include "./sv.h"
2324

2425
// TODO: Save file dialog
2526
// Needed when ded is ran without any file so it does not know where to save.
@@ -55,6 +56,7 @@ static File_Browser fb = {0};
5556
// TODO: display errors reported via flash_error right in the text editor window somehow
5657
#define flash_error(...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while(0)
5758

59+
5860
int main(int argc, char **argv)
5961
{
6062
Errno err;
@@ -294,19 +296,22 @@ int main(int argc, char **argv)
294296
for (size_t i = 0; i < 4; ++i) {
295297
editor_insert_char(&editor, ' ');
296298
}
297-
} break;
299+
}
300+
break;
298301

299302
case SDLK_c: {
300303
if (event.key.keysym.mod & KMOD_CTRL) {
301304
editor_clipboard_copy(&editor);
302305
}
303-
} break;
306+
}
307+
break;
304308

305309
case SDLK_v: {
306310
if (event.key.keysym.mod & KMOD_CTRL) {
307311
editor_clipboard_paste(&editor);
308312
}
309-
} break;
313+
}
314+
break;
310315

311316
case SDLK_UP: {
312317
editor_update_selection(&editor, event.key.keysym.mod & KMOD_SHIFT);

0 commit comments

Comments
 (0)