shithub: orca

Download patch

ref: b9f1b0038904401222a9b99d308e13ac6094462a
parent: 89235b596c5191df516b95d2acbe1aa3b9f79c09
author: cancel <cancel@cancel.fm>
date: Fri Jan 3 14:12:48 EST 2020

Add start of bracketed paste support

--- a/tui_main.c
+++ b/tui_main.c
@@ -2447,11 +2447,17 @@
     mouseinterval(0);
   }
 
+  printf("\033[?2004h\n"); // Ask terminal to use bracketed paste.
+
   WINDOW* cont_window = NULL;
 
   int key = KEY_RESIZE;
   wtimeout(stdscr, 0);
   int cur_timeout = 0;
+  Usz bracketed_paste_starting_y = 0, bracketed_paste_starting_x = 0;
+  bool is_in_bracketed_paste = false;
+  bool bracketed_paste_went_off_right_edge = false;
+  bool bracketed_paste_went_off_bottom_edge = false;
 
   // Send initial BPM
   send_num_message(ged_state.oosc_dev, "/orca/bpm", (I32)ged_state.bpm);
@@ -2862,6 +2868,8 @@
       break;
     case '\r':
     case KEY_ENTER:
+      if (is_in_bracketed_paste)
+        goto newline_in_bracketed_paste;
       // Currently unused. Formerly was the toggle for insert/append mode.
       break;
     case CTRL_PLUS('i'):
@@ -2896,6 +2904,8 @@
       ged_input_cmd(&ged_state, Ged_input_cmd_toggle_selresize_mode);
       break;
     case ' ':
+      if (is_in_bracketed_paste)
+        goto key_input_in_bracketed_paste;
       if (ged_state.input_mode == Ged_input_mode_append) {
         ged_input_character(&ged_state, '.');
       } else {
@@ -2902,9 +2912,58 @@
         ged_input_cmd(&ged_state, Ged_input_cmd_toggle_play_pause);
       }
       break;
-    case 27: // Escape
+    case 27: { // Escape
+      // Check for escape sequences we're interested in that ncurses didn't
+      // handle.
+      int esc1 = wgetch(stdscr);
+      if (esc1 == '[') {
+        int esc2 = wgetch(stdscr);
+        if (esc2 == '2') {
+          int esc3 = wgetch(stdscr);
+          if (esc3 == '0') {
+            int esc4 = wgetch(stdscr);
+            // Start or end of bracketed paste
+            if (esc4 == '0' || esc4 == '1') {
+              int esc5 = wgetch(stdscr);
+              if (esc5 == '~') {
+                switch (esc4) {
+                case '0': // Enter bracketed paste
+                  if (!is_in_bracketed_paste) {
+                    is_in_bracketed_paste = true;
+                    bracketed_paste_went_off_right_edge = false;
+                    bracketed_paste_went_off_bottom_edge = false;
+                    undo_history_push(&ged_state.undo_hist, &ged_state.field,
+                                      ged_state.tick_num);
+                    bracketed_paste_starting_y = ged_state.ged_cursor.y;
+                    bracketed_paste_starting_x = ged_state.ged_cursor.x;
+                  }
+                  goto finished_escape_sequence;
+                case '1': // End bracketed paste
+                  if (is_in_bracketed_paste) {
+                    is_in_bracketed_paste = false;
+                    ged_state.ged_cursor.y = bracketed_paste_starting_y;
+                    ged_state.ged_cursor.x = bracketed_paste_starting_x;
+                    ged_cursor_confine(&ged_state.ged_cursor,
+                                       ged_state.field.height,
+                                       ged_state.field.width);
+                    ged_state.needs_remarking = true;
+                    ged_state.is_draw_dirty = true;
+                  }
+                  goto finished_escape_sequence;
+                }
+              }
+              ungetch(esc5);
+            }
+            ungetch(esc4);
+          }
+          ungetch(esc3);
+        }
+        ungetch(esc2);
+      }
+      ungetch(esc1);
       ged_input_cmd(&ged_state, Ged_input_cmd_escape);
-      break;
+    finished_escape_sequence:;
+    } break;
 
     // Selection size modification. These may not work in all terminals. (Only
     // tested in xterm so far.)
@@ -2980,6 +3039,41 @@
       break;
 
     default:
+      if (is_in_bracketed_paste) {
+      key_input_in_bracketed_paste:
+        if (key >= CHAR_MIN && key <= CHAR_MAX) {
+          if ((char)key == '\n') {
+          newline_in_bracketed_paste:
+            if (bracketed_paste_went_off_bottom_edge)
+              break;
+            bracketed_paste_went_off_right_edge = false;
+            ged_state.ged_cursor.x = bracketed_paste_starting_x;
+            ++ged_state.ged_cursor.y; // TODO overflow check
+            if (ged_state.ged_cursor.y >= ged_state.field.height)
+              bracketed_paste_went_off_bottom_edge = true;
+            ged_cursor_confine(&ged_state.ged_cursor, ged_state.field.height,
+                               ged_state.field.width);
+            break;
+          }
+          if (bracketed_paste_went_off_right_edge ||
+              bracketed_paste_went_off_bottom_edge)
+            break;
+          if (key != ' ') {
+            char cleaned = (char)key;
+            if (!is_valid_glyph((Glyph)key))
+              cleaned = '.';
+            gbuffer_poke(ged_state.field.buffer, ged_state.field.height,
+                         ged_state.field.width, ged_state.ged_cursor.y,
+                         ged_state.ged_cursor.x, cleaned);
+          }
+          ++ged_state.ged_cursor.x; // TODO overflow check
+          if (ged_state.ged_cursor.x >= ged_state.field.width)
+            bracketed_paste_went_off_right_edge = true;
+          ged_cursor_confine(&ged_state.ged_cursor, ged_state.field.height,
+                             ged_state.field.width);
+        }
+        break;
+      }
       if (key >= CHAR_MIN && key <= CHAR_MAX && is_valid_glyph((Glyph)key)) {
         ged_input_character(&ged_state, (char)key);
       }
@@ -3003,6 +3097,7 @@
   if (cont_window) {
     delwin(cont_window);
   }
+  printf("\033[?2004h\n"); // Tell terminal to not use bracketed paste
   endwin();
   ged_deinit(&ged_state);
   heapstr_deinit(&file_name);