From e9357bfd982b37672ed9c319956af32bf3db7856 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 13 Feb 2021 15:47:30 -0500 Subject: view-only mode --- buffer.c | 18 ++++++++++++++++-- colors.h | 6 +++++- filesystem-posix.c | 8 ++++++++ filesystem-win.c | 2 ++ filesystem.h | 8 ++++++++ main.c | 3 +++ node.c | 19 +++++++++++++------ ted.cfg | 2 ++ ted.h | 2 ++ 9 files changed, 59 insertions(+), 9 deletions(-) diff --git a/buffer.c b/buffer.c index 7bf1c74..332a8a2 100644 --- a/buffer.c +++ b/buffer.c @@ -1196,6 +1196,8 @@ static Status buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) { // inserts the given text, returning the position of the end of the text BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 str) { + if (buffer->view_only) + return pos; if (str.len > U32_MAX) { buffer_seterr(buffer, "Inserting too much text (length: %zu).", str.len); BufferPos ret = {0,0}; @@ -1407,11 +1409,13 @@ static void buffer_delete_lines(TextBuffer *buffer, u32 first_line_idx, u32 nlin } void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) { + if (buffer->view_only) return; if (nchars_ < 0) { buffer_seterr(buffer, "Deleting negative characters (specifically, " I64_FMT ").", nchars_); return; } if (nchars_ <= 0) return; + if (nchars_ > U32_MAX) nchars_ = U32_MAX; u32 nchars = (u32)nchars_; @@ -1839,6 +1843,10 @@ Status buffer_load_file(TextBuffer *buffer, char const *filename) { buffer->lines_capacity = lines_capacity; buffer->filename = filename_copy; buffer->last_write_time = time_last_modified(buffer->filename); + if (!(fs_path_permission(filename) & FS_PERMISSION_WRITE)) { + // can't write to this file; make the buffer view only. + buffer->view_only = true; + } } } } else { @@ -1908,6 +1916,11 @@ void buffer_new_file(TextBuffer *buffer, char const *filename) { bool buffer_save(TextBuffer *buffer) { Settings const *settings = buffer_settings(buffer); if (!buffer->is_line_buffer && buffer->filename) { + if (buffer->view_only) { + buffer_seterr(buffer, "Can't save view-only file."); + return false; + } + FILE *out = fopen(buffer->filename, "wb"); if (out) { if (settings->auto_add_newline) { @@ -2120,7 +2133,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { V2((float)n_columns_highlighted * char_width, char_height) ); buffer_clip_rect(buffer, &hl_rect); - gl_geometry_rect(hl_rect, colors[COLOR_SELECTION_BG]); + gl_geometry_rect(hl_rect, colors[buffer->view_only ? COLOR_VIEW_ONLY_SELECTION_BG : COLOR_SELECTION_BG]); } index1 = 0; } @@ -2257,7 +2270,8 @@ void buffer_render(TextBuffer *buffer, Rect r) { if (is_on) { if (buffer_clip_rect(buffer, &cursor_rect)) { - gl_geometry_rect(cursor_rect, colors[COLOR_CURSOR]); + // draw cursor + gl_geometry_rect(cursor_rect, colors[buffer->view_only ? COLOR_VIEW_ONLY_CURSOR : COLOR_CURSOR]); } } gl_geometry_draw(); diff --git a/colors.h b/colors.h index 43becf1..a5139c7 100644 --- a/colors.h +++ b/colors.h @@ -7,11 +7,13 @@ ENUM_U16 { COLOR_HL, COLOR_CURSOR, COLOR_CURSOR_LINE_BG, + COLOR_SELECTION_BG, + COLOR_VIEW_ONLY_CURSOR, + COLOR_VIEW_ONLY_SELECTION_BG, COLOR_MATCHING_BRACKET_HL, COLOR_BORDER, COLOR_TEXT_FOLDER, COLOR_TEXT_OTHER, - COLOR_SELECTION_BG, COLOR_MENU_BACKDROP, COLOR_MENU_BG, COLOR_MENU_HL, @@ -54,6 +56,8 @@ static ColorName const color_names[COLOR_COUNT] = { {COLOR_HL, "hl"}, {COLOR_CURSOR, "cursor"}, {COLOR_CURSOR_LINE_BG, "cursor-line-bg"}, + {COLOR_VIEW_ONLY_CURSOR, "view-only-cursor"}, + {COLOR_VIEW_ONLY_SELECTION_BG, "view-only-selection-bg"}, {COLOR_MATCHING_BRACKET_HL, "matching-bracket-hl"}, {COLOR_BORDER, "border"}, {COLOR_TEXT_FOLDER, "text-folder"}, diff --git a/filesystem-posix.c b/filesystem-posix.c index ebf1407..8af0bf2 100644 --- a/filesystem-posix.c +++ b/filesystem-posix.c @@ -16,6 +16,14 @@ FsType fs_path_type(char const *path) { return FS_OTHER; } +FsPermission fs_path_permission(char const *path) { + int bits = access(path, R_OK | W_OK); + FsPermission perm = 0; + if (!(bits & R_OK)) perm |= FS_PERMISSION_READ; + if (!(bits & W_OK)) perm |= FS_PERMISSION_WRITE; + return perm; +} + bool fs_file_exists(char const *path) { return fs_path_type(path) == FS_FILE; } diff --git a/filesystem-win.c b/filesystem-win.c index f27fe82..8d7a95a 100644 --- a/filesystem-win.c +++ b/filesystem-win.c @@ -13,6 +13,8 @@ FsType fs_path_type(char const *path) { return FS_OTHER; } +#error "TODO: fs_path_permission" + bool fs_file_exists(char const *path) { return fs_path_type(path) == FS_FILE; } diff --git a/filesystem.h b/filesystem.h index 2e561cd..6325bd7 100644 --- a/filesystem.h +++ b/filesystem.h @@ -8,8 +8,15 @@ typedef enum { FS_OTHER } FsType; +enum { + FS_PERMISSION_READ = 0x01, + FS_PERMISSION_WRITE = 0x02, +}; +typedef u8 FsPermission; + // returns what kind of thing this is. FsType fs_path_type(char const *path); +FsPermission fs_path_permission(char const *path); // Does this file exist? Returns false for directories. bool fs_file_exists(char const *path); // Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist. @@ -29,5 +36,6 @@ int fs_mkdir(char const *path); // -1 if we can't get the cwd for whatever reason. int fs_get_cwd(char *buf, size_t buflen); + #endif // FILESYSTEM_H_ diff --git a/main.c b/main.c index 772a8b3..5cbbb79 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,5 @@ // @TODO: +// - open file in view-only mode menu // - split // - completion // - view-only @@ -657,6 +658,8 @@ int main(int argc, char **argv) { print("Frame (noswap): %.1f ms\n", (frame_end_noswap - frame_start) * 1000); } #endif + + SDL_SetWindowTitle(window, ted->window_title); SDL_GL_SwapWindow(window); PROFILE_TIME(frame_end); diff --git a/node.c b/node.c index 3e2c117..7ca4843 100644 --- a/node.c +++ b/node.c @@ -135,21 +135,28 @@ static void node_frame(Ted *ted, Node *node, Rect r) { // tab border gl_geometry_rect_border(tab_rect, border_thickness, colors[COLOR_BORDER]); - if (i == node->active_tab) { - // highlight active tab - gl_geometry_rect(tab_rect, colors[is_active ? COLOR_ACTIVE_TAB_HL : COLOR_HL]); - } // tab title { - char const *surround = buffer_unsaved_changes(buffer) ? "*" : ""; - strbuf_printf(tab_title, "%s%s%s", surround, filename, surround); + if (buffer_unsaved_changes(buffer)) + strbuf_printf(tab_title, "*%s*", filename); + else if (buffer->view_only) + strbuf_printf(tab_title, "VIEW %s", filename); + else + strbuf_printf(tab_title, "%s", filename); } text_state.max_x = rect_x2(tab_rect); rgba_u32_to_floats(colors[COLOR_TEXT], text_state.color); text_state.x = tab_rect.pos.x; text_state.y = tab_rect.pos.y; text_utf8_with_state(font, &text_state, tab_title); + + if (i == node->active_tab) { + // highlight active tab + gl_geometry_rect(tab_rect, colors[is_active ? COLOR_ACTIVE_TAB_HL : COLOR_HL]); + // set window title to active tab's title + strbuf_printf(ted->window_title, "ted %s", tab_title); + } } gl_geometry_draw(); diff --git a/ted.cfg b/ted.cfg index 69b2aa4..f89e7aa 100644 --- a/ted.cfg +++ b/ted.cfg @@ -119,6 +119,8 @@ cursor = #3ff # color to highlight matching brackets with matching-bracket-hl = #fda8 selection-bg = #36aa +view-only-cursor = #0d0 +view-only-selection-bg = #0a05 hl = #ccc text = #fff # less prominent text color diff --git a/ted.h b/ted.h index 15a2dca..a1150f3 100644 --- a/ted.h +++ b/ted.h @@ -136,6 +136,7 @@ typedef struct { bool modified; bool will_chain_edits; bool chaining_edits; // are we chaining undo events together? + bool view_only; float x1, y1, x2, y2; u32 nlines; u32 lines_capacity; @@ -248,6 +249,7 @@ typedef struct Ted { Node nodes[TED_MAX_NODES]; bool buffers_used[TED_MAX_BUFFERS]; TextBuffer buffers[TED_MAX_BUFFERS]; + char window_title[256]; char error[512]; char error_shown[512]; // error display in box on screen } Ted; -- cgit v1.2.3