Skip to content

Commit 505b387

Browse files
author
Yorhel
committed
Add support for bracketed paste mode + confirm-to-send multiline strings
Slightly modified patch from http://dev.yorhel.nl/ncdc/bug/66
1 parent 4b5607d commit 505b387

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

src/commands.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,13 @@ void cmd_handle(char *ostr) {
13131313
// it is a command, extract cmd and args
13141314
} else {
13151315
cmd++;
1316+
1317+
if(strchr(cmd, '\n')) {
1318+
g_free(str);
1319+
ui_m(NULL, 0, "Commands cannot contain newlines");
1320+
return;
1321+
}
1322+
13161323
char *sep = strchr(cmd, ' ');
13171324
if(sep)
13181325
*sep = 0;

src/main.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ GMainLoop *main_loop;
5050
#define INPT_CODE(key) ((gunichar)((key)&G_GUINT64_CONSTANT(0xFFFFFFFF)))
5151
#define INPT_TYPE(key) ((char)((key)>>32))
5252

53-
#define KEY_ESCAPE (KEY_MAX+1)
53+
#define KEY_ESCAPE (KEY_MAX+1)
54+
#define KEY_BRACKETED_PASTE_START (KEY_ESCAPE+1)
55+
#define KEY_BRACKETED_PASTE_END (KEY_BRACKETED_PASTE_START+1)
5456

5557
#endif
5658

@@ -126,7 +128,7 @@ static void handle_input() {
126128
if(INPT_TYPE(key) != 1)
127129
continue;
128130
if(INPT_CODE(key) == '[') {
129-
curignore = 0;
131+
curignore = 1;
130132
continue;
131133
}
132134
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) {
503505
refresh();
504506
endwin();
505507

508+
// reset bracketed paste mode
509+
printf("\x1b[?2004l"); // http://www.xfree86.org/current/ctlseqs.html#C1%20%288-Bit%29%20Control%20Characters
510+
506511
printf("Flushing unsaved data to disk...");
507512
fflush(stdout);
508513
}

src/ui.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ void ui_init() {
254254
keypad(stdscr, 1);
255255
nodelay(stdscr, 1);
256256

257+
// ensure curses is init'd before event-keys defined before events happen
258+
define_key("\x1b[200~", KEY_BRACKETED_PASTE_START);
259+
define_key("\x1b[201~", KEY_BRACKETED_PASTE_END);
260+
261+
const char paste_mode[] = "\x1b[?2004h";
262+
write(STDOUT_FILENO, paste_mode, sizeof(paste_mode)-1);
263+
257264
// global textinput field
258265
ui_global_textinput = ui_textinput_create(TRUE, cmd_suggest);
259266

src/ui_textinput.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ struct ui_textinput_t {
152152
void (*complete)(char *, char **);
153153
char *c_q, *c_last, **c_sug;
154154
int c_cur;
155+
gboolean bracketed_paste;
155156
};
156157

157158
#endif
@@ -163,6 +164,7 @@ ui_textinput_t *ui_textinput_create(gboolean usehist, void (*complete)(char *, c
163164
ti->usehist = usehist;
164165
ti->s_pos = -1;
165166
ti->complete = complete;
167+
ti->bracketed_paste = FALSE;
166168
return ti;
167169
}
168170

@@ -284,7 +286,9 @@ void ui_textinput_draw(ui_textinput_t *ti, int y, int x, int col, ui_cursor_t *c
284286
if(f <= -col)
285287
break;
286288
if(f < 0) {
287-
addnstr(ostr, str-ostr);
289+
// Don't display control characters
290+
if(*ostr >= 32)
291+
addnstr(ostr, str-ostr);
288292
if(i < ti->pos)
289293
pos += l;
290294
}
@@ -426,12 +430,47 @@ gboolean ui_textinput_key(ui_textinput_t *ti, guint64 key, char **str) {
426430
return FALSE;
427431
break;
428432
case INPT_CTRL('i'): // tab - autocomplete
429-
ui_textinput_complete(ti);
430-
completereset = FALSE;
433+
if(ti->bracketed_paste) {
434+
g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, ' ');
435+
ti->pos++;
436+
return FALSE;
437+
} else {
438+
ui_textinput_complete(ti);
439+
completereset = FALSE;
440+
}
431441
break;
432442
case INPT_CTRL('j'): // newline - accept & clear
443+
if(ti->bracketed_paste) {
444+
g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, '\n');
445+
ti->pos++;
446+
return FALSE;
447+
}
448+
449+
// if not responded to, input simply keeps buffering; avoids modality
450+
// reappearing after each (non-bracketed) newline avoids user confusion
451+
// UTF-8: <32 always 1 byte from trusted input
452+
{
453+
int num_lines = 1;
454+
char *c;
455+
for(c=ti->str->str; *c; c++)
456+
num_lines += *c == '\n';
457+
if(num_lines > 1) {
458+
ui_mf(NULL, UIM_NOLOG, "Press Ctrl-y to accept %d-line paste", num_lines);
459+
break;
460+
}
461+
}
462+
463+
*str = ui_textinput_reset(ti);
464+
break;
465+
case INPT_CTRL('y'): // C-y - accept bracketed paste
433466
*str = ui_textinput_reset(ti);
434467
break;
468+
case KEY_BRACKETED_PASTE_START:
469+
ti->bracketed_paste = TRUE;
470+
break;
471+
case KEY_BRACKETED_PASTE_END:
472+
ti->bracketed_paste = FALSE;
473+
break;
435474
default:
436475
if(INPT_TYPE(key) == 1) { // char
437476
g_string_insert_unichar(ti->str, g_utf8_offset_to_pointer(ti->str->str, ti->pos)-ti->str->str, INPT_CODE(key));

0 commit comments

Comments
 (0)