From 31c1f3acc7a56683b5512620419b8989a26dad4b Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 13 Aug 2023 13:10:56 -0300 Subject: documentation --- base.h | 64 +++++++++++-------- buffer.c | 37 ++++++----- command.c | 2 +- config.c | 2 +- find.c | 4 +- main.c | 3 +- node.c | 61 +++++++++--------- syntax.c | 2 +- ted-internal.h | 18 ++++++ ted.c | 10 +-- ted.h | 191 ++++++++++++++++++++++++++++++++++----------------------- ui.c | 23 +++---- util.c | 2 +- 13 files changed, 245 insertions(+), 174 deletions(-) diff --git a/base.h b/base.h index be4031e..dfc9f2f 100644 --- a/base.h +++ b/base.h @@ -17,6 +17,7 @@ #if __GNUC__ #define FALLTHROUGH __attribute__((fallthrough)); #else +/// used to mark switch cases that can fallthrough. #define FALLTHROUGH #endif @@ -25,12 +26,11 @@ #include #include #define PATH_SEPARATOR '\\' -#define PATH_SEPARATOR_STR "\\" -// on windows, let the user use forwards slashes as well as backslashes #define ALL_PATH_SEPARATORS "\\/" #else +/// the default path separator for this OS #define PATH_SEPARATOR '/' -#define PATH_SEPARATOR_STR "/" +/// a string containing all possible path separators for this OS #define ALL_PATH_SEPARATORS "/" #endif @@ -50,52 +50,63 @@ #if __linux__ || _WIN32 #include #else -// OpenBSD has uchar.h but it doesn't seem to define char32_t ? +/// UTF-32 character +/// +/// OpenBSD has `uchar.h` but it doesn't seem to define `char32_t` ? (as of writing) typedef uint32_t char32_t; #endif #if !__TINYC__ && __STDC_VERSION__ >= 201112 #define static_assert_if_possible(cond) _Static_assert(cond, "Static assertion failed"); #else +/// perform static assertion if it's available. #define static_assert_if_possible(cond) #endif +/// 8-bit unsigned integer typedef uint8_t u8; +/// 16-bit unsigned integer typedef uint16_t u16; +/// 32-bit unsigned integer typedef uint32_t u32; +/// 64-bit unsigned integer typedef uint64_t u64; -// (for u8 and u16, you can use %u) -#define U32_FMT "%" PRIu32 -#define U64_FMT "%" PRIu64 +/// maximum value of \ref u8 #define U8_MAX 0xff +/// maximum value of \ref u16 #define U16_MAX 0xffff +/// maximum value of \ref u32 #define U32_MAX 0xffffffff +/// maximum value of \ref u64 #define U64_MAX 0xffffffffffffffff +/// 8-bit signed integer typedef int8_t i8; +/// 16-bit signed integer typedef int16_t i16; +/// 32-bit signed integer typedef int32_t i32; +/// 64-bit signed integer typedef int64_t i64; -// (for i8 and i16, you can use %d) -#define I32_FMT "%" PRId32 -#define I64_FMT "%" PRId64 +/// minimum value of \ref i8 #define I8_MIN ((i8)0x80) +/// minimum value of \ref i16 #define I16_MIN ((i16)0x8000) +/// minimum value of \ref i32 #define I32_MIN ((i32)0x80000000) +/// minimum value of \ref i64 #define I64_MIN ((i64)0x8000000000000000) +/// maximum value of \ref i8 #define I8_MAX 0x7f +/// maximum value of \ref i16 #define I16_MAX 0x7fff +/// maximum value of \ref i32 #define I32_MAX 0x7fffffff +/// maximum value of \ref i64 #define I64_MAX 0x7fffffffffffffff -typedef unsigned int uint; -typedef unsigned long ulong; - -typedef long long llong; -typedef unsigned long long ullong; - /// allows /// ``` /// switch (c) { @@ -108,6 +119,7 @@ typedef unsigned long long ullong; #ifdef __GNUC__ #define WarnUnusedResult __attribute__((warn_unused_result)) #else +/// add warn-if-unused attribute if it's available. #define WarnUnusedResult #endif @@ -124,11 +136,13 @@ typedef unsigned long long ullong; #define PRINTF_FORMAT_STRING #endif -/// this type is an alias for bool, except that it +/// this type is an alias for `bool`, except that it /// produces a warning if it's not used. -/// false = error, true = success +/// +/// `false` = error, `true` = success #define Status bool WarnUnusedResult +/// number of elements in static array #define arr_count(a) (sizeof (a) / sizeof *(a)) #ifdef __GNUC__ @@ -142,7 +156,9 @@ typedef unsigned long long ullong; #define no_warn_end _Pragma("GCC diagnostic pop") #else +/// disable compiler warnings temporarily #define no_warn_start +/// reenable compiler warnings #define no_warn_end #endif @@ -158,24 +174,24 @@ static void print(const char *fmt, ...) { } #define eprint print #else +/// print to `stdout`, or debugger output on Windows #define print printf +/// print to `stderr`, or debugger output on Windows #define eprint(...) fprintf(stderr, __VA_ARGS__) #endif +/// like \ref print, but adds a newline #define println(...) print(__VA_ARGS__), print("\n") +/// like \ref eprint, but adds a newline #define eprintln(...) eprint(__VA_ARGS__), eprint("\n") #if DEBUG #define debug_print print #define debug_println println #else +/// like \ref print, but only enabled in debug mode #define debug_print(...) +/// like \ref println, but only enabled in debug mode #define debug_println(...) #endif -#if PROFILE -#define PROFILE_TIME(var) double var = time_get_seconds(); -#else -#define PROFILE_TIME(var) -#endif - #endif // BASE_H_ diff --git a/buffer.c b/buffer.c index a33cfad..cc9fd80 100644 --- a/buffer.c +++ b/buffer.c @@ -197,6 +197,11 @@ double buffer_get_scroll_lines(TextBuffer *buffer) { return buffer->scroll_y; } +void buffer_scroll_to(TextBuffer *buffer, double cols, double lines) { + buffer->scroll_x = cols; + buffer->scroll_y = lines; +} + double buffer_last_write_time(TextBuffer *buffer) { return buffer->last_write_time; } @@ -693,7 +698,7 @@ static BufferPos buffer_pos_max(BufferPos p1, BufferPos p2) { } static void buffer_pos_print(BufferPos p) { - printf("[" U32_FMT ":" U32_FMT "]", p.line, p.index); + printf("[%" PRIu32 ":%" PRIu32 "]", p.line, p.index); } // for debugging @@ -755,7 +760,7 @@ static Status buffer_edit_create(TextBuffer *buffer, BufferEdit *edit, BufferPos static void buffer_edit_print(BufferEdit *edit) { buffer_pos_print(edit->pos); - printf(" (" U32_FMT " chars): ", edit->prev_len); + printf(" (%" PRIu32 " chars): ", edit->prev_len); for (size_t i = 0; i < edit->prev_len; ++i) { char32_t c = edit->prev_text[i]; if (c == '\n') @@ -763,7 +768,7 @@ static void buffer_edit_print(BufferEdit *edit) { else printf("%lc", (wint_t)c); } - printf(" => " U32_FMT " chars.\n", edit->new_len); + printf(" => %" PRIu32 " chars.\n", edit->new_len); } static void buffer_print_undo_history(TextBuffer *buffer) { @@ -1053,19 +1058,14 @@ static u32 buffer_xoff_to_index(TextBuffer *buffer, u32 line_number, double xoff } -void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns) { - if (lines) { - *lines = buffer->nlines; - } - if (columns) { - double longest_line = 0; - // which line on screen is the longest? - for (u32 l = buffer->first_line_on_screen; l <= buffer->last_line_on_screen && l < buffer->nlines; ++l) { - Line *line = &buffer->lines[l]; - longest_line = maxd(longest_line, buffer_index_to_xoff(buffer, l, line->len)); - } - *columns = (u32)(longest_line / text_font_char_width(buffer_font(buffer), ' ')); +u32 buffer_column_count(TextBuffer *buffer) { + double longest_line = 0; + // which line on screen is the longest? + for (u32 l = buffer->first_line_on_screen; l <= buffer->last_line_on_screen && l < buffer->nlines; ++l) { + Line *line = &buffer->lines[l]; + longest_line = maxd(longest_line, buffer_index_to_xoff(buffer, l, line->len)); } + return (u32)(longest_line / text_font_char_width(buffer_font(buffer), ' ')); } @@ -1083,8 +1083,7 @@ static void buffer_correct_scroll(TextBuffer *buffer) { buffer->scroll_x = 0; if (buffer->scroll_y < 0) buffer->scroll_y = 0; - u32 nlines, ncols; - buffer_text_dimensions(buffer, &nlines, &ncols); + u32 nlines = buffer_line_count(buffer), ncols = buffer_column_count(buffer); double max_scroll_x = (double)ncols - buffer_display_cols(buffer); max_scroll_x += 2; // allow "overscroll" (makes it so you can see the cursor when it's on the right side of the screen) double max_scroll_y = (double)nlines - buffer_display_lines(buffer); @@ -2265,7 +2264,7 @@ 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_error(buffer, "Deleting negative characters (specifically, " I64_FMT ").", nchars_); + buffer_error(buffer, "Deleting negative characters (specifically, %" PRId64 ").", nchars_); return; } if (nchars_ <= 0) return; @@ -3243,7 +3242,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { u32 cursor_line = buffer->cursor_pos.line; for (u32 line = start_line; line < nlines; ++line) { char str[32] = {0}; - strbuf_printf(str, U32_FMT, line + 1); // convert line number to string + strbuf_printf(str, "%" PRIu32, line + 1); // convert line number to string float x = x1 + line_number_width - text_get_size_vec2(font, str).x; // right justify // set color rgba_u32_to_floats(colors[line == cursor_line ? COLOR_CURSOR_LINE_NUMBER : COLOR_LINE_NUMBERS], diff --git a/command.c b/command.c index b5d2f5d..50696be 100644 --- a/command.c +++ b/command.c @@ -529,7 +529,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen break; case CMD_OPEN_CONFIG: { char local_config_filename[TED_PATH_MAX]; - strbuf_printf(local_config_filename, "%s" PATH_SEPARATOR_STR TED_CFG, ted->local_data_dir); + strbuf_printf(local_config_filename, "%s%c" TED_CFG, ted->local_data_dir, PATH_SEPARATOR); ted_open_file(ted, local_config_filename); } break; case CMD_COMMAND_SELECTOR: diff --git a/config.c b/config.c index 192549b..ff5f25c 100644 --- a/config.c +++ b/config.c @@ -494,7 +494,7 @@ static void get_config_path(Ted *ted, char *expanded, size_t expanded_sz, const expanded[0] = '\0'; if (path[0] == '~' && strchr(ALL_PATH_SEPARATORS, path[1])) { - str_printf(expanded, expanded_sz, "%s" PATH_SEPARATOR_STR "%s", ted->home, path + 1); + str_printf(expanded, expanded_sz, "%s%c%s", ted->home, PATH_SEPARATOR, path + 1); } else if (!path_is_absolute(path)) { if (!ted_get_file(ted, path, expanded, expanded_sz)) { str_cpy(expanded, expanded_sz, path); diff --git a/find.c b/find.c index 5d3bdb4..92015bc 100644 --- a/find.c +++ b/find.c @@ -431,9 +431,9 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) { char str[32]; u32 match_idx = find_match_idx(ted); if (match_idx == U32_MAX) { - strbuf_printf(str, U32_FMT " matches", arr_len(ted->find_results)); + strbuf_printf(str, "%" PRIu32 " matches", arr_len(ted->find_results)); } else { - strbuf_printf(str, U32_FMT " of " U32_FMT, match_idx + 1, arr_len(ted->find_results)); + strbuf_printf(str, "%" PRIu32 " of %" PRIu32, match_idx + 1, arr_len(ted->find_results)); } text_get_size(font, str, &w, &h); text_utf8(font, str, x2 - w, rect_ymid(find_buffer_bounds) - h * 0.5f, colors[COLOR_TEXT]); diff --git a/main.c b/main.c index 6c9b88f..de4657f 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ /* TODO: - fix find +- fix ask-reload menu (clicking "no" will probably do nothing) - public Node API - public Selector/FileSelector API - public Settings API @@ -299,7 +300,7 @@ int main(int argc, char **argv) { command_init(); color_init(); - syntax_register_builtin_languages(); + syntax_init(); // read command-line arguments int dash_dash = argc; diff --git a/node.c b/node.c index ae46a33..4382300 100644 --- a/node.c +++ b/node.c @@ -77,38 +77,37 @@ static u8 node_depth(Ted *ted, Node *node) { void node_join(Ted *ted, Node *node) { Node *parent = node_parent(ted, node); - if (parent) { - Node *a = parent->split_a; - Node *b = parent->split_b; - if (a->tabs && b->tabs) { - if (ted->active_node == a || ted->active_node == b) { - ted->active_node = parent; - } - arr_foreach_ptr(a->tabs, TextBufferPtr, tab) { - arr_add(parent->tabs, *tab); - } - arr_foreach_ptr(b->tabs, TextBufferPtr, tab) { - arr_add(parent->tabs, *tab); - } - if (!parent->tabs) { - ted_out_of_mem(ted); - return; - } - - parent->split_a = NULL; - parent->split_b = NULL; - if (node == a) { - parent->active_tab = a->active_tab; - } else { - parent->active_tab = (u16)arr_len(a->tabs) + b->active_tab; - } - node_free(a); - node_free(b); - arr_remove_item(ted->nodes, a); - arr_remove_item(ted->nodes, b); - - } + if (!parent) return; + + Node *a = parent->split_a; + Node *b = parent->split_b; + if (!(a->tabs && b->tabs)) return; + + if (ted->active_node == a || ted->active_node == b) { + ted->active_node = parent; + } + arr_foreach_ptr(a->tabs, TextBufferPtr, tab) { + arr_add(parent->tabs, *tab); + } + arr_foreach_ptr(b->tabs, TextBufferPtr, tab) { + arr_add(parent->tabs, *tab); + } + if (!parent->tabs) { + ted_out_of_mem(ted); + return; + } + + parent->split_a = NULL; + parent->split_b = NULL; + if (node == a) { + parent->active_tab = a->active_tab; + } else { + parent->active_tab = (u16)arr_len(a->tabs) + b->active_tab; } + node_free(a); + node_free(b); + arr_remove_item(ted->nodes, a); + arr_remove_item(ted->nodes, b); } void node_close(Ted *ted, Node *node) { diff --git a/syntax.c b/syntax.c index be6ebbf..53c2425 100644 --- a/syntax.c +++ b/syntax.c @@ -2066,7 +2066,7 @@ static void syntax_highlight_ted_cfg(SyntaxState *state, const char32_t *line, u } -void syntax_register_builtin_languages(void) { +void syntax_init(void) { static const LanguageInfo builtins[] = { { .id = LANG_TEXT, diff --git a/ted-internal.h b/ted-internal.h index 64b3b6e..1b34fd4 100644 --- a/ted-internal.h +++ b/ted-internal.h @@ -14,6 +14,14 @@ #include "sdl-inc.h" #include "lib/glcorearb.h" +#if PROFILE +#define PROFILE_TIME(var) double var = time_get_seconds(); +#else +/// get current time for profiling +#define PROFILE_TIME(var) +#endif + + /// Minimum text size #define TEXT_SIZE_MIN 6 /// Maximum text size @@ -718,6 +726,8 @@ void node_free(Node *node); void node_frame(Ted *ted, Node *node, Rect r); // === syntax.c === +/// register built-in languages, etc. +void syntax_init(void); /// free up resources used by `syntax.c` void syntax_quit(void); @@ -726,6 +736,10 @@ void syntax_quit(void); SymbolInfo *tags_get_symbols(Ted *ted); // === ted.c === +/// set ted's active buffer to something nice +void ted_reset_active_buffer(Ted *ted); +/// set ted's error message to the buffer's error. +void ted_error_from_buffer(Ted *ted, TextBuffer *buffer); /// Get LSP by ID. Returns NULL if there is no LSP with that ID. LSP *ted_get_lsp_by_id(Ted *ted, LSPID id); /// go to this LSP document position, opening a new buffer containing the file if necessary. @@ -747,5 +761,9 @@ void ted_check_for_node_problems(Ted *ted); void ted_load_configs(Ted *ted); /// get colors to use for message box void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_color, ColorSetting *border_color); +/// Load all the fonts ted will use, freeing any previous ones. +void ted_load_fonts(Ted *ted); +/// Free all of ted's fonts. +void ted_free_fonts(Ted *ted); #endif // TED_INTERNAL_H_ diff --git a/ted.c b/ted.c index 379217d..771f344 100644 --- a/ted.c +++ b/ted.c @@ -317,12 +317,12 @@ Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz) { return true; } if (*ted->local_data_dir) { - str_printf(out, outsz, "%s" PATH_SEPARATOR_STR "%s", ted->local_data_dir, name); + str_printf(out, outsz, "%s%c%s", ted->local_data_dir, PATH_SEPARATOR, name); if (fs_file_exists(out)) return true; } if (*ted->global_data_dir) { - str_printf(out, outsz, "%s" PATH_SEPARATOR_STR "%s", ted->global_data_dir, name); + str_printf(out, outsz, "%s%c%s", ted->global_data_dir, PATH_SEPARATOR, name); if (fs_file_exists(out)) return true; } @@ -689,9 +689,9 @@ void ted_load_configs(Ted *ted) { // copy global config to local config char local_config_filename[TED_PATH_MAX]; - strbuf_printf(local_config_filename, "%s" PATH_SEPARATOR_STR TED_CFG, ted->local_data_dir); + strbuf_printf(local_config_filename, "%s%c" TED_CFG, ted->local_data_dir, PATH_SEPARATOR); char global_config_filename[TED_PATH_MAX]; - strbuf_printf(global_config_filename, "%s" PATH_SEPARATOR_STR TED_CFG, ted->global_data_dir); + strbuf_printf(global_config_filename, "%s%c" TED_CFG, ted->global_data_dir, PATH_SEPARATOR); if (!fs_file_exists(local_config_filename)) { if (fs_file_exists(global_config_filename)) { if (!copy_file(global_config_filename, local_config_filename)) { @@ -709,7 +709,7 @@ void ted_load_configs(Ted *ted) { if (ted->search_start_cwd) { // read config in start_cwd char start_cwd_filename[TED_PATH_MAX]; - strbuf_printf(start_cwd_filename, "%s" PATH_SEPARATOR_STR TED_CFG, ted->start_cwd); + strbuf_printf(start_cwd_filename, "%s%c" TED_CFG, ted->start_cwd, PATH_SEPARATOR); config_read(ted, &parts, start_cwd_filename); } diff --git a/ted.h b/ted.h index c8aaf71..c7bb45b 100644 --- a/ted.h +++ b/ted.h @@ -97,6 +97,7 @@ enum SyntaxCharType { /// Type of syntax highlighting. typedef u8 SyntaxCharType; /// Function for syntax highlighting. +/// /// If you want to add a language to `ted`, you will need to implement this function. /// /// `state` is used to keep track of state between lines (e.g. whether or not we are in a multiline comment)\n @@ -116,7 +117,7 @@ typedef void (*SyntaxHighlightFunction)(SyntaxState *state, const char32_t *line /// for markdown #define SYNTAX_LINK SYNTAX_CONSTANT -/// Settings +/// All of ted's settings typedef struct Settings Settings; /// A buffer - this includes line buffers, unnamed buffers, the build buffer, etc. @@ -318,12 +319,14 @@ typedef u64 EditNotifyID; // === buffer.c === /// Returns `true` if the buffer is in view-only mode. bool buffer_is_view_only(TextBuffer *buffer); -/// Set whether the buffer should be in view only mode. +/// Set whether the buffer should be in view-only mode. void buffer_set_view_only(TextBuffer *buffer, bool view_only); /// amount scrolled horizontally, in terms of the width of a space character double buffer_get_scroll_columns(TextBuffer *buffer); -///n number of lines scrolled vertically +/// number of lines scrolled vertically double buffer_get_scroll_lines(TextBuffer *buffer); +/// set scroll position +void buffer_scroll_to(TextBuffer *buffer, double cols, double lines); /// get last time buffer was written to, in the format of \ref time_get_seconds double buffer_last_write_time(TextBuffer *buffer); /// get position of the cursor @@ -375,7 +378,7 @@ void line_buffer_clear_submitted(TextBuffer *buffer); char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos); /// returns the character after the cursor, or 0 if the cursor is at the end of a line char32_t buffer_char_at_cursor(TextBuffer *buffer); -/// returns the character before position `pos`, or 0 if pos is invalid or at the start of a line +/// returns the character before position `pos`, or 0 if `pos` is invalid or at the start of a line char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos); /// returns the character to the left of the cursor, or 0 if the cursor at the start of the line. char32_t buffer_char_before_cursor(TextBuffer *buffer); @@ -383,9 +386,13 @@ char32_t buffer_char_before_cursor(TextBuffer *buffer); BufferPos buffer_pos_start_of_file(TextBuffer *buffer); /// buffer position of end of file BufferPos buffer_pos_end_of_file(TextBuffer *buffer); -/// move position to matching bracket. returns the matching bracket character if there is one, otherwise returns 0 and does nothing. +/// move position to matching bracket. +/// +/// \returns the matching bracket character if there is one, or 0 otherwise. char32_t buffer_pos_move_to_matching_bracket(TextBuffer *buffer, BufferPos *pos); -/// move cursor to matching bracket. returns true if cursor was to the right of a bracket. +/// move cursor to matching bracket. +/// +/// \returns `true` if cursor was to the right of a bracket. bool buffer_cursor_move_to_matching_bracket(TextBuffer *buffer); /// ensures that `p` refers to a valid position, moving it if needed. void buffer_pos_validate(TextBuffer *buffer, BufferPos *p); @@ -393,7 +400,9 @@ void buffer_pos_validate(TextBuffer *buffer, BufferPos *p); bool buffer_pos_valid(TextBuffer *buffer, BufferPos p); /// get programming language of buffer contents Language buffer_language(TextBuffer *buffer); -/// clip the rectangle so it's all inside the buffer. returns true if there's any rectangle left. +/// clip the rectangle so it's all inside the buffer. +/// +/// \returns `true` if there's any rectangle left. bool buffer_clip_rect(TextBuffer *buffer, Rect *r); /// Get the font used for this buffer. Font *buffer_font(TextBuffer *buffer); @@ -407,30 +416,38 @@ u8 buffer_tab_width(TextBuffer *buffer); bool buffer_indent_with_spaces(TextBuffer *buffer); /// returns the number of lines in the buffer. u32 buffer_line_count(TextBuffer *buffer); -/// get line contents. does not include a newline character. +/// get line contents. +/// +/// does not include a newline character. +/// /// NOTE: this string will be invalidated when the line is edited!!! /// only use it briefly!! /// /// returns an empty string if `line_number` is out of range. String32 buffer_get_line(TextBuffer *buffer, u32 line_number); -/// get line contents. does not include a newline character. +/// get line contents as UTF-8. +/// +/// does not include a newline character. /// /// string must be freed by caller. /// returns an empty string if `line_number` is out of range. char *buffer_get_line_utf8(TextBuffer *buffer, u32 line_number); /// get at most `nchars` characters starting from position `pos`. +/// /// returns the number of characters actually available. -/// you can pass NULL for text if you just want to know how many +/// +/// you can pass `NULL` for `text` if you just want to know how many /// characters *could* be accessed before the end of the file. size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t *text, size_t nchars); /// returns a UTF-32 string of at most `nchars` code points from `buffer` starting at `pos` +/// /// the string should be passed to str32_free. String32 buffer_get_str32_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars); /// get UTF-8 string at position, up to `nchars` code points (NOT bytes). /// /// the resulting string should be freed. char *buffer_get_utf8_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars); -/// Puts a UTF-8 string containing the contents of the buffer into out. +/// Puts a UTF-8 string containing the contents of the buffer into `out`. /// /// Returns the number of bytes, including a null terminator. /// To use this function, first pass NULL for out to get the number of bytes you need to allocate. @@ -441,30 +458,30 @@ size_t buffer_contents_utf8(TextBuffer *buffer, char *out); char *buffer_contents_utf8_alloc(TextBuffer *buffer); /// clear contents, undo history, etc. of a buffer void buffer_clear(TextBuffer *buffer); -/// returns the length of the `line_number`th line (0-indexed), +/// returns the number of characters in the `line_number`th line (0-indexed), /// or 0 if `line_number` is out of range. u32 buffer_line_len(TextBuffer *buffer, u32 line_number); -/// returns the number of lines of text in the buffer into *lines (if not NULL), -/// and the number of columns of text, i.e. the width of the longest column divided by the width of the space character, into *cols (if not NULL) -void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns); -/// returns the number of rows of text that can fit in the buffer +/// returns the length of the longest on-screen line in space widths. +u32 buffer_column_count(TextBuffer *buffer); +/// returns the number of lines of text that can fit on screen in the buffer float buffer_display_lines(TextBuffer *buffer); -/// returns the number of columns of text that can fit in the buffer +/// returns the number of columns of text that can fit on screen in the buffer float buffer_display_cols(TextBuffer *buffer); /// scroll by deltas (measured in lines and columns) void buffer_scroll(TextBuffer *buffer, double dx, double dy); /// returns the screen position of the character at the given position in the buffer. vec2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos); /// convert pixel coordinates to a position in the buffer, selecting the closest character. -/// returns false if the position is not inside the buffer, but still sets *pos to the closest character. +/// +/// returns false if the position is not inside the buffer, but still sets `*pos` to the closest character. bool buffer_pixels_to_pos(TextBuffer *buffer, vec2 pixel_coords, BufferPos *pos); /// scroll to `pos`, scrolling as little as possible while maintaining scrolloff. void buffer_scroll_to_pos(TextBuffer *buffer, BufferPos pos); -/// scroll in such a way that this position is in the center of the screen +/// scroll in such a way that `pos` is in the center of the buffer's screen rectangle. void buffer_scroll_center_pos(TextBuffer *buffer, BufferPos pos); /// scroll so that the cursor is on screen void buffer_scroll_to_cursor(TextBuffer *buffer); -/// scroll so that the cursor is in the center of the buffer's rectangle. +/// scroll so that the cursor is in the center of the buffer's screen rectangle. void buffer_center_cursor(TextBuffer *buffer); /// returns the number of characters successfully moved by. i64 buffer_pos_move_left(TextBuffer *buffer, BufferPos *pos, i64 by); @@ -506,16 +523,20 @@ i64 buffer_cursor_move_right_words(TextBuffer *buffer, i64 nwords); void buffer_cursor_move_to_prev_pos(TextBuffer *buffer); /// Get the start and end index of the word at the given position. void buffer_word_span_at_pos(TextBuffer *buffer, BufferPos pos, u32 *word_start, u32 *word_end); -/// Returns a string of word characters (see is32_word) around the position, -/// or an empty string if neither of the characters to the left and right of the cursor are word characters. +/// returns a string of word characters (see \ref is32_word) around the position. +/// +/// returns an empty string if neither of the characters to the left and right of the cursor are word characters. +// /// NOTE: The string is invalidated when the buffer is changed!!! /// The return value should NOT be freed. String32 buffer_word_at_pos(TextBuffer *buffer, BufferPos pos); /// Get the word at the cursor. +/// /// NOTE: The string is invalidated when the buffer is changed!!! /// The return value should NOT be freed. String32 buffer_word_at_cursor(TextBuffer *buffer); /// Get a UTF-8 string consisting of the word at the cursor. +/// /// The return value should be freed. char *buffer_word_at_cursor_utf8(TextBuffer *buffer); /// Used for \ref CMD_INCREMENT_NUMBER and \ref CMD_DECREMENT_NUMBER @@ -603,28 +624,34 @@ void buffer_insert_utf8_at_pos(TextBuffer *buffer, BufferPos pos, const char *ut /// Insert UTF-8 text at the cursor, and move the cursor to the end of it. void buffer_insert_utf8_at_cursor(TextBuffer *buffer, const char *utf8); /// Insert a "tab" at the cursor position, and move the cursor past it. +/// /// This inserts spaces if ted is configured to indent with spaces. void buffer_insert_tab_at_cursor(TextBuffer *buffer); /// Insert a newline at the cursor position. +/// /// If `buffer` is a line buffer, this "submits" the buffer. /// If not, this auto-indents the next line, and moves the cursor to it. void buffer_newline(TextBuffer *buffer); /// Delete `nchars` characters after the cursor. void buffer_delete_chars_at_cursor(TextBuffer *buffer, i64 nchars); -/// Delete `nchars` characters before *pos, and set *pos to just before the deleted characters. -/// Returns the number of characters actually deleted. +/// Delete `nchars` characters before `*pos`, and set `*pos` to just before the deleted characters. +/// +/// \returns the number of characters actually deleted. i64 buffer_backspace_at_pos(TextBuffer *buffer, BufferPos *pos, i64 nchars); /// Delete `nchars` characters before the cursor position, and set the cursor position accordingly. -/// Returns the number of characters actually deleted. +/// +/// \returns the number of characters actually deleted. i64 buffer_backspace_at_cursor(TextBuffer *buffer, i64 nchars); /// Delete `nwords` words after the position. void buffer_delete_words_at_pos(TextBuffer *buffer, BufferPos pos, i64 nwords); /// Delete `nwords` words after the cursor. void buffer_delete_words_at_cursor(TextBuffer *buffer, i64 nwords); -/// Delete `nwords` words before *pos, and set *pos to just before the deleted words. +/// Delete `nwords` words before `*pos`, and set `*pos` to just before the deleted words. +/// /// Returns the number of words actually deleted. void buffer_backspace_words_at_pos(TextBuffer *buffer, BufferPos *pos, i64 nwords); /// Delete `nwords` words before the cursor position, and set the cursor position accordingly. +/// /// Returns the number of words actually deleted. void buffer_backspace_words_at_cursor(TextBuffer *buffer, i64 nwords); /// Undo `ntimes` times @@ -643,17 +670,19 @@ void buffer_copy(TextBuffer *buffer); void buffer_cut(TextBuffer *buffer); /// Insert the clipboard contents at the cursor position. void buffer_paste(TextBuffer *buffer); -/// Load the file `path`. If `path` is not an absolute path, -/// this function will fail. +/// Load the file at absolute path `path`. bool buffer_load_file(TextBuffer *buffer, const char *path); /// Reloads the file loaded in the buffer. void buffer_reload(TextBuffer *buffer); /// has this buffer been changed by another program since last save? bool buffer_externally_changed(TextBuffer *buffer); /// Clear `buffer`, and set its path to `path`. +/// /// if `path` is NULL, this will turn `buffer` into an untitled buffer. void buffer_new_file(TextBuffer *buffer, const char *path); -/// Save the buffer to its current filename. This will rewrite the entire file, +/// Save the buffer to its current filename. +/// +/// This will rewrite the entire file, /// even if there are no unsaved changes. bool buffer_save(TextBuffer *buffer); /// Save, but with a different path. @@ -698,7 +727,7 @@ bool buffer_pos_eq(BufferPos p1, BufferPos p2); /// /// faster than \ref buffer_pos_diff (constant time) int buffer_pos_cmp(BufferPos p1, BufferPos p2); -/// returns "`p2 - p1`", that is, the number of characters between `p1` and `p2`, +/// returns `p2 - p1`, that is, the number of characters between `p1` and `p2`, /// but negative if `p1` comes after `p2`. i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2); @@ -735,6 +764,7 @@ void build_check_for_errors(Ted *ted); ColorSetting color_setting_from_str(const char *str); /// get string corresponding to color setting const char *color_setting_to_str(ColorSetting s); +/// parse color (e.g. `"#ff0000"`) Status color_from_str(const char *str, u32 *color); /// perform alpha blending with `bg` and `fg`. u32 color_blend(u32 bg, u32 fg); @@ -752,8 +782,8 @@ void command_execute(Ted *ted, Command c, i64 argument); void command_execute_string_argument(Ted *ted, Command c, const char *string); // === config.c === -/// returns the best guess for the root directory of the project containing `path` -/// (which should be an absolute path). +/// returns the best guess for the root directory of the project containing absolute path `path`. +/// /// the return value should be freed. char *settings_get_root_dir(Settings *settings, const char *path); @@ -841,7 +871,7 @@ const char *document_link_at_buffer_pos(Ted *ted, BufferPos pos); void hover_reset_timer(Ted *ted); // === ide-rename-symbol.c === -/// renname symbol at cursor of `buffer` to `new_name` +/// rename symbol at cursor of `buffer` to `new_name` void rename_symbol_at_cursor(Ted *ted, TextBuffer *buffer, const char *new_name); // === ide-signature-help.c === @@ -887,18 +917,20 @@ void *menu_get_context(Ted *ted); bool menu_is_open(Ted *ted, const char *menu_name); /// is any menu open? bool menu_is_any_open(Ted *ted); -/// process a :escape command (by default this happens when the escape key is pressed) +/// process a `:escape` command for the currently open menu void menu_escape(Ted *ted); /// get rectangle which menu takes up Rect menu_rect(Ted *ted); // === node.c === /// go to the `n`th next tab (e.g. `n=1` goes to the next tab) +/// /// going past the end of the tabs will "wrap around" to the first one. /// /// if `node` is a split, nothing happens. void node_tab_next(Ted *ted, Node *node, i32 n); /// go to the `n`th previous tab (e.g. `n=1` goes to the previous tab) +/// /// going before the first tab will "wrap around" to the last one. /// /// if `node` is a split, nothing happens. @@ -925,7 +957,7 @@ u32 node_tab_count(Ted *ted, Node *node); /// returns `NULL` if `tab` is out of range. TextBuffer *node_tab_get(Ted *ted, Node *node, u32 tab); */ -/// returns parent node, or NULL if this is the root node. +/// returns parent node, or `NULL` if this is the root node. Node *node_parent(Ted *ted, Node *node); /// join this node with its sibling void node_join(Ted *ted, Node *node); @@ -956,8 +988,6 @@ void session_read(Ted *ted); /// /// this should be done before loading configs so language-specific settings are recognized properly. void syntax_register_language(const LanguageInfo *info); -/// register ted's built-in languages. -void syntax_register_builtin_languages(void); /// returns `true` if `language` is a valid language ID bool language_is_valid(Language language); /// read language name from `str`. returns `LANG_NONE` if `str` is invalid. @@ -966,22 +996,26 @@ Language language_from_str(const char *str); const char *language_to_str(Language language); /// get the color setting associated with the given syntax highlighting type ColorSetting syntax_char_type_to_color_setting(SyntaxCharType t); -/// returns ')' for '(', '[' for ']', etc., or 0 if c is not a bracket +/// returns ')' for '(', '[' for ']', etc., or 0 if `c` is not a bracket char32_t syntax_matching_bracket(Language lang, char32_t c); /// returns true for opening brackets, false for closing brackets/non-brackets bool syntax_is_opening_bracket(Language lang, char32_t c); -/// This is the main syntax highlighting function. It will determine which colors to use for each character. -/// Rather than returning colors, it returns a character type (e.g. comment) which can be converted to a color. -/// To highlight multiple lines, start out with a zeroed SyntaxState, and pass a pointer to it each time. -/// You can set char_types to NULL if you just want to advance the state, and don't care about the character types. +/// main syntax highlighting function. +/// +/// determines which colors to use for each character. +/// +/// To highlight multiple lines, start out with a zeroed \ref SyntaxState, and pass a pointer to it each time. +/// You can set `char_types` to `NULL` if you just want to advance the state, and don't care about the character types. void syntax_highlight(SyntaxState *state, Language lang, const char32_t *line, u32 line_len, SyntaxCharType *char_types); // === tags.c === +/// generate tags file void tags_generate(Ted *ted, bool run_in_build_window); -/// find all tags beginning with the given prefix, returning them into `*out`, writing at most out_size entries. -/// you may pass NULL for `out`, in which case just the number of matching tags is returned +/// find all tags beginning with the given prefix, returning them into `out[0..out_size]`. +/// +/// you can pass NULL for `out`, in which case just the number of matching tags is returned /// (still maxing out at `out_size`). -/// each element in `out` should be freed when you're done with them. +/// each element in `out` should be freed when you're done with it. size_t tags_beginning_with(Ted *ted, const char *prefix, char **out, size_t out_size, bool error_if_tags_does_not_exist); /// go to the definition of the given tag bool tag_goto(Ted *ted, const char *tag); @@ -1027,11 +1061,11 @@ void ted_info(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRI void ted_log(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); /// set error to "out of memory" message. void ted_out_of_mem(Ted *ted); -/// allocate memory, producing an error message and returning NULL on failure +/// allocate memory, producing an error message and returning `NULL` on failure void *ted_malloc(Ted *ted, size_t size); -/// allocate memory, producing an error message and returning NULL on failure +/// allocate memory, producing an error message and returning `NULL` on failure void *ted_calloc(Ted *ted, size_t n, size_t size); -/// allocate memory, producing an error message and returning NULL on failure +/// allocate memory, producing an error message and returning `NULL` on failure void *ted_realloc(Ted *ted, void *p, size_t new_size); /// get width of menu (e.g. "open file" menu) in pixels float ted_get_menu_width(Ted *ted); @@ -1039,13 +1073,9 @@ float ted_get_menu_width(Ted *ted); /// (i.e. look for it in the local and global data directories), /// and return the full path. Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz); -/// get full path relative to ted->cwd. +/// get full path relative to ted working directory. void ted_path_full(Ted *ted, const char *relpath, char *abspath, size_t abspath_size); -/// set ted->active_buffer to something nice -void ted_reset_active_buffer(Ted *ted); -/// set ted's error message to the buffer's error. -void ted_error_from_buffer(Ted *ted, TextBuffer *buffer); -/// Returns the buffer containing the file at absolute path `path`, or NULL if there is none. +/// Returns the buffer containing the file at absolute path `path`, or `NULL` if there is none. TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path); /// close this buffer, discarding unsaved changes. void ted_close_buffer(Ted *ted, TextBuffer *buffer); @@ -1057,17 +1087,17 @@ bool ted_close_buffer_with_file(Ted *ted, const char *path); bool ted_save_all(Ted *ted); /// reload all buffers from their files void ted_reload_all(Ted *ted); -/// Load all the fonts ted will use, freeing any previous ones. -void ted_load_fonts(Ted *ted); -/// Change ted's font size. Avoid calling this super often since it trashes all current font textures. +/// Change ted's font size. +/// +/// Avoid calling this super often since it trashes all current font textures. void ted_change_text_size(Ted *ted, float new_size); -/// Free all of ted's fonts. -void ted_free_fonts(Ted *ted); /// Get likely root directory of project containing `path`. +/// /// The returned value should be freed. char *ted_get_root_dir_of(Ted *ted, const char *path); /// Get the root directory of the project containing the active buffer's file, /// or `ted->cwd` if no file is open. +/// /// The returned value should be freed. char *ted_get_root_dir(Ted *ted); /// the settings of the active buffer, or the default settings if there is no active buffer @@ -1075,27 +1105,31 @@ Settings *ted_active_settings(Ted *ted); /// Get the settings for a file at the given path in the given language. Settings *ted_get_settings(Ted *ted, const char *path, Language language); /// Get LSP which should be used for the given path and language. +/// /// If no running LSP server would cover the path and language, a new one is /// started if possible. -/// Returns NULL on failure (e.g. there is no LSP server +/// Returns `NULL` on failure (e.g. there is no LSP server /// specified for the given path and language). struct LSP *ted_get_lsp(Ted *ted, const char *path, Language language); -/// Get the LSP of the active buffer/ted->cwd. -/// Returns NULL if there is no such server. +/// Get the LSP of the active buffer or directory. +/// +/// Returns `NULL` if there is no such server. struct LSP *ted_active_lsp(Ted *ted); -/// get the value of the given color setting, according to `ted_active_settings(ted)`. +/// get the value of the given color setting, according to \ref ted_active_settings. u32 ted_active_color(Ted *ted, ColorSetting color); /// open the given file, or switch to it if it's already open. +/// /// returns true on success. bool ted_open_file(Ted *ted, const char *filename); /// create a new buffer for the file `filename`, or open it if it's already open. -/// if `filename` is NULL, this creates an untitled buffer. +/// +/// if `filename` is `NULL`, this creates an untitled buffer. +/// /// returns true on success. bool ted_new_file(Ted *ted, const char *filename); /// save all changes to all buffers with unsaved changes. bool ted_save_all(Ted *ted); -/// sets the active buffer to this buffer, and updates active_node, etc. accordingly -/// you can pass NULL to buffer to make it so no buffer is active. +/// sets the active buffer to this buffer void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer); /// switch to this node void ted_node_switch(Ted *ted, Node *node); @@ -1104,7 +1138,8 @@ void ted_reload_configs(Ted *ted); /// handle a key press void ted_press_key(Ted *ted, i32 keycode, u32 modifier); /// get the buffer and buffer position where the mouse is. -/// returns false if the mouse is not in a buffer. +/// +/// returns `false` if the mouse is not in a buffer. Status ted_get_mouse_buffer_pos(Ted *ted, TextBuffer **pbuffer, BufferPos *ppos); /// make the cursor red for a bit to indicate an error (e.g. no autocompletions) void ted_flash_error_cursor(Ted *ted); @@ -1112,9 +1147,11 @@ void ted_flash_error_cursor(Ted *ted); float ted_line_buffer_height(Ted *ted); /// add a \ref EditNotify callback which will be called whenever `buffer` is edited. /// -/// returns an ID which can be used with \ref ted_remove_edit_notify +/// \returns an ID which can be used with \ref ted_remove_edit_notify EditNotifyID ted_add_edit_notify(Ted *ted, EditNotify notify, void *context); -/// remove edit notify callback. if `id` is zero or invalid, no action is taken. +/// remove edit notify callback. +/// +/// if `id` is zero or invalid, no action is taken. void ted_remove_edit_notify(Ted *ted, EditNotifyID id); // === ui.c === @@ -1124,18 +1161,18 @@ void selector_up(Ted *ted, Selector *s, i64 n); void selector_down(Ted *ted, Selector *s, i64 n); /// sort entries alphabetically void selector_sort_entries_by_name(Selector *s); -/// returns a null-terminated UTF-8 string of the entry selected, or NULL if none was. +/// returns a null-terminated UTF-8 string of the entry selected, or `NULL` if none was. /// -/// also, sel->cursor will be set to the index of the entry, even if the mouse was used. -/// you should call free() on the return value. +/// also, the cursor will be set to the index of the entry, even if the mouse was used. +/// you should free the return value. char *selector_update(Ted *ted, Selector *s); /// render selector /// /// NOTE: also renders the line buffer void selector_render(Ted *ted, Selector *s); -/// free resources uesd by file selecor +/// free resources used by file selector void file_selector_free(FileSelector *fs); -/// returns the name of the selected file, or NULL if none was selected. +/// returns the name of the selected file, or `NULL` if none was selected. /// /// the returned pointer should be freed. char *file_selector_update(Ted *ted, FileSelector *fs); @@ -1145,13 +1182,13 @@ void file_selector_render(Ted *ted, FileSelector *fs); vec2 button_get_size(Ted *ted, const char *text); /// render button void button_render(Ted *ted, Rect button, const char *text, u32 color); -/// returns true if the button was clicked on. +/// returns `true` if the button was clicked on. bool button_update(Ted *ted, Rect button); -/// returns selected option, or POPUP_NONE if none was selected +/// returns selected option, or 0 if none was selected PopupOption popup_update(Ted *ted, u32 options); /// render popup menu. /// -/// `options` should be a bitwise or of the POPUP_* constants. +/// `options` should be a bitwise-or of the `POPUP_*` constants. void popup_render(Ted *ted, u32 options, const char *title, const char *body); /// update and render checkbox vec2 checkbox_frame(Ted *ted, bool *value, const char *label, vec2 pos); diff --git a/ui.c b/ui.c index b47694d..9481df6 100644 --- a/ui.c +++ b/ui.c @@ -253,11 +253,11 @@ static Status file_selector_cd1(Ted *ted, FileSelector *fs, const char *name, si } } else { char path[TED_PATH_MAX]; - // join fs->cwd with name to get full path - str_printf(path, TED_PATH_MAX, "%s%s%*s", cwd, - cwd[strlen(cwd) - 1] == PATH_SEPARATOR ? - "" : PATH_SEPARATOR_STR, - (int)name_len, name); + strbuf_cpy(path, cwd); + if (path[strlen(path) - 1] != PATH_SEPARATOR) + strbuf_catf(path, "%c", PATH_SEPARATOR); + strbuf_catf(path, "%*s", (int)name_len, name); + if (fs_path_type(path) != FS_DIRECTORY) { // trying to cd to something that's not a directory! return false; @@ -281,7 +281,7 @@ static Status file_selector_cd1(Ted *ted, FileSelector *fs, const char *name, si // add path separator to end if not already there (which could happen in the case of /) if (cwd[strlen(cwd) - 1] != PATH_SEPARATOR) - str_cat(cwd, sizeof fs->cwd, PATH_SEPARATOR_STR); + str_catf(cwd, sizeof fs->cwd, "%c", PATH_SEPARATOR); // add name itself strn_cat(cwd, sizeof fs->cwd, name, name_len); } @@ -297,10 +297,11 @@ static Status file_selector_cd_(Ted *ted, FileSelector *fs, const char *path, in // absolute path (e.g. /foo, c:\foo) // start out by replacing cwd with the start of the absolute path if (path[0] == PATH_SEPARATOR) { - char new_cwd[TED_PATH_MAX]; + char root[TED_PATH_MAX]; // necessary because the full path of \ on windows isn't just \, it's c:\ or something - ted_path_full(ted, PATH_SEPARATOR_STR, new_cwd, sizeof new_cwd); - strcpy(cwd, new_cwd); + char pathsep[] = {PATH_SEPARATOR, '\0'}; + ted_path_full(ted, pathsep, root, sizeof root); + strcpy(cwd, root); path += 1; } #if _WIN32 @@ -315,11 +316,11 @@ static Status file_selector_cd_(Ted *ted, FileSelector *fs, const char *path, in const char *p = path; while (*p) { - size_t len = strcspn(p, PATH_SEPARATOR_STR); + size_t len = strcspn(p, ALL_PATH_SEPARATORS); if (!file_selector_cd1(ted, fs, p, len, symlink_depth)) return false; p += len; - p += strspn(p, PATH_SEPARATOR_STR); + p += strspn(p, ALL_PATH_SEPARATORS); } return true; diff --git a/util.c b/util.c index 7d5a853..2be0f19 100644 --- a/util.c +++ b/util.c @@ -451,7 +451,7 @@ void path_full(const char *dir, const char *relpath, char *abspath, size_t abspa } } else { if (len == 0 || abspath[len - 1] != PATH_SEPARATOR) - str_cat(abspath, abspath_size, PATH_SEPARATOR_STR); + str_catf(abspath, abspath_size, "%c", PATH_SEPARATOR); strn_cat(abspath, abspath_size, relpath, component_len); } if (*component_end == 0) -- cgit v1.2.3