summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c65
-rw-r--r--config.c3
-rw-r--r--menu.c4
-rw-r--r--node.c7
-rw-r--r--ted-internal.h1
-rw-r--r--ted.cfg8
-rw-r--r--ui.c6
7 files changed, 84 insertions, 10 deletions
diff --git a/buffer.c b/buffer.c
index 9ef2467..63755d2 100644
--- a/buffer.c
+++ b/buffer.c
@@ -77,6 +77,14 @@ struct TextBuffer {
/// If set to true, buffer will be scrolled to the cursor position next frame.
/// This is to fix the problem that \ref x1, \ref y1, \ref x2, \ref y2 are not updated until the buffer is rendered.
bool center_cursor_next_frame;
+ /// whether to indent with spaces
+ ///
+ /// this is either set according to the user's settings or according to the autodetected indentation
+ bool indent_with_spaces;
+ /// tab size
+ ///
+ /// this is either set according to the user's settings or according to the autodetected indentation
+ uint8_t tab_width;
/// x coordinate of left side of buffer
float x1;
/// y coordinate of top side of buffer
@@ -359,6 +367,10 @@ static char *buffer_strdup(TextBuffer *buffer, const char *src) {
static void buffer_set_up(Ted *ted, TextBuffer *buffer) {
buffer->store_undo_events = true;
buffer->ted = ted;
+ // will be overwritten by buffer_new_file, buffer_load_file for file buffers
+ const Settings *settings = buffer_settings(buffer);
+ buffer->indent_with_spaces = settings->indent_with_spaces;
+ buffer->tab_width = settings->tab_width;
}
static void line_buffer_set_up(Ted *ted, TextBuffer *buffer) {
@@ -544,11 +556,11 @@ void buffer_recompute_settings(TextBuffer *buffer) {
}
u8 buffer_tab_width(TextBuffer *buffer) {
- return buffer_settings(buffer)->tab_width;
+ return buffer->tab_width;
}
bool buffer_indent_with_spaces(TextBuffer *buffer) {
- return buffer_settings(buffer)->indent_with_spaces;
+ return buffer->indent_with_spaces;
}
u32 buffer_line_count(TextBuffer *buffer) {
@@ -2965,6 +2977,50 @@ void buffer_paste(TextBuffer *buffer) {
}
}
+static void buffer_detect_indentation(TextBuffer *buffer) {
+ const Settings *settings = buffer_settings(buffer);
+ if (settings->autodetect_indentation && buffer->nlines > 1) {
+ bool use_tabs = false;
+ uint32_t spcs2 = 0, spcs4 = 0, spcs8 = 0;
+ for (uint32_t i = 0; i < buffer->nlines; i++) {
+ const Line *line = &buffer->lines[i];
+ if (line->len == 0) continue;
+ if (line->str[0] == '\t') {
+ use_tabs = true;
+ break;
+ }
+ uint32_t nspc = 0;
+ for (nspc = 0; nspc < line->len; nspc++) {
+ if (line->str[nspc] != ' ') {
+ break;
+ }
+ }
+ spcs2 += nspc == 2;
+ spcs4 += nspc == 4;
+ spcs8 += nspc == 8;
+ }
+ if (use_tabs) {
+ buffer->indent_with_spaces = false;
+ buffer->tab_width = settings->tab_width;
+ } else if (spcs2 * 50 > spcs4) {
+ buffer->indent_with_spaces = true;
+ buffer->tab_width = 2;
+ } else if (spcs4 * 50 > spcs8) {
+ buffer->indent_with_spaces = true;
+ buffer->tab_width = 4;
+ } else if (spcs8) {
+ buffer->indent_with_spaces = true;
+ buffer->tab_width = 8;
+ } else {
+ buffer->indent_with_spaces = settings->indent_with_spaces;
+ buffer->tab_width = settings->tab_width;
+ }
+ } else {
+ buffer->indent_with_spaces = settings->indent_with_spaces;
+ buffer->tab_width = settings->tab_width;
+ }
+}
+
// if an error occurs, buffer is left untouched (except for the error field) and the function returns false.
Status buffer_load_file(TextBuffer *buffer, const char *path) {
if (!unicode_is_valid_utf8(path)) {
@@ -3097,6 +3153,7 @@ Status buffer_load_file(TextBuffer *buffer, const char *path) {
buffer_error(buffer, "Couldn't open file %s: %s.", path, strerror(errno));
success = false;
}
+ buffer_detect_indentation(buffer);
return success;
}
@@ -3137,6 +3194,9 @@ void buffer_new_file(TextBuffer *buffer, const char *path) {
buffer->lines_capacity = 4;
buffer->lines = buffer_calloc(buffer, buffer->lines_capacity, sizeof *buffer->lines);
buffer->nlines = 1;
+ const Settings *settings = buffer_settings(buffer);
+ buffer->indent_with_spaces = settings->indent_with_spaces;
+ buffer->tab_width = settings->tab_width;
}
static bool buffer_write_to_file(TextBuffer *buffer, const char *path) {
@@ -3295,6 +3355,7 @@ bool buffer_save_as(TextBuffer *buffer, const char *new_path) {
buffer->last_lsp_check = -INFINITY;
// we'll send a didOpen the next time buffer_lsp is called.
free(prev_path);
+ buffer_detect_indentation(buffer);
return true;
} else {
free(buffer->path);
diff --git a/config.c b/config.c
index 4eb536a..7bdcc7c 100644
--- a/config.c
+++ b/config.c
@@ -95,6 +95,7 @@ static const SettingBool settings_bool[] = {
{"auto-reload", &settings_zero.auto_reload, true},
{"auto-reload-config", &settings_zero.auto_reload_config, false},
{"syntax-highlighting", &settings_zero.syntax_highlighting, true},
+ {"autodetect-indentation", &settings_zero.autodetect_indentation, true},
{"line-numbers", &settings_zero.line_numbers, true},
{"restore-session", &settings_zero.restore_session, false},
{"regenerate-tags-if-not-found", &settings_zero.regenerate_tags_if_not_found, true},
@@ -115,7 +116,7 @@ static const SettingBool settings_bool[] = {
#define SETTING_CRLF {"crlf", &settings_zero.crlf, true}
SETTING_CRLF,
#define SETTING_CRLF_WINDOWS {"crlf-windows", &settings_zero.crlf_windows, true}
- {"crlf-windows", &settings_zero.crlf_windows, true},
+ SETTING_CRLF_WINDOWS,
{"jump-to-build-error", &settings_zero.jump_to_build_error, true},
{"force-monospace", &settings_zero.force_monospace, true},
{"show-diagnostics", &settings_zero.show_diagnostics, true},
diff --git a/menu.c b/menu.c
index 7c7f16f..dce442b 100644
--- a/menu.c
+++ b/menu.c
@@ -540,7 +540,7 @@ void menu_init(Ted *ted) {
ted_add_edit_notify(ted, menu_edit_notify, ted);
ted->command_selector = selector_new();
- for (Command c = 0; c < CMD_COUNT; ++c) {
+ for (Command c = 0; c < CMD_COUNT; ++c) {
const char *name = command_to_str(c);
if (c != CMD_UNKNOWN && *name) {
SelectorEntry entry = {
@@ -548,7 +548,7 @@ void menu_init(Ted *ted) {
};
selector_add_entry(ted->command_selector, &entry);
}
- }
+ }
MenuInfo save_as_menu = {
.open = save_as_menu_open,
diff --git a/node.c b/node.c
index f4fe8fc..8f32087 100644
--- a/node.c
+++ b/node.c
@@ -418,8 +418,11 @@ void node_frame(Ted *ted, Node *node, Rect r) {
// highlight active tab
gl_geometry_rect(tab_rect, settings_color(settings, is_active ? COLOR_ACTIVE_TAB_HL : COLOR_SELECTED_TAB_HL));
// set window title to active tab's title
- strbuf_printf(ted->window_title, "ted %s | %s", tab_title,
- settings->indent_with_spaces ? "spaces" : "tabs");
+ strbuf_printf(ted->window_title, "ted %s | ", tab_title);
+ if (buffer_indent_with_spaces(buffer))
+ strbuf_catf(ted->window_title, "%u spaces", buffer_tab_width(buffer));
+ else
+ strbuf_catf(ted->window_title, "tabs");
if (*rc_str(settings->lsp, "")) {
LSP *lsp = buffer_lsp(buffer);
strbuf_catf(ted->window_title, " | LSP %s",
diff --git a/ted-internal.h b/ted-internal.h
index c8a72c3..f5e3211 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -121,6 +121,7 @@ struct Settings {
bool jump_to_build_error;
bool force_monospace;
bool show_diagnostics;
+ bool autodetect_indentation;
KeyCombo hover_key;
KeyCombo highlight_key;
u8 tab_width;
diff --git a/ted.cfg b/ted.cfg
index 702284b..ea59963 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -3,6 +3,14 @@
[core]
tab-width = 4
indent-with-spaces = off
+# if enabled, indentation type will be automatically detected from file when possible
+# how this currently works:
+# 1. if any lines start with a tab character, tabs are used
+# 2. otherwise, if # 4-spaced lines / 50 < # 2-spaced lines, 2 spaces are used
+# 3. otherwise, if # 8-spaced lines / 50 < # 4-spaced lines, 4 spaces are used
+# 4. otherwise, if any lines start with exactly 8 spaces, 8 spaces are used
+# 5. otherwise, your default settings are used
+autodetect-indentation = on
# cursor width in pixels
cursor-width = 1
# time to blink cursor for (i.e. it will be on for cursor-blink-time-on seconds, then off for cursor-blink-time-off seconds)
diff --git a/ui.c b/ui.c
index 995c631..2af72fa 100644
--- a/ui.c
+++ b/ui.c
@@ -501,9 +501,9 @@ static bool file_selector_cd(Ted *ted, FileSelector *fs, const char *path) {
static ColorSetting color_setting_for_file_type(FsType type) {
switch (type) {
- case FS_FILE: return COLOR_TEXT;
- case FS_DIRECTORY: return COLOR_TEXT_FOLDER;
- default: return COLOR_TEXT_OTHER;
+ case FS_FILE: return COLOR_TEXT;
+ case FS_DIRECTORY: return COLOR_TEXT_FOLDER;
+ default: return COLOR_TEXT_OTHER;
}
}