diff --git a/configure.ac b/configure.ac
index 891d6783..5bbdb1b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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,
diff --git a/doc/faq.html b/doc/faq.html
index 8d74b6b8..73f3863a 100644
--- a/doc/faq.html
+++ b/doc/faq.html
@@ -150,16 +150,18 @@
--disable-color Disable color and syntax highlighting
--disable-comment Disable the comment/uncomment function
--disable-extra Disable the easter egg
+ --disable-formatter Disable the formatting tool
--disable-help Disable the built-in help texts
--disable-histories Disable the saving of search strings and cursor positions
--disable-justify Disable the justify/unjustify functions
--disable-libmagic Disable the use of libmagic for determining a file's syntax
--disable-linenumbers Disable line numbering
+ --disable-linter Disable the linting tool
--disable-mouse Disable mouse support
--disable-multibuffer Disable the opening of multiple file buffers
--disable-nanorc Disable the use of .nanorc files
--disable-operatingdir Disable the setting of an operating directory
- --disable-speller Disable the spell-checker functions
+ --disable-speller Disable the spell-checking tool
--disable-tabcomp Disable the tab-completion functions
--disable-wordcomp Disable the word-completion function
--disable-wrapping Disable all hard-wrapping of text
diff --git a/doc/nano.1 b/doc/nano.1
index 1b46e3f0..d7d0723b 100644
--- a/doc/nano.1
+++ b/doc/nano.1
@@ -74,6 +74,12 @@ using the arrow keys. Holding down the Ctrl or Alt key too will increase
the stride.
Any cursor movement without Shift being held will cancel such a selection.
.sp
+Any valid Unicode code point can be inserted into the buffer by typing
+\fBM\-V\fR followed by the hexadecimal digits of the code point (concluded
+with \fB\fR or \fB\fR when it are fewer than six digits).
+A literal control code (except \fB^J\fR) can be inserted by typing
+\fBM\-V\fR followed by the pertinent keystroke.
+.sp
The two lines at the bottom of the screen show some important commands;
the built-in help (\fB^G\fR) lists all the available ones.
The default key bindings can be changed via a \fInanorc\fR file -- see
diff --git a/doc/nano.texi b/doc/nano.texi
index 816b95a2..aaed711d 100644
--- a/doc/nano.texi
+++ b/doc/nano.texi
@@ -222,14 +222,18 @@ typed the key with that value.
@item
For any possible character, pressing @kbd{M-V} (Alt+V) and then typing a
-six-digit hexadecimal number (starting with @kbd{0} or @kbd{1}) will enter the
-corresponding Unicode character into the buffer.
+series of hexadecimal digits (at most six, or concluded with @kbd{Enter} or
+@kbd{Space}) will enter the corresponding Unicode character into the buffer.
@end itemize
For example, typing @kbd{Esc Esc 2 3 4} will enter the character "ê" ---
useful when writing about a French party. Typing @kbd{M-V 0 0 2 2 c 4}
will enter the symbol "⋄", a little diamond.
+Typing @kbd{M-V} followed by anything other than a hexadecimal digit
+will enter this keystroke verbatim into the buffer, allowing the user
+to insert literal control codes (except @code{^J}) or escape sequences.
+
@node Commands
@section Commands
@@ -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.
diff --git a/doc/nanorc.5 b/doc/nanorc.5
index c8166c02..6e73db1e 100644
--- a/doc/nanorc.5
+++ b/doc/nanorc.5
@@ -426,6 +426,14 @@ It also means that lookahead and lookbehind are not possible.
A complete explanation can be found in the manual page of GNU grep:
\fBman grep\fR.
.sp
+Each regular expression in a \fBnanorc\fR file should be wrapped in
+double quotes (\fB""\fR). Multiple regular expressions can follow
+each other on a line by separating them with blanks. This means that
+a regular expression cannot contain a double quote followed by a blank.
+When you need this combination inside a regular expression,
+then either the double quote or the blank should be put
+between square brackets (\fB[]\fR).
+.sp
For each kind of file a separate syntax can be defined
via the following commands:
.TP
@@ -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.
diff --git a/doc/sample.nanorc.in b/doc/sample.nanorc.in
index e74c1077..f3c7ea37 100644
--- a/doc/sample.nanorc.in
+++ b/doc/sample.nanorc.in
@@ -292,6 +292,9 @@
## For copying a marked region to the system clipboard:
# bind Sh-M-T "{execute}|xsel -ib{enter}{undo}" main
+## For snipping trailing blanks when you save a file:
+# bind ^S "{execute}| sed 's/\s\+$//' {enter}{savefile}" main
+
## If you would like nano to have keybindings that are more "usual",
## such as ^O for Open, ^F for Find, ^H for Help, and ^Q for Quit,
## then uncomment these:
diff --git a/src/browser.c b/src/browser.c
index e633592a..6f93226a 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -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.
diff --git a/src/definitions.h b/src/definitions.h
index 23ffd223..2bc87667 100644
--- a/src/definitions.h
+++ b/src/definitions.h
@@ -214,16 +214,12 @@
#define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F
-/* A special keycode for when a string bind has been partially implanted. */
+/* Special keycodes for when a string bind has been partially implanted
+ * or has an unpaired opening brace, or when a function in a string bind
+ * needs execution or a specified function name is invalid. */
#define MORE_PLANTS 0x4EA
-
-/* A special keycode for when a string bind has an unpaired opening brace. */
#define MISSING_BRACE 0x4EB
-
-/* A special keycode for when a function in a string bind needs execution. */
#define PLANTED_COMMAND 0x4EC
-
-/* A special keycode for when a function name in a string bind is invalid. */
#define NO_SUCH_FUNCTION 0x4EF
/* A special keycode for when is pressed while the mark is on. */
@@ -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. */
diff --git a/src/files.c b/src/files.c
index b885a0cd..75256a96 100644
--- a/src/files.c
+++ b/src/files.c
@@ -57,7 +57,7 @@ void make_new_buffer(void)
openfile->next = newnode;
/* There is more than one buffer: show "Close" in help lines. */
- exitfunc->desc = close_tag;
+ exitfunc->tag = close_tag;
more_than_one = !inhelp || more_than_one;
}
#endif
@@ -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);
diff --git a/src/global.c b/src/global.c
index fabca4c7..c6c9a48f 100644
--- a/src/global.c
+++ b/src/global.c
@@ -317,8 +317,8 @@ void discard_buffer(void) {;}
void do_cancel(void) {;}
/* Add a function to the linked list of functions. */
-void add_to_funcs(void (*function)(void), int menus, const char *desc,
- const char *help, bool blank_after)
+void add_to_funcs(void (*function)(void), int menus, const char *tag,
+ const char *phrase, bool blank_after)
{
funcstruct *f = nmalloc(sizeof(funcstruct));
@@ -331,9 +331,9 @@ void add_to_funcs(void (*function)(void), int menus, const char *desc,
f->next = NULL;
f->func = function;
f->menus = menus;
- f->desc = desc;
+ f->tag = tag;
#ifdef ENABLE_HELP
- f->help = help;
+ f->phrase = phrase;
f->blank_after = blank_after;
#endif
}
@@ -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
diff --git a/src/help.c b/src/help.c
index 91c75e7e..ebb90671 100644
--- a/src/help.c
+++ b/src/help.c
@@ -224,7 +224,7 @@ void help_init(void)
* plus translated text, plus one or two \n's. */
for (f = allfuncs; f != NULL; f = f->next)
if (f->menus & currmenu)
- allocsize += strlen(_(f->help)) + 21;
+ allocsize += strlen(_(f->phrase)) + 21;
#ifndef NANO_TINY
/* If we're on the main list, we also count the toggle help text.
@@ -282,7 +282,7 @@ void help_init(void)
ptr += 10;
/* The shortcut's description. */
- ptr += sprintf(ptr, "%s\n", _(f->help));
+ ptr += sprintf(ptr, "%s\n", _(f->phrase));
if (f->blank_after)
ptr += sprintf(ptr, "\n");
diff --git a/src/history.c b/src/history.c
index 5cf4cb93..d5b96787 100644
--- a/src/history.c
+++ b/src/history.c
@@ -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);
diff --git a/src/nano.c b/src/nano.c
index 91fc1ce1..f784768f 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -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. */
diff --git a/src/prompt.c b/src/prompt.c
index 4a828638..84d4ef64 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -182,16 +182,12 @@ void copy_the_answer(void)
void paste_into_answer(void)
{
size_t pastelen = strlen(cutbuffer->data);
- char *fusion = nmalloc(strlen(answer) + pastelen + 1);
- /* Concatenate: the current answer before the cursor, the first line
- * of the cutbuffer, plus the rest of the current answer. */
- strncpy(fusion, answer, typing_x);
- strncpy(fusion + typing_x, cutbuffer->data, pastelen);
- strcpy(fusion + typing_x + pastelen, answer + typing_x);
+ answer = nrealloc(answer, strlen(answer) + pastelen + 1);
+ memmove(answer + typing_x + pastelen, answer + typing_x,
+ strlen(answer) - typing_x + 1);
+ strncpy(answer + typing_x, cutbuffer->data, pastelen);
- free(answer);
- answer = fusion;
typing_x += pastelen;
}
#endif
@@ -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)
diff --git a/src/prototypes.h b/src/prototypes.h
index 35ce7f6c..48a5521c 100644
--- a/src/prototypes.h
+++ b/src/prototypes.h
@@ -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);
diff --git a/src/rcfile.c b/src/rcfile.c
index 85f741ec..966da5d8 100644
--- a/src/rcfile.c
+++ b/src/rcfile.c
@@ -153,18 +153,6 @@ static bool seen_color_command = FALSE;
static colortype *lastcolor = NULL;
/* The end of the color list for the current syntax. */
#endif
-
-#define NUMBER_OF_MENUS 16
-char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith",
- "yesno", "gotoline", "writeout", "insert",
- "execute", "help", "spell", "linter",
- "browser", "whereisfile", "gotodir",
- "all" };
-int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH,
- MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE,
- MEXECUTE, MHELP, MSPELL, MLINTER,
- MBROWSER, MWHEREISFILE, MGOTODIR,
- MMOST|MBROWSER|MHELP|MYESNO };
#endif /* ENABLE_NANORC */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
@@ -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;
}
diff --git a/src/search.c b/src/search.c
index 576b42e9..4b603225 100644
--- a/src/search.c
+++ b/src/search.c
@@ -222,8 +222,9 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
continue;
}
#endif
- /* The match is valid. */
- break;
+ /* When not on the magic line, the match is valid. */
+ if (line->next || line->data[0])
+ break;
}
#ifndef NANO_TINY
@@ -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;
diff --git a/src/text.c b/src/text.c
index 48df9934..268ae35a 100644
--- a/src/text.c
+++ b/src/text.c
@@ -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"));
diff --git a/src/utils.c b/src/utils.c
index 22631b5b..d6470ccc 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -168,14 +168,19 @@ void recode_NUL_to_LF(char *string, size_t length)
}
}
-/* In the given string, recode each embedded newline as a NUL. */
-void recode_LF_to_NUL(char *string)
+/* In the given string, recode each embedded newline as a NUL,
+ * and return the number of bytes in the string. */
+size_t recode_LF_to_NUL(char *string)
{
+ char *beginning = string;
+
while (*string != '\0') {
if (*string == '\n')
*string = '\0';
string++;
}
+
+ return (string - beginning);
}
#if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
@@ -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)
diff --git a/src/winio.c b/src/winio.c
index d2e5a3f3..309233a3 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -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();