diff --git a/src/common.c b/src/common.c index 46bcfc50..552cde5a 100644 --- a/src/common.c +++ b/src/common.c @@ -48,7 +48,8 @@ Errno read_entire_dir(const char *dir_path, Files *files) errno = 0; struct dirent *ent = readdir(dir); while (ent != NULL) { - da_append(files, temp_strdup(ent->d_name)); + char *dir_name = temp_strdup(ent->d_name); + da_append(files, dir_name); ent = readdir(dir); } @@ -79,16 +80,18 @@ Errno write_entire_file(const char *file_path, const char *buf, size_t buf_size) static Errno file_size(FILE *file, size_t *size) { + errno = 0; long saved = ftell(file); - if (saved < 0) return errno; + if (errno) return errno; if (fseek(file, 0, SEEK_END) < 0) return errno; long result = ftell(file); - if (result < 0) return errno; + if (errno) return errno; if (fseek(file, saved, SEEK_SET) < 0) return errno; *size = (size_t) result; return 0; } +// ram go boom boom Errno read_entire_file(const char *file_path, String_Builder *sb) { Errno result = 0; diff --git a/src/editor.h b/src/editor.h index 4b5ddd58..a8d5a316 100644 --- a/src/editor.h +++ b/src/editor.h @@ -44,6 +44,8 @@ typedef struct { Uint32 last_stroke; String_Builder clipboard; + + bool drag_mouse; } Editor; Errno editor_save_as(Editor *editor, const char *file_path); diff --git a/src/free_glyph.c b/src/free_glyph.c index fe2b55b3..7b7aab9b 100644 --- a/src/free_glyph.c +++ b/src/free_glyph.c @@ -1,12 +1,13 @@ #include #include #include "./free_glyph.h" +#define TAB_SIZE 4 void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face) { // TODO: Introduction of SDF font slowed down the start up time // We need to investigate what's up with that - FT_Int32 load_flags = FT_LOAD_RENDER | FT_LOAD_TARGET_(FT_RENDER_MODE_SDF); + FT_Int32 load_flags = FT_LOAD_RENDER; for (int i = 32; i < 128; ++i) { if (FT_Load_Char(face, i, load_flags)) { fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i); @@ -17,6 +18,8 @@ void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face) if (atlas->atlas_height < face->glyph->bitmap.rows) { atlas->atlas_height = face->glyph->bitmap.rows; } + + load_flags = FT_LOAD_RENDER | FT_LOAD_TARGET_(FT_RENDER_MODE_SDF); } glActiveTexture(GL_TEXTURE0); @@ -41,6 +44,7 @@ void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face) NULL); int x = 0; + load_flags = FT_LOAD_RENDER; for (int i = 32; i < 128; ++i) { if (FT_Load_Char(face, i, load_flags)) { fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i); @@ -72,7 +76,29 @@ void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face) GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer); x += face->glyph->bitmap.width; + load_flags = FT_LOAD_RENDER | FT_LOAD_TARGET_(FT_RENDER_MODE_SDF); + } + + // tab hack + load_flags = FT_LOAD_RENDER; + int i = '\t'; + if (FT_Load_Char(face, 32, load_flags)) { + fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i); + exit(1); + } + + if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) { + fprintf(stderr, "ERROR: could not render glyph of a character with code %d\n", i); + exit(1); } + + atlas->metrics[i].ax = (face->glyph->advance.x >> 6) * TAB_SIZE; + atlas->metrics[i].ay = face->glyph->advance.y >> 6; + atlas->metrics[i].bw = face->glyph->bitmap.width * TAB_SIZE; + atlas->metrics[i].bh = face->glyph->bitmap.rows; + atlas->metrics[i].bl = face->glyph->bitmap_left; + atlas->metrics[i].bt = face->glyph->bitmap_top; + atlas->metrics[i].tx = (float) 0 / (float) atlas->atlas_width; } float free_glyph_atlas_cursor_pos(const Free_Glyph_Atlas *atlas, const char *text, size_t text_size, Vec2f pos, size_t col) diff --git a/src/main.c b/src/main.c index e9ca5efe..d564bf8c 100644 --- a/src/main.c +++ b/src/main.c @@ -3,13 +3,16 @@ #include #include #include - +#define TABS_INSTEAD_OF_SPACES #include #define GLEW_STATIC #include #define GL_GLEXT_PROTOTYPES #include +#define DRAG_X_MIN 1 +#define DRAG_Y_MIN 1 + #include #include FT_FREETYPE_H @@ -94,6 +97,7 @@ int main(int argc, char **argv) err = editor_load_from_file(&editor, file_path); if (err != 0) { fprintf(stderr, "ERROR: Could not read file %s: %s\n", file_path, strerror(err)); + fprintf(stderr, "HELP: If you're trying to open a directory, don't give any arguments, press F3 inside the editor.\n"); return 1; } } @@ -170,19 +174,138 @@ int main(int argc, char **argv) } break; + case SDL_MOUSEBUTTONUP: + if(!file_browser && (event.button.button & SDL_BUTTON_LEFT) == SDL_BUTTON_LEFT) { + editor.drag_mouse = false; + } + + break; + + case SDL_MOUSEMOTION: + if(!file_browser && editor.drag_mouse) { + int x_rel = event.motion.xrel; + int y_rel = event.motion.yrel; + int is_x_left = x_rel < 0; + int is_y_down = y_rel < 0; + x_rel = abs(x_rel); + y_rel = abs(y_rel); + while(y_rel > DRAG_Y_MIN) { + if(is_y_down) { + editor_move_line_up(&editor); + } else { + editor_move_line_down(&editor); + } + + y_rel -= DRAG_Y_MIN; + } + + while(x_rel > DRAG_X_MIN) { + if(event.key.keysym.mod & KMOD_CTRL) { + if(is_x_left) { + editor_move_word_left(&editor); + } else { + editor_move_word_right(&editor); + } + } else { + if(is_x_left) { + editor_move_char_left(&editor); + } else { + editor_move_char_right(&editor); + } + } + + x_rel -= DRAG_X_MIN; + } + + editor.last_stroke = SDL_GetTicks(); + } + + break; + + case SDL_MOUSEWHEEL: + if(event.wheel.y > 0) { + editor_move_line_up(&editor); + } else if(event.wheel.y < 0) { + editor_move_line_down(&editor); + } + + if(file_browser) { + if(event.wheel.y > 0) { + if(fb.cursor > 0) fb.cursor -= 1; + } else if(event.wheel.y < 0) { + if(fb.cursor + 1 < fb.files.count) fb.cursor += 1; + } + } + + break; + + + case SDL_MOUSEBUTTONDOWN: + if(file_browser && (event.button.button & SDL_BUTTON_LEFT) == SDL_BUTTON_LEFT) { + const char *file_path = fb_file_path(&fb); + File_Type ft; + err = type_of_file(file_path, &ft); + if (err != 0) { + flash_error("Could not determine type of file %s: %s", file_path, strerror(err)); + } else { + 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"); + } + } + } else if((event.button.button & SDL_BUTTON_LEFT) == SDL_BUTTON_LEFT) { + editor.drag_mouse = true; + } + + break; + case SDL_KEYDOWN: { if (file_browser) { switch (event.key.keysym.sym) { - case SDLK_F3: { + case SDLK_q: + if(event.key.keysym.mod & KMOD_CTRL) { + quit = true; + } + + break; + + case SDLK_ESCAPE: { file_browser = false; } break; + case SDLK_w: case SDLK_UP: { if (fb.cursor > 0) fb.cursor -= 1; } break; + case SDLK_s: case SDLK_DOWN: { if (fb.cursor + 1 < fb.files.count) fb.cursor += 1; } @@ -258,26 +381,42 @@ int main(int argc, char **argv) } break; - case SDLK_F2: { - if (editor.file_path.count > 0) { - err = editor_save(&editor); - if (err != 0) { - flash_error("Could not save currently edited file: %s", strerror(err)); - } - } else { - // TODO: ask the user for the path to save to in this situation - flash_error("Nowhere to save the text"); - } - } - break; - - case SDLK_F3: { - file_browser = true; + case SDLK_q: + if(event.key.keysym.mod & KMOD_CTRL) { + quit = true; + } + + break; + + case SDLK_r: + if(event.key.keysym.mod & KMOD_CTRL) { + simple_renderer_reload_shaders(&sr); + } + + break; + + case SDLK_s: { + if(event.key.keysym.mod & KMOD_CTRL) { + if (editor.file_path.count > 0) { + err = editor_save(&editor); + if (err != 0) { + flash_error("Could not save currently edited file: %s", strerror(err)); + } + } else { + // TODO: ask the user for the path to save to in this situation + flash_error("Nowhere to save the text"); + } + } } break; - case SDLK_F5: { - simple_renderer_reload_shaders(&sr); + case SDLK_ESCAPE: { + if(editor.searching) { + editor_stop_search(&editor); + editor_update_selection(&editor, event.key.keysym.mod & KMOD_SHIFT); + } else { + file_browser = true; + } } break; @@ -304,12 +443,6 @@ int main(int argc, char **argv) } break; - case SDLK_ESCAPE: { - editor_stop_search(&editor); - editor_update_selection(&editor, event.key.keysym.mod & KMOD_SHIFT); - } - break; - case SDLK_a: { if (event.key.keysym.mod & KMOD_CTRL) { editor.selection = true; @@ -320,16 +453,14 @@ int main(int argc, char **argv) break; case SDLK_TAB: { - // TODO: indent on Tab instead of just inserting 4 spaces at the cursor - // That is insert the spaces at the beginning of the line. Shift+TAB should - // do unindent, that is remove 4 spaces from the beginning of the line. - // TODO: customizable indentation style - // - tabs/spaces - // - tab width - // - etc. - for (size_t i = 0; i < 4; ++i) { - editor_insert_char(&editor, ' '); - } + // XXX: Tabs are kind of a hack, needs a redo. + #ifdef TABS_INSTEAD_OF_SPACES + editor_insert_char(&editor, '\t'); + #else + for(int i = 0; i < TAB_SIZE; i++) { + editor_insert_char(&editor, ' '); + } + #endif } break; @@ -412,6 +543,8 @@ int main(int argc, char **argv) } } + + { int w, h; SDL_GetWindowSize(window, &w, &h);