From 541a2dbc88419f023c9b1961ba8df081c6622a4f Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 25 Aug 2022 08:48:07 +0200 Subject: [PATCH 01/43] feedback: suppress undo/redo messages when option --zero is in effect This fixes https://savannah.gnu.org/bugs/?62956. Problem existed since version 6.0, since --zero was introduced. --- src/text.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text.c b/src/text.c index bb54b972..faa3f411 100644 --- a/src/text.c +++ b/src/text.c @@ -658,7 +658,7 @@ void do_undo(void) break; } - if (undidmsg && !pletion_line) + if (undidmsg && !ISSET(ZERO) && !pletion_line) statusline(HUSH, _("Undid %s"), undidmsg); openfile->current_undo = openfile->current_undo->next; @@ -828,7 +828,7 @@ void do_redo(void) break; } - if (redidmsg) + if (redidmsg && !ISSET(ZERO)) statusline(HUSH, _("Redid %s"), redidmsg); openfile->current_undo = u; From b1f3bdfcbd61ae28ee6c00029c015d8743ccf3f5 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 26 Aug 2022 09:02:08 +0200 Subject: [PATCH 02/43] extra: use the whole terminal for the crawl, and quicken it a bit Since version 6.0, with option --zero, the edit window can cover the whole terminal. Make use of this also for the credits crawl. Also, shorten and quicken the crawl a bit, and make it start always on the bottom row, instead of (for mysterious reasons) one row higher when the terminal has an odd number of rows. Furthermore, don't put back the key the user typed to stop the crawl. --- src/winio.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/winio.c b/src/winio.c index 2462e427..0676b2ea 100644 --- a/src/winio.c +++ b/src/winio.c @@ -3593,16 +3593,17 @@ void spotlight_softwrapped(size_t from_col, size_t to_col) #endif #ifdef ENABLE_EXTRA -#define CREDIT_LEN 54 +#define CREDIT_LEN 52 #define XLCREDIT_LEN 9 /* Fully blank the terminal screen, then slowly "crawl" the credits over it. * Abort the crawl upon any keystroke. */ void do_credits(void) { - bool with_empty_line = ISSET(EMPTY_LINE); + bool with_interface = !ISSET(ZERO); bool with_help = !ISSET(NO_HELP); int kbinput = ERR, crpos = 0, xlpos = 0; + const char *credits[CREDIT_LEN] = { NULL, /* "The nano text editor" */ NULL, /* "version" */ @@ -3650,13 +3651,11 @@ void do_credits(void) "", "", "", - "", "(C) 2022", "Free Software Foundation, Inc.", "", "", "", - "", "https://nano-editor.org/" }; @@ -3672,8 +3671,8 @@ void do_credits(void) N_("Thank you for using nano!") }; - if (with_empty_line || with_help) { - UNSET(EMPTY_LINE); + if (with_interface || with_help) { + SET(ZERO); SET(NO_HELP); window_init(); } @@ -3681,14 +3680,9 @@ void do_credits(void) nodelay(midwin, TRUE); scrollok(midwin, TRUE); - blank_titlebar(); blank_edit(); - blank_statusbar(); - - wrefresh(topwin); wrefresh(midwin); - wrefresh(footwin); - napms(700); + napms(600); for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) { if (crpos < CREDIT_LEN) { @@ -3699,31 +3693,27 @@ void do_credits(void) else what = credits[crpos]; - mvwaddstr(midwin, editwinrows - 1 - (editwinrows % 2), - COLS / 2 - breadth(what) / 2 - 1, what); + mvwaddstr(midwin, editwinrows - 1, (COLS - breadth(what)) / 2, what); wrefresh(midwin); } if ((kbinput = wgetch(midwin)) != ERR) break; - napms(700); + napms(600); wscrl(midwin, 1); wrefresh(midwin); if ((kbinput = wgetch(midwin)) != ERR) break; - napms(700); + napms(600); wscrl(midwin, 1); wrefresh(midwin); } - if (kbinput != ERR) - ungetch(kbinput); - - if (with_empty_line) - SET(EMPTY_LINE); + if (with_interface) + UNSET(ZERO); if (with_help) UNSET(NO_HELP); window_init(); From cd9402075a2a8931b7c4e32817eee9187bfe239b Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 26 Aug 2022 09:29:44 +0200 Subject: [PATCH 03/43] tweaks: elide a variable, rename another, and reshuffle an assignment --- src/winio.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/winio.c b/src/winio.c index 0676b2ea..2663af50 100644 --- a/src/winio.c +++ b/src/winio.c @@ -3602,7 +3602,7 @@ void do_credits(void) { bool with_interface = !ISSET(ZERO); bool with_help = !ISSET(NO_HELP); - int kbinput = ERR, crpos = 0, xlpos = 0; + int crpos = 0, xlpos = 0; const char *credits[CREDIT_LEN] = { NULL, /* "The nano text editor" */ @@ -3686,25 +3686,23 @@ void do_credits(void) for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) { if (crpos < CREDIT_LEN) { - const char *what; + const char *text = credits[crpos]; - if (credits[crpos] == NULL) - what = _(xlcredits[xlpos++]); - else - what = credits[crpos]; + if (!text) + text = _(xlcredits[xlpos++]); - mvwaddstr(midwin, editwinrows - 1, (COLS - breadth(what)) / 2, what); + mvwaddstr(midwin, editwinrows - 1, (COLS - breadth(text)) / 2, text); wrefresh(midwin); } - if ((kbinput = wgetch(midwin)) != ERR) + if (wgetch(midwin) != ERR) break; napms(600); wscrl(midwin, 1); wrefresh(midwin); - if ((kbinput = wgetch(midwin)) != ERR) + if (wgetch(midwin) != ERR) break; napms(600); From d0dc270eec8ca8eeab9ea5314d340e96bbb67efa Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 28 Aug 2022 08:57:03 +0200 Subject: [PATCH 04/43] tweaks: rename two record elements and three parameters, for clarity --- src/definitions.h | 11 +++++------ src/files.c | 4 ++-- src/global.c | 8 ++++---- src/help.c | 4 ++-- src/nano.c | 4 ++-- src/rcfile.c | 2 +- src/winio.c | 2 +- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/definitions.h b/src/definitions.h index e80b2c29..e12598aa 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -639,14 +639,13 @@ typedef struct keystruct { typedef struct funcstruct { void (*func)(void); /* The actual function to call. */ - const char *desc; - /* The function's short description, for example "Where Is". */ + const char *tag; + /* The function's help-line label, for example "Where Is". */ #ifdef ENABLE_HELP - const char *help; - /* The help-screen text for this function. */ + const char *phrase; + /* The function's description for in the help viewer. */ bool blank_after; - /* Whether there should be a blank line after the help text - * for this function. */ + /* Whether to distance this function from the next in the help viewer. */ #endif int menus; /* In what menus this function applies. */ diff --git a/src/files.c b/src/files.c index 998342f7..0b768b04 100644 --- a/src/files.c +++ b/src/files.c @@ -57,7 +57,7 @@ void make_new_buffer(void) openfile->next = newnode; /* There is more than one buffer: show "Close" in help lines. */ - exitfunc->desc = close_tag; + exitfunc->tag = close_tag; more_than_one = !inhelp || more_than_one; } #endif @@ -627,7 +627,7 @@ void close_buffer(void) /* When just one buffer remains open, show "Exit" in the help lines. */ if (openfile && openfile == openfile->next) - exitfunc->desc = exit_tag; + exitfunc->tag = exit_tag; } #endif /* ENABLE_MULTIBUFFER */ diff --git a/src/global.c b/src/global.c index a7ca1862..fe28e703 100644 --- a/src/global.c +++ b/src/global.c @@ -317,8 +317,8 @@ void discard_buffer(void) {;} void do_cancel(void) {;} /* Add a function to the linked list of functions. */ -void add_to_funcs(void (*function)(void), int menus, const char *desc, - const char *help, bool blank_after) +void add_to_funcs(void (*function)(void), int menus, const char *tag, + const char *phrase, bool blank_after) { funcstruct *f = nmalloc(sizeof(funcstruct)); @@ -331,9 +331,9 @@ void add_to_funcs(void (*function)(void), int menus, const char *desc, f->next = NULL; f->func = function; f->menus = menus; - f->desc = desc; + f->tag = tag; #ifdef ENABLE_HELP - f->help = help; + f->phrase = phrase; f->blank_after = blank_after; #endif } diff --git a/src/help.c b/src/help.c index 91c75e7e..ebb90671 100644 --- a/src/help.c +++ b/src/help.c @@ -224,7 +224,7 @@ void help_init(void) * plus translated text, plus one or two \n's. */ for (f = allfuncs; f != NULL; f = f->next) if (f->menus & currmenu) - allocsize += strlen(_(f->help)) + 21; + allocsize += strlen(_(f->phrase)) + 21; #ifndef NANO_TINY /* If we're on the main list, we also count the toggle help text. @@ -282,7 +282,7 @@ void help_init(void) ptr += 10; /* The shortcut's description. */ - ptr += sprintf(ptr, "%s\n", _(f->help)); + ptr += sprintf(ptr, "%s\n", _(f->phrase)); if (f->blank_after) ptr += sprintf(ptr, "\n"); diff --git a/src/nano.c b/src/nano.c index 943cdd3b..27762a94 100644 --- a/src/nano.c +++ b/src/nano.c @@ -480,7 +480,7 @@ void mouse_init(void) #endif /* ENABLE_MOUSE */ /* Print the usage line for the given option to the screen. */ -void print_opt(const char *shortflag, const char *longflag, const char *desc) +void print_opt(const char *shortflag, const char *longflag, const char *description) { int firstwidth = breadth(shortflag); int secondwidth = breadth(longflag); @@ -493,7 +493,7 @@ void print_opt(const char *shortflag, const char *longflag, const char *desc) if (secondwidth < 24) printf("%*s", 24 - secondwidth, " "); - printf("%s\n", _(desc)); + printf("%s\n", _(description)); } /* Explain how to properly use nano and its command-line options. */ diff --git a/src/rcfile.c b/src/rcfile.c index 85f741ec..393867b8 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -1348,7 +1348,7 @@ static void check_vitals_mapped(void) if (f->func == vitals[v] && f->menus & inmenus[v]) { if (first_sc_for(inmenus[v], f->func) == NULL) { jot_error(N_("No key is bound to function '%s' in menu '%s'. " - " Exiting.\n"), f->desc, menu_to_name(inmenus[v])); + " Exiting.\n"), f->tag, menu_to_name(inmenus[v])); die(_("If needed, use nano with the -I option " "to adjust your nanorc settings.\n")); } else diff --git a/src/winio.c b/src/winio.c index 2663af50..9a80b8d2 100644 --- a/src/winio.c +++ b/src/winio.c @@ -2484,7 +2484,7 @@ void bottombars(int menu) if (index + 2 >= number) thiswidth += COLS % itemwidth; - post_one_key(s->keystr, _(f->desc), thiswidth); + post_one_key(s->keystr, _(f->tag), thiswidth); index++; } From 7bab8780ad9c8ebdf01b9cd9996d38431c1203c4 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 23 Aug 2022 10:47:07 +0200 Subject: [PATCH 05/43] tweaks: rewrap some lines, drop a redundant call, and reshuffle a line Six years ago, commit a878f5f1 introduced a call of regenerate_screen() directly in the input routine, which made the call of refresh_func() in the prompt routine redundant -- except when in the file browser. --- src/nano.c | 7 +++---- src/prompt.c | 10 ++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/nano.c b/src/nano.c index 27762a94..0fb894bd 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1379,9 +1379,8 @@ bool wanted_to_move(void (*func)(void)) /* Return TRUE when the given function makes a change -- no good for view mode. */ bool changes_something(const void *f) { - return (f == do_savefile || f == do_writeout || f == do_enter || - f == do_tab || f == do_delete || f == do_backspace || - f == cut_text || f == paste_text || f == do_replace || + return (f == do_savefile || f == do_writeout || f == do_enter || f == do_tab || + f == do_delete || f == do_backspace || f == cut_text || f == paste_text || #ifndef NANO_TINY f == chop_previous_word || f == chop_next_word || f == zap_text || f == cut_till_eof || f == do_execute || @@ -1399,7 +1398,7 @@ bool changes_something(const void *f) #ifdef ENABLE_WORDCOMPLETION f == complete_a_word || #endif - f == do_verbatim_input); + f == do_replace || f == do_verbatim_input); } #ifndef NANO_TINY diff --git a/src/prompt.c b/src/prompt.c index 4a828638..f99bec25 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -442,7 +442,7 @@ functionptrtype acquire_an_answer(int *actual, bool *listed, #ifndef NANO_TINY /* If the window size changed, go reformat the prompt string. */ if (input == KEY_WINCH) { - refresh_func(); + refresh_func(); /* Only needed when in file browser. */ *actual = KEY_WINCH; #ifdef ENABLE_HISTORIES free(stored_string); @@ -595,20 +595,18 @@ int do_prompt(int menu, const char *provided, linestruct **history_list, function = acquire_an_answer(&retval, &listed, history_list, refresh_func); free(prompt); - prompt = saved_prompt; #ifndef NANO_TINY if (retval == KEY_WINCH) goto redo_theprompt; #endif - /* If we're done with this prompt, restore the x position to what - * it was at a possible previous prompt. */ + /* Restore a possible previous prompt and maybe the typing position. */ + prompt = saved_prompt; if (function == do_cancel || function == do_enter) typing_x = was_typing_x; - /* If we left the prompt via Cancel or Enter, set the return value - * properly. */ + /* Set the proper return value for Cancel and Enter. */ if (function == do_cancel) retval = -1; else if (function == do_enter) From 4f9abb52a46a30cee505ab8521653bf7172fc4d3 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 28 Aug 2022 12:57:45 +0200 Subject: [PATCH 06/43] build: fix compilation when configured with --enable-tiny Problem existed since commit d1e28417 from four days ago. --- src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 22631b5b..661a35ca 100644 --- a/src/utils.c +++ b/src/utils.c @@ -484,6 +484,7 @@ void get_range(linestruct **top, linestruct **bot) also_the_last = TRUE; } } +#endif /* !NANO_TINY */ /* Return a pointer to the line that has the given line number. */ linestruct *line_from_number(ssize_t number) @@ -499,7 +500,6 @@ linestruct *line_from_number(ssize_t number) return line; } -#endif /* !NANO_TINY */ /* Count the number of characters from begin to end, and return it. */ size_t number_of_characters_in(const linestruct *begin, const linestruct *end) From 6243831dfbcb87e4de200e70a2b7b95a86948035 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 28 Aug 2022 16:31:04 +0200 Subject: [PATCH 07/43] build: add options --disable-formatter and --disable-linter to configure This makes more sense than letting the formatter and the linter depend on ENABLE_COLOR (which maybe should have been named ENABLE_SYNTAX). This fulfills https://savannah.gnu.org/bugs/?50080. --- configure.ac | 54 +++++++++++++++++++++++++++++++++++++++++++++--- src/global.c | 18 ++++++++++------ src/nano.c | 14 ++++++++++++- src/prototypes.h | 4 +++- src/rcfile.c | 4 +++- src/text.c | 12 +++++++---- 6 files changed, 90 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 5cad9a75..3b37b3d8 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,30 @@ if test "x$enable_extra" != xno; then AC_DEFINE(ENABLE_EXTRA, 1, [Define this to have an Easter egg.]) fi +AC_ARG_ENABLE(formatter, +AS_HELP_STRING([--disable-formatter], [Disable the formatting tool])) +if test "x$enable_tiny" = xyes; then + if test "x$enable_formatter" = xyes; then + if test "x$enable_color" != xyes; then + AC_MSG_ERROR([ + *** --enable-formatter needs both --enable-color and --enable-nanorc to work]) + fi + else + enable_formatter=no + fi +fi +if test "x$enable_color" = xno; then + if test "x$enable_formatter" = xyes; then + AC_MSG_ERROR([ + *** --enable-formatter cannot work with --disable-color nor --disable-nanorc]) + else + enable_formatter=no + fi +fi +if test "x$enable_formatter" != xno; then + AC_DEFINE(ENABLE_FORMATTER, 1, [Define this to have access to a formatter.]) +fi + AC_ARG_ENABLE(help, AS_HELP_STRING([--disable-help], [Disable the built-in help texts])) if test "x$enable_tiny" = xyes; then @@ -206,7 +230,7 @@ if test "x$enable_libmagic" = xyes; then if test "x$enable_tiny" = xyes; then if test "x$enable_color" != xyes; then AC_MSG_ERROR([ - *** --enable-libmagic needs --enable-color and --enable-nanorc to work]) + *** --enable-libmagic needs both --enable-color and --enable-nanorc to work]) fi fi if test "x$enable_color" = xno; then @@ -215,6 +239,30 @@ if test "x$enable_libmagic" = xyes; then fi fi +AC_ARG_ENABLE(linter, +AS_HELP_STRING([--disable-linter], [Disable the linting tool])) +if test "x$enable_tiny" = xyes; then + if test "x$enable_linter" = xyes; then + if test "x$enable_color" != xyes; then + AC_MSG_ERROR([ + *** --enable-linter needs both --enable-color and --enable-nanorc to work]) + fi + else + enable_linter=no + fi +fi +if test "x$enable_color" = xno; then + if test "x$enable_linter" = xyes; then + AC_MSG_ERROR([ + *** --enable-linter cannot work with --disable-color nor --disable-nanorc]) + else + enable_linter=no + fi +fi +if test "x$enable_linter" != xno; then + AC_DEFINE(ENABLE_LINTER, 1, [Define this to have access to a linter.]) +fi + AC_ARG_ENABLE(linenumbers, AS_HELP_STRING([--disable-linenumbers], [Disable line numbering])) if test "x$enable_tiny" = xyes; then @@ -272,14 +320,14 @@ if test "x$enable_operatingdir" != xno; then fi AC_ARG_ENABLE(speller, -AS_HELP_STRING([--disable-speller], [Disable the spell-checker functions])) +AS_HELP_STRING([--disable-speller], [Disable the spell-checking tool])) if test "x$enable_tiny" = xyes; then if test "x$enable_speller" != xyes; then enable_speller=no fi fi if test "x$enable_speller" != xno; then - AC_DEFINE(ENABLE_SPELLER, 1, [Define this to have the spell-checker functions.]) + AC_DEFINE(ENABLE_SPELLER, 1, [Define this to have access to a spell checker.]) fi AC_ARG_ENABLE(tabcomp, diff --git a/src/global.c b/src/global.c index fe28e703..8af8dc8d 100644 --- a/src/global.c +++ b/src/global.c @@ -689,10 +689,12 @@ void shortcut_init(void) const char *browserrefresh_gist = N_("Refresh the file list"); const char *gotodir_gist = N_("Go to directory"); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER const char *lint_gist = N_("Invoke the linter, if available"); const char *prevlint_gist = N_("Go to previous linter msg"); const char *nextlint_gist = N_("Go to next linter msg"); +#endif +#ifdef ENABLE_FORMATTER const char *formatter_gist = N_("Invoke a program to format/arrange/manipulate the buffer"); #endif @@ -1013,9 +1015,11 @@ void shortcut_init(void) add_to_funcs(do_spell, MMAIN, N_("Spell Check"), WHENHELP(spell_gist), TOGETHER); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER add_to_funcs(do_linter, MMAIN, N_("Linter"), WHENHELP(lint_gist), TOGETHER); +#endif +#ifdef ENABLE_FORMATTER add_to_funcs(do_formatter, MMAIN, N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER); #endif @@ -1055,7 +1059,7 @@ void shortcut_init(void) add_to_funcs(do_spell, MEXECUTE, N_("Spell Check"), WHENHELP(spell_gist), TOGETHER); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER add_to_funcs(do_linter, MEXECUTE, N_("Linter"), WHENHELP(lint_gist), BLANKAFTER); #endif @@ -1063,7 +1067,7 @@ void shortcut_init(void) add_to_funcs(do_full_justify, MEXECUTE, N_("Full Justify"), WHENHELP(fulljustify_gist), TOGETHER); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_FORMATTER add_to_funcs(do_formatter, MEXECUTE, N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER); #endif @@ -1143,7 +1147,7 @@ void shortcut_init(void) add_to_funcs(discard_buffer, MWRITEFILE, N_("Discard buffer"), WHENHELP(discardbuffer_gist), BLANKAFTER); -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER add_to_funcs(do_page_up, MLINTER, /* TRANSLATORS: The next two strings may be up to 37 characters each. */ N_("Previous Linter message"), WHENHELP(prevlint_gist), TOGETHER); @@ -1197,9 +1201,11 @@ void shortcut_init(void) #ifdef ENABLE_JUSTIFY add_to_sclist(MMAIN, "^J", '\n', do_justify, 0); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER add_to_sclist(MMAIN, "M-B", 0, do_linter, 0); add_to_sclist(MEXECUTE, "^Y", 0, do_linter, 0); +#endif +#ifdef ENABLE_FORMATTER add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0); add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0); #endif diff --git a/src/nano.c b/src/nano.c index 0fb894bd..588ed4b9 100644 --- a/src/nano.c +++ b/src/nano.c @@ -688,6 +688,9 @@ void version(void) #ifdef ENABLE_EXTRA printf(" --enable-extra"); #endif +#ifdef ENABLE_FORMATTER + printf(" --enable-formatter"); +#endif #ifdef ENABLE_HELP printf(" --enable-help"); #endif @@ -703,6 +706,9 @@ void version(void) #ifdef ENABLE_LINENUMBERS printf(" --enable-linenumbers"); #endif +#ifdef ENABLE_LINTER + printf(" --enable-linter"); +#endif #ifdef ENABLE_MOUSE printf(" --enable-mouse"); #endif @@ -737,6 +743,9 @@ void version(void) #ifndef ENABLE_EXTRA printf(" --disable-extra"); #endif +#ifndef ENABLE_FORMATTER + printf(" --disable-formatter"); +#endif #ifndef ENABLE_HELP printf(" --disable-help"); #endif @@ -752,6 +761,9 @@ void version(void) #ifndef ENABLE_LINENUMBERS printf(" --disable-linenumbers"); #endif +#ifndef ENABLE_LINTER + printf(" --disable-linter"); +#endif #ifndef ENABLE_MOUSE printf(" --disable-mouse"); #endif @@ -1392,7 +1404,7 @@ bool changes_something(const void *f) #ifdef ENABLE_SPELLER f == do_spell || #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_FORMATTER f == do_formatter || #endif #ifdef ENABLE_WORDCOMPLETION diff --git a/src/prototypes.h b/src/prototypes.h index eb70bfbe..0390f6a5 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -520,8 +520,10 @@ void do_full_justify(void); #ifdef ENABLE_SPELLER void do_spell(void); #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER void do_linter(void); +#endif +#ifdef ENABLE_FORMATTER void do_formatter(void); #endif #ifndef NANO_TINY diff --git a/src/rcfile.c b/src/rcfile.c index 393867b8..58053ab7 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -276,9 +276,11 @@ keystruct *strtosc(const char *input) !strcmp(input, "speller")) s->func = do_spell; #endif -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER else if (!strcmp(input, "linter")) s->func = do_linter; +#endif +#ifdef ENABLE_FORMATTER else if (!strcmp(input, "formatter")) s->func = do_formatter; #endif diff --git a/src/text.c b/src/text.c index faa3f411..5837cd41 100644 --- a/src/text.c +++ b/src/text.c @@ -2024,7 +2024,7 @@ void do_full_justify(void) } #endif /* ENABLE_JUSTIFY */ -#if defined(ENABLE_SPELLER) || defined (ENABLE_COLOR) +#if defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER) /* Set up an argument list for executing the given command. */ void construct_argument_list(char ***arguments, char *command, char *filename) { @@ -2041,7 +2041,9 @@ void construct_argument_list(char ***arguments, char *command, char *filename) (*arguments)[count - 2] = filename; (*arguments)[count - 1] = NULL; } +#endif +#if defined(ENABLE_SPELLER) || defined (ENABLE_FORMATTER) /* Open the specified file, and if that succeeds, remove the text of the marked * region or of the entire buffer and read the file contents into its place. */ bool replace_buffer(const char *filename, undo_type action, const char *operation) @@ -2219,7 +2221,7 @@ void treat(char *tempfile_name, char *theprogram, bool spelling) statusline(REMARK, _("Buffer has been processed")); #endif } -#endif /* ENABLE_SPELLER || ENABLE_COLOR */ +#endif /* ENABLE_SPELLER || ENABLE_FORMATTER */ #ifdef ENABLE_SPELLER /* Let the user edit the misspelled word. Return FALSE if the user cancels. */ @@ -2564,7 +2566,7 @@ void do_spell(void) } #endif /* ENABLE_SPELLER */ -#ifdef ENABLE_COLOR +#ifdef ENABLE_LINTER /* Run a linting program on the current buffer. */ void do_linter(void) { @@ -2910,7 +2912,9 @@ void do_linter(void) titlebar(NULL); #endif } +#endif /* ENABLE_LINTER */ +#ifdef ENABLE_FORMATTER /* Run a manipulation program on the contents of the buffer. */ void do_formatter(void) { @@ -2945,7 +2949,7 @@ void do_formatter(void) unlink(temp_name); free(temp_name); } -#endif /* ENABLE_COLOR */ +#endif /* ENABLE_FORMATTER */ #ifndef NANO_TINY /* Our own version of "wc". Note that the character count is in From 80f7852941cf314de864cb4ff7ad52c3d35f9e18 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 28 Aug 2022 17:11:25 +0200 Subject: [PATCH 08/43] docs: describe --disable-formatter and --disable-linter configure options --- doc/faq.html | 4 +++- doc/nano.texi | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/faq.html b/doc/faq.html index 8d74b6b8..73f3863a 100644 --- a/doc/faq.html +++ b/doc/faq.html @@ -150,16 +150,18 @@ --disable-color Disable color and syntax highlighting --disable-comment Disable the comment/uncomment function --disable-extra Disable the easter egg + --disable-formatter Disable the formatting tool --disable-help Disable the built-in help texts --disable-histories Disable the saving of search strings and cursor positions --disable-justify Disable the justify/unjustify functions --disable-libmagic Disable the use of libmagic for determining a file's syntax --disable-linenumbers Disable line numbering + --disable-linter Disable the linting tool --disable-mouse Disable mouse support --disable-multibuffer Disable the opening of multiple file buffers --disable-nanorc Disable the use of .nanorc files --disable-operatingdir Disable the setting of an operating directory - --disable-speller Disable the spell-checker functions + --disable-speller Disable the spell-checking tool --disable-tabcomp Disable the tab-completion functions --disable-wordcomp Disable the word-completion function --disable-wrapping Disable all hard-wrapping of text diff --git a/doc/nano.texi b/doc/nano.texi index 816b95a2..7490e357 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -1941,6 +1941,9 @@ Exclude the single-keystroke comment/uncomment function (@w{@kbd{M-3}}). @item --disable-extra Exclude the Easter egg: a crawl of major contributors. +@item --disable-formatter +Exclude the code for calling a formatting tool. + @item --disable-help Exclude the help texts (@kbd{^G}). This makes the binary much smaller, but also makes it difficult for new users to learn more than very basic @@ -1966,6 +1969,9 @@ in most cases the regexes for filename and header line will be enough). Exclude the ability to show line numbers. This also eliminates the @option{-l} command-line option, which turns line numbering on. +@item --disable-linter +Exclude the code for calling a linting tool. + @item --disable-mouse Exclude all mouse functionality. This also eliminates the @option{-m} command-line option, which enables the mouse functionality. From ccabaac5a035f4caf352bc0b422071129595b666 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 29 Aug 2022 08:44:28 +0200 Subject: [PATCH 09/43] build: exclude two unneeded functions correctly from the tiny version This also amends commit 4f9abb52 from yesterday -- I don't know how I managed to overlook the warning. :/ --- src/prototypes.h | 4 +++- src/search.c | 2 ++ src/utils.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/prototypes.h b/src/prototypes.h index 0390f6a5..03ae8fa6 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -469,7 +469,9 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only, const linestruct *real_current, size_t *real_current_x); void do_replace(void); void ask_for_and_do_replacements(void); +#if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER) void goto_line_posx(ssize_t line, size_t pos_x); +#endif void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer, bool interactive); void do_gotolinecolumn(void); @@ -572,7 +574,7 @@ void get_region(linestruct **top, size_t *top_x, linestruct **bot, size_t *bot_x void get_range(linestruct **top, linestruct **bot); #endif size_t number_of_characters_in(const linestruct *begin, const linestruct *end); -#ifndef NANO_TINY +#if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER) linestruct *line_from_number(ssize_t number); #endif diff --git a/src/search.c b/src/search.c index d1583eba..4d12138f 100644 --- a/src/search.c +++ b/src/search.c @@ -736,6 +736,7 @@ void ask_for_and_do_replacements(void) "Replaced %zd occurrences", numreplaced), numreplaced); } +#if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER) /* Go to the specified line and x position. */ void goto_line_posx(ssize_t linenumber, size_t pos_x) { @@ -751,6 +752,7 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x) refresh_needed = TRUE; } +#endif /* Go to the specified line and column, or ask for them if interactive * is TRUE. In the latter case also update the screen afterwards. diff --git a/src/utils.c b/src/utils.c index 661a35ca..f1bd5c96 100644 --- a/src/utils.c +++ b/src/utils.c @@ -486,6 +486,7 @@ void get_range(linestruct **top, linestruct **bot) } #endif /* !NANO_TINY */ +#if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER) /* Return a pointer to the line that has the given line number. */ linestruct *line_from_number(ssize_t number) { @@ -500,6 +501,7 @@ linestruct *line_from_number(ssize_t number) return line; } +#endif /* Count the number of characters from begin to end, and return it. */ size_t number_of_characters_in(const linestruct *begin, const linestruct *end) From 97fa42c82bc26b23bec36dccd845c6c5311f0652 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 31 Aug 2022 16:20:29 +0200 Subject: [PATCH 10/43] memory: avoid a leak when a string bind specifies an unknown menu (It is a harmless leak, but LeakSanitizer is loud when it complains.) After having determined that there is a menu name, first check that it is valid, before processing the string or the function name. This fixes https://savannah.gnu.org/bugs/?62991. Problem existed since version 2.9.4, since string binds were introduced. --- src/rcfile.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rcfile.c b/src/rcfile.c index 58053ab7..7ef9d76d 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -787,6 +787,12 @@ void parse_binding(char *ptr, bool dobind) goto free_things; } + menu = name_to_menu(menuptr); + if (menu < 1) { + jot_error(N_("Cannot map name \"%s\" to a menu"), menuptr); + goto free_things; + } + if (dobind) { /* If the thing to bind starts with a double quote, it is a string, * otherwise it is the name of a function. */ @@ -806,12 +812,6 @@ void parse_binding(char *ptr, bool dobind) } } - menu = name_to_menu(menuptr); - if (menu < 1) { - jot_error(N_("Cannot map name \"%s\" to a menu"), menuptr); - goto free_things; - } - /* Wipe the given shortcut from the given menu. */ for (keystruct *s = sclist; s != NULL; s = s->next) if ((s->menus & menu) && s->keycode == keycode) From 3925c137a493888c4bf5770a19b064846e3ee5db Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 31 Aug 2022 16:49:48 +0200 Subject: [PATCH 11/43] tweaks: make two error messages more succinct and easier to translate "Cannot map name %s to ..." was unnecessarily verbose and vague. I have kept these strings unchanged all these years because I didn't want to invalidate the existing translations. But now it's time to harmonize things and simply say "Unknown : %s" for an invalid function name, menu name, option name, and syntax name. ("No such : %s" is nice and snappy, but its translations often are clumsy and longer and unclear.) --- src/nano.c | 2 +- src/rcfile.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nano.c b/src/nano.c index 588ed4b9..5db4f202 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1285,7 +1285,7 @@ void unbound_key(int code) else if (code == MISSING_BRACE) statusline(AHEM, _("Missing }")); else if (code == NO_SUCH_FUNCTION) - statusline(AHEM, _("No such function: %s"), commandname); + statusline(AHEM, _("Unknown function: %s"), commandname); #endif #ifndef NANO_TINY else if (code > KEY_F0 && code < KEY_F0 + 25) diff --git a/src/rcfile.c b/src/rcfile.c index 7ef9d76d..3f72fbda 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -789,7 +789,7 @@ void parse_binding(char *ptr, bool dobind) menu = name_to_menu(menuptr); if (menu < 1) { - jot_error(N_("Cannot map name \"%s\" to a menu"), menuptr); + jot_error(N_("Unknown menu: %s"), menuptr); goto free_things; } @@ -807,7 +807,7 @@ void parse_binding(char *ptr, bool dobind) newsc = strtosc(funcptr); if (newsc == NULL) { - jot_error(N_("Cannot map name \"%s\" to a function"), funcptr); + jot_error(N_("Unknown function: %s"), funcptr); goto free_things; } } @@ -1532,7 +1532,7 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only) } if (rcopts[i].name == NULL) { - jot_error(N_("Unknown option \"%s\""), option); + jot_error(N_("Unknown option: %s"), option); continue; } From 41b89aef8c36e35d96fcf310aeb9657ebc301d7b Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 31 Aug 2022 17:28:09 +0200 Subject: [PATCH 12/43] tweaks: move the arrays of menu names and symbols to where they are used Also, use a better return value for the "unrecognized name" case, so that it cannot possibly be confused with the "all menus" case. --- src/rcfile.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/rcfile.c b/src/rcfile.c index 3f72fbda..966da5d8 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -153,18 +153,6 @@ static bool seen_color_command = FALSE; static colortype *lastcolor = NULL; /* The end of the color list for the current syntax. */ #endif - -#define NUMBER_OF_MENUS 16 -char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith", - "yesno", "gotoline", "writeout", "insert", - "execute", "help", "spell", "linter", - "browser", "whereisfile", "gotodir", - "all" }; -int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH, - MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE, - MEXECUTE, MHELP, MSPELL, MLINTER, - MBROWSER, MWHEREISFILE, MGOTODIR, - MMOST|MBROWSER|MHELP|MYESNO }; #endif /* ENABLE_NANORC */ #if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES) @@ -495,6 +483,18 @@ keystruct *strtosc(const char *input) return s; } +#define NUMBER_OF_MENUS 16 +char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith", + "yesno", "gotoline", "writeout", "insert", + "execute", "help", "spell", "linter", + "browser", "whereisfile", "gotodir", + "all" }; +int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH, + MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE, + MEXECUTE, MHELP, MSPELL, MLINTER, + MBROWSER, MWHEREISFILE, MGOTODIR, + MMOST|MBROWSER|MHELP|MYESNO }; + /* Return the symbol that corresponds to the given menu name. */ int name_to_menu(const char *name) { @@ -504,7 +504,7 @@ int name_to_menu(const char *name) if (strcmp(name, menunames[index]) == 0) return menusymbols[index]; - return -1; + return 0; } /* Return the name that corresponds to the given menu symbol. */ @@ -788,7 +788,7 @@ void parse_binding(char *ptr, bool dobind) } menu = name_to_menu(menuptr); - if (menu < 1) { + if (menu == 0) { jot_error(N_("Unknown menu: %s"), menuptr); goto free_things; } From 9904aa5538dabf885f3cdb6d1e0e88714aef0138 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 1 Sep 2022 08:34:06 +0200 Subject: [PATCH 13/43] tweaks: make the crawl use the whole screen also in the tiny version Nobody will configure nano with --enable-tiny --enable-extra, but *if* someone does, the title bar should be absent during the crawl. Also, swap two messages, so that their order in the POT file will be more sensible -- a closing brace comes after the function name. --- src/nano.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/nano.c b/src/nano.c index 5db4f202..4346895a 100644 --- a/src/nano.c +++ b/src/nano.c @@ -423,10 +423,9 @@ void window_init(void) int toprows = ((ISSET(EMPTY_LINE) && LINES > 6) ? 2 : 1); int bottomrows = ((ISSET(NO_HELP) || LINES < 6) ? 1 : 3); -#ifndef NANO_TINY if (ISSET(MINIBAR) || ISSET(ZERO)) toprows = 0; -#endif + editwinrows = LINES - toprows - bottomrows + (ISSET(ZERO) ? 1 : 0); /* Set up the normal three subwindows. */ @@ -1282,10 +1281,10 @@ void unbound_key(int code) * (from the keyboard) that nano does not recognize. */ statusline(AHEM, _("Unknown sequence")); #ifdef ENABLE_NANORC - else if (code == MISSING_BRACE) - statusline(AHEM, _("Missing }")); else if (code == NO_SUCH_FUNCTION) statusline(AHEM, _("Unknown function: %s"), commandname); + else if (code == MISSING_BRACE) + statusline(AHEM, _("Missing }")); #endif #ifndef NANO_TINY else if (code > KEY_F0 && code < KEY_F0 + 25) From e7491920fd06bdb5eb42303cd84dbb9caca42cb7 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 1 Sep 2022 12:27:24 +0200 Subject: [PATCH 14/43] docs: explain how to include a double quote plus space in a nanorc regex As double-quote-plus-space indicates the end of a regular expression in a nanorc file, the inclusion of this combination *in* a regular expression requires breaking the juxtaposition of the two, which can be achieved by putting either of them between square brackets. (It can also be achieved by preceding the space with a backslash, which is shorter, but... the above method is more symmetrical.) This addresses https://savannah.gnu.org/bugs/?62997. --- doc/nano.texi | 8 ++++++++ doc/nanorc.5 | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/doc/nano.texi b/doc/nano.texi index 7490e357..9b4a13d1 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -1201,6 +1201,14 @@ It also means that lookahead and lookbehind are not possible. A complete explanation can be found in the manual of GNU grep: @code{info grep regular}. +Each regular expression in a @file{nanorc} file should be wrapped in +double quotes (@code{""}). Multiple regular expressions can follow +each other on a line by separating them with blanks. This means that +a regular expression cannot contain a double quote followed by a blank. +When you need this combination inside a regular expression, +then either the double quote or the blank should be put +between square brackets (@code{[]}). + A separate syntax can be defined for each kind of file via the following commands in a nanorc file: diff --git a/doc/nanorc.5 b/doc/nanorc.5 index c8166c02..a707ffd7 100644 --- a/doc/nanorc.5 +++ b/doc/nanorc.5 @@ -426,6 +426,14 @@ It also means that lookahead and lookbehind are not possible. A complete explanation can be found in the manual page of GNU grep: \fBman grep\fR. .sp +Each regular expression in a \fBnanorc\fR file should be wrapped in +double quotes (\fB""\fR). Multiple regular expressions can follow +each other on a line by separating them with blanks. This means that +a regular expression cannot contain a double quote followed by a blank. +When you need this combination inside a regular expression, +then either the double quote or the blank should be put +between square brackets (\fB[]\fR). +.sp For each kind of file a separate syntax can be defined via the following commands: .TP From 40b9e68e02522df3d29941ab89b027d84435795f Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 4 Sep 2022 10:40:17 +0200 Subject: [PATCH 15/43] goto: don't center the current line when the user specified a column only This does not quite do what I would have liked (scroll only when needed) when on a softwrapped line and jumping to a different chunk, but... it's still better than needlessly centering the line. (The user can still center the line, if that is what they want, by using a period or a slash instead of a comma.) This addresses https://savannah.gnu.org/bugs/?63008. --- src/search.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.c b/src/search.c index 4d12138f..d759668b 100644 --- a/src/search.c +++ b/src/search.c @@ -829,9 +829,9 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer, openfile->placewewant = breadth(openfile->current->data); #endif - /* When the position was manually given, center the target line. */ + /* When a line number was manually given, center the target line. */ if (interactive) { - adjust_viewport(CENTERING); + adjust_viewport((*answer == ',') ? STATIONARY : CENTERING); refresh_needed = TRUE; } else { int rows_from_tail; From 75e5f885e5d3d0f63d63e8251fdbc3c3bd334a44 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 6 Sep 2022 17:02:28 +0200 Subject: [PATCH 16/43] verbatim: allow the user to finish Unicode input with or Instead of requiring always six digits, allow the user to indicate with or that the digits typed so far are the complete Unicode code point (when prefixed with the missing number of zeroes). This fulfills https://savannah.gnu.org/bugs/?63021. Inspired-by: the shortcut that some desktops have --- src/winio.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/winio.c b/src/winio.c index 9a80b8d2..76b37cee 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1357,6 +1357,8 @@ long add_unicode_digit(int symbol, long factor, long *unicode) *unicode += (symbol - '0') * factor; else if ('a' <= tolower(symbol) && tolower(symbol) <= 'f') *unicode += (tolower(symbol) - 'a' + 10) * factor; + else if (symbol == '\r' || symbol == ' ') + return (*unicode / factor) >> 4; else return INVALID_DIGIT; @@ -1374,18 +1376,13 @@ long assemble_unicode(int symbol) switch (++digits) { case 1: - unicode = (symbol - '0') * 0x100000; + unicode = 0; + retval = add_unicode_digit(symbol, 0x100000, &unicode); break; case 2: - /* The second digit must be zero if the first was one, but - * may be any hexadecimal value if the first was zero. */ - if (symbol == '0' || unicode == 0) - retval = add_unicode_digit(symbol, 0x10000, &unicode); - else - retval = INVALID_DIGIT; + retval = add_unicode_digit(symbol, 0x10000, &unicode); break; case 3: - /* Later digits may be any hexadecimal value. */ retval = add_unicode_digit(symbol, 0x1000, &unicode); break; case 4: @@ -1397,9 +1394,9 @@ long assemble_unicode(int symbol) case 6: retval = add_unicode_digit(symbol, 0x1, &unicode); /* If also the sixth digit was a valid hexadecimal value, then - * the Unicode sequence is complete, so return it. */ + * the Unicode sequence is complete, so return it when valid. */ if (retval == PROCEED) - retval = unicode; + retval = (unicode < 0x110000) ? unicode : INVALID_DIGIT; break; } @@ -1407,9 +1404,8 @@ long assemble_unicode(int symbol) if (retval == PROCEED && currmenu == MMAIN) { char partial[7] = "......"; - /* Construct the partial result, right-padding it with dots. */ - snprintf(partial, digits + 1, "%06lX", unicode); - partial[digits] = '.'; + /* Construct the partial result, left-padded with dots. */ + snprintf(partial + 6 - digits, digits + 1, "%06lX", unicode); /* TRANSLATORS: This is shown while a six-digit hexadecimal * Unicode character code (%s) is being typed in. */ @@ -1451,7 +1447,7 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count) #ifdef ENABLE_UTF8 /* If the first code is a valid Unicode starter digit (0 or 1), * commence Unicode input. Otherwise, put the code back. */ - if (using_utf8() && (keycode == '0' || keycode == '1')) { + if (using_utf8() && isxdigit(keycode)) { long unicode = assemble_unicode(keycode); char multibyte[MB_CUR_MAX]; From c98528f8d3daec05026491a50b938a036cbf5440 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 7 Sep 2022 11:12:02 +0200 Subject: [PATCH 17/43] tweaks: simplify a function now that a Unicode code can be typed quicker --- src/winio.c | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/winio.c b/src/winio.c index 76b37cee..c8299c22 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1351,14 +1351,14 @@ int get_kbinput(WINDOW *frame, bool showcursor) /* If the given symbol is a valid hexadecimal digit, multiply it by factor * and add the result to the given unicode, and return PROCEED to signify * okay. When not a hexadecimal digit, return the symbol itself. */ -long add_unicode_digit(int symbol, long factor, long *unicode) +long add_unicode_digit(int symbol, long *unicode) { if ('0' <= symbol && symbol <= '9') - *unicode += (symbol - '0') * factor; + *unicode = (*unicode << 4) + symbol - '0'; else if ('a' <= tolower(symbol) && tolower(symbol) <= 'f') - *unicode += (tolower(symbol) - 'a' + 10) * factor; + *unicode = (*unicode << 4) + tolower(symbol) - 'a' + 10; else if (symbol == '\r' || symbol == ' ') - return (*unicode / factor) >> 4; + return *unicode; else return INVALID_DIGIT; @@ -1374,47 +1374,30 @@ long assemble_unicode(int symbol) static int digits = 0; long retval = PROCEED; - switch (++digits) { - case 1: - unicode = 0; - retval = add_unicode_digit(symbol, 0x100000, &unicode); - break; - case 2: - retval = add_unicode_digit(symbol, 0x10000, &unicode); - break; - case 3: - retval = add_unicode_digit(symbol, 0x1000, &unicode); - break; - case 4: - retval = add_unicode_digit(symbol, 0x100, &unicode); - break; - case 5: - retval = add_unicode_digit(symbol, 0x10, &unicode); - break; - case 6: - retval = add_unicode_digit(symbol, 0x1, &unicode); - /* If also the sixth digit was a valid hexadecimal value, then - * the Unicode sequence is complete, so return it when valid. */ - if (retval == PROCEED) - retval = (unicode < 0x110000) ? unicode : INVALID_DIGIT; - break; - } + retval = add_unicode_digit(symbol, &unicode); + + /* If also the sixth digit was a valid hexadecimal value, then the + * Unicode sequence is complete, so return it (when it's valid). */ + if (++digits == 6 && retval == PROCEED) + retval = (unicode < 0x110000) ? unicode : INVALID_DIGIT; /* Show feedback only when editing, not when at a prompt. */ if (retval == PROCEED && currmenu == MMAIN) { char partial[7] = "......"; /* Construct the partial result, left-padded with dots. */ - snprintf(partial + 6 - digits, digits + 1, "%06lX", unicode); + sprintf(partial + 6 - digits, "%0*lX", digits, unicode); /* TRANSLATORS: This is shown while a six-digit hexadecimal * Unicode character code (%s) is being typed in. */ statusline(INFO, _("Unicode Input: %s"), partial); } - /* If we have an end result, reset the Unicode digit counter. */ - if (retval != PROCEED) + /* If we have an end result, reset the value and the counter. */ + if (retval != PROCEED) { + unicode = 0; digits = 0; + } return retval; } From 3e3f4a167a6cb701f335653a2d172a5132343253 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 7 Sep 2022 11:27:20 +0200 Subject: [PATCH 18/43] tweaks: elide a function that does not need to be a separate function Also elide three calls of tolower(), using ORing with 0x20 instead, as we're dealing with plain ASCII here. Rename a variable too, away from a double abbreviation. --- src/winio.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/winio.c b/src/winio.c index c8299c22..f0419ccb 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1348,41 +1348,32 @@ int get_kbinput(WINDOW *frame, bool showcursor) #ifdef ENABLE_UTF8 #define INVALID_DIGIT -77 -/* If the given symbol is a valid hexadecimal digit, multiply it by factor - * and add the result to the given unicode, and return PROCEED to signify - * okay. When not a hexadecimal digit, return the symbol itself. */ -long add_unicode_digit(int symbol, long *unicode) -{ - if ('0' <= symbol && symbol <= '9') - *unicode = (*unicode << 4) + symbol - '0'; - else if ('a' <= tolower(symbol) && tolower(symbol) <= 'f') - *unicode = (*unicode << 4) + tolower(symbol) - 'a' + 10; - else if (symbol == '\r' || symbol == ' ') - return *unicode; - else - return INVALID_DIGIT; - - return PROCEED; -} - /* For each consecutive call, gather the given symbol into a six-digit Unicode * (from 000000 to 10FFFF, case-insensitive). When it is complete, return the - * assembled Unicode; until then, return PROCEED when the symbol is valid. */ + * assembled Unicode; until then, return PROCEED when the symbol is valid; and + * return an error code for anything other than hexadecimal, Space, and Enter. */ long assemble_unicode(int symbol) { static long unicode = 0; static int digits = 0; - long retval = PROCEED; + long outcome = PROCEED; - retval = add_unicode_digit(symbol, &unicode); + if ('0' <= symbol && symbol <= '9') + unicode = (unicode << 4) + symbol - '0'; + else if ('a' <= (symbol | 0x20) && (symbol | 0x20) <= 'f') + unicode = (unicode << 4) + (symbol | 0x20) - 'a' + 10; + else if (symbol == '\r' || symbol == ' ') + outcome = unicode; + else + outcome = INVALID_DIGIT; /* If also the sixth digit was a valid hexadecimal value, then the * Unicode sequence is complete, so return it (when it's valid). */ - if (++digits == 6 && retval == PROCEED) - retval = (unicode < 0x110000) ? unicode : INVALID_DIGIT; + if (++digits == 6 && outcome == PROCEED) + outcome = (unicode < 0x110000) ? unicode : INVALID_DIGIT; /* Show feedback only when editing, not when at a prompt. */ - if (retval == PROCEED && currmenu == MMAIN) { + if (outcome == PROCEED && currmenu == MMAIN) { char partial[7] = "......"; /* Construct the partial result, left-padded with dots. */ @@ -1394,12 +1385,12 @@ long assemble_unicode(int symbol) } /* If we have an end result, reset the value and the counter. */ - if (retval != PROCEED) { + if (outcome != PROCEED) { unicode = 0; digits = 0; } - return retval; + return outcome; } #endif /* ENABLE_UTF8 */ From e30eadb4debf2548f737c06d51d7e6db1f27c754 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 09:18:37 +0200 Subject: [PATCH 19/43] verbatim: don't show dots during Unicode input, as they give wrong idea The dots gave the impression that the next keystroke (hex digit) would land somewhere on the dots. But this is not so -- the current digits are instead shifted to the left and the new digit is added at the end. Also adjust and improve several comments. --- src/winio.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/winio.c b/src/winio.c index f0419ccb..bcacd283 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1348,10 +1348,10 @@ int get_kbinput(WINDOW *frame, bool showcursor) #ifdef ENABLE_UTF8 #define INVALID_DIGIT -77 -/* For each consecutive call, gather the given symbol into a six-digit Unicode - * (from 000000 to 10FFFF, case-insensitive). When it is complete, return the - * assembled Unicode; until then, return PROCEED when the symbol is valid; and - * return an error code for anything other than hexadecimal, Space, and Enter. */ +/* For each consecutive call, gather the given symbol into a Unicode code point. + * When it's complete (with six digits, or when Space or Enter is typed), return + * the assembled code. Until then, return PROCEED when the symbol is valid, or + * an error code for anything other than hexadecimal, Space, and Enter. */ long assemble_unicode(int symbol) { static long unicode = 0; @@ -1374,9 +1374,8 @@ long assemble_unicode(int symbol) /* Show feedback only when editing, not when at a prompt. */ if (outcome == PROCEED && currmenu == MMAIN) { - char partial[7] = "......"; + char partial[7] = " "; - /* Construct the partial result, left-padded with dots. */ sprintf(partial + 6 - digits, "%0*lX", digits, unicode); /* TRANSLATORS: This is shown while a six-digit hexadecimal @@ -1404,7 +1403,6 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count) reveal_cursor = TRUE; - /* Read in the first code. */ keycode = get_input(frame); #ifndef NANO_TINY @@ -1419,14 +1417,14 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count) yield = nmalloc(6 * sizeof(int)); #ifdef ENABLE_UTF8 - /* If the first code is a valid Unicode starter digit (0 or 1), - * commence Unicode input. Otherwise, put the code back. */ + /* If the key code is a hexadecimal digit, commence Unicode input. */ if (using_utf8() && isxdigit(keycode)) { long unicode = assemble_unicode(keycode); char multibyte[MB_CUR_MAX]; reveal_cursor = FALSE; + /* Gather at most six hexadecimal digits. */ while (unicode == PROCEED) { keycode = get_input(frame); unicode = assemble_unicode(keycode); @@ -1439,7 +1437,7 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count) return NULL; } #endif - /* For an invalid digit, discard its possible continuation bytes. */ + /* For an invalid keystroke, discard its possible continuation bytes. */ if (unicode == INVALID_DIGIT) { if (keycode == ESC_CODE && waiting_codes) { get_input(NULL); From 7034c3cc4727f808259aa8eecdcf8e7024663d32 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 11:42:10 +0200 Subject: [PATCH 20/43] tweaks: drop shunting of flags by calling the needed function directly Calling strstrwrapper() with the Backwards, Casesens, and Regex flags unset is equivalent to calling mbstrcasestr(). So... do that instead and quit saving and restoring the flags for each call of findfile(). This saving-and-restoring has been redundant since commit b0957254 from eight years ago. --- src/browser.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/browser.c b/src/browser.c index e633592a..fb8f838c 100644 --- a/src/browser.c +++ b/src/browser.c @@ -263,16 +263,6 @@ void findfile(const char *needle, bool forwards) /* The location in the file list of the filename we're looking at. */ const char *thename; /* The plain filename, without the path. */ - unsigned stash[sizeof(flags) / sizeof(flags[0])]; - /* A storage place for the current flag settings. */ - - /* Save the settings of all flags. */ - memcpy(stash, flags, sizeof(flags)); - - /* Search forward, case insensitive, and without regexes. */ - UNSET(BACKWARDS_SEARCH); - UNSET(CASE_SENSITIVE); - UNSET(USE_REGEXP); /* Step through each filename in the list until a match is found or * we've come back to the point where we started. */ @@ -294,7 +284,7 @@ void findfile(const char *needle, bool forwards) /* If the needle matches, we're done. And if we're back at the file * where we started, it is the only occurrence. */ - if (strstrwrapper(thename, needle, thename)) { + if (mbstrcasestr(thename, needle)) { if (looking_at == selected) statusbar(_("This is the only occurrence")); break; @@ -307,9 +297,6 @@ void findfile(const char *needle, bool forwards) } } - /* Restore the settings of all flags. */ - memcpy(flags, stash, sizeof(flags)); - /* Select the one we've found. */ selected = looking_at; } From 7b935e0d40df568d385c3e53076aefe17c14a30c Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 11:57:11 +0200 Subject: [PATCH 21/43] tweaks: elide an intermediary variable that is no longer needed --- src/browser.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/browser.c b/src/browser.c index fb8f838c..96d43cc5 100644 --- a/src/browser.c +++ b/src/browser.c @@ -261,8 +261,6 @@ void findfile(const char *needle, bool forwards) { size_t looking_at = selected; /* The location in the file list of the filename we're looking at. */ - const char *thename; - /* The plain filename, without the path. */ /* Step through each filename in the list until a match is found or * we've come back to the point where we started. */ @@ -279,12 +277,9 @@ void findfile(const char *needle, bool forwards) } } - /* Get the bare filename, without the path. */ - thename = tail(filelist[looking_at]); - /* If the needle matches, we're done. And if we're back at the file * where we started, it is the only occurrence. */ - if (mbstrcasestr(thename, needle)) { + if (mbstrcasestr(tail(filelist[looking_at]), needle)) { if (looking_at == selected) statusbar(_("This is the only occurrence")); break; From 358a10e3cc0575fdc0b118183a26e3e9779a72ac Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 12:02:07 +0200 Subject: [PATCH 22/43] tweaks: elide an assignment by iterating with the target variable --- src/browser.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/browser.c b/src/browser.c index 96d43cc5..288d4fbd 100644 --- a/src/browser.c +++ b/src/browser.c @@ -259,41 +259,37 @@ void browser_refresh(void) * search forward in the list; otherwise, search backward. */ void findfile(const char *needle, bool forwards) { - size_t looking_at = selected; - /* The location in the file list of the filename we're looking at. */ + size_t began_at = selected; /* Step through each filename in the list until a match is found or * we've come back to the point where we started. */ while (TRUE) { if (forwards) { - if (looking_at++ == list_length - 1) { - looking_at = 0; + if (selected++ == list_length - 1) { + selected = 0; statusbar(_("Search Wrapped")); } } else { - if (looking_at-- == 0) { - looking_at = list_length - 1; + if (selected-- == 0) { + selected = list_length - 1; statusbar(_("Search Wrapped")); } } /* If the needle matches, we're done. And if we're back at the file * where we started, it is the only occurrence. */ - if (mbstrcasestr(tail(filelist[looking_at]), needle)) { - if (looking_at == selected) + if (mbstrcasestr(tail(filelist[selected]), needle)) { + if (selected == began_at) statusbar(_("This is the only occurrence")); - break; + return; } /* If we're back at the beginning and didn't find any match... */ - if (looking_at == selected) { + if (selected == began_at) { not_found_msg(needle); - break; + return; } } - - /* Select the one we've found. */ - selected = looking_at; } /* Prepare the prompt and ask the user what to search for; then search for it. From 8198fd9c58a2b0570eea80c2388166158af04f9b Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 12:11:41 +0200 Subject: [PATCH 23/43] tweaks: reword and/or condense four comments --- src/browser.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/browser.c b/src/browser.c index 288d4fbd..6f93226a 100644 --- a/src/browser.c +++ b/src/browser.c @@ -255,13 +255,12 @@ void browser_refresh(void) wnoutrefresh(midwin); } -/* Look for the given needle in the list of files. If forwards is TRUE, - * search forward in the list; otherwise, search backward. */ +/* Look for the given needle in the list of files, forwards or backwards. */ void findfile(const char *needle, bool forwards) { size_t began_at = selected; - /* Step through each filename in the list until a match is found or + /* Iterate through the list of filenames, until a match is found or * we've come back to the point where we started. */ while (TRUE) { if (forwards) { @@ -276,15 +275,14 @@ void findfile(const char *needle, bool forwards) } } - /* If the needle matches, we're done. And if we're back at the file - * where we started, it is the only occurrence. */ + /* When the needle occurs in the basename of the file, we have a match. */ if (mbstrcasestr(tail(filelist[selected]), needle)) { if (selected == began_at) statusbar(_("This is the only occurrence")); return; } - /* If we're back at the beginning and didn't find any match... */ + /* When we're back at the starting point without any match... */ if (selected == began_at) { not_found_msg(needle); return; From bdaec3f934b758a00605059d1abace5b6fb83018 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 9 Sep 2022 16:32:41 +0200 Subject: [PATCH 24/43] docs: clarify the distinction between binding a function and "{function}" This addresses https://savannah.gnu.org/bugs/?63010. Inspired-by: Tasos Papastylianou --- doc/nano.texi | 16 +++++++++++++--- doc/nanorc.5 | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/doc/nano.texi b/doc/nano.texi index 9b4a13d1..8582ff68 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -1344,9 +1344,9 @@ Rebinds @code{key} to @code{function} in the context of @code{menu} @item bind key "string" menu Makes @code{key} produce @code{string} in the context of @code{menu} (or in all menus where the key exists when @code{all} is used). -Besides literal text, the @code{string} may contain function names -between braces. These functions will be invoked when the key is typed. -To include a literal opening brace, use @code{@{@{@}}. +Besides literal text and/or control codes, the @code{string} may contain +function names between braces. These functions will be invoked when the +key is typed. To include a literal opening brace, use @code{@{@{@}}. @item unbind key menu Unbinds @code{key} from @code{menu} @@ -1354,6 +1354,16 @@ Unbinds @code{key} from @code{menu} @end table +Note that @code{bind key "@{function@}" menu} is equivalent to +@code{bind key function menu}, except that for the latter form +@command{nano} will check the availabilty of the @code{function} +in the given @code{menu} at startup time (and report an error if +it does not exist there), whereas for the first form @command{nano} +will check at execution time that the @code{function} exists but not +whether it makes any sense in the current menu. The user has to take +care that a function name between braces (or any sequence of them) +is appropriate. Strange behavior can result when it is not. + @sp 1 The format of @code{key} should be one of: diff --git a/doc/nanorc.5 b/doc/nanorc.5 index a707ffd7..df117133 100644 --- a/doc/nanorc.5 +++ b/doc/nanorc.5 @@ -559,14 +559,23 @@ Rebinds the given \fIkey\fP to the given \fIfunction\fP in the given \fImenu\fP .BI bind " key " """" string """" " menu" Makes the given \fIkey\fR produce the given \fIstring\fR in the given \fImenu\fR (or in all menus where the key exists when \fBall\fR is used). -Besides literal text, the \fIstring\fR may contain function names -between braces. These functions will be invoked when the key is typed. -To include a literal opening brace, use \fB{{}\fR. +Besides literal text and/or control codes, the \fIstring\fR may contain +function names between braces. These functions will be invoked when +the key is typed. To include a literal opening brace, use \fB{{}\fR. .TP .BI unbind " key menu" Unbinds the given \fIkey\fP from the given \fImenu\fP (or from all menus where the key exists when \fBall\fP is used). .RE +.sp +Note that \fBbind \fIkey\fR \fB"{\fIfunction\fB}"\fR \fImenu\fR is equivalent +to \fBbind \fIkey\fR \fIfunction\fR \fImenu\fR, except that for the latter form +\fBnano\fR will check the availabilty of the \fIfunction\fR in the given \fImenu\fR +at startup time (and report an error if it does not exist there), whereas for the +first form \fBnano\fR will check at execution time that the \fIfunction\fR exists +but not whether it makes any sense in the current menu. The user has to take care +that a function name between braces (or any sequence of them) is appropriate. +Strange behavior can result when it is not. .TP The format of \fIkey\fP should be one of: From f90b710c9b69901f65881c53be776c3637b417cf Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 11 Sep 2022 17:48:05 +0200 Subject: [PATCH 25/43] tweaks: group the special keycodes for implanted strings together This shows better that they are related. --- src/definitions.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/definitions.h b/src/definitions.h index e12598aa..776fd4f7 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -214,16 +214,12 @@ #define SHIFT_DELETE 0x45D #define SHIFT_TAB 0x45F -/* A special keycode for when a string bind has been partially implanted. */ +/* Special keycodes for when a string bind has been partially implanted + * or has an unpaired opening brace, or when a function in a string bind + * needs execution or a specified function name is invalid. */ #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 is pressed while the mark is on. */ From 567310e698323e4c7a910818aae4dcbbbfaa60a8 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 12 Sep 2022 08:44:34 +0200 Subject: [PATCH 26/43] tweaks: reduce four variations of a message to a single common form (This could have been done a long time ago, but it simply didn't occur to me.) --- src/nano.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nano.c b/src/nano.c index 4346895a..0302e971 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1301,17 +1301,17 @@ void unbound_key(int code) #endif #ifdef ENABLE_NANORC if (shifted_metas && 'A' <= code && code <= 'Z') - statusline(AHEM, _("Unbound key: Sh-M-%c"), code); + statusline(AHEM, _("Unbound key: %s%c"), "Sh-M-", code); else #endif - statusline(AHEM, _("Unbound key: M-%c"), toupper(code)); + statusline(AHEM, _("Unbound key: %s%c"), "M-", toupper(code)); } else if (code == ESC_CODE) statusline(AHEM, _("Unbindable key: ^[")); else if (code < 0x20) - statusline(AHEM, _("Unbound key: ^%c"), code + 0x40); + statusline(AHEM, _("Unbound key: %s%c"), "^", code + 0x40); #if defined(ENABLE_BROWSER) || defined (ENABLE_HELP) else - statusline(AHEM, _("Unbound key: %c"), code); + statusline(AHEM, _("Unbound key: %s%c"), "", code); #endif set_blankdelay_to_one(); } From 50954a4b6a38467ec0fd2114e87727cc967abea5 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 8 Sep 2022 12:17:08 +0200 Subject: [PATCH 27/43] search: skip a match on the magic line, as it is a just convenience line As the magic line isn't really a line (it is not counted in the number of lines read and written), and nothing is on it (not even a newline), it doesn't make sense to allow any regex, like ^ or $, to match it. This fixes https://savannah.gnu.org/bugs/?63034. Indirectly-reported-by: Mike Scalora Bug existed since before version 2.0.0. --- src/search.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search.c b/src/search.c index d759668b..57236667 100644 --- a/src/search.c +++ b/src/search.c @@ -222,8 +222,9 @@ int findnextstr(const char *needle, bool whole_word_only, int modus, continue; } #endif - /* The match is valid. */ - break; + /* When not on the magic line, the match is valid. */ + if (line->next || line->data[0]) + break; } #ifndef NANO_TINY From f420f7c1775b141acda11f6e8216875d499fb862 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 13 Sep 2022 13:49:17 +0200 Subject: [PATCH 28/43] verbatim: do not overwrite the status bar when the code is invalid Move the triggering of the line redraw out of the error path, and into a better place: next to the normal clearing of the feedback. This fixes https://savannah.gnu.org/bugs/?63053. Bug existed since version 6.0, commit 6d828cf4. --- src/text.c | 8 +++++++- src/winio.c | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/text.c b/src/text.c index 5837cd41..fbe2bd9d 100644 --- a/src/text.c +++ b/src/text.c @@ -3039,7 +3039,13 @@ void do_verbatim_input(void) if (count < 999) inject(bytes, count); - wipe_statusbar(); +#ifndef NANO_TINY + /* Ensure that the feedback will be overwritten, or clear it. */ + if (ISSET(ZERO) && currmenu == MMAIN) + wredrawln(midwin, editwinrows - 1, 1); + else +#endif + wipe_statusbar(); } else /* TRANSLATORS: An invalid verbatim Unicode code was typed. */ statusline(AHEM, _("Invalid code")); diff --git a/src/winio.c b/src/winio.c index bcacd283..904e9915 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1518,9 +1518,6 @@ char *get_verbatim_kbinput(WINDOW *frame, size_t *count) /* Turn bracketed-paste mode back on. */ printf("\x1B[?2004h"); fflush(stdout); - - if (ISSET(ZERO) && currmenu == MMAIN) - wredrawln(midwin, editwinrows - 1, 1); #endif /* Turn flow control characters back on if necessary and turn the From 98e9a881c039fcc4f813a8f1d51ba9c9d2b131c4 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 13 Sep 2022 11:01:03 +0200 Subject: [PATCH 29/43] docs: mention in the man page how M-V can insert any Unicode code point This addresses https://savannah.gnu.org/bugs/?63055. Inspired-by: Tasos Papastylianou --- doc/nano.1 | 6 ++++++ doc/nano.texi | 11 ++++++++--- doc/nanorc.5 | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/doc/nano.1 b/doc/nano.1 index 1b46e3f0..d7d0723b 100644 --- a/doc/nano.1 +++ b/doc/nano.1 @@ -74,6 +74,12 @@ using the arrow keys. Holding down the Ctrl or Alt key too will increase the stride. Any cursor movement without Shift being held will cancel such a selection. .sp +Any valid Unicode code point can be inserted into the buffer by typing +\fBM\-V\fR followed by the hexadecimal digits of the code point (concluded +with \fB\fR or \fB\fR when it are fewer than six digits). +A literal control code (except \fB^J\fR) can be inserted by typing +\fBM\-V\fR followed by the pertinent keystroke. +.sp The two lines at the bottom of the screen show some important commands; the built-in help (\fB^G\fR) lists all the available ones. The default key bindings can be changed via a \fInanorc\fR file -- see diff --git a/doc/nano.texi b/doc/nano.texi index 8582ff68..aaed711d 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -222,14 +222,18 @@ typed the key with that value. @item For any possible character, pressing @kbd{M-V} (Alt+V) and then typing a -six-digit hexadecimal number (starting with @kbd{0} or @kbd{1}) will enter the -corresponding Unicode character into the buffer. +series of hexadecimal digits (at most six, or concluded with @kbd{Enter} or +@kbd{Space}) will enter the corresponding Unicode character into the buffer. @end itemize For example, typing @kbd{Esc Esc 2 3 4} will enter the character "ê" --- useful when writing about a French party. Typing @kbd{M-V 0 0 2 2 c 4} will enter the symbol "⋄", a little diamond. +Typing @kbd{M-V} followed by anything other than a hexadecimal digit +will enter this keystroke verbatim into the buffer, allowing the user +to insert literal control codes (except @code{^J}) or escape sequences. + @node Commands @section Commands @@ -1619,7 +1623,8 @@ Switches to editing/viewing the previous buffer when multiple buffers are open. Switches to editing/viewing the next buffer when multiple buffers are open. @item verbatim -Inserts the next keystroke verbatim into the file. +Inserts the next keystroke verbatim into the file, or begins Unicode input +when a hexadecimal digit is typed (@pxref{Entering Text} for details). @item tab Inserts a tab at the current cursor location. diff --git a/doc/nanorc.5 b/doc/nanorc.5 index df117133..6e73db1e 100644 --- a/doc/nanorc.5 +++ b/doc/nanorc.5 @@ -828,7 +828,8 @@ Switches to editing/viewing the previous buffer when multiple buffers are open. Switches to editing/viewing the next buffer when multiple buffers are open. .TP .B verbatim -Inserts the next keystroke verbatim into the file. +Inserts the next keystroke verbatim into the file, or begins Unicode input +when a hexadecimal digit is typed. .TP .B tab Inserts a tab at the current cursor location. From 5b654ce9fb1c115871457b61eb003d70c832a720 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 18 Sep 2022 10:38:48 +0200 Subject: [PATCH 30/43] docs: suggest a key binding for snipping trailing blanks This addresses https://savannah.gnu.org/bugs/?63062. --- doc/sample.nanorc.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/sample.nanorc.in b/doc/sample.nanorc.in index e74c1077..f3c7ea37 100644 --- a/doc/sample.nanorc.in +++ b/doc/sample.nanorc.in @@ -292,6 +292,9 @@ ## For copying a marked region to the system clipboard: # bind Sh-M-T "{execute}|xsel -ib{enter}{undo}" main +## For snipping trailing blanks when you save a file: +# bind ^S "{execute}| sed 's/\s\+$//' {enter}{savefile}" main + ## If you would like nano to have keybindings that are more "usual", ## such as ^O for Open, ^F for Find, ^H for Help, and ^Q for Quit, ## then uncomment these: From c7a600063d4b9a5042821e1f95861ae7d7795569 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 20 Sep 2022 16:17:02 +0200 Subject: [PATCH 31/43] tweaks: reshuffle some lines, to be more readable instead of compact --- src/winio.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/winio.c b/src/winio.c index 904e9915..7ba04f9d 100644 --- a/src/winio.c +++ b/src/winio.c @@ -362,19 +362,24 @@ int get_code_from_plantation(void) 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 + if (!planted_shortcut) return NO_SUCH_FUNCTION; + + plants_pointer = closing + 1; + + if (*plants_pointer != '\0') + put_back(MORE_PLANTS); + + return PLANTED_COMMAND; } else { char *opening = strchr(plants_pointer, '{'); - int length = (opening ? opening - plants_pointer : strlen(plants_pointer)); + int length; - if (opening) + if (opening) { + length = opening - plants_pointer; put_back(MORE_PLANTS); + } else + length = strlen(plants_pointer); for (int index = length - 1; index >= 0; index--) put_back((unsigned char)plants_pointer[index]); From 7eb66d3e09f53ced613c001af3a6e6d58d5abc6e Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 22 Sep 2022 10:45:56 +0200 Subject: [PATCH 32/43] tweaks: condense a comment, add two small ones, and reshuffle a line (Apart from reducing the verbosity of the long comment, also harmonize its format: mentioning the FreeBSD key always first.) --- src/winio.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/winio.c b/src/winio.c index 7ba04f9d..3afa9bab 100644 --- a/src/winio.c +++ b/src/winio.c @@ -160,22 +160,17 @@ void run_macro(void) * We support escape sequences for ANSI, VT100, VT220, VT320, the Linux * console, the FreeBSD console, the Mach console, xterm, and Terminal, * and some for Konsole, rxvt, Eterm, and iTerm2. Among these sequences, - * there are several conflicts and omissions: + * there are some conflicts: * - * - Tab on ANSI == PageUp on FreeBSD console; the former is omitted. + * - PageUp on FreeBSD console == Tab on ANSI; the latter is omitted. * (Ctrl-I is also Tab on ANSI, which we already support.) * - PageDown on FreeBSD console == Center (5) on numeric keypad with - * NumLock off on Linux console; the latter is omitted. (The editing - * keypad key is more important to have working than the numeric - * keypad key, because the latter has no value when NumLock is off.) - * - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the - * latter is omitted. (Mouse input will only work properly if the - * extended keypad value KEY_MOUSE is generated on mouse events - * instead of the escape sequence.) + * NumLock off on Linux console; the latter is useless and omitted. + * - F1 on FreeBSD console == the mouse sequence on xterm/rxvt/Eterm; + * the latter is omitted. (Mouse input works only when KEY_MOUSE + * is generated on mouse events, not with the raw escape sequence.) * - F9 on FreeBSD console == PageDown on Mach console; the former is - * omitted. (The editing keypad is more important to have working - * than the function keys, because the functions of the former are - * not arbitrary and the functions of the latter are.) + * omitted. (Moving the cursor is more important than a function key.) * - F10 on FreeBSD console == PageUp on Mach console; the former is * omitted. (Same as above.) */ @@ -202,6 +197,7 @@ void read_keys_from(WINDOW *frame) lastmessage != INFO) || spotlighted)) { timed = TRUE; halfdelay(ISSET(QUICK_BLANK) ? 8 : 15); + /* Counteract a side effect of half-delay mode. */ disable_kb_interrupt(); } #endif @@ -218,6 +214,7 @@ void read_keys_from(WINDOW *frame) if (timed) { timed = FALSE; + /* Leave half-delay mode. */ raw(); if (input == ERR) { @@ -251,8 +248,9 @@ void read_keys_from(WINDOW *frame) /* Initiate the keystroke buffer, and save the keycode in it. */ key_buffer = nrealloc(key_buffer, sizeof(int)); - nextcodes = key_buffer; key_buffer[0] = input; + + nextcodes = key_buffer; waiting_codes = 1; #ifndef NANO_TINY From 0d1438a73126460a562ed43893397cc3776dcfe3 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 23 Sep 2022 09:20:29 +0200 Subject: [PATCH 33/43] tweaks: reshuffle a declaration, and correct the wording of a comment Also, drop an unneeded condition, as memmove() allows moving zero bytes. --- src/winio.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/winio.c b/src/winio.c index 3afa9bab..fe7437dc 100644 --- a/src/winio.c +++ b/src/winio.c @@ -48,6 +48,10 @@ static int *nextcodes = NULL; /* A pointer pointing at the next keycode in the keystroke buffer. */ static size_t waiting_codes = 0; /* The number of key codes waiting in the keystroke buffer. */ +#ifdef ENABLE_NANORC +static const char *plants_pointer = NULL; + /* Points into the expansion string for the current implantation. */ +#endif static int digit_count = 0; /* How many digits of a three-digit character code we've eaten. */ static bool reveal_cursor = FALSE; @@ -64,10 +68,6 @@ 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. */ -#ifdef ENABLE_NANORC -static const char *plants_pointer = NULL; - /* Points into the expansion string for the current implantation. */ -#endif #ifndef NANO_TINY static size_t sequel_column = 0; /* The starting column of the next chunk when softwrapping. */ @@ -86,7 +86,7 @@ void add_to_macrobuffer(int code) macro_buffer[macro_length - 1] = code; } -/* Remove the last key code plus any trailing Esc codes from macro buffer. */ +/* Remove the last key code plus any leading Esc codes from macro buffer. */ void snip_last_keystroke(void) { macro_length--; @@ -317,8 +317,7 @@ void put_back(int keycode) /* If there is no room at the head of the keystroke buffer, make room. */ if (nextcodes == key_buffer) { key_buffer = nrealloc(key_buffer, (waiting_codes + 1) * sizeof(int)); - if (waiting_codes) - memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int)); + memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int)); nextcodes = key_buffer; } else nextcodes--; From 3922b531a8e4f1076dcabee77b6c87f72af0bf37 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 25 Sep 2022 09:22:29 +0200 Subject: [PATCH 34/43] input: allocate a small keystroke buffer, and never free it Instead of allocating and freeing a tiny fragment of memory for every keystroke, reserve a small piece in the beginning and then retain it, because it will be needed again and again and again. Increase the size when needed (for a large paste, probably), but don't bother to shrink it afterward. This addresses the first part of https://savannah.gnu.org/bugs/?63086. --- src/prototypes.h | 1 + src/winio.c | 32 +++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/prototypes.h b/src/prototypes.h index 03ae8fa6..771a436d 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -581,6 +581,7 @@ linestruct *line_from_number(ssize_t number); /* Most functions in winio.c. */ void record_macro(void); void run_macro(void); +void reserve_space_for(size_t newsize); size_t waiting_keycodes(void); #ifdef ENABLE_NANORC void implant(const char *string); diff --git a/src/winio.c b/src/winio.c index fe7437dc..f8b95356 100644 --- a/src/winio.c +++ b/src/winio.c @@ -46,6 +46,8 @@ static int *key_buffer = NULL; /* A buffer for the keystrokes that haven't been handled yet. */ static int *nextcodes = NULL; /* A pointer pointing at the next keycode in the keystroke buffer. */ +static size_t capacity = 32; + /* The size of the keystroke buffer; gets doubled whenever needed. */ static size_t waiting_codes = 0; /* The number of key codes waiting in the keystroke buffer. */ #ifdef ENABLE_NANORC @@ -126,7 +128,8 @@ void run_macro(void) return; } - key_buffer = nrealloc(key_buffer, macro_length * sizeof(int)); + if (macro_length > capacity) + reserve_space_for(macro_length); for (size_t i = 0; i < macro_length; i++) key_buffer[i] = macro_buffer[i]; @@ -137,6 +140,14 @@ void run_macro(void) } #endif /* !NANO_TINY */ +/* Allocate the requested space for the keystroke buffer. */ +void reserve_space_for(size_t newsize) +{ + key_buffer = nrealloc(key_buffer, newsize * sizeof(int)); + nextcodes = key_buffer; + capacity = newsize; +} + /* Control character compatibility: * * - Ctrl-H is Backspace under ASCII, ANSI, VT100, and VT220. @@ -246,8 +257,10 @@ void read_keys_from(WINDOW *frame) curs_set(0); - /* Initiate the keystroke buffer, and save the keycode in it. */ - key_buffer = nrealloc(key_buffer, sizeof(int)); + /* When there is no keystroke buffer yet, allocate one. */ + if (!key_buffer) + reserve_space_for(capacity); + key_buffer[0] = input; nextcodes = key_buffer; @@ -284,10 +297,11 @@ void read_keys_from(WINDOW *frame) if (input == ERR) break; - /* Extend the keystroke buffer, and save the keycode at its end. */ - key_buffer = nrealloc(key_buffer, ++waiting_codes * sizeof(int)); - key_buffer[waiting_codes - 1] = input; - nextcodes = key_buffer; + /* When the keystroke buffer is full, extend it. */ + if (waiting_codes == capacity) + reserve_space_for(2 * capacity); + + key_buffer[waiting_codes++] = input; } /* Restore blocking-input mode. */ @@ -316,9 +330,9 @@ void put_back(int keycode) /* If there is no room at the head of the keystroke buffer, make room. */ if (nextcodes == key_buffer) { - key_buffer = nrealloc(key_buffer, (waiting_codes + 1) * sizeof(int)); + if (waiting_codes == capacity) + reserve_space_for(2 * capacity); memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int)); - nextcodes = key_buffer; } else nextcodes--; From e4abef5768a8d1a43d7525486cb99a2f76ee9d52 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 25 Sep 2022 09:57:05 +0200 Subject: [PATCH 35/43] input: give up when the capacity of the keystroke buffer overflows In theory, the 'size_t' of 'capacity' could be just two bytes, which means the keystroke buffer would overflow for pastes that are larger than 32 kilobytes -- which are unlikely to occur, but... possible. However, previously there was *no* overflow check when extending the keystroke buffer (only when trying to put back a key code), so this check is an improvement. (On a regular machine, 'size_t' is at least four bytes, which means the keystroke buffer would overflow at 2 gigabytes. Such a paste is extremely unlikely to occur, so this check is really a no-op.) --- src/winio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/winio.c b/src/winio.c index f8b95356..018c4d07 100644 --- a/src/winio.c +++ b/src/winio.c @@ -143,6 +143,9 @@ void run_macro(void) /* Allocate the requested space for the keystroke buffer. */ void reserve_space_for(size_t newsize) { + if (newsize < capacity) + die(_("Too much input at once\n")); + key_buffer = nrealloc(key_buffer, newsize * sizeof(int)); nextcodes = key_buffer; capacity = newsize; @@ -324,10 +327,6 @@ size_t waiting_keycodes(void) /* Add the given keycode to the front of the keystroke buffer. */ void put_back(int keycode) { - /* If the keystroke buffer is at maximum capacity, don't add anything. */ - if (waiting_codes + 1 < waiting_codes) - return; - /* If there is no room at the head of the keystroke buffer, make room. */ if (nextcodes == key_buffer) { if (waiting_codes == capacity) From 6fde7d8a51a18eb127a375e78b88df6c5e7a7f91 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 25 Sep 2022 15:51:02 +0200 Subject: [PATCH 36/43] input: allocate two small character buffers too, and never free them Analogous to commit 3922b531: instead of allocating and later freeing a tiny fragment of memory for every character that the user enters (in the edit window or at a prompt), reserve a small piece in the beginning and retain it, and increase (but never decrease) its size as needed. This addresses the second part of https://savannah.gnu.org/bugs/?63086. --- src/nano.c | 18 +++++++++++------- src/prompt.c | 17 +++++++++++------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/nano.c b/src/nano.c index 0302e971..206f54ed 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1547,6 +1547,8 @@ void process_a_keystroke(void) /* The keystroke we read in: a character or a shortcut. */ static char *puddle = NULL; /* The input buffer for actual characters. */ + static size_t capacity = 12; + /* The size of the input buffer; gets doubled whenever needed. */ static size_t depth = 0; /* The length of the input buffer. */ #ifndef NANO_TINY @@ -1593,21 +1595,23 @@ void process_a_keystroke(void) refresh_needed = TRUE; } #endif - /* Store the byte, and leave room for a terminating zero. */ - puddle = nrealloc(puddle, depth + 2); + /* When the input buffer (plus room for terminating NUL) is full, + * extend it; otherwise, if it does not exist yet, create it. */ + if (depth + 1 == capacity) { + capacity = 2 * capacity; + puddle = nrealloc(puddle, capacity); + } else if (!puddle) + puddle = nmalloc(capacity); + puddle[depth++] = (char)input; } } /* If we have a command, or if there aren't any other key codes waiting, * it's time to insert the gathered bytes into the edit buffer. */ - if ((function || waiting_keycodes() == 0) && puddle != NULL) { + if (depth > 0 && (function || waiting_keycodes() == 0)) { puddle[depth] = '\0'; - inject(puddle, depth); - - free(puddle); - puddle = NULL; depth = 0; } diff --git a/src/prompt.c b/src/prompt.c index f99bec25..df697f2b 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -256,6 +256,8 @@ void absorb_character(int input, functionptrtype function) { static char *puddle = NULL; /* The input buffer. */ + static size_t capacity = 8; + /* The size of the input buffer; gets doubled whenever needed. */ static size_t depth = 0; /* The length of the input buffer. */ @@ -267,7 +269,14 @@ void absorb_character(int input, functionptrtype function) beep(); else if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || openfile->filename[0] == '\0') { - puddle = nrealloc(puddle, depth + 2); + /* When the input buffer (plus room for terminating NUL) is full, + * extend it; otherwise, if it does not exist yet, create it. */ + if (depth + 1 == capacity) { + capacity = 2 * capacity; + puddle = nrealloc(puddle, capacity); + } else if (!puddle) + puddle = nmalloc(capacity); + puddle[depth++] = (char)input; } } @@ -275,13 +284,9 @@ void absorb_character(int input, functionptrtype function) /* If we got a shortcut, or if there aren't any other keystrokes waiting, * it's time to insert all characters in the input buffer (if not empty) * into the answer, and then clear the input buffer. */ - if ((function || waiting_keycodes() == 0) && puddle != NULL) { + if (depth > 0 && (function || waiting_keycodes() == 0)) { puddle[depth] = '\0'; - inject_into_answer(puddle, depth); - - free(puddle); - puddle = NULL; depth = 0; } } From 162c213e7b68d91d47cce4012249719b2700d6d5 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 26 Sep 2022 15:51:06 +0200 Subject: [PATCH 37/43] tweaks: improve two comments, and exclude two unneeded prototypes And declare two more variables as 'static', like all its neighbors. --- src/nano.c | 4 ++-- src/prompt.c | 5 ++--- src/prototypes.h | 2 ++ src/winio.c | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/nano.c b/src/nano.c index 206f54ed..390cd77b 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1607,8 +1607,8 @@ void process_a_keystroke(void) } } - /* If we have a command, or if there aren't any other key codes waiting, - * it's time to insert the gathered bytes into the edit buffer. */ + /* If there are gathered bytes and we have a command or no other key codes + * are waiting, it's time to insert these bytes into the edit buffer. */ if (depth > 0 && (function || waiting_keycodes() == 0)) { puddle[depth] = '\0'; inject(puddle, depth); diff --git a/src/prompt.c b/src/prompt.c index df697f2b..de085248 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -281,9 +281,8 @@ void absorb_character(int input, functionptrtype function) } } - /* If we got a shortcut, or if there aren't any other keystrokes waiting, - * it's time to insert all characters in the input buffer (if not empty) - * into the answer, and then clear the input buffer. */ + /* If there are gathered bytes and we have a command or no other key codes + * are waiting, it's time to insert these bytes into the answer. */ if (depth > 0 && (function || waiting_keycodes() == 0)) { puddle[depth] = '\0'; inject_into_answer(puddle, depth); diff --git a/src/prototypes.h b/src/prototypes.h index 771a436d..d638a01a 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -579,8 +579,10 @@ linestruct *line_from_number(ssize_t number); #endif /* Most functions in winio.c. */ +#ifndef NANO_TINY void record_macro(void); void run_macro(void); +#endif void reserve_space_for(size_t newsize); size_t waiting_keycodes(void); #ifdef ENABLE_NANORC diff --git a/src/winio.c b/src/winio.c index 018c4d07..644e79fd 100644 --- a/src/winio.c +++ b/src/winio.c @@ -62,9 +62,9 @@ static bool linger_after_escape = FALSE; /* Whether to give ncurses some time to get the next code. */ static int statusblank = 0; /* The number of keystrokes left before we blank the status bar. */ -size_t from_x = 0; +static size_t from_x = 0; /* From where in the relevant line the current row is drawn. */ -size_t till_x = 0; +static size_t till_x = 0; /* Until where in the relevant line the current row is drawn. */ static bool has_more = FALSE; /* Whether the current line has more text after the displayed part. */ From 034af70a652291c043c428172ce83887205bc835 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 26 Sep 2022 16:02:28 +0200 Subject: [PATCH 38/43] tweaks: simplify a pasting routine, modelling it after the injection one --- src/prompt.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/prompt.c b/src/prompt.c index de085248..84d4ef64 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -182,16 +182,12 @@ void copy_the_answer(void) void paste_into_answer(void) { size_t pastelen = strlen(cutbuffer->data); - char *fusion = nmalloc(strlen(answer) + pastelen + 1); - /* Concatenate: the current answer before the cursor, the first line - * of the cutbuffer, plus the rest of the current answer. */ - strncpy(fusion, answer, typing_x); - strncpy(fusion + typing_x, cutbuffer->data, pastelen); - strcpy(fusion + typing_x + pastelen, answer + typing_x); + answer = nrealloc(answer, strlen(answer) + pastelen + 1); + memmove(answer + typing_x + pastelen, answer + typing_x, + strlen(answer) - typing_x + 1); + strncpy(answer + typing_x, cutbuffer->data, pastelen); - free(answer); - answer = fusion; typing_x += pastelen; } #endif From 8d7b716ea77a118a1ad4e4c28a2e879fd58a2d6b Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 27 Sep 2022 11:48:42 +0200 Subject: [PATCH 39/43] startup: quit when standard input is not a TTY (after handling arguments) Not quitting would make nano hang for several seconds (which is very annoying) and then die and save an emergency file (which is useless). This fixes https://savannah.gnu.org/bugs/?63109. Bug existed chiefly since version 5.9, commit 8d1a666d, but basically existed since before version 2.0.0. --- src/nano.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nano.c b/src/nano.c index 390cd77b..62aa2771 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2512,6 +2512,10 @@ int main(int argc, char **argv) /* After handling the files on the command line, allow inserting files. */ UNSET(NOREAD_MODE); + /* Nano is a hands-on editor -- it needs a keyboard. */ + if (!isatty(STDIN_FILENO)) + die(_("Standard input is not a terminal\n")); + /* If no filenames were given, or all of them were invalid things like * directories, then open a blank buffer and allow editing. Otherwise, * switch from the last opened file to the next, that is: the first. */ From 1dc2a75cb61d4632d2acd8481b4e5476d6093598 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Tue, 27 Sep 2022 15:29:56 +0200 Subject: [PATCH 40/43] files: before sending data to an external command, decode LF back to NUL (There is no need to recode the NULs back to LFs because the sending of the data happens in a separate process, which then simply disappears.) This fixes https://savannah.gnu.org/bugs/?63106. Bug existed since version 2.9.8, since filtering a buffer or a region through an external command was introduced. --- src/files.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/files.c b/src/files.c index 0b768b04..1950de30 100644 --- a/src/files.c +++ b/src/files.c @@ -988,7 +988,16 @@ void send_data(const linestruct *line, int fd) /* Send each line, except a final empty line. */ while (line != NULL && (line->next != NULL || line->data[0] != '\0')) { - fprintf(tube, "%s%s", line->data, line->next == NULL ? "" : "\n"); + size_t length = strlen(line->data); + + recode_LF_to_NUL(line->data); + + if (fwrite(line->data, sizeof(char), length, tube) < length) + exit(5); + + if (line->next && putc('\n', tube) == EOF) + exit(6); + line = line->next; } From ceb305a780f8f744cd208d89cb797937972b3c8e Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 28 Sep 2022 12:21:52 +0200 Subject: [PATCH 41/43] tweaks: avoid iterating over the same string twice in a row The function recode_LF_to_NUL() has to iterate over the string anyway (to replace each \n with \0), so... instead of calling strlen() right before it, just let recode_LF_to_NUL() return the length of the string. (This is not speed-critical code, but... it saves one iteration over the entire buffer contents whenever writing out a file.) --- src/files.c | 9 +++------ src/history.c | 7 ++----- src/prototypes.h | 2 +- src/utils.c | 9 +++++++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/files.c b/src/files.c index 1950de30..c40b389d 100644 --- a/src/files.c +++ b/src/files.c @@ -988,9 +988,7 @@ void send_data(const linestruct *line, int fd) /* Send each line, except a final empty line. */ while (line != NULL && (line->next != NULL || line->data[0] != '\0')) { - size_t length = strlen(line->data); - - recode_LF_to_NUL(line->data); + size_t length = recode_LF_to_NUL(line->data); if (fwrite(line->data, sizeof(char), length, tube) < length) exit(5); @@ -1865,11 +1863,10 @@ bool write_file(const char *name, FILE *thefile, bool normal, statusbar(_("Writing...")); while (TRUE) { - size_t data_len = strlen(line->data); - size_t wrote; + size_t data_len, wrote; /* Decode LFs as the NULs that they are, before writing to disk. */ - recode_LF_to_NUL(line->data); + data_len = recode_LF_to_NUL(line->data); wrote = fwrite(line->data, sizeof(char), data_len, thefile); diff --git a/src/history.c b/src/history.c index 5cf4cb93..0f8f2577 100644 --- a/src/history.c +++ b/src/history.c @@ -304,10 +304,8 @@ bool write_list(const linestruct *head, FILE *histfile) const linestruct *item; for (item = head; item != NULL; item = item->next) { - size_t length = strlen(item->data); - /* Decode 0x0A bytes as embedded NULs. */ - recode_LF_to_NUL(item->data); + size_t length = recode_LF_to_NUL(item->data); if (fwrite(item->data, sizeof(char), length, histfile) < length) return FALSE; @@ -451,10 +449,9 @@ void save_poshistory(void) path_and_place = nmalloc(strlen(item->filename) + 44); sprintf(path_and_place, "%s %zd %zd\n", item->filename, item->linenumber, item->columnnumber); - length = strlen(path_and_place); /* Encode newlines in filenames as NULs. */ - recode_LF_to_NUL(path_and_place); + length = recode_LF_to_NUL(path_and_place); /* Restore the terminating newline. */ path_and_place[length - 1] = '\n'; diff --git a/src/prototypes.h b/src/prototypes.h index d638a01a..530c4b9f 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -544,7 +544,7 @@ int digits(ssize_t n); bool parse_num(const char *str, ssize_t *result); bool parse_line_column(const char *str, ssize_t *line, ssize_t *column); void recode_NUL_to_LF(char *string, size_t length); -void recode_LF_to_NUL(char *string); +size_t recode_LF_to_NUL(char *string); #if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER) void free_chararray(char **array, size_t len); #endif diff --git a/src/utils.c b/src/utils.c index f1bd5c96..d6470ccc 100644 --- a/src/utils.c +++ b/src/utils.c @@ -168,14 +168,19 @@ void recode_NUL_to_LF(char *string, size_t length) } } -/* In the given string, recode each embedded newline as a NUL. */ -void recode_LF_to_NUL(char *string) +/* In the given string, recode each embedded newline as a NUL, + * and return the number of bytes in the string. */ +size_t recode_LF_to_NUL(char *string) { + char *beginning = string; + while (*string != '\0') { if (*string == '\n') *string = '\0'; string++; } + + return (string - beginning); } #if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER) From 119ec47072824e1a3f01fa81d7573a784cebfed0 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 28 Sep 2022 12:37:56 +0200 Subject: [PATCH 42/43] tweaks: replace sizeof(char) with 1, as that is assumed anyway Since commit c848ec3d from three years ago, nano has assumed that 'char' is always a single byte. So... elide the last occurrences of sizeof(char), as they give a false impression of generality. --- src/files.c | 10 +++++----- src/history.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/files.c b/src/files.c index c40b389d..0a940d73 100644 --- a/src/files.c +++ b/src/files.c @@ -218,7 +218,7 @@ bool write_lockfile(const char *lockfilename, const char *filename, bool modifie strncpy(&lockdata[108], filename, 768); lockdata[1007] = (modified) ? 0x55 : 0x00; - wroteamt = fwrite(lockdata, sizeof(char), LOCKSIZE, filestream); + wroteamt = fwrite(lockdata, 1, LOCKSIZE, filestream); free(lockdata); @@ -990,7 +990,7 @@ void send_data(const linestruct *line, int fd) while (line != NULL && (line->next != NULL || line->data[0] != '\0')) { size_t length = recode_LF_to_NUL(line->data); - if (fwrite(line->data, sizeof(char), length, tube) < length) + if (fwrite(line->data, 1, length, tube) < length) exit(5); if (line->next && putc('\n', tube) == EOF) @@ -1536,12 +1536,12 @@ int copy_file(FILE *inn, FILE *out, bool close_out) int (*flush_out_fnc)(FILE *) = (close_out) ? fclose : fflush; do { - charsread = fread(buf, sizeof(char), BUFSIZ, inn); + charsread = fread(buf, 1, BUFSIZ, inn); if (charsread == 0 && ferror(inn)) { retval = -1; break; } - if (fwrite(buf, sizeof(char), charsread, out) < charsread) { + if (fwrite(buf, 1, charsread, out) < charsread) { retval = 2; break; } @@ -1868,7 +1868,7 @@ bool write_file(const char *name, FILE *thefile, bool normal, /* Decode LFs as the NULs that they are, before writing to disk. */ data_len = recode_LF_to_NUL(line->data); - wrote = fwrite(line->data, sizeof(char), data_len, thefile); + wrote = fwrite(line->data, 1, data_len, thefile); /* Re-encode any embedded NULs as LFs. */ recode_NUL_to_LF(line->data, data_len); diff --git a/src/history.c b/src/history.c index 0f8f2577..d5b96787 100644 --- a/src/history.c +++ b/src/history.c @@ -307,7 +307,7 @@ bool write_list(const linestruct *head, FILE *histfile) /* Decode 0x0A bytes as embedded NULs. */ size_t length = recode_LF_to_NUL(item->data); - if (fwrite(item->data, sizeof(char), length, histfile) < length) + if (fwrite(item->data, 1, length, histfile) < length) return FALSE; if (putc('\n', histfile) == EOF) return FALSE; @@ -455,7 +455,7 @@ void save_poshistory(void) /* Restore the terminating newline. */ path_and_place[length - 1] = '\n'; - if (fwrite(path_and_place, sizeof(char), length, histfile) < length) + if (fwrite(path_and_place, 1, length, histfile) < length) jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno)); free(path_and_place); From d4d2840f5d456adecfbc5ddfcb08e4550f55ae9e Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 28 Sep 2022 16:21:10 +0200 Subject: [PATCH 43/43] filtering: when returning to a line number, ensure it is within range The function line_from_number() can handle only line numbers that exist, and will crash otherwise. (The lack of checks makes the function fast.) This fixes https://savannah.gnu.org/bugs/?63120. Bug existed since commit d1e28417 from five weeks ago. --- src/search.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.c b/src/search.c index 57236667..fdcdfb87 100644 --- a/src/search.c +++ b/src/search.c @@ -747,7 +747,11 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x) recook |= perturbed; #endif - openfile->current = line_from_number(linenumber); + if (linenumber < openfile->filebot->lineno) + openfile->current = line_from_number(linenumber); + else + openfile->current = openfile->filebot; + openfile->current_x = pos_x; openfile->placewewant = xplustabs();