about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-08-09 20:01:42 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-08-09 20:01:42 -0700
commite709c65e67f873541b958ba43e425b08f3e073e3 (patch)
tree37d7203b4f2874e41e178938f1f00917dae949c8
parent6fef33fd0872ffcb5141a926d1dae5b0eded3071 (diff)
downloadmu-e709c65e67f873541b958ba43e425b08f3e073e3.tar.gz
1964 - don't mess up paste
It took me a long time to fix termbox because the escape codes it was
seeing seemed all wrong. Had to stop calling tb_shutdown/printf and put
in the extra 3 lines to log to a file. Then everything cleared up.
Weird.
-rw-r--r--edit.mu61
-rw-r--r--termbox/input.inl35
-rw-r--r--termbox/output.inl28
-rw-r--r--termbox/termbox.c2
-rw-r--r--termbox/termbox.h2
5 files changed, 115 insertions, 13 deletions
diff --git a/edit.mu b/edit.mu
index 369d0089..a61940e7 100644
--- a/edit.mu
+++ b/edit.mu
@@ -83,6 +83,7 @@ recipe new-editor [
   *y <- copy *init
   # initial render to screen, just for some old tests
   _, screen <- render screen, result
+  +editor-initialization
   reply result
 ]
 
@@ -1017,7 +1018,16 @@ scenario editor-wraps-cursor-after-inserting-characters-2 [
   ]
 ]
 
-# if newline, move cursor to start of next line
+# if newline, move cursor to start of next line, and maybe align indent with previous line
+
+container editor-data [
+  indent:boolean
+]
+
+after +editor-initialization [
+  indent:address:boolean <- get-address *result, indent:offset
+  *indent <- copy 1/true
+]
 
 scenario editor-moves-cursor-down-after-inserting-newline [
   assume-screen 10/width, 5/height
@@ -1052,6 +1062,8 @@ after +insert-character-special-case [
       *cursor-row <- subtract *cursor-row, 1  # bring back into screen range
     }
     # indent if necessary
+    indent?:boolean <- get *editor, indent:offset
+    reply-unless indent?
     d:address:duplex-list <- get *editor, data:offset
     end-of-previous-line:address:duplex-list <- prev-duplex *before-cursor
     indent:number <- line-indent end-of-previous-line, d
@@ -1173,6 +1185,52 @@ ef]
   ]
 ]
 
+scenario editor-skips-indent-around-paste [
+  assume-screen 10/width, 10/height
+  1:address:array:character <- new [ab
+  cd
+ef]
+  2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right
+  # position cursor after 'cd' and hit 'newline' surrounded by paste markers
+  assume-console [
+    left-click 2, 8
+    press 65507  # start paste
+    type [
+]
+    press 65506  # end paste
+  ]
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+    3:number <- get *2:address:editor-data, cursor-row:offset
+    4:number <- get *2:address:editor-data, cursor-column:offset
+  ]
+  # cursor should be below start of previous line
+  memory-should-contain [
+    3 <- 3  # cursor row
+    4 <- 0  # cursor column (not indented)
+  ]
+]
+
+after +handle-special-key [
+  {
+    paste-start?:boolean <- equal *k, 65507/paste-start
+    break-unless paste-start?
+    indent:address:boolean <- get-address *editor, indent:offset
+    *indent <- copy 0/false
+    reply
+  }
+]
+
+after +handle-special-key [
+  {
+    paste-end?:boolean <- equal *k, 65506/paste-end
+    break-unless paste-end?
+    indent:address:boolean <- get-address *editor, indent:offset
+    *indent <- copy 1/true
+    reply
+  }
+]
+
 ## special shortcuts for manipulating the editor
 # Some keys on the keyboard generate unicode characters, others generate
 # terminfo key codes. We need to modify different places in the two cases.
@@ -3765,6 +3823,7 @@ recipe new-programming-environment [
   current-sandbox:address:address:editor-data <- get-address *result, current-sandbox:offset
   *current-sandbox <- new-editor initial-sandbox-contents, screen, new-left, width/right
   screen <- render-all screen, result
+  +programming-environment-initialization
   reply result
 ]
 
diff --git a/termbox/input.inl b/termbox/input.inl
index 618e0b28..4cbba0a5 100644
--- a/termbox/input.inl
+++ b/termbox/input.inl
@@ -12,9 +12,20 @@ static bool starts_with(const char *s1, int len, const char *s2)
   return *s2 == 0;
 }
 
+#define FOO(...) { \
+  FILE* f = fopen("log", "a+"); \
+  fprintf(f, __VA_ARGS__); \
+  fclose(f); \
+}
+
 // convert escape sequence to event, and return consumed bytes on success (failure == 0)
 static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
 {
+//?   int x = 0;
+//?   FOO("-- %d\n", len);
+//?   for (x = 0; x < len; ++x) {
+//?     FOO("%d\n", (unsigned char)buf[x]);
+//?   }
   if (len >= 6 && starts_with(buf, len, "\033[M")) {
 
     switch (buf[3] & 3) {
@@ -58,6 +69,18 @@ static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
       return strlen(keys[i]);
     }
   }
+
+  if (starts_with(buf, len, "\033[200~")) {
+    event->ch = 0;
+    event->key = TB_KEY_START_PASTE;
+    return strlen("\033[200~");
+  }
+  if (starts_with(buf, len, "\033[201~")) {
+    event->ch = 0;
+    event->key = TB_KEY_END_PASTE;
+    return strlen("\033[201~");
+  }
+
   return 0;
 }
 
@@ -68,8 +91,15 @@ static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf)
   if (len == 0)
     return false;
 
+//?   int x = 0;
+//?   FOO("== %d\n", len);
+//?   for (x = 0; x < len; ++x) {
+//?     FOO("%x\n", (unsigned char)buf[x]);
+//?   }
   if (buf[0] == '\033') {
+//?     FOO("AAA\n");
     int n = parse_escape_seq(event, buf, len);
+//?     FOO("AAA: %u %u %u %u\n", n, (unsigned int)event->type, (unsigned int)event->key, event->ch);
     if (n != 0) {
       bool success = true;
       if (n < 0) {
@@ -79,6 +109,7 @@ static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf)
       bytebuffer_truncate(inbuf, n);
       return success;
     } else {
+//?       FOO("escape sequence\n");
       // it's not escape sequence; assume it's esc
       event->ch = 0;
       event->key = TB_KEY_ESC;
@@ -94,6 +125,7 @@ static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf)
   if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
       (unsigned char)buf[0] == TB_KEY_BACKSPACE2)
   {
+//?     FOO("BBB\n");
     // fill event, pop buffer, return success */
     event->ch = 0;
     event->key = (uint16_t)buf[0];
@@ -105,8 +137,10 @@ static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf)
 
   // check if there is all bytes
   if (len >= tb_utf8_char_length(buf[0])) {
+//?     FOO("CCC\n");
     /* everything ok, fill event, pop buffer, return success */
     tb_utf8_char_to_unicode(&event->ch, buf);
+//?     FOO("CCC: %d\n", event->ch);
     event->key = 0;
     bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
     return true;
@@ -114,5 +148,6 @@ static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf)
 
   // event isn't recognized, perhaps there is not enough bytes in utf8
   // sequence
+//?   FOO("ZZZ\n");
   return false;
 }
diff --git a/termbox/output.inl b/termbox/output.inl
index 427f221c..277817fa 100644
--- a/termbox/output.inl
+++ b/termbox/output.inl
@@ -13,6 +13,8 @@ enum {
   T_EXIT_KEYPAD,
   T_ENTER_MOUSE,
   T_EXIT_MOUSE,
+  T_ENTER_BRACKETED_PASTE,
+  T_EXIT_BRACKETED_PASTE,
   T_FUNCS_NUM,
 };
 
@@ -23,7 +25,7 @@ static const char *rxvt_256color_keys[] = {
   "\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C", 0
 };
 static const char *rxvt_256color_funcs[] = {
-  "\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>", "\033[?1000h", "\033[?1000l",
+  "\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>", "\033[?1000h", "\033[?1000l", "\033[?2004h", "\033[?2004l",
 };
 
 // Eterm
@@ -31,7 +33,7 @@ static const char *eterm_keys[] = {
   "\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C", 0
 };
 static const char *eterm_funcs[] = {
-  "\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "", "", "",
+  "\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "", "", "", "", "",
 };
 
 // screen
@@ -39,7 +41,7 @@ static const char *screen_keys[] = {
   "\033OP", "\033OQ", "\033OR", "\033OS", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[1~", "\033[4~", "\033[5~", "\033[6~", "\033OA", "\033OB", "\033OD", "\033OC", 0
 };
 static const char *screen_funcs[] = {
-  "\033[?1049h", "\033[?1049l", "\033[34h\033[?25h", "\033[?25l", "\033[H\033[J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>", "\033[?1000h", "\033[?1000l",
+  "\033[?1049h", "\033[?1049l", "\033[34h\033[?25h", "\033[?25l", "\033[H\033[J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>", "\033[?1000h", "\033[?1000l", "\033[?2004h", "\033[?2004l",
 };
 
 // rxvt-unicode
@@ -47,7 +49,7 @@ static const char *rxvt_unicode_keys[] = {
   "\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C", 0
 };
 static const char *rxvt_unicode_funcs[] = {
-  "\033[?1049h", "\033[r\033[?1049l", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m\033(B", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>", "\033[?1000h", "\033[?1000l",
+  "\033[?1049h", "\033[r\033[?1049l", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m\033(B", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>", "\033[?1000h", "\033[?1000l", "\033[?2004h", "\033[?2004l",
 };
 
 // linux
@@ -55,7 +57,7 @@ static const char *linux_keys[] = {
   "\033[[A", "\033[[B", "\033[[C", "\033[[D", "\033[[E", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[1~", "\033[4~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C", 0
 };
 static const char *linux_funcs[] = {
-  "", "", "\033[?25h\033[?0c", "\033[?25l\033[?1c", "\033[H\033[J", "\033[0;10m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "", "", "",
+  "", "", "\033[?25h\033[?0c", "\033[?25l\033[?1c", "\033[H\033[J", "\033[0;10m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "", "", "", "", "",
 };
 
 // xterm
@@ -63,7 +65,7 @@ static const char *xterm_keys[] = {
   "\033OP", "\033OQ", "\033OR", "\033OS", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033OH", "\033OF", "\033[5~", "\033[6~", "\033OA", "\033OB", "\033OD", "\033OC", 0
 };
 static const char *xterm_funcs[] = {
-  "\033[?1049h", "\033[?1049l", "\033[?12l\033[?25h", "\033[?25l", "\033[H\033[2J", "\033(B\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>", "\033[?1000h", "\033[?1000l",
+  "\033[?1049h", "\033[?1049l", "\033[?12l\033[?25h", "\033[?25l", "\033[H\033[2J", "\033(B\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>", "\033[?1000h", "\033[?1000l", "\033[?2004h", "\033[?2004l",
 };
 
 static struct term {
@@ -273,15 +275,17 @@ static int init_term(void) {
   keys[TB_KEYS_NUM] = 0;
 
   funcs = malloc(sizeof(const char*) * T_FUNCS_NUM);
-  // the last two entries are reserved for mouse. because the table offset is
+  // the last four entries are reserved for mouse, bracketed paste. because the table offset is
   // not there, the two entries have to fill in manually
-  for (i = 0; i < T_FUNCS_NUM-2; i++) {
+  for (i = 0; i < T_FUNCS_NUM-4; i++) {
     funcs[i] = terminfo_copy_string(data,
       str_offset + 2 * ti_funcs[i], table_offset);
   }
 
-  funcs[T_FUNCS_NUM-2] = "\033[?1000h";
-  funcs[T_FUNCS_NUM-1] = "\033[?1000l";
+  funcs[T_FUNCS_NUM-4] = "\033[?1000h";
+  funcs[T_FUNCS_NUM-3] = "\033[?1000l";
+  funcs[T_FUNCS_NUM-2] = "\033[?2004h";
+  funcs[T_FUNCS_NUM-1] = "\033[?2004l";
 
   init_from_terminfo = true;
   free(data);
@@ -294,10 +298,10 @@ static void shutdown_term(void) {
     for (i = 0; i < TB_KEYS_NUM; i++) {
       free((void*)keys[i]);
     }
-    // the last two entries are reserved for mouse. because the table offset
+    // the last four entries are reserved for mouse, bracketed paste. because the table offset
     // is not there, the two entries have to fill in manually and do not
     // need to be freed.
-    for (i = 0; i < T_FUNCS_NUM-2; i++) {
+    for (i = 0; i < T_FUNCS_NUM-4; i++) {
       free((void*)funcs[i]);
     }
     free(keys);
diff --git a/termbox/termbox.c b/termbox/termbox.c
index 0092abd1..d8cc4514 100644
--- a/termbox/termbox.c
+++ b/termbox/termbox.c
@@ -116,6 +116,7 @@ int tb_init(void)
   bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]);
   bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]);
   bytebuffer_puts(&output_buffer, funcs[T_ENTER_MOUSE]);
+  bytebuffer_puts(&output_buffer, funcs[T_ENTER_BRACKETED_PASTE]);
   send_clear();
 
   update_term_size();
@@ -137,6 +138,7 @@ void tb_shutdown(void)
   bytebuffer_puts(&output_buffer, funcs[T_EXIT_CA]);
   bytebuffer_puts(&output_buffer, funcs[T_EXIT_KEYPAD]);
   bytebuffer_puts(&output_buffer, funcs[T_EXIT_MOUSE]);
+  bytebuffer_puts(&output_buffer, funcs[T_EXIT_BRACKETED_PASTE]);
   bytebuffer_flush(&output_buffer, inout);
   tcsetattr(inout, TCSAFLUSH, &orig_tios);
 
diff --git a/termbox/termbox.h b/termbox/termbox.h
index c257434c..c629b01c 100644
--- a/termbox/termbox.h
+++ b/termbox/termbox.h
@@ -127,6 +127,8 @@ struct tb_event {
 #define TB_KEY_MOUSE_RELEASE    (0xFFFF-25)
 #define TB_KEY_MOUSE_WHEEL_UP   (0xFFFF-26)
 #define TB_KEY_MOUSE_WHEEL_DOWN (0xFFFF-27)
+#define TB_KEY_START_PASTE (0xFFFF-28)
+#define TB_KEY_END_PASTE (0xFFFF-29)
 /* These are all ASCII code points below SPACE character and a BACKSPACE key. */
 #define TB_KEY_CTRL_TILDE       0x00
 #define TB_KEY_CTRL_2           0x00 /* clash with 'CTRL_TILDE' */