Compare commits

..

223 Commits
v6.2 ... master

Author SHA1 Message Date
Benno Schulenberg
ef35ea72cf input: neutralize two spurious keycodes from VTE terminals
At least some of the VTE-based terminals claim to be compatible with
xterm-25color (and set TERM to that value).  But they really aren't:
they mishandle the focus-in and focus-out events, for example.  So,
catch and discard the corresponding keycodes that nano shouldn't be
seeing at all.

This improves the fix for https://savannah.gnu.org/bugs/?64578.
2023-10-16 08:55:06 +02:00
Benno Schulenberg
8804b6dcd4 tweaks: adjust a comment for the changed handling of gray #rgb codes 2023-10-03 15:41:00 +02:00
Andy Koppe
86b8388889 rcfile: map the gray #rgb codes (#111 to #EEE) to the xterm grayscale
When the red, green and blue components of a three-digit hex #RGB code
are equal and they aren't #000 for black or #FFF for white, map them to
xterm-256color's 24-level grayscale ranging from index 232 to 255.

This means that the 14 gray levels available in #RGB codes all map to
different tones, whereas previously they mapped to only the four gray
tones available in the 6x6x6 color cube.

Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
2023-09-25 16:10:42 +02:00
Benno Schulenberg
812c48dde4 tweaks: add a comment that refers to the VTE spurious-code issue 2023-08-29 16:17:40 +02:00
Benno Schulenberg
f0f1c94afa input: intercept a spurious keycode and say what the actual problem is
Xfce Terminal sets TERM to xterm-256color even though it does not have
all the capabilities that an xterm has, leading it to misinterpret some
escape sequence and produce a spurious 0x24C key code.

Intercept this mistaken key code and tell the user what is wrong.

This mitigates https://savannah.gnu.org/bugs/?64578.
Reported-by: Lawrence R. Steeger
2023-08-27 15:01:37 +02:00
Benno Schulenberg
75b312ded1 revert the previous commit -- forget about -? as a synonym for --help
An ambiguous option like --back or --word would cause nano to spew
the entire help text.  It should do the latter only when the user
explicitly requests it.
2023-08-27 14:56:05 +02:00
Mateusz Kazimierczuk
e65b0ba654 options: add -? as a synonym of -h (--help)
The short option '-?' was removed nine years ago in commit 43019189,
then restored six years later in 5bd92d4c, and then removed again two
months later in 743100fe due to getopt() returning '?' for options
that aren't recognized, preventing the use of '-?' as a valid option.

However, getopt() provides a way to check for unrecognized options
via the 'optopt' variable, which gets set only for invalid options.

Signed-off-by: Mateusz Kazimierczuk <mataha+savannah@protonmail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2023-07-31 07:40:07 +02:00
Benno Schulenberg
d3dd403dc7 browser: report an error instead of crashing when the folder disappears
When the directory that the user is browsing in is deleted by another
process at the moment that nano is building the list of file names,
this can result in an empty list, which some items in the main loop
in browse() cannot handle.  Prevent this mishandling by not entering
the loop when the list is empty.

This fixes https://savannah.gnu.org/bugs/?64465.
Reported-by: Jerry Meng <jerrytstng@gmail.com>
2023-07-24 15:25:35 +02:00
Benno Schulenberg
7f4c2c6a25 docs: add a caveat in the FAQ about bracketed pastes 2023-06-04 08:07:10 +02:00
Benno Schulenberg
cb1b3a28ab tweaks: normalize the indentation after the previous changes 2023-05-21 11:29:02 +02:00
Benno Schulenberg
f7d8735b6b tweaks: reshuffle four lines, to allow folding some #ifdefs together
Also remove an unneeded pair of braces, split a comment,
and correct a mistaken #ifdef.
2023-05-21 11:27:45 +02:00
Benno Schulenberg
fc42ab9b46 bindings: allow speller and friends to be rebound also in restricted mode
Speller, linter, formatter, and execute-a-command cannot be used in
restricted mode, but the relevant keys should report that the function
is *disabled*, not that the key is unbound.

This fixes https://savannah.gnu.org/bugs/?64226.

Problem existed since version 3.2, since nano reads the nanorc files
also in restricted mode.
2023-05-21 10:51:37 +02:00
Benno Schulenberg
7f17777a4b docs: mention that a restricted nano does not access the history files
With some imagination, the lack of access could be inferred from the
other descriptions, but it's much better to be clear and explicit.

Also, separate two items that are unrelated and reshuffle them into
a neater order.

Triggered by https://savannah.gnu.org/bugs/?64181.
2023-05-14 08:17:25 +02:00
Benno Schulenberg
bcdb27416c docs: describe nano more specifically as a text editor
Especially the first sentences introducing nano should use the words
"text editor" and not just "editor".
2023-05-14 08:11:44 +02:00
Benno Schulenberg
15c6396d42 tweaks: rename a symbol (to be clearer), and add three missing comments 2023-05-14 08:11:05 +02:00
Benno Schulenberg
2c19345e58 docs: in a synopsis, use braces around a choice of required parts
This seems to be the convention.  For an example, see `man tar`.

This addresses https://savannah.gnu.org/bugs/?64125.
Reported-by: Eric S. Raymond <esr@thyrsus.com>
2023-05-01 10:48:02 +02:00
Benno Schulenberg
69a7dd86ec feedback: suppress filename and linecount when --zero is active
This suppression prevents the filename flashing by at the bottom
of the screen when switching between buffers.

This addresses https://savannah.gnu.org/bugs/?64019
Reported-by: Alan Cristhian Ruiz <alancristhian@protonmail.com>

Problem existed since version 6.0, since --zero was introduced.
2023-04-12 09:58:28 +02:00
Benno Schulenberg
fdcafb83e3 startup: use a format string, to deflect format-string attacks
This fixes the second part of https://savannah.gnu.org/bugs/?63964.

Reported-by: Vince Vince
2023-03-27 12:09:21 +02:00
Benno Schulenberg
b8ead3b511 linter: use a format string, to deflect format-string attacks
This fixes the first part of https://savannah.gnu.org/bugs/?63964.

Reported-by: Vince Vince
2023-03-27 12:09:21 +02:00
Benno Schulenberg
ffff664918 tweaks: shrink the set of characters recognized as line-column separator
This slightly reduces the chance that a filename is accidentally parsed
as containing both a line and a column number at its end.
2023-03-10 15:14:31 +01:00
Benno Schulenberg
bf984ecb9b docs: document the <filename>:<linenumber> thing for cursor positioning 2023-03-09 16:14:44 +01:00
Benno Schulenberg
f1e238a9af tweaks: condense the code that searches for a colon plus line number 2023-03-09 12:56:17 +01:00
Benjamin Valentin
5290a85afd new feature: interpret also <filename>:<linenumber> when opening a file
Various tools will output filenames with line numbers in the format
<filename>:<line>:<column>.  Support this format in addition to the
+<line>,<column> format when opening files.

Signed-off-by: Benjamin Valentin <benpicco@googlemail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2023-03-08 11:48:20 +01:00
Benno Schulenberg
b5157dd9cb tweaks: avoid calling isblank()/isalpha() on what could be a signed char
The isxxxxx() functions expect their parameter to be either EOF or
a value in the unsigned char range.  Passing a negative char value
could (in theory) result in unexpected behavior.
2023-02-24 17:31:58 +01:00
Benno Schulenberg
94812d17c8 tweaks: rename a struct element, to avoid a theoretical name collision
The <term.h> header file form ncurses defines the name "tab".
2023-02-23 17:08:45 +01:00
Benno Schulenberg
7681090c12 docs: clarify that a fileregex is matched against the absolute filename 2023-02-16 11:02:15 +01:00
Benno Schulenberg
866490c41f docs: add two examples of custom key bindings to the nanorc manpage 2023-02-16 10:44:10 +01:00
Benno Schulenberg
0662fc4d42 shutdown: ignore a modified buffer when in view mode
In view mode it should be impossible to modify any buffer, but...
when (through some bug) the user did succeed in modifying a buffer,
this should not lead to writing out this modified buffer to disk.

Had this safety stop been present earlier, it would have prevented
the second part of https://savannah.gnu.org/bugs/?63616.
2023-02-14 10:25:38 +01:00
Benno Schulenberg
078d612b9e tweaks: add a missing 'type' attribute to a <style> tag
To stop the W3 validator from complaining.
2023-02-03 17:30:27 +01:00
Benno Schulenberg
26025f79ce docs: add a reference to the 'help-nano' mailing list 2023-01-30 17:13:17 +01:00
Benno Schulenberg
1c307bc1be docs: add a clarifying note to the description of --tabstospaces 2023-01-26 17:01:48 +01:00
Benno Schulenberg
7abddbd752 tweaks: slightly improve a comment, to be more accurate
A string bind can only contain bytes (chars), not keycodes (integers,
in nano upto 0x4FF).  So, apart from an error code or a placeholder
command code, get_code_from_plantation() can only return a byte.
2023-01-26 17:01:02 +01:00
Benno Schulenberg
51c9f7270c input: let the handler of string binds return a byte whenever possible
The function get_code_from_plantation() should return ERR only when
the string bind is fully exhausted.  In the normal case, where some
bytes are still available, it should return the first of these bytes,
so that the {verbatim} function will work too.

This fixes https://savannah.gnu.org/bugs/?63702.

Bug existed since version 7.0, commit 958ec294,
since command cartouches were introduced.
2023-01-26 10:01:18 +01:00
Benno Schulenberg
b896670e85 tweaks: make two strings equal to a third, to slightly ease translation 2023-01-25 16:45:50 +01:00
Benno Schulenberg
69dd0c40bb help: give the "Replace with" prompt its own help text
This addresses https://savannah.gnu.org/bugs/?63691.

Problem existed since the help texts were introduced,
in version 1.1.3, commit b3655b4c.
2023-01-23 16:41:25 +01:00
Matteo Raso
c374c773ad syntax: python: colorize decorators specially
Decorators are documented at https://peps.python.org/pep-0318/.

Signed-off-by: Matteo Raso <matteo_luigi_raso@protonmail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2023-01-22 12:31:45 +01:00
Benno Schulenberg
2fd7888a51 bindings: show ^- instead of ^/ for 'flipgoto' when on a Linux console
This should have been part of commit 344db835 from three days ago.
2023-01-20 14:55:11 +01:00
Jordi Mallach
d19915ea44 docs: fix "availabilty" typo in the manual and the nanorc manpage 2023-01-19 09:24:58 +01:00
Benno Schulenberg
549e37d218 po: update translations and regenerate POT file and PO files 2023-01-18 09:52:50 +01:00
Benno Schulenberg
7b48a9f671 bump version numbers and add a news item for the 7.2 release 2023-01-18 09:07:41 +01:00
Benno Schulenberg
344db835e4 bindings: let ^/ toggle between the 'search' and 'gotoline' menus
This extra binding allows the user to start a forward search with ^/^/,
so that they can avoid the ^W keystroke that would close a browser tab.
2023-01-17 11:00:27 +01:00
Benno Schulenberg
04353acccf gnulib: update to its current upstream state 2023-01-17 10:51:40 +01:00
Benno Schulenberg
c33f0b7d8d docs: give ^K and ^U some useful function in the alternative bindings
Make them behave like in a shell: let ^K delete till end-of-line,
and let ^U delete to beginning-of-line.
2023-01-12 15:55:38 +01:00
Benno Schulenberg
fd51fee424 docs: put the binding of ^Y after its unbinding, for it to be effective
The misordering existed since commit 16ee4636 from a year ago.
2023-01-12 15:44:01 +01:00
Benno Schulenberg
c8b44816fe tweaks: separate a special thanks from the preceding ones
This separation avoids the impression that we're thanking the mentioned
people for their use of nano (something they probably don't do).

(Also, remove two other blank lines -- effectively moving these two
lines further up, keeping the total amount of whitespace the same.)
2023-01-06 12:37:08 +01:00
Benno Schulenberg
6e88389fb8 copyright: update the years for the FSF 2023-01-06 10:37:15 +01:00
Benno Schulenberg
298447e22d syntax: html: colorize specially the other two emphasizing tags too
In most cases, <em> behaves like <i> and <strong> behaves like <b>,
so it makes sense to treat all of them in the same manner.
2023-01-05 17:01:20 +01:00
Benno Schulenberg
a3c7de8a50 tweaks: rewrap an old news item 2023-01-05 11:50:06 +01:00
Benno Schulenberg
264f305d94 input: disallow bracketed pastes when in view mode
When in view mode, nothing shouldbe allowed to be entered into
(or deleted from) the buffer.

This fixes https://savannah.gnu.org/bugs/?63616.
Reported-by: Timothy Liu <liuxf19@163.com>

Bug existed since version 4.8, commit 0e6d693d.
2023-01-04 11:10:28 +01:00
Benno Schulenberg
f8ec08a928 tweaks: avoid warnings when compiling with -Wpedantic 2023-01-02 10:48:18 +01:00
Benno Schulenberg
f09e6c183e po: update translations and regenerate POT file and PO files 2022-12-14 11:34:51 +01:00
Benno Schulenberg
3791ed86a3 bump version numbers and add a news item for the 7.1 release 2022-12-14 10:50:32 +01:00
Benno Schulenberg
7f772693eb tweaks: wrap overlong lines in the Tcl syntax, to make them manageable
(And also to stay within the theoretical 256-byte POSIX limit.)
2022-12-11 12:40:22 +01:00
Benno Schulenberg
5771f1ea14 copyright: update the last year for significantly changed files 2022-12-11 12:28:07 +01:00
Benno Schulenberg
0f4db1ed0d docs: say thanks to the Albanian translator
Also, properly sort a nearby name and add its missing diacritic.
2022-12-09 11:58:07 +01:00
Benno Schulenberg
4b35626aec rcfile: report an error when an included file does not exist
That is: do not silently return from parse_one_include() when the
given file does not exist, *and* return the filename (or pattern)
itself when it matches nothing.

This fixes https://savannah.gnu.org/bugs/?63446.

Bug existed since version 4.0, commit d3f0d32e.
2022-12-02 11:37:05 +01:00
Benno Schulenberg
846588ee81 tweaks: avoid passing NULL to access()
This prevents an unwanted message when nano
is compiled with -fsanitize=undefined.

This fixes https://savannah.gnu.org/bugs/?63447.

Problem existed since version 4.8, commit 343f97b3,
since the --rcfile option was added.
2022-11-30 12:08:47 +01:00
Benno Schulenberg
4f92b12a6a text: upon Enter, eat only lefthand blanks, not any other characters
Make sure that there is only whitespace to the left of the cursor
before setting 'allblanks' to TRUE, because this latter value will
cause these characters to be eaten (as a special case, to avoid
creating lines that contain only blanks when both --autoindent
and --breaklonglines are on).

This fixes https://savannah.gnu.org/bugs/?63407.
Reported-by: Tasos Papastylianou <tpapastylianou@hotmail.com>

Bug existed since version 2.9.8, commit d00ab406.
2022-11-28 11:01:50 +01:00
Benno Schulenberg
4b4b20f8a9 build: fix compilation when configured with --disable-comment
This fixes https://savannah.gnu.org/bugs/?63372.
Reported-by: Hannu Nyman <hannu.nyman@iki.fi>

Problem existed since version 7.0, commit 4b928b46.
2022-11-18 16:49:23 +01:00
Benno Schulenberg
e26fe9bddd po: update translations and regenerate POT file and PO files 2022-11-15 11:44:29 +01:00
Benno Schulenberg
972be2df04 bump version numbers and add a news item for the 7.0 release 2022-11-15 11:17:34 +01:00
Benno Schulenberg
374cb6a7f8 gnulib: update to its current upstream state 2022-11-13 12:23:45 +01:00
Benno Schulenberg
923d6300ad tweaks: attribute some of the features that were added in the last years 2022-11-11 16:39:34 +01:00
Benno Schulenberg
baa4edc6ca docs: improve the legibility of an itemized list
Also, mention my email address in the colophon of the PDF,
to avoid the impression that Chris is the sole responsible.

And improve the general layout by adding three blank lines.
2022-10-20 15:44:44 +02:00
Benno Schulenberg
9875311bcc startup: for +/string, center the found occurrence when possible
This places the cursor in a more predictable position.

This fixes https://savannah.gnu.org/bugs/?63223.

Issue existed since version 4.4, commit a9dd73fb,
since the +/string feature was introduced.
2022-10-17 12:11:41 +02:00
Benno Schulenberg
c3a453512a startup: report an empty search string also when there is a modifier
Not just for +/ (a search command without a string) should nano report
an "Empty search string", but also for +c/ or +r/ or similar.

This fixes https://savannah.gnu.org/bugs/?63222.

Bug existed since version 4.4, commit 2326bf69.
2022-10-16 11:22:32 +02:00
Benno Schulenberg
e413ed8e1d execute: show "Cancelled" instead of "Error" when the user hits ^C
(The "Cancelled" is shown with a red background, like an error,
but that is needed so that do_undo() will be called afterward.)
2022-10-09 16:28:06 +02:00
Benno Schulenberg
858f411447 filtering: terminate also the sender process when the user hits ^C
When the user interrupts an external command that hangs or takes too
long, nano should also kill the data-sending process (when present).

This fixes https://savannah.gnu.org/bugs/?63177.

Bug existed in this form since version 4.3, commit d946f38a,
but basically existed since version 3.0, commit ec339d3b.
2022-10-09 11:24:03 +02:00
Benno Schulenberg
19c8cea8e5 files: improve the error handling when executing an external command
When something goes wrong while executing an external command or while
piping text to it, report an error on the status bar and restore the
state of the buffer to what it was before the execution.

This fixes https://savannah.gnu.org/bugs/?63114.

Bug existed since version 2.9.8, since filtering text was introduced,
but basically existed since before version 2.0.0, since executing an
external command was introduced.
2022-10-07 09:32:11 +02:00
Benno Schulenberg
1ae10b1487 tweaks: elide an unused return value
The execute_command() function — then called open_pipe() — was changed
to have a boolean return value in commit ce62e82a eighteen years ago,
but the value has never been used or checked.
2022-10-03 10:28:43 +02:00
Benno Schulenberg
35cde9f8d7 tweaks: elide an unused parameter
The parameter has been redundant since commit 9faa9545 from two years ago.
2022-10-03 10:10:10 +02:00
Benno Schulenberg
d4d2840f5d filtering: when returning to a line number, ensure it is within range
The function line_from_number() can handle only line numbers that exist,
and will crash otherwise.  (The lack of checks makes the function fast.)

This fixes https://savannah.gnu.org/bugs/?63120.

Bug existed since commit d1e28417 from five weeks ago.
2022-09-28 16:40:31 +02:00
Benno Schulenberg
119ec47072 tweaks: replace sizeof(char) with 1, as that is assumed anyway
Since commit c848ec3d from three years ago, nano has assumed that
'char' is always a single byte.  So... elide the last occurrences
of sizeof(char), as they give a false impression of generality.
2022-09-28 12:48:45 +02:00
Benno Schulenberg
ceb305a780 tweaks: avoid iterating over the same string twice in a row
The function recode_LF_to_NUL() has to iterate over the string anyway
(to replace each \n with \0), so... instead of calling strlen() right
before it, just let recode_LF_to_NUL() return the length of the string.

(This is not speed-critical code, but... it saves one iteration over
the entire buffer contents whenever writing out a file.)
2022-09-28 12:22:40 +02:00
Benno Schulenberg
1dc2a75cb6 files: before sending data to an external command, decode LF back to NUL
(There is no need to recode the NULs back to LFs because the sending of
the data happens in a separate process, which then simply disappears.)

This fixes https://savannah.gnu.org/bugs/?63106.

Bug existed since version 2.9.8, since filtering a buffer or a region
through an external command was introduced.
2022-09-27 15:48:03 +02:00
Benno Schulenberg
8d7b716ea7 startup: quit when standard input is not a TTY (after handling arguments)
Not quitting would make nano hang for several seconds (which is very
annoying) and then die and save an emergency file (which is useless).

This fixes https://savannah.gnu.org/bugs/?63109.

Bug existed chiefly since version 5.9, commit 8d1a666d,
but basically existed since before version 2.0.0.
2022-09-27 12:18:28 +02:00
Benno Schulenberg
034af70a65 tweaks: simplify a pasting routine, modelling it after the injection one 2022-09-26 16:10:15 +02:00
Benno Schulenberg
162c213e7b tweaks: improve two comments, and exclude two unneeded prototypes
And declare two more variables as 'static', like all its neighbors.
2022-09-26 15:53:22 +02:00
Benno Schulenberg
6fde7d8a51 input: allocate two small character buffers too, and never free them
Analogous to commit 3922b531: instead of allocating and later freeing
a tiny fragment of memory for every character that the user enters (in
the edit window or at a prompt), reserve a small piece in the beginning
and retain it, and increase (but never decrease) its size as needed.

This addresses the second part of https://savannah.gnu.org/bugs/?63086.
2022-09-25 16:15:31 +02:00
Benno Schulenberg
e4abef5768 input: give up when the capacity of the keystroke buffer overflows
In theory, the 'size_t' of 'capacity' could be just two bytes, which
means the keystroke buffer would overflow for pastes that are larger
than 32 kilobytes -- which are unlikely to occur, but... possible.
However, previously there was *no* overflow check when extending the
keystroke buffer (only when trying to put back a key code), so this
check is an improvement.

(On a regular machine, 'size_t' is at least four bytes, which means
the keystroke buffer would overflow at 2 gigabytes.  Such a paste
is extremely unlikely to occur, so this check is really a no-op.)
2022-09-25 10:17:32 +02:00
Benno Schulenberg
3922b531a8 input: allocate a small keystroke buffer, and never free it
Instead of allocating and freeing a tiny fragment of memory for every
keystroke, reserve a small piece in the beginning and then retain it,
because it will be needed again and again and again.  Increase the size
when needed (for a large paste, probably), but don't bother to shrink
it afterward.

This addresses the first part of https://savannah.gnu.org/bugs/?63086.
2022-09-25 09:22:29 +02:00
Benno Schulenberg
0d1438a731 tweaks: reshuffle a declaration, and correct the wording of a comment
Also, drop an unneeded condition, as memmove() allows moving zero bytes.
2022-09-23 09:34:14 +02:00
Benno Schulenberg
7eb66d3e09 tweaks: condense a comment, add two small ones, and reshuffle a line
(Apart from reducing the verbosity of the long comment, also harmonize
its format: mentioning the FreeBSD key always first.)
2022-09-22 10:50:05 +02:00
Benno Schulenberg
c7a600063d tweaks: reshuffle some lines, to be more readable instead of compact 2022-09-20 16:21:32 +02:00
Benno Schulenberg
5b654ce9fb docs: suggest a key binding for snipping trailing blanks
This addresses https://savannah.gnu.org/bugs/?63062.
2022-09-18 10:44:05 +02:00
Benno Schulenberg
98e9a881c0 docs: mention in the man page how M-V can insert any Unicode code point
This addresses https://savannah.gnu.org/bugs/?63055.

Inspired-by: Tasos Papastylianou <tpapastylianou@hotmail.com>
2022-09-18 09:05:28 +02:00
Benno Schulenberg
f420f7c177 verbatim: do not overwrite the status bar when the code is invalid
Move the triggering of the line redraw out of the error path, and
into a better place: next to the normal clearing of the feedback.

This fixes https://savannah.gnu.org/bugs/?63053.

Bug existed since version 6.0, commit 6d828cf4.
2022-09-13 16:57:28 +02:00
Benno Schulenberg
50954a4b6a search: skip a match on the magic line, as it is a just convenience line
As the magic line isn't really a line (it is not counted in the number
of lines read and written), and nothing is on it (not even a newline),
it doesn't make sense to allow any regex, like ^ or $, to match it.

This fixes https://savannah.gnu.org/bugs/?63034.
Indirectly-reported-by: Mike Scalora <mike@scalora.org>

Bug existed since before version 2.0.0.
2022-09-12 08:47:51 +02:00
Benno Schulenberg
567310e698 tweaks: reduce four variations of a message to a single common form
(This could have been done a long time ago, but it simply didn't occur
to me.)
2022-09-12 08:45:37 +02:00
Benno Schulenberg
f90b710c9b tweaks: group the special keycodes for implanted strings together
This shows better that they are related.
2022-09-11 17:49:44 +02:00
Benno Schulenberg
bdaec3f934 docs: clarify the distinction between binding a function and "{function}"
This addresses https://savannah.gnu.org/bugs/?63010.

Inspired-by: Tasos Papastylianou <tpapastylianou@hotmail.com>
2022-09-11 16:29:18 +02:00
Benno Schulenberg
8198fd9c58 tweaks: reword and/or condense four comments 2022-09-11 16:29:02 +02:00
Benno Schulenberg
358a10e3cc tweaks: elide an assignment by iterating with the target variable 2022-09-11 12:03:06 +02:00
Benno Schulenberg
7b935e0d40 tweaks: elide an intermediary variable that is no longer needed 2022-09-11 11:57:11 +02:00
Benno Schulenberg
7034c3cc47 tweaks: drop shunting of flags by calling the needed function directly
Calling strstrwrapper() with the Backwards, Casesens, and Regex flags
unset is equivalent to calling mbstrcasestr().  So... do that instead
and quit saving and restoring the flags for each call of findfile().

This saving-and-restoring has been redundant since commit b0957254
from eight years ago.
2022-09-11 11:51:34 +02:00
Benno Schulenberg
e30eadb4de verbatim: don't show dots during Unicode input, as they give wrong idea
The dots gave the impression that the next keystroke (hex digit) would
land somewhere on the dots.  But this is not so -- the current digits
are instead shifted to the left and the new digit is added at the end.

Also adjust and improve several comments.
2022-09-11 09:23:44 +02:00
Benno Schulenberg
3e3f4a167a tweaks: elide a function that does not need to be a separate function
Also elide three calls of tolower(), using ORing with 0x20 instead,
as we're dealing with plain ASCII here.

Rename a variable too, away from a double abbreviation.
2022-09-11 09:01:06 +02:00
Benno Schulenberg
c98528f8d3 tweaks: simplify a function now that a Unicode code can be typed quicker 2022-09-11 09:01:06 +02:00
Benno Schulenberg
75e5f885e5 verbatim: allow the user to finish Unicode input with <Enter> or <Space>
Instead of requiring always six digits, allow the user to indicate
with <Enter> or <Space> that the digits typed so far are the complete
Unicode code point (when prefixed with the missing number of zeroes).

This fulfills https://savannah.gnu.org/bugs/?63021.

Inspired-by: the <Ctrl+Shift+U> shortcut that some desktops have
2022-09-11 09:01:06 +02:00
Benno Schulenberg
40b9e68e02 goto: don't center the current line when the user specified a column only
This does not quite do what I would have liked (scroll only when needed)
when on a softwrapped line and jumping to a different chunk, but... it's
still better than needlessly centering the line.

(The user can still center the line, if that is what they want, by using
a period or a slash instead of a comma.)

This addresses https://savannah.gnu.org/bugs/?63008.
2022-09-04 10:49:52 +02:00
Benno Schulenberg
e7491920fd docs: explain how to include a double quote plus space in a nanorc regex
As double-quote-plus-space indicates the end of a regular expression
in a nanorc file, the inclusion of this combination *in* a regular
expression requires breaking the juxtaposition of the two, which
can be achieved by putting either of them between square brackets.

(It can also be achieved by preceding the space with a backslash,
which is shorter, but... the above method is more symmetrical.)

This addresses https://savannah.gnu.org/bugs/?62997.
2022-09-01 17:29:04 +02:00
Benno Schulenberg
9904aa5538 tweaks: make the crawl use the whole screen also in the tiny version
Nobody will configure nano with --enable-tiny --enable-extra, but *if*
someone does, the title bar should be absent during the crawl.

Also, swap two messages, so that their order in the POT file will be
more sensible -- a closing brace comes after the function name.
2022-09-01 08:38:18 +02:00
Benno Schulenberg
41b89aef8c tweaks: move the arrays of menu names and symbols to where they are used
Also, use a better return value for the "unrecognized name" case,
so that it cannot possibly be confused with the "all menus" case.
2022-08-31 17:28:09 +02:00
Benno Schulenberg
3925c137a4 tweaks: make two error messages more succinct and easier to translate
"Cannot map name %s to <thing>..." was unnecessarily verbose and vague.
I have kept these strings unchanged all these years because I didn't
want to invalidate the existing translations.  But now it's time to
harmonize things and simply say "Unknown <thing>: %s" for an invalid
function name, menu name, option name, and syntax name.

("No such <thing>: %s" is nice and snappy, but its translations often
are clumsy and longer and unclear.)
2022-08-31 16:57:58 +02:00
Benno Schulenberg
97fa42c82b memory: avoid a leak when a string bind specifies an unknown menu
(It is a harmless leak, but LeakSanitizer is loud when it complains.)

After having determined that there is a menu name, first check that
it is valid, before processing the string or the function name.

This fixes https://savannah.gnu.org/bugs/?62991.

Problem existed since version 2.9.4, since string binds were introduced.
2022-08-31 16:32:40 +02:00
Benno Schulenberg
ccabaac5a0 build: exclude two unneeded functions correctly from the tiny version
This also amends commit 4f9abb52 from yesterday -- I don't know how I
managed to overlook the warning.  :/
2022-08-29 12:31:39 +02:00
Benno Schulenberg
80f7852941 docs: describe --disable-formatter and --disable-linter configure options 2022-08-29 08:30:30 +02:00
Benno Schulenberg
6243831dfb build: add options --disable-formatter and --disable-linter to configure
This makes more sense than letting the formatter and the linter depend
on ENABLE_COLOR (which maybe should have been named ENABLE_SYNTAX).

This fulfills https://savannah.gnu.org/bugs/?50080.
2022-08-29 08:28:28 +02:00
Benno Schulenberg
4f9abb52a4 build: fix compilation when configured with --enable-tiny
Problem existed since commit d1e28417 from four days ago.
2022-08-28 14:56:44 +02:00
Benno Schulenberg
7bab8780ad tweaks: rewrap some lines, drop a redundant call, and reshuffle a line
Six years ago, commit a878f5f1 introduced a call of regenerate_screen()
directly in the input routine, which made the call of refresh_func() in
the prompt routine redundant -- except when in the file browser.
2022-08-28 09:03:09 +02:00
Benno Schulenberg
d0dc270eec tweaks: rename two record elements and three parameters, for clarity 2022-08-28 08:58:36 +02:00
Benno Schulenberg
cd9402075a tweaks: elide a variable, rename another, and reshuffle an assignment 2022-08-26 09:29:44 +02:00
Benno Schulenberg
b1f3bdfcbd extra: use the whole terminal for the crawl, and quicken it a bit
Since version 6.0, with option --zero, the edit window can cover
the whole terminal.  Make use of this also for the credits crawl.

Also, shorten and quicken the crawl a bit, and make it start always
on the bottom row, instead of (for mysterious reasons) one row higher
when the terminal has an odd number of rows.

Furthermore, don't put back the key the user typed to stop the crawl.
2022-08-26 09:17:17 +02:00
Benno Schulenberg
541a2dbc88 feedback: suppress undo/redo messages when option --zero is in effect
This fixes https://savannah.gnu.org/bugs/?62956.

Problem existed since version 6.0, since --zero was introduced.
2022-08-25 08:48:07 +02:00
Benno Schulenberg
d1e28417d5 tweaks: move to a given line number more efficiently
Instead of starting always from the top of the buffer, start at the
current line, as it is quite likely to be near the target line.

(Since the previous commit we're assuming that openfile->current is
always valid, so we might as well make use of this assumption.)

Also, rename a parameter to make its meaning more explicit.
2022-08-24 16:29:29 +02:00
Benno Schulenberg
9410a55679 undo: make sure the current line is defined before it is referenced
After undoing an <Enter> or redoing a line join, it is likely that the
"eaten" and freed line was the current line.  In fact, goto_line_posx()
should not refer to it any more, but... accommodate for this and just
set openfile->current to a valid value before calling goto_line_posx().

This fixes https://savannah.gnu.org/bugs/?62952.

Bug existed since version 6.3, commit eea3e1f0.
2022-08-24 15:45:24 +02:00
Benno Schulenberg
25ceefbd89 prompt: ingest queued characters before handling any subsequent function
This fixes https://savannah.gnu.org/bugs/?62946.

Bug existed since commit 40a4225e from five days ago.
2022-08-24 09:28:14 +02:00
Benno Schulenberg
a37c4bb59e tweaks: reshuffle a line, to group things better 2022-08-23 15:40:27 +02:00
Benno Schulenberg
ee1f8a0494 prompt: return FALSE for non-editing functions also in the tiny version
This fixes https://savannah.gnu.org/bugs/?62942.

Bug existed since commit 2f25b6a6 from four days ago.
2022-08-23 15:32:30 +02:00
Benno Schulenberg
2c5459a1b7 tweaks: fold two cases together, because they basically do the same 2022-08-21 16:57:03 +02:00
Benno Schulenberg
b561c386c3 tweaks: discard a bracketed paste in the browser more efficiently 2022-08-21 10:45:49 +02:00
Benno Schulenberg
a374dd0359 prompt: toggle the help lines only for the 'nohelp' toggle
This fixes https://savannah.gnu.org/bugs/?62914.

Problem existed since commit 958ec294 from three days ago.
2022-08-21 10:22:38 +02:00
Benno Schulenberg
aba4f4e0e2 tweaks: avoid sometimes calling a function three times in a row 2022-08-21 09:59:55 +02:00
Benno Schulenberg
210c94d82f prompt: allow rebinding also ^N, ^Q, and ^Y at the yes-no prompt
Checking for the literal ^N, ^Q, and ^Y before checking for do_toggle
and full_refresh made it impossible to rebind any of those keystrokes
to these two functions.  (Not that anyone would want this, but...)

Problem existed since version 4.3, commits 341601e1 and 82aea04c.
2022-08-21 09:42:21 +02:00
Benno Schulenberg
c410ba4d42 tweaks: reshuffle two lines, for conciseness and in preparation 2022-08-21 09:28:07 +02:00
Benno Schulenberg
f3738fe164 tweaks: don't use a pointer when the value itself is all that is needed 2022-08-21 09:12:35 +02:00
Benno Schulenberg
04a08fe6a5 tweaks: rename a variable, away from an abbreviation 2022-08-21 09:02:32 +02:00
Benno Schulenberg
69d33ec170 tweaks: rewrap line, improve wording, and correct typo in old news item 2022-08-19 16:58:09 +02:00
Benno Schulenberg
40a4225ed8 tweaks: reshuffle some code, to not determine a shortcut twice
This addresses https://savannah.gnu.org/bugs/?62913.

Problem has existed since version 2.1.0, commit eb64314f.
2022-08-19 16:38:55 +02:00
Benno Schulenberg
801622ce19 tweaks: normalize the indentation after the previous change 2022-08-19 12:48:15 +02:00
Benno Schulenberg
67750a30ba tweaks: reshuffle some code and drop some comments, for conciseness 2022-08-19 12:47:49 +02:00
Benno Schulenberg
2f25b6a650 tweaks: elide a parameter by moving the general case one level up 2022-08-19 11:56:01 +02:00
Benno Schulenberg
5a3bd329d6 prompt: prevent execution of inadmissible functions in view mode
This fixes https://savannah.gnu.org/bugs/?62912.

Bug existed since commit 958ec294 from earlier today,
but was enabled by commit 433dd921 from three days ago.
2022-08-18 16:01:31 +02:00
Benno Schulenberg
8b4bf2bb8d docs: mention that string binds may contain function names between braces 2022-08-18 09:11:49 +02:00
Benno Schulenberg
2a515058be docs: replace control codes in the examples with {command} cartouches
This avoids https://savannah.gnu.org/bugs/?61720.

Problem existed since version 5.8, commit 74c6bdac.
2022-08-18 09:11:49 +02:00
Benno Schulenberg
3785f762fc syntax: nanorc: colorize valid function names plus surrounding braces 2022-08-18 09:11:49 +02:00
Benno Schulenberg
5cee9f183b build: exclude some pieces that are not needed with --disable-nanorc 2022-08-18 09:11:49 +02:00
Benno Schulenberg
958ec294b2 input: interpret commands of the form {functionname} inside string binds
This allows specifying bindable functions in a string bind by name
instead of by the literal control code or escape sequence to which
they are bound, which makes for a much more readable string bind,
and also allows specifying functions that are not bound to any key.

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

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

Original-idea-by: Brand Huntsman <alpha@qzx.com>
  https://lists.gnu.org/archive/html/nano-devel/2018-02/msg00006.html
2022-08-18 09:07:05 +02:00
Benno Schulenberg
3a781fd719 help: move the M-Del item up, so that M-PgUp and M-PgDn are paired
(It needs a huge terminal and a tiny font for these to come into view,
but... it's possible.)
2022-08-17 15:11:03 +02:00
Benno Schulenberg
f4a2e7efe2 tweaks: move the --magic option up, so that --zero comes last
This makes that the three options that change the default layout
of the interface (--stateflags, --minibar, --zero) come last.

Also, sort the option letters into a consistent order in the code.
2022-08-17 14:31:44 +02:00
Benno Schulenberg
027365503f tweaks: add parentheses for consistency, and reshuffle for conciseness
(That 'also_the_last' now gets reset to FALSE whenever the cursor moves
to a different line is fine -- it is redundant when the mark is off, but
it does no harm.)
2022-08-17 09:34:08 +02:00
Benno Schulenberg
e31d59ebc8 tweaks: move two checks plus corresponding calls to a better place
It was silly to check again specifically for <Del> and <Bsp> after
any possible keystroke had been handled.  It was an anomaly.

This makes the tail of do_deletion() similar to the tail of inject().

(That sometimes the current line is redrawn twice is acceptable -- how
often does one type <Backspace> while having Shift-selected something?
Normally one wouldn't, because it would cancel the selection, so it's
fine to accept some inefficiency for this case.)
2022-08-17 09:01:55 +02:00
Benno Schulenberg
11178e14ab tweaks: rename a macro for clarity, and normalize some indentation
(Continuation lines should be indented by at least two extra tabs.)
2022-08-17 08:41:14 +02:00
Benno Schulenberg
0bcbd0015f tweaks: check the multiline regexes only for Delete and Backspace
The checking for all functions that are marked as not-okay-for-view-mode
was excessive and unneeded.  It had been inherited from commit d47d8cd4
from thirteen years ago, and was never verified for correctness.

This addresses the main part of https://savannah.gnu.org/bugs/?62903.
2022-08-16 16:23:44 +02:00
Benno Schulenberg
271bd5d3ba tweaks: allow the linter to be used in view mode, as it makes no changes
The linter has been marked as NOVIEW since it was introduced in 2.3.3.
But that was a mistake, as the tool does not change the buffer contents.

This addresses a minor part of https://savannah.gnu.org/bugs/?62903.
2022-08-16 16:06:18 +02:00
Benno Schulenberg
74d252a68f tweaks: drop a parameter that is no longer used
The previous commit made the 'viewok' parameter redundant.
2022-08-16 15:12:52 +02:00
Benno Schulenberg
4b928b466a tweaks: determine in another way whether a shortcut is okay in view mode
This addresses the other part of https://savannah.gnu.org/bugs/?62899.
2022-08-16 15:03:02 +02:00
Benno Schulenberg
10b4d0c8ad tweaks: use an auxiliary variable to avoid dereferences of 'shortcut'
This is especially meant to avoid dereferences of 'shortcut' after its
linked function has been executed, because in an upcoming commit this
execution may have freed the shortcut's structure.

(For symmetry, make the same change also in do_statusbar_input(), even
though it is not needed there.)

This addresses one part of https://savannah.gnu.org/bugs/?62899.
2022-08-16 15:03:02 +02:00
Benno Schulenberg
433dd92196 tweaks: drop an unneeded check for permissibility of prompt shortcuts
The only menus that are accessible in view mode are WhereIs, Insert,
WhereIsFile, GoToDirectory, and Help.  In the WhereIs menu, the only
keystroke that is not allowed in view mode (^R) is caught explicitly.
In the other four menus, all available shortcuts are permissible in
view mode, so... there is no need to check them at execution time.

(The ^R keystroke in the WhereIs menu is still shown in view mode
so as not to upset the pairing of the subsequent shortcuts.)
2022-08-15 14:49:03 +02:00
Benno Schulenberg
78d284881c help: don't show the New-Buffer toggle when in view mode
Since commit 63f2be7a from four years ago, view mode always sets
multibuffer mode, allowing ^R (Insert) to be invoked.  But the
user is then not allowed to switch multibuffer mode off, so...
don't show the toggle.
2022-08-15 11:53:54 +02:00
Benno Schulenberg
a36b726bde completion: search through all open buffers for possible completions
This allows one to complete also words that are present in other files
(when these are open in other buffers).

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

Original-patch-by: Marco Diego Aurélio Mesquita <marcodiegomesquita@gmail.com>
2022-08-12 10:20:27 +02:00
Benno Schulenberg
83629b9991 startup: ensure that +/string centers the match also with --linenumbers
When confirm_margin() first sets the margin needed for the requested
line numbers, also then it needs to keep 'focusing' TRUE.  Only when
actually toggling --linenumbers ON (from a zero margin to something)
should focusing be suppressed, in order to obtain smooth scrolling
when the cursor is pushed off-screen.

This fixes https://savannah.gnu.org/bugs/?62885.

Bug existed since version 4.4, since the search-at-startup feature
was introduced.
2022-08-11 09:32:01 +02:00
Benno Schulenberg
405c66e864 tweaks: delete a flag that is no longer used
Suspension is always enabled since version 6.0.

(Also, swap two conditions, to match identical pairs elsewhere.)
2022-08-09 12:01:09 +02:00
Benno Schulenberg
e5df84a9ed help: prioritize the unshifted Meta keystrokes for buffer switching
In many keyboard layouts M-< and M-> are awkward to type (in a Spanish
layout, for example: Alt+Shift+AltGr+Z and Alt+Shift+AltGr+X when there
is no LSGT key), whereas M-, and M-. are simple two-key keystrokes in
most Latin-script layouts.  So, show M-,/M-. before showing M-</M->.

Also, make a condition more precise, to not show M-Left and M-Right in
the tiny version, when those shortcuts are not understood.
2022-08-05 16:29:21 +02:00
Benno Schulenberg
614a977259 po: update translations and regenerate POT file and PO files 2022-08-02 09:23:26 +02:00
Benno Schulenberg
f1651abdac bump version numbers and add a news item for the 6.4 release 2022-08-02 08:44:50 +02:00
Benno Schulenberg
05a06048fc tweaks: add a missing word to a news item 2022-08-01 09:21:55 +02:00
Benno Schulenberg
c599bc9bff tweaks: rename a variable, to not be the same as a function name 2022-08-01 09:17:35 +02:00
Benno Schulenberg
54ded4527a options: stop accepting -z, as --suspendable has been dropped too
This should have been part of commit 98f9518b from seven weeks ago.
2022-07-31 19:47:11 +02:00
Benno Schulenberg
4f433cd601 tweaks: add a translator hint 2022-07-27 11:24:08 +02:00
Benno Schulenberg
accecb9863 tweaks: reshuffle a few lines, to group things better 2022-07-26 12:28:49 +02:00
Benno Schulenberg
079588cac5 gnulib: update to its current upstream state 2022-07-26 12:28:49 +02:00
Benno Schulenberg
1d10ee71bf syntax: python: mention an alternative linter in a comment 2022-07-26 12:28:49 +02:00
Benno Schulenberg
0520cbdccb syntax: perl: add missing keywords, and reduce the length of some lines
Also, compact the keywords less, so that things are easier to read.
2022-07-25 15:53:03 +02:00
Benno Schulenberg
3d3270c1b2 tweaks: put each regex on separate line, to better show many keywords
(The long list of keywords was divided over five separate regexes to
avoid exceeding the possible limit of 256 bytes/characters per regex.)
2022-07-25 14:48:40 +02:00
Benno Schulenberg
b60a26d40b tweaks: reshuffle a description and rewrap another
The reshuffling places the detailed descriptions of some commands
in the same section.
2022-07-25 10:45:02 +02:00
Benno Schulenberg
36fcdce886 docs: concisely describe how the linter behaves 2022-07-25 10:27:15 +02:00
Benno Schulenberg
b760388bbf help: reshuffle two shortcuts so that more help-line items are paired
Since version 6.0, Suspend is no longer bound by default, which meant
that it dropped out of the help lines, leaving the items after it in an
unpaired arrangement.  Move the Suspend item and its intended partner
to near the end of the list, to reestablish pairing for several items.
2022-07-25 09:08:02 +02:00
Benno Schulenberg
bb18524cce formatter: instead of leaving curses, use full_refresh() to wipe messages
This makes invoking the formatter cleaner, by giving feedback and *not*
leaving curses mode.  Leaving curses mode had the small advantage that
any messages from the formatter would be on the terminal after closing
nano.  But it had the disadvantage that invoking the formatter flashed
the screen.

This basically reverts commit 2b9f0619 from three years ago and then
solves the issue of intruding formatter messages in a different way.

This fulfills https://savannah.gnu.org/bugs/?62789.
Requested-by: Gert Cuykens <gert.cuykens@gmail.com>
2022-07-25 08:25:15 +02:00
Benno Schulenberg
05eaa0f0d7 tweaks: improve a comment, and reshuffle two functions plus some lines 2022-07-24 16:51:39 +02:00
Benno Schulenberg
d4a1dbd4a9 tweaks: rename two variables, to not contain the name of another
Also, elide an unneeded condition: when not softwrapping, left_x will
be zero, which is always smaller than or equal to the indentation.

Furthermore, reshuffle a few lines, improve three comments, and adjust
one to mention the parameter that was added in the previous commit.
2022-07-22 15:27:41 +02:00
Benno Schulenberg
0e9bef3429 display: remember text and column positions when softwrapping a line
This adjusts the main softwrapping routine so that it remembers the
reached point in a line's text and the corresponding column.  This
avoids having to scan the line from the beginning for each iterative
call, and thus saves a substantial amount of time when softwrapping
very long lines.

This mitigates https://savannah.gnu.org/bugs/?62442.
Reported-by: Devin Hussey <husseydevin@gmail.com>

Original-patch-by: Devin Hussey <husseydevin@gmail.com>
2022-07-20 14:06:24 +02:00
Benno Schulenberg
34238dc119 files: designate the root directory with a simple "/", not with "//"
The double slash would derail the file browser, causing a crash.

This fixes https://savannah.gnu.org/bugs/?62760.
Reported-by: Frank Wolff

Bug existed since version 6.3, commit fdd946c0.
2022-07-13 19:28:53 +02:00
Benno Schulenberg
18a40caa48 docs: remove the two notices about the changed defaults
It has been more than three years since version 4.0 was released,
the moment that the defaults for line wrapping, smooth scrolling,
and the size of the editing window were changed.

Keep the note in the texi manual, though, as it is less in the way,
and the manual generally contains more info than the man pages.
2022-06-19 10:30:44 +02:00
Benno Schulenberg
1980f1b2ba docs: stop mentioning the obsoleted keywords that were removed
But keep the note about --suspendable, as it has been obsoleted rather
recentl.  Move it to the NOTES section.
2022-06-19 10:29:46 +02:00
LIU Hao
ec0c13afda build: ignore errors from git describe
Due to CVE-2022-24765, Git refuses to operate on local repositories if
it runs as a different user from its owner.  Since version 2.35.2:

  $ sudo git describe --tags
  fatal: unsafe repository ('/home/lh_mouse/GitHub/nano-win' is owned by someone else)
  To add an exception for this directory, call:

    git config --global --add safe.directory /home/lh_mouse/GitHub/nano-win

Conventionally, a user, who wishes to build and install nano from Git,
does this:

  $ ./configure
  $ make
  $ sudo make install

The first `make` command builds the program as the current user.
The `make install` then installs the built files.

However, we have a recipe for 'revision.h' that is always executed,
even in the case of `make install`.  As here it is run as root, Git
actually fails and produces an empty string.  This causes `make install`
to rebuild nano.o and winio.o and results in an empty version string in
the upper left corner.

The solution is simple: First we attempt a dryrun of `git describe`.
If it fails, 'revision.h', which should have been updated by the first
`make` command, will be left intact.

Reference: https://nvd.nist.gov/vuln/detail/CVE-2022-24765

Signed-off-by: LIU Hao <lh_mouse@126.com>
2022-06-14 11:54:47 +02:00
Benno Schulenberg
ed41b3cefa version: condense the copyright message, to not dominate the output
It is enough to mention the year of the current release in the copyright
statement -- no need to specify the historical range of years.
2022-06-12 17:31:08 +02:00
Benno Schulenberg
80a924edfa docs: rename README.GIT to README.hacking, so it's clearer what is meant 2022-06-12 17:29:32 +02:00
Benno Schulenberg
98f9518bf2 rcfile: remove five obsolete or deprecated keywords 2022-06-12 17:03:15 +02:00
Benno Schulenberg
1de47610f4 syntax: default: do not colorize a square or angle bracket after a URL
Sometimes a URL is wrapped in [] or <> brackets -- the closing ] or >
is not part of the URL and should not be colored.
2022-06-07 17:24:23 +02:00
Benno Schulenberg
25ba7712f7 po: update translations and regenerate POT file and PO files 2022-04-28 10:36:42 +02:00
Benno Schulenberg
a6b534d760 bump version numbers and add a news item for the 6.3 release 2022-04-28 10:08:34 +02:00
Benno Schulenberg
494b191d55 gnulib: pull in the workaround for a build problem on NetBSD 2022-04-27 11:23:09 +02:00
Benno Schulenberg
450bfa7a75 build: fix compilation for --enable-{tiny,nanorc,color} 2022-04-22 11:47:21 +02:00
Benno Schulenberg
a52ac1375a formatting: change cursor position only after saving it in the undo item
When one wants an Undo to restore the cursor to where it was before an
operation, one shouldn't fiddle with the position before it is stored
in the relevant undo item.

This fixes https://savannah.gnu.org/bugs/?62341.

Bug existed since version 4.9, commit 38af812a.

(This effectively reverts commit 38af812a from two years ago.)
2022-04-21 12:31:19 +02:00
Benno Schulenberg
4990713e9e tweaks: change the indentation of a list, to match other indentations 2022-04-19 11:15:18 +02:00
Benno Schulenberg
c022c4cc6d docs: add an example binding for copying text to the system clipboard 2022-04-12 11:18:25 +02:00
Benno Schulenberg
6257dec0a7 filtering: close all output descriptors, so that 'xsel' will terminate
For some reason, when copying something to the system clipboard
with 'xsel', it wants to see all output descriptors closed before
it will exit without requiring ^C.

This fixes https://savannah.gnu.org/bugs/?62276.
Reported-by: Shi Yanling <sylphenix@126.com>

Bug existed since version 2.9.8, since piping text through an
external command was introduced.
2022-04-12 11:09:09 +02:00
Benno Schulenberg
ea9d49b9d8 tweaks: remove some stray spaces before a comma 2022-04-11 10:31:39 +02:00
Benno Schulenberg
42c7bfcf8a verbatim: with --zero, keep cursor in viewport when it was on bottom row
This fixes https://savannah.gnu.org/bugs/?62285.

Bug existed since version 6.0, since --zero was introduced.
2022-04-11 10:28:09 +02:00
Benno Schulenberg
e67d1bfeb8 build: fix compilation when configured with --disable-color 2022-04-08 11:35:44 +02:00
Benno Schulenberg
e2f444cfdf gnulib: update to its current upstream state 2022-04-08 10:52:55 +02:00
Benno Schulenberg
03b85df4eb tweaks: remove redundant braces, and add two translator hints 2022-04-08 09:38:42 +02:00
Benno Schulenberg
7db5c2f225 files: when the working directory exists, still check its accessibility
This fixes https://savannah.gnu.org/bugs/?62258.

Bug existed since commit 940b5eaa from yesterday.
2022-04-06 16:41:45 +02:00
Benno Schulenberg
603ce231d0 tweaks: simplify a fragment of code, and fold two lines together 2022-04-05 12:40:45 +02:00
Benno Schulenberg
940b5eaad1 files: show a warning when the working directory is gone (when used)
Instead of silently opening an empty buffer when the user tries to
open a file in the current but disappeared directory, give a clear
warning about the absence of this directory.

This improves the fix for https://savannah.gnu.org/bugs/?62244.
2022-04-05 12:34:04 +02:00
Benno Schulenberg
fdd946c02c files: do not change to a higher directory when the working one is gone
When the working directory has been deleted from under nano's feet,
get_full_path() would move up in the directory tree until getcwd()
would succeed.  This meant that a filename that was specified on the
command line without any path (or with a relative path) would refer
to a different file than what the user intended.  Not good.

So, stop changing directories in get_full_path().  Use the realpath()
function with NULL as second parameter instead -- it has been part of
the POSIX standard since 2008, time enough for operating systems to
have caught up.

In the bargain, this saves seventy lines of complicated logic.

This fixes https://savannah.gnu.org/bugs/?62244.

Bug existed since version 2.0.0, commit 85e35e67.
2022-04-04 12:52:35 +02:00
Benno Schulenberg
81e5b57d74 syntax: xml: colorize user-defined entities differently
Also improve two comments.
2022-04-04 12:08:23 +02:00
Benno Schulenberg
b568705eec syntax: xml: colorize /> properly, and colorize prolog tags differently
Use lightgrey for the prolog tags, as they normally are unimportant
boiler-plate stuff.  Comments are likely to be more relevant.

Any /> is part of the tag itself, not of the attributes.
2022-04-04 10:01:49 +02:00
Benno Schulenberg
fe42eb7a1a painting: stop coloring an extremely long line after 2000 bytes
Especially when softwrapping and when multiline regexes are involved,
colorizing takes roughly exponential time relative to the line length.
To avoid bogging down, stop colorizing a line beyond a certain point.

This mitigates https://savannah.gnu.org/bugs/?61799.
Reported-by: Devin Hussey <husseydevin@gmail.com>
2022-04-03 12:28:22 +02:00
Benno Schulenberg
df7b0a6d97 execute: clear an anchor only when the whole buffer gets filtered
Although an anchor at the top line is rather pointless, it shouldn't
get cleared when the user pipes just a part of the buffer through an
external command.
2022-03-28 11:38:22 +02:00
Benno Schulenberg
fcf598e797 execute: stay on the same line number when filtering the whole buffer
When the filter command makes just small, per-line changes, keeping the
cursor at the same line number allows the user to observe the effect of
the changes -- which is not possible when the cursor gets moved to the
end of the buffer.

This partially fulfills https://savannah.gnu.org/bugs/?57248.
2022-03-28 11:15:04 +02:00
Benno Schulenberg
d9cb12f6e3 tweaks: move the saving and restoring of flags to where it is needed 2022-03-27 18:44:48 +02:00
Benno Schulenberg
0f23729253 tweaks: prevent the adding of an unwanted newline in a different way
The prevention is needed only for temporary files, not for normal files.
2022-03-27 18:20:17 +02:00
Benno Schulenberg
3def429290 tweaks: don't leave an orphaned temporary file behind when writing fails 2022-03-27 12:37:01 +02:00
Benno Schulenberg
803ea0d7a0 justify: stay at the same line number when doing a full justification
The same line number may not be the same position in the text, but
it will be approximately -- and it is certainly better than leaving
the cursor at the end of the buffer.

This fulfills https://savannah.gnu.org/bugs/?61175.
2022-03-24 17:05:55 +01:00
Benno Schulenberg
9b014876cd tweaks: trim a few comments, rename a function, and reshuffle some code 2022-03-20 13:20:31 +01:00
Benno Schulenberg
9ccf85eaa8 tweaks: avoid a function call when two plain assignments will do 2022-03-18 11:40:03 +01:00
Benno Schulenberg
93fa53c3e8 tweaks: elide an unneeded call of strlen() 2022-03-18 11:36:10 +01:00
Benno Schulenberg
eea3e1f0b2 tweaks: make the triggering of the recalculation of multidata less eager
Also, trigger recalculation when an undo or redo causes a large enough
forward jump.
2022-03-18 11:29:18 +01:00
Benno Schulenberg
e6e22ea976 tweaks: normalize the indentation after the previous change 2022-03-17 14:09:09 +01:00
Benno Schulenberg
80c2000f87 tweaks: simplify a bit of code, eliding two labels and three gotos 2022-03-17 14:09:09 +01:00
Benno Schulenberg
15a0a129c8 painting: recalculate the multidata when making large strides or changes
When making a forward movement larger than a screenful, we cannot rely
on the multidata of the line before the new screen start to have been
set correctly by a previous screen drawing, so we need to recompute all
of the multidata, for the whole buffer, so that afterward we can freely
move around and draw the screen without having to do any backtracking.

Also when a piece of text larger than a screenful is pasted or inserted,
all the multidata needs to be recomputed.

This fixes https://savannah.gnu.org/bugs/?60041,
and fixes https://savannah.gnu.org/bugs/?62056.

First bug existed in this form since version 2.4.2, commit d49c267f
(but editing Python was incomparably slower in those days).

Second bug existed since version 5.6, commit 43d94692.
2022-03-17 14:07:42 +01:00
Benno Schulenberg
51bd04b541 painting: colorize text also after an unterminated start match
This does not waste time looking for an end match, which is especially
wasteful when there is none.  Also, it makes the coloring behavior more
consistent: any start match will cause coloring of the subsequent text,
no matter whether the user is in the middle of the file or near the end.
2022-03-14 09:12:55 +01:00
Benno Schulenberg
18ba7f60c1 painting: tighten the check for a lacking end match on a colored line
As it's possible for the start regex to match what is actually the end
match of a multiline thing (see the Python triple quotes, for example),
make sure that such a detected start match is *not* an end match, just
to avoid a needless full-screen refresh.
2022-03-08 09:47:36 +01:00
Benno Schulenberg
5c3e00d70a build: remove an obsolete check -- the dependent code was deleted
The code fragment that was conditionalized on REDEFINING_MACROS_OK
was deleted five weeks ago in commit 3f494e35.
2022-03-07 18:09:51 +01:00
Benno Schulenberg
6c4c77971e build: add the --disable-maintainer-mode option to ./configure
By passing --disable-maintainer-mode to ./configure the user can disable
autoconf build rules that would cause configure to be rebuilt and rerun.

Kind-of-requested-by: Mike Frysinger <vapier@gentoo.org>
2022-03-07 17:26:30 +01:00
Benno Schulenberg
67adef8f6c display: suppress spotlight yellow and error red when NO_COLOR is set
This makes nano conform to the https://no-color.org/ idea: suppressing
any color in the output (in the default setup) when NO_COLOR is set in
the environment.

Specifying a color for any interface element will, however, re-enable
also yellow for the spotlight and red for error messages.
2022-03-06 17:03:42 +01:00
Benno Schulenberg
ed60e16974 tweaks: exclude the extra truncation warning from the tiny version 2022-03-04 12:12:48 +01:00
Benno Schulenberg
47c11ae83d feedback: show extra warning when writing failed due to "No space left"
This mitigates https://savannah.gnu.org/bugs/?36864.
Reported-by: Clarence Risher <sparr0@gmail.com>

Problem has existed since the beginning, as nano empties the existing
file before writing the current buffer contents into it.
2022-03-03 11:12:41 +01:00
Mike Frysinger
8173b1bfbe general: fix building for Windows
Fix building with x86_64-w64-mingw32 to cross-compile native Windows
programs.  Need to:

  * add checks for missing functions
  * don't use signals that are unavailable on the platform
  * avoid useless non-Linux sys/ioctl.h include
  * use putenv instead of setenv as the latter is unavailable
2022-03-01 11:05:07 +01:00
Benno Schulenberg
93400ec8a1 execute: don't crash when an empty buffer is piped through a command
That is, take into account that the cutbuffer could be NULL
(when updating the undo item).

This fixes https://savannah.gnu.org/bugs/?62107.

Bug existed since version 4.9, commit b15c5a7e.
2022-02-24 16:50:18 +01:00
Benno Schulenberg
0d85a798e5 painting: look for another start match only after the actual end match
The 'endmatch.rm_eo' value is relative to the end of the start match,
so to find the end of the end match, one has to add 'startmatch.rm_eo'
plus 'endmatch.rm_eo' to the starting point of the line.

This addresses https://savannah.gnu.org/bugs/?62091.

Problem existed since version 5.6, commit 0596b875.
2022-02-21 10:46:28 +01:00
82 changed files with 32817 additions and 25303 deletions

View File

@@ -8,7 +8,9 @@ Chris Allegretta <chrisa@asty.org>
Benno Schulenberg <bensberg@telfort.nl>
* An array of small bug fixes, the cut-word and block-jump
routines, text selection by holding Shift, macro recording
and replay, plus some key bindings. Current maintainer.
and replay, extra key bindings, the --indicator, --minibar,
and --zero options, and braced functions in string binds.
Current maintainer.
David Lawrence Ramsey <pooka109@gmail.com>
* Former stable series maintainer. Multiple buffer support,

214
ChangeLog
View File

@@ -1,3 +1,217 @@
Changes between v7.1 and v7.2:
------------------------------
Benno Schulenberg (11):
bindings: let ^/ toggle between the 'search' and 'gotoline' menus
bump version numbers and add a news item for the 7.2 release
copyright: update the years for the FSF
docs: give ^K and ^U some useful function in the alternative bindings
docs: put the binding of ^Y after its unbinding, for it to be effective
gnulib: update to its current upstream state
input: disallow bracketed pastes when in view mode
syntax: html: colorize specially the other two emphasizing tags too
tweaks: avoid warnings when compiling with -Wpedantic
tweaks: rewrap an old news item
tweaks: separate a special thanks from the preceding ones
Changes between v7.0 and v7.1:
------------------------------
Benno Schulenberg (8):
build: fix compilation when configured with --disable-comment
bump version numbers and add a news item for the 7.1 release
copyright: update the last year for significantly changed files
docs: say thanks to the Albanian translator
rcfile: report an error when an included file does not exist
text: upon Enter, eat only lefthand blanks, not any other characters
tweaks: avoid passing NULL to access()
tweaks: wrap overlong lines in the Tcl syntax, to make them manageable
Changes between v6.4 and v7.0:
------------------------------
Benno Schulenberg (94):
build: add options --disable-formatter and --disable-linter to configure
build: exclude some pieces that are not needed with --disable-nanorc
build: exclude two unneeded functions correctly from the tiny version
build: fix compilation when configured with --enable-tiny
bump version numbers and add a news item for the 7.0 release
completion: search through all open buffers for possible completions
docs: clarify the distinction between binding a function and "{function}"
docs: describe --disable-formatter and --disable-linter configure options
docs: explain how to include a double quote plus space in a nanorc regex
docs: improve the legibility of an itemized list
docs: mention in the man page how M-V can insert any Unicode code point
docs: mention that string binds may contain function names between braces
docs: replace control codes in the examples with {command} cartouches
docs: suggest a key binding for snipping trailing blanks
execute: show "Cancelled" instead of "Error" when the user hits ^C
extra: use the whole terminal for the crawl, and quicken it a bit
feedback: suppress undo/redo messages when option --zero is in effect
files: before sending data to an external command, decode LF back to NUL
files: improve the error handling when executing an external command
filtering: terminate also the sender process when the user hits ^C
filtering: when returning to a line number, ensure it is within range
gnulib: update to its current upstream state
goto: don't center the current line when the user specified a column only
help: don't show the New-Buffer toggle when in view mode
help: move the M-Del item up, so that M-PgUp and M-PgDn are paired
help: prioritize the unshifted Meta keystrokes for buffer switching
input: allocate a small keystroke buffer, and never free it
input: allocate two small character buffers too, and never free them
input: give up when the capacity of the keystroke buffer overflows
input: interpret commands of the form {functionname} inside string binds
memory: avoid a leak when a string bind specifies an unknown menu
prompt: allow rebinding also ^N, ^Q, and ^Y at the yes-no prompt
prompt: ingest queued characters before handling any subsequent function
prompt: prevent execution of inadmissible functions in view mode
prompt: return FALSE for non-editing functions also in the tiny version
prompt: toggle the help lines only for the 'nohelp' toggle
search: skip a match on the magic line, as it is a just convenience line
startup: ensure that +/string centers the match also with --linenumbers
startup: for +/string, center the found occurrence when possible
startup: quit when standard input is not a TTY (after handling arguments)
startup: report an empty search string also when there is a modifier
syntax: nanorc: colorize valid function names plus surrounding braces
tweaks: add parentheses for consistency, and reshuffle for conciseness
tweaks: allow the linter to be used in view mode, as it makes no changes
tweaks: attribute some of the features that were added in the last years
tweaks: avoid iterating over the same string twice in a row
tweaks: avoid sometimes calling a function three times in a row
tweaks: check the multiline regexes only for Delete and Backspace
tweaks: condense a comment, add two small ones, and reshuffle a line
tweaks: delete a flag that is no longer used
tweaks: determine in another way whether a shortcut is okay in view mode
tweaks: discard a bracketed paste in the browser more efficiently
tweaks: don't use a pointer when the value itself is all that is needed
tweaks: drop an unneeded check for permissibility of prompt shortcuts
tweaks: drop a parameter that is no longer used
tweaks: drop shunting of flags by calling the needed function directly
tweaks: elide a function that does not need to be a separate function
tweaks: elide an assignment by iterating with the target variable
tweaks: elide an intermediary variable that is no longer needed
tweaks: elide an unused parameter
tweaks: elide an unused return value
tweaks: elide a parameter by moving the general case one level up
tweaks: elide a variable, rename another, and reshuffle an assignment
tweaks: fold two cases together, because they basically do the same
tweaks: group the special keycodes for implanted strings together
tweaks: improve two comments, and exclude two unneeded prototypes
tweaks: make the crawl use the whole screen also in the tiny version
tweaks: make two error messages more succinct and easier to translate
tweaks: move the arrays of menu names and symbols to where they are used
tweaks: move the --magic option up, so that --zero comes last
tweaks: move to a given line number more efficiently
tweaks: move two checks plus corresponding calls to a better place
tweaks: normalize the indentation after the previous change
tweaks: reduce four variations of a message to a single common form
tweaks: rename a macro for clarity, and normalize some indentation
tweaks: rename a variable, away from an abbreviation
tweaks: rename two record elements and three parameters, for clarity
tweaks: replace sizeof(char) with 1, as that is assumed anyway
tweaks: reshuffle a declaration, and correct the wording of a comment
tweaks: reshuffle a line, to group things better
tweaks: reshuffle some code and drop some comments, for conciseness
tweaks: reshuffle some code, to not determine a shortcut twice
tweaks: reshuffle some lines, to be more readable instead of compact
tweaks: reshuffle two lines, for conciseness and in preparation
tweaks: reword and/or condense four comments
tweaks: rewrap line, improve wording, and correct typo in old news item
tweaks: rewrap some lines, drop a redundant call, and reshuffle a line
tweaks: simplify a function now that a Unicode code can be typed quicker
tweaks: simplify a pasting routine, modelling it after the injection one
tweaks: use an auxiliary variable to avoid dereferences of 'shortcut'
undo: make sure the current line is defined before it is referenced
verbatim: allow the user to finish Unicode input with <Enter> or <Space>
verbatim: do not overwrite the status bar when the code is invalid
verbatim: don't show dots during Unicode input, as they give wrong idea
Changes between v6.3 and v6.4:
------------------------------
Benno Schulenberg (24):
bump version numbers and add a news item for the 6.4 release
display: remember text and column positions when softwrapping a line
docs: concisely describe how the linter behaves
docs: remove the two notices about the changed defaults
docs: rename README.GIT to README.hacking, so it's clearer what is meant
docs: stop mentioning the obsoleted keywords that were removed
files: designate the root directory with a simple "/", not with "//"
formatter: instead of leaving curses, use full_refresh() to wipe messages
gnulib: update to its current upstream state
help: reshuffle two shortcuts so that more help-line items are paired
options: stop accepting -z, as --suspendable has been dropped too
rcfile: remove five obsolete or deprecated keywords
syntax: default: do not colorize a square or angle bracket after a URL
syntax: perl: add missing keywords, and reduce the length of some lines
syntax: python: mention an alternative linter in a comment
tweaks: add a missing word to a news item
tweaks: add a translator hint
tweaks: improve a comment, and reshuffle two functions plus some lines
tweaks: put each regex on separate line, to better show many keywords
tweaks: rename a variable, to not be the same as a function name
tweaks: rename two variables, to not contain the name of another
tweaks: reshuffle a description and rewrap another
tweaks: reshuffle a few lines, to group things better
version: condense the copyright message, to not dominate the output
LIU Hao (1):
build: ignore errors from `git describe`
Changes between v6.2 and v6.3:
------------------------------
Benno Schulenberg (41):
build: add the --disable-maintainer-mode option to ./configure
build: fix compilation for --enable-{tiny,nanorc,color}
build: fix compilation when configured with --disable-color
build: remove an obsolete check -- the dependent code was deleted
bump version numbers and add a news item for the 6.3 release
display: suppress spotlight yellow and error red when NO_COLOR is set
docs: add an example binding for copying text to the system clipboard
execute: clear an anchor only when the whole buffer gets filtered
execute: don't crash when an empty buffer is piped through a command
execute: stay on the same line number when filtering the whole buffer
feedback: show extra warning when writing failed due to "No space left"
files: do not change to a higher directory when the working one is gone
files: show a warning when the working directory is gone (when used)
files: when the working directory exists, still check its accessibility
filtering: close all output descriptors, so that 'xsel' will terminate
formatting: change cursor position only after saving it in the undo item
gnulib: pull in the workaround for a build problem on NetBSD
gnulib: update to its current upstream state
justify: stay at the same line number when doing a full justification
painting: colorize text also after an unterminated start match
painting: look for another start match only after the actual end match
painting: recalculate the multidata when making large strides or changes
painting: stop coloring an extremely long line after 2000 bytes
painting: tighten the check for a lacking end match on a colored line
syntax: xml: colorize /> properly, and colorize prolog tags differently
syntax: xml: colorize user-defined entities differently
tweaks: avoid a function call when two plain assignments will do
tweaks: change the indentation of a list, to match other indentations
tweaks: don't leave an orphaned temporary file behind when writing fails
tweaks: elide an unneeded call of strlen()
tweaks: exclude the extra truncation warning from the tiny version
tweaks: make the triggering of the recalculation of multidata less eager
tweaks: move the saving and restoring of flags to where it is needed
tweaks: normalize the indentation after the previous change
tweaks: prevent the adding of an unwanted newline in a different way
tweaks: remove redundant braces, and add two translator hints
tweaks: remove some stray spaces before a comma
tweaks: simplify a bit of code, eliding two labels and three gotos
tweaks: simplify a fragment of code, and fold two lines together
tweaks: trim a few comments, rename a function, and reshuffle some code
verbatim: with --zero, keep cursor in viewport when it was on bottom row
Mike Frysinger (1):
general: fix building for Windows
Changes between v6.1 and v6.2:
------------------------------

View File

@@ -1,6 +1,11 @@
Improvements in GNU nano
========================
Since 7.0:
- String binds may contain bindable function names between braces.
- Word completion looks for candidates in all open buffers.
- Unicode codes can be entered without leading zeroes.
Since 6.0:
- Option --zero hides the interface and uses the whole terminal for editing.
- Colors can be given also in #rgb hexadecimal, to select the nearest color

75
NEWS
View File

@@ -1,3 +1,40 @@
2023.01.18 - GNU nano 7.2 "Boer doe mij 't hekke lös!"
• <Shift+Insert> is prevented from pasting in view mode.
2022.12.14 - GNU nano 7.1 "And the devices shall be made of wood"
• When --autoindent and --breaklonglines are combined, pressing
<Enter> at a specific position no longer eats characters.
2022.11.15 - GNU nano 7.0 "Una existencia simple bajo el sol"
• String binds may contain bindable function names between braces.
For example, to move the current line down to after the next one:
bind ^D "{cut}{down}{paste}{up}" main. Of course, braced function
names may be mixed with literal text. If an existing string bind
contains a literal {, replace it with {{}.
• Unicode codes can be entered (via M-V) without leading zeroes,
by finishing short codes with <Space> or <Enter>.
• Word completion (^]) looks for candidates in all open buffers.
• No regular expression matches the final empty line any more.
2022.08.02 - GNU nano 6.4 "Regentag Dunkelbunt Hundertwasser"
• The file browser does not crash when moving up to the root folder.
• Softwrapping very long lines is done more efficiently.
• Invoking the formatter does not blink the screen.
2022.04.28 - GNU nano 6.3 "Wat zullen we drinken? Wat een dorst!"
• For multiline regexes, text is now colored as soon as a start match
is found, also when there is no end match at all.
• The colorizing of any line is stopped after two thousand bytes,
to avoid frustrating delays.
• When environment variable NO_COLOR is set, the two default colors
(yellow for the spotlight, red for error messages) are suppressed
when no interface colors are specified in a nanorc file.
• Full justification and piping the whole buffer through a command
now keep the cursor at the same line number.
• Utility 'xsel' can be used to copy a marked region to the system's
clipboard. See doc/sample.nanorc for an example.
2022.02.18 - GNU nano 6.2 "Kamperfoelie"
• The file browser clears the prompt bar also when using --minibar.
• Linting now works also with a newer 'pyflakes'.
@@ -764,22 +801,22 @@
the undo implementation and the default syntax config are
also included. As always, Share and Enjoy!
2014.05.28 - GNU nano 2.3.3 is in its right place. This release contains
many many improvements to the core system, including
substantial improvements to the undo/redo code, UTF-8
handling, the configure script, and display of shortcuts
on very wide terminals. New features include the
ability to write to named pipes (--noread), as well as
linter support (see the nanorc man page for details). Also
included are much improved syntax highlighting code, and
configurations for JSON, texinfo, Go, and a default syntax
for catch-all highlighting. Finally, nano now has the
ability to set the color of the title bar, status bar, and
shortcut keys (e.g. "^X") and their descriptions. Again
see the nanorc page for details. There's much more, too
much to include here, but please keep those reports and
general feedback coming! Thank you for helping us help
you help us all.
2014.05.28 - GNU nano 2.3.3 is in its right place. This release
contains many many improvements to the core system,
including substantial improvements to the undo/redo code,
UTF-8 handling, the configure script, and display of
shortcuts on very wide terminals. New features include
the ability to write to named pipes (--noread), as well
as linter support (see the nanorc man page for details).
Also included are much improved syntax highlighting code,
and configurations for JSON, texinfo, Go, and a default
syntax for catch-all highlighting. Finally, nano now has
the ability to set the color of the title bar, status bar,
and shortcut keys (e.g. "^X") and their descriptions.
Again see the nanorc page for details. There's much more,
too much to include here, but please keep those reports
and general feedback coming! Thank you for helping us
help you help us all.
2013.03.22 - GNU nano 2.3.2 "Annoy your coworkers for fun and profit" is
released. This release introduces vim-style file locking
@@ -918,13 +955,13 @@
the command line will now override any related .nanorc
entries. Speak now or forever hold your bugs!
2009.11.15 - GNU nano 2.1.99pre1 "take a bow" is out there, man, it's
out there all right. This release contains mainly
2009.11.15 - GNU nano 2.1.99pre1 "take a bow" is out there, man,
it's out there all right. This release contains mainly
bugfixes, underscoring that we are preparing for the
next stable series release. Included are many fixes
for the new soft wrapping code, compiler warning tweaks,
and the modification time warning no longer triggers
when saving a file as a new name. Also include are
when saving a file with a new name. Also included are
some fixes for various nanorc options, and there are
surely more bugs to find before we call the code base
stable, so please keep those reports coming!

2
README
View File

@@ -15,7 +15,7 @@ Appearance
In rough ASCII graphics, this is what nano's screen looks like:
____________________________________________________________________
| GNU nano 6.2 filename Modified |
| GNU nano 7.2 filename Modified |
--------------------------------------------------------------------
| This is the text window, displaying the contents of a 'buffer', |
| the contents of the file you are editing. |

View File

@@ -8,19 +8,18 @@ building this needs a bit more care than the official tarballs.
Prerequisites
-------------
To successfully compile GNU nano from git, you'll need the following
packages:
To successfully compile GNU nano from git, you'll need the following:
- autoconf (version >= 2.69)
- automake (version >= 1.14)
- autopoint (version >= 0.18.3)
- gcc (version >= 5.0)
- gettext (version >= 0.18.3)
- git (version >= 2.7.4)
- groff (version >= 1.12)
- make (any version)
- pkg-config (version >= 0.22)
- texinfo (version >= 4.0)
autoconf (version >= 2.69)
automake (version >= 1.14)
autopoint (version >= 0.18.3)
gcc (version >= 5.0)
gettext (version >= 0.18.3)
git (version >= 2.7.4)
groff (version >= 1.12)
make (any version)
pkg-config (version >= 0.22)
texinfo (version >= 4.0)
You will also need to have the header files for ncurses installed,
from libncurses-dev on Debian, ncurses-devel on Fedora, or similar.
@@ -29,14 +28,14 @@ These should all be available in your distro's package manager or
software center, or otherwise on any GNU mirror.
Download the source
-------------------
Clone the source
----------------
To obtain the current nano development branch (called 'master'), use the
following command. It will create in your current working directory a
subdirectory called 'nano' containing a copy of all of the files:
$ git clone git://git.savannah.gnu.org/nano.git nano
$ git clone git://git.savannah.gnu.org/nano.git
Generate the configure script
@@ -84,6 +83,7 @@ Problems?
Please submit any bugs you find in the code in git via the bug tracker
on Savannah (https://savannah.gnu.org/bugs/?group=nano).
Contributing something
----------------------

3
THANKS
View File

@@ -6,8 +6,9 @@ Translations:
============
Pedro Albuquerque <palbuquerque73@gmail.com> Portuguese
Josef Andersson <josef.andersson@fripost.org> Swedish
Laurentiu Buzdugan <buzdugan@voyager.net> Romanian
Mario Blättermann <mario.blaettermann@gmail.com> German
Besnik Bleta <besnik@programeshqip.org> Albanian
Laurențiu Buzdugan <buzdugan@voyager.net> Romanian
Ricardo Cárdenes Medina <ricardo@conisys.com> Spanish
Antonio Ceballos <aceballos@gmail.com> Spanish
Wei-Lun CHAO <chaoweilun@pcmail.com.tw> Chinese (traditional)

View File

@@ -2,7 +2,7 @@
# Generate configure & friends for GIT users.
gnulib_url="git://git.sv.gnu.org/gnulib.git"
gnulib_hash="6ef3d783333346333f35bb181ba90f5bc46c0b29"
gnulib_hash="2cf7f442f52f70b3df6eb396eb93ea08e54883c5"
modules="
futimens

View File

@@ -1,6 +1,6 @@
# Configuration for GNU nano - a small and user-friendly text editor
#
# Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc.
# Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
# Copyright (C) 2014, 2017 Mike Frysinger
#
# GNU nano is free software: you can redistribute it and/or modify
@@ -16,10 +16,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
AC_INIT([GNU nano], [6.2], [nano-devel@gnu.org], [nano])
AC_INIT([GNU nano], [7.2], [nano-devel@gnu.org], [nano])
AC_CONFIG_SRCDIR([src/nano.c])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.14])
AM_MAINTAINER_MODE([enable])
AC_CONFIG_HEADERS([config.h])
dnl Make sure the ONCE macros are available.
@@ -152,6 +153,30 @@ if test "x$enable_extra" != xno; then
AC_DEFINE(ENABLE_EXTRA, 1, [Define this to have an Easter egg.])
fi
AC_ARG_ENABLE(formatter,
AS_HELP_STRING([--disable-formatter], [Disable the formatting tool]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_formatter" = xyes; then
if test "x$enable_color" != xyes; then
AC_MSG_ERROR([
*** --enable-formatter needs both --enable-color and --enable-nanorc to work])
fi
else
enable_formatter=no
fi
fi
if test "x$enable_color" = xno; then
if test "x$enable_formatter" = xyes; then
AC_MSG_ERROR([
*** --enable-formatter cannot work with --disable-color nor --disable-nanorc])
else
enable_formatter=no
fi
fi
if test "x$enable_formatter" != xno; then
AC_DEFINE(ENABLE_FORMATTER, 1, [Define this to have access to a formatter.])
fi
AC_ARG_ENABLE(help,
AS_HELP_STRING([--disable-help], [Disable the built-in help texts]))
if test "x$enable_tiny" = xyes; then
@@ -205,7 +230,7 @@ if test "x$enable_libmagic" = xyes; then
if test "x$enable_tiny" = xyes; then
if test "x$enable_color" != xyes; then
AC_MSG_ERROR([
*** --enable-libmagic needs --enable-color and --enable-nanorc to work])
*** --enable-libmagic needs both --enable-color and --enable-nanorc to work])
fi
fi
if test "x$enable_color" = xno; then
@@ -214,6 +239,30 @@ if test "x$enable_libmagic" = xyes; then
fi
fi
AC_ARG_ENABLE(linter,
AS_HELP_STRING([--disable-linter], [Disable the linting tool]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_linter" = xyes; then
if test "x$enable_color" != xyes; then
AC_MSG_ERROR([
*** --enable-linter needs both --enable-color and --enable-nanorc to work])
fi
else
enable_linter=no
fi
fi
if test "x$enable_color" = xno; then
if test "x$enable_linter" = xyes; then
AC_MSG_ERROR([
*** --enable-linter cannot work with --disable-color nor --disable-nanorc])
else
enable_linter=no
fi
fi
if test "x$enable_linter" != xno; then
AC_DEFINE(ENABLE_LINTER, 1, [Define this to have access to a linter.])
fi
AC_ARG_ENABLE(linenumbers,
AS_HELP_STRING([--disable-linenumbers], [Disable line numbering]))
if test "x$enable_tiny" = xyes; then
@@ -271,14 +320,14 @@ if test "x$enable_operatingdir" != xno; then
fi
AC_ARG_ENABLE(speller,
AS_HELP_STRING([--disable-speller], [Disable the spell-checker functions]))
AS_HELP_STRING([--disable-speller], [Disable the spell-checking tool]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_speller" != xyes; then
enable_speller=no
fi
fi
if test "x$enable_speller" != xno; then
AC_DEFINE(ENABLE_SPELLER, 1, [Define this to have the spell-checker functions.])
AC_DEFINE(ENABLE_SPELLER, 1, [Define this to have access to a spell checker.])
fi
AC_ARG_ENABLE(tabcomp,
@@ -353,6 +402,9 @@ if test "x$enable_utf8" != xno; then
AC_CHECK_FUNCS(iswalpha iswalnum iswpunct mbstowcs wctomb)
fi
AC_CHECK_FUNCS_ONCE(chmod chown fchmod fchown flockfile funlockfile
fork fsync geteuid pipe wait waitpid)
dnl Checks for available flags.
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"], [], [])
@@ -510,21 +562,6 @@ int main(void)
*** Can't check need for _XOPEN_SOURCE_EXTENDED when cross-compiling.]))
fi
AC_MSG_CHECKING([whether LINES and COLS can be redefined])
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <curses.h>
int main(void)
{
LINES = 80;
COLS = 25;
return 0;
}]])],
AC_DEFINE(REDEFINING_MACROS_OK, 1, [Define this if you know your curses library allows LINES and COLS to be redefined to deal with a resizing bug.])
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no),
AC_MSG_WARN([
*** Can't check for macro redefinability when cross-compiling.]))
AS_IF([test "x$enable_libmagic" != "xno"], [
AC_CHECK_HEADERS([magic.h])
AC_CHECK_LIB(magic, magic_open)

View File

@@ -5,7 +5,7 @@
<title>The GNU nano editor FAQ</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" content="The genesis story of the nano editor, plus the solution to some common problems.">
<style>
<style type="text/css">
.indented { margin-left: 2em; font-family: courier; font-size: 110%; }
</style>
</head>
@@ -27,7 +27,7 @@
<a href="#2.1">2.1. FTP and WWW sites that carry nano.</a><br>
<a href="#2.2">2.2. RedHat and derivatives (.rpm) packages.</a><br>
<a href="#2.3">2.3. Debian (.deb) packages.</a><br>
<a href="#2.4">2.4. By GIT (for the brave).</a>
<a href="#2.4">2.4. By git (for the brave).</a>
</p></blockquote>
<h3><a href="#3">3. Installation and Configuration</a></h3>
<blockquote><p>
@@ -72,7 +72,7 @@
<a href="#7.2">7.2. How do I submit a bug report or patch?</a><br>
<a href="#7.3">7.3. I want to send the development team a big load of cash (or just a thank you).</a><br>
<a href="#7.4">7.4. How do I join the development team?</a><br>
<a href="#7.5">7.5. Can I have write access to the GIT tree?</a>
<a href="#7.5">7.5. Can I have write access to the git tree?</a>
</p></blockquote>
<hr width="100%">
@@ -92,7 +92,7 @@
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program &quot;establishes a full duplex terminal connection to a remote host&quot;, and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
<h3><a name="1.4"></a>1.4. What is the current version of nano?</h3>
<blockquote><p>The current version of nano <i>should</i> be <b>6.2</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
<blockquote><p>The current version of nano <i>should</i> be <b>7.2</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
<h3><a name="1.5"></a>1.5. I want to read the man page without having to download the program!</h3>
<blockquote><p>Jeez, demanding, aren't we? Okay, look <a href="https://nano-editor.org/dist/latest/nano.1.html">here</a>.</p></blockquote>
<hr width="100%">
@@ -121,8 +121,8 @@
</ul>
<p>You can also have a look at the <a href="http://ftp.debian.org/debian/pool/main/n/nano/">Package Pool</a> to see all the available binary and source packages.</p>
</blockquote>
<h3><a name="2.4"></a>2.4. By GIT (for the brave).</h3>
<blockquote><p>For the 'bleeding edge' current version of nano, you can use GIT to download the current source code. <b>Note:</b> believe it or not, by downloading code that has not yet stabilized into an official release, there could quite possibly be bugs, in fact the code may not even compile! Anyway, see <a href="http://git.savannah.gnu.org/cgit/nano.git/tree/README.GIT">the nano GIT document</a> for info on anonymous GIT access to the nano source.</p></blockquote>
<h3><a name="2.4"></a>2.4. By git (for the brave).</h3>
<blockquote><p>For the "bleeding edge" current version of nano, you can use <b>git</b> to download the current source code. <i>Note:</i> believe it or not, by downloading code that has not yet stabilized into an official release, there could quite possibly be bugs, in fact the code may not even compile! Anyway, see <a href="http://git.savannah.gnu.org/cgit/nano.git/tree/README.hacking">the hacking document</a> for info on getting and building nano from git.</p></blockquote>
<hr width="100%">
<h1><a name="3"></a>3. Installation and Configuration</h1>
@@ -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>
@@ -220,10 +222,10 @@
<blockquote><p>Try holding down the Shift key and selecting or pasting the text as you normally would.</p></blockquote>
<h3><a name="4.6"></a>4.6. When I paste text into a document, each line gets indented further than the last. Why? And how can I stop this?</h3>
<blockquote><p>You have the <i>autoindent</i> feature turned on. Hit <b>Meta-I</b> to turn it off, paste your text, and then hit <b>Meta-I</b> again to turn it back on.</p>
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste, so you no longer need to toggle it off and on manually.</p></blockquote>
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need to toggle it off and on manually.</p></blockquote>
<h3><a name="4.7"></a>4.7. When I paste from Windows into a remote nano, nano rewraps the lines. What gives?</h3>
<blockquote><p>When pasting from Windows, in some situations linefeeds are sent instead of carriage returns (Enters). And linefeeds are <b>^J</b>s, which make nano justify (rewrap) the current paragraph. To prevent these linefeeds from causing these unwanted justifications, add this line to your .nanorc on the remote Linux box: <b>unbind ^J main</b> or <b>bind ^J enter main</b>, depending on whether the paste contains CR + LF or only LF.</p>
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste, so you no longer need the above workaround.</p></blockquote>
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need the above workaround.</p></blockquote>
<h3><a name="4.8"></a>4.8. I've compiled nano with color support, but I don't see any color when I run it!</h3>
<blockquote><p>If you want nano to actually use color, you have to specify the color configurations you want it to use in your .nanorc. Several example configurations are in the <b>syntax/</b> subdirectory of the nano source, which are normally installed to <b>/usr/local/share/nano/</b>. To enable all of them, uncomment the line <b># include "/usr/local/share/nano/*.nanorc"</b> in your nanorc. See also section <a href="#3.9">3.9</a>.</p></blockquote>
<h3><a name="4.9"></a>4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</h3>

View File

@@ -1,4 +1,4 @@
.\" Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc.
.\" Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
.\"
.\" This document is dual-licensed. You may distribute and/or modify it
.\" under the terms of either of the following licenses:
@@ -16,19 +16,22 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANO 1 "version 6.2" "February 2022"
.TH NANO 1 "version 7.2" "January 2023"
.SH NAME
nano \- Nano's ANOther editor, inspired by Pico
nano \- Nano's ANOther text editor, inspired by Pico
.SH SYNOPSIS
.B nano
.RI [ options "] [[\fB+" line [\fB, column "]] " file ]...
.sp
.BR nano " [" \fIoptions "] [[" + [ crCR ]( / | ? ) \fIstring "] " \fIfile ]...
.B nano
.RI [ options "] [" file [\fB: line [\fB: column "]]]..."
.sp
.BR nano " [" \fIoptions "] [[" + [ crCR ]{ / | ? } \fIstring "] " \fIfile ]...
.SH DESCRIPTION
\fBnano\fP is a small and friendly editor. It copies the look and feel
\fBnano\fP is a small and friendly text editor. It copies the look and feel
of Pico, but is free software, and implements several features that Pico
lacks, such as: opening multiple files, scrolling per line, undo/redo,
syntax coloring, line numbering, and soft-wrapping overlong lines.
@@ -36,7 +39,11 @@ syntax coloring, line numbering, and soft-wrapping overlong lines.
When giving a filename on the command line, the cursor can be put on a
specific line by adding the line number with a plus sign (\fB+\fR) before
the filename, and even in a specific column by adding it with a comma.
(Negative numbers count from the end of the file or line.)
Negative numbers count from the end of the file or line.
The line and column numbers may also be specified by gluing them with colons
after the filename. (When a filename contains a colon followed by digits,
escape the colon by preceding it with a triple backslash.)
.sp
The cursor can be put on the first or last occurrence of a specific string
by specifying that string after \fB+/\fR or \fB+?\fR before the filename.
The string can be made case sensitive and/or caused to be interpreted as a
@@ -74,25 +81,17 @@ 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
.BR nanorc (5).
.SH NOTICE
Since version 4.0, \fBnano\fR by default:
.sp
.RS 4
\(bu does not automatically hard-wrap lines that become overlong,
.br
\(bu includes the line below the title bar in the editing area,
.br
\(bu does linewise (smooth) scrolling.
.RE
.sp
If you want the old, Pico behavior back, you can use \fB\-\-breaklonglines\fR,
\fB\-\-emptyline\fR, and \fB\-\-jumpyscrolling\fR (or \fB\-bej\fR for short).
.SH OPTIONS
.TP
.BR \-A ", " \-\-smarthome
@@ -120,6 +119,7 @@ nanorc file. See \fBnanorc\fR(5).
.BR \-E ", " \-\-tabstospaces
Convert each typed tab to spaces -- to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
.TP
.BR \-F ", " \-\-multibuffer
Read a file into a new buffer by default.
@@ -309,7 +309,6 @@ using the built-in corrector that calls \fBhunspell\fR(1) or \fBspell\fR(1).
.TP
.BR \-t ", " \-\-saveonexit
Save a changed buffer without prompting (when exiting with \fB^X\fR).
(The old form of the long option, \fB\-\-tempfile\fR, is deprecated.)
.TP
.BR \-u ", " \-\-unix
Save a file by default in Unix format. This overrides nano's
@@ -332,10 +331,9 @@ Don't show the two help lines at the bottom of the screen.
.BR \-y ", " \-\-afterends
Make Ctrl+Right and Ctrl+Delete stop at word ends instead of beginnings.
.TP
.BR \-z ", " \-\-suspendable
Obsolete option; ignored. Suspension is enabled by default,
reachable via \fB^T^Z\fR. (If you want a plain \fB^Z\fR to
suspend nano, add \fBbind ^Z suspend main\fR to your nanorc.)
.BR \-! ", " \-\-magic
When neither the file's name nor its first line give a clue,
try using libmagic to determine the applicable syntax.
.TP
.BR \-% ", " \-\-stateflags
Use the top-right corner of the screen for showing some state flags:
@@ -369,10 +367,6 @@ The status bar appears only when there is a significant message,
and disappears after 1.5 seconds or upon the next keystroke.
With \fBM\-Z\fR the title bar plus status bar can be toggled.
With \fBM\-X\fR the help lines.
.TP
.BR \-! ", " \-\-magic
When neither the file's name nor its first line give a clue,
try using libmagic to determine the applicable syntax.
.SH TOGGLES
Several of the above options can be switched on and off also while
@@ -400,6 +394,14 @@ See \fI/usr/share/nano/\fR and \fI/usr/share/nano/extra/\fR
for available syntax-coloring definitions.
.SH NOTES
Option \fB\-z\fR (\fB\-\-suspendable\fR) has been removed.
Suspension is enabled by default, reachable via \fB^T^Z\fR.
(If you want a plain \fB^Z\fR to suspend nano, add
\fBbind ^Z suspend main\fR to your nanorc.)
.sp
When you want to copy marked text from \fBnano\fR to the system's clipboard,
see one of the examples in the \fBnanorc\fR(5) man page.
.sp
If no alternative spell checker command is specified on the command
line nor in one of the \fInanorc\fP files, \fBnano\fP will check the
\fBSPELL\fP environment variable for one.
@@ -413,6 +415,9 @@ that name already exists in the current directory, it will add ".save"
plus a number (e.g.\& ".save.1") to the current filename in order to make
it unique. In multibuffer mode, \fBnano\fP will write all the open
buffers to their respective emergency files.
.sp
If you have any question about how to use \fBnano\fR in some specific
situation, you can ask on \fIhelp-nano@gnu.org\fR.
.SH BUGS
The recording and playback of keyboard macros works correctly only on a

View File

@@ -12,9 +12,9 @@ The complete manual for the GNU nano text editor.
@end documentdescription
@smallbook
@set EDITION 0.6
@set VERSION 6.2
@set UPDATED February 2022
@set EDITION 0.7
@set VERSION 7.2
@set UPDATED January 2023
@dircategory Editors
@direntry
@@ -29,18 +29,18 @@ The complete manual for the GNU nano text editor.
@title GNU @command{nano}
@subtitle a small and friendly text editor
@subtitle version 6.2
@subtitle version 7.2
@author Chris Allegretta
@page
This manual documents the GNU @command{nano} editor.
This manual documents the GNU @command{nano} text editor.
@sp 1
The contents of this manual are part of the GNU @command{nano} distribution.
@sp 5
Copyright @copyright{} 1999-2009, 2014-2022 Free Software Foundation, Inc.
Copyright @copyright{} 1999-2009, 2014-2023 Free Software Foundation, Inc.
@sp 1
This document is dual-licensed. You may distribute and/or modify it
under the terms of either of the following licenses:
@@ -58,6 +58,9 @@ under the terms of either of the following licenses:
@sp 5
You may contact the original author by e-mail: @email{chrisa@@asty.org}
Or contact the current maintainer: @email{bensberg@@coevern.nl}
@sp 1
For suggesting improvements: @email{nano-devel@@gnu.org}
@@ -76,7 +79,7 @@ For suggesting improvements: @email{nano-devel@@gnu.org}
@node Top
@top
This manual documents GNU @command{nano}, version 6.2.
This manual documents GNU @command{nano}, version 7.2.
@menu
* Introduction::
@@ -120,6 +123,9 @@ following options: @option{--breaklonglines},
@blankline
Please report bugs via @url{https://savannah.gnu.org/bugs/?group=nano}.
@blankline
Questions about using nano you can ask at @email{help-nano@@gnu.org}.
@blankline
For background information see @url{https://nano-editor.org/}.
@@ -136,12 +142,17 @@ The usual way to invoke @command{nano} is:
@blankline
But it is also possible to specify one or more options (@pxref{Command-line Options}),
and to edit several files in a row. Additionally, the cursor
can be put on a specific line of a file by adding the line number
with a plus sign before the filename, and even in a specific column by
adding it with a comma.
(Negative numbers count from the end of the file or line.)
The cursor can also be put on the first or last occurrence of a specific string
and to edit several files in a row.
The cursor can be put on a specific line of a file by adding
the line number with a plus sign before the filename, and even
in a specific column by adding it with a comma.
Negative numbers count from the end of the file or line.
The line and column numbers may also be specified by gluing them with colons
after the filename. (When a filename contains a colon followed by digits,
escape the colon by preceding it with a triple backslash.)
The cursor can be put on the first or last occurrence of a specific string
by specifying that string after @code{+/} or @code{+?} before the filename.
The string can be made case sensitive and/or caused to be interpreted as a
regular expression by inserting a @code{c} and/or @code{r} after the plus sign.
@@ -152,7 +163,7 @@ A more complete command synopsis thus is:
@blankline
@example
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR](/|?)STRING] FILE]@dots{}}
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR]@{/|?@}STRING] FILE]@dots{}}
@end example
@blankline
@@ -222,14 +233,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
@@ -399,6 +414,7 @@ nanorc file. @xref{@code{set keycolor}} for details.
@itemx --tabstospaces
Convert each typed tab to spaces --- to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
@item -F
@itemx --multibuffer
@@ -636,7 +652,6 @@ to be installed.
Save a changed buffer without prompting (when exiting with @kbd{^X}).
This can be handy when @command{nano} is used as the composer of an
email program.
(The old form of the long option, @code{--tempfile}, is deprecated.)
@item -u
@item --unix
@@ -673,11 +688,10 @@ disabled to display the help-system navigation keys.
Make @kbd{Ctrl+Right} and @kbd{Ctrl+Delete} stop at word ends
instead of beginnings.
@item -z
@itemx --suspendable
Obsolete option; ignored. Suspension is enabled by default,
reachable via @kbd{^T^Z}. (If you want a plain @kbd{^Z} to
suspend nano, add @code{bind ^Z suspend main} to your nanorc.)
@item -!
@itemx --magic
When neither the file's name nor its first line give a clue,
try using libmagic to determine the applicable syntax.
@item -%
@itemx --stateflags
@@ -715,13 +729,14 @@ and disappears after 1.5 seconds or upon the next keystroke.
With @kbd{M-Z} the title bar plus status bar can be toggled.
With @kbd{M-X} the help lines.
@item -!
@itemx --magic
When neither the file's name nor its first line give a clue,
try using libmagic to determine the applicable syntax.
@end table
@sp 1
Option @code{-z} (@code{--suspendable}) has been removed.
Suspension is enabled by default, reachable via @kbd{^T^Z}.
(If you want a plain @kbd{^Z} to suspend nano, add
@code{bind ^Z suspend main} to your nanorc.)
@node Feature Toggles
@chapter Feature Toggles
@@ -732,6 +747,7 @@ or nanorc options. Each toggle can be flicked via a Meta-key combination
--- the @kbd{Meta} key is normally the @kbd{Alt} key (@pxref{Commands}
for more details). The following global toggles are available:
@sp 1
@table @code
@item Constant Cursor Position Display
@@ -1073,7 +1089,6 @@ Regular expressions in @command{nano} are of the extended type (ERE).
@item set saveonexit
Save a changed buffer automatically on exit (@kbd{^X}); don't prompt.
(The old form of this option, @code{set tempfile}, is deprecated.)
@item set scrollercolor @var{fgcolor},@var{bgcolor}
Use this color combination for the indicator alias "scrollbar".
@@ -1127,11 +1142,6 @@ Use this color combination for the status bar.
Use this color combination for the vertical guiding stripe.
@xref{@code{set keycolor}} for valid color names.
@item set suspendable
Obsolete option; ignored. Suspension is enabled by default,
reachable via @kbd{^T^Z}. (If you want a plain @kbd{^Z} to
suspend nano, add @code{bind ^Z suspend main} to your nanorc.)
@item set tabsize @var{number}
Use a tab size of @var{number} columns. The value of @var{number} must be
greater than 0. The default value is @t{8}.
@@ -1139,6 +1149,7 @@ greater than 0. The default value is @t{8}.
@item set tabstospaces
Convert each typed tab to spaces --- to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
@item set titlecolor [bold,][italic,]@var{fgcolor},@var{bgcolor}
Use this color combination for the title bar.
@@ -1209,6 +1220,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:
@@ -1221,9 +1240,10 @@ will be added to this syntax, until a new @code{syntax}
command is encountered.
When @command{nano} is run, this syntax will be automatically
activated if the current filename matches the extended regular
expression @var{fileregex}. Or the syntax can be explicitly
activated by using the @option{-Y} or @option{--syntax}
activated (for the relevant buffer) if the absolute filename
matches the extended regular expression @var{fileregex}.
Or the syntax can be explicitly activated (for all buffers)
by using the @option{-Y} or @option{--syntax}
command-line option followed by the @var{name}.
The @code{default} syntax is special: it takes no @var{fileregex},
@@ -1246,9 +1266,6 @@ on the system and will be silently ignored otherwise.)
@item formatter @var{program} [@var{argument} @dots{}]
Run the given @var{program} on the full contents of the current buffer.
(The current buffer is written out to a temporary file, the program is
run on it, and then the temporary file is read back in, replacing the
contents of the buffer.)
@item linter @var{program} [@var{argument} @dots{}]
Use the given @var{program} to do a syntax check on the current buffer.
@@ -1347,9 +1364,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).
The @code{string} can consist of text or commands or a mix of them.
(To enter a command into the @code{string}, precede its keystroke
with @kbd{M-V}.)
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}
@@ -1357,37 +1374,50 @@ 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 availability 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:
@itemize @w{}
@item
@code{^@var{X}} ------ where @var{X} is a Latin letter, or one of several
@indentedblock
@table @asis
@item @code{^@var{X}}
where @var{X} is a Latin letter, or one of several
ASCII characters (@@, ], \, ^, _), or the word "Space".
Example: @code{^C}.
@item
@code{M-@var{X}} ------ where @var{X} is any ASCII character except [,
or the word "Space".
@item @code{M-@var{X}}
where @var{X} is any ASCII character except [, or the word "Space".
Example: @code{M-8}.
@item
@code{Sh-M-@var{X}} ------ where @var{X} is a Latin letter.
@item @code{Sh-M-@var{X}}
where @var{X} is a Latin letter.
Example: @code{Sh-M-U}.
By default, each Meta+letter keystroke does the same as the corresponding
Shift+Meta+letter. But when any Shift+Meta bind is made, that will
no longer be the case, for all letters.
@item
@code{F@var{n}} ------ where @var{n} is a numeric value from 1 to 24.
@item @code{F@var{n}}
where @var{n} is a numeric value from 1 to 24.
Example: @code{F10}.
(Often, @code{F13} to @code{F24} can be typed as @code{F1} to @code{F12}
with Shift.)
@item
@code{Ins} or @code{Del}.
@end itemize
@item @code{Ins} or @code{Del}
@end table
@end indentedblock
@sp 1
Rebinding @code{^M} (Enter) or @code{^I} (Tab) is probably not a good idea.
Rebinding @code{^[} (Esc) is not possible, because its keycode
is the starter byte of Meta keystrokes and escape sequences.
@@ -1471,7 +1501,6 @@ Or, when it is set, unsets the mark.
@item location
Reports the current position of the cursor in the buffer:
the line, column, and character positions.
(The old name of this function, 'curpos', is deprecated.)
@item wordcount
Counts and reports on the status bar the number of lines, words,
@@ -1488,15 +1517,23 @@ or GNU @command{spell}, or the one defined by @option{--speller} or
@item formatter
Invokes a full-buffer-processing program (if the active syntax defines one).
(The current buffer is written out to a temporary file, the program
is run on it, and then the temporary file is read back in, replacing
the contents of the buffer.)
@item linter
Invokes a syntax-checking program (if the active syntax defines one).
If this program produces lines of the form "filename:linenum:charnum:
some message", then the cursor will be put at the indicated position
in the mentioned file while showing "some message" on the status bar.
You can move from message to message with @kbd{PgUp} and @kbd{PgDn},
and leave linting mode with @kbd{^C} or @kbd{Enter}.
@item justify
Justifies the current paragraph (or the marked region).
A paragraph is a group of contiguous lines
that, apart from possibly the first line, all have the same indentation. The
beginning of a paragraph is detected by either this lone line with a differing
A paragraph is a group of contiguous lines that, apart from possibly
the first line, all have the same indentation. The beginning of a
paragraph is detected by either this lone line with a differing
indentation or by a preceding blank line.
@item fulljustify
@@ -1605,7 +1642,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.
@@ -1803,7 +1841,6 @@ The 'go to directory' menu in the file browser.
The menu for inserting the output from an external command,
or for filtering the buffer (or the marked region) through
an external command, or for executing one of several tools.
(The old form of this menu name, 'extcmd', is deprecated.)
@item spell
The menu of the integrated spell checker where the user can edit a misspelled word.
@@ -1946,6 +1983,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
@@ -1971,6 +2011,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

@@ -1,4 +1,4 @@
.\" Copyright (C) 2003-2011, 2013-2022 Free Software Foundation, Inc.
.\" Copyright (C) 2003-2011, 2013-2023 Free Software Foundation, Inc.
.\"
.\" This document is dual-licensed. You may distribute and/or modify it
.\" under the terms of either of the following licenses:
@@ -16,14 +16,14 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANORC 5 "version 6.2" "February 2022"
.TH NANORC 5 "version 7.2" "January 2023"
.SH NAME
nanorc \- GNU nano's configuration file
.SH DESCRIPTION
The \fInanorc\fP files contain the default settings for \fBnano\fP,
a small and friendly editor. During startup, if \fB\-\-rcfile\fR
a small and friendly text editor. During startup, if \fB\-\-rcfile\fR
is not given, \fBnano\fR will read two files: first the
system-wide settings, from \fI/etc/nanorc\fP (the exact path might be
different on your system), and then the user-specific settings, either
@@ -32,20 +32,6 @@ or from \fI~/.config/nano/nanorc\fR, whichever is encountered first.
If \fB\-\-rcfile\fR is given, \fBnano\fR will read just the specified
settings file.
.SH NOTICE
Since version 4.0, \fBnano\fR by default:
.sp
.RS 4
\(bu does not automatically hard-wrap lines that become overlong,
.br
\(bu includes the line below the title bar in the editing area,
.br
\(bu does linewise (smooth) scrolling.
.RE
.sp
To get the old, Pico behavior back, you can use \fBset breaklonglines\fR,
\fBset emptyline\fR, and \fBset jumpyscrolling\fR.
.SH OPTIONS
The configuration file accepts a series of \fBset\fP and \fBunset\fP
commands, which can be used to configure nano on startup without using
@@ -289,7 +275,6 @@ Regular expressions in \fBnano\fR are of the extended type (ERE).
.TP
.B set saveonexit
Save a changed buffer automatically on exit (\fB^X\fR); don't prompt.
(The old form of this option, \fBset tempfile\fR, is deprecated.)
.TP
.B set scrollercolor \fIfgcolor\fB,\fIbgcolor\fR
Use this color combination for the indicator alias "scrollbar".
@@ -335,7 +320,7 @@ and \fBS\fR when soft-wrapping.
When the buffer is modified, a star (\fB*\fR) is shown after the
filename in the center of the title bar.
.TP
.B set statuscolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
.B set statuscolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
Use this color combination for the status bar.
See \fBset titlecolor\fR for more details.
.TP
@@ -343,11 +328,6 @@ See \fBset titlecolor\fR for more details.
Use this color combination for the vertical guiding stripe.
See \fBset titlecolor\fR for more details.
.TP
.B set suspendable
Obsolete option; ignored. Suspension is enabled by default,
reachable via \fB^T^Z\fR. (If you want a plain \fB^Z\fR to
suspend nano, add \fBbind ^Z suspend main\fR to your nanorc.)
.TP
.B set tabsize \fInumber\fR
Use a tab size of \fInumber\fR columns. The value of \fInumber\fP must be
greater than 0. The default value is \fB8\fR.
@@ -355,6 +335,7 @@ greater than 0. The default value is \fB8\fR.
.B set tabstospaces
Convert each typed tab to spaces -- to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
.TP
.B set titlecolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
Use this color combination for the title bar.
@@ -440,6 +421,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
@@ -450,9 +439,10 @@ will be added to this syntax, until a new \fBsyntax\fR
command is encountered.
.sp
When \fBnano\fR is run, this syntax will be automatically
activated if the current filename matches the extended regular
expression \fIfileregex\fR. Or the syntax can be explicitly
activated by using the \fB\-Y\fR or \fB\-\-syntax\fR
activated (for the relevant buffer) if the absolute filename
matches the extended regular expression \fIfileregex\fR.
Or the syntax can be explicitly activated (for all buffers)
by using the \fB\-Y\fR or \fB\-\-syntax\fR
command-line option followed by the \fIname\fR.
.sp
The syntax \fBdefault\fP is special: it takes no \fIfileregex\fR,
@@ -475,9 +465,6 @@ system and will be silently ignored otherwise.)
.TP
.BI formatter " program " \fR[ "argument " \fR...]
Run the given \fIprogram\fR on the full contents of the current buffer.
(The current buffer is written out to a temporary file, the program is
run on it, and then the temporary file is read back in, replacing the
contents of the buffer.)
.TP
.BI linter " program " \fR[ "argument " \fR...]
Use the given \fIprogram\fR to run a syntax check on the current buffer.
@@ -568,14 +555,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).
The \fIstring\fR can consist of text or commands or a mix of them.
(To enter a command into the \fIstring\fR, precede its keystroke
with \fBM\-V\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 availability 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:
@@ -687,7 +683,6 @@ Or, when it is set, unsets the mark.
.B location
Reports the current position of the cursor in the buffer:
the line, column, and character positions.
(The old name of this function, 'curpos', is deprecated.)
.TP
.B wordcount
Counts and reports on the status bar the number of lines, words,
@@ -703,15 +698,23 @@ Invokes a spell-checking program, either the default \fBhunspell\fR(1) or GNU
.TP
.B formatter
Invokes a full-buffer-processing program (if the active syntax defines one).
(The current buffer is written out to a temporary file, the program
is run on it, and then the temporary file is read back in, replacing
the contents of the buffer.)
.TP
.B linter
Invokes a syntax-checking program (if the active syntax defines one).
If this program produces lines of the form "filename:linenum:charnum:
some message", then the cursor will be put at the indicated position
in the mentioned file while showing "some message" on the status bar.
You can move from message to message with <PgUp> and <PgDn>,
and leave linting mode with \fB^C\fR or <Enter>.
.TP
.B justify
Justifies the current paragraph (or the marked region).
A paragraph is a group of contiguous lines
that, apart from possibly the first line, all have the same indentation. The
beginning of a paragraph is detected by either this lone line with a differing
A paragraph is a group of contiguous lines that, apart from possibly
the first line, all have the same indentation. The beginning of a
paragraph is detected by either this lone line with a differing
indentation or by a preceding blank line.
.TP
.B fulljustify
@@ -821,7 +824,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.
@@ -1017,7 +1021,6 @@ The 'go to directory' menu in the file browser.
The menu for inserting the output from an external command,
or for filtering the buffer (or the marked region) through
an external command, or for executing one of several tools.
(The old form of this menu name, 'extcmd', is deprecated.)
.TP
.B spell
The menu of the integrated spell checker where the user can edit a misspelled word.
@@ -1031,6 +1034,20 @@ For \fBbind\fR it means all menus where the specified \fIfunction\fR exists;
for \fBunbind\fR it means all menus where the specified \fIkey\fR exists.
.RE
.SH EXAMPLES
To make \fBCtrl+Z\fR suspend nano:
.sp
.RS
.B bind ^Z suspend main
.RE
.sp
To make \fBShift+Alt+C\fR copy the marked region to the system's clipboard:
.sp
.RS
.B bind Sh-M-C """{execute}| xsel -ib {enter}{undo}""" main
.RE
.sp
.SH FILES
.TP
.I /etc/nanorc

View File

@@ -1,4 +1,4 @@
.\" Copyright (C) 2002-2007, 2014-2022 Free Software Foundation, Inc.
.\" Copyright (C) 2002-2007, 2014-2023 Free Software Foundation, Inc.
.\"
.\" This document is dual-licensed. You may distribute and/or modify it
.\" under the terms of either of the following licenses:
@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH RNANO 1 "version 6.2" "February 2022"
.TH RNANO 1 "version 7.2" "January 2023"
.SH NAME
rnano \- a restricted nano
@@ -32,15 +32,19 @@ access to the filesystem nor to a command shell.
.sp
In restricted mode, \fBnano\fR will:
.IP \[bu] 2
not make backups;
.IP \[bu]
not allow suspending;
.IP \[bu]
not allow spell checking;
.IP \[bu]
not read nor write the history files;
.IP \[bu]
not allow saving the current buffer under a different name;
.IP \[bu]
not allow inserting another file or opening a new buffer;
.IP \[bu]
not allow appending or prepending to any file;
.IP \[bu]
not make backup files nor do spell checking.
not allow appending or prepending to any file.
.SH OPTIONS
.TP

View File

@@ -146,7 +146,6 @@
## Save a changed buffer automatically on exit; don't prompt.
# set saveonexit
## (The old form of this option, 'set tempfile', is deprecated.)
## Put the cursor on the highlighted item in the file browser, and
## show the cursor in the help viewer; useful for people who use a
@@ -285,11 +284,16 @@
# unbind M-T main
## (Those functions are still accessible through ^T^J and ^T^V.)
## For quickly uppercasing or lowercasing the word under the cursor.
## (These effectively do a Ctrl+Right followed by a Shift+Ctrl+Left,
## and then pipe the selected text through a sed command.)
# bind Sh-M-U "Oc|sed 's/.*/\U&/'
" main
## For quickly uppercasing or lowercasing the word under or after the cursor.
## (These effectively select a word and pipe it through a sed command.)
#bind Sh-M-U "{nextword}{mark}{prevword}{execute}|sed 's/.*/\U&/'{enter}" main
#bind Sh-M-L "{nextword}{mark}{prevword}{execute}|sed 's/.*/\L&/'{enter}" main
## 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,
@@ -309,9 +313,6 @@
#bind ^B wherewas all
#bind ^D findprevious all
#bind ^R replace main
#bind ^D findprevious all
#bind ^R replace main
#bind ^Z undo main
#unbind ^U all
#unbind ^N main
#unbind ^Y all
@@ -324,3 +325,7 @@
#bind ^T cutrestoffile execute
#bind ^L linter execute
#bind ^E execute main
#bind ^K "{mark}{end}{zap}" main
#bind ^U "{mark}{home}{zap}" main
#bind ^Z undo main
#bind ^Y redo main

View File

@@ -1,2 +1,2 @@
# List of available languages.
bg ca cs da de eo es eu fi fr ga gl hr hu id is it ja ko ms nb nl pl pt pt_BR ro ru sk sl sr sv tr uk vi zh_CN zh_TW
bg ca cs da de eo es eu fi fr ga gl hr hu id is it ja ka ko ms nb nl pl pt pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_TW

1296
po/bg.po

File diff suppressed because it is too large Load Diff

1258
po/ca.po

File diff suppressed because it is too large Load Diff

1258
po/cs.po

File diff suppressed because it is too large Load Diff

1583
po/da.po

File diff suppressed because it is too large Load Diff

1260
po/de.po

File diff suppressed because it is too large Load Diff

1254
po/eo.po

File diff suppressed because it is too large Load Diff

1257
po/es.po

File diff suppressed because it is too large Load Diff

1252
po/eu.po

File diff suppressed because it is too large Load Diff

1411
po/fi.po

File diff suppressed because it is too large Load Diff

1266
po/fr.po

File diff suppressed because it is too large Load Diff

1260
po/ga.po

File diff suppressed because it is too large Load Diff

1266
po/gl.po

File diff suppressed because it is too large Load Diff

1312
po/hr.po

File diff suppressed because it is too large Load Diff

1312
po/hu.po

File diff suppressed because it is too large Load Diff

1341
po/id.po

File diff suppressed because it is too large Load Diff

1398
po/is.po

File diff suppressed because it is too large Load Diff

1449
po/it.po

File diff suppressed because it is too large Load Diff

1256
po/ja.po

File diff suppressed because it is too large Load Diff

2919
po/ka.po Normal file

File diff suppressed because it is too large Load Diff

1256
po/ko.po

File diff suppressed because it is too large Load Diff

1346
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1257
po/nb.po

File diff suppressed because it is too large Load Diff

1254
po/nl.po

File diff suppressed because it is too large Load Diff

1271
po/pl.po

File diff suppressed because it is too large Load Diff

1354
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1347
po/ro.po

File diff suppressed because it is too large Load Diff

1260
po/ru.po

File diff suppressed because it is too large Load Diff

1258
po/sk.po

File diff suppressed because it is too large Load Diff

1353
po/sl.po

File diff suppressed because it is too large Load Diff

3098
po/sq.po Normal file

File diff suppressed because it is too large Load Diff

1255
po/sr.po

File diff suppressed because it is too large Load Diff

1280
po/sv.po

File diff suppressed because it is too large Load Diff

1330
po/tr.po

File diff suppressed because it is too large Load Diff

1254
po/uk.po

File diff suppressed because it is too large Load Diff

1682
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#!/bin/bash
VERSION="6.2"
VERSION="7.2"
./configure -C --enable-tiny && make && ./configure -C &&
@@ -20,7 +20,7 @@ gpg -a -b nano-$VERSION.tar.xz &&
gpg --verify nano-$VERSION.tar.gz.asc &&
gpg --verify nano-$VERSION.tar.xz.asc &&
git tag -u A0ACE884 -a v$VERSION -m "the nano $VERSION release" &&
git tag -u B8E1961F -a v$VERSION -m "the nano $VERSION release" &&
make pdf && rm -rf doc/nano.t2p &&
scp doc/nano.pdf bens@wh0rd.org:nano.pdf &&

View File

@@ -16,7 +16,8 @@ winio.o: revision.h
# only when the revision actually changed.
revision.h: FORCE
@[ -f $@ ] || touch $@
@echo "#define $(SOMETHING)" | cmp -s $@ - || \
@! git describe >/dev/null 2>&1 || \
echo "#define $(SOMETHING)" | cmp -s $@ - || \
echo "#define $(SOMETHING)" > $@
FORCE:

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* browser.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2015-2016, 2020 Benno Schulenberg *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2016, 2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -47,9 +47,10 @@ static size_t selected = 0;
* files that can be displayed per screen row. And sort the list too. */
void read_the_list(const char *path, DIR *dir)
{
size_t path_len = strlen(path), index = 0;
size_t path_len = strlen(path);
const struct dirent *entry;
size_t widest = 0;
size_t index = 0;
/* Find the width of the widest filename in the current folder. */
while ((entry = readdir(dir)) != NULL) {
@@ -91,9 +92,8 @@ void read_the_list(const char *path, DIR *dir)
index++;
}
/* Maybe the number of files in the directory decreased between the
* first time we scanned and the second time. index is the actual
* length of the file list, so record it. */
/* Maybe the number of files in the directory decreased between
* the first time we scanned and the second time. */
list_length = index;
/* Sort the list of names. */
@@ -107,28 +107,23 @@ void read_the_list(const char *path, DIR *dir)
usable_rows = editwinrows - (ISSET(ZERO) && LINES > 1 ? 1 : 0);
}
/* Look for needle. If we find it, set selected to its location.
* Note that needle must be an exact match for a file in the list. */
void browser_select_dirname(const char *needle)
/* Reselect the given file or directory name, if it still exists. */
void reselect(const char *name)
{
size_t looking_at = 0;
for (; looking_at < list_length; looking_at++) {
if (strcmp(filelist[looking_at], needle) == 0) {
selected = looking_at;
break;
}
}
while (looking_at < list_length && strcmp(filelist[looking_at], name) != 0)
looking_at++;
/* If the sought name isn't found, move the highlight so that the
* changed selection will be noticed. */
if (looking_at == list_length) {
/* If the sought name was found, select it; otherwise, just move
* the highlight so that the changed selection will be noticed,
* but make sure to stay within the current available range. */
if (looking_at < list_length)
selected = looking_at;
else if (selected > list_length)
selected = list_length - 1;
else
--selected;
/* Make sure we stay within the available range. */
if (selected >= list_length)
selected = list_length - 1;
}
}
/* Display at most a screenful of filenames from the gleaned filelist. */
@@ -260,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.
@@ -450,13 +421,12 @@ char *browse(char *path)
dir = NULL;
}
/* If given, reselect the present_name and then discard it. */
/* If something was selected before, reselect it;
* otherwise, just select the first item (..). */
if (present_name != NULL) {
browser_select_dirname(present_name);
reselect(present_name);
free(present_name);
present_name = NULL;
/* Otherwise, select the first file or directory in the list. */
} else
selected = 0;
@@ -466,8 +436,11 @@ char *browse(char *path)
titlebar(path);
while (TRUE) {
functionptrtype func;
if (list_length == 0) {
statusline(ALERT, _("No entries"));
napms(1200);
} else while (TRUE) {
functionptrtype function;
int kbinput;
lastmessage = VACUUM;
@@ -511,73 +484,70 @@ char *browse(char *path)
}
#endif /* ENABLE_MOUSE */
#ifndef NANO_TINY
if (bracketed_paste || kbinput == BRACKETED_PASTE_MARKER) {
while (bracketed_paste)
kbinput = get_kbinput(midwin, BLIND);
if (kbinput == BRACKETED_PASTE_MARKER) {
beep();
continue;
}
#endif
func = interpret(&kbinput);
function = interpret(kbinput);
if (func == full_refresh) {
full_refresh();
if (function == full_refresh || function == do_help) {
function();
#ifndef NANO_TINY
/* Simulate a terminal resize to force a directory reread. */
/* Simulate a terminal resize to force a directory reread,
* or because the terminal dimensions might have changed. */
kbinput = KEY_WINCH;
#endif
} else if (func == do_help) {
do_help();
#ifndef NANO_TINY
/* The terminal dimensions might have changed, so act as if. */
kbinput = KEY_WINCH;
} else if (func == do_toggle) {
} else if (function == do_toggle && get_shortcut(kbinput)->toggle == NO_HELP) {
TOGGLE(NO_HELP);
window_init();
kbinput = KEY_WINCH;
#endif
} else if (func == do_search_backward) {
} else if (function == do_search_backward) {
search_filename(BACKWARD);
} else if (func == do_search_forward) {
} else if (function == do_search_forward) {
search_filename(FORWARD);
} else if (func == do_findprevious) {
} else if (function == do_findprevious) {
research_filename(BACKWARD);
} else if (func == do_findnext) {
} else if (function == do_findnext) {
research_filename(FORWARD);
} else if (func == do_left) {
} else if (function == do_left) {
if (selected > 0)
selected--;
} else if (func == do_right) {
} else if (function == do_right) {
if (selected < list_length - 1)
selected++;
} else if (func == to_prev_word) {
} else if (function == to_prev_word) {
selected -= (selected % piles);
} else if (func == to_next_word) {
} else if (function == to_next_word) {
selected += piles - 1 - (selected % piles);
if (selected >= list_length)
selected = list_length - 1;
} else if (func == do_up) {
} else if (function == do_up) {
if (selected >= piles)
selected -= piles;
} else if (func == do_down) {
} else if (function == do_down) {
if (selected + piles <= list_length - 1)
selected += piles;
} else if (func == to_prev_block) {
} else if (function == to_prev_block) {
selected = ((selected / (usable_rows * piles)) * usable_rows * piles) +
selected % piles;
} else if (func == to_next_block) {
} else if (function == to_next_block) {
selected = ((selected / (usable_rows * piles)) * usable_rows * piles) +
selected % piles + usable_rows * piles - piles;
if (selected >= list_length)
selected = (list_length / piles) * piles + selected % piles;
if (selected >= list_length)
selected -= piles;
} else if (func == do_page_up) {
} else if (function == do_page_up) {
if (selected < piles)
selected = 0;
else if (selected < usable_rows * piles)
selected = selected % piles;
else
selected -= usable_rows * piles;
} else if (func == do_page_down) {
} else if (function == do_page_down) {
if (selected + piles >= list_length - 1)
selected = list_length - 1;
else if (selected + usable_rows * piles >= list_length)
@@ -585,11 +555,11 @@ char *browse(char *path)
list_length - piles;
else
selected += usable_rows * piles;
} else if (func == to_first_file) {
} else if (function == to_first_file) {
selected = 0;
} else if (func == to_last_file) {
} else if (function == to_last_file) {
selected = list_length - 1;
} else if (func == goto_dir) {
} else if (function == goto_dir) {
/* Ask for the directory to go to. */
if (do_prompt(MGOTODIR, "", NULL,
/* TRANSLATORS: This is a prompt. */
@@ -628,7 +598,7 @@ char *browse(char *path)
/* Try opening and reading the specified directory. */
goto read_directory_contents;
} else if (func == do_enter) {
} else if (function == do_enter) {
struct stat st;
/* It isn't possible to move up from the root directory. */
@@ -668,14 +638,14 @@ char *browse(char *path)
path = mallocstrcpy(path, filelist[selected]);
goto read_directory_contents;
#ifdef ENABLE_NANORC
} else if (func == (functionptrtype)implant) {
implant(first_sc_for(MBROWSER, func)->expansion);
} else if (function == (functionptrtype)implant) {
implant(first_sc_for(MBROWSER, function)->expansion);
#endif
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
; /* Gets handled below. */
#endif
} else if (func == do_exit) {
} else if (function == do_exit) {
break;
} else
unbound_key(kbinput);
@@ -715,14 +685,10 @@ char *browse_in(const char *inpath)
path = free_and_assign(path, strip_last_component(path));
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
char *currentdir = nmalloc(PATH_MAX + 1);
path = free_and_assign(path, getcwd(currentdir, PATH_MAX + 1));
path = free_and_assign(path, realpath(".", NULL));
if (path == NULL) {
statusline(MILD, _("The working directory has disappeared"));
free(currentdir);
beep();
statusline(ALERT, _("The working directory has disappeared"));
napms(1200);
return NULL;
}
@@ -730,8 +696,8 @@ char *browse_in(const char *inpath)
}
#ifdef ENABLE_OPERATINGDIR
/* If the resulting path isn't in the operating directory, use
* the operating directory instead. */
/* If the resulting path isn't in the operating directory,
* use the operating directory instead. */
if (outside_of_confinement(path, FALSE))
path = mallocstrcpy(path, operating_dir);
#endif

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* chars.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016-2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* color.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017, 2020, 2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -53,6 +53,7 @@ void set_interface_colorpairs(void)
}
init_pair(index + 1, combo->fg, combo->bg);
interface_color_pair[index] = COLOR_PAIR(index + 1) | combo->attributes;
rescind_colors = FALSE;
} else {
if (index == FUNCTION_TAG || index == SCROLL_BAR)
interface_color_pair[index] = A_NORMAL;
@@ -72,6 +73,11 @@ void set_interface_colorpairs(void)
free(color_combo[index]);
}
if (rescind_colors) {
interface_color_pair[SPOTLIGHTED] = A_REVERSE;
interface_color_pair[ERROR_MESSAGE] = A_REVERSE;
}
}
/* Assign a pair number to each of the foreground/background color combinations
@@ -255,12 +261,14 @@ void check_the_multis(linestruct *line)
if (line->multidata[ink->id] == NOTHING) {
if (!astart)
continue;
} else if (line->multidata[ink->id] & (WHOLELINE|WOULDBE)) {
if (!astart && !anend)
} else if (line->multidata[ink->id] == WHOLELINE) {
/* Ensure that a detected start match is not actually an end match. */
if (!anend && (!astart || regexec(ink->end, line->data, 1,
&endmatch, 0) != 0))
continue;
} else if (line->multidata[ink->id] == JUSTONTHIS) {
if (astart && anend && regexec(ink->start, line->data + endmatch.rm_eo,
1, &startmatch, 0) != 0)
if (astart && anend && regexec(ink->start, line->data + startmatch.rm_eo +
endmatch.rm_eo, 1, &startmatch, 0) != 0)
continue;
} else if (line->multidata[ink->id] == STARTSHERE) {
if (astart && !anend)
@@ -272,6 +280,7 @@ void check_the_multis(linestruct *line)
/* There is a mismatch, so something changed: repaint. */
refresh_needed = TRUE;
perturbed = TRUE;
return;
}
}
@@ -342,21 +351,17 @@ void precalc_multicolorinfo(void)
1, &endmatch, 0) != 0)
tailline = tailline->next;
/* When there is no end match, mark relevant lines as such. */
if (tailline == NULL) {
for (; line->next != NULL; line = line->next)
line->multidata[ink->id] = WOULDBE;
line->multidata[ink->id] = WOULDBE;
break;
}
/* We found it, we found it, la lala lala. Mark the lines. */
line->multidata[ink->id] = STARTSHERE;
// Note that this also advances the line in the main loop.
for (line = line->next; line != tailline; line = line->next)
line->multidata[ink->id] = WHOLELINE;
if (tailline == NULL) {
line = openfile->filebot;
break;
}
tailline->multidata[ink->id] = ENDSHERE;
/* Look for a possible new start after the end match. */

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* cut.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mark Majeres *
* Copyright (C) 2016, 2018-2020 Benno Schulenberg *
* *
@@ -97,6 +97,13 @@ void do_deletion(undo_type action)
/* We're at the end-of-file: nothing to do. */
return;
#ifdef ENABLE_COLOR
if (!refresh_needed)
check_the_multis(openfile->current);
#endif
if (!refresh_needed)
update_line(openfile->current, openfile->current_x);
/* Adjust the file size, and remember it for a possible redo. */
openfile->totsize--;
#ifndef NANO_TINY
@@ -435,9 +442,19 @@ void ingraft_buffer(linestruct *topline)
/* Meld a copy of the given buffer into the current file buffer. */
void copy_from_buffer(linestruct *somebuffer)
{
#ifdef ENABLE_COLOR
size_t threshold = openfile->edittop->lineno + editwinrows - 1;
#endif
linestruct *the_copy = copy_buffer(somebuffer);
ingraft_buffer(the_copy);
#ifdef ENABLE_COLOR
if (openfile->current->lineno > threshold || ISSET(SOFTWRAP))
recook = TRUE;
else
perturbed = TRUE;
#endif
}
#ifndef NANO_TINY
@@ -485,7 +502,7 @@ void do_snip(bool marked, bool until_eof, bool append)
/* When not at the end of a line, move the rest of this line into
* the cutbuffer. Otherwise, when not at the end of the buffer,
* move just the "line separator" into the cutbuffer. */
if (openfile->current_x < strlen(openfile->current->data))
if (line->data[openfile->current_x] != '\0')
extract_segment(line, openfile->current_x, line, strlen(line->data));
else if (openfile->current != openfile->filebot) {
extract_segment(line, openfile->current_x, line->next, 0);
@@ -509,6 +526,9 @@ void do_snip(bool marked, bool until_eof, bool append)
set_modified();
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
perturbed = TRUE;
#endif
}
/* Move text from the current buffer into the cutbuffer. */

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* definitions.h -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -170,8 +170,6 @@
/* The start regex matches on an earlier line, the end regex on this one. */
#define JUSTONTHIS (1<<5)
/* Both the start and end regexes match within this line. */
#define WOULDBE (1<<6)
/* An unpaired start match is on or before this line. */
#endif
/* Basic control codes. */
@@ -216,6 +214,17 @@
#define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F
#define FOCUS_IN 0x491
#define FOCUS_OUT 0x499
/* Special keycodes for when a string bind has been partially implanted
* or has an unpaired opening brace, or when a function in a string bind
* needs execution or a specified function name is invalid. */
#define MORE_PLANTS 0x4EA
#define MISSING_BRACE 0x4EB
#define PLANTED_A_COMMAND 0x4EC
#define NO_SUCH_FUNCTION 0x4EF
/* A special keycode for when <Tab> is pressed while the mark is on. */
#define INDENT_KEY 0x4F1
@@ -321,7 +330,6 @@ enum {
CASE_SENSITIVE,
CONSTANT_SHOW,
NO_HELP,
SUSPENDABLE,
NO_WRAP,
AUTOINDENT,
VIEW_MODE,
@@ -427,7 +435,7 @@ typedef struct syntaxtype {
/* The command with which to lint this type of file. */
char *formatter;
/* The command with which to format/modify/arrange this type of file. */
char *tab;
char *tabstring;
/* What the Tab key should produce; NULL for default behavior. */
#ifdef ENABLE_COMMENT
char *comment;
@@ -630,17 +638,14 @@ 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
bool viewok;
/* Is this function allowed when in view mode? */
int menus;
/* In what menus this function applies. */
struct funcstruct *next;

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* files.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2015-2021 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -33,6 +33,10 @@
#define RW_FOR_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#ifndef HAVE_FSYNC
# define fsync(...) 0
#endif
/* Add an item to the circular list of openfile structs. */
void make_new_buffer(void)
{
@@ -53,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
@@ -143,7 +147,7 @@ const char *locking_suffix = ".swp";
* existing version of that file. Return TRUE on success; FALSE otherwise. */
bool write_lockfile(const char *lockfilename, const char *filename, bool modified)
{
#ifdef HAVE_PWD_H
#if defined(HAVE_PWD_H) && defined(HAVE_GETEUID)
pid_t mypid = getpid();
uid_t myuid = geteuid();
struct passwd *mypwuid = getpwuid(myuid);
@@ -214,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);
@@ -346,8 +350,18 @@ bool has_valid_path(const char *filename)
char *parentdir = dirname(namecopy);
struct stat parentinfo;
bool validity = FALSE;
bool gone = FALSE;
if (stat(parentdir, &parentinfo) == -1) {
if (strcmp(parentdir, ".") == 0) {
char *currentdir = realpath(".", NULL);
gone = (currentdir == NULL && errno == ENOENT);
free(currentdir);
}
if (gone)
statusline(ALERT, _("The working directory has disappeared"));
else if (stat(parentdir, &parentinfo) == -1) {
if (errno == ENOENT)
/* TRANSLATORS: Keep the next ten messages at most 76 characters. */
statusline(ALERT, _("Directory '%s' does not exist"), parentdir);
@@ -411,7 +425,7 @@ bool open_buffer(const char *filename, bool new_one)
free(realname);
return FALSE;
}
#else
#elif defined(HAVE_GETEUID)
if (new_one && !(fileinfo.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) &&
geteuid() == ROOT_UID)
statusline(ALERT, _("%s is meant to be read-only"), realname);
@@ -521,7 +535,8 @@ void mention_name_and_linecount(void)
if (ISSET(MINIBAR)) {
report_size = TRUE;
return;
}
} else if (ISSET(ZERO))
return;
if (openfile->fmt > NIX_FILE)
/* TRANSLATORS: First %s is file name, second %s is file format. */
@@ -560,13 +575,14 @@ void redecorate_after_switch(void)
/* Prevent a possible Shift selection from getting cancelled. */
shift_held = TRUE;
/* If the switched-to buffer gave an error during opening, show the message
* once; otherwise, indicate on the status bar which file we switched to. */
if (openfile->errormessage) {
statusline(ALERT, openfile->errormessage);
free(openfile->errormessage);
openfile->errormessage = NULL;
} else
/* Indicate on the status bar where we switched to. */
mention_name_and_linecount();
mention_name_and_linecount();
}
/* Switch to the previous entry in the circular list of buffers. */
@@ -612,7 +628,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 */
@@ -675,9 +691,13 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
block_sigwinch(TRUE);
#endif
#ifdef HAVE_FLOCKFILE
/* Lock the file before starting to read it, to avoid the overhead
* of locking it for each single byte that we read from it. */
flockfile(f);
#else
# define getc_unlocked getc
#endif
control_C_was_pressed = FALSE;
@@ -741,8 +761,10 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
errornumber = errno;
#ifdef HAVE_FUNLOCKFILE
/* We are done with the file, unlock it. */
funlockfile(f);
#endif
#ifndef NANO_TINY
block_sigwinch(FALSE);
@@ -826,12 +848,14 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
report_size = TRUE;
/* If we inserted less than a screenful, don't center the cursor. */
if (undoable && less_than_a_screenful(was_lineno, was_leftedge))
if (undoable && less_than_a_screenful(was_lineno, was_leftedge)) {
focusing = FALSE;
#ifdef ENABLE_COLOR
else if (undoable)
precalc_multicolorinfo();
perturbed = TRUE;
} else if (undoable) {
recook = TRUE;
#endif
}
#ifndef NANO_TINY
if (undoable)
@@ -946,11 +970,20 @@ char *get_next_filename(const char *name, const char *suffix)
#ifndef NANO_TINY
static pid_t pid_of_command = -1;
/* The PID of a forked process -- needed when wanting to abort it. */
static pid_t pid_of_sender = -1;
/* The PID of the process that pipes data to the above process. */
static bool should_pipe = FALSE;
/* Whether we are piping data to the external command. */
/* Send an unconditional kill signal to the running external command. */
void cancel_the_command(int signal)
{
kill(pid_of_command, SIGKILL);
#ifdef SIGKILL
if (pid_of_command > 0)
kill(pid_of_command, SIGKILL);
if (should_pipe && pid_of_sender > 0)
kill(pid_of_sender, SIGKILL);
#endif
}
/* Send the text that starts at the given line to file descriptor fd. */
@@ -963,28 +996,39 @@ 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;
}
fclose(tube);
}
/* Execute the given command in a shell. Return TRUE on success. */
bool execute_command(const char *command)
/* Execute the given command in a shell. */
void execute_command(const char *command)
{
#if defined(HAVE_FORK) && defined(HAVE_PIPE) && defined(HAVE_WAIT)
int from_fd[2], to_fd[2];
/* The pipes through which text will be written and read. */
struct sigaction oldaction, newaction = {{0}};
/* Original and temporary handlers for SIGINT. */
const bool should_pipe = (command[0] == '|');
ssize_t was_lineno = (openfile->mark ? 0 : openfile->current->lineno);
int command_status, sender_status;
FILE *stream;
should_pipe = (command[0] == '|');
/* Create a pipe to read the command's output from, and, if needed,
* a pipe to feed the command's input through. */
if (pipe(from_fd) == -1 || (should_pipe && pipe(to_fd) == -1)) {
statusline(ALERT, _("Could not create pipe: %s"), strerror(errno));
return FALSE;
return;
}
/* Fork a child process to run the command in. */
@@ -1008,6 +1052,7 @@ bool execute_command(const char *command)
if (should_pipe) {
if (dup2(to_fd[0], STDIN_FILENO) < 0)
exit(5);
close(from_fd[1]);
close(to_fd[1]);
}
@@ -1024,7 +1069,7 @@ bool execute_command(const char *command)
if (pid_of_command == -1) {
statusline(ALERT, _("Could not fork: %s"), strerror(errno));
close(from_fd[0]);
return FALSE;
return;
}
statusbar(_("Executing..."));
@@ -1054,16 +1099,20 @@ bool execute_command(const char *command)
}
add_undo(CUT, NULL);
do_snip(openfile->mark != NULL, openfile->mark == NULL, FALSE);
openfile->filetop->has_anchor = FALSE;
if (openfile->filetop->next == NULL)
openfile->filetop->has_anchor = FALSE;
update_undo(CUT);
}
/* Create a separate process for piping the data to the command. */
if (fork() == 0) {
if ((pid_of_sender = fork()) == 0) {
send_data(whole_buffer ? openfile->filetop : cutbuffer, to_fd[1]);
exit(0);
}
if (pid_of_sender == -1)
statusline(ALERT, _("Could not fork: %s"), strerror(errno));
close(to_fd[0]);
close(to_fd[1]);
@@ -1090,13 +1139,32 @@ bool execute_command(const char *command)
else
read_file(stream, 0, "pipe", TRUE);
if (should_pipe && !ISSET(MULTIBUFFER))
if (should_pipe && !ISSET(MULTIBUFFER)) {
if (was_lineno)
goto_line_posx(was_lineno, 0);
add_undo(COUPLE_END, N_("filtering"));
}
/* Wait for the external command (and possibly data sender) to terminate. */
wait(NULL);
if (should_pipe)
wait(NULL);
waitpid(pid_of_command, &command_status, 0);
if (should_pipe && pid_of_sender > 0)
waitpid(pid_of_sender, &sender_status, 0);
/* If the command failed, show what the shell reported. */
if (WIFEXITED(command_status) == 0 || WEXITSTATUS(command_status))
statusline(ALERT, WIFSIGNALED(command_status) ? _("Cancelled") :
_("Error: %s"), openfile->current->prev &&
strstr(openfile->current->prev->data, ": ") ?
strstr(openfile->current->prev->data, ": ") + 2 : "---");
else if (should_pipe && pid_of_sender > 0 &&
(WIFEXITED(sender_status) == 0 || WEXITSTATUS(sender_status)))
statusline(ALERT, _("Piping failed"));
/* If there was an error, undo and discard what the command did. */
if (lastmessage == ALERT) {
do_undo();
discard_until(openfile->current_undo);
}
/* Restore the original handler for SIGINT. */
sigaction(SIGINT, &oldaction, NULL);
@@ -1104,8 +1172,7 @@ bool execute_command(const char *command)
/* Restore the terminal to its desired state, and disable
* interpretation of the special control keys again. */
terminal_init();
return TRUE;
#endif
}
#endif /* NANO_TINY */
@@ -1178,7 +1245,7 @@ void insert_a_file_or(bool execute)
ssize_t was_current_lineno = openfile->current->lineno;
size_t was_current_x = openfile->current_x;
#if !defined(NANO_TINY) || defined(ENABLE_BROWSER) || defined(ENABLE_MULTIBUFFER)
functionptrtype func = func_from_key(&response);
functionptrtype function = func_from_key(response);
#endif
given = mallocstrcpy(given, answer);
@@ -1186,7 +1253,7 @@ void insert_a_file_or(bool execute)
break;
#ifdef ENABLE_MULTIBUFFER
if (func == flip_newbuffer) {
if (function == flip_newbuffer) {
/* Allow toggling only when not in view mode. */
if (!ISSET(VIEW_MODE))
TOGGLE(MULTIBUFFER);
@@ -1196,22 +1263,22 @@ void insert_a_file_or(bool execute)
}
#endif
#ifndef NANO_TINY
if (func == flip_convert) {
if (function == flip_convert) {
TOGGLE(NO_CONVERT);
continue;
}
if (func == flip_execute) {
if (function == flip_execute) {
execute = !execute;
continue;
}
if (func == flip_pipe) {
if (function == flip_pipe) {
add_or_remove_pipe_symbol_from_answer();
given = mallocstrcpy(given, answer);
continue;
}
#endif
#ifdef ENABLE_BROWSER
if (func == to_files) {
if (function == to_files) {
char *chosen = browse_in(answer);
/* If no file was chosen, go back to the prompt. */
@@ -1322,106 +1389,37 @@ void do_execute(void)
* absolute path (plus filename) when the path exists, and NULL when not. */
char *get_full_path(const char *origpath)
{
char *allocation, *here, *target, *last_slash;
char *just_filename = NULL;
int attempts = 0;
char *untilded, *target, *slash;
struct stat fileinfo;
bool path_only;
if (origpath == NULL)
return NULL;
allocation = nmalloc(PATH_MAX + 1);
here = getcwd(allocation, PATH_MAX + 1);
untilded = real_dir_from_tilde(origpath);
target = realpath(untilded, NULL);
slash = strrchr(untilded, '/');
/* If getting the current directory failed, go up one level and try again,
* until we find an existing directory, and use that as the current one. */
while (here == NULL && attempts < 20) {
IGNORE_CALL_RESULT(chdir(".."));
here = getcwd(allocation, PATH_MAX + 1);
attempts++;
}
/* If realpath() returned NULL, try without the last component,
* as this can be a file that does not exist yet. */
if (!target && slash && slash[1]) {
*slash = '\0';
target = realpath(untilded, NULL);
/* If we found a directory, make sure its path ends in a slash. */
if (here != NULL) {
if (strcmp(here, "/") != 0) {
here = nrealloc(here, strlen(here) + 2);
strcat(here, "/");
}
} else {
here = copy_of("");
free(allocation);
}
target = real_dir_from_tilde(origpath);
/* Determine whether the target path refers to a directory. If statting
* target fails, however, assume that it refers to a new, unsaved buffer. */
path_only = (stat(target, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode));
/* If the target is a directory, make sure its path ends in a slash. */
if (path_only) {
size_t length = strlen(target);
if (target[length - 1] != '/') {
target = nrealloc(target, length + 2);
strcat(target, "/");
/* Upon success, re-add the last component of the original path. */
if (target) {
target = nrealloc(target, strlen(target) + strlen(slash + 1) + 1);
strcat(target, slash + 1);
}
}
last_slash = strrchr(target, '/');
/* If the target path does not contain a slash, then it is a bare filename
* and must therefore be located in the working directory. */
if (last_slash == NULL) {
just_filename = target;
target = here;
} else {
/* If target contains a filename, separate the two. */
if (!path_only) {
just_filename = copy_of(last_slash + 1);
*(last_slash + 1) = '\0';
}
/* If we can't change to the target directory, give up. Otherwise,
* get the canonical path to this target directory. */
if (chdir(target) == -1) {
free(target);
target = NULL;
} else {
free(target);
allocation = nmalloc(PATH_MAX + 1);
target = getcwd(allocation, PATH_MAX + 1);
/* If we got a result, make sure it ends in a slash.
* Otherwise, ensure that we return NULL. */
if (target != NULL) {
if (strcmp(target, "/") != 0) {
target = nrealloc(target, strlen(target) + 2);
strcat(target, "/");
}
} else {
path_only = TRUE;
free(allocation);
}
/* Finally, go back to where we were before. We don't check
* for an error, since we can't do anything if we get one. */
IGNORE_CALL_RESULT(chdir(here));
}
free(here);
/* Ensure that a non-apex directory path ends with a slash. */
if (target && target[1] && stat(target, &fileinfo) == 0 &&
S_ISDIR(fileinfo.st_mode)) {
target = nrealloc(target, strlen(target) + 2);
strcat(target, "/");
}
/* If we were given more than a bare path, concatenate the target path
* with the filename portion to get the full, absolute file path. */
if (!path_only && target != NULL) {
target = nrealloc(target, strlen(target) + strlen(just_filename) + 1);
strcat(target, just_filename);
}
free(just_filename);
free(untilded);
return target;
}
@@ -1563,12 +1561,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;
}
@@ -1653,6 +1651,7 @@ bool make_backup_of(char *realname)
if (backup_file == NULL)
goto problem;
#ifdef HAVE_FCHOWN
/* Try to change owner and group to those of the original file;
* ignore permission errors, as a normal user cannot change the owner. */
if (fchown(descriptor, openfile->statinfo->st_uid,
@@ -1660,7 +1659,8 @@ bool make_backup_of(char *realname)
fclose(backup_file);
goto problem;
}
#endif
#ifdef HAVE_FCHMOD
/* Set the backup's permissions to those of the original file.
* It is not a security issue if this fails, as we have created
* the file with just read and write permission for the owner. */
@@ -1668,6 +1668,7 @@ bool make_backup_of(char *realname)
fclose(backup_file);
goto problem;
}
#endif
original = fopen(realname, "rb");
@@ -1887,13 +1888,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);
@@ -1974,6 +1974,19 @@ bool write_file(const char *name, FILE *thefile, bool normal,
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
cleanup_and_exit:
#ifndef NANO_TINY
if (errno == ENOSPC && normal) {
napms(3200); lastmessage = VACUUM;
/* TRANSLATORS: This warns for data loss when the disk is full. */
statusline(ALERT, _("File on disk has been truncated!"));
napms(3200); lastmessage = VACUUM;
/* TRANSLATORS: This is a suggestion to the user,
* where "resume" means resuming from suspension.
* Try to keep this at most 76 characters. */
statusline(ALERT, _("Maybe ^T^Z, make room on disk, resume, then ^S^X"));
stat_with_alloc(realname, &openfile->statinfo);
}
#endif
free(tempname);
free(realname);
return FALSE;
@@ -2055,7 +2068,7 @@ bool write_region_to_file(const char *name, FILE *stream, bool normal,
get_region(&topline, &top_x, &botline, &bot_x);
/* When needed, prepare a magic end line for the region. */
if (bot_x > 0 && !ISSET(NO_NEWLINES)) {
if (normal && bot_x > 0 && !ISSET(NO_NEWLINES)) {
stopper = make_new_node(botline);
stopper->data = copy_of("");
} else
@@ -2112,7 +2125,7 @@ int write_it_out(bool exiting, bool withprompt)
#endif
while (TRUE) {
functionptrtype func;
functionptrtype function;
const char *msg;
int response = 0;
int choice = NO;
@@ -2159,10 +2172,10 @@ int write_it_out(bool exiting, bool withprompt)
return 0;
}
func = func_from_key(&response);
function = func_from_key(response);
/* Upon request, abandon the buffer. */
if (func == discard_buffer) {
if (function == discard_buffer) {
free(given);
return 2;
}
@@ -2170,7 +2183,7 @@ int write_it_out(bool exiting, bool withprompt)
given = mallocstrcpy(given, answer);
#ifdef ENABLE_BROWSER
if (func == to_files) {
if (function == to_files) {
char *chosen = browse_in(answer);
if (chosen == NULL)
@@ -2181,17 +2194,17 @@ int write_it_out(bool exiting, bool withprompt)
} else
#endif
#ifndef NANO_TINY
if (func == dos_format) {
if (function == dos_format) {
openfile->fmt = (openfile->fmt == DOS_FILE) ? NIX_FILE : DOS_FILE;
continue;
} else if (func == mac_format) {
} else if (function == mac_format) {
openfile->fmt = (openfile->fmt == MAC_FILE) ? NIX_FILE : MAC_FILE;
continue;
} else if (func == back_it_up) {
} else if (function == back_it_up) {
TOGGLE(MAKE_BACKUP);
continue;
} else if (func == prepend_it || func == append_it) {
if (func == prepend_it)
} else if (function == prepend_it || function == append_it) {
if (function == prepend_it)
method = (method == PREPEND) ? OVERWRITE : PREPEND;
else
method = (method == APPEND) ? OVERWRITE : APPEND;
@@ -2200,7 +2213,7 @@ int write_it_out(bool exiting, bool withprompt)
continue;
} else
#endif
if (func == do_help)
if (function == do_help)
continue;
#ifdef ENABLE_EXTRA
@@ -2419,13 +2432,13 @@ int diralphasort(const void *va, const void *vb)
/* Return TRUE when the given path is a directory. */
bool is_dir(const char *path)
{
char *realpath = real_dir_from_tilde(path);
char *thepath = real_dir_from_tilde(path);
struct stat fileinfo;
bool retval;
retval = (stat(realpath, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode));
retval = (stat(thepath, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode));
free(realpath);
free(thepath);
return retval;
}
@@ -2473,8 +2486,8 @@ char **username_completion(const char *morsel, size_t length, size_t *num_matche
* This code is 'as is' with no warranty.
* This code may safely be consumed by a BSD or GPL license. */
/* Try to complete the given fragment of given length to a filename. */
char **filename_completion(const char *morsel, size_t length, size_t *num_matches)
/* Try to complete the given fragment to an existing filename. */
char **filename_completion(const char *morsel, size_t *num_matches)
{
char *dirname = copy_of(morsel);
char *slash, *filename;
@@ -2567,7 +2580,7 @@ char *input_tab(char *morsel, size_t *place, void (*refresh_func)(void), bool *l
/* If there are no matches yet, try matching against filenames. */
if (matches == NULL)
matches = filename_completion(morsel, *place, &num_matches);
matches = filename_completion(morsel, &num_matches);
/* If possible completions were listed before but none will be listed now... */
if (*listed && num_matches < 2) {

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* global.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2014-2021 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -107,6 +107,7 @@ int altpageup, altpagedown;
int altinsert, altdelete;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif
int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
ssize_t fill = -COLUMNS_FROM_EOL;
@@ -201,6 +202,12 @@ char *syntaxstr = NULL;
/* The color syntax name specified on the command line. */
bool have_palette = FALSE;
/* Whether the colors for the current syntax have been initialized. */
bool rescind_colors = FALSE;
/* Becomes TRUE when NO_COLOR is set in the environment. */
bool perturbed = FALSE;
/* Whether the multiline-coloring situation has changed. */
bool recook = FALSE;
/* Whether the multidata should be recalculated. */
#endif
int currmenu = MMOST;
@@ -260,6 +267,12 @@ char *startup_problem = NULL;
#endif
#ifdef ENABLE_NANORC
char *custom_nanorc = NULL;
/* The argument of the --rcfile option, when given. */
char *commandname = NULL;
/* The name (of a function) between braces in a string bind. */
keystruct *planted_shortcut = NULL;
/* The function that the above name resolves to, if any. */
#endif
bool spotlighted = FALSE;
@@ -274,11 +287,6 @@ size_t light_to_col = 0;
#define NOVIEW FALSE
#define BLANKAFTER TRUE /* A blank line after this one. */
#define TOGETHER FALSE
#ifdef ENABLE_MULTIBUFFER
#define CAN_OPEN_OTHER_BUFFER TRUE
#else
#define CAN_OPEN_OTHER_BUFFER FALSE
#endif
/* Empty functions, for the most part corresponding to toggles. */
void case_sens_void(void) {;}
@@ -313,8 +321,8 @@ void discard_buffer(void) {;}
void do_cancel(void) {;}
/* Add a function to the linked list of functions. */
void add_to_funcs(void (*func)(void), int menus, const char *desc,
const char *help, bool blank_after, bool viewok)
void add_to_funcs(void (*function)(void), int menus, const char *tag,
const char *phrase, bool blank_after)
{
funcstruct *f = nmalloc(sizeof(funcstruct));
@@ -325,12 +333,11 @@ void add_to_funcs(void (*func)(void), int menus, const char *desc,
tailfunc = f;
f->next = NULL;
f->func = func;
f->func = function;
f->menus = menus;
f->desc = desc;
f->viewok = viewok;
f->tag = tag;
#ifdef ENABLE_HELP
f->help = help;
f->phrase = phrase;
f->blank_after = blank_after;
#endif
}
@@ -382,7 +389,7 @@ int keycode_from_string(const char *keystring)
/* Add a key combo to the linked list of shortcuts. */
void add_to_sclist(int menus, const char *scstring, const int keycode,
void (*func)(void), int toggle)
void (*function)(void), int toggle)
{
static keystruct *tailsc;
#ifndef NANO_TINY
@@ -399,7 +406,7 @@ void add_to_sclist(int menus, const char *scstring, const int keycode,
/* Fill in the data. */
sc->menus = menus;
sc->func = func;
sc->func = function;
#ifndef NANO_TINY
sc->toggle = toggle;
/* When not the same toggle as the previous one, increment the ID. */
@@ -413,11 +420,11 @@ void add_to_sclist(int menus, const char *scstring, const int keycode,
}
/* Return the first shortcut in the list of shortcuts that
* matches the given func in the given menu. */
const keystruct *first_sc_for(int menu, void (*func)(void))
* matches the given function in the given menu. */
const keystruct *first_sc_for(int menu, void (*function)(void))
{
for (keystruct *sc = sclist; sc != NULL; sc = sc->next)
if ((sc->menus & menu) && sc->func == func && sc->keystr[0])
if ((sc->menus & menu) && sc->func == function && sc->keystr[0])
return sc;
return NULL;
@@ -445,24 +452,28 @@ size_t shown_entries_for(int menu)
}
/* Return the first shortcut in the current menu that matches the given input. */
const keystruct *get_shortcut(int *keycode)
const keystruct *get_shortcut(const int keycode)
{
/* Plain characters and upper control codes cannot be shortcuts. */
if (!meta_key && 0x20 <= *keycode && *keycode <= 0xFF)
if (!meta_key && 0x20 <= keycode && keycode <= 0xFF)
return NULL;
/* Lower control codes with Meta cannot be shortcuts either. */
if (meta_key && *keycode < 0x20)
if (meta_key && keycode < 0x20)
return NULL;
#ifndef NANO_TINY
/* During a paste at a prompt, ignore all command keycodes. */
if (bracketed_paste && *keycode != BRACKETED_PASTE_MARKER)
if (bracketed_paste && keycode != BRACKETED_PASTE_MARKER)
return NULL;
#endif
#ifdef ENABLE_NANORC
if (keycode == PLANTED_A_COMMAND)
return planted_shortcut;
#endif
for (keystruct *sc = sclist; sc != NULL; sc = sc->next) {
if ((sc->menus & currmenu) && *keycode == sc->keycode)
if ((sc->menus & currmenu) && keycode == sc->keycode)
return sc;
}
@@ -470,7 +481,7 @@ const keystruct *get_shortcut(int *keycode)
}
/* Return a pointer to the function that is bound to the given key. */
functionptrtype func_from_key(int *keycode)
functionptrtype func_from_key(const int keycode)
{
const keystruct *sc = get_shortcut(keycode);
@@ -481,15 +492,15 @@ functionptrtype func_from_key(int *keycode)
/* Return the function that is bound to the given key in the file browser or
* the help viewer. Accept also certain plain characters, for compatibility
* with Pico or to mimic 'less' and similar text viewers. */
functionptrtype interpret(int *keycode)
functionptrtype interpret(const int keycode)
{
if (!meta_key) {
if (*keycode == 'N')
if (keycode == 'N')
return do_findprevious;
if (*keycode == 'n')
if (keycode == 'n')
return do_findnext;
switch (tolower(*keycode)) {
switch (tolower(keycode)) {
case 'b':
case '-':
return do_page_up;
@@ -682,52 +693,54 @@ 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
#endif /* ENABLE_HELP */
#ifdef ENABLE_HELP
#define WITHORSANS(help) help
#define WHENHELP(description) description
#else
#define WITHORSANS(help) ""
#define WHENHELP(description) ""
#endif
/* Start populating the different menus with functions. */
#ifdef ENABLE_HELP
add_to_funcs(do_help, (MMOST | MBROWSER) & ~MFINDINHELP,
/* TRANSLATORS: Try to keep the next thirteen strings at most 10 characters. */
N_("Help"), WITHORSANS(help_gist), TOGETHER, VIEW);
/* TRANSLATORS: Try to keep the next thirteen strings at most 10 characters. */
N_("Help"), WHENHELP(help_gist), TOGETHER);
#endif
add_to_funcs(do_cancel, ((MMOST & ~MMAIN) | MYESNO),
N_("Cancel"), WITHORSANS(cancel_gist), BLANKAFTER, VIEW);
N_("Cancel"), WHENHELP(cancel_gist), BLANKAFTER);
add_to_funcs(do_exit, MMAIN,
exit_tag, WITHORSANS(exit_gist), TOGETHER, VIEW);
exit_tag, WHENHELP(exit_gist), TOGETHER);
/* Remember the entry for Exit, to be able to replace it with Close. */
exitfunc = tailfunc;
#ifdef ENABLE_BROWSER
add_to_funcs(do_exit, MBROWSER,
close_tag, WITHORSANS(exitbrowser_gist), TOGETHER, VIEW);
close_tag, WHENHELP(exitbrowser_gist), TOGETHER);
#endif
#ifndef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN|MREPLACE, "Refresh", "x", 0, VIEW);
add_to_funcs(full_refresh, MMAIN|MREPLACE, "Refresh", "x", 0);
#ifndef NANO_TINY
add_to_funcs(full_refresh, MINSERTFILE|MEXECUTE, "Refresh", "x", 0, VIEW);
add_to_funcs(full_refresh, MINSERTFILE|MEXECUTE, "Refresh", "x", 0);
#endif
add_to_funcs(flip_goto, MWHEREIS, "Go To Line", "x", 0, VIEW);
add_to_funcs(flip_goto, MGOTOLINE, "Go To Text", "x", 0, VIEW);
add_to_funcs(flip_goto, MWHEREIS, "Go To Line", "x", 0);
add_to_funcs(flip_goto, MGOTOLINE, "Go To Text", "x", 0);
#endif
add_to_funcs(do_writeout, MMAIN,
N_("Write Out"), WITHORSANS(writeout_gist), TOGETHER, NOVIEW);
N_("Write Out"), WHENHELP(writeout_gist), TOGETHER);
#ifdef ENABLE_JUSTIFY
/* In restricted mode, replace Insert with Justify, when possible;
@@ -735,358 +748,347 @@ void shortcut_init(void)
if (!ISSET(RESTRICTED))
#endif
add_to_funcs(do_insertfile, MMAIN,
N_("Read File"), WITHORSANS(readfile_gist), BLANKAFTER,
/* We allow inserting files in view mode if multibuffer mode
* is available, so that the user can view multiple files. */
CAN_OPEN_OTHER_BUFFER);
N_("Read File"), WHENHELP(readfile_gist), BLANKAFTER);
#ifdef ENABLE_JUSTIFY
else
add_to_funcs(do_justify, MMAIN,
N_("Justify"), WITHORSANS(justify_gist), BLANKAFTER, NOVIEW);
N_("Justify"), WHENHELP(justify_gist), BLANKAFTER);
#endif
#ifdef ENABLE_HELP
/* The description ("x") and blank_after (0) are irrelevant,
* because the help viewer does not have a help text. */
add_to_funcs(full_refresh, MHELP, N_("Refresh"), "x", 0, VIEW);
add_to_funcs(do_exit, MHELP, close_tag, "x", 0, VIEW);
add_to_funcs(full_refresh, MHELP, N_("Refresh"), "x", 0);
add_to_funcs(do_exit, MHELP, close_tag, "x", 0);
#endif
add_to_funcs(do_search_forward, MMAIN|MHELP,
N_("Where Is"), WITHORSANS(whereis_gist), TOGETHER, VIEW);
N_("Where Is"), WHENHELP(whereis_gist), TOGETHER);
add_to_funcs(do_replace, MMAIN,
N_("Replace"), WITHORSANS(replace_gist), TOGETHER, NOVIEW);
N_("Replace"), WHENHELP(replace_gist), TOGETHER);
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MHELP,
N_("Where Was"), WITHORSANS(wherewas_gist), TOGETHER, VIEW);
N_("Where Was"), WHENHELP(wherewas_gist), TOGETHER);
add_to_funcs(do_findprevious, MMAIN|MHELP,
N_("Previous"), WITHORSANS(findprev_gist), TOGETHER, VIEW);
N_("Previous"), WHENHELP(findprev_gist), TOGETHER);
add_to_funcs(do_findnext, MMAIN|MHELP,
N_("Next"), WITHORSANS(findnext_gist), BLANKAFTER, VIEW);
N_("Next"), WHENHELP(findnext_gist), BLANKAFTER);
#endif
add_to_funcs(cut_text, MMAIN,
N_("Cut"), WITHORSANS(cut_gist), TOGETHER, NOVIEW);
N_("Cut"), WHENHELP(cut_gist), TOGETHER);
add_to_funcs(paste_text, MMAIN,
N_("Paste"), WITHORSANS(paste_gist), BLANKAFTER, NOVIEW);
N_("Paste"), WHENHELP(paste_gist), BLANKAFTER);
if (!ISSET(RESTRICTED)) {
#ifndef NANO_TINY
add_to_funcs(do_execute, MMAIN,
N_("Execute"), WITHORSANS(execute_gist), TOGETHER, NOVIEW);
N_("Execute"), WHENHELP(execute_gist), TOGETHER);
#endif
#ifdef ENABLE_JUSTIFY
add_to_funcs(do_justify, MMAIN,
N_("Justify"), WITHORSANS(justify_gist), BLANKAFTER, NOVIEW);
N_("Justify"), WHENHELP(justify_gist), BLANKAFTER);
#endif
}
add_to_funcs(report_cursor_position, MMAIN,
/* TRANSLATORS: This refers to the position of the cursor. */
N_("Location"), WITHORSANS(cursorpos_gist), TOGETHER, VIEW);
/* TRANSLATORS: This refers to the position of the cursor. */
N_("Location"), WHENHELP(cursorpos_gist), TOGETHER);
#if defined(NANO_TINY) || defined(ENABLE_JUSTIFY)
/* Conditionally placing this one here or further on, to keep the
* help items nicely paired in most conditions. */
add_to_funcs(do_gotolinecolumn, MMAIN,
N_("Go To Line"), WITHORSANS(gotoline_gist), BLANKAFTER, VIEW);
N_("Go To Line"), WHENHELP(gotoline_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(do_undo, MMAIN,
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
N_("Undo"), WITHORSANS(undo_gist), TOGETHER, NOVIEW);
N_("Undo"), WHENHELP(undo_gist), TOGETHER);
add_to_funcs(do_redo, MMAIN,
N_("Redo"), WITHORSANS(redo_gist), BLANKAFTER, NOVIEW);
N_("Redo"), WHENHELP(redo_gist), BLANKAFTER);
add_to_funcs(do_mark, MMAIN,
N_("Set Mark"), WITHORSANS(mark_gist), TOGETHER, VIEW);
N_("Set Mark"), WHENHELP(mark_gist), TOGETHER);
add_to_funcs(copy_text, MMAIN,
N_("Copy"), WITHORSANS(copy_gist), BLANKAFTER, VIEW);
N_("Copy"), WHENHELP(copy_gist), BLANKAFTER);
#endif
add_to_funcs(case_sens_void, MWHEREIS|MREPLACE,
N_("Case Sens"), WITHORSANS(case_gist), TOGETHER, VIEW);
N_("Case Sens"), WHENHELP(case_gist), TOGETHER);
add_to_funcs(regexp_void, MWHEREIS|MREPLACE,
N_("Reg.exp."), WITHORSANS(regexp_gist), TOGETHER, VIEW);
N_("Reg.exp."), WHENHELP(regexp_gist), TOGETHER);
add_to_funcs(backwards_void, MWHEREIS|MREPLACE,
N_("Backwards"), WITHORSANS(reverse_gist), BLANKAFTER, VIEW);
N_("Backwards"), WHENHELP(reverse_gist), BLANKAFTER);
add_to_funcs(flip_replace, MWHEREIS,
N_("Replace"), WITHORSANS(replace_gist), BLANKAFTER, VIEW);
N_("Replace"), WHENHELP(replace_gist), BLANKAFTER);
add_to_funcs(flip_replace, MREPLACE,
N_("No Replace"), WITHORSANS(whereis_gist), BLANKAFTER, VIEW);
N_("No Replace"), WHENHELP(whereis_gist), BLANKAFTER);
#ifdef ENABLE_HISTORIES
add_to_funcs(get_older_item, MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE,
N_("Older"), WITHORSANS(older_gist), TOGETHER, VIEW);
N_("Older"), WHENHELP(older_gist), TOGETHER);
add_to_funcs(get_newer_item, MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE,
N_("Newer"), WITHORSANS(newer_gist), BLANKAFTER, VIEW);
#endif
#ifdef ENABLE_HELP
add_to_funcs(flip_goto, MWHEREIS,
N_("Go To Line"), WITHORSANS(gotoline_gist), BLANKAFTER, VIEW);
N_("Newer"), WHENHELP(newer_gist), BLANKAFTER);
#endif
#ifdef ENABLE_BROWSER
add_to_funcs(goto_dir, MBROWSER,
/* TRANSLATORS: Try to keep the next four strings at most 10 characters. */
N_("Go To Dir"), WITHORSANS(gotodir_gist), TOGETHER, VIEW);
/* TRANSLATORS: Try to keep the next four strings at most 10 characters. */
N_("Go To Dir"), WHENHELP(gotodir_gist), TOGETHER);
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MBROWSER,
N_("Refresh"), WITHORSANS(browserrefresh_gist), BLANKAFTER, VIEW);
N_("Refresh"), WHENHELP(browserrefresh_gist), BLANKAFTER);
#endif
add_to_funcs(do_search_forward, MBROWSER,
N_("Where Is"), WITHORSANS(browserwhereis_gist), TOGETHER, VIEW);
N_("Where Is"), WHENHELP(browserwhereis_gist), TOGETHER);
add_to_funcs(do_search_backward, MBROWSER,
N_("Where Was"), WITHORSANS(browserwherewas_gist), TOGETHER, VIEW);
N_("Where Was"), WHENHELP(browserwherewas_gist), TOGETHER);
add_to_funcs(do_findprevious, MBROWSER,
N_("Previous"), WITHORSANS(findprev_gist), TOGETHER, VIEW);
N_("Previous"), WHENHELP(findprev_gist), TOGETHER);
add_to_funcs(do_findnext, MBROWSER,
N_("Next"), WITHORSANS(findnext_gist), BLANKAFTER, VIEW);
N_("Next"), WHENHELP(findnext_gist), BLANKAFTER);
#endif
#ifdef NANO_TINY
add_to_funcs(to_prev_word, MMAIN,
"Prev Word", WITHORSANS(prevword_gist), TOGETHER, VIEW);
"Prev Word", WHENHELP(prevword_gist), TOGETHER);
add_to_funcs(to_next_word, MMAIN,
"Next Word", WITHORSANS(nextword_gist), BLANKAFTER, VIEW);
"Next Word", WHENHELP(nextword_gist), BLANKAFTER);
#else
add_to_funcs(do_find_bracket, MMAIN,
N_("To Bracket"), WITHORSANS(bracket_gist), BLANKAFTER, VIEW);
N_("To Bracket"), WHENHELP(bracket_gist), BLANKAFTER);
add_to_funcs(do_search_backward, MMAIN|MHELP,
/* TRANSLATORS: This starts a backward search. */
N_("Where Was"), WITHORSANS(wherewas_gist), TOGETHER, VIEW);
/* TRANSLATORS: This starts a backward search. */
N_("Where Was"), WHENHELP(wherewas_gist), TOGETHER);
add_to_funcs(do_findprevious, MMAIN|MHELP,
/* TRANSLATORS: This refers to searching the preceding occurrence. */
N_("Previous"), WITHORSANS(findprev_gist), TOGETHER, VIEW);
/* TRANSLATORS: This refers to searching the preceding occurrence. */
N_("Previous"), WHENHELP(findprev_gist), TOGETHER);
add_to_funcs(do_findnext, MMAIN|MHELP,
N_("Next"), WITHORSANS(findnext_gist), BLANKAFTER, VIEW);
N_("Next"), WHENHELP(findnext_gist), BLANKAFTER);
#endif
add_to_funcs(do_left, MMAIN,
/* TRANSLATORS: This means move the cursor one character back. */
N_("Back"), WITHORSANS(back_gist), TOGETHER, VIEW);
/* TRANSLATORS: This means move the cursor one character back. */
N_("Back"), WHENHELP(back_gist), TOGETHER);
add_to_funcs(do_right, MMAIN,
N_("Forward"), WITHORSANS(forward_gist), TOGETHER, VIEW);
N_("Forward"), WHENHELP(forward_gist), TOGETHER);
#ifdef ENABLE_BROWSER
add_to_funcs(do_left, MBROWSER,
N_("Back"), WITHORSANS(backfile_gist), TOGETHER, VIEW);
N_("Back"), WHENHELP(backfile_gist), TOGETHER);
add_to_funcs(do_right, MBROWSER,
N_("Forward"), WITHORSANS(forwardfile_gist), TOGETHER, VIEW);
N_("Forward"), WHENHELP(forwardfile_gist), TOGETHER);
#endif
#ifndef NANO_TINY
add_to_funcs(to_prev_word, MMAIN,
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
N_("Prev Word"), WITHORSANS(prevword_gist), TOGETHER, VIEW);
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
N_("Prev Word"), WHENHELP(prevword_gist), TOGETHER);
add_to_funcs(to_next_word, MMAIN,
N_("Next Word"), WITHORSANS(nextword_gist), TOGETHER, VIEW);
N_("Next Word"), WHENHELP(nextword_gist), TOGETHER);
#endif
add_to_funcs(do_home, MMAIN,
N_("Home"), WITHORSANS(home_gist), TOGETHER, VIEW);
N_("Home"), WHENHELP(home_gist), TOGETHER);
add_to_funcs(do_end, MMAIN,
N_("End"), WITHORSANS(end_gist), BLANKAFTER, VIEW);
N_("End"), WHENHELP(end_gist), BLANKAFTER);
add_to_funcs(do_up, MMAIN|MBROWSER|MHELP,
N_("Prev Line"), WITHORSANS(prevline_gist), TOGETHER, VIEW);
N_("Prev Line"), WHENHELP(prevline_gist), TOGETHER);
add_to_funcs(do_down, MMAIN|MBROWSER|MHELP,
N_("Next Line"), WITHORSANS(nextline_gist), TOGETHER, VIEW);
N_("Next Line"), WHENHELP(nextline_gist), TOGETHER);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
add_to_funcs(do_scroll_up, MMAIN,
N_("Scroll Up"), WITHORSANS(scrollup_gist), TOGETHER, VIEW);
N_("Scroll Up"), WHENHELP(scrollup_gist), TOGETHER);
add_to_funcs(do_scroll_down, MMAIN,
N_("Scroll Down"), WITHORSANS(scrolldown_gist), BLANKAFTER, VIEW);
N_("Scroll Down"), WHENHELP(scrolldown_gist), BLANKAFTER);
#endif
add_to_funcs(to_prev_block, MMAIN,
N_("Prev Block"), WITHORSANS(prevblock_gist), TOGETHER, VIEW);
N_("Prev Block"), WHENHELP(prevblock_gist), TOGETHER);
add_to_funcs(to_next_block, MMAIN,
N_("Next Block"), WITHORSANS(nextblock_gist), TOGETHER, VIEW);
N_("Next Block"), WHENHELP(nextblock_gist), TOGETHER);
#ifdef ENABLE_JUSTIFY
add_to_funcs(to_para_begin, MMAIN|MGOTOLINE,
/* TRANSLATORS: Try to keep these two strings at most 16 characters. */
N_("Begin of Paragr."), WITHORSANS(parabegin_gist), TOGETHER, VIEW);
/* TRANSLATORS: Try to keep these two strings at most 16 characters. */
N_("Begin of Paragr."), WHENHELP(parabegin_gist), TOGETHER);
add_to_funcs(to_para_end, MMAIN|MGOTOLINE,
N_("End of Paragraph"), WITHORSANS(paraend_gist), BLANKAFTER, VIEW);
N_("End of Paragraph"), WHENHELP(paraend_gist), BLANKAFTER);
#endif
add_to_funcs(do_page_up, MMAIN|MHELP,
/* TRANSLATORS: Try to keep the next six strings at most 12 characters. */
N_("Prev Page"), WITHORSANS(prevpage_gist), TOGETHER, VIEW);
/* TRANSLATORS: Try to keep the next six strings at most 12 characters. */
N_("Prev Page"), WHENHELP(prevpage_gist), TOGETHER);
add_to_funcs(do_page_down, MMAIN|MHELP,
N_("Next Page"), WITHORSANS(nextpage_gist), TOGETHER, VIEW);
N_("Next Page"), WHENHELP(nextpage_gist), TOGETHER);
add_to_funcs(to_first_line, MMAIN|MHELP|MGOTOLINE,
N_("First Line"), WITHORSANS(firstline_gist), TOGETHER, VIEW);
N_("First Line"), WHENHELP(firstline_gist), TOGETHER);
add_to_funcs(to_last_line, MMAIN|MHELP|MGOTOLINE,
N_("Last Line"), WITHORSANS(lastline_gist), BLANKAFTER, VIEW);
N_("Last Line"), WHENHELP(lastline_gist), BLANKAFTER);
#ifdef ENABLE_MULTIBUFFER
add_to_funcs(switch_to_prev_buffer, MMAIN,
N_("Prev File"), WITHORSANS(prevfile_gist), TOGETHER, VIEW);
N_("Prev File"), WHENHELP(prevfile_gist), TOGETHER);
add_to_funcs(switch_to_next_buffer, MMAIN,
N_("Next File"), WITHORSANS(nextfile_gist), BLANKAFTER, VIEW);
N_("Next File"), WHENHELP(nextfile_gist), BLANKAFTER);
#endif
#if !defined(NANO_TINY) && !defined(ENABLE_JUSTIFY)
add_to_funcs(do_gotolinecolumn, MMAIN,
N_("Go To Line"), WITHORSANS(gotoline_gist), BLANKAFTER, VIEW);
N_("Go To Line"), WHENHELP(gotoline_gist), BLANKAFTER);
#endif
add_to_funcs(do_tab, MMAIN,
/* TRANSLATORS: The next four strings are names of keyboard keys. */
N_("Tab"), WITHORSANS(tab_gist), TOGETHER, NOVIEW);
/* TRANSLATORS: The next four strings are names of keyboard keys. */
N_("Tab"), WHENHELP(tab_gist), TOGETHER);
add_to_funcs(do_enter, MMAIN,
N_("Enter"), WITHORSANS(enter_gist), BLANKAFTER, NOVIEW);
N_("Enter"), WHENHELP(enter_gist), BLANKAFTER);
add_to_funcs(do_backspace, MMAIN,
N_("Backspace"), WITHORSANS(backspace_gist), TOGETHER, NOVIEW);
N_("Backspace"), WHENHELP(backspace_gist), TOGETHER);
add_to_funcs(do_delete, MMAIN,
N_("Delete"), WITHORSANS(delete_gist),
#ifndef NANO_TINY
TOGETHER,
#else
BLANKAFTER,
#endif
NOVIEW);
N_("Delete"), WHENHELP(delete_gist), BLANKAFTER);
#ifndef NANO_TINY
add_to_funcs(chop_previous_word, MMAIN,
/* TRANSLATORS: The next two strings refer to deleting words. */
N_("Chop Left"), WITHORSANS(chopwordleft_gist), TOGETHER, NOVIEW);
/* TRANSLATORS: The next two strings refer to deleting words. */
N_("Chop Left"), WHENHELP(chopwordleft_gist), TOGETHER);
add_to_funcs(chop_next_word, MMAIN,
N_("Chop Right"), WITHORSANS(chopwordright_gist), TOGETHER, NOVIEW);
N_("Chop Right"), WHENHELP(chopwordright_gist), TOGETHER);
add_to_funcs(cut_till_eof, MMAIN,
N_("Cut Till End"), WITHORSANS(cuttilleof_gist), BLANKAFTER, NOVIEW);
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
#endif
#ifdef ENABLE_JUSTIFY
add_to_funcs(do_full_justify, MMAIN,
N_("Full Justify"), WITHORSANS(fulljustify_gist), TOGETHER, NOVIEW);
N_("Full Justify"), WHENHELP(fulljustify_gist), TOGETHER);
#endif
#ifndef NANO_TINY
add_to_funcs(count_lines_words_and_characters, MMAIN,
N_("Word Count"), WITHORSANS(wordcount_gist), TOGETHER, VIEW);
N_("Word Count"), WHENHELP(wordcount_gist), TOGETHER);
#endif
add_to_funcs(do_verbatim_input, MMAIN,
N_("Verbatim"), WITHORSANS(verbatim_gist), BLANKAFTER, NOVIEW);
N_("Verbatim"), WHENHELP(verbatim_gist), BLANKAFTER);
#ifndef NANO_TINY
add_to_funcs(do_suspend, MMAIN,
N_("Suspend"), WITHORSANS(suspend_gist), TOGETHER, VIEW);
#endif
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN,
N_("Refresh"), WITHORSANS(refresh_gist), BLANKAFTER, VIEW);
#endif
#ifndef NANO_TINY
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
#else
add_to_funcs(do_indent, MMAIN,
N_("Indent"), WITHORSANS(indent_gist), TOGETHER, NOVIEW);
N_("Indent"), WHENHELP(indent_gist), TOGETHER);
add_to_funcs(do_unindent, MMAIN,
N_("Unindent"), WITHORSANS(unindent_gist), BLANKAFTER, NOVIEW);
N_("Unindent"), WHENHELP(unindent_gist), BLANKAFTER);
#endif
#ifdef ENABLE_COMMENT
add_to_funcs(do_comment, MMAIN,
N_("Comment Lines"), WITHORSANS(comment_gist), TOGETHER, NOVIEW);
N_("Comment Lines"), WHENHELP(comment_gist), TOGETHER);
#endif
#ifdef ENABLE_WORDCOMPLETION
add_to_funcs(complete_a_word, MMAIN,
N_("Complete"), WITHORSANS(completion_gist), BLANKAFTER, NOVIEW);
N_("Complete"), WHENHELP(completion_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(record_macro, MMAIN,
N_("Record"), WITHORSANS(recordmacro_gist), TOGETHER, VIEW);
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
add_to_funcs(run_macro, MMAIN,
N_("Run Macro"), WITHORSANS(runmacro_gist), BLANKAFTER, VIEW);
add_to_funcs(put_or_lift_anchor, MMAIN,
N_("Anchor"), WITHORSANS(anchor_gist), TOGETHER, VIEW);
add_to_funcs(to_prev_anchor, MMAIN,
N_("Up to anchor"), WITHORSANS(prevanchor_gist), TOGETHER, VIEW);
add_to_funcs(to_next_anchor, MMAIN,
N_("Down to anchor"), WITHORSANS(nextanchor_gist), BLANKAFTER, VIEW);
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
add_to_funcs(zap_text, MMAIN,
/* TRANSLATORS: This refers to deleting a line or marked region. */
N_("Zap"), WITHORSANS(zap_gist), BLANKAFTER, NOVIEW);
/* TRANSLATORS: This refers to deleting a line or marked region. */
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
add_to_funcs(put_or_lift_anchor, MMAIN,
N_("Anchor"), WHENHELP(anchor_gist), TOGETHER);
add_to_funcs(to_prev_anchor, MMAIN,
N_("Up to anchor"), WHENHELP(prevanchor_gist), TOGETHER);
add_to_funcs(to_next_anchor, MMAIN,
N_("Down to anchor"), WHENHELP(nextanchor_gist), BLANKAFTER);
if (!ISSET(RESTRICTED)) {
#ifdef ENABLE_SPELLER
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WITHORSANS(spell_gist), TOGETHER, NOVIEW);
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif
#ifdef ENABLE_COLOR
add_to_funcs(do_linter, MMAIN,
N_("Linter"), WITHORSANS(lint_gist), TOGETHER, NOVIEW);
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WITHORSANS(formatter_gist), BLANKAFTER, NOVIEW);
#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
/* Although not allowed in restricted mode, keep execution rebindable. */
if (ISSET(RESTRICTED))
add_to_funcs(do_execute, MMAIN,
N_("Execute"), WHENHELP(execute_gist), TOGETHER);
add_to_funcs(do_suspend, MMAIN,
N_("Suspend"), WHENHELP(suspend_gist), TOGETHER);
#endif /* !NANO_TINY */
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WITHORSANS(wherewas_gist), BLANKAFTER, VIEW);
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN,
N_("Refresh"), WHENHELP(refresh_gist), TOGETHER);
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
add_to_funcs(do_center, MMAIN,
N_("Center"), WITHORSANS(center_gist), BLANKAFTER, VIEW);
N_("Center"), WHENHELP(center_gist), BLANKAFTER);
#endif
add_to_funcs(do_savefile, MMAIN,
N_("Save"), WITHORSANS(savefile_gist), BLANKAFTER, NOVIEW);
N_("Save"), WHENHELP(savefile_gist), BLANKAFTER);
#ifdef ENABLE_MULTIBUFFER
/* Multiple buffers are only available when not in restricted mode. */
if (!ISSET(RESTRICTED))
/* Include the new-buffer toggle only when it can actually be used. */
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
add_to_funcs(flip_newbuffer, MINSERTFILE|MEXECUTE,
N_("New Buffer"), WITHORSANS(newbuffer_gist), TOGETHER, NOVIEW);
N_("New Buffer"), WHENHELP(newbuffer_gist), TOGETHER);
#endif
#ifndef NANO_TINY
add_to_funcs(flip_pipe, MEXECUTE,
N_("Pipe Text"), WITHORSANS(pipe_gist), BLANKAFTER, NOVIEW);
N_("Pipe Text"), WHENHELP(pipe_gist), BLANKAFTER);
#endif
#ifdef ENABLE_SPELLER
add_to_funcs(do_spell, MEXECUTE,
N_("Spell Check"), WITHORSANS(spell_gist), TOGETHER, NOVIEW);
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif
#ifdef ENABLE_COLOR
#ifdef ENABLE_LINTER
add_to_funcs(do_linter, MEXECUTE,
N_("Linter"), WITHORSANS(lint_gist), BLANKAFTER, NOVIEW);
N_("Linter"), WHENHELP(lint_gist), BLANKAFTER);
#endif
#ifdef ENABLE_JUSTIFY
add_to_funcs(do_full_justify, MEXECUTE,
N_("Full Justify"), WITHORSANS(fulljustify_gist), TOGETHER, NOVIEW);
N_("Full Justify"), WHENHELP(fulljustify_gist), TOGETHER);
#endif
#ifdef ENABLE_COLOR
#ifdef ENABLE_FORMATTER
add_to_funcs(do_formatter, MEXECUTE,
N_("Formatter"), WITHORSANS(formatter_gist), BLANKAFTER, NOVIEW);
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
#endif
#ifdef ENABLE_HELP
add_to_funcs(flip_goto, MWHEREIS,
N_("Go To Line"), WHENHELP(gotoline_gist), BLANKAFTER);
add_to_funcs(flip_goto, MGOTOLINE,
N_("Go To Text"), WITHORSANS(whereis_gist), BLANKAFTER, VIEW);
N_("Go To Text"), WHENHELP(whereis_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(dos_format, MWRITEFILE,
N_("DOS Format"), WITHORSANS(dos_gist), TOGETHER, NOVIEW);
N_("DOS Format"), WHENHELP(dos_gist), TOGETHER);
add_to_funcs(mac_format, MWRITEFILE,
N_("Mac Format"), WITHORSANS(mac_gist), TOGETHER, NOVIEW);
N_("Mac Format"), WHENHELP(mac_gist), TOGETHER);
/* If we're using restricted mode, the Append, Prepend, and Backup toggles
* are disabled. The first and second are not useful as they only allow
@@ -1094,68 +1096,67 @@ void shortcut_init(void)
* would write to a file not specified on the command line. */
if (!ISSET(RESTRICTED)) {
add_to_funcs(append_it, MWRITEFILE,
N_("Append"), WITHORSANS(append_gist), TOGETHER, NOVIEW);
N_("Append"), WHENHELP(append_gist), TOGETHER);
add_to_funcs(prepend_it, MWRITEFILE,
N_("Prepend"), WITHORSANS(prepend_gist), TOGETHER, NOVIEW);
N_("Prepend"), WHENHELP(prepend_gist), TOGETHER);
add_to_funcs(back_it_up, MWRITEFILE,
N_("Backup File"), WITHORSANS(backup_gist), BLANKAFTER, NOVIEW);
N_("Backup File"), WHENHELP(backup_gist), BLANKAFTER);
}
add_to_funcs(flip_convert, MINSERTFILE,
N_("No Conversion"), WITHORSANS(convert_gist), BLANKAFTER, NOVIEW);
N_("No Conversion"), WHENHELP(convert_gist), BLANKAFTER);
/* Command execution is only available when not in restricted mode. */
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
add_to_funcs(flip_execute, MINSERTFILE,
N_("Execute Command"), WITHORSANS(execute_gist), BLANKAFTER, NOVIEW);
N_("Execute Command"), WHENHELP(execute_gist), BLANKAFTER);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WITHORSANS(cuttilleof_gist), BLANKAFTER, NOVIEW);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
add_to_funcs(do_suspend, MEXECUTE,
N_("Suspend"), WITHORSANS(suspend_gist), BLANKAFTER, VIEW);
}
add_to_funcs(do_suspend, MEXECUTE,
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
#endif /* !NANO_TINY */
#ifdef ENABLE_BROWSER
/* The file browser is only available when not in restricted mode. */
if (!ISSET(RESTRICTED))
add_to_funcs(to_files, MWRITEFILE|MINSERTFILE,
/* TRANSLATORS: This invokes the file browser. */
N_("Browse"), WITHORSANS(tofiles_gist), BLANKAFTER, VIEW);
/* TRANSLATORS: This invokes the file browser. */
N_("Browse"), WHENHELP(tofiles_gist), BLANKAFTER);
add_to_funcs(do_page_up, MBROWSER,
N_("Prev Page"), WITHORSANS(prevpage_gist), TOGETHER, VIEW);
N_("Prev Page"), WHENHELP(prevpage_gist), TOGETHER);
add_to_funcs(do_page_down, MBROWSER,
N_("Next Page"), WITHORSANS(nextpage_gist), TOGETHER, VIEW);
N_("Next Page"), WHENHELP(nextpage_gist), TOGETHER);
add_to_funcs(to_first_file, MBROWSER|MWHEREISFILE,
N_("First File"), WITHORSANS(firstfile_gist), TOGETHER, VIEW);
N_("First File"), WHENHELP(firstfile_gist), TOGETHER);
add_to_funcs(to_last_file, MBROWSER|MWHEREISFILE,
N_("Last File"), WITHORSANS(lastfile_gist), BLANKAFTER, VIEW);
N_("Last File"), WHENHELP(lastfile_gist), BLANKAFTER);
#ifndef NANO_TINY
add_to_funcs(to_prev_word, MBROWSER,
N_("Left Column"), WITHORSANS(browserlefthand_gist), TOGETHER, VIEW);
N_("Left Column"), WHENHELP(browserlefthand_gist), TOGETHER);
add_to_funcs(to_next_word, MBROWSER,
N_("Right Column"), WITHORSANS(browserrighthand_gist), TOGETHER, VIEW);
N_("Right Column"), WHENHELP(browserrighthand_gist), TOGETHER);
add_to_funcs(to_prev_block, MBROWSER,
N_("Top Row"), WITHORSANS(browsertoprow_gist), TOGETHER, VIEW);
N_("Top Row"), WHENHELP(browsertoprow_gist), TOGETHER);
add_to_funcs(to_next_block, MBROWSER,
N_("Bottom Row"), WITHORSANS(browserbottomrow_gist), BLANKAFTER, VIEW);
N_("Bottom Row"), WHENHELP(browserbottomrow_gist), BLANKAFTER);
#endif
#endif /* ENABLE_BROWSER */
add_to_funcs(discard_buffer, MWRITEFILE,
N_("Discard buffer"), WITHORSANS(discardbuffer_gist), BLANKAFTER, NOVIEW);
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"), WITHORSANS(prevlint_gist), TOGETHER, VIEW);
/* TRANSLATORS: The next two strings may be up to 37 characters each. */
N_("Previous Linter message"), WHENHELP(prevlint_gist), TOGETHER);
add_to_funcs(do_page_down, MLINTER,
N_("Next Linter message"), WITHORSANS(nextlint_gist), TOGETHER, VIEW);
N_("Next Linter message"), WHENHELP(nextlint_gist), TOGETHER);
#endif
#ifdef __linux__
@@ -1189,25 +1190,26 @@ void shortcut_init(void)
add_to_sclist(MMOST, "^K", 0, cut_text, 0);
#ifdef NANO_TINY
add_to_sclist(MMAIN, "^U", 0, paste_text, 0);
#ifdef ENABLE_SPELLER
add_to_sclist(MMAIN, "^T", 0, do_spell, 0);
#endif
#else
add_to_sclist(MMOST, "^U", 0, paste_text, 0);
add_to_sclist(MMAIN, "^T", 0, do_execute, 0);
#ifdef ENABLE_SPELLER
if (!ISSET(PRESERVE))
add_to_sclist(MEXECUTE, "^S", 0, do_spell, 0);
add_to_sclist(MEXECUTE, "^T", 0, do_spell, 0);
#endif
#endif
#ifdef ENABLE_JUSTIFY
add_to_sclist(MMAIN, "^J", '\n', do_justify, 0);
#endif
#ifdef ENABLE_SPELLER
#ifndef NANO_TINY
if (!ISSET(PRESERVE))
add_to_sclist(MEXECUTE, "^S", 0, do_spell, 0);
add_to_sclist(MEXECUTE, "^T", 0, do_spell, 0);
#else
add_to_sclist(MMAIN, "^T", 0, do_spell, 0);
#endif
#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
@@ -1274,7 +1276,7 @@ void shortcut_init(void)
add_to_sclist(MMOST|MBROWSER|MHELP, "\xE2\x96\xb8", KEY_RIGHT, do_right, 0);
add_to_sclist(MSOME, "^\xE2\x97\x82", CONTROL_LEFT, to_prev_word, 0);
add_to_sclist(MSOME, "^\xE2\x96\xb8", CONTROL_RIGHT, to_next_word, 0);
#if !defined(NANO_TINY) && defined(ENABLE_MULTIBUFFER)
#if defined(ENABLE_MULTIBUFFER) && !defined(NANO_TINY)
if (!on_a_vt) {
add_to_sclist(MMAIN, "M-\xE2\x97\x82", ALT_LEFT, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-\xE2\x96\xb8", ALT_RIGHT, switch_to_next_buffer, 0);
@@ -1287,7 +1289,7 @@ void shortcut_init(void)
add_to_sclist(MMOST|MBROWSER|MHELP, "Right", KEY_RIGHT, do_right, 0);
add_to_sclist(MSOME, "^Left", CONTROL_LEFT, to_prev_word, 0);
add_to_sclist(MSOME, "^Right", CONTROL_RIGHT, to_next_word, 0);
#ifdef ENABLE_MULTIBUFFER
#if defined(ENABLE_MULTIBUFFER) && !defined(NANO_TINY)
if (!on_a_vt) {
add_to_sclist(MMAIN, "M-Left", ALT_LEFT, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-Right", ALT_RIGHT, switch_to_next_buffer, 0);
@@ -1343,10 +1345,10 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
#endif
#ifdef ENABLE_MULTIBUFFER
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
#endif
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
#ifndef NANO_TINY
@@ -1406,6 +1408,7 @@ void shortcut_init(void)
add_to_sclist(MWHEREIS|MREPLACE, "M-B", 0, backwards_void, 0);
add_to_sclist(MWHEREIS|MREPLACE, "^R", 0, flip_replace, 0);
add_to_sclist(MWHEREIS|MGOTOLINE, "^T", 0, flip_goto, 0);
add_to_sclist(MWHEREIS|MGOTOLINE, SLASH_OR_DASH, 0, flip_goto, 0);
#ifdef ENABLE_HISTORIES
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "^P", 0, get_older_item, 0);
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "^N", 0, get_newer_item, 0);
@@ -1456,32 +1459,29 @@ void shortcut_init(void)
add_to_sclist(MINSERTFILE, "M-N", 0, flip_convert, 0);
#endif
#ifdef ENABLE_MULTIBUFFER
/* Only when not in restricted mode, allow multiple buffers. */
if (!ISSET(RESTRICTED)) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
add_to_sclist(MINSERTFILE|MEXECUTE, "M-F", 0, flip_newbuffer, 0);
#ifndef NANO_TINY
add_to_sclist(MEXECUTE, "M-\\", 0, flip_pipe, 0);
#endif
}
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
#ifdef ENABLE_BROWSER
/* Only when not in restricted mode, allow entering the file browser. */
if (!ISSET(RESTRICTED))
add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", 0, to_files, 0);
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
/* Allow exiting from the file browser and the help viewer with
* the same key as they were entered. */
#ifdef ENABLE_BROWSER
/* Allow exiting the file browser with the same key as used for entry. */
add_to_sclist(MBROWSER, "^T", 0, do_exit, 0);
#endif
#ifdef ENABLE_HELP
/* Allow exiting the help viewer with the same keys as used for entry. */
add_to_sclist(MHELP, "^G", 0, do_exit, 0);
add_to_sclist(MHELP, "F1", KEY_F(1), do_exit, 0);
add_to_sclist(MHELP, "Home", KEY_HOME, to_first_line, 0);
add_to_sclist(MHELP, "End", KEY_END, to_last_line, 0);
#endif
#ifdef ENABLE_COLOR
#ifdef ENABLE_LINTER
add_to_sclist(MLINTER, "^X", 0, do_cancel, 0);
#endif
add_to_sclist(MMOST & ~MFINDINHELP, "F1", KEY_F(1), do_help, 0);

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* help.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2000-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2000-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2017 Rishabh Dave *
* Copyright (C) 2014-2019 Benno Schulenberg *
* *
@@ -50,7 +50,7 @@ void help_init(void)
char *ptr;
/* First, set up the initial help text for the current function. */
if (currmenu & (MWHEREIS|MREPLACE|MREPLACEWITH)) {
if (currmenu & (MWHEREIS|MREPLACE)) {
htx[0] = N_("Search Command Help Text\n\n "
"Enter the words or characters you would like to "
"search for, and then press Enter. If there is a "
@@ -65,6 +65,13 @@ void help_init(void)
"will be replaced.\n\n The following function keys are "
"available in Search mode:\n\n");
htx[2] = NULL;
} else if (currmenu == MREPLACEWITH) {
htx[0] = N_("=== Replacement ===\n\n "
"Type the characters that should replace the characters that "
"you typed at the previous prompt, and press Enter.\n\n");
htx[1] = N_(" The following function keys "
"are available at this prompt:\n\n");
htx[2] = NULL;
} else if (currmenu == MGOTOLINE) {
htx[0] = N_("Go To Line Help Text\n\n "
"Enter the line number that you wish to go to and hit "
@@ -126,8 +133,8 @@ void help_init(void)
"shown in brackets after the search prompt. Hitting "
"Enter without entering any text will perform the "
"previous search.\n\n");
htx[1] = N_(" The following function keys are available in "
"Browser Search mode:\n\n");
htx[1] = N_(" The following function keys "
"are available at this prompt:\n\n");
htx[2] = NULL;
} else if (currmenu == MGOTODIR) {
htx[0] = N_("Browser Go To Directory Help Text\n\n "
@@ -167,8 +174,8 @@ void help_init(void)
htx[1] = N_("If you just need another blank buffer, do not enter any "
"command.\n\n You can also pick one of four tools, or cut a "
"large piece of the buffer, or put the editor to sleep.\n\n");
htx[2] = N_(" The following function keys are "
"available in Execute Command mode:\n\n");
htx[2] = N_(" The following function keys "
"are available at this prompt:\n\n");
} else if (currmenu == MLINTER) {
htx[0] = N_("=== Linter ===\n\n "
"In this mode, the status bar shows an error message or "
@@ -224,7 +231,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 +289,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");
@@ -317,10 +324,10 @@ void help_init(void)
/* Hard-wrap the concatenated help text, and write it into a new buffer. */
void wrap_help_text_into_buffer(void)
{
size_t sum = 0;
/* Avoid overtight and overwide paragraphs in the introductory text. */
size_t wrapping_point = ((COLS < 40) ? 40 : (COLS > 74) ? 74 : COLS) - thebar;
const char *ptr = start_of_body;
size_t sum = 0;
make_new_buffer();
@@ -389,7 +396,7 @@ void wrap_help_text_into_buffer(void)
void show_help(void)
{
int kbinput = ERR;
functionptrtype func;
functionptrtype function;
/* The function of the key the user typed in. */
int oldmenu = currmenu;
/* The menu we were called from. */
@@ -475,28 +482,28 @@ void show_help(void)
continue;
}
#endif
func = interpret(&kbinput);
function = interpret(kbinput);
if (func == full_refresh) {
if (function == full_refresh) {
full_refresh();
} else if (ISSET(SHOW_CURSOR) && (func == do_left || func == do_right ||
func == do_up || func == do_down)) {
func();
} else if (func == do_up || func == do_scroll_up) {
} else if (ISSET(SHOW_CURSOR) && (function == do_left || function == do_right ||
function == do_up || function == do_down)) {
function();
} else if (function == do_up || function == do_scroll_up) {
do_scroll_up();
} else if (func == do_down || func == do_scroll_down) {
} else if (function == do_down || function == do_scroll_down) {
if (openfile->edittop->lineno + editwinrows - 1 < openfile->filebot->lineno)
do_scroll_down();
} else if (func == do_page_up || func == do_page_down ||
func == to_first_line || func == to_last_line) {
func();
} else if (func == do_search_backward || func == do_search_forward ||
func == do_findprevious || func == do_findnext) {
func();
} else if (function == do_page_up || function == do_page_down ||
function == to_first_line || function == to_last_line) {
function();
} else if (function == do_search_backward || function == do_search_forward ||
function == do_findprevious || function == do_findnext) {
function();
bottombars(MHELP);
#ifdef ENABLE_NANORC
} else if (func == (functionptrtype)implant) {
implant(first_sc_for(MHELP, func)->expansion);
} else if (function == (functionptrtype)implant) {
implant(first_sc_for(MHELP, function)->expansion);
#endif
#ifdef ENABLE_MOUSE
} else if (kbinput == KEY_MOUSE) {
@@ -507,7 +514,7 @@ void show_help(void)
} else if (kbinput == KEY_WINCH) {
; /* Nothing to do. */
#endif
} else if (func == do_exit) {
} else if (function == do_exit) {
break;
} else
unbound_key(kbinput);

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* history.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2003-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2003-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -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

@@ -1,7 +1,7 @@
/**************************************************************************
* move.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2018 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -44,6 +44,9 @@ void to_last_line(void)
openfile->current_y = editwinrows - 1;
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
recook |= perturbed;
#endif
focusing = FALSE;
}
@@ -95,8 +98,8 @@ size_t proper_x(linestruct *line, size_t *leftedge, bool forward,
* the middle of a tab that crosses a row boundary. */
void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
{
bool shifted = FALSE;
size_t was_edge = *leftedge;
bool shifted = FALSE;
openfile->current_x = proper_x(openfile->current, leftedge, forward,
actual_last_column(*leftedge, target), &shifted);
@@ -222,6 +225,9 @@ void to_para_end(void)
openfile->current_x = strlen(openfile->current->data);
edit_redraw(was_current, CENTERING);
#ifdef ENABLE_COLOR
recook |= perturbed;
#endif
}
#endif /* ENABLE_JUSTIFY */
@@ -263,6 +269,9 @@ void to_next_block(void)
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
#ifdef ENABLE_COLOR
recook |= perturbed;
#endif
}
/* Move to the previous word. */
@@ -401,12 +410,12 @@ void do_home(void)
bool moved_off_chunk = TRUE;
#ifndef NANO_TINY
bool moved = FALSE;
size_t leftedge = 0, leftedge_x = 0;
size_t leftedge = 0;
size_t left_x = 0;
if (ISSET(SOFTWRAP)) {
leftedge = leftedge_for(was_column, openfile->current);
leftedge_x = proper_x(openfile->current, &leftedge, FALSE, leftedge,
NULL);
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
}
if (ISSET(SMART_HOME)) {
@@ -419,7 +428,7 @@ void do_home(void)
if (openfile->current_x == indent_x) {
openfile->current_x = 0;
moved = TRUE;
} else if (!ISSET(SOFTWRAP) || leftedge_x <= indent_x) {
} else if (left_x <= indent_x) {
openfile->current_x = indent_x;
moved = TRUE;
}
@@ -429,10 +438,10 @@ void do_home(void)
if (!moved && ISSET(SOFTWRAP)) {
/* If already at the left edge of the screen, move fully home.
* Otherwise, move to the left edge. */
if (openfile->current_x == leftedge_x)
if (openfile->current_x == left_x)
openfile->current_x = 0;
else {
openfile->current_x = leftedge_x;
openfile->current_x = left_x;
openfile->placewewant = leftedge;
moved_off_chunk = FALSE;
}
@@ -463,11 +472,12 @@ void do_end(void)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool kickoff = TRUE;
bool last_chunk = FALSE;
size_t leftedge = leftedge_for(was_column, openfile->current);
size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
leftedge, &last_chunk);
size_t rightedge_x;
leftedge, &kickoff, &last_chunk);
size_t right_x;
/* If we're on the last chunk, we're already at the end of the line.
* Otherwise, we're one column past the end of the line. Shifting
@@ -476,14 +486,14 @@ void do_end(void)
if (!last_chunk)
rightedge--;
rightedge_x = actual_x(openfile->current->data, rightedge);
right_x = actual_x(openfile->current->data, rightedge);
/* If already at the right edge of the screen, move fully to
* the end of the line. Otherwise, move to the right edge. */
if (openfile->current_x == rightedge_x)
if (openfile->current_x == right_x)
openfile->current_x = line_len;
else {
openfile->current_x = rightedge_x;
openfile->current_x = right_x;
openfile->placewewant = rightedge;
moved_off_chunk = FALSE;
}

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* nano.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2014-2021 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -26,7 +26,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#if defined(__linux__) || !defined(NANO_TINY)
#ifdef __linux__
#include <sys/ioctl.h>
#endif
#ifdef ENABLE_UTF8
@@ -303,7 +303,7 @@ void do_exit(void)
/* When unmodified, simply close. Else, when doing automatic saving
* and the file has a name, simply save. Otherwise, ask the user. */
if (!openfile->modified)
if (!openfile->modified || ISSET(VIEW_MODE))
choice = NO;
else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
choice = YES;
@@ -339,7 +339,7 @@ void emergency_save(const char *filename)
fprintf(stderr, _("\nToo many .save files\n"));
else if (write_file(targetname, NULL, SPECIAL, OVERWRITE, NONOTES)) {
fprintf(stderr, _("\nBuffer written to %s\n"), targetname);
#ifndef NANO_TINY
#if !defined(NANO_TINY) && defined(HAVE_CHMOD) && defined(HAVE_CHOWN)
/* Try to chmod/chown the saved file to the values of the original file,
* but ignore any failure as we are in a hurry to get out. */
if (openfile->statinfo) {
@@ -358,9 +358,9 @@ void emergency_save(const char *filename)
* that were modified. */
void die(const char *msg, ...)
{
va_list ap;
openfilestruct *firstone = openfile;
static int stabs = 0;
va_list ap;
/* When dying for a second time, just give up. */
if (++stabs > 1)
@@ -423,10 +423,9 @@ void window_init(void)
int toprows = ((ISSET(EMPTY_LINE) && LINES > 6) ? 2 : 1);
int bottomrows = ((ISSET(NO_HELP) || LINES < 6) ? 1 : 3);
#ifndef NANO_TINY
if (ISSET(MINIBAR) || ISSET(ZERO))
toprows = 0;
#endif
editwinrows = LINES - toprows - bottomrows + (ISSET(ZERO) ? 1 : 0);
/* Set up the normal three subwindows. */
@@ -480,7 +479,7 @@ void mouse_init(void)
#endif /* ENABLE_MOUSE */
/* Print the usage line for the given option to the screen. */
void print_opt(const char *shortflag, const char *longflag, const char *desc)
void print_opt(const char *shortflag, const char *longflag, const char *description)
{
int firstwidth = breadth(shortflag);
int secondwidth = breadth(longflag);
@@ -493,7 +492,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. */
@@ -651,13 +650,15 @@ void usage(void)
print_opt("-x", "--nohelp", N_("Don't show the two help lines"));
#ifndef NANO_TINY
print_opt("-y", "--afterends", N_("Make Ctrl+Right stop at word ends"));
print_opt("-%", "--stateflags", N_("Show some states on the title bar"));
print_opt("-_", "--minibar", N_("Show a feedback bar at the bottom"));
print_opt("-0", "--zero", N_("Hide all bars, use whole terminal"));
#endif
#ifdef HAVE_LIBMAGIC
print_opt("-!", "--magic", N_("Also try magic to determine syntax"));
#endif
#ifndef NANO_TINY
print_opt("-%", "--stateflags", N_("Show some states on the title bar"));
print_opt("-_", "--minibar", N_("Show a feedback bar at the bottom"));
print_opt("-0", "--zero", N_("Hide all bars, use whole terminal"));
#endif
}
/* Display the version number of this nano, a copyright notice, some contact
@@ -670,8 +671,8 @@ void version(void)
printf(_(" GNU nano, version %s\n"), VERSION);
#endif
#ifndef NANO_TINY
printf(" (C) 1999-2011, 2013-2022 Free Software Foundation, Inc.\n");
printf(_(" (C) 2014-%s the contributors to nano\n"), "2022");
/* TRANSLATORS: The %s is the year of the latest release. */
printf(_(" (C) %s the Free Software Foundation and various contributors\n"), "2023");
#endif
printf(_(" Compiled options:"));
@@ -686,6 +687,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
@@ -701,6 +705,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
@@ -735,6 +742,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
@@ -750,6 +760,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
@@ -894,10 +907,11 @@ void signal_init(void)
sigaction(SIGTERM, &deed, NULL);
#ifndef NANO_TINY
#ifdef SIGWINCH
/* Trap SIGWINCH because we want to handle window resizes. */
deed.sa_handler = handle_sigwinch;
sigaction(SIGWINCH, &deed, NULL);
#endif
#ifdef SIGTSTP
/* Prevent the suspend handler from getting interrupted. */
sigfillset(&deed.sa_mask);
@@ -998,11 +1012,13 @@ void continue_nano(int signal)
/* Block or unblock the SIGWINCH signal, depending on the blockit parameter. */
void block_sigwinch(bool blockit)
{
#ifdef SIGWINCH
sigset_t winch;
sigemptyset(&winch);
sigaddset(&winch, SIGWINCH);
sigprocmask(blockit ? SIG_BLOCK : SIG_UNBLOCK, &winch, NULL);
#endif
#ifndef NANO_TINY
if (the_window_resized)
@@ -1091,7 +1107,7 @@ void toggle_this(int flag)
refresh_needed = TRUE;
break;
case TABS_TO_SPACES:
if (openfile->syntax && openfile->syntax->tab) {
if (openfile->syntax && openfile->syntax->tabstring) {
statusline(AHEM, _("Current syntax determines Tab"));
TOGGLE(flag);
return;
@@ -1264,6 +1280,12 @@ void unbound_key(int code)
/* TRANSLATORS: This refers to a sequence of escape codes
* (from the keyboard) that nano does not recognize. */
statusline(AHEM, _("Unknown sequence"));
#ifdef ENABLE_NANORC
else if (code == NO_SUCH_FUNCTION)
statusline(AHEM, _("Unknown function: %s"), commandname);
else if (code == MISSING_BRACE)
statusline(AHEM, _("Missing }"));
#endif
#ifndef NANO_TINY
else if (code > KEY_F0 && code < KEY_F0 + 25)
/* TRANSLATORS: This refers to an unbound function key. */
@@ -1279,17 +1301,17 @@ void unbound_key(int code)
#endif
#ifdef ENABLE_NANORC
if (shifted_metas && 'A' <= code && code <= 'Z')
statusline(AHEM, _("Unbound key: Sh-M-%c"), code);
statusline(AHEM, _("Unbound key: %s%c"), "Sh-M-", code);
else
#endif
statusline(AHEM, _("Unbound key: M-%c"), toupper(code));
statusline(AHEM, _("Unbound key: %s%c"), "M-", toupper(code));
} else if (code == ESC_CODE)
statusline(AHEM, _("Unbindable key: ^["));
else if (code < 0x20)
statusline(AHEM, _("Unbound key: ^%c"), code + 0x40);
statusline(AHEM, _("Unbound key: %s%c"), "^", code + 0x40);
#if defined(ENABLE_BROWSER) || defined (ENABLE_HELP)
else
statusline(AHEM, _("Unbound key: %c"), code);
statusline(AHEM, _("Unbound key: %s%c"), "", code);
#endif
set_blankdelay_to_one();
}
@@ -1353,7 +1375,7 @@ int do_mouse(void)
/* Return TRUE when the given function is a cursor-moving command. */
bool wanted_to_move(void (*func)(void))
{
return func == do_left || func == do_right ||
return (func == do_left || func == do_right ||
func == do_up || func == do_down ||
func == do_home || func == do_end ||
func == to_prev_word || func == to_next_word ||
@@ -1362,19 +1384,35 @@ bool wanted_to_move(void (*func)(void))
#endif
func == to_prev_block || func == to_next_block ||
func == do_page_up || func == do_page_down ||
func == to_first_line || func == to_last_line;
func == to_first_line || func == to_last_line);
}
/* Return TRUE when the given shortcut is admissible in view mode. */
bool okay_for_view(const keystruct *shortcut)
/* Return TRUE when the given function makes a change -- no good for view mode. */
bool changes_something(functionptrtype f)
{
funcstruct *item = allfuncs;
/* Search the function of the given shortcut in the list of functions. */
while (item != NULL && item->func != shortcut->func)
item = item->next;
return (item == NULL || item->viewok);
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 ||
f == do_indent || f == do_unindent ||
#endif
#ifdef ENABLE_JUSTIFY
f == do_justify || f == do_full_justify ||
#endif
#ifdef ENABLE_COMMENT
f == do_comment ||
#endif
#ifdef ENABLE_SPELLER
f == do_spell ||
#endif
#ifdef ENABLE_FORMATTER
f == do_formatter ||
#endif
#ifdef ENABLE_WORDCOMPLETION
f == complete_a_word ||
#endif
f == do_replace || f == do_verbatim_input);
}
#ifndef NANO_TINY
@@ -1405,7 +1443,10 @@ void suck_up_input_and_paste_it(void)
beep();
}
paste_text();
if (ISSET(VIEW_MODE))
print_view_warning();
else
paste_text();
free_lines(cutbuffer);
cutbuffer = was_cutbuffer;
@@ -1512,6 +1553,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
@@ -1519,6 +1562,7 @@ void process_a_keystroke(void)
#endif
static bool give_a_hint = TRUE;
const keystruct *shortcut;
functionptrtype function;
/* Read in a keystroke, and show the cursor while waiting. */
input = get_kbinput(midwin, VISIBLE);
@@ -1541,10 +1585,11 @@ void process_a_keystroke(void)
#endif
/* Check for a shortcut in the main list. */
shortcut = get_shortcut(&input);
shortcut = get_shortcut(input);
function = (shortcut ? shortcut->func : NULL);
/* If not a command, discard anything that is not a normal character byte. */
if (shortcut == NULL) {
if (!function) {
if (input < 0x20 || input > 0xFF || meta_key)
unbound_key(input);
else if (ISSET(VIEW_MODE))
@@ -1556,31 +1601,33 @@ 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 ((shortcut || 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;
}
if (shortcut == NULL) {
if (!function) {
pletion_line = NULL;
keep_cutbuffer = FALSE;
return;
}
if (ISSET(VIEW_MODE) && !okay_for_view(shortcut)) {
if (ISSET(VIEW_MODE) && changes_something(function)) {
print_view_warning();
return;
}
@@ -1593,25 +1640,25 @@ void process_a_keystroke(void)
give_a_hint = FALSE;
/* When not cutting or copying text, drop the cutbuffer the next time. */
if (shortcut->func != cut_text) {
if (function != cut_text) {
#ifndef NANO_TINY
if (shortcut->func != copy_text && shortcut->func != zap_text)
if (function != copy_text && function != zap_text)
#endif
keep_cutbuffer = FALSE;
}
#ifdef ENABLE_WORDCOMPLETION
if (shortcut->func != complete_a_word)
if (function != complete_a_word)
pletion_line = NULL;
#endif
#ifdef ENABLE_NANORC
if (shortcut->func == (functionptrtype)implant) {
if (function == (functionptrtype)implant) {
implant(shortcut->expansion);
return;
}
#endif
#ifndef NANO_TINY
if (shortcut->func == do_toggle) {
if (function == do_toggle) {
toggle_this(shortcut->toggle);
if (shortcut->toggle == CUT_FROM_CURSOR)
keep_cutbuffer = FALSE;
@@ -1630,32 +1677,21 @@ void process_a_keystroke(void)
#endif
/* Execute the function of the shortcut. */
shortcut->func();
function();
#ifndef NANO_TINY
/* When the marked region changes without Shift being held,
* discard a soft mark. And when the marked region covers a
* different set of lines, reset the "last line too" flag. */
if (openfile->mark) {
if (!shift_held && openfile->softmark &&
(openfile->current != was_current ||
openfile->current_x != was_x ||
wanted_to_move(shortcut->func))) {
openfile->mark = NULL;
refresh_needed = TRUE;
} else if (openfile->current != was_current)
also_the_last = FALSE;
}
#endif
#ifdef ENABLE_COLOR
if (!refresh_needed && !okay_for_view(shortcut))
check_the_multis(openfile->current);
#endif
if (!refresh_needed && (shortcut->func == do_delete ||
shortcut->func == do_backspace))
update_line(openfile->current, openfile->current_x);
* discard a soft mark. And when the set of lines changes,
* reset the "last line too" flag. */
if (openfile->mark && openfile->softmark && !shift_held &&
(openfile->current != was_current ||
openfile->current_x != was_x ||
wanted_to_move(function))) {
openfile->mark = NULL;
refresh_needed = TRUE;
} else if (openfile->current != was_current)
also_the_last = FALSE;
#ifndef NANO_TINY
if (bracketed_paste)
suck_up_input_and_paste_it();
@@ -1733,13 +1769,11 @@ int main(int argc, char **argv)
{"speller", 1, NULL, 's'},
#endif
{"saveonexit", 0, NULL, 't'},
{"tempfile", 0, NULL, 't'}, /* Deprecated; remove in 2022. */
{"view", 0, NULL, 'v'},
#ifdef ENABLE_WRAPPING
{"nowrap", 0, NULL, 'w'},
#endif
{"nohelp", 0, NULL, 'x'},
{"suspendable", 0, NULL, 'z'}, /* Obsolete; remove in 2022. */
#ifndef NANO_TINY
{"smarthome", 0, NULL, 'A'},
{"backup", 0, NULL, 'B'},
@@ -1786,10 +1820,12 @@ int main(int argc, char **argv)
/* Back up the terminal settings so that they can be restored. */
tcgetattr(STDIN_FILENO, &original_state);
#if defined(F_GETFL) && defined(F_SETFL)
/* Get the state of standard input and ensure it uses blocking mode. */
stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
if (stdin_flags != -1)
fcntl(STDIN_FILENO, F_SETFL, stdin_flags & ~O_NONBLOCK);
#endif
#ifdef ENABLE_UTF8
/* If setting the locale is successful and it uses UTF-8, we will
@@ -1812,8 +1848,8 @@ int main(int argc, char **argv)
if (*(tail(argv[0])) == 'r')
SET(RESTRICTED);
while ((optchr = getopt_long(argc, argv, "0ABC:DEFGHIJ:KLMNOPQ:RST:UVWX:Y:Z"
"abcdef:ghijklmno:pqr:s:tuvwxyz$%_!", long_options, NULL)) != -1) {
while ((optchr = getopt_long(argc, argv, "ABC:DEFGHIJ:KLMNOPQ:RS$T:UVWX:Y:Z"
"abcdef:ghijklmno:pqr:s:tuvwxy!%_0", long_options, NULL)) != -1) {
switch (optchr) {
#ifndef NANO_TINY
case 'A':
@@ -2046,8 +2082,11 @@ int main(int argc, char **argv)
SET(AFTER_ENDS);
break;
#endif
case 'z':
#ifdef HAVE_LIBMAGIC
case '!':
SET(USE_MAGIC);
break;
#endif
#ifndef NANO_TINY
case '%':
SET(STATEFLAGS);
@@ -2058,11 +2097,6 @@ int main(int argc, char **argv)
case '0':
SET(ZERO);
break;
#endif
#ifdef HAVE_LIBMAGIC
case '!':
SET(USE_MAGIC);
break;
#endif
default:
printf(_("Type '%s -h' for a list of available options.\n"), argv[0]);
@@ -2072,7 +2106,7 @@ int main(int argc, char **argv)
/* Curses needs TERM; if it is unset, try falling back to a VT220. */
if (getenv("TERM") == NULL)
setenv("TERM", "vt220", 0);
putenv("TERM=vt220");
/* Enter into curses mode. Abort if this fails. */
if (initscr() == NULL)
@@ -2082,6 +2116,9 @@ int main(int argc, char **argv)
/* If the terminal can do colors, tell ncurses to switch them on. */
if (has_colors())
start_color();
/* When requested, suppress the default spotlight and error colors. */
rescind_colors = (getenv("NO_COLOR") != NULL);
#endif
/* Set up the function and shortcut lists. This needs to be done
@@ -2168,7 +2205,7 @@ int main(int argc, char **argv)
alt_speller = alt_speller_cmdline;
}
/* Strip leading whitespace from the speller command, if any. */
while (alt_speller && *alt_speller && isblank(*alt_speller))
while (alt_speller && (*alt_speller == ' ' || *alt_speller == '\t'))
memmove(alt_speller, alt_speller + 1, strlen(alt_speller));
#endif
@@ -2389,6 +2426,8 @@ int main(int argc, char **argv)
shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
#endif
mousefocusin = get_keycode("kxIN", FOCUS_IN);
mousefocusout = get_keycode("kxOUT", FOCUS_OUT);
#ifdef HAVE_SET_ESCDELAY
/* Tell ncurses to pass the Esc key quickly. */
@@ -2406,7 +2445,7 @@ int main(int argc, char **argv)
#ifndef NANO_TINY
int n = 1;
while (isalpha(argv[optind][n])) {
while (isalpha((unsigned char)argv[optind][n])) {
switch (argv[optind][n++]) {
case 'c': SET(CASE_SENSITIVE); break;
case 'C': UNSET(CASE_SENSITIVE); break;
@@ -2423,7 +2462,7 @@ int main(int argc, char **argv)
searchstring = copy_of(&argv[optind][n + 1]);
if (argv[optind][n] == '?')
SET(BACKWARDS_SEARCH);
} else if (n == 1)
} else
statusline(ALERT, _("Empty search string"));
optind++;
} else
@@ -2445,8 +2484,26 @@ int main(int argc, char **argv)
continue;
} else
#endif
if (!open_buffer(argv[optind++], TRUE))
continue;
{
char *filename = argv[optind++];
char *colon = filename + (*filename ? 1 : 0);
/* Search the filename for a colon. If the colon is preceded by
* a backslash, elide the backslash and skip the colon. If there
* is a valid number after the colon, chop colon and number off.
* The number is later used to place the cursor on that line. */
while ((colon = strchr(colon, ':'))) {
if (*(colon - 1) == '\\')
memmove(colon - 1, colon, strlen(colon) + 1);
else if (parse_line_column(colon + 1, &givenline, &givencol))
*colon = '\0';
else
++colon;
}
if (!open_buffer(filename, TRUE))
continue;
}
/* If a position was given on the command line, go there. */
if (givenline != 0 || givencol != 0)
@@ -2461,6 +2518,7 @@ int main(int argc, char **argv)
else if (lastmessage <= REMARK)
wipe_statusbar();
openfile->placewewant = xplustabs();
adjust_viewport(CENTERING);
if (ISSET(USE_REGEXP))
tidy_up_after_search();
free(last_search);
@@ -2481,6 +2539,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. */
@@ -2505,7 +2567,7 @@ int main(int argc, char **argv)
#ifdef ENABLE_NANORC
if (startup_problem != NULL)
statusline(ALERT, startup_problem);
statusline(ALERT, "%s", startup_problem);
#define NOTREBOUND first_sc_for(MMAIN, do_help) && \
first_sc_for(MMAIN, do_help)->keycode == 0x07
@@ -2519,6 +2581,11 @@ int main(int argc, char **argv)
statusbar(_("Welcome to nano. For basic help, type Ctrl+G."));
#endif
#ifdef ENABLE_LINENUMBERS
/* Set the margin to an impossible value to force re-evaluation. */
margin = 12345;
#endif
we_are_running = TRUE;
while (TRUE) {
@@ -2558,7 +2625,7 @@ int main(int argc, char **argv)
edit_scroll(FORWARD);
wnoutrefresh(midwin);
}
wredrawln(footwin, 0 ,1);
wredrawln(footwin, 0, 1);
wnoutrefresh(footwin);
place_the_cursor();
} else if (ISSET(ZERO) && lastmessage > VACUUM)

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* prompt.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -41,6 +41,33 @@ void do_statusbar_end(void)
}
#ifndef NANO_TINY
/* Move to the previous word in the answer. */
void do_statusbar_prev_word(void)
{
bool seen_a_word = FALSE, step_forward = FALSE;
/* Move backward until we pass over the start of a word. */
while (typing_x != 0) {
typing_x = step_left(answer, typing_x);
if (is_word_char(answer + typing_x, FALSE))
seen_a_word = TRUE;
#ifdef ENABLE_UTF8
else if (is_zerowidth(answer + typing_x))
; /* skip */
#endif
else if (seen_a_word) {
/* This is space now: we've overshot the start of the word. */
step_forward = TRUE;
break;
}
}
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
typing_x = step_right(answer, typing_x);
}
/* Move to the next word in the answer. */
void do_statusbar_next_word(void)
{
@@ -78,33 +105,6 @@ void do_statusbar_next_word(void)
}
}
}
/* Move to the previous word in the answer. */
void do_statusbar_prev_word(void)
{
bool seen_a_word = FALSE, step_forward = FALSE;
/* Move backward until we pass over the start of a word. */
while (typing_x != 0) {
typing_x = step_left(answer, typing_x);
if (is_word_char(answer + typing_x, FALSE))
seen_a_word = TRUE;
#ifdef ENABLE_UTF8
else if (is_zerowidth(answer + typing_x))
; /* skip */
#endif
else if (seen_a_word) {
/* This is space now: we've overshot the start of the word. */
step_forward = TRUE;
break;
}
}
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
typing_x = step_right(answer, typing_x);
}
#endif /* !NANO_TINY */
/* Move left one character in the answer. */
@@ -131,6 +131,17 @@ void do_statusbar_right(void)
}
}
/* Backspace over one character in the answer. */
void do_statusbar_backspace(void)
{
if (typing_x > 0) {
size_t was_x = typing_x;
typing_x = step_left(answer, typing_x);
memmove(answer + typing_x, answer + was_x, strlen(answer) - was_x + 1);
}
}
/* Delete one character in the answer. */
void do_statusbar_delete(void)
{
@@ -146,17 +157,6 @@ void do_statusbar_delete(void)
}
}
/* Backspace over one character in the answer. */
void do_statusbar_backspace(void)
{
if (typing_x > 0) {
size_t was_x = typing_x;
typing_x = step_left(answer, typing_x);
memmove(answer + typing_x, answer + was_x, strlen(answer) - was_x + 1);
}
}
/* Zap the part of the answer after the cursor, or the whole answer. */
void lop_the_answer(void)
{
@@ -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
@@ -229,7 +225,7 @@ void inject_into_answer(char *burst, size_t count)
answer = nrealloc(answer, strlen(answer) + count + 1);
memmove(answer + typing_x + count, answer + typing_x,
strlen(answer) - typing_x + 1);
strncpy(answer + typing_x, burst , count);
strncpy(answer + typing_x, burst, count);
typing_x += count;
}
@@ -250,132 +246,92 @@ void do_statusbar_verbatim_input(void)
free(bytes);
}
/* Read in a keystroke, interpret it if it is a shortcut or toggle, and
* return it. Set finished to TRUE if we're done after running
* or trying to run a function associated with a shortcut key. */
int do_statusbar_input(bool *finished)
/* Add the given input to the input buffer when it's a normal byte,
* and inject the gathered bytes into the answer when ready. */
void absorb_character(int input, functionptrtype function)
{
int input;
/* The character we read in. */
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. */
const keystruct *shortcut;
*finished = FALSE;
/* Read in a character. */
input = get_kbinput(footwin, VISIBLE);
#ifndef NANO_TINY
if (input == KEY_WINCH)
return KEY_WINCH;
#endif
#ifdef ENABLE_MOUSE
/* If we got a mouse click and it was on a shortcut, read in the
* shortcut character. */
if (input == KEY_MOUSE) {
if (do_statusbar_mouse() == 1)
input = get_kbinput(footwin, BLIND);
else
return ERR;
}
#endif
/* Check for a shortcut in the current list. */
shortcut = get_shortcut(&input);
/* If not a command, discard anything that is not a normal character byte.
* Apart from that, only accept input when not in restricted mode, or when
* not at the "Write File" prompt, or when there is no filename yet. */
if (shortcut == NULL) {
if (!function) {
if (input < 0x20 || input > 0xFF || meta_key)
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 ((shortcut || 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;
}
}
if (shortcut) {
if (shortcut->func == do_tab || shortcut->func == do_enter)
;
#ifdef ENABLE_HISTORIES
else if (shortcut->func == get_older_item ||
shortcut->func == get_newer_item)
;
#endif
else if (shortcut->func == do_left)
do_statusbar_left();
else if (shortcut->func == do_right)
do_statusbar_right();
/* Handle any editing shortcut, and return TRUE when handled. */
bool handle_editing(functionptrtype function)
{
if (function == do_left)
do_statusbar_left();
else if (function == do_right)
do_statusbar_right();
#ifndef NANO_TINY
else if (shortcut->func == to_prev_word)
do_statusbar_prev_word();
else if (shortcut->func == to_next_word)
do_statusbar_next_word();
else if (function == to_prev_word)
do_statusbar_prev_word();
else if (function == to_next_word)
do_statusbar_next_word();
#endif
else if (shortcut->func == do_home)
do_statusbar_home();
else if (shortcut->func == do_end)
do_statusbar_end();
/* When in restricted mode at the "Write File" prompt and the
* filename isn't blank, disallow any input and deletion. */
else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE &&
openfile->filename[0] != '\0' &&
(shortcut->func == do_verbatim_input ||
shortcut->func == do_delete ||
shortcut->func == do_backspace ||
shortcut->func == cut_text ||
shortcut->func == paste_text))
;
#ifdef ENABLE_NANORC
else if (shortcut->func == (functionptrtype)implant)
implant(shortcut->expansion);
#endif
else if (shortcut->func == do_verbatim_input)
do_statusbar_verbatim_input();
else if (shortcut->func == do_delete)
do_statusbar_delete();
else if (shortcut->func == do_backspace)
do_statusbar_backspace();
else if (shortcut->func == cut_text)
lop_the_answer();
else if (function == do_home)
do_statusbar_home();
else if (function == do_end)
do_statusbar_end();
/* When in restricted mode at the "Write File" prompt and the
* filename isn't blank, disallow any input and deletion. */
else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE &&
openfile->filename[0] != '\0' &&
(function == do_verbatim_input ||
function == do_delete || function == do_backspace ||
function == cut_text || function == paste_text))
;
else if (function == do_verbatim_input)
do_statusbar_verbatim_input();
else if (function == do_delete)
do_statusbar_delete();
else if (function == do_backspace)
do_statusbar_backspace();
else if (function == cut_text)
lop_the_answer();
#ifndef NANO_TINY
else if (shortcut->func == copy_text)
copy_the_answer();
else if (shortcut->func == paste_text) {
if (cutbuffer != NULL)
paste_into_answer();
}
#endif
else {
/* Handle any other shortcut in the current menu, setting finished
* to TRUE to indicate that we're done after running or trying to
* run its associated function. */
if (!ISSET(VIEW_MODE) || okay_for_view(shortcut))
shortcut->func();
*finished = TRUE;
}
else if (function == copy_text)
copy_the_answer();
else if (function == paste_text) {
if (cutbuffer != NULL)
paste_into_answer();
}
#endif
else
return FALSE;
return input;
/* Don't handle any handled function again. */
return TRUE;
}
/* Return the column number of the first character of the answer that is
@@ -460,9 +416,6 @@ void add_or_remove_pipe_symbol_from_answer(void)
functionptrtype acquire_an_answer(int *actual, bool *listed,
linestruct **history_list, void (*refresh_func)(void))
{
int kbinput = ERR;
bool finished;
functionptrtype func;
#ifdef ENABLE_HISTORIES
char *stored_string = NULL;
/* Whatever the answer was before the user foraged into history. */
@@ -472,7 +425,10 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
size_t fragment_length = 0;
/* The length of the fragment that the user tries to tab complete. */
#endif
#endif /* ENABLE_HISTORIES */
#endif
const keystruct *shortcut;
functionptrtype function;
int input;
if (typing_x > strlen(answer))
typing_x = strlen(answer);
@@ -480,27 +436,40 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
while (TRUE) {
draw_the_promptbar();
kbinput = do_statusbar_input(&finished);
/* Read in one keystroke. */
input = get_kbinput(footwin, VISIBLE);
#ifndef NANO_TINY
/* If the window size changed, go reformat the prompt string. */
if (kbinput == KEY_WINCH) {
refresh_func();
if (input == KEY_WINCH) {
refresh_func(); /* Only needed when in file browser. */
*actual = KEY_WINCH;
#ifdef ENABLE_HISTORIES
free(stored_string);
#endif
return NULL;
}
#endif /* !NANO_TINY */
#endif
#ifdef ENABLE_MOUSE
/* For a click on a shortcut, read in the resulting keycode. */
if (input == KEY_MOUSE && do_statusbar_mouse() == 1)
input = get_kbinput(footwin, BLIND);
if (input == KEY_MOUSE)
continue;
#endif
func = func_from_key(&kbinput);
/* Check for a shortcut in the current list. */
shortcut = get_shortcut(input);
function = (shortcut ? shortcut->func : NULL);
if (func == do_cancel || func == do_enter)
/* When it's a normal character, add it to the answer. */
absorb_character(input, function);
if (function == do_cancel || function == do_enter)
break;
#ifdef ENABLE_TABCOMP
if (func == do_tab) {
if (function == do_tab) {
#ifdef ENABLE_HISTORIES
if (history_list != NULL) {
if (!previous_was_tab)
@@ -517,9 +486,9 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
if ((currmenu & (MINSERTFILE|MWRITEFILE|MGOTODIR)) && !ISSET(RESTRICTED))
answer = input_tab(answer, &typing_x, refresh_func, listed);
} else
#endif /* ENABLE_TABCOMP */
#endif
#ifdef ENABLE_HISTORIES
if (func == get_older_item && history_list != NULL) {
if (function == get_older_item && history_list != NULL) {
/* If this is the first step into history, start at the bottom. */
if (stored_string == NULL)
reset_history_pointer_for(*history_list);
@@ -534,7 +503,7 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
answer = mallocstrcpy(answer, (*history_list)->data);
typing_x = strlen(answer);
}
} else if (func == get_newer_item && history_list != NULL) {
} else if (function == get_newer_item && history_list != NULL) {
/* If there is a newer item, move to it and copy its string. */
if ((*history_list)->next != NULL) {
*history_list = (*history_list)->next;
@@ -549,29 +518,33 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
}
} else
#endif /* ENABLE_HISTORIES */
/* If we ran a function that should not exit from the prompt... */
if (func == do_help || func == full_refresh)
finished = FALSE;
if (function == do_help || function == full_refresh)
function();
#ifndef NANO_TINY
else if (func == do_nothing)
finished = FALSE;
else if (func == do_toggle) {
else if (function == do_toggle && shortcut->toggle == NO_HELP) {
TOGGLE(NO_HELP);
window_init();
focusing = FALSE;
refresh_func();
bottombars(currmenu);
finished = FALSE;
}
} else if (function == do_nothing)
;
#endif
/* If we have a shortcut with an associated function, break out if
* we're finished after running or trying to run the function. */
if (finished)
break;
#ifdef ENABLE_NANORC
else if (function == (functionptrtype)implant)
implant(shortcut->expansion);
#endif
else if (function && !handle_editing(function)) {
/* When it's a permissible shortcut, run it and done. */
if (!ISSET(VIEW_MODE) || !changes_something(function)) {
function();
break;
} else
beep();
}
#if defined(ENABLE_HISTORIES) && defined(ENABLE_TABCOMP)
previous_was_tab = (func == do_tab);
previous_was_tab = (function == do_tab);
#endif
}
@@ -583,9 +556,9 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
}
#endif
*actual = kbinput;
*actual = input;
return func;
return function;
}
/* Ask a question on the status bar. Return 0 when text was entered,
@@ -595,10 +568,10 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
int do_prompt(int menu, const char *provided, linestruct **history_list,
void (*refresh_func)(void), const char *msg, ...)
{
functionptrtype function = NULL;
bool listed = FALSE;
va_list ap;
int retval;
functionptrtype func = NULL;
bool listed = FALSE;
/* Save a possible current status-bar x position and prompt. */
size_t was_typing_x = typing_x;
char *saved_prompt = prompt;
@@ -620,25 +593,23 @@ int do_prompt(int menu, const char *provided, linestruct **history_list,
lastmessage = VACUUM;
func = acquire_an_answer(&retval, &listed, history_list, refresh_func);
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. */
if (func == do_cancel || func == do_enter)
/* 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. */
if (func == do_cancel)
/* Set the proper return value for Cancel and Enter. */
if (function == do_cancel)
retval = -1;
else if (func == do_enter)
else if (function == do_enter)
retval = (*answer == '\0') ? -2 : 0;
if (lastmessage == VACUUM)
@@ -667,6 +638,8 @@ int ask_user(bool withall, const char *question)
const char *yesstr = _("Yy");
const char *nostr = _("Nn");
const char *allstr = _("Aa");
const keystruct *shortcut;
functionptrtype function;
while (choice == UNDECIDED) {
#ifdef ENABLE_NLS
@@ -722,9 +695,11 @@ int ask_user(bool withall, const char *question)
if (kbinput == KEY_WINCH)
continue;
/* Accept the first character of an external paste. */
if (bracketed_paste && kbinput == BRACKETED_PASTE_MARKER)
/* Accept first character of an external paste and ignore the rest. */
if (bracketed_paste)
kbinput = get_kbinput(footwin, BLIND);
while (bracketed_paste)
get_kbinput(footwin, BLIND);
#endif
#ifdef ENABLE_NLS
@@ -756,8 +731,27 @@ int ask_user(bool withall, const char *question)
choice = NO;
else if (withall && strchr("Aa", kbinput) != NULL)
choice = ALL;
else if (func_from_key(&kbinput) == do_cancel)
if (choice != UNDECIDED)
break;
shortcut = get_shortcut(kbinput);
function = (shortcut ? shortcut->func : NULL);
if (function == do_cancel)
choice = CANCEL;
else if (function == full_refresh)
full_refresh();
#ifndef NANO_TINY
else if (function == do_toggle && shortcut->toggle == NO_HELP) {
TOGGLE(NO_HELP);
window_init();
titlebar(NULL);
focusing = FALSE;
edit_refresh();
focusing = TRUE;
}
#endif
/* Interpret ^N and ^Q as "No", to allow exiting in anger. */
else if (kbinput == '\x0E' || kbinput == '\x11')
choice = NO;
@@ -781,27 +775,9 @@ int ask_user(bool withall, const char *question)
choice = UNDECIDED;
}
}
#endif
else if (func_from_key(&kbinput) == full_refresh)
full_refresh();
#ifndef NANO_TINY
else if (func_from_key(&kbinput) == do_toggle) {
TOGGLE(NO_HELP);
window_init();
titlebar(NULL);
focusing = FALSE;
edit_refresh();
focusing = TRUE;
}
#endif
else
beep();
#ifndef NANO_TINY
/* Ignore the rest of an external paste. */
while (bracketed_paste)
kbinput = get_kbinput(footwin, BLIND);
#endif
}
return choice;

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* prototypes.h -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -80,6 +80,7 @@ extern int altinsert, altdelete;
extern int shiftaltleft, shiftaltright;
extern int shiftaltup, shiftaltdown;
#endif
extern int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
extern ssize_t fill;
@@ -141,6 +142,9 @@ extern char *alt_speller;
extern syntaxtype *syntaxes;
extern char *syntaxstr;
extern bool have_palette;
extern bool rescind_colors;
extern bool perturbed;
extern bool recook;
#endif
extern bool refresh_needed;
@@ -178,6 +182,9 @@ extern char *startup_problem;
#endif
#ifdef ENABLE_NANORC
extern char *custom_nanorc;
extern char *commandname;
extern keystruct *planted_shortcut;
#endif
extern bool spotlighted;
@@ -313,12 +320,12 @@ char *input_tab(char *buf, size_t *place, void (*refresh_func)(void), bool *list
#endif
/* Some functions in global.c. */
const keystruct *first_sc_for(int menu, void (*func)(void));
const keystruct *first_sc_for(int menu, void (*function)(void));
size_t shown_entries_for(int menu);
const keystruct *get_shortcut(int *keycode);
functionptrtype func_from_key(int *keycode);
const keystruct *get_shortcut(const int keycode);
functionptrtype func_from_key(const int keycode);
#if defined(ENABLE_BROWSER) || defined(ENABLE_HELP)
functionptrtype interpret(int *keycode);
functionptrtype interpret(const int keycode);
#endif
int keycode_from_string(const char *keystring);
void shortcut_init(void);
@@ -421,7 +428,7 @@ void terminal_init(void);
void confirm_margin(void);
#endif
void unbound_key(int code);
bool okay_for_view(const keystruct *shortcut);
bool changes_something(functionptrtype f);
void inject(char *burst, size_t count);
/* Most functions in prompt.c. */
@@ -438,6 +445,7 @@ void display_rcfile_errors(void);
void jot_error(const char *msg, ...);
#endif
#ifdef ENABLE_NANORC
keystruct *strtosc(const char *input);
#ifdef ENABLE_COLOR
void parse_one_include(char *file, syntaxtype *syntax);
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
@@ -462,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);
@@ -513,15 +523,19 @@ 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
void count_lines_words_and_characters(void);
#endif
void do_verbatim_input(void);
#ifdef ENABLE_WORDCOMPLETION
void complete_a_word(void);
#endif
/* All functions in utils.c. */
void get_homedir(void);
@@ -531,7 +545,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
@@ -561,13 +575,16 @@ 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. */
#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);
@@ -604,8 +621,8 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge);
bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge);
void edit_scroll(bool direction);
#ifndef NANO_TINY
size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
bool *end_of_line);
size_t get_softwrap_breakpoint(const char *linedata, size_t leftedge,
bool *kickoff, bool *end_of_line);
size_t get_chunk_and_edge(size_t column, linestruct *line, size_t *leftedge);
size_t chunk_for(size_t column, linestruct *line);
size_t leftedge_for(size_t column, linestruct *line);

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* rcfile.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mike Frysinger *
* Copyright (C) 2019 Brand Huntsman *
* Copyright (C) 2014-2021 Benno Schulenberg *
@@ -90,9 +90,6 @@ static const rcoption rcopts[] = {
#ifdef ENABLE_SPELLER
{"speller", 0},
#endif
{"suspend", SUSPENDABLE}, /* Deprecated; remove in 2022. */
{"suspendable", SUSPENDABLE}, /* Obsolete; remove in 2022. */
{"tempfile", SAVE_ON_EXIT}, /* Deprecated; remove in 2022. */
#ifndef NANO_TINY
{"afterends", AFTER_ENDS},
{"allow_insecure_backup", INSECURE_BACKUP},
@@ -156,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 17 /* Remove the deprecated 'extcmd' in 2022. */
char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith",
"yesno", "gotoline", "writeout", "insert",
"execute", "extcmd", "help", "spell", "linter",
"browser", "whereisfile", "gotodir",
"all" };
int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH,
MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE,
MEXECUTE, MEXECUTE, MHELP, MSPELL, MLINTER,
MBROWSER, MWHEREISFILE, MGOTODIR,
MMOST|MBROWSER|MHELP|MYESNO };
#endif /* ENABLE_NANORC */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
@@ -279,14 +264,15 @@ 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
else if (!strcmp(input, "location") ||
!strcmp(input, "curpos")) /* Deprecated; remove in 2022. */
else if (!strcmp(input, "location"))
s->func = report_cursor_position;
else if (!strcmp(input, "gotoline"))
s->func = do_gotolinecolumn;
@@ -497,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)
{
@@ -506,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. */
@@ -676,7 +674,7 @@ void begin_new_syntax(char *ptr)
live_syntax->magics = NULL;
live_syntax->linter = NULL;
live_syntax->formatter = NULL;
live_syntax->tab = NULL;
live_syntax->tabstring = NULL;
#ifdef ENABLE_COMMENT
live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER);
#endif
@@ -789,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. */
@@ -803,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)
@@ -901,7 +899,7 @@ bool is_good_file(char *file)
#ifdef ENABLE_COLOR
/* Partially parse the syntaxes in the given file, or (when syntax
* is not NULL) fully parse one specific syntax from the file . */
* is not NULL) fully parse one specific syntax from the file. */
void parse_one_include(char *file, syntaxtype *syntax)
{
char *was_nanorc = nanorc;
@@ -910,7 +908,7 @@ void parse_one_include(char *file, syntaxtype *syntax)
FILE *rcstream;
/* Don't open directories, character files, or block files. */
if (!is_good_file(file))
if (access(file, R_OK) == 0 && !is_good_file(file))
return;
rcstream = fopen(file, "rb");
@@ -978,7 +976,7 @@ void parse_includes(char *ptr)
/* Expand a tilde first, then try to match the globbing pattern. */
expanded = real_dir_from_tilde(pattern);
result = glob(expanded, GLOB_ERR, NULL, &files);
result = glob(expanded, GLOB_ERR|GLOB_NOCHECK, NULL, &files);
/* If there are matches, process each of them. Otherwise, only
* report an error if it's something other than zero matches. */
@@ -993,16 +991,22 @@ void parse_includes(char *ptr)
}
/* Return the index of the color that is closest to the given RGB levels,
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color.
* When red == green == blue, return an index in the xterm gray scale. */
short closest_index_color(short red, short green, short blue)
{
/* Translation table, from 16 intended levels to 6 available levels. */
/* Translation table, from 16 intended color levels to 6 available levels. */
static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
if (COLORS == 256)
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
else
/* Translation table, from 14 intended gray levels to 24 available levels. */
static const short gray[] = { 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 18, 21, 23 };
if (COLORS != 256)
return THE_DEFAULT;
else if (red == green && green == blue && 0 < red && red < 0xF)
return 232 + gray[red - 1];
else
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
}
#define COLORCOUNT 34
@@ -1327,7 +1331,7 @@ bool parse_syntax_commands(char *keyword, char *ptr)
pick_up_name("comment", ptr, &live_syntax->comment);
#endif
} else if (strcmp(keyword, "tabgives") == 0) {
pick_up_name("tabgives", ptr, &live_syntax->tab);
pick_up_name("tabgives", ptr, &live_syntax->tabstring);
} else if (strcmp(keyword, "linter") == 0)
pick_up_name("linter", ptr, &live_syntax->linter);
else if (strcmp(keyword, "formatter") == 0)
@@ -1352,7 +1356,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
@@ -1534,7 +1538,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;
}
@@ -1709,7 +1713,7 @@ void do_rcfiles(void)
{
if (custom_nanorc) {
nanorc = get_full_path(custom_nanorc);
if (access(nanorc, F_OK) != 0)
if (nanorc == NULL || access(nanorc, F_OK) != 0)
die(_("Specified rcfile does not exist\n"));
} else
nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* search.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2015-2020 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -65,6 +65,9 @@ void tidy_up_after_search(void)
if (openfile->mark)
refresh_needed = TRUE;
#endif
#ifdef ENABLE_COLOR
recook |= perturbed;
#endif
}
/* Prepare the prompt and ask the user what to search for. Keep looping
@@ -88,7 +91,7 @@ void search_init(bool replacing, bool retain_answer)
thedefault = copy_of("");
while (TRUE) {
functionptrtype func;
functionptrtype function;
/* Ask the user what to search for (or replace). */
int response = do_prompt(
inhelp ? MFINDINHELP : (replacing ? MREPLACE : MWHEREIS),
@@ -135,23 +138,23 @@ void search_init(bool replacing, bool retain_answer)
retain_answer = TRUE;
func = func_from_key(&response);
function = func_from_key(response);
/* If we're here, one of the five toggles was pressed, or
* a shortcut was executed. */
if (func == case_sens_void)
if (function == case_sens_void)
TOGGLE(CASE_SENSITIVE);
else if (func == backwards_void)
else if (function == backwards_void)
TOGGLE(BACKWARDS_SEARCH);
else if (func == regexp_void)
else if (function == regexp_void)
TOGGLE(USE_REGEXP);
else if (func == flip_replace) {
else if (function == flip_replace) {
if (ISSET(VIEW_MODE)) {
print_view_warning();
napms(600);
} else
replacing = !replacing;
} else if (func == flip_goto) {
} else if (function == flip_goto) {
goto_line_and_column(openfile->current->lineno,
openfile->placewewant + 1, TRUE, TRUE);
break;
@@ -219,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
@@ -281,7 +285,7 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
} else
meta_key = FALSE;
if (func_from_key(&input) == do_cancel) {
if (func_from_key(input) == do_cancel) {
#ifndef NANO_TINY
if (the_window_resized)
regenerate_screen();
@@ -443,8 +447,8 @@ void go_looking(void)
* text in the passed string only when create is TRUE. */
int replace_regexp(char *string, bool create)
{
const char *c = answer;
size_t replacement_size = 0;
const char *c = answer;
/* Iterate through the replacement text to handle subexpression
* replacement using \1, \2, \3, etc. */
@@ -522,11 +526,11 @@ char *replace_line(const char *needle)
ssize_t do_replace_loop(const char *needle, bool whole_word_only,
const linestruct *real_current, size_t *real_current_x)
{
bool skipone = ISSET(BACKWARDS_SEARCH);
bool replaceall = FALSE;
int modus = REPLACING;
ssize_t numreplaced = -1;
size_t match_len;
bool replaceall = FALSE;
bool skipone = ISSET(BACKWARDS_SEARCH);
int modus = REPLACING;
#ifndef NANO_TINY
linestruct *was_mark = openfile->mark;
linestruct *top, *bot;
@@ -657,6 +661,10 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
free(openfile->current->data);
openfile->current->data = altered;
#ifdef ENABLE_COLOR
check_the_multis(openfile->current);
refresh_needed = FALSE;
#endif
set_modified();
as_an_at = TRUE;
numreplaced++;
@@ -729,18 +737,27 @@ 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 line, size_t pos_x)
void goto_line_posx(ssize_t linenumber, size_t pos_x)
{
for (openfile->current = openfile->filetop; line > 1 &&
openfile->current != openfile->filebot; line--)
openfile->current = openfile->current->next;
#ifdef ENABLE_COLOR
if (linenumber > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && linenumber > openfile->current->lineno))
recook |= perturbed;
#endif
if (linenumber < openfile->filebot->lineno)
openfile->current = line_from_number(linenumber);
else
openfile->current = openfile->filebot;
openfile->current_x = pos_x;
openfile->placewewant = xplustabs();
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.
@@ -760,7 +777,7 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
return;
}
if (func_from_key(&response) == flip_goto) {
if (func_from_key(response) == flip_goto) {
UNSET(BACKWARDS_SEARCH);
/* Switch to searching but retain what the user typed so far. */
search_init(FALSE, TRUE);
@@ -790,6 +807,12 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
if (line < 1)
line = 1;
#ifdef ENABLE_COLOR
if (line > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
recook |= perturbed;
#endif
/* Iterate to the requested line. */
for (openfile->current = openfile->filetop; line > 1 &&
openfile->current != openfile->filebot; line--)
@@ -811,9 +834,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;
@@ -992,6 +1015,11 @@ void go_to_and_confirm(linestruct *line)
if (line != openfile->current) {
openfile->current = line;
openfile->current_x = 0;
#ifdef ENABLE_COLOR
if (line->lineno > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))
recook |= perturbed;
#endif
edit_redraw(was_current, CENTERING);
statusbar(_("Jumped to anchor"));
} else if (openfile->current->has_anchor)

View File

@@ -1,12 +1,12 @@
/**************************************************************************
* text.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2015 Mark Majeres *
* Copyright (C) 2016 Mike Scalora *
* Copyright (C) 2016 Sumedh Pendurkar *
* Copyright (C) 2018 Marco Diego Aurélio Mesquita *
* Copyright (C) 2015-2021 Benno Schulenberg *
* Copyright (C) 2015-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -65,8 +65,8 @@ void do_mark(void)
void do_tab(void)
{
#ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->tab)
inject(openfile->syntax->tab, strlen(openfile->syntax->tab));
if (openfile->syntax && openfile->syntax->tabstring)
inject(openfile->syntax->tabstring, strlen(openfile->syntax->tabstring));
else
#endif
#ifndef NANO_TINY
@@ -117,8 +117,8 @@ void indent_a_line(linestruct *line, char *indentation)
* depending on whether --tabstospaces is in effect. */
void do_indent(void)
{
char *indentation;
linestruct *top, *bot, *line;
char *indentation;
/* Use either all the marked lines or just the current line. */
get_range(&top, &bot);
@@ -134,8 +134,8 @@ void do_indent(void)
indentation = nmalloc(tabsize + 1);
#ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->tab)
indentation = mallocstrcpy(indentation, openfile->syntax->tab);
if (openfile->syntax && openfile->syntax->tabstring)
indentation = mallocstrcpy(indentation, openfile->syntax->tabstring);
else
#endif
/* Set the indentation to either a bunch of spaces or a single tab. */
@@ -173,10 +173,10 @@ size_t length_of_white(const char *text)
size_t white_count = 0;
#ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->tab) {
size_t thelength = strlen(openfile->syntax->tab);
if (openfile->syntax && openfile->syntax->tabstring) {
size_t thelength = strlen(openfile->syntax->tabstring);
while (text[white_count] == openfile->syntax->tab[white_count])
while (text[white_count] == openfile->syntax->tabstring[white_count])
if (++white_count == thelength)
return thelength;
@@ -502,10 +502,11 @@ void redo_cut(undostruct *u)
void do_undo(void)
{
undostruct *u = openfile->current_undo;
linestruct *line = NULL, *intruder;
linestruct *oldcutbuffer;
char *data, *undidmsg = NULL;
linestruct *oldcutbuffer, *intruder;
linestruct *line = NULL;
size_t original_x, regain_from_x;
char *undidmsg = NULL;
char *data;
if (u == NULL) {
statusline(AHEM, _("Nothing to undo"));
@@ -539,6 +540,7 @@ void do_undo(void)
line->has_anchor |= line->next->has_anchor;
unlink_node(line->next);
renumber_from(line);
openfile->current = line;
goto_line_posx(u->head_lineno, original_x);
break;
case BACK:
@@ -558,7 +560,8 @@ void do_undo(void)
* and the nonewlines flag isn't set, do not re-add a newline that
* wasn't actually deleted; just position the cursor. */
if ((u->xflags & WAS_BACKSPACE_AT_EOF) && !ISSET(NO_NEWLINES)) {
goto_line_posx(openfile->filebot->lineno, 0);
openfile->current = openfile->filebot;
openfile->current_x = 0;
break;
}
line->data[u->tail_x] = '\0';
@@ -655,7 +658,7 @@ void do_undo(void)
break;
}
if (undidmsg && !pletion_line)
if (undidmsg && !ISSET(ZERO) && !pletion_line)
statusline(HUSH, _("Undid %s"), undidmsg);
openfile->current_undo = openfile->current_undo->next;
@@ -665,6 +668,13 @@ void do_undo(void)
openfile->totsize = u->wassize;
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT)
perturbed = TRUE;
#endif
/* When at the point where the buffer was last saved, unset "Modified". */
if (openfile->current_undo == openfile->last_saved) {
openfile->modified = FALSE;
@@ -676,10 +686,12 @@ void do_undo(void)
/* Redo the last thing(s) we undid. */
void do_redo(void)
{
linestruct *line = NULL, *intruder;
char *data, *redidmsg = NULL;
bool suppress_modification = FALSE;
undostruct *u = openfile->undotop;
bool suppress_modification = FALSE;
linestruct *line = NULL;
linestruct *intruder;
char *redidmsg = NULL;
char *data;
if (u == NULL || u == openfile->current_undo) {
statusline(AHEM, _("Nothing to redo"));
@@ -735,6 +747,7 @@ void do_redo(void)
strcat(line->data, u->strdata);
unlink_node(line->next);
renumber_from(line);
openfile->current = line;
goto_line_posx(u->tail_lineno, u->tail_x);
break;
case REPLACE:
@@ -815,7 +828,7 @@ void do_redo(void)
break;
}
if (redidmsg)
if (redidmsg && !ISSET(ZERO))
statusline(HUSH, _("Redid %s"), redidmsg);
openfile->current_undo = u;
@@ -825,6 +838,13 @@ void do_redo(void)
openfile->totsize = u->newsize;
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT)
recook = TRUE;
#endif
/* When at the point where the buffer was last saved, unset "Modified". */
if (openfile->current_undo == openfile->last_saved) {
openfile->modified = FALSE;
@@ -857,7 +877,7 @@ void do_enter(void)
if (extra > openfile->current_x)
extra = openfile->current_x;
else if (extra == openfile->current_x)
allblanks = TRUE;
allblanks = (indent_length(openfile->current->data) == extra);
}
#endif /* NANO_TINY */
newnode->data = nmalloc(strlen(openfile->current->data +
@@ -1177,7 +1197,8 @@ void update_undo(undo_type action)
else if (cutbuffer != NULL) {
free_lines(u->cutbuffer);
u->cutbuffer = copy_buffer(cutbuffer);
}
} else
break;
if (!(u->xflags & MARK_WAS_SET)) {
linestruct *bottomline = u->cutbuffer;
size_t count = 0;
@@ -1745,6 +1766,8 @@ void justify_text(bool whole_buffer)
/* The leading part for lines after the first one. */
size_t secondary_len = 0;
/* The length of that later lead. */
ssize_t was_the_linenumber = openfile->current->lineno;
/* The line to return to after a full justification. */
/* TRANSLATORS: This one goes with Undid/Redid messages. */
add_undo(COUPLE_BEGIN, N_("justification"));
@@ -1961,7 +1984,8 @@ void justify_text(bool whole_buffer)
openfile->current_x = openfile->mark_x;
openfile->mark = bottom;
openfile->mark_x = bottom_x;
}
} else if (whole_buffer && !openfile->mark)
goto_line_posx(was_the_linenumber, 0);
add_undo(COUPLE_END, N_("justification"));
@@ -2000,7 +2024,7 @@ void do_full_justify(void)
}
#endif /* ENABLE_JUSTIFY */
#if defined(ENABLE_SPELLER) || defined (ENABLE_COLOR)
#if defined(ENABLE_SPELLER) || defined (ENABLE_LINTER) || defined (ENABLE_FORMATTER)
/* Set up an argument list for executing the given command. */
void construct_argument_list(char ***arguments, char *command, char *filename)
{
@@ -2017,7 +2041,9 @@ void construct_argument_list(char ***arguments, char *command, char *filename)
(*arguments)[count - 2] = filename;
(*arguments)[count - 1] = NULL;
}
#endif
#if defined(ENABLE_SPELLER) || defined (ENABLE_FORMATTER)
/* Open the specified file, and if that succeeds, remove the text of the marked
* region or of the entire buffer and read the file contents into its place. */
bool replace_buffer(const char *filename, undo_type action, const char *operation)
@@ -2031,11 +2057,19 @@ bool replace_buffer(const char *filename, undo_type action, const char *operatio
if (descriptor < 0)
return FALSE;
#ifndef NANO_TINY
add_undo(COUPLE_BEGIN, operation);
#endif
/* When replacing the whole buffer, start cutting at the top. */
if (action == CUT_TO_EOF) {
openfile->current = openfile->filetop;
openfile->current_x = 0;
}
cutbuffer = NULL;
#ifndef NANO_TINY
add_undo(COUPLE_BEGIN, operation);
/* Cut either the marked region or the whole buffer. */
add_undo(action, NULL);
do_snip(openfile->mark != NULL, openfile->mark == NULL, FALSE);
@@ -2060,6 +2094,7 @@ bool replace_buffer(const char *filename, undo_type action, const char *operatio
/* Execute the given program, with the given temp file as last argument. */
void treat(char *tempfile_name, char *theprogram, bool spelling)
{
#if defined(HAVE_FORK) && defined(HAVE_WAIT)
ssize_t was_lineno = openfile->current->lineno;
size_t was_pww = openfile->placewewant;
size_t was_x = openfile->current_x;
@@ -2089,8 +2124,11 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
timestamp_nsec = (long)fileinfo.st_mtim.tv_nsec;
}
/* Exit from curses mode to give the program control of the terminal. */
endwin();
/* The spell checker needs the screen, so exit from curses mode. */
if (spelling)
endwin();
else
statusbar(_("Invoking formatter..."));
construct_argument_list(&arguments, theprogram, tempfile_name);
@@ -2110,9 +2148,13 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
errornumber = errno;
/* Restore the terminal state and reenter curses mode. */
terminal_init();
doupdate();
/* After spell checking, restore terminal state and reenter curses mode;
* after formatting, make sure that any formatter output is wiped. */
if (spelling) {
terminal_init();
doupdate();
} else
full_refresh();
if (thepid < 0) {
statusline(ALERT, _("Could not fork: %s"), strerror(errornumber));
@@ -2154,14 +2196,9 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
openfile->mark = line_from_number(was_mark_lineno);
} else
#endif
{
openfile->current = openfile->filetop;
openfile->current_x = 0;
replaced = replace_buffer(tempfile_name, CUT_TO_EOF,
/* TRANSLATORS: The next two go with Undid/Redid messages. */
(spelling ? N_("spelling correction") : N_("formatting")));
}
/* Go back to the old position. */
goto_line_posx(was_lineno, was_x);
@@ -2182,8 +2219,9 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
statusline(REMARK, _("Finished checking spelling"));
else
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. */
@@ -2294,12 +2332,14 @@ bool fix_spello(const char *word)
* correction. */
void do_int_speller(const char *tempfile_name)
{
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *misspellings, *pointer, *oneword;
long pipesize;
size_t buffersize, bytesread, totalread;
int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
pid_t pid_spell, pid_sort, pid_uniq;
int spell_status, sort_status, uniq_status;
unsigned stash[sizeof(flags) / sizeof(flags[0])];
/* Create all three pipes up front. */
if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1) {
@@ -2424,6 +2464,9 @@ void do_int_speller(const char *tempfile_name)
terminal_init();
doupdate();
/* Save the settings of the global flags. */
memcpy(stash, flags, sizeof(flags));
/* Do any replacements case-sensitively, forward, and without regexes. */
SET(CASE_SENSITIVE);
UNSET(BACKWARDS_SEARCH);
@@ -2454,6 +2497,9 @@ void do_int_speller(const char *tempfile_name)
free(misspellings);
refresh_needed = TRUE;
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
/* Process the end of the three processes. */
waitpid(pid_spell, &spell_status, 0);
waitpid(pid_sort, &sort_status, 0);
@@ -2467,6 +2513,7 @@ void do_int_speller(const char *tempfile_name)
statusline(ALERT, _("Error invoking \"spell\""));
else
statusline(REMARK, _("Finished checking spelling"));
#endif
}
/* Spell check the current file. If an alternate spell checker is
@@ -2475,7 +2522,6 @@ void do_spell(void)
{
FILE *stream;
char *temp_name;
unsigned stash[sizeof(flags) / sizeof(flags[0])];
bool okay;
ran_a_tool = TRUE;
@@ -2490,12 +2536,6 @@ void do_spell(void)
return;
}
/* Save the settings of the global flags. */
memcpy(stash, flags, sizeof(flags));
/* Don't add an extra newline when writing out the (selected) text. */
SET(NO_NEWLINES);
#ifndef NANO_TINY
if (openfile->mark)
okay = write_region_to_file(temp_name, stream, TEMPORARY, OVERWRITE);
@@ -2505,6 +2545,7 @@ void do_spell(void)
if (!okay) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
unlink(temp_name);
free(temp_name);
return;
}
@@ -2519,19 +2560,17 @@ void do_spell(void)
unlink(temp_name);
free(temp_name);
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
/* Ensure the help lines will be redrawn and a selection is retained. */
currmenu = MMOST;
shift_held = TRUE;
}
#endif /* ENABLE_SPELLER */
#ifdef ENABLE_COLOR
#ifdef ENABLE_LINTER
/* Run a linting program on the current buffer. */
void do_linter(void)
{
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *lintings, *pointer, *onelint;
long pipesize;
size_t buffersize, bytesread, totalread;
@@ -2726,7 +2765,7 @@ void do_linter(void)
while (TRUE) {
int kbinput;
functionptrtype func;
functionptrtype function;
struct stat lintfileinfo;
if (stat(curlint->filename, &lintfileinfo) != -1 &&
@@ -2807,7 +2846,7 @@ void do_linter(void)
confirm_margin();
#endif
edit_refresh();
statusline(NOTICE, curlint->msg);
statusline(NOTICE, "%s", curlint->msg);
bottombars(MLINTER);
}
@@ -2821,16 +2860,16 @@ void do_linter(void)
if (kbinput == KEY_WINCH)
continue;
#endif
func = func_from_key(&kbinput);
function = func_from_key(kbinput);
tmplint = curlint;
if (func == do_cancel || func == do_enter) {
if (function == do_cancel || function == do_enter) {
wipe_statusbar();
break;
} else if (func == do_help) {
} else if (function == do_help) {
tmplint = NULL;
do_help();
} else if (func == do_page_up || func == to_prev_block) {
} else if (function == do_page_up || function == to_prev_block) {
if (curlint->prev != NULL)
curlint = curlint->prev;
else if (last_wait != time(NULL)) {
@@ -2838,9 +2877,9 @@ void do_linter(void)
beep();
napms(600);
last_wait = time(NULL);
statusline(NOTICE, curlint->msg);
statusline(NOTICE, "%s", curlint->msg);
}
} else if (func == do_page_down || func == to_next_block) {
} else if (function == do_page_down || function == to_next_block) {
if (curlint->next != NULL)
curlint = curlint->next;
else if (last_wait != time(NULL)) {
@@ -2848,7 +2887,7 @@ void do_linter(void)
beep();
napms(600);
last_wait = time(NULL);
statusline(NOTICE, curlint->msg);
statusline(NOTICE, "%s", curlint->msg);
}
} else
beep();
@@ -2871,8 +2910,11 @@ void do_linter(void)
lastmessage = VACUUM;
currmenu = MMOST;
titlebar(NULL);
#endif
}
#endif /* ENABLE_LINTER */
#ifdef ENABLE_FORMATTER
/* Run a manipulation program on the contents of the buffer. */
void do_formatter(void)
{
@@ -2899,18 +2941,15 @@ void do_formatter(void)
if (temp_name != NULL)
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
if (!okay) {
if (!okay)
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
free(temp_name);
return;
}
treat(temp_name, openfile->syntax->formatter, FALSE);
else
treat(temp_name, openfile->syntax->formatter, FALSE);
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
@@ -2977,6 +3016,13 @@ void do_verbatim_input(void)
size_t count = 1;
char *bytes;
#ifndef NANO_TINY
/* When barless and with cursor on bottom row, make room for the feedback. */
if (ISSET(ZERO) && openfile->current_y == editwinrows - 1 && LINES > 1) {
edit_scroll(FORWARD);
edit_refresh();
}
#endif
/* TRANSLATORS: Shown when the next keystroke will be inserted verbatim. */
statusline(INFO, _("Verbatim Input"));
place_the_cursor();
@@ -2993,7 +3039,13 @@ void do_verbatim_input(void)
if (count < 999)
inject(bytes, count);
wipe_statusbar();
#ifndef NANO_TINY
/* Ensure that the feedback will be overwritten, or clear it. */
if (ISSET(ZERO) && currmenu == MMAIN)
wredrawln(midwin, editwinrows - 1, 1);
else
#endif
wipe_statusbar();
} else
/* TRANSLATORS: An invalid verbatim Unicode code was typed. */
statusline(AHEM, _("Invalid code"));
@@ -3021,12 +3073,14 @@ char *copy_completion(char *text)
return word;
}
/* Look at the fragment the user has typed, then search the current buffer for
/* Look at the fragment the user has typed, then search all buffers for
* the first word that starts with this fragment, and tentatively complete the
* fragment. If the user types 'Complete' again, search and paste the next
* possible completion. */
void complete_a_word(void)
{
static openfilestruct *scouring = NULL;
/* The buffer that is being searched for possible completions. */
char *shard, *completion = NULL;
size_t start_of_shard, shard_length = 0;
size_t i = 0, j = 0;
@@ -3049,6 +3103,7 @@ void complete_a_word(void)
openfile->last_action = OTHER;
/* Initialize the starting point for searching. */
scouring = openfile;
pletion_line = openfile->filetop;
pletion_x = 0;
@@ -3160,9 +3215,17 @@ void complete_a_word(void)
pletion_line = pletion_line->next;
pletion_x = 0;
#ifdef ENABLE_MULTIBUFFER
/* When at end of buffer and there is another, search that one. */
if (pletion_line == NULL && scouring->next != openfile) {
scouring = scouring->next;
pletion_line = scouring->filetop;
}
#endif
}
/* The search has reached the end of the file. */
/* The search has gone through all buffers. */
if (list_of_completions != NULL) {
edit_refresh();
statusline(AHEM, _("No further matches"));

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* utils.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -130,14 +130,14 @@ bool parse_num(const char *string, ssize_t *result)
* *line and *column. Return FALSE on error, and TRUE otherwise. */
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
{
bool retval;
char *firstpart;
const char *comma;
char *firstpart;
bool retval;
while (*str == ' ')
str++;
comma = strpbrk(str, "m,. /;");
comma = strpbrk(str, ",.:");
if (comma == NULL)
return parse_num(str, line);
@@ -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

@@ -1,8 +1,8 @@
/**************************************************************************
* winio.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2022 Free Software Foundation, Inc. *
* Copyright (C) 2014-2021 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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,9 +62,9 @@ static bool linger_after_escape = FALSE;
/* Whether to give ncurses some time to get the next code. */
static int statusblank = 0;
/* The number of keystrokes left before we blank the status bar. */
size_t from_x = 0;
static size_t from_x = 0;
/* From where in the relevant line the current row is drawn. */
size_t till_x = 0;
static size_t till_x = 0;
/* Until where in the relevant line the current row is drawn. */
static bool has_more = FALSE;
/* Whether the current line has more text after the displayed part. */
@@ -82,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--;
@@ -122,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];
@@ -133,6 +140,17 @@ void run_macro(void)
}
#endif /* !NANO_TINY */
/* 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.
@@ -156,22 +174,17 @@ void run_macro(void)
* We support escape sequences for ANSI, VT100, VT220, VT320, the Linux
* console, the FreeBSD console, the Mach console, xterm, and Terminal,
* and some for Konsole, rxvt, Eterm, and iTerm2. Among these sequences,
* there are several conflicts and omissions:
* there are some conflicts:
*
* - Tab on ANSI == PageUp on FreeBSD console; the former is omitted.
* - PageUp on FreeBSD console == Tab on ANSI; the latter is omitted.
* (Ctrl-I is also Tab on ANSI, which we already support.)
* - PageDown on FreeBSD console == Center (5) on numeric keypad with
* NumLock off on Linux console; the latter is omitted. (The editing
* keypad key is more important to have working than the numeric
* keypad key, because the latter has no value when NumLock is off.)
* - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the
* latter is omitted. (Mouse input will only work properly if the
* extended keypad value KEY_MOUSE is generated on mouse events
* instead of the escape sequence.)
* NumLock off on Linux console; the latter is useless and omitted.
* - F1 on FreeBSD console == the mouse sequence on xterm/rxvt/Eterm;
* the latter is omitted. (Mouse input works only when KEY_MOUSE
* is generated on mouse events, not with the raw escape sequence.)
* - F9 on FreeBSD console == PageDown on Mach console; the former is
* omitted. (The editing keypad is more important to have working
* than the function keys, because the functions of the former are
* not arbitrary and the functions of the latter are.)
* omitted. (Moving the cursor is more important than a function key.)
* - F10 on FreeBSD console == PageUp on Mach console; the former is
* omitted. (Same as above.) */
@@ -198,6 +211,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
@@ -214,12 +228,13 @@ void read_keys_from(WINDOW *frame)
if (timed) {
timed = FALSE;
/* Leave half-delay mode. */
raw();
if (input == ERR) {
if (spotlighted || ISSET(ZERO) || LINES == 1) {
if (ISSET(ZERO) && lastmessage > VACUUM)
wredrawln(midwin, editwinrows - 1 , 1);
wredrawln(midwin, editwinrows - 1, 1);
lastmessage = VACUUM;
spotlighted = FALSE;
update_line(openfile->current, openfile->current_x);
@@ -245,10 +260,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
@@ -282,10 +300,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. */
@@ -308,16 +327,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--;
@@ -326,14 +340,66 @@ void put_back(int keycode)
}
#ifdef ENABLE_NANORC
/* Insert the given string into the keyboard buffer. */
/* Set up the given expansion string to be ingested by the keyboard routines. */
void implant(const char *string)
{
for (int i = strlen(string); i > 0; i--)
put_back((unsigned char)string[i - 1]);
plants_pointer = string;
put_back(MORE_PLANTS);
mute_modifiers = TRUE;
}
/* Continue processing an expansion string. Returns either an error code,
* a plain character byte, or a placeholder for a command shortcut. */
int get_code_from_plantation(void)
{
if (*plants_pointer == '{') {
char *closing = strchr(plants_pointer + 1, '}');
if (!closing)
return MISSING_BRACE;
if (plants_pointer[1] == '{' && plants_pointer[2] == '}') {
plants_pointer += 3;
if (*plants_pointer != '\0')
put_back(MORE_PLANTS);
return '{';
}
free(commandname);
free(planted_shortcut);
commandname = measured_copy(plants_pointer + 1, closing - plants_pointer - 1);
planted_shortcut = strtosc(commandname);
if (!planted_shortcut)
return NO_SUCH_FUNCTION;
plants_pointer = closing + 1;
if (*plants_pointer != '\0')
put_back(MORE_PLANTS);
return PLANTED_A_COMMAND;
} else {
char *opening = strchr(plants_pointer, '{');
char firstbyte = *plants_pointer;
int length;
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]);
plants_pointer += length;
return (firstbyte) ? firstbyte : ERR;
}
}
#endif
/* Return one code from the keystroke buffer. If the buffer is empty
@@ -347,7 +413,13 @@ int get_input(WINDOW *frame)
if (waiting_codes > 0) {
waiting_codes--;
return *(nextcodes++);
#ifdef ENABLE_NANORC
if (*nextcodes == MORE_PLANTS) {
nextcodes++;
return get_code_from_plantation();
} else
#endif
return *(nextcodes++);
} else
return ERR;
}
@@ -940,7 +1012,8 @@ int parse_kbinput(WINDOW *frame)
} else if (++escapes > 2)
escapes = (last_escape_was_alone ? 0 : 1);
return ERR;
}
} else if (keycode == ERR)
return ERR;
if (escapes == 0) {
/* Most key codes in byte range cannot be special keys. */
@@ -1172,6 +1245,10 @@ int parse_kbinput(WINDOW *frame)
return INDENT_KEY;
#endif
/* Spurious codes from VTE -- see https://sv.gnu.org/bugs/?64578. */
if (keycode == mousefocusin || keycode == mousefocusout)
return ERR;
switch (keycode) {
case KEY_SLEFT:
shift_held = TRUE;
@@ -1291,79 +1368,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 */
@@ -1377,7 +1423,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
@@ -1392,14 +1437,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);
@@ -1412,7 +1457,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);
@@ -1493,9 +1538,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
@@ -1620,7 +1662,7 @@ int get_mouseinput(int *mouse_y, int *mouse_x, bool allow_shortcuts)
}
#if NCURSES_MOUSE_VERSION >= 2
/* Handle "presses" of the fourth and fifth mouse buttons
* (upward and downward rolls of the mouse wheel) . */
* (upward and downward rolls of the mouse wheel). */
else if (event.bstate & (BUTTON4_PRESSED | BUTTON5_PRESSED)) {
if (in_footer)
/* Shift the coordinates to be relative to the bottom window. */
@@ -2267,7 +2309,7 @@ void statusline(message_type importance, const char *msg, ...)
return;
}
#if !defined(NANO_TINY) && defined(ENABLE_MULTIBUFFER)
#if defined(ENABLE_MULTIBUFFER) && !defined(NANO_TINY)
if (!we_are_running && importance == ALERT && openfile && !openfile->fmt &&
!openfile->errormessage && openfile->next != openfile)
openfile->errormessage = copy_of(compound);
@@ -2427,7 +2469,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++;
}
@@ -2475,6 +2517,9 @@ void place_the_cursor(void)
openfile->current_y = row;
}
/* The number of bytes after which to stop painting, to avoid major slowdowns. */
#define PAINT_LIMIT 2000
/* Draw the given text on the given row of the edit window. line is the
* line to be drawn, and converted is the actual string to be written with
* tabs and control characters replaced by strings of regular characters.
@@ -2543,14 +2588,12 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
/* The match positions of a single-line regex. */
const linestruct *start_line = line->prev;
/* The first line before line that matches 'start'. */
linestruct *end_line = line;
/* The line that matches 'end'. */
regmatch_t startmatch, endmatch;
/* The match positions of the start and end regexes. */
/* First case: varnish is a single-line expression. */
if (varnish->end == NULL) {
while (index < till_x) {
while (index < PAINT_LIMIT && index < till_x) {
/* If there is no match, go on to the next line. */
if (regexec(varnish->start, &line->data[index], 1,
&match, (index == 0) ? 0 : REG_NOTBOL) != 0)
@@ -2598,117 +2641,41 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
/* Assume nothing gets painted until proven otherwise below. */
line->multidata[varnish->id] = NOTHING;
/* Apart from the first row, check the multidata of the preceding line:
* it tells us about the situation so far, and thus what to do here. */
if (row > 0 && start_line != NULL && start_line->multidata != NULL) {
if (start_line->multidata[varnish->id] == WHOLELINE ||
start_line->multidata[varnish->id] == STARTSHERE ||
start_line->multidata[varnish->id] == WOULDBE)
goto seek_an_end;
if (start_line->multidata[varnish->id] == NOTHING ||
start_line->multidata[varnish->id] == ENDSHERE ||
start_line->multidata[varnish->id] == JUSTONTHIS)
goto step_two;
}
if (start_line && !start_line->multidata)
statusline(ALERT, "Missing multidata -- please report a bug");
else
/* The preceding line has no precalculated multidata.
* So, do some backtracking to find out what to paint. */
/* First step: see if there is a line before current that
* matches 'start' and is not complemented by an 'end'. */
while (start_line != NULL && regexec(varnish->start,
start_line->data, 1, &startmatch, 0) == REG_NOMATCH) {
/* There is no start on this line; but if there is an end,
* there is no need to look for starts on earlier lines. */
if (regexec(varnish->end, start_line->data, 0, NULL, 0) == 0)
goto step_two;
start_line = start_line->prev;
}
/* If no start was found, skip to the next step. */
if (start_line == NULL)
goto step_two;
/* If the start has been qualified as an end earlier, believe it. */
if (start_line->multidata != NULL &&
(start_line->multidata[varnish->id] == ENDSHERE ||
start_line->multidata[varnish->id] == JUSTONTHIS))
goto step_two;
/* Maybe there is an end on that same line? If yes, maybe
* there is another start after it? And so on, until EOL. */
while (TRUE) {
/* Begin searching for an end after the start match. */
index += startmatch.rm_eo;
/* If there is no end after this last start, good. */
if (regexec(varnish->end, start_line->data + index, 1, &endmatch,
(index == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH)
break;
/* Begin searching for a new start after the end match. */
index += endmatch.rm_eo;
/* If both start and end match are mere anchors, advance. */
if (startmatch.rm_so == startmatch.rm_eo &&
endmatch.rm_so == endmatch.rm_eo) {
if (start_line->data[index] == '\0')
goto step_two;
index = step_right(start_line->data, index);
/* If there is an unterminated start match before the current line,
* we need to look for an end match first. */
if (start_line && (start_line->multidata[varnish->id] == WHOLELINE ||
start_line->multidata[varnish->id] == STARTSHERE)) {
/* If there is no end on this line, paint whole line, and be done. */
if (regexec(varnish->end, line->data, 1, &endmatch, 0) == REG_NOMATCH) {
wattron(midwin, varnish->attributes);
mvwaddnstr(midwin, row, margin, converted, -1);
wattroff(midwin, varnish->attributes);
line->multidata[varnish->id] = WHOLELINE;
continue;
}
/* If there is no later start on this line, next step. */
if (regexec(varnish->start, start_line->data + index,
1, &startmatch, REG_NOTBOL) == REG_NOMATCH)
goto step_two;
/* Only if it is visible, paint the part to be coloured. */
if (endmatch.rm_eo > from_x) {
paintlen = actual_x(converted, wideness(line->data,
endmatch.rm_eo) - from_col);
wattron(midwin, varnish->attributes);
mvwaddnstr(midwin, row, margin, converted, paintlen);
wattroff(midwin, varnish->attributes);
}
line->multidata[varnish->id] = ENDSHERE;
}
seek_an_end:
/* We've already checked that there is no end between the start
* and the current line. But is there an end after the start
* at all? Because we don't paint unterminated starts. */
if (row == 0) {
while (end_line != NULL && regexec(varnish->end, end_line->data,
1, &endmatch, 0) == REG_NOMATCH)
end_line = end_line->next;
} else if (regexec(varnish->end, line->data, 1, &endmatch, 0) != 0)
end_line = line->next;
/* If there is no end, there is nothing to paint. */
if (end_line == NULL) {
line->multidata[varnish->id] = WOULDBE;
continue;
}
/* If it was already determined that there is no end... */
if (end_line != line && line->prev == start_line && line->prev->multidata &&
line->prev->multidata[varnish->id] == WOULDBE) {
line->multidata[varnish->id] = WOULDBE;
continue;
}
/* If the end is on a later line, paint whole line, and be done. */
if (end_line != line) {
wattron(midwin, varnish->attributes);
mvwaddnstr(midwin, row, margin, converted, -1);
wattroff(midwin, varnish->attributes);
line->multidata[varnish->id] = WHOLELINE;
continue;
}
/* Only if it is visible, paint the part to be coloured. */
if (endmatch.rm_eo > from_x) {
paintlen = actual_x(converted, wideness(line->data,
endmatch.rm_eo) - from_col);
wattron(midwin, varnish->attributes);
mvwaddnstr(midwin, row, margin, converted, paintlen);
wattroff(midwin, varnish->attributes);
}
line->multidata[varnish->id] = ENDSHERE;
step_two:
/* Second step: look for starts on this line, but begin
* looking only after an end match, if there is one. */
index = (paintlen == 0) ? 0 : endmatch.rm_eo;
while (regexec(varnish->start, line->data + index, 1, &startmatch,
(index == 0) ? 0 : REG_NOTBOL) == 0) {
while (index < PAINT_LIMIT && regexec(varnish->start, line->data + index,
1, &startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
/* Make the match relative to the beginning of the line. */
startmatch.rm_so += index;
startmatch.rm_eo += index;
@@ -2746,33 +2713,12 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
continue;
}
/* There is no end on this line. But maybe on later lines? */
end_line = line->next;
while (end_line && regexec(varnish->end, end_line->data,
0, NULL, 0) == REG_NOMATCH)
end_line = end_line->next;
/* If there is no end, we're done with this regex. */
if (end_line == NULL) {
line->multidata[varnish->id] = WOULDBE;
break;
}
/* Paint the rest of the line, and we're done. */
wattron(midwin, varnish->attributes);
mvwaddnstr(midwin, row, margin + start_col, thetext, -1);
wattroff(midwin, varnish->attributes);
line->multidata[varnish->id] = STARTSHERE;
if (end_line->multidata == NULL) {
end_line->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
for (short item = 0; item < openfile->syntax->nmultis; item++)
end_line->multidata[item] = 0;
}
end_line->multidata[varnish->id] = ENDSHERE;
break;
}
}
@@ -2921,6 +2867,8 @@ int update_softwrapped_line(linestruct *line)
/* The end column of the current chunk. */
char *converted;
/* The data of the chunk with tabs and control characters expanded. */
bool kickoff = TRUE;
/* This tells the softwrapping routine to start at beginning-of-line. */
bool end_of_line = FALSE;
/* Becomes TRUE when the last chunk of the line has been reached. */
@@ -2945,7 +2893,7 @@ int update_softwrapped_line(linestruct *line)
starting_row = row;
while (!end_of_line && row < editwinrows) {
to_col = get_softwrap_breakpoint(line->data, from_col, &end_of_line);
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
sequel_column = (end_of_line) ? 0 : to_col;
@@ -3026,13 +2974,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
size_t current_leftedge = *leftedge;
bool kickoff = TRUE;
/* Advance through the requested number of chunks. */
for (i = nrows; i > 0; i--) {
bool end_of_line = FALSE;
current_leftedge = get_softwrap_breakpoint((*line)->data,
current_leftedge, &end_of_line);
current_leftedge, &kickoff, &end_of_line);
if (!end_of_line)
continue;
@@ -3042,6 +2991,7 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
*line = (*line)->next;
current_leftedge = 0;
kickoff = TRUE;
}
/* Only change leftedge when we actually could move. */
@@ -3077,8 +3027,8 @@ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge)
/* Draw a scroll bar on the righthand side of the screen. */
void draw_scrollbar(void)
{
int totallines = openfile->filebot->lineno;
int fromline = openfile->edittop->lineno - 1;
int totallines = openfile->filebot->lineno;
int coveredlines = editwinrows;
if (ISSET(SOFTWRAP)) {
@@ -3163,24 +3113,34 @@ void edit_scroll(bool direction)
}
#ifndef NANO_TINY
/* Get the column number after leftedge where we can break the given text, and
* return it. This will always be editwincols or less after leftedge. Set
* end_of_line to TRUE if we reach the end of the line while searching the
* text. Assume leftedge is the leftmost column of a softwrapped chunk. */
size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
bool *end_of_line)
/* Get the column number after leftedge where we can break the given linedata,
* and return it. (This will always be at most editwincols after leftedge.)
* When kickoff is TRUE, start at the beginning of the linedata; otherwise,
* continue from where the previous call left off. Set end_of_line to TRUE
* when end-of-line is reached while searching for a possible breakpoint. */
size_t get_softwrap_breakpoint(const char *linedata, size_t leftedge,
bool *kickoff, bool *end_of_line)
{
static const char *text;
/* Pointer at the current character in this line's data. */
static size_t column;
/* Column position that corresponds to the above pointer. */
size_t goal_column = leftedge + editwincols;
/* The place at or before which text must be broken. */
size_t breaking_col = goal_column;
/* The column where text can be broken, when there's no better. */
size_t column = 0;
/* Current column position in text. */
size_t last_blank_col = 0;
/* The column position of the last seen whitespace character. */
const char *farthest_blank = NULL;
/* A pointer to the last seen whitespace character in text. */
/* Initialize the static variables when it's another line. */
if (*kickoff) {
text = linedata;
column = 0;
*kickoff = FALSE;
}
/* First find the place in text where the current chunk starts. */
while (*text != '\0' && column < leftedge)
text += advance_over(text, &column);
@@ -3221,26 +3181,29 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
return (editwincols > 1) ? breaking_col : column - 1;
}
/* Get the row of the softwrapped chunk of the given line that column is on,
* relative to the first row (zero-based), and return it. If leftedge isn't
* NULL, return the leftmost column of the chunk in it. */
/* Return the row number of the softwrapped chunk in the given line that the
* given column is on, relative to the first row (zero-based). If leftedge
* isn't NULL, return in it the leftmost column of the chunk. */
size_t get_chunk_and_edge(size_t column, linestruct *line, size_t *leftedge)
{
size_t current_chunk = 0, start_col = 0, end_col;
size_t current_chunk = 0;
bool end_of_line = FALSE;
bool kickoff = TRUE;
size_t start_col = 0;
size_t end_col;
while (TRUE) {
end_col = get_softwrap_breakpoint(line->data, start_col, &end_of_line);
end_col = get_softwrap_breakpoint(line->data, start_col, &kickoff, &end_of_line);
/* We reached the end of the line and/or found column, so get out. */
/* When the column is in range or we reached end-of-line, we're done. */
if (end_of_line || (start_col <= column && column < end_col)) {
if (leftedge != NULL)
*leftedge = start_col;
return current_chunk;
}
current_chunk++;
start_col = end_col;
current_chunk++;
}
}
@@ -3292,9 +3255,10 @@ size_t actual_last_column(size_t leftedge, size_t column)
{
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool kickoff = TRUE;
bool last_chunk = FALSE;
size_t end_col = get_softwrap_breakpoint(openfile->current->data,
leftedge, &last_chunk) - leftedge;
leftedge, &kickoff, &last_chunk) - leftedge;
/* If we're not on the last chunk, we're one column past the end of
* the row. Shifting back one column might put us in the middle of
@@ -3403,6 +3367,12 @@ void edit_refresh(void)
/* When needed and useful, initialize the colors for the current syntax. */
if (openfile->syntax && !have_palette && !ISSET(NO_SYNTAX) && has_colors())
prepare_palette();
if (recook) {
precalc_multicolorinfo();
perturbed = FALSE;
recook = FALSE;
}
#endif
/* If the current line is out of view, get it back on screen. */
@@ -3566,6 +3536,7 @@ void spotlight_softwrapped(size_t from_col, size_t to_col)
size_t leftedge = leftedge_for(from_col, openfile->current);
size_t break_col;
bool end_of_line = FALSE;
bool kickoff = TRUE;
char *word;
place_the_cursor();
@@ -3573,7 +3544,7 @@ void spotlight_softwrapped(size_t from_col, size_t to_col)
while (row < editwinrows) {
break_col = get_softwrap_breakpoint(openfile->current->data,
leftedge, &end_of_line);
leftedge, &kickoff, &end_of_line);
/* If the highlighting ends on this chunk, we can stop after it. */
if (break_col >= to_col) {
@@ -3607,16 +3578,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" */
@@ -3660,17 +3632,15 @@ void do_credits(void)
"Zeyd Ben-Halim",
"Eric S. Raymond",
NULL, /* "and anyone else we forgot..." */
"",
"",
NULL, /* "Thank you for using nano!" */
"",
"",
"",
"",
"(C) 2022",
"(C) 2023",
"Free Software Foundation, Inc.",
"",
"",
"",
"",
"https://nano-editor.org/"
};
@@ -3686,8 +3656,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();
}
@@ -3695,49 +3665,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();

View File

@@ -8,8 +8,8 @@ comment "#"
color ,red " + +"
# Nano's release motto, then name plus version.
color italic,lime "\<[Nn]ano [1-6]\.[0-9][-.[:alnum:]]* "[^"]+""
color brightred "\<(GNU )?[Nn]ano [1-6]\.[0-9][-.[:alnum:]]*\>"
color italic,lime "\<[Nn]ano [1-7]\.[0-9][-.[:alnum:]]* "[^"]+""
color brightred "\<(GNU )?[Nn]ano [1-7]\.[0-9][-.[:alnum:]]*\>"
# Dates
color latte "\<[12][0-9]{3}\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])\>"
@@ -18,7 +18,7 @@ color latte "\<[12][0-9]{3}\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])\>"
color magenta "<[[:alnum:].%_+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}>"
# URLs.
color lightblue "\<https?://\S+\.\S+[^[:space:],.)]"
color lightblue "\<https?://\S+\.\S+[^])>[:space:],.]"
# Bracketed captions in certain config files.
color brightgreen "^\[[^][]+\]$"

View File

@@ -8,8 +8,8 @@ formatter tidy -m -q
# Tags:
color cyan "<[[:alpha:]/!?][^>]*>"
# Bold, italic, and underlined:
color brightmagenta "</?[biu]>"
# Bold, italic, underlined, emphasis, and importance:
color brightmagenta "</?(b|i|u|em|strong)>"
# Named character references:
color red "&[^;[:space:]]*;"

View File

@@ -25,6 +25,16 @@ color brightgreen "^[[:blank:]]*(syntax[[:blank:]]+[^[:space:]]+|(formatter|lint
# Strings
color brightmagenta "[[:blank:]](start=)?".+""
# Function names in string binds
color crimson "\{(help|cancel|exit|savefile|writeout|discardbuffer|insert|where(is|was)|find(previous|next|bracket)|replace)\}"
color crimson "\{(cut|copy|paste|zap|chopword(left|right)|cutrestoffile|execute|mark|speller|linter|formatter|(full)?justify)\}"
color crimson "\{(location|gotoline|(begin|end)para|comment|complete|(un)?indent|wordcount|(record|run)macro|anchor|undo|redo)\}"
color crimson "\{(left|right|up|down|home|end|(scroll|page)(up|down)|center|(prev|next)(word|block|anchor|buf))\}"
color crimson "\{(tab|enter|delete|backspace|verbatim|refresh|suspend|casesens|regexp|backwards|older|newer|(dos|mac)format)\}"
color crimson "\{(append|prepend|backup|flip(goto|replace|execute|pipe|convert|newbuffer)|browser|gotodir|(first|last)(file|line))\}"
color crimson "\{(nohelp|constantshow|softwrap|linenumbers|whitespacedisplay|nosyntax|zero)\}"
color crimson "\{(smarthome|autoindent|cutfromcursor|breaklonglines|tabstospaces|mouse|\{)\}"
# Commands
color green "^[[:blank:]]*((un)?(bind|set)|include|syntax|header|magic|comment|formatter|linter|tabgives|extendsyntax)\>"
color magenta "^[[:blank:]]*i?color\>|[[:blank:]](start=|end=)"

View File

@@ -5,8 +5,22 @@ header "^#!.*perl"
magic "Perl script"
comment "#"
color red "\<(accept|alarm|atan2|bin(d|mode)|c(aller|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\>" "\<(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\>" "\<(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\>" "\<(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\>" "\<(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\>"
color magenta "\<(continue|else|elsif|do|for|foreach|if|unless|until|while|eq|ne|lt|gt|le|ge|cmp|x|my|sub|use|package|can|isa)\>"
# Functions.
color red "\<(abs|accept|alarm|atan2|bin(d|mode)|bless|caller|ch(dir|mod|op|omp|own|r|root)|close(dir)?|connect|cos|crypt)\>"
color red "\<(dbm(close|open)|defined|delete|dump|each|eof|eval(bytes)?|exec|exists|exp|fc|fcntl|fileno|flock|fork|format|formline)\>"
color red "\<(get(c|login|peername|pgrp|ppid|priority|(gr|pw)nam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport))\>"
color red "\<(([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|glob|gmtime|grep|hex|import|index|int|ioctl|join)\>"
color red "\<(keys|kill|lc|lcfirst|length|link|listen|local(time)?|lock|log|lstat|map|mkdir|msg(ctl|get|snd|rcv)|oct)\>"
color red "\<(open(dir)?|ord|pack|pipe|pop|pos|printf?|prototype|push|q|qq|qr|qx|qw|quotemeta|rand|read(dir|line|link|pipe)?)\>"
color red "\<(recv|redo|ref|rename|require|reset|reverse|rewinddir|rindex|rmdir|say|scalar|seek(dir)?|select|sem(ctl|get|op))\>"
color red "\<(send|set(pgrp|priority|sockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|splice|split)\>"
color red "\<(sprintf|sqrt|srand|state?|study|substr|symlink|sys(call|open|read|seek|tem|write)|tell(dir)?|tied?|times?|try?)\>"
color red "\<(truncate|uc|ucfirst|umask|un(def|link|pack|shift|tie)|utime|values|vec|wait(pid)?|wantarray|warn|write)\>"
# Control flow, logical operators, declarations.
color magenta "\<(continue|die|do|else|elsif|exit|for(each)?|fork|goto|if|last|next|return|unless|until|while)\>"
color magenta "\<(and|cmp|eq|ge|gt|isa|le|lt|ne|not|or|x|xor)\>"
color magenta "\<(my|no|our|package|sub|use)\>"
# Variable names.
color cyan "[$%&@]([A-Za-z_][0-9A-Za-z_]*|\^[][A-Z?\^_]|[0-9]+)\>"
@@ -14,8 +28,10 @@ color cyan "[$%&@]\{(\^?[A-Za-z_][0-9A-Za-z_]*|\^[][?\^][0-9]+)\}"
color cyan "[$%&@]([][!"#'()*+,.:;<=>?`|~-]|\{[][!-/:-@\`|~]\})|\$[$%&@]"
color cyan "(^|[[:blank:]])[$%@][/\]"
# Strings.
color yellow "".*"|qq\|.*\|"
color white "[sm]/.*/"
color white "[smy]/.*/"
color white start="(^use| = new)" end=";"
# Comments.

View File

@@ -5,6 +5,7 @@ header "^#!.*python"
magic "Python script"
comment "#"
# Alternative linter: pylint --exit-zero
linter pyflakes
# Function definitions.
@@ -23,6 +24,9 @@ color brightcyan "\<(exec|print)([[:blank:]]|$)"
# Special values.
color brightmagenta "\<(False|None|True)\>"
# Decorators.
color cyan "@[[:alpha:]_][[:alnum:]_.]*"
# Mono-quoted strings.
color brightgreen "'([^'\]|\\.)*'|"([^"\]|\\.)*"|'''|""""
color normal "'''|""""

View File

@@ -5,18 +5,29 @@ magic "Tcl(/Tk)? script"
comment "#"
# Standard Tcl [info commands]:
color green "\<(after|append|array|auto_execok|auto_import|auto_load|auto_load_index|auto_qualify|binary|break|case|catch|cd|clock|close|concat|continue|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|file|fileevent|flush|for|foreach|format|gets|glob|global|history|if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort|namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return|scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace|unknown|unset|update|uplevel|upvar|variable|vwait|while)\>"
color green "\<(after|append|array|auto_(execok|import|load(_index)?|qualify)|binary|break)\>"
color green "\<(case|catch|cd|clock|close|concat|continue|encoding|eof|error|eval|exec|exit|expr)\>"
color green "\<(fblocked|fconfigure|fcopy|file(event)?|flush|for|foreach|format|gets|glob|global|history)\>"
color green "\<(if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort)\>"
color green "\<(namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return)\>"
color green "\<(scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace)\>"
color green "\<(unknown|unset|update|uplevel|upvar|variable|vwait|while)\>"
# Basic Tcl subcommands:
color green "\<array (anymore|donesearch|exists|get|names|nextelement|set|size|startsearch|statistics|unset)\>"
color green "\<string (bytelength|compare|equal|first|index|is|last|length|map|match|range|repeat|replace|to|tolower|totitle|toupper|trim|trimleft|trimright|will|wordend|wordstart)\>"
color green "\<string (compare|equal|first|index|is|last|(byte)?length|map|match|range|repeat|replace|to(lower|title|upper)?|trim(left|right)?|will|word(end|start))\>"
# Extended TclX [info commands]:
color green "\<(alarm|auto_load_pkg|bsearch|catclose|catgets|catopen|ccollate|cconcat|cequal|chgrp|chmod|chown|chroot|cindex|clength|cmdtrace|commandloop|crange|csubstr|ctoken|ctype|dup|echo|execl|fcntl|flock|fork|fstat|ftruncate|funlock|host_info|id|infox|keyldel|keylget|keylkeys|keylset|kill|lassign|lcontain|lempty|lgets|link|lmatch|loadlibindex|loop|lvarcat|lvarpop|lvarpush|max|min|nice|pipe|profile|random|readdir|replicate|scancontext|scanfile|scanmatch|select|server_accept|server_create|signal|sleep|sync|system|tclx_findinit|tclx_fork|tclx_load_tndxs|tclx_sleep|tclx_system|tclx_wait|times|translit|try_eval|umask|wait)\>"
color green "\<(alarm|auto_load_pkg|bsearch|cat(close|gets|open)|ccollate|cconcat|cequal|chgrp|chmod|chown|chroot)\>"
color green "\<(cindex|clength|cmdtrace|commandloop|crange|csubstr|ctoken|ctype|dup|echo|execl)\>"
color green "\<(fcntl|flock|fork|fstat|ftruncate|funlock|host_info|id|infox|keyl(del|get|keys|set)|kill)\>"
color green "\<(lassign|lcontain|lempty|lgets|link|lmatch|loadlibindex|loop|lvar(cat|pop|push)|max|min|nice)\>"
color green "\<(pipe|profile|random|readdir|replicate|scan(context|file|match)|select|server_(accept|create)|signal)\>"
color green "\<(sleep|sync|system|tclx_(findinit|fork|load_tndxs|sleep|system|wait)|times|translit|try_eval|umask|wait)\>"
# Syntax:
color green "[!$&();<=>\`|]"
color brightblue "\<proc[[:blank:]]|\{|\}"
color green "\(|\)|\;|`|\\|\$|<|>|!|=|&|\|"
color brightyellow ""([^"\]|\\.)*"|'([^'\]|\\.)*'"
color brightred "\$\{?[0-9A-Za-z_!@#$*?-]+\}?"

View File

@@ -5,18 +5,22 @@ header "<\?xml.*version=.*\?>"
magic "(XML|SGML) (sub)?document"
comment "<!--|-->"
# The entire content of the tag:
# First the entire content of the tag (for the attributes):
color green start="<" end=">"
# The angled brackets and the name of the tag:
color cyan "<[^> ]+|>"
color cyan "<[^> ]+|/?>"
# The strings inside the tag:
color magenta ""[^"]*""
# Prolog stuff:
color #888 "<\?.+\?>|<!DOCTYPE[^>]+>|\]>"
color #888 start="<!DOCTYPE[^>]*$" end="^[^<]*>"
# Comments:
color yellow start="<!DOCTYPE" end="[/]?>"
color yellow start="<!--" end="-->"
# Escapes:
color red "&[^;]*;"
# Entities (custom and predefined):
color pink "&[^; ]+;"
color red "&(amp|apos|gt|lt|quot);"