nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

commit 958ec294b247c7104fe8af34a519935e5e1cd8a9
parent 3a781fd719eeb14cb1b6f4d026e0f1b749efb375
Author: Benno Schulenberg <bensberg@telfort.nl>
Date:   Tue,  9 Aug 2022 17:04:18 +0200

input: interpret commands of the form {functionname} inside string binds

This allows specifying bindable functions in a string bind by name
instead of by the literal control code or escape sequence to which
they are bound, which makes for a much more readable string bind,
and also allows specifying functions that are not bound to any key.

The opening brace, {, is made into a special symbol inside a string
bind, and each literal occurrence there needs to be escaped as {{}.

This fulfills https://savannah.gnu.org/bugs/?61692.
Requested-by: Tasos Papastylianou <tpapastylianou@hotmail.com>

Original-idea-by: Brand Huntsman <alpha@qzx.com>
  https://lists.gnu.org/archive/html/nano-devel/2018-02/msg00006.html

Diffstat:
Msrc/definitions.h | 12++++++++++++
Msrc/global.c | 7+++++++
Msrc/nano.c | 4++++
Msrc/prototypes.h | 4++++
Msrc/winio.c | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
5 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/src/definitions.h b/src/definitions.h @@ -214,6 +214,18 @@ #define SHIFT_DELETE 0x45D #define SHIFT_TAB 0x45F +/* A special keycode for when a string bind has been partially implanted. */ +#define MORE_PLANTS 0x4EA + +/* A special keycode for when a string bind has an unpaired opening brace. */ +#define MISSING_BRACE 0x4EB + +/* A special keycode for when a function in a string bind needs execution. */ +#define PLANTED_COMMAND 0x4EC + +/* A special keycode for when a function name in a string bind is invalid. */ +#define NO_SUCH_FUNCTION 0x4EF + /* A special keycode for when <Tab> is pressed while the mark is on. */ #define INDENT_KEY 0x4F1 diff --git a/src/global.c b/src/global.c @@ -266,6 +266,9 @@ char *startup_problem = NULL; #endif #ifdef ENABLE_NANORC char *custom_nanorc = NULL; + +char *commandname = NULL; +keystruct *planted_shortcut = NULL; #endif bool spotlighted = FALSE; @@ -460,6 +463,10 @@ const keystruct *get_shortcut(int *keycode) if (bracketed_paste && *keycode != BRACKETED_PASTE_MARKER) return NULL; #endif +#ifdef ENABLE_NANORC + if (*keycode == PLANTED_COMMAND) + return planted_shortcut; +#endif for (keystruct *sc = sclist; sc != NULL; sc = sc->next) { if ((sc->menus & currmenu) && *keycode == sc->keycode) diff --git a/src/nano.c b/src/nano.c @@ -1269,6 +1269,10 @@ void unbound_key(int code) /* TRANSLATORS: This refers to a sequence of escape codes * (from the keyboard) that nano does not recognize. */ statusline(AHEM, _("Unknown sequence")); + else if (code == MISSING_BRACE) + statusline(AHEM, _("Missing }")); + else if (code == NO_SUCH_FUNCTION) + statusline(AHEM, _("No such function: %s"), commandname); #ifndef NANO_TINY else if (code > KEY_F0 && code < KEY_F0 + 25) /* TRANSLATORS: This refers to an unbound function key. */ diff --git a/src/prototypes.h b/src/prototypes.h @@ -181,6 +181,9 @@ extern char *startup_problem; #endif #ifdef ENABLE_NANORC extern char *custom_nanorc; + +extern char *commandname; +extern keystruct *planted_shortcut; #endif extern bool spotlighted; @@ -440,6 +443,7 @@ void display_rcfile_errors(void); void jot_error(const char *msg, ...); #endif #ifdef ENABLE_NANORC +keystruct *strtosc(const char *input); #ifdef ENABLE_COLOR void parse_one_include(char *file, syntaxtype *syntax); void grab_and_store(const char *kind, char *ptr, regexlisttype **storage); diff --git a/src/winio.c b/src/winio.c @@ -64,6 +64,8 @@ static bool has_more = FALSE; /* Whether the current line has more text after the displayed part. */ static bool is_shorter = TRUE; /* Whether a row's text is narrower than the screen's width. */ +static const char *plants_pointer = NULL; + /* Points into the expansion string for the current implantation. */ #ifndef NANO_TINY static size_t sequel_column = 0; /* The starting column of the next chunk when softwrapping. */ @@ -326,14 +328,60 @@ void put_back(int keycode) } #ifdef ENABLE_NANORC -/* Insert the given string into the keyboard buffer. */ +/* Set up the given expansion string to be ingested by the keyboard routines. */ void implant(const char *string) { - for (int i = strlen(string); i > 0; i--) - put_back((unsigned char)string[i - 1]); + plants_pointer = string; + put_back(MORE_PLANTS); mute_modifiers = TRUE; } + +/* Continue processing an expansion string. Returns either an error code, + * a plain keycode, or a placeholder for a command shortcut. */ +int get_code_from_plantation(void) +{ + if (*plants_pointer == '{') { + char *closing = strchr(plants_pointer + 1, '}'); + + if (!closing) + return MISSING_BRACE; + + if (plants_pointer[1] == '{' && plants_pointer[2] == '}') { + plants_pointer += 3; + if (*plants_pointer != '\0') + put_back(MORE_PLANTS); + return '{'; + } + + free(commandname); + free(planted_shortcut); + + commandname = measured_copy(plants_pointer + 1, closing - plants_pointer - 1); + planted_shortcut = strtosc(commandname); + + if (planted_shortcut) { + plants_pointer = closing + 1; + if (*plants_pointer != '\0') + put_back(MORE_PLANTS); + return PLANTED_COMMAND; + } else + return NO_SUCH_FUNCTION; + } else { + char *opening = strchr(plants_pointer, '{'); + int length = (opening ? opening - plants_pointer : strlen(plants_pointer)); + + if (opening) + put_back(MORE_PLANTS); + + for (int index = length - 1; index >= 0; index--) + put_back((unsigned char)plants_pointer[index]); + + plants_pointer += length; + + return ERR; + } +} #endif /* Return one code from the keystroke buffer. If the buffer is empty @@ -347,7 +395,11 @@ int get_input(WINDOW *frame) if (waiting_codes > 0) { waiting_codes--; - return *(nextcodes++); + if (*nextcodes == MORE_PLANTS) { + nextcodes++; + return get_code_from_plantation(); + } else + return *(nextcodes++); } else return ERR; } @@ -940,7 +992,8 @@ int parse_kbinput(WINDOW *frame) } else if (++escapes > 2) escapes = (last_escape_was_alone ? 0 : 1); return ERR; - } + } else if (keycode == ERR) + return ERR; if (escapes == 0) { /* Most key codes in byte range cannot be special keys. */