esc

Externally Scriptable Editor

git clone git://mccd.space/esc

commit adbfcdaeca908232daad90536e393e7e4695db67
parent 1aea1035cbc523e5abc7ffffed6e3ba80867be89
Author: Marc Coquand <marc@coquand.email>
Date:   Thu, 19 Feb 2026 14:33:32 +0100

*

Diffstat:
Mmain.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};