Compare commits

..

6 Commits

Author SHA1 Message Date
960ff2f3bf Patch 06 2023-04-01 13:11:17 -07:00
75f480ba10 Patch 05 2023-04-01 13:05:03 -07:00
1e08853a8b Add missing line 2023-04-01 12:55:28 -07:00
c47c742e88 Patch 04 2023-04-01 12:50:14 -07:00
cb1507bdd4 add folding.c 2023-04-01 12:35:48 -07:00
e13b24e0ce 3 changes 2023-04-01 12:33:42 -07:00
122 changed files with 40605 additions and 46591 deletions

1
.gitignore vendored
View File

@@ -45,7 +45,6 @@ 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,15 +13,16 @@ Benno Schulenberg <bensberg@telfort.nl>
Current maintainer.
David Lawrence Ramsey <pooka109@gmail.com>
* 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.
* 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.
Jordi Mallach <jordi@gnu.org>
* Debian package maintainer, fellow bug squasher, translator
for Catalan. Former head of internationalization support.
* Debian package maintainer, fellow bug squasher.
* Internationalization support head, ca.po maintainer.
Adam Rogoyski <rogoyski@cs.utexas.edu>
* New write_file() function, read_file() optimization, mouse
@@ -34,9 +35,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
@@ -44,11 +45,11 @@ David Benbennick <dbenbenn@math.cornell.edu>
miscellaneous fixes.
Mike Frysinger <vapier@gentoo.org>
* 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.
* 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.
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 fix for bug #9 -- when tabs % 8 == 0, we should only
Added bug#9 fix - when tabs % 8 == 0, we should only
increment tabs by 1.
titlebar(): Fixed overrun in titlebar on very long filenames.

View File

@@ -1,24 +1,6 @@
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,109 +1,3 @@
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.
@@ -993,23 +887,26 @@
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 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!
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!
2009.12.12 - GNU nano 2.2.1 "DLR strikes back" is open for business.
This release fixes many bugs, including: missing
@@ -1694,7 +1591,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 9.2 filename Modified |
| GNU nano 7.2 filename Modified |
--------------------------------------------------------------------
| This is the text window, displaying the contents of a 'buffer', |
| the contents of the file you are editing. |
@@ -29,7 +29,7 @@ Appearance
| |
--------------------------------------------------------------------
| [ Some status message ] |
|^G Help ^O Write Out ^F Where Is ^K Cut ^T Execute |
|^G Help ^O Write Out ^W 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, see https://www.gnu.org/.
The nano editor is an official GNU package. For more information on
GNU and the Free Software Foundation, please see https://www.gnu.org/.
License
@@ -81,9 +81,7 @@ 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. And
use --sysconfdir=/etc when you want your self-compiled nano to read
the /etc/nanorc file.
to override the default installation directory of /usr/local.
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.20)
autopoint (version >= 0.18.3)
gcc (version >= 5.0)
gettext (version >= 0.20)
gettext (version >= 0.18.3)
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.git.savannah.gnu.org/nano.git
$ git clone git://git.savannah.gnu.org/nano.git
Generate the configure script
@@ -57,9 +57,6 @@ 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,7 +5,6 @@ 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
@@ -48,7 +47,6 @@ 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
@@ -81,7 +79,6 @@ 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,10 +2,9 @@
# Generate configure & friends for GIT users.
gnulib_url="git://git.sv.gnu.org/gnulib.git"
gnulib_hash="833eea6be5607a85bc964bf728a7a82ca461b5b1"
gnulib_hash="2cf7f442f52f70b3df6eb396eb93ea08e54883c5"
modules="
canonicalize-lgpl
futimens
getdelim
getline
@@ -19,20 +18,20 @@ modules="
regex
sigaction
snprintf-posix
stdarg-h
stdarg
strcase
strcasestr-simple
strnlen
sys_wait
vsnprintf-posix
wchar-h
wchar
wctype-h
wcwidth
"
# Make sure the local gnulib git repo is up-to-date.
if [ ! -d "gnulib" ]; then
git clone --depth=2222 ${gnulib_url}
git clone --depth=1111 ${gnulib_url}
fi
cd gnulib >/dev/null || exit 1
curr_hash=$(git log -1 --format=%H)
@@ -43,11 +42,20 @@ 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 "Autoreconf..."
autoreconf --install --symlink --force
echo "Aclocal..."
aclocal -I m4
echo "Autoconf..."
autoconf
echo "Autoheader..."
autoheader
echo "Automake..."
automake --add-missing
echo "Done."

View File

@@ -1,6 +1,6 @@
# Configuration for GNU nano - a small and user-friendly text editor
#
# Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc.
# Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
# Copyright (C) 2014, 2017 Mike Frysinger
#
# GNU nano is free software: you can redistribute it and/or modify
@@ -16,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], [9.2], [nano-devel@gnu.org], [nano])
AC_INIT([GNU nano], [7.2], [nano-devel@gnu.org], [nano])
AC_CONFIG_SRCDIR([src/nano.c])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.14])
@@ -48,7 +48,7 @@ PKG_PROG_PKG_CONFIG
dnl Internationalization macros.
AM_GNU_GETTEXT_VERSION([0.20])
AM_GNU_GETTEXT_VERSION([0.18.3])
AM_GNU_GETTEXT([external], [need-ngettext])
AM_CONDITIONAL(USE_NLS, test x$USE_NLS = xyes)

View File

@@ -12,8 +12,8 @@
<body>
<br>
<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>
<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>
<br>
<table align="center"><tbody>
@@ -33,6 +33,7 @@
<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>
@@ -42,10 +43,10 @@
<b>Search and replace</b>
<table><tbody>
<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>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>Alt+R</td><td>Start a replacing session</td></tr>
</tbody></table>
<br>
@@ -63,16 +64,11 @@
<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+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+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+;</td><td>Replay macro</td></tr>
</tbody></table>
<br>
@@ -81,8 +77,8 @@
<b>Moving around</b>
<table><tbody>
<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 &nbsp;&nbsp;</td><td>One character backward</td></tr>
<tr><td>Ctrl+F</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>
@@ -91,8 +87,6 @@
<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>
@@ -102,35 +96,33 @@
<b>Special movement</b>
<table><tbody>
<tr><td>Alt+G &nbsp;&nbsp;&nbsp;&nbsp;</td><td>Go to a specified line</td></tr>
<tr><td>Alt+G &nbsp;&nbsp;&nbsp;</td><td>Go to 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>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>
<tr><td>Alt+&lt;</td><td>Switch to preceding buffer</td></tr>
<tr><td>Alt+&gt;</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 counts</td></tr>
<tr><td>Alt+D</td><td>Report line/word/character count</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 &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+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+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+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>
<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>
</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. 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.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.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, git, ...)?</a><br>
<a href="#4.9">4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</a><br>
</p></blockquote>
<h3><a href="#5">5. Internationalization</a></h3>
<blockquote><p>
@@ -76,10 +76,10 @@
</p></blockquote>
<hr width="100%">
<h1 id="1">1. General</h1>
<h3 id="1.1">1.1. What is GNU nano?</h3>
<h1><a name="1"></a>1. General</h1>
<h3><a name="1.1"></a>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 id="1.2">1.2. What is the history behind nano?</h3>
<h3><a name="1.2"></a>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 id="1.3">1.3. Why the name change from TIP?</h3>
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program &quot;establishes a full duplex terminal connection to a remote host&quot;, and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
<h3 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>
<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>
<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 id="2">2. Where to get GNU nano.</h1>
<h3 id="2.1">2.1. Web sites that carry nano.</h3>
<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>
<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 id="2.2">2.2. RPM packages (RedHat, OpenSuse, and derivatives).</h3>
<h3><a name="2.2"></a>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 id="2.3">2.3. Deb packages (Debian and derivatives):</h3>
<h3><a name="2.3"></a>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 id="2.4">2.4. By git (for the brave).</h3>
<h3><a name="2.4"></a>2.4. By git (for the brave).</h3>
<blockquote><p>For the "bleeding edge" current version of nano, you can use <b>git</b> to download the current source code. <i>Note:</i> believe it or not, by downloading code that has not yet stabilized into an official release, there could quite possibly be bugs, in fact the code may not even compile! Anyway, see <a href="http://git.savannah.gnu.org/cgit/nano.git/tree/README.hacking">the hacking document</a> for info on getting and building nano from git.</p></blockquote>
<hr width="100%">
<h1 id="3">3. Installation and Configuration</h1>
<h3 id="3.1">3.1. How do I install the RPM or DEB package?</h3>
<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>
<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 id="3.2">3.2. Compiling from source: WHAT THE HECK DO I DO NOW?</h3>
<h3><a name="3.2"></a>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 id="3.3">3.3. Why does everything go into /usr/local?</h3>
<h3><a name="3.3"></a>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 id="3.4">3.4. nano should automatically run strip on the binary when installing it!</h3>
<h3><a name="3.4"></a>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 id="3.5">3.5. How can I make the executable smaller? This is too bloated!</h3>
<h3><a name="3.5"></a>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,22 +167,20 @@
<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 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>
<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>
<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 id="3.8">3.8. How do I make a .nanorc file that will be read when I start nano?</h3>
<h3><a name="3.8"></a>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 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>
<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>
<hr width="100%">
<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>
<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>
<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
@@ -195,7 +193,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 id="4.2">4.2. How can I make Ctrl+Shift+Left/Right select words on urxvt?</h3>
<h3><a name="4.2"></a>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
@@ -210,39 +208,31 @@
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~
URxvt.keysym.S-Page_Up: \033[5;2~
URxvt.keysym.S-Page_Down: \033[6;2~</pre>
URxvt.keysym.M-Page_Down: \033[6;3~</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 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>
<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>
<blockquote><p>Try holding down the Shift key and selecting or pasting the text as you normally would.</p></blockquote>
<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>
<h3><a name="4.6"></a>4.6. When I paste text into a document, each line gets indented further than the last. Why? And how can I stop this?</h3>
<blockquote><p>You have the <i>autoindent</i> feature turned on. Hit <b>Meta-I</b> to turn it off, paste your text, and then hit <b>Meta-I</b> again to turn it back on.</p>
<p><i>Update:</i> Since version 4.8, nano 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>
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste, so you no longer need to toggle it off and on manually.</p></blockquote>
<h3><a name="4.7"></a>4.7. When I paste from Windows into a remote nano, nano rewraps the lines. What gives?</h3>
<blockquote><p>When pasting from Windows, in some situations linefeeds are sent instead of carriage returns (Enters). And linefeeds are <b>^J</b>s, which make nano justify (rewrap) the current paragraph. To prevent these linefeeds from causing these unwanted justifications, add this line to your .nanorc on the remote Linux box: <b>unbind ^J main</b> or <b>bind ^J enter main</b>, depending on whether the paste contains CR + LF or only LF.</p>
<p><i>Update:</i> Since version 4.8, nano 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>
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste, so you no longer need the above workaround.</p></blockquote>
<h3><a name="4.8"></a>4.8. I've compiled nano with color support, but I don't see any color when I run it!</h3>
<blockquote><p>If you want nano to actually use color, you have to specify the color configurations you want it to use in your .nanorc. Several example configurations are in the <b>syntax/</b> subdirectory of the nano source, which are normally installed to <b>/usr/local/share/nano/</b>. To enable all of them, uncomment the line <b># include "/usr/local/share/nano/*.nanorc"</b> in your nanorc. See also section <a href="#3.9">3.9</a>.</p></blockquote>
<h3 id="4.9">4.9. How do I make nano my default editor (in Pine, mutt, git, ...)?</h3>
<h3><a name="4.9"></a>4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</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>
@@ -250,50 +240,47 @@
<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>
<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>
<p>Again, replace x.y with the version of nano you use.</p></blockquote>
<hr width="100%">
<h1 id="5">5. Internationalization</h1>
<h3 id="5.1">5.1. There's no translation for my language!</h3>
<h1><a name="5"></a>5. Internationalization</h1>
<h3><a name="5.1"></a>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 id="5.2">5.2. I don't like the translation for &lt;x&gt; in my language. How can I fix it?</h3>
<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>
<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 id="5.3">5.3. What is the status of Unicode support?</h3>
<h3><a name="5.3"></a>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 id="6">6. Advocacy and Licensing</h1>
<h3 id="6.1">6.1. Why should I use nano instead of Pico?</h3>
<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>
<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 id="6.2">6.2. Why should I use Pico instead of nano?</h3>
<h3><a name="6.2"></a>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 id="6.3">6.3. What is so bad about the older Pine license?</h3>
<h3><a name="6.3"></a>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 id="6.4">6.4. Okay, well, what mail program should I use then?</h3>
<h3><a name="6.4"></a>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 id="7">7. Miscellaneous</h1>
<h3 id="7.1">7.1. Where can I ask questions or send suggestions?</h3>
<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>
<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 id="7.2">7.3. How do I submit a bug report or patch?</h3>
<h3><a name="7.2"></a>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 id="7.3">7.3. I want to send the development team a big load of cash (or just a thank you).</h3>
<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>
<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 id="7.4">7.4. How do I join the development team?</h3>
<h3><a name="7.4"></a>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 id="7.5">7.5. Can I have write access to the git tree?</h3>
<h3><a name="7.5"></a>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-2026 Free Software Foundation, Inc.
.\" Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc.
.\"
.\" This document is dual-licensed. You may distribute and/or modify it
.\" under the terms of either of the following licenses:
@@ -16,20 +16,23 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANO 1 "July 2026" "GNU nano 9.2"
.TH NANO 1 "version 7.2" "January 2023"
.SH NAME
nano \- Nano's ANOther text editor, inspired by Pico
nano \- Nano's ANOther editor, inspired by Pico
.SH SYNOPSIS
.B nano
.RI [ options "] [[\fB+" line [\fB, column "]] " file ]...
.sp
.BR nano " [" \fIoptions "] [[" + [ crCR ]{ / | ? } \fIstring "] " \fIfile ]...
.B nano
.RI [ options "] [" file [\fB: line [\fB: column "]]]..."
.sp
.BR nano " [" \fIoptions "] [[" + [ crCR ]( / | ? ) \fIstring "] " \fIfile ]...
.SH DESCRIPTION
\fBnano\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
\fBnano\fP is a small and friendly editor. It copies the look and feel
of Pico, but is free software, and implements several features that Pico
lacks, such as: opening multiple files, scrolling per line, undo/redo,
syntax coloring, line numbering, and soft-wrapping overlong lines.
.sp
@@ -37,6 +40,9 @@ 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.
@@ -54,61 +60,26 @@ 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 are straightforward: typing the
Entering text and moving around in a file is 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 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
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
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 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.
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.
.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 increases
using the arrow keys. Holding down the Ctrl or Alt key too will increase
the stride.
Any cursor movement without Shift being held cancels such a selection.
Any cursor movement without Shift being held will cancel such a selection.
.sp
Any valid Unicode code point can be inserted into the buffer by typing
\fBM\-V\fR followed by the hexadecimal digits of the code point (concluded
@@ -118,43 +89,40 @@ 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 \[em] see
The default key bindings can be changed via a \fInanorc\fR file -- 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 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.
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.
.TP
.BR \-B ", " \-\-backup
When saving a file, back up the previous version of it, using the current
filename suffixed with a tilde (\fB\[ti]\fR).
filename suffixed with a tilde (\fB~\fP).
.TP
.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.
.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.
.TP
.BR \-D ", " \-\-boldtext
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).
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).
.TP
.BR \-E ", " \-\-tabstospaces
Convert each typed tab to spaces \[em] to the number of spaces
Convert each typed tab to spaces -- to the number of spaces
that a tab at that position would take up.
(Note: pasted tabs are not converted.)
.TP
.BR \-F ", " \-\-newbuffer
.BR \-F ", " \-\-multibuffer
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.
@@ -166,17 +134,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
.BI \-J " number\fR, " \-\-guidestripe= number
.BR \-J\ \fInumber ", " \-\-guidestripe= \fInumber
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 \fI\%ncurses\fR
Interpret escape sequences directly, instead of asking \fBncurses\fR
to translate them. (If you need this option to get some keys to work
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.)
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.)
Using this option disables \fBnano\fR's mouse support.
.TP
.BR \-L ", " \-\-nonewlines
@@ -188,7 +156,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 format.
Disable automatic conversion of files from DOS/Mac format.
.TP
.BR \-O ", " \-\-bookstyle
When justifying, treat any line that starts with whitespace as the
@@ -197,49 +165,38 @@ 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
.BI "\-Q """ regex\fB"\fR, " \-\-quotestr=""" regex """"
.BR "\-Q ""\fIregex\fB""" ", " "\-\-quotestr=""" \fIregex """
Set the regular expression for matching the quoting part of a line.
The default value is "\fB^([\ \\t]*([!#%:;>|}]|//))+\fR".
(Note that \fB\\t\fR stands for an actual Tab.)
(Note that \fB\\t\fP 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
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).
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").
.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 screen's edge, by using also \fB\-\-atblanks\fR.)
(The old short option, \fB\-$\fR, is deprecated.)
.TP
.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.
.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.
.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
@@ -250,14 +207,14 @@ Show the current version number and exit.
Detect word boundaries differently by treating punctuation
characters as part of a word.
.TP
.BI "\-X """ characters\fB"\fR, " \-\-wordchars=""" characters """"
.BR "\-X ""\fIcharacters\fB""" ", " "\-\-wordchars=""" \fIcharacters """
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
.BI \-Y " name\fR, " \-\-syntax= name
.BR \-Y\ \fIname ", " \-\-syntax= \fIname
Specify the name of the syntax highlighting to use from among the ones
defined in the \fInanorc\fR files.
defined in the \fInanorc\fP files.
.TP
.BR \-Z ", " \-\-zap
Let an unmodified Backspace or Delete erase the marked region
@@ -268,16 +225,13 @@ 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,
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]
Automatically hard-wrap the current line when it becomes overlong.
(This option is the opposite of \fB\-w\fR (\fB\-\-nowrap\fR) --
the last one given takes effect.)
.TP
.BR \-c ", " \-\-constantshow
Constantly report the cursor position on the status bar.
Note that this overrides option \fB\-U\fR (\fB\-\-\%quickblank\fR).
Constantly show 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
@@ -287,9 +241,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
.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.
.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.
.TP
.BR \-g ", " \-\-showcursor
Make the cursor visible in the file browser (putting it on the
@@ -318,59 +272,58 @@ 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 works in the X Window
click), and execute shortcuts. The mouse will work 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 starts with a blank buffer,
and writes to the pipe when the user saves the \[lq]file\[rq]. This way
\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 can be used as an editor in combination with for instance
\fBgpg\fR without having to write sensitive data to disk first.
.TP
.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.
.BR \-o\ \fIdirectory ", " \-\-operatingdir= \fIdirectory
Set the operating directory. This makes \fBnano\fP set up something
similar to a chroot.
.TP
.BR \-p ", " \-\-preserve
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.
Preserve the XON and XOFF sequences (\fB^Q\fR and \fB^S\fR) so they
will be caught by the terminal.
.TP
.BR \-q ", " \-\-indicator
Display a \[lq]scrollbar\[rq] on the righthand side of the edit window.
Display a "scrollbar" 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
.BI \-r " number\fR, " \-\-fill= number
.BR \-r\ \fInumber ", " \-\-fill= \fInumber
Set the target width for justifying and automatic hard-wrapping at this
\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
\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
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 \fB\%hunspell\fR(1) or \fBspell\fR(1).
using the built-in corrector that calls \fBhunspell\fR(1) or \fBspell\fR(1).
.TP
.BR \-t ", " \-\-saveonexit
Save a changed buffer without prompting (when exiting with \fB^X\fR).
.TP
.BR \-u ", " \-\-unix
Save a file by default in Unix format. This overrides \fBnano\fR's
Save a file by default in Unix format. This overrides nano'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) \[em] the last one given takes effect.)
(\fB\-\-breaklonglines\fR) -- the last one given takes effect.)
.TP
.BR \-x ", " \-\-nohelp
Don't show the two help lines at the bottom of the screen.
@@ -378,22 +331,9 @@ Don't show the two help lines at the bottom of the screen.
.BR \-y ", " \-\-afterends
Make Ctrl+Right and Ctrl+Delete stop at word ends instead of beginnings.
.TP
.BR \-z ", " \-\-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 \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.
try using libmagic to determine the applicable syntax.
.TP
.BR \-% ", " \-\-stateflags
Use the top-right corner of the screen for showing some state flags:
@@ -406,19 +346,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 \[lq]mini bar\[rq] the filename is shown
for the status bar. In this "minibar" 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)
@@ -427,27 +367,6 @@ The status bar appears only when there is a significant message,
and disappears after 1.5 seconds or upon the next keystroke.
With \fBM\-Z\fR the title bar plus status bar can be toggled.
With \fBM\-X\fR the help lines.
.TP
.BR \-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
@@ -462,61 +381,43 @@ 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 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
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
\fInanorc\fR (if it exists), and then the user's \fInanorc\fR (if it
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
exists), either \fI~/.nanorc\fR or \fI$XDG_CONFIG_HOME/nano/nanorc\fR
or \fI~/.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 \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.
\fBbind ^Z suspend main\fR to your nanorc.)
.sp
When you want to copy marked text from \fBnano\fR to the system's clipboard,
see one of the examples in the \fBnanorc\fR(5) man page.
.sp
If no alternative spell checker command is specified on the command
line nor in one of the \fInanorc\fR files, \fBnano\fR checks the
\fBSPELL\fR environment variable for one.
line nor in one of the \fInanorc\fP files, \fBnano\fP will check the
\fBSPELL\fP environment variable for one.
.sp
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 .
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.
.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
@@ -527,7 +428,7 @@ Please report any other bugs that you encounter via:
.br
.IR https://savannah.gnu.org/bugs/?group=nano .
.sp
When \fBnano\fR crashes, it saves any modified buffers to emergency \fI.save\fR files.
When nano crashes, it will save any modified buffers to emergency .save files.
If you are able to reproduce the crash and you want to get a backtrace, define
the environment variable \fBNANO_NOCATCH\fR.
@@ -537,4 +438,4 @@ the environment variable \fBNANO_NOCATCH\fR.
.SH SEE ALSO
.BR nanorc (5)
.sp
\fI/usr/share/doc/nano/\fR (or equivalent on your system)
\fI/usr/share/doc/nano/\fP (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-2026 Free Software Foundation, Inc.
.\" Copyright (C) 2002-2007, 2014-2023 Free Software Foundation, Inc.
.\"
.\" This document is dual-licensed. You may distribute and/or modify it
.\" under the terms of either of the following licenses:
@@ -16,48 +16,31 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH RNANO 1 "July 2026" "GNU nano 9.2"
.TH RNANO 1 "version 7.2" "January 2023"
.SH NAME
rnano \- a restricted nano
.SH SYNOPSIS
.B rnano
.RI [ options "] [[\fB+" line [\fB, column "]] " file ]...
.RI [ options "] [[+" line [, column "]]\ " file "]..."
.SH DESCRIPTION
\fBrnano\fR runs the \fBnano\fR editor in restricted mode. This allows
editing only the \fIfile\fR (or files) specified on the command line.
editing only the specified file or files, and doesn't allow the user
access to the filesystem nor to a command shell.
.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 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).
not allow appending or prepending to any file;
.IP \[bu]
not make backup files nor do spell checking.
.SH OPTIONS
.TP

View File

@@ -8,16 +8,6 @@
## 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
@@ -54,11 +44,7 @@
## Do case-sensitive searches by default.
# set casesensitive
## 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.
## Constantly display the cursor position in the status bar or minibar.
# set constantshow
## Use cut-from-cursor-to-end-of-line by default.
@@ -76,7 +62,7 @@
## (This option does not have a default value.)
# set guidestripe 75
## Remember the used search/replace/command strings for the next session.
## Remember the used search/replace strings for the next session.
# set historylog
## Display a "scrollbar" on the righthand side of the edit window.
@@ -88,8 +74,9 @@
## Display line numbers to the left (and any anchors in the margin).
# set linenumbers
## Let other users (of nano or vim) know that you are editing the file
## they are trying to edit, and the other way around.
## 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.
# set locking
## Fall back to slow libmagic to try and determine an applicable syntax.
@@ -105,15 +92,16 @@
# 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
## two clicks), and execute shortcuts. The mouse will work in the
## 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 System, and on the console when gpm is running.
# set mouse
## With ^R, insert a file into a separate buffer by default.
# set newbuffer
## Switch on multiple file buffers (inserting a file will put it into
## a separate buffer).
# set multibuffer
## Don't convert files from DOS format.
## Don't convert files from DOS/Mac format.
# set noconvert
## Don't display the helpful shortcut lists at the bottom of the screen.
@@ -128,14 +116,14 @@
## string means the operating-directory feature is turned off.
# set operatingdir ""
## Remember the position of cursor and anchors for the next editing session.
## Remember the cursor position in each file 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 terminating characters,
## This may not contain blank characters. Only these closing punctuations,
## optionally followed by closing brackets, can end sentences.
# set punct "!.?"
@@ -174,9 +162,6 @@
## 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"
@@ -194,7 +179,7 @@
## Snip whitespace at the end of lines when justifying or hard-wrapping.
# set trimblanks
## Save files always in Unix format (also when they were DOS).
## Save files by default in Unix format (also when they were DOS or Mac).
# set unix
## The two single-column characters used to display the first characters
@@ -229,9 +214,9 @@
# set statuscolor bold,white,green
# set errorcolor bold,white,red
# set spotlightcolor black,lightyellow
# set selectedcolor lightwhite,#804
# set stripecolor ,#444
# set scrollercolor slate,#222
# set selectedcolor lightwhite,magenta
# set stripecolor ,yellow
# set scrollercolor cyan
# set numbercolor cyan
# set keycolor cyan
# set functioncolor green
@@ -254,12 +239,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.
@@ -269,6 +254,9 @@
## 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.
@@ -296,23 +284,13 @@
# unbind M-T main
## (Those functions are still accessible through ^T^J and ^T^V.)
## For quickly uppercasing or lowercasing the word that the cursor is on.
## For quickly uppercasing or lowercasing the word under or after the cursor.
## (These effectively select a word and pipe it through a sed command.)
# bind Sh-M-U "{nextword}{mark}{prevword}{execute}| sed 's/.*/\U&/' {enter}" main
# bind Sh-M-L "{nextword}{mark}{prevword}{execute}| sed 's/.*/\L&/' {enter}" main
#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
## 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 copying a marked region to the system clipboard:
# bind Sh-M-T "{execute}|xsel -ib{enter}{undo}" main
## For snipping trailing blanks when you save a file:
# bind ^S "{execute}| sed 's/\s\+$//' {enter}{savefile}" main
@@ -320,34 +298,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 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
#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

View File

@@ -31,5 +31,6 @@ 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.
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
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

View File

@@ -7,7 +7,6 @@ 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

File diff suppressed because it is too large Load Diff

1639
po/bg.po

File diff suppressed because it is too large Load Diff

1721
po/ca.po

File diff suppressed because it is too large Load Diff

1812
po/cs.po

File diff suppressed because it is too large Load Diff

1639
po/da.po

File diff suppressed because it is too large Load Diff

1715
po/de.po

File diff suppressed because it is too large Load Diff

1686
po/eo.po

File diff suppressed because it is too large Load Diff

1737
po/es.po

File diff suppressed because it is too large Load Diff

1629
po/eu.po

File diff suppressed because it is too large Load Diff

1676
po/fi.po

File diff suppressed because it is too large Load Diff

1674
po/fr.po

File diff suppressed because it is too large Load Diff

1682
po/ga.po

File diff suppressed because it is too large Load Diff

1723
po/gl.po

File diff suppressed because it is too large Load Diff

3026
po/hr.po

File diff suppressed because it is too large Load Diff

1684
po/hu.po

File diff suppressed because it is too large Load Diff

1694
po/id.po

File diff suppressed because it is too large Load Diff

1948
po/is.po

File diff suppressed because it is too large Load Diff

2001
po/it.po

File diff suppressed because it is too large Load Diff

1700
po/ja.po

File diff suppressed because it is too large Load Diff

1649
po/ka.po

File diff suppressed because it is too large Load Diff

3146
po/kk.po

File diff suppressed because it is too large Load Diff

1688
po/ko.po

File diff suppressed because it is too large Load Diff

1937
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1694
po/nb.po

File diff suppressed because it is too large Load Diff

1691
po/nl.po

File diff suppressed because it is too large Load Diff

1672
po/pl.po

File diff suppressed because it is too large Load Diff

1758
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1721
po/ro.po

File diff suppressed because it is too large Load Diff

1677
po/ru.po

File diff suppressed because it is too large Load Diff

1774
po/sk.po

File diff suppressed because it is too large Load Diff

1649
po/sl.po

File diff suppressed because it is too large Load Diff

1765
po/sq.po

File diff suppressed because it is too large Load Diff

1698
po/sr.po

File diff suppressed because it is too large Load Diff

1703
po/sv.po

File diff suppressed because it is too large Load Diff

1673
po/tr.po

File diff suppressed because it is too large Load Diff

1716
po/uk.po

File diff suppressed because it is too large Load Diff

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

View File

@@ -43,8 +43,8 @@ nano_SOURCES = \
utils.c \
winio.c
nano_LDADD = $(top_builddir)/lib/libgnu.a @LIBINTL@ \
$(GETRANDOM_LIB) $(CLOCK_TIME_LIB) $(LIBTHREAD)
nano_LDADD = @LIBINTL@ $(top_builddir)/lib/libgnu.a \
$(LIB_CLOCK_GETTIME) $(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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2015, 2016, 2020, 2022, 2025 Benno Schulenberg *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2016, 2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.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) < 0 || S_ISLNK(state.st_mode)) {
if (stat(filelist[index], &state) < 0 || !S_ISDIR(state.st_mode))
if (lstat(filelist[index], &state) == -1 || S_ISLNK(state.st_mode)) {
if (stat(filelist[index], &state) == -1 || !S_ISDIR(state.st_mode))
info = copy_of("--");
else
/* TRANSLATORS: Anything more than 7 cells gets clipped. */
/* TRANSLATORS: Try to keep this at most 7 characters. */
info = copy_of(_("(dir)"));
} else if (S_ISDIR(state.st_mode)) {
if (strcmp(thename, "..") == 0) {
/* TRANSLATORS: Anything more than 12 cells gets clipped. */
/* TRANSLATORS: Try to keep this at most 12 characters. */
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: Anything more than 7 cells gets clipped.
/* TRANSLATORS: Try to keep this at most 7 characters.
* 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) {
if (*last_search != '\0') {
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) {
if (*answer != '\0') {
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)
if (*last_search == '\0' && searchbot->prev != NULL)
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 directly by ^W^Y. */
/* Select the first file in the list -- called by ^W^Y. */
void to_first_file(void)
{
selected = 0;
}
/* Select the last file in the list -- called directly by ^W^V. */
/* Select the last file in the list -- called 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)
if (last_slash != NULL)
*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 = NULL;
DIR *dir;
/* 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)
if (path != NULL)
dir = opendir(path);
if (path == NULL || dir == NULL) {
@@ -414,20 +414,16 @@ char *browse(char *path)
present_name = mallocstrcpy(present_name, filelist[selected]);
}
if (dir) {
if (dir != NULL) {
/* 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) {
if (present_name != NULL) {
reselect(present_name);
free(present_name);
present_name = NULL;
@@ -440,10 +436,7 @@ char *browse(char *path)
titlebar(path);
if (list_length == 0) {
statusline(ALERT, _("No entries"));
napms(1200);
} else while (TRUE) {
while (TRUE) {
functionptrtype function;
int kbinput;
@@ -465,7 +458,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) == 0 &&
if (get_mouseinput(&mouse_y, &mouse_x, TRUE) == 0 &&
wmouse_trafo(midwin, &mouse_y, &mouse_x, FALSE)) {
selected = selected - selected % (usable_rows * piles) +
(mouse_y * piles) + (mouse_x / (gauge + 2));
@@ -487,20 +480,26 @@ 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 == do_help)
do_help();
else if (function == full_refresh) {
#ifdef NANO_TINY
full_refresh();
#else
kbinput = THE_WINDOW_RESIZED;
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;
} else if (function == do_toggle && get_shortcut(kbinput)->toggle == NO_HELP) {
TOGGLE(NO_HELP);
window_init();
kbinput = THE_WINDOW_RESIZED;
kbinput = KEY_WINCH;
#endif
} else if (function == do_search_backward) {
search_filename(BACKWARD);
@@ -553,32 +552,35 @@ char *browse(char *path)
list_length - piles;
else
selected += usable_rows * piles;
} else if (function == to_first_file || function == to_last_file) {
function();
} else if (function == to_first_file) {
selected = 0;
} else if (function == to_last_file) {
selected = list_length - 1;
} 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"));
goto testresize;
continue;
}
path = free_and_assign(path, expand_leading_tilde(answer));
path = free_and_assign(path, real_dir_from_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 (operating_dir && outside_of_confinement(path, FALSE)) {
if (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);
goto testresize;
continue;
}
#endif
/* Snip any trailing slashes, so the name can be compared. */
@@ -606,13 +608,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 (operating_dir && outside_of_confinement(filelist[selected], FALSE)) {
if (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) < 0) {
if (stat(filelist[selected], &st) == -1) {
statusline(ALERT, _("Error reading %s: %s"),
filelist[selected], strerror(errno));
continue;
@@ -637,11 +639,7 @@ char *browse(char *path)
implant(first_sc_for(MBROWSER, function)->expansion);
#endif
#ifndef NANO_TINY
} 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) {
} else if (kbinput == KEY_WINCH) {
; /* Gets handled below. */
#endif
} else if (function == do_exit) {
@@ -649,10 +647,9 @@ 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 == THE_WINDOW_RESIZED || resized_for_browser) {
if (kbinput == KEY_WINCH) {
/* Remember the selected file, to be able to reselect it. */
present_name = copy_of(filelist[selected]);
goto read_directory_contents;
@@ -676,15 +673,15 @@ char *browse(char *path)
* start browsing in that directory, otherwise in the current directory. */
char *browse_in(const char *inpath)
{
char *path = expand_leading_tilde(inpath);
char *path = real_dir_from_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) < 0 || !S_ISDIR(fileinfo.st_mode)) {
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
path = free_and_assign(path, strip_last_component(path));
if (stat(path, &fileinfo) < 0 || !S_ISDIR(fileinfo.st_mode)) {
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
path = free_and_assign(path, realpath(".", NULL));
if (path == NULL) {
@@ -698,7 +695,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 (operating_dir && outside_of_confinement(path, FALSE))
if (outside_of_confinement(path, FALSE))
path = mallocstrcpy(path, operating_dir);
#endif

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* chars.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016-2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -23,10 +23,26 @@
#include <ctype.h>
#include <string.h>
#ifdef ENABLE_UTF8
#include <wchar.h>
#include <wctype.h>
#endif
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 */
#ifdef ENABLE_SPELLER
/* Return TRUE when the given character is some kind of letter. */
@@ -82,12 +98,12 @@ bool is_blank_char(const char *c)
bool is_cntrl_char(const char *c)
{
#ifdef ENABLE_UTF8
if (using_utf8)
if (use_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. */
@@ -118,15 +134,14 @@ bool is_word_char(const char *c, bool allow_punct)
if (allow_punct && is_punct_char(c))
return TRUE;
if (word_chars && *word_chars) {
if (word_chars != NULL && *word_chars != '\0') {
char symbol[MAXCHARLEN + 1];
int symlen = collect_char(c, symbol);
symbol[symlen] = '\0';
return (strstr(word_chars, symbol) != NULL);
}
return FALSE;
} else
return FALSE;
}
/* Return the visible representation of control character c. */
@@ -138,8 +153,8 @@ char control_rep(const signed char c)
return '=';
else if (c < 0)
return c + 224;
return c + 64;
else
return c + 64;
}
/* Return the visible representation of multibyte control character c. */
@@ -150,15 +165,14 @@ char control_mbrep(const char *c, bool isdata)
return '@';
#ifdef ENABLE_UTF8
if (using_utf8) {
if (use_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
@@ -166,9 +180,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 && using_utf8) {
unsigned char v1 = c[0];
unsigned char v2 = c[1] ^ 0x80;
if ((signed char)*c < 0 && use_utf8) {
unsigned char v1 = (unsigned char)c[0];
unsigned char v2 = (unsigned char)c[1] ^ 0x80;
if (v2 > 0x3F || v1 < 0xC2)
return -1;
@@ -178,7 +192,7 @@ int mbtowide(wchar_t *wc, const char *c)
return 2;
}
unsigned char v3 = c[2] ^ 0x80;
unsigned char v3 = (unsigned char)c[2] ^ 0x80;
if (v3 > 0x3F)
return -1;
@@ -192,7 +206,7 @@ int mbtowide(wchar_t *wc, const char *c)
return -1;
}
unsigned char v4 = c[3] ^ 0x80;
unsigned char v4 = (unsigned char)c[3] ^ 0x80;
if (v4 > 0x3F || v1 > 0xF4)
return -1;
@@ -215,7 +229,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 || !using_utf8)
if ((unsigned char)*ch < 0xE1 || !use_utf8)
return FALSE;
if (mbtowide(&wc, ch) < 0)
@@ -230,7 +244,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 || !using_utf8)
if ((unsigned char)*ch < 0xCC || !use_utf8)
return FALSE;
if (mbtowide(&wc, ch) < 0)
@@ -250,9 +264,9 @@ bool is_zerowidth(const char *ch)
int char_length(const char *pointer)
{
#ifdef ENABLE_UTF8
if ((unsigned char)*pointer > 0xC1 && using_utf8) {
unsigned char c1 = pointer[0];
unsigned char c2 = pointer[1];
if ((unsigned char)*pointer > 0xC1 && use_utf8) {
unsigned char c1 = (unsigned char)pointer[0];
unsigned char c2 = (unsigned char)pointer[1];
if ((c2 ^ 0x80) > 0x3F)
return 1;
@@ -280,8 +294,7 @@ int char_length(const char *pointer)
return 4;
}
#endif
return 1;
return 1;
}
/* Return the number of (multibyte) characters in the given string. */
@@ -289,7 +302,7 @@ size_t mbstrlen(const char *pointer)
{
size_t count = 0;
while (*pointer) {
while (*pointer != '\0') {
pointer += char_length(pointer);
count++;
}
@@ -314,7 +327,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 && using_utf8) {
if ((signed char)*string < 0 && use_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;
@@ -358,7 +371,7 @@ int advance_over(const char *string, size_t *column)
size_t step_left(const char *buf, size_t pos)
{
#ifdef ENABLE_UTF8
if (using_utf8) {
if (use_utf8) {
size_t before, charlen = 0;
if (pos < 4)
@@ -387,10 +400,9 @@ 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
@@ -410,10 +422,10 @@ int mbstrcasecmp(const char *s1, const char *s2)
int mbstrncasecmp(const char *s1, const char *s2, size_t n)
{
#ifdef ENABLE_UTF8
if (using_utf8) {
if (use_utf8) {
wchar_t wc1, wc2;
while (*s1 && *s2 && n > 0) {
while (*s1 != '\0' && *s2 != '\0' && 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') {
@@ -452,20 +464,19 @@ 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 (using_utf8) {
if (use_utf8) {
size_t needle_len = mbstrlen(needle);
while (*haystack) {
while (*haystack != '\0') {
if (mbstrncasecmp(haystack, needle, needle_len) == 0)
return (char *)haystack;
@@ -473,10 +484,9 @@ 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
@@ -525,7 +535,7 @@ char *mbrevstrcasestr(const char *haystack, const char *needle,
const char *pointer)
{
#ifdef ENABLE_UTF8
if (using_utf8) {
if (use_utf8) {
size_t needle_len = mbstrlen(needle);
size_t tail_len = mbstrlen(pointer);
@@ -544,18 +554,17 @@ 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. */
const char *mbstrchr(const char *string, const char *chr)
char *mbstrchr(const char *string, const char *chr)
{
#ifdef ENABLE_UTF8
if (using_utf8) {
if (use_utf8) {
bool bad_s = FALSE, bad_c = FALSE;
wchar_t ws, wc;
@@ -564,7 +573,7 @@ const char *mbstrchr(const char *string, const char *chr)
bad_c = TRUE;
}
while (*string) {
while (*string != '\0') {
int symlen = mbtowide(&ws, string);
if (symlen < 0) {
@@ -582,10 +591,9 @@ const 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 */
@@ -594,8 +602,8 @@ const char *mbstrchr(const char *string, const char *chr)
* the characters in accept, searching forward. */
char *mbstrpbrk(const char *string, const char *accept)
{
while (*string) {
if (mbstrchr(accept, string))
while (*string != '\0') {
if (mbstrchr(accept, string) != NULL)
return (char *)string;
string += char_length(string);
@@ -615,7 +623,7 @@ char *mbrevstrpbrk(const char *head, const char *accept, const char *pointer)
}
while (TRUE) {
if (mbstrchr(accept, pointer))
if (mbstrchr(accept, pointer) != NULL)
return (char *)pointer;
/* If we've reached the head of the string, we found nothing. */
@@ -631,7 +639,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 && !is_blank_char(string))
while (*string != '\0' && !is_blank_char(string))
string += char_length(string);
return *string;
@@ -641,17 +649,8 @@ 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 && (is_blank_char(string) || *string == '\r'))
while (*string != '\0' && (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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017, 2020, 2021 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.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) {
if (combo != NULL) {
if (!defaults_allowed) {
if (combo->fg == THE_DEFAULT)
combo->fg = COLOR_WHITE;
@@ -67,15 +67,8 @@ 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 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 {
} else
interface_color_pair[index] = hilite_attribute;
}
}
free(color_combo[index]);
@@ -150,7 +143,7 @@ void find_and_prime_applicable_syntax(void)
return;
/* If we specified a syntax-override string, use it. */
if (syntaxstr) {
if (syntaxstr != NULL) {
/* An override of "none" is like having no syntax at all. */
if (strcmp(syntaxstr, "none") == 0)
return;
@@ -210,7 +203,7 @@ void find_and_prime_applicable_syntax(void)
}
/* Now try and find a syntax that matches the magic string. */
if (magicstring) {
if (magicstring != NULL) {
for (sntx = syntaxes; sntx != NULL; sntx = sntx->next)
if (found_in_list(sntx->magics, magicstring))
break;
@@ -229,7 +222,7 @@ void find_and_prime_applicable_syntax(void)
}
/* When the syntax isn't loaded yet, parse it and initialize its colors. */
if (sntx && sntx->filename) {
if (sntx != NULL && sntx->filename != NULL) {
parse_one_include(sntx->filename, sntx);
set_syntax_colorpairs(sntx);
}
@@ -247,7 +240,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 || openfile->syntax->multiscore == 0)
if (openfile->syntax == NULL || openfile->syntax->nmultis == 0)
return;
if (line->multidata == NULL) {
@@ -270,7 +263,8 @@ 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 +
@@ -299,7 +293,7 @@ void precalc_multicolorinfo(void)
regmatch_t startmatch, endmatch;
linestruct *line, *tailline;
if (!openfile->syntax || openfile->syntax->multiscore == 0 || ISSET(NO_SYNTAX))
if (!openfile->syntax || openfile->syntax->nmultis == 0 || ISSET(NO_SYNTAX))
return;
//#define TIMEPRECALC 123
@@ -311,7 +305,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->multiscore * sizeof(short));
line->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
for (ink = openfile->syntax->color; ink != NULL; ink = ink->next) {
/* If this is not a multi-line regex, skip it. */
@@ -353,7 +347,8 @@ 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;
@@ -376,7 +371,7 @@ void precalc_multicolorinfo(void)
}
#ifdef TIMEPRECALC
statusline(NOTICE, "Precalculation: %.1f ms", 1000 * (double)(clock() - start) / CLOCKS_PER_SEC);
statusline(INFO, "Precalculation: %.1f ms", 1000 * (double)(clock() - start) / CLOCKS_PER_SEC);
napms(1200);
#endif
}

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* cut.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mark Majeres *
* Copyright (C) 2016, 2018-2020 Benno Schulenberg *
* *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,14 +24,13 @@
#include <string.h>
/* Delete the character at the current position, and
* add or update an undo item for the given action. */
void expunge(undo_type action)
/* Delete the character under the cursor. */
void do_deletion(undo_type action)
{
openfile->placewewant = xplustabs();
/* When in the middle of a line, delete the current character. */
if (openfile->current->data[openfile->current_x]) {
if (openfile->current->data[openfile->current_x] != '\0') {
int charlen = char_length(openfile->current->data + openfile->current_x);
size_t line_len = strlen(openfile->current->data + openfile->current_x);
#ifndef NANO_TINY
@@ -54,12 +53,10 @@ void expunge(undo_type action)
/* 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. */
@@ -70,7 +67,8 @@ void expunge(undo_type action)
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);
@@ -118,8 +116,7 @@ void expunge(undo_type action)
set_modified();
}
/* 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. */
/* Delete the character under the cursor. */
void do_delete(void)
{
#ifndef NANO_TINY
@@ -128,18 +125,17 @@ void do_delete(void)
else
#endif
{
expunge(DEL);
do_deletion(DEL);
#ifdef ENABLE_UTF8
while (openfile->current->data[openfile->current_x] &&
while (openfile->current->data[openfile->current_x] != '\0' &&
is_zerowidth(openfile->current->data + openfile->current_x))
expunge(DEL);
do_deletion(DEL);
#endif
}
}
/* Backspace over one character. That is, move the cursor left one
* character, and then delete the character under the cursor. Or,
* when mark is on and --zap is active, delete the marked region. */
* character, and then delete the character under the cursor. */
void do_backspace(void)
{
#ifndef NANO_TINY
@@ -149,16 +145,11 @@ void do_backspace(void)
#endif
if (openfile->current_x > 0) {
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
expunge(BACK);
do_deletion(BACK);
} else if (openfile->current != openfile->filetop) {
#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);
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
do_deletion(BACK);
}
}
@@ -194,8 +185,8 @@ bool is_cuttable(bool test_cliff)
void chop_word(bool forward)
{
/* Remember the current cursor position. */
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
linestruct *is_current = openfile->current;
size_t is_current_x = openfile->current_x;
/* Remember where the cutbuffer is, then make it seem blank. */
linestruct *is_cutbuffer = cutbuffer;
@@ -207,18 +198,19 @@ void chop_word(bool forward)
* edge instead, so that lines will not be joined unexpectedly. */
if (!forward) {
do_prev_word(ALLOW_FOLDED);
if (openfile->current != was_current) {
if (was_x > 0) {
openfile->current = was_current;
if (openfile->current != is_current) {
if (is_current_x > 0) {
openfile->current = is_current;
openfile->current_x = 0;
} else
openfile->current_x = strlen(openfile->current->data);
}
} else {
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);
if (openfile->current != is_current &&
is_current->data[is_current_x] != '\0') {
openfile->current = is_current;
openfile->current_x = strlen(is_current->data);
}
}
UNFOLD_SEGMENT(openfile->current);
@@ -228,8 +220,8 @@ void chop_word(bool forward)
openfile->mark_x = openfile->current_x;
/* Put the cursor back where it was, so an undo will put it there too. */
openfile->current = was_current;
openfile->current_x = was_x;
openfile->current = is_current;
openfile->current_x = is_current_x;
/* Now kill the marked region and a word is gone. */
add_undo(CUT, NULL);
@@ -350,7 +342,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) {
if (cutbottom->next != NULL) {
cutbottom->next->prev = cutbottom;
cutbottom = last;
}
@@ -378,7 +370,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])
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
new_magicline();
}
@@ -398,7 +390,7 @@ void ingraft_buffer(linestruct *topline)
UNFOLD_SEGMENT(line);
while (botline->next)
while (botline->next != NULL)
botline = botline->next;
/* Add the size of the text to be grafted to the buffer size. */
@@ -455,7 +447,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])
if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
new_magicline();
}
@@ -522,7 +514,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])
if (line->data[openfile->current_x] != '\0')
extract_segment(line, openfile->current_x, line, strlen(line->data));
else if (openfile->current != openfile->filebot) {
extract_segment(line, openfile->current_x, line->next, 0);
@@ -654,7 +646,6 @@ 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,
@@ -667,24 +658,17 @@ void copy_text(void)
linestruct *was_current = openfile->current;
linestruct *addition;
#ifndef NANO_TINY
if (openfile->mark || openfile->last_action != COPY)
keep_cutbuffer = FALSE;
#endif
if (!keep_cutbuffer) {
if (openfile->mark || openfile->last_action != COPY || !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) ||
@@ -734,11 +718,10 @@ 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)

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* definitions.h -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017, 2020-2022, 2024 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2017 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* 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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -41,11 +41,6 @@
#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
@@ -65,7 +60,10 @@
#include <stdlib.h>
#include <sys/stat.h>
#ifdef HAVE_NCURSES_H
/* Prefer wide ncurses over normal ncurses over curses. */
#if defined(HAVE_NCURSESW_NCURSES_H)
#include <ncursesw/ncurses.h>
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#else
#include <curses.h>
@@ -125,6 +123,11 @@
#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
@@ -143,9 +146,6 @@
/* 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,8 +195,6 @@
#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
@@ -205,6 +203,8 @@
#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,28 +214,19 @@
#define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F
#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_COMMAND 0x4EC
#define NO_SUCH_FUNCTION 0x4EF
#ifndef NANO_TINY
/* A special keycode for Ctrl + the central key on the numeric keypad. */
#define KEY_CENTER 0x4F0
/* A special keycode for when <Tab> is pressed while the mark is on. */
#define INDENT_KEY 0x4F1
/* A special keycode for when we get a SIGWINCH (a window resize). */
#define THE_WINDOW_RESIZED 0x4F7
#endif
/* A special keycode to signal the beginning and end of a bracketed paste. */
#define BRACKETED_PASTE_MARKER 0x4FB
/* A special keycode for when a key produces an unknown escape sequence. */
#define FOREIGN_SEQUENCE 0x4FC
@@ -244,6 +235,9 @@
#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)
@@ -290,7 +284,7 @@
/* Enumeration types. */
typedef enum {
UNSPECIFIED, NIX_FILE, DOS_FILE
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
} format_type;
typedef enum {
@@ -298,8 +292,8 @@ typedef enum {
} message_type;
typedef enum {
OVERWRITE, APPEND, PREPEND, SPECIAL
} writing_type;
OVERWRITE, APPEND, PREPEND
} kind_of_writing_type;
typedef enum {
CENTERING, FLOWING, STATIONARY
@@ -333,7 +327,6 @@ enum {
ERROR_MESSAGE,
KEY_COMBO,
FUNCTION_TAG,
FOLDED_LINE,
NUMBER_OF_ELEMENTS
};
@@ -351,7 +344,7 @@ enum {
SAVE_ON_EXIT,
CUT_FROM_CURSOR,
BACKWARDS_SEARCH,
NEW_BUFFER,
MULTIBUFFER,
REBIND_DELETE,
RAW_SEQUENCES,
NO_CONVERT,
@@ -384,13 +377,10 @@ enum {
EMPTY_LINE,
INDICATOR,
BOOKSTYLE,
COLON_PARSING,
STATEFLAGS,
USE_MAGIC,
MINIBAR,
ZERO,
MODERN_BINDINGS,
SOLO_SIDESCROLL
ZERO
};
typedef enum {
@@ -465,7 +455,7 @@ typedef struct syntaxtype {
#endif
colortype *color;
/* The colors and their regexes used in this syntax. */
short multiscore;
short nmultis;
/* How many multiline regex strings this syntax has. */
struct syntaxtype *next;
/* Next syntax. */
@@ -552,18 +542,16 @@ typedef struct undostruct {
#endif /* !NANO_TINY */
#ifdef ENABLE_HISTORIES
typedef struct positionstruct {
typedef struct poshiststruct {
char *filename;
/* The full path plus name of the file. */
ssize_t linenumber;
/* The line where the cursor was when the file was closed. */
/* The line where the cursor was when we closed the file. */
ssize_t columnnumber;
/* The column where the cursor was. */
char *anchors;
/* The line numbers where anchors were placed, in string form. */
struct positionstruct *next;
/* The next item in the positions register. */
} positionstruct;
struct poshiststruct *next;
/* The next item of position history. */
} poshiststruct;
#endif
typedef struct openfilestruct {
@@ -585,11 +573,9 @@ typedef struct openfilestruct {
size_t current_x;
/* The file's x-coordinate position. */
size_t placewewant;
/* 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. */
/* The file's x position we would like. */
ssize_t current_y;
/* The file's y-coordinate position. */
struct stat *statinfo;
/* The file's stat information from when it was opened or last saved. */
#ifdef ENABLE_WRAPPING
@@ -604,7 +590,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. */
/* The file's format -- Unix or DOS or Mac. */
char *lock_filename;
/* The path of the lockfile, if we created one. */
undostruct *undotop;

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/**************************************************************************
* folding.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2023 rexy712 *
* Copyright (C) 2022 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 *
@@ -20,21 +20,27 @@
#include "prototypes.h"
#include <string.h>
#include <ctype.h>
/* isspace */
#ifdef ENABLE_FOLDING
/* Unfold a folded segment containing the given line. */
void unfold_folded_segment(linestruct *line)
/* Remove a folded segment from the given line until end of segment */
void unfold_folded_segment_from(linestruct *line)
{
line = get_start_of_folded_segment(line);
if (line != NULL)
refresh_needed = TRUE;
for (; line != NULL && line->folded; line = line->next)
for(;line != NULL && line->folded;line = line->next)
line->folded = FALSE;
}
/* Get the first line of the folded segment. */
/* Remove a folded segment containing the given line */
void unfold_folded_segment(linestruct *line)
{
unfold_folded_segment_from(get_start_of_folded_segment(line));
}
/* Get the first member of the folded segment */
linestruct *get_start_of_folded_segment(linestruct *line)
{
if (!line->folded)
@@ -45,7 +51,7 @@ linestruct *get_start_of_folded_segment(linestruct *line)
return line;
}
/* Get the last line of the folded segment. */
/* Get the last member of the folded segment */
linestruct *get_end_of_folded_segment(linestruct *line)
{
if (!line->folded)
@@ -57,7 +63,7 @@ linestruct *get_end_of_folded_segment(linestruct *line)
return line;
}
/* Get the number of lines in a folded segment. */
/* Get the span length of a folded_segment */
int get_folded_segment_length(linestruct *line)
{
int i = 1;
@@ -66,93 +72,67 @@ int get_folded_segment_length(linestruct *line)
return 0;
line = get_start_of_folded_segment(line);
for (; line->next != NULL && line->next->folded; line = line->next)
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. */
/* Remove any folded_segments within the range [top, bottom].
* Returns true if any segments are removed. */
bool do_unfold_segment(linestruct *line)
{
/* If current line is folded, just unfold and finish. */
if (line->folded) {
unfold_folded_segment(line);
return TRUE;
/* Attempt to find a bracketed region first.
* If not, top is unmodified. */
if (!line->folded) {
linestruct *bot;
find_bracketed_region(openfile->current, &line, &bot);
}
/* 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;
}
if (line->folded) {
unfold_folded_segment(line);
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. */
/* Fold the currently selected lines unless the current selection
* already contains a folded_segment. In that case, remove any
* segments that are selected. */
void do_fold_segment(void)
{
linestruct *top, *bot, *line;
linestruct *top, *bot;
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);
/* First try to unfold if this line/bracketed region is folded */
if (do_unfold_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;
}
/* When not selecting multiple lines, try to find bounding
* brackets to act as top and bot. */
if (!find_bracketed_region(openfile->current, &top, &bot)) {
statusline(AHEM, _("No valid region found for automatic fold"));
return;
}
}
if (region_found == TRUE) {
for (line = top; line != bot->next; line = line->next)
line->folded = TRUE;
for (linestruct* 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;
if (top->lineno < openfile->edittop->lineno &&
bot->lineno > openfile->edittop->lineno)
openfile->edittop = top;
/* Place the cursor at the start of the fold segment.
* Anywhere else within the segment is invalid. */
if (openfile->current->folded)
openfile->current = get_start_of_folded_segment(top);
openfile->mark = NULL;
openfile->mark = NULL;
refresh_needed = TRUE;
} else
if (!do_unfold_segment(openfile->current))
statusline(AHEM, _("No valid region found for automatic fold"));
refresh_needed = TRUE;
}
#endif /* ENABLE_FOLDING */

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* global.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2026 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,20 +24,15 @@
#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. */
@@ -47,6 +42,8 @@ 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. */
@@ -54,16 +51,8 @@ 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. */
@@ -73,8 +62,6 @@ 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. */
@@ -112,15 +99,14 @@ int controlleft, controlright, controlup, controldown;
int controlhome, controlend;
#ifndef NANO_TINY
int controldelete, controlshiftdelete;
int shiftup, shiftdown;
int shiftleft, shiftright, shiftup, shiftdown;
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
int shiftcontrolhome, shiftcontrolend;
int altleft, altright, altup, altdown;
int althome, altend, altpageup, altpagedown;
int altpageup, altpagedown;
int altinsert, altdelete;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif
int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
ssize_t fill = -COLUMNS_FROM_EOL;
@@ -144,16 +130,13 @@ 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 sidebar = 0;
/* Becomes 1 when the indicator "scroll bar" must be shown. */
int thebar = 0;
/* Becomes 1 when a scrollbar is 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;
@@ -283,12 +266,9 @@ char *startup_problem = NULL;
#endif
#ifdef ENABLE_NANORC
char *custom_nanorc = NULL;
/* The argument of the --rcfile option, when given. */
char *commandname = NULL;
/* The name (of a function) between braces in a string bind. */
keystruct *planted_shortcut = NULL;
/* The function that the above name resolves to, if any. */
#endif
bool spotlighted = FALSE;
@@ -322,6 +302,7 @@ 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) {;}
@@ -376,26 +357,10 @@ int keycode_from_string(const char *keystring)
else
return -1;
} else if (keystring[0] == 'M') {
if (keystring[1] == '-' && keystring[3] == '\0') {
if ('A' <= keystring[2] && keystring[2] <= 'Z')
return (keystring[2] | 0x20);
else
return keystring[2];
}
if (keystring[1] == '-' && keystring[3] == '\0')
return tolower((unsigned char)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
@@ -418,15 +383,6 @@ 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)
@@ -477,14 +433,15 @@ size_t shown_entries_for(int menu)
size_t maximum = ((COLS + 40) / 20) * 2;
size_t count = 0;
while (count < maximum && item) {
while (count < maximum && item != NULL) {
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;
@@ -501,8 +458,13 @@ 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)
if (keycode == PLANTED_COMMAND)
return planted_shortcut;
#endif
@@ -528,7 +490,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 && keycode < 0x7F) {
if (!meta_key) {
if (keycode == 'N')
return do_findprevious;
if (keycode == 'n')
@@ -594,8 +556,6 @@ 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");
@@ -605,8 +565,9 @@ 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)");
@@ -628,26 +589,20 @@ 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 *scrollleft_gist = N_("Scroll the viewport a tabsize to the left");
const char *scrollright_gist = N_("Scroll the viewport a tabsize to the right");
const char *bracket_gist = N_("Go to the matching bracket");
#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");
@@ -706,17 +661,14 @@ 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");
#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");
const char *convert_gist = N_("Do not convert from DOS/Mac format");
#endif
#ifdef ENABLE_MULTIBUFFER
const char *newbuffer_gist = N_("Toggle the use of a new buffer");
@@ -751,10 +703,6 @@ 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
@@ -786,6 +734,8 @@ 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,
@@ -819,12 +769,12 @@ void shortcut_init(void)
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MHELP,
"Where Was", WHENHELP(wherewas_gist), TOGETHER);
N_("Where Was"), WHENHELP(wherewas_gist), TOGETHER);
add_to_funcs(do_findprevious, MMAIN|MHELP,
"Previous", WHENHELP(findprev_gist), TOGETHER);
N_("Previous"), WHENHELP(findprev_gist), TOGETHER);
add_to_funcs(do_findnext, MMAIN|MHELP,
"Next", WHENHELP(findnext_gist), BLANKAFTER);
N_("Next"), WHENHELP(findnext_gist), BLANKAFTER);
#endif
add_to_funcs(cut_text, MMAIN,
@@ -857,7 +807,7 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(do_undo, MMAIN,
/* TRANSLATORS: Try to keep the next four strings at most 12 characters. */
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
N_("Undo"), WHENHELP(undo_gist), TOGETHER);
add_to_funcs(do_redo, MMAIN,
N_("Redo"), WHENHELP(redo_gist), BLANKAFTER);
@@ -869,10 +819,9 @@ void shortcut_init(void)
#endif
add_to_funcs(case_sens_void, MWHEREIS|MREPLACE,
/* TRANSLATORS: Try to keep the next four strings at most 16 characters. */
N_("Case sensitive"), WHENHELP(case_gist), TOGETHER);
N_("Case Sens"), WHENHELP(case_gist), TOGETHER);
add_to_funcs(regexp_void, MWHEREIS|MREPLACE,
N_("Reg.expression"), WHENHELP(regexp_gist), TOGETHER);
N_("Reg.exp."), WHENHELP(regexp_gist), TOGETHER);
add_to_funcs(backwards_void, MWHEREIS|MREPLACE,
N_("Backwards"), WHENHELP(reverse_gist), BLANKAFTER);
@@ -883,16 +832,9 @@ 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
@@ -948,32 +890,23 @@ void shortcut_init(void)
#ifndef NANO_TINY
add_to_funcs(to_prev_word, MMAIN,
/* TRANSLATORS: Try to keep the next four strings at most 13 characters. */
/* TRANSLATORS: Try to keep the next ten strings at most 12 characters. */
N_("Prev Word"), WHENHELP(prevword_gist), TOGETHER);
add_to_funcs(to_next_word, MMAIN,
N_("Next Word"), 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), 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
N_("End"), WHENHELP(end_gist), BLANKAFTER);
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);
@@ -985,21 +918,14 @@ 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 23 characters. */
N_("Start of Paragraph"), WHENHELP(parabegin_gist), TOGETHER);
/* TRANSLATORS: Try to keep these two strings at most 16 characters. */
N_("Begin of Paragr."), WHENHELP(parabegin_gist), TOGETHER);
add_to_funcs(to_para_end, MMAIN|MGOTOLINE,
N_("End of Paragraph"), 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 four strings at most 10 characters. */
/* TRANSLATORS: Try to keep the next six strings at most 12 characters. */
N_("Prev Page"), WHENHELP(prevpage_gist), TOGETHER);
add_to_funcs(do_page_down, MMAIN|MHELP,
N_("Next Page"), WHENHELP(nextpage_gist), TOGETHER);
@@ -1011,7 +937,6 @@ 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);
@@ -1051,18 +976,12 @@ 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,
N_("Verbatim"), WHENHELP(verbatim_gist), BLANKAFTER);
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
"Where Was", WHENHELP(wherewas_gist), BLANKAFTER);
#else
#ifndef NANO_TINY
add_to_funcs(do_indent, MMAIN,
N_("Indent"), WHENHELP(indent_gist), TOGETHER);
add_to_funcs(do_unindent, MMAIN,
@@ -1101,36 +1020,36 @@ void shortcut_init(void)
add_to_funcs(to_next_anchor, MMAIN,
N_("Down to anchor"), WHENHELP(nextanchor_gist), BLANKAFTER);
if (!ISSET(RESTRICTED)) {
#ifdef ENABLE_SPELLER
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif
#ifdef ENABLE_LINTER
add_to_funcs(do_linter, MMAIN,
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
add_to_funcs(do_linter, MMAIN,
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
#endif
#ifdef ENABLE_FORMATTER
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
#endif
/* Although not allowed in restricted mode, keep execution rebindable. */
if (ISSET(RESTRICTED))
add_to_funcs(do_execute, MMAIN,
N_("Execute"), WHENHELP(execute_gist), TOGETHER);
add_to_funcs(do_suspend, MMAIN,
N_("Suspend"), WHENHELP(suspend_gist), TOGETHER);
}
#endif /* !NANO_TINY */
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
#else
add_to_funcs(do_suspend, MMAIN,
N_("Suspend"), WHENHELP(suspend_gist), TOGETHER);
#endif
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN,
N_("Refresh"), WHENHELP(refresh_gist), BLANKAFTER);
N_("Refresh"), WHENHELP(refresh_gist), TOGETHER);
#endif
#ifndef NANO_TINY
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
add_to_funcs(do_center, MMAIN,
N_("Center"), WHENHELP(center_gist), TOGETHER);
add_to_funcs(do_cycle, MMAIN,
N_("Cycle"), WHENHELP(cycle_gist), BLANKAFTER);
N_("Center"), WHENHELP(center_gist), BLANKAFTER);
#endif
add_to_funcs(do_savefile, MMAIN,
@@ -1148,7 +1067,6 @@ 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
@@ -1164,42 +1082,49 @@ 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), BLANKAFTER);
N_("Prepend"), WHENHELP(prepend_gist), TOGETHER);
add_to_funcs(back_it_up, MWRITEFILE,
N_("Backup File"), WHENHELP(backup_gist), BLANKAFTER);
}
add_to_funcs(flip_convert, MINSERTFILE,
N_("No Conversion"), WHENHELP(convert_gist), BLANKAFTER);
/* Command execution is only available when not in restricted mode. */
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
add_to_funcs(flip_execute, MINSERTFILE,
N_("Execute Command"), WHENHELP(execute_gist), BLANKAFTER);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
add_to_funcs(do_suspend, MEXECUTE,
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
add_to_funcs(do_suspend, MEXECUTE,
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))
@@ -1229,6 +1154,9 @@ 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. */
@@ -1246,69 +1174,34 @@ 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, "^I", '\t', do_tab, 0);
add_to_sclist(MMOST, "Tab", '\t', do_tab, 0);
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, "^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, "^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, "^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, "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, ISSET(MODERN_BINDINGS) ? "^E" : "^T", 0, do_spell, 0);
add_to_sclist(MMAIN, "^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, ISSET(MODERN_BINDINGS) ? "^E" : "^T", 0, do_execute, 0);
add_to_sclist(MMAIN, "^T", 0, do_execute, 0);
#ifdef ENABLE_SPELLER
if (!ISSET(PRESERVE))
add_to_sclist(MEXECUTE, "^S", 0, do_spell, 0);
@@ -1319,18 +1212,23 @@ 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
#ifdef ENABLE_FOLDING
add_to_sclist(MMAIN, "M-[", 0, do_fold_segment, 0);
#endif
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
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);
@@ -1339,23 +1237,26 @@ 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);
@@ -1367,12 +1268,8 @@ 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);
@@ -1380,10 +1277,10 @@ void shortcut_init(void)
#ifdef ENABLE_COMMENT
add_to_sclist(MMAIN, "M-3", 0, do_comment, 0);
#endif
add_to_sclist(MMOST & ~MMAIN, "^B", 0, do_left, 0);
add_to_sclist(MMOST & ~MMAIN, "^F", 0, do_right, 0);
add_to_sclist(MMOST|MBROWSER, "^B", 0, do_left, 0);
add_to_sclist(MMOST|MBROWSER, "^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);
@@ -1410,10 +1307,14 @@ 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);
@@ -1436,7 +1337,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
@@ -1453,7 +1354,9 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
#endif
#ifdef ENABLE_MULTIBUFFER
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
#endif
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
@@ -1470,15 +1373,13 @@ 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
#ifndef NANO_TINY
add_to_sclist(MMAIN, "M-<", 0, do_scroll_left, 0);
add_to_sclist(MMAIN, "M->", 0, do_scroll_right, 0);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
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. */
@@ -1515,13 +1416,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
@@ -1551,16 +1452,17 @@ 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(PRESERVE))
if (ISSET(SAVE_ON_EXIT) && !ISSET(PRESERVE))
add_to_sclist(MWRITEFILE, "^Q", 0, discard_buffer, 0);
#ifndef NANO_TINY
add_to_sclist(MWRITEFILE, "M-D", 0, dos_format, 0);
/* Only when not in restricted mode, allow making backups,
* appending, prepending, and executing a command. */
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. */
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);
@@ -1573,22 +1475,24 @@ void shortcut_init(void)
#endif
}
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
#ifdef ENABLE_BROWSER
/* Only when not in restricted mode, allow entering the file browser. */
if (!ISSET(RESTRICTED))
add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", 0, to_files, 0);
/* Allow exiting the file browser with the same key as used for entry. */
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
/* Allow exiting from the file browser and the help viewer with
* the same key as they were entered. */
#ifdef ENABLE_BROWSER
add_to_sclist(MBROWSER, "^T", 0, do_exit, 0);
#endif
#ifdef ENABLE_HELP
/* Allow exiting the help viewer with the same keys as used for entry. */
add_to_sclist(MHELP, "^G", 0, do_exit, 0);
add_to_sclist(MHELP, "F1", KEY_F(1), do_exit, 0);
add_to_sclist(MHELP, "Home", KEY_HOME, to_first_line, 0);
add_to_sclist(MHELP, "End", KEY_END, to_last_line, 0);
#endif
#ifdef ENABLE_LINTER
#ifdef ENABLE_COLOR
add_to_sclist(MLINTER, "^X", 0, do_cancel, 0);
#endif
add_to_sclist(MMOST & ~MFINDINHELP, "F1", KEY_F(1), do_help, 0);
@@ -1607,16 +1511,11 @@ 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);
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);
/* Catch and ignore bracketed paste marker keys. */
add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "", BRACKETED_PASTE_MARKER, 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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2000-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2017 Rishabh Dave *
* Copyright (C) 2014-2019 Benno Schulenberg *
* *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.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 what you "
"typed at the previous prompt, and press Enter.\n\n");
"Type the characters that should replace the characters that "
"you typed at the previous prompt, and press Enter.\n\n");
htx[1] = N_(" The following function keys "
"are available at this prompt:\n\n");
htx[2] = NULL;
@@ -150,14 +150,16 @@ void help_init(void)
#endif /* ENABLE_BROWSER */
#ifdef ENABLE_SPELLER
else if (currmenu == MSPELL) {
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[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[2] = NULL;
}
#endif /* ENABLE_SPELLER */
@@ -213,15 +215,15 @@ void help_init(void)
}
htx[0] = _(htx[0]);
if (htx[1])
if (htx[1] != NULL)
htx[1] = _(htx[1]);
if (htx[2])
if (htx[2] != NULL)
htx[2] = _(htx[2]);
allocsize += strlen(htx[0]);
if (htx[1])
if (htx[1] != NULL)
allocsize += strlen(htx[1]);
if (htx[2])
if (htx[2] != NULL)
allocsize += strlen(htx[2]);
/* Calculate the length of the descriptions of the shortcuts.
@@ -249,9 +251,9 @@ void help_init(void)
/* Now add the text we want. */
strcpy(help_text, htx[0]);
if (htx[1])
if (htx[1] != NULL)
strcat(help_text, htx[1]);
if (htx[2])
if (htx[2] != NULL)
strcat(help_text, htx[2]);
/* Remember this end-of-introduction, start-of-shortcuts. */
@@ -272,10 +274,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") ? 9 : 7);
ptr += (strstr(s->keystr, "\xE2") != NULL ? 9 : 7);
} else {
sprintf(ptr, "(%s) ", s->keystr);
ptr += (strstr(s->keystr, "\xE2") ? 12 : 10);
ptr += (strstr(s->keystr, "\xE2") != NULL ? 12 : 10);
break;
}
}
@@ -323,7 +325,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) - sidebar;
size_t wrapping_point = ((COLS < 40) ? 40 : (COLS > 74) ? 74 : COLS) - thebar;
const char *ptr = start_of_body;
size_t sum = 0;
@@ -337,12 +339,12 @@ void wrap_help_text_into_buffer(void)
}
/* Copy the help text into the just-created new buffer. */
while (*ptr) {
while (*ptr != '\0') {
int length, shim;
char *oneline;
if (ptr == end_of_intro)
wrapping_point = ((COLS < 40) ? 40 : COLS) - sidebar;
wrapping_point = ((COLS < 40) ? 40 : COLS) - thebar;
if (ptr < end_of_intro || *(ptr - 1) == '\n') {
length = break_line(ptr, wrapping_point, TRUE);
@@ -350,7 +352,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) - sidebar, TRUE);
length = break_line(ptr, ((COLS < 40) ? 22 : COLS - 18) - thebar, TRUE);
oneline = nmalloc(length + 5);
snprintf(oneline, length + 5, "\t\t %s", ptr);
}
@@ -402,13 +404,10 @@ 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) ? copy_of(answer) : NULL;
char *saved_answer = (answer != NULL) ? 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. */
@@ -434,13 +433,10 @@ void show_help(void)
UNSET(WHITESPACE_DISPLAY);
#ifdef ENABLE_LINENUMBERS
editwincols = COLS - sidebar;
editwincols = COLS - thebar;
margin = 0;
#endif
tabsize = 8;
#ifndef NANO_TINY
spotlighted = FALSE;
#endif
#ifdef ENABLE_COLOR
syntaxstr = "nanohelp";
#endif
@@ -480,11 +476,18 @@ void show_help(void)
#ifndef NANO_TINY
spotlighted = FALSE;
if (bracketed_paste || kbinput == BRACKETED_PASTE_MARKER) {
beep();
continue;
}
#endif
function = interpret(kbinput);
if (ISSET(SHOW_CURSOR) && (function == do_left || function == do_right ||
function == do_up || function == do_down)) {
if (function == full_refresh) {
full_refresh();
} else if (ISSET(SHOW_CURSOR) && (function == do_left || function == do_right ||
function == do_up || function == do_down)) {
function();
} else if (function == do_up || function == do_scroll_up) {
do_scroll_up();
@@ -505,18 +508,12 @@ void show_help(void)
#ifdef ENABLE_MOUSE
} else if (kbinput == KEY_MOUSE) {
int dummy_row, dummy_col;
get_mouseinput(&dummy_row, &dummy_col);
get_mouseinput(&dummy_row, &dummy_col, TRUE);
#endif
#ifndef NANO_TINY
} 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) {
} else if (kbinput == KEY_WINCH) {
; /* Nothing to do. */
#endif
} else if (function == full_refresh) {
full_refresh();
} else if (function == do_exit) {
break;
} else
@@ -542,12 +539,9 @@ void show_help(void)
#ifdef ENABLE_LINENUMBERS
margin = was_margin;
editwincols = COLS - margin - sidebar;
editwincols = COLS - margin - thebar;
#endif
tabsize = was_tabsize;
#ifndef NANO_TINY
spotlighted = was_lighted;
#endif
#ifdef ENABLE_COLOR
syntaxstr = was_syntax;
have_palette = FALSE;
@@ -570,7 +564,7 @@ void show_help(void)
bottombars(oldmenu);
#ifdef ENABLE_BROWSER
if (oldmenu & (MBROWSER|MGOTODIR|MWHEREISFILE))
if (oldmenu & (MBROWSER|MWHEREISFILE|MGOTODIR))
browser_refresh();
else
#endif

View File

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

View File

@@ -1,8 +1,8 @@
/**************************************************************************
* move.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2014-2018, 2020, 2024, 2026 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2018 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* 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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -47,7 +47,7 @@ void to_last_line(void)
openfile->placewewant = xplustabs();
/* Set the last line of the screen as the target for the cursor. */
openfile->cursor_row = editwinrows - 1;
openfile->current_y = editwinrows - 1;
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
@@ -89,7 +89,7 @@ size_t proper_x(linestruct *line, size_t *leftedge, bool forward,
column / tabsize < (*leftedge + editwincols - 1) / tabsize))) {
index++;
if (shifted)
if (shifted != NULL)
*shifted = TRUE;
}
@@ -139,7 +139,7 @@ void do_page_up(void)
if (ISSET(JUMPY_SCROLLING)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->cursor_row = 0;
openfile->current_y = 0;
target_column = 0;
} else
#endif
@@ -171,7 +171,7 @@ void do_page_down(void)
if (ISSET(JUMPY_SCROLLING)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->cursor_row = 0;
openfile->current_y = 0;
target_column = 0;
} else
#endif
@@ -191,68 +191,11 @@ 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)
if ((*line)->prev != NULL)
*line = (*line)->prev;
while (!begpar(*line, 0))
@@ -262,10 +205,11 @@ 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 && !inpar(*line))
while ((*line)->next != NULL && !inpar(*line))
*line = (*line)->next;
while ((*line)->next && inpar((*line)->next) && !begpar((*line)->next, 0))
while ((*line)->next != NULL && inpar((*line)->next) &&
!begpar((*line)->next, 0))
*line = (*line)->next;
}
@@ -289,7 +233,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) {
if (openfile->current->next != NULL) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
} else
@@ -310,7 +254,7 @@ void to_prev_block(void)
bool is_text = FALSE, seen_text = FALSE;
/* Skip backward until first blank line after some nonblank line(s). */
while (line_step && (!seen_text || is_text)) {
while (line_step != NULL && (!seen_text || is_text)) {
openfile->current = line_step;
line_step = get_prev_visible_line(line_step);
#ifdef ENABLE_FOLDING
@@ -324,7 +268,8 @@ void to_prev_block(void)
/* Step forward one line again if we passed text but this line is blank. */
line_step = get_next_visible_line(openfile->current);
if (seen_text && line_step && white_string(openfile->current->data)) {
if (seen_text && line_step != NULL &&
white_string(openfile->current->data)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
}
@@ -342,7 +287,7 @@ void to_next_block(void)
bool seen_white = is_white;
/* Skip forward until first nonblank line after some blank line(s). */
while (line_step && (!seen_white || is_white)) {
while (line_step != NULL && (!seen_white || is_white)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
#ifdef ENABLE_FOLDING
@@ -362,20 +307,20 @@ void to_next_block(void)
}
/* Move to the previous word.
* When allow_folded is true, will move to previous word even if inside
* a folded segment. */
* 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. */
@@ -394,7 +339,8 @@ void do_prev_word(bool allow_folded)
}
/* 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)) {
@@ -415,13 +361,14 @@ void do_prev_word(bool allow_folded)
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. 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. */
* 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);
@@ -433,7 +380,7 @@ bool do_next_word(bool after_ends, bool allow_folded)
#endif
#ifdef ENABLE_FOLDING
if (!allow_folded & openfile->current->folded) {
if (!allow_folded && openfile->current->folded) {
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}
@@ -450,7 +397,7 @@ bool do_next_word(bool after_ends, bool 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. */
* so skip to the end */
openfile->current = get_end_of_folded_segment(openfile->current);
openfile->current = openfile->current->next;
}
@@ -461,7 +408,8 @@ bool do_next_word(bool after_ends, bool allow_folded)
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
@@ -547,7 +495,7 @@ void do_home(void)
if (ISSET(SMART_HOME)) {
size_t indent_x = indent_length(openfile->current->data);
if (openfile->current->data[indent_x]) {
if (openfile->current->data[indent_x] != '\0') {
/* 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. */
@@ -657,8 +605,7 @@ void do_up(void)
set_proper_index_and_pww(&leftedge, target_column, FALSE);
if (openfile->cursor_row == 0 && !ISSET(JUMPY_SCROLLING) &&
(tabsize < editwincols || !ISSET(SOFTWRAP)))
if (openfile->current_y == 0 && !ISSET(JUMPY_SCROLLING))
edit_scroll(BACKWARD);
else
edit_redraw(was_current, FLOWING);
@@ -681,8 +628,7 @@ void do_down(void)
set_proper_index_and_pww(&leftedge, target_column, TRUE);
if (openfile->cursor_row == editwinrows - 1 && !ISSET(JUMPY_SCROLLING) &&
(tabsize < editwincols || !ISSET(SOFTWRAP)))
if (openfile->current_y == editwinrows - 1 && !ISSET(JUMPY_SCROLLING))
edit_scroll(FORWARD);
else
edit_redraw(was_current, FLOWING);
@@ -699,7 +645,7 @@ void do_scroll_up(void)
if (openfile->edittop->prev == NULL && openfile->firstcolumn == 0)
return;
if (openfile->cursor_row == editwinrows - 1)
if (openfile->current_y == editwinrows - 1)
do_up();
if (editwinrows > 1)
@@ -709,10 +655,10 @@ void do_scroll_up(void)
/* Scroll down one line or chunk without moving the cursor textwise. */
void do_scroll_down(void)
{
if (openfile->cursor_row == 0)
if (openfile->current_y == 0)
do_down();
if (editwinrows > 1 && (openfile->edittop->next
if (editwinrows > 1 && (openfile->edittop->next != NULL
#ifndef NANO_TINY
|| (ISSET(SOFTWRAP) && (extra_chunks_in(openfile->edittop) >
chunk_for(openfile->firstcolumn, openfile->edittop)))
@@ -720,6 +666,14 @@ 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. */
@@ -728,11 +682,13 @@ 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 = get_prev_visible_line(openfile->current);
@@ -754,12 +710,14 @@ void do_right(void)
openfile->current = was_current;
} else
#endif
if (openfile->current->data[openfile->current_x]) {
openfile->current_x = step_right(openfile->current->data, openfile->current_x);
if (openfile->current->data[openfile->current_x] != '\0') {
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
#ifdef ENABLE_UTF8
while (openfile->current->data[openfile->current_x] &&
while (openfile->current->data[openfile->current_x] != '\0' &&
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 = get_next_visible_line(openfile->current);
@@ -768,61 +726,3 @@ void do_right(void)
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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020-2022, 2025 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2018, 2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.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]) {
while (answer[typing_x] != '\0') {
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]) {
if (answer[typing_x] != '\0') {
typing_x = step_right(answer, typing_x);
#ifdef ENABLE_UTF8
while (answer[typing_x] && is_zerowidth(answer + typing_x))
while (answer[typing_x] != '\0' && 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]) {
if (answer[typing_x] != '\0') {
int charlen = char_length(answer + typing_x);
memmove(answer + typing_x, answer + typing_x + charlen,
@@ -184,7 +184,8 @@ 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;
@@ -192,21 +193,21 @@ void paste_into_answer(void)
#endif
#ifdef ENABLE_MOUSE
/* Handle a mouse click in the prompt bar or the help lines. */
int process_prompt_click(void)
/* Handle a mouse click on the status-bar prompt or the shortcut list. */
int do_statusbar_mouse(void)
{
int click_row, click_col;
int retval = get_mouseinput(&click_row, &click_col); /* Handles shortcuts. */
int retval = get_mouseinput(&click_row, &click_col, TRUE);
/* When the click is in the prompt bar, position the cursor. */
/* We can click on the status-bar window text to move the cursor. */
if (retval == 0 && wmouse_trafo(footwin, &click_row, &click_col, FALSE)) {
size_t start_col = breadth(prompt) + 2;
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;
/* 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);
}
return retval;
@@ -222,7 +223,8 @@ 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;
@@ -259,9 +261,10 @@ 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 != '\t') || meta_key || input > 0xFF)
if (input < 0x20 || input > 0xFF || meta_key)
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) {
@@ -302,7 +305,8 @@ 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] &&
else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE &&
openfile->filename[0] != '\0' &&
(function == do_verbatim_input ||
function == do_delete || function == do_backspace ||
function == cut_text || function == paste_text))
@@ -319,7 +323,7 @@ bool handle_editing(functionptrtype function)
else if (function == copy_text)
copy_the_answer();
else if (function == paste_text) {
if (cutbuffer)
if (cutbuffer != NULL)
paste_into_answer();
}
#endif
@@ -388,7 +392,6 @@ void draw_the_promptbar(void)
/* Place the cursor at the right spot. */
wmove(footwin, 0, column - the_page);
wnoutrefresh(footwin);
}
@@ -396,14 +399,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 == '|') {
if (answer[0] == '|') {
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 = '|';
answer[0] = '|';
typing_x++;
}
}
@@ -422,9 +425,6 @@ 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,19 +441,18 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
#ifndef NANO_TINY
/* If the window size changed, go reformat the prompt string. */
if (input == THE_WINDOW_RESIZED) {
*actual = THE_WINDOW_RESIZED;
if (input == KEY_WINCH) {
refresh_func(); /* Only needed when in file browser. */
*actual = KEY_WINCH;
#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 && process_prompt_click() == 1)
if (input == KEY_MOUSE && do_statusbar_mouse() == 1)
input = get_kbinput(footwin, BLIND);
if (input == KEY_MOUSE)
continue;
@@ -462,35 +461,23 @@ 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) {
if (history_list != NULL) {
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
@@ -501,7 +488,7 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
} else
#endif
#ifdef ENABLE_HISTORIES
if (function == get_older_item && history_list) {
if (function == get_older_item && history_list != NULL) {
/* If this is the first step into history, start at the bottom. */
if (stored_string == NULL)
reset_history_pointer_for(*history_list);
@@ -511,14 +498,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) {
if ((*history_list)->prev != NULL) {
*history_list = (*history_list)->prev;
answer = mallocstrcpy(answer, (*history_list)->data);
typing_x = strlen(answer);
}
} else if (function == get_newer_item && history_list) {
} else if (function == get_newer_item && history_list != NULL) {
/* If there is a newer item, move to it and copy its string. */
if ((*history_list)->next) {
if ((*history_list)->next != NULL) {
*history_list = (*history_list)->next;
answer = mallocstrcpy(answer, (*history_list)->data);
typing_x = strlen(answer);
@@ -550,11 +537,6 @@ 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
@@ -566,14 +548,9 @@ 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) {
if (stored_string != NULL) {
reset_history_pointer_for(*history_list);
free(stored_string);
}
@@ -620,17 +597,13 @@ int do_prompt(int menu, const char *provided, linestruct **history_list,
free(prompt);
#ifndef NANO_TINY
if (retval == THE_WINDOW_RESIZED)
if (retval == KEY_WINCH)
goto redo_theprompt;
#endif
/* Restore a possible previous prompt and maybe the typing position. */
prompt = saved_prompt;
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)
if (function == do_cancel || function == do_enter)
typing_x = was_typing_x;
/* Set the proper return value for Cancel and Enter. */
@@ -719,15 +692,14 @@ int ask_user(bool withall, const char *question)
kbinput = get_kbinput(footwin, !withall);
#ifndef NANO_TINY
if (kbinput == THE_WINDOW_RESIZED)
if (kbinput == KEY_WINCH)
continue;
/* Accept first character of an external paste and ignore the rest. */
if (kbinput == START_OF_PASTE) {
if (bracketed_paste)
kbinput = get_kbinput(footwin, BLIND);
while (get_kbinput(footwin, BLIND) != END_OF_PASTE)
;
}
while (bracketed_paste)
get_kbinput(footwin, BLIND);
#endif
#ifdef ENABLE_NLS
@@ -735,7 +707,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 (0xC0 <= kbinput && kbinput <= 0xF7 && using_utf8) {
if (using_utf8() && 0xC0 <= kbinput && kbinput <= 0xF7) {
int extras = (kbinput / 16) % 4 + (kbinput <= 0xCF ? 1 : 0);
while (extras <= waiting_keycodes() && extras-- > 0)
@@ -745,19 +717,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))
if (strstr(yesstr, letter) != NULL)
choice = YES;
else if (strstr(nostr, letter))
else if (strstr(nostr, letter) != NULL)
choice = NO;
else if (withall && strstr(allstr, letter))
else if (withall && strstr(allstr, letter) != NULL)
choice = ALL;
else
#endif /* ENABLE_NLS */
if (strchr("Yy", kbinput))
if (strchr("Yy", kbinput) != NULL)
choice = YES;
else if (strchr("Nn", kbinput))
else if (strchr("Nn", kbinput) != NULL)
choice = NO;
else if (withall && strchr("Aa", kbinput))
else if (withall && strchr("Aa", kbinput) != NULL)
choice = ALL;
if (choice != UNDECIDED)
@@ -780,22 +752,17 @@ int ask_user(bool withall, const char *question)
focusing = TRUE;
}
#endif
/* 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))) {
/* Interpret ^N and ^Q as "No", to allow exiting in anger. */
else if (kbinput == '\x0E' || kbinput == '\x11')
choice = NO;
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')
/* And interpret ^Y as "Yes". */
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) == 0 &&
if (get_mouseinput(&mouse_y, &mouse_x, FALSE) == 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-2026 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -24,31 +24,24 @@
#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;
@@ -75,19 +68,18 @@ 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;
extern int shiftaltup, shiftaltdown;
#endif
extern int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
extern ssize_t fill;
@@ -100,11 +92,10 @@ extern WINDOW *footwin;
extern int editwinrows;
extern int editwincols;
extern int margin;
extern int sidebar;
extern int thebar;
#ifndef NANO_TINY
extern int *bardata;
extern ssize_t stripe_column;
extern int cycling_aim;
#endif
extern linestruct *cutbuffer;
@@ -210,6 +201,10 @@ 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);
@@ -232,7 +227,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)
const char *mbstrchr(const char *string, const char *chr);
char *mbstrchr(const char *string, const char *chr);
#endif
#ifndef NANO_TINY
char *mbstrpbrk(const char *string, const char *accept);
@@ -242,9 +237,6 @@ 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
@@ -256,7 +248,6 @@ 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
@@ -275,8 +266,8 @@ void cut_text(void);
void cut_till_eof(void);
void zap_text(void);
void copy_marked_region(void);
#endif
void copy_text(void);
#endif
void paste_text(void);
/* Most functions in files.c. */
@@ -310,14 +301,16 @@ 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, writing_type method, bool annotate);
bool write_file(const char *name, FILE *thefile, bool normal,
kind_of_writing_type method, bool annotate);
#ifndef NANO_TINY
bool write_region_to_file(const char *name, FILE *stream, writing_type method);
bool write_region_to_file(const char *name, FILE *stream, bool normal,
kind_of_writing_type method);
#endif
int write_it_out(bool exiting, bool withprompt);
void do_writeout(void);
void do_savefile(void);
char *expand_leading_tilde(const char *path);
char *real_dir_from_tilde(const char *path);
#if defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
int diralphasort(const void *va, const void *vb);
#endif
@@ -354,9 +347,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_positions_register(void);
void update_positions_register(void);
void restore_cursor_position_if_any(void);
void load_poshistory(void);
void update_poshistory(void);
bool has_old_position(const char *file, ssize_t *line, ssize_t *column);
#endif
/* Most functions in move.c. */
@@ -364,12 +357,6 @@ 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);
@@ -389,14 +376,11 @@ 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);
@@ -445,7 +429,6 @@ 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. */
@@ -490,13 +473,11 @@ 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);
@@ -578,15 +559,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 *mallocstrcpy(char *dest, const char *src);
char *measured_copy(const char *string, size_t count);
char *mallocstrcpy(char *dest, const char *src);
char *copy_of(const char *string);
char *free_and_assign(char *dest, char *src);
size_t get_page_start(size_t column);
size_t actual_x(const char *text, size_t column);
size_t wideness(const char *text, size_t count);
size_t breadth(const char *text);
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 breadth(const char *text);
void new_magicline(void);
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
void remove_magicline(void);
@@ -608,8 +589,8 @@ linestruct *get_prev_visible_line(linestruct *line);
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
@@ -617,13 +598,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);
int get_mouseinput(int *mouse_y, int *mouse_x, bool allow_shortcuts);
#endif
void blank_edit(void);
void blank_statusbar(void);
void wipe_statusbar(void);
void blank_bottombars(void);
void blank_it_when_expired(void);
void check_statusblank(void);
void set_blankdelay_to_one(void);
char *display_string(const char *buf, size_t column, size_t span,
bool isdata, bool isprompt);
@@ -687,6 +668,7 @@ 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);
@@ -704,6 +686,7 @@ void do_cancel(void);
#ifdef ENABLE_FOLDING
void do_fold_segment(void);
void unfold_folded_segment(linestruct *line);
void unfold_folded_segment_from(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);

View File

@@ -1,10 +1,10 @@
/**************************************************************************
* rcfile.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2001-2011, 2013-2026 Free Software Foundation, Inc. *
* Copyright (C) 2001-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014 Mike Frysinger *
* Copyright (C) 2019 Brand Huntsman *
* Copyright (C) 2014-2021, 2024 Benno Schulenberg *
* Copyright (C) 2014-2021 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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -64,13 +64,12 @@ static const rcoption rcopts[] = {
{"mouse", USE_MOUSE},
#endif
#ifdef ENABLE_MULTIBUFFER
{"multibuffer", NEW_BUFFER}, /* Deprecated; remove in 2031. */
{"newbuffer", NEW_BUFFER},
{"multibuffer", MULTIBUFFER},
#endif
{"nohelp", NO_HELP},
{"nonewlines", NO_NEWLINES},
#ifdef ENABLE_WRAPPING
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2027. */
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2024. */
#endif
#ifdef ENABLE_OPERATINGDIR
{"operatingdir", 0},
@@ -99,7 +98,6 @@ static const rcoption rcopts[] = {
{"backup", MAKE_BACKUP},
{"backupdir", 0},
{"bookstyle", BOOKSTYLE},
{"colonparsing", COLON_PARSING},
{"cutfromcursor", CUT_FROM_CURSOR},
{"emptyline", EMPTY_LINE},
{"guidestripe", 0},
@@ -112,14 +110,12 @@ 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},
@@ -138,7 +134,6 @@ static const rcoption rcopts[] = {
{"errorcolor", 0},
{"keycolor", 0},
{"functioncolor", 0},
{"foldedcolor", 0},
#endif
{NULL, 0}
};
@@ -190,7 +185,7 @@ void jot_error(const char *msg, ...)
if (startup_problem == NULL) {
#ifdef ENABLE_NANORC
if (nanorc) {
if (nanorc != NULL) {
snprintf(textbuf, MAXSIZE, _("Mistakes in '%s'"), nanorc);
startup_problem = copy_of(textbuf);
} else
@@ -199,7 +194,8 @@ 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);
@@ -249,8 +245,6 @@ 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
@@ -258,6 +252,8 @@ 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"))
@@ -325,8 +321,6 @@ 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"))
@@ -340,17 +334,13 @@ 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;
@@ -364,16 +354,6 @@ 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;
@@ -402,6 +382,10 @@ 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"))
@@ -410,6 +394,8 @@ 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;
@@ -419,6 +405,8 @@ 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"))
@@ -475,7 +463,8 @@ keystruct *strtosc(const char *input)
else if (!strcmp(input, "cutfromcursor"))
s->toggle = CUT_FROM_CURSOR;
#ifdef ENABLE_WRAPPING
else if (!strcmp(input, "breaklonglines"))
else if (!strcmp(input, "breaklonglines") ||
!strcmp(input, "nowrap")) /* Deprecated; remove in 2024. */
s->toggle = BREAK_LONG_LINES;
#endif
else if (!strcmp(input, "tabstospaces"))
@@ -530,12 +519,12 @@ char *menu_to_name(int menu)
return "boooo";
}
/* 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. */
/* 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. */
char *parse_next_word(char *ptr)
{
while (*ptr && !isblank((unsigned char)*ptr))
while (!isblank((unsigned char)*ptr) && *ptr != '\0')
ptr++;
if (*ptr == '\0')
@@ -550,23 +539,25 @@ char *parse_next_word(char *ptr)
return ptr;
}
/* 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. */
/* 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. */
char *parse_argument(char *ptr)
{
const char *the_start = ptr;
const char *ptr_save = ptr;
char *last_quote = NULL;
if (*ptr != '"')
return parse_next_word(ptr);
while (*ptr)
while (*ptr != '\0') {
if (*++ptr == '"')
last_quote = ptr;
}
if (last_quote == NULL) {
jot_error(N_("Argument '%s' has an unterminated \""), the_start);
jot_error(N_("Argument '%s' has an unterminated \""), ptr_save);
return NULL;
}
@@ -593,7 +584,8 @@ 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 && (*ptr != '"' || (ptr[1] && !isblank((unsigned char)ptr[1]))))
while (*ptr != '\0' && (*ptr != '"' ||
(ptr[1] != '\0' && !isblank((unsigned char)ptr[1]))))
ptr++;
if (*ptr == '\0') {
@@ -687,7 +679,7 @@ void begin_new_syntax(char *ptr)
live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER);
#endif
live_syntax->color = NULL;
live_syntax->multiscore = 0;
live_syntax->nmultis = 0;
/* Hook the new syntax in at the top of the list. */
live_syntax->next = syntaxes;
@@ -697,13 +689,13 @@ void begin_new_syntax(char *ptr)
seen_color_command = FALSE;
/* The default syntax should have no associated extensions. */
if (*ptr && strcmp(live_syntax->name, "default") == 0) {
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
jot_error(N_("The \"default\" syntax does not accept extensions"));
return;
}
/* If there seem to be extension regexes, pick them up. */
if (*ptr)
if (*ptr != '\0')
grab_and_store("extension", ptr, &live_syntax->extensions);
}
#endif /* ENABLE_COLOR */
@@ -740,11 +732,9 @@ 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 *keycopy, *keyptr, *menuptr;
char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
int keycode, menu, mask = 0;
keystruct *newsc = NULL;
char *funcptr = NULL;
int keycode, menu;
int mask = 0;
check_for_nonempty_syntax();
@@ -758,13 +748,12 @@ 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] == '^') {
if ('a' <= keycopy[1] && keycopy[1] <= 'z')
keycopy[1] &= 0x5F;
} else if ('a' <= keycopy[0] && keycopy[0] <= 'z')
keycopy[0] &= 0x5F;
if (keycopy[0] == '^')
keycopy[1] = toupper((unsigned char)keycopy[1]);
else
keycopy[0] = toupper((unsigned char)keycopy[0]);
/* Verify that the key name is not too short. */
/* Verify that the key name is not too short, to allow the next call. */
if (keycopy[1] == '\0' || (keycopy[0] == 'M' && keycopy[2] == '\0')) {
jot_error(N_("Key name %s is invalid"), keycopy);
goto free_things;
@@ -789,11 +778,12 @@ void parse_binding(char *ptr, bool dobind)
}
menuptr = ptr;
parse_next_word(ptr);
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;
}
@@ -856,7 +846,8 @@ 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;
}
@@ -893,14 +884,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) == 0 && (S_ISDIR(rcinfo.st_mode) ||
if (stat(file, &rcinfo) != -1 && (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;
@@ -949,7 +940,7 @@ void parse_one_include(char *file, syntaxtype *syntax)
extra = syntax->augmentations;
/* Apply any stored extendsyntax commands. */
while (extra) {
while (extra != NULL) {
char *keyword = extra->data;
char *therest = parse_next_word(extra->data);
@@ -962,7 +953,6 @@ void parse_one_include(char *file, syntaxtype *syntax)
extra = extra->next;
}
/* Indicate that this syntax has been loaded. */
free(syntax->filename);
syntax->filename = NULL;
@@ -982,15 +972,10 @@ void parse_includes(char *ptr)
pattern = ptr;
if (*pattern == '"')
pattern++;
parse_argument(ptr);
if (strlen(pattern) > PATH_MAX) {
jot_error(N_("Path is too long"));
return;
}
ptr = parse_argument(ptr);
/* Expand a tilde first, then try to match the globbing pattern. */
expanded = expand_leading_tilde(pattern);
expanded = real_dir_from_tilde(pattern);
result = glob(expanded, GLOB_ERR|GLOB_NOCHECK, NULL, &files);
/* If there are matches, process each of them. Otherwise, only
@@ -1006,22 +991,16 @@ void parse_includes(char *ptr)
}
/* Return the index of the color that is closest to the given RGB levels,
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color.
* When red == green == blue, return an index in the xterm gray scale. */
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */
short closest_index_color(short red, short green, short blue)
{
/* Translation table, from 16 intended color levels to 6 available levels. */
/* Translation table, from 16 intended levels to 6 available levels. */
static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
/* Translation table, from 14 intended gray levels to 24 available levels. */
static const short gray[] = { 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 18, 21, 23 };
if (COLORS != 256)
return THE_DEFAULT;
else if (red == green && green == blue && 0 < red && red < 0xF)
return 232 + gray[red - 1];
else
if (COLORS == 256)
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
else
return THE_DEFAULT;
}
#define COLORCOUNT 34
@@ -1051,12 +1030,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]) {
/* Prefix "bright" is deprecated; remove in 2027. */
if (strncmp(colorname, "bright", 6) == 0 && colorname[6] != '\0') {
/* Prefix "bright" is deprecated; remove in 2024. */
*vivid = TRUE;
*thick = TRUE;
colorname += 6;
} else if (strncmp(colorname, "light", 5) == 0 && colorname[5]) {
} else if (strncmp(colorname, "light", 5) == 0 && colorname[5] != '\0') {
*vivid = TRUE;
*thick = FALSE;
colorname += 5;
@@ -1094,40 +1073,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 *combotext, short *fg, short *bg, int *attributes)
bool parse_combination(char *combostr, short *fg, short *bg, int *attributes)
{
bool vivid, thick;
char *comma;
*attributes = A_NORMAL;
if (strncmp(combotext, "bold", 4) == 0) {
if (strncmp(combostr, "bold", 4) == 0) {
*attributes |= A_BOLD;
if (combotext[4] != ',') {
if (combostr[4] != ',') {
jot_error(N_("An attribute requires a subsequent comma"));
return FALSE;
}
combotext += 5;
combostr += 5;
}
if (strncmp(combotext, "italic", 6) == 0) {
if (strncmp(combostr, "italic", 6) == 0) {
#ifdef A_ITALIC
*attributes |= A_ITALIC;
#endif
if (combotext[6] != ',') {
if (combostr[6] != ',') {
jot_error(N_("An attribute requires a subsequent comma"));
return FALSE;
}
combotext += 7;
combostr += 7;
}
comma = strchr(combotext, ',');
comma = strchr(combostr, ',');
if (comma)
*comma = '\0';
if (!comma || comma > combotext) {
*fg = color_to_short(combotext, &vivid, &thick);
if (!comma || comma > combostr) {
*fg = color_to_short(combostr, &vivid, &thick);
if (*fg == BAD_COLOR)
return FALSE;
if (vivid && !thick && COLORS > 8)
@@ -1174,7 +1153,7 @@ void parse_rule(char *ptr, int rex_flags)
return;
}
while (*ptr) {
while (*ptr != '\0') {
regex_t *start_rgx = NULL, *end_rgx = NULL;
/* Intermediate storage for compiled regular expressions. */
colortype *newcolor = NULL;
@@ -1233,22 +1212,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->multiscore;
live_syntax->multiscore++;
newcolor->id = live_syntax->nmultis;
live_syntax->nmultis++;
}
}
}
/* Set the colors for the given interface element to the given combination. */
void set_interface_color(int element, char *combotext)
/* Parse the argument of an interface color option. */
colortype *parse_interface_color(char *combostr)
{
colortype *trio = nmalloc(sizeof(colortype));
if (parse_combination(combotext, &trio->fg, &trio->bg, &trio->attributes)) {
free(color_combo[element]);
color_combo[element] = trio;
} else
if (!parse_combination(combostr, &trio->fg, &trio->bg, &trio->attributes)) {
free(trio);
return NULL;
} else
return trio;
}
/* Read regex strings enclosed in double quotes from the line pointed at
@@ -1264,7 +1243,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
}
/* The default syntax doesn't take any file matching stuff. */
if (*ptr && strcmp(live_syntax->name, "default") == 0) {
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
jot_error(N_("The \"default\" syntax does not accept '%s' regexes"), kind);
return;
}
@@ -1277,11 +1256,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 && lastthing->next)
while (lastthing != NULL && lastthing->next != NULL)
lastthing = lastthing->next;
/* Now gather any valid regexes and add them to the linked list. */
while (*ptr) {
while (*ptr != '\0') {
regex_t *packed_rgx = NULL;
regexstring = ++ptr;
@@ -1308,7 +1287,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
}
}
/* Gather and store the string after a comment/linter/formatter/tabgives command. */
/* Gather and store the string after a comment/linter command. */
void pick_up_name(const char *kind, char *ptr, char **storage)
{
if (*ptr == '\0') {
@@ -1347,21 +1326,19 @@ 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);
strip_leading_blanks_from(live_syntax->linter);
} else if (strcmp(keyword, "formatter") == 0) {
else if (strcmp(keyword, "formatter") == 0)
pick_up_name("formatter", ptr, &live_syntax->formatter);
strip_leading_blanks_from(live_syntax->formatter);
} else
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
@@ -1370,7 +1347,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]));
@@ -1385,7 +1362,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
* contain only color syntax commands. */
* to contain only color syntax commands. */
void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
{
char *buffer = NULL;
@@ -1464,9 +1441,9 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
newitem->data = argument;
newitem->next = NULL;
if (sntx->augmentations) {
if (sntx->augmentations != NULL) {
extra = sntx->augmentations;
while (extra->next)
while (extra->next != NULL)
extra = extra->next;
extra->next = newitem;
} else
@@ -1498,7 +1475,8 @@ 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 ||
@@ -1508,7 +1486,8 @@ 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;
@@ -1580,42 +1559,40 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
argument = ptr;
if (*argument == '"')
argument++;
parse_argument(ptr);
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)
set_interface_color(TITLE_BAR, argument);
color_combo[TITLE_BAR] = parse_interface_color(argument);
else if (strcmp(option, "numbercolor") == 0)
set_interface_color(LINE_NUMBER, argument);
color_combo[LINE_NUMBER] = parse_interface_color(argument);
else if (strcmp(option, "stripecolor") == 0)
set_interface_color(GUIDE_STRIPE, argument);
color_combo[GUIDE_STRIPE] = parse_interface_color(argument);
else if (strcmp(option, "scrollercolor") == 0)
set_interface_color(SCROLL_BAR, argument);
color_combo[SCROLL_BAR] = parse_interface_color(argument);
else if (strcmp(option, "selectedcolor") == 0)
set_interface_color(SELECTED_TEXT, argument);
color_combo[SELECTED_TEXT] = parse_interface_color(argument);
else if (strcmp(option, "spotlightcolor") == 0)
set_interface_color(SPOTLIGHTED, argument);
color_combo[SPOTLIGHTED] = parse_interface_color(argument);
else if (strcmp(option, "minicolor") == 0)
set_interface_color(MINI_INFOBAR, argument);
color_combo[MINI_INFOBAR] = parse_interface_color(argument);
else if (strcmp(option, "promptcolor") == 0)
set_interface_color(PROMPT_BAR, argument);
color_combo[PROMPT_BAR] = parse_interface_color(argument);
else if (strcmp(option, "statuscolor") == 0)
set_interface_color(STATUS_BAR, argument);
color_combo[STATUS_BAR] = parse_interface_color(argument);
else if (strcmp(option, "errorcolor") == 0)
set_interface_color(ERROR_MESSAGE, argument);
color_combo[ERROR_MESSAGE] = parse_interface_color(argument);
else if (strcmp(option, "keycolor") == 0)
set_interface_color(KEY_COMBO, argument);
color_combo[KEY_COMBO] = parse_interface_color(argument);
else if (strcmp(option, "functioncolor") == 0)
set_interface_color(FUNCTION_TAG, argument);
else if (strcmp(option, "foldedcolor") == 0)
set_interface_color(FOLDED_LINE, argument);
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
else
#endif
#ifdef ENABLE_OPERATINGDIR
@@ -1707,13 +1684,12 @@ void parse_one_nanorc(void)
/* If opening the file succeeded, parse it. Otherwise, only
* complain if the file actually exists. */
if (rcstream)
if (rcstream != NULL)
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)
@@ -1731,18 +1707,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"));
if (is_good_file(nanorc))
parse_one_nanorc();
} else {
const char *xdgconfdir;
} else
nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
if (have_nanorc(SYSCONFDIR, "/nanorc"))
parse_one_nanorc();
if (is_good_file(nanorc))
parse_one_nanorc();
if (custom_nanorc == NULL) {
const char *xdgconfdir = getenv("XDG_CONFIG_HOME");
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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2015-2022, 2025, 2026 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2015-2020, 2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -79,12 +79,13 @@ 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) {
if (*last_search != '\0') {
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("");
@@ -98,8 +99,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) ? _(" [Reg.exp.]") : "",
ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : "",
ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : "",
replacing ?
#ifndef NANO_TINY
@@ -117,7 +118,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) {
if (*answer != '\0') {
last_search = mallocstrcpy(last_search, answer);
#ifdef ENABLE_HISTORIES
update_history(&search_history, answer, PRUNE_DUPLICATE);
@@ -154,15 +155,14 @@ void search_init(bool replacing, bool retain_answer)
} else
replacing = !replacing;
} else if (function == flip_goto) {
ask_for_line_and_column(answer);
goto_line_and_column(openfile->current->lineno,
openfile->placewewant + 1, TRUE, TRUE);
break;
} else
break;
}
if (!inhelp)
tidy_up_after_search();
tidy_up_after_search();
free(thedefault);
}
@@ -202,21 +202,22 @@ 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) {
} else if (!ISSET(BACKWARDS_SEARCH) && *from != '\0') {
from += char_length(from);
found = strstrwrapper(line->data, needle, from);
}
} else
found = strstrwrapper(line->data, needle, from);
if (found) {
if (found != NULL) {
/* 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;
}
@@ -324,7 +325,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)
if (match_len != NULL)
*match_len = found_len;
#ifndef NANO_TINY
@@ -332,14 +333,6 @@ 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
@@ -370,7 +363,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)
if (*last_search == '\0' && searchbot->prev != NULL)
last_search = mallocstrcpy(last_search, searchbot->prev->data);
#endif
@@ -390,8 +383,7 @@ void do_research(void)
go_looking();
if (!inhelp)
tidy_up_after_search();
tidy_up_after_search();
}
/* Search in the backward direction for the next occurrence. */
@@ -424,7 +416,7 @@ void not_found_msg(const char *str)
void go_looking(void)
{
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
size_t was_current_x = openfile->current_x;
//#define TIMEIT 12
#ifdef TIMEIT
@@ -439,49 +431,56 @@ 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_x)
if (didfind == 1 && openfile->current == was_current &&
openfile->current_x == was_current_x)
statusline(REMARK, _("This is the only occurrence"));
else if (didfind == 0)
not_found_msg(last_search);
#ifdef TIMEIT
statusline(NOTICE, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
statusline(INFO, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
#endif
edit_redraw(was_current, CENTERING);
}
/* 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)
/* 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)
{
size_t replacement_size = 0;
const char *given = answer;
const char *c = answer;
while (*given) {
int digit = (given[1] - '0');
/* Iterate through the replacement text to handle subexpression
* replacement using \1, \2, \3, etc. */
while (*c != '\0') {
int num = (*(c + 1) - '0');
/* 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;
if (string) {
strncpy(string, openfile->current->data + regmatches[digit].rm_so, extent);
string += extent;
}
replacement_size += extent;
given += 2;
} else {
if (string)
*string++ = *given;
if (*c != '\\' || num < 1 || num > 9 || num > search_regexp.re_nsub) {
if (create)
*string++ = *c;
c++;
replacement_size++;
given++;
} else {
size_t i = regmatches[num].rm_eo - regmatches[num].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)
if (create)
*string = '\0';
return replacement_size;
@@ -497,7 +496,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) - match_len;
new_size += replace_regexp(NULL, FALSE) - match_len;
} else {
match_len = strlen(needle);
new_size += strlen(answer) - match_len;
@@ -510,7 +509,7 @@ char *replace_line(const char *needle)
/* Add the replacement text. */
if (ISSET(USE_REGEXP))
replace_regexp(copy + openfile->current_x);
replace_regexp(copy + openfile->current_x, TRUE);
else
strcpy(copy + openfile->current_x, answer);
@@ -589,13 +588,9 @@ 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);
#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
light_to_col = wideness(openfile->current->data,
openfile->current_x + match_len);
/* Refresh the edit window, scrolling it if necessary. */
edit_refresh();
@@ -685,6 +680,11 @@ 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;
}
@@ -706,24 +706,18 @@ 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, we're done. */
/* When cancelled, or when a function was run, get out. */
if (response == -1) {
statusbar(_("Cancelled"));
return;
@@ -768,74 +762,58 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
}
#endif
/* Implement the Go To Line menu. */
void do_gotolinecolumn(void)
/* 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)
{
ask_for_line_and_column("");
}
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 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 the user cancelled or gave a blank answer, get out. */
if (response < 0) {
statusbar(_("Cancelled"));
return;
}
/* 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;
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 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)
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))
@@ -857,8 +835,6 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool hugfloor)
/* 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;
@@ -872,59 +848,71 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool hugfloor)
openfile->placewewant = breadth(openfile->current->data);
#endif
if (!hugfloor)
return;
/* 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;
#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->cursor_row = editwinrows - 1 - rows_from_tail;
adjust_viewport(STATIONARY);
} else
adjust_viewport(CENTERING);
/* 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);
}
#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.
/* Search backwards for a line ending with a bracket, including the current line.
* top 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)
* a loop the halfway value isn't recomputed. */
bool find_start_of_bracketed_region(linestruct **top, size_t *xpos, size_t bracket_half)
{
/* Search forwards for a line ending with a bracket, including the current line */
for (; (*line) != NULL; *line = (reverse ? (*line)->prev : (*line)->next)) {
/* Search backwards for a line ending with a bracket, including the current line */
for (;(*top) != NULL;*top = (*top)->prev) {
char *found;
const char *bracket;
int len = strlen((*line)->data);
int len = strlen((*top)->data);
/* Find the last bracket on the search line */
found = mbrevstrpbrk((*line)->data, matchbrackets, (*line)->data + len);
found = mbrevstrpbrk((*top)->data, matchbrackets, (*top)->data + len);
if (found == NULL)
continue;
*xpos = found - (*line)->data;
*xpos = found - (*top)->data;
bracket = mbstrchr(matchbrackets, found);
/* We're looking for closing braces, not opening */
/* We're looking for opening braces, not closing */
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);
char *next = (*top)->data + step_right((*top)->data, *xpos);
if (*next == '\0')
return TRUE;
}
@@ -939,18 +927,16 @@ size_t get_matchbrackets_halfway(void)
size_t charcount = mbstrlen(matchbrackets) / 2;
size_t halfway = 0;
for (size_t i = 0; i < charcount; ++i)
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. */
* as a block of text starting with an opening bracket at the end of a line,
* and ending with a matching closing bracket.
* top and bot are out parameters. Returns the top/bottom line of the region.
* top_pos and bot_pos are out parameters. Returns the position within the
* top and bottom lines where the brackets are found. */
bool find_bracketed_region(linestruct *in_region,
linestruct **top, linestruct **bot)
{
@@ -959,12 +945,12 @@ bool find_bracketed_region(linestruct *in_region,
size_t bot_pos;
linestruct *was_top = *top;
linestruct *was_bot = *bot;
*bot = in_region;
*top = in_region;
for (; find_terminus_of_bracketed_region(top, &top_pos, bracket_half, TRUE)
; *top = (*top)->prev)
for (;find_start_of_bracketed_region(top, &top_pos, bracket_half)
;*top = (*top)->prev)
{
*bot= *top;
*bot = *top;
bot_pos = top_pos;
if (!find_matching_bracket_pos(bot, &bot_pos)) {
@@ -1055,7 +1041,8 @@ const char *get_bracket_compliment(const char *ch, bool *reverse)
wanted_ch = ch;
while (charcount-- > 0) {
if (*reverse)
wanted_ch = matchbrackets + step_left(matchbrackets, wanted_ch - matchbrackets);
wanted_ch = matchbrackets + step_left(matchbrackets,
wanted_ch - matchbrackets);
else
wanted_ch += char_length(wanted_ch);
}
@@ -1126,7 +1113,7 @@ int find_matching_bracket_pos(linestruct **line, size_t *xpos)
void do_find_bracket(void)
{
linestruct *was_current = openfile->current;
size_t was_x = openfile->current_x;
size_t was_current_x = openfile->current_x;
int res = find_matching_bracket_pos(&openfile->current,
&openfile->current_x);
@@ -1136,11 +1123,12 @@ void do_find_bracket(void)
return;
}
statusline(AHEM, _("No matching bracket"));
/* Restore the cursor position. */
openfile->current = was_current;
openfile->current_x = was_x;
openfile->current_x = was_current_x;
statusline(AHEM, res == NOT_FOUND_BRACKET ?
_("No matching bracket") :
_("Not a bracket"));
}
/* Place an anchor at the current line when none exists, otherwise remove it. */
@@ -1148,17 +1136,12 @@ void put_or_lift_anchor(void)
{
openfile->current->has_anchor = !openfile->current->has_anchor;
if (openfile->current != openfile->filetop)
update_line(openfile->current, openfile->current_x);
else
refresh_needed = TRUE;
update_line(openfile->current, openfile->current_x);
if (!ISSET(LINE_NUMBERS) && (!ISSET(MINIBAR) || ISSET(ZERO))) {
if (openfile->current->has_anchor)
statusline(REMARK, _("Placed anchor"));
else
statusline(HUSH, _("Removed anchor"));
}
if (openfile->current->has_anchor)
statusline(REMARK, _("Placed anchor"));
else
statusline(REMARK, _("Removed anchor"));
}
/* Make the given line the current line, or report the anchoredness. */
@@ -1176,8 +1159,7 @@ void go_to_and_confirm(linestruct *line)
recook |= perturbed;
#endif
edit_redraw(was_current, CENTERING);
if (!ISSET(LINE_NUMBERS))
statusbar(_("Jumped to anchor"));
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-2026 Free Software Foundation, Inc. *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2014-2015 Mark Majeres *
* Copyright (C) 2016 Mike Scalora *
* Copyright (C) 2016 Sumedh Pendurkar *
* Copyright (C) 2018 Marco Diego Aurélio Mesquita *
* Copyright (C) 2015-2022, 2024, 2026 Benno Schulenberg *
* Copyright (C) 2015-2022 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
@@ -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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -32,6 +32,17 @@
#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)
@@ -53,12 +64,6 @@ 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));
@@ -282,7 +287,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 && line->lineno <= group->bottom_line) {
while (line != NULL && line->lineno <= group->bottom_line) {
char *blanks = group->indentations[line->lineno - group->top_line];
if (undoing ^ add_indent)
@@ -438,8 +443,9 @@ void handle_comment_action(undostruct *u, bool undoing, bool add_comment)
while (group) {
linestruct *line = line_from_number(group->top_line);
while (line && line->lineno <= group->bottom_line) {
comment_line(undoing ^ add_comment ? COMMENT : UNCOMMENT, line, u->strdata);
while (line != NULL && line->lineno <= group->bottom_line) {
comment_line(undoing ^ add_comment ?
COMMENT : UNCOMMENT, line, u->strdata);
line = line->next;
}
@@ -560,8 +566,8 @@ void do_undo(void)
* and the nonewlines flag isn't set, do not re-add a newline that
* wasn't actually deleted; just position the cursor. */
if ((u->xflags & WAS_BACKSPACE_AT_EOF) && !ISSET(NO_NEWLINES)) {
goto_line_posx(openfile->filebot->lineno, 0);
focusing = FALSE;
openfile->current = openfile->filebot;
openfile->current_x = 0;
break;
}
line->data[u->tail_x] = '\0';
@@ -573,6 +579,8 @@ 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;
@@ -623,12 +631,12 @@ void do_undo(void)
case COUPLE_BEGIN:
undidmsg = u->strdata;
goto_line_posx(u->head_lineno, u->head_x);
openfile->cursor_row = u->tail_lineno;
openfile->current_y = 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->cursor_row;
openfile->current_undo->head_lineno = openfile->current_y;
openfile->current_undo = openfile->current_undo->next;
do_undo();
do_undo();
@@ -669,8 +677,8 @@ void do_undo(void)
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT || u->type == COUPLE_BEGIN)
recook = TRUE;
else if (u->type == INSERT)
perturbed = TRUE;
#endif
/* When at the point where the buffer was last saved, unset "Modified". */
@@ -750,6 +758,8 @@ 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;
@@ -762,7 +772,6 @@ 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");
@@ -800,7 +809,7 @@ void do_redo(void)
case COUPLE_END:
redidmsg = u->strdata;
goto_line_posx(u->tail_lineno, u->tail_x);
openfile->cursor_row = u->head_lineno;
openfile->current_y = u->head_lineno;
adjust_viewport(STATIONARY);
break;
case INDENT:
@@ -838,7 +847,7 @@ void do_redo(void)
#ifdef ENABLE_COLOR
if (u->type <= REPLACE)
check_the_multis(openfile->current);
else if (u->type == INSERT || u->type == COUPLE_END)
else if (u->type == INSERT)
recook = TRUE;
#endif
@@ -870,7 +879,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 &&
if (ISSET(BREAK_LONG_LINES) && sampleline->next != NULL &&
inpar(sampleline->next) && !begpar(sampleline->next, 0))
sampleline = sampleline->next;
#endif
@@ -883,25 +892,17 @@ 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
@@ -910,6 +911,13 @@ 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. */
@@ -941,14 +949,15 @@ void discard_until(const undostruct *thisitem)
undostruct *dropit = openfile->undotop;
groupstruct *group;
while (dropit && dropit != thisitem) {
while (dropit != NULL && dropit != thisitem) {
openfile->undotop = dropit->next;
free(dropit->strdata);
free_lines(dropit->cutbuffer);
group = dropit->grouping;
while (group) {
while (group != NULL) {
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;
}
@@ -1014,13 +1023,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])
if (thisline->next == openfile->filebot && thisline->data[0] != '\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]) {
if (thisline->data[openfile->current_x] != '\0') {
int charlen = char_length(thisline->data + u->head_x);
u->strdata = measured_copy(thisline->data + u->head_x, charlen);
@@ -1029,7 +1038,7 @@ void add_undo(undo_type action, const char *message)
break;
}
action = JOIN;
if (thisline->next) {
if (thisline->next != NULL) {
if (u->type == BACK) {
u->head_lineno = thisline->next->lineno;
u->head_x = 0;
@@ -1040,6 +1049,8 @@ 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:
@@ -1083,7 +1094,7 @@ void add_undo(undo_type action, const char *message)
u->xflags |= INCLUDED_LAST_LINE;
break;
case COUPLE_BEGIN:
u->tail_lineno = openfile->cursor_row;
u->tail_lineno = openfile->current_y;
/* Fall-through. */
case COUPLE_END:
u->strdata = copy_of(_(message));
@@ -1096,11 +1107,7 @@ 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;
@@ -1149,10 +1156,8 @@ 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;
@@ -1201,7 +1206,7 @@ void update_undo(undo_type action)
case CUT:
if (u->type == ZAP)
u->cutbuffer = cutbuffer;
else if (cutbuffer) {
else if (cutbuffer != NULL) {
free_lines(u->cutbuffer);
u->cutbuffer = copy_buffer(cutbuffer);
} else
@@ -1211,7 +1216,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) {
while (bottomline->next != NULL) {
bottomline = bottomline->next;
count++;
}
@@ -1233,11 +1238,7 @@ 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 */
@@ -1270,7 +1271,8 @@ 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)
@@ -1323,18 +1325,18 @@ void do_wrap(void)
}
/* Join the next line to this one. */
expunge(DEL);
do_delete();
#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--)
expunge(DEL);
do_delete();
#endif
/* Remove any extra blanks. */
while (is_blank_char(&line->data[openfile->current_x]))
expunge(DEL);
do_delete();
}
/* Go to the wrap location. */
@@ -1348,7 +1350,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;
expunge(DEL);
do_delete();
rear_x = step_left(line->data, rear_x);
}
}
@@ -1356,12 +1358,6 @@ 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) {
@@ -1416,12 +1412,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 && is_blank_char(pointer))
while (*pointer != '\0' && 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 && ((ssize_t)column <= goal)) {
while (*pointer != '\0' && ((ssize_t)column <= goal)) {
if (is_blank_char(pointer) && (!inhelp || column > 17 || goal < 40))
lastblank = pointer;
#ifdef ENABLE_HELP
@@ -1457,7 +1453,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 && is_blank_char(pointer)) {
while (*pointer != '\0' && is_blank_char(pointer)) {
lastblank = pointer;
pointer += char_length(pointer);
}
@@ -1473,7 +1469,7 @@ size_t indent_length(const char *line)
{
const char *start = line;
while (*line && is_blank_char(line))
while (*line != '\0' && is_blank_char(line))
line += char_length(line);
return (line - start);
@@ -1559,7 +1555,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)
while (!inpar(line) && line->next != NULL)
line = line->next;
*firstline = line;
@@ -1586,7 +1582,8 @@ 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
@@ -1597,7 +1594,8 @@ 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
@@ -1634,29 +1632,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) {
while (*from != '\0') {
if (is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
while (*from && is_blank_char(from))
while (*from != '\0' && is_blank_char(from))
from += char_length(from);
} else if (mbstrchr(punct, from)) {
} else if (mbstrchr(punct, from) != NULL) {
copy_character(&from, &to);
if (*from && mbstrchr(brackets, from))
if (*from != '\0' && mbstrchr(brackets, from) != NULL)
copy_character(&from, &to);
if (*from && is_blank_char(from)) {
if (*from != '\0' && is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
}
if (*from && is_blank_char(from)) {
if (*from != '\0' && is_blank_char(from)) {
from += char_length(from);
*(to++) = ' ';
}
while (*from && is_blank_char(from))
while (*from != '\0' && is_blank_char(from))
from += char_length(from);
} else
copy_character(&from, &to);
@@ -1709,14 +1707,8 @@ 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)
if ((*line)->next != NULL)
*line = (*line)->next;
}
@@ -1789,7 +1781,6 @@ 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"));
@@ -1859,7 +1850,8 @@ 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. */
@@ -1871,7 +1863,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 */
{
@@ -1892,8 +1884,7 @@ 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;
@@ -1909,7 +1900,7 @@ void justify_text(bool whole_buffer)
}
/* When possible, step one line further; otherwise, to line's end. */
if (endline->next) {
if (endline->next != NULL) {
endline = endline->next;
end_x = 0;
} else
@@ -1965,9 +1956,6 @@ 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
{
@@ -2001,7 +1989,7 @@ void justify_text(bool whole_buffer)
update_undo(PASTE);
/* After justifying a backward-marked text, swap mark and cursor. */
if (marked_backward) {
if (openfile->mark && !mark_is_before_cursor()) {
linestruct *bottom = openfile->current;
size_t bottom_x = openfile->current_x;
@@ -2046,9 +2034,6 @@ void do_full_justify(void)
{
justify_text(WHOLE_BUFFER);
ran_a_tool = TRUE;
#ifdef ENABLE_COLOR
recook = TRUE;
#endif
}
#endif /* ENABLE_JUSTIFY */
@@ -2060,7 +2045,7 @@ void construct_argument_list(char ***arguments, char *command, char *filename)
char *element = strtok(copy_of_command, " ");
int count = 2;
while (element) {
while (element != NULL) {
*arguments = nrealloc(*arguments, ++count * sizeof(char *));
(*arguments)[count - 3] = element;
element = strtok(NULL, " ");
@@ -2181,10 +2166,6 @@ 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();
@@ -2358,23 +2339,23 @@ bool fix_spello(const char *word)
return proceed;
}
/* 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)
/* 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)
{
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *misspellings, *pointer, *oneword;
long pipesize;
size_t buffersize, totalread;
ssize_t bytesread;
int errornumber;
size_t buffersize, bytesread, totalread;
int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
pid_t pid_spell, pid_sort, pid_uniq;
int spell_status, sort_status, uniq_status;
unsigned stash[sizeof(flags) / sizeof(flags[0])];
/* Create all three pipes up front. */
if (pipe(spell_fd) < 0 || pipe(sort_fd) < 0 || pipe(uniq_fd) < 0) {
if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1) {
statusline(ALERT, _("Could not create pipe: %s"), strerror(errno));
return;
}
@@ -2384,7 +2365,7 @@ void spell_check(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)) < 0)
if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
exit(6);
/* Connect standard input to the temporary file. */
@@ -2487,9 +2468,8 @@ void spell_check(const char *tempfile_name)
pointer = misspellings + totalread;
}
errornumber = errno;
close(uniq_fd[0]);
*pointer = '\0';
close(uniq_fd[0]);
block_sigwinch(FALSE);
@@ -2497,10 +2477,6 @@ void spell_check(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));
@@ -2513,7 +2489,7 @@ void spell_check(const char *tempfile_name)
oneword = misspellings;
/* Process each of the misspelled words. */
while (*pointer) {
while (*pointer != '\0') {
if ((*pointer == '\r') || (*pointer == '\n')) {
*pointer = '\0';
if (oneword != pointer) {
@@ -2531,26 +2507,23 @@ void spell_check(const char *tempfile_name)
if (oneword != pointer)
fix_spello(oneword);
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
finale:
free(misspellings);
refresh_needed = TRUE;
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
/* Process the end of the three processes. */
waitpid(pid_spell, &spell_status, 0);
waitpid(pid_sort, &sort_status, 0);
waitpid(pid_uniq, &uniq_status, 0);
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));
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\""));
else
statusline(REMARK, _("Finished checking spelling"));
#endif
@@ -2562,7 +2535,7 @@ void do_spell(void)
{
FILE *stream;
char *temp_name;
bool okay = FALSE;
bool okay;
ran_a_tool = TRUE;
@@ -2571,13 +2544,17 @@ 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 (temp_name && openfile->mark)
okay = write_region_to_file(temp_name, stream, SPECIAL);
if (openfile->mark)
okay = write_region_to_file(temp_name, stream, TEMPORARY, OVERWRITE);
else
#endif
if (temp_name)
okay = write_file(temp_name, stream, SPECIAL, NONOTES);
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
if (!okay) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
@@ -2591,7 +2568,7 @@ void do_spell(void)
if (alt_speller && *alt_speller)
treat(temp_name, alt_speller, TRUE);
else
spell_check(temp_name);
do_int_speller(temp_name);
unlink(temp_name);
free(temp_name);
@@ -2609,9 +2586,7 @@ void do_linter(void)
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
char *lintings, *pointer, *onelint;
long pipesize;
size_t buffersize, totalread;
ssize_t bytesread;
int errornumber;
size_t buffersize, bytesread, totalread;
bool parsesuccess = FALSE;
int lint_status, lint_fd[2];
pid_t pid_lint;
@@ -2624,7 +2599,7 @@ void do_linter(void)
if (in_restricted_mode())
return;
if (!openfile->syntax || !openfile->syntax->linter || !*openfile->syntax->linter) {
if (!openfile->syntax || !openfile->syntax->linter) {
statusline(AHEM, _("No linter is defined for this type of file"));
return;
}
@@ -2645,7 +2620,7 @@ void do_linter(void)
}
/* Create a pipe up front. */
if (pipe(lint_fd) < 0) {
if (pipe(lint_fd) == -1) {
statusline(ALERT, _("Could not create pipe: %s"), strerror(errno));
return;
}
@@ -2698,12 +2673,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;
@@ -2711,21 +2686,16 @@ void do_linter(void)
pointer = lintings + totalread;
}
errornumber = errno;
close(lint_fd[0]);
*pointer = '\0';
close(lint_fd[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) {
while (*pointer != '\0') {
if ((*pointer == '\r') || (*pointer == '\n')) {
*pointer = '\0';
if (onelint != pointer) {
@@ -2759,7 +2729,7 @@ void do_linter(void)
curlint = nmalloc(sizeof(lintstruct));
curlint->next = NULL;
curlint->prev = tmplint;
if (curlint->prev)
if (curlint->prev != NULL)
curlint->prev->next = curlint;
curlint->filename = copy_of(filename);
curlint->lineno = linenumber;
@@ -2778,7 +2748,6 @@ void do_linter(void)
pointer++;
}
epilog:
free(lintings);
/* Process the end of the linting process. */
@@ -2786,25 +2755,15 @@ 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();
@@ -2822,7 +2781,7 @@ void do_linter(void)
functionptrtype function;
struct stat lintfileinfo;
if (stat(curlint->filename, &lintfileinfo) == 0 &&
if (stat(curlint->filename, &lintfileinfo) != -1 &&
(openfile->statinfo == NULL ||
openfile->statinfo->st_ino != lintfileinfo.st_ino)) {
#ifdef ENABLE_MULTIBUFFER
@@ -2854,13 +2813,13 @@ void do_linter(void)
char *dontwantfile = copy_of(curlint->filename);
lintstruct *restlint = NULL;
while (curlint) {
while (curlint != NULL) {
if (strcmp(curlint->filename, dontwantfile) == 0) {
if (curlint == lints)
lints = curlint->next;
else
curlint->prev->next = curlint->next;
if (curlint->next)
if (curlint->next != NULL)
curlint->next->prev = curlint->prev;
tmplint = curlint;
curlint = curlint->next;
@@ -2912,7 +2871,7 @@ void do_linter(void)
kbinput = get_kbinput(footwin, VISIBLE);
#ifndef NANO_TINY
if (kbinput == THE_WINDOW_RESIZED)
if (kbinput == KEY_WINCH)
continue;
#endif
function = func_from_key(kbinput);
@@ -2925,7 +2884,7 @@ void do_linter(void)
tmplint = NULL;
do_help();
} else if (function == do_page_up || function == to_prev_block) {
if (curlint->prev)
if (curlint->prev != NULL)
curlint = curlint->prev;
else if (last_wait != time(NULL)) {
statusbar(_("At first message"));
@@ -2935,7 +2894,7 @@ void do_linter(void)
statusline(NOTICE, "%s", curlint->msg);
}
} else if (function == do_page_down || function == to_next_block) {
if (curlint->next)
if (curlint->next != NULL)
curlint = curlint->next;
else if (last_wait != time(NULL)) {
statusbar(_("At last message"));
@@ -2982,7 +2941,7 @@ void do_formatter(void)
if (in_restricted_mode())
return;
if (!openfile->syntax || !openfile->syntax->formatter || !*openfile->syntax->formatter) {
if (!openfile->syntax || !openfile->syntax->formatter) {
statusline(AHEM, _("No formatter is defined for this type of file"));
return;
}
@@ -2993,8 +2952,8 @@ void do_formatter(void)
temp_name = safe_tempfile(&stream);
if (temp_name)
okay = write_file(temp_name, stream, SPECIAL, NONOTES);
if (temp_name != NULL)
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
if (!okay)
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
@@ -3073,7 +3032,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->cursor_row == editwinrows - 1 && LINES > 1) {
if (ISSET(ZERO) && openfile->current_y == editwinrows - 1 && LINES > 1) {
edit_scroll(FORWARD);
edit_refresh();
}
@@ -3128,31 +3087,26 @@ 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 hits '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 types '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. */
#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. */
char *shard, *completion = NULL;
size_t start_of_shard, shard_length = 0;
size_t i = 0, j = 0;
completionstruct *some_word;
#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) {
while (list_of_completions != NULL) {
completionstruct *dropit = list_of_completions;
list_of_completions = list_of_completions->next;
free(dropit->word);
@@ -3163,9 +3117,7 @@ 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;
@@ -3202,12 +3154,9 @@ void complete_a_word(void)
shard[shard_length] = '\0';
/* Run through all of the lines in the buffer, looking for shard. */
while (pletion_line) {
ssize_t threshold = strlen(pletion_line->data) - shard_length;
while (pletion_line != NULL) {
ssize_t threshold = strlen(pletion_line->data) - shard_length - 1;
/* 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++) {
@@ -3234,7 +3183,8 @@ 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);
@@ -3245,7 +3195,7 @@ void complete_a_word(void)
some_word = some_word->next;
/* If we've already tried this word, skip it. */
if (some_word) {
if (some_word != NULL) {
free(completion);
continue;
}
@@ -3290,7 +3240,7 @@ void complete_a_word(void)
}
/* The search has gone through all buffers. */
if (list_of_completions) {
if (list_of_completions != NULL) {
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-2026 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019, 2020, 2026 Benno Schulenberg *
* Copyright (C) 1999-2011, 2013-2023 Free Software Foundation, Inc. *
* Copyright (C) 2016, 2017, 2019 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* 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 https://gnu.org/licenses/. *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
@@ -28,25 +28,27 @@
#include <string.h>
#include <unistd.h>
/* Set global variable `homedir` to the user's home directory. First try
* $HOME, otherwise consult the password database for the current UID. */
/* 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. */
void get_homedir(void)
{
if (homedir == NULL) {
const char *homenv = getenv("HOME");
#ifdef HAVE_PWD_H
/* When $HOME is unset, or when we're root, try the database. */
/* When HOME isn't set, or when we're root, get the home directory
* from the password file instead. */
if (homenv == NULL || geteuid() == ROOT_UID) {
const struct passwd *userage = getpwuid(geteuid());
if (userage)
if (userage != NULL)
homenv = userage->pw_dir;
}
#endif
/* Only set `homedir` if a home directory could be determined. */
if (homenv && *homenv)
/* Only set homedir if some home directory could be determined,
* otherwise keep homedir NULL. */
if (homenv != NULL && *homenv != '\0')
homedir = copy_of(homenv);
}
}
@@ -116,7 +118,7 @@ bool parse_num(const char *string, ssize_t *result)
value = (ssize_t)strtol(string, &excess, 10);
if (errno == ERANGE || *string == '\0' || *excess)
if (errno == ERANGE || *string == '\0' || *excess != '\0')
return FALSE;
*result = value;
@@ -124,30 +126,29 @@ bool parse_num(const char *string, ssize_t *result)
return TRUE;
}
/* 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)
/* 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)
{
const char *comma;
char *firstpart;
bool retval;
while (*string == ' ')
string++;
while (*str == ' ')
str++;
comma = strpbrk(string, ",.:");
comma = strpbrk(str, ",.:");
if (comma == NULL)
return parse_num(string, line);
return parse_num(str, line);
retval = parse_num(comma + 1, column);
if (comma == string)
if (comma == str)
return retval;
firstpart = copy_of(string);
firstpart[comma - string] = '\0';
firstpart = copy_of(str);
firstpart[comma - str] = '\0';
retval = parse_num(firstpart, line) && retval;
@@ -173,7 +174,7 @@ size_t recode_LF_to_NUL(char *string)
{
char *beginning = string;
while (*string) {
while (*string != '\0') {
if (*string == '\n')
*string = '\0';
string++;
@@ -197,13 +198,16 @@ 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)));
}
@@ -214,7 +218,8 @@ 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)) {
@@ -244,14 +249,16 @@ const char *strstrwrapper(const char *haystack, const char *needle, const char *
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;
@@ -260,7 +267,8 @@ const char *strstrwrapper(const char *haystack, const char *needle, const char *
/* 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;
@@ -343,22 +351,6 @@ 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)
@@ -367,8 +359,15 @@ size_t get_page_start(size_t column)
return column - (editwincols - 2);
}
/* Return the index in the given text of the character that (when displayed)
* will not overshoot the given column. */
/* 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. */
size_t actual_x(const char *text, size_t column)
{
const char *start = text;
@@ -376,7 +375,7 @@ size_t actual_x(const char *text, size_t column)
size_t width = 0;
/* The current accumulated span, in columns. */
while (*text) {
while (*text != '\0') {
int charlen = advance_over(text, &width);
if (width > column)
@@ -388,21 +387,22 @@ size_t actual_x(const char *text, size_t column)
return (text - start);
}
/* Return the number of columns that the first count bytes of text occupy. */
size_t wideness(const char *text, size_t count)
/* 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)
{
size_t width = 0;
if (count == 0)
if (maxlen == 0)
return 0;
while (*text) {
while (*text != '\0') {
size_t charlen = advance_over(text, &width);
if (count <= charlen)
if (maxlen <= charlen)
break;
count -= charlen;
maxlen -= charlen;
text += charlen;
}
@@ -414,18 +414,12 @@ size_t breadth(const char *text)
{
size_t span = 0;
while (*text)
while (*text != '\0')
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)
{
@@ -440,9 +434,8 @@ 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->current == openfile->filebot)
openfile->current = openfile->current->prev;
if (openfile->filebot->data[0] == '\0' &&
openfile->filebot != openfile->filetop) {
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,6 +6,7 @@ pkgdata_DATA = asm.nanorc \
c.nanorc \
css.nanorc \
default.nanorc \
elisp.nanorc \
email.nanorc \
go.nanorc \
groff.nanorc \

View File

@@ -1,18 +1,15 @@
## 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 "\<[[: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)\>"
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)"
# 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|case|esac|ifelse|for|in|do|done)\>"
color yellow "\<(if|test|then|elif|else|fi|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,22 +1,20 @@
## Syntax highlighting for AWK scripts.
## Original author: Donnie Berkholz
syntax awk "\.awk$"
header "^#!.*awk"
magic "awk script"
comment "#"
# Records.
color brightred "\$[[:alnum:]_!@#$*?-]+"
color brightred "\$[0-9A-Za-z_!@#$*?-]+"
# 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 and brackets/braces/slashes/parentheses.
color green "[][!%&()*+/:;<=>?\^{|}~-]"
# Operators.
color green "\{|\}|\(|\)|\;|\[|\]|\\|<|>|!|=|&|\+|-|\*|%|/|\?:|\^|\|"
# Flow control.
color brightyellow "\<(for|if|while|do|else|in|delete|exit)\>"
color brightyellow "\<(break|continue|return)\>"
@@ -32,8 +30,6 @@ 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,29 +6,25 @@ magic "^(C|C\+\+) (source|program)"
comment "//"
# Constants.
color brightred "\<[[:upper:]_][[:upper:][:digit:]_]*\>"
color brightred "\<[A-Z_][0-9A-Z_]*\>"
# Labels.
color brightmagenta "^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*:[[:blank:]]*$"
color brightmagenta "^[[:blank:]]*[A-Z_a-z][0-9A-Z_a-z]*:[[:blank:]]*$"
color normal ":[[:blank:]]*$"
# Types and related keywords.
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)\>"
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)\>"
# 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|(co_)?return)\>"
color magenta "\<(break|continue|goto|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)__"
@@ -36,11 +32,11 @@ color cyan "__attribute__[[:blank:]]*\(\([^)]*\)\)|__(aligned|asm|builtin|hidden
color brightyellow ""([^"]|\\")*"|#[[:blank:]]*include[[:blank:]]*<[^>]+>"
# Preprocessor directives.
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)\>|$)"
color brightcyan start="^[[:blank:]]*#[[:blank:]]*(if(n?def)?|elif|warning|error|pragma)\>" end="(\`|[^\])$"
color brightcyan "^[[:blank:]]*#[[:blank:]]*((define|else|endif|include(_next)?|line|undef)\>|$)"
# Comments.
color brightblue "//[^"]*$|(^|[[:blank:]])//.*"
color brightblue "//.*"
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)[[:digit:]-]{8}"
color red "^(19|20)[0-9-]{8}"
# Email addresses.
color yellow "<[^>]*@[^>]*>"
# Command-line options.
color cyan "[[:blank:]]-[[:alpha:]$]|--[[:lower:]8-]+"
color cyan "[[:blank:]]-[a-zA-Z\$]|--[8a-z-]+"
# Bug and patch numbers.
color cyan "(BZ|bug|patch) #[[:digit:]]+|PR [[:alnum:]]+/[[:digit:]]+"
color cyan "(BZ|bug|patch)[ ]#[0-9]+|PR [[:alnum:]]+/[0-9]+"
# Probable constants, for variety.
color brightred "\<[[:upper:]_][[:upper:][:digit:]_]+\>"
color brightred "\<[A-Z_][0-9A-Z_]+\>"
# Key sequences.
color brightblue "\^[[:upper:]\^_]|\<M-.|\<F1?[[:digit:]]|(\^|M-)Space"
color brightblue "\^[A-Z^\]|\<M-.|\<F1?[0-9]|(\^|M-)Space"
# Changed files.
color magenta start="^( | {8})\* " end="(:( |$)|^$)"
# Release markers.
color brightblue "^(GNU )?nano[- ][[:digit:]]\.[[:digit:]]\.[^ ]+"
color brightblue "^(GNU )?nano[- ][0-9]\.[0-9]\.[^ ]+"
# Trailing whitespace.
color ,green "[[:space:]]+$"

View File

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

View File

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

33
syntax/elisp.nanorc Normal file
View File

@@ -0,0 +1,33 @@
## 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,7 +1,5 @@
## Syntax highlighting for Fortran 90/95.
## Original author: Pascal Gentil
syntax fortran "\.(f|for|f90|f95)$"
comment "!"
@@ -12,7 +10,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,7 +1,5 @@
## Syntax highlighting for POV-Ray files.
## Original author: Donnie Berkholz
syntax pov "\.(pov|POV|povray|POVRAY)$"
comment "//"

View File

@@ -1,7 +1,5 @@
## Syntax highlighting for RPM spec files.
## Original author: Asterios Dramis
syntax spec "\.spec(\.[^/]+)?$"
comment "#"
@@ -14,9 +12,7 @@ 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 "\<((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)\>"
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)\>"
# 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:]]+(([[:alnum:]_]+[[:blank:]]*)+,[[:blank:]]*)*[[:alnum:]_]+"
color brightcyan "//[[:blank:]]*\+build[[:blank:]]+(([a-zA-Z_0-9]+[[:blank:]]*)+,[[:blank:]]*)*[a-zA-Z_0-9]+"
# Trailing whitespace.
color ,green "[[:space:]]+$"

View File

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

View File

@@ -1,30 +1,23 @@
## Syntax highlighting for Guile Scheme.
## Original authors: Mark Oteiza and Benno Schulenberg
## License: GPL version 3 or newer
syntax guile "\.(scm|sld|sls|ss)$"
syntax guile "\.scm$"
header "^#!.*guile"
comment ";"
# 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)\>"
# Basic scheme functions
color green "\<(do|if|lambda|let(rec)?|map|unless|when)\>"
# Defining things
color brightgreen "\<define(-macro|-module|-public|-syntax)?\>"
color brightcyan "\<define(-macro|-module|-public|-syntax)?\>"
# Quoted symbols
color lightyellow "'(\w|[!$%&*+/:<=>?@^_~])(\w|[!$%&*+/:<=>?@^_~.0-9-])*"
# Characters
color brightyellow "'\<(\w|-)+\>"
# Chars
color brightmagenta "#\\(.|\w+)"
# Booleans
color brightred "#(t|true|f|false)\>"
color brightred "(#t|#f)\>"
# Keywords
color lagoon "#?:(\w|[?-])+"
color blue "#?:(\w|[?-])+"
# Strings
color yellow start="^[[:blank:]]*"([^"\]|\\.)*$" end="(^|[^\]|[^\]\\\\)""
color yellow start="^[[:blank:]]+"" end="[^\]""
color yellow ""([^"\]|\\.)*""
# Comments
color italic,#aaa "(^|[[:blank:]]);.*"
color cyan "(^|[[:blank:]]);.*"

View File

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

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