Merge branch 'master' into rexy712

This commit is contained in:
rexy712 2022-10-04 16:06:16 -07:00
commit 263c7fefbf
20 changed files with 423 additions and 320 deletions

View File

@ -167,6 +167,30 @@ if test "x$enable_extra" != xno; then
AC_DEFINE(ENABLE_EXTRA, 1, [Define this to have an Easter egg.]) AC_DEFINE(ENABLE_EXTRA, 1, [Define this to have an Easter egg.])
fi 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, AC_ARG_ENABLE(help,
AS_HELP_STRING([--disable-help], [Disable the built-in help texts])) AS_HELP_STRING([--disable-help], [Disable the built-in help texts]))
if test "x$enable_tiny" = xyes; then if test "x$enable_tiny" = xyes; then
@ -220,7 +244,7 @@ if test "x$enable_libmagic" = xyes; then
if test "x$enable_tiny" = xyes; then if test "x$enable_tiny" = xyes; then
if test "x$enable_color" != xyes; then if test "x$enable_color" != xyes; then
AC_MSG_ERROR([ 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
fi fi
if test "x$enable_color" = xno; then if test "x$enable_color" = xno; then
@ -229,6 +253,30 @@ if test "x$enable_libmagic" = xyes; then
fi fi
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, AC_ARG_ENABLE(linenumbers,
AS_HELP_STRING([--disable-linenumbers], [Disable line numbering])) AS_HELP_STRING([--disable-linenumbers], [Disable line numbering]))
if test "x$enable_tiny" = xyes; then if test "x$enable_tiny" = xyes; then
@ -286,14 +334,14 @@ if test "x$enable_operatingdir" != xno; then
fi fi
AC_ARG_ENABLE(speller, 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_tiny" = xyes; then
if test "x$enable_speller" != xyes; then if test "x$enable_speller" != xyes; then
enable_speller=no enable_speller=no
fi fi
fi fi
if test "x$enable_speller" != xno; then 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 fi
AC_ARG_ENABLE(tabcomp, AC_ARG_ENABLE(tabcomp,

View File

@ -150,16 +150,18 @@
<b>--disable-color</b> Disable color and syntax highlighting <b>--disable-color</b> Disable color and syntax highlighting
<b>--disable-comment</b> Disable the comment/uncomment function <b>--disable-comment</b> Disable the comment/uncomment function
<b>--disable-extra</b> Disable the easter egg <b>--disable-extra</b> Disable the easter egg
<b>--disable-formatter</b> Disable the formatting tool
<b>--disable-help</b> Disable the built-in help texts <b>--disable-help</b> Disable the built-in help texts
<b>--disable-histories</b> Disable the saving of search strings and cursor positions <b>--disable-histories</b> Disable the saving of search strings and cursor positions
<b>--disable-justify</b> Disable the justify/unjustify functions <b>--disable-justify</b> Disable the justify/unjustify functions
<b>--disable-libmagic</b> Disable the use of libmagic for determining a file's syntax <b>--disable-libmagic</b> Disable the use of libmagic for determining a file's syntax
<b>--disable-linenumbers</b> Disable line numbering <b>--disable-linenumbers</b> Disable line numbering
<b>--disable-linter</b> Disable the linting tool
<b>--disable-mouse</b> Disable mouse support <b>--disable-mouse</b> Disable mouse support
<b>--disable-multibuffer</b> Disable the opening of multiple file buffers <b>--disable-multibuffer</b> Disable the opening of multiple file buffers
<b>--disable-nanorc</b> Disable the use of .nanorc files <b>--disable-nanorc</b> Disable the use of .nanorc files
<b>--disable-operatingdir</b> Disable the setting of an operating directory <b>--disable-operatingdir</b> Disable the setting of an operating directory
<b>--disable-speller</b> Disable the spell-checker functions <b>--disable-speller</b> Disable the spell-checking tool
<b>--disable-tabcomp</b> Disable the tab-completion functions <b>--disable-tabcomp</b> Disable the tab-completion functions
<b>--disable-wordcomp</b> Disable the word-completion function <b>--disable-wordcomp</b> Disable the word-completion function
<b>--disable-wrapping</b> Disable all hard-wrapping of text</pre> <b>--disable-wrapping</b> Disable all hard-wrapping of text</pre>

View File

@ -74,6 +74,12 @@ using the arrow keys. Holding down the Ctrl or Alt key too will increase
the stride. the stride.
Any cursor movement without Shift being held will cancel such a selection. Any cursor movement without Shift being held will cancel such a selection.
.sp .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<Space>\fR or \fB<Enter>\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 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 built-in help (\fB^G\fR) lists all the available ones.
The default key bindings can be changed via a \fInanorc\fR file -- see The default key bindings can be changed via a \fInanorc\fR file -- see

View File

@ -222,14 +222,18 @@ typed the key with that value.
@item @item
For any possible character, pressing @kbd{M-V} (Alt+V) and then typing a 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 series of hexadecimal digits (at most six, or concluded with @kbd{Enter} or
corresponding Unicode character into the buffer. @kbd{Space}) will enter the corresponding Unicode character into the buffer.
@end itemize @end itemize
For example, typing @kbd{Esc Esc 2 3 4} will enter the character "ê" --- 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} useful when writing about a French party. Typing @kbd{M-V 0 0 2 2 c 4}
will enter the symbol "⋄", a little diamond. 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 @node Commands
@section Commands @section Commands
@ -1201,6 +1205,14 @@ It also means that lookahead and lookbehind are not possible.
A complete explanation can be found in the manual of GNU grep: A complete explanation can be found in the manual of GNU grep:
@code{info grep regular}. @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 A separate syntax can be defined for each kind of file
via the following commands in a nanorc file: via the following commands in a nanorc file:
@ -1336,9 +1348,9 @@ Rebinds @code{key} to @code{function} in the context of @code{menu}
@item bind key "string" menu @item bind key "string" menu
Makes @code{key} produce @code{string} in the context of @code{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). (or in all menus where the key exists when @code{all} is used).
Besides literal text, the @code{string} may contain function names Besides literal text and/or control codes, the @code{string} may contain
between braces. These functions will be invoked when the key is typed. function names between braces. These functions will be invoked when the
To include a literal opening brace, use @code{@{@{@}}. key is typed. To include a literal opening brace, use @code{@{@{@}}.
@item unbind key menu @item unbind key menu
Unbinds @code{key} from @code{menu} Unbinds @code{key} from @code{menu}
@ -1346,6 +1358,16 @@ Unbinds @code{key} from @code{menu}
@end table @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 @sp 1
The format of @code{key} should be one of: The format of @code{key} should be one of:
@ -1601,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. Switches to editing/viewing the next buffer when multiple buffers are open.
@item verbatim @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 @item tab
Inserts a tab at the current cursor location. Inserts a tab at the current cursor location.
@ -1941,6 +1964,9 @@ Exclude the single-keystroke comment/uncomment function (@w{@kbd{M-3}}).
@item --disable-extra @item --disable-extra
Exclude the Easter egg: a crawl of major contributors. Exclude the Easter egg: a crawl of major contributors.
@item --disable-formatter
Exclude the code for calling a formatting tool.
@item --disable-help @item --disable-help
Exclude the help texts (@kbd{^G}). This makes the binary much smaller, 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 but also makes it difficult for new users to learn more than very basic
@ -1966,6 +1992,9 @@ in most cases the regexes for filename and header line will be enough).
Exclude the ability to show line numbers. This also eliminates Exclude the ability to show line numbers. This also eliminates
the @option{-l} command-line option, which turns line numbering on. 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 @item --disable-mouse
Exclude all mouse functionality. This also eliminates the @option{-m} Exclude all mouse functionality. This also eliminates the @option{-m}
command-line option, which enables the mouse functionality. command-line option, which enables the mouse functionality.

View File

@ -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: A complete explanation can be found in the manual page of GNU grep:
\fBman grep\fR. \fBman grep\fR.
.sp .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 For each kind of file a separate syntax can be defined
via the following commands: via the following commands:
.TP .TP
@ -551,14 +559,23 @@ Rebinds the given \fIkey\fP to the given \fIfunction\fP in the given \fImenu\fP
.BI bind " key " """" string """" " menu" .BI bind " key " """" string """" " menu"
Makes the given \fIkey\fR produce the given \fIstring\fR in the given 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). \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 Besides literal text and/or control codes, the \fIstring\fR may contain
between braces. These functions will be invoked when the key is typed. function names between braces. These functions will be invoked when
To include a literal opening brace, use \fB{{}\fR. the key is typed. To include a literal opening brace, use \fB{{}\fR.
.TP .TP
.BI unbind " key menu" .BI unbind " key menu"
Unbinds the given \fIkey\fP from the given \fImenu\fP (or from all Unbinds the given \fIkey\fP from the given \fImenu\fP (or from all
menus where the key exists when \fBall\fP is used). menus where the key exists when \fBall\fP is used).
.RE .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 .TP
The format of \fIkey\fP should be one of: The format of \fIkey\fP should be one of:
@ -811,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. Switches to editing/viewing the next buffer when multiple buffers are open.
.TP .TP
.B verbatim .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 .TP
.B tab .B tab
Inserts a tab at the current cursor location. Inserts a tab at the current cursor location.

View File

@ -292,6 +292,9 @@
## For copying a marked region to the system clipboard: ## For copying a marked region to the system clipboard:
# bind Sh-M-T "{execute}|xsel -ib{enter}{undo}" main # 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", ## 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, ## such as ^O for Open, ^F for Find, ^H for Help, and ^Q for Quit,
## then uncomment these: ## then uncomment these:

View File

@ -255,63 +255,39 @@ void browser_refresh(void)
wnoutrefresh(midwin); wnoutrefresh(midwin);
} }
/* Look for the given needle in the list of files. If forwards is TRUE, /* Look for the given needle in the list of files, forwards or backwards. */
* search forward in the list; otherwise, search backward. */
void findfile(const char *needle, bool forwards) void findfile(const char *needle, bool forwards)
{ {
size_t looking_at = selected; size_t began_at = selected;
/* 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. */ /* Iterate through the list of filenames, until a match is found or
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. */ * we've come back to the point where we started. */
while (TRUE) { while (TRUE) {
if (forwards) { if (forwards) {
if (looking_at++ == list_length - 1) { if (selected++ == list_length - 1) {
looking_at = 0; selected = 0;
statusbar(_("Search Wrapped")); statusbar(_("Search Wrapped"));
} }
} else { } else {
if (looking_at-- == 0) { if (selected-- == 0) {
looking_at = list_length - 1; selected = list_length - 1;
statusbar(_("Search Wrapped")); statusbar(_("Search Wrapped"));
} }
} }
/* Get the bare filename, without the path. */ /* When the needle occurs in the basename of the file, we have a match. */
thename = tail(filelist[looking_at]); if (mbstrcasestr(tail(filelist[selected]), needle)) {
if (selected == began_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 (strstrwrapper(thename, needle, thename)) {
if (looking_at == selected)
statusbar(_("This is the only occurrence")); statusbar(_("This is the only occurrence"));
break; 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 (looking_at == selected) { if (selected == began_at) {
not_found_msg(needle); not_found_msg(needle);
break; return;
} }
} }
/* Restore the settings of all flags. */
memcpy(flags, stash, sizeof(flags));
/* Select the one we've found. */
selected = looking_at;
} }
/* Prepare the prompt and ask the user what to search for; then search for it. /* Prepare the prompt and ask the user what to search for; then search for it.

View File

@ -214,16 +214,12 @@
#define SHIFT_DELETE 0x45D #define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F #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 #define MORE_PLANTS 0x4EA
/* A special keycode for when a string bind has an unpaired opening brace. */
#define MISSING_BRACE 0x4EB #define MISSING_BRACE 0x4EB
/* A special keycode for when a function in a string bind needs execution. */
#define PLANTED_COMMAND 0x4EC #define PLANTED_COMMAND 0x4EC
/* A special keycode for when a function name in a string bind is invalid. */
#define NO_SUCH_FUNCTION 0x4EF #define NO_SUCH_FUNCTION 0x4EF
/* A special keycode for when <Tab> is pressed while the mark is on. */ /* A special keycode for when <Tab> is pressed while the mark is on. */
@ -658,14 +654,13 @@ typedef struct keystruct {
typedef struct funcstruct { typedef struct funcstruct {
void (*func)(void); void (*func)(void);
/* The actual function to call. */ /* The actual function to call. */
const char *desc; const char *tag;
/* The function's short description, for example "Where Is". */ /* The function's help-line label, for example "Where Is". */
#ifdef ENABLE_HELP #ifdef ENABLE_HELP
const char *help; const char *phrase;
/* The help-screen text for this function. */ /* The function's description for in the help viewer. */
bool blank_after; bool blank_after;
/* Whether there should be a blank line after the help text /* Whether to distance this function from the next in the help viewer. */
* for this function. */
#endif #endif
int menus; int menus;
/* In what menus this function applies. */ /* In what menus this function applies. */

View File

@ -57,7 +57,7 @@ void make_new_buffer(void)
openfile->next = newnode; openfile->next = newnode;
/* There is more than one buffer: show "Close" in help lines. */ /* 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; more_than_one = !inhelp || more_than_one;
} }
#endif #endif
@ -218,7 +218,7 @@ bool write_lockfile(const char *lockfilename, const char *filename, bool modifie
strncpy(&lockdata[108], filename, 768); strncpy(&lockdata[108], filename, 768);
lockdata[1007] = (modified) ? 0x55 : 0x00; lockdata[1007] = (modified) ? 0x55 : 0x00;
wroteamt = fwrite(lockdata, sizeof(char), LOCKSIZE, filestream); wroteamt = fwrite(lockdata, 1, LOCKSIZE, filestream);
free(lockdata); free(lockdata);
@ -627,7 +627,7 @@ void close_buffer(void)
/* When just one buffer remains open, show "Exit" in the help lines. */ /* When just one buffer remains open, show "Exit" in the help lines. */
if (openfile && openfile == openfile->next) if (openfile && openfile == openfile->next)
exitfunc->desc = exit_tag; exitfunc->tag = exit_tag;
} }
#endif /* ENABLE_MULTIBUFFER */ #endif /* ENABLE_MULTIBUFFER */
@ -989,7 +989,14 @@ void send_data(const linestruct *line, int fd)
/* Send each line, except a final empty line. */ /* Send each line, except a final empty line. */
while (line != NULL && (line->next != NULL || line->data[0] != '\0')) { while (line != NULL && (line->next != NULL || line->data[0] != '\0')) {
fprintf(tube, "%s%s", line->data, line->next == NULL ? "" : "\n"); size_t length = recode_LF_to_NUL(line->data);
if (fwrite(line->data, 1, length, tube) < length)
exit(5);
if (line->next && putc('\n', tube) == EOF)
exit(6);
line = line->next; line = line->next;
} }
@ -1530,12 +1537,12 @@ int copy_file(FILE *inn, FILE *out, bool close_out)
int (*flush_out_fnc)(FILE *) = (close_out) ? fclose : fflush; int (*flush_out_fnc)(FILE *) = (close_out) ? fclose : fflush;
do { do {
charsread = fread(buf, sizeof(char), BUFSIZ, inn); charsread = fread(buf, 1, BUFSIZ, inn);
if (charsread == 0 && ferror(inn)) { if (charsread == 0 && ferror(inn)) {
retval = -1; retval = -1;
break; break;
} }
if (fwrite(buf, sizeof(char), charsread, out) < charsread) { if (fwrite(buf, 1, charsread, out) < charsread) {
retval = 2; retval = 2;
break; break;
} }
@ -1857,13 +1864,12 @@ bool write_file(const char *name, FILE *thefile, bool normal,
statusbar(_("Writing...")); statusbar(_("Writing..."));
while (TRUE) { while (TRUE) {
size_t data_len = strlen(line->data); size_t data_len, wrote;
size_t wrote;
/* Decode LFs as the NULs that they are, before writing to disk. */ /* 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); wrote = fwrite(line->data, 1, data_len, thefile);
/* Re-encode any embedded NULs as LFs. */ /* Re-encode any embedded NULs as LFs. */
recode_NUL_to_LF(line->data, data_len); recode_NUL_to_LF(line->data, data_len);

View File

@ -317,8 +317,8 @@ void discard_buffer(void) {;}
void do_cancel(void) {;} void do_cancel(void) {;}
/* Add a function to the linked list of functions. */ /* Add a function to the linked list of functions. */
void add_to_funcs(void (*function)(void), int menus, const char *desc, void add_to_funcs(void (*function)(void), int menus, const char *tag,
const char *help, bool blank_after) const char *phrase, bool blank_after)
{ {
funcstruct *f = nmalloc(sizeof(funcstruct)); 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->next = NULL;
f->func = function; f->func = function;
f->menus = menus; f->menus = menus;
f->desc = desc; f->tag = tag;
#ifdef ENABLE_HELP #ifdef ENABLE_HELP
f->help = help; f->phrase = phrase;
f->blank_after = blank_after; f->blank_after = blank_after;
#endif #endif
} }
@ -692,10 +692,12 @@ void shortcut_init(void)
const char *browserrefresh_gist = N_("Refresh the file list"); const char *browserrefresh_gist = N_("Refresh the file list");
const char *gotodir_gist = N_("Go to directory"); const char *gotodir_gist = N_("Go to directory");
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
const char *lint_gist = N_("Invoke the linter, if available"); const char *lint_gist = N_("Invoke the linter, if available");
const char *prevlint_gist = N_("Go to previous linter msg"); const char *prevlint_gist = N_("Go to previous linter msg");
const char *nextlint_gist = N_("Go to next linter msg"); const char *nextlint_gist = N_("Go to next linter msg");
#endif
#ifdef ENABLE_FORMATTER
const char *formatter_gist = const char *formatter_gist =
N_("Invoke a program to format/arrange/manipulate the buffer"); N_("Invoke a program to format/arrange/manipulate the buffer");
#endif #endif
@ -1023,9 +1025,11 @@ void shortcut_init(void)
add_to_funcs(do_spell, MMAIN, add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER); N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
add_to_funcs(do_linter, MMAIN, add_to_funcs(do_linter, MMAIN,
N_("Linter"), WHENHELP(lint_gist), TOGETHER); N_("Linter"), WHENHELP(lint_gist), TOGETHER);
#endif
#ifdef ENABLE_FORMATTER
add_to_funcs(do_formatter, MMAIN, add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER); N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
#endif #endif
@ -1065,7 +1069,7 @@ void shortcut_init(void)
add_to_funcs(do_spell, MEXECUTE, add_to_funcs(do_spell, MEXECUTE,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER); N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
add_to_funcs(do_linter, MEXECUTE, add_to_funcs(do_linter, MEXECUTE,
N_("Linter"), WHENHELP(lint_gist), BLANKAFTER); N_("Linter"), WHENHELP(lint_gist), BLANKAFTER);
#endif #endif
@ -1073,7 +1077,7 @@ void shortcut_init(void)
add_to_funcs(do_full_justify, MEXECUTE, add_to_funcs(do_full_justify, MEXECUTE,
N_("Full Justify"), WHENHELP(fulljustify_gist), TOGETHER); N_("Full Justify"), WHENHELP(fulljustify_gist), TOGETHER);
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_FORMATTER
add_to_funcs(do_formatter, MEXECUTE, add_to_funcs(do_formatter, MEXECUTE,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER); N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
#endif #endif
@ -1153,7 +1157,7 @@ void shortcut_init(void)
add_to_funcs(discard_buffer, MWRITEFILE, add_to_funcs(discard_buffer, MWRITEFILE,
N_("Discard buffer"), WHENHELP(discardbuffer_gist), BLANKAFTER); N_("Discard buffer"), WHENHELP(discardbuffer_gist), BLANKAFTER);
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
add_to_funcs(do_page_up, MLINTER, add_to_funcs(do_page_up, MLINTER,
/* TRANSLATORS: The next two strings may be up to 37 characters each. */ /* TRANSLATORS: The next two strings may be up to 37 characters each. */
N_("Previous Linter message"), WHENHELP(prevlint_gist), TOGETHER); N_("Previous Linter message"), WHENHELP(prevlint_gist), TOGETHER);
@ -1207,9 +1211,11 @@ void shortcut_init(void)
#ifdef ENABLE_JUSTIFY #ifdef ENABLE_JUSTIFY
add_to_sclist(MMAIN, "^J", '\n', do_justify, 0); add_to_sclist(MMAIN, "^J", '\n', do_justify, 0);
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
add_to_sclist(MMAIN, "M-B", 0, do_linter, 0); add_to_sclist(MMAIN, "M-B", 0, do_linter, 0);
add_to_sclist(MEXECUTE, "^Y", 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(MMAIN, "M-F", 0, do_formatter, 0);
add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0); add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0);
#endif #endif

View File

@ -224,7 +224,7 @@ void help_init(void)
* plus translated text, plus one or two \n's. */ * plus translated text, plus one or two \n's. */
for (f = allfuncs; f != NULL; f = f->next) for (f = allfuncs; f != NULL; f = f->next)
if (f->menus & currmenu) if (f->menus & currmenu)
allocsize += strlen(_(f->help)) + 21; allocsize += strlen(_(f->phrase)) + 21;
#ifndef NANO_TINY #ifndef NANO_TINY
/* If we're on the main list, we also count the toggle help text. /* If we're on the main list, we also count the toggle help text.
@ -282,7 +282,7 @@ void help_init(void)
ptr += 10; ptr += 10;
/* The shortcut's description. */ /* The shortcut's description. */
ptr += sprintf(ptr, "%s\n", _(f->help)); ptr += sprintf(ptr, "%s\n", _(f->phrase));
if (f->blank_after) if (f->blank_after)
ptr += sprintf(ptr, "\n"); ptr += sprintf(ptr, "\n");

View File

@ -304,12 +304,10 @@ bool write_list(const linestruct *head, FILE *histfile)
const linestruct *item; const linestruct *item;
for (item = head; item != NULL; item = item->next) { for (item = head; item != NULL; item = item->next) {
size_t length = strlen(item->data);
/* Decode 0x0A bytes as embedded NULs. */ /* 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) if (fwrite(item->data, 1, length, histfile) < length)
return FALSE; return FALSE;
if (putc('\n', histfile) == EOF) if (putc('\n', histfile) == EOF)
return FALSE; return FALSE;
@ -451,14 +449,13 @@ void save_poshistory(void)
path_and_place = nmalloc(strlen(item->filename) + 44); path_and_place = nmalloc(strlen(item->filename) + 44);
sprintf(path_and_place, "%s %zd %zd\n", sprintf(path_and_place, "%s %zd %zd\n",
item->filename, item->linenumber, item->columnnumber); item->filename, item->linenumber, item->columnnumber);
length = strlen(path_and_place);
/* Encode newlines in filenames as NULs. */ /* 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. */ /* Restore the terminating newline. */
path_and_place[length - 1] = '\n'; 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)); jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno));
free(path_and_place); free(path_and_place);

View File

@ -430,10 +430,9 @@ void window_init(void)
int toprows = ((ISSET(EMPTY_LINE) && LINES > 6) ? 2 : 1); int toprows = ((ISSET(EMPTY_LINE) && LINES > 6) ? 2 : 1);
int bottomrows = ((ISSET(NO_HELP) || LINES < 6) ? 1 : 3); int bottomrows = ((ISSET(NO_HELP) || LINES < 6) ? 1 : 3);
#ifndef NANO_TINY
if (ISSET(MINIBAR) || ISSET(ZERO)) if (ISSET(MINIBAR) || ISSET(ZERO))
toprows = 0; toprows = 0;
#endif
editwinrows = LINES - toprows - bottomrows + (ISSET(ZERO) ? 1 : 0); editwinrows = LINES - toprows - bottomrows + (ISSET(ZERO) ? 1 : 0);
/* Set up the normal three subwindows. */ /* Set up the normal three subwindows. */
@ -487,7 +486,7 @@ void mouse_init(void)
#endif /* ENABLE_MOUSE */ #endif /* ENABLE_MOUSE */
/* Print the usage line for the given option to the screen. */ /* 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 firstwidth = breadth(shortflag);
int secondwidth = breadth(longflag); int secondwidth = breadth(longflag);
@ -500,7 +499,7 @@ void print_opt(const char *shortflag, const char *longflag, const char *desc)
if (secondwidth < 24) if (secondwidth < 24)
printf("%*s", 24 - secondwidth, " "); printf("%*s", 24 - secondwidth, " ");
printf("%s\n", _(desc)); printf("%s\n", _(description));
} }
/* Explain how to properly use nano and its command-line options. */ /* Explain how to properly use nano and its command-line options. */
@ -695,6 +694,9 @@ void version(void)
#ifdef ENABLE_EXTRA #ifdef ENABLE_EXTRA
printf(" --enable-extra"); printf(" --enable-extra");
#endif #endif
#ifdef ENABLE_FORMATTER
printf(" --enable-formatter");
#endif
#ifdef ENABLE_HELP #ifdef ENABLE_HELP
printf(" --enable-help"); printf(" --enable-help");
#endif #endif
@ -710,6 +712,9 @@ void version(void)
#ifdef ENABLE_LINENUMBERS #ifdef ENABLE_LINENUMBERS
printf(" --enable-linenumbers"); printf(" --enable-linenumbers");
#endif #endif
#ifdef ENABLE_LINTER
printf(" --enable-linter");
#endif
#ifdef ENABLE_MOUSE #ifdef ENABLE_MOUSE
printf(" --enable-mouse"); printf(" --enable-mouse");
#endif #endif
@ -744,6 +749,9 @@ void version(void)
#ifndef ENABLE_EXTRA #ifndef ENABLE_EXTRA
printf(" --disable-extra"); printf(" --disable-extra");
#endif #endif
#ifndef ENABLE_FORMATTER
printf(" --disable-formatter");
#endif
#ifndef ENABLE_HELP #ifndef ENABLE_HELP
printf(" --disable-help"); printf(" --disable-help");
#endif #endif
@ -759,6 +767,9 @@ void version(void)
#ifndef ENABLE_LINENUMBERS #ifndef ENABLE_LINENUMBERS
printf(" --disable-linenumbers"); printf(" --disable-linenumbers");
#endif #endif
#ifndef ENABLE_LINTER
printf(" --disable-linter");
#endif
#ifndef ENABLE_MOUSE #ifndef ENABLE_MOUSE
printf(" --disable-mouse"); printf(" --disable-mouse");
#endif #endif
@ -1277,10 +1288,10 @@ void unbound_key(int code)
* (from the keyboard) that nano does not recognize. */ * (from the keyboard) that nano does not recognize. */
statusline(AHEM, _("Unknown sequence")); statusline(AHEM, _("Unknown sequence"));
#ifdef ENABLE_NANORC #ifdef ENABLE_NANORC
else if (code == NO_SUCH_FUNCTION)
statusline(AHEM, _("Unknown function: %s"), commandname);
else if (code == MISSING_BRACE) else if (code == MISSING_BRACE)
statusline(AHEM, _("Missing }")); statusline(AHEM, _("Missing }"));
else if (code == NO_SUCH_FUNCTION)
statusline(AHEM, _("No such function: %s"), commandname);
#endif #endif
#ifndef NANO_TINY #ifndef NANO_TINY
else if (code > KEY_F0 && code < KEY_F0 + 25) else if (code > KEY_F0 && code < KEY_F0 + 25)
@ -1297,17 +1308,17 @@ void unbound_key(int code)
#endif #endif
#ifdef ENABLE_NANORC #ifdef ENABLE_NANORC
if (shifted_metas && 'A' <= code && code <= 'Z') 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 else
#endif #endif
statusline(AHEM, _("Unbound key: M-%c"), toupper(code)); statusline(AHEM, _("Unbound key: %s%c"), "M-", toupper(code));
} else if (code == ESC_CODE) } else if (code == ESC_CODE)
statusline(AHEM, _("Unbindable key: ^[")); statusline(AHEM, _("Unbindable key: ^["));
else if (code < 0x20) 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) #if defined(ENABLE_BROWSER) || defined (ENABLE_HELP)
else else
statusline(AHEM, _("Unbound key: %c"), code); statusline(AHEM, _("Unbound key: %s%c"), "", code);
#endif #endif
set_blankdelay_to_one(); set_blankdelay_to_one();
} }
@ -1386,9 +1397,8 @@ bool wanted_to_move(void (*func)(void))
/* Return TRUE when the given function makes a change -- no good for view mode. */ /* Return TRUE when the given function makes a change -- no good for view mode. */
bool changes_something(const void *f) bool changes_something(const void *f)
{ {
return (f == do_savefile || f == do_writeout || f == do_enter || return (f == do_savefile || f == do_writeout || f == do_enter || f == do_tab ||
f == do_tab || f == do_delete || f == do_backspace || f == do_delete || f == do_backspace || f == cut_text || f == paste_text ||
f == cut_text || f == paste_text || f == do_replace ||
#ifndef NANO_TINY #ifndef NANO_TINY
f == chop_previous_word || f == chop_next_word || f == chop_previous_word || f == chop_next_word ||
f == zap_text || f == cut_till_eof || f == do_execute || f == zap_text || f == cut_till_eof || f == do_execute ||
@ -1400,13 +1410,13 @@ bool changes_something(const void *f)
#ifdef ENABLE_SPELLER #ifdef ENABLE_SPELLER
f == do_spell || f == do_spell ||
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_FORMATTER
f == do_formatter || f == do_formatter ||
#endif #endif
#ifdef ENABLE_WORDCOMPLETION #ifdef ENABLE_WORDCOMPLETION
f == complete_a_word || f == complete_a_word ||
#endif #endif
f == do_verbatim_input); f == do_replace || f == do_verbatim_input);
} }
#ifndef NANO_TINY #ifndef NANO_TINY
@ -1545,6 +1555,8 @@ void process_a_keystroke(void)
/* The keystroke we read in: a character or a shortcut. */ /* The keystroke we read in: a character or a shortcut. */
static char *puddle = NULL; static char *puddle = NULL;
/* The input buffer for actual characters. */ /* 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; static size_t depth = 0;
/* The length of the input buffer. */ /* The length of the input buffer. */
#ifndef NANO_TINY #ifndef NANO_TINY
@ -1591,21 +1603,23 @@ void process_a_keystroke(void)
refresh_needed = TRUE; refresh_needed = TRUE;
} }
#endif #endif
/* Store the byte, and leave room for a terminating zero. */ /* When the input buffer (plus room for terminating NUL) is full,
puddle = nrealloc(puddle, depth + 2); * 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; puddle[depth++] = (char)input;
} }
} }
/* If we have a command, or if there aren't any other key codes waiting, /* If there are gathered bytes and we have a command or no other key codes
* it's time to insert the gathered bytes into the edit buffer. */ * are waiting, it's time to insert these bytes into the edit buffer. */
if ((function || waiting_keycodes() == 0) && puddle != NULL) { if (depth > 0 && (function || waiting_keycodes() == 0)) {
puddle[depth] = '\0'; puddle[depth] = '\0';
inject(puddle, depth); inject(puddle, depth);
free(puddle);
puddle = NULL;
depth = 0; depth = 0;
} }
@ -2506,6 +2520,10 @@ int main(int argc, char **argv)
/* After handling the files on the command line, allow inserting files. */ /* After handling the files on the command line, allow inserting files. */
UNSET(NOREAD_MODE); 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 /* If no filenames were given, or all of them were invalid things like
* directories, then open a blank buffer and allow editing. Otherwise, * directories, then open a blank buffer and allow editing. Otherwise,
* switch from the last opened file to the next, that is: the first. */ * switch from the last opened file to the next, that is: the first. */

View File

@ -182,16 +182,12 @@ void copy_the_answer(void)
void paste_into_answer(void) void paste_into_answer(void)
{ {
size_t pastelen = strlen(cutbuffer->data); size_t pastelen = strlen(cutbuffer->data);
char *fusion = nmalloc(strlen(answer) + pastelen + 1);
/* Concatenate: the current answer before the cursor, the first line answer = nrealloc(answer, strlen(answer) + pastelen + 1);
* of the cutbuffer, plus the rest of the current answer. */ memmove(answer + typing_x + pastelen, answer + typing_x,
strncpy(fusion, answer, typing_x); strlen(answer) - typing_x + 1);
strncpy(fusion + typing_x, cutbuffer->data, pastelen); strncpy(answer + typing_x, cutbuffer->data, pastelen);
strcpy(fusion + typing_x + pastelen, answer + typing_x);
free(answer);
answer = fusion;
typing_x += pastelen; typing_x += pastelen;
} }
#endif #endif
@ -256,6 +252,8 @@ void absorb_character(int input, functionptrtype function)
{ {
static char *puddle = NULL; static char *puddle = NULL;
/* The input buffer. */ /* The input buffer. */
static size_t capacity = 8;
/* The size of the input buffer; gets doubled whenever needed. */
static size_t depth = 0; static size_t depth = 0;
/* The length of the input buffer. */ /* The length of the input buffer. */
@ -267,21 +265,23 @@ void absorb_character(int input, functionptrtype function)
beep(); beep();
else if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || else if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE ||
openfile->filename[0] == '\0') { 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; puddle[depth++] = (char)input;
} }
} }
/* If we got a shortcut, or if there aren't any other keystrokes waiting, /* If there are gathered bytes and we have a command or no other key codes
* it's time to insert all characters in the input buffer (if not empty) * are waiting, it's time to insert these bytes into the answer. */
* into the answer, and then clear the input buffer. */ if (depth > 0 && (function || waiting_keycodes() == 0)) {
if ((function || waiting_keycodes() == 0) && puddle != NULL) {
puddle[depth] = '\0'; puddle[depth] = '\0';
inject_into_answer(puddle, depth); inject_into_answer(puddle, depth);
free(puddle);
puddle = NULL;
depth = 0; depth = 0;
} }
} }
@ -442,7 +442,7 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
#ifndef NANO_TINY #ifndef NANO_TINY
/* If the window size changed, go reformat the prompt string. */ /* If the window size changed, go reformat the prompt string. */
if (input == KEY_WINCH) { if (input == KEY_WINCH) {
refresh_func(); refresh_func(); /* Only needed when in file browser. */
*actual = KEY_WINCH; *actual = KEY_WINCH;
#ifdef ENABLE_HISTORIES #ifdef ENABLE_HISTORIES
free(stored_string); 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); function = acquire_an_answer(&retval, &listed, history_list, refresh_func);
free(prompt); free(prompt);
prompt = saved_prompt;
#ifndef NANO_TINY #ifndef NANO_TINY
if (retval == KEY_WINCH) if (retval == KEY_WINCH)
goto redo_theprompt; goto redo_theprompt;
#endif #endif
/* If we're done with this prompt, restore the x position to what /* Restore a possible previous prompt and maybe the typing position. */
* it was at a possible previous prompt. */ prompt = saved_prompt;
if (function == do_cancel || function == do_enter) if (function == do_cancel || function == do_enter)
typing_x = was_typing_x; typing_x = was_typing_x;
/* If we left the prompt via Cancel or Enter, set the return value /* Set the proper return value for Cancel and Enter. */
* properly. */
if (function == do_cancel) if (function == do_cancel)
retval = -1; retval = -1;
else if (function == do_enter) else if (function == do_enter)

View File

@ -470,7 +470,9 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
const linestruct *real_current, size_t *real_current_x); const linestruct *real_current, size_t *real_current_x);
void do_replace(void); void do_replace(void);
void ask_for_and_do_replacements(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); 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, void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
bool interactive); bool interactive);
void do_gotolinecolumn(void); void do_gotolinecolumn(void);
@ -524,8 +526,10 @@ void do_full_justify(void);
#ifdef ENABLE_SPELLER #ifdef ENABLE_SPELLER
void do_spell(void); void do_spell(void);
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
void do_linter(void); void do_linter(void);
#endif
#ifdef ENABLE_FORMATTER
void do_formatter(void); void do_formatter(void);
#endif #endif
#ifndef NANO_TINY #ifndef NANO_TINY
@ -544,7 +548,7 @@ int digits(ssize_t n);
bool parse_num(const char *str, ssize_t *result); bool parse_num(const char *str, ssize_t *result);
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column); 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_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) #if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
void free_chararray(char **array, size_t len); void free_chararray(char **array, size_t len);
#endif #endif
@ -574,15 +578,18 @@ void get_region(linestruct **top, size_t *top_x, linestruct **bot, size_t *bot_x
void get_range(linestruct **top, linestruct **bot); void get_range(linestruct **top, linestruct **bot);
#endif #endif
size_t number_of_characters_in(const linestruct *begin, const linestruct *end); 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); linestruct *line_from_number(ssize_t number);
#endif #endif
/* Most functions in winio.c. */ /* Most functions in winio.c. */
linestruct *get_next_visible_line(linestruct *line); linestruct *get_next_visible_line(linestruct *line);
linestruct *get_prev_visible_line(linestruct *line); linestruct *get_prev_visible_line(linestruct *line);
#ifndef NANO_TINY
void record_macro(void); void record_macro(void);
void run_macro(void); void run_macro(void);
#endif
void reserve_space_for(size_t newsize);
size_t waiting_keycodes(void); size_t waiting_keycodes(void);
#ifdef ENABLE_NANORC #ifdef ENABLE_NANORC
void implant(const char *string); void implant(const char *string);

View File

@ -153,18 +153,6 @@ static bool seen_color_command = FALSE;
static colortype *lastcolor = NULL; static colortype *lastcolor = NULL;
/* The end of the color list for the current syntax. */ /* The end of the color list for the current syntax. */
#endif #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 */ #endif /* ENABLE_NANORC */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES) #if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
@ -276,9 +264,11 @@ keystruct *strtosc(const char *input)
!strcmp(input, "speller")) !strcmp(input, "speller"))
s->func = do_spell; s->func = do_spell;
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
else if (!strcmp(input, "linter")) else if (!strcmp(input, "linter"))
s->func = do_linter; s->func = do_linter;
#endif
#ifdef ENABLE_FORMATTER
else if (!strcmp(input, "formatter")) else if (!strcmp(input, "formatter"))
s->func = do_formatter; s->func = do_formatter;
#endif #endif
@ -493,6 +483,18 @@ keystruct *strtosc(const char *input)
return s; 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. */ /* Return the symbol that corresponds to the given menu name. */
int name_to_menu(const char *name) int name_to_menu(const char *name)
{ {
@ -502,7 +504,7 @@ int name_to_menu(const char *name)
if (strcmp(name, menunames[index]) == 0) if (strcmp(name, menunames[index]) == 0)
return menusymbols[index]; return menusymbols[index];
return -1; return 0;
} }
/* Return the name that corresponds to the given menu symbol. */ /* Return the name that corresponds to the given menu symbol. */
@ -785,6 +787,12 @@ void parse_binding(char *ptr, bool dobind)
goto free_things; goto free_things;
} }
menu = name_to_menu(menuptr);
if (menu == 0) {
jot_error(N_("Unknown menu: %s"), menuptr);
goto free_things;
}
if (dobind) { if (dobind) {
/* If the thing to bind starts with a double quote, it is a string, /* If the thing to bind starts with a double quote, it is a string,
* otherwise it is the name of a function. */ * otherwise it is the name of a function. */
@ -799,17 +807,11 @@ void parse_binding(char *ptr, bool dobind)
newsc = strtosc(funcptr); newsc = strtosc(funcptr);
if (newsc == NULL) { if (newsc == NULL) {
jot_error(N_("Cannot map name \"%s\" to a function"), funcptr); jot_error(N_("Unknown function: %s"), funcptr);
goto free_things; 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;
}
/* Wipe the given shortcut from the given menu. */ /* Wipe the given shortcut from the given menu. */
for (keystruct *s = sclist; s != NULL; s = s->next) for (keystruct *s = sclist; s != NULL; s = s->next)
if ((s->menus & menu) && s->keycode == keycode) if ((s->menus & menu) && s->keycode == keycode)
@ -1348,7 +1350,7 @@ static void check_vitals_mapped(void)
if (f->func == vitals[v] && f->menus & inmenus[v]) { if (f->func == vitals[v] && f->menus & inmenus[v]) {
if (first_sc_for(inmenus[v], f->func) == NULL) { if (first_sc_for(inmenus[v], f->func) == NULL) {
jot_error(N_("No key is bound to function '%s' in menu '%s'. " 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 " die(_("If needed, use nano with the -I option "
"to adjust your nanorc settings.\n")); "to adjust your nanorc settings.\n"));
} else } else
@ -1530,7 +1532,7 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
} }
if (rcopts[i].name == NULL) { if (rcopts[i].name == NULL) {
jot_error(N_("Unknown option \"%s\""), option); jot_error(N_("Unknown option: %s"), option);
continue; continue;
} }

View File

@ -222,8 +222,9 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
continue; continue;
} }
#endif #endif
/* The match is valid. */ /* When not on the magic line, the match is valid. */
break; if (line->next || line->data[0])
break;
} }
#ifndef NANO_TINY #ifndef NANO_TINY
@ -738,6 +739,7 @@ void ask_for_and_do_replacements(void)
"Replaced %zd occurrences", numreplaced), numreplaced); "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. */ /* Go to the specified line and x position. */
void goto_line_posx(ssize_t linenumber, size_t pos_x) void goto_line_posx(ssize_t linenumber, size_t pos_x)
{ {
@ -747,13 +749,18 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
recook |= perturbed; recook |= perturbed;
#endif #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->current_x = pos_x;
openfile->placewewant = xplustabs(); openfile->placewewant = xplustabs();
UNFOLD_SEGMENT(openfile->current); UNFOLD_SEGMENT(openfile->current);
refresh_needed = TRUE; refresh_needed = TRUE;
} }
#endif
/* Go to the specified line and column, or ask for them if interactive /* Go to the specified line and column, or ask for them if interactive
* is TRUE. In the latter case also update the screen afterwards. * is TRUE. In the latter case also update the screen afterwards.
@ -839,9 +846,9 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
openfile->placewewant = breadth(openfile->current->data); openfile->placewewant = breadth(openfile->current->data);
#endif #endif
/* When the position was manually given, center the target line. */ /* When a line number was manually given, center the target line. */
if (interactive) { if (interactive) {
adjust_viewport(CENTERING); adjust_viewport((*answer == ',') ? STATIONARY : CENTERING);
refresh_needed = TRUE; refresh_needed = TRUE;
} else { } else {
int rows_from_tail; int rows_from_tail;

View File

@ -665,7 +665,7 @@ void do_undo(void)
break; break;
} }
if (undidmsg && !pletion_line) if (undidmsg && !ISSET(ZERO) && !pletion_line)
statusline(HUSH, _("Undid %s"), undidmsg); statusline(HUSH, _("Undid %s"), undidmsg);
openfile->current_undo = openfile->current_undo->next; openfile->current_undo = openfile->current_undo->next;
@ -835,7 +835,7 @@ void do_redo(void)
break; break;
} }
if (redidmsg) if (redidmsg && !ISSET(ZERO))
statusline(HUSH, _("Redid %s"), redidmsg); statusline(HUSH, _("Redid %s"), redidmsg);
openfile->current_undo = u; openfile->current_undo = u;
@ -2039,7 +2039,7 @@ void do_full_justify(void)
} }
#endif /* ENABLE_JUSTIFY */ #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. */ /* Set up an argument list for executing the given command. */
void construct_argument_list(char ***arguments, char *command, char *filename) void construct_argument_list(char ***arguments, char *command, char *filename)
{ {
@ -2056,7 +2056,9 @@ void construct_argument_list(char ***arguments, char *command, char *filename)
(*arguments)[count - 2] = filename; (*arguments)[count - 2] = filename;
(*arguments)[count - 1] = NULL; (*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 /* 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. */ * 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) bool replace_buffer(const char *filename, undo_type action, const char *operation)
@ -2234,7 +2236,7 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
statusline(REMARK, _("Buffer has been processed")); statusline(REMARK, _("Buffer has been processed"));
#endif #endif
} }
#endif /* ENABLE_SPELLER || ENABLE_COLOR */ #endif /* ENABLE_SPELLER || ENABLE_FORMATTER */
#ifdef ENABLE_SPELLER #ifdef ENABLE_SPELLER
/* Let the user edit the misspelled word. Return FALSE if the user cancels. */ /* Let the user edit the misspelled word. Return FALSE if the user cancels. */
@ -2579,7 +2581,7 @@ void do_spell(void)
} }
#endif /* ENABLE_SPELLER */ #endif /* ENABLE_SPELLER */
#ifdef ENABLE_COLOR #ifdef ENABLE_LINTER
/* Run a linting program on the current buffer. */ /* Run a linting program on the current buffer. */
void do_linter(void) void do_linter(void)
{ {
@ -2926,7 +2928,9 @@ void do_linter(void)
titlebar(NULL); titlebar(NULL);
#endif #endif
} }
#endif /* ENABLE_LINTER */
#ifdef ENABLE_FORMATTER
/* Run a manipulation program on the contents of the buffer. */ /* Run a manipulation program on the contents of the buffer. */
void do_formatter(void) void do_formatter(void)
{ {
@ -2961,7 +2965,7 @@ void do_formatter(void)
unlink(temp_name); unlink(temp_name);
free(temp_name); free(temp_name);
} }
#endif /* ENABLE_COLOR */ #endif /* ENABLE_FORMATTER */
#ifndef NANO_TINY #ifndef NANO_TINY
/* Our own version of "wc". Note that the character count is in /* Our own version of "wc". Note that the character count is in
@ -3051,7 +3055,13 @@ void do_verbatim_input(void)
if (count < 999) if (count < 999)
inject(bytes, count); 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 } else
/* TRANSLATORS: An invalid verbatim Unicode code was typed. */ /* TRANSLATORS: An invalid verbatim Unicode code was typed. */
statusline(AHEM, _("Invalid code")); statusline(AHEM, _("Invalid code"));

View File

@ -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. */ /* In the given string, recode each embedded newline as a NUL,
void recode_LF_to_NUL(char *string) * and return the number of bytes in the string. */
size_t recode_LF_to_NUL(char *string)
{ {
char *beginning = string;
while (*string != '\0') { while (*string != '\0') {
if (*string == '\n') if (*string == '\n')
*string = '\0'; *string = '\0';
string++; string++;
} }
return (string - beginning);
} }
#if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER) #if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
@ -484,7 +489,9 @@ void get_range(linestruct **top, linestruct **bot)
also_the_last = TRUE; also_the_last = TRUE;
} }
} }
#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. */ /* Return a pointer to the line that has the given line number. */
linestruct *line_from_number(ssize_t number) linestruct *line_from_number(ssize_t number)
{ {
@ -499,7 +506,7 @@ linestruct *line_from_number(ssize_t number)
return line; return line;
} }
#endif /* !NANO_TINY */ #endif
/* Count the number of characters from begin to end, and return it. */ /* Count the number of characters from begin to end, and return it. */
size_t number_of_characters_in(const linestruct *begin, const linestruct *end) size_t number_of_characters_in(const linestruct *begin, const linestruct *end)

View File

@ -46,8 +46,14 @@ static int *key_buffer = NULL;
/* A buffer for the keystrokes that haven't been handled yet. */ /* A buffer for the keystrokes that haven't been handled yet. */
static int *nextcodes = NULL; static int *nextcodes = NULL;
/* A pointer pointing at the next keycode in the keystroke buffer. */ /* 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; static size_t waiting_codes = 0;
/* The number of key codes waiting in the keystroke buffer. */ /* 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; static int digit_count = 0;
/* How many digits of a three-digit character code we've eaten. */ /* How many digits of a three-digit character code we've eaten. */
static bool reveal_cursor = FALSE; static bool reveal_cursor = FALSE;
@ -56,18 +62,14 @@ static bool linger_after_escape = FALSE;
/* Whether to give ncurses some time to get the next code. */ /* Whether to give ncurses some time to get the next code. */
static int statusblank = 0; static int statusblank = 0;
/* The number of keystrokes left before we blank the status bar. */ /* 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. */ /* 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. */ /* Until where in the relevant line the current row is drawn. */
static bool has_more = FALSE; static bool has_more = FALSE;
/* Whether the current line has more text after the displayed part. */ /* Whether the current line has more text after the displayed part. */
static bool is_shorter = TRUE; static bool is_shorter = TRUE;
/* Whether a row's text is narrower than the screen's width. */ /* 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 #ifndef NANO_TINY
static size_t sequel_column = 0; static size_t sequel_column = 0;
/* The starting column of the next chunk when softwrapping. */ /* The starting column of the next chunk when softwrapping. */
@ -86,7 +88,7 @@ void add_to_macrobuffer(int code)
macro_buffer[macro_length - 1] = 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) void snip_last_keystroke(void)
{ {
macro_length--; macro_length--;
@ -126,7 +128,8 @@ void run_macro(void)
return; 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++) for (size_t i = 0; i < macro_length; i++)
key_buffer[i] = macro_buffer[i]; key_buffer[i] = macro_buffer[i];
@ -186,6 +189,17 @@ linestruct *get_prev_visible_line(linestruct *line)
return line->prev; return line->prev;
} }
/* 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;
}
/* Control character compatibility: /* Control character compatibility:
* *
* - Ctrl-H is Backspace under ASCII, ANSI, VT100, and VT220. * - Ctrl-H is Backspace under ASCII, ANSI, VT100, and VT220.
@ -209,22 +223,17 @@ linestruct *get_prev_visible_line(linestruct *line)
* We support escape sequences for ANSI, VT100, VT220, VT320, the Linux * We support escape sequences for ANSI, VT100, VT220, VT320, the Linux
* console, the FreeBSD console, the Mach console, xterm, and Terminal, * console, the FreeBSD console, the Mach console, xterm, and Terminal,
* and some for Konsole, rxvt, Eterm, and iTerm2. Among these sequences, * 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.) * (Ctrl-I is also Tab on ANSI, which we already support.)
* - PageDown on FreeBSD console == Center (5) on numeric keypad with * - PageDown on FreeBSD console == Center (5) on numeric keypad with
* NumLock off on Linux console; the latter is omitted. (The editing * NumLock off on Linux console; the latter is useless and omitted.
* keypad key is more important to have working than the numeric * - F1 on FreeBSD console == the mouse sequence on xterm/rxvt/Eterm;
* keypad key, because the latter has no value when NumLock is off.) * the latter is omitted. (Mouse input works only when KEY_MOUSE
* - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the * is generated on mouse events, not with the raw escape sequence.)
* 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.)
* - F9 on FreeBSD console == PageDown on Mach console; the former is * - F9 on FreeBSD console == PageDown on Mach console; the former is
* omitted. (The editing keypad is more important to have working * omitted. (Moving the cursor is more important than a function key.)
* than the function keys, because the functions of the former are
* not arbitrary and the functions of the latter are.)
* - F10 on FreeBSD console == PageUp on Mach console; the former is * - F10 on FreeBSD console == PageUp on Mach console; the former is
* omitted. (Same as above.) */ * omitted. (Same as above.) */
@ -251,6 +260,7 @@ void read_keys_from(WINDOW *frame)
lastmessage != INFO) || spotlighted)) { lastmessage != INFO) || spotlighted)) {
timed = TRUE; timed = TRUE;
halfdelay(ISSET(QUICK_BLANK) ? 8 : 15); halfdelay(ISSET(QUICK_BLANK) ? 8 : 15);
/* Counteract a side effect of half-delay mode. */
disable_kb_interrupt(); disable_kb_interrupt();
} }
#endif #endif
@ -267,6 +277,7 @@ void read_keys_from(WINDOW *frame)
if (timed) { if (timed) {
timed = FALSE; timed = FALSE;
/* Leave half-delay mode. */
raw(); raw();
if (input == ERR) { if (input == ERR) {
@ -298,10 +309,13 @@ void read_keys_from(WINDOW *frame)
curs_set(0); curs_set(0);
/* Initiate the keystroke buffer, and save the keycode in it. */ /* When there is no keystroke buffer yet, allocate one. */
key_buffer = nrealloc(key_buffer, sizeof(int)); if (!key_buffer)
nextcodes = key_buffer; reserve_space_for(capacity);
key_buffer[0] = input; key_buffer[0] = input;
nextcodes = key_buffer;
waiting_codes = 1; waiting_codes = 1;
#ifndef NANO_TINY #ifndef NANO_TINY
@ -335,10 +349,11 @@ void read_keys_from(WINDOW *frame)
if (input == ERR) if (input == ERR)
break; break;
/* Extend the keystroke buffer, and save the keycode at its end. */ /* When the keystroke buffer is full, extend it. */
key_buffer = nrealloc(key_buffer, ++waiting_codes * sizeof(int)); if (waiting_codes == capacity)
key_buffer[waiting_codes - 1] = input; reserve_space_for(2 * capacity);
nextcodes = key_buffer;
key_buffer[waiting_codes++] = input;
} }
/* Restore blocking-input mode. */ /* Restore blocking-input mode. */
@ -361,16 +376,11 @@ size_t waiting_keycodes(void)
/* Add the given keycode to the front of the keystroke buffer. */ /* Add the given keycode to the front of the keystroke buffer. */
void put_back(int keycode) 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 there is no room at the head of the keystroke buffer, make room. */
if (nextcodes == key_buffer) { if (nextcodes == key_buffer) {
key_buffer = nrealloc(key_buffer, (waiting_codes + 1) * sizeof(int)); if (waiting_codes == capacity)
if (waiting_codes) reserve_space_for(2 * capacity);
memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int)); memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int));
nextcodes = key_buffer;
} else } else
nextcodes--; nextcodes--;
@ -411,19 +421,24 @@ int get_code_from_plantation(void)
commandname = measured_copy(plants_pointer + 1, closing - plants_pointer - 1); commandname = measured_copy(plants_pointer + 1, closing - plants_pointer - 1);
planted_shortcut = strtosc(commandname); planted_shortcut = strtosc(commandname);
if (planted_shortcut) { if (!planted_shortcut)
plants_pointer = closing + 1;
if (*plants_pointer != '\0')
put_back(MORE_PLANTS);
return PLANTED_COMMAND;
} else
return NO_SUCH_FUNCTION; return NO_SUCH_FUNCTION;
plants_pointer = closing + 1;
if (*plants_pointer != '\0')
put_back(MORE_PLANTS);
return PLANTED_COMMAND;
} else { } else {
char *opening = strchr(plants_pointer, '{'); 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); put_back(MORE_PLANTS);
} else
length = strlen(plants_pointer);
for (int index = length - 1; index >= 0; index--) for (int index = length - 1; index >= 0; index--)
put_back((unsigned char)plants_pointer[index]); put_back((unsigned char)plants_pointer[index]);
@ -1397,79 +1412,48 @@ int get_kbinput(WINDOW *frame, bool showcursor)
#ifdef ENABLE_UTF8 #ifdef ENABLE_UTF8
#define INVALID_DIGIT -77 #define INVALID_DIGIT -77
/* If the given symbol is a valid hexadecimal digit, multiply it by factor /* For each consecutive call, gather the given symbol into a Unicode code point.
* and add the result to the given unicode, and return PROCEED to signify * When it's complete (with six digits, or when Space or Enter is typed), return
* okay. When not a hexadecimal digit, return the symbol itself. */ * the assembled code. Until then, return PROCEED when the symbol is valid, or
long add_unicode_digit(int symbol, long factor, long *unicode) * an error code for anything other than hexadecimal, Space, and Enter. */
{
if ('0' <= symbol && symbol <= '9')
*unicode += (symbol - '0') * factor;
else if ('a' <= tolower(symbol) && tolower(symbol) <= 'f')
*unicode += (tolower(symbol) - 'a' + 10) * factor;
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. */
long assemble_unicode(int symbol) long assemble_unicode(int symbol)
{ {
static long unicode = 0; static long unicode = 0;
static int digits = 0; static int digits = 0;
long retval = PROCEED; long outcome = PROCEED;
switch (++digits) { if ('0' <= symbol && symbol <= '9')
case 1: unicode = (unicode << 4) + symbol - '0';
unicode = (symbol - '0') * 0x100000; else if ('a' <= (symbol | 0x20) && (symbol | 0x20) <= 'f')
break; unicode = (unicode << 4) + (symbol | 0x20) - 'a' + 10;
case 2: else if (symbol == '\r' || symbol == ' ')
/* The second digit must be zero if the first was one, but outcome = unicode;
* may be any hexadecimal value if the first was zero. */ else
if (symbol == '0' || unicode == 0) outcome = INVALID_DIGIT;
retval = add_unicode_digit(symbol, 0x10000, &unicode);
else /* If also the sixth digit was a valid hexadecimal value, then the
retval = INVALID_DIGIT; * Unicode sequence is complete, so return it (when it's valid). */
break; if (++digits == 6 && outcome == PROCEED)
case 3: outcome = (unicode < 0x110000) ? unicode : INVALID_DIGIT;
/* Later digits may be any hexadecimal value. */
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. */
if (retval == PROCEED)
retval = unicode;
break;
}
/* Show feedback only when editing, not when at a prompt. */ /* Show feedback only when editing, not when at a prompt. */
if (retval == PROCEED && currmenu == MMAIN) { if (outcome == PROCEED && currmenu == MMAIN) {
char partial[7] = "......"; char partial[7] = " ";
/* Construct the partial result, right-padding it with dots. */ sprintf(partial + 6 - digits, "%0*lX", digits, unicode);
snprintf(partial, digits + 1, "%06lX", unicode);
partial[digits] = '.';
/* TRANSLATORS: This is shown while a six-digit hexadecimal /* TRANSLATORS: This is shown while a six-digit hexadecimal
* Unicode character code (%s) is being typed in. */ * Unicode character code (%s) is being typed in. */
statusline(INFO, _("Unicode Input: %s"), partial); statusline(INFO, _("Unicode Input: %s"), partial);
} }
/* If we have an end result, reset the Unicode digit counter. */ /* If we have an end result, reset the value and the counter. */
if (retval != PROCEED) if (outcome != PROCEED) {
unicode = 0;
digits = 0; digits = 0;
}
return retval; return outcome;
} }
#endif /* ENABLE_UTF8 */ #endif /* ENABLE_UTF8 */
@ -1483,7 +1467,6 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count)
reveal_cursor = TRUE; reveal_cursor = TRUE;
/* Read in the first code. */
keycode = get_input(frame); keycode = get_input(frame);
#ifndef NANO_TINY #ifndef NANO_TINY
@ -1498,14 +1481,14 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count)
yield = nmalloc(6 * sizeof(int)); yield = nmalloc(6 * sizeof(int));
#ifdef ENABLE_UTF8 #ifdef ENABLE_UTF8
/* If the first code is a valid Unicode starter digit (0 or 1), /* If the key code is a hexadecimal digit, commence Unicode input. */
* commence Unicode input. Otherwise, put the code back. */ if (using_utf8() && isxdigit(keycode)) {
if (using_utf8() && (keycode == '0' || keycode == '1')) {
long unicode = assemble_unicode(keycode); long unicode = assemble_unicode(keycode);
char multibyte[MB_CUR_MAX]; char multibyte[MB_CUR_MAX];
reveal_cursor = FALSE; reveal_cursor = FALSE;
/* Gather at most six hexadecimal digits. */
while (unicode == PROCEED) { while (unicode == PROCEED) {
keycode = get_input(frame); keycode = get_input(frame);
unicode = assemble_unicode(keycode); unicode = assemble_unicode(keycode);
@ -1518,7 +1501,7 @@ int *parse_verbatim_kbinput(WINDOW *frame, size_t *count)
return NULL; return NULL;
} }
#endif #endif
/* For an invalid digit, discard its possible continuation bytes. */ /* For an invalid keystroke, discard its possible continuation bytes. */
if (unicode == INVALID_DIGIT) { if (unicode == INVALID_DIGIT) {
if (keycode == ESC_CODE && waiting_codes) { if (keycode == ESC_CODE && waiting_codes) {
get_input(NULL); get_input(NULL);
@ -1599,9 +1582,6 @@ char *get_verbatim_kbinput(WINDOW *frame, size_t *count)
/* Turn bracketed-paste mode back on. */ /* Turn bracketed-paste mode back on. */
printf("\x1B[?2004h"); printf("\x1B[?2004h");
fflush(stdout); fflush(stdout);
if (ISSET(ZERO) && currmenu == MMAIN)
wredrawln(midwin, editwinrows - 1, 1);
#endif #endif
/* Turn flow control characters back on if necessary and turn the /* Turn flow control characters back on if necessary and turn the
@ -2533,7 +2513,7 @@ void bottombars(int menu)
if (index + 2 >= number) if (index + 2 >= number)
thiswidth += COLS % itemwidth; thiswidth += COLS % itemwidth;
post_one_key(s->keystr, _(f->desc), thiswidth); post_one_key(s->keystr, _(f->tag), thiswidth);
index++; index++;
} }
@ -3794,16 +3774,17 @@ void spotlight_softwrapped(size_t from_col, size_t to_col)
#endif #endif
#ifdef ENABLE_EXTRA #ifdef ENABLE_EXTRA
#define CREDIT_LEN 54 #define CREDIT_LEN 52
#define XLCREDIT_LEN 9 #define XLCREDIT_LEN 9
/* Fully blank the terminal screen, then slowly "crawl" the credits over it. /* Fully blank the terminal screen, then slowly "crawl" the credits over it.
* Abort the crawl upon any keystroke. */ * Abort the crawl upon any keystroke. */
void do_credits(void) void do_credits(void)
{ {
bool with_empty_line = ISSET(EMPTY_LINE); bool with_interface = !ISSET(ZERO);
bool with_help = !ISSET(NO_HELP); bool with_help = !ISSET(NO_HELP);
int kbinput = ERR, crpos = 0, xlpos = 0; int crpos = 0, xlpos = 0;
const char *credits[CREDIT_LEN] = { const char *credits[CREDIT_LEN] = {
NULL, /* "The nano text editor" */ NULL, /* "The nano text editor" */
NULL, /* "version" */ NULL, /* "version" */
@ -3851,13 +3832,11 @@ void do_credits(void)
"", "",
"", "",
"", "",
"",
"(C) 2022", "(C) 2022",
"Free Software Foundation, Inc.", "Free Software Foundation, Inc.",
"", "",
"", "",
"", "",
"",
"https://nano-editor.org/" "https://nano-editor.org/"
}; };
@ -3873,8 +3852,8 @@ void do_credits(void)
N_("Thank you for using nano!") N_("Thank you for using nano!")
}; };
if (with_empty_line || with_help) { if (with_interface || with_help) {
UNSET(EMPTY_LINE); SET(ZERO);
SET(NO_HELP); SET(NO_HELP);
window_init(); window_init();
} }
@ -3882,49 +3861,38 @@ void do_credits(void)
nodelay(midwin, TRUE); nodelay(midwin, TRUE);
scrollok(midwin, TRUE); scrollok(midwin, TRUE);
blank_titlebar();
blank_edit(); blank_edit();
blank_statusbar();
wrefresh(topwin);
wrefresh(midwin); wrefresh(midwin);
wrefresh(footwin); napms(600);
napms(700);
for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) { for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
if (crpos < CREDIT_LEN) { if (crpos < CREDIT_LEN) {
const char *what; const char *text = credits[crpos];
if (credits[crpos] == NULL) if (!text)
what = _(xlcredits[xlpos++]); text = _(xlcredits[xlpos++]);
else
what = credits[crpos];
mvwaddstr(midwin, editwinrows - 1 - (editwinrows % 2), mvwaddstr(midwin, editwinrows - 1, (COLS - breadth(text)) / 2, text);
COLS / 2 - breadth(what) / 2 - 1, what);
wrefresh(midwin); wrefresh(midwin);
} }
if ((kbinput = wgetch(midwin)) != ERR) if (wgetch(midwin) != ERR)
break; break;
napms(700); napms(600);
wscrl(midwin, 1); wscrl(midwin, 1);
wrefresh(midwin); wrefresh(midwin);
if ((kbinput = wgetch(midwin)) != ERR) if (wgetch(midwin) != ERR)
break; break;
napms(700); napms(600);
wscrl(midwin, 1); wscrl(midwin, 1);
wrefresh(midwin); wrefresh(midwin);
} }
if (kbinput != ERR) if (with_interface)
ungetch(kbinput); UNSET(ZERO);
if (with_empty_line)
SET(EMPTY_LINE);
if (with_help) if (with_help)
UNSET(NO_HELP); UNSET(NO_HELP);
window_init(); window_init();