diff options
-rw-r--r-- | buffer.c | 76 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | ted.h | 7 |
3 files changed, 69 insertions, 17 deletions
@@ -308,6 +308,13 @@ Settings *buffer_settings(TextBuffer *buffer) { return ted_get_settings(buffer->ted, buffer->path, buffer_language(buffer)); } +u8 buffer_tab_width(TextBuffer *buffer) { + return buffer_settings(buffer)->tab_width; +} + +bool buffer_indent_with_spaces(TextBuffer *buffer) { + return buffer_settings(buffer)->indent_with_spaces; +} String32 buffer_get_line(TextBuffer *buffer, u32 line_number) { Line *line = &buffer->lines[line_number]; @@ -643,6 +650,12 @@ static void buffer_remove_last_edit_if_empty(TextBuffer *buffer) { } } +u32 buffer_line_len(TextBuffer *buffer, u32 line_number) { + if (line_number >= buffer->nlines) + return 0; + return buffer->lines[line_number].len; +} + // returns true if allocation was succesful static Status buffer_line_set_len(TextBuffer *buffer, Line *line, u32 new_len) { if (new_len >= 8) { @@ -774,7 +787,7 @@ static void buffer_print(TextBuffer const *buffer) { static u32 buffer_index_to_column(TextBuffer *buffer, u32 line, u32 index) { char32_t *str = buffer->lines[line].str; u32 col = 0; - uint tab_width = buffer_settings(buffer)->tab_width; + uint tab_width = buffer_tab_width(buffer); for (u32 i = 0; i < index && i < buffer->lines[line].len; ++i) { switch (str[i]) { case '\t': { @@ -798,7 +811,7 @@ static u32 buffer_column_to_index(TextBuffer *buffer, u32 line, u32 column) { char32_t *str = buffer->lines[line].str; u32 len = buffer->lines[line].len; u32 col = 0; - uint tab_width = buffer_settings(buffer)->tab_width; + uint tab_width = buffer_tab_width(buffer); for (u32 i = 0; i < len; ++i) { switch (str[i]) { case '\t': { @@ -2001,10 +2014,9 @@ void buffer_insert_utf8_at_cursor(TextBuffer *buffer, const char *utf8) { } void buffer_insert_tab_at_cursor(TextBuffer *buffer) { - const Settings *settings = buffer_settings(buffer); - - if (settings->indent_with_spaces) { - for (int i = 0; i < settings->tab_width; ++i) + if (buffer_indent_with_spaces(buffer)) { + u16 tab_width = buffer_tab_width(buffer); + for (int i = 0; i < tab_width; ++i) buffer_insert_char_at_cursor(buffer, ' '); } else { buffer_insert_char_at_cursor(buffer, '\t'); @@ -2042,10 +2054,29 @@ void buffer_newline(TextBuffer *buffer) { } void buffer_delete_chars_at_cursor(TextBuffer *buffer, i64 nchars) { - if (buffer->selection) + if (buffer->selection) { buffer_delete_selection(buffer); - else - buffer_delete_chars_at_pos(buffer, buffer->cursor_pos, nchars); + } else { + BufferPos cursor_pos = buffer->cursor_pos; + u16 tab_width = buffer_tab_width(buffer); + bool delete_soft_tab = false; + if (buffer_indent_with_spaces(buffer) + && cursor_pos.index + tab_width <= buffer_line_len(buffer, cursor_pos.line) + && cursor_pos.index % tab_width == 0) { + delete_soft_tab = true; + // check that all characters deleted + all characters before cursor are ' ' + for (u32 i = 0; i < cursor_pos.index + tab_width; ++i) { + BufferPos p = {.line = cursor_pos.line, .index = i }; + if (buffer_char_at_pos(buffer, p) != ' ') + delete_soft_tab = false; + } + } + + if (delete_soft_tab) + nchars = tab_width; + buffer_delete_chars_at_pos(buffer, cursor_pos, nchars); + + } buffer_scroll_to_cursor(buffer); } @@ -2055,13 +2086,27 @@ i64 buffer_backspace_at_pos(TextBuffer *buffer, BufferPos *pos, i64 ntimes) { return n; } -// returns number of characters backspaced i64 buffer_backspace_at_cursor(TextBuffer *buffer, i64 ntimes) { i64 ret=0; if (buffer->selection) { ret = buffer_delete_selection(buffer); } else { BufferPos cursor_pos = buffer->cursor_pos; + // check whether to delete the "soft tab" if indent-with-spaces is enabled + u16 tab_width = buffer_tab_width(buffer); + bool delete_soft_tab = false; + if (buffer_indent_with_spaces(buffer) && cursor_pos.index > 0 + && cursor_pos.index % tab_width == 0) { + delete_soft_tab = true; + // check that all characters before cursor are ' ' + for (u32 i = 0; i + 1 < cursor_pos.index; ++i) { + BufferPos p = {.line = cursor_pos.line, .index = i }; + if (buffer_char_at_pos(buffer, p) != ' ') + delete_soft_tab = false; + } + } + if (delete_soft_tab) + ntimes = tab_width; ret = buffer_backspace_at_pos(buffer, &cursor_pos, ntimes); buffer_cursor_move_to_pos(buffer, cursor_pos); } @@ -2818,7 +2863,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { case '\n': assert(0); break; case '\r': break; // for CRLF line endings case '\t': { - uint tab_width = settings->tab_width; + uint tab_width = buffer_tab_width(buffer); do { text_char_with_state(font, &text_state, ' '); ++column; @@ -2913,13 +2958,13 @@ void buffer_render(TextBuffer *buffer, Rect r) { void buffer_indent_lines(TextBuffer *buffer, u32 first_line, u32 last_line) { assert(first_line <= last_line); - const Settings *settings = buffer_settings(buffer); buffer_start_edit_chain(buffer); for (u32 l = first_line; l <= last_line; ++l) { BufferPos pos = {.line = l, .index = 0}; - if (settings->indent_with_spaces) { - for (int i = 0; i < settings->tab_width; ++i) + if (buffer_indent_with_spaces(buffer)) { + u16 tab_width = buffer_tab_width(buffer); + for (int i = 0; i < tab_width; ++i) buffer_insert_char_at_pos(buffer, pos, ' '); } else { buffer_insert_char_at_pos(buffer, pos, '\t'); @@ -2934,8 +2979,7 @@ void buffer_dedent_lines(TextBuffer *buffer, u32 first_line, u32 last_line) { buffer_validate_line(buffer, &last_line); buffer_start_edit_chain(buffer); - const Settings *settings = buffer_settings(buffer); - const u8 tab_width = settings->tab_width; + const u8 tab_width = buffer_tab_width(buffer); for (u32 line_idx = first_line; line_idx <= last_line; ++line_idx) { Line *line = &buffer->lines[line_idx]; @@ -6,12 +6,13 @@ - texlab bug report: - textDocument/definition gives LocationLink regardless of client capabilities FUTURE FEATURES: +- doxygen documentation for ted.h - better interaction between language-specific and path-specific settings - manual.md -- better handling of backspace with space indentation - CSS highlighting - option for separate colors for read/write highlights - styles ([color] sections) +- handle non-UTF8 file by using 0xD800-0xD8FF or something for raw bytes - make go-to-definition/hover/highlight modifier key configurable - return to previous location in buffer - font setting & support for multiple fonts to cover more characters @@ -651,6 +651,10 @@ bool buffer_clip_rect(TextBuffer *buffer, Rect *r); LSP *buffer_lsp(TextBuffer *buffer); // Get the settings used for this buffer. Settings *buffer_settings(TextBuffer *buffer); +// Get tab width for this buffer +u8 buffer_tab_width(TextBuffer *buffer); +// Get whether or not to indent with spaces for this buffer. +bool buffer_indent_with_spaces(TextBuffer *buffer); // NOTE: this string will be invalidated when the line is edited!!! // only use it briefly!! String32 buffer_get_line(TextBuffer *buffer, u32 line_number); @@ -678,6 +682,9 @@ void buffer_check_valid(TextBuffer *buffer); void buffer_free(TextBuffer *buffer); // clear buffer contents void buffer_clear(TextBuffer *buffer); +// returns the length of 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 number of columns in the longest line displayed, into *cols (if not NULL) void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns); |