summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-10-15 15:23:58 -0400
committerpommicket <pommicket@gmail.com>2023-10-15 15:23:58 -0400
commita01d4de1e2feda34a20bb8dd65ec76fef3c20d6b (patch)
treec24f71d8536663d6758a14194b50508041cc03ec
parent479219152b85b2cf12e5bfee6fdebca033355beb (diff)
use reference-counted strings for string settings
this lets us remove the length limitations which were previously imposed
-rw-r--r--buffer.c6
-rw-r--r--build.c4
-rw-r--r--config.c62
-rw-r--r--node.c2
-rw-r--r--ted-internal.h18
-rw-r--r--ted.c12
-rw-r--r--util.c38
-rw-r--r--util.h19
8 files changed, 114 insertions, 47 deletions
diff --git a/buffer.c b/buffer.c
index 35330ec..56f0447 100644
--- a/buffer.c
+++ b/buffer.c
@@ -3834,7 +3834,7 @@ void buffer_dedent_cursor_line(TextBuffer *buffer) {
void buffer_comment_lines(TextBuffer *buffer, u32 first_line, u32 last_line) {
const Settings *settings = buffer_settings(buffer);
- const char *start = settings->comment_start, *end = settings->comment_end;
+ const char *start = rc_str(settings->comment_start, ""), *end = rc_str(settings->comment_end, "");
if (!start[0] && !end[0])
return;
String32 start32 = str32_from_utf8(start), end32 = str32_from_utf8(end);
@@ -3889,7 +3889,7 @@ static bool buffer_line_ends_with_ascii(TextBuffer *buffer, u32 line_idx, const
void buffer_uncomment_lines(TextBuffer *buffer, u32 first_line, u32 last_line) {
const Settings *settings = buffer_settings(buffer);
- const char *start = settings->comment_start, *end = settings->comment_end;
+ const char *start = rc_str(settings->comment_start, ""), *end = rc_str(settings->comment_end, "");
if (!start[0] && !end[0])
return;
u32 start_len = (u32)strlen(start), end_len = (u32)strlen(end);
@@ -3913,7 +3913,7 @@ void buffer_uncomment_lines(TextBuffer *buffer, u32 first_line, u32 last_line) {
void buffer_toggle_comment_lines(TextBuffer *buffer, u32 first_line, u32 last_line) {
const Settings *settings = buffer_settings(buffer);
- const char *start = settings->comment_start, *end = settings->comment_end;
+ const char *start = rc_str(settings->comment_start, ""), *end = rc_str(settings->comment_end, "");
if (!start[0] && !end[0])
return;
// if first line is a comment, uncomment lines, otherwise, comment lines
diff --git a/build.c b/build.c
index df9a140..5df00fc 100644
--- a/build.c
+++ b/build.c
@@ -104,7 +104,7 @@ void build_start_with_command(Ted *ted, const char *command) {
void build_start(Ted *ted) {
const Settings *settings = ted_active_settings(ted);
- const char *command = settings->build_command;
+ const char *command = rc_str(settings->build_command, "");
{
char *root = ted_get_root_dir(ted);
@@ -113,7 +113,7 @@ void build_start(Ted *ted) {
}
if (*command == 0) {
- command = settings->build_default_command;
+ command = rc_str(settings->build_default_command, "");
typedef struct {
const char *filename;
const char *command;
diff --git a/config.c b/config.c
index 3e9aa2a..6a12b89 100644
--- a/config.c
+++ b/config.c
@@ -61,8 +61,7 @@ typedef struct {
} SettingU32;
typedef struct {
const char *name;
- const char *control;
- size_t buf_size;
+ RcStr *const *control;
bool per_language;
} SettingString;
typedef struct {
@@ -153,15 +152,15 @@ static const SettingFloat settings_float[] = {
{"lsp-delay", &settings_zero.lsp_delay, 0, 100, true},
};
static const SettingString settings_string[] = {
- {"build-default-command", settings_zero.build_default_command, sizeof settings_zero.build_default_command, true},
- {"build-command", settings_zero.build_command, sizeof settings_zero.build_command, true},
- {"root-identifiers", settings_zero.root_identifiers, sizeof settings_zero.root_identifiers, true},
- {"lsp", settings_zero.lsp, sizeof settings_zero.lsp, true},
- {"lsp-configuration", settings_zero.lsp_configuration, sizeof settings_zero.lsp_configuration, true},
- {"comment-start", settings_zero.comment_start, sizeof settings_zero.comment_start, true},
- {"comment-end", settings_zero.comment_end, sizeof settings_zero.comment_end, true},
- {"font", settings_zero.font, sizeof settings_zero.font, false},
- {"font-bold", settings_zero.font_bold, sizeof settings_zero.font_bold, false},
+ {"build-default-command", &settings_zero.build_default_command, true},
+ {"build-command", &settings_zero.build_command, true},
+ {"root-identifiers", &settings_zero.root_identifiers, true},
+ {"lsp", &settings_zero.lsp, true},
+ {"lsp-configuration", &settings_zero.lsp_configuration, true},
+ {"comment-start", &settings_zero.comment_start, true},
+ {"comment-end", &settings_zero.comment_end, true},
+ {"font", &settings_zero.font, false},
+ {"font-bold", &settings_zero.font_bold, false},
};
static const SettingKeyCombo settings_key_combo[] = {
{"hover-key", &settings_zero.hover_key, true},
@@ -189,8 +188,9 @@ static void setting_float_set(Settings *settings, const SettingFloat *set, float
*(float *)((char *)settings + ((char*)set->control - (char*)&settings_zero)) = value;
}
static void setting_string_set(Settings *settings, const SettingString *set, const char *value) {
- char *control = (char *)settings + (set->control - (char*)&settings_zero);
- str_cpy(control, set->buf_size, value);
+ RcStr **control = (RcStr **)((char *)settings + ((char *)set->control - (char*)&settings_zero));
+ if (*control) rc_str_decref(control);
+ *control = rc_str_new(value, -1);
}
static void setting_key_combo_set(Settings *settings, const SettingKeyCombo *set, KeyCombo value) {
KeyCombo *control = (KeyCombo *)((char *)settings + ((char*)set->control - (char*)&settings_zero));
@@ -272,7 +272,11 @@ static void settings_copy(Settings *dest, const Settings *src) {
gl_rc_sab_incref(dest->bg_shader);
gl_rc_texture_incref(dest->bg_texture);
-
+ for (size_t i = 0; i < arr_count(settings_string); i++) {
+ const SettingString *s = &settings_string[i];
+ RcStr *rc = *(RcStr **)((char *)dest + ((char *)s->control - (char *)&settings_zero));
+ rc_str_incref(rc);
+ }
context_copy(&dest->context, &src->context);
dest->language_extensions = arr_copy(src->language_extensions);
dest->key_actions = arr_copy(src->key_actions);
@@ -1061,11 +1065,7 @@ static void config_parse_line(ConfigReader *cfg, Settings **applicable_settings,
} break;
case SETTING_STRING: {
const SettingString *setting = &setting_any->u._string;
- if (strlen(value) >= setting->buf_size) {
- config_err(cfg, "%s is too long (length: %zu, maximum length: %zu).", key, strlen(value), setting->buf_size - 1);
- } else {
- setting_string_set(settings, setting, value);
- }
+ setting_string_set(settings, setting, value);
} break;
case SETTING_KEY_COMBO: {
const SettingKeyCombo *setting = &setting_any->u._key;
@@ -1217,13 +1217,22 @@ static void gluint_eliminate_duplicates(GLuint **arr) {
arr_set_len(*arr, count);
}
+static void settings_free(Settings *settings) {
+ context_free(&settings->context);
+ arr_free(settings->language_extensions);
+ gl_rc_sab_decref(&settings->bg_shader);
+ gl_rc_texture_decref(&settings->bg_texture);
+ arr_free(settings->key_actions);
+ for (size_t i = 0; i < arr_count(settings_string); i++) {
+ const SettingString *s = &settings_string[i];
+ RcStr **rc = (RcStr **)((char *)settings + ((char *)s->control - (char *)&settings_zero));
+ rc_str_decref(rc);
+ }
+}
+
void config_free(Ted *ted) {
arr_foreach_ptr(ted->all_settings, Settings, settings) {
- context_free(&settings->context);
- arr_free(settings->language_extensions);
- gl_rc_sab_decref(&settings->bg_shader);
- gl_rc_texture_decref(&settings->bg_texture);
- arr_free(settings->key_actions);
+ settings_free(settings);
}
@@ -1257,13 +1266,14 @@ char *settings_get_root_dir(const Settings *settings, const char *path) {
if (entries) { // note: this may actually be NULL on the first iteration if `path` is a file
for (int e = 0; entries[e]; ++e) {
const char *entry_name = entries[e]->name;
- const char *ident_name = settings->root_identifiers;
+ const char *root_identifiers = rc_str(settings->root_identifiers, "");
+ const char *ident_name = root_identifiers;
while (*ident_name) {
const char *separators = ", \t\n\r\v";
size_t ident_len = strcspn(ident_name, separators);
if (strlen(entry_name) == ident_len && strncmp(entry_name, ident_name, ident_len) == 0) {
// we found an identifier!
- u32 score = U32_MAX - (u32)(ident_name - settings->root_identifiers);
+ u32 score = U32_MAX - (u32)(ident_name - root_identifiers);
if (score > best_path_score) {
best_path_score = score;
strbuf_cpy(best_path, pathbuf);
diff --git a/node.c b/node.c
index d7b021c..f4fe8fc 100644
--- a/node.c
+++ b/node.c
@@ -420,7 +420,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
// set window title to active tab's title
strbuf_printf(ted->window_title, "ted %s | %s", tab_title,
settings->indent_with_spaces ? "spaces" : "tabs");
- if (*settings->lsp) {
+ if (*rc_str(settings->lsp, "")) {
LSP *lsp = buffer_lsp(buffer);
strbuf_catf(ted->window_title, " | LSP %s",
lsp && lsp_is_initialized(lsp) && !lsp_has_exited(lsp)
diff --git a/ted-internal.h b/ted-internal.h
index 5594adc..fe377a4 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -151,23 +151,23 @@ struct Settings {
GlRcSAB *bg_shader;
GlRcTexture *bg_texture;
/// string used to start comments
- char comment_start[16];
+ RcStr *comment_start;
/// string used to end comments
- char comment_end[16];
+ RcStr *comment_end;
/// Comma-separated list of file names which identify the project root
- char root_identifiers[4096];
+ RcStr *root_identifiers;
/// LSP server command
- char lsp[512];
+ RcStr *lsp;
/// LSP "configuration" JSON
- char lsp_configuration[4096];
+ RcStr *lsp_configuration;
/// Build command. If non-empty, this overrides running `cargo build` if `Cargo.toml` exists, etc.
- char build_command[1024];
+ RcStr *build_command;
/// Default build command for if `Cargo.toml`, `Makefile`, etc. do not exist.
- char build_default_command[1024];
+ RcStr *build_default_command;
/// Comma separated list of paths to font files.
- char font[4096];
+ RcStr *font;
/// Comma separated list of paths to bold font files.
- char font_bold[4096];
+ RcStr *font_bold;
LanguageExtension *language_extensions;
/// dynamic array, sorted by KEY_COMBO(modifier, key)
KeyAction *key_actions;
diff --git a/ted.c b/ted.c
index d1db1fb..ee1c636 100644
--- a/ted.c
+++ b/ted.c
@@ -264,7 +264,7 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) {
if (!lsp) break;
const char *const lsp_command = lsp_get_command(lsp);
const u16 lsp_port = lsp_get_port(lsp);
- if (lsp_command && !streq(lsp_command, settings->lsp)) continue;
+ if (lsp_command && !streq(lsp_command, rc_str(settings->lsp, ""))) continue;
if (lsp_port != settings->lsp_port) continue;
if (!lsp_is_initialized(lsp)) {
@@ -286,15 +286,15 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) {
}
if (i == TED_LSP_MAX)
return NULL; // why are there so many LSP open???
- if (*settings->lsp || settings->lsp_port) {
+ if (*rc_str(settings->lsp, "") || settings->lsp_port) {
// start up this LSP
FILE *log = settings->lsp_log ? ted->log : NULL;
char *root_dir = settings_get_root_dir(settings, path);
LSPSetup setup = {
.root_dir = root_dir,
- .command = *settings->lsp ? settings->lsp : NULL,
+ .command = rc_str(settings->lsp, NULL),
.port = settings->lsp_port,
- .configuration = settings->lsp_configuration,
+ .configuration = rc_str(settings->lsp_configuration, NULL),
.log = log,
.send_delay = settings->lsp_delay,
};
@@ -434,13 +434,13 @@ void ted_load_fonts(Ted *ted) {
ted_free_fonts(ted);
const Settings *settings = ted_active_settings(ted);
- ted->font = ted_load_multifont(ted, settings->font);
+ ted->font = ted_load_multifont(ted, rc_str(settings->font, ""));
if (!ted->font) {
ted->font = ted_load_multifont(ted, "assets/font.ttf");
if (!ted->font)
die("Couldn't load default font: %s.", ted->message);
}
- ted->font_bold = ted_load_multifont(ted, settings->font_bold);
+ ted->font_bold = ted_load_multifont(ted, rc_str(settings->font_bold, ""));
if (!ted->font_bold) {
ted->font_bold = ted->font;
}
diff --git a/util.c b/util.c
index 89b3dc2..1649f91 100644
--- a/util.c
+++ b/util.c
@@ -17,6 +17,42 @@
// on 16-bit systems, this is 16383. on 32/64-bit systems, this is 1073741823
// it is unusual to have a string that long.
#define STRLEN_SAFE_MAX (UINT_MAX >> 2)
+struct RcStr {
+ u32 ref_count;
+ char str[];
+};
+
+RcStr *rc_str_new(const char *s, i64 len) {
+ if (len < 0) {
+ len = (i64)strlen(s);
+ }
+ RcStr *rc = calloc(1, sizeof(RcStr) + (size_t)len + 1);
+ assert(rc);
+ memcpy(rc->str, s, (size_t)len);
+ rc->ref_count = 1;
+ return rc;
+}
+
+void rc_str_incref(RcStr *str) {
+ if (str)
+ str->ref_count += 1;
+}
+
+void rc_str_decref(RcStr **pstr) {
+ RcStr *const str = *pstr;
+ if (!str) return;
+ str->ref_count -= 1;
+ if (str->ref_count == 0) {
+ *pstr = NULL;
+ free(str);
+ }
+}
+
+const char *rc_str(RcStr *str, const char *default_value) {
+ if (!str) return default_value;
+ assert(str->ref_count > 0);
+ return str->str;
+}
bool is32_word(char32_t c) {
return c > WCHAR_MAX || c == '_' || iswalnum((wint_t)c);
@@ -151,6 +187,8 @@ bool str_has_path_prefix(const char *path, const char *prefix) {
}
bool streq(const char *a, const char *b) {
+ assert(a);
+ assert(b);
return strcmp(a, b) == 0;
}
diff --git a/util.h b/util.h
index edbcbe3..1d60cf9 100644
--- a/util.h
+++ b/util.h
@@ -41,7 +41,26 @@ typedef struct {
size_t len;
} String32;
+/// reference-counted string
+typedef struct RcStr RcStr;
+/// allocate new ref-counted string
+///
+/// if `len == -1`, `s` is assumed to be null-terminated. otherwise,
+/// at most `len` bytes are copied from `s`.
+RcStr *rc_str_new(const char *s, i64 len);
+/// increases the reference count of `str`.
+///
+/// does nothing if `str` is `NULL`.
+void rc_str_incref(RcStr *str);
+/// decrease reference count of `*str` and set `*str` to `NULL`.
+///
+/// this frees `*str` if the reference count hits 0.
+///
+/// does nothing if `*str` is NULL.
+void rc_str_decref(RcStr **str);
+/// get rc string with default value if `s == NULL`
+const char *rc_str(RcStr *s, const char *value_if_null);
/// `isword` for 32-bit chars.
bool is32_word(char32_t c);
/// `isspace` for 32-bit chars.