From f705a9674b2ad75702f2c1e8c989558d45a7d243 Mon Sep 17 00:00:00 2001 From: Brand Huntsman Date: Fri, 3 Jan 2020 16:52:21 -0700 Subject: [PATCH] input: recognize the start and stop sequences of a bracketed paste Also, tell the terminal to switch on bracketed-paste mode, and toggle a boolean when the start and stop sequences of such a paste are seen. This boolean can later be used to suppress auto-indent and such. Signed-off-by: Brand Huntsman --- src/global.c | 20 ++++++++++++++++++++ src/nano.c | 19 +++++++++++++++++++ src/nano.h | 3 +++ src/prompt.c | 2 ++ src/proto.h | 2 ++ src/winio.c | 12 ++++++++++++ 6 files changed, 58 insertions(+) diff --git a/src/global.c b/src/global.c index d73bdcd0..5dfc2b1c 100644 --- a/src/global.c +++ b/src/global.c @@ -38,6 +38,8 @@ bool meta_key; /* Whether the current keystroke is a Meta key. */ bool shift_held; /* Whether Shift was being held together with a movement key. */ +bool bracketed_paste = FALSE; + /* Whether text is being pasted into nano from outside. */ bool focusing = TRUE; /* Whether an update of the edit window should center the cursor. */ @@ -336,6 +338,11 @@ void do_cancel(void) { } +/* Ignore the start and stop sequences of a bracketed paste. */ +void do_nothing(void) +{ +} + /* Add a function to the linked list of functions. */ void add_to_funcs(void (*func)(void), int menus, const char *desc, const char *help, bool blank_after, bool viewok) @@ -447,6 +454,16 @@ const keystruct *get_shortcut(int *kbinput) (*kbinput >= 0xA0 && *kbinput <= 0xFF))) return NULL; + if (bracketed_paste && *kbinput != BRACKETED_PASTE_MARKER) { + /* Beep and ignore all non-printable characters in prompts. */ + if (currmenu != MMAIN) + return NULL; + + /* Beep and ignore most non-printable characters in buffer. */ + if (*kbinput != 0x09 && *kbinput != 0xD) + return NULL; + } + for (keystruct *s = sclist; s != NULL; s = s->next) { if ((s->menus & currmenu) && *kbinput == s->keycode && meta_key == s->meta) @@ -1397,6 +1414,9 @@ void shortcut_init(void) #ifdef ENABLE_SPELLER add_to_sclist(MMAIN, "F12", 0, do_spell, 0); #endif + + /* Catch and ignore bracketed paste marker keys. */ + add_to_sclist(MMOST|MHELP|MBROWSER|MYESNO, "", BRACKETED_PASTE_MARKER, do_nothing, 0); } #ifndef NANO_TINY diff --git a/src/nano.c b/src/nano.c index 482e7a21..5b02b0ae 100644 --- a/src/nano.c +++ b/src/nano.c @@ -304,6 +304,13 @@ void say_there_is_no_help(void) } #endif +/* Tell the terminal to disable bracketed pastes. */ +void disable_bracketed_paste(void) +{ + printf("\e[?2004l"); + fflush(stdout); +} + /* Exit normally: restore the terminal state and save history files. */ void finish(void) { @@ -323,6 +330,8 @@ void finish(void) curs_set(1); endwin(); + disable_bracketed_paste(); + /* Restore the old terminal settings. */ tcsetattr(0, TCSANOW, &original_state); @@ -354,6 +363,8 @@ void die(const char *msg, ...) curs_set(1); endwin(); + disable_bracketed_paste(); + /* Restore the old terminal settings. */ tcsetattr(0, TCSANOW, &original_state); @@ -919,6 +930,8 @@ bool scoop_stdin(void) endwin(); tcsetattr(0, TCSANOW, &original_state); + disable_bracketed_paste(); + /* When input comes from a terminal, show a helpful message. */ if (isatty(STANDARD_INPUT)) fprintf(stderr, _("Reading data from keyboard; " @@ -1035,6 +1048,8 @@ RETSIGTYPE do_suspend(int signal) curs_set(1); endwin(); + disable_bracketed_paste(); + printf("\n\n"); /* Display our helpful message. */ @@ -1300,6 +1315,10 @@ void terminal_init(void) } else tcsetattr(0, TCSANOW, &desired_state); #endif + + /* Tell the terminal to enable bracketed pastes. */ + printf("\e[?2004h"); + fflush(stdout); } /* Ask ncurses for a keycode, or assign a default one. */ diff --git a/src/nano.h b/src/nano.h index ba05501c..2011fcde 100644 --- a/src/nano.h +++ b/src/nano.h @@ -610,6 +610,9 @@ enum /* A special keycode for when is pressed while the mark is on. */ #define INDENT_KEY 0x4F1 +/* A special keycode to signal the beginning and end of a bracketed paste. */ +#define BRACKETED_PASTE_MARKER 0x4FB + #ifdef USE_SLANG #ifdef ENABLE_UTF8 #define KEY_BAD 0xFF /* Clipped error code. */ diff --git a/src/prompt.c b/src/prompt.c index d08f8e81..686e0862 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -485,6 +485,8 @@ functionptrtype acquire_an_answer(int *actual, bool allow_tabs, if (func == do_cancel || func == do_enter) break; + if (func == do_nothing) + finished = FALSE; #ifdef ENABLE_TABCOMP if (func != do_tab) diff --git a/src/proto.h b/src/proto.h index 8850c735..c7fc3b5d 100644 --- a/src/proto.h +++ b/src/proto.h @@ -30,6 +30,7 @@ extern bool on_a_vt; extern bool meta_key; extern bool shift_held; +extern bool bracketed_paste; extern bool focusing; @@ -697,3 +698,4 @@ void flip_newbuffer(void); #endif void discard_buffer(void); void do_cancel(void); +void do_nothing(void); diff --git a/src/winio.c b/src/winio.c index 221995fb..92c13070 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1105,6 +1105,18 @@ int convert_sequence(const int *seq, size_t length, int *consumed) /* Discard broken sequences that Slang produces. */ *consumed = 4; #endif + else if (length > 4 && seq[2] == '0' && seq[4] == '~') { + /* Esc [ 2 0 0 ~ == start of a bracketed paste, + * Esc [ 2 0 1 ~ == end of a bracketed paste. */ + *consumed = 5; + if (seq[3] == '0') { + bracketed_paste = TRUE; + return BRACKETED_PASTE_MARKER; + } else if (seq[3] == '1') { + bracketed_paste = FALSE; + return BRACKETED_PASTE_MARKER; + } + } break; case '3': /* Esc [ 3 ~ == Delete on VT220/VT320/ * Linux console/xterm/Terminal. */