Browse Source

terminal: support bracketed paste mode

K. Lange 1 year ago
parent
commit
00493418a3
5 changed files with 78 additions and 8 deletions
  1. 59 6
      apps/bim.c
  2. 7 1
      apps/terminal-vga.c
  3. 7 1
      apps/terminal.c
  4. 1 0
      base/usr/include/toaru/termemu.h
  5. 4 0
      lib/termemu.c

+ 59 - 6
apps/bim.c

@@ -1,9 +1,9 @@
 /**
  * This is a baked, single-file version of bim.
- * It was built Thu Dec 19 13:41:35 2019
- * It is based on git commit 8860761a4e0906246a38f41939551fe7ed050c5b
+ * It was built Fri Dec 20 20:55:42 2019
+ * It is based on git commit 7c3983dd0c630558d7b7cd9573145e75ceecf4d7
  */
-#define GIT_TAG "8860761-baked"
+#define GIT_TAG "7c3983d-baked"
 /* Bim - A Text Editor
  *
  * Copyright (C) 2012-2019 K. Lange
@@ -96,6 +96,8 @@ enum Key {
 	KEY_ALT_UP, KEY_ALT_DOWN, KEY_ALT_RIGHT, KEY_ALT_LEFT,
 	KEY_ALT_SHIFT_UP, KEY_ALT_SHIFT_DOWN, KEY_ALT_SHIFT_RIGHT, KEY_ALT_SHIFT_LEFT,
 	KEY_SHIFT_TAB,
+	/* Special signals for paste start, paste end */
+	KEY_PASTE_BEGIN, KEY_PASTE_END,
 };
 
 struct key_name_map {
@@ -198,6 +200,7 @@ typedef struct {
 	unsigned int can_256color:1;
 	unsigned int can_italic:1;
 	unsigned int can_insert:1;
+	unsigned int can_bracketedpaste:1;
 	unsigned int history_enabled:1;
 	unsigned int highlight_parens:1;
 	unsigned int smart_case:1;
@@ -641,6 +644,7 @@ global_config_t global_config = {
 	.can_256color = 1, /* can use 265 colors */
 	.can_italic = 1, /* can use italics (without inverting) */
 	.can_insert = 0, /* ^[[L */
+	.can_bracketedpaste = 0, /* puts escapes before and after pasted stuff */
 	/* Configuration options */
 	.history_enabled = 1,
 	.highlight_parens = 1, /* highlight parens/braces when cursor moves */
@@ -688,6 +692,7 @@ struct key_name_map KeyNames[] = {
 	{KEY_ALT_UP, "<alt-up>"},{KEY_ALT_DOWN, "<alt-down>"},{KEY_ALT_RIGHT, "<alt-right>"},{KEY_ALT_LEFT, "<alt-left>"},
 	{KEY_ALT_SHIFT_UP, "<alt-shift-up>"},{KEY_ALT_SHIFT_DOWN, "<alt-shift-down>"},{KEY_ALT_SHIFT_RIGHT, "<alt-shift-right>"},{KEY_ALT_SHIFT_LEFT, "<alt-shift-left>"},
 	{KEY_SHIFT_TAB,"<shift-tab>"},
+	{KEY_PASTE_BEGIN,"<paste-begin>"},{KEY_PASTE_END,"<paste-end>"},
 };
 
 char * name_from_key(enum Key keycode) {
@@ -940,6 +945,12 @@ int bim_getkey(int read_timeout) {
 									case '5': timeout = 0; return KEY_PAGE_UP;
 									case '6': timeout = 0; return KEY_PAGE_DOWN;
 								}
+							} else if (timeout == 5) {
+								if (this_buf[2] == '2' && this_buf[3] == '0' && this_buf[4] == '0') {
+									return KEY_PASTE_BEGIN;
+								} else if (this_buf[2] == '2' && this_buf[3] == '0' && this_buf[4] == '1') {
+									return KEY_PASTE_END;
+								}
 							} else if (this_buf[2] == '1') {
 								switch (this_buf[3]) {
 									case '5': return KEY_F5;
@@ -2426,6 +2437,24 @@ void unset_alternate_screen(void) {
 	}
 }
 
+/**
+ * Enable bracketed paste mode.
+ */
+void set_bracketed_paste(void) {
+	if (global_config.can_bracketedpaste) {
+		printf("\033[?2004h");
+	}
+}
+
+/**
+ * Disable bracketed paste mode.
+ */
+void unset_bracketed_paste(void) {
+	if (global_config.can_bracketedpaste) {
+		printf("\033[?2004l");
+	}
+}
+
 /**
  * Get the name of just a file from a full path.
  * Returns a pointer within the original string.
@@ -3688,6 +3717,7 @@ void SIGTSTP_handler(int sig) {
 	reset();
 	clear_screen();
 	show_cursor();
+	unset_bracketed_paste();
 	unset_alternate_screen();
 	fflush(stdout);
 
@@ -3698,6 +3728,7 @@ void SIGTSTP_handler(int sig) {
 void SIGCONT_handler(int sig) {
 	(void)sig;
 	set_alternate_screen();
+	set_bracketed_paste();
 	set_unbuffered();
 	update_screen_size();
 	mouse_enable();
@@ -4169,6 +4200,7 @@ void quit(const char * message) {
 	reset();
 	clear_screen();
 	show_cursor();
+	unset_bracketed_paste();
 	unset_alternate_screen();
 	if (message) {
 		fprintf(stdout, "%s\n", message);
@@ -9325,6 +9357,22 @@ BIM_ACTION(shift_horizontally, ARG_IS_CUSTOM,
 	redraw_text();
 }
 
+static int state_before_paste = 0;
+BIM_ACTION(paste_begin, 0, "Begin bracketed paste; disable indentation, completion, etc.")(void) {
+	if (global_config.smart_complete) state_before_paste |= 0x01;
+	if (env->indent) state_before_paste |= 0x02;
+
+	global_config.smart_complete = 0;
+	env->indent = 0;
+	/* TODO: We need env->loading == 1, but with history (manual breaks, though) */
+}
+
+BIM_ACTION(paste_end, 0, "End bracketed paste; restore indentation, completion, etc.")(void) {
+	if (state_before_paste & 0x01) global_config.smart_complete = 1;
+	if (state_before_paste & 0x02) env->indent = 1;
+	redraw_statusbar();
+}
+
 struct action_map _NORMAL_MAP[] = {
 	{KEY_BACKSPACE, cursor_left_with_wrap, opt_rep, 0},
 	{'V',           enter_line_selection, 0, 0},
@@ -9364,6 +9412,8 @@ struct action_map _INSERT_MAP[] = {
 	{'\t',          smart_tab, 0, 0},
 	{'/',           smart_comment_end, opt_arg, '/'},
 	{'}',           smart_brace_end, opt_arg, '}'},
+	{KEY_PASTE_BEGIN, paste_begin, 0, 0},
+	{KEY_PASTE_END, paste_end, 0, 0},
 	{-1, NULL, 0, 0},
 };
 
@@ -10290,11 +10340,13 @@ void detect_weird_terminals(void) {
 		global_config.can_24bit = 0; /* Also not strictly true */
 		global_config.can_256color = 0; /* Not strictly true */
 	}
-	if (term && strstr(term,"toaru") == term) {
+	if (term && strstr(term,"xterm-256color") == term) {
 		global_config.can_insert = 1;
+		global_config.can_bracketedpaste = 1;
 	}
-	if (term && strstr(term,"xterm-256color") == term) {
+	if (term && strstr(term,"toaru") == term) {
 		global_config.can_insert = 1;
+		global_config.can_bracketedpaste = 1;
 	}
 
 	if (!global_config.can_unicode) {
@@ -10359,6 +10411,7 @@ void init_terminal(void) {
 		global_config.tty_in = STDERR_FILENO;
 	}
 	set_alternate_screen();
+	set_bracketed_paste();
 	update_screen_size();
 	get_initial_termios();
 	set_unbuffered();
@@ -11337,7 +11390,7 @@ void paint_c_string(struct syntax_state * state) {
 				}
 			}
 			last = -1;
-		} else if (charat() == '%') {
+		} else if (charat() == '%' && nextchar() != '"') {
 			paint(1, FLAG_ESCAPE);
 			if (charat() == '%') {
 				paint(1, FLAG_ESCAPE);

+ 7 - 1
apps/terminal-vga.c

@@ -741,7 +741,13 @@ void key_event(int ret, key_event_t * event) {
 			(event->keycode == 'v')) {
 			/* Paste selection */
 			if (selection_text) {
-				handle_input_s(selection_text);
+				if (ansi_state->paste_mode) {
+					handle_input_s("\033[200~");
+					handle_input_s(selection_text);
+					handle_input_s("\033[201~");
+				} else {
+					handle_input_s(selection_text);
+				}
 			}
 			return;
 		}

+ 7 - 1
apps/terminal.c

@@ -1942,7 +1942,13 @@ static void * handle_incoming(void) {
 						memcpy(selection_text, cb->content, cb->size);
 						selection_text[cb->size] = '\0';
 					}
-					handle_input_s(selection_text);
+					if (ansi_state->paste_mode) {
+						handle_input_s("\033[200~");
+						handle_input_s(selection_text);
+						handle_input_s("\033[201~");
+					} else {
+						handle_input_s(selection_text);
+					}
 				}
 				break;
 			case YUTANI_MSG_WINDOW_MOUSE_EVENT:

+ 1 - 0
base/usr/include/toaru/termemu.h

@@ -60,6 +60,7 @@ typedef struct {
 	uint32_t img_collected;
 	uint32_t img_size;
 	char *   img_data;
+	uint8_t  paste_mode;
 } term_state_t;
 
 /* Triggers escape mode. */

+ 4 - 0
lib/termemu.c

@@ -329,6 +329,8 @@ static void _ansi_put(term_state_t * s, char c) {
 								s->mouse_on |= TERMEMU_MOUSE_SGR;
 							} else if (!strcmp(argv[0], "?25")) {
 								callbacks->set_csr_on(1);
+							} else if (!strcmp(argv[0], "?2004")) {
+								s->paste_mode = 1;
 							}
 						}
 						break;
@@ -344,6 +346,8 @@ static void _ansi_put(term_state_t * s, char c) {
 								s->mouse_on &= ~TERMEMU_MOUSE_SGR;
 							} else if (!strcmp(argv[0], "?25")) {
 								callbacks->set_csr_on(0);
+							} else if (!strcmp(argv[0], "?2004")) {
+								s->paste_mode = 0;
 							}
 						}
 						break;