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.])
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
@ -220,7 +244,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
@ -229,6 +253,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
@ -286,14 +334,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,

View File

@ -150,16 +150,18 @@
<b>--disable-color</b> Disable color and syntax highlighting
<b>--disable-comment</b> Disable the comment/uncomment function
<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-histories</b> Disable the saving of search strings and cursor positions
<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-linenumbers</b> Disable line numbering
<b>--disable-linter</b> Disable the linting tool
<b>--disable-mouse</b> Disable mouse support
<b>--disable-multibuffer</b> Disable the opening of multiple file buffers
<b>--disable-nanorc</b> Disable the use of .nanorc files
<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-wordcomp</b> Disable the word-completion function
<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.
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<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 built-in help (\fB^G\fR) lists all the available ones.
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
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
@ -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:
@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:
@ -1336,9 +1348,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}
@ -1346,6 +1358,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:
@ -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.
@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.
@ -1941,6 +1964,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 +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
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.

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:
\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
@ -551,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:
@ -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.
.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.

View File

@ -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:

View File

@ -255,63 +255,39 @@ 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 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. */
unsigned stash[sizeof(flags) / sizeof(flags[0])];
/* A storage place for the current flag settings. */
size_t began_at = selected;
/* 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
/* 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) {
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"));
}
}
/* 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 (strstrwrapper(thename, needle, thename)) {
if (looking_at == selected)
/* 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"));
break;
return;
}
/* If we're back at the beginning and didn't find any match... */
if (looking_at == selected) {
/* When we're back at the starting point without any match... */
if (selected == began_at) {
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.

View File

@ -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 <Tab> is pressed while the mark is on. */
@ -658,14 +654,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. */

View File

@ -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
@ -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);
@ -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 */
@ -989,7 +989,14 @@ 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 = 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;
}
@ -1530,12 +1537,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;
}
@ -1857,13 +1864,12 @@ 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);
wrote = fwrite(line->data, 1, data_len, thefile);
/* Re-encode any embedded NULs as LFs. */
recode_NUL_to_LF(line->data, data_len);

View File

@ -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
}
@ -692,10 +692,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
@ -1023,9 +1025,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
@ -1065,7 +1069,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
@ -1073,7 +1077,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
@ -1153,7 +1157,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);
@ -1207,9 +1211,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

View File

@ -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");

View File

@ -304,12 +304,10 @@ 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)
if (fwrite(item->data, 1, length, histfile) < length)
return FALSE;
if (putc('\n', histfile) == EOF)
return FALSE;
@ -451,14 +449,13 @@ 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';
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);

View File

@ -430,10 +430,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. */
@ -487,7 +486,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);
@ -500,7 +499,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. */
@ -695,6 +694,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
@ -710,6 +712,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
@ -744,6 +749,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
@ -759,6 +767,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
@ -1277,10 +1288,10 @@ void unbound_key(int code)
* (from the keyboard) that nano does not recognize. */
statusline(AHEM, _("Unknown sequence"));
#ifdef ENABLE_NANORC
else if (code == NO_SUCH_FUNCTION)
statusline(AHEM, _("Unknown function: %s"), commandname);
else if (code == MISSING_BRACE)
statusline(AHEM, _("Missing }"));
else if (code == NO_SUCH_FUNCTION)
statusline(AHEM, _("No such function: %s"), commandname);
#endif
#ifndef NANO_TINY
else if (code > KEY_F0 && code < KEY_F0 + 25)
@ -1297,17 +1308,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();
}
@ -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. */
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 ||
@ -1400,13 +1410,13 @@ 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
f == complete_a_word ||
#endif
f == do_verbatim_input);
f == do_replace || f == do_verbatim_input);
}
#ifndef NANO_TINY
@ -1545,6 +1555,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
@ -1591,21 +1603,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 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);
free(puddle);
puddle = NULL;
depth = 0;
}
@ -2506,6 +2520,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. */

View File

@ -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
@ -256,6 +252,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,21 +265,23 @@ 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;
}
}
/* 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 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);
free(puddle);
puddle = NULL;
depth = 0;
}
}
@ -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)

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);
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);
@ -524,8 +526,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
@ -544,7 +548,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
@ -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);
#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
/* Most functions in winio.c. */
linestruct *get_next_visible_line(linestruct *line);
linestruct *get_prev_visible_line(linestruct *line);
#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
void implant(const char *string);

View File

@ -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)
@ -276,9 +264,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
@ -493,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)
{
@ -502,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. */
@ -785,6 +787,12 @@ void parse_binding(char *ptr, bool dobind)
goto free_things;
}
menu = name_to_menu(menuptr);
if (menu == 0) {
jot_error(N_("Unknown menu: %s"), 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. */
@ -799,17 +807,11 @@ 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;
}
}
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)
@ -1348,7 +1350,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
@ -1530,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;
}

View File

@ -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
@ -738,6 +739,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)
{
@ -747,13 +749,18 @@ 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();
UNFOLD_SEGMENT(openfile->current);
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.
@ -839,9 +846,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;

View File

@ -665,7 +665,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;
@ -835,7 +835,7 @@ void do_redo(void)
break;
}
if (redidmsg)
if (redidmsg && !ISSET(ZERO))
statusline(HUSH, _("Redid %s"), redidmsg);
openfile->current_undo = u;
@ -2039,7 +2039,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)
{
@ -2056,7 +2056,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)
@ -2234,7 +2236,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. */
@ -2579,7 +2581,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)
{
@ -2926,7 +2928,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)
{
@ -2961,7 +2965,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
@ -3051,7 +3055,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"));

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. */
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)
@ -484,7 +489,9 @@ void get_range(linestruct **top, linestruct **bot)
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. */
linestruct *line_from_number(ssize_t number)
{
@ -499,7 +506,7 @@ linestruct *line_from_number(ssize_t number)
return line;
}
#endif /* !NANO_TINY */
#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)

View File

@ -46,8 +46,14 @@ 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
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;
@ -56,18 +62,14 @@ 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. */
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 +88,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--;
@ -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];
@ -186,6 +189,17 @@ linestruct *get_prev_visible_line(linestruct *line)
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:
*
* - 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
* 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.) */
@ -251,6 +260,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
@ -267,6 +277,7 @@ void read_keys_from(WINDOW *frame)
if (timed) {
timed = FALSE;
/* Leave half-delay mode. */
raw();
if (input == ERR) {
@ -298,10 +309,13 @@ 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));
nextcodes = key_buffer;
/* When there is no keystroke buffer yet, allocate one. */
if (!key_buffer)
reserve_space_for(capacity);
key_buffer[0] = input;
nextcodes = key_buffer;
waiting_codes = 1;
#ifndef NANO_TINY
@ -335,10 +349,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. */
@ -361,16 +376,11 @@ 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) {
key_buffer = nrealloc(key_buffer, (waiting_codes + 1) * sizeof(int));
if (waiting_codes)
memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int));
nextcodes = key_buffer;
if (waiting_codes == capacity)
reserve_space_for(2 * capacity);
memmove(key_buffer + 1, key_buffer, waiting_codes * sizeof(int));
} else
nextcodes--;
@ -411,19 +421,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]);
@ -1397,79 +1412,48 @@ 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 factor, long *unicode)
{
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. */
/* 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;
static int digits = 0;
long retval = PROCEED;
long outcome = PROCEED;
switch (++digits) {
case 1:
unicode = (symbol - '0') * 0x100000;
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;
break;
case 3:
/* 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;
}
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 && outcome == PROCEED)
outcome = (unicode < 0x110000) ? unicode : INVALID_DIGIT;
/* Show feedback only when editing, not when at a prompt. */
if (retval == PROCEED && currmenu == MMAIN) {
char partial[7] = "......";
if (outcome == PROCEED && currmenu == MMAIN) {
char partial[7] = " ";
/* Construct the partial result, right-padding it with dots. */
snprintf(partial, digits + 1, "%06lX", unicode);
partial[digits] = '.';
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 (outcome != PROCEED) {
unicode = 0;
digits = 0;
}
return retval;
return outcome;
}
#endif /* ENABLE_UTF8 */
@ -1483,7 +1467,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
@ -1498,14 +1481,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 (using_utf8() && (keycode == '0' || keycode == '1')) {
/* 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);
@ -1518,7 +1501,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);
@ -1599,9 +1582,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
@ -2533,7 +2513,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++;
}
@ -3794,16 +3774,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;
int crpos = 0, xlpos = 0;
const char *credits[CREDIT_LEN] = {
NULL, /* "The nano text editor" */
NULL, /* "version" */
@ -3851,13 +3832,11 @@ void do_credits(void)
"",
"",
"",
"",
"(C) 2022",
"Free Software Foundation, Inc.",
"",
"",
"",
"",
"https://nano-editor.org/"
};
@ -3873,8 +3852,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();
}
@ -3882,49 +3861,38 @@ 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) {
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 - (editwinrows % 2),
COLS / 2 - breadth(what) / 2 - 1, what);
mvwaddstr(midwin, editwinrows - 1, (COLS - breadth(text)) / 2, text);
wrefresh(midwin);
}
if ((kbinput = wgetch(midwin)) != ERR)
if (wgetch(midwin) != ERR)
break;
napms(700);
napms(600);
wscrl(midwin, 1);
wrefresh(midwin);
if ((kbinput = wgetch(midwin)) != ERR)
if (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();