Compare commits

...

608 Commits

Author SHA1 Message Date
c56bbe74bf Merge in changes from upstream 2026-08-12 16:33:21 -07:00
Benno Schulenberg
8e6360d166 po: update translations and regenerate POT file and PO files 2026-07-31 08:26:25 +02:00
Benno Schulenberg
4e8238edec bump version numbers and add a news item for the 9.2 release 2026-07-31 08:00:11 +02:00
Benno Schulenberg
c497a5f90b copyright: update the years for significantly changed files 2026-07-29 15:25:04 +02:00
Benno Schulenberg
b04a2a18ea docs: in the FAQ, adjust the wording in the item about multiple buffers
That is: mention also the new option names --newbuffer / set newbuffer.

And don't mention M-< and M-> for switching between buffers, as those
keystrokes have been reassigned to horizontal scrolling since nano-9.0.
2026-07-29 15:01:34 +02:00
Benno Schulenberg
613fe4b9b2 docs: improve the description of the flipnewbuffer bindable function 2026-07-29 15:01:34 +02:00
Benno Schulenberg
27bf87d21a docs: implement the renaming of --multibuffer to --newbuffer 2026-07-28 10:42:56 +02:00
Benno Schulenberg
b6faa5d5bb tweaks: rename the internal flag, to match the new name of the option
It also better distinguishes it from the ENABLE_MULTIBUFFER thing.
2026-07-28 10:42:56 +02:00
Benno Schulenberg
4ebd490225 options: add --newbuffer as a more fitting synonym of --multibuffer
It matches the "New Buffer" description of the M-F toggle in the file-
insertion menu, similar to how --noconvert matches "No Conversion".

(This should have been done ages ago, but it never occurred to me.)
2026-07-28 10:42:56 +02:00
Benno Schulenberg
f6e9c00f59 gnulib: update to its current upstream state 2026-07-25 09:15:11 +02:00
Benno Schulenberg
79b18f462c screen: do a full refresh for Shift+Home and Shift+End when needed
That is: make line_needs_update(), when the mark is on, return TRUE
only when "page start" for old and new cursor position are the same
OR, otherwise, when NOT doing whole-window sidescrolling (that is:
when --solosidescroll is active).

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

Bug existed since version 9.0, since whole-window sideways scrolling
was introduced.
2026-07-24 16:44:18 +02:00
Benno Schulenberg
ff68fa7304 tweaks: replace an if with an else
When the identical item is not the first one, then it necessarily has
a preceding item, so there is no need to check its `prev` pointer.
2026-07-24 11:28:38 +02:00
Benno Schulenberg
b6aa309aa7 tweaks: elide an auxiliary variable that is no longer needed 2026-07-24 09:20:00 +02:00
Benno Schulenberg
6e39b405c8 tweaks: don't renumber all history items -- "renumber" only the last
Only the `lineno` of the last history item is ever referenced, so...
adjust only that number when an item is removed from the list.

This works, because whenever an item is added, it is added after the
last item, giving it automatically that item's line number plus one.

Also, make the relevant comparison a little more robust.
2026-07-23 16:29:20 +02:00
Benno Schulenberg
0c3e596ad7 tweaks: elide an unneeded auxiliary variable 2026-07-23 10:56:02 +02:00
Benno Schulenberg
b41de01e6c tweaks: drop four null-derefence guards that are no longer needed
Since the previous commit, the history routines no longer make use
of splice_node() and unlink_node(), so now `openfile` will always
have a value when these functions are called.
2026-07-23 10:40:24 +02:00
Benno Schulenberg
e075df83e9 tweaks: don't call unlink_node() nor splice_node() for history items
This makes use of some knowledge about history lists: that there is
always another item when an identical item is found (because each
list ends with an empty item), that there is no item before the
head of the list, and that a new item is always added at the end.

This code is not time critical, but not calling splice_node() when
populating the search histories during startup saves upto three
hundred function calls, double the number of ifs, and triple the
number of assignments...  Several tens of microseconds.
2026-07-23 10:40:24 +02:00
Benno Schulenberg
1cff717d98 tweaks: adjust the style of a comment and the order of a comparison
Use the same style and order as used in the two succeeding functions.
2026-07-22 16:15:02 +02:00
Benno Schulenberg
68d4b84610 startup: do not crash when a section of a history file is overlong
That is: do not dereference a null pointer when -- during startup, when
no files have been opened yet -- the search history file is read in and
a section contains more than the maximum number of items.

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

Bug existed since version 4.2, commit 34d22d3f.
2026-07-22 16:04:42 +02:00
Benno Schulenberg
a41f238042 tweaks: avoid a false positive when doing static analysis
(Found with Clang's `scan-build`.)
2026-07-20 10:48:28 +02:00
Benno Schulenberg
e18c6c95e7 tweaks: drop an unneeded null-dereference guard
The function delete_node() is called right after this and
it dereferences `openfile` twice, without a guard, so...

(Found with Clang's `scan-build`.)
2026-07-20 10:48:28 +02:00
Benno Schulenberg
c4948d5035 tweaks: drop three assignments of function results, as they are not used
(Found with Clang's `scan-build`.)
2026-07-20 10:48:28 +02:00
Benno Schulenberg
4c3ab6f5fb docs: say thanks to the Italian, Kazakh, and Arabic translators 2026-07-17 11:01:02 +02:00
Vincent Yang
757ce59330 startup: quit when standard output is not a TTY, to avoid user confusion
There is no reason to redirect nano's output, as it is just a lot of
ANSI codes, so not allowing this redirection has no negative effect.

But forbidding the redirection will prevent users from accidentally
doing so and then getting stuck, not realizing what has happened.

Signed-off-by: Vincent Yang <yang.vincent.h@icloud.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-07-15 16:28:01 +02:00
Benno Schulenberg
9375b99c52 tweaks: exclude three error checks from a normal build
Unknown or mismatching undo types would be programming errors -- they
could only occur if a new type were added and not properly handled.
2026-07-14 10:18:42 +02:00
Benno Schulenberg
50df473643 tweaks: drop several unneeded elses, and correct an indentation 2026-07-14 08:30:41 +02:00
Benno Schulenberg
0c242b8666 docs: reword and reshuffle the line about saving-and-exiting 2026-07-10 11:11:22 +02:00
Benno Schulenberg
96adcef377 doc: in the FAQ, adjust the description of the Ctrl+T toggle 2026-07-09 10:42:11 +02:00
Benno Schulenberg
a6046c6668 docs: add a reference to the texi manual, via info and online 2026-07-08 17:00:07 +02:00
Benno Schulenberg
cfb9c08580 docs: explicitly mention in the man page how to save and exit
These are the two most important commands, so it's good to have them
in the man page, especially since the help lines do not list ^S.

Inspired-by: Sébastien Desreux <seb@h-k.fr>
2026-07-08 16:29:51 +02:00
Benno Schulenberg
fde24946da bindings: add a blind ^T toggle in the WhereIs and GotoLine menus
"Blind" meaning that the toggle is not shown in the help lines
nor in the help text, and that its function (`flipgoto`) cannot
be bound to another keystroke.

This addresses https://savannah.gnu.org/bugs/?68503 and
https://lists.gnu.org/archive/html/nano-devel/2026-07/msg00006.html.

Apparently there are some users who are in the habit of typing ^W^T
when they want to jump to a specific line.  Avoid frustrating their
muscle memory.

In other words: handle ^W^T and ^/^T similar to how ^W^Y and ^W^V
are handled since commit 8e302738 from seven years ago.
2026-07-08 15:34:21 +02:00
Benno Schulenberg
9797150ffd docs: mention in the FAQ how to get the ^W^T combo back
(Although ^/ and M-G have existed since nano's initial revision.)
2026-07-06 11:49:28 +02:00
Benno Schulenberg
d43809146f tweaks: invert two ifs, to reduce duplication of code
Also, drop two unneeded initializations.
2026-07-06 11:47:27 +02:00
Benno Schulenberg
2c1bbb5552 tweaks: reshuffle two declarations and rename the function in one of them
Also, drop a redundant call of fflush() -- copy_file() already did it.
2026-07-05 13:56:12 +02:00
Benno Schulenberg
f63547027c tweaks: treat temp file for speller in similar way as for formatter 2026-07-05 11:14:12 +02:00
Benno Schulenberg
ab597a6c2f tweaks: rename a variable while inverting its logic
Now the name actually conveys the purpose of the variable.
2026-06-30 07:34:15 +02:00
Benno Schulenberg
9383ed03a2 files: compare either only full names or bare names, not full with bare
And in the bargain get rid of the wrapped and nested conditionals,
which was hard to understand.
2026-06-30 07:23:09 +02:00
Benno Schulenberg
e1d954c739 docs: fix a typo in NEWS
(It went unnoticed because the local rule colorized also invalid dates.)
2026-06-23 08:07:35 +02:00
Benno Schulenberg
6d98026285 po: update translations and regenerate POT file and PO files 2026-06-23 07:46:24 +02:00
Benno Schulenberg
21d5d8707f bump version numbers and add a news item for the 9.1 release 2026-06-23 07:10:48 +02:00
Benno Schulenberg
982bca3bd3 tweaks: swap the two arms of an 'if', to have the positive case first
Also, put the actions in the two arms in the same order.
And add a comment, while dropping two unneeded ones.
2026-06-21 11:31:29 +02:00
Benno Schulenberg
834b88eed9 tweaks: rename three variables, to be more descriptive 2026-06-21 11:05:26 +02:00
Benno Schulenberg
b273b69cad tweaks: elide an unneeded parameter, and improve the related comment
And drop two other overexplicative comments.
2026-06-21 11:05:26 +02:00
Benno Schulenberg
81a3c3e82f syntax: c: add several missing C++23 keywords
References:
  https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf
  https://en.wikipedia.org/wiki/C++23
2026-06-20 16:04:31 +02:00
Benno Schulenberg
cebb2a383d tweaks: in the C syntax, gather all type specifiers into one regex
And put all lowercase type modifiers into a second regex.

Also, move 'register' and 'volatile' to the modifiers regex
-- the remaining ones in the last “green” regex are all C++
keywords, but that list is far from complete.

Furthermore, make the regex for binary and hex more succinct
-- the final \> will prevent an apostrophe from coming last.
2026-06-18 08:54:50 +02:00
Vincent Yang
2adaa1139c syntax: c: add new C23 keywords and preprocessor directives
A summary of the changes:
  https://en.wikipedia.org/wiki/C23_(C_standard_revision)

An accessible draft of the standard:
  https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf

Signed-off-by: Vincent Yang <yang.vincent.h@icloud.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-06-17 07:51:04 +02:00
Benno Schulenberg
ad92fe6638 syntax: c: colorize hexadecimal and binary numbers, and boolean constants
C23 introduced binary numbers (things like 0b101010) and predefined
constants 'true', 'false', and 'nullptr'.  Colorize them specially,
and colorize hexadecimal numbers too, for good measure.

(Note that binary and hexadecimal numbers may contain apostrophes,
for separating groups of digits, for better legibility.)

Inspired-by: Vincent Yang <yang.vincent.h@icloud.com>
2026-06-17 07:51:04 +02:00
Benno Schulenberg
4b21ed39c7 tweaks: harmonize the form of two error messages with two others
Two identical messages were adjusted a week ago, in commit 96cf1b38,
but these two in another file were overlooked.
2026-06-14 10:31:29 +02:00
Benno Schulenberg
21b833d423 gnulib: update to its current upstream state 2026-06-14 08:38:23 +02:00
Benno Schulenberg
afb9cdac24 help: further improve and modernize the Spellcheck help text
The previous commit changed the help text for the Spell Checker,
so this is a good time to further improve that text.  That is:
speak of "buffer" instead of "file", speak of "marked region"
instead of "selected text", make use of the standard phrase for
introducing the function keys, and modernize the title: wrap it
in "===" and don't include the redundant "Help Text".

Most of all, tune the text to the actual phase of the process:
here the user can make spelling *corrections* -- the checking
has already been done.
2026-06-14 08:07:07 +02:00
Benno Schulenberg
ca9d6e7dec help: use a better word in the Spellcheck help text
Suggested-by: Mirko Adam <development@four-m.de>
2026-06-13 12:35:57 +02:00
Benno Schulenberg
03a1a00ef3 help: remember, clear, and restore the value of 'spotlighted'
Otherwise the help viewer would attempt to highlight something random,
*and* the original highlighting would be gone after closing the viewer.

This fixes https://savannah.gnu.org/bugs/?68443.
Reported-by: Mirko Adam <development@four-m.de>

The underflow bug existed since version 6.0, commit 8762e046,
the spotlight-losing bug since version 5.6, commit 37717bae.
2026-06-13 12:25:41 +02:00
Benno Schulenberg
1e5c40765d docs: add an xclip example binding for copying text to system clipboard
For some reason, `xclip` needs to have its stdout and stderr forcibly
closed to make it stop running after it has ingested text.

That solution was found here:
  https://github.com/astrand/xclip/issues/34#issuecomment-686744880

This addresses https://savannah.gnu.org/bugs/?68444.
2026-06-13 12:00:34 +02:00
Benno Schulenberg
67af31e8f3 tweaks: move a function, improve three comments, and rename a parameter 2026-06-12 10:43:04 +02:00
Benno Schulenberg
57d70fedf1 tweaks: don't use index 0 when no higher indexes are used 2026-06-11 09:18:41 +02:00
Benno Schulenberg
bf4bc730c4 tweaks: slightly adjust two wordings in the main man page 2026-06-09 12:52:23 +02:00
Benno Schulenberg
6adbd4249e docs: move the notices in the main man page to after the description
For new users, the description is more important than the notices,
and... old users probably don't look at the man page anyway.

(Arguably, the notices should be moved to after the editing section,
but I don't like how things look then.)
2026-06-09 12:52:23 +02:00
Benno Schulenberg
96cf1b3807 tweaks: harmonize the form of five error messages 2026-06-09 12:31:51 +02:00
Benno Schulenberg
be46139504 files: report an error when the given filename ends in a slash
When the specified name (including the final slash) is not an existing
directory, then reject it as an invalid name -- instead of complaining
later, when the user tries to save the buffer, that the specified name
is a folder, which isn't actually true.

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

Buglet existed since before version 2.0.0.
2026-06-08 12:49:37 +02:00
Benno Schulenberg
61abc2e59a files: make get_full_path() work properly also for nonexistent files
That is: make it conform to the function's comment, which says that it
returns the canonical path when this path exists (and is reachable).

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

Problem existed since version 6.3, commit fdd946c0.
2026-06-08 11:22:11 +02:00
Benno Schulenberg
b53833c4f3 tweaks: make three different error messages identical to an existing one
(This saves some seventy bytes of string storage, as all the
"new" strings already exist somewhere else in the code.)
2026-06-08 08:26:49 +02:00
Benno Schulenberg
f6d38a5be0 tweaks: harmonize checking the exit status of a child process 2026-06-08 08:19:30 +02:00
Benno Schulenberg
00d137baf3 tweaks: harmonize seven more error checks with similar ones 2026-06-08 08:15:07 +02:00
Benno Schulenberg
27244483fe tweaks: modernize a URL 2026-06-06 11:17:13 +02:00
Benno Schulenberg
78f7424f37 tweaks: reshuffle and adjust a comment while dropping an unneeded 'else' 2026-06-04 20:59:15 +02:00
Benno Schulenberg
2a9121fc2d files: don't bother updating notes when closing the buffer right after
There's no point in statting the file again in write_file() after it's
been written to disk when immediately afterward the buffer gets closed.
2026-06-04 20:53:09 +02:00
Benno Schulenberg
c77a5e5169 tweaks: elide a parameter from write_file() and write_region_to_file()
The non-normality of the file to be written is easily expressed as
a separate writing method: SPECIAL.
2026-06-04 12:04:42 +02:00
Benno Schulenberg
21bedd0db9 tweaks: harmonize three error checks with those of similar calls 2026-06-04 07:40:11 +02:00
Benno Schulenberg
7fe76a4dfb tweaks: slightly improve a sentence in the nanorc manpage
(Making the same change as was what sneaked into commit 66da03e5.)
2026-06-03 19:46:07 +02:00
Benno Schulenberg
fd72375aa4 history: don't leave NUL bytes in the string of anchors
When restoring a series of anchors, don't ruin the string by leaving
a NUL byte after each number -- restore each space that was there.

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

Bug existed since version 8.5, commit 60e2f2ba, since the saving
and restoring of anchors was introduced.
2026-06-03 12:50:42 +02:00
Benno Schulenberg
e9c0c8b930 docs: prevent highlighted words in the man pages from getting hyphenated 2026-06-01 12:39:30 +02:00
Benno Schulenberg
66da03e555 docs: fix a typo made a month ago, in commit 269b96b7
While adjusting Branden's patch for the changed state of the repo,
I must have mistyped the second \% in that diff.
2026-06-01 12:39:06 +02:00
Benno Schulenberg
382bcc77c0 docs: mention that M-Ins and M-Del are valid keynames
Also colorize them as valid.
2026-06-01 09:04:51 +02:00
Benno Schulenberg
dbc1f29296 rcfile: allow rebinding M-Ins and M-Del
Allowing to rebind M-Del gives the user the chance to make M-Bsp and
M-Del do symmetrical things: delete a word leftward and rightward,
respectively.  With --modernbindings, ^H calls `help` and thus the
user can no longer bind this code to `chopwordleft` to make Ctrl+Bsp
behave symmetrically to Ctrl+Del.  So, to give the user the chance
to still have symmetrical Bsp/Del combos, allow to rebind M-Del.

(Allowing to rebind M-Ins is just for symmetry -- on my two laptops
that key combination is dead: it does not produce any keycode.)
2026-06-01 09:04:51 +02:00
Benno Schulenberg
799577b4df tweaks: rename a variable, for aptness, and remove unneeded braces 2026-06-01 09:04:51 +02:00
Benno Schulenberg
57e2cc251d tweaks: unwrap some seventy lines that don't need to be wrapped
(This assumes a more modern terminal width of 100 columns.  And it
allows to exercise nano's horizontal-scrolling feature on terminals
that have the old 80-column standard width.)
2026-06-01 09:04:51 +02:00
Benno Schulenberg
8cb86c9582 files: do not call chmod() and chown() on a .save emergency file
The reason to not call chmod() on a partially edited file is that this
file may contain stuff that the person who did the editing may not want
others to see.  Whereas calling chown() is pointless for normal users,
and would be falsifying information for root.

(This does oblige the user to do `cp file.save file && rm file.save`
instead of the simple `mv file.save file` to recover the partially
edited file.  But... .save files should be such a seldom occurrence
that this extra step should not be a problem.)

This addresses the third part of
  https://lists.gnu.org/archive/html/nano-devel/2026-05/msg00040.html.
Reported-by: Arjun Basnet <disclose@securin.io>

The minor problem existed since version 2.2.0, since the chmod()
and chown() were added in 2009, in commit 123110c5, upon a request
by Mike Frysinger made in https://savannah.gnu.org/bugs/?27273.
2026-05-29 09:07:42 +02:00
Benno Schulenberg
e4852e4f56 tweaks: improve a comment, add one, and move one
Also, normalize the spelling of two keystrokes in an old news item.
2026-05-29 09:06:08 +02:00
Benno Schulenberg
2abf56546b tweaks: condense a comment, rename a function, and reshuffle four lines 2026-05-29 09:05:49 +02:00
Benno Schulenberg
02825602e2 linting: properly check for a negative return value from read()
This addresses the second part of
  https://lists.gnu.org/archive/html/nano-devel/2026-05/msg00040.html.
Reported-by: Arjun Basnet <disclose@securin.io>

Problem existed since version 2.3.3, commit 5575bfad.
2026-05-29 09:03:55 +02:00
Benno Schulenberg
0daeab17cd tweaks: reshuffle two lines of code, to avoid a memory leak 2026-05-25 15:32:56 +02:00
Benno Schulenberg
6b49b498cc spelling: properly check for a negative return value from read()
This addresses the first part of
  https://lists.gnu.org/archive/html/nano-devel/2026-05/msg00040.html.
Reported-by: Arjun Basnet <disclose@securin.io>

Problem existed since version 1.1.8, commit f21f3fcc.
2026-05-25 15:29:17 +02:00
Benno Schulenberg
924190ce7d tweaks: compare two syntaxes directly, instead of comparing their names
In theory two different syntaxes could have the same name, so comparing
their names was actually incorrect.
2026-05-24 07:21:30 +02:00
Benno Schulenberg
4a347cd7dc search: place the viewport flush left when a match easily fits within it
This avoids having the viewport positioned slightly to the right
when an earlier match needed it shifted and the current match is
somewhere near the beginning of the line.  I found that behavior
annoying, especially when the entire line fit within the viewport.
2026-05-23 09:44:15 +02:00
Benno Schulenberg
1e022b55d1 tweaks: avoid miscompilation on macOS, where 'st_atim' is unknown
Since commit d0ee91f4 from earlier today, the full timestamp is used
('st_atim' instead of 'st_atime', for example).  As macOS does not
seem to know the shorter names (see commit f516cddc from seven years
ago), define those shorter names when compiling for macOS.
2026-05-22 11:51:47 +02:00
Benno Schulenberg
29ff6abec6 tweaks: check calls of stat() for success instead of for not-failure 2026-05-22 11:51:47 +02:00
Benno Schulenberg
054b478999 tweaks: remove a fragment of code that is redundant since previous commit 2026-05-22 11:51:47 +02:00
Benno Schulenberg
e6ce29d531 files: always make a backup when the WriteOut prompt says "[Backup]"
Nano should do what it says: when it says "[Backup]" at the prompt,
it must make a backup.  No exceptions.

True, this might overwrite an earlier backup (that the user might wish
to keep) with work by another user, but really... when multiple users
could be editing a file, this file should be under version control.

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

Bug existed since before version 2.0.0.
2026-05-22 10:44:22 +02:00
Benno Schulenberg
b3c195ef00 files: use the correct timestamp for the backup file
When overwriting another file, or when appending or prepending to it,
the backup file should get the original timestamp of that other file,
not the timestamp of the file in the current buffer.

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

Bug existed since before version 2.0.0.
2026-05-22 10:17:52 +02:00
Benno Schulenberg
f0b1606f28 tweaks: move two assignments to where they are used
Also, drop a pointless 'static' specifier, and slightly rename
the variable, to be more fitting (as it holds two times).
2026-05-22 10:06:35 +02:00
Benno Schulenberg
d0ee91f4eb files: for a backup, use the full timestamp, not just the seconds 2026-05-22 10:02:37 +02:00
Benno Schulenberg
266a4fc748 files: allow editing a file named ~ (a lone tilde)
Nano cannot edit directories, so when the user specifies a solitary
tilde on the command line, they can only mean a file by that name.

(Other editors behave like this too, with the exception of Emacs.)

This addresses https://savannah.gnu.org/bugs/?68373.
Reported-by: Chris Martin <987687@gmail.com>
2026-05-22 08:54:52 +02:00
Benno Schulenberg
d985946ef5 syntax: lua: colorize also various backslash escapes specially
Main reference:
  https://lua.org/manual/5.5/manual.html#3.1

Also, give strings and numbers a more visible color -- red was too dark.
2026-05-21 11:23:27 +02:00
Benno Schulenberg
9644ca0ca5 syntax: lua: add new keywords and drop long-deprecated ones
• add operators `&`, `|`, and `~` (Lua-5.3)
• add statements `goto` (Lua-5.2) and `global` (Lua-5.5)
• drop `math` functions `atan2`, `cosh`, `sinh`, and `pow`
  (deprecated by Lua-5.3, `frexp` and `ldexp` returned in Lua-5.5)
• drop function `module` (deprecated since Lua-5.2)
• drop `package.seeall` (gone together with `module`)
• drop functions `getfenv` and `setfenv` (gone from Lua-5.2)
• drop functions `math.log10` and `table.maxn` (Lua-5.2)
• move function `unpack` to the `table` library (Lua-5.2)
• drop `math.mod` (renamed to `math.fmod` since Lua-5.1)
• add function `table.create` (Lua-5.5)
• add function `warn` (Lua-5.4)

Also, colorize only `==` as an operator, not a lone `=`,
because coloring also the latter looked too garish.

Furthermore, colorize labels (`::somename::`) specially,
and give _G and _VERSION from the rule for basic functions
their own rule as they are not functions.

Main reference:
  https://lua.org/manual/5.5/contents.html#index
2026-05-21 07:48:58 +02:00
Benno Schulenberg
83f0a593fd syntax: lua: colorize also multiline strings
This coloring rule existed since the syntax for Lua was added
(fifteen years ago, in commit 090e2cf7), but it was commented
out -- probably because it came after the coloring rule for
multiline comments, and would thus recolor those comments red.

Seven years later, commit 21cd953e removed the inactive rule,
but after just seven months, commit bf594939 swapped the order
of the coloring rules for strings and comments, and since then
a coloring rule for multiline strings would have worked right.

(Also, remove a rule that doesn't make sense -- the one that
colored everything between [[ and ]] in brightwhite first.)
2026-05-19 16:12:01 +02:00
G. Branden Robinson
3948c09d2b docs: more consistently set nano's name in bold
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-05-16 15:19:49 +02:00
Benno Schulenberg
b89ab4a99d docs: italicize 'nanorc' in the rnano manpage, like in the other manpages
(This should have been included in commit 5660833c, but I forgot.)
2026-05-16 15:19:49 +02:00
Benno Schulenberg
c04aa40543 docs: remove the description of the flipgoto toggle
The toggle itself was removed three commits ago.

Also, remove `flipgoto` from the relevant syntax file.
2026-05-11 11:25:23 +02:00
Benno Schulenberg
6ee4c67226 tweaks: adjust two translator hints and add two after the previous change
The available space for some has increased.
2026-05-11 11:25:23 +02:00
Benno Schulenberg
b70851e488 help: unabbreviate three words, in three different help items
And adjust two prompt modifiers to match those new help items better.
2026-05-11 11:25:23 +02:00
Benno Schulenberg
7cf20d7227 menus: remove the ^T toggle between the Where-Is and Go-To-Line menus
The `flipgoto` toggle (^T) made for an uneven number of help items in
the Where-Is and Go-To-Line menus, and an odd item doesn't look good.
Also, removing the ^T toggle from the Where-Is menu makes its number
of help items equal to that of the Replace menu, which looks nice
when toggling between the two with ^R.  And reducing the number of
help items gives the remaining ones more space, which will allow to
unabbreviate three of them in the next commit, which will look better.

Furthermore, this gets rid of the strange and unclear "Go To Text" tag
in the Go-To-Line menu.

Users who insist on having the ^T toggle can help themselves:

  bind ^T "{cancel}{gotoline}" search
  bind ^T "{cancel}{whereis}" gotoline

The only difference with the old behavior is that these bindings
don't preserve what was typed at the prompt before ^T was hit.
2026-05-11 11:25:23 +02:00
Benno Schulenberg
355a5a3bfa tweaks: rename a few variables, to harmonize with the general scheme
Also, having both `openfile->current` and `is_current` was confusing:
which one held the actual current value?
2026-05-11 11:25:08 +02:00
Benno Schulenberg
6c3e9848b2 tweaks: drop most != '\0' comparisons 2026-05-11 11:12:03 +02:00
Benno Schulenberg
ac83dddcd2 tweaks: drop most != NULL comparisons
They are redundant, are not used in several other places,
and not having them gives more contrast with `== NULL`.
2026-05-10 12:16:12 +02:00
Benno Schulenberg
e40ba24d89 tweaks: adjust the suggested max help-item length in six translator hints
Five of the counts were inaccurate, and for the sixth the available space
was reduced two years ago by commit a13cd6a1.
2026-05-05 15:10:09 +02:00
Benno Schulenberg
9639971a0e tweaks: just check for negativeness instead of for exactly minus one
(In theory this should be a teeny bit faster.)
2026-05-04 16:49:04 +02:00
Benno Schulenberg
bbab2770c5 tweaks: drop an inconsistent space before a closing parenthesis 2026-05-03 12:08:27 +02:00
Benno Schulenberg
0e7f744744 tweaks: move a condition out of a function, to avoid unneeded calls
But mostly: it makes it clearer what outside_of_confinement() checks,
and makes the function simpler.
2026-05-02 17:01:03 +02:00
Benno Schulenberg
0d36dc4942 tweaks: rename a function, to better describe what it does 2026-05-02 11:10:31 +02:00
Benno Schulenberg
faf90cfaa6 tweaks: shorten four conditions, clarify a fifth, and improve a comment 2026-05-02 09:28:29 +02:00
Benno Schulenberg
34cfbcc4d0 files: drop an unneeded call of real_dir_from_tilde()
It was made redundant ten years ago by commit bfe418fe.
2026-05-01 17:14:40 +02:00
G. Branden Robinson
376ae53608 docs: use a better word in the description of the 'locking' option
The same word as used in the nano.1 man page.

And drop the unneeded word "for".

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-30 13:02:29 +02:00
G. Branden Robinson
95bcb90691 docs: swap the left and middle footer of the man pages
Also, say "GNU nano" instead of "version".

Having the name of the software on the left and the date in the middle
aligns better with preponderant practice.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-30 12:12:41 +02:00
Benno Schulenberg
0edc6610dd docs: use curly double quotes when scare quotes are meant
Inspired-by: G. Branden Robinson <g.branden.robinson@gmail.com>
2026-04-29 12:56:17 +02:00
Benno Schulenberg
fc84a19883 docs: replace the e.g. and i.e. abbreviations with plain English words
Inspired-by: G. Branden Robinson <g.branden.robinson@gmail.com>
2026-04-29 12:56:17 +02:00
G. Branden Robinson
35e11ce7ff docs: consistently use minus sign for M- notation
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-29 12:56:17 +02:00
G. Branden Robinson
269b96b703 docs: set "foreign" software in italics, not bold
As libmagic, ncurses, and terminfo are software components that
aren't topics of nano's own man pages, use italics for them.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-29 12:55:55 +02:00
Benno Schulenberg
286aefa34a docs: reword a description to make it clearer what typeface applies
Also, make the typeface usage in the texi version more consistent.

Inspired-by: G. Branden Robinson <g.branden.robinson@gmail.com>
2026-04-28 17:33:08 +02:00
3cdc00fdf6 Merge remote-tracking branch 'upstream/master' into line-folding 2026-04-27 10:39:46 -07:00
G. Branden Robinson
5660833ce8 docs: consistently set file names in italics
Also protect them from hyphenation (by prepending \%)
and add hyphenless break points (\:) to lengthy file names.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-27 17:21:51 +02:00
G. Branden Robinson
8499183c02 docs: favor the \[ti] special character over a literal ~
Some output devices render a plain ASCII tilde as U+02DC (small tilde).

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-27 16:28:17 +02:00
G. Branden Robinson
2e59a695e7 docs: style function names with bold, not backticks
Using bold is more consistent with the rest of nano's man pages.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-27 13:15:04 +02:00
G. Branden Robinson
6fe93a6c3f docs: fix three unescaped hyphens before option names
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-27 13:15:04 +02:00
Benno Schulenberg
09db112412 syntax: man: colorize also the \[xx] special-character syntax 2026-04-27 13:15:04 +02:00
G. Branden Robinson
2de91de36b docs: use groff-style special-character syntax: \[xx] instead of \(xx
The \(xx style looks ugly with its unbalanced left parenthesis,
and \[bu], \[Fc], and \[md] are already being used.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-27 13:14:47 +02:00
Benno Schulenberg
f43240e9b0 docs: prevent some keywords and compound keywords from getting hyphenated
Inspired-by: G. Branden Robinson <g.branden.robinson@gmail.com>
2026-04-26 12:33:18 +02:00
G. Branden Robinson
ac1bf7d60e docs: sync rnano's synopsis markup with nano's
The plus and the comma are literals, so should be in bold.

(See commit a06b921f1 from seven years ago.)

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-26 11:21:22 +02:00
Benno Schulenberg
b11349d901 build: fix compilation when configured with --enable-tiny
(This should have been part of commit 22e2ea3c from last week.)
2026-04-25 09:09:28 +02:00
Benno Schulenberg
2838b2429e docs: more precisely describe what --restricted forbids and allows 2026-04-23 12:11:41 +02:00
Benno Schulenberg
97d72f4821 docs: remove all mention of the old Mac file format 2026-04-18 15:57:06 +02:00
Benno Schulenberg
5bb19b0598 help: reshuffle the Backup toggle, to keep Append and Prepend paired 2026-04-18 15:56:27 +02:00
Benno Schulenberg
22e2ea3cf4 tweaks: fold two fragments of code together 2026-04-18 15:48:22 +02:00
Benno Schulenberg
cad7948400 tweaks: normalize the indentation after the previous change 2026-04-18 15:48:22 +02:00
Benno Schulenberg
bf342bcb3c files: remove the code for reading and writing old Mac files
Twenty five years after the Mac switched from Carriage Return (CR)
to Line Feed (LF) as the line ending, it is time to ditch the code
for reading and writing the old format.
2026-04-18 15:48:08 +02:00
Benno Schulenberg
d75b7a3072 syntax: default: colorize the release motto for the 9.* series too 2026-04-12 14:04:04 +02:00
bf4d6244c6 Merged master 2026-04-08 14:31:23 -07:00
Benno Schulenberg
c7276e58c9 po: update translations and regenerate POT file and PO files 2026-04-08 17:09:21 +02:00
Benno Schulenberg
b7c9882428 bump version numbers and add a news item for the 9.0 release 2026-04-08 16:52:40 +02:00
Benno Schulenberg
cb43493e00 history: create the ~/.local directory with limited access rights
Permitting everyone to write to the .local directory gave attackers
(on platforms where umask is 000) a tiny opportunity to become the
owner of the .local/share subdirectory, which would allow them to
install malicious .desktop files.

This fixes https://bugzilla.redhat.com/2455314.
Reported-by: Michał Majchrowicz <mmajchrowicz@afine.com>
Patch-by: Michał Majchrowicz <mmajchrowicz@afine.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>

Bug existed since version 2.9.1, commit 4200ed30,
from shortly after support for XDG was added.
2026-04-06 11:23:42 +02:00
Benno Schulenberg
7cf0125e9c docs: trim stuff that is more than four years old from the changelog 2026-04-04 12:17:03 +02:00
Benno Schulenberg
3b22c1cce8 copyright: update the years for significantly changed files 2026-04-04 09:23:31 +02:00
Benno Schulenberg
c1ea0601c9 tweaks: defend against hypothetical format specifiers
With this change, any format specifiers that the now third parameter
of statusline() *might* contain will not lead to unintended accesses
of memory.

Suggested-by: Jonathan Echavarria <jrec93@gmail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-02 11:18:24 +02:00
Benno Schulenberg
0b7328bce4 feedback: prevent interpretation of %s and similar in a filename
When a filename contains things that look like format specifiers
(%s, %p, %n, ...) and opening this file throws some error and this
file is opened together with others, then switching to the relevant
buffer would cause the %x parts to be interpreted as actual format
specifiers, resulting in the leakage of information, or in a crash,
or possibly in arbitrary memory writes.

Reported-by: Jonathan Echavarria <jrec93@gmail.com>
Patch-by: Jonathan Echavarria <jrec93@gmail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-04-01 12:23:50 +02:00
Benno Schulenberg
0e430310b8 docs: add ^B among the list of keystrokes for --modernbindings
Even though ^B is the default binding for a backward search, the
default for a forward search (^F) is mentioned too, so...
2026-04-01 12:05:06 +02:00
Benno Schulenberg
dbfce437af moving: make the minimum step for sideways scrolling two cells
Otherwise, with a tabsize of 1, rightward scrolling would get "stuck"
on a double-width character.
2026-04-01 08:02:52 +02:00
Benno Schulenberg
a01bc5f117 docs: adjust the description of scrollright for the improved behavior
And make the description more concise.
2026-04-01 08:00:08 +02:00
Benno Schulenberg
adff8171cc moving: when scrolling sideways, search also upward for a longer line
Otherwise, when the cursor is near the bottom of the viewport, and there
are overlong lines visible *above* the cursor, it is frustrating that
nano refuses to scroll sideways further than the bottom lines allow.

(Trying to move the cursor up has to happen before trying to move it
down, otherwise nano can get "stuck" on a long line that is present
just below the viewport.)
2026-03-31 16:57:19 +02:00
Benno Schulenberg
f16e8d8888 build: add move.c to the list of files that contain translatable strings 2026-03-29 12:06:06 +02:00
Benno Schulenberg
e637fdb42c gnulib: update to its current upstream state 2026-03-29 11:36:15 +02:00
Benno Schulenberg
0b17713756 moving: ignore scrollleft and scrollright with --solosidescroll too
And give feedback when those functions are called while --softwrap or
--solosidescroll are in effect.
2026-03-26 12:21:22 +01:00
Benno Schulenberg
5d31b0f595 docs: in the cheatsheet, place Ctrl+L in the Special movement section
More than redrawing the entire screen, its most obvious effect is
centering the current line, which is a movement of the viewport.

(Also, improve the wording for Alt+G.)
2026-03-23 16:32:42 +01:00
Benno Schulenberg
a3cb12ccff syntax: elisp: remove file -- something specific to Emacs is not for nano
(Nano doesn't have a syntax for vimscript either.)

The file has been moved to:

  https://nano-editor.org/more-syntaxes/elisp.nanorc
2026-03-22 07:56:07 +01:00
Benno Schulenberg
84f7eb2d1e tweaks: rename two variables, away from abbreviations 2026-03-21 13:21:54 +01:00
Benno Schulenberg
9e2f8e0fb3 tweaks: rename a variable, for contrast, and to be more fitting
The name `list` better indicates that a "history" is a list of things
(that were typed at a prompt in the past).
2026-03-21 12:46:05 +01:00
Benno Schulenberg
8abdd80f24 tweaks: rename three functions, to be more accurate 2026-03-21 12:38:10 +01:00
Benno Schulenberg
3dc49fa6b8 tweaks: rename a variable, to be more fitting and away from an abbrev 2026-03-20 12:30:29 +01:00
Benno Schulenberg
d3019a1c40 tweaks: rename a variable, away from a double abbreviation 2026-03-20 12:15:53 +01:00
Benno Schulenberg
63594a3f92 tweaks: rename a variable, to be more fitting
The list of filenames-plus-their-last-cursor-position contains just one
cursor position per file, not a record of the last two hundred cursor
positions per file.  So the name `register` is much more fitting than
the name `history`.

Also, correct a comment.
2026-03-20 12:04:21 +01:00
Benno Schulenberg
3e104064db tweaks: rename a type, away from a double abbreviation 2026-03-20 11:48:26 +01:00
Benno Schulenberg
c05a9009be docs: adjust the description of scrollright for the changed behavior
The previous commit restricted the line-jumping behavior of the cursor
to just the lines in the current viewport, thus keeping the viewport in
the (linewise) same position in the buffer.
2026-03-17 17:44:06 +01:00
Benno Schulenberg
902378fd7d moving: stay in the viewport when stepping to a longer line
When the current line is not long enough to allow the viewport to be
scrolled another tabsize to the right, then look for a longer line
only within the current viewport (and after the current line) --
because changing the vertical position of the viewport when doing an
essentially horizontal movement was not a good idea.
2026-03-16 08:36:17 +01:00
Benno Schulenberg
3ac3b27259 help: group the sideways scrolling keystrokes with the horizontal movers
This better fits the original grouping of increasing vertical strides.
2026-03-15 13:41:57 +01:00
Benno Schulenberg
a334b64e89 display: correct the previous commit -- the -1 is needed when going left
Otherwise the step is tabsize-1, and one doesn't reach column 1 again.
2026-03-15 12:25:17 +01:00
Benno Schulenberg
f6e9b78b73 display: put cursor at CUSHION columns from edge when scrolling sideways
Put it at CUSHION columns, not at CUSHION+1 columns, when scrolling to
the right and the cursor would otherwise be outside this inner frame.

(The -1 and +1 came from attempts to make it work before I decided to
make it scroll a tabsize number of columns.)
2026-03-15 12:09:07 +01:00
Benno Schulenberg
d896becfee docs: mention that M-Left, M-Right, M-Up, and M-Down are valid keynames 2026-03-15 09:01:04 +01:00
Benno Schulenberg
98ad9496cc docs: adjust the cheatsheet for the new functions and changed bindings
And reshuffle an item to keep the two columns balanced.
2026-03-14 17:20:24 +01:00
Benno Schulenberg
80f6650c81 docs: add notices about the reassignment of the M-< and M-> keystrokes
And mention how to get their old behavior back.
2026-03-14 17:00:24 +01:00
Benno Schulenberg
c3139b8d65 docs: use rebindable names M-Up and M-Down instead of Alt+Up and Alt+Down 2026-03-14 17:00:24 +01:00
Benno Schulenberg
50107bd23a moving: ignore scrollleft and scrollright when softwrapping
When softwrapping, there is nothing to the sides of the viewport, so
it does not make sense to try and scroll the viewport sideways then.
2026-03-14 17:00:24 +01:00
Benno Schulenberg
df20e9895f display: draw the "<" marker only if part of the line is onscreen
If all text on a line is scrolled offscreen to the left, it looks ugly
to show the highlighted "<" continuation marker.  And it is misleading:
there is nothing onscreen (on that line) that is continued on the left.
2026-03-14 17:00:24 +01:00
Benno Schulenberg
df0aa86e05 syntax: nanorc: colorize M-Left, M-Right, M-Up, M-Down as valid keynames
Also, colorize {scrollleft} and {scrollright} as valid braced names.
2026-03-14 10:50:31 +01:00
Benno Schulenberg
81a6abc623 rcfile: allow rebinding M-Left, M-Right, M-Up, and M-Down
This will allow the user to make <Alt+Left> and <Alt+Right> scroll
sideways, similar to how <Alt+Up> and <Alt+Down> scroll vertically,
so that Alt plus the arrow keys work in a consistent manner.
2026-03-14 10:50:31 +01:00
Benno Schulenberg
4b14e562e2 docs: document the new bindable scrollleft and scrollright functions 2026-03-14 10:50:31 +01:00
Benno Schulenberg
6aa0f3ba39 bindings: assign M-< and M-> to the sideways-scrolling functions
Nowadays probably most people use <Alt+Left> and <Alt+Right> for
switching between buffers, and most of the others use M-, and M-.
-- most likely nobody uses M-< and M->, as they require holding
down Shift (on a US keyboard).

M-< and M-> seem like a good choice for the sideways-scrolling
functions, because "<" and ">" are used to indicate offscreen
continuation of the line, and requiring the user to hold Shift
is good as it helps to prevent accidental horizontal scrolling.
2026-03-14 10:50:31 +01:00
Benno Schulenberg
c65d25da2f new feature: bindable functions for scrolling a tabsize left or right
Now that nano can do whole-window sideways scrolling, it makes sense
to have the functions `scrollleft` and `scrollright` -- analogous to
the functions `scrollup` and `scrolldown`.  Because having to first
navigate the cursor to an overlong line and then pressing <End> (or
holding down <Ctrl+Right>) in order to see what is on the rest of
the line does not speak "ease of use".  (Sure, toggling softwrap is
much easier, but that messes with the vertical alignment of things.)
2026-03-14 10:50:31 +01:00
49a78cbb75 Fix drawing lines when folded 2026-03-09 11:22:32 -07:00
68f10939d4 Merge branch 'master' of https://git.savannah.gnu.org/git/nano into line-folding 2026-03-08 17:53:33 -07:00
Benno Schulenberg
287b7ef90b tweaks: rename a variable whose function has changed over time
The `start_line` variable hasn't been used for backtracking
since commit 15a0a129 from four years ago.
2026-03-07 14:06:27 +01:00
Benno Schulenberg
b1f5531063 display: begin looking for new start matches at the correct place
The `paintlen` variable becomes non-zero only when the endmatch
is onscreen, so choose instead a sure way of setting the `index`
to the end of the endmatch.

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

Bug existed in this form since version 2.4.3, commit 3f1878d9
(things being worse before that), but became visible since the
introduction of whole-window sideways scrolling.
2026-03-06 11:30:05 +01:00
Benno Schulenberg
9713f804df syntax: groff, man: colorize also \" tail comments and \# line comments
This fixes https://savannah.gnu.org/bugs/?68109.
Reported-by: G. Branden Robinson <g.branden.robinson@gmail.com>
2026-03-06 09:32:29 +01:00
Benno Schulenberg
bdac995173 docs: advise the use of --sysconfdir=/etc when configuring nano
This makes a self-compiled nano read /etc/nanorc instead of the
unexpected /usr/local/etc/nanorc.

This addresses https://savannah.gnu.org/bugs/?68117.
Reported-by: Alexandre Conseil <contact@alexandreconseil.fr>
2026-03-04 16:41:41 +01:00
Benno Schulenberg
793d6723ec tweaks: correct and simplify the logic from the previous two commits 2026-03-01 17:06:22 +01:00
Benno Schulenberg
5670c57dd2 display: redraw the screen also when 'brink' is not what it should be
This amends the previous commit.

This addresses https://savannah.gnu.org/bugs/?68105 better.
2026-03-01 12:08:40 +01:00
Benno Schulenberg
bf8b527375 display: when scrolling sideways, refresh edit window only if mark is on
This avoids unneeded full redraws for simple cursor movements.

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

Problem existed since whole-window sideways scrolling was introduced
in commit 7779a199 from five weeks ago.
2026-03-01 11:29:50 +01:00
Benno Schulenberg
a63141ecf4 tweaks: give the three "debugging" feedback messages a more unusual color
In this way they stand out from the usual status-bar feedback and errors.
2026-03-01 09:30:28 +01:00
Benno Schulenberg
dd50adb61b docs: reshuffle the --solosidescroll option to match the order in --help 2026-03-01 09:30:28 +01:00
Benno Schulenberg
4694c95524 build: exclude whole-window sideways scrolling from the tiny version
Let the tiny version scroll sideways only the current line, always.
(It then does not need the --solosidescroll option either.)
2026-03-01 09:30:28 +01:00
Benno Schulenberg
49be1275e6 syntax: guile: colorize more syntax words and procedure names
Also, colorize more quoted symbols and booleans, make the green for
syntax words and the blue for keywords lighter, and show comments
in grey italics.  Also, don't miscolorize some empty strings as if
they were the start of a multiline string.

This addresses most of https://savannah.gnu.org/patch/?10558.
2026-02-21 16:41:33 +01:00
Benno Schulenberg
8d49be96d6 syntaxes: add a license line to the files created by Mark Oteiza
He agreed to this by private email.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-02-19 17:22:18 +01:00
Benno Schulenberg
5df0b2e41a tweaks: no need to be overpolite when giving directions
(When requesting bug reports, then it's okay to say "please".)
2026-02-18 16:17:03 +01:00
Benno Schulenberg
07f84b7b61 tweaks: replace the three instances of impersonal "one" with direct "you"
This better matches the style in the rest of the manual.
2026-02-18 16:17:03 +01:00
Benno Schulenberg
083d6c70ee tweaks: lowercase subsequent words in section titles, to be less pompous 2026-02-18 16:17:03 +01:00
Benno Schulenberg
83ef26dc74 input: prevent also a string bind from breaking a chain of cuts or copies
The content of a string bind will probably break that chain, but the
keystroke itself (to which the string is bound) should not break it.
2026-02-18 16:10:05 +01:00
Benno Schulenberg
f1db15c7b6 input: prevent most toggles from breaking a series of cuts or copies
Only the cut-from-cursor toggle should break a chain of cuts or copies,
because it affects how those operations behave.  All other toggles have
no effect on those operations nor on the position of the cursor, so they
should not break a chain of cutting or copying keystrokes.

Achieve this by reshuffling a fragment of code to before the fragment
that triggers cutbuffer clearing for most operations.

(This has as interesting side effect that none of the toggles breaks a
chain of completions either.)

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

Bug existed since version 4.3, commit 6c4f228f.
2026-02-18 16:10:05 +01:00
Benno Schulenberg
93ae8259c8 input: allow recordmacro and runmacro to continue cuts and copies
Starting the recording or replaying of a macro does not change anything
about the position of the cursor or the state of the buffer, so those
functions should not interrupt a series of cuts (^K) or copies (M-6).

This allows a macro to complete a series of cuts or copies that were
initiated manually (or by a previous macro).

This addresses https://savannah.gnu.org/bugs/?68046.
2026-02-15 12:32:05 +01:00
Benno Schulenberg
8771acb98a tweaks: slightly adjust a wording 2026-02-15 12:21:36 +01:00
Benno Schulenberg
a29c225b7a docs: add a section about the recording and replaying of keyboard macros
Also, move the text of the section about Limitations into this new
section, as the only documented limitation concerns macros.
2026-02-15 12:17:27 +01:00
Benno Schulenberg
db9ada1bf8 tweaks: move a function to a more logical place
Adding stuff to the macro buffer happens after recording has started
and before the macro is run.
2026-02-15 09:58:37 +01:00
Benno Schulenberg
1d3a8bc24e tweaks: reduce the scope of two variables 2026-02-15 09:50:50 +01:00
Charles Mirabile
00bfeb2dcf macro: cancel the recording if nothing was entered between start and stop
When the user stops a macro recording immediately after starting it,
cancel the recording and restore the macro that existed previously,
instead of storing a new empty macro.

This avoids overwriting an existing macro when the user realizes at
once that they've hit `recordmacro` instead of `runmacro`.

Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2026-02-15 09:34:44 +01:00
Benno Schulenberg
617c559628 syntax: python: require a blank after the keyword match
This avoids colorizing "match" in calls of re.match().

Reported-by: Stanislaw Majewski <essdoem@yahoo.com>
2026-02-11 16:50:10 +01:00
Benno Schulenberg
6b547f3afe tweaks: normalize brace placement after the previous change 2026-02-11 16:45:43 +01:00
Benno Schulenberg
a8dca7c918 display: let option --jumpyscrolling affect also sideways scrolling
When using --jumpy, the viewport scrolls vertically in steps of
half a screen (height).  Then it makes sense that the viewport
also scrolls horizontally in steps of half a screen (width).
2026-02-11 14:41:34 +01:00
Benno Schulenberg
965531485f tweaks: reorder a list of keys, starting with singles, ending with group 2026-02-11 14:37:25 +01:00
Benno Schulenberg
9419bc38de tweaks: condense the Python coloring rules, and reword a comment 2026-02-07 09:09:41 +01:00
Benno Schulenberg
1b7e24dc30 docs: copy the 8.7.1 news item from the release branch 2026-02-07 08:22:23 +01:00
Benno Schulenberg
bf194dae5d syntax: python: colorize also the match and case keywords
These keywords were introduced in Python-3.10:
  https://docs.python.org/3/whatsnew/3.10.html#pep-634-structural-pattern-matching

Reported-by: Stanislaw Majewski <essdoem@yahoo.com>
2026-02-03 16:37:37 +01:00
Benno Schulenberg
46a015c624 docs: add a notice about the changed sideways scrolling behavior
And mention how to get the old behavior back.
2026-01-31 15:49:03 +01:00
Benno Schulenberg
20c554c9b3 docs: add an Exit Status section to the man page and the manual
And correct and improve the description of the `discardbuffer`
bindable function.

This addresses https://savannah.gnu.org/bugs/?67979.
Reported-by: Tasos Papastylianou <tpapastylianou@hotmail.com>
2026-01-31 11:44:24 +01:00
Benno Schulenberg
c5902343bd display: store brink per buffer, to keep the viewport stable
This fixes https://savannah.gnu.org/bugs/?67993.

Bug existed since whole-window sideways scrolling was introduced
in commit 7779a199 from last week.
2026-01-31 08:49:10 +01:00
Benno Schulenberg
aca7face38 build: avoid three warnings when compiling against glibc-2.43
Functions like strchr() now return 'const char' instead of just 'char'.

This addresses the second part of https://savannah.gnu.org/bugs/?67954.
Reported-by: Rudi Heitbaum <rudi@heitbaum.com>
2026-01-30 08:58:20 +01:00
Benno Schulenberg
5131dca77f gnulib: update to a recent version, to allow compiling against glibc-2.43
Parentheses were missing in the declaration of wmemchr().
They were added two months ago in gnulib commit df17f4f37e.

This addresses the first part of https://savannah.gnu.org/bugs/?67954.
Reported-by: Rudi Heitbaum <rudi@heitbaum.com>
2026-01-30 08:58:06 +01:00
869f75830d Merge in master 2026-01-24 20:32:53 -08:00
Benno Schulenberg
2e2a40ea09 docs: document the new --solosidescroll and 'set solosidescroll' options
These re-enable the historical jerky single-line sideways scrolling.
2026-01-23 17:37:03 +01:00
Benno Schulenberg
38f87fb5c3 display: add extra variable, to avoid one-way toggling of SOLO_SIDESCROLL
Panning should not be switched off for the whole session
when the window became too narrow at some point.
2026-01-23 17:37:03 +01:00
Benno Schulenberg
f6297f0933 display: for narrow windows, fall back to single-line sidescrolling
Otherwise the cursor can get misplaced sometimes.
2026-01-23 17:37:03 +01:00
Benno Schulenberg
a7e8dd7d6b options: accept --solosidescroll and 'set solosidescroll'
These options activate the old, jerky, single-line sideways scrolling
instead of the new default smooth whole-window sideways scrolling.
2026-01-23 17:37:03 +01:00
Benno Schulenberg
7779a19903 new default feature: smooth whole-window sideways scrolling
Instead of horizontally scrolling just the current line by nearly
a screen width when the cursor is about to go offscreen, now all
screen lines are scrolled horizontally together by just the amount
needed to keep the cursor comfortably in view.

References:
  https://lists.gnu.org/archive/html/nano-devel/2026-01/msg00000.html
  https://lists.gnu.org/archive/html/nano-devel/2026-01/msg00003.html
  https://lists.gnu.org/archive/html/nano-devel/2014-05/msg00025.html
  https://lists.gnu.org/archive/html/nano-devel/2014-06/msg00152.html

Nano could have acquired this feature nearly twelve years ago, but...
somehow that old patch fell through the cracks and was forgotten.  :|

Motivated-by: Xylia Allegretta <xylia.allegretta@gmail.com>
Original-patch-by: Mark Majeres <mark@engine12.com>
2026-01-23 17:37:03 +01:00
Benno Schulenberg
255845cc13 tweaks: correct a comment 2026-01-23 16:27:10 +01:00
244b25c88a Merge branch 'master' of https://git.savannah.gnu.org/git/nano into line-folding 2026-01-18 20:21:38 -08:00
Benno Schulenberg
f7c96dba4a copyright: update the years for the FSF 2026-01-17 12:12:55 +01:00
Benno Schulenberg
299aab6acf tweaks: refer to two renamed gnulib modules with their adjusted names 2025-12-06 12:11:05 +01:00
Benno Schulenberg
3295ca6bd8 copyright: update the years for significantly changed files 2025-11-27 11:27:31 +01:00
Benno Schulenberg
632542462a tweaks: rename two functions, reword some comments, rewrap a line 2025-11-24 15:23:02 +01:00
Benno Schulenberg
bd72b21c18 mouse: allow clicking before the answer to place cursor at its beginning
In the prompt bar, clicking beyond the end of the answer places the
cursor at the end of the answer.  Then it makes sense that clicking
before the beginning of the answer places the cursor at its beginning.
2025-11-24 13:07:30 +01:00
Benno Schulenberg
31fc5194b2 new feature: clicking in the scrollbar jumps to the corresponding line
With --mouse and --indicator, clicking in the rightmost column of
the edit window (the "scrollbar" area) now makes the cursor jump
to the line that places the indicator at the clicked position.

Inspired-by: Firefox, and originally by tilde and fte.
2025-11-24 11:21:08 +01:00
Benno Schulenberg
fc1d88a00f tweaks: avoid having to restore the original click coordinates
When going to handle clicks on shortcuts, the help lines are present,
so we know exactly where the prompt is (third line from the bottom),
so there is no need to first convert the coordinates to be relative
to the bottom window and then restore them when `mouse_y` is zero.
2025-11-24 11:05:23 +01:00
Benno Schulenberg
54e1619d6e tweaks: condense two oververbose comments 2025-11-24 11:05:23 +01:00
Benno Schulenberg
b4246d2cac tweaks: remove an unneeded parameter from get_mouseinput()
Only the Yes-No routine handles clicks on shortcuts itself, so just
exclude that menu from the shortcut handling by mouse, instead of
burdening every call with an unclear parameter.
2025-11-24 11:05:23 +01:00
Benno Schulenberg
3539d4862e tweaks: add a comment for an unclear fragment of code 2025-11-22 17:39:57 +01:00
Benno Schulenberg
1457013c53 docs: explain what "overlong" means for --breaklonglines
Inspired-by-a-report-from: Sébastien Desreux <seb@h-k.fr>
2025-11-21 16:45:45 +01:00
Benno Schulenberg
c32fdec09f tweaks: slightly improve three comments in the sample nanorc 2025-11-21 12:05:31 +01:00
Benno Schulenberg
3b983dd889 files: include also the slash when re-adding the filename to the path
Otherwise a mistaken name gets recorded in the file-positions history.

Buglet existed since version 6.1, commit fdd946c0.
2025-11-19 11:48:12 +01:00
Benno Schulenberg
71c60563a2 tweaks: reshuffle or transmute a few lines, to elide an 'if' 2025-11-14 10:17:17 +01:00
Benno Schulenberg
fd531c248e po: update translations and regenerate POT file and PO files 2025-11-12 10:48:25 +01:00
Benno Schulenberg
9735af4d78 bump version numbers and add a news item for the 8.7 release 2025-11-12 08:35:56 +01:00
Benno Schulenberg
88aa9157d1 gnulib: update to its current upstream state 2025-11-11 11:24:21 +01:00
Benno Schulenberg
2593572392 tweaks: improve a few comments, drop one, and unwrap some lines 2025-10-31 10:17:44 +01:00
Benno Schulenberg
e83e1ca4e3 display: regenerate the screen after a resize during a spell check
This refixes https://savannah.gnu.org/bugs/?56033.

This became needed after the previous commit removed the regeneration
of the screen from the blocking/unblocking of SIGWINCHes.
2025-10-29 07:49:56 +01:00
Benno Schulenberg
75ed9e4d55 display: regenerate the screen only before and after waiting for input
Otherwise a SIGWINCH could occur between finalizing the reading of the
specified files and becoming ready for user input, which would result
in the first keystroke getting transformed into the THE_WINDOW_RESIZED
meta symbol, and thus effectively being discarded.

This fixes the third part of https://savannah.gnu.org/bugs/?67635.
The issue was reported by `twofiftysix`.

Buglet has existed for a long time.
2025-10-29 07:49:56 +01:00
Benno Schulenberg
3c129ffded tweaks: reshuffle some #ifdefs, and rename a function 2025-10-29 07:49:56 +01:00
Benno Schulenberg
6136b28af7 startup: register the handler for SIGWINCH much earlier
Otherwise nano is deaf for SIGWINCHes during several milliseconds,
which can cause it to start off with wrong dimensions.

This fixes the second part of https://savannah.gnu.org/bugs/?67635.
The issue was reported, and the solution suggested, by `twofiftysix`.

Buglet has existed for a long time.
2025-10-29 07:48:02 +01:00
Benno Schulenberg
c11569fb99 display: upon resize, redraw the subwindows only when fully initialized
Otherwise 'currmenu' still has an invalid value, causing a division by
zero in bottombars() because shown_entries_for() returns zero.

This fixes the first part of https://savannah.gnu.org/bugs/?67635.
The issue was reported by `twofiftysix`.

Bug existed since version 8.6, commit 09d574ba.
2025-10-28 12:04:04 +01:00
Benno Schulenberg
a23ad70e0e tweaks: improve the punctuation of one item in the sample nanorc 2025-10-27 15:00:33 +01:00
Benno Schulenberg
e1df83c885 build: avoid a warning when configured with --disable-multibuffer 2025-10-26 11:55:10 +01:00
Benno Schulenberg
ffc456ebac docs: add example of copy-to-clipboard-with-OSC52 to the sample nanorc 2025-10-14 11:23:09 +02:00
Benno Schulenberg
4b7ec23db3 new feature: execute a command without capturing the output
The feature is activated by preceding the command with two pipes (||).
This lets the command's output go to the terminal, enabling the user
to implement the OSC52 copy-to-clipboard command with a string bind:

  bind M-* "{execute}|| printf "\033]52;c;%s\007" "$(base64 | tr -d '\n')" {enter}{undo}" main

This keystroke now copies the buffer (or the selected region) to the
local system clipboard, also when nano is running on a remote host --
if and when the used terminal implements the OSC52 command.

Inspired-by: Alessandro Carminati <alessandro.carminati@gmail.com>
2025-10-12 12:50:24 +02:00
Benno Schulenberg
50e186bc81 moving: prevent a negative relative jump from going beyond top of buffer
This fixes https://savannah.gnu.org/bugs/?67581.
Reported-by: Ivan Vorontsov <ivrntsv@yandex.ru>

Bug existed since version 8.6, since relative jumps were introduced.
2025-10-05 12:22:32 +02:00
Benno Schulenberg
3823e8e209 tweaks: unwrap three lines, for esthetics 2025-10-05 12:21:38 +02:00
Benno Schulenberg
f08c0300ce text: when blanking a line due to --autoindent, keep the mark in sync
When Enter is pressed at the end of a line that contains only blanks
while --autoindent is in effect, and thus this line gets emptied, then
the mark should be adjusted accordingly (when somewhere on this line).

This fixes https://savannah.gnu.org/bugs/?67578.
The issue was reported by `correctmost`.

Bug existed since version 2.8.1, commit 005ee8ed, but
became more exposed since version 4.0, commit f7f5514e.
2025-10-05 11:56:18 +02:00
Benno Schulenberg
43f0618f77 tweaks: replace a remaining double dash with a true emdash
Also, avoid a cluster of parentheses by replacing two with an emdash.
2025-09-09 10:34:02 +02:00
Benno Schulenberg
54c7709964 docs: mention that execute can pipe buffer or region to the command
(This should have been part of commit a18b48f0 from seven years ago.)
2025-09-06 16:22:10 +02:00
Benno Schulenberg
326e4146b2 po: update translations and regenerate POT file and PO files 2025-08-21 08:06:48 +02:00
Benno Schulenberg
fd5900c252 bump version numbers and add a news item for the 8.6 release 2025-08-20 12:44:42 +02:00
Benno Schulenberg
74faba1251 gnulib: update to its current upstream state 2025-08-20 08:37:08 +02:00
Benno Schulenberg
70e580c002 completion: don't stop looking for candidates one byte too early
This fixes https://savannah.gnu.org/bugs/?67405.
Reported-by: Ivan Vorontsov <ivrntsv@yandex.ru>

Bug existed since version 2.7.2, since word completion was introduced.
2025-08-07 15:40:29 +02:00
Benno Schulenberg
1ee74172c2 rcfile: accept also {}} in a string bind, for symmetry with {{} 2025-08-02 09:48:05 +02:00
625e1b9d12 Merge remote-tracking branch 'upstream/master' into line-folding 2025-07-29 16:16:07 -07:00
Benno Schulenberg
121dd596d9 tweaks: swap two symbolic menu names, for giggles 2025-07-10 12:02:14 +02:00
Benno Schulenberg
ea5e199d3b browser: let a refresh also reread the file list, like it used to
Until two commits ago, a full refresh (^L) would first refresh the
screen and then reread the file list and redo the screen again.
Now it will just reread the list and redo the screen, skipping the
redundant refresh.  The latter is done only for the tiny version.

Also rename a label, to be more precise.
2025-07-10 10:04:39 +02:00
Benno Schulenberg
e7c28bcb66 browser: redo the layout only when an actual resize occurred
This improves upon the previous commit.

This fixes https://savannah.gnu.org/bugs/?67294 in a better way.
2025-07-10 09:49:45 +02:00
Benno Schulenberg
21207b47a0 browser: redo the layout when the window _might_ have resized
The user may have resized the window not only while in the help viewer
but also while at the Search or Goto prompt.  Ensure that after all of
them the browser rebuilds the list according to the current dimensions.

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

Bug existed since version 2.5.3, commit 813f9f72.
2025-07-09 16:07:45 +02:00
Benno Schulenberg
09d574bae9 display: when resizing, redraw the bottom bars also when in file browser
This fixes https://savannah.gnu.org/bugs/?67293.

Bug existed since version 8.2, commit fe0b928b.
2025-07-09 11:37:18 +02:00
Benno Schulenberg
b68d74effc syntax: po: colorize also the %b and %B format specifiers
Glibc's printf() recognizes these specifiers since version 2.35:
  https://sourceware.org/pipermail/libc-announce/2022/000033.html
2025-07-08 16:05:25 +02:00
Benno Schulenberg
88309f981a tweaks: put two related checks together, like they are elsewhere 2025-07-06 15:01:26 +02:00
Benno Schulenberg
653432b6a8 tweaks: reshuffle some lines, to group things better 2025-07-06 11:43:10 +02:00
Benno Schulenberg
4d4c231dad tweaks: use a direct parameter instead of an intermediary boolean
The intermediary boolean is needed in search_init(), which contains
a loop and several toggles, but it's not needed here.
2025-07-06 11:43:10 +02:00
Benno Schulenberg
a195ba6cc0 tweaks: rename a parameter, and invert its logic 2025-07-05 14:22:11 +02:00
Benno Schulenberg
e05b7a5cd5 tweaks: normalize the indentation after the previous change 2025-07-05 14:22:11 +02:00
Benno Schulenberg
2a51d35e25 tweaks: split the goto function into an interactive and command-line one 2025-07-05 14:22:11 +02:00
Benno Schulenberg
d7e427daac tweaks: reshuffle a condition to a better place, like it is elsewhere 2025-07-03 13:01:55 +02:00
Benno Schulenberg
ee37afd1e2 tweaks: reshuffle a few lines, for density and to elide an 'else' 2025-07-03 11:41:15 +02:00
Benno Schulenberg
d2e261d873 history: do not forget anchors when line number is given on command line
When a line number is given on the command line, the position-history
file needs to be read first, because it might contain saved anchors.

(Before placing the cursor on the given line, or searching for a given
string, the current position now needs to be set back to top-of-file,
as otherwise the saved column position is likely to be inherited, or
the search will start from the inherited position.)

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

Bug existed since version 8.5, commit 60e2f2ba,
since the saving of anchors was introduced.
2025-07-03 11:28:53 +02:00
Benno Schulenberg
2525291ef0 docs: document the ++/-- prefix feature for the gotoline function 2025-07-02 15:02:09 +02:00
Benno Schulenberg
124b41acdb new feature: interpret a line number prefixed with ++ or -- as relative
This permits jumping a precise number of lines forward or backward.

Inspired-by: Brian Sandro <email@bsandro.tech>
2025-07-02 15:01:44 +02:00
Benno Schulenberg
2ce71a1332 tweaks: remove a check for a symbol that never gets defined
Twelve years ago, commit 2e4228f7 added a check for the 'ncursesw/
ncurses.h' header file.  A week later commit 66e5972c removed that
check again, but forgot to remove the corresponding #ifdef.

This addresses https://savannah.gnu.org/bugs/?67225.
2025-06-20 10:51:04 +02:00
Benno Schulenberg
a74e326448 po: update translations and regenerate POT file and PO files 2025-06-12 09:35:40 +02:00
Benno Schulenberg
173cd01731 docs: baptize the release 2025-06-12 09:24:23 +02:00
Benno Schulenberg
737f4057fb bump version numbers and add a news item for the 8.5 release 2025-06-12 09:09:45 +02:00
Benno Schulenberg
62966d085f gnulib: update to its current upstream state 2025-06-11 16:20:22 +02:00
Benno Schulenberg
8036d4beaa build: fix compilation when configured with --disable-histories
In a tiny nano, there are no anchors, so none need saving/restoring.
2025-06-09 12:31:02 +02:00
Benno Schulenberg
14f17c3601 tweaks: use the correct modifier, to avoid a warning on 32-bit machines 2025-06-08 14:07:06 +02:00
Benno Schulenberg
8cfa180fae docs: reword the descriptions of --operatingdir and 'set operatingdir' 2025-05-30 10:22:22 +02:00
Benno Schulenberg
e95469bcbb tweaks: properly tag some keywords in texi doc, instead of using quotes 2025-05-29 14:20:06 +02:00
Benno Schulenberg
cf71d761dc tweaks: shorten a URL, and update it to use https 2025-05-25 12:37:44 +02:00
Benno Schulenberg
c2b9211bd5 build: fix compilation for config with --enable-tiny --enable-histories 2025-05-22 14:38:48 +02:00
Benno Schulenberg
7a7405571c tweaks: rename 'use_utf8' to 'using_utf8', and make it a global variable
This elides a function call in some parts of the code.
2025-05-21 13:48:55 +02:00
Benno Schulenberg
1270657602 tweaks: elide the unneeded use of an auxiliary function 2025-05-21 11:55:05 +02:00
Benno Schulenberg
6c80b97694 feedback: suppress "Removed anchor" when the mini bar is hidden
Showing only "Placed anchor" and not "Removed anchor" makes it possible
to notice without looking at the status bar whether an anchor has been
placed or removed.  (The mini bar is not just a different interface but
is also about minimizing status-bar output.)
2025-05-20 10:39:51 +02:00
Benno Schulenberg
e6b087bcae feedback: suppress "Jumped to anchor" when line numbers are active
When line numbers are present, any anchors are displayed in the margin,
so it should be rather obvious where the cursor jumped to -- no need to
mention this on the status bar.
2025-05-20 10:39:45 +02:00
Benno Schulenberg
a0918c5e98 tweaks: random unimportant edits here and there 2025-05-18 12:34:07 +02:00
Benno Schulenberg
879885a736 tweaks: use reallocations, instead of new allocations plus frees
Probably more than half of the reallocations will be no-ops, so
this should be faster.
2025-05-18 12:27:18 +02:00
Benno Schulenberg
155258e06e docs: add a suggested key combo for wiping all anchors to sample nanorc 2025-05-18 09:42:41 +02:00
Benno Schulenberg
06e48df8a3 feedback: report the setting and removing of an anchor just once
When line numbers or the mini bar are active, there is no need for
the status-bar messages.  Only when both line numbers and mini bar
are absent, the feedback messages are needed.
2025-05-17 17:51:25 +02:00
Benno Schulenberg
88776e0eee docs: mention that --positionlog also saves the positions of anchors 2025-05-17 17:51:25 +02:00
Benno Schulenberg
9be62a6964 build: fix compilation when configured with --disable-utf8
Always include the function using_utf8(), to be able to avoid
the cluttering #ifdef that was removed in the previous commit.
2025-05-17 17:51:11 +02:00
Benno Schulenberg
c000917cda anchor: change the aspect of any anchor to a dagger (†)
Now that anchors are always saved, there is no need to differentiate
anchors that are saved (■) from anchors that will evaporate (⬥).

Choose a new appearance (†) to signal the changed behavior.
(And because I didn't much like the look of the block.)
2025-05-17 11:32:57 +02:00
Benno Schulenberg
76b87890d8 history: always save the positions of any anchors
Let the saving of anchors not depend on the presence of an anchor
on the first line.  That was a clever mechanism to allow avoiding
the unnecessary saving-of-anchors, but... it was awkward and ugly.
2025-05-17 11:32:57 +02:00
Benno Schulenberg
d0796bde4f history: always save the last cursor position, also for line=1,column=1
This may seem a little wasteful, as line=1,column=1 is the default
cursor position, but this change enables the next commit: always
saving any anchors.  In the bargain, the position-history file now
contains a list of all files that were recently opened with nano.
2025-05-17 11:31:48 +02:00
Benno Schulenberg
a6e7d5c99b tweaks: elide an auxiliary variable that is no longer needed 2025-05-17 09:14:28 +02:00
Benno Schulenberg
b37cc32de0 history: reverse the order in the file-positions list, to latest first
Putting the record for the last-edited file at the top of the list
ensures that (in case of a duplicate entry) the newest entry will
be encountered first and thus reused.  It also makes searching the
list faster, because the files that the user is likely to soon edit
again will be near the top of the list instead of near the end.

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

Problem existed since version 2.3.0, since position logging was
introduced, but was aggravated by the recent anchor-saving code.
2025-05-17 08:55:45 +02:00
Benno Schulenberg
6d724f6d07 feedback: show in mini bar the presence of an anchor on the cursor line
And as the presence of an anchor is now visible in the mini bar,
the "Placed anchor"/"Removed anchor" messages are no longer needed
when the mini bar is active.
2025-05-14 15:51:45 +02:00
Benno Schulenberg
1cc19c8c6a feedback: change the appearance of anchors when they will be saved
When an anchor is present on the first line of the buffer, make any
anchors appear as little blocks (■) instead of the usual diamonds (⬥).

This different appearance lets the user know whether a placed anchor
anywhere in the file will be saved or not -- when line numbers are
active.  (In an 8-bit locale an = replaces the usual +).
2025-05-14 15:51:45 +02:00
Benno Schulenberg
60e2f2baf2 new feature: save and restore anchors when the first line has an anchor
When an anchor is placed on the first line in a buffer and --positionlog
is active, nano will now save the positions of the anchors when the file
is closed, and will restore the anchors when the file is reopened.

(The positions are stored in the file-positions history file, along
with the cursor position.)

This fulfills https://savannah.gnu.org/bugs/?62269.
Requested-by: Shi Yanling <sylphenix@126.com>
Requested-by: Sébastien Desreux <seb@h-k.fr>

Sponsored-by: Sébastien Desreux <https://doc-solus.fr>
2025-05-14 15:51:24 +02:00
Benno Schulenberg
b8c684193e tweaks: elide the unneeded passing around of three parameters
The function has_old_position() was used just twice, and both calls
were followed by basically the same call of goto_line_and_column().
So... move the latter call into the first function, to avoid the
unneeded passing back and forth of the line and column numbers.
2025-05-09 12:14:06 +02:00
Benno Schulenberg
84b1fdf6c6 syntaxes: add a license line to files that were created by Mike Frysinger
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2025-05-08 10:31:44 +02:00
Benno Schulenberg
2181853574 syntaxes: use character classes instead of range expressions
In some locales certain normal ASCII characters are not included in
the ranges [A-Z] and [a-z].  So, use [[:upper:]] and [[:lower:]]
instead, and [[:alpha:]] for [A-Za-z], and similarly for others.

This fixes https://savannah.gnu.org/bugs/?67094.
2025-05-08 10:24:49 +02:00
Benno Schulenberg
281197895f bindings: lowercase an ASCII character in a locale-proof manner
Calling tolower() on the 'I' (of "M-I") in a Turkish locale will not
return 'i' but 'I' instead.  This is because the lowercase of 'I' is
'ı' (a dotless i), which does not fit in an 8-bit character type, so
tolower() will return the 'I' unchanged.

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

Buglet existed since before version 2.2.0.
2025-05-07 11:02:15 +02:00
Benno Schulenberg
d50e8feed9 tweaks: avoid using toupper() and tolower() where easily possible
Those functions can misbehave for some characters in certain locales.
2025-05-07 11:02:04 +02:00
Benno Schulenberg
8e104117a4 new feature: exit with an error status (2) for ^X^Q and ^O^Q
Nano used to exit always with a success status (0).  But now, if
the user wants to make nano report failure to a calling program,
they can use ^X^Q (when the buffer is modified) or ^O^Q (always).

This fulfills https://savannah.gnu.org/bugs/?65755.
2025-05-06 11:00:02 +02:00
Benno Schulenberg
b8b71399e8 menus: reshuffle an item, to avoid truncating its help-line label
The label "Discard buffer" is rather long (and is in most translations),
so make the item the last-but-one so that it effectively has the space
for two labels available (because the number of items in the WriteOut
menu is currently uneven).
2025-05-05 13:39:34 +02:00
Benno Schulenberg
fb78eea6fc bindings: always bind ^Q in the WriteOut menu, not only for --saveonexit
This gives the user a keystroke combo (for abandonning a buffer) that is
always the same, no matter whether the buffer is modified or not: ^O^Q.
2025-05-05 12:45:49 +02:00
Benno Schulenberg
a942be9f6f feedback: change the level of a certain message, to show it is special 2025-05-04 12:02:05 +02:00
Benno Schulenberg
34db8682b3 moving: make cycling (M-%) independent from centering (^L)
The first strike of M-% should always try to center the cursor,
also when the preceding keystroke was ^L.
2025-05-03 10:12:49 +02:00
Benno Schulenberg
61dee21466 bindings: let ^L just center the cursor, not cycle it -- let M-% cycle it
In my experience the default cycling behavior of ^L was puzzling:
hitting ^L twice left me wondering sometimes: where is the cursor?

Inspired-by: Peter Michaux <petermichaux@gmail.com>
2025-04-28 12:53:49 +02:00
Benno Schulenberg
820f68f147 bindings: do not list ^L twice (in main help text and help lines)
In my eyes this wasn't really a problem, but... better be precise.

Reported-by: Peter Michaux <petermichaux@gmail.com>
2025-04-28 12:20:25 +02:00
Benno Schulenberg
fabc1e1219 syntax: default: show hard spaces with a lightgrey background
Some keyboard layouts allow typing hard spaces (U+00A0),
which means that sometimes they can get typed by accident.
Colorize those spaces to make such accidents noticeable.

Inspired-by: Sébastien Desreux <seb@h-k.fr>
2025-04-26 12:18:42 +02:00
Benno Schulenberg
2fec40e2ec docs: in cheatsheet, equalize the spacing in three consecutive blocks 2025-04-26 11:45:07 +02:00
Benno Schulenberg
95731b800d options: accept --whitespacedisplay and 'set whitespacedisplay'
Allow some people to use 'set whitespacedisplay' in their rcfiles
(or --whitespacedisplay on the command line), but leave the option
undocumented as I think it shouldn't exist.
2025-04-25 17:07:28 +02:00
Benno Schulenberg
3142d471e1 build: swap two linker arguments, to enable compilation on Cygwin
Since nano-8.1 (which moved to gettext-0.20), compiling on Cygwin
failed with: "undefined reference to `libintl_dgettext'".  Avoid
this by moving the '-lintl' argument to after the gnulib one.

Reported-by: Philippe Baril Lecavalier <pbl.ltx@gmail.com>
2025-04-24 09:41:15 +02:00
Benno Schulenberg
045664107e tweaks: in the browser, implement M-\ and M-/ in a slightly denser way
Inspired-by: Peter Michaux <petermichaux@gmail.com>
2025-04-23 11:50:18 +02:00
Peter Michaux
e512466ff0 build: add the 'm4/host-cpu-c-abi.m4' file to .gitignore
For some reason `autopoint` from gettext-0.20 (used since nano-8.1)
started to include the 'm4/host-cpu-c-abi.m4' file.  Ignore it, to
prevent it from accidentally getting tracked.

Signed-off-by: Peter Michaux <petermichaux@gmail.com>
2025-04-22 12:05:25 +02:00
Benno Schulenberg
131849e7e8 gnulib: pull in the fix for a cross-compilation failure
This addresses https://savannah.gnu.org/bugs/?66978.
Reported-by: Chris Renshaw <osm0sis@outlook.com>
2025-04-14 10:52:12 +02:00
9a96973b00 Merge branch 'master' of https://git.savannah.gnu.org/git/nano into line-folding 2025-04-02 15:23:18 -07:00
Benno Schulenberg
186896f072 po: update translations and regenerate POT file and PO files 2025-04-02 11:07:28 +02:00
Benno Schulenberg
78eb483bc2 bump version numbers and add a news item for the 8.4 release 2025-04-02 09:29:24 +02:00
Benno Schulenberg
c7033324a9 gnulib: update to its current upstream state 2025-03-24 10:27:28 +01:00
Benno Schulenberg
334604a591 syntax: po: colorize also format specifiers like "%.6f" 2025-03-17 12:48:04 +01:00
Benno Schulenberg
7905ba80ea docs: add a suggestion to the FAQ on how to configure nano for git 2025-03-17 12:47:15 +01:00
Benno Schulenberg
ccff4685df docs: in the FAQ, replace an old item with an item about Byte Order Marks 2025-03-15 12:08:20 +01:00
Benno Schulenberg
0167f78dca feedback: warn when the cursor sits on a Byte Order Mark (BOM)
The ceck is only done at the start of a line, because in other places
the BOM will be glued to the preceding character.

This partially addresses https://bugs.debian.org/964901.
Reported-by: Nils König <oneric@oneric.de>
2025-03-15 09:17:01 +01:00
Benno Schulenberg
282ec08e5e docs: change two interface colors in the sample nanorc
For esthetics, and to showcase possibilities.
2025-03-14 11:48:29 +01:00
Benno Schulenberg
5efb7f31df tweaks: add a translator hint for the three changed file-writing prompts 2025-03-14 08:07:23 +01:00
Benno Schulenberg
bf39ffe903 prompt: accept tabs in an external paste as literal tabs
This fixes https://savannah.gnu.org/bugs/?66892.

Buglet existed since before version 2.0.0.
2025-03-12 16:59:58 +01:00
Benno Schulenberg
f2c30aa437 prompt: beep when an external paste contains a command code
Until the previous commit, nano used to beep for any command code
in an external paste.  It's better to continue doing that.

(When pasting multiple lines, it's debatable whether nano should
beep for each discarded CR.  But for any other command code, it
definitely should beep.  Maybe it should even show a message.)
2025-03-11 16:27:08 +01:00
Benno Schulenberg
bf12c90b07 input: implement bracketed pastes in a different manner
Ask ncurses to recognize the escape sequences that mark the start
and end of a bracketed paste, and thus benefit from the waiting that
ncurses does for an escape sequence to complete.  This helps prevent
nano from failing to recognize an end-of-paste sequence (resulting
in hanging or inserting some sequence characters into the buffer).

This addresses https://savannah.gnu.org/bugs/?66858 in a better way.
Reported-by: Doug Smythies <dsmythies@telus.net>
2025-03-10 17:17:07 +01:00
Benno Schulenberg
615570cf5e tweaks: remove two commented-out lines and two unused variables
And harmonize some whitespace.
2025-03-09 10:25:45 +01:00
Benno Schulenberg
aff9f4742c input: remove single-keycode detection from the bracketed-paste routine
It interferes with an upcoming change.
2025-03-08 12:08:30 +01:00
Benno Schulenberg
31a2cc9d76 tweaks: swap two fragments of code, to allow unwrapping a line 2025-03-08 12:07:49 +01:00
Benno Schulenberg
9c6a62d319 tweaks: remove an unwanted newline from a debugging message 2025-03-06 12:19:29 +01:00
Benno Schulenberg
38c8845b05 input: remove a special-case workaround
Let the more general flaw handling (added in commit 41c1b962, and
amended in the previous commit) handle also this case: it's better
to let the user know that they are using poor pasting software than
to silently work around the issue.

This effectively reverts commit 555a9878 from last week.
2025-03-06 09:42:53 +01:00
Benno Schulenberg
934d122dd4 input: robustness is good, but dropping a key code is not a good idea
If (on a bogged-down computer) a paste goes so slow that the bytes
come in one by one, nano shouldn't discard any of them -- the user
is unlikely to appreciate this.  Just switch the bracketed paste
off, for the possibility that the closing sequence went missing,
and accept that this closing sequence gets pasted into the buffer.
2025-03-06 09:42:43 +01:00
Benno Schulenberg
f8de98f7cd tweaks: condense a fragment of code 2025-03-04 16:44:32 +01:00
Benno Schulenberg
ef7f825d97 input: adjust file browser and help viewer for changed bracketed pastes
Since the previous commit, the escape-sequence-parsing code does not
set 'bracketed_paste' to FALSE any more when the closing sequence is
deficient.  So, the browser and viewer need to do that themselves.

Also, instead of just beeping and wordlessly discarding a paste when
it's done in the file browser or help viewer, report that it is being
ignored.  This is much more friendly.
2025-03-04 16:44:32 +01:00
Benno Schulenberg
41c1b9623e input: make bracketed paste more robust against loss of closing sequence
A bracketed paste should be one large batch (or several batches)
of bytes, not single bytes coming in one by one.  When the latter
happens, assume the end-of-paste sequence got swallowed somehow,
stop the bracketed paste and display a warning, while discarding
the first byte that came in alone.

This change was inspired by this report from Doug Smythies:
  https://lists.gnu.org/archive/html/nano-devel/2025-02/msg00001.html
2025-03-04 16:44:32 +01:00
Benno Schulenberg
555a987844 input: wait a bit for "~" when bracketed-paste sequence is incomplete
When pasting something into nano over OpenSSH_for_Windows, the final
tilde of the end-of-paste sequence can lag some 29 ms behind the rest
of the sequence, causing ncurses to split it off into a next batch of
bytes.  Accommodate for this by noticing the missing tilde and then
waiting at most one second for it to arrive.  This prevents the tilde
from appearing spuriously in the buffer after the paste.

This addresses https://savannah.gnu.org/bugs/?66858.
Reported-by: Doug Smythies <dsmythies@telus.net>
2025-03-04 16:44:32 +01:00
1d4ac090d8 Merge branch 'master' of https://git.savannah.gnu.org/git/nano into line-folding 2025-02-28 11:42:40 -08:00
Benno Schulenberg
c1df6dfd05 execute: retain what the user typed before a tool was invoked
When the user types something at the Execute prompt and then invokes
one of the six tools or special functions (that don't take any input),
stash the typed string and restore it upon the next invocation of the
Execute menu.  This way the typed string is not lost when the tool or
special function was invoked by accident -- which it likely was, as
those tools and functions don't take any input from the prompt.

This addresses https://savannah.gnu.org/bugs/?66637.
Suggested-by: Evgeny Pestov <fsdhfhhf@gmail.com>
2025-02-28 17:12:43 +01:00
Benno Schulenberg
163c569919 syntax: po: colorize also format specifiers like "%<PRIu64>" 2025-02-28 11:34:42 +01:00
Benno Schulenberg
63a7be115a syntax: po: colorize also a 'msgctxt' line, and the 'c++-format' flag 2025-02-20 13:49:03 +01:00
Benno Schulenberg
fed31f2a79 syntax: po: colorize also Python's "%(name)x" format specifiers 2025-02-17 13:58:35 +01:00
Benno Schulenberg
5d496b3152 syntax: po: colorize also the Python-specific conversion specifier "%r" 2025-02-16 09:44:18 +01:00
Benno Schulenberg
f5a2b8983d syntax: groff: highlight the zeroeth macro argument too
It is used in some .tmac files.
2025-02-15 17:47:20 +01:00
Benno Schulenberg
8f44800588 tweaks: add missing closing quotes, as reported by mandoc -T lint ... 2025-02-15 17:44:16 +01:00
Benno Schulenberg
68c9b6af07 tweaks: prevent some more keywords from getting hyphenated 2025-02-14 17:22:38 +01:00
Benno Schulenberg
8536b4bfcb tweaks: prevent some color keywords from getting hyphenated in man page 2025-02-14 16:50:16 +01:00
Benno Schulenberg
0694c616a2 syntax: man: highlight some escapes, like \& and \(em, specially
This helps prevent reading things like \e and \(em as text.
2025-02-14 16:42:45 +01:00
Benno Schulenberg
8e456bab9f docs: use proper emdashes instead of double hyphens: "--" => "\(em"
Also, remove redundant double quotes, protect single quotes from
possibly getting misinterpreted, and protect periods from getting
treated as end-of-sentence.  Also, use \e instead of \\.

(Overlong lines are left alone -- they don't bother me.)

This partially addresses https://bugs.debian.org/1095957.
Reported-by: Bjarni Ingi Gislason <bjarniig@simnet.is>
2025-02-14 16:29:13 +01:00
Benno Schulenberg
aa663ae386 tweaks: consistently use "\fR" for switching back to normal, roman font 2025-02-12 09:34:29 +01:00
Benno Schulenberg
01c8ffd61f tweaks: avoid running tolower() on an out-of-range value
Functions like tolower() expect characters in the range -1..255.

Reference: https://savannah.gnu.org/bugs/?50289.

The other occurrences of toupper(), tolower(), and isxdigit() that
don't do a cast are fine, because the values of 'code' or 'keycode'
are already guaranteed to be in range by the surrounding code.
2025-02-12 09:34:06 +01:00
Benno Schulenberg
58c7358cb3 tweaks: change the man-page markup of options that take an argument
This is an attempt to work around a bug in the Debian HTML-renderer of
manual pages: see how after "-C" everything is in italics [1], instead
of just the "directory" arguments.  (The renderer for Arch Linux does
even worse, showing the first argument in bold italics [2].)

The old markup was fine, though, as `groff` had no problem generating
properly formatted HTML [3].

[1] https://manpages.debian.org/bookworm/nano/nano.1.en.html
[2] https://man.archlinux.org/man/nano.1.en
[3] https://nano-editor.org/dist/v7/nano.1.html
2025-02-10 16:34:15 +01:00
Benno Schulenberg
1a150bf544 syntax: po: colorize also the %llu and %hhi format specifiers
And colorize %% only by itself, not combined with anything.
2025-02-10 11:04:06 +01:00
Benno Schulenberg
98bab0db07 docs: improve the description of the constantshow bindable function
And of the '--constantshow' and 'set constantshow' options.
2025-01-20 15:25:40 +01:00
Brand Huntsman
b9c65193af files: improve the wording of the normal file-writing prompts
Make them similar to the prompts for writing out a selection.

Signed-off-by: Brand Huntsman <alpha@qzx.com>

(The change was first proposed seven years ago as part of a patch set:
  https://lists.gnu.org/archive/html/nano-devel/2018-02/msg00144.html,
then reposted by myself:
  https://lists.gnu.org/archive/html/nano-devel/2018-02/msg00147.html,
and then... forgotten.)
2025-01-17 11:11:04 +01:00
Benno Schulenberg
20403ef8bb copyright: update the years for the FSF 2025-01-14 11:00:11 +01:00
Benno Schulenberg
e26cdd3dab tweaks: remove three redundant pairs of parentheses from a nanorc regex 2025-01-12 12:32:27 +01:00
Benno Schulenberg
2065713e5c docs: replace a word that is better not used in the plural
Noted by https://fossies.org/linux/misc/nano-8.3.tar.xz/codespell.html.
2024-12-24 17:14:23 +01:00
Benno Schulenberg
a9cf841042 po: update translations and regenerate POT file and PO files 2024-12-21 11:55:15 +01:00
Benno Schulenberg
46466530a5 bump version numbers and add a news item for the 8.3 release 2024-12-21 11:23:05 +01:00
Benno Schulenberg
94ed548366 gnulib: update to its current upstream state 2024-12-20 12:15:44 +01:00
Benno Schulenberg
1e4c69baa7 tweaks: adjust another translator hint, and add two more
The "Prev Line"/"Next Line" tags are shown in the help viewer,
so on an 80-column terminal they may be only 10 cells wide.
2024-12-16 11:16:10 +01:00
Benno Schulenberg
f04c1a6ab5 syntax: markdown: accept also digit 0 in a list marker
For ordered lists, 10., 20., 30., ... were not getting colorized.

Also, https://daringfireball.net/projects/markdown/dingus
accepts 0. by itself just fine as marker.

This addresses https://savannah.gnu.org/patch/?10492.
2024-12-15 11:39:06 +01:00
Benno Schulenberg
6393edf40a tweaks: add a small clarifying comment 2024-12-11 17:12:50 +01:00
Lukáš Zaoral
7fd38e88c1 memory: avoid a leak when linter aborts after producing parsable output
Any collected messages should be freed also after an
abnormal exit of the linter.

Buglet existed since version 2.4.1, commit f225991b.
2024-12-11 08:22:17 +01:00
Benno Schulenberg
ee66c13487 tweaks: adjust a translator hint, and add another one
For the affected four "tags" only 10 character cells are available
(on an 80-column terminal) since they are used in the help viewer.

For the other two "tags" 15 cells are available, as they are shown
only when the terminal is at least 380 columns wide.

Indirectly-reported-by: Rafael Fontenelle <rafaelff@gnome.org>
2024-11-24 17:41:04 +01:00
Benno Schulenberg
250192c603 tweaks: drop six unneeded casts
The cast is implied by the type of the assignee.
2024-11-24 17:41:02 +01:00
Benno Schulenberg
9d181a1cc6 build: fix a compilation error with gcc-15
Assigning a pointer to a boolean variable without a cast
is not accepted any more.

This addresses https://savannah.gnu.org/bugs/?66467.
Reported-by: Rudi Heitbaum <rudi@heitbaum.com>
2024-11-20 13:06:22 +01:00
LIU Hao
07a92c3988 syntax: asm: add end-of-word anchors to the keywords
Previously some of these regexes could color part of a directive;
for example, the `.int` part of `.intel_syntax`.

Signed-off-by: LIU Hao <lh_mouse@126.com>
2024-11-05 17:12:25 +01:00
Benno Schulenberg
e9b0a57490 docs: put a space after "|" and before "{enter}" in the sample nanorc
This makes the example bindings slightly more legible.

Also improve a comment.
2024-11-04 16:22:07 +01:00
Benno Schulenberg
2fca581095 syntax: groff: correct the mistaken .rof extension to .roff
Buglet existed since version 2.9.8, commit cdd637d6.
2024-10-23 11:14:48 +02:00
Benno Schulenberg
53afd90ad4 syntax: groff: recognize also the .mom extension
This addresses https://savannah.gnu.org/bugs/?66369.
Reported-by: Elfener <elfenermarcell@gmail.com>
2024-10-23 11:07:05 +02:00
Benno Schulenberg
d9ea07515b docs: clarify the possible effects of a misuse of braced function names
And fix a nearby grammatical mistake that was
caused by commit 77a8841d from four months ago.

Inspired-by: Max Gammache <bigjango13@gmail.com>
2024-10-20 17:19:27 +02:00
Benno Schulenberg
de82920819 docs: add Shift+PgUp/PgDown to the FAQ item about urxvt modified keys
So that those keystrokes will select text per screenful also on urxvt.

Inspired-by: Sébastien Desreux <seb@h-k.fr>
2024-10-12 12:57:15 +02:00
Benno Schulenberg
9a842e4bf2 tweaks: add a translator hint
This should help translators to avoid mistakenly interpreting
"Home" and "End" as names of keys.
2024-10-11 11:59:01 +02:00
9cfda05f71 Merge remote-tracking branch 'upstream/master' into line-folding 2024-10-06 17:43:50 -07:00
Benno Schulenberg
1862995aab syntax: spec: colorize all canonical architecture names
The list of canonical names was found in:
  https://github.com/rpm-software-management/rpm/blob/master/rpmrc.in

The canonical names were extracted with:

  grep arch_canon rpmrc.in | sed 's/^.*:\s*//' | sed 's/\s*..\?$//'

and then sorted and condensed into a regular expression.

Inspired-by: Funda Wang <fundawang@gmail.com>
2024-09-22 12:34:28 +02:00
Benno Schulenberg
468613c9db syntax: makefile: colorize also multiple targets
Multiple targets are separated by spaces.  Furthermore, there
may be spaces before the first target and before the colon.
2024-09-06 13:56:56 +02:00
Benno Schulenberg
28642cd047 po: update translations and regenerate POT file and PO files 2024-09-05 11:41:30 +02:00
Benno Schulenberg
f96f3546c7 bump version numbers and add a news item for the 8.2 release 2024-09-05 09:18:12 +02:00
Benno Schulenberg
205066ed12 gnulib: update to its current upstream state 2024-09-04 14:52:27 +02:00
Benno Schulenberg
7e8ee46c09 syntax: autoconf: colorize the keywords 'case', 'esac', and 'ifelse' too
Case statements occur a lot in gnulib's m4 files,
and 'ifelse' is simply part of the m4 language.
2024-08-28 17:12:17 +02:00
Collin Funk
d1e2febb6d build: update a symbol that was renamed in gnulib
As noted in a gnulib NEWS item of 2023-01-07, linking now happens
against $(CLOCK_TIME_LIB) instead of $(LIB_CLOCK_GETTIME).
2024-08-27 10:20:56 +02:00
Benno Schulenberg
3d0273de45 tweaks: improve or rewrap six comments, and add two missing ones
Also, stop initializing three variables that don't need it.
2024-08-17 10:37:41 +02:00
Benno Schulenberg
109386dfe8 syntax: nanorc: an unquoted argument of 'include' may not contain blanks
Anything after the first "word" after 'include' will be ignored
and should thus remain colorized in bright red.
2024-08-16 15:49:28 +02:00
Benno Schulenberg
ebddb49041 docs: do not quote the argument of 'include' statements in sample nanorc
This avoids those arguments getting colorized as if they were regexes
(when the relevant lines are uncommented), and instead allows them to
get colorized in bold purple by a dedicated rule.
2024-08-16 15:42:37 +02:00
Benno Schulenberg
b5f320a2f9 tweaks: delete three redundant checks from the undo/redo code
Since commit 50954a4b from two years ago, a replacing session will
not ever change the final empty line, and thus a fresh magic line
will never need to be undone or redone.

This complements commit c6a26641 from five months ago.
2024-08-12 08:41:58 +02:00
Benno Schulenberg
7568bd9af5 docs: trim stuff that is more than four years old from the changelog
A detailed list of changes is useful for just a small number of users,
and only when the changes are fairly recent.
2024-08-12 08:39:57 +02:00
Benno Schulenberg
0384c251ff docs: mention former maintainership last among an author's contributions 2024-08-10 17:36:31 +02:00
Benno Schulenberg
b812ad2926 tweaks: unwrap three lines that don't need to be wrapped
(These lines were noticed while checking that all
calls of nrealloc() use a size bigger than zero.)
2024-08-04 16:09:42 +02:00
Benno Schulenberg
fe0b928b39 tweaks: move a condition to the only place that needs it
Most calls of draw_all_subwindows() are made while in the edit window.
The only call that could occur while in the file browser is the one in
regenerate_screen().  So only this call needs to be guarded against
being made while the file list is being shown.
2024-07-31 10:04:00 +02:00
Benno Schulenberg
4b1a81e773 docs: mention the availability of ^Y, ^N, and ^A at a Yes-No prompt 2024-07-28 13:55:31 +02:00
Benno Schulenberg
af2f218192 bindings: at a Yes-No-All prompt, accept also ^A for "All"
This can be useful when replacing text in a Japanese locale,
avoiding the need to guide the input method to produce "A".

Inspired-by: Takeshi Hamasaki <hmatrjp@users.sourceforge.jp>
2024-07-28 13:54:41 +02:00
Benno Schulenberg
572247dbd8 tweaks: reshuffle a seldom-used function to the end of an if-else series 2024-07-22 15:43:37 +02:00
Benno Schulenberg
c5a0e6b60c syntax: awk: colorize escape sequences specially 2024-07-21 14:32:56 +02:00
9c2ec9f3af Merge remote-tracking branch 'upstream/master' into line-folding 2024-07-19 13:41:12 -07:00
Benno Schulenberg
d7e8665782 syntax: awk: rewrite a regex more densely, and add the missing ~ operator
Also, improve the comment.
2024-07-18 16:14:25 +02:00
Benno Schulenberg
7c86c1a185 syntax: awk: add a missing "|" between "\?" and ":"
The "\?" and ":" are meant to match the ? and : in this construct:

    condition ? thenthis : otherwisethis

The missing "|" seems to have been a typo.
2024-07-18 13:02:54 +02:00
Benno Schulenberg
4b03cc60cf moving: for Alt+Home/Alt+End, refresh the screen when the mark is on
When the mark is on, moving the cursor to the top or bottom row should
highlight the relevant area -- thus requiring a call of edit_refresh()
to be scheduled.

Also, drop two calls of place_the_cursor(), as that is done anyhow in
the main loop, either directly, or indirectly through edit_refresh().

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

Bug existed since version 8.0, since Alt+Home/Alt+End were introduced.
2024-07-17 17:23:12 +02:00
Benno Schulenberg
c356db9f44 macro: insert it in keystroke buffer without discarding latter's contents
Instead of simply overwriting the current contents of the keystroke
buffer with the contents of the macro buffer, insert the latter's
contents at the head of the keystroke buffer.

This allows using {runmacro} in a string bind, and allows typing ahead
over a laggy connection after invoking `runmacro` (normally with M-;).

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

Bug exists since version 2.9.4, since string binds were introduced.
2024-07-16 16:44:48 +02:00
Benno Schulenberg
c53839cefa tweaks: rename a symbol, away from an obscure abbreviation
Also, reshuffle its definition, and change its value to match
other special codes.
2024-07-15 09:38:01 +02:00
Benno Schulenberg
887803cb67 bindings: let the central numpad key (with Ctrl) center the current line
When NumLock is off, let Ctrl plus the central key on the numeric keypad
center the current line.

(This binding is not advertised anywhere
-- it's left as a little Easter egg.)
2024-07-15 09:37:48 +02:00
Benno Schulenberg
f69a08fc63 syntax: man: colorize also the .MT .ME .EX .EE .SY .OP and .YS macros
Furthermore, colorize .LP .P and .PP like .TP, as paragraph macros,
instead of inconsistenly as if they specified type faces.
2024-07-15 07:48:14 +02:00
Benno Schulenberg
4ddd61cfde po: update translations and regenerate POT file and PO files 2024-07-12 11:23:42 +02:00
Benno Schulenberg
fe39d137c7 bump version numbers and add a news item for the 8.1 release 2024-07-12 10:57:24 +02:00
Benno Schulenberg
ade975891b tweaks: add a space after a '+', for consistent formatting 2024-07-07 17:11:30 +02:00
Benno Schulenberg
479e56bdd6 tweaks: slightly reword a phrase in the explanation of --colonparsing 2024-07-07 14:27:02 +02:00
Benno Schulenberg
e5d36de24c tweaks: discard a bracketed paste in the help viewer with fewer beeps
The same change was made for the file browser two years ago,
in commit b561c386.
2024-07-07 14:25:04 +02:00
Benno Schulenberg
d824c4e633 docs: properly escape a literal '@' in the texi document
This avoids a failing `make pdf`.

Problem existed since commit 4930fbbb from five weeks ago.
2024-07-01 15:45:51 +02:00
Benno Schulenberg
f499635461 gnulib: update to its current upstream state
Also, stop distributing 'wchar_t.m4', as it was removed from gnulib
two weeks ago.
2024-07-01 11:07:03 +02:00
Benno Schulenberg
e8cf0f37f1 docs: add 'set colonparsing' to the sample nanorc 2024-06-18 15:55:00 +02:00
Benno Schulenberg
12a0c0f690 tweaks: rewrap some lines, for more even lengths
Also, slightly improve a few descriptions.
2024-06-18 10:53:28 +02:00
Benno Schulenberg
77a8841d25 tweaks: elide unhelpful occurrences of the word "will"
In most cases, "will" is just a filler word and doesn't improve clarity.

And in the bargain improve two descriptions.
2024-06-18 09:56:01 +02:00
Benno Schulenberg
7d8f13b9f7 build: use the standard autoreconf invocation
As version 0.20 of `autopoint` no longer overwrites 'extern-inline.m4',
there is no need any more for the custom calls of the various parts of
`autoreconf`.

This effectively reverts commit 4a1db96d from two and a half years ago.
2024-06-17 11:07:40 +02:00
Benno Schulenberg
ec177c84b3 build: require version 0.20 of gettext for building nano from git
Gettext-0.20 is the first version where its `autopoint` does not
overwrite the newer 'extern-inline.m4' from gnulib.

Version 0.20 is five years old, so most users will be on a distro
that includes that version of gettext or a newer one.
2024-06-17 09:50:08 +02:00
Benno Schulenberg
3809c67bb2 docs: add the Alt+Home/Alt+End shortcuts to the cheatsheet
Also, reshuffle Alt+T for balance, slightly reword the description
of Alt+A (as it differs in nature from the other toggles), and add
some spaces for better alignment.
2024-06-17 09:10:07 +02:00
Benno Schulenberg
dff779e3ad tweaks: in FAQ, use 'id' attribute instead of empty anchor with 'name'
The 'name' attribute for the <a> tag is deprecated -- 'id' is the
standard attribute that can be used in almost every tag.
2024-06-17 09:09:37 +02:00
Benno Schulenberg
ef1c9b9f2b tweaks: implement do_center() with a single call instead of three
This works because the main loop sets 'cycling_aim' to zero
whenever the current keystroke is not bound to `cycle`.
2024-06-15 09:57:06 +02:00
Benno Schulenberg
90e62db26e help: regroup the center item, placing it with the new cycle 2024-06-15 09:57:06 +02:00
Benno Schulenberg
498154804c bindings: let ^L put the cursor line at center, then top, then bottom
Something similar can be achieved with:

  bind ^T "{center}{bottomrow}{center}{toprow}" main
  bind ^B "{center}{toprow}{center}{bottomrow}" main

But that requires allocating two extra shortcuts, and it works right only
when the edit window has an odd number of rows, not with an even number.
Also, this new ^L behavior is available by default, out-of-the-box.
2024-06-15 09:57:06 +02:00
Benno Schulenberg
34dda64610 docs: explain the behavior of the new function cycle
Also colorize {cycle} when found in a nanorc file.
2024-06-15 09:57:06 +02:00
Benno Schulenberg
d1c723bc14 new feature: add bindable function cycle that pushes cursor line around
On the first call, `cycle` centers the line with the cursor, on the
second consecutive call it pushes that line to the top of the viewport,
and on the third consecutive call to the bottom of the viewport.
2024-06-15 09:57:06 +02:00
Benno Schulenberg
d477bfd4ee tweaks: drop two redundant conditions
The function do_tab() is only ever called when in the main edit window,
and never called while a bracketed paste is in progress.

(The two conditions were thoughtlessly copied when this fragment of code
was moved here three commits ago.)
2024-06-10 14:07:30 +02:00
Benno Schulenberg
6c81f60914 moving: use edit_scroll() only when scrolling one row is enough
When softwrapping with a tabsize larger than the width of the viewport,
scrolling one row when the cursor goes offscreen might not be enough,
so in that case use edit_redraw() instead.

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

Bug existed since version 2.9.6, commit 0d9080a2.
2024-06-10 08:15:28 +02:00
Benno Schulenberg
aa844ada4e tweaks: remove the now unneeded special keycode INDENT_KEY 2024-06-09 16:48:06 +02:00
Benno Schulenberg
9b7a813069 text: do not check for <Tab> + mark while getting input but in do_tab()
This allows a {tab} in a string bind to indent a marked region.

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

Problem existed since version 7.0, since braced function names
were introduced.
2024-06-09 16:42:14 +02:00
baadfa34f1 Merge branch 'master' of https://git.savannah.gnu.org/git/nano into line-folding 2024-06-09 07:27:29 -07:00
Benno Schulenberg
bc09f0992e tweaks: reshuffle some lines, to put vaguely related things together
And to slightly reduce the number of #ifdefs.
2024-06-08 17:08:17 +02:00
Benno Schulenberg
00e2309987 tweaks: make the inclusion condition for do_center() more strict
There is no reason why --enable-help should cause the centering function
to be included in a tiny version.
2024-06-08 16:56:52 +02:00
Benno Schulenberg
a98f82e27b startup: no not activate --modernbindings when name starts with "e"
Activating --modernbindings when the binary's name starts with "e"
interferes with Debian's alternatives system that symlinks `editor`
to `nano` in a default install.

(Also: why "e"?  It would have made more sense to check for "m",
similar to the checking for "r" for a restricted nano.)

This reverts commit 580eaf29 from fifteen months ago.

This addresses https://savannah.gnu.org/bugs/?65810.
Reported-by: Colin Snover <nano@zetafleet.com>
2024-06-08 12:14:08 +02:00
Benno Schulenberg
c70e6919c2 syntaxes: mention the original author of most of the syntax files
The names of the authors were retrieved from:

  git log -p --follow  syntax/<name>.nanorc

and from:

  git log -p --follow --all --  doc/nanorc.sample

For some files the original author is unclear, or
the file is/was too small to mention an author for.
2024-06-08 12:10:25 +02:00
Jaroslav Fowkes
abdf069ce3 syntax: fortran: fix a typo (a missing backslash)
The typo prevented several keywords from getting colorized.

This addresses https://savannah.gnu.org/patch/?10459.

Bug existed since version 2.1.6, commit 513157df,
since the Fortran syntax was introduced.
2024-06-07 15:34:03 +02:00
Benno Schulenberg
6be1f7e95a docs: avert hyphenation of the technical words "ncurses" and "terminfo"
This prevents an observed wrong hyphenation: "ter-minfo".

Also, add markup for "terminfo", like "ncurses" already has.
2024-06-07 14:57:02 +02:00
Benno Schulenberg
a1159ff484 syntax: man: colorize some of the things that manipulate hyphenation
Reference:
  https://www.gnu.org/software/groff/manual/groff.html.node/Manipulating-Hyphenation.html
2024-06-06 13:29:01 +02:00
Benno Schulenberg
0c2caa50cc docs: correct the description of --bold, as function tags are unaffected
The succinct function descriptions in the help lines are not shown in
reverse video by default, so they are not bolded by -D/--bold either.

Also, mention 'promptcolor' and 'minicolor' where they were missing.
2024-06-04 17:01:11 +02:00
Benno Schulenberg
dcbbbf8134 input: make sure that a string-bind return value is non-negative
A negative value would lead to misinterpretation by parse_kbinput().

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

Bug existed since version 8.0, commit 51c9f727.
2024-06-03 15:40:03 +02:00
Benno Schulenberg
05602e29cd syntax: patch: recognize also the .rej extension
The addition was inspired by `davidhcefx`.
2024-06-02 17:16:22 +02:00
Benno Schulenberg
cd53f7cf8c docs: don't say any more that -z was removed, as it has been repurposed 2024-06-02 09:23:09 +02:00
Benno Schulenberg
689748843c files: with --rectrict, prevent invoking the browser and toggling backups
Prevent also the toggling of Append and Prepend.  All four functions
should not be available in restricted mode, and are absent from the
WriteOut menu in that mode, but using {browser}, {backup}, {append}
or {prepend} in a string bind allowed to bypass the menu checks.

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

Problem existed since version 7.0, since braced function names
were introduced.
2024-06-01 11:31:09 +02:00
Benno Schulenberg
ea07eb6aa3 help: show option -Y/--syntax in --help output also in restricted mode
Since version 3.2, commit 5ca444e5, nano reads the nanorc files also
in restricted mode (when not also --ignorercfiles is given), meaning
that syntaxes are available and that a specific syntax can be selected
on the command line.  So, the --help output in restricted mode should
list the relevant option: -Y<name> / --syntax=<name>.

(This should have been part of commit b81995af from six years ago.)
2024-06-01 11:00:49 +02:00
Benno Schulenberg
5251ce1b20 tweaks: simplify a condition, to match the same condition five lines back 2024-06-01 09:30:44 +02:00
Benno Schulenberg
b3780aab33 docs: remove the 'filename:linenumber' format from the synopsis
(This should have been part of commit 4930fbbb from five days ago.)
2024-05-31 16:48:08 +02:00
Benno Schulenberg
5bc6d0ef2e tweaks: extend the deprecation period of 'set nowrap' and prefix 'bright' 2024-05-31 16:41:46 +02:00
Benno Schulenberg
b92cbf5f09 rcfile: remove old bindable function 'nowrap', alias of 'breaklonglines'
The bindable function 'nowrap' has been deprecated for three years,
since version 5.5, commit e14127b8.

(The obsolete options --nowrap and 'set nowrap' continue to exist.)
2024-05-31 15:57:01 +02:00
Benno Schulenberg
c26f901ba9 options: remove the deprecated synonym -$ of -S/--softwrap
The old short option -$ has been deprecated for four years,
since version 5.0, commit 7d3aad40.
2024-05-31 12:45:18 +02:00
Benno Schulenberg
a590645cde docs: document the new --listsyntaxes (-z) option 2024-05-31 11:14:24 +02:00
Benno Schulenberg
49c2f5dea9 new feature: option -z lists the names of available syntaxes
When one has installed additional syntaxes, one tends to forget
what exactly is there.  So it's nice to be able to list them.

The syntaxes are listed in the reverse order in which they were
read: the most recent first.

The long form of the option is, of course, --listsyntaxes,
which can be abbreviated to --list.

This fulfills https://savannah.gnu.org/bugs/?65779.
The feature was suggested by `davidhcefx`.
2024-05-31 11:14:24 +02:00
Benno Schulenberg
b408147f48 tweaks: exclude the colon-parsing code from the tiny version
The option --colonparsing is not available in the tiny version,
so there is no need for the code either.
2024-05-28 17:12:30 +02:00
Benno Schulenberg
4930fbbba7 docs: explain the details of --colonparsing / -@ / 'set colonparsing'
Also, remove the earlier explanation, when colon parsing was still
done by default.
2024-05-26 17:11:09 +02:00
Benno Schulenberg
02dd0b4ed5 options: require --colonparsing/-@ to parse colon+number after a filename
Stop doing colon parsing by default, to avoid surprises and frustration
for users that have filenames that end in a colon plus digits.

The equivalent rcfile option is, of course, 'set colonparsing'.

Using +1, or similar, before the filename disables any colon parsing
and the filename is taken as is.
2024-05-25 16:48:35 +02:00
Benno Schulenberg
add945e717 files: look for digits and colons starting from the end of the filename
Starting from the end of the provided filename avoids needlessly looking
at colons that are somewhere in the middle of the path or the filename.

It also avoids inconsistenly interpreting a specified line number as a
column number when the filename itself ends with a colon plus digits
and the filename without the colon plus digits exists too.

This also removes the eliding of a backslash before a colon, which
would mangle the filename if the name actually contained a backslash
followed by a colon.

Negative line and column numbers are no longer allowed when using the
colon notation.

This fixes https://savannah.gnu.org/bugs/?65781,
and fixes https://savannah.gnu.org/bugs/?65782.

Problems existed since version 8.0, since colon parsing was introduced.
2024-05-25 16:48:24 +02:00
Benno Schulenberg
259a3c70e3 general: disable the type-ahead checking that ncurses normally does
While updating the screen, ncurses by default polls the input source
now and then to see if there is new input, and if so, stops updating
the screen and waits for the next call of doupdate() or refresh().

  https://lists.gnu.org/archive/html/bug-ncurses/2024-05/msg00077.html

Disable this polling, as it is just a waste of time, and there *might*
be situations where the intruding keystroke does not actually trigger
a new update, which could result in a half-updated screen.
2024-05-20 17:14:09 +02:00
Benno Schulenberg
2445e77535 files: avoid mistakenly setting the column number to a given line number
When the file 'foo:24' exists (but not 'foo') and the user wants to
use the colon notation to place the cursor on a certain line, then
nano would first interpret the given line number as a column number,
before noticing that 'foo' does not exist and then skipping the first
colon.  So, when such a misinterpretation occurs, the column number
needs to be reset to zero.
2024-05-18 16:02:09 +02:00
Benno Schulenberg
d64235eb6e tweaks: reshuffle a declaration, adjust a comment, normalize indentation 2024-05-18 16:02:09 +02:00
Benno Schulenberg
54c8cb8c81 files: when a filename with a colon and digits exists, open that file
When the user specifies, on the command line, a filename that ends with
a colon plus digits, and that filename exists in the file system, then
open that file, instead of interpreting the digits as a line number.

Also, if the filename stripped of the colon plus digits does not exist,
then do not interpret the digits as a line number either but treat them
as part of the file name.

Before this change, the user would have to escape the colon whenever
they wanted to open a file whose name ended with a colon plus digits.
Now the user needs to escape the colon only when 'foo' exists and they
want to create, say, 'foo:24'.

Problem-was-reported-by: Ralph Corderoy <ralph@inputplus.co.uk>
  https://lists.gnu.org/archive/html/nano-devel/2024-05/msg00001.html
Mitigation-was-suggested-by: Mike Scalora <mike@scalora.org>
  https://lists.gnu.org/archive/html/nano-devel/2024-05/msg00008.html
2024-05-18 16:02:09 +02:00
758130f5b9 Merge in upstream changes 2024-05-14 19:11:00 -07:00
Benno Schulenberg
803a16cbcd input: drop recognition of the urxvt escape sequences for M-Home/M-End
Nano does not recognize the urxvt escape sequences for other
<Alt+cursorkey> combinations either.  And with the previous
two commits, the urxvt user can now "help themselves".

This reverts commit 363a4378 from three days ago.
2024-05-14 16:39:34 +02:00
Benno Schulenberg
0b43c8da11 docs: extend the FAQ item about urxvt modified keys, with M-Home/M-End 2024-05-14 16:39:14 +02:00
Benno Schulenberg
c446904c19 input: recognize the raw Xterm escape sequences for Alt+Home and Alt+End
This makes those keystrokes work too when --raw is used.

But more importantly: these raw sequences can be used in an
~/.Xresources file to override the odd behavior of urxvt for
those keystrokes, making the previous commit redundant.
2024-05-12 10:27:35 +02:00
Benno Schulenberg
363a4378b7 input: provide for urxvt setting a high bit or sending an extra escape
When pressing Alt+Home/Alt+End on urxvt, urxvt either sets the high bit
of the last byte in the sequence for Home/End (when Meta8 is True), or
sends an extra escape before that same sequence (when Meta8 is False).
Accommodate for this bug by recognizing the produced code sequences.

Indirectly-reported-by: Sébastien Desreux <seb@h-k.fr>
  https://lists.gnu.org/archive/html/nano-devel/2024-05/msg00007.html
2024-05-11 16:28:04 +02:00
Benno Schulenberg
f70f528730 build: check for the correct function in an #ifdef
Problem existed since version 7.0, commit 19c8cea8,
that replaced calls of wait() with calls of waitpid().
2024-05-05 10:43:23 +02:00
Benno Schulenberg
2334dedba6 tweaks: make a comment more accurate, and unabbreviate a variable name 2024-05-05 10:27:21 +02:00
Benno Schulenberg
e9c7dfa992 minibar: do not falsely report that a new, empty file is in Mac format
The 'openfile->fmt' element gets initialized to 'UNSPECIFIED',
so the code has to take that possibility into account.

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

Bug existed since version 8.0, commit fe4f74f6.
2024-05-03 12:12:09 +02:00
Benno Schulenberg
33eaf3e947 po: update translations and regenerate POT file and PO files 2024-05-01 10:42:51 +02:00
Benno Schulenberg
ce5513b009 bump version numbers and add a news item for the 8.0 release 2024-05-01 10:10:15 +02:00
Benno Schulenberg
a98b03e46e tweaks: rewrap two old news items 2024-04-28 16:49:09 +02:00
Benno Schulenberg
e4c3ffcd38 tweaks: rename a variable, away from an abbreviation 2024-04-28 13:45:08 +02:00
Benno Schulenberg
5e7a3c2e7e files: run chmod and chown on the descriptor, not on the filename
This closes a window of opportunity where the emergency file could be
replaced by a malicious symlink.

The issue was reported by `MartinJM` and `InvisibleMeerkat`.

Problem existed since version 2.2.0, commit 123110c5, when chmodding
and chowning of the emergency .save file was added.
2024-04-28 10:56:21 +02:00
Benno Schulenberg
c020d53e23 input: snip the recordmacro and runmacro keystrokes in a better way
When recording a macro over a laggy connection or on a slow, overloaded
computer, several keystrokes could be recorded in one burst, and if any
but the last of those keystrokes was the shortcut for `runmacro`, then
running the macro would lead to an infinite loop and nano would hang.

This new implementation of snipping the "last keystroke" will, however,
snip *too many* keystrokes when several of them were recorded at once
and `runmacro` or `recordmacro` was among them, resulting in a cropped
and thus misrecorded macro.  But... that's better than hanging.

In general, though, the user should be slow and deliberate when
recording a macro: waiting for nano to have processed the last
keystroke before typing the next.

This fixes https://savannah.gnu.org/bugs/?65649.
The issue was reported by `correctmost`.

Problem existed since version 2.9.0, since macros were introduced.
2024-04-27 17:17:03 +02:00
Benno Schulenberg
cb02937714 wrapping: delete only single characters, not a possibly marked region
These calls of do_delete() were meant to delete just one character,
but over time do_delete() morphed into doing also other things...
Change the calls to invoke the correct function instead.

(This also avoids snipping any zero-width characters that come after
a snipped space, as that is probably not what the user wants.)

This fixes https://savannah.gnu.org/bugs/?65636.
The issue was reported by `correctmost`.

Bug existed since version 3.2, commit ae3ec178,
when --zap was introduced.
2024-04-25 11:01:42 +02:00
Benno Schulenberg
1327e296c2 tweaks: rename a function, for contrast, and update antiquated comments 2024-04-25 10:34:03 +02:00
Benno Schulenberg
d53521a631 syntax: sh: recognize more shells than sh on a shebang line for busybox
Also, elide an unneeded pair of parentheses.

Original-patch-by: Sertonix <sertonix@posteo.net>
  https://lists.gnu.org/archive/html/nano-devel/2024-04/msg00026.html
2024-04-22 10:29:02 +02:00
Benno Schulenberg
5beb14cffe softwrap: realign start-of-screen when redoing an automatic hard-wrap
Redoing an automatic hard-wrap while one or more chunks of the affected
line are offscreen, can leave 'firstcolumn' with a value that doesn't
fit the situation.  So, make sure that it has a valid value.

This complements the previous commit.

This fixes https://savannah.gnu.org/bugs/?65611.
The issue was reported by `correctmost`.

Bug existed since version 2.8.6, commit e375995d.
2024-04-19 16:11:14 +02:00
Benno Schulenberg
7b07e1ee5c softwrap: adjust start-of-screen when the 'edittop' line is hard-wrapped
When one or more chunks of the current line are above the viewport,
and this line gets hard-wrapped, then 'edittop' needs to be advanced,
otherwise the first row could be blank -- representing a chunk that
doesn't exist any more.

This fixes https://savannah.gnu.org/bugs/?65604.
The issue was reported by `correctmost`.

Bug existed since version 2.8.6, commit e375995d.
2024-04-17 17:12:09 +02:00
Benno Schulenberg
c02aec557c syntax: makefile, sh: recognize also a fresh Makefile and fresh .profile
When opening a nonexistent file with nano, it likely consists of only a
name without any path component, and thus without any slash.  So when a
file regex checks for a slash, it should check also for start-of-string.

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

Problem existed for the Makefile since version 2.9.8, commit 22663f8a,
and for .profile since version 3.0, commit 4a268678 (but earlier, nano
did not recognize .profile files at all).
2024-04-14 12:09:36 +02:00
Benno Schulenberg
c695d49a86 editing: adjust the mark before trimming redundant blanks
When an entirely blank line is trimmed (when --autoindent is active and
Enter is pressed while the cursor is at the end of the current indent),
the mark needs be adjusted *before* 'current_x' is zeroed, otherwise the
mark gets moved too much to the right, which causes the region to become
bigger than what the user intended, or leads to accessing unallocated
memory.

This fixes https://savannah.gnu.org/bugs/?65586.
The issue was reported by `correctmost`.

Bug existed since version 2.8.1, commit 005ee8ed.
2024-04-13 16:24:18 +02:00
Benno Schulenberg
3cd3ba0397 gnulib: update to its current upstream state 2024-04-12 10:57:03 +02:00
Benno Schulenberg
829ab5e72d syntax: nanorc: colorize {toprow} and {bottomrow} for string binds 2024-04-07 15:55:38 +02:00
Benno Schulenberg
4ae8082552 files: do not allow M-U to remove text read from standard input
This fixes https://savannah.gnu.org/bugs/?65565.

Problem existed since version 2.1.8, commit 25d459aa,
since reading from standard input was introduced.
2024-04-07 11:33:34 +02:00
Benno Schulenberg
2c8d57fbb2 docs: document the new bindable functions 'toprow' and 'bottomrow' 2024-04-07 10:57:07 +02:00
Benno Schulenberg
e51a28e492 rcfile: add bindable functions for moving the cursor to top or bottom row 2024-04-07 10:47:03 +02:00
Benno Schulenberg
72c83badf6 feedback: lowercase a letter, as the phrase is not a full sentence
It could also have been after a comma (instead of between parentheses).
2024-04-07 10:39:06 +02:00
Benno Schulenberg
fe4f74f631 minibar: mention the file format when it's DOS or Mac
This provides feedback about the file format in a better way than
how it was done until the previous commit.
2024-04-07 10:27:21 +02:00
Benno Schulenberg
2b335060b0 feedback: suppress format-conversion messages for --zero and --mini
A "Read xx lines (converted from...)" message should be suppressed when
--zero or --minibar are active (just like the normal "Read xx lines"),
as otherwise it gets shown at a confusing moment when multiple files
are opened at the same time.  The message should get shown, however,
when inserting a file into the current buffer.

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

Bug existed since version 6.0, commit f147131e.
2024-04-06 17:55:29 +02:00
Benno Schulenberg
c3fc3ec73d tweaks: slightly reword the help text for the Replace-With prompt
To avoid the vague impression that the characters typed at the two
prompts should correspond one to one.
2024-03-31 14:02:29 +02:00
Benno Schulenberg
be14fc593f tweaks: rename two variables, to be clearer and to match others
Also trim a verbose comment.
2024-03-30 12:39:15 +01:00
Benno Schulenberg
f2bfa53b61 tweaks: elide a redundant variable 2024-03-30 12:39:04 +01:00
Benno Schulenberg
25d07b422d tweaks: rename a variable, to better indicate what it represents
And also to get away from the abundance of the word "current".
2024-03-30 11:35:41 +01:00
Benno Schulenberg
8610857015 feedback: drop an unnecessary warning, to not bother the user
The idea of the warning was that `row < 0 || row >= editwinrows` would
never be true: that the check was redundant and could be removed.

As it appears to be too hard to make sure in advance that a chunk will
not fall outside the viewport, just drop the warning and leave the check
in place.

This also addresses https://savannah.gnu.org/bugs/?64168.
Reported-by: Matteo Raso <matteo_luigi_raso@protonmail.com>
2024-03-30 11:15:32 +01:00
Benno Schulenberg
17abce073f display: do not attempt to draw a line that is outside the viewport
When we're on the last row in the viewport, it is unwise to try and draw
the next line.

This fixes https://savannah.gnu.org/bugs/?65539.
The issue was reported by `correctmost`.

Bug existed since commit c2322f85 from three days ago.
2024-03-30 10:49:29 +01:00
Benno Schulenberg
02d50bd4aa help: mention M-Home and M-End in the help text and help lines
Make these new keystrokes discoverable for people who read help texts.
2024-03-29 12:56:15 +01:00
Benno Schulenberg
67d459b262 bindings: let <Alt+Home/End> move the cursor to top/bottom of viewport
For now these are hidden keystrokes -- they are not listed anywhere,
and the functions are not bindable by the user.
2024-03-28 16:04:34 +01:00
Benno Schulenberg
5ecefb8766 moving: preserve horizontal position when jumping to top or bottom row 2024-03-28 16:04:34 +01:00
Benno Schulenberg
52eb0e992d new feature: functions that jump to the top or bottom of the viewport
(The next commit will preserve the horizontal cursor position.)
2024-03-28 16:04:34 +01:00
Benno Schulenberg
19ddc081c1 tweaks: rename a variable, to be more readable 2024-03-28 16:01:48 +01:00
Benno Schulenberg
8e91e26cc5 tweaks: reshuffle three fragments of code, moving related things together
And avoid calling xplustabs() twice in a row.
2024-03-28 15:58:28 +01:00
Benno Schulenberg
c2322f8563 display: draw a new magic line rightaway when there are multiline regexes
Drawing a line will allocate multidata for it (even when the line is
actually empty), so that this multidata will not be missing later on
when the next line gets drawn in the same burst of keystrokes.

(This also removes the triggering of a full refresh when line numbers
are active: only the new magic line needs to be additionally drawn, in
order to get the line number printed.)

This fixes https://savannah.gnu.org/bugs/?65516.
The issue was reported by `correctmost`.

Problem existed since version 6.3, commit 80c2000f.
2024-03-27 11:12:47 +01:00
Benno Schulenberg
4f0683a481 docs: add an example binding for normalizing Unicode to the sample nanorc
This requires `uconv` from the 'icu-devtools' package (on Debian).
2024-03-26 11:37:29 +01:00
Benno Schulenberg
b9449de5cf docs: improve the description of the 'flipexecute' bindable function
It is bindable only in the Insert menu -- in the Execute menu it has
a "blind", unadvertised binding (because I consider toggling between
menus somewhat of a misfeature).
2024-03-26 11:29:56 +01:00
Benno Schulenberg
c3a9578b82 feedback: raise the level of "Macro is empty", to match similar messages
The other three "... is empty" messages use the AHEM error level too.
2024-03-26 11:27:38 +01:00
Benno Schulenberg
6351dab3e6 bindings: let M-" place/remove an anchor, and let M-' jump to one
On my current laptop, typing <Alt+Insert> is awkward because it requires
holding down <Fn> too.  Also, M-" and M-' are in the normal symbols area
of the keyboard, which makes them easier to type and more discoverable.
Furthermore, being next to M-: and M-; (on a US keyboard) reinforces the
meanings: start/place, stop/remove, run/goto.
2024-03-25 11:01:14 +01:00
Benno Schulenberg
3ef6399d56 tweaks: rename a variable, away from an abbreviation
And rename its sister too.
2024-03-24 10:46:46 +01:00
Benno Schulenberg
f4754bfb5a memory: prevent a leak by freeing a possibly already existing color combo
This fixes https://savannah.gnu.org/bugs/?65505.

Buglet existed in this form since version 2.9.3, commit 4b24ce1c.
2024-03-23 11:04:23 +01:00
Benno Schulenberg
3fb8efc8f2 input: prevent 'macro_length' from underflowing when hammering M-:
Normally, when recording a macro, users will make their keystrokes
slowly and carefully, and will most likely wait to see the effect
of the previous keystroke before making the next.  So, the chances
of two `recordmacro` keystrokes coming in in quick succession is
normally nil.  The 'macro_length' variable just needs a guard to
prevent it from underflowing when someone is hammering the keys.

This fixes https://savannah.gnu.org/bugs/?65394 in a better way.
2024-03-22 16:27:34 +01:00
Benno Schulenberg
9ae84071eb input: store key codes in the macro buffer as they come in from ncurses
Otherwise the leading ESC of keystrokes like M-A does not get recorded.

This reverts commit 191cf671 from three weeks ago.

This fixes https://savannah.gnu.org/bugs/?65507.
2024-03-22 16:27:11 +01:00
Benno Schulenberg
c2b4c2ae0e docs: mention that 'light' background colors do not work on Linux console
This addresses https://savannah.gnu.org/bugs/?65501.
Reported-by: Alan Cristhian Ruiz <alancristhian@protonmail.com>
2024-03-22 11:23:05 +01:00
Benno Schulenberg
9f1431be17 justify: keep as much of the marked region onscreen as possible
When the justified region fits in its entirety onscreen, then it should
be shown in its entirety, because the user is probably curious what the
region looks like after justification.  This behavior will mean that
the line above the topline of the screen will still have multidata
(when the syntax has multiline regexes).  When the justified region
does not fit onscreen, then as much as possible should be shown --
meaning that the cursor should be either at the top or the bottom
of the viewport, meaning that it should not be centered.

This fixes https://savannah.gnu.org/bugs/?65482.
The issue was reported by `correctmost`.

Bug existed since version 4.0, since justifying a region was introduced.
2024-03-19 17:18:18 +01:00
Benno Schulenberg
e1c6ae7cf3 justify: keep the cursor at the original end of a marked region
When justifying a region that was marked backwards, the cursor
should stay at the beginning of this region.  The old logic was
faulty because mark_is_before_cursor() does not give the correct
result *after* the justification has been done: for some reason
the mark ends up always before the cursor.

Bug existed since version 5.2, commit 0f8423eb,
which mistakenly removed the auxiliary variable.  :/
2024-03-19 16:45:02 +01:00
Benno Schulenberg
bb7a9fe7d2 tweaks: ungettextize three strings, to make a translator hint right again
The strings are gettextized further down, for the non-tiny version,
so they will get translated anyhow.  The relevant translator hint
is the earlier one about "the next thirteen strings".

Also adjust an indentation, and ungettextize another string for
consistency.
2024-03-19 11:56:33 +01:00
Benno Schulenberg
d77263d8ed bindings: let M-& show the ncurses version+patch, as a small Easter egg 2024-03-18 10:33:40 +01:00
Benno Schulenberg
fdd92af3ac display: add a wnoutrefresh() call for NetBSD, to force a cursor update
With NetBSD curses, when only the cursor is moved (without writing any
text), then a call of wnoutrefresh() is needed to make doupdate() move
the cursor.  Ncurses does not need this.

This addresses https://savannah.gnu.org/patch/?10438.
2024-03-18 10:02:11 +01:00
Benno Schulenberg
dd009e0bc7 tweaks: rename a function and variable, to describe better what they do 2024-03-17 17:18:48 +01:00
Benno Schulenberg
170e7d79e7 tweaks: express an 'if' more concisely, and add two blank lines
The calls of wnoutrefresh() after those new blank lines are not needed
for ncurses to show the cursor in the right place, but are logically
needed because things have been written to the screen in the preceding
code -- although nano seems to work correctly also without those calls.
2024-03-17 16:57:19 +01:00
Benno Schulenberg
a7635ceb5d tweaks: rename a variable, to be a bit more indicative 2024-03-17 16:40:04 +01:00
Benno Schulenberg
64fb0be8b2 tweaks: add another translator hint, to help avoid overlong key tags 2024-03-16 16:28:16 +01:00
Benno Schulenberg
a5a8487132 tweaks: improve three translator hints
The browser listing has a rigid format: longer translations
for "(dir)", "(parent dir)", and "(huge)" will be clipped.
2024-03-15 14:06:14 +01:00
Benno Schulenberg
8cf61af551 indicator: do not oversize the scroller when softwrapping
This fixes https://savannah.gnu.org/bugs/?65445.

Bug existed since version 5.7, commit 49d8b99e.
2024-03-11 11:18:28 +01:00
Benno Schulenberg
778f000a3b docs: use a space after #, like everywhere else in the sample nanorc
Also, use a more mnemonic example shortcut for copy-to-clipboard.
2024-03-10 17:32:09 +01:00
Benno Schulenberg
623ff4e1ed docs: trim stuff that is more than five years old from the changelog
A detailed list of changes is useful for a small number of users only,
and only when the changes are fairly recent.

The NEWS file, that contains a summary of user-visible changes and
will be useful for a larger number of users, is distributed in full.
2024-03-09 17:18:04 +01:00
Benno Schulenberg
260f00c76d screen: recalculate the multidata when detecting the need for it
This fixes https://savannah.gnu.org/bugs/?65435.
The issue was reported by `correctmost`.

Problem existed since version 6.3, commit 80c2000f.
2024-03-09 09:01:31 +01:00
Benno Schulenberg
0c8a3b5c3e tweaks: pull a fragment of code a bit forward, to enable the next commit 2024-03-09 08:32:47 +01:00
Benno Schulenberg
e76068a2de docs: adjust an example help line in the README to the current state 2024-03-08 17:12:28 +01:00
Benno Schulenberg
a12e45c355 help: show ^F/^B as primary shortcuts for search, not as secondary
This looks better in the help viewer (^F/^B matching the pair M-B/M-F),
and showing ^F instead of ^W for search in the main edit window will
prevent novice users from using ^W in situations where they shouldn't.
2024-03-08 11:50:20 +01:00
Benno Schulenberg
74b9dd6881 help: rebalance the help items when --preserve is used
As a backward search is now normally always bound (to ^B, instead of
conditionally to ^Q), ^L should always be shown in the help viewer.

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

Problem existed since commit 8a304bdf, since ^F/^B do a search.
2024-03-08 11:31:02 +01:00
Benno Schulenberg
edd0823d96 docs: mention that --modernbindings overrides --preserve 2024-03-08 11:25:14 +01:00
Benno Schulenberg
4ef4eb4f12 options: make --modernbindings actually override --preserve
When modern bindings are requested, ^S should save and ^Q must exit,
so --preserve and 'set preserve' need to be cancelled.

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

Bug existed since commit 18b37c98, which introduced --modernbindings.
2024-03-08 11:04:48 +01:00
Benno Schulenberg
862574f381 undo: force a screen refresh also for the special case Bsp-at-EOF
Because meanwhile the cursor might be someplace where EOF is offscreen.

This effectively reverts commit 9ccf85ea from two years ago, but also
sets 'focusing' to false so that the last line of the buffer will be at
the bottom of the edit window, where it probably was when Bsp was typed.

This fixes https://savannah.gnu.org/bugs/?65428.
The issue was reported by `correctmost`.

Bug existed since version 6.3, commit 9ccf85ea.
2024-03-07 17:14:18 +01:00
Benno Schulenberg
c67ea1ffc1 undo: recompute the multidata when a piece of text is replaced
When a justification (or even a spell check) is undone or redone,
this might affect the matching of multiline regexes, so... schedule
a recalculation of the multidata in those cases.

This fixes https://savannah.gnu.org/bugs/?65426.
The issue was reported by `correctmost`.

Problem existed since version 6.3, commit 80c2000f.
2024-03-07 16:51:08 +01:00
Benno Schulenberg
5bd5bcd06a docs: mention backreferences (for replacements with regular expressions)
Also mention that nano prompts for each occurrence, and that, when
a region is marked, replacements are made only within that region.
2024-03-05 15:50:15 +01:00
Benno Schulenberg
a13cd6a177 execute: show "Older" and "Newer" in the help lines, to allow rebinding
Since commits c8363a0d and a75bf0a1 from seven years ago, the Execute
menu permits retrieving previously executed commands, but the help text
and help lines never showed the corresponding keystrokes.

Four years ago commit d3954901 made the Execute menu directly accessible,
but I preferred to not mention the ^P/^N keystrokes in the help lines,
to leave as much space as possible for the executable functions (added
in subsequent commits), thinking that no one would want to rebind those
keystrokes anyway, as the Up/Down arrows seem more logical and easier.

The issue was reported by Ivan Vorontsov:
  https://lists.gnu.org/archive/html/help-nano/2024-02/msg00003.html
2024-03-05 11:31:48 +01:00
Benno Schulenberg
f60c6b25ad docs: delete a remark about libvte that is no longer relevant
Libvte 0.55 is more than five years old -- almost all users will
have upgraded by now to 0.55 or newer.
2024-03-05 08:44:04 +01:00
Benno Schulenberg
c6a2664106 tweaks: delete a redundant fragment of code from do_replace_loop()
Since commit 50954a4b from a year and a half ago, a replacing session
will not ever change the final empty line, so a fresh magic line will
never be needed.
2024-03-04 16:30:09 +01:00
Benno Schulenberg
4ab80abb5e justify: recompute the multidata for paragraphs larger than the viewport
A freshly justified paragraph does not yet have any multidata,
and if this new paragraph has more lines than fit in the viewport
(minus one line for the cursor), then the line above the top of the
new viewport will be without multidata.  The coloring code cannot
handle this, so all the multidata then needs to be recalculated.

This fixes https://savannah.gnu.org/bugs/?65396.
The issue was reported by `correctmost`.

Problem existed since version 6.3, commit 80c2000f.
2024-03-04 12:52:18 +01:00
Benno Schulenberg
f37d097c1c rcfile: avoid crashing on an include path that is way too long
The `gnulib` globbing module apparently does not handle an overload
of slashes well, so avoid feeding it more than it can take.

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

Problem probably existed since version 2.3.3,
since globbing was introduced.
2024-03-04 11:44:22 +01:00
Benno Schulenberg
191cf671be input: store keystroke in macro buffer only when about to interpret it
When the keystroke after the keystroke bound to `recordmacro` arrived
so quickly that the two got stored together in nano's keystroke buffer,
the main loop had not yet interpreted the `recordmacro` command and had
thus not yet set 'recording' to true, meaning that that second keystroke
would not get recorded.

Nano should record keystrokes into the macro buffer when fetching them
from its own keystroke buffer, not when fetching them from ncurses.

This fixes https://savannah.gnu.org/bugs/?65394.
The issue was reported by `correctmost`.

Bug existed since version 2.9.0, since macros were introduced.
2024-03-02 17:45:11 +01:00
Benno Schulenberg
3098315e05 replacing: stash the string to be replaced while asking for replacement
During the Replace-With prompt the user could search in its help text,
which would overwite the 'last_search' string.  Make therefore sure that
the latter gets restored to what it was before the Replace-With prompt.

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

Bug existed since version 2.8.2,
since searching in a help text became possible.
2024-02-28 11:44:03 +01:00
Benno Schulenberg
39db2e9d66 tweaks: implement the fix of the previous commit somewhat differently 2024-02-27 17:24:32 +01:00
Benno Schulenberg
ee1a1306e2 search: avoid crashing after searching a help text during a regex replace
Searching in a help text does not support using regular expressions,
so when 'inhelp' is set, do not free a compiled regex -- because if
there is such a regex, it belongs to a replacement session that is
about to begin.

This fixes https://savannah.gnu.org/bugs/?65369.
The issue was reported by `correctmost`.

Bug existed since version 2.8.2,
since searching in a help text became possible.
2024-02-26 13:20:24 +01:00
Benno Schulenberg
db72774458 verbatim: avoid referencing an uninitialized value
Only check input bytes when their count is nonzero.

This fixes https://savannah.gnu.org/bugs/?65365.
The issue was reported by `correctmost`.

The problem existed since version 5.7, commit c75a3839,
but occurred more easily since version 7.0, commit 75e5f885.
2024-02-26 10:48:51 +01:00
Benno Schulenberg
3d727266c3 input: for one bump of the mousewheel scroll two lines, not three
Scrolling three lines at a time goes too fast: it feels erratic.
Whereas scrolling two lines at a time still feels like scrolling.
2024-02-25 16:14:44 +01:00
Andy Koppe
4673e709b2 input: scroll on mousewheel events instead of moving the cursor
Translate mousewheel events into Alt+Up/Down key presses instead of
into plain Up/Down key presses, as the latter only start scrolling
once the cursor reaches the top or bottom.

Scrolling rather than moving the cursor is the standard behavior for
mousewheel events in GUI editors such as Gedit and Kate, as well as
in the mouse mode of terminal editors such as vim, joe, and mcedit.

Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
2024-02-23 16:06:33 +01:00
Benno Schulenberg
f1a04f780a syntax: javascript: recognize also the .mjs extension
The V8 JavaScript-engine developers recommend using this extension:
  https://v8.dev/features/modules#mjs

Also, add the fairly new "JavaScript source" as magic description.

This fulfills https://savannah.gnu.org/bugs/?65334.
Requested-by: Matt Whitlock <gnu@mattwhitlock.name>
2024-02-20 17:00:48 +01:00
Benno Schulenberg
eca5856d99 tweaks: remove two pairs of unneeded braces, and normalize a line 2024-02-18 15:02:51 +01:00
Benno Schulenberg
190221c91c justify: set x = 0 for the undo item, for when using --cutfromcursor
When --cutfromcursor is active, 'current_x' needs to be set to zero when
doing a justification, so that the correct starting position gets stored
in the undo item.  (Without --cutfromcursor, the value of 'current_x'
does not matter.)

This fixes https://savannah.gnu.org/bugs/?65317.
The issue was indirectly reported by `correctmost`.

Bug existed in this form since version 5.0, commit ae5a4ece.

Between versions 4.0 and 5.0, nano would not eat a line but would
instead crash when undoing a justification that was done with the
cursor away from the left edge.
2024-02-16 15:56:22 +01:00
Benno Schulenberg
77d74b5d81 input: flush the keystroke buffer upon any kind of error condition
This stops the execution of a macro or a string bind whenever something
unexpected happens, to prevent the waiting keystrokes from doing things
that were not intended.

Especially this prevents an infinite loop: when during the recording
of a macro the `runmacro` keystroke is typed in some menu (where the
keystroke is not bound), and the macro is later replayed in a way that
results in exiting from that menu before the `runmacro` keystroke gets
replayed...

This fixes https://savannah.gnu.org/bugs/?65301.
The issue was reported by `correctmost`.

Bug existed since version 2.9.0, since the macro feature was introduced.
2024-02-14 09:23:18 +01:00
Benno Schulenberg
0e44752ba1 justify: set the correct starting point also with --cutfromcursor
When --cutfromcursor is active, 'current_x' does need to be zero for
the segment extraction to do the right thing.

This fixes https://savannah.gnu.org/bugs/?65289.
The issue was indirectly reported by `correctmost`.

Bug existed since version 4.0, commit 2500debb.
2024-02-11 16:31:20 +01:00
Benno Schulenberg
20692e0c29 browser: restore typing position at prompt after "^R name ^T ^F ^V ^C"
When going back from the browser to a file prompt, restore the typing
position also after a 'to_first_file' (^Y) and 'to_last_file (^V).

The cursor misplacement existed since version 5.9, commit 508301a2.
2024-02-11 16:05:56 +01:00
Benno Schulenberg
206b4e2a7e search: avoid a crash after a nested search, reported by correctmost
When going back to a previous prompt, restore the typing position
also for 'to_first_line' (^Y) and 'to_last_line (^V).

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

Bug existed since version 5.9, commit 6d5b1656, which allowed exiting
from a Search-in-help prompt with ^Y or ^V.
2024-02-11 14:57:24 +01:00
Benno Schulenberg
8fefee2d41 undo: prevent a use-after-free, reported by correctmost
When the cursor is on the last line, and an undo removes this line,
do not let 'openfile->current' become invalid.

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

Bug existed since version 6.3, commit eea3e1f0.

(It should have been fixed in commit 9410a556, more than a year ago.)
2024-02-10 12:14:52 +01:00
Benno Schulenberg
cdaa43b396 syntax: makefile: ensure that the <Tab> key always produces a tab
Making it independent from the `tabstospaces` setting.

And remove the now-redundant suggestion from the sample nanorc.
2024-02-05 17:17:37 +01:00
Benno Schulenberg
a0eebf20db bindings: in the tiny version, bind M-6 only in main, not at the prompts
This prevents M-6 from unexpectedly exiting from the prompt
and then copying a line in the edit window.
2024-01-31 08:34:02 +01:00
Benno Schulenberg
b84f6fc15f general: include the Copy function (M-6 or ^C) into the tiny version
When using --modernbindings with the tiny version, it was strange that
^X cuts and ^V pastes but ^C complains about being unbound.  Fix that.
2024-01-31 08:21:28 +01:00
Benno Schulenberg
d0a1bc361a help: restore ^H and ^D as the primary shortcuts for Backspace and Delete
Commit 18b37c98 moved the bindings of ^H and ^D further down.  Now move
the bindings of <Bsp> and <Del> to after those, so that ^H and ^D will
be shown again first in the help text (when not using --modernbindings).
2024-01-30 08:13:23 +01:00
Benno Schulenberg
d35650b034 docs: document the new --modernbindings option 2024-01-29 10:40:48 +01:00
Benno Schulenberg
580eaf29d6 bindings: set up modern bindings also when binary's name starts with "e"
This allows activating the "modern" bindings without having to pass an
option, by simply invoking nano through a symlink -- for example: `en`
(short for "editor nano"), or `et` (short for "edit"), or just `e`.
2024-01-29 10:40:48 +01:00
Benno Schulenberg
a27da0d75b bindings: with --modern, do not let ^Q^Q quit nano without saving
With --modernbindings, instead accept ^Q^X for abandoning any changes
-- the inverse of the normal (but undocumented) ^X^Q.

This prevents the unintentional loss of work when the user hits ^Q twice
by accident.
2024-01-29 10:40:48 +01:00
Benno Schulenberg
26c75a6828 bindings: with --modern, use ^H for Help when the terminal allows it
Also, allow using ^H (or ^N) for exiting from Help too.
2024-01-29 10:40:48 +01:00
Benno Schulenberg
c32828bb13 tweaks: normalize the indentation after the previous change 2024-01-29 10:40:48 +01:00
Benno Schulenberg
18b37c980a new feature: option --modernbindings sets up more widespread key bindings
With --modernbindings, ^Q quits, ^F finds, ^B finds backwards, ^G finds
again, ^D finds again backwards, ^X cuts, ^C copies, ^V pastes, ^A sets
the mark, ^R replaces, ^O opens a file, ^W writes out a file, ^S saves,
^Z undoes, ^Y redoes, ^P shows the position, ^T goes to a given line,
and ^E executes.

Note that with --modernbindings ^Q and ^S are always bound, meaning that
--preserve / 'set preserve' is ignored.  This is necessary because ^Q is
an essential keystroke in the modern bindings.

Also note that these "modern bindings" are effective only in the main
edit window, not in the various menus.  In all menus ^C means Cancel,
and I can't think of a good alternative default keystroke for that
(in order for ^C to mean Copy).  And in a few menus ^V has a meaning,
and there is no good alternative for that either.  So... in the menus
the user has to use M-6 for Copy and ^U for Paste (and ^K for Erase --
Cut does not exist in the menus), like with the default bindings.
2024-01-29 10:40:48 +01:00
Benno Schulenberg
64ac4610de tweaks: rewrap a comment, and reshuffle seven declarations
Also, drop three unneeded initializations.
2024-01-28 09:35:40 +01:00
Benno Schulenberg
dea34733a4 tweaks: move two static declarations to the only function that uses them 2024-01-27 11:41:57 +01:00
Benno Schulenberg
0e72c0d372 chars: add a helper function for stripping leading blanks from a string
And apply this function to the formatter and linter command strings,
to complement the bug fixes in the previous two commits.
2024-01-25 16:50:09 +01:00
Benno Schulenberg
88c8da143f linter: do not mess up the input stream when the linter command is empty
Instead simply say that no linter is defined.

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

Bug existed since version 5.5, commit bc368133, but before
that commit nano would crash on an empty linter command.
2024-01-24 16:23:09 +01:00
Benno Schulenberg
367f84b0ec formatter: do not crash when the formatter command is empty
Instead simply say that no formatter is defined.

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

Bug existed since version 4.6, since the formatter was reintroduced.
2024-01-24 16:22:04 +01:00
Benno Schulenberg
1a3ef7e497 docs: fix a ten-year-old typo, reported by correctmost
This fixes https://savannah.gnu.org/bugs/?65193.
2024-01-23 13:18:09 +01:00
Benno Schulenberg
c19012d4cd docs: say "mini bar", not "minibar", when referring to the actual bar
Like is done for the other bars: title bar, status bar, prompt bar.
2024-01-20 11:02:54 +01:00
Benno Schulenberg
b502631d10 docs: mention the changed meanings of ^F/^B and also in the texi manual
Also somewhat reword the note for version 4.0.
2024-01-18 11:06:01 +01:00
Benno Schulenberg
6728e5d791 docs: mention the missing two options that override --bold
And improve one word.
2024-01-16 16:15:22 +01:00
Benno Schulenberg
101b53b541 docs: add ^T^S (spell check) and M-S (softwrap) to the cheatsheet
Also, adjust the alignment of the two header lines,
and slightly reword one of the descriptions.
2024-01-16 10:56:41 +01:00
Benno Schulenberg
11c492fdd0 docs: add M-C and M-Z to the cheatsheet, and reshuffle for balance 2024-01-13 11:27:28 +01:00
Benno Schulenberg
792d4e9a23 docs: adjust the cheatsheet for the changed meanings of ^F, ^B, M-F, M-B 2024-01-13 11:22:14 +01:00
Mike Frysinger
c59e9d228e build: link in $(GETRANDOM_LIB) from gnulib
On Windows builds, gnulib might set GETRANDOM_LIB to -lbcrypt and then
use that API.  But since we don't include $(GETRANDOM_LIB) when linking,
we fail.  On Linux systems, this is empty as getrandom APIs are part of
the main C library already.  This is also what the link requirements say
in gnulib's modules/getrandom spec.
2024-01-12 17:00:34 +01:00
Mike Frysinger
d8848df14f gnulib: import canonicalize-lgpl for realpath
Building for mingw fails due to missing realpath.  Pull in the gnulib
module to get it working again.
2024-01-12 16:59:40 +01:00
Benno Schulenberg
4a2729b780 copyright: update the years for the FSF 2024-01-10 11:24:28 +01:00
Benno Schulenberg
7c174a1a25 syntax: c: require a preceding blank when a line comment contains a quote
This avoids miscolorizing part of a string when it contains a URL.

This fixes https://savannah.gnu.org/bugs/?64340.
Reported-by: Yonut Smith <deanlast3@gmail.com>

Problem has existed for more than twenty years, at least since support
for multine-line regexes was added in commit 6c1e6612 in 2002.
2024-01-09 10:20:50 +01:00
Benno Schulenberg
f0e69b4a51 tweaks: use a pair of parentheses to clarify the order of operations
(Parentheses are used everywhere else with a bitwise &.)
2024-01-08 17:25:03 +01:00
Benno Schulenberg
4a915b1ed5 input: avoid hanging after a 39-character paste on a VSCode terminal
The terminal in VSCode splits pastes into 50-byte chunks and can
thus split an escape sequence somewhere in the middle, resulting
in nano failing to recognize the end-of-bracketed-paste sequence
and thus hanging -- until another, different-sized paste is made.

Avoid this hang by interpreting any invalid escape sequence that
starts with "\e [ 2" as a truncated end-of-bracketed-paste.

(This will leave a spurious tilde after the 39-character paste,
which is not nice but... better than hanging.)

This works around https://savannah.gnu.org/bugs/?64996.
Reported-by: Jacob Lifshay <programmerjake@gmail.com>
2023-12-21 15:40:21 +01:00
Benno Schulenberg
cbf5a5b5d3 docs: in the sample nanorc, set the guidestripe to a soft grey
This gives both an example of the #rgb format and shows that the
guidestripe can be set to an unobtrusive color.
2023-12-18 16:14:10 +01:00
Benno Schulenberg
41b52d70be input: recognize certain escape sequences for F13 to F16 again
Even though in nano the names F13 to F24 exist, these names actually
refer to Shift+F1...Shift+F12.  One cannot blame people for thinking
that F13 in nano is the same as F13 in Xorg, so... recognize the escape
sequence for the latter and map it to what nano calls F13.

This accommodates users that put F13...F16 in a custom keymap for Xorg.

This fixes https://savannah.gnu.org/bugs/?64632.
Reported-by: Danny Milosavljevic <dannym@scratchpost.org>

Problem existed since version 5.0, commit 9a6158cd.
2023-12-17 17:48:04 +01:00
Benno Schulenberg
129696cdbe gnulib: update to current upstream state, to make a fresh checkout work
Also, increase the checkout depth, so that it will work for longer.

Indirectly-reported-by: Jacob Lifshay <programmerjake@gmail.com>
2023-12-10 10:58:01 +01:00
Benno Schulenberg
8cc3ab213d tweaks: rename a variable, to be clearer when seen in context 2023-12-09 16:25:02 +01:00
Benno Schulenberg
9bf966af37 tweaks: add an extra variable, to avoid reusing one for another purpose 2023-12-08 16:12:17 +01:00
Benno Schulenberg
a76a6bf692 softwrap: remember the actual breaking point when wrapping at blanks
When softwrapping at blanks, the wrapping routine should, when called
again, continue searching from where the previous chunk ended, not from
the point it reached during that previous search, because this could be
*just* beyond the space that could be the next breaking point.

This fixes https://savannah.gnu.org/bugs/?64945.
Reported-by: Andreas Schamanek <schamane@fam.tuwien.ac.at>

Bug existed since version 6.4, commit 0e9bef34.
2023-12-06 17:18:41 +01:00
Benno Schulenberg
6a7a0c8f50 display: show the help lines down to the tiniest possible terminal size
That is: compute the minimum needed terminal height more accurately.
2023-11-25 17:07:05 +01:00
Benno Schulenberg
f5bc261944 general: let the constant-show toggle override the zero-interface mode
When the user hits the M-C toggle while option --zero is in effect,
instead of complaining "Not possible", do what the user probably
tries to achieve: cancel `zero` mode and switch on `constantshow`.
2023-11-25 17:07:05 +01:00
Benno Schulenberg
8a304bdf7c bindings: make ^F start a forward search by default
This makes nano more usable for users that are accustomed to the
near universal use of ^F for Find/Search in other programs, and
especially for users that somehow access a terminal through their
browser (where ^W will, destructively, close the terminal tab).

(To keep the bindings consistent, make ^B start a backward search,
and let M-F and M-B search for the next occurrence in the matching
direction.)

Suggested-by: Chris Allegretta <chrisa@asty.org>
Suggested-by: Donnie Ferris <DonnyBahama@gmx.com>
  https://lists.gnu.org/archive/html/nano-devel/2023-01/msg00001.html
2023-11-24 16:24:08 +01:00
Benno Schulenberg
124e86a6d2 undo the prelast commit in order to redo it with a fuller commit message 2023-11-24 14:42:08 +01:00
Benno Schulenberg
96df9e0a20 docs: mention how to get the old behavior of ^F, ^B, M-F, and M-B back 2023-11-22 10:52:34 +01:00
9228180b1e Merge branch 'master' into line-folding 2023-11-01 12:47:08 -07:00
Benno Schulenberg
a04d2a433c bindings: make ^F start a forward search by default
This makes nano more usable for users that are accustomed to the
near universal use of ^F for Find/Search in other programs.

To keep the bindings consistent, make ^B start a backward search,
and let M-F and M-B search for the next occurrence in the matching
direction.
2023-10-30 15:01:53 +01:00
b2f79e3a6e Merge branch 'master' into line-folding 2023-08-25 12:48:22 -07:00
4622210cfb Fix some sh*t 2023-06-03 19:49:44 -07:00
9317206586 Add colorization to folding segments.
I already added this for myself since I've been using this patch for a while
so I figured I'd include it. This simply makes it possible to colorize the
folded segments as the user desires. An option 'foldedcolor' is enabled for
the rcfile.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:52:59 -07:00
7027b9b601 Add option '--enable-folding' and add shortcut for folding.
In order to test the functionality, one actually has to be able to build it!
This patch adds an option to the configure script, builds 'folding.c', and
adds a shortcut to make folding possible. The shortcut here is set to 'M-['.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:52:38 -07:00
fc3598f116 Handle all the more complicated modifications to existing functionality.
Not everything is as simple as just UNFOLD_SEGMENT. These are the cases where
specific modifications were needed. Most of the actual heavy lifting was done
when modifying the functions 'update_line' and 'do_prev_word'.

Most of the changes here actually came down to 'get_row_from_edittop' or
changing from 'update_line' to 'update_line_at'.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:52:13 -07:00
90dac326c1 Modify line number arithmetic to no longer assume linear increments.
When adding folding lines, the lines drawn on screen are no longer
guaranteed to increment one by one. There could be a large skip when
handling folded segments. So instances where the codebase assumed
'openfile->current->lineno - edittop->lineno' would yield the position
on screen of the current line needed to be modified. Similar problems
existed in many places so a function 'get_row_from_edittop' handles
finding the current position of a line in relation to 'edittop'.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:51:53 -07:00
a299827554 Modify signatures of functions to be modular for further folding patches.
The bracket search functions 'find_a_bracket' is very useful for searching for
region to fold when no selection is made. To make this possible, the function
needed to be modularized so it could be reused in a way not originally
intended.
The functions 'do_prev_word' and 'do_next_word' were interesting in that
sometimes it is desirable to get the corresponding word within a folded
segment and sometimes it was better to skip folded segments. So a boolean
parameter seemed like a good way to not duplicate functionality while
making the function work for both cases.
The 'update_line' function only worked in relation to edittop from the
given line's lineno. This obviously won't get the correct position if
there are folded lines. So I added a new function 'update_line_at' to
allow specifying where in the window to update when calling the function.
The original 'update_line' still exists to not modify existing code
utilizing it.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:50:46 -07:00
a39e61a3e0 Add calls to UNFOLD_SEGMENT in existing functions.
Nano's existing functionality needs to mesh with the ability to
fold lines. The most common of these issues is needing to unfold
when a line is updated or the user accesses a line inside of a folded
segment. This patch handles all the places this can be done simply
with a 1 or 2 line modification.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:50:22 -07:00
584571248f Add the basic support structure for the folding.
Adds in some preprocessor directives for easily adding in unfolding
support to existing functions that require it. Also adds in some
helper functions in 'folding.c' for common tasks which will need
performed. And of course add the 'folded' boolean to the linestruct
type so we know which lines are currently folded.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2023-04-06 11:49:38 -07:00
122 changed files with 49231 additions and 42608 deletions

1
.gitignore vendored
View File

@@ -45,6 +45,7 @@ core
/m4/gettext.m4
/m4/glibc2.m4
/m4/glibc21.m4
/m4/host-cpu-c-abi.m4
/m4/iconv.m4
/m4/intdiv0.m4
/m4/intl.m4

31
AUTHORS
View File

@@ -13,16 +13,15 @@ Benno Schulenberg <bensberg@telfort.nl>
Current maintainer.
David Lawrence Ramsey <pooka109@gmail.com>
* Former stable series maintainer. Multiple buffer support,
operating dir (-o) option, bug fixes for display routines,
wrapping code, spelling fixes, constantshow mode, parts of
UTF-8 support, softwrap overhaul, undoable (un)indentations,
undoable justifications, justifiable regions, and numerous
other fixes.
* Multiple-buffer support, operating-dir option (-o), bug fixes
for display routines, wrapping code, spelling fixes, parts of
UTF-8 support, softwrap overhaul, constantshow mode, undoable
indentations, undoable justifications, justifiable regions,
and numerous other fixes. Former stable-series maintainer.
Jordi Mallach <jordi@gnu.org>
* Debian package maintainer, fellow bug squasher.
* Internationalization support head, ca.po maintainer.
* Debian package maintainer, fellow bug squasher, translator
for Catalan. Former head of internationalization support.
Adam Rogoyski <rogoyski@cs.utexas.edu>
* New write_file() function, read_file() optimization, mouse
@@ -35,9 +34,9 @@ Robert Siemborski <rjs3@andrew.cmu.edu>
new edit display routines.
Rocco Corsi <rocco.corsi@sympatico.ca>
* Internal spelling code, many optimizations and bug fixes for
findnextstr() and search-related functions, various display
and file handling fixes.
* Internal spelling code, many optimizations and bug fixes
for findnextstr() and search-related functions, various
display and file-handling fixes.
David Benbennick <dbenbenn@math.cornell.edu>
* Wrap and justify bugfixes/enhancements, new color syntax
@@ -45,11 +44,11 @@ David Benbennick <dbenbenn@math.cornell.edu>
miscellaneous fixes.
Mike Frysinger <vapier@gentoo.org>
* Gentoo package maintainer. Whitespace display mode,
--enable-utf8/--disable-utf8 configure options for ncurses,
many new color regexes and improvements to existing color
regexes in syntax/*.nanorc, the move from svn to git, the
conversion to gnulib, and miscellaneous bug fixes.
* Whitespace display mode, --enable-utf8/--disable-utf8 configure
options for ncurses, many new color regexes and improvements to
existing ones in syntax/*.nanorc, the move from svn to git, the
conversion to gnulib, and miscellaneous bug fixes. Former
Gentoo package maintainer.
Mark Majeres <mark@engine12.com>
* A functional undo/redo system, and coloring nano's interface.

5654
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -8246,7 +8246,7 @@ nano-0.7.7 - 2000.01.19
- Added check for keystroke key sequence 407 or NANO_CONTROL_Z
in main while loop because suspend mode was broken. This should
fix it, at least for now.
- Added long option support (By popular harassment ;-) - Added
- Added long option support (by popular harassment ;-) : added
#include for getopt.h, changed getopt() to getopt_long().
Options added so far: --version (-V), --nowrap (-w), --suspend
(-z), --help (-h), --nohelp (-x).
@@ -8258,15 +8258,15 @@ nano 0.7.6 - 2000.01.15
main(): Bound CONTROL_H to backspace (oops).
Added more Alt-[-key combinations, for page up & down.
read_bytes(): New function. (Adam Rogoyski)
read_file(): Optimizations - malloc()s *buf a little at a time rather
than one huge buffer, and replaced the strcat at the end
with an index variable. Added call to read_bytes().
read_file(): Optimizations -- malloc()s *buf a little at a time
rather than one huge buffer, and replaced the strcat() at
the end with an index variable. Added call to read_bytes().
do_next_word(): New function, binding is Ctrl-Space (0). (Chris)
- winio.c:
bottombars(): Fixed non-expanding shortcut keys at bottom of screen.
(formula is extra space needed = COLS / 6 - 13).
actual_x() & strlenpt():
Added bug#9 fix - when tabs % 8 == 0, we should only
Added fix for bug #9 -- when tabs % 8 == 0, we should only
increment tabs by 1.
titlebar(): Fixed overrun in titlebar on very long filenames.

View File

@@ -1,6 +1,24 @@
Improvements in GNU nano
========================
Since 9.0:
- With M-< and M-> the viewport can be scrolled sideways.
- When the cursor nears the edge, all lines are scrolled sideways.
- M-Left, M-Right, M-Up, and M-Down have become rebindable.
- Immediately stopping a recording retains the existing macro.
- Clicking in the scrollbar crudely navigates in the buffer.
Since 8.0:
- To accommodate newcomers, ^F now starts a forward search.
- Option --modernbindings makes ^Q quit, ^X cut, ^C copy, ^V paste,
^Z undo, ^Y redo, ^O open a file, and ^G find again, among others.
- M-Home/M-End put the cursor on the first/last row in the viewport.
- With `nano filename:number` the given file will be opened with the
cursor on the given line number (when 'set colonparsing' is used).
- Option --listsyntaxes lists the names of available syntaxes.
- Anchors are saved and restored (when --positionlog is active).
- Key combos ^O^Q and ^X^Q cause an exit status of 2.
Since 7.0:
- String binds may contain bindable function names between braces.
- Word completion looks for candidates in all open buffers.

141
NEWS
View File

@@ -1,3 +1,109 @@
2026.07.31 - GNU nano 9.2 "Alquézar"
• Nano refuses to start when standard output is not a terminal.
• Options --newbuffer and 'set newbuffer' were added as better
synonyms of --multibuffer and 'set multibuffer'.
• Legacy keystroke pairs ^W^T and ^/^T are recognized again.
2026.06.23 - GNU nano 9.1 "met een hongerig paard aan ons been"
• When searching, the viewport is placed snug left where possible.
• The ability to read and write files in old Mac format was removed
(that is: files that use a lone carriage return as line ending).
• The ^T toggle between WhereIs and GotoLine has been dropped.
• When --backup is active, in some situations no backup was made,
or it had a wrong timestamp. Both issues are fixed now.
• When nano crashes or is killed, any .save file is not chmodded
to the permissions of the base file, nor chowned to its owner.
• M-Ins and M-Del have become rebindable.
2026.04.08 - GNU nano 9.0 "Le bonheur est dans le pré"
• When the cursor almost goes offscreen to the right, all lines are
now scrolled sideways together, by just the amount needed to keep
the cursor in view. Use --solosidescroll or 'set solosidescroll'
to get back the old, jerky, single-line horizontal scrolling.
• The viewport can be scrolled sideways (in steps of one tabsize)
with M-< and M->. See `man nanorc` if M-< and M-> should switch
between buffers (as they did earlier).
• M-Left, M-Right, M-Up, and M-Down have become rebindable.
• Stopping the recording of a macro immediately after starting it
cancels the recording and leaves an existing macro in place.
• Feature toggles no longer break a chain of ^K cuts or M-6 copies,
except the M-K cut-from-cursor toggle.
• With --mouse and --indicator, one can click in the scrollbar area
to roughly navigate within the buffer.
2026.02.04 - GNU nano 8.7.1 "Tende Samnug"
• A build failure when compiling against glibc-2.43 is fixed.
2025.11.12 - GNU nano 8.7 "Blue Highways"
• At the Execute prompt, preceding the command with two pipe symbols
allows implementing a copy-to-clipboard feature in your nanorc (on
terminals that support OSC 52). See the doc/sample.nanorc file.
2025.08.21 - GNU nano 8.6 "reason alone was a defective compass"
• The GotoLine menu accepts the prefixes ++ and -- for jumping
a number of lines forward or backward.
• Anchors are not forgotten when a line number is given on the
command line.
2025.06.12 - GNU nano 8.5 "Sigourney"
• Anchors are now saved when a file is closed, and restored when
the file is reopened -- if and when --positionlog is active.
• Nano exits with an error status upon keystrokes ^O^Q and ^X^Q.
• Keystroke ^L just centers the cursor, while M-% cycles it.
• Option --whitespace is accepted, but left undocumented.
• Syntax coloring now works correctly in more locales.
2025.04.02 - GNU nano 8.4 "Five Miles Out"
• Bracketed pastes over a slow connection are more reliable.
• Tabs in an external paste at a prompt are not dropped.
• Feedback occurs when the cursor sits on a Byte Order Mark.
• The Execute prompt is more forgiving of a typo.
2024.12.21 - GNU nano 8.3 "like mice in the dream of a tabby cat"
• A build failure with gcc-15 is fixed.
• Several translations were updated.
2024.09.05 - GNU nano 8.2 "Charlotte will climb walls!"
• At a Yes-No prompt, beside Y and the localized initial for "Yes",
also ^Y is accepted. Similarly, ^N for "No", and ^A for "All".
• A text-highlighting bug with Alt+Home/Alt+End is fixed.
2024.07.12 - GNU nano 8.1 "de dag van de bitterkoekjespudding"
• The idiom `nano filename:linenumber` is understood only when the
option --colonparsing (or 'set colonparsing') is used.
• Modern bindings are *not* activated when nano's invocation name
starts with "e", as it jars with Debian's alternatives system.
• New bindable function 'cycle' first centers the current row,
then moves it to the top of the viewport, then to the bottom.
It is bound by default to ^L.
• Option --listsyntaxes/-z lists the names of available syntaxes.
2024.05.01 - GNU nano 8.0 "Grus grus"
• By default ^F is bound to starting a forward search, and ^B to
starting a backward search, while M-F and M-B repeat the search
in the corresponding direction. (See the documentation if you
want the old bindings back.)
• Command-line option --modernbindings (-/) makes ^Q quit, ^X cut,
^C copy, ^V paste, ^Z undo, ^Y redo, ^O open a file, ^W write a
file, ^R replace, ^G find again, ^D find again backwards, ^A set
the mark, ^T jump to a line, ^P show the position, and ^E execute.
• Above modern bindings are activated also when the name of nano's
executable (or a symlink to it) starts with the letter "e".
• To open a file at a certain line number, one can now use also
`nano filename:number`, besides `nano +number filename`.
• <Alt+Home> and <Alt+End> put the cursor on the first and last
row in the viewport, while retaining the horizontal position.
• When the three digits in an #RGB color code are all the same,
the code is mapped to the xterm grey scale, giving access to
fourteen levels of grey instead of just four.
• For easier access, M-" is bound to placing/removing an anchor,
and M-' to jumping to the next anchor.
• Whenever an error occurs, the keystroke buffer is cleared, thus
stopping the execution of a macro or a string bind.
• The mousewheel scrolls the viewport instead of moving the cursor.
2023.01.18 - GNU nano 7.2 "Boer doe mij 't hekke lös!"
• <Shift+Insert> is prevented from pasting in view mode.
@@ -887,26 +993,23 @@
fixes for that version are still forthcoming.
2010.02.11 - GNU nano 2.2.3 "fumbling toward stability" is released.
This release contains a fix for only one bug, but a
rather irritating one: when paging up/down with smooth
scrolling, the cursor position was not being preserved
due to a bug in 2.2.2. With such a targeted fix
like this what could POSSIBLY go WRONG? Hahaha.
Enjoy and if you find new bugs, as always please
use Savannah's bug tracker.
This release contains a fix for only one bug, but a rather
irritating one: when paging up/down with smooth scrolling,
the cursor position was not being preserved due to a bug
in 2.2.2. With such a targeted fix like this what could
POSSIBLY go WRONG? Hahaha. Enjoy, and if you find new
bugs, as always please use Savannah's bug tracker:
https://savannah.gnu.org/bugs/?func=additem&group=nano
2010.01.17 - GNU nano 2.2.2 is released for you, you, you. This
release includes fixes for: crashes when writing
backup files in certain conditions, improper
screen centering when moving up/down in various
combination of smooth scrolling and soft wrapping modes,
a search crash on the armel arch, and issues with
lots of keybinding customizations causing crashing
particularly on FreeBSD. Also included are better
help menu entries for forward/back in the file browser,
some man page tweaks and one assert fix. As always,
share and enjoy!
2010.01.17 - GNU nano 2.2.2 is released for you, you, you. This release
includes fixes for: crashes when writing backup files in
certain conditions, improper screen centering when moving
up/down in various combinations of smooth scrolling and soft
wrapping modes, a search crash on the armel arch, and issues
with lots of keybinding customizations causing crashing
particularly on FreeBSD. Also included are better help menu
entries for forward/back in the file browser, some man page
tweaks and one assert fix. As always, share and enjoy!
2009.12.12 - GNU nano 2.2.1 "DLR strikes back" is open for business.
This release fixes many bugs, including: missing
@@ -1591,7 +1694,7 @@
allow multiple syntax highlighting types, and a new -Y,
--syntax flag to set a specific one if there's no
filename regex to match it against (i.e. w/mutt). The
^space and M-space keys will now show up in the help
^Space and M-Space keys will now show up in the help
menu, which itself has been tweaked a bit, and many more
configure options should now cooperate (like the odd
pairing of --enable-tiny and --enable-multibuffer). The

12
README
View File

@@ -15,7 +15,7 @@ Appearance
In rough ASCII graphics, this is what nano's screen looks like:
____________________________________________________________________
| GNU nano 7.2 filename Modified |
| GNU nano 9.2 filename Modified |
--------------------------------------------------------------------
| This is the text window, displaying the contents of a 'buffer', |
| the contents of the file you are editing. |
@@ -29,7 +29,7 @@ Appearance
| |
--------------------------------------------------------------------
| [ Some status message ] |
|^G Help ^O Write Out ^W Where Is ^K Cut ^T Execute |
|^G Help ^O Write Out ^F Where Is ^K Cut ^T Execute |
|^X Exit ^R Read File ^\ Replace ^U Paste ^J Justify |
--------------------------------------------------------------------
@@ -52,8 +52,8 @@ Origin
Nowadays, nano wants to be a generally useful editor with sensible
defaults (linewise scrolling, no automatic line breaking).
The nano editor is an official GNU package. For more information on
GNU and the Free Software Foundation, please see https://www.gnu.org/.
The nano editor is an official GNU package. For more information
on GNU and the Free Software Foundation, see https://www.gnu.org/.
License
@@ -81,7 +81,9 @@ How to compile and install nano
You will need the header files of ncurses installed for ./configure
to succeed -- get them from libncurses-dev (Debian) or ncurses-devel
(Fedora) or a similarly named package. Use --prefix with ./configure
to override the default installation directory of /usr/local.
to override the default installation directory of /usr/local. And
use --sysconfdir=/etc when you want your self-compiled nano to read
the /etc/nanorc file.
After installation you may want to copy the doc/sample.nanorc file
to your home directory, rename it to ".nanorc", and then edit it

View File

@@ -12,9 +12,9 @@ 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)
autopoint (version >= 0.20)
gcc (version >= 5.0)
gettext (version >= 0.18.3)
gettext (version >= 0.20)
git (version >= 2.7.4)
groff (version >= 1.12)
make (any version)
@@ -35,7 +35,7 @@ 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
$ git clone git://git.git.savannah.gnu.org/nano.git
Generate the configure script
@@ -57,6 +57,9 @@ directory:
$ ./configure [--add-options-here]
Use --sysconfdir=/etc when you want your self-compiled nano to read
/etc/nanorc instead of /usr/local/etc/nanorc.
Build and install
-----------------

3
THANKS
View File

@@ -5,6 +5,7 @@ If we missed you here, let us know!
Translations:
============
Pedro Albuquerque <palbuquerque73@gmail.com> Portuguese
Zayed Al-Saidi <zayed.alsaidi@gmail.com> Arabic
Josef Andersson <josef.andersson@fripost.org> Swedish
Mario Blättermann <mario.blaettermann@gmail.com> German
Besnik Bleta <besnik@programeshqip.org> Albanian
@@ -47,6 +48,7 @@ Jordi Mallach <jordi@gnu.org> Catalan
João Victor Duarte Martins <jvdm@sdf.lonestar.org> Brazilian Portuguese
Pavel Maryanov <acid@jack.kiev.ua> Russian
Daniele Medri <madrid@linux.it> Italian
Baurzhan Muftakhidinov <baurthefirst@gmail.com> Kazakh
Gergely Nagy <algernon@debian.org> Hungarian
Claudio Neves <cneves@nextis.com> Brazilian Portuguese
Kalle Olavi Niemitalo <kon@iki.fi> Finnish
@@ -79,6 +81,7 @@ Jacobo Tarrío <jtarrio@trasno.net> Galician
Andika Triwidada <andika@gmail.com> Indonesian
Francisco Javier Tsao Santín <tsao@members.fsf.org> Galician
Balázs Úr <urbalazs@gmail.com> Hungarian
Luca Vercelli <luca.vercelli.to@gmail.com> Italian
Miquel Vidal <miquel@sindominio.net> Catalan
Phan Vinh Thinh <teppi82@gmail.com> Vietnamese
Pauli Virtanen <pauli.virtanen@saunalahti.fi> Finnish

View File

@@ -2,9 +2,10 @@
# Generate configure & friends for GIT users.
gnulib_url="git://git.sv.gnu.org/gnulib.git"
gnulib_hash="2cf7f442f52f70b3df6eb396eb93ea08e54883c5"
gnulib_hash="833eea6be5607a85bc964bf728a7a82ca461b5b1"
modules="
canonicalize-lgpl
futimens
getdelim
getline
@@ -18,20 +19,20 @@ modules="
regex
sigaction
snprintf-posix
stdarg
stdarg-h
strcase
strcasestr-simple
strnlen
sys_wait
vsnprintf-posix
wchar
wchar-h
wctype-h
wcwidth
"
# Make sure the local gnulib git repo is up-to-date.
if [ ! -d "gnulib" ]; then
git clone --depth=1111 ${gnulib_url}
git clone --depth=2222 ${gnulib_url}
fi
cd gnulib >/dev/null || exit 1
curr_hash=$(git log -1 --format=%H)
@@ -42,20 +43,11 @@ if [ "${gnulib_hash}" != "${curr_hash}" ]; then
fi
cd .. >/dev/null || exit 1
echo "Autopoint..."
autopoint --force
rm -rf lib
echo "Gnulib-tool..."
./gnulib/gnulib-tool --import ${modules}
echo
echo "Aclocal..."
aclocal -I m4
echo "Autoconf..."
autoconf
echo "Autoheader..."
autoheader
echo "Automake..."
automake --add-missing
echo "Autoreconf..."
autoreconf --install --symlink --force
echo "Done."

View File

@@ -1,6 +1,6 @@
# Configuration for GNU nano - a small and user-friendly text editor
#
# Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
# Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc.
# Copyright (C) 2014, 2017 Mike Frysinger
#
# GNU nano is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
# 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], [7.2], [nano-devel@gnu.org], [nano])
AC_INIT([GNU nano], [9.2], [nano-devel@gnu.org], [nano])
AC_CONFIG_SRCDIR([src/nano.c])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.14])
@@ -48,7 +48,7 @@ PKG_PROG_PKG_CONFIG
dnl Internationalization macros.
AM_GNU_GETTEXT_VERSION([0.18.3])
AM_GNU_GETTEXT_VERSION([0.20])
AM_GNU_GETTEXT([external], [need-ngettext])
AM_CONDITIONAL(USE_NLS, test x$USE_NLS = xyes)
@@ -128,6 +128,20 @@ if test "x$enable_color" != xno; then
color_support=yes
fi
AC_ARG_ENABLE(folding,
AS_HELP_STRING([--disable-folding], [Disable line folding support]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_folding" = xyes; then
AC_MSG_ERROR([
*** --enable-folding cannot work with --enable-tiny])
else
enable_folding=no
fi
fi
if test "x$enable_folding" != xno; then
AC_DEFINE(ENABLE_FOLDING, 1, [Define this to have line folding support.])
fi
AC_ARG_ENABLE(comment,
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
if test "x$enable_tiny" = xyes; then

View File

@@ -12,8 +12,8 @@
<body>
<br>
<h1 align="center">Overview of nano's shortcuts &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h1>
<h3 align="center">The editor's keystrokes and their functions &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h3>
<h1 align="center">Overview of nano's shortcuts &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h1>
<h3 align="center">The editor's keystrokes and their functions &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h3>
<br>
<table align="center"><tbody>
@@ -33,7 +33,6 @@
<tr><td>Ctrl+K &nbsp;&nbsp;</td><td>Cut current line into cutbuffer</td></tr>
<tr><td>Alt+6</td><td>Copy current line into cutbuffer</td></tr>
<tr><td>Ctrl+U</td><td>Paste contents of cutbuffer</td></tr>
<tr><td>Alt+T</td><td>Cut until end of buffer</td></tr>
<tr><td>Ctrl+]</td><td>Complete current word</td></tr>
<tr><td>Alt+3</td><td>Comment/uncomment line/region</td></tr>
<tr><td>Alt+U</td><td>Undo last action</td></tr>
@@ -43,10 +42,10 @@
<b>Search and replace</b>
<table><tbody>
<tr><td>Ctrl+Q &nbsp;&nbsp;</td><td>Start backward search</td></tr>
<tr><td>Ctrl+W</td><td>Start forward search</td></tr>
<tr><td>Alt+Q</td><td>Find next occurrence backward</td></tr>
<tr><td>Alt+W</td><td>Find next occurrence forward</td></tr>
<tr><td>Ctrl+B &nbsp;&nbsp;</td><td>Start backward search</td></tr>
<tr><td>Ctrl+F</td><td>Start forward search</td></tr>
<tr><td>Alt+B</td><td>Find next occurrence backward</td></tr>
<tr><td>Alt+F</td><td>Find next occurrence forward</td></tr>
<tr><td>Alt+R</td><td>Start a replacing session</td></tr>
</tbody></table>
<br>
@@ -64,11 +63,16 @@
<b>Operations</b>
<table><tbody>
<tr><td>Ctrl+T &nbsp;&nbsp;</td><td>Execute some command</td></tr>
<tr><td>Ctrl+T Ctrl+S</td><td>Run a spell check</td></tr>
<tr><td>Ctrl+T Ctrl+Y</td><td>Run a syntax check</td></tr>
<tr><td>Ctrl+T Ctrl+O &nbsp;</td><td>Run a formatter</td></tr>
<tr><td>Tab</td><td>Indent marked region</td></tr>
<tr><td>Shift+Tab &nbsp;&nbsp;</td><td>Unindent marked region</td></tr>
<tr><td>Ctrl+J</td><td>Justify paragraph or region</td></tr>
<tr><td>Alt+J</td><td>Justify entire buffer</td></tr>
<tr><td>Alt+B</td><td>Run a syntax check</td></tr>
<tr><td>Alt+F</td><td>Run a formatter/fixer/arranger</td></tr>
<tr><td>Alt+:</td><td>Start/stop recording of macro</td></tr>
<tr><td>Alt+T</td><td>Cut until end of buffer</td></tr>
<tr><td>Alt+V</td><td>Enter next keystroke verbatim</td></tr>
<tr><td>Alt+:</td><td>Start/stop recording of macro &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td></tr>
<tr><td>Alt+;</td><td>Replay macro</td></tr>
</tbody></table>
<br>
@@ -77,8 +81,8 @@
<b>Moving around</b>
<table><tbody>
<tr><td>Ctrl+B &nbsp;&nbsp;</td><td>One character backward</td></tr>
<tr><td>Ctrl+F</td><td>One character forward</td></tr>
<tr><td><b>&larr;</b></td><td>One character backward</td></tr>
<tr><td><b>&rarr;</b></td><td>One character forward</td></tr>
<tr><td>Ctrl+<b>&larr;</b></td><td>One word backward</td></tr>
<tr><td>Ctrl+<b>&rarr;</b></td><td>One word forward</td></tr>
<tr><td>Ctrl+A</td><td>To start of line</td></tr>
@@ -87,6 +91,8 @@
<tr><td>Ctrl+N</td><td>One line down</td></tr>
<tr><td>Ctrl+<b>&uarr;</b></td><td>To previous block</td></tr>
<tr><td>Ctrl+<b>&darr;</b></td><td>To next block</td></tr>
<tr><td>Alt+Home &nbsp;</td><td>To first row in viewport</td></tr>
<tr><td>Alt+End</td><td>To last row in viewport</td></tr>
<tr><td>Ctrl+Y</td><td>One page up</td></tr>
<tr><td>Ctrl+V</td><td>One page down</td></tr>
<tr><td>Alt+\</td><td>To top of buffer</td></tr>
@@ -96,33 +102,35 @@
<b>Special movement</b>
<table><tbody>
<tr><td>Alt+G &nbsp;&nbsp;&nbsp;</td><td>Go to specified line</td></tr>
<tr><td>Alt+G &nbsp;&nbsp;&nbsp;&nbsp;</td><td>Go to a specified line</td></tr>
<tr><td>Alt+]</td><td>Go to complementary bracket</td></tr>
<tr><td>Alt+&lt;</td><td>Scroll viewport to the left</td></tr>
<tr><td>Alt+&gt;</td><td>Scroll viewport to the right</td></tr>
<tr><td>Alt+<b>&uarr;</b></td><td>Scroll viewport up</td></tr>
<tr><td>Alt+<b>&darr;</b></td><td>Scroll viewport down</td></tr>
<tr><td>Alt+&lt;</td><td>Switch to preceding buffer</td></tr>
<tr><td>Alt+&gt;</td><td>Switch to succeeding buffer</td></tr>
<tr><td>Ctrl+L</td><td>Center the current line</td></tr>
<tr><td>Alt+<b>&larr;</b></td><td>Switch to preceding buffer</td></tr>
<tr><td>Alt+<b>&rarr;</b></td><td>Switch to succeeding buffer</td></tr>
</tbody></table>
<br>
<b>Information</b>
<table><tbody>
<tr><td>Ctrl+C &nbsp;&nbsp;</td><td>Report cursor position</td></tr>
<tr><td>Alt+D</td><td>Report line/word/character count</td></tr>
<tr><td>Alt+D</td><td>Report line/word/character counts</td></tr>
<tr><td>Ctrl+G</td><td>Display help text</td></tr>
</tbody></table>
<br>
<b>Various</b>
<table><tbody>
<tr><td>Alt+A</td><td>Turn the mark on/off</td></tr>
<tr><td>Tab</td><td>Indent marked region</td></tr>
<tr><td>Shift+Tab &nbsp;&nbsp;</td><td>Unindent marked region</td></tr>
<tr><td>Alt+V</td><td>Enter next keystroke verbatim</td></tr>
<tr><td>Alt+A &nbsp;&nbsp;&nbsp;&nbsp;</td><td>Set or unset the mark</td></tr>
<tr><td>Alt+C</td><td>Turn constant position info on/off</td></tr>
<tr><td>Alt+N</td><td>Turn line numbers on/off</td></tr>
<tr><td>Alt+P</td><td>Turn visible whitespace on/off</td></tr>
<tr><td>Alt+X</td><td>Hide or unhide the help lines</td></tr>
<tr><td>Ctrl+L</td><td>Refresh the screen</td></tr>
<tr><td>Alt+S</td><td>Turn softwrapping on/off</td></tr>
<tr><td>Alt+X</td><td>Hide/unhide the help lines</td></tr>
<tr><td>Alt+Z</td><td>Hide/unhide the info bars</td></tr>
</tbody></table>
<br>

View File

@@ -45,13 +45,13 @@
<blockquote><p>
<a href="#4.1">4.1. Alt+Up does nothing on a Linux console. How can I make it scroll?</a><br>
<a href="#4.2">4.2. How can I make Ctrl+Shift+Left/Right select words on urxvt?</a><br>
<a href="#4.3">4.3. Ack! My numeric keypad's keys don't work properly when NumLock is off! What can I do?</a><br>
<a href="#4.4">4.4. With what keystroke can I paste text from the clipboard into nano?</a><br>
<a href="#4.3">4.3. How do I remove an unwanted Byte Order Mark?</a><br>
<a href="#4.4">4.4. Where did Ctrl+T in the Search menu go?</a><br>
<a href="#4.5">4.5. How do I select text for or paste text from the clipboard when nano's mouse support is turned on?</a><br>
<a href="#4.6">4.6. When I paste text into a document, each line gets indented further than the last. Why? And how can I stop this?</a><br>
<a href="#4.7">4.7. When I paste from Windows into a remote nano, nano rewraps the lines. What gives?</a><br>
<a href="#4.8">4.8. I've compiled nano with color support, but I don't see any color when I run it!</a><br>
<a href="#4.9">4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</a><br>
<a href="#4.9">4.9. How do I make nano my default editor (in Pine, mutt, git, ...)?</a><br>
</p></blockquote>
<h3><a href="#5">5. Internationalization</a></h3>
<blockquote><p>
@@ -76,10 +76,10 @@
</p></blockquote>
<hr width="100%">
<h1><a name="1"></a>1. General</h1>
<h3><a name="1.1"></a>1.1. What is GNU nano?</h3>
<h1 id="1">1. General</h1>
<h3 id="1.1">1.1. What is GNU nano?</h3>
<blockquote><p>GNU nano was designed to be a free replacement for the Pico text editor, part of the Pine email suite from <a href="http://www.washington.edu/pine/">The University of Washington</a>. It aimed to &quot;emulate Pico as closely as is reasonable and then include extra functionality&quot;.</p></blockquote>
<h3><a name="1.2"></a>1.2. What is the history behind nano?</h3>
<h3 id="1.2">1.2. What is the history behind nano?</h3>
<blockquote><p>Funny you should ask!</p>
<p><b>In the beginning...</b></p>
<p>For years Pine was THE program used to read email on a Unix system. The Pico text editor is the portion of the program one would use to compose his or her mail messages. Many beginners to Unix flocked to Pico and Pine because of their well organized, easy to use interfaces. With the proliferation of GNU/Linux in the mid to late 90's, many University students became intimately familiar with the strengths (and weaknesses) of Pine and Pico.</p>
@@ -89,30 +89,30 @@
<p>It was in late 1999 when Chris Allegretta (our hero) was yet again complaining to himself about the less-than-perfect license Pico was distributed under, the 1000 makefiles that came with it and how just a few small improvements could make it the Best Editor in the World (TM). Having been a convert from Slackware to Debian, he missed having a simple binary package that included Pine and Pico, and had grown tired of downloading them himself.</p>
<p>Finally something snapped inside and Chris coded and hacked like a madman for many hours straight one weekend to make a (barely usable) Pico clone, at the time called TIP (Tip Isn't Pico). The program could not be invoked without a filename, could not save files, had no help text display, spell checker, and so forth. But over time it improved, and with the help of a few great coders it matured to the (hopefully) stable state it is in today.</p>
<p>In February 2001, nano was declared an official GNU program by Richard Stallman. nano also reached its first production release on March 22, 2001.</p></blockquote>
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
<h3 id="1.3">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>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>
<h3 id="1.4">1.4. What is the current version of nano?</h3>
<blockquote><p>The current version of nano <i>should</i> be <b>9.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 id="1.5">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%">
<h1><a name="2"></a>2. Where to get GNU nano.</h1>
<h3><a name="2.1"></a>2.1. Web sites that carry nano.</h3>
<h1 id="2">2. Where to get GNU nano.</h1>
<h3 id="2.1">2.1. Web sites that carry nano.</h3>
<blockquote><p>The nano source tarballs can be downloaded from the following web sites:</p>
<ul>
<li><a href="https://nano-editor.org/dist/latest/">https://nano-editor.org/dist/latest/</a></li>
<li><a href="https://ftpmirror.gnu.org/gnu/nano/">https://ftpmirror.gnu.org/gnu/nano/</a></li>
</ul>
</blockquote>
<h3><a name="2.2"></a>2.2. RPM packages (RedHat, OpenSuse, and derivatives).</h3>
<h3 id="2.2">2.2. RPM packages (RedHat, OpenSuse, and derivatives).</h3>
<blockquote>
<ul>
<li><a href="https://kojipkgs.fedoraproject.org//packages/nano/">https://kojipkgs.fedoraproject.org//packages/nano/</a></li>
<li><a href="https://software.opensuse.org/package/nano">https://software.opensuse.org/package/nano</a></li>
</ul>
</blockquote>
<h3><a name="2.3"></a>2.3. Deb packages (Debian and derivatives):</h3>
<h3 id="2.3">2.3. Deb packages (Debian and derivatives):</h3>
<blockquote><p>Debian users can check out the current nano packages for:</p>
<ul>
<li><a href="https://packages.debian.org/stable/editors/nano">stable</a></li>
@@ -121,14 +121,14 @@
</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>
<h3 id="2.4">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>
<h3><a name="3.1"></a>3.1. How do I install the RPM or DEB package?</h3>
<h1 id="3">3. Installation and Configuration</h1>
<h3 id="3.1">3.1. How do I install the RPM or DEB package?</h3>
<blockquote><p>It's simple really! As root, type <b>rpm -Uvh nano-x.y-1*.rpm</b> if you have a RedHat-ish system or <b>dpkg -i nano_x.y-1*.deb</b> if you have a Debian-ish system, where <b>x.y</b> is the version number of nano. There are other programs to install packages, and if you wish to use those, knock yourself out.</p></blockquote>
<h3><a name="3.2"></a>3.2. Compiling from source: WHAT THE HECK DO I DO NOW?</h3>
<h3 id="3.2">3.2. Compiling from source: WHAT THE HECK DO I DO NOW?</h3>
<blockquote><p>Okay, take a deep breath, this really isn't hard. Unpack the nano source with a command like:</p>
<p class="indented"><b>tar -xvf nano-x.y.tar.gz</b></p>
<p>Then you need to run <b>configure</b> with any options you might want (if any).</p>
@@ -137,13 +137,13 @@
<b>./configure</b><br>
<b>make</b><br>
<b>make install</b>&nbsp;&nbsp; #(as root, of course)</p></blockquote>
<h3><a name="3.3"></a>3.3. Why does everything go into /usr/local?</h3>
<h3 id="3.3">3.3. Why does everything go into /usr/local?</h3>
<blockquote><p>Well, that's what the <b>configure</b> script defaults to. If you wish to change this, simply do this:</p>
<p class="indented"><b>./configure --prefix=/usr</b></p>
<p>This will put nano into /usr/bin when you run <b>make install</b>.</p></blockquote>
<h3><a name="3.4"></a>3.4. nano should automatically run strip on the binary when installing it!</h3>
<h3 id="3.4">3.4. nano should automatically run strip on the binary when installing it!</h3>
<blockquote><p>It does when you use <b>make install-strip</b>. The default <b>make install</b> does not, and will not, run strip automatically.</p></blockquote>
<h3><a name="3.5"></a>3.5. How can I make the executable smaller? This is too bloated!</h3>
<h3 id="3.5">3.5. How can I make the executable smaller? This is too bloated!</h3>
<blockquote><p>Actually, there are several parts of the editor that can be disabled. You can pass arguments to the <b>configure</b> script that disable certain features. Here's a brief list:</p>
<pre>
<b>--disable-browser</b> Disable the built-in file browser
@@ -167,20 +167,22 @@
<b>--disable-wrapping</b> Disable all hard-wrapping of text</pre>
<p>There's also the <b>--enable-tiny</b> option which disables everything above, as well as some larger chunks of the program (like the undo/redo code and the code for selecting text). Also, if you know you don't need other languages, you can use <b>--disable-nls</b> to disable internationalization and save a few kilobytes. And finally, there's always good old <b>strip</b> to remove all unneeded symbols.</p>
</blockquote>
<h3><a name="3.6"></a>3.6. Tell me more about this multibuffer stuff!</h3>
<blockquote><p>To use multiple file buffers, you must not have configured nano with <b>--disable-multibuffer</b> nor with <b>--enable-tiny</b> (use <b>nano -V</b> to check the compilation options). Then when you want to insert a file into its own buffer instead of into the current file, just hit <b>Meta-F</b> after typing <b>^R</b>. If you always want files to be loaded into their own buffers, use the <b>-F</b> or <b>--multibuffer</b> flag when you invoke nano, or add <b>set multibuffer</b> to your .nanorc file.</p>
<p>You can move between the buffers you have open with the <b>Meta-&lt;</b> and <b>Meta-&gt;</b> keys, or more easily without holding Shift: <b>Meta-,</b> and <b>Meta-.</b> (clear as mud, right? =-). When you have more than one buffer open, the ^X shortcut will say &quot;Close&quot;, instead of &quot;Exit&quot;.</p></blockquote>
<h3><a name="3.7"></a>3.7. Tell me more about this verbatim input stuff!</h3>
<h3 id="3.6">3.6. Tell me more about this multibuffer stuff!</h3>
<blockquote><p>To use multiple file buffers, you must not have configured nano with <b>--disable-multibuffer</b> nor with <b>--enable-tiny</b> (use <b>nano -V</b> to check the compilation options). Then when you want to insert a file into its own buffer instead of into the current file, just hit <b>Meta-F</b> after typing <b>^R</b>.</p>
<p>If you want files to be loaded always into their own buffers, use the <b>-F</b> or <b>--multibuffer</b> flag when you invoke nano, or add <b>set multibuffer</b> to your .nanorc file. (Since nano-9.2 these options are named <b>--newbuffer</b> and <b>set newbuffer</b>.)</p>
<p>You can switch between open buffers with <b>Meta-,</b> and <b>Meta-.</b> (Alt+comma and Alt+period).</p>
<p>When you have more than one buffer open, the help lines will say &quot;<i>Close</i>&quot; instead of &quot;<i>Exit</i>&quot; for the <b>^X</b> shortcut.</p></blockquote>
<h3 id="3.7">3.7. Tell me more about this verbatim input stuff!</h3>
<blockquote><p>When you want to insert a literal character into the file you're editing, such as a control character that nano usually treats as a command, first press <b>Meta-V</b> (if you're not at a prompt, you'll get the message &quot;Verbatim Input&quot; on the status bar), then press the key(s) that generate the character you want.</p>
<p>Alternatively, if Unicode support is enabled (see section <a href="#5.3">5.3</a>), you can press <b>Meta-V</b> and then type a six-digit hexadecimal code (from 000000 to 10FFFF, case-insensitive), and the character with the corresponding value will be inserted. The status bar will change to &quot;Unicode Input: ......&quot; when you do this.</p></blockquote>
<h3><a name="3.8"></a>3.8. How do I make a .nanorc file that will be read when I start nano?</h3>
<h3 id="3.8">3.8. How do I make a .nanorc file that will be read when I start nano?</h3>
<blockquote><p>It's not hard at all! Simply copy the <b>sample.nanorc</b> from the doc/ directory in the nano source package (or from /usr/doc/nano on your system) to <b>.nanorc</b> in your home directory, and then edit it. If you didn't get a sample nanorc, the syntax of the file is simple: features are turned on and off by using the words <b>set</b> and <b>unset</b> followed by the long option name of the feature (see <b>man nanorc</b> for the full list of options). For example, &quot;set quickblank&quot; or &quot;set smarthome&quot;. Of course, for this to work, your nano must <b>not</b> have been compiled with <b>--disable-nanorc</b>.</p></blockquote>
<h3><a name="3.9"></a>3.9. Why does my self-compiled nano not read /etc/nanorc?</h3>
<blockquote><p>By default (see <a href="#3.3">3.3</a>), nano gets installed into /usr/local. This also means that, at startup, nano will read <b>/usr/local/etc/nanorc</b> instead of <b>/etc/nanorc</b>. You can make a symlink from the former to the latter if you want your self-compiled nano to read the same nanorc as the system-installed nano. Or you can configure your nano to overwrite the system nano (again, see <a href="#3.3">3.3</a>).</p></blockquote>
<h3 id="3.9">3.9. Why does my self-compiled nano not read /etc/nanorc?</h3>
<blockquote><p>By default (see <a href="#3.3">3.3</a>), nano gets installed into /usr/local. This also means that, at startup, nano reads <b>/usr/local/etc/nanorc</b> instead of <b>/etc/nanorc</b>. You can make a symlink from the former to the latter if you want your self-compiled nano to read the same nanorc as the system-installed nano. Or you can simply configure your nano with <b>--sysconfdir=/etc</b>.</p></blockquote>
<hr width="100%">
<h1><a name="4"></a>4. Running</h1>
<h3><a name="4.1"></a>4.1. Alt+Up does nothing on a Linux console. How can I make it scroll?</h3>
<h1 id="4">4. Running</h1>
<h3 id="4.1">4.1. Alt+Up does nothing on a Linux console. How can I make it scroll?</h3>
<blockquote><p>On Debian and its derivatives, the <b>Alt+Up</b> keystroke on a Linux console
produces by default a 'KeyboardSignal', which normally does absolutely nothing and is useless
for the average user. To get the keystroke to do what it ought to do (scroll the viewport
@@ -193,7 +195,7 @@
&nbsp;&nbsp;&nbsp;&nbsp;sed -i 's/KeyboardSignal/Up/' ${file%.gz};<br>
&nbsp;&nbsp;&nbsp;&nbsp;gzip ${file%.gz};<br>
done</b></p></blockquote>
<h3><a name="4.2"></a>4.2. How can I make Ctrl+Shift+Left/Right select words on urxvt?</h3>
<h3 id="4.2">4.2. How can I make Ctrl+Shift+Left/Right select words on urxvt?</h3>
<blockquote><p>The urxvt terminal emulator produces non-standard escape sequences for the modified cursor keys. These deviant sequences are not listed in the terminfo database, which means that ncurses does not recognize them. The easiest way around this is to tell urxvt to produce xterm-compatible escape sequences for the relevant keystrokes. To achieve this, add the following lines to your ~/.Xresources file:</p>
<pre>
URxvt.iso14755_52: False
@@ -208,31 +210,39 @@
URxvt.keysym.M-Right: \033[1;3C
URxvt.keysym.M-Left: \033[1;3D
URxvt.keysym.M-Home: \033[1;3H
URxvt.keysym.M-End: \033[1;3F
URxvt.keysym.M-Insert: \033[2;3~
URxvt.keysym.M-Delete: \033[3;3~
URxvt.keysym.M-Page_Up: \033[5;3~
URxvt.keysym.M-Page_Down: \033[6;3~</pre>
URxvt.keysym.M-Page_Down: \033[6;3~
URxvt.keysym.S-Page_Up: \033[5;2~
URxvt.keysym.S-Page_Down: \033[6;2~</pre>
<p>Then run <b>xrdb ~/.Xresources</b> and restart your urxvt terminal. Now <b>Ctrl+Shift+Left</b> and <b>Ctrl+Shift+Right</b> will select words, <b>Alt+Up</b> and <b>Alt+Down</b> will scroll the text without moving the cursor, and several such things more.</p></blockquote>
<h3><a name="4.3"></a>4.3. Ack! My numeric keypad's keys don't work properly when NumLock is off! What can I do?</h3>
<blockquote><p>You can use the <b>-K</b> or <b>--rawsequences</b> option on the command line, or add the line <b>set rawsequences</b> to your .nanorc. However, nano's mouse support will be disabled if you do any of these things.</p></blockquote>
<h3><a name="4.4"></a>4.4. With what keystroke can I paste text from the clipboard into nano?</h3>
<blockquote><p>In most desktop environments <b>Shift+Insert</b> will paste the contents of the clipboard.</p></blockquote>
<h3><a name="4.5"></a>4.5. How do I select text for or paste text from the clipboard when nano's mouse support is turned on?</h3>
<h3 id="4.3">4.3. How do I remove an unwanted Byte Order Mark?</h3>
<blockquote><p>To check whether a file contains a Byte Order Mark (BOM), open the file and type <b>Ctrl+Home</b>. If there is a BOM, the status bar will tell you so. Now type <b>Delete</b> to remove the BOM, and <b>^S</b> to save the file.</p>
<p>If you've accidentally deleted a Byte Order Mark from a file that needs it, and you want to restore it, then type: <b>Ctrl+Home Alt+V feff Enter</b>. Verify that the BOM is back with <b>Ctrl+Home</b>, and save the file with <b>^S</b>. (Note that on Unix, files should not contain a BOM.)</p></blockquote>
<h3 id="4.4">4.4. Where did Ctrl+T in the Search menu go?</h3>
<blockquote><p>Actually, the <b>Ctrl+T</b> toggle is still there &mdash; it's just not listed in the help lines nor in the help text, and the function it executes cannot be rebound to another key. If you do want to use another key, you can emulate the rebinding with something like this in your .nanorc:</p>
<pre>
bind ^E "{cancel}{gotoline}" search
bind ^E "{cancel}{whereis}" gotoline</pre>
<p>But since forever there are also direct keystrokes for jumping to a line number: <b>Ctrl+/</b> and <b>Alt+G</b> in the main menu.</p></blockquote>
<h3 id="4.5">4.5. How do I select text for or paste text from the clipboard when nano's mouse support is turned on?</h3>
<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>
<h3 id="4.6">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 (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>
<p><i>Update:</i> Since version 4.8, nano suppresses 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 id="4.7">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 (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>
<p><i>Update:</i> Since version 4.8, nano ignores 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 id="4.8">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>
<h3 id="4.9">4.9. How do I make nano my default editor (in Pine, mutt, git, ...)?</h3>
<blockquote><p>You need to make nano your $EDITOR. If you want this to be saved, you should put a line like this in your <b>.bashrc</b> if you use bash (or <b>.zshrc</b> if you believe in zsh):</p>
<p class="indented"><b>export EDITOR=/usr/local/bin/nano</b></p>
<p>or, if you use tcsh, put this in your <b>.cshrc</b> file:</p>
<p class="indented"><b>setenv EDITOR /usr/local/bin/nano</b></p>
<p>Change /usr/local/bin/nano to wherever nano is installed on your system. Type &quot;which nano&quot; to find out. This will not take effect until the next time you log in. So log out and back in again.</p>
<p>Then, on top of that, if you use Pine, you must go into setup (type <b>S</b> at the main menu), and then configure (type <b>C</b>). Hit Enter on the lines that say:</p>
<p class="indented"><b>[ ] enable-alternate-editor-cmd</b><br>
@@ -240,47 +250,50 @@
<p>Then exit (<b>E</b>) and select Yes (<b>Y</b>).</p>
<p>If you're a mutt user, you should see an effect immediately the next time you log in. No further configuration is needed. However, if you want to let people know you use nano to compose your email messages, you can put a line like this in your <b>.muttrc</b>:</p>
<p class="indented"><b>my_hdr X-Composer: nano-x.y</b></p>
<p>Again, replace x.y with the version of nano you use.</p></blockquote>
<p>Again, replace x.y with the version of nano you use.</p>
<p>To use nano to edit your git commit messages, you can run:</p>
<p class="indented"><b>git config --global core.editor "nano --guide=74 --nohelp +1"</b></p>
<p>Note the <b>+1</b> at the end — it makes nano start always at the top of the edit window. The guidestripe helps you keep the text within a reasonable width.</blockquote>
<hr width="100%">
<h1><a name="5"></a>5. Internationalization</h1>
<h3><a name="5.1"></a>5.1. There's no translation for my language!</h3>
<h1 id="5">5. Internationalization</h1>
<h3 id="5.1">5.1. There's no translation for my language!</h3>
<blockquote><p>In June 2001, GNU nano entered the <a href="https://translationproject.org/html/welcome.html">Translation Project</a> and since then, translations should be managed from there.</p>
<p>If there isn't a translation for your language, you could ask <a href="https://translationproject.org/team/">your language team</a> to translate nano, or better still, join that team and do it yourself. Joining a team is easy. You just need to ask the team leader to add you, and then send a <a href="https://translationproject.org/disclaim.txt">translation disclaimer to the FSF</a> (this is necessary as nano is an official GNU package, but it does <b>not</b> mean that you transfer the rights of your work to the FSF, it's just so the FSF can legally manage them).</p>
<p>In any case, translating nano is easy. Just grab the latest <b>nano.pot</b> file listed on <a href="https://translationproject.org/domain/nano.html">nano's page</a> at the TP, and translate each <b>msgid</b> line into your native language on the <b>msgstr</b> line. When you're done, you should send it to the TP's central PO-file repository.</p></blockquote>
<h3><a name="5.2"></a>5.2. I don't like the translation for &lt;x&gt; in my language. How can I fix it?</h3>
<h3 id="5.2">5.2. I don't like the translation for &lt;x&gt; in my language. How can I fix it?</h3>
<blockquote><p>The best way is to send an e-mail with your suggested corrections to the team's mailing list. The address is mentioned in the <code>Language-Team:</code> field in the relevant PO file. The team leader or the assigned translator can then make the changes reach the nano-devel list.</p></blockquote>
<h3><a name="5.3"></a>5.3. What is the status of Unicode support?</h3>
<h3 id="5.3">5.3. What is the status of Unicode support?</h3>
<blockquote><p>Unicode should be fully usable nowadays. When the encoding of your terminal is set to UTF-8, and your locale (mainly the LANG environment variable) is UTF-8 too, then you should be able to read, enter and save Unicode text.</p></blockquote>
<hr width="100%">
<h1><a name="6"></a>6. Advocacy and Licensing</h1>
<h3><a name="6.1"></a>6.1. Why should I use nano instead of Pico?</h3>
<h1 id="6">6. Advocacy and Licensing</h1>
<h3 id="6.1">6.1. Why should I use nano instead of Pico?</h3>
<blockquote><p>If you want features like undo/redo, syntax highlighting, line numbers, soft-wrapping, opening multiple files at once, an interface localized to your language, or search and replace with support for regular expressions, then you want nano.</p></blockquote>
<h3><a name="6.2"></a>6.2. Why should I use Pico instead of nano?</h3>
<h3 id="6.2">6.2. Why should I use Pico instead of nano?</h3>
<blockquote><p>If you use your editor only to write emails or other texts and have no need for the above-mentioned features, then Pico will do fine for you.</p></blockquote>
<h3><a name="6.3"></a>6.3. What is so bad about the older Pine license?</h3>
<h3 id="6.3">6.3. What is so bad about the older Pine license?</h3>
<blockquote><p>The U of W license for older versions of Pine and Pico is not considered truly Free Software according to both the Free Software Foundation and the <a href="https://www.debian.org/social_contract#guidelines">Debian Free Software Guidelines</a>. The main problem regards the limitations on distributing derived works: according to UW, you can distribute their software, and you can modify it, but you can not do both, i.e. distribute modified binaries.</p></blockquote>
<h3><a name="6.4"></a>6.4. Okay, well, what mail program should I use then?</h3>
<h3 id="6.4">6.4. Okay, well, what mail program should I use then?</h3>
<blockquote><p>If you are looking to use a Free Software program similar to Pine, and Emacs is not your thing, you should definitely take a look at <a href="http://www.mutt.org/">mutt</a>. It is a full-screen, console based mail program that actually has a lot more flexibility than Pine, but has a keymap included in the distribution that allows you to use the same keystrokes as Pine would to send and receive mail. It's also under the GNU General Public License, version 2.0.</p>
<p>Of course, due to the license change you can now use the <a href="http://www.washington.edu/alpine/">Alpine distribution</a> of PINE as it is now considered Free Software, but you would be sacrificing many of nano's features to do so.</p></blockquote>
<hr width="100%">
<h1><a name="7"></a>7. Miscellaneous</h1>
<h3><a name="7.1"></a>7.1. Where can I ask questions or send suggestions?</h3>
<h1 id="7">7. Miscellaneous</h1>
<h3 id="7.1">7.1. Where can I ask questions or send suggestions?</h3>
<blockquote><p>There are three mailing lists for nano hosted at <a href="https://savannah.gnu.org/">Savannah</a>: info-nano, help-nano and nano-devel. info-nano is a very low traffic list where new versions of nano are announced (surprise!). help-nano is for getting help with the editor without needing to hear all of the development issues surrounding it. nano-devel is a normally low, sometimes high traffic list for discussing the present and future development of nano. Here are links to where you can sign up for a given list:</p>
<p>info-nano - <a href="https://lists.gnu.org/mailman/listinfo/info-nano/">https://lists.gnu.org/mailman/listinfo/info-nano/</a><br>
help-nano - <a href="https://lists.gnu.org/mailman/listinfo/help-nano/">https://lists.gnu.org/mailman/listinfo/help-nano/</a><br>
nano-devel - <a href="https://lists.gnu.org/mailman/listinfo/nano-devel/">https://lists.gnu.org/mailman/listinfo/nano-devel/</a></p></blockquote>
<h3><a name="7.2"></a>7.3. How do I submit a bug report or patch?</h3>
<h3 id="7.2">7.3. How do I submit a bug report or patch?</h3>
<blockquote>
<p>The best way to submit bugs is through the <a href="https://savannah.gnu.org/bugs/?group=nano">Savannah bug tracker</a>, as you can check whether the bug you are reporting has already been submitted, and it makes it easier for the maintainers to keep track of them.
<p>You can submit patches for nano via <a href="https://savannah.gnu.org/patch/?group=nano">Savannah's patch manager</a>.</p></blockquote>
<h3><a name="7.3"></a>7.3. I want to send the development team a big load of cash (or just a thank you).</h3>
<h3 id="7.3">7.3. I want to send the development team a big load of cash (or just a thank you).</h3>
<blockquote><p>That's fine. Send it <a href="mailto:nano-devel@gnu.org">our way</a>! Better yet, fix a <a href="https://savannah.gnu.org/bugs/?group=nano">bug</a> in the program or implement a <a href="https://nano-editor.org/dist/latest/TODO">cool feature</a> and send us that instead (though cash is fine too).</p></blockquote>
<h3><a name="7.4"></a>7.4. How do I join the development team?</h3>
<h3 id="7.4">7.4. How do I join the development team?</h3>
<blockquote><p>The easiest way is to consistently send in good patches that add some needed functionality, fix a bug or two, and/or make the program more optimized/efficient. Then ask nicely and you will probably be added to the Savannah development list and be given write access after a while. There is a lot of responsibility that goes along with being a team member, so don't think it's just something to add to your resume.</p></blockquote>
<h3><a name="7.5"></a>7.5. Can I have write access to the git tree?</h3>
<h3 id="7.5">7.5. Can I have write access to the git tree?</h3>
<blockquote><p>Re-read section <a href="#7.4">7.4</a> and you should know the answer.</p></blockquote>
<hr width="100%">

View File

@@ -1,4 +1,4 @@
.\" Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
.\" Copyright (C) 1999-2011, 2013-2026 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 NANO 1 "version 7.2" "January 2023"
.TH NANO 1 "July 2026" "GNU nano 9.2"
.SH NAME
nano \- Nano's ANOther text editor, inspired by Pico
@@ -25,14 +25,11 @@ nano \- Nano's ANOther text editor, inspired by Pico
.B nano
.RI [ options "] [[\fB+" line [\fB, column "]] " file ]...
.sp
.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 text editor. It copies the look and feel
of Pico, but is free software, and implements several features that Pico
\fBnano\fR is a small and friendly text editor. It copies the look and feel
of Pico, but is free software, and implements a few features that Pico
lacks, such as: opening multiple files, scrolling per line, undo/redo,
syntax coloring, line numbering, and soft-wrapping overlong lines.
.sp
@@ -40,9 +37,6 @@ 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.
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.
@@ -60,26 +54,61 @@ the first occurrence of the word "Foo", you would do:
As a special case: if instead of a filename a dash (\fB\-\fR) is given,
\fBnano\fR will read data from standard input.
.SH NOTICES
Since version 9.0, all lines are scrolled horizontally together
(when the cursor approaches the edge), by just the amount needed,
instead of scrolling only the current line by a large step.
If you prefer the old behavior, you can use \fB\-\-\%solo\fR on the
command line or \fBset \%solosidescroll\fR in your \fInanorc\fR.
.sp
Also since version 9.0, keystrokes \fBM\-<\fR and \fBM\->\fR have
been reassigned to the \fB\%scrollleft\fR and \fB\%scrollright\fR functions.
If you want those keystrokes to do what they did before version 9.0,
add these two lines at the end of your \fInanorc\fR file:
.sp
.RS 4
.B bind M\-< prevbuf main
.br
.B bind M\-> nextbuf main
.RE
.sp
Since version 8.0, to be newcomer friendly, \fB^F\fR starts a forward search,
\fB^B\fR starts a backward search, \fBM\-F\fR searches the next occurrence
forward, and \fBM\-B\fR searches the next occurrence backward. If you want
those keystrokes to do what they did before version 8.0, add the following
four lines at the end of your \fInanorc\fR file:
.sp
.RS 4
.B bind ^F forward main
.br
.B bind ^B back main
.br
.B bind M\-F formatter main
.br
.B bind M\-B linter main
.RE
.sp
.SH EDITING
Entering text and moving around in a file is straightforward: typing the
Entering text and moving around in a file are straightforward: typing the
letters and using the normal cursor movement keys. Commands are entered
by using the Control (^) and the Alt or Meta (M\-) keys.
Typing \fB^K\fR deletes the current line and puts it in the cutbuffer.
Consecutive \fB^K\fRs will put all deleted lines together in the cutbuffer.
Any cursor movement or executing any other command will cause the next
\fB^K\fR to overwrite the cutbuffer. A \fB^U\fR will paste the current
Consecutive \fB^K\fRs put all deleted lines together in the cutbuffer.
Any cursor movement or executing any other command causes the next
\fB^K\fR to overwrite the cutbuffer. A \fB^U\fR pastes the current
contents of the cutbuffer at the current cursor position.
.sp
When a more precise piece of text needs to be cut or copied, you can mark
its start with \fB^6\fR, move the cursor to its end (the marked text will be
highlighted), and then use \fB^K\fR to cut it, or \fBM\-6\fR to copy it to the
cutbuffer. You can also save the marked text to a file with \fB^O\fR, or
spell check it with \fB^T^T\fR.
its start with \fB^6\fR, move the cursor to its end (the marked text is
highlighted), and then use \fB^K\fR to cut it, or \fBM\-6\fR to copy it to
the cutbuffer. You can also save the marked text to a file with \fB^O\fR,
or spell check it with \fB^T^T\fR.
.sp
On some terminals, text can be selected also by holding down Shift while
using the arrow keys. Holding down the Ctrl or Alt key too will increase
using the arrow keys. Holding down the Ctrl or Alt key too increases
the stride.
Any cursor movement without Shift being held will cancel such a selection.
Any cursor movement without Shift being held cancels 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
@@ -89,40 +118,43 @@ A literal control code (except \fB^J\fR) can be inserted by typing
.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
The default key bindings can be changed via a \fInanorc\fR file \[em] see
.BR nanorc (5).
.sp
With \fB^S^X\fR you can save the buffer and exit from \fBnano\fR.
.SH OPTIONS
.TP
.BR \-A ", " \-\-smarthome
Make the Home key smarter. When Home is pressed anywhere but at the
very beginning of non-whitespace characters on a line, the cursor will
jump to that beginning (either forwards or backwards). If the cursor is
already at that position, it will jump to the true beginning of the
line.
very beginning of non-whitespace characters on a line, the cursor jumps
to that beginning (either forwards or backwards). If the cursor is
already at that position, it jumps to the true beginning of the line.
.TP
.BR \-B ", " \-\-backup
When saving a file, back up the previous version of it, using the current
filename suffixed with a tilde (\fB~\fP).
filename suffixed with a tilde (\fB\[ti]\fR).
.TP
.BR \-C\ \fIdirectory ", " \-\-backupdir= \fIdirectory
Make and keep not just one backup file, but make and keep a uniquely
numbered one every time a file is saved -- when backups are enabled (\fB\-B\fR).
The uniquely numbered files are stored in the specified \fIdirectory\fR.
.BI \-C " directory\fR, " \-\-backupdir= directory
Make and keep not just one backup file, but make and keep a uniquely numbered
one every time a file is saved \[em] when backups are enabled (\fB\-B\fR).
The uniquely numbered files are stored in the specified \fI\%directory\fR.
.TP
.BR \-D ", " \-\-boldtext
For the interface, use bold instead of reverse video. This will be overridden
by setting the options \fBtitlecolor\fP, \fBstatuscolor\fP, \fBkeycolor\fP,
\fBfunctioncolor\fP, \fBnumbercolor\fP, and/or \fBselectedcolor\fP in your
nanorc file. See \fBnanorc\fR(5).
For the interface, use bold instead of reverse video.
This can be overridden for specific elements by setting the options
\fB\%titlecolor\fR, \fB\%statuscolor\fR, \fB\%promptcolor\fR,
\fB\%minicolor\fR, \fB\%keycolor\fR, \fB\%numbercolor\fR, and/or
\fB\%selectedcolor\fR in your \fInanorc\fR file. See \fBnanorc\fR(5).
.TP
.BR \-E ", " \-\-tabstospaces
Convert each typed tab to spaces -- to the number of spaces
Convert each typed tab to spaces \[em] to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
.TP
.BR \-F ", " \-\-multibuffer
.BR \-F ", " \-\-newbuffer
Read a file into a new buffer by default.
(The old form of this option, \fB\-\-\%multibuffer\fR, is deprecated.)
.TP
.BR \-G ", " \-\-locking
Use vim-style file locking when editing files.
@@ -134,17 +166,17 @@ executed commands, so they can be easily reused in later sessions.
.BR \-I ", " \-\-ignorercfiles
Don't look at the system's \fInanorc\fR nor at the user's \fInanorc\fR.
.TP
.BR \-J\ \fInumber ", " \-\-guidestripe= \fInumber
.BI \-J " number\fR, " \-\-guidestripe= number
Draw a vertical stripe at the given column, to help judge the width of the
text. (The color of the stripe can be changed with \fBset stripecolor\fR
text. (The color of the stripe can be changed with \fBset \%stripecolor\fR
in your \fInanorc\fR file.)
.TP
.BR \-K ", " \-\-rawsequences
Interpret escape sequences directly, instead of asking \fBncurses\fR
Interpret escape sequences directly, instead of asking \fI\%ncurses\fR
to translate them. (If you need this option to get some keys to work
properly, it means that the terminfo terminal description that is used
does not fully match the actual behavior of your terminal. This can
happen when you ssh into a BSD machine, for example.)
properly, it means that the \fI\%terminfo\fR terminal description that
is used does not fully match the actual behavior of your terminal.
This can happen when you ssh into a BSD machine, for example.)
Using this option disables \fBnano\fR's mouse support.
.TP
.BR \-L ", " \-\-nonewlines
@@ -156,7 +188,7 @@ Snip trailing whitespace from the wrapped line when automatic
hard-wrapping occurs or when text is justified.
.TP
.BR \-N ", " \-\-noconvert
Disable automatic conversion of files from DOS/Mac format.
Disable automatic conversion of files from DOS format.
.TP
.BR \-O ", " \-\-bookstyle
When justifying, treat any line that starts with whitespace as the
@@ -165,38 +197,49 @@ beginning of a paragraph (unless auto-indenting is on).
.BR \-P ", " \-\-positionlog
For the 200 most recent files, log the last position of the cursor,
and place it at that position again upon reopening such a file.
Also save and restore the positions of any anchors.
.TP
.BR "\-Q ""\fIregex\fB""" ", " "\-\-quotestr=""" \fIregex """
.BI "\-Q """ regex\fB"\fR, " \-\-quotestr=""" regex """"
Set the regular expression for matching the quoting part of a line.
The default value is "\fB^([\ \\t]*([!#%:;>|}]|//))+\fR".
(Note that \fB\\t\fP stands for an actual Tab.)
(Note that \fB\\t\fR stands for an actual Tab.)
This makes it possible to rejustify blocks of quoted text when composing
email, and to rewrap blocks of line comments when writing source code.
.TP
.BR \-R ", " \-\-restricted
Restricted mode: don't read or write to any file not specified on the
command line. This means: don't read or write history files;
don't allow suspending; don't allow spell checking;
don't allow a file to be appended to, prepended to, or saved under a
different name if it already has one; and don't make backup files.
Restricted mode can also be activated by invoking \fBnano\fP
with any name beginning with 'r' (e.g. "rnano").
Read and write only the \fIfile\fR (or files) specified on the command line.
This means: don't read or write the history files; don't allow suspending;
don't allow spell checking; don't allow executing any command in the shell;
don't allow the current buffer to be saved under a different name; don't
allow appending or prepending to any file; and don't make backup files.
.sp
As an exception, before the specified file or files, the \fInanorc\fR files
are read, to allow customization. If customization should not be allowed,
use option \fB\-I\fR (\fB\-\-\%ignorercfiles\fR) as well.
.sp
When no \fIfile\fR is specified on the command line, restricted mode
allows you to save the contents that you type into the new buffer
under any name, except that existing files may not be overwritten.
If the places where this new file may be created should be limited,
then use option \fB\-o\fR (\fB\-\-\%operatingdir\fR) as well.
.sp
Restricted mode can also be activated by invoking \fBnano\fR
with a name beginning with 'r' (for example: \fBrnano\fR).
.TP
.BR \-S ", " \-\-softwrap
Display over multiple screen rows lines that exceed the screen's width.
(You can make this soft-wrapping occur at whitespace instead of rudely at
the screen's edge, by using also \fB\-\-atblanks\fR.)
(The old short option, \fB\-$\fR, is deprecated.)
the screen's edge, by using also \fB\-\-\%atblanks\fR.)
.TP
.BR \-T\ \fInumber ", " \-\-tabsize= \fInumber
Set the size (width) of a tab to \fInumber\fP columns. The value of
\fInumber\fR must be greater than 0. The default value is \fB8\fR.
.BI \-T " number\fR, " \-\-tabsize= number
Set the size (width) of a tab to \fI\%number\fR columns. The value of
\fI\%number\fR must be greater than 0. The default value is \fB8\fR.
.TP
.BR \-U ", " \-\-quickblank
Make status-bar messages disappear after 1 keystroke instead of after 20.
Note that option \fB\-c\fR (\fB\-\-constantshow\fR) overrides this.
When option \fB\-\-minibar\fR or \fB\-\-zero\fR is in effect,
\fB\-\-quickblank\fR makes a message disappear after
Note that option \fB\-c\fR (\fB\-\-\%constantshow\fR) overrides this.
When option \fB\-\-\%minibar\fR or \fB\-\-\%zero\fR is in effect,
\fB\-\-\%quickblank\fR makes a message disappear after
0.8 seconds instead of after the default 1.5 seconds.
.
.TP
@@ -207,14 +250,14 @@ Show the current version number and exit.
Detect word boundaries differently by treating punctuation
characters as part of a word.
.TP
.BR "\-X ""\fIcharacters\fB""" ", " "\-\-wordchars=""" \fIcharacters """
.BI "\-X """ characters\fB"\fR, " \-\-wordchars=""" characters """"
Specify which other characters (besides the normal alphanumeric ones)
should be considered as part of a word. When using this option, you
probably want to omit \fB\-W\fR (\fB\-\-wordbounds\fR).
probably want to omit \fB\-W\fR (\fB\-\-\%wordbounds\fR).
.TP
.BR \-Y\ \fIname ", " \-\-syntax= \fIname
.BI \-Y " name\fR, " \-\-syntax= name
Specify the name of the syntax highlighting to use from among the ones
defined in the \fInanorc\fP files.
defined in the \fInanorc\fR files.
.TP
.BR \-Z ", " \-\-zap
Let an unmodified Backspace or Delete erase the marked region
@@ -225,13 +268,16 @@ When doing soft line wrapping, wrap lines at whitespace
instead of always at the edge of the screen.
.TP
.BR \-b ", " \-\-breaklonglines
Automatically hard-wrap the current line when it becomes overlong.
(This option is the opposite of \fB\-w\fR (\fB\-\-nowrap\fR) --
Automatically hard-wrap the current line when it becomes overlong,
that is: when it becomes wider than the value given with \fB\-r\fR
(\fB\-\-fill\fR). The default value for \fB\-r\fR is the terminal's
width minus eight.
(This option is the opposite of \fB\-w\fR (\fB\-\-\%nowrap\fR) \[em]
the last one given takes effect.)
.TP
.BR \-c ", " \-\-constantshow
Constantly show the cursor position on the status bar.
Note that this overrides option \fB\-U\fR (\fB\-\-quickblank\fR).
Constantly report the cursor position on the status bar.
Note that this overrides option \fB\-U\fR (\fB\-\-\%quickblank\fR).
.TP
.BR \-d ", " \-\-rebinddelete
Interpret the Delete and Backspace keys differently so that both Backspace
@@ -241,9 +287,9 @@ system either Backspace acts like Delete or Delete acts like Backspace.
.BR \-e ", " \-\-emptyline
Do not use the line below the title bar, leaving it entirely blank.
.TP
.BR \-f\ \fIfile ", " \-\-rcfile= \fIfile
Read only this \fIfile\fR for setting nano's options, instead of reading
both the system-wide and the user's nanorc files.
.BI \-f " file\fR, " \-\-rcfile= file
Read only this \fIfile\fR for setting \fBnano\fR's options, instead of reading
both the system-wide and the user's \fInanorc\fR files.
.TP
.BR \-g ", " \-\-showcursor
Make the cursor visible in the file browser (putting it on the
@@ -272,58 +318,59 @@ Display line numbers to the left of the text area.
.BR \-m ", " \-\-mouse
Enable mouse support, if available for your system. When enabled, mouse
clicks can be used to place the cursor, set the mark (with a double
click), and execute shortcuts. The mouse will work in the X Window
click), and execute shortcuts. The mouse works in the X Window
System, and on the console when gpm is running. Text can still be
selected through dragging by holding down the Shift key.
.TP
.BR \-n ", " \-\-noread
Treat any name given on the command line as a new file. This allows
\fBnano\fR to write to named pipes: it will start with a blank buffer,
and will write to the pipe when the user saves the "file". This way
\fBnano\fR to write to named pipes: it starts with a blank buffer,
and writes to the pipe when the user saves the \[lq]file\[rq]. This way
\fBnano\fR can be used as an editor in combination with for instance
\fBgpg\fR without having to write sensitive data to disk first.
.TP
.BR \-o\ \fIdirectory ", " \-\-operatingdir= \fIdirectory
Set the operating directory. This makes \fBnano\fP set up something
similar to a chroot.
.BI \-o " directory\fR, " \-\-operatingdir= directory
Change to the given \fI\%directory\fR, and allow reading and writing
files only in this directory and its subdirectories.
.TP
.BR \-p ", " \-\-preserve
Preserve the XON and XOFF sequences (\fB^Q\fR and \fB^S\fR) so they
will be caught by the terminal.
Preserve the XOFF and XON sequences (\fB^S\fR and \fB^Q\fR) so that
they are caught by the terminal (stopping and resuming the output).
Note that option \fB\-/\fR (\fB\-\-\%modernbindings\fR) overrides this.
.TP
.BR \-q ", " \-\-indicator
Display a "scrollbar" on the righthand side of the edit window.
Display a \[lq]scrollbar\[rq] on the righthand side of the edit window.
It shows the position of the viewport in the buffer
and how much of the buffer is covered by the viewport.
.TP
.BR \-r\ \fInumber ", " \-\-fill= \fInumber
.BI \-r " number\fR, " \-\-fill= number
Set the target width for justifying and automatic hard-wrapping at this
\fInumber\fR of columns. If the value is 0 or less, wrapping will occur
at the width of the screen minus \fInumber\fR columns, allowing the wrap
\fI\%number\fR of columns. If the value is 0 or less, wrapping occurs
at the width of the screen minus \fI\%number\fR columns, allowing the wrap
point to vary along with the width of the screen if the screen is resized.
The default value is \fB\-8\fR.
.TP
.B "\-s ""\fIprogram\fR [\fIargument \fR...]\fB""\fR, \fB\-\-speller=""\fIprogram\fR [\fIargument \fR...]\fB"""
Use this command to perform spell checking and correcting, instead of
using the built-in corrector that calls \fBhunspell\fR(1) or \fBspell\fR(1).
using the built-in corrector that calls \fB\%hunspell\fR(1) or \fBspell\fR(1).
.TP
.BR \-t ", " \-\-saveonexit
Save a changed buffer without prompting (when exiting with \fB^X\fR).
.TP
.BR \-u ", " \-\-unix
Save a file by default in Unix format. This overrides nano's
Save a file by default in Unix format. This overrides \fBnano\fR's
default behavior of saving a file in the format that it had.
(This option has no effect when you also use \fB\-\-noconvert\fR.)
(This option has no effect when you also use \fB\-\-\%noconvert\fR.)
.TP
.BR \-v ", " \-\-view
Just view the file and disallow editing: read-only mode.
This mode allows the user to open also other files for viewing,
unless \fB\-\-restricted\fR is given too.
unless \fB\-\-\%restricted\fR is given too.
.TP
.BR \-w ", " \-\-nowrap
Do not automatically hard-wrap the current line when it becomes overlong.
This is the default. (This option is the opposite of \fB\-b\fR
(\fB\-\-breaklonglines\fR) -- the last one given takes effect.)
(\fB\-\-\%breaklonglines\fR) \[em] the last one given takes effect.)
.TP
.BR \-x ", " \-\-nohelp
Don't show the two help lines at the bottom of the screen.
@@ -331,9 +378,22 @@ 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 ", " \-\-listsyntaxes
List the names of the available syntaxes and exit.
.TP
.BR \-! ", " \-\-magic
When neither the file's name nor its first line give a clue,
try using libmagic to determine the applicable syntax.
try using \fI\%libmagic\fR to determine the applicable syntax.
.TP
.BR \-@ ", " \-\-colonparsing
When a filename given on the command line ends in a colon plus digits
and this filename does not exist, then snip the colon plus digits and
understand the digits as a line number. If the trimmed filename does
not exist either, then repeat the process and understand the obtained
two numbers as line and column number. But if the doubly trimmed
filename does not exist either, then forget the trimming and accept
the original filename as is. To disable this colon parsing for some
file, use \fB+1\fR or similar before the relevant filename.
.TP
.BR \-% ", " \-\-stateflags
Use the top-right corner of the screen for showing some state flags:
@@ -346,19 +406,19 @@ filename in the center of the title bar.
.BR \-_ ", " \-\-minibar
Suppress the title bar and instead show information about
the current buffer at the bottom of the screen, in the space
for the status bar. In this "minibar" the filename is shown
for the status bar. In this \[lq]mini bar\[rq] the filename is shown
on the left, followed by an asterisk if the buffer has been modified.
On the right are displayed the current line and column number, the
code of the character under the cursor (in Unicode format: U+xxxx),
the same flags as are shown by \fB\-\-stateflags\fR, and a percentage
the same flags as are shown by \fB\-\-\%stateflags\fR, and a percentage
that expresses how far the cursor is into the file (linewise).
When a file is loaded or saved, and also when switching between buffers,
the number of lines in the buffer is displayed after the filename.
This number is cleared upon the next keystroke, or replaced with an
[i/n] counter when multiple buffers are open.
The line plus column numbers and the character code are displayed only when
\fB\-\-constantshow\fR is used, and can be toggled on and off with \fBM\-C\fR.
The state flags are displayed only when \fB\-\-stateflags\fR is used.
\fB\-\-\%constantshow\fR is used, and can be toggled on and off with \fBM\-C\fR.
The state flags are displayed only when \fB\-\-\%stateflags\fR is used.
.TP
.BR \-0 ", " \-\-zero
Hide all elements of the interface (title bar, status bar, and help lines)
@@ -367,6 +427,27 @@ 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 \-1 ", " \-\-solosidescroll
When the cursor approaches the right edge of the edit window, scroll only the
current line sideways by a large amount, instead of scrolling all visible lines
sideways by just the amount needed to keep the cursor in view.
This latter whole-window smooth sideways scrolling is the new default behavior.
The single-line jerky sideways scrolling enabled by this option was the old
behavior \[em] the only behavior that \fBnano\fR knew.
.TP
.BR \-/ ", " \-\-modernbindings
Use key bindings similar to the ones that most modern programs use:
\fB^X\fR cuts, \fB^C\fR copies, \fB^V\fR pastes,
\fB^Z\fR undoes, \fB^Y\fR redoes,
\fB^F\fR searches forward, \fB^G\fR searches next,
\fB^S\fR saves, \fB^O\fR opens a file, \fB^Q\fR quits,
and (when the terminal permits) \fB^H\fR shows help.
Furthermore, \fB^A\fR sets the mark, \fB^B\fR searches backward,
\fB^D\fR searches previous, \fB^R\fR makes replacements,
\fB^P\fR shows the position, \fB^T\fR goes to a line,
\fB^W\fR writes out a file, and \fB^E\fR executes a command.
Note that this option overrides option \fB\-p\fR (\fB\-\-\%preserve\fR).
.SH TOGGLES
Several of the above options can be switched on and off also while
@@ -381,43 +462,61 @@ the help viewer and the linter. All other toggles work in
the main menu only.
.SH FILES
When \fB\-\-rcfile\fR is given, \fBnano\fR will read just the specified file
for setting its options and syntaxes and key bindings. Without that option,
\fBnano\fR will read two configuration files: first the system's
When \fB\-\-\%rcfile\fR is given, \fBnano\fR reads just the specified file
for setting its options and syntaxes and key bindings. Without that
option, \fBnano\fR reads two configuration files: first the system's
\fInanorc\fR (if it exists), and then the user's \fInanorc\fR (if it
exists), either \fI~/.nanorc\fR or \fI$XDG_CONFIG_HOME/nano/nanorc\fR
or \fI~/.config/nano/nanorc\fR, whichever is encountered first. See
exists), either \fI\%\[ti]/.nanorc\fR or \fI\%$XDG_CONFIG_HOME/\:nano/\:nanorc\fR
or \fI\%\[ti]/.config/\:nano/\:nanorc\fR, whichever is encountered first. See
.BR nanorc (5)
for more information on the possible contents of those files.
.sp
See \fI/usr/share/nano/\fR and \fI/usr/share/nano/extra/\fR
See \fI/usr/\:share/\:nano/\fR and \fI/usr/\:share/\:nano/\:extra/\fR
for available syntax-coloring definitions.
.SH EXIT STATUS
.TP
.B 0
The editor finished normally.
.TP
.B 1
An invalid option or option argument was given.
.TP
.B 2
The last open buffer was discarded (with \fB^O^Q\fR or \fB^X^Q\fR).
.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.)
\fBbind ^Z suspend main\fR to your \fInanorc\fR.)
.sp
At a Yes-No prompt, \fB^Y\fR can be used for "Yes", \fB^N\fR for "No",
and \fB^A\fR for "All".
(And when exiting, \fB^Q\fR can be used for "Quit with error".)
These unlisted bindings work in any locale.
.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.
line nor in one of the \fInanorc\fR files, \fBnano\fR checks the
\fBSPELL\fR environment variable for one.
.sp
In some cases \fBnano\fP will try to dump the buffer into an emergency
file. This will happen mainly if \fBnano\fP receives a SIGHUP or
SIGTERM or runs out of memory. It will write the buffer into a file
named \fInano.save\fP if the buffer didn't have a name already, or will
add a ".save" suffix to the current filename. If an emergency file with
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.
In some cases \fBnano\fR tries to dump the buffer into an emergency file.
This happens mainly if \fBnano\fR receives a SIGHUP or SIGTERM or runs out
of memory. It writes the buffer into a file named \fI\%nano.save\fR if the
buffer didn't have a name already, or adds a ".save" suffix to the current
filename. If an emergency file with that name already exists in the
current directory, it adds ".save" plus a number (for example: ".save.1") to
the current filename in order to make it unique. When multiple buffers are
open, \fBnano\fR writes each modified buffer to its respective emergency file.
.sp
The complete manual is maintained in Texinfo format.
You can read it with \fBinfo nano\fR, or at
.IR https://nano\-editor.org/dist/latest/nano.html .
.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.
situation, you can ask on \fIhelp\-nano@gnu.org\fR.
.SH BUGS
The recording and playback of keyboard macros works correctly only on a
@@ -428,7 +527,7 @@ Please report any other bugs that you encounter via:
.br
.IR https://savannah.gnu.org/bugs/?group=nano .
.sp
When nano crashes, it will save any modified buffers to emergency .save files.
When \fBnano\fR crashes, it saves any modified buffers to emergency \fI.save\fR files.
If you are able to reproduce the crash and you want to get a backtrace, define
the environment variable \fBNANO_NOCATCH\fR.
@@ -438,4 +537,4 @@ the environment variable \fBNANO_NOCATCH\fR.
.SH SEE ALSO
.BR nanorc (5)
.sp
\fI/usr/share/doc/nano/\fP (or equivalent on your system)
\fI/usr/share/doc/nano/\fR (or equivalent on your system)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
.\" Copyright (C) 2002-2007, 2014-2023 Free Software Foundation, Inc.
.\" Copyright (C) 2002-2007, 2014-2026 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,35 +16,48 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH RNANO 1 "version 7.2" "January 2023"
.TH RNANO 1 "July 2026" "GNU nano 9.2"
.SH NAME
rnano \- a restricted nano
.SH SYNOPSIS
.B rnano
.RI [ options "] [[+" line [, column "]]\ " file "]..."
.RI [ options "] [[\fB+" line [\fB, column "]] " file ]...
.SH DESCRIPTION
\fBrnano\fR runs the \fBnano\fR editor in restricted mode. This allows
editing only the specified file or files, and doesn't allow the user
access to the filesystem nor to a command shell.
editing only the \fIfile\fR (or files) specified on the command line.
.sp
In restricted mode, \fBnano\fR will:
.RS 4
.IP \[bu] 2
not make backups;
.IP \[bu]
not read nor write the history files;
.IP \[bu]
not allow suspending;
.IP \[bu]
not allow spell checking;
.IP \[bu]
not read nor write the history files;
not allow running any command in the shell;
.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.
.RE
.sp
As an exception, before the specified file or files, the \fInanorc\fR files
are read, to allow customization. If customization should not be allowed,
use option \fB\-I\fR (\fB\-\-ignorercfiles\fR) as well.
.sp
When no \fIfile\fR is specified on the command line, the user may save
the contents that they type into the new buffer under any name, except
that existing files may not be overwritten. If the places where this
new file may be created should be limited, then additionally use the
option \fB\-o\fR (\fB\-\-operatingdir\fR).
.SH OPTIONS
.TP

View File

@@ -8,6 +8,16 @@
## Inside string parameters, quotes should not be escaped -- the last
## double quote on the line will be seen as the closing quote.
## If you want ^F, ^B, M-F and M-B to do what they did before version 8.0:
# bind ^F forward main
# bind ^B back main
# bind M-F formatter main
# bind M-B linter main
## Make M-< and M-> switch between buffers, as they did before version 9.0:
# bind M-< prevbuf main
# bind M-> nextbuf main
## Make 'nextword' (Ctrl+Right) and 'chopwordright' (Ctrl+Delete)
## stop at word ends instead of at beginnings.
# set afterends
@@ -44,7 +54,11 @@
## Do case-sensitive searches by default.
# set casesensitive
## Constantly display the cursor position in the status bar or minibar.
## Interpret digits after a colon after a filename (on the command line)
## as the line number to go to in that file.
# set colonparsing
## Constantly report the cursor position, in the status bar or minibar.
# set constantshow
## Use cut-from-cursor-to-end-of-line by default.
@@ -62,7 +76,7 @@
## (This option does not have a default value.)
# set guidestripe 75
## Remember the used search/replace strings for the next session.
## Remember the used search/replace/command strings for the next session.
# set historylog
## Display a "scrollbar" on the righthand side of the edit window.
@@ -74,9 +88,8 @@
## Display line numbers to the left (and any anchors in the margin).
# set linenumbers
## Enable vim-style lock-files. This is just to let a vim user know you
## are editing a file [s]he is trying to edit and vice versa. There are
## no plans to implement vim-style undo state in these files.
## Let other users (of nano or vim) know that you are editing the file
## they are trying to edit, and the other way around.
# set locking
## Fall back to slow libmagic to try and determine an applicable syntax.
@@ -92,16 +105,15 @@
# set minibar
## Enable mouse support, if available for your system. When enabled,
## mouse clicks can be used to place the cursor, set the mark (with a
## double click), and execute shortcuts. The mouse will work in the
## mouse clicks can be used to place the cursor, set the mark (with
## two clicks), and execute shortcuts. The mouse will work in the
## X Window System, and on the console when gpm is running.
# set mouse
## Switch on multiple file buffers (inserting a file will put it into
## a separate buffer).
# set multibuffer
## With ^R, insert a file into a separate buffer by default.
# set newbuffer
## Don't convert files from DOS/Mac format.
## Don't convert files from DOS format.
# set noconvert
## Don't display the helpful shortcut lists at the bottom of the screen.
@@ -116,14 +128,14 @@
## string means the operating-directory feature is turned off.
# set operatingdir ""
## Remember the cursor position in each file for the next editing session.
## Remember the position of cursor and anchors for the next editing session.
# set positionlog
## Preserve the XON and XOFF keys (^Q and ^S).
# set preserve
## The characters treated as closing punctuation when justifying paragraphs.
## This may not contain blank characters. Only these closing punctuations,
## This may not contain blank characters. Only these terminating characters,
## optionally followed by closing brackets, can end sentences.
# set punct "!.?"
@@ -162,6 +174,9 @@
## Spread overlong lines over multiple screen lines.
# set softwrap
## Scroll only the current line sideways (instead of all lines).
# set solosidescroll
## Use this spelling checker instead of the internal one. This option
## does not have a default value.
# set speller "aspell -x -c"
@@ -179,7 +194,7 @@
## Snip whitespace at the end of lines when justifying or hard-wrapping.
# set trimblanks
## Save files by default in Unix format (also when they were DOS or Mac).
## Save files always in Unix format (also when they were DOS).
# set unix
## The two single-column characters used to display the first characters
@@ -214,9 +229,9 @@
# set statuscolor bold,white,green
# set errorcolor bold,white,red
# set spotlightcolor black,lightyellow
# set selectedcolor lightwhite,magenta
# set stripecolor ,yellow
# set scrollercolor cyan
# set selectedcolor lightwhite,#804
# set stripecolor ,#444
# set scrollercolor slate,#222
# set numbercolor cyan
# set keycolor cyan
# set functioncolor green
@@ -239,12 +254,12 @@
## For all details, see 'man nanorc', section SYNTAX HIGHLIGHTING.
## To include most of the existing syntax definitions, you can do:
# include "@PKGDATADIR@/*.nanorc"
# include @PKGDATADIR@/*.nanorc
## Or you can select just the ones you need. For example:
# include "@PKGDATADIR@/html.nanorc"
# include "@PKGDATADIR@/python.nanorc"
# include "@PKGDATADIR@/sh.nanorc"
# include @PKGDATADIR@/html.nanorc
# include @PKGDATADIR@/python.nanorc
# include @PKGDATADIR@/sh.nanorc
## In @PKGDATADIR@/extra/ you can find some syntaxes that are
## specific for certain distros or for some less common languages.
@@ -254,9 +269,6 @@
## independent of the settings of 'tabsize' and 'tabstospaces':
# extendsyntax python tabgives " "
## If <Tab> should always produce an actual TAB when editing a Makefile:
# extendsyntax makefile tabgives " "
## === Key bindings ===
## For all details, see 'man nanorc', section REBINDING KEYS.
@@ -284,13 +296,23 @@
# unbind M-T main
## (Those functions are still accessible through ^T^J and ^T^V.)
## For quickly uppercasing or lowercasing the word under or after the cursor.
## For quickly uppercasing or lowercasing the word that the cursor is on.
## (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
# 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
## Two ways of copying a marked region to the system clipboard:
# bind Sh-M-C "{execute}| xsel -ib {enter}{undo}" main
# bind Sh-M-P "{execute}| xclip -select clipboard 1>&- 2>&- {enter}{undo}" main
## For copying text to the local clipboard via OSC 52 (if terminal supports it):
# bind M-* "{execute}|| printf "\033]52;c;%s\007" "$(base64 | tr -d '\n')" {enter}{undo}" main
## For normalizing Unicode to precomposed characters:
# bind Sh-M-N "{execute}| uconv -x nfc {enter}" main
## For wiping all anchors in a buffer:
# bind Sh-M-W "{execute}| cat {enter}" main
## For snipping trailing blanks when you save a file:
# bind ^S "{execute}| sed 's/\s\+$//' {enter}{savefile}" main
@@ -298,34 +320,34 @@
## If you would like nano to have keybindings that are more "usual",
## such as ^O for Open, ^F for Find, ^H for Help, and ^Q for Quit,
## then uncomment these:
#bind ^X cut main
#bind ^C copy main
#bind ^V paste all
#bind ^Q exit all
#bind ^S savefile main
#bind ^W writeout main
#bind ^O insert main
#set multibuffer
#bind ^H help all
#bind ^H exit help
#bind ^F whereis all
#bind ^G findnext all
#bind ^B wherewas all
#bind ^D findprevious all
#bind ^R replace main
#unbind ^U all
#unbind ^N main
#unbind ^Y all
#unbind M-J main
#unbind M-T main
#bind ^A mark main
#bind ^P location main
#bind ^T gotoline main
#bind ^T gotodir browser
#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
# bind ^X cut main
# bind ^C copy main
# bind ^V paste all
# bind ^Q exit all
# bind ^S savefile main
# bind ^W writeout main
# bind ^O insert main
# set newbuffer
# bind ^H help all
# bind ^H exit help
# bind ^F whereis all
# bind ^G findnext all
# bind ^B wherewas all
# bind ^D findprevious all
# bind ^R replace main
# unbind ^U all
# unbind ^N main
# unbind ^Y all
# unbind M-J main
# unbind M-T main
# bind ^A mark main
# bind ^P location main
# bind ^T gotoline main
# bind ^T gotodir browser
# 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

@@ -31,6 +31,5 @@ EXTRA_DIST = \
threadlib.m4 \
uintmax_t.m4 \
visibility.m4 \
wchar_t.m4 \
wint_t.m4 \
xsize.m4

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 ka ko ms nb nl pl pt pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_TW
ar bg ca cs da de eo es eu fi fr ga gl hr hu id is it ja ka kk ko ms nb nl pl pt pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_TW

View File

@@ -7,6 +7,7 @@ src/files.c
src/global.c
src/help.c
src/history.c
src/move.c
src/nano.c
src/prompt.c
src/rcfile.c

3175
po/ar.po Normal file

File diff suppressed because it is too large Load Diff

1915
po/bg.po

File diff suppressed because it is too large Load Diff

1687
po/ca.po

File diff suppressed because it is too large Load Diff

1876
po/cs.po

File diff suppressed because it is too large Load Diff

1693
po/da.po

File diff suppressed because it is too large Load Diff

1709
po/de.po

File diff suppressed because it is too large Load Diff

1788
po/eo.po

File diff suppressed because it is too large Load Diff

1817
po/es.po

File diff suppressed because it is too large Load Diff

1889
po/eu.po

File diff suppressed because it is too large Load Diff

1900
po/fi.po

File diff suppressed because it is too large Load Diff

1786
po/fr.po

File diff suppressed because it is too large Load Diff

1898
po/ga.po

File diff suppressed because it is too large Load Diff

1843
po/gl.po

File diff suppressed because it is too large Load Diff

3028
po/hr.po

File diff suppressed because it is too large Load Diff

1808
po/hu.po

File diff suppressed because it is too large Load Diff

1774
po/id.po

File diff suppressed because it is too large Load Diff

2042
po/is.po

File diff suppressed because it is too large Load Diff

2097
po/it.po

File diff suppressed because it is too large Load Diff

1722
po/ja.po

File diff suppressed because it is too large Load Diff

1895
po/ka.po

File diff suppressed because it is too large Load Diff

3146
po/kk.po Normal file

File diff suppressed because it is too large Load Diff

1794
po/ko.po

File diff suppressed because it is too large Load Diff

2075
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1772
po/nb.po

File diff suppressed because it is too large Load Diff

1797
po/nl.po

File diff suppressed because it is too large Load Diff

1780
po/pl.po

File diff suppressed because it is too large Load Diff

1860
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1713
po/ro.po

File diff suppressed because it is too large Load Diff

1831
po/ru.po

File diff suppressed because it is too large Load Diff

1854
po/sk.po

File diff suppressed because it is too large Load Diff

1931
po/sl.po

File diff suppressed because it is too large Load Diff

1755
po/sq.po

File diff suppressed because it is too large Load Diff

1808
po/sr.po

File diff suppressed because it is too large Load Diff

1727
po/sv.po

File diff suppressed because it is too large Load Diff

1751
po/tr.po

File diff suppressed because it is too large Load Diff

1790
po/uk.po

File diff suppressed because it is too large Load Diff

1702
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="7.2"
VERSION="9.2"
./configure -C --enable-tiny && make && ./configure -C &&

View File

@@ -30,6 +30,7 @@ nano_SOURCES = \
color.c \
cut.c \
files.c \
folding.c \
global.c \
help.c \
history.c \
@@ -42,8 +43,8 @@ nano_SOURCES = \
utils.c \
winio.c
nano_LDADD = @LIBINTL@ $(top_builddir)/lib/libgnu.a \
$(LIB_CLOCK_GETTIME) $(LIBTHREAD)
nano_LDADD = $(top_builddir)/lib/libgnu.a @LIBINTL@ \
$(GETRANDOM_LIB) $(CLOCK_TIME_LIB) $(LIBTHREAD)
install-exec-hook:
cd $(DESTDIR)$(bindir) && rm -f rnano && $(LN_S) nano rnano

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* browser.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2016, 2020, 2022 Benno Schulenberg *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2015, 2016, 2020, 2022, 2025 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -178,15 +178,15 @@ void browser_refresh(void)
/* Show information about the file: "--" for symlinks (except when
* they point to a directory) and for files that have disappeared,
* "(dir)" for directories, and the file size for normal files. */
if (lstat(filelist[index], &state) == -1 || S_ISLNK(state.st_mode)) {
if (stat(filelist[index], &state) == -1 || !S_ISDIR(state.st_mode))
if (lstat(filelist[index], &state) < 0 || S_ISLNK(state.st_mode)) {
if (stat(filelist[index], &state) < 0 || !S_ISDIR(state.st_mode))
info = copy_of("--");
else
/* TRANSLATORS: Try to keep this at most 7 characters. */
/* TRANSLATORS: Anything more than 7 cells gets clipped. */
info = copy_of(_("(dir)"));
} else if (S_ISDIR(state.st_mode)) {
if (strcmp(thename, "..") == 0) {
/* TRANSLATORS: Try to keep this at most 12 characters. */
/* TRANSLATORS: Anything more than 12 cells gets clipped. */
info = copy_of(_("(parent dir)"));
infomaxlen = 12;
} else
@@ -215,7 +215,7 @@ void browser_refresh(void)
if (result < (1 << 10))
sprintf(info, "%4ju %cB", (intmax_t)result, modifier);
else
/* TRANSLATORS: Try to keep this at most 7 characters.
/* TRANSLATORS: Anything more than 7 cells gets clipped.
* If necessary, you can leave out the parentheses. */
info = mallocstrcpy(info, _("(huge)"));
}
@@ -298,7 +298,7 @@ void search_filename(bool forwards)
int response;
/* If something was searched for before, show it between square brackets. */
if (*last_search != '\0') {
if (*last_search) {
char *disp = display_string(last_search, 0, COLS / 3, FALSE, FALSE);
thedefault = nmalloc(strlen(disp) + 7);
@@ -324,7 +324,7 @@ void search_filename(bool forwards)
}
/* If the user typed an answer, remember it. */
if (*answer != '\0') {
if (*answer) {
last_search = mallocstrcpy(last_search, answer);
#ifdef ENABLE_HISTORIES
update_history(&search_history, answer, PRUNE_DUPLICATE);
@@ -341,7 +341,7 @@ void research_filename(bool forwards)
{
#ifdef ENABLE_HISTORIES
/* If nothing was searched for yet, take the last item from history. */
if (*last_search == '\0' && searchbot->prev != NULL)
if (*last_search == '\0' && searchbot->prev)
last_search = mallocstrcpy(last_search, searchbot->prev->data);
#endif
@@ -353,13 +353,13 @@ void research_filename(bool forwards)
}
}
/* Select the first file in the list -- called by ^W^Y. */
/* Select the first file in the list -- called directly by ^W^Y. */
void to_first_file(void)
{
selected = 0;
}
/* Select the last file in the list -- called by ^W^V. */
/* Select the last file in the list -- called directly by ^W^V. */
void to_last_file(void)
{
selected = list_length - 1;
@@ -372,7 +372,7 @@ char *strip_last_component(const char *path)
char *copy = copy_of(path);
char *last_slash = strrchr(copy, '/');
if (last_slash != NULL)
if (last_slash)
*last_slash = '\0';
return copy;
@@ -387,7 +387,7 @@ char *browse(char *path)
* were in before backing up to "..". */
size_t old_selected;
/* The number of the selected file before the current selected file. */
DIR *dir;
DIR *dir = NULL;
/* The directory whose contents we are showing. */
char *chosen = NULL;
/* The name of the file that the user picked, or NULL if none. */
@@ -397,7 +397,7 @@ char *browse(char *path)
path = free_and_assign(path, get_full_path(path));
if (path != NULL)
if (path)
dir = opendir(path);
if (path == NULL || dir == NULL) {
@@ -414,16 +414,20 @@ char *browse(char *path)
present_name = mallocstrcpy(present_name, filelist[selected]);
}
if (dir != NULL) {
if (dir) {
/* Get the file list, and set gauge and piles in the process. */
read_the_list(path, dir);
closedir(dir);
dir = NULL;
}
#ifndef NANO_TINY
resized_for_browser = FALSE;
#endif
/* If something was selected before, reselect it;
* otherwise, just select the first item (..). */
if (present_name != NULL) {
if (present_name) {
reselect(present_name);
free(present_name);
present_name = NULL;
@@ -461,7 +465,7 @@ char *browse(char *path)
int mouse_x, mouse_y;
/* When the user clicked in the file list, select a filename. */
if (get_mouseinput(&mouse_y, &mouse_x, TRUE) == 0 &&
if (get_mouseinput(&mouse_y, &mouse_x) == 0 &&
wmouse_trafo(midwin, &mouse_y, &mouse_x, FALSE)) {
selected = selected - selected % (usable_rows * piles) +
(mouse_y * piles) + (mouse_x / (gauge + 2));
@@ -483,26 +487,20 @@ char *browse(char *path)
continue;
}
#endif /* ENABLE_MOUSE */
#ifndef NANO_TINY
while (bracketed_paste)
kbinput = get_kbinput(midwin, BLIND);
if (kbinput == BRACKETED_PASTE_MARKER) {
beep();
continue;
}
#endif
function = interpret(kbinput);
if (function == full_refresh || function == do_help) {
function();
#ifndef NANO_TINY
/* Simulate a terminal resize to force a directory reread,
* or because the terminal dimensions might have changed. */
kbinput = KEY_WINCH;
if (function == do_help)
do_help();
else if (function == full_refresh) {
#ifdef NANO_TINY
full_refresh();
#else
kbinput = THE_WINDOW_RESIZED;
} else if (function == do_toggle && get_shortcut(kbinput)->toggle == NO_HELP) {
TOGGLE(NO_HELP);
window_init();
kbinput = KEY_WINCH;
kbinput = THE_WINDOW_RESIZED;
#endif
} else if (function == do_search_backward) {
search_filename(BACKWARD);
@@ -555,35 +553,32 @@ char *browse(char *path)
list_length - piles;
else
selected += usable_rows * piles;
} else if (function == to_first_file) {
selected = 0;
} else if (function == to_last_file) {
selected = list_length - 1;
} else if (function == to_first_file || function == to_last_file) {
function();
} else if (function == goto_dir) {
/* Ask for the directory to go to. */
if (do_prompt(MGOTODIR, "", NULL,
/* TRANSLATORS: This is a prompt. */
browser_refresh, _("Go To Directory")) < 0) {
statusbar(_("Cancelled"));
continue;
goto testresize;
}
path = free_and_assign(path, real_dir_from_tilde(answer));
path = free_and_assign(path, expand_leading_tilde(answer));
/* If the given path is relative, join it with the current path. */
if (*path != '/') {
path = nrealloc(path, strlen(present_path) +
strlen(answer) + 1);
path = nrealloc(path, strlen(present_path) + strlen(answer) + 1);
sprintf(path, "%s%s", present_path, answer);
}
#ifdef ENABLE_OPERATINGDIR
if (outside_of_confinement(path, FALSE)) {
if (operating_dir && outside_of_confinement(path, FALSE)) {
/* TRANSLATORS: This refers to the confining effect of
* the option --operatingdir, not of --restricted. */
statusline(ALERT, _("Can't go outside of %s"), operating_dir);
path = mallocstrcpy(path, present_path);
continue;
goto testresize;
}
#endif
/* Snip any trailing slashes, so the name can be compared. */
@@ -611,13 +606,13 @@ char *browse(char *path)
/* Note: The selected file can be outside the operating
* directory if it's ".." or if it's a symlink to a
* directory outside the operating directory. */
if (outside_of_confinement(filelist[selected], FALSE)) {
if (operating_dir && outside_of_confinement(filelist[selected], FALSE)) {
statusline(ALERT, _("Can't go outside of %s"), operating_dir);
continue;
}
#endif
/* If for some reason the file is inaccessible, complain. */
if (stat(filelist[selected], &st) == -1) {
if (stat(filelist[selected], &st) < 0) {
statusline(ALERT, _("Error reading %s: %s"),
filelist[selected], strerror(errno));
continue;
@@ -642,7 +637,11 @@ char *browse(char *path)
implant(first_sc_for(MBROWSER, function)->expansion);
#endif
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
} else if (kbinput == START_OF_PASTE) {
while (get_kbinput(midwin, BLIND) != END_OF_PASTE)
;
statusline(AHEM, _("Paste is ignored"));
} else if (kbinput == THE_WINDOW_RESIZED) {
; /* Gets handled below. */
#endif
} else if (function == do_exit) {
@@ -650,9 +649,10 @@ char *browse(char *path)
} else
unbound_key(kbinput);
testresize:
#ifndef NANO_TINY
/* If the terminal resized (or might have), refresh the file list. */
if (kbinput == KEY_WINCH) {
if (kbinput == THE_WINDOW_RESIZED || resized_for_browser) {
/* Remember the selected file, to be able to reselect it. */
present_name = copy_of(filelist[selected]);
goto read_directory_contents;
@@ -676,15 +676,15 @@ char *browse(char *path)
* start browsing in that directory, otherwise in the current directory. */
char *browse_in(const char *inpath)
{
char *path = real_dir_from_tilde(inpath);
char *path = expand_leading_tilde(inpath);
struct stat fileinfo;
/* If path is not a directory, try to strip a filename from it; if then
* still not a directory, use the current working directory instead. */
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
if (stat(path, &fileinfo) < 0 || !S_ISDIR(fileinfo.st_mode)) {
path = free_and_assign(path, strip_last_component(path));
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
if (stat(path, &fileinfo) < 0 || !S_ISDIR(fileinfo.st_mode)) {
path = free_and_assign(path, realpath(".", NULL));
if (path == NULL) {
@@ -698,7 +698,7 @@ 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 (outside_of_confinement(path, FALSE))
if (operating_dir && 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-2023 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016-2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -23,26 +23,10 @@
#include <ctype.h>
#include <string.h>
#ifdef ENABLE_UTF8
#include <wchar.h>
#include <wctype.h>
static bool use_utf8 = FALSE;
/* Whether we've enabled UTF-8 support. */
/* Enable UTF-8 support. */
void utf8_init(void)
{
use_utf8 = TRUE;
}
/* Is UTF-8 support enabled? */
bool using_utf8(void)
{
return use_utf8;
}
#endif /* ENABLE_UTF8 */
#endif
#ifdef ENABLE_SPELLER
/* Return TRUE when the given character is some kind of letter. */
@@ -98,12 +82,12 @@ bool is_blank_char(const char *c)
bool is_cntrl_char(const char *c)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8)
return ((c[0] & 0xE0) == 0 || c[0] == DEL_CODE ||
((signed char)c[0] == -62 && (signed char)c[1] < -96));
} else
#endif
return ((*c & 0x60) == 0 || *c == DEL_CODE);
return ((*c & 0x60) == 0 || *c == DEL_CODE);
}
/* Return TRUE when the given character is a punctuation character. */
@@ -134,14 +118,15 @@ bool is_word_char(const char *c, bool allow_punct)
if (allow_punct && is_punct_char(c))
return TRUE;
if (word_chars != NULL && *word_chars != '\0') {
if (word_chars && *word_chars) {
char symbol[MAXCHARLEN + 1];
int symlen = collect_char(c, symbol);
symbol[symlen] = '\0';
return (strstr(word_chars, symbol) != NULL);
} else
return FALSE;
}
return FALSE;
}
/* Return the visible representation of control character c. */
@@ -153,8 +138,8 @@ char control_rep(const signed char c)
return '=';
else if (c < 0)
return c + 224;
else
return c + 64;
return c + 64;
}
/* Return the visible representation of multibyte control character c. */
@@ -165,14 +150,15 @@ char control_mbrep(const char *c, bool isdata)
return '@';
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
if ((unsigned char)c[0] < 128)
return control_rep(c[0]);
else
return control_rep(c[1]);
} else
}
#endif
return control_rep(*c);
return control_rep(*c);
}
#ifdef ENABLE_UTF8
@@ -180,9 +166,9 @@ char control_mbrep(const char *c, bool isdata)
* the number of bytes in the sequence, or -1 for an invalid sequence. */
int mbtowide(wchar_t *wc, const char *c)
{
if ((signed char)*c < 0 && use_utf8) {
unsigned char v1 = (unsigned char)c[0];
unsigned char v2 = (unsigned char)c[1] ^ 0x80;
if ((signed char)*c < 0 && using_utf8) {
unsigned char v1 = c[0];
unsigned char v2 = c[1] ^ 0x80;
if (v2 > 0x3F || v1 < 0xC2)
return -1;
@@ -192,7 +178,7 @@ int mbtowide(wchar_t *wc, const char *c)
return 2;
}
unsigned char v3 = (unsigned char)c[2] ^ 0x80;
unsigned char v3 = c[2] ^ 0x80;
if (v3 > 0x3F)
return -1;
@@ -206,7 +192,7 @@ int mbtowide(wchar_t *wc, const char *c)
return -1;
}
unsigned char v4 = (unsigned char)c[3] ^ 0x80;
unsigned char v4 = c[3] ^ 0x80;
if (v4 > 0x3F || v1 > 0xF4)
return -1;
@@ -229,7 +215,7 @@ bool is_doublewidth(const char *ch)
wchar_t wc;
/* Only from U+1100 can code points have double width. */
if ((unsigned char)*ch < 0xE1 || !use_utf8)
if ((unsigned char)*ch < 0xE1 || !using_utf8)
return FALSE;
if (mbtowide(&wc, ch) < 0)
@@ -244,7 +230,7 @@ bool is_zerowidth(const char *ch)
wchar_t wc;
/* Only from U+0300 can code points have zero width. */
if ((unsigned char)*ch < 0xCC || !use_utf8)
if ((unsigned char)*ch < 0xCC || !using_utf8)
return FALSE;
if (mbtowide(&wc, ch) < 0)
@@ -264,9 +250,9 @@ bool is_zerowidth(const char *ch)
int char_length(const char *pointer)
{
#ifdef ENABLE_UTF8
if ((unsigned char)*pointer > 0xC1 && use_utf8) {
unsigned char c1 = (unsigned char)pointer[0];
unsigned char c2 = (unsigned char)pointer[1];
if ((unsigned char)*pointer > 0xC1 && using_utf8) {
unsigned char c1 = pointer[0];
unsigned char c2 = pointer[1];
if ((c2 ^ 0x80) > 0x3F)
return 1;
@@ -294,7 +280,8 @@ int char_length(const char *pointer)
return 4;
}
#endif
return 1;
return 1;
}
/* Return the number of (multibyte) characters in the given string. */
@@ -302,7 +289,7 @@ size_t mbstrlen(const char *pointer)
{
size_t count = 0;
while (*pointer != '\0') {
while (*pointer) {
pointer += char_length(pointer);
count++;
}
@@ -327,7 +314,7 @@ int collect_char(const char *string, char *thechar)
int advance_over(const char *string, size_t *column)
{
#ifdef ENABLE_UTF8
if ((signed char)*string < 0 && use_utf8) {
if ((signed char)*string < 0 && using_utf8) {
/* A UTF-8 upper control code has two bytes and takes two columns. */
if (((unsigned char)string[0] == 0xC2 && (signed char)string[1] < -96)) {
*column += 2;
@@ -371,7 +358,7 @@ int advance_over(const char *string, size_t *column)
size_t step_left(const char *buf, size_t pos)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
size_t before, charlen = 0;
if (pos < 4)
@@ -400,9 +387,10 @@ size_t step_left(const char *buf, size_t pos)
}
return before - charlen;
} else
}
#endif
return (pos == 0 ? 0 : pos - 1);
return (pos == 0 ? 0 : pos - 1);
}
/* Return the index in buf of the beginning of the multibyte character
@@ -422,10 +410,10 @@ int mbstrcasecmp(const char *s1, const char *s2)
int mbstrncasecmp(const char *s1, const char *s2, size_t n)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
wchar_t wc1, wc2;
while (*s1 != '\0' && *s2 != '\0' && n > 0) {
while (*s1 && *s2 && n > 0) {
if ((signed char)*s1 >= 0 && (signed char)*s2 >= 0) {
if ('A' <= (*s1 & 0x5F) && (*s1 & 0x5F) <= 'Z') {
if ('A' <= (*s2 & 0x5F) && (*s2 & 0x5F) <= 'Z') {
@@ -464,19 +452,20 @@ int mbstrncasecmp(const char *s1, const char *s2, size_t n)
}
return (n > 0) ? ((unsigned char)*s1 - (unsigned char)*s2) : 0;
} else
}
#endif
return strncasecmp(s1, s2, n);
return strncasecmp(s1, s2, n);
}
/* This function is equivalent to strcasestr() for multibyte strings. */
char *mbstrcasestr(const char *haystack, const char *needle)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
size_t needle_len = mbstrlen(needle);
while (*haystack != '\0') {
while (*haystack) {
if (mbstrncasecmp(haystack, needle, needle_len) == 0)
return (char *)haystack;
@@ -484,9 +473,10 @@ char *mbstrcasestr(const char *haystack, const char *needle)
}
return NULL;
} else
}
#endif
return (char *)strcasestr(haystack, needle);
return (char *)strcasestr(haystack, needle);
}
/* This function is equivalent to strstr(), except in that it scans the
@@ -535,7 +525,7 @@ char *mbrevstrcasestr(const char *haystack, const char *needle,
const char *pointer)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
size_t needle_len = mbstrlen(needle);
size_t tail_len = mbstrlen(pointer);
@@ -554,17 +544,18 @@ char *mbrevstrcasestr(const char *haystack, const char *needle,
pointer = haystack + step_left(haystack, pointer - haystack);
}
} else
}
#endif
return revstrcasestr(haystack, needle, pointer);
return revstrcasestr(haystack, needle, pointer);
}
#if !defined(NANO_TINY) || defined(ENABLE_JUSTIFY)
/* This function is equivalent to strchr() for multibyte strings. */
char *mbstrchr(const char *string, const char *chr)
const char *mbstrchr(const char *string, const char *chr)
{
#ifdef ENABLE_UTF8
if (use_utf8) {
if (using_utf8) {
bool bad_s = FALSE, bad_c = FALSE;
wchar_t ws, wc;
@@ -573,7 +564,7 @@ char *mbstrchr(const char *string, const char *chr)
bad_c = TRUE;
}
while (*string != '\0') {
while (*string) {
int symlen = mbtowide(&ws, string);
if (symlen < 0) {
@@ -591,9 +582,10 @@ char *mbstrchr(const char *string, const char *chr)
return NULL;
return (char *)string;
} else
}
#endif
return strchr(string, *chr);
return strchr(string, *chr);
}
#endif /* !NANO_TINY || ENABLE_JUSTIFY */
@@ -602,8 +594,8 @@ char *mbstrchr(const char *string, const char *chr)
* the characters in accept, searching forward. */
char *mbstrpbrk(const char *string, const char *accept)
{
while (*string != '\0') {
if (mbstrchr(accept, string) != NULL)
while (*string) {
if (mbstrchr(accept, string))
return (char *)string;
string += char_length(string);
@@ -623,7 +615,7 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer)
}
while (TRUE) {
if (mbstrchr(accept, pointer) != NULL)
if (mbstrchr(accept, pointer))
return (char *)pointer;
/* If we've reached the head of the string, we found nothing. */
@@ -639,7 +631,7 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer)
/* Return TRUE if the given string contains at least one blank character. */
bool has_blank_char(const char *string)
{
while (*string != '\0' && !is_blank_char(string))
while (*string && !is_blank_char(string))
string += char_length(string);
return *string;
@@ -649,8 +641,17 @@ bool has_blank_char(const char *string)
/* Return TRUE when the given string is empty or consists of only blanks. */
bool white_string(const char *string)
{
while (*string != '\0' && (is_blank_char(string) || *string == '\r'))
while (*string && (is_blank_char(string) || *string == '\r'))
string += char_length(string);
return !*string;
}
#if defined(ENABLE_SPELLER) || defined(ENABLE_COLOR)
/* Remove leading whitespace from the given string. */
void strip_leading_blanks_from(char *string)
{
while (string && (*string == ' ' || *string == '\t'))
memmove(string, string + 1, strlen(string));
}
#endif

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* color.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017, 2020, 2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -44,7 +44,7 @@ void set_interface_colorpairs(void)
for (size_t index = 0; index < NUMBER_OF_ELEMENTS; index++) {
colortype *combo = color_combo[index];
if (combo != NULL) {
if (combo) {
if (!defaults_allowed) {
if (combo->fg == THE_DEFAULT)
combo->fg = COLOR_WHITE;
@@ -67,8 +67,15 @@ void set_interface_colorpairs(void)
else if (index == ERROR_MESSAGE) {
init_pair(index + 1, COLOR_WHITE, COLOR_RED);
interface_color_pair[index] = COLOR_PAIR(index + 1) | A_BOLD;
} else
} else if (index == FOLDED_LINE) {
if (COLORS > 15)
init_pair(index + 1, COLOR_BLACK + 8, COLOR_BLACK);
else
init_pair(index + 1, COLOR_WHITE, COLOR_BLACK);
interface_color_pair[index] = COLOR_PAIR(index + 1);
} else {
interface_color_pair[index] = hilite_attribute;
}
}
free(color_combo[index]);
@@ -143,7 +150,7 @@ void find_and_prime_applicable_syntax(void)
return;
/* If we specified a syntax-override string, use it. */
if (syntaxstr != NULL) {
if (syntaxstr) {
/* An override of "none" is like having no syntax at all. */
if (strcmp(syntaxstr, "none") == 0)
return;
@@ -203,7 +210,7 @@ void find_and_prime_applicable_syntax(void)
}
/* Now try and find a syntax that matches the magic string. */
if (magicstring != NULL) {
if (magicstring) {
for (sntx = syntaxes; sntx != NULL; sntx = sntx->next)
if (found_in_list(sntx->magics, magicstring))
break;
@@ -222,7 +229,7 @@ void find_and_prime_applicable_syntax(void)
}
/* When the syntax isn't loaded yet, parse it and initialize its colors. */
if (sntx != NULL && sntx->filename != NULL) {
if (sntx && sntx->filename) {
parse_one_include(sntx->filename, sntx);
set_syntax_colorpairs(sntx);
}
@@ -240,7 +247,7 @@ void check_the_multis(linestruct *line)
char *afterstart;
/* If there is no syntax or no multiline regex, there is nothing to do. */
if (openfile->syntax == NULL || openfile->syntax->nmultis == 0)
if (!openfile->syntax || openfile->syntax->multiscore == 0)
return;
if (line->multidata == NULL) {
@@ -263,8 +270,7 @@ void check_the_multis(linestruct *line)
continue;
} 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))
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 + startmatch.rm_eo +
@@ -293,7 +299,7 @@ void precalc_multicolorinfo(void)
regmatch_t startmatch, endmatch;
linestruct *line, *tailline;
if (!openfile->syntax || openfile->syntax->nmultis == 0 || ISSET(NO_SYNTAX))
if (!openfile->syntax || openfile->syntax->multiscore == 0 || ISSET(NO_SYNTAX))
return;
//#define TIMEPRECALC 123
@@ -305,7 +311,7 @@ void precalc_multicolorinfo(void)
/* For each line, allocate cache space for the multiline-regex info. */
for (line = openfile->filetop; line != NULL; line = line->next)
if (!line->multidata)
line->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
line->multidata = nmalloc(openfile->syntax->multiscore * sizeof(short));
for (ink = openfile->syntax->color; ink != NULL; ink = ink->next) {
/* If this is not a multi-line regex, skip it. */
@@ -347,8 +353,7 @@ void precalc_multicolorinfo(void)
/* Look for an end match on later lines. */
tailline = line->next;
while (tailline && regexec(ink->end, tailline->data,
1, &endmatch, 0) != 0)
while (tailline && regexec(ink->end, tailline->data, 1, &endmatch, 0) != 0)
tailline = tailline->next;
line->multidata[ink->id] = STARTSHERE;
@@ -371,7 +376,7 @@ void precalc_multicolorinfo(void)
}
#ifdef TIMEPRECALC
statusline(INFO, "Precalculation: %.1f ms", 1000 * (double)(clock() - start) / CLOCKS_PER_SEC);
statusline(NOTICE, "Precalculation: %.1f ms", 1000 * (double)(clock() - start) / CLOCKS_PER_SEC);
napms(1200);
#endif
}

108
src/cut.c
View File

@@ -1,7 +1,7 @@
/**************************************************************************
* cut.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mark Majeres *
* Copyright (C) 2016, 2018-2020 Benno Schulenberg *
* *
@@ -16,7 +16,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,13 +24,14 @@
#include <string.h>
/* Delete the character under the cursor. */
void do_deletion(undo_type action)
/* Delete the character at the current position, and
* add or update an undo item for the given action. */
void expunge(undo_type action)
{
openfile->placewewant = xplustabs();
/* When in the middle of a line, delete the current character. */
if (openfile->current->data[openfile->current_x] != '\0') {
if (openfile->current->data[openfile->current_x]) {
int charlen = char_length(openfile->current->data + openfile->current_x);
size_t line_len = strlen(openfile->current->data + openfile->current_x);
#ifndef NANO_TINY
@@ -48,23 +49,28 @@ void do_deletion(undo_type action)
memmove(&openfile->current->data[openfile->current_x],
&openfile->current->data[openfile->current_x + charlen],
line_len - charlen + 1);
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
/* When softwrapping, a changed number of chunks requires a refresh. */
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
refresh_needed = TRUE;
/* When panning, and we have come near edge of the viewport... */
else if (united_sidescroll && openfile->placewewant < openfile->brink + CUSHION)
refresh_needed = TRUE;
/* Adjust the mark if it is after the cursor on the current line. */
if (openfile->mark == openfile->current &&
openfile->mark_x > openfile->current_x)
if (openfile->mark == openfile->current && openfile->mark_x > openfile->current_x)
openfile->mark_x -= charlen;
#endif
/* Otherwise, when not at end of buffer, join this line with the next. */
} else if (openfile->current != openfile->filebot) {
linestruct *joining = openfile->current->next;
UNFOLD_SEGMENT(openfile->current);
UNFOLD_SEGMENT(joining);
/* If there is a magic line, and we're before it: don't eat it. */
if (joining == openfile->filebot && openfile->current_x != 0 &&
!ISSET(NO_NEWLINES)) {
if (joining == openfile->filebot && openfile->current_x != 0 && !ISSET(NO_NEWLINES)) {
#ifndef NANO_TINY
if (action == BACK)
add_undo(BACK, NULL);
@@ -112,7 +118,8 @@ void do_deletion(undo_type action)
set_modified();
}
/* Delete the character under the cursor. */
/* Delete the character under the cursor plus any succeeding zero-widths,
* or, when the mark is on and --zap is active, delete the marked region. */
void do_delete(void)
{
#ifndef NANO_TINY
@@ -121,17 +128,18 @@ void do_delete(void)
else
#endif
{
do_deletion(DEL);
expunge(DEL);
#ifdef ENABLE_UTF8
while (openfile->current->data[openfile->current_x] != '\0' &&
while (openfile->current->data[openfile->current_x] &&
is_zerowidth(openfile->current->data + openfile->current_x))
do_deletion(DEL);
expunge(DEL);
#endif
}
}
/* Backspace over one character. That is, move the cursor left one
* character, and then delete the character under the cursor. */
* character, and then delete the character under the cursor. Or,
* when mark is on and --zap is active, delete the marked region. */
void do_backspace(void)
{
#ifndef NANO_TINY
@@ -141,10 +149,16 @@ void do_backspace(void)
#endif
if (openfile->current_x > 0) {
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
do_deletion(BACK);
expunge(BACK);
} else if (openfile->current != openfile->filetop) {
do_left();
do_deletion(BACK);
#ifdef ENABLE_FOLDING
if (openfile->current->prev->folded) {
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
} else
#endif
do_left();
expunge(BACK);
}
}
@@ -180,8 +194,8 @@ bool is_cuttable(bool test_cliff)
void chop_word(bool forward)
{
/* Remember the current cursor position. */
linestruct *is_current = openfile->current;
size_t is_current_x = openfile->current_x;
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
/* Remember where the cutbuffer is, then make it seem blank. */
linestruct *is_cutbuffer = cutbuffer;
@@ -192,30 +206,30 @@ void chop_word(bool forward)
* on the edge of the original line, then put the cursor on that
* edge instead, so that lines will not be joined unexpectedly. */
if (!forward) {
do_prev_word();
if (openfile->current != is_current) {
if (is_current_x > 0) {
openfile->current = is_current;
do_prev_word(ALLOW_FOLDED);
if (openfile->current != was_current) {
if (was_x > 0) {
openfile->current = was_current;
openfile->current_x = 0;
} else
openfile->current_x = strlen(openfile->current->data);
}
} else {
do_next_word(ISSET(AFTER_ENDS));
if (openfile->current != is_current &&
is_current->data[is_current_x] != '\0') {
openfile->current = is_current;
openfile->current_x = strlen(is_current->data);
do_next_word(ISSET(AFTER_ENDS), ALLOW_FOLDED);
if (openfile->current != was_current && was_current->data[was_x]) {
openfile->current = was_current;
openfile->current_x = strlen(was_current->data);
}
}
UNFOLD_SEGMENT(openfile->current);
/* Set the mark at the start of that word. */
openfile->mark = openfile->current;
openfile->mark_x = openfile->current_x;
/* Put the cursor back where it was, so an undo will put it there too. */
openfile->current = is_current;
openfile->current_x = is_current_x;
openfile->current = was_current;
openfile->current_x = was_x;
/* Now kill the marked region and a word is gone. */
add_undo(CUT, NULL);
@@ -262,9 +276,13 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
if (top == bot && top_x == bot_x)
return;
if (top != bot)
for (linestruct *line = top->next; line != bot->next; line = line->next)
if (top != bot) {
UNFOLD_SEGMENT(top);
for (linestruct *line = top->next; line != bot->next; line = line->next) {
UNFOLD_SEGMENT(line);
had_anchor |= line->has_anchor;
}
}
#endif
if (top == bot) {
@@ -332,7 +350,7 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
cutbottom->next = taken->next;
delete_node(taken);
if (cutbottom->next != NULL) {
if (cutbottom->next) {
cutbottom->next->prev = cutbottom;
cutbottom = last;
}
@@ -360,7 +378,7 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
}
/* If the text doesn't end with a newline, and it should, add one. */
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0])
new_magicline();
}
@@ -378,7 +396,9 @@ void ingraft_buffer(linestruct *topline)
#endif
linestruct *botline = topline;
while (botline->next != NULL)
UNFOLD_SEGMENT(line);
while (botline->next)
botline = botline->next;
/* Add the size of the text to be grafted to the buffer size. */
@@ -435,7 +455,7 @@ void ingraft_buffer(linestruct *topline)
renumber_from(line);
/* If the text doesn't end with a newline, and it should, add one. */
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0])
new_magicline();
}
@@ -502,7 +522,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 (line->data[openfile->current_x] != '\0')
if (line->data[openfile->current_x])
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);
@@ -634,6 +654,7 @@ void copy_marked_region(void)
botline->data[bot_x] = saved_byte;
botline->next = afterline;
}
#endif /* !NANO_TINY */
/* Copy text from the current buffer into the cutbuffer. The text is either
* the marked region, the whole line, the text from cursor to end-of-line,
@@ -646,17 +667,24 @@ void copy_text(void)
linestruct *was_current = openfile->current;
linestruct *addition;
if (openfile->mark || openfile->last_action != COPY || !keep_cutbuffer) {
#ifndef NANO_TINY
if (openfile->mark || openfile->last_action != COPY)
keep_cutbuffer = FALSE;
#endif
if (!keep_cutbuffer) {
free_lines(cutbuffer);
cutbuffer = NULL;
}
wipe_statusbar();
#ifndef NANO_TINY
if (openfile->mark) {
copy_marked_region();
return;
}
#endif
/* When at the very end of the buffer, there is nothing to do. */
if (openfile->current->next == NULL && at_eol && (ISSET(CUT_FROM_CURSOR) ||
@@ -706,10 +734,11 @@ void copy_text(void)
edit_redraw(was_current, FLOWING);
#ifndef NANO_TINY
openfile->last_action = COPY;
#endif
keep_cutbuffer = TRUE;
}
#endif /* !NANO_TINY */
/* Copy text from the cutbuffer into the current buffer. */
void paste_text(void)
@@ -728,6 +757,7 @@ void paste_text(void)
statusline(AHEM, _("Cutbuffer is empty"));
return;
}
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
add_undo(PASTE, NULL);

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* definitions.h -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017, 2020-2022, 2024 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -41,6 +41,11 @@
#define ROOT_UID 0
#endif
#if defined(__APPLE__) && !defined(st_atim)
#define st_atim st_atimespec
#define st_mtim st_mtimespec
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
@@ -60,10 +65,7 @@
#include <stdlib.h>
#include <sys/stat.h>
/* Prefer wide ncurses over normal ncurses over curses. */
#if defined(HAVE_NCURSESW_NCURSES_H)
#include <ncursesw/ncurses.h>
#elif defined(HAVE_NCURSES_H)
#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#else
#include <curses.h>
@@ -123,11 +125,6 @@
#define REPLACING 1
#define INREGION 2
#define NORMAL TRUE
#define SPECIAL FALSE
#define TEMPORARY FALSE
#define ANNOTATE TRUE
#define NONOTES FALSE
#define PRUNE_DUPLICATE TRUE
@@ -146,6 +143,9 @@
/* The default number of columns from end of line where wrapping occurs. */
#define COLUMNS_FROM_EOL 8
/* The number of columns the cursor should stay away from the edge. */
#define CUSHION 3
/* The default comment character when a syntax does not specify any. */
#define GENERAL_COMMENT_CHARACTER "#"
@@ -195,6 +195,8 @@
#define ALT_RIGHT 0x422
#define ALT_UP 0x423
#define ALT_DOWN 0x424
#define ALT_HOME 0x425
#define ALT_END 0x426
#define ALT_PAGEUP 0x427
#define ALT_PAGEDOWN 0x428
#define ALT_INSERT 0x42C
@@ -203,8 +205,6 @@
#define SHIFT_ALT_RIGHT 0x432
#define SHIFT_ALT_UP 0x433
#define SHIFT_ALT_DOWN 0x434
//#define SHIFT_LEFT 0x451
//#define SHIFT_RIGHT 0x452
#define SHIFT_UP 0x453
#define SHIFT_DOWN 0x454
#define SHIFT_HOME 0x455
@@ -214,22 +214,28 @@
#define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F
#define FOCUS_IN 0x491
#define FOCUS_OUT 0x499
#define FOCUS_IN 0x491
#define FOCUS_OUT 0x499
/* Custom keycodes for signaling the start and end of a bracketed paste. */
#define START_OF_PASTE 0x4B5
#define END_OF_PASTE 0x4BE
/* 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
#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
#ifndef NANO_TINY
/* A special keycode for Ctrl + the central key on the numeric keypad. */
#define KEY_CENTER 0x4F0
/* A special keycode to signal the beginning and end of a bracketed paste. */
#define BRACKETED_PASTE_MARKER 0x4FB
/* A special keycode for when we get a SIGWINCH (a window resize). */
#define THE_WINDOW_RESIZED 0x4F7
#endif
/* A special keycode for when a key produces an unknown escape sequence. */
#define FOREIGN_SEQUENCE 0x4FC
@@ -238,9 +244,6 @@
#define KEY_FRESH 0x4FE
#ifndef NANO_TINY
/* A special keycode for when we get a SIGWINCH (a window resize). */
#define KEY_WINCH -2
/* Some extra flags for the undo function. */
#define WAS_BACKSPACE_AT_EOF (1<<1)
#define WAS_WHOLE_LINE (1<<2)
@@ -276,9 +279,18 @@
#define MSOME MMAIN|MBROWSER
#endif
#ifdef ENABLE_FOLDING
#define UNFOLD_SEGMENT(line) unfold_folded_segment(line)
#else
#define UNFOLD_SEGMENT(line)
#endif
#define ALLOW_FOLDED TRUE
#define DISALLOW_FOLDED FALSE
/* Enumeration types. */
typedef enum {
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
UNSPECIFIED, NIX_FILE, DOS_FILE
} format_type;
typedef enum {
@@ -286,8 +298,8 @@ typedef enum {
} message_type;
typedef enum {
OVERWRITE, APPEND, PREPEND
} kind_of_writing_type;
OVERWRITE, APPEND, PREPEND, SPECIAL
} writing_type;
typedef enum {
CENTERING, FLOWING, STATIONARY
@@ -321,6 +333,7 @@ enum {
ERROR_MESSAGE,
KEY_COMBO,
FUNCTION_TAG,
FOLDED_LINE,
NUMBER_OF_ELEMENTS
};
@@ -338,7 +351,7 @@ enum {
SAVE_ON_EXIT,
CUT_FROM_CURSOR,
BACKWARDS_SEARCH,
MULTIBUFFER,
NEW_BUFFER,
REBIND_DELETE,
RAW_SEQUENCES,
NO_CONVERT,
@@ -371,12 +384,21 @@ enum {
EMPTY_LINE,
INDICATOR,
BOOKSTYLE,
COLON_PARSING,
STATEFLAGS,
USE_MAGIC,
MINIBAR,
ZERO
ZERO,
MODERN_BINDINGS,
SOLO_SIDESCROLL
};
typedef enum {
FOUND_BRACKET = 0,
NOT_FOUND_BRACKET,
NOT_A_BRACKET
} bracket_search_result;
/* Structure types. */
#ifdef ENABLE_COLOR
typedef struct colortype {
@@ -443,7 +465,7 @@ typedef struct syntaxtype {
#endif
colortype *color;
/* The colors and their regexes used in this syntax. */
short nmultis;
short multiscore;
/* How many multiline regex strings this syntax has. */
struct syntaxtype *next;
/* Next syntax. */
@@ -483,6 +505,10 @@ typedef struct linestruct {
bool has_anchor;
/* Whether the user has placed an anchor at this line. */
#endif
#ifdef ENABLE_FOLDING
bool folded;
/* Whether or not this line is in a fold segment */
#endif
} linestruct;
#ifndef NANO_TINY
@@ -526,16 +552,18 @@ typedef struct undostruct {
#endif /* !NANO_TINY */
#ifdef ENABLE_HISTORIES
typedef struct poshiststruct {
typedef struct positionstruct {
char *filename;
/* The full path plus name of the file. */
ssize_t linenumber;
/* The line where the cursor was when we closed the file. */
/* The line where the cursor was when the file was closed. */
ssize_t columnnumber;
/* The column where the cursor was. */
struct poshiststruct *next;
/* The next item of position history. */
} poshiststruct;
char *anchors;
/* The line numbers where anchors were placed, in string form. */
struct positionstruct *next;
/* The next item in the positions register. */
} positionstruct;
#endif
typedef struct openfilestruct {
@@ -557,9 +585,11 @@ typedef struct openfilestruct {
size_t current_x;
/* The file's x-coordinate position. */
size_t placewewant;
/* The file's x position we would like. */
ssize_t current_y;
/* The file's y-coordinate position. */
/* The preferred column for the cursor. */
size_t brink;
/* From which column the edit window is drawn (when panning). */
ssize_t cursor_row;
/* The row in the edit window that the cursor is on. */
struct stat *statinfo;
/* The file's stat information from when it was opened or last saved. */
#ifdef ENABLE_WRAPPING
@@ -574,7 +604,7 @@ typedef struct openfilestruct {
bool softmark;
/* Whether a marked region was made by holding Shift. */
format_type fmt;
/* The file's format -- Unix or DOS or Mac. */
/* The file's format -- Unix or DOS. */
char *lock_filename;
/* The path of the lockfile, if we created one. */
undostruct *undotop;

File diff suppressed because it is too large Load Diff

158
src/folding.c Normal file
View File

@@ -0,0 +1,158 @@
/**************************************************************************
* folding.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2023 rexy712 *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, either version 3 of the License, *
* or (at your option) any later version. *
* *
* GNU nano is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty *
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
#include "prototypes.h"
#include <string.h>
#ifdef ENABLE_FOLDING
/* Unfold a folded segment containing the given line. */
void unfold_folded_segment(linestruct *line)
{
line = get_start_of_folded_segment(line);
if (line != NULL)
refresh_needed = TRUE;
for (; line != NULL && line->folded; line = line->next)
line->folded = FALSE;
}
/* Get the first line of the folded segment. */
linestruct *get_start_of_folded_segment(linestruct *line)
{
if (!line->folded)
return line;
while (line->prev != NULL && line->prev->folded)
line = line->prev;
return line;
}
/* Get the last line of the folded segment. */
linestruct *get_end_of_folded_segment(linestruct *line)
{
if (!line->folded)
return line;
while (line->next != NULL && line->next->folded)
line = line->next;
return line;
}
/* Get the number of lines in a folded segment. */
int get_folded_segment_length(linestruct *line)
{
int i = 1;
if (!line->folded)
return 0;
line = get_start_of_folded_segment(line);
for (; line->next != NULL && line->next->folded; line = line->next)
++i;
return i;
}
/* Unfolds a folded segment containing line, or if line is not folded
* does nothing. Returns true if any segments are unfolded. */
bool do_unfold_segment(linestruct *line)
{
/* If current line is folded, just unfold and finish. */
if (line->folded) {
unfold_folded_segment(line);
return TRUE;
}
/* If all else fails, attempt to find the next folded line in the file. */
for (line = openfile->current; line != NULL; line = line->next) {
if (line->folded) {
unfold_folded_segment(line);
openfile->current = line;
if (line->prev)
do_up();
else
move_cursor_to_proper_column();
return TRUE;
}
}
return FALSE;
}
/* Fold the currently selected lines unless the current line is
* a folded lines. In that case, remove unfold the lines. */
void do_fold_segment(void)
{
linestruct *top, *bot, *line;
get_range(&top, &bot);
size_t top_pos, bot_pos;
bool region_found = (top != bot);
if (top == bot) {
/* First try to unfold if this line/bracketed region is folded. */
if (top->folded) {
unfold_folded_segment(top);
return;
}
/* When no selection is made, attempt to find the next line
* ending with an opening bracket as the top bound. */
for (; find_terminus_of_bracketed_region(&top, &top_pos, get_matchbrackets_halfway(), FALSE)
; top = top->next) {
bot = top;
bot_pos = top_pos;
if (find_matching_bracket_pos(&bot, &bot_pos) == FOUND_BRACKET
&& bot->lineno - top->lineno >= 2) {
top = top->next;
bot = bot->prev;
/* Unfold if already folded. */
region_found = !top->folded;
break;
}
}
}
if (region_found == TRUE) {
for (line = top; line != bot->next; line = line->next)
line->folded = TRUE;
/* Place the cursor after the new fold, accounting for possible
* fold concatenations occurring. */
openfile->current = get_end_of_folded_segment(bot);
if (bot->next)
do_down();
else
move_cursor_to_proper_column();
if (top->lineno < openfile->edittop->lineno &&
bot->lineno > openfile->edittop->lineno)
openfile->edittop = top;
openfile->mark = NULL;
refresh_needed = TRUE;
} else
if (!do_unfold_segment(openfile->current))
statusline(AHEM, _("No valid region found for automatic fold"));
}
#endif /* ENABLE_FOLDING */

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* global.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2022 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2026 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,15 +24,20 @@
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <term.h>
/* Global variables. */
#ifndef NANO_TINY
volatile sig_atomic_t the_window_resized = FALSE;
/* Set to TRUE by the handler whenever a SIGWINCH occurs. */
volatile sig_atomic_t resized_for_browser = FALSE;
/* Same as above, but used by the file browser. */
#endif
bool on_a_vt = FALSE;
/* Whether we're running on a Linux console (a VT). */
bool using_utf8 = FALSE;
/* Whether we're in a UTF-8 locale. */
bool shifted_metas = FALSE;
/* Whether any Sh-M-<letter> combo has been bound. */
@@ -42,8 +47,6 @@ bool shift_held;
/* Whether Shift was being held together with a movement key. */
bool mute_modifiers = FALSE;
/* Whether to ignore modifier keys while running a macro or string bind. */
bool bracketed_paste = FALSE;
/* Whether text is being pasted into nano from outside. */
bool we_are_running = FALSE;
/* Becomes TRUE as soon as all options and files have been read. */
@@ -51,8 +54,16 @@ bool more_than_one = FALSE;
/* Whether more than one buffer is or has been open. */
bool report_size = TRUE;
/* Whether to show the number of lines when the minibar is used. */
bool ran_a_tool = FALSE;
/* Whether a tool has been run at the Execute-Command prompt. */
#ifndef NANO_TINY
char *foretext = NULL;
/* What was typed at the Execute prompt before invoking a tool. */
#endif
int final_status = 0;
/* The status value that nano returns upon exit. */
bool inhelp = FALSE;
/* Whether we are in the help viewer. */
@@ -62,6 +73,8 @@ char *title = NULL;
bool refresh_needed = FALSE;
/* Did a command mangle enough of the buffer that we should
* repaint the screen? */
bool united_sidescroll = TRUE;
/* Whether to scroll all lines sideways. That is: whether to pan. */
bool focusing = TRUE;
/* Whether an update of the edit window should center the cursor. */
@@ -99,11 +112,11 @@ int controlleft, controlright, controlup, controldown;
int controlhome, controlend;
#ifndef NANO_TINY
int controldelete, controlshiftdelete;
int shiftleft, shiftright, shiftup, shiftdown;
int shiftup, shiftdown;
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
int shiftcontrolhome, shiftcontrolend;
int altleft, altright, altup, altdown;
int altpageup, altpagedown;
int althome, altend, altpageup, altpagedown;
int altinsert, altdelete;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif
@@ -131,13 +144,16 @@ int editwincols = -1;
/* The number of usable columns in the edit window: COLS - margin. */
int margin = 0;
/* The amount of space reserved at the left for line numbers. */
int thebar = 0;
/* Becomes 1 when a scrollbar is shown. */
int sidebar = 0;
/* Becomes 1 when the indicator "scroll bar" must be shown. */
#ifndef NANO_TINY
int *bardata = NULL;
/* An array of characters that together depict the scrollbar. */
ssize_t stripe_column = 0;
/* The column at which a vertical bar will be drawn. */
int cycling_aim = 0;
/* Whether to center the line with the cursor (0), push it
* to the top of the viewport (1), or to the bottom (2). */
#endif
linestruct *cutbuffer = NULL;
@@ -306,7 +322,6 @@ void goto_dir(void) {;}
void do_nothing(void) {;}
void do_toggle(void) {;}
void dos_format(void) {;}
void mac_format(void) {;}
void append_it(void) {;}
void prepend_it(void) {;}
void back_it_up(void) {;}
@@ -361,10 +376,26 @@ int keycode_from_string(const char *keystring)
else
return -1;
} else if (keystring[0] == 'M') {
if (keystring[1] == '-' && keystring[3] == '\0')
return tolower((unsigned char)keystring[2]);
if (keystring[1] == '-' && keystring[3] == '\0') {
if ('A' <= keystring[2] && keystring[2] <= 'Z')
return (keystring[2] | 0x20);
else
return keystring[2];
}
if (strcasecmp(keystring, "M-Space") == 0)
return (int)' ';
else if (strcasecmp(keystring, "M-Left") == 0)
return ALT_LEFT;
else if (strcasecmp(keystring, "M-Right") == 0)
return ALT_RIGHT;
else if (strcasecmp(keystring, "M-Up") == 0)
return ALT_UP;
else if (strcasecmp(keystring, "M-Down") == 0)
return ALT_DOWN;
else if (strcasecmp(keystring, "M-Ins") == 0)
return ALT_INSERT;
else if (strcasecmp(keystring, "M-Del") == 0)
return ALT_DELETE;
else
return -1;
#ifdef ENABLE_NANORC
@@ -387,6 +418,15 @@ int keycode_from_string(const char *keystring)
return -1;
}
#if defined(ENABLE_EXTRA) && defined(NCURSES_VERSION_PATCH)
/* Report the version of ncurses that nano is linked against. */
void show_curses_version(void)
{
statusline(NOTICE, "ncurses-%i.%i, patch %li", NCURSES_VERSION_MAJOR,
NCURSES_VERSION_MINOR, NCURSES_VERSION_PATCH);
}
#endif
/* Add a key combo to the linked list of shortcuts. */
void add_to_sclist(int menus, const char *scstring, const int keycode,
void (*function)(void), int toggle)
@@ -437,15 +477,14 @@ size_t shown_entries_for(int menu)
size_t maximum = ((COLS + 40) / 20) * 2;
size_t count = 0;
while (count < maximum && item != NULL) {
while (count < maximum && item) {
if (item->menus & menu)
count++;
item = item->next;
}
/* When --saveonexit is not used, widen the grid of the WriteOut menu. */
if (menu == MWRITEFILE && item == NULL &&
first_sc_for(menu, discard_buffer) == NULL)
if (menu == MWRITEFILE && item == NULL && first_sc_for(menu, discard_buffer) == NULL)
count--;
return count;
@@ -462,11 +501,6 @@ const keystruct *get_shortcut(const int keycode)
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)
return NULL;
#endif
#ifdef ENABLE_NANORC
if (keycode == PLANTED_A_COMMAND)
return planted_shortcut;
@@ -494,7 +528,7 @@ functionptrtype func_from_key(const int keycode)
* with Pico or to mimic 'less' and similar text viewers. */
functionptrtype interpret(const int keycode)
{
if (!meta_key) {
if (!meta_key && keycode < 0x7F) {
if (keycode == 'N')
return do_findprevious;
if (keycode == 'n')
@@ -560,6 +594,8 @@ void shortcut_init(void)
N_("Search backward for a string or a regular expression");
const char *cut_gist =
N_("Cut current line (or marked region) and store it in cutbuffer");
const char *copy_gist =
N_("Copy current line (or marked region) and store it in cutbuffer");
const char *paste_gist =
N_("Paste the contents of cutbuffer at current cursor position");
const char *cursorpos_gist = N_("Display the position of the cursor");
@@ -569,9 +605,8 @@ void shortcut_init(void)
const char *replace_gist = N_("Replace a string or a regular expression");
const char *gotoline_gist = N_("Go to line and column number");
#ifndef NANO_TINY
const char *bracket_gist = N_("Go to the matching bracket");
const char *mark_gist = N_("Mark text starting from the cursor position");
const char *copy_gist =
N_("Copy current line (or marked region) and store it in cutbuffer");
const char *zap_gist = N_("Throw away the current line (or marked region)");
const char *indent_gist = N_("Indent the current line (or marked lines)");
const char *unindent_gist = N_("Unindent the current line (or marked lines)");
@@ -593,20 +628,26 @@ void shortcut_init(void)
N_("Go to beginning of paragraph; then of previous paragraph");
const char *paraend_gist =
N_("Go just beyond end of paragraph; then of next paragraph");
#endif
#ifndef NANO_TINY
const char *toprow_gist = N_("Go to first row in the viewport");
const char *bottomrow_gist = N_("Go to last row in the viewport");
const char *center_gist = N_("Center the line where the cursor is");
const char *cycle_gist = N_("Push the cursor line to the center, then top, then bottom");
#endif
const char *prevpage_gist = N_("Go one screenful up");
const char *nextpage_gist = N_("Go one screenful down");
const char *firstline_gist = N_("Go to the first line of the file");
const char *lastline_gist = N_("Go to the last line of the file");
#ifndef NANO_TINY
const char *bracket_gist = N_("Go to the matching bracket");
const char *scrollleft_gist = N_("Scroll the viewport a tabsize to the left");
const char *scrollright_gist = N_("Scroll the viewport a tabsize to the right");
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
const char *scrollup_gist =
N_("Scroll up one line without moving the cursor textually");
const char *scrolldown_gist =
N_("Scroll down one line without moving the cursor textually");
const char *center_gist = N_("Center the line where the cursor is");
#endif
#ifdef ENABLE_MULTIBUFFER
const char *prevfile_gist = N_("Switch to the previous file buffer");
@@ -646,6 +687,9 @@ void shortcut_init(void)
const char *savefile_gist = N_("Save file without prompting");
const char *findprev_gist = N_("Search next occurrence backward");
const char *findnext_gist = N_("Search next occurrence forward");
#ifdef ENABLE_FOLDING
const char *fold_gist = N_("Fold/unfold the currently selected lines");
#endif
#ifndef NANO_TINY
const char *recordmacro_gist = N_("Start/stop recording a macro");
const char *runmacro_gist = N_("Run the last recorded macro");
@@ -662,14 +706,17 @@ void shortcut_init(void)
#endif
#ifndef NANO_TINY
const char *dos_gist = N_("Toggle the use of DOS format");
const char *mac_gist = N_("Toggle the use of Mac format");
const char *append_gist = N_("Toggle appending");
const char *prepend_gist = N_("Toggle prepending");
const char *backup_gist = N_("Toggle backing up of the original file");
const char *execute_gist = N_("Execute a function or an external command");
const char *pipe_gist =
N_("Pipe the current buffer (or marked region) to the command");
const char *convert_gist = N_("Do not convert from DOS/Mac format");
#ifdef ENABLE_HISTORIES
const char *older_command_gist = N_("Recall the previous command");
const char *newer_command_gist = N_("Recall the next command");
#endif
const char *convert_gist = N_("Do not convert from DOS format");
#endif
#ifdef ENABLE_MULTIBUFFER
const char *newbuffer_gist = N_("Toggle the use of a new buffer");
@@ -704,6 +751,10 @@ void shortcut_init(void)
#endif
#endif /* ENABLE_HELP */
/* If Backspace is not ^H, then ^H can be used for Help. */
char *bsp_string = tgetstr("kb", NULL);
char *help_key = (bsp_string && *bsp_string != 0x08) ? "^H" : "^N";
#ifdef ENABLE_HELP
#define WHENHELP(description) description
#else
@@ -735,8 +786,6 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(full_refresh, MINSERTFILE|MEXECUTE, "Refresh", "x", 0);
#endif
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,
@@ -770,12 +819,12 @@ void shortcut_init(void)
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MHELP,
N_("Where Was"), WHENHELP(wherewas_gist), TOGETHER);
"Where Was", WHENHELP(wherewas_gist), TOGETHER);
add_to_funcs(do_findprevious, MMAIN|MHELP,
N_("Previous"), WHENHELP(findprev_gist), TOGETHER);
"Previous", WHENHELP(findprev_gist), TOGETHER);
add_to_funcs(do_findnext, MMAIN|MHELP,
N_("Next"), WHENHELP(findnext_gist), BLANKAFTER);
"Next", WHENHELP(findnext_gist), BLANKAFTER);
#endif
add_to_funcs(cut_text, MMAIN,
@@ -808,7 +857,7 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(do_undo, MMAIN,
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
/* TRANSLATORS: Try to keep the next four strings at most 12 characters. */
N_("Undo"), WHENHELP(undo_gist), TOGETHER);
add_to_funcs(do_redo, MMAIN,
N_("Redo"), WHENHELP(redo_gist), BLANKAFTER);
@@ -820,9 +869,10 @@ void shortcut_init(void)
#endif
add_to_funcs(case_sens_void, MWHEREIS|MREPLACE,
N_("Case Sens"), WHENHELP(case_gist), TOGETHER);
/* TRANSLATORS: Try to keep the next four strings at most 16 characters. */
N_("Case sensitive"), WHENHELP(case_gist), TOGETHER);
add_to_funcs(regexp_void, MWHEREIS|MREPLACE,
N_("Reg.exp."), WHENHELP(regexp_gist), TOGETHER);
N_("Reg.expression"), WHENHELP(regexp_gist), TOGETHER);
add_to_funcs(backwards_void, MWHEREIS|MREPLACE,
N_("Backwards"), WHENHELP(reverse_gist), BLANKAFTER);
@@ -833,9 +883,16 @@ void shortcut_init(void)
#ifdef ENABLE_HISTORIES
add_to_funcs(get_older_item, MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE,
/* TRANSLATORS: Try to keep the next two strings at most 10 characters. */
N_("Older"), WHENHELP(older_gist), TOGETHER);
add_to_funcs(get_newer_item, MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE,
N_("Newer"), WHENHELP(newer_gist), BLANKAFTER);
#ifndef NANO_TINY
add_to_funcs(get_older_item, MEXECUTE,
N_("Older"), WHENHELP(older_command_gist), TOGETHER);
add_to_funcs(get_newer_item, MEXECUTE,
N_("Newer"), WHENHELP(newer_command_gist), BLANKAFTER);
#endif
#endif
#ifdef ENABLE_BROWSER
@@ -891,23 +948,32 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(to_prev_word, MMAIN,
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
/* TRANSLATORS: Try to keep the next four strings at most 13 characters. */
N_("Prev Word"), WHENHELP(prevword_gist), TOGETHER);
add_to_funcs(to_next_word, MMAIN,
N_("Next Word"), WHENHELP(nextword_gist), TOGETHER);
#endif
add_to_funcs(do_home, MMAIN,
/* TRANSLATORS: These two mean: "to beginning of line", "to end of line". */
N_("Home"), WHENHELP(home_gist), TOGETHER);
add_to_funcs(do_end, MMAIN,
N_("End"), WHENHELP(end_gist), BLANKAFTER);
N_("End"), WHENHELP(end_gist), TOGETHER);
#ifndef NANO_TINY
add_to_funcs(do_scroll_left, MMAIN,
/* TRANSLATORS: Try to keep the next two strings at most 13 characters. */
N_("Scroll Left"), WHENHELP(scrollleft_gist), TOGETHER);
add_to_funcs(do_scroll_right, MMAIN,
N_("Scroll Right"), WHENHELP(scrollright_gist), BLANKAFTER);
#endif
add_to_funcs(do_up, MMAIN|MBROWSER|MHELP,
/* TRANSLATORS: Try to keep the next two strings at most 10 characters. */
N_("Prev Line"), WHENHELP(prevline_gist), TOGETHER);
add_to_funcs(do_down, MMAIN|MBROWSER|MHELP,
N_("Next Line"), WHENHELP(nextline_gist), TOGETHER);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
add_to_funcs(do_scroll_up, MMAIN,
/* TRANSLATORS: Try to keep the next four strings at most 13 characters. */
N_("Scroll Up"), WHENHELP(scrollup_gist), TOGETHER);
add_to_funcs(do_scroll_down, MMAIN,
N_("Scroll Down"), WHENHELP(scrolldown_gist), BLANKAFTER);
@@ -919,14 +985,21 @@ void shortcut_init(void)
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."), WHENHELP(parabegin_gist), TOGETHER);
/* TRANSLATORS: Try to keep these two strings at most 23 characters. */
N_("Start of Paragraph"), WHENHELP(parabegin_gist), TOGETHER);
add_to_funcs(to_para_end, MMAIN|MGOTOLINE,
N_("End of Paragraph"), WHENHELP(paraend_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(to_top_row, MMAIN,
N_("Top Row"), WHENHELP(toprow_gist), TOGETHER);
add_to_funcs(to_bottom_row, MMAIN,
N_("Bottom Row"), WHENHELP(bottomrow_gist), BLANKAFTER);
#endif
add_to_funcs(do_page_up, MMAIN|MHELP,
/* TRANSLATORS: Try to keep the next six strings at most 12 characters. */
/* TRANSLATORS: Try to keep the next four strings at most 10 characters. */
N_("Prev Page"), WHENHELP(prevpage_gist), TOGETHER);
add_to_funcs(do_page_down, MMAIN|MHELP,
N_("Next Page"), WHENHELP(nextpage_gist), TOGETHER);
@@ -938,6 +1011,7 @@ void shortcut_init(void)
#ifdef ENABLE_MULTIBUFFER
add_to_funcs(switch_to_prev_buffer, MMAIN,
/* TRANSLATORS: Try to keep these two strings at most 14 characters. */
N_("Prev File"), WHENHELP(prevfile_gist), TOGETHER);
add_to_funcs(switch_to_next_buffer, MMAIN,
N_("Next File"), WHENHELP(nextfile_gist), BLANKAFTER);
@@ -977,6 +1051,9 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(count_lines_words_and_characters, MMAIN,
N_("Word Count"), WHENHELP(wordcount_gist), TOGETHER);
#else
add_to_funcs(copy_text, MMAIN,
N_("Copy"), WHENHELP(copy_gist), BLANKAFTER);
#endif
add_to_funcs(do_verbatim_input, MMAIN,
@@ -984,7 +1061,7 @@ void shortcut_init(void)
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
"Where Was", WHENHELP(wherewas_gist), BLANKAFTER);
#else
add_to_funcs(do_indent, MMAIN,
N_("Indent"), WHENHELP(indent_gist), TOGETHER);
@@ -1005,7 +1082,14 @@ void shortcut_init(void)
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
add_to_funcs(run_macro, MMAIN,
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
#endif
#ifdef ENABLE_FOLDING
add_to_funcs(do_fold_segment, MMAIN, N_("Fold"),
WHENHELP(fold_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(zap_text, MMAIN,
/* TRANSLATORS: This refers to deleting a line or marked region. */
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
@@ -1040,11 +1124,13 @@ void shortcut_init(void)
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN,
N_("Refresh"), WHENHELP(refresh_gist), TOGETHER);
N_("Refresh"), WHENHELP(refresh_gist), BLANKAFTER);
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
#ifndef NANO_TINY
add_to_funcs(do_center, MMAIN,
N_("Center"), WHENHELP(center_gist), BLANKAFTER);
N_("Center"), WHENHELP(center_gist), TOGETHER);
add_to_funcs(do_cycle, MMAIN,
N_("Cycle"), WHENHELP(cycle_gist), BLANKAFTER);
#endif
add_to_funcs(do_savefile, MMAIN,
@@ -1062,6 +1148,7 @@ void shortcut_init(void)
#endif
#ifdef ENABLE_SPELLER
add_to_funcs(do_spell, MEXECUTE,
/* TRANSLATORS: Try to keep the next four strings at most 10 characters. */
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif
#ifdef ENABLE_LINTER
@@ -1077,31 +1164,22 @@ void shortcut_init(void)
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"), WHENHELP(whereis_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(dos_format, MWRITEFILE,
N_("DOS Format"), WHENHELP(dos_gist), TOGETHER);
add_to_funcs(mac_format, MWRITEFILE,
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
* reduplicating the current file, and the third is not allowed as it
* would write to a file not specified on the command line. */
if (!ISSET(RESTRICTED)) {
add_to_funcs(back_it_up, MWRITEFILE,
N_("Backup File"), WHENHELP(backup_gist), TOGETHER);
add_to_funcs(append_it, MWRITEFILE,
N_("Append"), WHENHELP(append_gist), TOGETHER);
add_to_funcs(prepend_it, MWRITEFILE,
N_("Prepend"), WHENHELP(prepend_gist), TOGETHER);
add_to_funcs(back_it_up, MWRITEFILE,
N_("Backup File"), WHENHELP(backup_gist), BLANKAFTER);
N_("Prepend"), WHENHELP(prepend_gist), BLANKAFTER);
}
add_to_funcs(flip_convert, MINSERTFILE,
@@ -1119,6 +1197,9 @@ void shortcut_init(void)
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
#endif /* !NANO_TINY */
add_to_funcs(discard_buffer, MWRITEFILE,
N_("Discard buffer"), WHENHELP(discardbuffer_gist), BLANKAFTER);
#ifdef ENABLE_BROWSER
/* The file browser is only available when not in restricted mode. */
if (!ISSET(RESTRICTED))
@@ -1148,9 +1229,6 @@ void shortcut_init(void)
#endif
#endif /* ENABLE_BROWSER */
add_to_funcs(discard_buffer, MWRITEFILE,
N_("Discard buffer"), WHENHELP(discardbuffer_gist), BLANKAFTER);
#ifdef ENABLE_LINTER
add_to_funcs(do_page_up, MLINTER,
/* TRANSLATORS: The next two strings may be up to 37 characters each. */
@@ -1168,34 +1246,69 @@ void shortcut_init(void)
/* Link key combos to functions in certain menus. */
add_to_sclist(MMOST|MBROWSER, "^M", '\r', do_enter, 0);
add_to_sclist(MMOST|MBROWSER, "Enter", KEY_ENTER, do_enter, 0);
add_to_sclist(MMOST, "^H", '\b', do_backspace, 0);
add_to_sclist(MMOST, "Bsp", KEY_BACKSPACE, do_backspace, 0);
add_to_sclist(MMOST, "Sh-Del", SHIFT_DELETE, do_backspace, 0);
add_to_sclist(MMOST, "^D", 0, do_delete, 0);
add_to_sclist(MMOST, "Del", KEY_DC, do_delete, 0);
add_to_sclist(MMOST, "^I", '\t', do_tab, 0);
add_to_sclist(MMOST, "Tab", '\t', do_tab, 0);
add_to_sclist((MMOST|MBROWSER) & ~MFINDINHELP, "^G", 0, do_help, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^X", 0, do_exit, 0);
if (!ISSET(PRESERVE))
add_to_sclist(MMAIN|MBROWSER|MHELP, "^B", 0, do_search_backward, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^F", 0, do_search_forward, 0);
if (ISSET(MODERN_BINDINGS)) {
add_to_sclist((MMOST|MBROWSER) & ~MFINDINHELP, help_key, 0, do_help, 0);
add_to_sclist(MHELP, help_key, 0, do_exit, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^Q", 0, do_exit, 0);
add_to_sclist(MMAIN, "^S", 0, do_savefile, 0);
add_to_sclist(MMAIN, "^O", 0, do_writeout, 0);
add_to_sclist(MMAIN, "^R", 0, do_insertfile, 0);
add_to_sclist(MMAIN, "^W", 0, do_writeout, 0);
add_to_sclist(MMAIN, "^O", 0, do_insertfile, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^D", 0, do_findprevious, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^G", 0, do_findnext, 0);
add_to_sclist(MMAIN, "^R", 0, do_replace, 0);
add_to_sclist(MMAIN, "^T", 0, do_gotolinecolumn, 0);
add_to_sclist(MMAIN, "^P", 0, report_cursor_position, 0);
#ifndef NANO_TINY
add_to_sclist(MMAIN, "^Z", 0, do_undo, 0);
add_to_sclist(MMAIN, "^Y", 0, do_redo, 0);
add_to_sclist(MMAIN, "^A", 0, do_mark, 0);
#endif
add_to_sclist(MMAIN, "^X", 0, cut_text, 0);
add_to_sclist(MMAIN, "^C", 0, copy_text, 0);
add_to_sclist(MMAIN, "^V", 0, paste_text, 0);
} else {
add_to_sclist((MMOST|MBROWSER) & ~MFINDINHELP, "^G", 0, do_help, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^X", 0, do_exit, 0);
if (!ISSET(PRESERVE))
add_to_sclist(MMAIN, "^S", 0, do_savefile, 0);
add_to_sclist(MMAIN, "^O", 0, do_writeout, 0);
add_to_sclist(MMAIN, "^R", 0, do_insertfile, 0);
if (!ISSET(PRESERVE))
add_to_sclist(MMAIN|MBROWSER|MHELP, "^Q", 0, do_search_backward, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^W", 0, do_search_forward, 0);
add_to_sclist(MMOST, "^A", 0, do_home, 0);
add_to_sclist(MMOST, "^E", 0, do_end, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^P", 0, do_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^N", 0, do_down, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "^Y", 0, do_page_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "^V", 0, do_page_down, 0);
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
add_to_sclist(MMOST, "^H", '\b', do_backspace, 0);
add_to_sclist(MMOST, "^D", 0, do_delete, 0);
}
add_to_sclist(MMOST, "Bsp", KEY_BACKSPACE, do_backspace, 0);
add_to_sclist(MMOST, "Sh-Del", SHIFT_DELETE, do_backspace, 0);
add_to_sclist(MMOST, "Del", KEY_DC, do_delete, 0);
add_to_sclist(MMAIN, "Ins", KEY_IC, do_insertfile, 0);
if (!ISSET(PRESERVE))
add_to_sclist(MMAIN|MBROWSER|MHELP, "^Q", 0, do_search_backward, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^W", 0, do_search_forward, 0);
add_to_sclist(MMAIN, "^\\", 0, do_replace, 0);
add_to_sclist(MMAIN, "M-R", 0, do_replace, 0);
add_to_sclist(MMOST, "^K", 0, cut_text, 0);
#ifdef NANO_TINY
add_to_sclist(MMAIN, "M-6", 0, copy_text, 0);
add_to_sclist(MMAIN, "M-^", 0, copy_text, 0);
add_to_sclist(MMAIN, "^U", 0, paste_text, 0);
#ifdef ENABLE_SPELLER
add_to_sclist(MMAIN, "^T", 0, do_spell, 0);
add_to_sclist(MMAIN, ISSET(MODERN_BINDINGS) ? "^E" : "^T", 0, do_spell, 0);
#endif
#else
add_to_sclist(MMOST, "M-6", 0, copy_text, 0);
add_to_sclist(MMOST, "M-^", 0, copy_text, 0);
add_to_sclist(MMOST, "^U", 0, paste_text, 0);
add_to_sclist(MMAIN, "^T", 0, do_execute, 0);
add_to_sclist(MMAIN, ISSET(MODERN_BINDINGS) ? "^E" : "^T", 0, do_execute, 0);
#ifdef ENABLE_SPELLER
if (!ISSET(PRESERVE))
add_to_sclist(MEXECUTE, "^S", 0, do_spell, 0);
@@ -1206,20 +1319,18 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "^J", '\n', do_justify, 0);
#endif
#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
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
#ifdef ENABLE_FOLDING
add_to_sclist(MMAIN, "M-[", 0, do_fold_segment, 0);
#endif
add_to_sclist(MMAIN, SLASH_OR_DASH, 0, do_gotolinecolumn, 0);
add_to_sclist(MMAIN, "M-G", 0, do_gotolinecolumn, 0);
add_to_sclist(MMAIN, "^_", 0, do_gotolinecolumn, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "^Y", 0, do_page_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "PgUp", KEY_PPAGE, do_page_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "^V", 0, do_page_down, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP|MLINTER, "PgDn", KEY_NPAGE, do_page_down, 0);
add_to_sclist(MBROWSER|MHELP, "Bsp", KEY_BACKSPACE, do_page_up, 0);
add_to_sclist(MBROWSER|MHELP, "Sh-Del", SHIFT_DELETE, do_page_up, 0);
@@ -1228,26 +1339,23 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP, "^Home", CONTROL_HOME, to_first_line, 0);
add_to_sclist(MMAIN|MHELP, "M-/", 0, to_last_line, 0);
add_to_sclist(MMAIN|MHELP, "^End", CONTROL_END, to_last_line, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "M-B", 0, do_findprevious, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "M-F", 0, do_findnext, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "M-W", 0, do_findnext, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "M-Q", 0, do_findprevious, 0);
#ifdef NANO_TINY
#ifdef ENABLE_LINENUMBERS
add_to_sclist(MMAIN, "M-N", 0, toggle_numbers, 0);
#else
add_to_sclist(MMAIN, "M-B", 0, to_prev_word, 0);
add_to_sclist(MMAIN, "M-N", 0, to_next_word, 0);
#endif
add_to_sclist(MMAIN, "M-D", 0, to_prev_word, 0);
add_to_sclist(MMAIN, "M-F", 0, to_next_word, 0);
#else
add_to_sclist(MMAIN, "M-]", 0, do_find_bracket, 0);
add_to_sclist(MMAIN, "M-A", 0, do_mark, 0);
add_to_sclist(MMAIN, "^6", 0, do_mark, 0);
add_to_sclist(MMAIN, "^^", 0, do_mark, 0);
add_to_sclist(MMOST, "M-6", 0, copy_text, 0);
add_to_sclist(MMOST, "M-^", 0, copy_text, 0);
add_to_sclist(MMAIN, "M-}", 0, do_indent, 0);
add_to_sclist(MMAIN, "", INDENT_KEY, do_indent, 0);
add_to_sclist(MMAIN, "M-{", 0, do_unindent, 0);
add_to_sclist(MMAIN, "Sh-Tab", SHIFT_TAB, do_unindent, 0);
add_to_sclist(MMAIN, "M-:", 0, record_macro, 0);
@@ -1259,8 +1367,12 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "^Del", CONTROL_DELETE, chop_next_word, 0);
add_to_sclist(MMAIN, "M-Del", ALT_DELETE, zap_text, 0);
add_to_sclist(MMAIN, "M-Ins", ALT_INSERT, put_or_lift_anchor, 0);
add_to_sclist(MMAIN, "M-Home", ALT_HOME, to_top_row, 0);
add_to_sclist(MMAIN, "M-End", ALT_END, to_bottom_row, 0);
add_to_sclist(MMAIN, "M-PgUp", ALT_PAGEUP, to_prev_anchor, 0);
add_to_sclist(MMAIN, "M-PgDn", ALT_PAGEDOWN, to_next_anchor, 0);
add_to_sclist(MMAIN, "M-\"", 0, put_or_lift_anchor, 0);
add_to_sclist(MMAIN, "M-'", 0, to_next_anchor, 0);
#endif
#ifdef ENABLE_WORDCOMPLETION
add_to_sclist(MMAIN, "^]", 0, complete_a_word, 0);
@@ -1268,10 +1380,10 @@ void shortcut_init(void)
#ifdef ENABLE_COMMENT
add_to_sclist(MMAIN, "M-3", 0, do_comment, 0);
#endif
add_to_sclist(MMOST|MBROWSER, "^B", 0, do_left, 0);
add_to_sclist(MMOST|MBROWSER, "^F", 0, do_right, 0);
add_to_sclist(MMOST & ~MMAIN, "^B", 0, do_left, 0);
add_to_sclist(MMOST & ~MMAIN, "^F", 0, do_right, 0);
#ifdef ENABLE_UTF8
if (using_utf8()) {
if (using_utf8) {
add_to_sclist(MMOST|MBROWSER|MHELP, "\xE2\x97\x82", KEY_LEFT, do_left, 0);
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);
@@ -1298,14 +1410,10 @@ void shortcut_init(void)
}
add_to_sclist(MMOST, "M-Space", 0, to_prev_word, 0);
add_to_sclist(MMOST, "^Space", 0, to_next_word, 0);
add_to_sclist(MMOST, "^A", 0, do_home, 0);
add_to_sclist(MMOST, "Home", KEY_HOME, do_home, 0);
add_to_sclist(MMOST, "^E", 0, do_end, 0);
add_to_sclist(MMOST, "End", KEY_END, do_end, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^P", 0, do_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "^N", 0, do_down, 0);
#ifdef ENABLE_UTF8
if (using_utf8()) {
if (using_utf8) {
add_to_sclist(MMAIN|MBROWSER|MHELP, "\xE2\x96\xb4", KEY_UP, do_up, 0);
add_to_sclist(MMAIN|MBROWSER|MHELP, "\xE2\x96\xbe", KEY_DOWN, do_down, 0);
add_to_sclist(MMAIN|MBROWSER|MLINTER, "^\xE2\x96\xb4", CONTROL_UP, to_prev_block, 0);
@@ -1328,7 +1436,7 @@ void shortcut_init(void)
#endif
#ifndef NANO_TINY
#ifdef ENABLE_UTF8
if (using_utf8()) {
if (using_utf8) {
add_to_sclist(MMAIN|MHELP, "M-\xE2\x96\xb4", ALT_UP, do_scroll_up, 0);
add_to_sclist(MMAIN|MHELP, "M-\xE2\x96\xbe", ALT_DOWN, do_scroll_down, 0);
} else
@@ -1346,9 +1454,7 @@ void shortcut_init(void)
#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_next_buffer, 0);
#endif
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
#ifndef NANO_TINY
@@ -1364,13 +1470,15 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "M-J", 0, do_full_justify, 0);
add_to_sclist(MEXECUTE, "^J", 0, do_full_justify, 0);
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
#ifndef NANO_TINY
add_to_sclist(MMAIN, "M-<", 0, do_scroll_left, 0);
add_to_sclist(MMAIN, "M->", 0, do_scroll_right, 0);
add_to_sclist(MMAIN, "^L", 0, do_center, 0);
add_to_sclist(MMAIN, "M-%", 0, do_cycle, 0);
add_to_sclist((MMOST|MBROWSER|MHELP|MYESNO)&~MMAIN, "^L", 0, full_refresh, 0);
#else
add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "^L", 0, full_refresh, 0);
#endif
if (!ISSET(PRESERVE))
add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "^L", 0, full_refresh, 0);
else
add_to_sclist(MMOST|MBROWSER|MYESNO, "^L", 0, full_refresh, 0);
#ifndef NANO_TINY
/* Group of "Appearance" toggles. */
@@ -1407,13 +1515,13 @@ void shortcut_init(void)
add_to_sclist(MWHEREIS|MREPLACE, "M-R", 0, regexp_void, 0);
add_to_sclist(MWHEREIS|MREPLACE, "M-B", 0, backwards_void, 0);
add_to_sclist(MWHEREIS|MREPLACE, "^R", 0, flip_replace, 0);
/* Add this blind keystroke for long-time users. */
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);
#ifdef ENABLE_UTF8
if (using_utf8()) {
if (using_utf8) {
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "\xE2\x96\xb4", KEY_UP, get_older_item, 0);
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "\xE2\x96\xbe", KEY_DOWN, get_newer_item, 0);
} else
@@ -1443,17 +1551,16 @@ void shortcut_init(void)
add_to_sclist(MBROWSER, "M-G", 0, goto_dir, 0);
add_to_sclist(MBROWSER, "^_", 0, goto_dir, 0);
#endif
if (ISSET(SAVE_ON_EXIT) && !ISSET(PRESERVE))
if (!ISSET(PRESERVE))
add_to_sclist(MWRITEFILE, "^Q", 0, discard_buffer, 0);
#ifndef NANO_TINY
add_to_sclist(MWRITEFILE, "M-D", 0, dos_format, 0);
add_to_sclist(MWRITEFILE, "M-M", 0, mac_format, 0);
/* Only when not in restricted mode, allow Appending, Prepending,
* making backups, and executing a command. */
/* Only when not in restricted mode, allow making backups,
* appending, prepending, and executing a command. */
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
add_to_sclist(MWRITEFILE, "M-B", 0, back_it_up, 0);
add_to_sclist(MWRITEFILE, "M-A", 0, append_it, 0);
add_to_sclist(MWRITEFILE, "M-P", 0, prepend_it, 0);
add_to_sclist(MWRITEFILE, "M-B", 0, back_it_up, 0);
add_to_sclist(MINSERTFILE|MEXECUTE, "^X", 0, flip_execute, 0);
}
add_to_sclist(MINSERTFILE, "M-N", 0, flip_convert, 0);
@@ -1500,11 +1607,16 @@ void shortcut_init(void)
#ifdef ENABLE_SPELLER
add_to_sclist(MMAIN, "F12", KEY_F(12), do_spell, 0);
#endif
#if defined(ENABLE_EXTRA) && defined(NCURSES_VERSION_PATCH)
add_to_sclist(MMAIN, "M-&", 0, show_curses_version, 0);
#endif
#ifndef NANO_TINY
add_to_sclist((MMOST & ~MMAIN) | MYESNO, "", KEY_CANCEL, do_cancel, 0);
add_to_sclist(MMAIN, "", KEY_CENTER, do_center, 0);
add_to_sclist(MMAIN, "", KEY_SIC, do_insertfile, 0);
/* Catch and ignore bracketed paste marker keys. */
add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "", BRACKETED_PASTE_MARKER, do_nothing, 0);
add_to_sclist(MMAIN, "", START_OF_PASTE, suck_up_input_and_paste_it, 0);
add_to_sclist(MMOST, "", START_OF_PASTE, do_nothing, 0);
add_to_sclist(MMOST, "", END_OF_PASTE, do_nothing, 0);
#else
add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "", KEY_FRESH, full_refresh, 0);
#endif

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* help.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2000-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2000-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2017 Rishabh Dave *
* Copyright (C) 2014-2019 Benno Schulenberg *
* *
@@ -16,7 +16,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -67,8 +67,8 @@ void help_init(void)
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");
"Type the characters that should replace what 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;
@@ -150,16 +150,14 @@ void help_init(void)
#endif /* ENABLE_BROWSER */
#ifdef ENABLE_SPELLER
else if (currmenu == MSPELL) {
htx[0] = N_("Spell Check Help Text\n\n "
"The spell checker checks the spelling of all text in "
"the current file. When an unknown word is "
"encountered, it is highlighted and a replacement can "
"be edited. It will then prompt to replace every "
"instance of the given misspelled word in the current "
"file, or, if you have selected text with the mark, in "
"the selected text.\n\n The following function keys "
"are available in Spell Check mode:\n\n");
htx[1] = NULL;
htx[0] = N_("=== Spelling correction ===\n\n "
"The spell checker has examined the spelling of all text "
"in the current buffer or marked region. An unknown word "
"has been encountered -- it is highlighted and a replacement "
"can now be edited. After this you will be asked whether "
"to replace each instance of that unknown word.\n\n");
htx[1] = N_(" The following function keys "
"are available at this prompt:\n\n");
htx[2] = NULL;
}
#endif /* ENABLE_SPELLER */
@@ -215,15 +213,15 @@ void help_init(void)
}
htx[0] = _(htx[0]);
if (htx[1] != NULL)
if (htx[1])
htx[1] = _(htx[1]);
if (htx[2] != NULL)
if (htx[2])
htx[2] = _(htx[2]);
allocsize += strlen(htx[0]);
if (htx[1] != NULL)
if (htx[1])
allocsize += strlen(htx[1]);
if (htx[2] != NULL)
if (htx[2])
allocsize += strlen(htx[2]);
/* Calculate the length of the descriptions of the shortcuts.
@@ -251,9 +249,9 @@ void help_init(void)
/* Now add the text we want. */
strcpy(help_text, htx[0]);
if (htx[1] != NULL)
if (htx[1])
strcat(help_text, htx[1]);
if (htx[2] != NULL)
if (htx[2])
strcat(help_text, htx[2]);
/* Remember this end-of-introduction, start-of-shortcuts. */
@@ -274,10 +272,10 @@ void help_init(void)
if (++tally == 1) {
sprintf(ptr, "%s ", s->keystr);
/* Unicode arrows take three bytes instead of one. */
ptr += (strstr(s->keystr, "\xE2") != NULL ? 9 : 7);
ptr += (strstr(s->keystr, "\xE2") ? 9 : 7);
} else {
sprintf(ptr, "(%s) ", s->keystr);
ptr += (strstr(s->keystr, "\xE2") != NULL ? 12 : 10);
ptr += (strstr(s->keystr, "\xE2") ? 12 : 10);
break;
}
}
@@ -325,7 +323,7 @@ void help_init(void)
void wrap_help_text_into_buffer(void)
{
/* Avoid overtight and overwide paragraphs in the introductory text. */
size_t wrapping_point = ((COLS < 40) ? 40 : (COLS > 74) ? 74 : COLS) - thebar;
size_t wrapping_point = ((COLS < 40) ? 40 : (COLS > 74) ? 74 : COLS) - sidebar;
const char *ptr = start_of_body;
size_t sum = 0;
@@ -339,12 +337,12 @@ void wrap_help_text_into_buffer(void)
}
/* Copy the help text into the just-created new buffer. */
while (*ptr != '\0') {
while (*ptr) {
int length, shim;
char *oneline;
if (ptr == end_of_intro)
wrapping_point = ((COLS < 40) ? 40 : COLS) - thebar;
wrapping_point = ((COLS < 40) ? 40 : COLS) - sidebar;
if (ptr < end_of_intro || *(ptr - 1) == '\n') {
length = break_line(ptr, wrapping_point, TRUE);
@@ -352,7 +350,7 @@ void wrap_help_text_into_buffer(void)
shim = (*(ptr + length - 1) == ' ') ? 0 : 1;
snprintf(oneline, length + shim, "%s", ptr);
} else {
length = break_line(ptr, ((COLS < 40) ? 22 : COLS - 18) - thebar, TRUE);
length = break_line(ptr, ((COLS < 40) ? 22 : COLS - 18) - sidebar, TRUE);
oneline = nmalloc(length + 5);
snprintf(oneline, length + 5, "\t\t %s", ptr);
}
@@ -404,10 +402,13 @@ void show_help(void)
int was_margin = margin;
#endif
ssize_t was_tabsize = tabsize;
#ifndef NANO_TINY
bool was_lighted = spotlighted;
#endif
#ifdef ENABLE_COLOR
char *was_syntax = syntaxstr;
#endif
char *saved_answer = (answer != NULL) ? copy_of(answer) : NULL;
char *saved_answer = (answer) ? copy_of(answer) : NULL;
/* The current answer when the user invokes help at the prompt. */
unsigned stash[sizeof(flags) / sizeof(flags[0])];
/* A storage place for the current flag settings. */
@@ -433,10 +434,13 @@ void show_help(void)
UNSET(WHITESPACE_DISPLAY);
#ifdef ENABLE_LINENUMBERS
editwincols = COLS - thebar;
editwincols = COLS - sidebar;
margin = 0;
#endif
tabsize = 8;
#ifndef NANO_TINY
spotlighted = FALSE;
#endif
#ifdef ENABLE_COLOR
syntaxstr = "nanohelp";
#endif
@@ -476,18 +480,11 @@ void show_help(void)
#ifndef NANO_TINY
spotlighted = FALSE;
if (bracketed_paste || kbinput == BRACKETED_PASTE_MARKER) {
beep();
continue;
}
#endif
function = interpret(kbinput);
if (function == full_refresh) {
full_refresh();
} else if (ISSET(SHOW_CURSOR) && (function == do_left || function == do_right ||
function == do_up || function == do_down)) {
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();
@@ -508,12 +505,18 @@ void show_help(void)
#ifdef ENABLE_MOUSE
} else if (kbinput == KEY_MOUSE) {
int dummy_row, dummy_col;
get_mouseinput(&dummy_row, &dummy_col, TRUE);
get_mouseinput(&dummy_row, &dummy_col);
#endif
#ifndef NANO_TINY
} else if (kbinput == KEY_WINCH) {
} else if (kbinput == START_OF_PASTE) {
while (get_kbinput(midwin, BLIND) != END_OF_PASTE)
;
statusline(AHEM, _("Paste is ignored"));
} else if (kbinput == THE_WINDOW_RESIZED) {
; /* Nothing to do. */
#endif
} else if (function == full_refresh) {
full_refresh();
} else if (function == do_exit) {
break;
} else
@@ -539,9 +542,12 @@ void show_help(void)
#ifdef ENABLE_LINENUMBERS
margin = was_margin;
editwincols = COLS - margin - thebar;
editwincols = COLS - margin - sidebar;
#endif
tabsize = was_tabsize;
#ifndef NANO_TINY
spotlighted = was_lighted;
#endif
#ifdef ENABLE_COLOR
syntaxstr = was_syntax;
have_palette = FALSE;
@@ -564,7 +570,7 @@ void show_help(void)
bottombars(oldmenu);
#ifdef ENABLE_BROWSER
if (oldmenu & (MBROWSER|MWHEREISFILE|MGOTODIR))
if (oldmenu & (MBROWSER|MGOTODIR|MWHEREISFILE))
browser_refresh();
else
#endif

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* history.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2003-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019 Benno Schulenberg *
* Copyright (C) 2003-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019, 2025 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -36,12 +36,12 @@
static bool history_changed = FALSE;
/* Whether any of the history lists has changed. */
static char *poshistname = NULL;
/* The name of the positions-history file. */
static char *registername = NULL;
/* The name of the positions-register file. */
static time_t latest_timestamp = 942927132;
/* The last time the positions-history file was written. */
static poshiststruct *position_history = NULL;
/* The list of filenames with their last cursor positions. */
/* The last time the positions-register file was written. */
static positionstruct *positions_register = NULL;
/* A list of recently opened files with their last cursor position. */
/* Initialize the lists of historical search and replace strings
* and the list of historical executed commands. */
@@ -114,29 +114,30 @@ void update_history(linestruct **item, const char *text, bool avoid_duplicates)
/* If an identical string was found, delete that item. */
if (thesame) {
linestruct *after = thesame->next;
/* If the string is at the head of the list, move the head. */
if (thesame == *htop)
*htop = after;
*htop = thesame->next;
else
thesame->prev->next = thesame->next;
thesame->next->prev = thesame->prev;
unlink_node(thesame);
renumber_from(after);
free(thesame->data);
free(thesame);
(*hbot)->lineno--;
}
/* If the history is full, delete the oldest item (the one at the
* head of the list), to make room for a new item at the end. */
if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
linestruct *oldest = *htop;
if ((*hbot)->lineno > MAX_SEARCH_HISTORY) {
*htop = (*htop)->next;
unlink_node(oldest);
renumber_from(*htop);
free((*htop)->prev->data);
free((*htop)->prev);
(*htop)->prev = NULL;
(*hbot)->lineno--;
}
/* Store the fresh string in the last item, then create a new item. */
(*hbot)->data = mallocstrcpy((*hbot)->data, text);
splice_node(*hbot, make_new_node(*hbot));
(*hbot)->next = make_new_node(*hbot);
*hbot = (*hbot)->next;
(*hbot)->data = copy_of("");
@@ -172,7 +173,7 @@ char *get_history_completion(linestruct **here, char *string, size_t len)
* for a match of len characters. Skip over an exact match. */
item = find_in_history((*here)->prev, htop, string, len);
while (item != NULL && strcmp(item->data, string) == 0)
while (item && strcmp(item->data, string) == 0)
item = find_in_history(item->prev, htop, string, len);
if (item) {
@@ -183,7 +184,7 @@ char *get_history_completion(linestruct **here, char *string, size_t len)
/* Now search from the bottom of the list to the original position. */
item = find_in_history(hbot, *here, string, len);
while (item != NULL && strcmp(item->data, string) == 0)
while (item && strcmp(item->data, string) == 0)
item = find_in_history(item->prev, *here, string, len);
if (item) {
@@ -204,11 +205,11 @@ bool have_statedir(void)
get_homedir();
if (homedir != NULL) {
if (homedir) {
statedir = concatenate(homedir, "/.nano/");
if (stat(statedir, &dirinfo) == 0 && S_ISDIR(dirinfo.st_mode)) {
poshistname = concatenate(statedir, POSITION_HISTORY);
registername = concatenate(statedir, POSITION_HISTORY);
return TRUE;
}
}
@@ -219,21 +220,21 @@ bool have_statedir(void)
if (homedir == NULL && xdgdatadir == NULL)
return FALSE;
if (xdgdatadir != NULL)
if (xdgdatadir)
statedir = concatenate(xdgdatadir, "/nano/");
else
statedir = concatenate(homedir, "/.local/share/nano/");
if (stat(statedir, &dirinfo) == -1) {
if (stat(statedir, &dirinfo) < 0) {
if (xdgdatadir == NULL) {
char *statepath = concatenate(homedir, "/.local");
mkdir(statepath, S_IRWXU | S_IRWXG | S_IRWXO);
mkdir(statepath, S_IRWXU);
free(statepath);
statepath = concatenate(homedir, "/.local/share");
mkdir(statepath, S_IRWXU);
free(statepath);
}
if (mkdir(statedir, S_IRWXU) == -1) {
if (mkdir(statedir, S_IRWXU) < 0) {
jot_error(N_("Unable to create directory %s: %s\n"
"It is required for saving/loading "
"search history or cursor positions.\n"),
@@ -248,49 +249,49 @@ bool have_statedir(void)
return FALSE;
}
poshistname = concatenate(statedir, POSITION_HISTORY);
registername = concatenate(statedir, POSITION_HISTORY);
return TRUE;
}
/* Load the histories for Search, Replace With, and Execute Command. */
void load_history(void)
{
char *histname = concatenate(statedir, SEARCH_HISTORY);
FILE *histfile = fopen(histname, "rb");
char *historyname = concatenate(statedir, SEARCH_HISTORY);
FILE *histories = fopen(historyname, "rb");
/* If reading an existing file failed, don't save history when we quit. */
if (histfile == NULL && errno != ENOENT) {
jot_error(N_("Error reading %s: %s"), histname, strerror(errno));
if (histories == NULL && errno != ENOENT) {
jot_error(N_("Error reading %s: %s"), historyname, strerror(errno));
UNSET(HISTORYLOG);
}
if (histfile == NULL) {
free(histname);
if (histories == NULL) {
free(historyname);
return;
}
linestruct **history = &search_history;
linestruct **list = &search_history;
char *stanza = NULL;
size_t dummy = 0;
ssize_t read;
/* Load the three history lists (first search, then replace, then execute)
* from oldest entry to newest. Between two lists there is an empty line. */
while ((read = getline(&stanza, &dummy, histfile)) > 0) {
while ((read = getline(&stanza, &dummy, histories)) > 0) {
stanza[--read] = '\0';
if (read > 0) {
recode_NUL_to_LF(stanza, read);
update_history(history, stanza, IGNORE_DUPLICATES);
} else if (history == &search_history)
history = &replace_history;
update_history(list, stanza, IGNORE_DUPLICATES);
} else if (list == &search_history)
list = &replace_history;
else
history = &execute_history;
list = &execute_history;
}
if (fclose(histfile) == EOF)
jot_error(N_("Error reading %s: %s"), histname, strerror(errno));
if (fclose(histories) == EOF)
jot_error(N_("Error reading %s: %s"), historyname, strerror(errno));
free(histname);
free(historyname);
free(stanza);
/* Reading in the lists has marked them as changed; undo this side effect. */
@@ -299,7 +300,7 @@ void load_history(void)
/* Write the lines of a history list, starting at head, from oldest to newest,
* to the given file. Return TRUE if writing succeeded, and FALSE otherwise. */
bool write_list(const linestruct *head, FILE *histfile)
bool write_list(const linestruct *head, FILE *histories)
{
const linestruct *item;
@@ -307,9 +308,9 @@ bool write_list(const linestruct *head, FILE *histfile)
/* Decode 0x0A bytes as embedded NULs. */
size_t length = recode_LF_to_NUL(item->data);
if (fwrite(item->data, 1, length, histfile) < length)
if (fwrite(item->data, 1, length, histories) < length)
return FALSE;
if (putc('\n', histfile) == EOF)
if (putc('\n', histories) == EOF)
return FALSE;
}
@@ -319,66 +320,108 @@ bool write_list(const linestruct *head, FILE *histfile)
/* Save the histories for Search, Replace With, and Execute Command. */
void save_history(void)
{
char *histname;
FILE *histfile;
/* If the histories are unchanged, don't bother saving them. */
if (!history_changed)
return;
histname = concatenate(statedir, SEARCH_HISTORY);
histfile = fopen(histname, "wb");
char *historyname = concatenate(statedir, SEARCH_HISTORY);
FILE *histories = fopen(historyname, "wb");
if (histfile == NULL) {
jot_error(N_("Error writing %s: %s"), histname, strerror(errno));
free(histname);
if (histories == NULL) {
jot_error(N_("Error writing %s: %s"), historyname, strerror(errno));
free(historyname);
return;
}
/* Don't allow others to read or write the history file. */
if (chmod(histname, S_IRUSR | S_IWUSR) < 0)
jot_error(N_("Cannot limit permissions on %s: %s"), histname, strerror(errno));
if (chmod(historyname, S_IRUSR | S_IWUSR) < 0)
jot_error(N_("Cannot limit permissions on %s: %s"), historyname, strerror(errno));
if (!write_list(searchtop, histfile) || !write_list(replacetop, histfile) ||
!write_list(executetop, histfile))
jot_error(N_("Error writing %s: %s"), histname, strerror(errno));
if (!write_list(searchtop, histories) || !write_list(replacetop, histories) ||
!write_list(executetop, histories))
jot_error(N_("Error writing %s: %s"), historyname, strerror(errno));
if (fclose(histfile) == EOF)
jot_error(N_("Error writing %s: %s"), histname, strerror(errno));
if (fclose(histories) == EOF)
jot_error(N_("Error writing %s: %s"), historyname, strerror(errno));
free(histname);
free(historyname);
}
/* Load the recorded cursor positions for files that were edited. */
void load_poshistory(void)
/* Return as a string... the line numbers of the lines with an anchor. */
char *stringify_anchors(void)
{
FILE *histfile = fopen(poshistname, "rb");
char *string = copy_of("");
#ifndef NANO_TINY
char number[24];
/* If reading an existing file failed, don't save history when we quit. */
if (histfile == NULL && errno != ENOENT) {
jot_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
for (linestruct *line = openfile->filetop; line != NULL; line = line->next)
if (line->has_anchor) {
sprintf(number, "%zi ", line->lineno);
string = nrealloc(string, strlen(string) + strlen(number) + 1);
strcat(string, number);
}
#endif
return string;
}
/* Set an anchor for each line number in the given string. */
void restore_anchors(char *string)
{
#ifndef NANO_TINY
linestruct *line = openfile->filetop;
ssize_t number;
char *space;
while (*string) {
if ((space = strchr(string, ' ')) == NULL)
return;
*space = '\0';
number = atoi(string);
*space = ' ';
string = space + 1;
while (line->lineno < number)
if ((line = line->next) == NULL)
return;
line->has_anchor = TRUE;
}
#endif
}
/* Load the recorded cursor positions for files that were opened. */
void load_positions_register(void)
{
FILE *registry = fopen(registername, "rb");
/* If reading an existing file failed, don't save the register when we quit. */
if (registry == NULL && errno != ENOENT) {
jot_error(N_("Error reading %s: %s"), registername, strerror(errno));
UNSET(POSITIONLOG);
}
if (histfile == NULL)
if (registry == NULL)
return;
poshiststruct *lastitem = NULL;
poshiststruct *newitem;
char *lineptr, *columnptr;
char *stanza = NULL;
positionstruct *lastitem = NULL;
positionstruct *newitem;
char *stanza, *lineptr, *columnptr;
char *phrase = NULL;
struct stat fileinfo;
size_t dummy = 0;
ssize_t count = 0;
ssize_t read;
int count = 0;
ssize_t length;
/* Read and parse each line, and store the extracted data. */
while ((read = getline(&stanza, &dummy, histfile)) > 5) {
while (count++ < 200 && (length = getline(&phrase, &dummy, registry)) > 1) {
stanza = strchr(phrase, '/');
length -= (stanza ? stanza - phrase : 0);
/* Decode NULs as embedded newlines. */
recode_NUL_to_LF(stanza, read);
recode_NUL_to_LF(stanza, length);
/* Find the spaces before column number and line number. */
columnptr = revstrstr(stanza, " ", stanza + read - 3);
columnptr = revstrstr(stanza, " ", stanza + length - 3);
if (columnptr == NULL)
continue;
lineptr = revstrstr(stanza, " ", columnptr - 2);
@@ -390,59 +433,55 @@ void load_poshistory(void)
*(lineptr++) = '\0';
/* Create a new position record. */
newitem = nmalloc(sizeof(poshiststruct));
newitem = nmalloc(sizeof(positionstruct));
newitem->filename = copy_of(stanza);
newitem->linenumber = atoi(lineptr);
newitem->columnnumber = atoi(columnptr);
newitem->anchors = (phrase == stanza) ? NULL : measured_copy(phrase, stanza - phrase);
newitem->next = NULL;
/* Add the record to the list. */
if (position_history == NULL)
position_history = newitem;
if (positions_register == NULL)
positions_register = newitem;
else
lastitem->next = newitem;
lastitem = newitem;
/* Impose a limit, so the file will not grow indefinitely. */
if (++count > 200) {
poshiststruct *drop_record = position_history;
position_history = position_history->next;
free(drop_record->filename);
free(drop_record);
}
}
if (fclose(histfile) == EOF)
jot_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
if (fclose(registry) == EOF)
jot_error(N_("Error reading %s: %s"), registername, strerror(errno));
free(stanza);
free(phrase);
if (stat(poshistname, &fileinfo) == 0)
if (stat(registername, &fileinfo) == 0)
latest_timestamp = fileinfo.st_mtime;
}
/* Save the recorded cursor positions for files that were edited. */
void save_poshistory(void)
/* Save the recorded cursor positions for files that were opened. */
void save_positions_register(void)
{
FILE *histfile = fopen(poshistname, "wb");
FILE *registry = fopen(registername, "wb");
struct stat fileinfo;
poshiststruct *item;
positionstruct *item;
int count = 0;
if (histfile == NULL) {
jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno));
if (registry == NULL) {
jot_error(N_("Error writing %s: %s"), registername, strerror(errno));
return;
}
/* Don't allow others to read or write the history file. */
if (chmod(poshistname, S_IRUSR | S_IWUSR) < 0)
jot_error(N_("Cannot limit permissions on %s: %s"), poshistname, strerror(errno));
/* Don't allow others to read or write the positions-register file. */
if (chmod(registername, S_IRUSR | S_IWUSR) < 0)
jot_error(N_("Cannot limit permissions on %s: %s"), registername, strerror(errno));
for (item = position_history; item != NULL; item = item->next) {
for (item = positions_register; item != NULL && count++ < 200; item = item->next) {
char *path_and_place;
size_t length;
size_t length = (item->anchors == NULL) ? 0 : strlen(item->anchors);
/* First write the string of line numbers with anchors, if any. */
if (length && fwrite(item->anchors, 1, length, registry) < length)
jot_error(N_("Error writing %s: %s"), registername, strerror(errno));
/* Assume 20 decimal positions each for line and column number,
* plus two spaces, plus the line feed, plus the null byte. */
@@ -455,131 +494,106 @@ void save_poshistory(void)
/* Restore the terminating newline. */
path_and_place[length - 1] = '\n';
if (fwrite(path_and_place, 1, length, histfile) < length)
jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno));
if (fwrite(path_and_place, 1, length, registry) < length)
jot_error(N_("Error writing %s: %s"), registername, strerror(errno));
free(path_and_place);
}
if (fclose(histfile) == EOF)
jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno));
if (fclose(registry) == EOF)
jot_error(N_("Error writing %s: %s"), registername, strerror(errno));
if (stat(poshistname, &fileinfo) == 0)
if (stat(registername, &fileinfo) == 0)
latest_timestamp = fileinfo.st_mtime;
}
/* Reload the position history file if it has been modified since last load. */
/* Reload the positions-register file if it has been modified since last load. */
void reload_positions_if_needed(void)
{
poshiststruct *item, *nextone;
positionstruct *item, *nextone;
struct stat fileinfo;
if (stat(poshistname, &fileinfo) != 0 || fileinfo.st_mtime == latest_timestamp)
if (stat(registername, &fileinfo) < 0 || fileinfo.st_mtime == latest_timestamp)
return;
for (item = position_history; item != NULL; item = nextone) {
for (item = positions_register; item != NULL; item = nextone) {
nextone = item->next;
free(item->filename);
free(item->anchors);
free(item);
}
position_history = NULL;
positions_register = NULL;
load_poshistory();
load_positions_register();
}
/* Update the recorded last file positions with the current position in the
* current buffer. If no existing entry is found, add a new one at the end. */
void update_poshistory(void)
* current buffer. If no existing entry is found, add a new one at the top. */
void update_positions_register(void)
{
char *fullpath = get_full_path(openfile->filename);
poshiststruct *previous = NULL;
poshiststruct *item, *theone;
positionstruct *previous = NULL;
positionstruct *item;
if (fullpath == NULL || openfile->filename[0] == '\0') {
free(fullpath);
if (fullpath == NULL)
return;
}
reload_positions_if_needed();
/* Look for a matching filename in the list. */
for (item = position_history; item != NULL; item = item->next) {
for (item = positions_register; item != NULL; item = item->next) {
if (!strcmp(item->filename, fullpath))
break;
previous = item;
}
/* Don't record files that have the default cursor position. */
if (openfile->current->lineno == 1 && openfile->current_x == 0) {
if (item != NULL) {
if (previous == NULL)
position_history = item->next;
else
previous->next = item->next;
free(item->filename);
free(item);
save_poshistory();
}
free(fullpath);
return;
/* If no match was found, make a new node; otherwise, unlink the match. */
if (item == NULL) {
item = nmalloc(sizeof(positionstruct));
item->filename = copy_of(fullpath);
item->anchors = NULL;
} else if (previous)
previous->next = item->next;
/* Place the found or new node at the beginning, if not already there. */
if (item != positions_register) {
item->next = positions_register;
positions_register = item;
}
theone = item;
/* If we didn't find it, make a new node; otherwise, if we're
* not at the end, move the matching one to the end. */
if (theone == NULL) {
theone = nmalloc(sizeof(poshiststruct));
theone->filename = copy_of(fullpath);
if (position_history == NULL)
position_history = theone;
else
previous->next = theone;
} else if (item->next != NULL) {
if (previous == NULL)
position_history = item->next;
else
previous->next = item->next;
while (item->next != NULL)
item = item->next;
item->next = theone;
}
/* Store the last cursor position. */
theone->linenumber = openfile->current->lineno;
theone->columnnumber = xplustabs() + 1;
theone->next = NULL;
/* Record the last cursor position and any anchors. */
item->linenumber = openfile->current->lineno;
item->columnnumber = xplustabs() + 1;
free(item->anchors);
item->anchors = stringify_anchors();
free(fullpath);
save_poshistory();
save_positions_register();
}
/* Check whether the given file matches an existing entry in the recorded
* last file positions. If not, return FALSE. If yes, return TRUE and
* set line and column to the retrieved values. */
bool has_old_position(const char *file, ssize_t *line, ssize_t *column)
/* Check whether the current filename matches an entry in the list of
* recorded positions. If yes, restore the relevant cursor position. */
void restore_cursor_position_if_any(void)
{
char *fullpath = get_full_path(file);
poshiststruct *item;
char *fullpath = get_full_path(openfile->filename);
positionstruct *item;
if (fullpath == NULL)
return FALSE;
return;
reload_positions_if_needed();
item = position_history;
while (item != NULL && strcmp(item->filename, fullpath) != 0)
item = positions_register;
while (item && strcmp(item->filename, fullpath) != 0)
item = item->next;
free(fullpath);
if (item == NULL)
return FALSE;
*line = item->linenumber;
*column = item->columnnumber;
return TRUE;
if (item && item->anchors)
restore_anchors(item->anchors);
if (item)
goto_line_and_column(item->linenumber, item->columnnumber, TRUE);
}
#endif /* ENABLE_HISTORIES */

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* move.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2018 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2018, 2020, 2024, 2026 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -37,11 +37,17 @@ void to_first_line(void)
void to_last_line(void)
{
openfile->current = openfile->filebot;
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
openfile->current = get_start_of_folded_segment(openfile->current);
openfile->current_x = 0;
} else
#endif
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
openfile->placewewant = xplustabs();
/* Set the last line of the screen as the target for the cursor. */
openfile->current_y = editwinrows - 1;
openfile->cursor_row = editwinrows - 1;
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
@@ -83,7 +89,7 @@ size_t proper_x(linestruct *line, size_t *leftedge, bool forward,
column / tabsize < (*leftedge + editwincols - 1) / tabsize))) {
index++;
if (shifted != NULL)
if (shifted)
*shifted = TRUE;
}
@@ -112,6 +118,15 @@ void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
openfile->placewewant = *leftedge + target;
}
/* Move the cursor position on the current line to the desired column */
void move_cursor_to_proper_column(void)
{
size_t leftedge;
size_t target_column;
get_edge_and_target(&leftedge, &target_column);
set_proper_index_and_pww(&leftedge, target_column, TRUE);
}
/* Move up almost one screenful. */
void do_page_up(void)
{
@@ -124,7 +139,7 @@ void do_page_up(void)
if (ISSET(JUMPY_SCROLLING)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
openfile->cursor_row = 0;
target_column = 0;
} else
#endif
@@ -156,7 +171,7 @@ void do_page_down(void)
if (ISSET(JUMPY_SCROLLING)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
openfile->cursor_row = 0;
target_column = 0;
} else
#endif
@@ -176,11 +191,68 @@ void do_page_down(void)
refresh_needed = TRUE;
}
#ifndef NANO_TINY
/* Place the cursor on the first row in the viewport. */
void to_top_row(void)
{
size_t leftedge, offset;
get_edge_and_target(&leftedge, &offset);
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
set_proper_index_and_pww(&leftedge, offset, FALSE);
refresh_needed = (openfile->mark != NULL);
}
/* Place the cursor on the last row in the viewport, when possible. */
void to_bottom_row(void)
{
size_t leftedge, offset;
get_edge_and_target(&leftedge, &offset);
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
go_forward_chunks(editwinrows - 1, &openfile->current, &leftedge);
set_proper_index_and_pww(&leftedge, offset, TRUE);
refresh_needed = (openfile->mark != NULL);
}
/* Put the cursor line at the center, then the top, then the bottom. */
void do_cycle(void)
{
if (cycling_aim == 0)
adjust_viewport(CENTERING);
else {
openfile->cursor_row = (cycling_aim == 1) ? 0 : editwinrows - 1;
adjust_viewport(STATIONARY);
}
cycling_aim = (cycling_aim + 1) % 3;
draw_all_subwindows();
full_refresh();
}
/* Scroll the line with the cursor to the center of the screen. */
void do_center(void)
{
adjust_viewport(CENTERING);
draw_all_subwindows();
full_refresh();
}
#endif /* !NANO_TINY */
#ifdef ENABLE_JUSTIFY
/* Move to the first beginning of a paragraph before the current line. */
void do_para_begin(linestruct **line)
{
if ((*line)->prev != NULL)
if ((*line)->prev)
*line = (*line)->prev;
while (!begpar(*line, 0))
@@ -190,11 +262,10 @@ void do_para_begin(linestruct **line)
/* Move down to the last line of the first found paragraph. */
void do_para_end(linestruct **line)
{
while ((*line)->next != NULL && !inpar(*line))
while ((*line)->next && !inpar(*line))
*line = (*line)->next;
while ((*line)->next != NULL && inpar((*line)->next) &&
!begpar((*line)->next, 0))
while ((*line)->next && inpar((*line)->next) && !begpar((*line)->next, 0))
*line = (*line)->next;
}
@@ -218,7 +289,7 @@ void to_para_end(void)
/* Step beyond the last line of the paragraph, if possible;
* otherwise, move to the end of the line. */
if (openfile->current->next != NULL) {
if (openfile->current->next) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
} else
@@ -235,19 +306,28 @@ void to_para_end(void)
void to_prev_block(void)
{
linestruct *was_current = openfile->current;
linestruct *line_step = get_prev_visible_line(openfile->current);
bool is_text = FALSE, seen_text = FALSE;
/* Skip backward until first blank line after some nonblank line(s). */
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
openfile->current = openfile->current->prev;
while (line_step && (!seen_text || is_text)) {
openfile->current = line_step;
line_step = get_prev_visible_line(line_step);
#ifdef ENABLE_FOLDING
/* Skip over the visibly drawn line of the folded segment */
if (openfile->current->folded)
continue;
#endif
is_text = !white_string(openfile->current->data);
seen_text = seen_text || is_text;
}
/* Step forward one line again if we passed text but this line is blank. */
if (seen_text && openfile->current->next != NULL &&
white_string(openfile->current->data))
openfile->current = openfile->current->next;
line_step = get_next_visible_line(openfile->current);
if (seen_text && line_step && white_string(openfile->current->data)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
}
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
@@ -257,12 +337,19 @@ void to_prev_block(void)
void to_next_block(void)
{
linestruct *was_current = openfile->current;
linestruct *line_step = get_next_visible_line(openfile->current);
bool is_white = white_string(openfile->current->data);
bool seen_white = is_white;
/* Skip forward until first nonblank line after some blank line(s). */
while (openfile->current->next != NULL && (!seen_white || is_white)) {
openfile->current = openfile->current->next;
while (line_step && (!seen_white || is_white)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
#ifdef ENABLE_FOLDING
/* Skip over the visibly drawn line of the folded segment */
if (openfile->current->folded)
continue;
#endif
is_white = white_string(openfile->current->data);
seen_white = seen_white || is_white;
}
@@ -274,25 +361,40 @@ void to_next_block(void)
#endif
}
/* Move to the previous word. */
void do_prev_word(void)
/* Move to the previous word.
* When allow_folded is true, will move to previous word even if inside
* a folded segment. */
void do_prev_word(bool allow_folded)
{
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
bool seen_a_word = FALSE, step_forward = FALSE;
#ifdef ENABLE_FOLDING
if (!allow_folded && openfile->current->folded) {
openfile->current = get_prev_visible_line(openfile->current);
openfile->current_x = strlen(openfile->current->data);
}
#endif
/* Move backward until we pass over the start of a word. */
while (TRUE) {
/* If at the head of a line, move to the end of the preceding one. */
if (openfile->current_x == 0) {
if (openfile->current->prev == NULL)
break;
openfile->current = openfile->current->prev;
#ifdef ENABLE_FOLDING
if (!allow_folded) {
openfile->current = get_prev_visible_line(openfile->current);
if (openfile->current->folded)
openfile->current = openfile->current->prev;
} else
#endif
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
}
/* Step back one character. */
openfile->current_x = step_left(openfile->current->data,
openfile->current_x);
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
if (is_word_char(openfile->current->data + openfile->current_x,
punctuation_as_letters)) {
@@ -313,13 +415,14 @@ void do_prev_word(void)
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
openfile->current_x = step_right(openfile->current->data, openfile->current_x);
UNFOLD_SEGMENT(openfile->current);
}
/* Move to the next word. If after_ends is TRUE, stop at the ends of words
* instead of at their beginnings. Return TRUE if we started on a word. */
bool do_next_word(bool after_ends)
* instead of at their beginnings. If allow_folded is true, go to next word
* even if it's inside a folded segment. Return TRUE if we started on a word. */
bool do_next_word(bool after_ends, bool allow_folded)
{
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
bool started_on_word = is_word_char(openfile->current->data +
@@ -329,6 +432,12 @@ bool do_next_word(bool after_ends)
bool seen_word = started_on_word;
#endif
#ifdef ENABLE_FOLDING
if (!allow_folded & openfile->current->folded) {
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}
#endif
/* Move forward until we reach the start of a word. */
while (TRUE) {
/* If at the end of a line, move to the beginning of the next one. */
@@ -336,13 +445,23 @@ bool do_next_word(bool after_ends)
/* When at end of file, stop. */
if (openfile->current->next == NULL)
break;
openfile->current = openfile->current->next;
#ifdef ENABLE_FOLDING
if (!allow_folded) {
openfile->current = get_next_visible_line(openfile->current);
if (openfile->current->folded) {
/* get_next_visible_line() gives the start of a folded segment,
* so skip to the end. */
openfile->current = get_end_of_folded_segment(openfile->current);
openfile->current = openfile->current->next;
}
} else
#endif
openfile->current = openfile->current->next;
openfile->current_x = 0;
seen_space = TRUE;
} else {
/* Step forward one character. */
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
openfile->current_x = step_right(openfile->current->data, openfile->current_x);
}
#ifndef NANO_TINY
@@ -376,6 +495,8 @@ bool do_next_word(bool after_ends)
}
}
UNFOLD_SEGMENT(openfile->current);
return started_on_word;
}
@@ -384,7 +505,7 @@ void to_prev_word(void)
{
linestruct *was_current = openfile->current;
do_prev_word();
do_prev_word(DISALLOW_FOLDED);
edit_redraw(was_current, FLOWING);
}
@@ -395,7 +516,7 @@ void to_next_word(void)
{
linestruct *was_current = openfile->current;
do_next_word(ISSET(AFTER_ENDS));
do_next_word(ISSET(AFTER_ENDS), DISALLOW_FOLDED);
edit_redraw(was_current, FLOWING);
}
@@ -413,6 +534,11 @@ void do_home(void)
size_t leftedge = 0;
size_t left_x = 0;
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
return;
#endif
if (ISSET(SOFTWRAP)) {
leftedge = leftedge_for(was_column, openfile->current);
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
@@ -421,7 +547,7 @@ void do_home(void)
if (ISSET(SMART_HOME)) {
size_t indent_x = indent_length(openfile->current->data);
if (openfile->current->data[indent_x] != '\0') {
if (openfile->current->data[indent_x]) {
/* If we're exactly on the indent, move fully home. Otherwise,
* when not softwrapping or not after the first nonblank chunk,
* move to the first nonblank character. */
@@ -470,6 +596,11 @@ void do_end(void)
size_t line_len = strlen(openfile->current->data);
bool moved_off_chunk = TRUE;
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
return;
#endif
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool kickoff = TRUE;
@@ -526,7 +657,8 @@ void do_up(void)
set_proper_index_and_pww(&leftedge, target_column, FALSE);
if (openfile->current_y == 0 && !ISSET(JUMPY_SCROLLING))
if (openfile->cursor_row == 0 && !ISSET(JUMPY_SCROLLING) &&
(tabsize < editwincols || !ISSET(SOFTWRAP)))
edit_scroll(BACKWARD);
else
edit_redraw(was_current, FLOWING);
@@ -549,7 +681,8 @@ void do_down(void)
set_proper_index_and_pww(&leftedge, target_column, TRUE);
if (openfile->current_y == editwinrows - 1 && !ISSET(JUMPY_SCROLLING))
if (openfile->cursor_row == editwinrows - 1 && !ISSET(JUMPY_SCROLLING) &&
(tabsize < editwincols || !ISSET(SOFTWRAP)))
edit_scroll(FORWARD);
else
edit_redraw(was_current, FLOWING);
@@ -566,7 +699,7 @@ void do_scroll_up(void)
if (openfile->edittop->prev == NULL && openfile->firstcolumn == 0)
return;
if (openfile->current_y == editwinrows - 1)
if (openfile->cursor_row == editwinrows - 1)
do_up();
if (editwinrows > 1)
@@ -576,10 +709,10 @@ void do_scroll_up(void)
/* Scroll down one line or chunk without moving the cursor textwise. */
void do_scroll_down(void)
{
if (openfile->current_y == 0)
if (openfile->cursor_row == 0)
do_down();
if (editwinrows > 1 && (openfile->edittop->next != NULL
if (editwinrows > 1 && (openfile->edittop->next
#ifndef NANO_TINY
|| (ISSET(SOFTWRAP) && (extra_chunks_in(openfile->edittop) >
chunk_for(openfile->firstcolumn, openfile->edittop)))
@@ -587,14 +720,6 @@ void do_scroll_down(void)
))
edit_scroll(FORWARD);
}
/* Scroll the line with the cursor to the center of the screen. */
void do_center(void)
{
adjust_viewport(CENTERING);
draw_all_subwindows();
full_refresh();
}
#endif /* !NANO_TINY || ENABLE_HELP */
/* Move left one character. */
@@ -603,16 +728,14 @@ void do_left(void)
linestruct *was_current = openfile->current;
if (openfile->current_x > 0) {
openfile->current_x = step_left(openfile->current->data,
openfile->current_x);
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
#ifdef ENABLE_UTF8
while (openfile->current_x > 0 &&
is_zerowidth(openfile->current->data + openfile->current_x))
openfile->current_x = step_left(openfile->current->data,
openfile->current_x);
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
#endif
} else if (openfile->current != openfile->filetop) {
openfile->current = openfile->current->prev;
openfile->current = get_prev_visible_line(openfile->current);
openfile->current_x = strlen(openfile->current->data);
}
@@ -624,19 +747,82 @@ void do_right(void)
{
linestruct *was_current = openfile->current;
if (openfile->current->data[openfile->current_x] != '\0') {
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
openfile->current = get_next_visible_line(openfile->current);
if (openfile->current == NULL)
openfile->current = was_current;
} else
#endif
if (openfile->current->data[openfile->current_x]) {
openfile->current_x = step_right(openfile->current->data, openfile->current_x);
#ifdef ENABLE_UTF8
while (openfile->current->data[openfile->current_x] != '\0' &&
while (openfile->current->data[openfile->current_x] &&
is_zerowidth(openfile->current->data + openfile->current_x))
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
openfile->current_x = step_right(openfile->current->data, openfile->current_x);
#endif
} else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}
edit_redraw(was_current, FLOWING);
}
#ifndef NANO_TINY
/* Scroll the viewport horizontally to the left. */
void do_scroll_left(void)
{
size_t frame_x;
if (ISSET(SOFTWRAP) || ISSET(SOLO_SIDESCROLL)) {
/* TRANSLATORS: The %s is the name of an option. */
statusline(AHEM, _("Not possible with '%s'"), ISSET(SOFTWRAP) ? "--softwrap" : "--solo");
return;
}
openfile->brink -= (openfile->brink < tabsize) ? openfile->brink : (tabsize < 2) ? 2 : tabsize;
frame_x = actual_x(openfile->current->data, openfile->brink + editwincols - CUSHION - 1);
if (openfile->current_x > frame_x) {
openfile->current_x = frame_x;
openfile->placewewant = xplustabs();
}
refresh_needed = TRUE;
}
/* Scroll the viewport horizontally to the right. */
void do_scroll_right(void)
{
size_t sill = openfile->edittop->lineno + editwinrows;
linestruct *line = openfile->current;
size_t frame_x;
if (ISSET(SOFTWRAP) || ISSET(SOLO_SIDESCROLL)) {
statusline(AHEM, _("Not possible with '%s'"), ISSET(SOFTWRAP) ? "--softwrap" : "--solo");
return;
}
openfile->brink += (tabsize < 2) ? 2 : tabsize;
/* If the current line does not allow further scrolling, seek
* in the viewport an earlier or later line that does allow it. */
while (line != openfile->edittop && breadth(line->data) < openfile->brink + CUSHION)
line = line->prev;
while (line->lineno < sill && breadth(line->data) < openfile->brink + CUSHION && line->next)
line = line->next;
if (line->lineno < sill && breadth(line->data) >= openfile->brink + CUSHION)
openfile->current = line;
frame_x = actual_x(openfile->current->data, openfile->brink + CUSHION);
if (openfile->current_x < frame_x) {
openfile->current_x = frame_x;
openfile->placewewant = xplustabs();
}
refresh_needed = TRUE;
}
#endif /* !NANO_TINY */

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* prompt.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020, 2022 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020-2022, 2025 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -76,7 +76,7 @@ void do_statusbar_next_word(void)
/* Move forward until we reach either the end or the start of a word,
* depending on whether the AFTER_ENDS flag is set or not. */
while (answer[typing_x] != '\0') {
while (answer[typing_x]) {
typing_x = step_right(answer, typing_x);
if (ISSET(AFTER_ENDS)) {
@@ -122,10 +122,10 @@ void do_statusbar_left(void)
/* Move right one character in the answer. */
void do_statusbar_right(void)
{
if (answer[typing_x] != '\0') {
if (answer[typing_x]) {
typing_x = step_right(answer, typing_x);
#ifdef ENABLE_UTF8
while (answer[typing_x] != '\0' && is_zerowidth(answer + typing_x))
while (answer[typing_x] && is_zerowidth(answer + typing_x))
typing_x = step_right(answer, typing_x);
#endif
}
@@ -145,7 +145,7 @@ void do_statusbar_backspace(void)
/* Delete one character in the answer. */
void do_statusbar_delete(void)
{
if (answer[typing_x] != '\0') {
if (answer[typing_x]) {
int charlen = char_length(answer + typing_x);
memmove(answer + typing_x, answer + typing_x + charlen,
@@ -184,8 +184,7 @@ void paste_into_answer(void)
size_t pastelen = strlen(cutbuffer->data);
answer = nrealloc(answer, strlen(answer) + pastelen + 1);
memmove(answer + typing_x + pastelen, answer + typing_x,
strlen(answer) - typing_x + 1);
memmove(answer + typing_x + pastelen, answer + typing_x, strlen(answer) - typing_x + 1);
strncpy(answer + typing_x, cutbuffer->data, pastelen);
typing_x += pastelen;
@@ -193,21 +192,21 @@ void paste_into_answer(void)
#endif
#ifdef ENABLE_MOUSE
/* Handle a mouse click on the status-bar prompt or the shortcut list. */
int do_statusbar_mouse(void)
/* Handle a mouse click in the prompt bar or the help lines. */
int process_prompt_click(void)
{
int click_row, click_col;
int retval = get_mouseinput(&click_row, &click_col, TRUE);
int retval = get_mouseinput(&click_row, &click_col); /* Handles shortcuts. */
/* We can click on the status-bar window text to move the cursor. */
/* When the click is in the prompt bar, position the cursor. */
if (retval == 0 && wmouse_trafo(footwin, &click_row, &click_col, FALSE)) {
size_t start_col = breadth(prompt) + 2;
/* Move to where the click occurred. */
if (click_row == 0 && click_col >= start_col)
typing_x = actual_x(answer,
get_statusbar_page_start(start_col, start_col +
wideness(answer, typing_x)) + click_col - start_col);
if (click_col >= start_col)
typing_x = actual_x(answer, get_statusbar_page_start(start_col, start_col +
wideness(answer, typing_x)) + click_col - start_col);
else
typing_x = 0;
}
return retval;
@@ -223,8 +222,7 @@ void inject_into_answer(char *burst, size_t count)
burst[index] = '\n';
answer = nrealloc(answer, strlen(answer) + count + 1);
memmove(answer + typing_x + count, answer + typing_x,
strlen(answer) - typing_x + 1);
memmove(answer + typing_x + count, answer + typing_x, strlen(answer) - typing_x + 1);
strncpy(answer + typing_x, burst, count);
typing_x += count;
@@ -261,10 +259,9 @@ void absorb_character(int input, functionptrtype function)
* 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 (!function) {
if (input < 0x20 || input > 0xFF || meta_key)
if ((input < 0x20 && input != '\t') || meta_key || input > 0xFF)
beep();
else if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE ||
openfile->filename[0] == '\0') {
else if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || openfile->filename[0] == '\0') {
/* 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) {
@@ -305,8 +302,7 @@ bool handle_editing(functionptrtype function)
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' &&
else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE && openfile->filename[0] &&
(function == do_verbatim_input ||
function == do_delete || function == do_backspace ||
function == cut_text || function == paste_text))
@@ -323,7 +319,7 @@ bool handle_editing(functionptrtype function)
else if (function == copy_text)
copy_the_answer();
else if (function == paste_text) {
if (cutbuffer != NULL)
if (cutbuffer)
paste_into_answer();
}
#endif
@@ -392,6 +388,7 @@ void draw_the_promptbar(void)
/* Place the cursor at the right spot. */
wmove(footwin, 0, column - the_page);
wnoutrefresh(footwin);
}
@@ -399,14 +396,14 @@ void draw_the_promptbar(void)
/* Remove or add the pipe character at the answer's head. */
void add_or_remove_pipe_symbol_from_answer(void)
{
if (answer[0] == '|') {
if (*answer == '|') {
memmove(answer, answer + 1, strlen(answer));
if (typing_x > 0)
typing_x--;
} else {
answer = nrealloc(answer, strlen(answer) + 2);
memmove(answer + 1, answer, strlen(answer) + 1);
answer[0] = '|';
*answer = '|';
typing_x++;
}
}
@@ -425,6 +422,9 @@ 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
#ifndef NANO_TINY
bool bracketed_paste = FALSE;
#endif
const keystruct *shortcut;
functionptrtype function;
@@ -441,18 +441,19 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
#ifndef NANO_TINY
/* If the window size changed, go reformat the prompt string. */
if (input == KEY_WINCH) {
refresh_func(); /* Only needed when in file browser. */
*actual = KEY_WINCH;
if (input == THE_WINDOW_RESIZED) {
*actual = THE_WINDOW_RESIZED;
#ifdef ENABLE_HISTORIES
free(stored_string);
#endif
return NULL;
}
if (input == START_OF_PASTE || input == END_OF_PASTE)
bracketed_paste = (input == START_OF_PASTE);
#endif
#ifdef ENABLE_MOUSE
/* For a click on a shortcut, read in the resulting keycode. */
if (input == KEY_MOUSE && do_statusbar_mouse() == 1)
if (input == KEY_MOUSE && process_prompt_click() == 1)
input = get_kbinput(footwin, BLIND);
if (input == KEY_MOUSE)
continue;
@@ -461,23 +462,35 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
/* Check for a shortcut in the current list. */
shortcut = get_shortcut(input);
function = (shortcut ? shortcut->func : NULL);
#ifndef NANO_TINY
/* Tabs in an external paste are not commands. */
if (input == '\t' && bracketed_paste)
function = NULL;
#endif
/* When it's a normal character, add it to the answer. */
absorb_character(input, function);
#ifndef NANO_TINY
/* Ignore any commands inside an external paste. */
if (bracketed_paste) {
if (function && function != do_nothing)
beep();
continue;
}
#endif
if (function == do_cancel || function == do_enter)
break;
#ifdef ENABLE_TABCOMP
if (function == do_tab) {
#ifdef ENABLE_HISTORIES
if (history_list != NULL) {
if (history_list) {
if (!previous_was_tab)
fragment_length = strlen(answer);
if (fragment_length > 0) {
answer = get_history_completion(history_list,
answer, fragment_length);
answer = get_history_completion(history_list, answer, fragment_length);
typing_x = strlen(answer);
}
} else
@@ -488,7 +501,7 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
} else
#endif
#ifdef ENABLE_HISTORIES
if (function == get_older_item && history_list != NULL) {
if (function == get_older_item && history_list) {
/* If this is the first step into history, start at the bottom. */
if (stored_string == NULL)
reset_history_pointer_for(*history_list);
@@ -498,14 +511,14 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
stored_string = mallocstrcpy(stored_string, answer);
/* If there is an older item, move to it and copy its string. */
if ((*history_list)->prev != NULL) {
if ((*history_list)->prev) {
*history_list = (*history_list)->prev;
answer = mallocstrcpy(answer, (*history_list)->data);
typing_x = strlen(answer);
}
} else if (function == get_newer_item && history_list != NULL) {
} else if (function == get_newer_item && history_list) {
/* If there is a newer item, move to it and copy its string. */
if ((*history_list)->next != NULL) {
if ((*history_list)->next) {
*history_list = (*history_list)->next;
answer = mallocstrcpy(answer, (*history_list)->data);
typing_x = strlen(answer);
@@ -537,6 +550,11 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
else if (function && !handle_editing(function)) {
/* When it's a permissible shortcut, run it and done. */
if (!ISSET(VIEW_MODE) || !changes_something(function)) {
#ifndef NANO_TINY
/* When invoking a tool at the Execute prompt, stash an "answer". */
if (currmenu == MEXECUTE)
foretext = mallocstrcpy(foretext, answer);
#endif
function();
break;
} else
@@ -548,9 +566,14 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
#endif
}
#ifndef NANO_TINY
/* When an external command was run, clear a possibly stashed answer. */
if (currmenu == MEXECUTE && function == do_enter)
*foretext = '\0';
#endif
#ifdef ENABLE_HISTORIES
/* If the history pointer was moved, point it at the bottom again. */
if (stored_string != NULL) {
if (stored_string) {
reset_history_pointer_for(*history_list);
free(stored_string);
}
@@ -597,13 +620,17 @@ int do_prompt(int menu, const char *provided, linestruct **history_list,
free(prompt);
#ifndef NANO_TINY
if (retval == KEY_WINCH)
if (retval == THE_WINDOW_RESIZED)
goto redo_theprompt;
#endif
/* Restore a possible previous prompt and maybe the typing position. */
prompt = saved_prompt;
if (function == do_cancel || function == do_enter)
if (function == do_cancel || function == do_enter ||
#ifdef ENABLE_BROWSER
function == to_first_file || function == to_last_file ||
#endif
function == to_first_line || function == to_last_line)
typing_x = was_typing_x;
/* Set the proper return value for Cancel and Enter. */
@@ -692,14 +719,15 @@ int ask_user(bool withall, const char *question)
kbinput = get_kbinput(footwin, !withall);
#ifndef NANO_TINY
if (kbinput == KEY_WINCH)
if (kbinput == THE_WINDOW_RESIZED)
continue;
/* Accept first character of an external paste and ignore the rest. */
if (bracketed_paste)
if (kbinput == START_OF_PASTE) {
kbinput = get_kbinput(footwin, BLIND);
while (bracketed_paste)
get_kbinput(footwin, BLIND);
while (get_kbinput(footwin, BLIND) != END_OF_PASTE)
;
}
#endif
#ifdef ENABLE_NLS
@@ -707,7 +735,7 @@ int ask_user(bool withall, const char *question)
#ifdef ENABLE_UTF8
/* If the received code is a UTF-8 starter byte, get also the
* continuation bytes and assemble them into one letter. */
if (using_utf8() && 0xC0 <= kbinput && kbinput <= 0xF7) {
if (0xC0 <= kbinput && kbinput <= 0xF7 && using_utf8) {
int extras = (kbinput / 16) % 4 + (kbinput <= 0xCF ? 1 : 0);
while (extras <= waiting_keycodes() && extras-- > 0)
@@ -717,19 +745,19 @@ int ask_user(bool withall, const char *question)
letter[index] = '\0';
/* See if the typed letter is in the Yes, No, or All strings. */
if (strstr(yesstr, letter) != NULL)
if (strstr(yesstr, letter))
choice = YES;
else if (strstr(nostr, letter) != NULL)
else if (strstr(nostr, letter))
choice = NO;
else if (withall && strstr(allstr, letter) != NULL)
else if (withall && strstr(allstr, letter))
choice = ALL;
else
#endif /* ENABLE_NLS */
if (strchr("Yy", kbinput) != NULL)
if (strchr("Yy", kbinput))
choice = YES;
else if (strchr("Nn", kbinput) != NULL)
else if (strchr("Nn", kbinput))
choice = NO;
else if (withall && strchr("Aa", kbinput) != NULL)
else if (withall && strchr("Aa", kbinput))
choice = ALL;
if (choice != UNDECIDED)
@@ -752,17 +780,22 @@ int ask_user(bool withall, const char *question)
focusing = TRUE;
}
#endif
/* Interpret ^N and ^Q as "No", to allow exiting in anger. */
else if (kbinput == '\x0E' || kbinput == '\x11')
/* Interpret ^N as "No", to allow exiting in anger, and ^Q or ^X too. */
else if (kbinput == '\x0E' || (kbinput == '\x11' && !ISSET(MODERN_BINDINGS)) ||
(kbinput == '\x18' && ISSET(MODERN_BINDINGS))) {
choice = NO;
/* And interpret ^Y as "Yes". */
else if (kbinput == '\x19')
if (kbinput != '\x0E') /* ^X^Q makes nano exit with an error. */
final_status = 2;
/* Also, interpret ^Y as "Yes, and ^A as "All". */
} else if (kbinput == '\x19')
choice = YES;
else if (kbinput == '\x01' && withall)
choice = ALL;
#ifdef ENABLE_MOUSE
else if (kbinput == KEY_MOUSE) {
int mouse_x, mouse_y;
/* We can click on the Yes/No/All shortcuts to select an answer. */
if (get_mouseinput(&mouse_y, &mouse_x, FALSE) == 0 &&
if (get_mouseinput(&mouse_y, &mouse_x) == 0 &&
wmouse_trafo(footwin, &mouse_y, &mouse_x, FALSE) &&
mouse_x < (width * 2) && mouse_y > 0) {
int x = mouse_x / width;

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* prototypes.h -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2026 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 *
@@ -14,7 +14,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,24 +24,31 @@
#ifndef NANO_TINY
extern volatile sig_atomic_t the_window_resized;
extern volatile sig_atomic_t resized_for_browser;
#endif
extern bool on_a_vt;
extern bool using_utf8;
extern bool shifted_metas;
extern bool meta_key;
extern bool shift_held;
extern bool mute_modifiers;
extern bool bracketed_paste;
extern bool we_are_running;
extern bool more_than_one;
extern bool report_size;
extern bool ran_a_tool;
extern char *foretext;
extern int final_status;
extern bool inhelp;
extern char *title;
extern bool united_sidescroll;
extern bool focusing;
extern bool as_an_at;
@@ -68,13 +75,13 @@ extern int controlup, controldown;
extern int controlhome, controlend;
#ifndef NANO_TINY
extern int controldelete, controlshiftdelete;
extern int shiftleft, shiftright;
extern int shiftup, shiftdown;
extern int shiftcontrolleft, shiftcontrolright;
extern int shiftcontrolup, shiftcontroldown;
extern int shiftcontrolhome, shiftcontrolend;
extern int altleft, altright;
extern int altup, altdown;
extern int althome, altend;
extern int altpageup, altpagedown;
extern int altinsert, altdelete;
extern int shiftaltleft, shiftaltright;
@@ -93,10 +100,11 @@ extern WINDOW *footwin;
extern int editwinrows;
extern int editwincols;
extern int margin;
extern int thebar;
extern int sidebar;
#ifndef NANO_TINY
extern int *bardata;
extern ssize_t stripe_column;
extern int cycling_aim;
#endif
extern linestruct *cutbuffer;
@@ -202,10 +210,6 @@ void to_last_file(void);
#endif
/* Most functions in chars.c. */
#ifdef ENABLE_UTF8
void utf8_init(void);
bool using_utf8(void);
#endif
bool is_alpha_char(const char *c);
bool is_blank_char(const char *c);
bool is_cntrl_char(const char *c);
@@ -228,7 +232,7 @@ char *mbstrcasestr(const char *haystack, const char *needle);
char *revstrstr(const char *haystack, const char *needle, const char *pointer);
char *mbrevstrcasestr(const char *haystack, const char *needle, const char *pointer);
#if !defined(NANO_TINY) || defined(ENABLE_JUSTIFY)
char *mbstrchr(const char *string, const char *chr);
const char *mbstrchr(const char *string, const char *chr);
#endif
#ifndef NANO_TINY
char *mbstrpbrk(const char *string, const char *accept);
@@ -238,6 +242,9 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer);
bool has_blank_char(const char *string);
#endif
bool white_string(const char *string);
#if defined(ENABLE_SPELLER) || defined(ENABLE_COLOR)
void strip_leading_blanks_from(char *string);
#endif
/* Most functions in color.c. */
#ifdef ENABLE_COLOR
@@ -249,6 +256,7 @@ void precalc_multicolorinfo(void);
#endif
/* Most functions in cut.c. */
void expunge(undo_type action);
void do_delete(void);
void do_backspace(void);
#ifndef NANO_TINY
@@ -267,8 +275,8 @@ void cut_text(void);
void cut_till_eof(void);
void zap_text(void);
void copy_marked_region(void);
void copy_text(void);
#endif
void copy_text(void);
void paste_text(void);
/* Most functions in files.c. */
@@ -302,16 +310,14 @@ bool outside_of_confinement(const char *currpath, bool allow_tabcomp);
void init_backup_dir(void);
#endif
int copy_file(FILE *inn, FILE *out, bool close_out);
bool write_file(const char *name, FILE *thefile, bool normal,
kind_of_writing_type method, bool annotate);
bool write_file(const char *name, FILE *thefile, writing_type method, bool annotate);
#ifndef NANO_TINY
bool write_region_to_file(const char *name, FILE *stream, bool normal,
kind_of_writing_type method);
bool write_region_to_file(const char *name, FILE *stream, writing_type method);
#endif
int write_it_out(bool exiting, bool withprompt);
void do_writeout(void);
void do_savefile(void);
char *real_dir_from_tilde(const char *path);
char *expand_leading_tilde(const char *path);
#if defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
int diralphasort(const void *va, const void *vb);
#endif
@@ -348,9 +354,9 @@ char *get_history_completion(linestruct **h, char *s, size_t len);
bool have_statedir(void);
void load_history(void);
void save_history(void);
void load_poshistory(void);
void update_poshistory(void);
bool has_old_position(const char *file, ssize_t *line, ssize_t *column);
void load_positions_register(void);
void update_positions_register(void);
void restore_cursor_position_if_any(void);
#endif
/* Most functions in move.c. */
@@ -358,6 +364,12 @@ void to_first_line(void);
void to_last_line(void);
void do_page_up(void);
void do_page_down(void);
#ifndef NANO_TINY
void to_top_row(void);
void to_bottom_row(void);
void do_cycle(void);
void do_center(void);
#endif
#ifdef ENABLE_JUSTIFY
void do_para_begin(linestruct **line);
void do_para_end(linestruct **line);
@@ -366,8 +378,8 @@ void to_para_end(void);
#endif
void to_prev_block(void);
void to_next_block(void);
void do_prev_word(void);
bool do_next_word(bool after_ends);
void do_prev_word(bool allow_folded);
bool do_next_word(bool after_ends, bool allow_folded);
void to_prev_word(void);
void to_next_word(void);
void do_home(void);
@@ -377,10 +389,14 @@ void do_down(void);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
void do_scroll_up(void);
void do_scroll_down(void);
void do_center(void);
#endif
void do_left(void);
void do_right(void);
void move_cursor_to_proper_column(void);
#ifndef NANO_TINY
void do_scroll_left(void);
void do_scroll_right(void);
#endif
/* Most functions in nano.c. */
linestruct *make_new_node(linestruct *prevnode);
@@ -429,6 +445,7 @@ void confirm_margin(void);
#endif
void unbound_key(int code);
bool changes_something(functionptrtype f);
void suck_up_input_and_paste_it(void);
void inject(char *burst, size_t count);
/* Most functions in prompt.c. */
@@ -473,10 +490,15 @@ 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);
void ask_for_line_and_column(char *provided);
void goto_line_and_column(ssize_t line, ssize_t column, bool hugfloor);
#ifndef NANO_TINY
size_t get_matchbrackets_halfway(void);
int find_matching_bracket_pos(linestruct **line, size_t *xpos);
bool find_terminus_of_bracketed_region(linestruct **line, size_t *xpos, size_t bracket_half, bool reverse);
bool find_bracketed_region(linestruct *in_region,
linestruct **top, linestruct **bot);
void do_find_bracket(void);
void put_or_lift_anchor(void);
void to_prev_anchor(void);
@@ -556,15 +578,15 @@ const char *strstrwrapper(const char *haystack, const char *needle,
const char *start);
void *nmalloc(size_t howmuch);
void *nrealloc(void *ptr, size_t howmuch);
char *measured_copy(const char *string, size_t count);
char *mallocstrcpy(char *dest, const char *src);
char *measured_copy(const char *string, size_t count);
char *copy_of(const char *string);
char *free_and_assign(char *dest, char *src);
size_t get_page_start(size_t column);
size_t xplustabs(void);
size_t actual_x(const char *text, size_t column);
size_t wideness(const char *text, size_t maxlen);
size_t wideness(const char *text, size_t count);
size_t breadth(const char *text);
size_t xplustabs(void);
void new_magicline(void);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
void remove_magicline(void);
@@ -580,12 +602,14 @@ linestruct *line_from_number(ssize_t number);
#endif
/* Most functions in winio.c. */
linestruct *get_next_visible_line(linestruct *line);
linestruct *get_prev_visible_line(linestruct *line);
#ifndef NANO_TINY
void record_macro(void);
void run_macro(void);
#endif
void reserve_space_for(size_t newsize);
size_t waiting_keycodes(void);
void put_back(int keycode);
#ifdef ENABLE_NANORC
void implant(const char *string);
#endif
@@ -593,13 +617,13 @@ int get_input(WINDOW *win);
int get_kbinput(WINDOW *win, bool showcursor);
char *get_verbatim_kbinput(WINDOW *win, size_t *count);
#ifdef ENABLE_MOUSE
int get_mouseinput(int *mouse_y, int *mouse_x, bool allow_shortcuts);
int get_mouseinput(int *mouse_y, int *mouse_x);
#endif
void blank_edit(void);
void blank_statusbar(void);
void wipe_statusbar(void);
void blank_bottombars(void);
void check_statusblank(void);
void blank_it_when_expired(void);
void set_blankdelay_to_one(void);
char *display_string(const char *buf, size_t column, size_t span,
bool isdata, bool isprompt);
@@ -611,6 +635,7 @@ void warn_and_briefly_pause(const char *msg);
void bottombars(int menu);
void post_one_key(const char *keystroke, const char *tag, int width);
void place_the_cursor(void);
int update_line_at(linestruct *line, size_t index, int row);
int update_line(linestruct *line, size_t index);
#ifndef NANO_TINY
int update_softwrapped_line(linestruct *line);
@@ -662,7 +687,6 @@ void goto_dir(void);
void do_nothing(void);
void do_toggle(void);
void dos_format(void);
void mac_format(void);
void append_it(void);
void prepend_it(void);
void back_it_up(void);
@@ -675,3 +699,12 @@ void flip_newbuffer(void);
#endif
void discard_buffer(void);
void do_cancel(void);
/* Most functions in folding.c. */
#ifdef ENABLE_FOLDING
void do_fold_segment(void);
void unfold_folded_segment(linestruct *line);
linestruct *get_start_of_folded_segment(linestruct* line);
linestruct *get_end_of_folded_segment(linestruct* line);
int get_folded_segment_length(linestruct *line);
#endif

View File

@@ -1,10 +1,10 @@
/**************************************************************************
* rcfile.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mike Frysinger *
* Copyright (C) 2019 Brand Huntsman *
* Copyright (C) 2014-2021 Benno Schulenberg *
* Copyright (C) 2014-2021, 2024 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 *
@@ -17,7 +17,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -64,12 +64,13 @@ static const rcoption rcopts[] = {
{"mouse", USE_MOUSE},
#endif
#ifdef ENABLE_MULTIBUFFER
{"multibuffer", MULTIBUFFER},
{"multibuffer", NEW_BUFFER}, /* Deprecated; remove in 2031. */
{"newbuffer", NEW_BUFFER},
#endif
{"nohelp", NO_HELP},
{"nonewlines", NO_NEWLINES},
#ifdef ENABLE_WRAPPING
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2024. */
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2027. */
#endif
#ifdef ENABLE_OPERATINGDIR
{"operatingdir", 0},
@@ -98,6 +99,7 @@ static const rcoption rcopts[] = {
{"backup", MAKE_BACKUP},
{"backupdir", 0},
{"bookstyle", BOOKSTYLE},
{"colonparsing", COLON_PARSING},
{"cutfromcursor", CUT_FROM_CURSOR},
{"emptyline", EMPTY_LINE},
{"guidestripe", 0},
@@ -110,12 +112,14 @@ static const rcoption rcopts[] = {
{"showcursor", SHOW_CURSOR},
{"smarthome", SMART_HOME},
{"softwrap", SOFTWRAP},
{"solosidescroll", SOLO_SIDESCROLL},
{"stateflags", STATEFLAGS},
{"tabsize", 0},
{"tabstospaces", TABS_TO_SPACES},
{"trimblanks", TRIM_BLANKS},
{"unix", MAKE_IT_UNIX},
{"whitespace", 0},
{"whitespacedisplay", WHITESPACE_DISPLAY},
{"wordbounds", WORD_BOUNDS},
{"wordchars", 0},
{"zap", LET_THEM_ZAP},
@@ -134,6 +138,7 @@ static const rcoption rcopts[] = {
{"errorcolor", 0},
{"keycolor", 0},
{"functioncolor", 0},
{"foldedcolor", 0},
#endif
{NULL, 0}
};
@@ -185,7 +190,7 @@ void jot_error(const char *msg, ...)
if (startup_problem == NULL) {
#ifdef ENABLE_NANORC
if (nanorc != NULL) {
if (nanorc) {
snprintf(textbuf, MAXSIZE, _("Mistakes in '%s'"), nanorc);
startup_problem = copy_of(textbuf);
} else
@@ -194,8 +199,7 @@ void jot_error(const char *msg, ...)
}
#ifdef ENABLE_NANORC
if (lineno > 0)
length = snprintf(textbuf, MAXSIZE, _("Error in %s on line %zu: "),
nanorc, lineno);
length = snprintf(textbuf, MAXSIZE, _("Error in %s on line %zu: "), nanorc, lineno);
#endif
va_start(ap, msg);
length += vsnprintf(textbuf + length, MAXSIZE - length, _(msg), ap);
@@ -245,6 +249,8 @@ keystruct *strtosc(const char *input)
s->func = do_replace;
else if (!strcmp(input, "cut"))
s->func = cut_text;
else if (!strcmp(input, "copy"))
s->func = copy_text;
else if (!strcmp(input, "paste"))
s->func = paste_text;
#ifndef NANO_TINY
@@ -252,8 +258,6 @@ keystruct *strtosc(const char *input)
s->func = do_execute;
else if (!strcmp(input, "cutrestoffile"))
s->func = cut_till_eof;
else if (!strcmp(input, "copy"))
s->func = copy_text;
else if (!strcmp(input, "zap"))
s->func = zap_text;
else if (!strcmp(input, "mark"))
@@ -321,6 +325,8 @@ keystruct *strtosc(const char *input)
s->func = do_undo;
else if (!strcmp(input, "redo"))
s->func = do_redo;
else if (!strcmp(input, "suspend"))
s->func = do_suspend;
#endif
else if (!strcmp(input, "left") ||
!strcmp(input, "back"))
@@ -334,13 +340,17 @@ keystruct *strtosc(const char *input)
else if (!strcmp(input, "down") ||
!strcmp(input, "nextline"))
s->func = do_down;
#ifndef NANO_TINY
else if (!strcmp(input, "scrollleft"))
s->func = do_scroll_left;
else if (!strcmp(input, "scrollright"))
s->func = do_scroll_right;
#endif
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
else if (!strcmp(input, "scrollup"))
s->func = do_scroll_up;
else if (!strcmp(input, "scrolldown"))
s->func = do_scroll_down;
else if (!strcmp(input, "center"))
s->func = do_center;
#endif
else if (!strcmp(input, "prevword"))
s->func = to_prev_word;
@@ -354,6 +364,16 @@ keystruct *strtosc(const char *input)
s->func = to_prev_block;
else if (!strcmp(input, "nextblock"))
s->func = to_next_block;
#ifndef NANO_TINY
else if (!strcmp(input, "toprow"))
s->func = to_top_row;
else if (!strcmp(input, "bottomrow"))
s->func = to_bottom_row;
else if (!strcmp(input, "center"))
s->func = do_center;
else if (!strcmp(input, "cycle"))
s->func = do_cycle;
#endif
else if (!strcmp(input, "pageup") ||
!strcmp(input, "prevpage"))
s->func = do_page_up;
@@ -382,10 +402,6 @@ keystruct *strtosc(const char *input)
s->func = do_backspace;
else if (!strcmp(input, "refresh"))
s->func = full_refresh;
#ifndef NANO_TINY
else if (!strcmp(input, "suspend"))
s->func = do_suspend;
#endif
else if (!strcmp(input, "casesens"))
s->func = case_sens_void;
else if (!strcmp(input, "regexp"))
@@ -394,8 +410,6 @@ keystruct *strtosc(const char *input)
s->func = backwards_void;
else if (!strcmp(input, "flipreplace"))
s->func = flip_replace;
else if (!strcmp(input, "flipgoto"))
s->func = flip_goto;
#ifdef ENABLE_HISTORIES
else if (!strcmp(input, "older"))
s->func = get_older_item;
@@ -405,8 +419,6 @@ keystruct *strtosc(const char *input)
#ifndef NANO_TINY
else if (!strcmp(input, "dosformat"))
s->func = dos_format;
else if (!strcmp(input, "macformat"))
s->func = mac_format;
else if (!strcmp(input, "append"))
s->func = append_it;
else if (!strcmp(input, "prepend"))
@@ -463,8 +475,7 @@ keystruct *strtosc(const char *input)
else if (!strcmp(input, "cutfromcursor"))
s->toggle = CUT_FROM_CURSOR;
#ifdef ENABLE_WRAPPING
else if (!strcmp(input, "breaklonglines") ||
!strcmp(input, "nowrap")) /* Deprecated; remove in 2024. */
else if (!strcmp(input, "breaklonglines"))
s->toggle = BREAK_LONG_LINES;
#endif
else if (!strcmp(input, "tabstospaces"))
@@ -519,12 +530,12 @@ char *menu_to_name(int menu)
return "boooo";
}
/* Parse the next word from the string, null-terminate it, and return
* a pointer to the first character after the null terminator. The
* returned pointer will point to '\0' if we hit the end of the line. */
/* Parse the next word from the string (if any), null-terminate it,
* and return a pointer to the next word. The returned pointer will
* point to '\0' when end-of-line was reached. */
char *parse_next_word(char *ptr)
{
while (!isblank((unsigned char)*ptr) && *ptr != '\0')
while (*ptr && !isblank((unsigned char)*ptr))
ptr++;
if (*ptr == '\0')
@@ -539,25 +550,23 @@ char *parse_next_word(char *ptr)
return ptr;
}
/* Parse an argument, with optional quotes, after a keyword that takes
* one. If the next word starts with a ", we say that it ends with the
* last " of the line. Otherwise, we interpret it as usual, so that the
* arguments can contain "'s too. */
/* Parse an argument (optionally enveloped in double quotes). When the
* argument starts with a ", then the last " of the line indicates its
* end -- meaning that an argument can contain "'s either way. */
char *parse_argument(char *ptr)
{
const char *ptr_save = ptr;
const char *the_start = ptr;
char *last_quote = NULL;
if (*ptr != '"')
return parse_next_word(ptr);
while (*ptr != '\0') {
while (*ptr)
if (*++ptr == '"')
last_quote = ptr;
}
if (last_quote == NULL) {
jot_error(N_("Argument '%s' has an unterminated \""), ptr_save);
jot_error(N_("Argument '%s' has an unterminated \""), the_start);
return NULL;
}
@@ -584,8 +593,7 @@ char *parse_next_regex(char *ptr)
/* Continue until the end of the line, or until a double quote followed
* by end-of-line or a blank. */
while (*ptr != '\0' && (*ptr != '"' ||
(ptr[1] != '\0' && !isblank((unsigned char)ptr[1]))))
while (*ptr && (*ptr != '"' || (ptr[1] && !isblank((unsigned char)ptr[1]))))
ptr++;
if (*ptr == '\0') {
@@ -679,7 +687,7 @@ void begin_new_syntax(char *ptr)
live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER);
#endif
live_syntax->color = NULL;
live_syntax->nmultis = 0;
live_syntax->multiscore = 0;
/* Hook the new syntax in at the top of the list. */
live_syntax->next = syntaxes;
@@ -689,13 +697,13 @@ void begin_new_syntax(char *ptr)
seen_color_command = FALSE;
/* The default syntax should have no associated extensions. */
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
if (*ptr && strcmp(live_syntax->name, "default") == 0) {
jot_error(N_("The \"default\" syntax does not accept extensions"));
return;
}
/* If there seem to be extension regexes, pick them up. */
if (*ptr != '\0')
if (*ptr)
grab_and_store("extension", ptr, &live_syntax->extensions);
}
#endif /* ENABLE_COLOR */
@@ -732,9 +740,11 @@ bool is_universal(void (*func)(void))
/* Bind or unbind a key combo, to or from a function. */
void parse_binding(char *ptr, bool dobind)
{
char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
int keycode, menu, mask = 0;
char *keycopy, *keyptr, *menuptr;
keystruct *newsc = NULL;
char *funcptr = NULL;
int keycode, menu;
int mask = 0;
check_for_nonempty_syntax();
@@ -748,12 +758,13 @@ void parse_binding(char *ptr, bool dobind)
keycopy = copy_of(keyptr);
/* Uppercase either the second or the first character of the key name. */
if (keycopy[0] == '^')
keycopy[1] = toupper((unsigned char)keycopy[1]);
else
keycopy[0] = toupper((unsigned char)keycopy[0]);
if (keycopy[0] == '^') {
if ('a' <= keycopy[1] && keycopy[1] <= 'z')
keycopy[1] &= 0x5F;
} else if ('a' <= keycopy[0] && keycopy[0] <= 'z')
keycopy[0] &= 0x5F;
/* Verify that the key name is not too short, to allow the next call. */
/* Verify that the key name is not too short. */
if (keycopy[1] == '\0' || (keycopy[0] == 'M' && keycopy[2] == '\0')) {
jot_error(N_("Key name %s is invalid"), keycopy);
goto free_things;
@@ -778,12 +789,11 @@ void parse_binding(char *ptr, bool dobind)
}
menuptr = ptr;
ptr = parse_next_word(ptr);
parse_next_word(ptr);
if (menuptr[0] == '\0') {
/* TRANSLATORS: Do not translate the word "all". */
jot_error(N_("Must specify a menu (or \"all\") "
"in which to bind/unbind the key"));
jot_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key"));
goto free_things;
}
@@ -846,8 +856,7 @@ void parse_binding(char *ptr, bool dobind)
if (!menu) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
jot_error(N_("Function '%s' does not exist in menu '%s'"),
funcptr, menuptr);
jot_error(N_("Function '%s' does not exist in menu '%s'"), funcptr, menuptr);
goto free_things;
}
@@ -884,14 +893,14 @@ bool is_good_file(char *file)
struct stat rcinfo;
/* First check that the file exists and is readable. */
if (access(file, R_OK) != 0)
if (access(file, R_OK) < 0)
return FALSE;
/* If the thing exists, it may be neither a directory nor a device. */
if (stat(file, &rcinfo) != -1 && (S_ISDIR(rcinfo.st_mode) ||
if (stat(file, &rcinfo) == 0 && (S_ISDIR(rcinfo.st_mode) ||
S_ISCHR(rcinfo.st_mode) || S_ISBLK(rcinfo.st_mode))) {
jot_error(S_ISDIR(rcinfo.st_mode) ? N_("\"%s\" is a directory") :
N_("\"%s\" is a device file"), file);
jot_error(S_ISDIR(rcinfo.st_mode) ? N_("'%s' is a directory") :
N_("'%s' is a device file"), file);
return FALSE;
} else
return TRUE;
@@ -940,7 +949,7 @@ void parse_one_include(char *file, syntaxtype *syntax)
extra = syntax->augmentations;
/* Apply any stored extendsyntax commands. */
while (extra != NULL) {
while (extra) {
char *keyword = extra->data;
char *therest = parse_next_word(extra->data);
@@ -953,6 +962,7 @@ void parse_one_include(char *file, syntaxtype *syntax)
extra = extra->next;
}
/* Indicate that this syntax has been loaded. */
free(syntax->filename);
syntax->filename = NULL;
@@ -972,10 +982,15 @@ void parse_includes(char *ptr)
pattern = ptr;
if (*pattern == '"')
pattern++;
ptr = parse_argument(ptr);
parse_argument(ptr);
if (strlen(pattern) > PATH_MAX) {
jot_error(N_("Path is too long"));
return;
}
/* Expand a tilde first, then try to match the globbing pattern. */
expanded = real_dir_from_tilde(pattern);
expanded = expand_leading_tilde(pattern);
result = glob(expanded, GLOB_ERR|GLOB_NOCHECK, NULL, &files);
/* If there are matches, process each of them. Otherwise, only
@@ -1036,12 +1051,12 @@ short indices[COLORCOUNT] = { COLOR_RED, COLOR_GREEN, COLOR_BLUE,
* vivid to TRUE for a lighter color, and thick for a heavier typeface. */
short color_to_short(const char *colorname, bool *vivid, bool *thick)
{
if (strncmp(colorname, "bright", 6) == 0 && colorname[6] != '\0') {
/* Prefix "bright" is deprecated; remove in 2024. */
if (strncmp(colorname, "bright", 6) == 0 && colorname[6]) {
/* Prefix "bright" is deprecated; remove in 2027. */
*vivid = TRUE;
*thick = TRUE;
colorname += 6;
} else if (strncmp(colorname, "light", 5) == 0 && colorname[5] != '\0') {
} else if (strncmp(colorname, "light", 5) == 0 && colorname[5]) {
*vivid = TRUE;
*thick = FALSE;
colorname += 5;
@@ -1079,40 +1094,40 @@ short color_to_short(const char *colorname, bool *vivid, bool *thick)
/* Parse the color name (or pair of color names) in the given string.
* Return FALSE when any color name is invalid; otherwise return TRUE. */
bool parse_combination(char *combostr, short *fg, short *bg, int *attributes)
bool parse_combination(char *combotext, short *fg, short *bg, int *attributes)
{
bool vivid, thick;
char *comma;
*attributes = A_NORMAL;
if (strncmp(combostr, "bold", 4) == 0) {
if (strncmp(combotext, "bold", 4) == 0) {
*attributes |= A_BOLD;
if (combostr[4] != ',') {
if (combotext[4] != ',') {
jot_error(N_("An attribute requires a subsequent comma"));
return FALSE;
}
combostr += 5;
combotext += 5;
}
if (strncmp(combostr, "italic", 6) == 0) {
if (strncmp(combotext, "italic", 6) == 0) {
#ifdef A_ITALIC
*attributes |= A_ITALIC;
#endif
if (combostr[6] != ',') {
if (combotext[6] != ',') {
jot_error(N_("An attribute requires a subsequent comma"));
return FALSE;
}
combostr += 7;
combotext += 7;
}
comma = strchr(combostr, ',');
comma = strchr(combotext, ',');
if (comma)
*comma = '\0';
if (!comma || comma > combostr) {
*fg = color_to_short(combostr, &vivid, &thick);
if (!comma || comma > combotext) {
*fg = color_to_short(combotext, &vivid, &thick);
if (*fg == BAD_COLOR)
return FALSE;
if (vivid && !thick && COLORS > 8)
@@ -1159,7 +1174,7 @@ void parse_rule(char *ptr, int rex_flags)
return;
}
while (*ptr != '\0') {
while (*ptr) {
regex_t *start_rgx = NULL, *end_rgx = NULL;
/* Intermediate storage for compiled regular expressions. */
colortype *newcolor = NULL;
@@ -1218,22 +1233,22 @@ void parse_rule(char *ptr, int rex_flags)
/* For a multiline rule, give it a number and increase the count. */
if (expectend) {
newcolor->id = live_syntax->nmultis;
live_syntax->nmultis++;
newcolor->id = live_syntax->multiscore;
live_syntax->multiscore++;
}
}
}
/* Parse the argument of an interface color option. */
colortype *parse_interface_color(char *combostr)
/* Set the colors for the given interface element to the given combination. */
void set_interface_color(int element, char *combotext)
{
colortype *trio = nmalloc(sizeof(colortype));
if (!parse_combination(combostr, &trio->fg, &trio->bg, &trio->attributes)) {
free(trio);
return NULL;
if (parse_combination(combotext, &trio->fg, &trio->bg, &trio->attributes)) {
free(color_combo[element]);
color_combo[element] = trio;
} else
return trio;
free(trio);
}
/* Read regex strings enclosed in double quotes from the line pointed at
@@ -1249,7 +1264,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
}
/* The default syntax doesn't take any file matching stuff. */
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
if (*ptr && strcmp(live_syntax->name, "default") == 0) {
jot_error(N_("The \"default\" syntax does not accept '%s' regexes"), kind);
return;
}
@@ -1262,11 +1277,11 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
lastthing = *storage;
/* If there was an earlier command, go to the last of those regexes. */
while (lastthing != NULL && lastthing->next != NULL)
while (lastthing && lastthing->next)
lastthing = lastthing->next;
/* Now gather any valid regexes and add them to the linked list. */
while (*ptr != '\0') {
while (*ptr) {
regex_t *packed_rgx = NULL;
regexstring = ++ptr;
@@ -1293,7 +1308,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
}
}
/* Gather and store the string after a comment/linter command. */
/* Gather and store the string after a comment/linter/formatter/tabgives command. */
void pick_up_name(const char *kind, char *ptr, char **storage)
{
if (*ptr == '\0') {
@@ -1332,19 +1347,21 @@ bool parse_syntax_commands(char *keyword, char *ptr)
#endif
} else if (strcmp(keyword, "tabgives") == 0) {
pick_up_name("tabgives", ptr, &live_syntax->tabstring);
} else if (strcmp(keyword, "linter") == 0)
} else if (strcmp(keyword, "linter") == 0) {
pick_up_name("linter", ptr, &live_syntax->linter);
else if (strcmp(keyword, "formatter") == 0)
strip_leading_blanks_from(live_syntax->linter);
} else if (strcmp(keyword, "formatter") == 0) {
pick_up_name("formatter", ptr, &live_syntax->formatter);
else
strip_leading_blanks_from(live_syntax->formatter);
} else
return FALSE;
return TRUE;
}
#endif /* ENABLE_COLOR */
/* Verify that the user has not unmapped every shortcut for a
* function that we consider 'vital' (such as "Exit"). */
/* Verify that the user has not unmapped every shortcut for
* a function that we consider 'vital' (such as "Exit"). */
static void check_vitals_mapped(void)
{
#define VITALS 4
@@ -1353,7 +1370,7 @@ static void check_vitals_mapped(void)
for (int v = 0; v < VITALS; v++) {
for (funcstruct *f = allfuncs; f != NULL; f = f->next) {
if (f->func == vitals[v] && f->menus & inmenus[v]) {
if (f->func == vitals[v] && (f->menus & inmenus[v])) {
if (first_sc_for(inmenus[v], f->func) == NULL) {
jot_error(N_("No key is bound to function '%s' in menu '%s'. "
" Exiting.\n"), f->tag, menu_to_name(inmenus[v]));
@@ -1368,7 +1385,7 @@ static void check_vitals_mapped(void)
/* Parse the rcfile, once it has been opened successfully at rcstream,
* and close it afterwards. If just_syntax is TRUE, allow the file to
* to contain only color syntax commands. */
* contain only color syntax commands. */
void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
{
char *buffer = NULL;
@@ -1447,9 +1464,9 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
newitem->data = argument;
newitem->next = NULL;
if (sntx->augmentations != NULL) {
if (sntx->augmentations) {
extra = sntx->augmentations;
while (extra->next != NULL)
while (extra->next)
extra = extra->next;
extra->next = newitem;
} else
@@ -1481,8 +1498,7 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
strcmp(keyword, "include") == 0 ||
strcmp(keyword, "extendsyntax") == 0)) {
if (intros_only)
jot_error(N_("Command \"%s\" not allowed in included file"),
keyword);
jot_error(N_("Command \"%s\" not allowed in included file"), keyword);
else
break;
} else if (intros_only && (strcmp(keyword, "color") == 0 ||
@@ -1492,8 +1508,7 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
strcmp(keyword, "linter") == 0 ||
strcmp(keyword, "formatter") == 0)) {
if (!opensyntax)
jot_error(N_("A '%s' command requires a preceding "
"'syntax' command"), keyword);
jot_error(N_("A '%s' command requires a preceding 'syntax' command"), keyword);
if (strstr("icolor", keyword))
seen_color_command = TRUE;
continue;
@@ -1565,40 +1580,42 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
argument = ptr;
if (*argument == '"')
argument++;
ptr = parse_argument(ptr);
parse_argument(ptr);
#ifdef ENABLE_UTF8
/* When in a UTF-8 locale, ignore arguments with invalid sequences. */
if (using_utf8() && mbstowcs(NULL, argument, 0) == (size_t)-1) {
if (using_utf8 && mbstowcs(NULL, argument, 0) == (size_t)-1) {
jot_error(N_("Argument is not a valid multibyte string"));
continue;
}
#endif
#ifdef ENABLE_COLOR
if (strcmp(option, "titlecolor") == 0)
color_combo[TITLE_BAR] = parse_interface_color(argument);
set_interface_color(TITLE_BAR, argument);
else if (strcmp(option, "numbercolor") == 0)
color_combo[LINE_NUMBER] = parse_interface_color(argument);
set_interface_color(LINE_NUMBER, argument);
else if (strcmp(option, "stripecolor") == 0)
color_combo[GUIDE_STRIPE] = parse_interface_color(argument);
set_interface_color(GUIDE_STRIPE, argument);
else if (strcmp(option, "scrollercolor") == 0)
color_combo[SCROLL_BAR] = parse_interface_color(argument);
set_interface_color(SCROLL_BAR, argument);
else if (strcmp(option, "selectedcolor") == 0)
color_combo[SELECTED_TEXT] = parse_interface_color(argument);
set_interface_color(SELECTED_TEXT, argument);
else if (strcmp(option, "spotlightcolor") == 0)
color_combo[SPOTLIGHTED] = parse_interface_color(argument);
set_interface_color(SPOTLIGHTED, argument);
else if (strcmp(option, "minicolor") == 0)
color_combo[MINI_INFOBAR] = parse_interface_color(argument);
set_interface_color(MINI_INFOBAR, argument);
else if (strcmp(option, "promptcolor") == 0)
color_combo[PROMPT_BAR] = parse_interface_color(argument);
set_interface_color(PROMPT_BAR, argument);
else if (strcmp(option, "statuscolor") == 0)
color_combo[STATUS_BAR] = parse_interface_color(argument);
set_interface_color(STATUS_BAR, argument);
else if (strcmp(option, "errorcolor") == 0)
color_combo[ERROR_MESSAGE] = parse_interface_color(argument);
set_interface_color(ERROR_MESSAGE, argument);
else if (strcmp(option, "keycolor") == 0)
color_combo[KEY_COMBO] = parse_interface_color(argument);
set_interface_color(KEY_COMBO, argument);
else if (strcmp(option, "functioncolor") == 0)
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
set_interface_color(FUNCTION_TAG, argument);
else if (strcmp(option, "foldedcolor") == 0)
set_interface_color(FOLDED_LINE, argument);
else
#endif
#ifdef ENABLE_OPERATINGDIR
@@ -1690,12 +1707,13 @@ void parse_one_nanorc(void)
/* If opening the file succeeded, parse it. Otherwise, only
* complain if the file actually exists. */
if (rcstream != NULL)
if (rcstream)
parse_rcfile(rcstream, FALSE, TRUE);
else if (errno != ENOENT)
jot_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
}
/* Return TRUE when path-plus-name denotes a readable, normal file. */
bool have_nanorc(const char *path, const char *name)
{
if (path == NULL)
@@ -1713,18 +1731,18 @@ void do_rcfiles(void)
{
if (custom_nanorc) {
nanorc = get_full_path(custom_nanorc);
if (nanorc == NULL || 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");
if (is_good_file(nanorc))
parse_one_nanorc();
} else {
const char *xdgconfdir;
if (is_good_file(nanorc))
parse_one_nanorc();
if (custom_nanorc == NULL) {
const char *xdgconfdir = getenv("XDG_CONFIG_HOME");
if (have_nanorc(SYSCONFDIR, "/nanorc"))
parse_one_nanorc();
get_homedir();
xdgconfdir = getenv("XDG_CONFIG_HOME");
/* Now try to find a nanorc file in the user's home directory or in the
* XDG configuration directories, and process the first one found. */

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* search.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2020, 2022 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2015-2022, 2025, 2026 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -79,13 +79,12 @@ void search_init(bool replacing, bool retain_answer)
/* What will be searched for when the user types just <Enter>. */
/* If something was searched for earlier, include it in the prompt. */
if (*last_search != '\0') {
if (*last_search) {
char *disp = display_string(last_search, 0, COLS / 3, FALSE, FALSE);
thedefault = nmalloc(strlen(disp) + 7);
/* We use (COLS / 3) here because we need to see more on the line. */
sprintf(thedefault, " [%s%s]", disp,
(breadth(last_search) > COLS / 3) ? "..." : "");
sprintf(thedefault, " [%s%s]", disp, (breadth(last_search) > COLS / 3) ? "..." : "");
free(disp);
} else
thedefault = copy_of("");
@@ -99,8 +98,8 @@ void search_init(bool replacing, bool retain_answer)
/* TRANSLATORS: This is the main search prompt. */
"%s%s%s%s%s%s", _("Search"),
/* TRANSLATORS: The next four modify the search prompt. */
ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : "",
ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
ISSET(CASE_SENSITIVE) ? _(" [Case sensitive]") : "",
ISSET(USE_REGEXP) ? _(" [Reg.exp.]") : "",
ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : "",
replacing ?
#ifndef NANO_TINY
@@ -118,7 +117,7 @@ void search_init(bool replacing, bool retain_answer)
/* If Enter was pressed, prepare to do a replace or a search. */
if (response == 0 || response == -2) {
/* If an actual answer was typed, remember it. */
if (*answer != '\0') {
if (*answer) {
last_search = mallocstrcpy(last_search, answer);
#ifdef ENABLE_HISTORIES
update_history(&search_history, answer, PRUNE_DUPLICATE);
@@ -155,14 +154,15 @@ void search_init(bool replacing, bool retain_answer)
} else
replacing = !replacing;
} else if (function == flip_goto) {
goto_line_and_column(openfile->current->lineno,
openfile->placewewant + 1, TRUE, TRUE);
ask_for_line_and_column(answer);
break;
} else
break;
}
tidy_up_after_search();
if (!inhelp)
tidy_up_after_search();
free(thedefault);
}
@@ -202,22 +202,21 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
if (ISSET(BACKWARDS_SEARCH) && from != line->data) {
from = line->data + step_left(line->data, from - line->data);
found = strstrwrapper(line->data, needle, from);
} else if (!ISSET(BACKWARDS_SEARCH) && *from != '\0') {
} else if (!ISSET(BACKWARDS_SEARCH) && *from) {
from += char_length(from);
found = strstrwrapper(line->data, needle, from);
}
} else
found = strstrwrapper(line->data, needle, from);
if (found != NULL) {
if (found) {
/* When doing a regex search, compute the length of the match. */
if (ISSET(USE_REGEXP))
found_len = regmatches[0].rm_eo - regmatches[0].rm_so;
#ifdef ENABLE_SPELLER
/* When we're spell checking, a match should be a separate word;
* if it's not, continue looking in the rest of the line. */
if (whole_word_only && !is_separate_word(found - line->data,
found_len, line->data)) {
if (whole_word_only && !is_separate_word(found - line->data, found_len, line->data)) {
from = found + char_length(found);
continue;
}
@@ -308,6 +307,8 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
}
}
UNFOLD_SEGMENT(line);
found_x = found - line->data;
nodelay(midwin, FALSE);
@@ -323,7 +324,7 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
openfile->current_x = found_x;
/* When requested, pass back the length of the match. */
if (match_len != NULL)
if (match_len)
*match_len = found_len;
#ifndef NANO_TINY
@@ -331,6 +332,14 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
spotlighted = TRUE;
light_from_col = xplustabs();
light_to_col = wideness(line->data, found_x + found_len);
/* When panning, "unpan" when the match fits within an unpanned viewport,
otherwise ensure that the end of the match will be visible too. */
if (united_sidescroll && light_to_col < editwincols - CUSHION)
openfile->brink = 0;
else if (united_sidescroll)
openfile->brink = get_page_start(light_to_col);
refresh_needed = TRUE;
}
#endif
@@ -361,7 +370,7 @@ void do_research(void)
#ifdef ENABLE_HISTORIES
/* If nothing was searched for yet during this run of nano, but
* there is a search history, take the most recent item. */
if (*last_search == '\0' && searchbot->prev != NULL)
if (*last_search == '\0' && searchbot->prev)
last_search = mallocstrcpy(last_search, searchbot->prev->data);
#endif
@@ -381,7 +390,8 @@ void do_research(void)
go_looking();
tidy_up_after_search();
if (!inhelp)
tidy_up_after_search();
}
/* Search in the backward direction for the next occurrence. */
@@ -414,7 +424,7 @@ void not_found_msg(const char *str)
void go_looking(void)
{
linestruct *was_current = openfile->current;
size_t was_current_x = openfile->current_x;
size_t was_x = openfile->current_x;
//#define TIMEIT 12
#ifdef TIMEIT
@@ -429,56 +439,49 @@ void go_looking(void)
/* If we found something, and we're back at the exact same spot
* where we started searching, then this is the only occurrence. */
if (didfind == 1 && openfile->current == was_current &&
openfile->current_x == was_current_x)
if (didfind == 1 && openfile->current == was_current && openfile->current_x == was_x)
statusline(REMARK, _("This is the only occurrence"));
else if (didfind == 0)
not_found_msg(last_search);
#ifdef TIMEIT
statusline(INFO, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
statusline(NOTICE, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
#endif
edit_redraw(was_current, CENTERING);
}
/* Calculate the size of the replacement text, taking possible
* subexpressions \1 to \9 into account. Return the replacement
* text in the passed string only when create is TRUE. */
int replace_regexp(char *string, bool create)
/* Return the size of the replacement text for the found regex, taking
* any references to subexpressions (\1 to \9) into account. Copy the
* replacement text into `string` when this parameter isn't NULL. */
int replace_regexp(char *string)
{
size_t replacement_size = 0;
const char *c = answer;
const char *given = answer;
/* Iterate through the replacement text to handle subexpression
* replacement using \1, \2, \3, etc. */
while (*c != '\0') {
int num = (*(c + 1) - '0');
while (*given) {
int digit = (given[1] - '0');
if (*c != '\\' || num < 1 || num > 9 || num > search_regexp.re_nsub) {
if (create)
*string++ = *c;
c++;
replacement_size++;
} else {
size_t i = regmatches[num].rm_eo - regmatches[num].rm_so;
/* When there is a valid backreference, use the relevant subexpression;
* otherwise, use the literal given answer. */
if (*given == '\\' && 0 < digit && digit < 10 && digit <= search_regexp.re_nsub) {
size_t extent = regmatches[digit].rm_eo - regmatches[digit].rm_so;
/* Skip over the replacement expression. */
c += 2;
/* But add the length of the subexpression to new_size. */
replacement_size += i;
/* And if create is TRUE, append the result of the
* subexpression match to the new line. */
if (create) {
strncpy(string, openfile->current->data + regmatches[num].rm_so, i);
string += i;
if (string) {
strncpy(string, openfile->current->data + regmatches[digit].rm_so, extent);
string += extent;
}
replacement_size += extent;
given += 2;
} else {
if (string)
*string++ = *given;
replacement_size++;
given++;
}
}
if (create)
if (string)
*string = '\0';
return replacement_size;
@@ -494,7 +497,7 @@ char *replace_line(const char *needle)
/* First adjust the size of the new line for the change. */
if (ISSET(USE_REGEXP)) {
match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
new_size += replace_regexp(NULL, FALSE) - match_len;
new_size += replace_regexp(NULL) - match_len;
} else {
match_len = strlen(needle);
new_size += strlen(answer) - match_len;
@@ -507,7 +510,7 @@ char *replace_line(const char *needle)
/* Add the replacement text. */
if (ISSET(USE_REGEXP))
replace_regexp(copy + openfile->current_x, TRUE);
replace_regexp(copy + openfile->current_x);
else
strcpy(copy + openfile->current_x, answer);
@@ -586,9 +589,13 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
if (!replaceall) {
spotlighted = TRUE;
light_from_col = xplustabs();
light_to_col = wideness(openfile->current->data,
openfile->current_x + match_len);
light_to_col = wideness(openfile->current->data, openfile->current_x + match_len);
#ifndef NANO_TINY
if (united_sidescroll && light_to_col < editwincols - CUSHION)
openfile->brink = 0;
else if (united_sidescroll)
openfile->brink = get_page_start(light_to_col);
#endif
/* Refresh the edit window, scrolling it if necessary. */
edit_refresh();
@@ -678,11 +685,6 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
openfile->mark = was_mark;
#endif
/* If "automatic newline" is enabled, and text has been added to the
* magic line, make a new magic line. */
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
new_magicline();
return numreplaced;
}
@@ -704,18 +706,24 @@ void ask_for_and_do_replacements(void)
size_t was_firstcolumn = openfile->firstcolumn;
linestruct *beginline = openfile->current;
size_t begin_x = openfile->current_x;
char *replacee = copy_of(last_search);
ssize_t numreplaced;
int response = do_prompt(MREPLACEWITH, "", &replace_history,
/* TRANSLATORS: This is a prompt. */
edit_refresh, _("Replace with"));
/* Set the string to be searched, as it might have changed at the prompt. */
free(last_search);
last_search = replacee;
#ifdef ENABLE_HISTORIES
/* When not "", add the replace string to the replace history list. */
if (response == 0)
update_history(&replace_history, answer, PRUNE_DUPLICATE);
#endif
/* When cancelled, or when a function was run, get out. */
/* When cancelled, or when a function was run, we're done. */
if (response == -1) {
statusbar(_("Cancelled"));
return;
@@ -754,73 +762,103 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
openfile->current_x = pos_x;
openfile->placewewant = xplustabs();
UNFOLD_SEGMENT(openfile->current);
refresh_needed = TRUE;
}
#endif
/* Go to the specified line and column, or ask for them if interactive
* is TRUE. In the latter case also update the screen afterwards.
* Note that both the line and column number should be one-based. */
void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
bool interactive)
/* Implement the Go To Line menu. */
void do_gotolinecolumn(void)
{
if (interactive) {
/* Ask for the line and column. */
int response = do_prompt(MGOTOLINE, retain_answer ? answer : "", NULL,
/* TRANSLATORS: This is a prompt. */
edit_refresh, _("Enter line number, column number"));
ask_for_line_and_column("");
}
/* If the user cancelled or gave a blank answer, get out. */
if (response < 0) {
statusbar(_("Cancelled"));
return;
}
/* Ask for a line and maybe column number, and then jump there. */
void ask_for_line_and_column(char *provided)
{
ssize_t line = openfile->current->lineno;
ssize_t column = openfile->placewewant + 1;
int response = do_prompt(MGOTOLINE, provided, NULL, edit_refresh,
/* TRANSLATORS: This is a prompt. */
_("Enter line number, column number"));
int doublesign = 0;
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);
return;
}
/* If a function was executed, we're done here. */
if (response > 0)
return;
/* Try to extract one or two numbers from the user's response. */
if (!parse_line_column(answer, &line, &column)) {
statusline(AHEM, _("Invalid line or column number"));
return;
}
} else {
if (line == 0)
line = openfile->current->lineno;
if (column == 0)
column = openfile->placewewant + 1;
/* When switching to Search, retain what the user typed so far. */
if (func_from_key(response) == flip_goto) {
UNSET(BACKWARDS_SEARCH);
search_init(FALSE, TRUE);
return;
}
/* When cancelled or blank, or when a function was run, we're done. */
if (response < 0) {
statusbar(_("Cancelled"));
return;
} else if (response > 0)
return;
/* A ++ or -- before the number signifies a relative jump. */
if ((answer[0] == '+' && answer[1] == '+') || (answer[0] == '-' && answer[1] == '-'))
doublesign = 1;
/* Try to extract one or two numbers from the user's response. */
if (!parse_line_column(answer + doublesign, &line, &column)) {
statusline(AHEM, _("Invalid line or column number"));
return;
}
if (doublesign)
line += openfile->current->lineno;
if (doublesign && line < 1)
line = 1;
goto_line_and_column(line, column, FALSE);
adjust_viewport((*answer == ',') ? STATIONARY : CENTERING);
refresh_needed = TRUE;
}
/* Go to the specified line and column. (Note that both are one-based.) */
void goto_line_and_column(ssize_t line, ssize_t column, bool hugfloor)
{
int rows_from_tail;
/* Take a negative line number to mean: from the end of the file. */
if (line < 0)
line = openfile->filebot->lineno + line + 1;
else if (line == 0)
line = openfile->current->lineno;
if (line < 1)
line = 1;
#ifdef ENABLE_COLOR
#ifdef ENABLE_FOLDING
linestruct *edit_bottom = openfile->edittop;
for (int i = 0; edit_bottom != openfile->filebot && i < editwinrows; ++i)
edit_bottom = get_next_visible_line(edit_bottom);
if (line > edit_bottom->lineno ||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
recook |= perturbed;
#else
if (line > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
recook |= perturbed;
#endif
#endif /* ENABLE_FOLDING */
#endif /* ENABLE_COLOR */
/* Iterate to the requested line. */
for (openfile->current = openfile->filetop; line > 1 &&
openfile->current != openfile->filebot; line--)
openfile->current = openfile->current->next;
UNFOLD_SEGMENT(openfile->current);
/* Take a negative column number to mean: from the end of the line. */
if (column < 0)
column = breadth(openfile->current->data) + column + 2;
else if (column == 0)
column = openfile->placewewant + 1;
if (column < 1)
column = 1;
@@ -834,61 +872,138 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
openfile->placewewant = breadth(openfile->current->data);
#endif
/* When a line number was manually given, center the target line. */
if (interactive) {
adjust_viewport((*answer == ',') ? STATIONARY : CENTERING);
refresh_needed = TRUE;
} else {
int rows_from_tail;
if (!hugfloor)
return;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
linestruct *currentline = openfile->current;
size_t leftedge = leftedge_for(xplustabs(), openfile->current);
if (ISSET(SOFTWRAP)) {
linestruct *currentline = openfile->current;
size_t leftedge = leftedge_for(xplustabs(), openfile->current);
rows_from_tail = (editwinrows / 2) - go_forward_chunks(
editwinrows / 2, &currentline, &leftedge);
} else
rows_from_tail = (editwinrows / 2) - go_forward_chunks(
editwinrows / 2, &currentline, &leftedge);
} else
#endif
rows_from_tail = openfile->filebot->lineno -
openfile->current->lineno;
rows_from_tail = openfile->filebot->lineno - openfile->current->lineno;
/* If the target line is close to the tail of the file, put the last
* line or chunk on the bottom line of the screen; otherwise, just
* center the target line. */
if (rows_from_tail < editwinrows / 2 && !ISSET(JUMPY_SCROLLING)) {
openfile->current_y = editwinrows - 1 - rows_from_tail;
adjust_viewport(STATIONARY);
} else
adjust_viewport(CENTERING);
}
}
/* Go to the specified line and column, asking for them beforehand. */
void do_gotolinecolumn(void)
{
goto_line_and_column(openfile->current->lineno,
openfile->placewewant + 1, FALSE, TRUE);
/* If the target line is close to the tail of the file, put the last
* line or chunk on the bottom line of the screen; otherwise, just
* center the target line. */
if (rows_from_tail < editwinrows / 2 && !ISSET(JUMPY_SCROLLING)) {
openfile->cursor_row = editwinrows - 1 - rows_from_tail;
adjust_viewport(STATIONARY);
} else
adjust_viewport(CENTERING);
}
#ifndef NANO_TINY
/* Search forwards for a line ending with a bracket, including the current line.
* line is an in/out parameter. The passed value is the start line for searching.
* xpos is an out parameter. It is the position in the line where the bracket is
* found. bracket_half is the halfway mark in the matchbrackets array. This way in
* a loop the halfway value isn't recomputed. If end is true, search for an ending
* bracket, else search for a starting bracket. */
bool find_terminus_of_bracketed_region(linestruct **line, size_t *xpos, size_t bracket_half, bool reverse)
{
/* Search forwards for a line ending with a bracket, including the current line */
for (; (*line) != NULL; *line = (reverse ? (*line)->prev : (*line)->next)) {
char *found;
const char *bracket;
int len = strlen((*line)->data);
/* Find the last bracket on the search line */
found = mbrevstrpbrk((*line)->data, matchbrackets, (*line)->data + len);
if (found == NULL)
continue;
*xpos = found - (*line)->data;
bracket = mbstrchr(matchbrackets, found);
/* We're looking for closing braces, not opening */
if (bracket >= matchbrackets + bracket_half)
continue;
/* Check if this is the last character in the line */
char *next = (*line)->data + step_right((*line)->data, *xpos);
if (*next == '\0')
return TRUE;
}
*xpos = 0;
return FALSE;
}
/* Get the halfway point in matchbrackets, where open and close
* brackets meet. */
size_t get_matchbrackets_halfway(void)
{
size_t charcount = mbstrlen(matchbrackets) / 2;
size_t halfway = 0;
for (size_t i = 0; i < charcount; ++i)
halfway += char_length(matchbrackets + halfway);
return halfway;
}
/* Get a region surrounding the line in_region. A region here is defined
* as a block of text ending with a closing bracket at the end of a line,
* and starting with a matching opening bracket. Or a block of text starting
* with an opening bracket at the end of a line and ending with a matching
* closing bracket.
* in_region is a line within the region. If a region is found but does not
* contain in_region, it is ignored.
* top and bot are out parameters. Returns the top/bottom line of the region. */
bool find_bracketed_region(linestruct *in_region,
linestruct **top, linestruct **bot)
{
size_t bracket_half = get_matchbrackets_halfway();
size_t top_pos;
size_t bot_pos;
linestruct *was_top = *top;
linestruct *was_bot = *bot;
*bot = in_region;
for (; find_terminus_of_bracketed_region(top, &top_pos, bracket_half, TRUE)
; *top = (*top)->prev)
{
*bot= *top;
bot_pos = top_pos;
if (!find_matching_bracket_pos(bot, &bot_pos)) {
if ((*bot)->lineno < in_region->lineno)
continue;
int linedist = (*bot)->lineno - (*top)->lineno;
if (linedist >= 2) {
*top = (*top)->next;
*bot = (*bot)->prev;
return TRUE;
}
}
}
*top = was_top;
*bot = was_bot;
return FALSE;
}
/* Search, starting from the current position, for any of the two characters
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
bool find_a_bracket(bool reverse, const char *bracket_pair)
bool find_a_bracket(bool reverse, const char *bracket_pair,
linestruct **inout_line, size_t *xpos)
{
linestruct *line = openfile->current;
linestruct *line = *inout_line;
const char *pointer, *found;
if (reverse) {
/* First step away from the current bracket. */
if (openfile->current_x == 0) {
if (*xpos == 0) {
line = line->prev;
if (line == NULL)
return FALSE;
pointer = line->data + strlen(line->data);
} else
pointer = line->data + step_left(line->data, openfile->current_x);
pointer = line->data + step_left(line->data, *xpos);
/* Now seek for any of the two brackets we are interested in. */
while (!(found = mbrevstrpbrk(line->data, bracket_pair, pointer))) {
@@ -898,7 +1013,7 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
pointer = line->data + strlen(line->data);
}
} else {
pointer = line->data + step_right(line->data, openfile->current_x);
pointer = line->data + step_right(line->data, *xpos);
while (!(found = mbstrpbrk(pointer, bracket_pair))) {
line = line->next;
@@ -908,45 +1023,24 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
}
}
/* Set the current position to the found bracket. */
openfile->current = line;
openfile->current_x = found - line->data;
/* Set the found position to the found bracket. */
*inout_line = line;
*xpos = found - line->data;
return TRUE;
}
/* Search for a match to the bracket at the current cursor position, if
* there is one. */
void do_find_bracket(void)
/* Search for the given bracket's compliment within matchbrackets.
* ch must be a pointer to within matchbrackets.
* reverse is true if the found compliment came before ch in matchbrackets. */
const char *get_bracket_compliment(const char *ch, bool *reverse)
{
linestruct *was_current = openfile->current;
size_t was_current_x = openfile->current_x;
/* The current cursor position, in case we don't find a complement. */
const char *ch;
/* The location in matchbrackets of the bracket under the cursor. */
int ch_len;
/* The length of ch in bytes. */
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
int wanted_ch_len;
/* The length of wanted_ch in bytes. */
char bracket_pair[MAXCHARLEN * 2 + 1];
/* The pair of characters in ch and wanted_ch. */
size_t halfway = 0;
/* The index in matchbrackets where the closing brackets start. */
size_t charcount = mbstrlen(matchbrackets) / 2;
/* Half the number of characters in matchbrackets. */
size_t balance = 1;
/* The initial bracket count. */
bool reverse;
/* The direction we search. */
ch = mbstrchr(matchbrackets, openfile->current->data + openfile->current_x);
if (ch == NULL) {
statusline(AHEM, _("Not a bracket"));
return;
}
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
size_t halfway = 0;
/* The index in matchbrackets where the closing brackets start. */
/* Find the halfway point in matchbrackets, where the closing ones start. */
for (size_t i = 0; i < charcount; i++)
@@ -954,19 +1048,34 @@ void do_find_bracket(void)
/* When on a closing bracket, we have to search backwards for a matching
* opening bracket; otherwise, forward for a matching closing bracket. */
reverse = (ch >= (matchbrackets + halfway));
*reverse = (ch >= (matchbrackets + halfway));
/* Step half the number of total characters either backwards or forwards
* through matchbrackets to find the wanted complementary bracket. */
wanted_ch = ch;
while (charcount-- > 0) {
if (reverse)
wanted_ch = matchbrackets + step_left(matchbrackets,
wanted_ch - matchbrackets);
if (*reverse)
wanted_ch = matchbrackets + step_left(matchbrackets, wanted_ch - matchbrackets);
else
wanted_ch += char_length(wanted_ch);
}
return wanted_ch;
}
/* Create a bracket pair string from the given bracket in ch, assigning
* the result to bracket_pair. Reverse is set to true if we need to
* search backward for a match. */
void create_bracket_pair(char *bracket_pair, const char *ch,
int ch_len, bool* reverse)
{
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
int wanted_ch_len;
/* The length of wanted_ch in bytes. */
wanted_ch = get_bracket_compliment(ch, reverse);
ch_len = char_length(ch);
wanted_ch_len = char_length(wanted_ch);
@@ -974,24 +1083,64 @@ void do_find_bracket(void)
strncpy(bracket_pair, ch, ch_len);
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
bracket_pair[ch_len + wanted_ch_len] = '\0';
}
while (find_a_bracket(reverse, bracket_pair)) {
/* Increment/decrement balance for an identical/other bracket. */
balance += (strncmp(openfile->current->data + openfile->current_x,
ch, ch_len) == 0) ? 1 : -1;
/* Get the bracket match position for the character currently under the cursor.
* If there is no bracket beneath the cursor, return NOT_A_BRACKET. If there is
* no match found, return NOT_FOUND_BRACKET. Otherwise returns FOUND_BRACKET
* and sets line and xpos to the found line and offset respectively. */
int find_matching_bracket_pos(linestruct **line, size_t *xpos)
{
const char *br_ch;
/* The location in matchbrackets of the bracket under the cursor. */
int br_ch_len;
/* The length of br_ch in bytes. */
char bracket_pair[MAXCHARLEN * 2 + 1];
/* The pair of characters in ch and wanted_ch. */
size_t balance = 1;
/* The initial bracket count. */
bool reversed;
/* The direction we search. */
/* When balance reached zero, we've found the complementary bracket. */
if (balance == 0) {
edit_redraw(was_current, FLOWING);
return;
}
br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
if (br_ch == NULL)
return NOT_A_BRACKET;
br_ch_len = char_length(br_ch);
create_bracket_pair(bracket_pair, br_ch, br_ch_len, &reversed);
while (find_a_bracket(reversed, bracket_pair, line, xpos)) {
balance += (strncmp((*line)->data + *xpos,
br_ch, br_ch_len) == 0) ? 1 : -1;
if (balance == 0)
return FOUND_BRACKET;
}
return NOT_FOUND_BRACKET;
}
/* Search for a match to the bracket at the current cursor position, if
* there is one. */
void do_find_bracket(void)
{
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
int res = find_matching_bracket_pos(&openfile->current,
&openfile->current_x);
if (res == FOUND_BRACKET) {
UNFOLD_SEGMENT(openfile->current);
edit_redraw(was_current, FLOWING);
return;
}
statusline(AHEM, _("No matching bracket"));
/* Restore the cursor position. */
openfile->current = was_current;
openfile->current_x = was_current_x;
openfile->current_x = was_x;
}
/* Place an anchor at the current line when none exists, otherwise remove it. */
@@ -999,12 +1148,17 @@ void put_or_lift_anchor(void)
{
openfile->current->has_anchor = !openfile->current->has_anchor;
update_line(openfile->current, openfile->current_x);
if (openfile->current->has_anchor)
statusline(REMARK, _("Placed anchor"));
if (openfile->current != openfile->filetop)
update_line(openfile->current, openfile->current_x);
else
statusline(REMARK, _("Removed anchor"));
refresh_needed = TRUE;
if (!ISSET(LINE_NUMBERS) && (!ISSET(MINIBAR) || ISSET(ZERO))) {
if (openfile->current->has_anchor)
statusline(REMARK, _("Placed anchor"));
else
statusline(HUSH, _("Removed anchor"));
}
}
/* Make the given line the current line, or report the anchoredness. */
@@ -1015,13 +1169,15 @@ void go_to_and_confirm(linestruct *line)
if (line != openfile->current) {
openfile->current = line;
openfile->current_x = 0;
UNFOLD_SEGMENT(openfile->current);
#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"));
if (!ISSET(LINE_NUMBERS))
statusbar(_("Jumped to anchor"));
} else if (openfile->current->has_anchor)
statusline(REMARK, _("This is the only anchor"));
else

View File

@@ -1,12 +1,12 @@
/**************************************************************************
* text.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2026 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-2022 Benno Schulenberg *
* Copyright (C) 2015-2022, 2024, 2026 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 *
@@ -19,7 +19,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -32,17 +32,6 @@
#include <unistd.h>
#include <sys/wait.h>
#if defined(__APPLE__) && !defined(st_mtim)
#define st_mtim st_mtimespec
#endif
#ifdef ENABLE_WORDCOMPLETION
static int pletion_x = 0;
/* The x position in pletion_line of the last found completion. */
static completionstruct *list_of_completions;
/* A linked list of the completions that have been attempted. */
#endif
#ifndef NANO_TINY
/* Toggle the mark. */
void do_mark(void)
@@ -64,6 +53,12 @@ void do_mark(void)
* of spaces that a tab would normally take up at this position. */
void do_tab(void)
{
#ifndef NANO_TINY
/* When <Tab> is pressed while a region is marked, indent the region. */
if (openfile->mark && openfile->mark != openfile->current)
do_indent();
else
#endif
#ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->tabstring)
inject(openfile->syntax->tabstring, strlen(openfile->syntax->tabstring));
@@ -96,6 +91,8 @@ void indent_a_line(linestruct *line, char *indentation)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Add the fabricated indentation to the beginning of the line. */
line->data = nrealloc(line->data, length + indent_len + 1);
memmove(line->data + indent_len, line->data, length + 1);
@@ -226,6 +223,8 @@ void unindent_a_line(linestruct *line, size_t indent_len)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Remove the first tab's worth of whitespace from this line. */
memmove(line->data, line->data + indent_len, length - indent_len + 1);
@@ -283,7 +282,7 @@ void handle_indent_action(undostruct *u, bool undoing, bool add_indent)
goto_line_posx(u->head_lineno, u->head_x);
/* For each line in the group, add or remove the individual indent. */
while (line != NULL && line->lineno <= group->bottom_line) {
while (line && line->lineno <= group->bottom_line) {
char *blanks = group->indentations[line->lineno - group->top_line];
if (undoing ^ add_indent)
@@ -317,6 +316,8 @@ bool comment_line(undo_type action, linestruct *line, const char *comment_seq)
/* Length of postfix. */
size_t line_len = strlen(line->data);
UNFOLD_SEGMENT(line);
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
return FALSE;
@@ -437,9 +438,8 @@ void handle_comment_action(undostruct *u, bool undoing, bool add_comment)
while (group) {
linestruct *line = line_from_number(group->top_line);
while (line != NULL && line->lineno <= group->bottom_line) {
comment_line(undoing ^ add_comment ?
COMMENT : UNCOMMENT, line, u->strdata);
while (line && line->lineno <= group->bottom_line) {
comment_line(undoing ^ add_comment ? COMMENT : UNCOMMENT, line, u->strdata);
line = line->next;
}
@@ -560,8 +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)) {
openfile->current = openfile->filebot;
openfile->current_x = 0;
goto_line_posx(openfile->filebot->lineno, 0);
focusing = FALSE;
break;
}
line->data[u->tail_x] = '\0';
@@ -573,8 +573,6 @@ void do_undo(void)
break;
case REPLACE:
undidmsg = _("replacement");
if ((u->xflags & INCLUDED_LAST_LINE) && !ISSET(NO_NEWLINES))
remove_magicline();
data = u->strdata;
u->strdata = line->data;
line->data = data;
@@ -625,12 +623,12 @@ void do_undo(void)
case COUPLE_BEGIN:
undidmsg = u->strdata;
goto_line_posx(u->head_lineno, u->head_x);
openfile->current_y = u->tail_lineno;
openfile->cursor_row = u->tail_lineno;
adjust_viewport(STATIONARY);
break;
case COUPLE_END:
/* Remember the row of the cursor for a possible redo. */
openfile->current_undo->head_lineno = openfile->current_y;
openfile->current_undo->head_lineno = openfile->cursor_row;
openfile->current_undo = openfile->current_undo->next;
do_undo();
do_undo();
@@ -671,8 +669,8 @@ void do_undo(void)
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT)
perturbed = TRUE;
else if (u->type == INSERT || u->type == COUPLE_BEGIN)
recook = TRUE;
#endif
/* When at the point where the buffer was last saved, unset "Modified". */
@@ -752,8 +750,6 @@ void do_redo(void)
break;
case REPLACE:
redidmsg = _("replacement");
if ((u->xflags & INCLUDED_LAST_LINE) && !ISSET(NO_NEWLINES))
new_magicline();
data = u->strdata;
u->strdata = line->data;
line->data = data;
@@ -766,6 +762,7 @@ void do_redo(void)
do_redo();
u = openfile->current_undo;
goto_line_posx(u->head_lineno, u->head_x);
ensure_firstcolumn_is_aligned();
break;
case SPLIT_END:
redidmsg = _("addition");
@@ -803,7 +800,7 @@ void do_redo(void)
case COUPLE_END:
redidmsg = u->strdata;
goto_line_posx(u->tail_lineno, u->tail_x);
openfile->current_y = u->head_lineno;
openfile->cursor_row = u->head_lineno;
adjust_viewport(STATIONARY);
break;
case INDENT:
@@ -841,7 +838,7 @@ void do_redo(void)
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT)
else if (u->type == INSERT || u->type == COUPLE_END)
recook = TRUE;
#endif
@@ -859,6 +856,12 @@ void do_enter(void)
{
linestruct *newnode = make_new_node(openfile->current);
size_t extra = 0;
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
newnode->folded = TRUE;
openfile->current->folded = FALSE;
}
#endif
#ifndef NANO_TINY
linestruct *sampleline = openfile->current;
bool allblanks = FALSE;
@@ -867,7 +870,7 @@ void do_enter(void)
#ifdef ENABLE_JUSTIFY
/* When doing automatic long-line wrapping and the next line is
* in this same paragraph, use its indentation as the model. */
if (ISSET(BREAK_LONG_LINES) && sampleline->next != NULL &&
if (ISSET(BREAK_LONG_LINES) && sampleline->next &&
inpar(sampleline->next) && !begpar(sampleline->next, 0))
sampleline = sampleline->next;
#endif
@@ -880,17 +883,25 @@ void do_enter(void)
allblanks = (indent_length(openfile->current->data) == extra);
}
#endif /* NANO_TINY */
newnode->data = nmalloc(strlen(openfile->current->data +
openfile->current_x) + extra + 1);
strcpy(&newnode->data[extra], openfile->current->data +
openfile->current_x);
newnode->data = nmalloc(strlen(openfile->current->data + openfile->current_x) + extra + 1);
strcpy(&newnode->data[extra], openfile->current->data + openfile->current_x);
#ifndef NANO_TINY
/* Adjust the mark if it is on the current line after the cursor. */
if (openfile->mark == openfile->current && openfile->mark_x > openfile->current_x) {
openfile->mark = newnode;
openfile->mark_x += extra - openfile->current_x;
}
if (ISSET(AUTOINDENT)) {
/* Copy the whitespace from the sample line to the new one. */
strncpy(newnode->data, sampleline->data, extra);
/* If there were only blanks before the cursor, trim them. */
if (allblanks)
openfile->current_x = 0;
if (allblanks && openfile->mark == openfile->current)
openfile->mark_x = 0;
}
#endif
@@ -899,13 +910,6 @@ void do_enter(void)
#ifndef NANO_TINY
add_undo(ENTER, NULL);
/* Adjust the mark if it was on the current line after the cursor. */
if (openfile->mark == openfile->current &&
openfile->mark_x > openfile->current_x) {
openfile->mark = newnode;
openfile->mark_x += extra - openfile->current_x;
}
#endif
/* Insert the newly created line after the current one and renumber. */
@@ -937,15 +941,14 @@ void discard_until(const undostruct *thisitem)
undostruct *dropit = openfile->undotop;
groupstruct *group;
while (dropit != NULL && dropit != thisitem) {
while (dropit && dropit != thisitem) {
openfile->undotop = dropit->next;
free(dropit->strdata);
free_lines(dropit->cutbuffer);
group = dropit->grouping;
while (group != NULL) {
while (group) {
groupstruct *next = group->next;
free_chararray(group->indentations,
group->bottom_line - group->top_line + 1);
free_chararray(group->indentations, group->bottom_line - group->top_line + 1);
free(group);
group = next;
}
@@ -1011,13 +1014,13 @@ void add_undo(undo_type action, const char *message)
case BACK:
/* If the next line is the magic line, don't ever undo this
* backspace, as it won't actually have deleted anything. */
if (thisline->next == openfile->filebot && thisline->data[0] != '\0')
if (thisline->next == openfile->filebot && thisline->data[0])
u->xflags |= WAS_BACKSPACE_AT_EOF;
/* Fall-through. */
case DEL:
/* When not at the end of a line, store the deleted character;
* otherwise, morph the undo item into a line join. */
if (thisline->data[openfile->current_x] != '\0') {
if (thisline->data[openfile->current_x]) {
int charlen = char_length(thisline->data + u->head_x);
u->strdata = measured_copy(thisline->data + u->head_x, charlen);
@@ -1026,7 +1029,7 @@ void add_undo(undo_type action, const char *message)
break;
}
action = JOIN;
if (thisline->next != NULL) {
if (thisline->next) {
if (u->type == BACK) {
u->head_lineno = thisline->next->lineno;
u->head_x = 0;
@@ -1037,8 +1040,6 @@ void add_undo(undo_type action, const char *message)
break;
case REPLACE:
u->strdata = copy_of(thisline->data);
if (thisline == openfile->filebot && answer[0] != '\0')
u->xflags |= INCLUDED_LAST_LINE;
break;
#ifdef ENABLE_WRAPPING
case SPLIT_BEGIN:
@@ -1082,7 +1083,7 @@ void add_undo(undo_type action, const char *message)
u->xflags |= INCLUDED_LAST_LINE;
break;
case COUPLE_BEGIN:
u->tail_lineno = openfile->current_y;
u->tail_lineno = openfile->cursor_row;
/* Fall-through. */
case COUPLE_END:
u->strdata = copy_of(_(message));
@@ -1095,7 +1096,11 @@ void add_undo(undo_type action, const char *message)
#endif
break;
default:
#ifdef DEBUG
die("Bad undo type -- please report a bug\n");
#else
break;
#endif
}
openfile->last_action = action;
@@ -1144,8 +1149,10 @@ void update_undo(undo_type action)
char *textposition;
int charlen;
#ifdef DEBUG
if (u->type != action)
die("Mismatching undo type -- please report a bug\n");
#endif
u->newsize = openfile->totsize;
@@ -1194,7 +1201,7 @@ void update_undo(undo_type action)
case CUT:
if (u->type == ZAP)
u->cutbuffer = cutbuffer;
else if (cutbuffer != NULL) {
else if (cutbuffer) {
free_lines(u->cutbuffer);
u->cutbuffer = copy_buffer(cutbuffer);
} else
@@ -1204,7 +1211,7 @@ void update_undo(undo_type action)
size_t count = 0;
/* Find the end of the cut for the undo/redo, using our copy. */
while (bottomline->next != NULL) {
while (bottomline->next) {
bottomline = bottomline->next;
count++;
}
@@ -1226,7 +1233,11 @@ void update_undo(undo_type action)
u->tail_x = openfile->current_x;
break;
default:
#ifdef DEBUG
die("Bad undo type -- please report a bug\n");
#else
break;
#endif
}
}
#endif /* !NANO_TINY */
@@ -1259,8 +1270,7 @@ void do_wrap(void)
/* The length of the remainder. */
/* First find the last blank character where we can break the line. */
wrap_loc = break_line(line->data + lead_len,
wrap_at - wideness(line->data, lead_len), FALSE);
wrap_loc = break_line(line->data + lead_len, wrap_at - wideness(line->data, lead_len), FALSE);
/* If no wrapping point was found before end-of-line, we don't wrap. */
if (wrap_loc < 0 || lead_len + wrap_loc == line_len)
@@ -1313,18 +1323,18 @@ void do_wrap(void)
}
/* Join the next line to this one. */
do_delete();
expunge(DEL);
#ifdef ENABLE_JUSTIFY
/* If the leading part of the current line equals the leading part of
* what was the next line, then strip this second leading part. */
if (strncmp(line->data, line->data + openfile->current_x, lead_len) == 0)
for (size_t i = lead_len; i > 0; i--)
do_delete();
expunge(DEL);
#endif
/* Remove any extra blanks. */
while (is_blank_char(&line->data[openfile->current_x]))
do_delete();
expunge(DEL);
}
/* Go to the wrap location. */
@@ -1338,7 +1348,7 @@ void do_wrap(void)
while ((rear_x != typed_x || cursor_x >= wrap_loc) &&
is_blank_char(line->data + rear_x)) {
openfile->current_x = rear_x;
do_delete();
expunge(DEL);
rear_x = step_left(line->data, rear_x);
}
}
@@ -1346,6 +1356,12 @@ void do_wrap(void)
/* Now split the line. */
do_enter();
#ifndef NANO_TINY
/* When wrapping a partially visible line, adjust start-of-screen. */
if (openfile->edittop == line && openfile->firstcolumn > 0 && cursor_x >= wrap_loc)
go_forward_chunks(1, &openfile->edittop, &openfile->firstcolumn);
#endif
#ifdef ENABLE_JUSTIFY
/* If the original line has quoting, copy it to the spillage line. */
if (quot_len > 0) {
@@ -1400,12 +1416,12 @@ ssize_t break_line(const char *textstart, ssize_t goal, bool snap_at_nl)
/* The column number that corresponds to the position of the pointer. */
/* Skip over leading whitespace, where a line should never be broken. */
while (*pointer != '\0' && is_blank_char(pointer))
while (*pointer && is_blank_char(pointer))
pointer += advance_over(pointer, &column);
/* Find the last blank that does not overshoot the target column.
* When treating a help text, do not break in the keystrokes area. */
while (*pointer != '\0' && ((ssize_t)column <= goal)) {
while (*pointer && ((ssize_t)column <= goal)) {
if (is_blank_char(pointer) && (!inhelp || column > 17 || goal < 40))
lastblank = pointer;
#ifdef ENABLE_HELP
@@ -1441,7 +1457,7 @@ ssize_t break_line(const char *textstart, ssize_t goal, bool snap_at_nl)
pointer = lastblank + char_length(lastblank);
/* Skip any consecutive blanks after the last blank. */
while (*pointer != '\0' && is_blank_char(pointer)) {
while (*pointer && is_blank_char(pointer)) {
lastblank = pointer;
pointer += char_length(pointer);
}
@@ -1457,7 +1473,7 @@ size_t indent_length(const char *line)
{
const char *start = line;
while (*line != '\0' && is_blank_char(line))
while (*line && is_blank_char(line))
line += char_length(line);
return (line - start);
@@ -1543,7 +1559,7 @@ bool find_paragraph(linestruct **firstline, size_t *const linecount)
linestruct *line = *firstline;
/* When not currently in a paragraph, move forward to a line that is. */
while (!inpar(line) && line->next != NULL)
while (!inpar(line) && line->next)
line = line->next;
*firstline = line;
@@ -1570,8 +1586,7 @@ void concat_paragraph(linestruct *line, size_t count)
linestruct *next_line = line->next;
size_t next_line_len = strlen(next_line->data);
size_t next_quot_len = quote_length(next_line->data);
size_t next_lead_len = next_quot_len +
indent_length(next_line->data + next_quot_len);
size_t next_lead_len = next_quot_len + indent_length(next_line->data + next_quot_len);
size_t line_len = strlen(line->data);
/* We're just about to tack the next line onto this one. If
@@ -1582,9 +1597,9 @@ void concat_paragraph(linestruct *line, size_t count)
line->data[line_len] = '\0';
}
line->data = nrealloc(line->data,
line_len + next_line_len - next_lead_len + 1);
line->data = nrealloc(line->data, line_len + next_line_len - next_lead_len + 1);
strcat(line->data, next_line->data + next_lead_len);
UNFOLD_SEGMENT(line);
#ifndef NANO_TINY
line->has_anchor |= next_line->has_anchor;
#endif
@@ -1619,29 +1634,29 @@ void squeeze(linestruct *line, size_t skip)
* all blanks after it; 2) if it is punctuation, copy it plus a possible
* tailing bracket, and change at most two subsequent blanks to spaces, and
* pass over all blanks after these; 3) leave anything else unchanged. */
while (*from != '\0') {
while (*from) {
if (is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
while (*from != '\0' && is_blank_char(from))
while (*from && is_blank_char(from))
from += char_length(from);
} else if (mbstrchr(punct, from) != NULL) {
} else if (mbstrchr(punct, from)) {
copy_character(&from, &to);
if (*from != '\0' && mbstrchr(brackets, from) != NULL)
if (*from && mbstrchr(brackets, from))
copy_character(&from, &to);
if (*from != '\0' && is_blank_char(from)) {
if (*from && is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
}
if (*from != '\0' && is_blank_char(from)) {
if (*from && is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
}
while (*from != '\0' && is_blank_char(from))
while (*from && is_blank_char(from))
from += char_length(from);
} else
copy_character(&from, &to);
@@ -1694,8 +1709,14 @@ void rewrap_paragraph(linestruct **line, char *lead_string, size_t lead_len)
*line = (*line)->next;
}
#ifdef ENABLE_COLOR
/* If the new paragraph exceeds the viewport, recalculate the multidata. */
if ((*line)->lineno >= editwinrows)
recook = TRUE;
#endif
/* When possible, go to the line after the rewrapped paragraph. */
if ((*line)->next != NULL)
if ((*line)->next)
*line = (*line)->next;
}
@@ -1768,6 +1789,7 @@ void justify_text(bool whole_buffer)
/* The length of that later lead. */
ssize_t was_the_linenumber = openfile->current->lineno;
/* The line to return to after a full justification. */
bool marked_backward = (openfile->mark && !mark_is_before_cursor());
/* TRANSLATORS: This one goes with Undid/Redid messages. */
add_undo(COUPLE_BEGIN, N_("justification"));
@@ -1837,8 +1859,7 @@ void justify_text(bool whole_buffer)
secondary_lead = nmalloc(secondary_len + 1);
strncpy(secondary_lead, startline->data, quot_len);
strncpy(secondary_lead + quot_len, sampleline->data + other_quot_len,
other_white_len);
strncpy(secondary_lead + quot_len, sampleline->data + other_quot_len, other_white_len);
secondary_lead[secondary_len] = '\0';
/* Include preceding and succeeding leads into the marked region. */
@@ -1850,7 +1871,7 @@ void justify_text(bool whole_buffer)
linecount = endline->lineno - startline->lineno + (end_x > 0 ? 1 : 0);
/* Remember whether the end of the region was before the end-of-line. */
before_eol = endline->data[end_x] != '\0';
before_eol = (endline->data[end_x] != '\0');
} else
#endif /* NANO_TINY */
{
@@ -1871,7 +1892,8 @@ void justify_text(bool whole_buffer)
#endif
refresh_needed = TRUE;
return;
}
} else
openfile->current_x = 0;
/* Set the starting point of the paragraph. */
startline = openfile->current;
@@ -1887,7 +1909,7 @@ void justify_text(bool whole_buffer)
}
/* When possible, step one line further; otherwise, to line's end. */
if (endline->next != NULL) {
if (endline->next) {
endline = endline->next;
end_x = 0;
} else
@@ -1943,6 +1965,9 @@ void justify_text(bool whole_buffer)
free(secondary_lead);
free(primary_lead);
/* Keep as much of the marked region onscreen as possible. */
focusing = FALSE;
} else
#endif
{
@@ -1976,7 +2001,7 @@ void justify_text(bool whole_buffer)
update_undo(PASTE);
/* After justifying a backward-marked text, swap mark and cursor. */
if (openfile->mark && !mark_is_before_cursor()) {
if (marked_backward) {
linestruct *bottom = openfile->current;
size_t bottom_x = openfile->current_x;
@@ -2021,6 +2046,9 @@ void do_full_justify(void)
{
justify_text(WHOLE_BUFFER);
ran_a_tool = TRUE;
#ifdef ENABLE_COLOR
recook = TRUE;
#endif
}
#endif /* ENABLE_JUSTIFY */
@@ -2032,7 +2060,7 @@ void construct_argument_list(char ***arguments, char *command, char *filename)
char *element = strtok(copy_of_command, " ");
int count = 2;
while (element != NULL) {
while (element) {
*arguments = nrealloc(*arguments, ++count * sizeof(char *));
(*arguments)[count - 3] = element;
element = strtok(NULL, " ");
@@ -2153,6 +2181,10 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
if (spelling) {
terminal_init();
doupdate();
#ifndef NANO_TINY
if (the_window_resized)
regenerate_screen();
#endif
} else
full_refresh();
@@ -2326,23 +2358,23 @@ bool fix_spello(const char *word)
return proceed;
}
/* Run a spell-check on the given file, using 'spell' to produce a list of all
* misspelled words, then feeding those through 'sort' and 'uniq' to obtain an
* alphabetical list, which words are then offered one by one to the user for
* correction. */
void do_int_speller(const char *tempfile_name)
/* Use 'spell' to get a list of misspelled words, feed them through 'sort'
* and 'uniq', then offer them one by one to the user for correction. */
void spell_check(const char *tempfile_name)
{
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *misspellings, *pointer, *oneword;
long pipesize;
size_t buffersize, bytesread, totalread;
size_t buffersize, totalread;
ssize_t bytesread;
int errornumber;
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) {
if (pipe(spell_fd) < 0 || pipe(sort_fd) < 0 || pipe(uniq_fd) < 0) {
statusline(ALERT, _("Could not create pipe: %s"), strerror(errno));
return;
}
@@ -2352,7 +2384,7 @@ void do_int_speller(const char *tempfile_name)
/* Fork a process to run spell in. */
if ((pid_spell = fork()) == 0) {
/* Child: open the temporary file that holds the text to be checked. */
if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
if ((tempfile_fd = open(tempfile_name, O_RDONLY)) < 0)
exit(6);
/* Connect standard input to the temporary file. */
@@ -2455,8 +2487,9 @@ void do_int_speller(const char *tempfile_name)
pointer = misspellings + totalread;
}
*pointer = '\0';
errornumber = errno;
close(uniq_fd[0]);
*pointer = '\0';
block_sigwinch(FALSE);
@@ -2464,6 +2497,10 @@ void do_int_speller(const char *tempfile_name)
terminal_init();
doupdate();
/* When reading from the pipe went wrong, skip the spell fixes. */
if (bytesread < 0)
goto finale;
/* Save the settings of the global flags. */
memcpy(stash, flags, sizeof(flags));
@@ -2476,7 +2513,7 @@ void do_int_speller(const char *tempfile_name)
oneword = misspellings;
/* Process each of the misspelled words. */
while (*pointer != '\0') {
while (*pointer) {
if ((*pointer == '\r') || (*pointer == '\n')) {
*pointer = '\0';
if (oneword != pointer) {
@@ -2494,23 +2531,26 @@ void do_int_speller(const char *tempfile_name)
if (oneword != pointer)
fix_spello(oneword);
free(misspellings);
refresh_needed = TRUE;
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
finale:
free(misspellings);
refresh_needed = TRUE;
/* Process the end of the three processes. */
waitpid(pid_spell, &spell_status, 0);
waitpid(pid_sort, &sort_status, 0);
waitpid(pid_uniq, &uniq_status, 0);
if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
statusline(ALERT, _("Error invoking \"uniq\""));
else if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
statusline(ALERT, _("Error invoking \"sort\""));
else if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
statusline(ALERT, _("Error invoking \"spell\""));
if (!WIFEXITED(uniq_status) || WEXITSTATUS(uniq_status))
statusline(ALERT, _("Error invoking '%s'"), "uniq");
else if (!WIFEXITED(sort_status) || WEXITSTATUS(sort_status))
statusline(ALERT, _("Error invoking '%s'"), "sort");
else if (!WIFEXITED(spell_status) || WEXITSTATUS(spell_status))
statusline(ALERT, _("Error invoking '%s'"), "spell");
else if (bytesread < 0)
statusline(ALERT, _("Error reading pipe: %s"), strerror(errornumber));
else
statusline(REMARK, _("Finished checking spelling"));
#endif
@@ -2522,7 +2562,7 @@ void do_spell(void)
{
FILE *stream;
char *temp_name;
bool okay;
bool okay = FALSE;
ran_a_tool = TRUE;
@@ -2531,17 +2571,13 @@ void do_spell(void)
temp_name = safe_tempfile(&stream);
if (temp_name == NULL) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
return;
}
#ifndef NANO_TINY
if (openfile->mark)
okay = write_region_to_file(temp_name, stream, TEMPORARY, OVERWRITE);
if (temp_name && openfile->mark)
okay = write_region_to_file(temp_name, stream, SPECIAL);
else
#endif
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
if (temp_name)
okay = write_file(temp_name, stream, SPECIAL, NONOTES);
if (!okay) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
@@ -2555,7 +2591,7 @@ void do_spell(void)
if (alt_speller && *alt_speller)
treat(temp_name, alt_speller, TRUE);
else
do_int_speller(temp_name);
spell_check(temp_name);
unlink(temp_name);
free(temp_name);
@@ -2573,7 +2609,9 @@ void do_linter(void)
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *lintings, *pointer, *onelint;
long pipesize;
size_t buffersize, bytesread, totalread;
size_t buffersize, totalread;
ssize_t bytesread;
int errornumber;
bool parsesuccess = FALSE;
int lint_status, lint_fd[2];
pid_t pid_lint;
@@ -2586,7 +2624,7 @@ void do_linter(void)
if (in_restricted_mode())
return;
if (!openfile->syntax || !openfile->syntax->linter) {
if (!openfile->syntax || !openfile->syntax->linter || !*openfile->syntax->linter) {
statusline(AHEM, _("No linter is defined for this type of file"));
return;
}
@@ -2607,7 +2645,7 @@ void do_linter(void)
}
/* Create a pipe up front. */
if (pipe(lint_fd) == -1) {
if (pipe(lint_fd) < 0) {
statusline(ALERT, _("Could not create pipe: %s"), strerror(errno));
return;
}
@@ -2660,12 +2698,12 @@ void do_linter(void)
/* Block resizing signals while reading from the pipe. */
block_sigwinch(TRUE);
/* Read in the returned syntax errors. */
totalread = 0;
buffersize = pipesize + 1;
lintings = nmalloc(buffersize);
pointer = lintings;
/* Read in the returned syntax errors. */
while ((bytesread = read(lint_fd[0], pointer, pipesize)) > 0) {
totalread += bytesread;
buffersize += pipesize;
@@ -2673,16 +2711,21 @@ void do_linter(void)
pointer = lintings + totalread;
}
*pointer = '\0';
errornumber = errno;
close(lint_fd[0]);
*pointer = '\0';
block_sigwinch(FALSE);
/* When reading from the pipe went wrong, skip the linting. */
if (bytesread < 0)
goto epilog;
pointer = lintings;
onelint = lintings;
/* Now parse the output of the linter. */
while (*pointer != '\0') {
while (*pointer) {
if ((*pointer == '\r') || (*pointer == '\n')) {
*pointer = '\0';
if (onelint != pointer) {
@@ -2716,7 +2759,7 @@ void do_linter(void)
curlint = nmalloc(sizeof(lintstruct));
curlint->next = NULL;
curlint->prev = tmplint;
if (curlint->prev != NULL)
if (curlint->prev)
curlint->prev->next = curlint;
curlint->filename = copy_of(filename);
curlint->lineno = linenumber;
@@ -2735,6 +2778,7 @@ void do_linter(void)
pointer++;
}
epilog:
free(lintings);
/* Process the end of the linting process. */
@@ -2742,15 +2786,25 @@ void do_linter(void)
if (!WIFEXITED(lint_status) || WEXITSTATUS(lint_status) > 2) {
statusline(ALERT, _("Error invoking '%s'"), openfile->syntax->linter);
for (curlint = lints; curlint != NULL;) {
tmplint = curlint;
curlint = curlint->next;
free(tmplint->msg);
free(tmplint->filename);
free(tmplint);
}
return;
} else if (bytesread < 0) {
statusline(ALERT, _("Error reading pipe: %s"), strerror(errornumber));
return;
}
if (!parsesuccess) {
statusline(REMARK, _("Got 0 parsable lines from command: %s"),
openfile->syntax->linter);
statusline(REMARK, _("Got 0 parsable lines from command: %s"), openfile->syntax->linter);
return;
}
/* When the help lines are off and there is room, force them on. */
if (helpless && LINES > 5) {
UNSET(NO_HELP);
window_init();
@@ -2768,7 +2822,7 @@ void do_linter(void)
functionptrtype function;
struct stat lintfileinfo;
if (stat(curlint->filename, &lintfileinfo) != -1 &&
if (stat(curlint->filename, &lintfileinfo) == 0 &&
(openfile->statinfo == NULL ||
openfile->statinfo->st_ino != lintfileinfo.st_ino)) {
#ifdef ENABLE_MULTIBUFFER
@@ -2800,13 +2854,13 @@ void do_linter(void)
char *dontwantfile = copy_of(curlint->filename);
lintstruct *restlint = NULL;
while (curlint != NULL) {
while (curlint) {
if (strcmp(curlint->filename, dontwantfile) == 0) {
if (curlint == lints)
lints = curlint->next;
else
curlint->prev->next = curlint->next;
if (curlint->next != NULL)
if (curlint->next)
curlint->next->prev = curlint->prev;
tmplint = curlint;
curlint = curlint->next;
@@ -2852,12 +2906,13 @@ void do_linter(void)
/* Place the cursor to indicate the affected line. */
place_the_cursor();
UNFOLD_SEGMENT(openfile->current);
wnoutrefresh(midwin);
kbinput = get_kbinput(footwin, VISIBLE);
#ifndef NANO_TINY
if (kbinput == KEY_WINCH)
if (kbinput == THE_WINDOW_RESIZED)
continue;
#endif
function = func_from_key(kbinput);
@@ -2870,7 +2925,7 @@ void do_linter(void)
tmplint = NULL;
do_help();
} else if (function == do_page_up || function == to_prev_block) {
if (curlint->prev != NULL)
if (curlint->prev)
curlint = curlint->prev;
else if (last_wait != time(NULL)) {
statusbar(_("At first message"));
@@ -2880,7 +2935,7 @@ void do_linter(void)
statusline(NOTICE, "%s", curlint->msg);
}
} else if (function == do_page_down || function == to_next_block) {
if (curlint->next != NULL)
if (curlint->next)
curlint = curlint->next;
else if (last_wait != time(NULL)) {
statusbar(_("At last message"));
@@ -2927,7 +2982,7 @@ void do_formatter(void)
if (in_restricted_mode())
return;
if (!openfile->syntax || !openfile->syntax->formatter) {
if (!openfile->syntax || !openfile->syntax->formatter || !*openfile->syntax->formatter) {
statusline(AHEM, _("No formatter is defined for this type of file"));
return;
}
@@ -2938,8 +2993,8 @@ void do_formatter(void)
temp_name = safe_tempfile(&stream);
if (temp_name != NULL)
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
if (temp_name)
okay = write_file(temp_name, stream, SPECIAL, NONOTES);
if (!okay)
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
@@ -2993,7 +3048,7 @@ void count_lines_words_and_characters(void)
* incrementing the word count for each successful step. */
while (openfile->current->lineno < botline->lineno ||
(openfile->current == botline && openfile->current_x < bot_x)) {
if (do_next_word(FALSE))
if (do_next_word(FALSE, ALLOW_FOLDED))
words++;
}
@@ -3018,7 +3073,7 @@ void do_verbatim_input(void)
#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) {
if (ISSET(ZERO) && openfile->cursor_row == editwinrows - 1 && LINES > 1) {
edit_scroll(FORWARD);
edit_refresh();
}
@@ -3073,26 +3128,31 @@ char *copy_completion(char *text)
return word;
}
/* 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. */
/* 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 hits 'Complete' again, search
* and paste the next possible completion. */
void complete_a_word(void)
{
#ifdef ENABLE_MULTIBUFFER
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;
completionstruct *some_word;
#endif
static completionstruct *list_of_completions;
/* A linked list of the completions that have been attempted. */
static int pletion_x = 0;
/* The x position in `pletion_line` of the last found completion. */
#ifdef ENABLE_WRAPPING
bool was_set_wrapping = ISSET(BREAK_LONG_LINES);
#endif
size_t start_of_shard;
size_t shard_length = 0;
char *shard;
/* If this is a fresh completion attempt... */
if (pletion_line == NULL) {
/* Clear the list of words of a previous completion run. */
while (list_of_completions != NULL) {
while (list_of_completions) {
completionstruct *dropit = list_of_completions;
list_of_completions = list_of_completions->next;
free(dropit->word);
@@ -3103,7 +3163,9 @@ void complete_a_word(void)
openfile->last_action = OTHER;
/* Initialize the starting point for searching. */
#ifdef ENABLE_MULTIBUFFER
scouring = openfile;
#endif
pletion_line = openfile->filetop;
pletion_x = 0;
@@ -3140,9 +3202,12 @@ void complete_a_word(void)
shard[shard_length] = '\0';
/* Run through all of the lines in the buffer, looking for shard. */
while (pletion_line != NULL) {
ssize_t threshold = strlen(pletion_line->data) - shard_length - 1;
while (pletion_line) {
ssize_t threshold = strlen(pletion_line->data) - shard_length;
/* The point where we can stop searching for shard. */
completionstruct *some_word;
char *completion;
size_t i, j;
/* Traverse the whole line, looking for shard. */
for (i = pletion_x; (ssize_t)i < threshold; i++) {
@@ -3169,8 +3234,7 @@ void complete_a_word(void)
continue;
/* If this match is the shard itself, ignore it. */
if (pletion_line == openfile->current &&
i == openfile->current_x - shard_length)
if (pletion_line == openfile->current && i == openfile->current_x - shard_length)
continue;
completion = copy_completion(pletion_line->data + i);
@@ -3181,7 +3245,7 @@ void complete_a_word(void)
some_word = some_word->next;
/* If we've already tried this word, skip it. */
if (some_word != NULL) {
if (some_word) {
free(completion);
continue;
}
@@ -3226,7 +3290,7 @@ void complete_a_word(void)
}
/* The search has gone through all buffers. */
if (list_of_completions != NULL) {
if (list_of_completions) {
edit_refresh();
statusline(AHEM, _("No further matches"));
} else

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* utils.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019, 2020, 2026 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 *
@@ -15,7 +15,7 @@
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* along with this program. If not, see https://gnu.org/licenses/. *
* *
**************************************************************************/
@@ -28,27 +28,25 @@
#include <string.h>
#include <unistd.h>
/* Return the user's home directory. We use $HOME, and if that fails,
* we fall back on the home directory of the effective user ID. */
/* Set global variable `homedir` to the user's home directory. First try
* $HOME, otherwise consult the password database for the current UID. */
void get_homedir(void)
{
if (homedir == NULL) {
const char *homenv = getenv("HOME");
#ifdef HAVE_PWD_H
/* When HOME isn't set, or when we're root, get the home directory
* from the password file instead. */
/* When $HOME is unset, or when we're root, try the database. */
if (homenv == NULL || geteuid() == ROOT_UID) {
const struct passwd *userage = getpwuid(geteuid());
if (userage != NULL)
if (userage)
homenv = userage->pw_dir;
}
#endif
/* Only set homedir if some home directory could be determined,
* otherwise keep homedir NULL. */
if (homenv != NULL && *homenv != '\0')
/* Only set `homedir` if a home directory could be determined. */
if (homenv && *homenv)
homedir = copy_of(homenv);
}
}
@@ -118,7 +116,7 @@ bool parse_num(const char *string, ssize_t *result)
value = (ssize_t)strtol(string, &excess, 10);
if (errno == ERANGE || *string == '\0' || *excess != '\0')
if (errno == ERANGE || *string == '\0' || *excess)
return FALSE;
*result = value;
@@ -126,29 +124,30 @@ bool parse_num(const char *string, ssize_t *result)
return TRUE;
}
/* Read two numbers, separated by a comma, from str, and store them in
* *line and *column. Return FALSE on error, and TRUE otherwise. */
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
/* Read one number (or two numbers separated by comma, period, or colon)
* from the given string and store the number(s) in *line (and *column).
* Return FALSE on a failed parsing, and TRUE otherwise. */
bool parse_line_column(const char *string, ssize_t *line, ssize_t *column)
{
const char *comma;
char *firstpart;
bool retval;
while (*str == ' ')
str++;
while (*string == ' ')
string++;
comma = strpbrk(str, ",.:");
comma = strpbrk(string, ",.:");
if (comma == NULL)
return parse_num(str, line);
return parse_num(string, line);
retval = parse_num(comma + 1, column);
if (comma == str)
if (comma == string)
return retval;
firstpart = copy_of(str);
firstpart[comma - str] = '\0';
firstpart = copy_of(string);
firstpart[comma - string] = '\0';
retval = parse_num(firstpart, line) && retval;
@@ -174,7 +173,7 @@ size_t recode_LF_to_NUL(char *string)
{
char *beginning = string;
while (*string != '\0') {
while (*string) {
if (*string == '\n')
*string = '\0';
string++;
@@ -198,16 +197,13 @@ void free_chararray(char **array, size_t len)
#endif
#ifdef ENABLE_SPELLER
/* Is the word starting at the given position in 'text' and of the given
/* Is the word starting at the given position in `text` and of the given
* length a separate word? That is: is it not part of a longer word? */
bool is_separate_word(size_t position, size_t length, const char *text)
{
const char *before = text + step_left(text, position);
const char *after = text + position + length;
/* If the word starts at the beginning of the line OR the character before
* the word isn't a letter, and if the word ends at the end of the line OR
* the character after the word isn't a letter, we have a whole word. */
return ((position == 0 || !is_alpha_char(before)) &&
(*after == '\0' || !is_alpha_char(after)));
}
@@ -218,8 +214,7 @@ bool is_separate_word(size_t position, size_t length, const char *text)
* than the given start; otherwise, we find the first match starting no earlier
* than start. If we are doing a regexp search, and we find a match, we fill
* in the global variable regmatches with at most 9 subexpression matches. */
const char *strstrwrapper(const char *haystack, const char *needle,
const char *start)
const char *strstrwrapper(const char *haystack, const char *needle, const char *start)
{
if (ISSET(USE_REGEXP)) {
if (ISSET(BACKWARDS_SEARCH)) {
@@ -249,16 +244,14 @@ const char *strstrwrapper(const char *haystack, const char *needle,
next_rung = step_right(haystack, last_find);
regmatches[0].rm_so = next_rung;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 1, regmatches,
REG_STARTEND) != 0)
if (regexec(&search_regexp, haystack, 1, regmatches, REG_STARTEND) != 0)
break;
}
/* Find the last match again, to get possible submatches. */
regmatches[0].rm_so = floor;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
if (regexec(&search_regexp, haystack, 10, regmatches, REG_STARTEND) != 0)
return NULL;
return haystack + regmatches[0].rm_so;
@@ -267,8 +260,7 @@ const char *strstrwrapper(const char *haystack, const char *needle,
/* Do a forward regex search from the starting point. */
regmatches[0].rm_so = start - haystack;
regmatches[0].rm_eo = strlen(haystack);
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
if (regexec(&search_regexp, haystack, 10, regmatches, REG_STARTEND) != 0)
return NULL;
else
return haystack + regmatches[0].rm_so;
@@ -351,6 +343,22 @@ char *free_and_assign(char *dest, char *src)
* displayed in the edit window when the cursor is at the given column. */
size_t get_page_start(size_t column)
{
#ifndef NANO_TINY
if (united_sidescroll) {
if (column < CUSHION)
return 0;
else if (column < openfile->brink + CUSHION) {
if (ISSET(JUMPY_SCROLLING))
return (column > editwincols / 2) ? column - editwincols / 2 : 0;
else
return column - CUSHION;
} else if (column > openfile->brink + editwincols - CUSHION - 1)
return column - editwincols + (ISSET(JUMPY_SCROLLING) ? editwincols / 2 : CUSHION) + 1;
else
return openfile->brink;
}
#endif
if (column == 0 || column + 2 < editwincols || ISSET(SOFTWRAP))
return 0;
else if (editwincols > 8)
@@ -359,15 +367,8 @@ size_t get_page_start(size_t column)
return column - (editwincols - 2);
}
/* Return the placewewant associated with current_x, i.e. the zero-based
* column position of the cursor. */
size_t xplustabs(void)
{
return wideness(openfile->current->data, openfile->current_x);
}
/* Return the index in text of the character that (when displayed) will
* not overshoot the given column. */
/* Return the index in the given text of the character that (when displayed)
* will not overshoot the given column. */
size_t actual_x(const char *text, size_t column)
{
const char *start = text;
@@ -375,7 +376,7 @@ size_t actual_x(const char *text, size_t column)
size_t width = 0;
/* The current accumulated span, in columns. */
while (*text != '\0') {
while (*text) {
int charlen = advance_over(text, &width);
if (width > column)
@@ -387,22 +388,21 @@ size_t actual_x(const char *text, size_t column)
return (text - start);
}
/* A strnlen() with tabs and multicolumn characters factored in:
* how many columns wide are the first maxlen bytes of text? */
size_t wideness(const char *text, size_t maxlen)
/* Return the number of columns that the first count bytes of text occupy. */
size_t wideness(const char *text, size_t count)
{
size_t width = 0;
if (maxlen == 0)
if (count == 0)
return 0;
while (*text != '\0') {
while (*text) {
size_t charlen = advance_over(text, &width);
if (maxlen <= charlen)
if (count <= charlen)
break;
maxlen -= charlen;
count -= charlen;
text += charlen;
}
@@ -414,12 +414,18 @@ size_t breadth(const char *text)
{
size_t span = 0;
while (*text != '\0')
while (*text)
text += advance_over(text, &span);
return span;
}
/* Return the (zero-based) column position of the cursor. */
size_t xplustabs(void)
{
return wideness(openfile->current->data, openfile->current_x);
}
/* Append a new magic line to the end of the buffer. */
void new_magicline(void)
{
@@ -434,8 +440,9 @@ void new_magicline(void)
* it isn't the only line in the file. */
void remove_magicline(void)
{
if (openfile->filebot->data[0] == '\0' &&
openfile->filebot != openfile->filetop) {
if (openfile->filebot->data[0] == '\0' && openfile->filebot != openfile->filetop) {
if (openfile->current == openfile->filebot)
openfile->current = openfile->current->prev;
openfile->filebot = openfile->filebot->prev;
delete_node(openfile->filebot->next);
openfile->filebot->next = NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,6 @@ pkgdata_DATA = asm.nanorc \
c.nanorc \
css.nanorc \
default.nanorc \
elisp.nanorc \
email.nanorc \
go.nanorc \
groff.nanorc \

View File

@@ -1,15 +1,18 @@
## Syntax highlighting for assembler.
## Original author: Mike Frysinger
## License: GPL version 3 or newer
syntax asm "\.(S|s|asm)$"
magic "assembler source"
comment "//"
color red "\<[A-Z_]{2,}\>"
color brightgreen "\.(data|subsection|text)"
color green "\.(align|file|globl|global|hidden|section|size|type|weak)"
color brightyellow "\.(ascii|asciz|byte|double|float|hword|int|long|short|single|struct|word)"
color brightred "^[[:blank:]]*[.0-9A-Za-z_]*:"
color brightcyan "^[[:blank:]]*#[[:blank:]]*(define|undef|include|ifn?def|endif|elif|else|if|warning|error)"
color red "\<[[:alpha:]_]{2,}\>"
color brightgreen "\.(data|subsection|text)\>"
color green "\.(align|file|globl|global|hidden|section|size|type|weak)\>"
color brightyellow "\.(ascii|asciz|byte|double|float|hword|int|long|short|single|struct|word)\>"
color brightred "^[[:blank:]]*[[:alnum:]_.]*:"
color brightcyan "^[[:blank:]]*#[[:blank:]]*(define|undef|include|ifn?def|endif|elif|else|if|warning|error)\>"
# Strings and names of included files.
color brightyellow ""([^"\]|\\.)*"|<[^= ]*>"

View File

@@ -7,11 +7,11 @@ syntax autoconf "\.(ac|m4)$"
comment "#"
# Keywords:
color yellow "\<(if|test|then|elif|else|fi|for|in|do|done)\>"
color yellow "\<(if|test|then|elif|else|fi|case|esac|ifelse|for|in|do|done)\>"
color yellow "=|!=|&&|\|\|"
# Macros:
color cyan "\<[[:upper:]_[:digit:]]+\>"
color cyan "\<[[:upper:][:digit:]_]+\>"
# Version numbers:
color red "\<[-_.0-9]+\>"
@@ -29,7 +29,7 @@ color brightred "^[[:blank:]]*\*\*\*.*"
color magenta "\[|\]|\(|\)"
# Comments:
color blue "^[[:blank:]]*#.*" "\<dnl.*"
color blue "^[[:blank:]]*#.*|\<dnl.*"
# Trailing whitespace:
color ,green "[[:space:]]+$"

View File

@@ -1,20 +1,22 @@
## Syntax highlighting for AWK scripts.
## Original author: Donnie Berkholz
syntax awk "\.awk$"
header "^#!.*awk"
magic "awk script"
comment "#"
# Records.
color brightred "\$[0-9A-Za-z_!@#$*?-]+"
color brightred "\$[[:alnum:]_!@#$*?-]+"
# Awk-set variables.
color red "\<(ARGC|ARGIND|ARGV|BINMODE|CONVFMT|ENVIRON|ERRNO|FIELDWIDTHS)\>"
color red "\<(FILENAME|FNR|FS|IGNORECASE|LINT|NF|NR|OFMT|OFS|ORS)\>"
color red "\<(PROCINFO|RS|RT|RSTART|RLENGTH|SUBSEP|TEXTDOMAIN)\>"
# Function declarations and special patterns.
color brightgreen "\<(function|extension|BEGIN|END)\>"
# Operators.
color green "\{|\}|\(|\)|\;|\[|\]|\\|<|>|!|=|&|\+|-|\*|%|/|\?:|\^|\|"
# Operators and brackets/braces/slashes/parentheses.
color green "[][!%&()*+/:;<=>?\^{|}~-]"
# Flow control.
color brightyellow "\<(for|if|while|do|else|in|delete|exit)\>"
color brightyellow "\<(break|continue|return)\>"
@@ -30,6 +32,8 @@ color magenta "\<(bindtextdomain|dcgettext|dcngettext)\>"
# Strings.
color brightyellow ""([^"\]|\\.)*""
# Escape sequences.
color brick "\\([abfnrtv\/"]|[0-7]{1,3}|x[[:xdigit:]]{1,2}|u[[:xdigit:]]{1,8})"
# Comments.
color brightblue "(^|[[:blank:]])#.*"

View File

@@ -6,25 +6,29 @@ magic "^(C|C\+\+) (source|program)"
comment "//"
# Constants.
color brightred "\<[A-Z_][0-9A-Z_]*\>"
color brightred "\<[[:upper:]_][[:upper:][:digit:]_]*\>"
# Labels.
color brightmagenta "^[[:blank:]]*[A-Z_a-z][0-9A-Z_a-z]*:[[:blank:]]*$"
color brightmagenta "^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*:[[:blank:]]*$"
color normal ":[[:blank:]]*$"
# Types and related keywords.
color green "\<(auto|bool|char|const|double|enum|extern|float|inline|int|long|restrict|short|signed|sizeof|static|struct|typedef|union|unsigned|void)\>"
color green "\<([[:lower:]][[:lower:]_]*|(u_?)?int(8|16|32|64))_t\>"
color green "\<(_(Alignas|Alignof|Atomic|Bool|Complex|Generic|Imaginary|Noreturn|Static_assert|Thread_local))\>"
color green "\<(class|explicit|friend|mutable|namespace|override|private|protected|public|register|template|this|typename|using|virtual|volatile)\>"
color green "\<(bool|char|double|enum|float|int|short|(un)?signed|struct|union|void|((u_?)?int(8|16|32|64)|[[:lower:]][[:lower:]_]*)_t)\>"
color green "\<(align(as|of)|auto|const(eval|expr|init)?|extern|inline|register|restrict|sizeof|static(_assert)?|thread_local|typedef|typeof(_unqual)?|volatile)\>"
color green "\<(_(Align(as|of)|Atomic|BitInt|Bool|Complex|Decimal(32|64|128)|Generic|Imaginary|Noreturn|Static_assert|Thread_local))\>"
color green "\<(class|explicit|final|friend|mutable|namespace|override|private|protected|public|template|this|typename|using|virtual)\>"
color green "\<(char(8|16|32)_t|wchar_t|(const|dynamic|reinterpret|static)_cast|decltype|export|import|module|noexcept|requires|typeid)\>"
# Flow control.
color brightyellow "\<(if|else|for|while|do|switch|case|default)\>"
color brightyellow "\<(try|throw|catch|operator|new|delete)\>"
color magenta "\<(break|continue|goto|return)\>"
color magenta "\<(break|continue|goto|(co_)?return)\>"
# Single-quoted stuff (characters, backslash escapes, hex and octal byte codes).
color brightmagenta "'([^'\]|\\(["'\abfnrtv]|x[[:xdigit:]]{1,2}|[0-3]?[0-7]{1,2}))'"
# Hexadecimal, binary, and boolean values.
color pink "\<(0[Xx][[:xdigit:]]['[:xdigit:]]*|0[Bb][01]['01]*|true|false|nullptr)\>"
# GCC builtins.
color cyan "__attribute__[[:blank:]]*\(\([^)]*\)\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
@@ -32,11 +36,11 @@ color cyan "__attribute__[[:blank:]]*\(\([^)]*\)\)|__(aligned|asm|builtin|hidden
color brightyellow ""([^"]|\\")*"|#[[:blank:]]*include[[:blank:]]*<[^>]+>"
# Preprocessor directives.
color brightcyan start="^[[:blank:]]*#[[:blank:]]*(if(n?def)?|elif|warning|error|pragma)\>" end="(\`|[^\])$"
color brightcyan "^[[:blank:]]*#[[:blank:]]*((define|else|endif|include(_next)?|line|undef)\>|$)"
color brightcyan start="^[[:blank:]]*#[[:blank:]]*((el)?if(n?def)?|error|pragma|warning)\>" end="(\`|[^\])$"
color brightcyan "^[[:blank:]]*#[[:blank:]]*((define|else|embed|endif|include(_next)?|line|undef)\>|$)"
# Comments.
color brightblue "//.*"
color brightblue "//[^"]*$|(^|[[:blank:]])//.*"
color brightblue start="/\*" end="\*/"
# Reminders.

View File

@@ -8,24 +8,24 @@ syntax changelog "Change[Ll]og[^/]*$"
# Author lines.
color green "^(19|20).*"
# Dates.
color red "^(19|20)[0-9-]{8}"
color red "^(19|20)[[:digit:]-]{8}"
# Email addresses.
color yellow "<[^>]*@[^>]*>"
# Command-line options.
color cyan "[[:blank:]]-[a-zA-Z\$]|--[8a-z-]+"
color cyan "[[:blank:]]-[[:alpha:]$]|--[[:lower:]8-]+"
# Bug and patch numbers.
color cyan "(BZ|bug|patch)[ ]#[0-9]+|PR [[:alnum:]]+/[0-9]+"
color cyan "(BZ|bug|patch) #[[:digit:]]+|PR [[:alnum:]]+/[[:digit:]]+"
# Probable constants, for variety.
color brightred "\<[A-Z_][0-9A-Z_]+\>"
color brightred "\<[[:upper:]_][[:upper:][:digit:]_]+\>"
# Key sequences.
color brightblue "\^[A-Z^\]|\<M-.|\<F1?[0-9]|(\^|M-)Space"
color brightblue "\^[[:upper:]\^_]|\<M-.|\<F1?[[:digit:]]|(\^|M-)Space"
# Changed files.
color magenta start="^( | {8})\* " end="(:( |$)|^$)"
# Release markers.
color brightblue "^(GNU )?nano[- ][0-9]\.[0-9]\.[^ ]+"
color brightblue "^(GNU )?nano[- ][[:digit:]]\.[[:digit:]]\.[^ ]+"
# Trailing whitespace.
color ,green "[[:space:]]+$"

View File

@@ -1,9 +1,11 @@
## Syntax highlighting for CMake files.
## Original author: Felipe Bugno
syntax cmake "(CMakeLists\.txt|\.cmake)$"
comment "#"
color green "^[[:blank:]]*[0-9A-Za-z_]+"
color green "^[[:blank:]]*[[:alnum:]_]+"
icolor brightyellow "^[[:blank:]]*(include|include_directories|include_external_msproject)\>"
icolor brightgreen "^[[:blank:]]*((else|end)?if|else|(end)?while|(end)?foreach|break)\>"

View File

@@ -1,5 +1,7 @@
## Syntax highlighting for CSS files.
## Original author: Simon Rupf
syntax css "\.css$"
comment "/*|*/"

View File

@@ -8,8 +8,8 @@ comment "#"
color ,red " + +"
# Nano's release motto, then name plus version.
color italic,lime "\<[Nn]ano [1-7]\.[0-9][-.[:alnum:]]* "[^"]+""
color brightred "\<(GNU )?[Nn]ano [1-7]\.[0-9][-.[:alnum:]]*\>"
color italic,lime "\<[Nn]ano [1-9]\.[0-9][-.[:alnum:]]* "[^"]+""
color brightred "\<(GNU )?[Nn]ano [1-9]\.[0-9][-.[:alnum:]]*\>"
# Dates
color latte "\<[12][0-9]{3}\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])\>"
@@ -26,5 +26,8 @@ color brightgreen "^\[[^][]+\]$"
# Comments.
color cyan "^[[:blank:]]*#.*"
# Make hard (non-breaking) spaces noticeable.
color ,#444 " "
# Control codes.
color orange "[[:cntrl:]]"

View File

@@ -1,33 +0,0 @@
## Syntax highlighting for Emacs Lisp.
syntax elisp "\.el$"
magic "Lisp/Scheme program"
comment ";"
# Basic functions/macros
color brightcyan "\<(if|when|unless|cond|and|or|lambda|let|progn|while|dolist|dotimes)\>"
color brightcyan "\<save-((window-)?excursion|restriction)\>"
color brightcyan "\<eval-(and|when)-compile\>"
# Defining functions
color brightcyan "\<def(un|macro|subst|generic|alias)\>"
color brightcyan "\<cl-def(un|macro|subst|generic|struct|type)\>"
color brightcyan "\<define-(derived|minor|generic)-mode\>"
# Defining variables
color brightcyan "\<def(class|const|var(-local|alias)?)\>"
# Customization functions
color brightcyan "\<def(custom|face|group|theme)\>"
# Setting values
color brightcyan "\<(setq(-default|-local)?|setf|push|pop|declare(-function)?)\>"
# Feature functions
color brightcyan "\<(require|provide)\>"
# Quoted symbols
color brightyellow "#?'\<(\w|-)+\>"
# Booleans
color brightred "\<(t|nil)\>"
# Keywords
color blue ":(\w|[?-])+"
# Strings
color yellow start="^[[:blank:]]+"" end="[^\]""
color yellow ""([^"\]|\\.)*""
# Comments
color cyan "(^|[[:blank:]]);.*"

View File

@@ -1,5 +1,7 @@
## Syntax highlighting for Fortran 90/95.
## Original author: Pascal Gentil
syntax fortran "\.(f|for|f90|f95)$"
comment "!"
@@ -10,7 +12,7 @@ icolor green "\<(append|asis|assign|assignment|associated|character|common)\>"
icolor green "\<(complex|data|default|delim|dimension|double precision)\>"
icolor green "\<(elemental|epsilon|external|file|fmt|form|format|huge)\>"
icolor green "\<(implicit|include|index|inquire|integer|intent|interface)\>"
icolor green "\<(intrinsic|iostat|kind|logical|module|none|null|only)>"
icolor green "\<(intrinsic|iostat|kind|logical|module|none|null|only)\>"
icolor green "\<(operator|optional|pack|parameter|pointer|position|private)\>"
icolor green "\<(program|public|real|recl|recursive|selected_int_kind)\>"
icolor green "\<(selected_real_kind|subroutine|status)\>"

View File

@@ -1,5 +1,7 @@
## Syntax highlighting for POV-Ray files.
## Original author: Donnie Berkholz
syntax pov "\.(pov|POV|povray|POVRAY)$"
comment "//"

View File

@@ -1,5 +1,7 @@
## Syntax highlighting for RPM spec files.
## Original author: Asterios Dramis
syntax spec "\.spec(\.[^/]+)?$"
comment "#"
@@ -12,7 +14,9 @@ color brightblue "\<(AutoReq|AutoProv|AutoReqProv)[[:space:]]*:"
color brightblue "\<(License|Copyright|Distribution|Vendor|Packager)[[:space:]]*:"
color brightblue "\<((Source|Patch)[0-9]*|Nosource|Nopatch)[[:space:]]*:"
# Architectures.
color brightred "\<(i386|i486|i586|i686|athlon|ia64|alpha|alphaev5|alphaev56|alphapca56|alphaev6|alphaev67|sparc|sparcv9|sparc64armv3l|armv4b|armv4lm|ips|mipsel|ppc|ppciseries|ppcpseries|ppc64|m68k|m68kmint|Sgi|rs6000|i370|s390x?|noarch)\>"
color brightred "\<((a|loong)arch64|alpha(ev(56?|67?)|pca56)?|amd64|armv(3l|4b|4l|5t(ej?)?l|6h?l|7(hn?)?l|8h?l)|athlon|em64t|geode|i370|i(3|4|5|6)86|ia32e|ia64|m68k(mint)?|mips(64)?(el|r6|r6el)?)\>"
color brightred "\<(pentium(3|4)|ppc(32dy4|8260|8560)?|ppc64(le|p7)?|ppc(64)?(i|p)series|riscv64|rs6000|s390x?|sgi|sh(3|4|4a)?|sparc(64v?|v8|v9v?)?|x86_64(_v2|_v3|_v4)?|xtensa)\>"
# Architecture and OS conditionals.
color brightred "%(ifarch|elifarch|ifnarch|ifos|elifos|ifnos)\>"
# %* strings.

View File

@@ -42,7 +42,7 @@ color brightblue "//.*"
color brightblue start="/\*" end="\*/"
# Special comments.
color brightcyan "//[[:blank:]]*\+build[[:blank:]]+(([a-zA-Z_0-9]+[[:blank:]]*)+,[[:blank:]]*)*[a-zA-Z_0-9]+"
color brightcyan "//[[:blank:]]*\+build[[:blank:]]+(([[:alnum:]_]+[[:blank:]]*)+,[[:blank:]]*)*[[:alnum:]_]+"
# Trailing whitespace.
color ,green "[[:space:]]+$"

View File

@@ -1,6 +1,8 @@
## Syntax highlighting for groff.
syntax groff "\.(m[ems]|rof|tmac)$|/tmac\.[^/]+$"
## Original author: Robert D. Goulding
syntax groff "\.(me|mm|mom|ms|roff|tmac)$|/tmac\.[^/]+$"
comment ".\""
# The setting of a string or register
@@ -15,7 +17,7 @@ color cyan start="\\(\\)?n\[" end="]"
# Requests
color brightgreen "^\.[[:blank:]]*[^[:space:]]*"
# Comments
color yellow "^\.\\".*"
color yellow "(^\\#|(^\.)?\\").*"
# References to strings
color green "\\(\\)?\*(.|\(..)"
color green start="\\(\\)?\*\[" end="]"
@@ -23,4 +25,4 @@ color green start="\\(\\)?\*\[" end="]"
color brightred "\\\(.."
color brightred start="\\\[" end="]"
# Macro arguments
color brightcyan "\\\\\$[1-9]"
color brightcyan "\\\\\$[0-9]"

View File

@@ -1,23 +1,30 @@
## Syntax highlighting for Guile Scheme.
syntax guile "\.scm$"
## Original authors: Mark Oteiza and Benno Schulenberg
## License: GPL version 3 or newer
syntax guile "\.(scm|sld|sls|ss)$"
header "^#!.*guile"
comment ";"
# Basic scheme functions
color green "\<(do|if|lambda|let(rec)?|map|unless|when)\>"
# Basic syntax
color lightgreen "\<((and|begin|case|cond|do|else|if|lambda|let(rec)?|or|quote|unless|when)\>|let\*|set!)"
# Basic procedures
color lightcyan "\<((append|apply|c[ad]{1,4}r|cons|display|for-each|list|map|newline)\>|reverse(\>|!)|set-c[ad]r!)"
color lightcyan "\<(boolean|char(-ci)?[<>]?=?|complex|eqv?|even|integer|list|nan|negative|null|number|odd|pair|positive|rational|real|string|symbol|vector|zero)\?"
color lightcyan "\<(abs|a?(cos|sin|tan)|ceiling|exp|floor|max|min|modulo|not|random|round|quotient|sqrt|square|truncate)\>"
# Defining things
color brightcyan "\<define(-macro|-module|-public|-syntax)?\>"
color brightgreen "\<define(-macro|-module|-public|-syntax)?\>"
# Quoted symbols
color brightyellow "'\<(\w|-)+\>"
# Chars
color lightyellow "'(\w|[!$%&*+/:<=>?@^_~])(\w|[!$%&*+/:<=>?@^_~.0-9-])*"
# Characters
color brightmagenta "#\\(.|\w+)"
# Booleans
color brightred "(#t|#f)\>"
color brightred "#(t|true|f|false)\>"
# Keywords
color blue "#?:(\w|[?-])+"
color lagoon "#?:(\w|[?-])+"
# Strings
color yellow start="^[[:blank:]]+"" end="[^\]""
color yellow start="^[[:blank:]]*"([^"\]|\\.)*$" end="(^|[^\]|[^\]\\\\)""
color yellow ""([^"\]|\\.)*""
# Comments
color cyan "(^|[[:blank:]]);.*"
color italic,#aaa "(^|[[:blank:]]);.*"

View File

@@ -1,6 +1,7 @@
## Syntax highlighting for Javascript.
syntax javascript "\.js$"
syntax javascript "\.m?js$"
magic "JavaScript source"
comment "//"
# Declarational stuff.

Some files were not shown because too many files have changed in this diff Show More