summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2014-05-11 08:34:26 +0200
committerYorhel <git@yorhel.nl>2014-05-11 08:36:42 +0200
commit505b387717bea9ea4623059cfff9e41965003bb6 (patch)
tree91342a6d7826093e5a313931ed7b8883e8911c25
parent4b5607df10dc78a22ee09603e2f5c598f62055dc (diff)
Add support for bracketed paste mode + confirm-to-send multiline strings
Slightly modified patch from http://dev.yorhel.nl/ncdc/bug/66
-rw-r--r--src/commands.c7
-rw-r--r--src/main.c9
-rw-r--r--src/ui.c7
-rw-r--r--src/ui_textinput.c45
4 files changed, 63 insertions, 5 deletions
diff --git a/src/commands.c b/src/commands.c
index f234d18..6c83267 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1313,6 +1313,13 @@ void cmd_handle(char *ostr) {
// it is a command, extract cmd and args
} else {
cmd++;
+
+ if(strchr(cmd, '\n')) {
+ g_free(str);
+ ui_m(NULL, 0, "Commands cannot contain newlines");
+ return;
+ }
+
char *sep = strchr(cmd, ' ');
if(sep)
*sep = 0;
diff --git a/src/main.c b/src/main.c
index 18743da..4487e34 100644
--- a/src/main.c
+++ b/src/main.c
@@ -50,7 +50,9 @@ GMainLoop *main_loop;
#define INPT_CODE(key) ((gunichar)((key)&G_GUINT64_CONSTANT(0xFFFFFFFF)))
#define INPT_TYPE(key) ((char)((key)>>32))
-#define KEY_ESCAPE (KEY_MAX+1)
+#define KEY_ESCAPE (KEY_MAX+1)
+#define KEY_BRACKETED_PASTE_START (KEY_ESCAPE+1)
+#define KEY_BRACKETED_PASTE_END (KEY_BRACKETED_PASTE_START+1)
#endif
@@ -126,7 +128,7 @@ static void handle_input() {
if(INPT_TYPE(key) != 1)
continue;
if(INPT_CODE(key) == '[') {
- curignore = 0;
+ curignore = 1;
continue;
}
key |= (guint64)3<<32; // a not very nice way of saying "turn this key into a INPT_ALT"
@@ -503,6 +505,9 @@ int main(int argc, char **argv) {
refresh();
endwin();
+ // reset bracketed paste mode
+ printf("\x1b[?2004l"); // http://www.xfree86.org/current/ctlseqs.html#C1%20%288-Bit%29%20Control%20Characters
+
printf("Flushing unsaved data to disk...");
fflush(stdout);
}
diff --git a/src/ui.c b/src/ui.c
index 4611d73..79c40be 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -254,6 +254,13 @@ void ui_init() {
keypad(stdscr, 1);
nodelay(stdscr, 1);
+ // ensure curses is init'd before event-keys defined before events happen
+ define_key("\x1b[200~", KEY_BRACKETED_PASTE_START);
+ define_key("\x1b[201~", KEY_BRACKETED_PASTE_END);
+
+ const char paste_mode[] = "\x1b[?2004h";
+ write(STDOUT_FILENO, paste_mode, sizeof(paste_mode)-1);
+
// global textinput field
ui_global_textinput = ui_textinput_create(TRUE, cmd_suggest);
diff --git a/src/ui_textinput.c b/src/ui_textinput.c
index b8608ea..a67cd18 100644
--- a/src/ui_textinput.c
+++ b/src/ui_textinput.c
@@ -152,6 +152,7 @@ struct ui_textinput_t {
void (*complete)(char *, char **);
char *c_q, *c_last, **c_sug;
int c_cur;
+ gboolean bracketed_paste;
};
#endif
@@ -163,6 +164,7 @@ ui_textinput_t *ui_textinput_create(gboolean usehist, void (*complete)(char *, c
ti->usehist = usehist;
ti->s_pos = -1;
ti->complete = complete;
+ ti->bracketed_paste = FALSE;
return ti;
}
@@ -284,7 +286,9 @@ void ui_textinput_draw(ui_textinput_t *ti, int y, int x, int col, ui_cursor_t *c
if(f <= -col)
break;
if(f < 0) {
- addnstr(ostr, str-ostr);
+ // Don't display control characters
+ if(*ostr >= 32)
+ addnstr(ostr, str-ostr);
if(i < ti->pos)
pos += l;
}
@@ -426,12 +430,47 @@ gboolean ui_textinput_key(ui_textinput_t *ti, guint64 key, char **str) {
return FALSE;
break;
case INPT_CTRL('i'): // tab - autocomplete
- ui_textinput_complete(ti);
- completereset = FALSE;
+ if(ti->bracketed_paste) {
+ g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, ' ');
+ ti->pos++;
+ return FALSE;
+ } else {
+ ui_textinput_complete(ti);
+ completereset = FALSE;
+ }
break;
case INPT_CTRL('j'): // newline - accept & clear
+ if(ti->bracketed_paste) {
+ g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, '\n');
+ ti->pos++;
+ return FALSE;
+ }
+
+ // if not responded to, input simply keeps buffering; avoids modality
+ // reappearing after each (non-bracketed) newline avoids user confusion
+ // UTF-8: <32 always 1 byte from trusted input
+ {
+ int num_lines = 1;
+ char *c;
+ for(c=ti->str->str; *c; c++)
+ num_lines += *c == '\n';
+ if(num_lines > 1) {
+ ui_mf(NULL, UIM_NOLOG, "Press Ctrl-y to accept %d-line paste", num_lines);
+ break;
+ }
+ }
+
+ *str = ui_textinput_reset(ti);
+ break;
+ case INPT_CTRL('y'): // C-y - accept bracketed paste
*str = ui_textinput_reset(ti);
break;
+ case KEY_BRACKETED_PASTE_START:
+ ti->bracketed_paste = TRUE;
+ break;
+ case KEY_BRACKETED_PASTE_END:
+ ti->bracketed_paste = FALSE;
+ break;
default:
if(INPT_TYPE(key) == 1) { // char
g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, INPT_CODE(key));