esc
Externally Scriptable Editor
git clone git://mccd.space/esc
| Log | Files | Refs | README |
commit adbfcdaeca908232daad90536e393e7e4695db67 parent 1aea1035cbc523e5abc7ffffed6e3ba80867be89 Author: Marc Coquand <marc@coquand.email> Date: Thu, 19 Feb 2026 14:33:32 +0100 * Diffstat:
| M | main.c | | | 166 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
1 file changed, 91 insertions(+), 75 deletions(-)
diff --git a/main.c b/main.c
@@ -55,7 +55,7 @@ int main(int argc, char *argv[]) {
TTF_Init();
SDL_Window *window = SDL_CreateWindow(
- "oi", 800, 600,
+ "ei", 800, 600,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
SDL_Renderer *renderer = SDL_CreateRenderer(window, NULL);
SDL_SetRenderLogicalPresentation(renderer, 800, 600,
@@ -83,78 +83,11 @@ int main(int argc, char *argv[]) {
while (running) {
SDL_Event event;
- // 2. USE WAITEVENT TO DROP CPU USAGE TO 0%
if (SDL_WaitEvent(&event)) {
do {
if (event.type == SDL_EVENT_QUIT)
running = false;
- else if (event.type ==
- SDL_EVENT_MOUSE_BUTTON_DOWN) {
- float mx, my;
- SDL_RenderCoordinatesFromWindow(
- renderer, event.button.x,
- event.button.y, &mx, &my);
-
- int target_col =
- (int)((mx - 20.0f + scroll_x +
- (char_width / 2.0f)) /
- char_width);
- int target_row =
- (int)((my - 20.0f + scroll_y) /
- line_height);
-
- if (target_col < 0)
- target_col = 0;
- if (target_row < 0)
- target_row = 0;
-
- int current_row = 0, current_col = 0;
- const char *ptr = text_buffer;
- const char *last_ptr = text_buffer;
-
- // Iterate through the buffer using
- // UTF-8 steps
- while (*ptr != '\0') {
- if (current_row == target_row &&
- current_col == target_col) {
- break;
- }
-
- last_ptr =
- ptr; // Keep track of the
- // start of the current
- // character
- Uint32 codepoint =
- SDL_StepUTF8(&ptr, NULL);
-
- if (codepoint == '\n') {
- if (current_row ==
- target_row) {
- // We reached
- // the end of
- // the target
- // line
- ptr = last_ptr;
- break;
- }
- current_row++;
- current_col = 0;
- } else {
- current_col++;
- }
-
- // If we've passed the target
- // row, stop at the end of the
- // previous line
- if (current_row > target_row) {
- ptr = last_ptr;
- break;
- }
- }
- cursor_idx = (int)(ptr - text_buffer);
- }
-
else if (event.type == SDL_EVENT_MOUSE_WHEEL) {
scroll_y -= event.wheel.y * line_height;
scroll_x -= -event.wheel.x * 30.0f;
@@ -163,9 +96,48 @@ int main(int argc, char *argv[]) {
scroll_x = 0;
if (scroll_y < 0)
scroll_y = 0;
+ } else if (event.type ==
+ SDL_EVENT_MOUSE_BUTTON_DOWN) {
+ if (event.button.button ==
+ SDL_BUTTON_LEFT) {
+ float mx, my;
+ SDL_RenderCoordinatesFromWindow(
+ renderer, event.button.x,
+ event.button.y, &mx, &my);
+ cursor_idx =
+ get_idx_from_coords(
+ text_buffer, mx, my,
+ scroll_x, scroll_y,
+ char_width,
+ line_height);
+ selection_idx = cursor_idx;
+
+ is_selecting = true;
+ }
+ } else if (event.type ==
+ SDL_EVENT_MOUSE_MOTION) {
+ if (is_selecting) {
+ float mx, my;
+ SDL_RenderCoordinatesFromWindow(
+ renderer, event.motion.x,
+ event.motion.y, &mx, &my);
+ cursor_idx =
+ get_idx_from_coords(
+ text_buffer, mx, my,
+ scroll_x, scroll_y,
+ char_width,
+ line_height);
+ }
+ } else if (event.type ==
+ SDL_EVENT_MOUSE_BUTTON_UP) {
+ if (event.button.button ==
+ SDL_BUTTON_LEFT) {
+ is_selecting = false;
+ }
}
else if (event.type == SDL_EVENT_KEY_DOWN) {
+ is_selecting = false;
SDL_Keycode key = event.key.key;
if (key == SDLK_BACKSPACE &&
@@ -197,6 +169,8 @@ int main(int argc, char *argv[]) {
text_buffer[cursor_idx] = '\n';
text_length++;
cursor_idx++;
+ selection_idx = cursor_idx;
+
} else if (key == SDLK_LEFT &&
cursor_idx > 0) {
cursor_idx--;
@@ -207,6 +181,7 @@ int main(int argc, char *argv[]) {
0xC0) == 0x80) {
cursor_idx--;
}
+ selection_idx = cursor_idx;
} else if (key == SDLK_DELETE &&
cursor_idx < text_length) {
const char *ptr =
@@ -270,6 +245,9 @@ int main(int argc, char *argv[]) {
target_idx =
prev_line_start;
}
+ selection_idx =
+ cursor_idx;
+
} else { // SDLK_DOWN
const char *next_line =
strchr(
@@ -282,6 +260,8 @@ int main(int argc, char *argv[]) {
text_buffer) +
1;
}
+ selection_idx =
+ cursor_idx;
}
if (target_idx != -1) {
@@ -307,13 +287,11 @@ int main(int argc, char *argv[]) {
cursor_idx < text_length) {
const char *next =
text_buffer + cursor_idx;
- SDL_StepUTF8(
- &next,
- NULL); // This jumps to the
- // start of the next
- // valid character
+ SDL_StepUTF8(&next, NULL);
+
cursor_idx =
(int)(next - text_buffer);
+ selection_idx = cursor_idx;
}
}
@@ -342,19 +320,57 @@ int main(int argc, char *argv[]) {
event.text.text, input_len);
text_length += input_len;
cursor_idx += input_len;
+ selection_idx = cursor_idx;
}
} while (SDL_PollEvent(&event));
}
// --- RENDER PHASE ---
- SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
- SDL_RenderClear(renderer);
int render_w, render_h;
SDL_GetRenderOutputSize(renderer, &render_w, &render_h);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
+ if (cursor_idx != selection_idx) {
+ int sel_min = (cursor_idx < selection_idx)
+ ? cursor_idx
+ : selection_idx;
+ int sel_max = (cursor_idx > selection_idx)
+ ? cursor_idx
+ : selection_idx;
+
+ SDL_SetRenderDrawColor(renderer, 200, 220, 255,
+ 255); // Light Blue
+
+ int cur_row = 0, cur_col = 0;
+ const char *p = text_buffer;
+ while (p < text_buffer + text_length) {
+ int start_of_char_idx = (int)(p - text_buffer);
+
+ if (start_of_char_idx >= sel_min &&
+ start_of_char_idx < sel_max) {
+ SDL_FRect sel_rect = {
+ 20.0f + (cur_col * char_width) -
+ scroll_x,
+ 20.0f + (cur_row * line_height) -
+ scroll_y,
+ (float)char_width, line_height};
+ SDL_RenderFillRect(renderer, &sel_rect);
+ }
+
+ if (*p == '\n') {
+ cur_row++;
+ cur_col = 0;
+ p++;
+ } else {
+ SDL_StepUTF8(&p, NULL);
+ cur_col++;
+ }
+ if ((int)(p - text_buffer) > sel_max)
+ break;
+ }
+ }
if (font && text_length > 0) {
SDL_Color black = {0, 0, 0, 255};