summaryrefslogtreecommitdiff
path: root/examples/dte/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/dte/config.c')
-rw-r--r--examples/dte/config.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/examples/dte/config.c b/examples/dte/config.c
new file mode 100644
index 0000000..dd24465
--- /dev/null
+++ b/examples/dte/config.c
@@ -0,0 +1,185 @@
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "commands.h"
+#include "editor.h"
+#include "error.h"
+#include "syntax/color.h"
+#include "util/debug.h"
+#include "util/readfile.h"
+#include "util/str-util.h"
+#include "../build/builtin-config.h"
+
+ConfigState current_config;
+
+// Odd number of backslashes at end of line?
+static bool has_line_continuation(StringView line)
+{
+ ssize_t pos = line.length - 1;
+ while (pos >= 0 && line.data[pos] == '\\') {
+ pos--;
+ }
+ return (line.length - 1 - pos) & 1;
+}
+
+UNITTEST {
+ BUG_ON(has_line_continuation(string_view(NULL, 0)));
+ BUG_ON(has_line_continuation(strview_from_cstring("0")));
+ BUG_ON(!has_line_continuation(strview_from_cstring("1 \\")));
+ BUG_ON(has_line_continuation(strview_from_cstring("2 \\\\")));
+ BUG_ON(!has_line_continuation(strview_from_cstring("3 \\\\\\")));
+ BUG_ON(has_line_continuation(strview_from_cstring("4 \\\\\\\\")));
+}
+
+void exec_config(CommandRunner *runner, StringView config)
+{
+ String buf = string_new(1024);
+
+ for (size_t i = 0, n = config.length; i < n; current_config.line++) {
+ StringView line = buf_slice_next_line(config.data, &i, n);
+ strview_trim_left(&line);
+ if (buf.len == 0 && strview_has_prefix(&line, "#")) {
+ // Comment line
+ continue;
+ }
+ if (has_line_continuation(line)) {
+ line.length--;
+ string_append_strview(&buf, &line);
+ } else {
+ string_append_strview(&buf, &line);
+ handle_command(runner, string_borrow_cstring(&buf));
+ string_clear(&buf);
+ }
+ }
+
+ if (unlikely(buf.len)) {
+ // This can only happen if the last line had a line continuation
+ handle_command(runner, string_borrow_cstring(&buf));
+ }
+
+ string_free(&buf);
+}
+
+String dump_builtin_configs(void)
+{
+ String str = string_new(1024);
+ for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
+ string_append_cstring(&str, builtin_configs[i].name);
+ string_append_byte(&str, '\n');
+ }
+ return str;
+}
+
+const BuiltinConfig *get_builtin_config(const char *name)
+{
+ for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
+ if (streq(name, builtin_configs[i].name)) {
+ return &builtin_configs[i];
+ }
+ }
+ return NULL;
+}
+
+const BuiltinConfig *get_builtin_configs_array(size_t *nconfigs)
+{
+ *nconfigs = ARRAYLEN(builtin_configs);
+ return &builtin_configs[0];
+}
+
+int do_read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
+{
+ const bool must_exist = flags & CFG_MUST_EXIST;
+ const bool builtin = flags & CFG_BUILTIN;
+
+ if (builtin) {
+ const BuiltinConfig *cfg = get_builtin_config(filename);
+ int err = 0;
+ if (cfg) {
+ current_config.file = filename;
+ current_config.line = 1;
+ exec_config(runner, cfg->text);
+ } else if (must_exist) {
+ error_msg (
+ "Error reading '%s': no built-in config exists for that path",
+ filename
+ );
+ err = 1;
+ }
+ return err;
+ }
+
+ char *buf;
+ ssize_t size = read_file(filename, &buf);
+ if (size < 0) {
+ int err = errno;
+ if (err != ENOENT || must_exist) {
+ error_msg("Error reading %s: %s", filename, strerror(err));
+ }
+ return err;
+ }
+
+ current_config.file = filename;
+ current_config.line = 1;
+ exec_config(runner, string_view(buf, size));
+ free(buf);
+ return 0;
+}
+
+int read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
+{
+ // Recursive
+ const ConfigState saved = current_config;
+ int ret = do_read_config(runner, filename, flags);
+ current_config = saved;
+ return ret;
+}
+
+void exec_builtin_color_reset(EditorState *e)
+{
+ clear_hl_colors(&e->colors);
+ const StringView reset = string_view(builtin_color_reset, sizeof(builtin_color_reset) - 1);
+ const ConfigState saved = current_config;
+ current_config.file = "color/reset";
+ current_config.line = 1;
+ exec_normal_config(e, reset);
+ current_config = saved;
+}
+
+void exec_builtin_rc(EditorState *e)
+{
+ exec_builtin_color_reset(e);
+ const StringView rc = string_view(builtin_rc, sizeof(builtin_rc) - 1);
+ const ConfigState saved = current_config;
+ current_config.file = "rc";
+ current_config.line = 1;
+ exec_normal_config(e, rc);
+ current_config = saved;
+}
+
+void collect_builtin_configs(PointerArray *a, const char *prefix)
+{
+ for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
+ const char *name = builtin_configs[i].name;
+ if (str_has_prefix(name, prefix)) {
+ ptr_array_append(a, xstrdup(name));
+ }
+ }
+}
+
+void collect_builtin_includes(PointerArray *a, const char *prefix)
+{
+ for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
+ const char *name = builtin_configs[i].name;
+ if (str_has_prefix(name, prefix) && !str_has_prefix(name, "syntax/")) {
+ ptr_array_append(a, xstrdup(name));
+ }
+ }
+}
+
+UNITTEST {
+ BUG_ON(!get_builtin_config("rc"));
+ BUG_ON(!get_builtin_config("color/reset"));
+}