aboutsummaryrefslogtreecommitdiff
path: root/config/c_mode_plugin.c
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-06-03 04:14:59 +0200
committerDavid Moc <personal@cdatgoose.org>2026-06-03 04:14:59 +0200
commitaba45a64364457f20e84de4189500f4426e11d53 (patch)
treefe42d47f01decd53e28bb187cd3d85de78035a46 /config/c_mode_plugin.c
parentc1ccd38b31d722c843ab311338e2b8d1905eb8f8 (diff)
Added ffap and fixed an eval memory leakmain
Diffstat (limited to 'config/c_mode_plugin.c')
-rw-r--r--config/c_mode_plugin.c170
1 files changed, 167 insertions, 3 deletions
diff --git a/config/c_mode_plugin.c b/config/c_mode_plugin.c
index e707bca..410f029 100644
--- a/config/c_mode_plugin.c
+++ b/config/c_mode_plugin.c
@@ -1,10 +1,17 @@
#include "ecex.h"
+#include <stdio.h>
#include <string.h>
#define C_MODE_PLUGIN_ID "c-mode"
#define C_MODE_LSP_PROVIDER_NAME "c-mode-clangd"
#define C_MODE_SLOT_CLANGD "clangd"
+#define C_MODE_TAB_WIDTH_DEFAULT 4
+
+static int c_mode_indent_width(void) {
+ int width = ecex_c_mode_tab_width();
+ return width > 0 ? width : C_MODE_TAB_WIDTH_DEFAULT;
+}
static int c_mode_line_starts_with(buffer_t *buffer, size_t first, size_t line_end, const char *word) {
size_t len = strlen(word);
@@ -108,6 +115,24 @@ static int c_mode_brace_depth_before(buffer_t *buffer, size_t limit) {
return depth;
}
+static int c_mode_line_indent_cols(buffer_t *buffer, size_t line_start, size_t line_end) {
+ int cols = 0;
+ if (!buffer) return 0;
+
+ for (size_t i = line_start; i < line_end; i++) {
+ if (buffer->data[i] == ' ') {
+ cols++;
+ } else if (buffer->data[i] == '\t') {
+ int width = c_mode_indent_width();
+ cols += width - (cols % width);
+ } else {
+ break;
+ }
+ }
+
+ return cols;
+}
+
static int cmd_c_indent_line(ecex_t *ed) {
if (!ed) return -1;
buffer_t *buffer = ecex_current_buffer(ed);
@@ -120,10 +145,11 @@ static int cmd_c_indent_line(ecex_t *ed) {
if (first < line_end && buffer->data[first] == '#') return ecex_indent_line_to(buffer, 0);
+ int width = c_mode_indent_width();
int depth = c_mode_brace_depth_before(buffer, line_start);
- int target = depth * 4;
+ int target = depth * width;
- if (first < line_end && buffer->data[first] == '}') target -= 4;
+ if (first < line_end && buffer->data[first] == '}') target -= width;
size_t prev = c_mode_previous_nonblank_line(buffer, line_start);
if (prev != (size_t)-1) {
@@ -137,7 +163,7 @@ static int cmd_c_indent_line(ecex_t *ed) {
!(c_mode_line_starts_with(buffer, first, line_end, "case") ||
c_mode_line_starts_with(buffer, first, line_end, "default") ||
(first < line_end && buffer->data[first] == '}'))) {
- target += 4;
+ target += width;
}
}
@@ -145,10 +171,137 @@ static int cmd_c_indent_line(ecex_t *ed) {
return ecex_indent_line_to(buffer, target);
}
+static int cmd_c_newline_and_indent(ecex_t *ed) {
+ if (!ed) return -1;
+ buffer_t *buffer = ecex_current_buffer(ed);
+ if (!buffer || buffer->read_only || buffer_is_interactive(buffer)) return -1;
+ if (buffer_insert_char(buffer, '\n') != 0) return -1;
+ return cmd_c_indent_line(ed);
+}
+
+static int cmd_c_dedent_line(ecex_t *ed) {
+ if (!ed) return -1;
+ buffer_t *buffer = ecex_current_buffer(ed);
+ if (!buffer || buffer->read_only || buffer_is_interactive(buffer)) return -1;
+
+ size_t line_start = buffer_current_line_start(buffer);
+ size_t line_end = buffer_current_line_end(buffer);
+ int current = c_mode_line_indent_cols(buffer, line_start, line_end);
+ int target = current - c_mode_indent_width();
+ if (target < 0) target = 0;
+ return ecex_indent_line_to(buffer, target);
+}
+
static int cmd_c_complete(ecex_t *ed) {
return ecex_complete_at_point(ed);
}
+static int c_mode_set_tab_width_command(ecex_t *ed, int width) {
+ int actual = ecex_c_mode_set_tab_width(width);
+ char message[64];
+ snprintf(message, sizeof(message), "c-mode tab width: %d", actual);
+ ecex_message(ed, message);
+ return 0;
+}
+
+static int cmd_c_tab_width_2(ecex_t *ed) { return c_mode_set_tab_width_command(ed, 2); }
+static int cmd_c_tab_width_4(ecex_t *ed) { return c_mode_set_tab_width_command(ed, 4); }
+static int cmd_c_tab_width_8(ecex_t *ed) { return c_mode_set_tab_width_command(ed, 8); }
+
+static int c_mode_path_char(char c) {
+ return (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '-' || c == '.' || c == '/' || c == '~' || c == '+';
+}
+
+static int c_mode_copy_range(buffer_t *buffer, size_t start, size_t end, char *out, size_t out_size) {
+ if (!buffer || !out || out_size == 0 || start > end || end > buffer->len) return -1;
+ size_t len = end - start;
+ if (len == 0) return -1;
+ if (len >= out_size) len = out_size - 1;
+ memcpy(out, buffer->data + start, len);
+ out[len] = '\0';
+ return 0;
+}
+
+static int c_mode_line_is_include(buffer_t *buffer, size_t line_start, size_t line_end) {
+ if (!buffer) return 0;
+ size_t p = line_start;
+ while (p < line_end && (buffer->data[p] == ' ' || buffer->data[p] == '\t')) p++;
+ return p + 8 <= line_end && strncmp(buffer->data + p, "#include", 8) == 0;
+}
+
+static int c_mode_quoted_path_at_point(buffer_t *buffer,
+ size_t line_start,
+ size_t line_end,
+ size_t point,
+ char *out,
+ size_t out_size) {
+ int include_line = c_mode_line_is_include(buffer, line_start, line_end);
+
+ for (size_t p = line_start; p < line_end; p++) {
+ char open = buffer->data[p];
+ char close = '\0';
+ if (open == '"') close = '"';
+ else if (include_line && open == '<') close = '>';
+ else continue;
+
+ size_t q = p + 1;
+ while (q < line_end && buffer->data[q] != close) q++;
+ if (q >= line_end) return -1;
+ if (point > p && point <= q) return c_mode_copy_range(buffer, p + 1, q, out, out_size);
+ p = q;
+ }
+
+ return -1;
+}
+
+static int c_mode_path_at_point(buffer_t *buffer, char *out, size_t out_size) {
+ if (out && out_size) out[0] = '\0';
+ if (!buffer || !out || out_size == 0 || !buffer->data) return -1;
+
+ size_t point = buffer->point > buffer->len ? buffer->len : buffer->point;
+ size_t line_start = buffer_line_start_at(buffer, point);
+ size_t line_end = buffer_line_end_at(buffer, point);
+
+ if (c_mode_quoted_path_at_point(buffer, line_start, line_end, point, out, out_size) == 0) {
+ return 0;
+ }
+
+ size_t pos = point;
+ if (pos == buffer->len || (pos < buffer->len && !c_mode_path_char(buffer->data[pos]))) {
+ if (pos == 0 || !c_mode_path_char(buffer->data[pos - 1])) return -1;
+ pos--;
+ }
+
+ size_t start = pos;
+ while (start > line_start && c_mode_path_char(buffer->data[start - 1])) start--;
+
+ size_t end = pos;
+ while (end < line_end && c_mode_path_char(buffer->data[end])) end++;
+
+ return c_mode_copy_range(buffer, start, end, out, out_size);
+}
+
+static int cmd_c_find_file_at_point(ecex_t *ed) {
+ if (!ed) return -1;
+ buffer_t *buffer = ecex_current_buffer(ed);
+ if (!buffer) return -1;
+
+ char path[1024];
+ if (c_mode_path_at_point(buffer, path, sizeof(path)) != 0) {
+ ecex_message(ed, "No file at point");
+ return 0;
+ }
+
+ return ecex_find_project_file(ed, buffer->path, path);
+}
+
+static int cmd_c_jump_to_definition(ecex_t *ed) {
+ return ecex_clangd_jump_to_definition(ed);
+}
+
static int c_mode_file_handler(ecex_t *ed, buffer_t *buffer) {
if (!ed || !buffer) return -1;
return ecex_buffer_set_major_mode_by_name(ed, buffer, "c-mode");
@@ -158,10 +311,21 @@ ECEX_PLUGIN_BEGIN(ecex_c_mode_plugin, C_MODE_PLUGIN_ID)
if (!ecex_define_major_mode(ed, "c-mode")) return -1;
ECEX_CONFIG_COMMAND("c-indent-line", cmd_c_indent_line);
+ ECEX_CONFIG_COMMAND("c-newline-and-indent", cmd_c_newline_and_indent);
+ ECEX_CONFIG_COMMAND("c-dedent-line", cmd_c_dedent_line);
ECEX_CONFIG_COMMAND("c-complete", cmd_c_complete);
+ ECEX_CONFIG_COMMAND("c-tab-width-2", cmd_c_tab_width_2);
+ ECEX_CONFIG_COMMAND("c-tab-width-4", cmd_c_tab_width_4);
+ ECEX_CONFIG_COMMAND("c-tab-width-8", cmd_c_tab_width_8);
+ ECEX_CONFIG_COMMAND("c-jump-to-definition", cmd_c_jump_to_definition);
+ ECEX_CONFIG_COMMAND("c-find-file-at-point", cmd_c_find_file_at_point);
ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "TAB", "c-indent-line"));
+ ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "S-TAB", "c-dedent-line"));
+ ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "ENTER", "c-newline-and-indent"));
ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "C-TAB", "c-complete"));
ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "C-S-TAB", "complete-at-point-previous"));
+ ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "C-g d", "c-jump-to-definition"));
+ ECEX_CONFIG_TRY(ecex_bind_mode_key(ed, "c-mode", "C-g f", "c-find-file-at-point"));
if (ecex_dependency_available("clangd")) {
ECEX_CONFIG_TRY(ecex_add_clangd_completion_provider(ed,