Browse Source

terminal: ugly but functioning scrollback selection

K. Lange 4 years ago
parent
commit
9dd4dda951
1 changed files with 163 additions and 35 deletions
  1. 163 35
      apps/terminal.c

+ 163 - 35
apps/terminal.c

@@ -190,6 +190,8 @@ static volatile int exit_application = 0;
 
 static void cell_redraw(uint16_t x, uint16_t y);
 static void cell_redraw_inverted(uint16_t x, uint16_t y);
+static void cell_redraw_offset(uint16_t x, uint16_t y);
+static void cell_redraw_offset_inverted(uint16_t x, uint16_t y);
 
 static uint64_t get_ticks(void) {
 	struct timeval now;
@@ -310,7 +312,7 @@ static void iterate_selection(void (*func)(uint16_t x, uint16_t y)) {
 
 /* Redraw the selection with the selection hint (inversion) */
 static void redraw_selection(void) {
-	iterate_selection(cell_redraw_inverted);
+	iterate_selection(cell_redraw_offset_inverted);
 }
 
 static void redraw_new_selection(int old_x, int old_y) {
@@ -320,10 +322,10 @@ static void redraw_new_selection(int old_x, int old_y) {
 		b = selection_end_y;
 		selection_end_x = old_x;
 		selection_end_y = old_y;
-		iterate_selection(cell_redraw);
+		iterate_selection(cell_redraw_offset);
 		selection_end_x = a;
 		selection_end_y = b;
-		iterate_selection(cell_redraw_inverted);
+		iterate_selection(cell_redraw_offset_inverted);
 	} else {
 		int a, b;
 		a = selection_start_x;
@@ -337,10 +339,10 @@ static void redraw_new_selection(int old_x, int old_y) {
 			/* Backwards */
 			if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) {
 				/* Selection extended */
-				iterate_selection(cell_redraw_inverted);
+				iterate_selection(cell_redraw_offset_inverted);
 			} else {
 				/* Selection got smaller */
-				iterate_selection(cell_redraw);
+				iterate_selection(cell_redraw_offset);
 			}
 		} else if (old_y == b) {
 			/* Was a single line */
@@ -349,54 +351,54 @@ static void redraw_new_selection(int old_x, int old_y) {
 				if (old_x < a) {
 					/* Backwards */
 					if (selection_end_x < old_x) {
-						iterate_selection(cell_redraw_inverted);
+						iterate_selection(cell_redraw_offset_inverted);
 					} else {
-						iterate_selection(cell_redraw);
+						iterate_selection(cell_redraw_offset);
 					}
 				} else {
 					if (selection_end_x < old_x) {
-						iterate_selection(cell_redraw);
+						iterate_selection(cell_redraw_offset);
 					} else {
-						iterate_selection(cell_redraw_inverted);
+						iterate_selection(cell_redraw_offset_inverted);
 					}
 				}
 			} else if (selection_end_y < b) {
 				/* Moved up */
 				if (old_x <= a) {
 					/* Should be fine with just append */
-					iterate_selection(cell_redraw_inverted);
+					iterate_selection(cell_redraw_offset_inverted);
 				} else {
 					/* Need to erase first */
-					iterate_selection(cell_redraw);
+					iterate_selection(cell_redraw_offset);
 					selection_start_x = a;
 					selection_start_y = b;
-					iterate_selection(cell_redraw_inverted);
+					iterate_selection(cell_redraw_offset_inverted);
 				}
 			} else if (selection_end_y > b) {
 				if (old_x >= a) {
 					/* Should be fine with just append */
-					iterate_selection(cell_redraw_inverted);
+					iterate_selection(cell_redraw_offset_inverted);
 				} else {
 					/* Need to erase first */
-					iterate_selection(cell_redraw);
+					iterate_selection(cell_redraw_offset);
 					selection_start_x = a;
 					selection_start_y = b;
-					iterate_selection(cell_redraw_inverted);
+					iterate_selection(cell_redraw_offset_inverted);
 				}
 			}
 		} else {
 			/* Forward */
 			if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) {
 				/* Selection got smaller */
-				iterate_selection(cell_redraw);
+				iterate_selection(cell_redraw_offset);
 			} else {
 				/* Selection extended */
-				iterate_selection(cell_redraw_inverted);
+				iterate_selection(cell_redraw_offset_inverted);
 			}
 		}
 
-		cell_redraw_inverted(a,b);
-		cell_redraw_inverted(selection_end_x, selection_end_y);
+		cell_redraw_offset_inverted(a,b);
+		cell_redraw_offset_inverted(selection_end_x, selection_end_y);
 
 		/* Restore */
 		selection_start_x = a;
@@ -405,12 +407,32 @@ static void redraw_new_selection(int old_x, int old_y) {
 }
 
 /* Figure out how long the UTF-8 selection string should be. */
-static void count_selection(uint16_t x, uint16_t y) {
-	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
-	if (!(cell->flags & ANSI_EXT_IMG)) {
-		if (((uint32_t *)cell)[0] != 0x00000000) {
-			char tmp[7];
-			_selection_count += to_eight(cell->c, tmp);
+static void count_selection(uint16_t x, uint16_t _y) {
+	int y = _y;
+	y -= scrollback_offset;
+	if (y >= 0) {
+		term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+		if (!(cell->flags & ANSI_EXT_IMG)) {
+			if (((uint32_t *)cell)[0] != 0x00000000) {
+				char tmp[7];
+				_selection_count += to_eight(cell->c, tmp);
+			}
+		}
+	} else {
+		node_t * node = scrollback_list->tail;
+		for (; y < -1; y++) {
+			if (!node) break;
+			node = node->prev;
+		}
+		if (node) {
+			struct scrollback_row * row = (struct scrollback_row *)node->value;
+			if (row && x < row->width) {
+				term_cell_t * cell = &row->cells[x];
+				if (cell && ((uint32_t *)cell)[0] != 0x00000000) {
+					char tmp[7];
+					_selection_count += to_eight(cell->c, tmp);
+				}
+			}
 		}
 	}
 	if (x == term_width - 1) {
@@ -419,15 +441,39 @@ static void count_selection(uint16_t x, uint16_t y) {
 }
 
 /* Fill the selection text buffer with the selected text. */
-void write_selection(uint16_t x, uint16_t y) {
-	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
-	if (!(cell->flags & ANSI_EXT_IMG)) {
-		if (((uint32_t *)cell)[0] != 0x00000000) {
-			char tmp[7];
-			int count = to_eight(cell->c, tmp);
-			for (int i = 0; i < count; ++i) {
-				selection_text[_selection_i] = tmp[i];
-				_selection_i++;
+void write_selection(uint16_t x, uint16_t _y) {
+	int y = _y;
+	y -= scrollback_offset;
+	if (y >= 0) {
+		term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+		if (!(cell->flags & ANSI_EXT_IMG)) {
+			if (((uint32_t *)cell)[0] != 0x00000000) {
+				char tmp[7];
+				int count = to_eight(cell->c, tmp);
+				for (int i = 0; i < count; ++i) {
+					selection_text[_selection_i] = tmp[i];
+					_selection_i++;
+				}
+			}
+		}
+	} else {
+		node_t * node = scrollback_list->tail;
+		for (; y < -1; y++) {
+			if (!node) break;
+			node = node->prev;
+		}
+		if (node) {
+			struct scrollback_row * row = (struct scrollback_row *)node->value;
+			if (row && x < row->width) {
+				term_cell_t * cell = &row->cells[x];
+				if (cell && ((uint32_t *)cell)[0] != 0x00000000) {
+					char tmp[7];
+					int count = to_eight(cell->c, tmp);
+					for (int i = 0; i < count; ++i) {
+						selection_text[_selection_i] = tmp[i];
+						_selection_i++;
+					}
+				}
 			}
 		}
 	}
@@ -921,6 +967,79 @@ static void redraw_cell_image(uint16_t x, uint16_t y, term_cell_t * cell) {
 	}
 }
 
+static void cell_redraw_offset(uint16_t x, uint16_t _y) {
+	int y = _y;
+	int i = y;
+
+	y -= scrollback_offset;
+
+	if (y >= 0) {
+		term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+		if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,i,cell); return; }
+		if (((uint32_t *)cell)[0] == 0x00000000) {
+			term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS);
+		} else {
+			term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags);
+		}
+	} else {
+		node_t * node = scrollback_list->tail;
+		for (; y < -1; y++) {
+			if (!node) break;
+			node = node->prev;
+		}
+		if (node) {
+			struct scrollback_row * row = (struct scrollback_row *)node->value;
+			if (row && x < row->width) {
+				term_cell_t * cell = &row->cells[x];
+				if (!cell || ((uint32_t *)cell)[0] == 0x00000000) {
+					term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS);
+				} else {
+					term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags);
+				}
+			} else {
+				term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS);
+			}
+		}
+	}
+}
+
+static void cell_redraw_offset_inverted(uint16_t x, uint16_t _y) {
+	int y = _y;
+	int i = y;
+
+	y -= scrollback_offset;
+
+	if (y >= 0) {
+		term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+		if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,i,cell); return; }
+		if (((uint32_t *)cell)[0] == 0x00000000) {
+			term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS|ANSI_SPECBG);
+		} else {
+			term_write_char(cell->c, x * char_width, i * char_height, cell->bg, cell->fg, cell->flags);
+		}
+	} else {
+		node_t * node = scrollback_list->tail;
+		for (; y < -1; y++) {
+			if (!node) break;
+			node = node->prev;
+		}
+		if (node) {
+			struct scrollback_row * row = (struct scrollback_row *)node->value;
+			if (row && x < row->width) {
+				term_cell_t * cell = &row->cells[x];
+				if (!cell || ((uint32_t *)cell)[0] == 0x00000000) {
+					term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS);
+				} else {
+					term_write_char(cell->c, x * char_width, i * char_height, cell->bg, cell->fg, cell->flags);
+				}
+			} else {
+				term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS);
+			}
+		}
+	}
+}
+
+
 /* Redraw a text cell normally. */
 static void cell_redraw(uint16_t x, uint16_t y) {
 	/* Avoid cells out of range. */
@@ -1463,12 +1582,20 @@ term_callbacks_t term_callbacks = {
 static void handle_input(char c) {
 	write(fd_master, &c, 1);
 	display_flip();
+	if (scrollback_offset != 0) {
+		scrollback_offset = 0;
+		term_redraw_all();
+	}
 }
 
 /* Write a string into the PTY */
 static void handle_input_s(char * c) {
 	write(fd_master, c, strlen(c));
 	display_flip();
+	if (scrollback_offset != 0) {
+		scrollback_offset = 0;
+		term_redraw_all();
+	}
 }
 
 /* Scroll the view up (scrollback) */
@@ -2042,7 +2169,7 @@ static void * handle_incoming(void) {
 						}
 					} else {
 						if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
-							term_redraw_all();
+							redraw_scrollback();
 							selection_start_x = new_x;
 							selection_start_y = new_y;
 							selection_end_x = new_x;
@@ -2063,6 +2190,7 @@ static void * handle_incoming(void) {
 							if (me->new_x == me->old_x && me->new_y == me->old_y) {
 								selection = 0;
 								term_redraw_all();
+								redraw_scrollback();
 								display_flip();
 							} /* else selection */
 						}