Browse Source

[bim] Add REPLACE mode

K. Lange 4 years ago
parent
commit
fcbcb51ec2
1 changed files with 159 additions and 35 deletions
  1. 159 35
      apps/bim.c

+ 159 - 35
apps/bim.c

@@ -372,6 +372,7 @@ buffer_t * env;
 #define MODE_NORMAL 0
 #define MODE_INSERT 1
 #define MODE_LINE_SELECTION 2
+#define MODE_REPLACE 3
 
 /**
  * Available buffers
@@ -2015,6 +2016,11 @@ void redraw_commandline(void) {
 		printf("-- LINE SELECTION --");
 		clear_to_end();
 		reset();
+	} else if (env->mode == MODE_REPLACE) {
+		set_bold();
+		printf("-- REPLACE --");
+		clear_to_end();
+		reset();
 	} else {
 		clear_to_end();
 	}
@@ -3658,6 +3664,25 @@ void insert_char(unsigned int c) {
 	set_modified();
 }
 
+/**
+ * Replace a single character at the current cursor point
+ */
+void replace_char(unsigned int c) {
+	if (env->col_no < 1 || env->col_no > env->lines[env->line_no-1]->actual) return;
+
+	char_t _c;
+	_c.codepoint = c;
+	_c.flags = 0;
+	_c.display_width = codepoint_width(c);
+
+	env->lines[env->line_no-1]->text[env->col_no-1] = _c;
+	recalculate_tabs(env->lines[env->line_no-1]);
+	recalculate_syntax(env->lines[env->line_no-1], env->line_no);
+
+	redraw_line(env->line_no - env->offset - 1, env->line_no-1);
+	set_modified();
+}
+
 /**
  * Move the cursor the start of the previous word.
  */
@@ -3817,7 +3842,7 @@ int handle_escape(int * this_buf, int * timeout, int c) {
 						goto_line(env->line_no - (global_config.term_height - 6));
 						break;
 					case '3':
-						if (env->mode == MODE_INSERT) {
+						if (env->mode == MODE_INSERT || env->mode == MODE_REPLACE) {
 							if (env->col_no < env->lines[env->line_no - 1]->actual + 1) {
 								line_delete(env->lines[env->line_no - 1], env->col_no, env->line_no - 1);
 								redraw_line(env->line_no - env->offset - 1, env->line_no-1);
@@ -4103,6 +4128,49 @@ _leave_select_line:
 	redraw_all();
 }
 
+/**
+ * Backspace from the current cursor position.
+ */
+void delete_at_cursor(void) {
+	if (env->col_no > 1) {
+		line_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1);
+		env->col_no -= 1;
+		redraw_line(env->line_no - env->offset - 1, env->line_no-1);
+		set_modified();
+		redraw_statusbar();
+		place_cursor_actual();
+	} else if (env->line_no > 1) {
+		int tmp = env->lines[env->line_no - 2]->actual;
+		merge_lines(env->lines, env->line_no - 1);
+		env->line_no -= 1;
+		env->col_no = tmp+1;
+		redraw_text();
+		set_modified();
+		redraw_statusbar();
+		place_cursor_actual();
+	}
+}
+
+/**
+ * Break the current line in two at the current cursor position.
+ */
+void insert_line_feed(void) {
+	if (env->col_no == env->lines[env->line_no - 1]->actual + 1) {
+		env->lines = add_line(env->lines, env->line_no);
+	} else {
+		env->lines = split_line(env->lines, env->line_no, env->col_no - 1);
+	}
+	env->col_no = 1;
+	env->line_no += 1;
+	add_indent(env->line_no-1,env->line_no-2);
+	if (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) {
+		env->offset += 1;
+	}
+	redraw_text();
+	set_modified();
+	redraw_statusbar();
+	place_cursor_actual();
+}
 
 /**
  * INSERT mode
@@ -4143,41 +4211,10 @@ void insert_mode(void) {
 						break;
 					case DELETE_KEY:
 					case BACKSPACE_KEY:
-						if (env->col_no > 1) {
-							line_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1);
-							env->col_no -= 1;
-							redraw_line(env->line_no - env->offset - 1, env->line_no-1);
-							set_modified();
-							redraw_statusbar();
-							place_cursor_actual();
-						} else if (env->line_no > 1) {
-							int tmp = env->lines[env->line_no - 2]->actual;
-							merge_lines(env->lines, env->line_no - 1);
-							env->line_no -= 1;
-							env->col_no = tmp+1;
-							redraw_text();
-							set_modified();
-							redraw_statusbar();
-							place_cursor_actual();
-						}
+						delete_at_cursor();
 						break;
 					case ENTER_KEY:
-						if (env->col_no == env->lines[env->line_no - 1]->actual + 1) {
-							env->lines = add_line(env->lines, env->line_no);
-						} else {
-							/* oh oh god we're all gonna die */
-							env->lines = split_line(env->lines, env->line_no, env->col_no - 1);
-						}
-						env->col_no = 1;
-						env->line_no += 1;
-						add_indent(env->line_no-1,env->line_no-2);
-						if (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) {
-							env->offset += 1;
-						}
-						redraw_text();
-						set_modified();
-						redraw_statusbar();
-						place_cursor_actual();
+						insert_line_feed();
 						break;
 					case '\t':
 						if (env->tabs) {
@@ -4209,6 +4246,80 @@ void insert_mode(void) {
 	}
 }
 
+/*
+ * REPLACE mode
+ *
+ * Like insert, but replaces characters.
+ */
+void replace_mode(void) {
+	int cin;
+	uint32_t c;
+
+	/* Set mode line */
+	env->mode = MODE_REPLACE;
+	redraw_commandline();
+
+	/* Place the cursor in the text area */
+	place_cursor_actual();
+
+	int timeout = 0;
+	int this_buf[20];
+	uint32_t istate = 0;
+	while ((cin = bim_getch())) {
+		if (cin == -1) {
+			if (timeout && this_buf[timeout-1] == '\033') {
+				leave_insert();
+				return;
+			}
+			timeout = 0;
+			continue;
+		}
+		if (!decode(&istate, &c, cin)) {
+			if (timeout == 0) {
+				switch (c) {
+					case '\033':
+						if (timeout == 0) {
+							this_buf[timeout] = c;
+							timeout++;
+						}
+						break;
+					case DELETE_KEY:
+					case BACKSPACE_KEY:
+						if (env->line_no > 1 && env->col_no == 1) {
+							env->line_no--;
+							env->col_no = env->lines[env->line_no-1]->actual;
+							place_cursor_actual();
+						} else {
+							cursor_left();
+						}
+						break;
+					case ENTER_KEY:
+						insert_line_feed();
+						break;
+					default:
+						if (env->col_no <= env->lines[env->line_no - 1]->actual) {
+							replace_char(c);
+							env->col_no += 1;
+						} else {
+							insert_char(c);
+						}
+						redraw_statusbar();
+						place_cursor_actual();
+						break;
+				}
+			} else {
+				if (handle_escape(this_buf,&timeout,c)) {
+					bim_unget(c);
+					leave_insert();
+					return;
+				}
+			}
+		} else if (istate == UTF8_REJECT) {
+			istate = 0;
+		}
+	}
+}
+
 static void show_usage(char * argv[]) {
 	printf(
 			"bim - Text editor\n"
@@ -4358,7 +4469,13 @@ int main(int argc, char * argv[]) {
 						break;
 					case DELETE_KEY:
 					case BACKSPACE_KEY:
-						cursor_left();
+						if (env->line_no > 1 && env->col_no == 1) {
+							env->line_no--;
+							env->col_no = env->lines[env->line_no-1]->actual;
+							place_cursor_actual();
+						} else {
+							cursor_left();
+						}
 						break;
 					case ':':
 						/* Switch to command mode */
@@ -4465,6 +4582,13 @@ _insert:
 						redraw_commandline();
 						timeout = 0;
 						break;
+					case 'R':
+						if (env->readonly) goto _readonly;
+						replace_mode();
+						redraw_statusbar();
+						redraw_commandline();
+						timeout = 0;
+						break;
 _readonly:
 						render_error("Buffer is read-only");
 						break;