summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c76
-rw-r--r--main.c3
-rw-r--r--ted.h7
3 files changed, 69 insertions, 17 deletions
diff --git a/buffer.c b/buffer.c
index 605a418..8059c4e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -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];
diff --git a/main.c b/main.c
index c7d67fe..9c63589 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/ted.h b/ted.h
index 76058af..1faf439 100644
--- a/ted.h
+++ b/ted.h
@@ -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);