Compare commits

...

131 Commits
v4.5 ... v4.6

Author SHA1 Message Date
Benno Schulenberg
fdf095c32f po: update translations and regenerate POT file and PO files 2019-11-29 11:26:13 +01:00
Benno Schulenberg
81402101d9 tweaks: baptize the release 2019-11-29 11:19:11 +01:00
Benno Schulenberg
154742c5e3 bump version numbers and add a news item for the 4.6 release 2019-11-29 11:08:22 +01:00
Benno Schulenberg
ec569b4bd0 tweaks: rename a variable, to be a bit more fitting 2019-11-27 11:58:40 +01:00
Benno Schulenberg
38743b0016 tweaks: reshuffle an 'if' to avoid a negation, and improve a comment 2019-11-27 11:56:35 +01:00
Benno Schulenberg
68c3aaf2df softwrap: when switching to another buffer, re-align the starting column
When we switch to another buffer, the window may have been resized
since we were last in this buffer, so make sure that 'firstcolumn'
gets a fitting value.

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

Bug existed since version 2.8.0, since the softwrap overhaul.
2019-11-27 11:49:09 +01:00
Benno Schulenberg
2a97cb9f41 bindings: allow to rebind ^/, even though it is synonymous with ^_
This fixes https://savannah.gnu.org/bugs/?57302.
Reported-by: Tiago Almeida <tjamadeira@gmail.com>
2019-11-26 19:25:24 +01:00
Benno Schulenberg
af8ffa8c94 tweaks: silence a warning when configured with --enable-tiny 2019-11-25 19:21:03 +01:00
Benno Schulenberg
3ffefbfddc build: fix compilation for --enable-tiny --enable-histories 2019-11-25 19:17:41 +01:00
Benno Schulenberg
8637acb106 docs: correct the description of the 'spell' menu 2019-11-25 17:42:40 +01:00
Benno Schulenberg
51a3f78d69 docs: mention that 'hunspell' is now the first default spelling program 2019-11-25 17:38:50 +01:00
Benno Schulenberg
4d77e0adbb speller: prefer 'hunspell' over 'spell', because it can handle UTF-8
Also, 'hunspell' is sensitive to the 'LANG' environment variable,
so that spell checking will take place for the language that the
user is using, instead of always for English.  (This is a behavior
change, and some people may not like it, expecting the spell check
to occur always for English, but... we'll see.)
2019-11-25 16:57:04 +01:00
Benno Schulenberg
2b8a73348c gnulib: update to its current upstream state 2019-11-24 13:12:41 +01:00
Benno Schulenberg
576502a5c5 speller: when 'spell' is not found, try running 'hunspell -l' instead
This increases the chances that spell checking will work out of the box,
without any extra installing or configuration.

This addresses https://savannah.gnu.org/bugs/?57296.
2019-11-24 12:12:38 +01:00
Benno Schulenberg
ec9a11c761 display: do refresh the edit window when exiting from the help viewer
There are several cases (searching, replacing, spell checking, ...)
where exiting from the help viewer does NOT return the user to the
editing of the buffer.

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

Bug existed since version 4.3, commit 5817e83e.
2019-11-23 20:22:31 +01:00
Benno Schulenberg
1c63bf0e38 bindings: the 'all' keyword should include the browser menu always
Also for the "universal" functions (like cursor movement) and the
special 'implant' function, the 'all' keyword should include the
browser menu.

This fully fixes https://savannah.gnu.org/bugs/?57280.

Bug existed since version 3.2, commit cc01bc3e.
2019-11-22 13:21:20 +01:00
Benno Schulenberg
4aa1678f3b bindings: the 'all' keyword should encompass the browser menu too
This fixes https://savannah.gnu.org/bugs/?57280.
Reported-by: Tiago Almeida <tjamadeira@gmail.com>

Bug existed since version 3.2, commit cc01bc3e.
2019-11-22 12:44:28 +01:00
Benno Schulenberg
c60d3bbb97 tweaks: don't do in the parent something that only the child needs 2019-11-17 08:20:32 +01:00
Benno Schulenberg
90d4b51837 tweaks: group the closing of two descriptors, and reword two comments 2019-11-17 08:15:52 +01:00
Benno Schulenberg
302ea79d1c syntaxes: put the 'linter' and 'formatter' commands on a separate line
To show that they are a different class of thing than the file-matching
regexes and the comment thing, which all kind of "describe" the file.
2019-11-04 20:56:41 +02:00
Benno Schulenberg
ebeed9c013 tweaks: fuse two regexes into one 2019-11-04 20:49:17 +02:00
Benno Schulenberg
75dd9bee38 syntax: javascript: colorize the boolean values 'true' and 'false' too
Original-patch-by: Ryan Westlund <rlwestlund@gmail.com>
2019-11-03 19:50:41 +02:00
Benno Schulenberg
9151abcd45 tweaks: avoid setting and resetting a variable when there is no need 2019-10-28 10:28:52 +01:00
Benno Schulenberg
3258bb0ff4 docs: adjust the compilation instructions to two-digit version numbers 2019-10-27 19:21:55 +01:00
Benno Schulenberg
3f3698640b syntax: ruby: colorize also lowercase global/instance variables
And avoid recoloring the reserved words BEGIN and END as constants.

Inspired-by: Rory Thrasher <thrasher@redhat.com>
2019-10-27 16:34:06 +01:00
Benno Schulenberg
432388b23e tweaks: add two translator hints
And unmark two identical strings, to cause the marked ones to sit
next to each other in the POT file.
2019-10-27 16:30:50 +01:00
Benno Schulenberg
bad618e537 tweaks: harmonize a message with another 2019-10-27 16:19:45 +01:00
Benno Schulenberg
7ae305fdc0 tweaks: group the closing of descriptors together, for compactness 2019-10-27 10:40:09 +01:00
Benno Schulenberg
7d4f279c04 tweaks: close the unused reading ends of two more output pipes
It is done for 'spell', so do it also for 'sort' and 'uniq'.
2019-10-27 10:34:12 +01:00
Benno Schulenberg
f230c46e5e tweaks: drop the unneeded closing of descriptors when exiting anyway
Also, when something goes wrong in the later stages of the pipeline,
the error code would try to close descriptors that are already closed,
which is not right.  So, just let exit() handle any file descriptors
that are still open.
2019-10-27 10:25:37 +01:00
Benno Schulenberg
bc5a225678 tweaks: improve some comments, and trim some repetitive ones 2019-10-27 10:10:03 +01:00
Benno Schulenberg
493b334ebb tweaks: mark two strings for translation
The marking was accidentally lost two weeks ago in commit d12191db.
2019-10-26 17:09:00 +02:00
Benno Schulenberg
7d54207627 tweaks: be explicit about which program complained 2019-10-26 12:04:10 +02:00
Benno Schulenberg
458933f09e tweaks: elide an unneeded and leaky function 2019-10-26 12:01:23 +02:00
Benno Schulenberg
2b49a19793 linter: report it as an error when running the linting program fails
When something goes wrong, nano should beep and the status bar should
use the error color (red by default).

This fixes https://savannah.gnu.org/bugs/?57116.
2019-10-26 11:52:53 +02:00
Benno Schulenberg
fc716156a4 tweaks: correct a comment, and retype a variable 2019-10-26 11:18:38 +02:00
Benno Schulenberg
2b9f06194f formatter: don't let output from the program pollute the screen
Run the formatting program outside of curses mode, so that any output
(complaints) that it produces will be on the terminal after exiting
from nano -- at least on a terminal emulator, not on a Linux VT.

This also allows the formatter to be an interactive program.

The disadvantage is that the screen flickers when typing M-F.

This fixes https://savannah.gnu.org/bugs/?57104.
2019-10-25 19:23:24 +02:00
Benno Schulenberg
631defb8b2 tweaks: reword an undo/redo string that was overlooked during the rename 2019-10-25 19:21:17 +02:00
Benno Schulenberg
a6dae403e6 formatter: accept the formatted result also upon a nonzero exit status
For a nonzero exit status of the formatting program, report on the
status bar that the program "complained", but read in the (probably)
reformatted text anyway -- it can be easily undone with M-U.  Only
report failure when the intended program could not be run.

This fixes https://savannah.gnu.org/bugs/?57105.
2019-10-25 17:45:52 +02:00
Benno Schulenberg
b4dbbe3799 syntax: html: add a formatter command, making use of 'tidy' 2019-10-25 17:27:14 +02:00
Benno Schulenberg
4281b6becb commands: rename 'fixer' to 'formatter', to be less misleading
The word "fixer" sounds too much as if the command would be able
to fix mistakes or correct errors.  Especially when seen next to
"linter", it sounds as if one does a syntax check and the other
fixes the found mistakes.  (Although the command might in theory
be used for this, it is not its intended purpose.)
2019-10-25 17:24:28 +02:00
Benno Schulenberg
34b1824822 syntax: default: don't colorize stuff between two pairs of brackets
That is, don't allow another bracket between the opening and the
closing bracket.
2019-10-25 12:23:40 +02:00
Jeroen Roovers
b025f67805 syntax: gentoo: highlight the BDEPEND variable as well
This fixes https://bugs.gentoo.org/698420.
Reported-by: Alessandro Barbieri <lssndrbarbieri@gmail.com>

Signed-off-by: Lars Wendler <polynomial-c@gentoo.org>
2019-10-24 17:24:06 +02:00
Benno Schulenberg
40f8ca0d07 syntax: html: colorize only full attributes, and colorize strings later
Attribute names that are a part of another word should not be colored,
nor should attribute names within strings.

This addresses the other half of https://savannah.gnu.org/patch/?9865.
Original-patch-by: Ryan Westlund <rlwestlund@gmail.com>
2019-10-24 17:19:04 +02:00
Benno Schulenberg
aae752912e syntax: javascript: colorize also special values 'null' and 'undefined'
This addresses one half of https://savannah.gnu.org/patch/?9865.
Original-patch-by: Ryan Westlund <rlwestlund@gmail.com>
2019-10-24 17:19:04 +02:00
Benno Schulenberg
3c695664ec tweaks: elide a function call for the plain ASCII case
When dealing with a plain, seven-bit ASCII character, don't bother
calling is_cntrl_mbchar() but determine directly whether it is a
control character.  Also reshuffle things so that we don't compare
charlen == 1 when we already know it is 1.
2019-10-21 18:52:44 +02:00
Benno Schulenberg
8a7634f070 tweaks: rename two parameters plus a variable, to match others
Also improve a comment and normalize an indentation.
2019-10-21 13:02:17 +02:00
Benno Schulenberg
fa88fcc8f2 tweaks: rename a function, and elide a parameter that is always NULL
After the previous change, all remaining calls of parse_mbchar() have
NULL as their third parameter.  So, drop that parameter and remove the
chunk of code that handles it.  Also rename the function, as there are
already too many functions that start with "parse".
2019-10-21 12:35:14 +02:00
Benno Schulenberg
c2d8641f01 chars: add a faster version of the character-parsing function
It elides a parameter that is always NULL, and elides two ifs
that always take the same path.
2019-10-21 12:24:23 +02:00
Benno Schulenberg
3d5e51bcd0 syntax: nanorc: colorize in bright red everything that is invalid
Random words or mistyped keywords should not stay uncolored.
2019-10-20 14:47:15 +02:00
Benno Schulenberg
95ae124891 history: don't wait when there is something wrong with the history files
Do not wait for the user to press a key when there is some problem
with any of the history files.  Just start and indicate the problem
on the status bar.  The precise error message is stored and will be
shown on the terminal when exiting from nano.

This addresses https://savannah.gnu.org/bugs/?56524.
2019-10-20 14:30:04 +02:00
Benno Schulenberg
1a8646393a tweaks: condense a fragment of code by making use of a helper function
(It copies a byte too many, which then gets overwritten in the next
statement, but this is not speed-critical code.)
2019-10-20 09:45:58 +02:00
Benno Schulenberg
054559dc93 tweaks: rename three variables, to be more descriptive 2019-10-20 09:45:58 +02:00
Benno Schulenberg
fdeab9b4c9 tweaks: order two functions more sensibly 2019-10-20 09:45:58 +02:00
Benno Schulenberg
f26c121ca9 tweaks: adjust two comments, to better fit the actual functions 2019-10-20 09:45:58 +02:00
Benno Schulenberg
17c16a4bf5 tweaks: rename a function and elide its first parameter 2019-10-20 09:45:58 +02:00
Benno Schulenberg
46566572d6 utils: don't accept NULL for the string to be copied
This should not occur, so crash when it does happen.
2019-10-20 09:45:58 +02:00
Benno Schulenberg
b4a5fac744 tweaks: use a literal NULL instead of a variable that is NULL
Now all calls of mallocstrncpy() have NULL as the first parameter
(apart from one call in utils.c, but that can be changed), so the
function can be simplified.
2019-10-20 09:45:58 +02:00
Benno Schulenberg
f816da413a tweaks: elide a variable that is the same as another 2019-10-18 17:12:51 +02:00
Benno Schulenberg
3a0ac428ba tweaks: remove a redundant check for an existing emergency file
This case is caught (by O_EXCL) later on, at the appropriate moment:
when the file is created.

Also, this removes a superfluous lstat() for each temporary file.
2019-10-18 17:04:55 +02:00
Benno Schulenberg
97ab28a164 tweaks: exclude two fragments of code from the tiny version
Also improve a comment, and recorrect an indentation.
2019-10-18 14:25:55 +02:00
Benno Schulenberg
ccb739dd7d tweaks: don't wrap calls of statusline() that slightly overshoot 80 cols 2019-10-18 14:04:15 +02:00
Benno Schulenberg
1082f2adec files: don't mention the name of the temp file when reading goes wrong
When writing a temp file goes wrong, its name is not mentioned either.
2019-10-18 13:38:20 +02:00
Benno Schulenberg
042b8394a0 tweaks: use a simpler positive/negative check for after copy_file() 2019-10-18 13:25:38 +02:00
Benno Schulenberg
f2d6e6fa5e tweaks: check the return value of copy_file() also after its other uses 2019-10-18 12:37:39 +02:00
Benno Schulenberg
5390f96900 files: distinguish between read error and write error when prepending
This fixes https://savannah.gnu.org/bugs/?57066.

Bug existed in this form since version 2.4.3 -- in older versions
it segfaulted.
2019-10-18 12:15:14 +02:00
Benno Schulenberg
50ed18be17 tweaks: move a call of umask() closer to where it is relevant 2019-10-17 17:29:11 +02:00
Benno Schulenberg
a6365707c0 tweaks: remove the superfluous closing of a file descriptor
The file itself is closed three lines earlier; this also closes the
corresponding descriptor.
2019-10-17 16:43:07 +02:00
Benno Schulenberg
6fad6a17da tweaks: rename a variable, to be distinct and visible 2019-10-17 12:17:09 +02:00
Benno Schulenberg
eb757e7c5b tweaks: simplify the opening of files when prepending
There is no need for a file descriptor: all reading and writing
is done on streams.
2019-10-17 12:12:07 +02:00
Benno Schulenberg
b554606047 tweaks: add a local variable, for clarity, to not preuse another one 2019-10-17 11:49:21 +02:00
Benno Schulenberg
e915fb1650 tweaks: adjust the indentation after the previous change, and another 2019-10-17 11:45:03 +02:00
Benno Schulenberg
4e40ec057e tweaks: elide an unneeded check when making a backup
When making a backup, we can be certain that the relevant file
is not a temporary file, so 'stream' will necessarily be NULL.
2019-10-17 11:45:03 +02:00
Benno Schulenberg
bd0026be86 tweaks: elide another two calls of umask(), and rename two variables 2019-10-17 11:43:42 +02:00
Benno Schulenberg
a1bef0e953 tweaks: avoid three unneeded calls of umask() in the normal case 2019-10-16 19:17:42 +02:00
Benno Schulenberg
f5693d4151 tweaks: elide a duplicate opening of the existing file when prepending 2019-10-16 17:40:52 +02:00
Benno Schulenberg
e3807f00a2 tweaks: rename two variables, and add a third, for more contrast 2019-10-16 17:16:48 +02:00
Benno Schulenberg
022cc084a7 files: when opening a file for copying, it should NOT be created
Weird bug.  The first occurrence is probably never hit because the
existing file has been tentatively opened fourteen lines earlier,
but that looks superfluous: double work.  And the second occurrence
will not be hit because the temp file is unlikely to have disappeared.
2019-10-16 16:27:23 +02:00
Benno Schulenberg
0f98466e2f tweaks: adjust the indentation after the previous change
Also, don't bother assigning the stream pointer of the existing file
to variable 'f', as it gets overwritten right away by the pointer of
the temp file.
2019-10-16 16:05:40 +02:00
Benno Schulenberg
40c067133a tweaks: remove two superfluous conditions when prepending
When prepending, we cannot be writing to a temp file,
so 'stream' (and thus 'f') will necessarily be NULL.
2019-10-16 15:47:35 +02:00
Benno Schulenberg
36270748dc tweaks: condense or improve some comments 2019-10-16 13:47:30 +02:00
Benno Schulenberg
1894c81412 tweaks: rename two parameters, for contrast and to match others 2019-10-16 13:07:41 +02:00
Benno Schulenberg
e917ef0105 tweaks: die on an impossible condition -- to be removed later 2019-10-16 12:27:27 +02:00
Benno Schulenberg
3347682fd0 tweaks: remove a pointless updating of the title bar
A possible change in filename won't be pushed to the screen until a
doupdate() is done, and that won't happen until nano is waiting for
a keystroke again.  So... just let it be.
2019-10-16 12:22:39 +02:00
Benno Schulenberg
7c5b104859 tweaks: rename three variables, to match others elsewhere 2019-10-16 11:46:22 +02:00
Benno Schulenberg
3b9a24a7ca tweaks: rename a local variable, to not shadow another 2019-10-16 11:11:19 +02:00
Benno Schulenberg
7d3290fb91 tweaks: rename three variables, to be consistent with other linestructs 2019-10-16 11:04:26 +02:00
Benno Schulenberg
df0ae2ace5 tweaks: reshuffle a few declarations, and reduce the scope of one 2019-10-16 10:48:14 +02:00
Benno Schulenberg
bc91af2e3c tweaks: pass an empty string as an answer instead of a NULL pointer
Also, rename a parameter, to be more distinct and to avoid an abbrev.
2019-10-15 13:39:57 +02:00
Benno Schulenberg
48b94d71c7 tweaks: pass an empty string for copying instead of a non-existent one 2019-10-15 11:49:07 +02:00
Benno Schulenberg
f14be47878 tweaks: move two functions to after the one that they make use of 2019-10-15 11:23:09 +02:00
Benno Schulenberg
c51f5f4bff docs: mention that the 'nopauses' option is obsolete 2019-10-15 11:23:05 +02:00
Benno Schulenberg
7f8851caa8 statusbar: show only the first error message, with dots to indicate more
The old default behavior of showing the first three messages with a
long pause after each of them was annoying, and the final "Further
messages were suppressed" hid the relevant information.  So, when
there is more than one error message, just pause very briefly and
then add trailing dots to the first message.

This makes the 'nopauses' option a no-op.

This addresses https://savannah.gnu.org/bugs/?57048.
2019-10-15 11:17:20 +02:00
Benno Schulenberg
bfdc31fbb4 docs: add the M-F and M-N keystrokes to the cheatsheet 2019-10-14 17:14:07 +02:00
Benno Schulenberg
69d2045c9f syntax: nanorc: colorize only lowercase keywords as valid
Nowhere does the manual say that nanorc keywords are case-insensitive,
and none of the examples use uppercase keywords.  So, simply consider
uppercase keywords to be invalid.  This will later allow nano to use
case-sensitive comparisons, which are slightly faster.
2019-10-14 11:45:56 +02:00
Benno Schulenberg
c63f4c1f58 docs: remove the note about the formatter having been removed
The 'fixer' command has taken the place of the 'formatter' command.

(Also, normalize a double blank line before a chapter.)
2019-10-14 10:30:04 +02:00
Benno Schulenberg
b8dc8d4a37 syntax: nanorc: colorize all arguments of 'fixer' and 'linter' as valid 2019-10-14 10:28:45 +02:00
Benno Schulenberg
8749ccb469 syntax: nanorc: colorize the 'fixer' command as valid
Also add a default formatting command to the Go syntax.
2019-10-14 10:28:45 +02:00
Benno Schulenberg
b5c5cde0d4 docs: document the 'fixer' command, a per-syntax content arranger 2019-10-14 10:28:45 +02:00
Benno Schulenberg
d8c03cd4cd tweaks: elide a variable, and add a condition to elide an assignment 2019-10-14 10:28:45 +02:00
Benno Schulenberg
1536a76ced tweaks: normalize the indentation after the previous change 2019-10-14 10:28:45 +02:00
Benno Schulenberg
d2fb371fe2 feedback: say it when spell check or manipulation did not change anything 2019-10-14 10:28:45 +02:00
Benno Schulenberg
34170611d3 restored feature: a per-syntax 'fixer' command that processes the buffer
The command can be used to run some kind of formatter or corrector or
arranging tool on the buffer.  By default the command is bound to M-F.
The formatter/corrector/arranging program must be non-interactive.

This addresses https://savannah.gnu.org/bugs/?55365,
and addresses https://savannah.gnu.org/bugs/?54651.
2019-10-14 10:28:45 +02:00
Benno Schulenberg
23c36ba667 tweaks: remove two pointless re-inclusion guards
The nano.h file is included only by proto.h, and the proto.h file is
included just once by each src/*.c file.  The include guards for these
two header files serve no purpose.

(Include guards are useful when you have bunches of header files
and several of them include others from amongst themselves.)
2019-10-13 19:14:27 +02:00
Benno Schulenberg
31d5cb1118 build: slightly speed up the compilation of the tiny version
Don't include header files when they won't actually be needed.

(Also, remove a superfluous #ifdef.)
2019-10-13 18:55:49 +02:00
Benno Schulenberg
f551c07e7a tweaks: add some "fall-through" comments, and reshuffle some breaks 2019-10-13 17:35:57 +02:00
Benno Schulenberg
2656f543f4 undo: don't try to copy a string that doesn't exist
This fixes https://savannah.gnu.org/bugs/?57051.

Bug existed since commit d256d0cb from earlier today.
2019-10-13 17:31:53 +02:00
Benno Schulenberg
ba79602281 tweaks: condense two comments, and rename two parameters
Also use 'while' instead of 'for'.
2019-10-13 16:45:02 +02:00
Benno Schulenberg
094758be15 tweaks: reshuffle a fragment of code into two alternatives 2019-10-13 16:11:15 +02:00
Benno Schulenberg
06bbc70d4a tweaks: use a string-copy function that checks for out-of-memory 2019-10-13 12:38:46 +02:00
Benno Schulenberg
d256d0cbc0 tweaks: add a helper function without the ubiquitous NULL argument
For conciseness and clarity.
2019-10-13 12:24:27 +02:00
Benno Schulenberg
ab6635c3a6 tweaks: use the given string instead of the found match, for clarity 2019-10-13 11:52:09 +02:00
Benno Schulenberg
416ad4c5fd tweaks: use a better variable name for the argument of an option 2019-10-13 11:46:22 +02:00
Benno Schulenberg
0374708597 undo: put the cursor back on the original row for a full-buffer operation
When an operation that replaces the entire buffer is undone, the
position of the viewport is lost.  Compensate for this by storing
the row of the cursor in the undo item, and, after executing the
undo item, arranging the viewport so that the cursor is back on
the original row -- the row where the operation was invoked.

This fixes https://savannah.gnu.org/bugs/?57039.
2019-10-12 11:20:41 +02:00
Benno Schulenberg
101987f5c6 build: fix compilation when configured with --disable-color 2019-10-12 11:20:19 +02:00
Benno Schulenberg
ad451933c6 tweaks: rename a function and add a parameter, so it becomes more general
Also adjust the comments and rename three variables.
2019-10-10 08:28:08 +02:00
Benno Schulenberg
222e67300e tweaks: reshuffle some declarations, and rename a variable 2019-10-10 08:23:16 +02:00
Benno Schulenberg
d12191db5a tweaks: pass any special undo/redo messages to the add_undo() function
For the three operations (justification, spell checking, and filtering)
that need to undo or redo two suboperations (cutting and then pasting)
in one go, pass the message that describes the operation to add_undo(),
so that the undo item does not need to be modified after the call.

This looks better, but does add some twenty NULL parameters elsewhere.
2019-10-09 19:21:27 +02:00
Benno Schulenberg
785efc2087 tweaks: make a function do a check so its calls don't need to 2019-10-09 18:58:30 +02:00
Benno Schulenberg
557ad827f9 tweaks: condense two comments, and rewrap a line 2019-10-09 14:49:42 +02:00
Benno Schulenberg
600f81cf98 tweaks: rename three variables, and reshuffle some lines 2019-10-09 14:20:29 +02:00
Benno Schulenberg
56d98052d1 tweaks: adjust the indentation after the previous change 2019-10-08 11:51:47 +02:00
Benno Schulenberg
265d3245af rcfile: process extensions to file-matching commands straightaway
When 'extendsyntax' is used with a 'header' or 'magic' command, it
must be processed immediately.  It is pointless to store the command,
because when then it is processed (when the syntax gets used), it is
too late to have any effect.

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

With-help-from: Brand Huntsman <alpha@qzx.com>

Bug existed since version 4.3, commit cba9d8d0.
2019-10-08 11:37:02 +02:00
Benno Schulenberg
53d4224be9 cutting: do nothing when trying to chop a word leftward at start of file
Instead of marking the buffer as modified, provide the feedback that
"nothing was cut", like when trying to chop a word rightward at the
end of the buffer.

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

Bug existed since version 4.4, commit 4314b8de.
2019-10-07 17:24:18 +02:00
Benno Schulenberg
f813fd0f4d rcfile: allow binding also F17...F24
For historical reasons the rebinding code allows binding F13...F16,
which on most terminals are typable with Shift plus F1...F4.  But,
at least on an Xfce Terminal, Shift plus F1...F12 produce F13...F24.
On a Linux console, Shift plus F1...F8 produce F13...F20.  So: allow
to bind the full shifted F13...F24 range.  It costs no extra code
and makes things more rounded.
2019-10-07 16:23:40 +02:00
Benno Schulenberg
e90b40e651 docs: add a note saying that rebinding ^M or ^I is not advisable
Also say that rebinding ^H is sometimes impossible, or when it's
made possible, that it rebinds the Backspace key too.

This addresses https://savannah.gnu.org/bugs/?56994.
Reported-by: Tiago Almeida <tjamadeira@gmail.com>
2019-10-07 13:28:27 +02:00
Benno Schulenberg
07c1e72216 tweaks: slightly reword some fragments in the manual's rebinding section 2019-10-07 13:01:18 +02:00
Benno Schulenberg
7338b45d36 docs: remove some excessive detail from the sample nanorc file
The sample file should just mention the basics.  The manual contains
all the details.
2019-10-06 14:50:27 +02:00
Benno Schulenberg
c95e5362e6 docs: mention that color rules are applied in the order they are listed
Suggested-by: Tiago Almeida <tjamadeira@gmail.com>
2019-10-06 14:27:29 +02:00
Benno Schulenberg
2698a2ba68 syntax: c: recognize some C++ header files by their Emacs modeline
For extensionless files, recognize C/C++ ones from the mode name
between the -*- marks on the first line.

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

Inspired-by: Devin Hussey <husseydevin@gmail.com>
2019-10-06 12:01:02 +02:00
Benno Schulenberg
ff0e01a69e bindings: don't hard-bind ^H in the help viewer or the file browser
Hard-binding the ^H control code prevents the user from rebinding
the keystroke.

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

Bug existed since version 4.0, commit 72a49dbb.
2019-10-05 12:43:46 +02:00
78 changed files with 21444 additions and 20232 deletions

137
ChangeLog
View File

@@ -1,3 +1,140 @@
Changes between v4.5 and v4.6:
------------------------------
Benno Schulenberg (128):
bindings: allow to rebind ^/, even though it is synonymous with ^_
bindings: don't hard-bind ^H in the help viewer or the file browser
bindings: the 'all' keyword should encompass the browser menu too
bindings: the 'all' keyword should include the browser menu always
build: fix compilation for --enable-tiny --enable-histories
build: fix compilation when configured with --disable-color
build: slightly speed up the compilation of the tiny version
bump version numbers and add a news item for the 4.6 release
chars: add a faster version of the character-parsing function
commands: rename 'fixer' to 'formatter', to be less misleading
cutting: do nothing when trying to chop a word leftward at start of file
display: do refresh the edit window when exiting from the help viewer
docs: add a note saying that rebinding ^M or ^I is not advisable
docs: add the M-F and M-N keystrokes to the cheatsheet
docs: adjust the compilation instructions to two-digit version numbers
docs: correct the description of the 'spell' menu
docs: document the 'fixer' command, a per-syntax content arranger
docs: mention that color rules are applied in the order they are listed
docs: mention that 'hunspell' is now the first default spelling program
docs: mention that the 'nopauses' option is obsolete
docs: remove some excessive detail from the sample nanorc file
docs: remove the note about the formatter having been removed
feedback: say it when spell check or manipulation did not change anything
files: distinguish between read error and write error when prepending
files: don't mention the name of the temp file when reading goes wrong
files: when opening a file for copying, it should NOT be created
formatter: accept the formatted result also upon a nonzero exit status
formatter: don't let output from the program pollute the screen
gnulib: update to its current upstream state
history: don't wait when there is something wrong with the history files
linter: report it as an error when running the linting program fails
rcfile: allow binding also F17...F24
rcfile: process extensions to file-matching commands straightaway
restored feature: a per-syntax 'fixer' command that processes the buffer
softwrap: when switching to another buffer, re-align the starting column
speller: prefer 'hunspell' over 'spell', because it can handle UTF-8
speller: when 'spell' is not found, try running 'hunspell -l' instead
statusbar: show only the first error message, with dots to indicate more
syntax: c: recognize some C++ header files by their Emacs modeline
syntax: default: don't colorize stuff between two pairs of brackets
syntax: html: add a formatter command, making use of 'tidy'
syntax: html: colorize only full attributes, and colorize strings later
syntax: javascript: colorize also special values 'null' and 'undefined'
syntax: javascript: colorize the boolean values 'true' and 'false' too
syntax: nanorc: colorize all arguments of 'fixer' and 'linter' as valid
syntax: nanorc: colorize in bright red everything that is invalid
syntax: nanorc: colorize only lowercase keywords as valid
syntax: nanorc: colorize the 'fixer' command as valid
syntax: ruby: colorize also lowercase global/instance variables
syntaxes: put the 'linter' and 'formatter' commands on a separate line
tweaks: add a helper function without the ubiquitous NULL argument
tweaks: add a local variable, for clarity, to not preuse another one
tweaks: add some "fall-through" comments, and reshuffle some breaks
tweaks: add two translator hints
tweaks: adjust the indentation after the previous change
tweaks: adjust the indentation after the previous change
tweaks: adjust the indentation after the previous change, and another
tweaks: adjust two comments, to better fit the actual functions
tweaks: avoid setting and resetting a variable when there is no need
tweaks: avoid three unneeded calls of umask() in the normal case
tweaks: be explicit about which program complained
tweaks: check the return value of copy_file() also after its other uses
tweaks: close the unused reading ends of two more output pipes
tweaks: condense a fragment of code by making use of a helper function
tweaks: condense or improve some comments
tweaks: condense two comments, and rename two parameters
tweaks: condense two comments, and rewrap a line
tweaks: correct a comment, and retype a variable
tweaks: die on an impossible condition -- to be removed later
tweaks: don't do in the parent something that only the child needs
tweaks: don't wrap calls of statusline() that slightly overshoot 80 cols
tweaks: drop the unneeded closing of descriptors when exiting anyway
tweaks: elide a duplicate opening of the existing file when prepending
tweaks: elide a function call for the plain ASCII case
tweaks: elide another two calls of umask(), and rename two variables
tweaks: elide an unneeded and leaky function
tweaks: elide an unneeded check when making a backup
tweaks: elide a variable, and add a condition to elide an assignment
tweaks: elide a variable that is the same as another
tweaks: exclude two fragments of code from the tiny version
tweaks: fuse two regexes into one
tweaks: group the closing of descriptors together, for compactness
tweaks: group the closing of two descriptors, and reword two comments
tweaks: harmonize a message with another
tweaks: improve some comments, and trim some repetitive ones
tweaks: make a function do a check so its calls don't need to
tweaks: mark two strings for translation
tweaks: move a call of umask() closer to where it is relevant
tweaks: move two functions to after the one that they make use of
tweaks: normalize the indentation after the previous change
tweaks: order two functions more sensibly
tweaks: pass an empty string as an answer instead of a NULL pointer
tweaks: pass an empty string for copying instead of a non-existent one
tweaks: pass any special undo/redo messages to the add_undo() function
tweaks: remove a pointless updating of the title bar
tweaks: remove a redundant check for an existing emergency file
tweaks: remove the superfluous closing of a file descriptor
tweaks: remove two pointless re-inclusion guards
tweaks: remove two superfluous conditions when prepending
tweaks: rename a function and add a parameter, so it becomes more general
tweaks: rename a function, and elide a parameter that is always NULL
tweaks: rename a function and elide its first parameter
tweaks: rename a local variable, to not shadow another
tweaks: rename a variable, to be a bit more fitting
tweaks: rename a variable, to be distinct and visible
tweaks: rename three variables, and reshuffle some lines
tweaks: rename three variables, to be consistent with other linestructs
tweaks: rename three variables, to be more descriptive
tweaks: rename three variables, to match others elsewhere
tweaks: rename two parameters, for contrast and to match others
tweaks: rename two parameters plus a variable, to match others
tweaks: rename two variables, and add a third, for more contrast
tweaks: reshuffle a few declarations, and reduce the scope of one
tweaks: reshuffle a fragment of code into two alternatives
tweaks: reshuffle an 'if' to avoid a negation, and improve a comment
tweaks: reshuffle some declarations, and rename a variable
tweaks: reword an undo/redo string that was overlooked during the rename
tweaks: silence a warning when configured with --enable-tiny
tweaks: simplify the opening of files when prepending
tweaks: slightly reword some fragments in the manual's rebinding section
tweaks: use a better variable name for the argument of an option
tweaks: use a literal NULL instead of a variable that is NULL
tweaks: use a simpler positive/negative check for after copy_file()
tweaks: use a string-copy function that checks for out-of-memory
tweaks: use the given string instead of the found match, for clarity
undo: don't try to copy a string that doesn't exist
undo: put the cursor back on the original row for a full-buffer operation
utils: don't accept NULL for the string to be copied
Jeroen Roovers (1):
syntax: gentoo: highlight the BDEPEND variable as well
Changes between v4.4 and v4.5:
------------------------------

9
NEWS
View File

@@ -1,3 +1,12 @@
2019.11.29 - GNU nano 4.6 "And don't you eat that yellow snow"
• The 'formatter' command has returned, bound by default to M-F.
It allows running a syntax-specific command on the contents of
the buffer.
• ^T will try to run 'hunspell' before 'spell', because it checks
spellling for the locale's language and understands UTF-8.
• Multiple errors or warnings on startup will no longer slow nano
down but will be indicated on the status bar with trailing dots.
2019.10.04 - GNU nano 4.5 "Košice"
• The new 'tabgives' command allows you to specify per syntax what
the <Tab> key should produce: some spaces, a hard TAB, ...

6
README
View File

@@ -25,10 +25,10 @@ Overview
How to compile and install nano
Download the nano source code, then:
Download the latest nano source tarball, then:
tar xvzf nano-x.y.z.tar.gz
cd nano-x.y.z
tar -xvf nano-x.y.tar.gz
cd nano-x.y
./configure
make
make install

View File

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

View File

@@ -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], [4.5], [nano-devel@gnu.org], [nano])
AC_INIT([GNU nano], [4.6], [nano-devel@gnu.org], [nano])
AC_CONFIG_SRCDIR([src/nano.c])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.14])

View File

@@ -66,6 +66,7 @@
<tr><td>Ctrl+J</td><td>Justify paragraph or region</td></tr>
<tr><td>Alt+J</td><td>Justify entire buffer</td></tr>
<tr><td>Alt+B</td><td>Run a syntax check</td></tr>
<tr><td>Alt+F</td><td>Run a formatter/fixer/arranger</td></tr>
<tr><td>Alt+:</td><td>Start/stop recording of macro</td></tr>
<tr><td>Alt+;</td><td>Replay macro</td></tr>
</tbody></table>
@@ -116,6 +117,7 @@
<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+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+V</td><td>Enter next keystroke verbatim</td></tr>
<tr><td>Ctrl+L</td><td>Refresh the screen</td></tr>

View File

@@ -85,7 +85,7 @@
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program &quot;establishes a full duplex terminal connection to a remote host&quot;, and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
<h3><a name="1.4"></a>1.4. What is the current version of nano?</h3>
<blockquote><p>The current version of nano <i>should</i> be <b>4.5</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
<blockquote><p>The current version of nano <i>should</i> be <b>4.6</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%">
@@ -112,7 +112,7 @@
<li><a href="https://packages.debian.org/testing/editors/nano">testing</a></li>
<li><a href="https://packages.debian.org/unstable/editors/nano">unstable</a></li>
</ul>
<p>You can also have a look at the <a href="ftp://ftp.debian.org/debian/pool/main/n/nano/">Package Pool</a> to see all the available binary and source packages.</p>
<p>You can also have a look at the <a href="http://ftp.debian.org/debian/pool/main/n/nano/">Package Pool</a> to see all the available binary and source packages.</p>
</blockquote>
<h3><a name="2.4"></a>2.4. By GIT (for the brave).</h3>
<blockquote><p>For the 'bleeding edge' current version of nano, you can use GIT to download the current source code. <b>Note:</b> believe it or not, by downloading code that has not yet stabilized into an official release, there could quite possibly be bugs, in fact the code may not even compile! Anyway, see <a href="http://git.savannah.gnu.org/cgit/nano.git/tree/README.GIT">the nano GIT document</a> for info on anonymous GIT access to the nano source.</p></blockquote>
@@ -120,13 +120,13 @@
<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.z-1.i386.rpm</b> if you have a RedHat-ish system or <b>dpkg -i nano_x.y.z-1.deb</b> if you have a Debian-ish system, where <b>x.y.z</b> is the release of nano. There are other programs to install packages, and if you wish to use those, knock yourself out.</p></blockquote>
<blockquote><p>It's simple really! As root, type <b>rpm -Uvh nano-x.y-1*.rpm</b> if you have a RedHat-ish system or <b>dpkg -i nano_x.y-1*.deb</b> if you have a Debian-ish system, where <b>x.y</b> is the version number of nano. There are other programs to install packages, and if you wish to use those, knock yourself out.</p></blockquote>
<h3><a name="3.2"></a>3.2. Compiling from source: WHAT THE HECK DO I DO NOW?</h3>
<blockquote><p>Okay, take a deep breath, this really isn't hard. Unpack the nano source with a command like:</p>
<p><b>tar -xvf nano-x.y.z.tar.gz</b></p>
<p><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>
<p>The average case is this:</p>
<p><b>cd nano-x.y.z/</b><br>
<p><b>cd nano-x.y/</b><br>
<b>./configure</b><br>
<b>make</b><br>
<b>make install</b> (as root, of course)</p></blockquote>
@@ -203,8 +203,8 @@
<b>[ ] enable-alternate-editor-implicitly</b></p>
<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><b>my_hdr X-Composer: nano x.y.z</b></p>
<p>Again, replace x.y.z with the version of nano you use.</p></blockquote>
<p><b>my_hdr X-Composer: nano-x.y</b></p>
<p>Again, replace x.y with the version of nano you use.</p></blockquote>
<hr width="100%">
<h1><a name="5"></a>5. Internationalization</h1>

View File

@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANO 1 "version 4.5" "October 2019"
.TH NANO 1 "version 4.6" "November 2019"
.SH NAME
nano \- Nano's ANOther editor, inspired by Pico
@@ -278,7 +278,8 @@ point to vary along with the width of the screen if the screen is resized.
The default value is \-8.
.TP
.B "\-s ""\fIprogram\fR [\fIarg\fR...]\fB""\fR, \fB\-\-speller=""\fIprogram\fR [\fIarg\fR...]\fB"""
Use this alternative command to perform spell checking.
Use this command to perform spell checking and correcting, instead of
using the built-in corrector that calls \fBhunspell\fR or GNU \fBspell\fR.
.TP
.BR \-t ", " \-\-tempfile
Save a changed buffer without prompting (when exiting with \fB^X\fR).

View File

@@ -8,8 +8,8 @@
@smallbook
@set EDITION 0.5
@set VERSION 4.5
@set UPDATED October 2019
@set VERSION 4.6
@set UPDATED November 2019
@dircategory Editors
@direntry
@@ -23,7 +23,7 @@
@titlepage
@title GNU @command{nano}
@subtitle a small and friendly text editor
@subtitle version 4.5
@subtitle version 4.6
@author Chris Allegretta
@page
@@ -57,13 +57,13 @@ You may contact the author by
e-mail: @email{chrisa@@asty.org}@*
@end titlepage
@ifnottex
@node Top
@top
This manual documents the GNU @command{nano} editor, version 4.5.
This manual documents the GNU @command{nano} editor, version 4.6.
@menu
* Introduction::
@@ -156,6 +156,7 @@ As a special case: when instead of a filename a dash is given, @command{nano}
will read data from standard input. This means you can pipe the output of
a command straight into a buffer, and then edit it.
@node Command-line Options
@chapter Command-line Options
@@ -402,7 +403,8 @@ Use the given program to do spell checking and correcting. By default,
@command{nano} uses the command specified in the @env{SPELL} environment
variable. If @env{SPELL} is not set, and @option{--speller} is
not specified either, then @command{nano} uses its own interactive spell
corrector, which requires the GNU @command{spell} program to be installed.
corrector, which requires either @command{hunspell} or GNU @command{spell}
to be installed.
@item -t
@itemx --tempfile
@@ -614,6 +616,7 @@ The recording and playback of keyboard macros works correctly only on a
terminal emulator, not on a Linux console (VT), because the latter does
not by default distinguish modified from unmodified arrow keys.
@node Built-in Help
@chapter Built-in Help
@@ -843,8 +846,7 @@ Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
@item set nopauses
Don't pause between warnings at startup. This means that only
the last one will be visible (when there are multiple ones).
Obsolete option. Ignored.
@item set nowrap
Deprecated option since it has become the default setting.
@@ -1046,6 +1048,12 @@ file, to determine whether this syntax should be used for it.
(This functionality only works when @code{libmagic} is installed
on the system and will be silently ignored otherwise.)
@item formatter @var{program} [@var{arg} @dots{}]
Run the given @var{program} on the full contents of the current buffer.
(The current buffer is written out to a temporary file, the program is
run on it, and then the temporary file is read back in, replacing the
contents of the buffer.)
@item linter @var{program} [@var{arg} @dots{}]
Use the given @var{program} to do a syntax check on the current buffer.
@@ -1077,6 +1085,9 @@ stronger highlight.
If your terminal supports transparency, not specifying a "bgcolor"
tells @command{nano} to attempt to use a transparent background.
All coloring commands are applied in the order in which they are specified,
which means that later commands can recolor stuff that was colored earlier.
@item icolor @var{fgcolor},@var{bgcolor} "@var{regex}" @dots{}
Same as above, except that the matching is case insensitive.
@@ -1099,28 +1110,12 @@ to @code{icolor}.
@item extendsyntax @var{name} @var{command} [@var{arg} @dots{}]
Extend the syntax previously defined as "@var{name}" with another @var{command}.
This allows you to add a new @code{color}, @code{icolor}, @code{header},
@code{magic}, @code{comment}, or @code{linter} command to an already
@code{magic}, @code{comment}, @code{linter}, or @code{formatter} command to an already
defined syntax --- useful when you want to slightly improve a syntax defined
in one of the system-installed files (which normally are not writable).
@end table
Note: the @code{formatter} command has been removed. It was superseded by
a more general mechanism: the filtering of buffer or marked text through
an external command. Such filtering is done by typing @code{^R^X} and then
preceding your formatter command with the pipe symbol (@code{|}). It has
the added advantage that the operation can be undone.
If you use such a formatting command regularly, you could assign the relevant
series of keystrokes to a single key in your nanorc:
@example
bind M-F "^R^X|yourformatcommand^M" main
@end example
(Note that the @key{^R}, @key{^X}, and @key{^M} are each a single, literal
control character. You can enter them by preceding each with @key{M-V}.)
@node Rebinding Keys
@section Rebinding Keys
@@ -1131,7 +1126,7 @@ nanorc file:
@item bind key function menu
Rebinds @code{key} to @code{function} in the context of @code{menu}
(or in all menus where the function exists by using @code{all}).
(or in all menus where the function exists when @code{all} is used).
@item bind key "string" menu
Makes @code{key} produce @code{string} in the context of @code{menu}
@@ -1142,7 +1137,7 @@ with @kbd{M-V}.)
@item unbind key menu
Unbinds @code{key} from @code{menu}
(or from all menus where it exists by using @code{all}).
(or from all menus where the key exists when @code{all} is used).
@end table
@@ -1151,22 +1146,29 @@ The format of @code{key} should be one of:
@itemize @w{}
@item
@code{^}@ followed by a Latin letter, by one of several ASCII characters
(@@, ], \, ^, or _), or by the word "Space".
@code{^@var{X}} ------ where @var{X} is a Latin letter, or one of several
ASCII characters (@@, ], \, ^, _), or the word "Space".
Example: @code{^C}.
@item
@code{M-}@ followed by any ASCII character except [, or by the word "Space".
@code{M-@var{X}} ------ where @var{X} is any ASCII character except [,
or the word "Space".
Example: @code{M-C}.
@item
@code{F}@ followed by a numeric value from 1 to 16.
@code{F@var{n}} ------ where @var{n} is a numeric value from 1 to 24.
Example: @code{F10}.
(Often, @code{F13} to @code{F24} can be typed as @code{F1} to @code{F12}
with Shift.)
@item
the word "Ins" or the word "Del".
@code{Ins} or @code{Del}.
@end itemize
Rebinding @code{^M} (Enter) or @code{^I} (Tab) is probably not a good idea.
On some terminals it's not possible to rebind @code{^H} (unless @code{--raw}
is used) because its keycode is identical to that of the Backspace key.
@sp 1
Valid names for the @code{function} to be bound are:
@@ -1246,8 +1248,12 @@ Shows the current cursor position: the line, column, and character positions.
Counts the number of words, lines and characters in the current buffer.
@item speller
Invokes a spell-checking program, either the default one, or the one
defined by @option{--speller} or @code{set speller}.
Invokes a spell-checking program, either the default @command{hunspell}
or GNU @command{spell}, or the one defined by @option{--speller} or
@code{set speller}.
@item formatter
Invokes a full-buffer-processing program (if the active syntax defines one).
@item linter
Invokes a syntax-checking program (if the active syntax defines one).
@@ -1531,7 +1537,7 @@ The menu for inserting output from an external command, reached from the insert
The help-viewer menu.
@item spell
The interactive spell checker Yes/no menu.
The menu of the integrated spell checker where the user can edit a misspelled word.
@item linter
The linter menu.

View File

@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH NANORC 5 "version 4.5" "October 2019"
.TH NANORC 5 "version 4.6" "November 2019"
.SH NAME
nanorc \- GNU nano's configuration file
@@ -183,8 +183,7 @@ Don't automatically add a newline when a text does not end with one.
(This can cause you to save non-POSIX text files.)
.TP
.B set nopauses
Don't pause between warnings at startup. This means that only
the last one will be visible (when there are multiple ones).
Obsolete option. Ignored.
.TP
.B set nowrap
Deprecated option since it has become the default setting.
@@ -262,8 +261,8 @@ When needed, use \fBunset jumpyscrolling\fR instead.
Enable soft line wrapping for easier viewing of very long lines.
.TP
.B set speller """\fIprogram\fR [\fIarg\fR...]\fB"""
Use the given \fIprogram\fR to do spell checking and correcting,
instead of the built-in corrector that calls \fBspell\fR.
Use the given \fIprogram\fR to do spell checking and correcting, instead of
using the built-in corrector that calls \fBhunspell\fR or GNU \fBspell\fR.
.TP
.B set statuscolor \fIfgcolor\fR,\fIbgcolor\fR
Specify the color combination to use for the status bar.
@@ -382,6 +381,12 @@ file, to determine whether this syntax should be used for it.
(This functionality only works when \fBlibmagic\fP is installed on the
system and will be silently ignored otherwise.)
.TP
.BI formatter " program " \fR[ "arg " \fR...]
Run the given \fIprogram\fR on the full contents of the current buffer.
(The current buffer is written out to a temporary file, the program is
run on it, and then the temporary file is read back in, replacing the
contents of the buffer.)
.TP
.BI linter " program " \fR[ "arg " \fR...]
Use the given \fIprogram\fR to run a syntax check on the current buffer.
.TP
@@ -411,6 +416,9 @@ one of which must be specified. Valid color names are:
You may use the prefix \fBbright\fR for the foreground color to get a
stronger highlight. If your terminal supports transparency, not specifying
a \fIbgcolor\fP tells \fBnano\fP to attempt to use a transparent background.
.sp
All coloring commands are applied in the order in which they are specified,
which means that later commands can recolor stuff that was colored earlier.
.TP
.BI "icolor " fgcolor , bgcolor " """ regex """ " \fR...
Same as above, except that the matching is case insensitive.
@@ -435,36 +443,18 @@ to \fBicolor\fP.
.BI extendsyntax " name command " \fR[ "arg " \fR...]
Extend the syntax previously defined as \fIname\fR with another
\fIcommand\fR. This allows adding a new \fBcolor\fP, \fBicolor\fP,
\fBheader\fP, \fBmagic\fP, \fBcomment\fP, or \fBlinter\fP
\fBheader\fP, \fBmagic\fP, \fBcomment\fP, \fBlinter\fP, or \fBformatter\fR
command to an already defined syntax -- useful when you want to
slightly improve a syntax defined in one of the system-installed
files (which normally are not writable).
.P
Note: the \fBformatter\fR command has been removed. It was superseded by
a more general mechanism: the filtering of buffer or marked text through
an external command. Such filtering is done by typing \fB^R^X\fR and then
preceding your formatter command with the pipe symbol (\fB|\fR). It has
the added advantage that the operation can be undone.
.sp
If you use such a formatting command regularly, you could assign the relevant
series of keystrokes to a single key in your nanorc:
.sp
.RS
.B "bind M\-F \(dq^R^X|yourformatcommand^M\(dq main"
.RE
.sp
(Note that the \fB^R\fR, \fB^X\fR, and \fB^M\fR are each a single, literal
control character. You can enter them by preceding each with \fBM\-V\fR.)
.SH REBINDING KEYS
Key bindings can be changed via the following three commands:
.RS 3
.TP
.BI bind " key function menu"
Rebinds the key \fIkey\fP to a new function named \fIfunction\fP in the
context of menu \fImenu\fP (or in all menus where the function exists
by using \fBall\fP).
Rebinds the given \fIkey\fP to the given \fIfunction\fP in the given \fImenu\fP
(or in all menus where the function exists when \fBall\fP is used).
.TP
.BI bind " key " """" string """" " menu"
Makes the given \fIkey\fR produce the given \fIstring\fR in the given
@@ -472,33 +462,38 @@ Makes the given \fIkey\fR produce the given \fIstring\fR in the given
The \fIstring\fR can consist of text or commands or a mix of them.
(To enter a command into the \fIstring\fR, precede its keystroke
with \fBM\-V\fR.)
.TP
.BI unbind " key menu"
Unbinds the key \fIkey\fP from the menu named \fImenu\fP (or from all
menus where it exists by using \fBall\fP).
Unbinds the given \fIkey\fP from the given \fImenu\fP (or from all
menus where the key exists when \fBall\fP is used).
.RE
.TP
The format of \fIkey\fP should be one of:
.RS 3
.TP 3
.B ^
followed by a Latin letter, by one of several ASCII characters
(@, ], \\, ^, or _), or by the word "Space".
.TP 5
.BI ^ X
where \fIX\fR is a Latin letter, or one of several ASCII characters
(@, ], \\, ^, _), or the word "Space".
Example: ^C.
.TP
.B M\-
followed by any ASCII character except [, or by the word "Space".
.BI M\- X
where \fIX\fR is any ASCII character except [, or the word "Space".
Example: M\-C.
.TP
.B F
followed by a numeric value from 1 to 16.
.BI F N
where \fIN\fR is a numeric value from 1 to 24.
Example: F10.
(Often, \fBF13\fR to \fBF24\fR can be typed as \fBF1\fR to \fBF12\fR with Shift.)
.TP
the word "Ins" or the word "Del".
.BR Ins " or " Del .
.RE
Rebinding \fB^M\fR (Enter) or \fB^I\fR (Tab) is probably not a good idea.
On some terminals it's not possible to rebind \fB^H\fR (unless \fB\-\-raw\fR
is used) because its keycode is identical to that of the Backspace key.
.TP
Valid \fIfunction\fP names to be bound are:
.RS 3
@@ -577,8 +572,11 @@ Shows the current cursor position: the line, column, and character positions.
Counts the number of words, lines and characters in the current buffer.
.TP
.B speller
Invokes a spell-checking program, either the default one, or the one
defined by \fB\-\-speller\fR or \fBset speller\fR.
Invokes a spell-checking program, either the default \fBhunspell\fR or GNU
\fBspell\fR, or the one defined by \fB\-\-speller\fR or \fBset speller\fR.
.TP
.B formatter
Invokes a full-buffer-processing program (if the active syntax defines one).
.TP
.B linter
Invokes a syntax-checking program (if the active syntax defines one).
@@ -860,7 +858,7 @@ The menu for inserting output from an external command, reached from the insert
The help-viewer menu.
.TP
.B spell
The interactive spell checker Yes/no menu.
The menu of the integrated spell checker where the user can edit a misspelled word.
.TP
.B linter
The linter menu.

View File

@@ -16,7 +16,7 @@
.\" Documentation License along with this program. If not, see
.\" <https://www.gnu.org/licenses/>.
.\"
.TH RNANO 1 "version 4.5" "October 2019"
.TH RNANO 1 "version 4.6" "November 2019"
.SH NAME
rnano \- a restricted nano

View File

@@ -97,10 +97,6 @@
## Don't automatically add a newline when a file does not end with one.
# set nonewlines
## Don't pause between warnings at startup. Which means that only the
## last one will be readable (when there are multiple ones).
# set nopauses
## Set operating directory. nano will not read or write files outside
## this directory and its subdirectories. Also, the current directory
## is changed to here, so any files are inserted from this dir. A blank
@@ -218,44 +214,31 @@
## Setup of syntax coloring.
##
## Format:
## syntax "name" ["filename regex" ...]
##
## syntax "short description" ["filename regex" ...]
## color|icolor foreground,background "regex" ["regex"...]
## [...]
##
## The "none" syntax is reserved; specifying it on the command line is
## the same as not having a syntax at all. The "default" syntax is
## special: it takes no filename regexes, and applies to files that
## don't match any other syntax's filename regexes.
##
## color foreground,background "regex" ["regex"...]
## or
## icolor foreground,background "regex" ["regex"...]
##
## "color" will do case-sensitive matches, while "icolor" will do
## 'color' will do case-sensitive matches, while 'icolor' will do
## case-insensitive matches.
##
## Valid color names ares: white, black, normal, red, blue, green,
## yellow, magenta, cyan. For foreground colors, you may use the
## prefix "bright" to get a stronger highlight.
## All color commands are applied in the order in which they are specified,
## meaning that later commands can recolor stuff that was colored earlier.
##
## Valid color names for foreground and background are: white, black, normal,
## red, blue, green, yellow, magenta, cyan. For foreground colors, you may
## use the prefix "bright" to get a stronger highlight.
##
## All regexes (regular expressions) are of the extended type (ERE).
##
## To use multi-line regexes, use the start="regex" end="regex"
## [start="regex" end="regex"...] format.
## If the coloring rule should span multiple lines, use the following format:
##
## If your system supports transparency, not specifying a background
## color will use a transparent color. If you don't want this, be sure
## to set the background color to black or white.
## color fg,bg start="regex" end="regex"
##
## If you wish, you may put your syntax definitions in separate files.
## You can make use of such files as follows:
##
## include "/path/to/syntax_file.nanorc"
##
## Unless otherwise noted, the name of the syntax file (without the
## ".nanorc" extension) should be the same as the "short description"
## name inside that file. These names are kept fairly short to make
## them easier to remember and faster to type using nano's -Y option.
## include "/path/to/syntax_file.nanorc"
## To include all existing syntax definitions, you can do:
# include "@PKGDATADIR@/*.nanorc"
@@ -264,7 +247,7 @@
## If <Tab> should always produce four spaces when editing a Python file,
## 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 " "

1104
po/bg.po

File diff suppressed because it is too large Load Diff

1097
po/ca.po

File diff suppressed because it is too large Load Diff

1088
po/cs.po

File diff suppressed because it is too large Load Diff

1090
po/da.po

File diff suppressed because it is too large Load Diff

1097
po/de.po

File diff suppressed because it is too large Load Diff

1090
po/eo.po

File diff suppressed because it is too large Load Diff

1090
po/es.po

File diff suppressed because it is too large Load Diff

1104
po/eu.po

File diff suppressed because it is too large Load Diff

1086
po/fi.po

File diff suppressed because it is too large Load Diff

1098
po/fr.po

File diff suppressed because it is too large Load Diff

1088
po/ga.po

File diff suppressed because it is too large Load Diff

1088
po/gl.po

File diff suppressed because it is too large Load Diff

1098
po/hr.po

File diff suppressed because it is too large Load Diff

1088
po/hu.po

File diff suppressed because it is too large Load Diff

1104
po/id.po

File diff suppressed because it is too large Load Diff

1088
po/it.po

File diff suppressed because it is too large Load Diff

1088
po/ja.po

File diff suppressed because it is too large Load Diff

1189
po/ko.po

File diff suppressed because it is too large Load Diff

1158
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1092
po/nb.po

File diff suppressed because it is too large Load Diff

1090
po/nl.po

File diff suppressed because it is too large Load Diff

1104
po/nn.po

File diff suppressed because it is too large Load Diff

1088
po/pl.po

File diff suppressed because it is too large Load Diff

1092
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1096
po/ro.po

File diff suppressed because it is too large Load Diff

1094
po/ru.po

File diff suppressed because it is too large Load Diff

1092
po/sl.po

File diff suppressed because it is too large Load Diff

1088
po/sr.po

File diff suppressed because it is too large Load Diff

1088
po/sv.po

File diff suppressed because it is too large Load Diff

1134
po/tr.po

File diff suppressed because it is too large Load Diff

1095
po/uk.po

File diff suppressed because it is too large Load Diff

1088
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="4.5"
VERSION="4.6"
./configure -C --enable-tiny && make && ./configure -C &&

View File

@@ -21,13 +21,13 @@
#include "proto.h"
#ifdef ENABLE_BROWSER
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#ifdef ENABLE_BROWSER
static char **filelist = NULL;
/* The list of files to display in the file browser. */
static size_t filelist_len = 0;
@@ -221,7 +221,7 @@ char *do_browser(char *path)
selected = filelist_len - 1;
} else if (func == goto_dir_void) {
/* Ask for the directory to go to. */
if (do_prompt(TRUE, FALSE, MGOTODIR, NULL, NULL,
if (do_prompt(TRUE, FALSE, MGOTODIR, "", NULL,
/* TRANSLATORS: This is a prompt. */
browser_refresh, _("Go To Directory")) < 0) {
statusbar(_("Cancelled"));
@@ -285,7 +285,7 @@ char *do_browser(char *path)
/* If it isn't a directory, a file was selected -- we're done. */
if (!S_ISDIR(st.st_mode)) {
retval = mallocstrcpy(NULL, filelist[selected]);
retval = copy_of(filelist[selected]);
break;
}
@@ -314,7 +314,7 @@ char *do_browser(char *path)
/* If the window resized, refresh the file list. */
if (kbinput == KEY_WINCH) {
/* Remember the selected file, to be able to reselect it. */
present_name = mallocstrcpy(NULL, filelist[selected]);
present_name = copy_of(filelist[selected]);
/* Reread the contents of the current directory. */
goto read_directory_contents;
}
@@ -453,7 +453,6 @@ functionptrtype parse_browser_input(int *kbinput)
{
if (!meta_key) {
switch (*kbinput) {
case BS_CODE:
case '-':
return do_page_up;
case ' ':
@@ -547,17 +546,17 @@ void browser_refresh(void)
* "(dir)" for directories, and the file size for normal files. */
if (lstat(filelist[i], &st) == -1 || S_ISLNK(st.st_mode)) {
if (stat(filelist[i], &st) == -1 || !S_ISDIR(st.st_mode))
info = mallocstrcpy(NULL, "--");
info = copy_of("--");
else
/* TRANSLATORS: Try to keep this at most 7 characters. */
info = mallocstrcpy(NULL, _("(dir)"));
info = copy_of(_("(dir)"));
} else if (S_ISDIR(st.st_mode)) {
if (strcmp(thename, "..") == 0) {
/* TRANSLATORS: Try to keep this at most 12 characters. */
info = mallocstrcpy(NULL, _("(parent dir)"));
info = copy_of(_("(parent dir)"));
infomaxlen = 12;
} else
info = mallocstrcpy(NULL, _("(dir)"));
info = copy_of(_("(dir)"));
} else {
off_t result = st.st_size;
char modifier;
@@ -665,10 +664,10 @@ int filesearch_init(bool forwards)
(breadth(last_search) > COLS / 3) ? "..." : "");
free(disp);
} else
thedefault = mallocstrcpy(NULL, "");
thedefault = copy_of("");
/* Now ask what to search for. */
response = do_prompt(FALSE, FALSE, MWHEREISFILE, NULL, &search_history,
response = do_prompt(FALSE, FALSE, MWHEREISFILE, "", &search_history,
browser_refresh, "%s%s%s", _("Search"),
/* TRANSLATORS: A modifier of the Search prompt. */
!forwards ? _(" [Backwards]") : "", thedefault);
@@ -793,7 +792,7 @@ void to_last_file(void)
* The returned string is dynamically allocated, and should be freed. */
char *strip_last_component(const char *path)
{
char *copy = mallocstrcpy(NULL, path);
char *copy = copy_of(path);
char *last_slash = strrchr(copy, '/');
if (last_slash != NULL)

View File

@@ -160,7 +160,7 @@ bool is_word_mbchar(const char *c, bool allow_punct)
if (word_chars != NULL && *word_chars != '\0') {
char symbol[MAXCHARLEN + 1];
int symlen = parse_mbchar(c, symbol, NULL);
int symlen = collect_char(c, symbol);
symbol[symlen] = '\0';
return (strstr(word_chars, symbol) != NULL);
@@ -244,7 +244,7 @@ char *make_mbchar(long code, int *length)
} else
#endif
{
mb_char = mallocstrncpy(NULL, (char *)&code, 1);
mb_char = measured_copy((char *)&code, 1);
*length = 1;
}
@@ -286,50 +286,67 @@ size_t mbstrlen(const char *pointer)
return count;
}
/* Parse a multibyte character from buf. Return the number of bytes
* used. If chr isn't NULL, store the multibyte character in it. If
* col isn't NULL, add the character's width (in columns) to it. */
int parse_mbchar(const char *buf, char *chr, size_t *col)
/* Return the length (in bytes) of the character at the start of the
* given string, and return a copy of this character in *thechar. */
int collect_char(const char *string, char *thechar)
{
int length;
int charlen;
#ifdef ENABLE_UTF8
/* If this is a UTF-8 starter byte, get the number of bytes of the character. */
if ((signed char)*buf < 0) {
length = mblen(buf, MAXCHARLEN);
if ((signed char)*string < 0) {
charlen = mblen(string, MAXCHARLEN);
/* When the multibyte sequence is invalid, only take the first byte. */
if (length <= 0)
length = 1;
if (charlen <= 0)
charlen = 1;
} else
#endif
length = 1;
charlen = 1;
/* When requested, store the multibyte character in chr. */
if (chr != NULL)
for (int i = 0; i < length; i++)
chr[i] = buf[i];
for (int i = 0; i < charlen; i++)
thechar[i] = string[i];
/* When requested, add the width of the character to col. */
if (col != NULL) {
/* If we have a tab, compute its width in columns based on the
* current value of col. */
if (*buf == '\t')
*col += tabsize - *col % tabsize;
/* If we have a control character, it's two columns wide: one
* column for the "^", and one for the visible character. */
else if (is_cntrl_mbchar(buf))
*col += 2;
/* If we have a normal character, get its width normally. */
else if (length == 1)
*col += 1;
return charlen;
}
/* Return the length (in bytes) of the character at the start of
* the given string, and add this character's width to *column. */
int advance_over(const char *string, size_t *column)
{
#ifdef ENABLE_UTF8
else
*col += mbwidth(buf);
#endif
}
if ((signed char)*string < 0) {
int charlen = mblen(string, MAXCHARLEN);
return length;
if (charlen > 0) {
if (is_cntrl_mbchar(string))
*column += 2;
else
*column += mbwidth(string);
} else {
charlen = 1;
*column += 1;
}
return charlen;
}
#endif
if ((unsigned char)*string < 0x20) {
if (*string == '\t')
*column += tabsize - *column % tabsize;
else
*column += 2;
} else if (*string == 0x7F)
*column += 2;
#ifndef ENABLE_UTF8
else if (0x7F < (unsigned char)*string && (unsigned char)*string < 0xA0)
*column += 2;
#endif
else
*column += 1;
return 1;
}
/* Return the index in buf of the beginning of the multibyte character
@@ -593,7 +610,7 @@ bool has_blank_char(const char *string)
char symbol[MAXCHARLEN];
while (*string != '\0') {
string += parse_mbchar(string, symbol, NULL);
string += collect_char(string, symbol);
if (is_blank_mbchar(symbol))
return TRUE;

View File

@@ -21,14 +21,14 @@
#include "proto.h"
#ifdef ENABLE_COLOR
#include <errno.h>
#ifdef HAVE_MAGIC_H
#include <magic.h>
#endif
#include <string.h>
#ifdef ENABLE_COLOR
/* For early versions of ncurses-6.0, use an additional A_PROTECT attribute
* for all colors, in order to work around an ncurses miscoloring bug. */
#if defined(NCURSES_VERSION_MAJOR) && (NCURSES_VERSION_MAJOR == 6) && \

View File

@@ -42,7 +42,7 @@ void do_deletion(undo_type action)
* line, create a new undo item, otherwise update the existing item. */
if (action != openfile->last_action ||
openfile->current->lineno != openfile->current_undo->lineno)
add_undo(action);
add_undo(action, NULL);
else
update_undo(action);
@@ -68,13 +68,13 @@ void do_deletion(undo_type action)
!ISSET(NO_NEWLINES)) {
#ifndef NANO_TINY
if (action == BACK)
add_undo(BACK);
add_undo(BACK, NULL);
#endif
return;
}
#ifndef NANO_TINY
add_undo(action);
add_undo(action, NULL);
#endif
/* Add the contents of the next line to those of the current one. */
openfile->current->data = charealloc(openfile->current->data,
@@ -182,7 +182,7 @@ void chop_word(bool forward)
openfile->current_x = is_current_x;
/* Now kill the marked region and a word is gone. */
add_undo(CUT);
add_undo(CUT, NULL);
do_snip(FALSE, TRUE, FALSE, FALSE);
update_undo(CUT);
@@ -194,7 +194,10 @@ void chop_word(bool forward)
/* Delete a word leftward. */
void chop_previous_word(void)
{
chop_word(BACKWARD);
if (openfile->current->prev == NULL && openfile->current_x == 0)
statusbar(_("Nothing was cut"));
else
chop_word(BACKWARD);
}
/* Delete a word rightward. */
@@ -382,7 +385,7 @@ void cut_text(void)
* the current cut is not contiguous with the previous cutting. */
if (openfile->last_action != CUT || !keep_cutbuffer) {
keep_cutbuffer = FALSE;
add_undo(CUT);
add_undo(CUT, NULL);
}
do_snip(FALSE, openfile->mark != NULL, FALSE, FALSE);
@@ -433,7 +436,7 @@ void cut_till_eof(void)
return;
}
add_undo(CUT_TO_EOF);
add_undo(CUT_TO_EOF, NULL);
do_snip(FALSE, FALSE, TRUE, FALSE);
update_undo(CUT_TO_EOF);
wipe_statusbar();
@@ -451,7 +454,7 @@ void zap_text(void)
/* Add a new undo item only when the current item is not a ZAP or when
* the current zap is not contiguous with the previous zapping. */
if (openfile->last_action != ZAP || !keep_cutbuffer)
add_undo(ZAP);
add_undo(ZAP, NULL);
/* Use the cutbuffer from the ZAP undo item, so the cut can be undone. */
cutbuffer = openfile->current_undo->cutbuffer;
@@ -479,7 +482,7 @@ void paste_text(void)
}
#ifndef NANO_TINY
add_undo(PASTE);
add_undo(PASTE, NULL);
if (ISSET(SOFTWRAP))
was_leftedge = leftedge_for(xplustabs(), openfile->current);

View File

@@ -35,7 +35,7 @@
/* Verify that the containing directory of the given filename exists. */
bool has_valid_path(const char *filename)
{
char *namecopy = mallocstrcpy(NULL, filename);
char *namecopy = copy_of(filename);
char *parentdir = dirname(namecopy);
struct stat parentinfo;
bool validity = FALSE;
@@ -86,10 +86,10 @@ void make_new_buffer(void)
/* Make the new buffer the current one, and start initializing it. */
openfile = newnode;
openfile->filename = mallocstrcpy(NULL, "");
openfile->filename = copy_of("");
openfile->filetop = make_new_node(NULL);
openfile->filetop->data = mallocstrcpy(NULL, "");
openfile->filetop->data = copy_of("");
openfile->filebot = openfile->filetop;
openfile->current = openfile->filetop;
@@ -293,8 +293,8 @@ int delete_lockfile(const char *lockfilename)
* creating the lockfile but we should continue to load the file. */
int do_lockfile(const char *filename)
{
char *namecopy = mallocstrcpy(NULL, filename);
char *secondcopy = mallocstrcpy(NULL, filename);
char *namecopy = copy_of(filename);
char *secondcopy = copy_of(filename);
size_t locknamesize = strlen(filename) + strlen(locking_prefix)
+ strlen(locking_suffix) + 3;
char *lockfilename = charalloc(locknamesize);
@@ -349,7 +349,7 @@ int do_lockfile(const char *filename)
room = COLS - breadth(question) + 7 - breadth(lockuser) -
breadth(lockprog) - breadth(pidstring);
if (room < 4)
postedname = mallocstrcpy(NULL, "_");
postedname = copy_of("_");
else if (room < breadth(filename)) {
char *fragment = display_string(filename,
breadth(filename) - room + 3, room, FALSE, FALSE);
@@ -420,8 +420,7 @@ bool open_buffer(const char *filename, bool new_buffer)
#ifdef ENABLE_OPERATINGDIR
if (outside_of_confinement(filename, FALSE)) {
statusline(ALERT, _("Can't read file from outside of %s"),
operating_dir);
statusline(ALERT, _("Can't read file from outside of %s"), operating_dir);
return FALSE;
}
#endif
@@ -513,7 +512,8 @@ bool open_buffer(const char *filename, bool new_buffer)
#ifdef ENABLE_SPELLER
/* Open the specified file, and if that succeeds, remove the text of the marked
* region or of the entire buffer and read the file contents into its place. */
bool replace_buffer(const char *filename, undo_type action, bool marked)
bool replace_buffer(const char *filename, undo_type action, bool marked,
const char *operation)
{
linestruct *was_cutbuffer = cutbuffer;
int descriptor;
@@ -525,8 +525,7 @@ bool replace_buffer(const char *filename, undo_type action, bool marked)
return FALSE;
#ifndef NANO_TINY
add_undo(COUPLE_BEGIN);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
add_undo(COUPLE_BEGIN, operation);
#endif
/* When nothing is marked, start at the top of the buffer. */
@@ -538,7 +537,7 @@ bool replace_buffer(const char *filename, undo_type action, bool marked)
/* Throw away the marked region or the whole buffer. */
cutbuffer = NULL;
#ifndef NANO_TINY
add_undo(action);
add_undo(action, NULL);
#endif
do_snip(FALSE, marked, !marked, FALSE);
#ifndef NANO_TINY
@@ -551,8 +550,7 @@ bool replace_buffer(const char *filename, undo_type action, bool marked)
read_file(f, descriptor, filename, TRUE);
#ifndef NANO_TINY
add_undo(COUPLE_END);
openfile->undotop->strdata = mallocstrcpy(NULL, _("spelling correction"));
add_undo(COUPLE_END, operation);
#endif
return TRUE;
}
@@ -607,10 +605,12 @@ void redecorate_after_switch(void)
}
#ifndef NANO_TINY
/* When not in softwrap mode, make sure firstcolumn is zero. It might
* be nonzero if we had softwrap mode on while in this buffer, and then
* turned softwrap mode off while in a different buffer. */
if (!ISSET(SOFTWRAP))
/* While in a different buffer, the screen may have been resized
* or softwrap mode maybe have been toggled, so make sure that the
* starting column for the first row gets an appropriate value. */
if (ISSET(SOFTWRAP))
ensure_firstcolumn_is_aligned();
else
openfile->firstcolumn = 0;
#endif
@@ -677,7 +677,7 @@ char *encode_data(char *buf, size_t buf_len)
unsunder(buf, buf_len);
buf[buf_len] = '\0';
return mallocstrcpy(NULL, buf);
return copy_of(buf);
}
/* Read the given open file f into the current buffer. filename should be
@@ -719,7 +719,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
#ifndef NANO_TINY
if (undoable)
add_undo(INSERT);
add_undo(INSERT, NULL);
if (ISSET(SOFTWRAP))
was_leftedge = leftedge_for(xplustabs(), openfile->current);
@@ -833,17 +833,16 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
/* If there was a real error during the reading, let the user know. */
if (ferror(f) && errornumber != EINTR && errornumber != 0)
statusline(ALERT, strerror(errornumber));
fclose(f);
if (fd > 0 && !undoable) {
close(fd);
if (fd > 0 && !undoable)
writable = (ISSET(VIEW_MODE) || access(filename, W_OK) == 0);
}
/* If the file ended with newline, or it was entirely empty, make the
* last line blank. Otherwise, put the last read data in. */
if (len == 0)
bottomline->data = mallocstrcpy(NULL, "");
bottomline->data = copy_of("");
else {
bool mac_line_needs_newline = FALSE;
@@ -869,7 +868,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
if (mac_line_needs_newline) {
bottomline->next = make_new_node(bottomline);
bottomline = bottomline->next;
bottomline->data = mallocstrcpy(NULL, "");
bottomline->data = copy_of("");
}
}
@@ -1026,7 +1025,7 @@ void do_insertfile(void)
{
int response;
const char *msg;
char *given = mallocstrcpy(NULL, "");
char *given = copy_of("");
/* The last answer the user typed at the statusbar prompt. */
#ifndef NANO_TINY
format_type was_fmt = openfile->fmt;
@@ -1212,9 +1211,7 @@ void do_insertfile(void)
/* If the current mode of operation allows it, go insert a file. */
void do_insertfile_void(void)
{
if (ISSET(RESTRICTED))
show_restricted_warning();
else
if (!in_restricted_mode())
do_insertfile();
}
@@ -1249,7 +1246,7 @@ char *get_full_path(const char *origpath)
strcat(here, "/");
}
} else {
here = mallocstrcpy(NULL, "");
here = copy_of("");
free(allocation);
}
@@ -1279,7 +1276,7 @@ char *get_full_path(const char *origpath)
} else {
/* If target contains a filename, separate the two. */
if (!path_only) {
just_filename = mallocstrcpy(NULL, last_slash + 1);
just_filename = copy_of(last_slash + 1);
*(last_slash + 1) = '\0';
}
@@ -1326,9 +1323,8 @@ char *get_full_path(const char *origpath)
return target;
}
/* Return the full version of path, as returned by get_full_path(). On
* error, or if path doesn't reference a directory, or if the directory
* isn't writable, return NULL. */
/* Check whether the given path refers to a directory that is writable.
* Return the absolute form of the path on success, and NULL on failure. */
char *check_writable_directory(const char *path)
{
char *full_path = get_full_path(path);
@@ -1336,9 +1332,7 @@ char *check_writable_directory(const char *path)
if (full_path == NULL)
return NULL;
/* If we can't write to path or path isn't a directory, return NULL. */
if (access(full_path, W_OK) != 0 ||
full_path[strlen(full_path) - 1] != '/') {
if (full_path[strlen(full_path) - 1] != '/' || access(full_path, W_OK) != 0) {
free(full_path);
return NULL;
}
@@ -1346,44 +1340,42 @@ char *check_writable_directory(const char *path)
return full_path;
}
/* This function calls mkstemp(($TMPDIR|P_tmpdir|/tmp/)"nano.XXXXXX").
* On success, it returns the malloc()ed filename and corresponding
* FILE stream, opened in "r+b" mode. On error, it returns NULL for
* the filename and leaves the FILE stream unchanged. */
char *safe_tempfile(FILE **f)
/* Create, safely, a temporary file in the standard temp directory.
* On success, return the malloc()ed filename, plus the corresponding
* file stream opened in read-write mode. On error, return NULL. */
char *safe_tempfile(FILE **stream)
{
const char *tmpdir_env = getenv("TMPDIR");
char *full_tempdir = NULL, *tempfile_name = NULL;
mode_t original_umask = 0;
const char *env_dir = getenv("TMPDIR");
char *tempdir = NULL, *tempfile_name = NULL;
mode_t was_mask;
int fd;
/* Get the absolute path for the first directory among $TMPDIR
* and P_tmpdir that is writable, otherwise use /tmp/. */
if (tmpdir_env != NULL)
full_tempdir = check_writable_directory(tmpdir_env);
if (env_dir != NULL)
tempdir = check_writable_directory(env_dir);
if (full_tempdir == NULL)
full_tempdir = check_writable_directory(P_tmpdir);
if (tempdir == NULL)
tempdir = check_writable_directory(P_tmpdir);
if (full_tempdir == NULL)
full_tempdir = mallocstrcpy(NULL, "/tmp/");
if (tempdir == NULL)
tempdir = copy_of("/tmp/");
tempfile_name = charealloc(full_tempdir, strlen(full_tempdir) + 12);
tempfile_name = charealloc(tempdir, strlen(tempdir) + 12);
strcat(tempfile_name, "nano.XXXXXX");
original_umask = umask(0);
umask(S_IRWXG | S_IRWXO);
was_mask = umask(S_IRWXG | S_IRWXO);
fd = mkstemp(tempfile_name);
if (fd != -1)
*f = fdopen(fd, "r+b");
else {
umask(was_mask);
if (fd == -1) {
free(tempfile_name);
tempfile_name = NULL;
return NULL;
}
umask(original_umask);
*stream = fdopen(fd, "r+b");
return tempfile_name;
}
@@ -1470,10 +1462,10 @@ void init_backup_dir(void)
}
#endif /* !NANO_TINY */
/* Read from inn, write to out. We assume inn is opened for reading,
* and out for writing. We return 0 on success, -1 on read error, or -2
* on write error. inn is always closed by this function, out is closed
* only if close_out is true. */
/* Read all data from inn, and write it to out. File inn must be open for
* reading, and out for writing. Return 0 on success, a negative number on
* read error, and a positive number on write error. File inn is always
* closed by this function, out is closed only if close_out is true. */
int copy_file(FILE *inn, FILE *out, bool close_out)
{
int retval = 0;
@@ -1488,64 +1480,51 @@ int copy_file(FILE *inn, FILE *out, bool close_out)
break;
}
if (fwrite(buf, sizeof(char), charsread, out) < charsread) {
retval = -2;
retval = 2;
break;
}
} while (charsread > 0);
if (fclose(inn) == EOF)
retval = -1;
retval = -3;
if (flush_out_fnc(out) == EOF)
retval = -2;
retval = 4;
return retval;
}
/* Write a file out to disk. If f_open isn't NULL, we assume that it is
* a stream associated with the file, and we don't try to open it
* ourselves. If tmp is TRUE, we set the umask to disallow anyone else
* from accessing the file, we don't set the filename to its name, and
* we don't print out how many lines we wrote on the statusbar.
*
* tmp means we are writing a temporary file in a secure fashion. We
* use it when spell checking or dumping the file on an error. If
* method is APPEND, it means we are appending instead of overwriting.
* If method is PREPEND, it means we are prepending instead of
* overwriting. If fullbuffer is TRUE, we set the current filename and
* stat info. But fullbuffer is irrelevant when appending or prepending,
* or when writing a temporary file.
*
* Return TRUE on success or FALSE on error. */
bool write_file(const char *name, FILE *f_open, bool tmp,
/* Write the current buffer to disk. If thefile isn't NULL, we write to a
* temporary file that is already open. If tmp is TRUE (when spell checking
* or emergency dumping, for example), we set the umask to disallow anyone else
* from accessing the file, and don't print out how many lines we wrote on the
* status bar. If method is APPEND or PREPEND, it means we will be appending
* or prepending instead of overwriting the given file. If fullbuffer is TRUE
* and when writing normally, we set the current filename and stat info.
* Return TRUE on success, and FALSE otherwise. */
bool write_file(const char *name, FILE *thefile, bool tmp,
kind_of_writing_type method, bool fullbuffer)
{
bool retval = FALSE;
/* Instead of returning in this function, you should always
* set retval and then goto cleanup_and_exit. */
size_t lineswritten = 0;
const linestruct *fileptr = openfile->filetop;
int fd;
/* The file descriptor we use. */
mode_t original_umask = 0;
/* Our umask, from when nano started. */
#ifndef NANO_TINY
bool isactualfile = FALSE;
/* TRUE when the file is non-temporary and exists, FALSE otherwise. */
#endif
/* Becomes TRUE when the file is non-temporary and exists. */
struct stat st;
/* The status fields filled in by stat(). */
#endif
char *realname;
/* The filename after tilde expansion. */
FILE *f = f_open;
/* The actual file, realname, we are writing to. */
char *tempname = NULL;
/* The name of the temporary file we write to on prepend. */
/* The name of the temporary file we use when prepending. */
linestruct *line = openfile->filetop;
/* An iterator for moving through the lines of the buffer. */
size_t lineswritten = 0;
/* The number of lines written, for feedback on the status bar. */
bool retval = FALSE;
/* The return value, to become TRUE when writing has succeeded. */
#ifndef NANO_TINY
if (*name == '\0')
return -1;
if (!tmp)
titlebar(NULL);
die("Tried to write a nameless file -- please report a bug\n");
#endif
realname = real_dir_from_tilde(name);
@@ -1557,11 +1536,6 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
goto cleanup_and_exit;
}
#endif
/* If the temp file exists and isn't already open, give up. */
if (tmp && (lstat(realname, &st) != -1) && f_open == NULL)
goto cleanup_and_exit;
#ifndef NANO_TINY
/* Check whether the file (at the end of the symlink) exists. */
if (!tmp)
@@ -1582,25 +1556,21 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
openfile->current_stat->st_mtime == st.st_mtime)) {
static struct timespec filetime[2];
char *backupname;
int backup_cflags, backup_fd;
FILE *backup_file = NULL;
int backup_cflags, backup_fd, verdict;
FILE *original = NULL, *backup_file = NULL;
/* Save the original file's access and modification times. */
filetime[0].tv_sec = openfile->current_stat->st_atime;
filetime[1].tv_sec = openfile->current_stat->st_mtime;
if (f_open == NULL) {
/* Open the original file to copy to the backup. */
f = fopen(realname, "rb");
/* Open the file of which a backup must be made. */
original = fopen(realname, "rb");
if (f == NULL) {
statusline(ALERT, _("Error reading %s: %s"), realname,
strerror(errno));
/* If we can't read from the original file, go on, since
* only saving the current buffer is better than saving
* nothing. */
goto skip_backup;
}
if (original == NULL) {
statusline(ALERT, _("Error reading %s: %s"), realname, strerror(errno));
/* If we can't read from the original file, go on, since saving
* only the current buffer is better than saving nothing. */
goto skip_backup;
}
/* If backup_dir is set, we set backupname to
@@ -1615,14 +1585,11 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
* filename portion of the given path. Otherwise, replace
* slashes with exclamation marks in the full path. */
if (backuptemp == NULL)
backuptemp = mallocstrcpy(NULL, tail(realname));
backuptemp = copy_of(tail(realname));
else {
size_t i = 0;
for (; backuptemp[i] != '\0'; i++) {
for (int i = 0; backuptemp[i] != '\0'; i++)
if (backuptemp[i] == '/')
backuptemp[i] = '!';
}
}
backupname = charalloc(strlen(backup_dir) + strlen(backuptemp) + 1);
@@ -1704,11 +1671,19 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
goto cleanup_and_exit;
}
/* Copy the file. */
if (copy_file(f, backup_file, FALSE) != 0) {
/* Copy the existing file to the backup. */
verdict = copy_file(original, backup_file, FALSE);
if (verdict < 0) {
fclose(backup_file);
statusline(ALERT, _("Error reading %s: %s"), realname,
strerror(errno));
statusline(ALERT, _("Error reading %s: %s"), realname, strerror(errno));
goto cleanup_and_exit;
} else if (verdict > 0) {
fclose(backup_file);
if (prompt_failed_backupwrite(backupname))
goto skip_backup;
statusline(HUSH, _("Error writing backup file %s: %s"),
backupname, strerror(errno));
goto cleanup_and_exit;
}
@@ -1727,77 +1702,55 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
}
skip_backup:
#endif /* !NANO_TINY */
if (f_open == NULL) {
original_umask = umask(0);
/* If we create a temp file, we don't let anyone else access it. */
if (tmp)
umask(S_IRWXG | S_IRWXO);
else
umask(original_umask);
}
#ifndef NANO_TINY
/* If we're prepending, copy the file to a temp file. */
/* When prepending, first copy the existing file to a temporary file. */
if (method == PREPEND) {
int fd_source;
FILE *f_source = NULL;
FILE *source = fopen(realname, "rb");
FILE *target = NULL;
int verdict;
if (f == NULL) {
f = fopen(realname, "rb");
if (f == NULL) {
statusline(ALERT, _("Error reading %s: %s"), realname,
strerror(errno));
goto cleanup_and_exit;
}
}
tempname = safe_tempfile(&f);
if (tempname == NULL) {
statusline(ALERT, _("Error writing temp file: %s"),
strerror(errno));
if (source == NULL) {
statusline(ALERT, _("Error reading %s: %s"), realname, strerror(errno));
goto cleanup_and_exit;
}
if (f_open == NULL) {
fd_source = open(realname, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
tempname = safe_tempfile(&target);
if (fd_source != -1) {
f_source = fdopen(fd_source, "rb");
if (f_source == NULL) {
statusline(ALERT, _("Error reading %s: %s"), realname,
strerror(errno));
close(fd_source);
fclose(f);
unlink(tempname);
goto cleanup_and_exit;
}
}
if (tempname == NULL) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
goto cleanup_and_exit;
}
if (f_source == NULL || copy_file(f_source, f, TRUE) != 0) {
statusline(ALERT, _("Error writing temp file: %s"),
strerror(errno));
verdict = copy_file(source, target, TRUE);
if (verdict < 0) {
statusline(ALERT, _("Error reading %s: %s"), realname, strerror(errno));
unlink(tempname);
goto cleanup_and_exit;
} else if (verdict > 0) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
unlink(tempname);
goto cleanup_and_exit;
}
}
if (S_ISFIFO(st.st_mode))
if (!tmp && S_ISFIFO(st.st_mode))
statusbar(_("Writing to FIFO..."));
#endif /* !NANO_TINY */
if (f_open == NULL) {
/* When it's not a temporary file, this is where we open or create it. */
if (thefile == NULL) {
mode_t was_mask = 0;
int fd;
/* When creating an emergency file, don't let others access it. */
if (tmp)
was_mask = umask(S_IRWXG | S_IRWXO);
#ifndef NANO_TINY
block_sigwinch(TRUE);
install_handler_for_Ctrl_C();
#endif
/* Now open the file in place. Use O_EXCL if tmp is TRUE. This
* is copied from joe, because wiggy says so *shrug*. */
/* Now open the file. Use O_EXCL for an emergency file. */
fd = open(realname, O_WRONLY | O_CREAT | ((method == APPEND) ?
O_APPEND : (tmp ? O_EXCL : O_TRUNC)), S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
@@ -1806,26 +1759,27 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
restore_handler_for_Ctrl_C();
block_sigwinch(FALSE);
#endif
/* Set the umask back to the user's original value. */
umask(original_umask);
/* When this is an emergency file, restore the original umask. */
if (tmp)
umask(was_mask);
/* If we couldn't open the file, give up. */
if (fd == -1) {
if (errno == EINTR || errno == 0)
statusline(ALERT, _("Interrupted"));
else
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
#ifndef NANO_TINY
if (tempname != NULL)
unlink(tempname);
#endif
goto cleanup_and_exit;
}
f = fdopen(fd, (method == APPEND) ? "ab" : "wb");
thefile = fdopen(fd, (method == APPEND) ? "ab" : "wb");
if (f == NULL) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
if (thefile == NULL) {
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
close(fd);
goto cleanup_and_exit;
}
@@ -1834,21 +1788,20 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
if (!tmp)
statusbar(_("Writing..."));
while (fileptr != NULL) {
size_t data_len = strlen(fileptr->data), size;
while (line != NULL) {
size_t data_len = strlen(line->data), size;
/* Decode LFs as the NULs that they are, before writing to disk. */
sunder(fileptr->data);
sunder(line->data);
size = fwrite(fileptr->data, sizeof(char), data_len, f);
size = fwrite(line->data, sizeof(char), data_len, thefile);
/* Re-encode any embedded NULs as LFs. */
unsunder(fileptr->data, data_len);
unsunder(line->data, data_len);
if (size < data_len) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
fclose(f);
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
fclose(thefile);
goto cleanup_and_exit;
}
@@ -1856,67 +1809,59 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
* character after it. If the last line of the file is blank,
* this means that zero bytes are written, in which case we
* don't count the last line in the total lines written. */
if (fileptr == openfile->filebot) {
if (fileptr->data[0] == '\0')
if (line == openfile->filebot) {
if (line->data[0] == '\0')
lineswritten--;
} else {
#ifndef NANO_TINY
if (openfile->fmt == DOS_FILE || openfile->fmt == MAC_FILE) {
if (putc('\r', f) == EOF) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
fclose(f);
if (putc('\r', thefile) == EOF) {
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
fclose(thefile);
goto cleanup_and_exit;
}
}
if (openfile->fmt != MAC_FILE)
#endif
if (putc('\n', f) == EOF) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
fclose(f);
if (putc('\n', thefile) == EOF) {
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
fclose(thefile);
goto cleanup_and_exit;
}
}
fileptr = fileptr->next;
line = line->next;
lineswritten++;
}
#ifndef NANO_TINY
/* If we're prepending, open the temp file, and append it to f. */
/* When prepending, append the temporary file to what we wrote above. */
if (method == PREPEND) {
int fd_source;
FILE *f_source = NULL;
FILE *source = fopen(tempname, "rb");
int verdict;
fd_source = open(tempname, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd_source != -1) {
f_source = fdopen(fd_source, "rb");
if (f_source == NULL)
close(fd_source);
}
if (f_source == NULL) {
statusline(ALERT, _("Error reading %s: %s"), tempname,
strerror(errno));
fclose(f);
if (source == NULL) {
statusline(ALERT, _("Error reading temp file: %s"), strerror(errno));
fclose(thefile);
goto cleanup_and_exit;
}
if (copy_file(f_source, f, TRUE) != 0) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
verdict = copy_file(source, thefile, TRUE);
if (verdict < 0) {
statusline(ALERT, _("Error reading temp file: %s"), strerror(errno));
goto cleanup_and_exit;
} else if (verdict > 0) {
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
goto cleanup_and_exit;
}
unlink(tempname);
} else
#endif
if (fclose(f) != 0) {
statusline(ALERT, _("Error writing %s: %s"), realname,
strerror(errno));
if (fclose(thefile) != 0) {
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
goto cleanup_and_exit;
}
@@ -1939,12 +1884,12 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
/* If the syntax changed, discard and recompute the multidata. */
if (strcmp(oldname, newname) != 0) {
linestruct *line = openfile->filetop;
linestruct *lin = openfile->filetop;
while (line != NULL) {
free(line->multidata);
line->multidata = NULL;
line = line->next;
while (lin != NULL) {
free(lin->multidata);
lin->multidata = NULL;
lin = lin->next;
}
precalc_multicolorinfo();
@@ -1970,8 +1915,8 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
retval = TRUE;
cleanup_and_exit:
free(realname);
free(tempname);
free(realname);
return retval;
}
@@ -1979,7 +1924,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
#ifndef NANO_TINY
/* Write a marked selection from a file out to disk. Return TRUE on
* success or FALSE on error. */
bool write_marked_file(const char *name, FILE *f_open, bool tmp,
bool write_marked_file(const char *name, FILE *stream, bool tmp,
kind_of_writing_type method)
{
bool retval;
@@ -1999,7 +1944,7 @@ bool write_marked_file(const char *name, FILE *f_open, bool tmp,
added_magicline = TRUE;
}
retval = write_file(name, f_open, tmp, method, FALSE);
retval = write_file(name, stream, tmp, method, FALSE);
if (added_magicline)
remove_magicline();
@@ -2033,11 +1978,11 @@ int do_writeout(bool exiting, bool withprompt)
/* Display newlines in filenames as ^J. */
as_an_at = FALSE;
given = mallocstrcpy(NULL,
#ifndef NANO_TINY
(openfile->mark && !exiting) ? "" :
given = copy_of((openfile->mark && !exiting) ? "" : openfile->filename);
#else
given = copy_of(openfile->filename);
#endif
openfile->filename);
while (TRUE) {
const char *msg;
@@ -2287,7 +2232,7 @@ char *real_dir_from_tilde(const char *path)
size_t i = 1;
if (*path != '~')
return mallocstrcpy(NULL, path);
return copy_of(path);
/* Figure out how much of the string we need to compare. */
while (path[i] != '/' && path[i] != '\0')
@@ -2295,12 +2240,12 @@ char *real_dir_from_tilde(const char *path)
if (i == 1) {
get_homedir();
tilded = mallocstrcpy(NULL, homedir);
tilded = copy_of(homedir);
} else {
#ifdef HAVE_PWD_H
const struct passwd *userdata;
tilded = mallocstrncpy(NULL, path, i + 1);
tilded = measured_copy(path, i + 1);
tilded[i] = '\0';
do {
@@ -2311,7 +2256,7 @@ char *real_dir_from_tilde(const char *path)
if (userdata != NULL)
tilded = mallocstrcpy(tilded, userdata->pw_dir);
#else
tilded = strdup("");
tilded = copy_of("");
#endif
}
@@ -2423,7 +2368,7 @@ char **username_tab_completion(const char *buf, size_t *num_matches,
char **cwd_tab_completion(const char *buf, bool allow_files,
size_t *num_matches, size_t buf_len)
{
char *dirname = mallocstrcpy(NULL, buf);
char *dirname = copy_of(buf);
char *slash, *filename;
size_t filenamelen;
char **matches = NULL;
@@ -2438,7 +2383,7 @@ char **cwd_tab_completion(const char *buf, bool allow_files,
if (slash != NULL) {
char *wasdirname = dirname;
filename = mallocstrcpy(NULL, ++slash);
filename = copy_of(++slash);
/* Cut off the filename part after the slash. */
*slash = '\0';
dirname = real_dir_from_tilde(dirname);
@@ -2451,7 +2396,7 @@ char **cwd_tab_completion(const char *buf, bool allow_files,
free(wasdirname);
} else {
filename = dirname;
dirname = mallocstrcpy(NULL, present_path);
dirname = copy_of(present_path);
}
dir = opendir(dirname);
@@ -2496,7 +2441,7 @@ char **cwd_tab_completion(const char *buf, bool allow_files,
matches = (char **)nrealloc(matches, (*num_matches + 1) *
sizeof(char *));
matches[*num_matches] = mallocstrcpy(NULL, nextdir->d_name);
matches[*num_matches] = copy_of(nextdir->d_name);
++(*num_matches);
}
}
@@ -2546,10 +2491,10 @@ char *input_tab(char *buf, bool allow_files, size_t *place,
/* Get the number of characters that all matches have in common. */
while (TRUE) {
len1 = parse_mbchar(matches[0] + common_len, char1, NULL);
len1 = collect_char(matches[0] + common_len, char1);
for (match = 1; match < num_matches; match++) {
len2 = parse_mbchar(matches[match] + common_len, char2, NULL);
len2 = collect_char(matches[match] + common_len, char2);
if (len1 != len2 || strncmp(char1, char2, len2) != 0)
break;

View File

@@ -259,10 +259,12 @@ int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH,
MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE,
MEXTCMD, MHELP, MSPELL, MLINTER,
MBROWSER, MWHEREISFILE, MGOTODIR,
MMOST|MHELP|MYESNO };
MMOST|MBROWSER|MHELP|MYESNO };
#endif
char *rcfile_with_errors = NULL;
/* The first nanorc file, if any, that produced warnings. */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
char *startup_problem = NULL;
/* An error message (if any) about nanorc files or history files. */
#endif
bool spotlighted = FALSE;
@@ -490,6 +492,8 @@ int keycode_from_string(const char *keystring)
if (strcasecmp(keystring, "^H") == 0)
return KEY_BACKSPACE;
#endif
if (keystring[1] == '/' && strlen(keystring) == 2)
return 31;
if (keystring[1] <= '_' && strlen(keystring) == 2)
return keystring[1] - 64;
else
@@ -503,7 +507,7 @@ int keycode_from_string(const char *keystring)
return -1;
} else if (keystring[0] == 'F') {
int fn = atoi(&keystring[1]);
if (fn < 1 || fn > 16)
if (fn < 1 || fn > 24)
return -1;
return KEY_F0 + fn;
} else if (!strcasecmp(keystring, "Ins"))
@@ -693,6 +697,10 @@ void shortcut_init(void)
const char *lint_gist = N_("Invoke the linter, if available");
const char *prevlint_gist = N_("Go to previous linter msg");
const char *nextlint_gist = N_("Go to next linter msg");
#ifdef ENABLE_SPELLER
const char *formatter_gist =
N_("Invoke a program to format/arrange/manipulate the buffer");
#endif
#endif
#endif /* ENABLE_HELP */
@@ -1001,9 +1009,14 @@ void shortcut_init(void)
N_("Zap Text"), WITHORSANS(zap_gist), BLANKAFTER, NOVIEW);
#ifdef ENABLE_COLOR
if (!ISSET(RESTRICTED))
if (!ISSET(RESTRICTED)) {
add_to_funcs(do_linter, MMAIN,
N_("To Linter"), WITHORSANS(lint_gist), BLANKAFTER, NOVIEW);
N_("To Linter"), WITHORSANS(lint_gist), TOGETHER, NOVIEW);
#ifdef ENABLE_SPELLER
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WITHORSANS(formatter_gist), BLANKAFTER, NOVIEW);
#endif
}
#endif
#endif
add_to_funcs(do_savefile, MMAIN,
@@ -1124,6 +1137,9 @@ void shortcut_init(void)
#endif
#ifdef ENABLE_COLOR
add_to_sclist(MMAIN, "M-B", 0, do_linter, 0);
#ifdef ENABLE_SPELLER
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
#endif
#endif
add_to_sclist(MMAIN, "^C", 0, do_cursorpos_void, 0);
add_to_sclist(MMAIN, "^_", 0, do_gotolinecolumn_void, 0);
@@ -1502,6 +1518,10 @@ keystruct *strtosc(const char *input)
#ifdef ENABLE_COLOR
else if (!strcasecmp(input, "linter"))
s->func = do_linter;
#ifdef ENABLE_SPELLER
else if (!strcasecmp(input, "formatter"))
s->func = do_formatter;
#endif
#endif
else if (!strcasecmp(input, "curpos"))
s->func = do_cursorpos_void;

View File

@@ -22,11 +22,11 @@
#include "proto.h"
#ifdef ENABLE_HELP
#include <errno.h>
#include <string.h>
#ifdef ENABLE_HELP
static char *help_text = NULL;
/* The text displayed in the help window. */
@@ -64,7 +64,7 @@ void wrap_help_text_into_buffer(void)
do {
openfile->current->next = make_new_node(openfile->current);
openfile->current = openfile->current->next;
openfile->current->data = mallocstrcpy(NULL, "");
openfile->current->data = copy_of("");
} while (*(++ptr) == '\n');
}
@@ -103,7 +103,7 @@ void do_help(void)
#ifdef ENABLE_COLOR
char *was_syntax = syntaxstr;
#endif
char *saved_answer = (answer != NULL) ? strdup(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. */
@@ -150,8 +150,7 @@ void do_help(void)
/* Extract the title from the head of the help text. */
length = break_line(help_text, MAX_BUF_SIZE, TRUE);
title = charalloc(length * sizeof(char) + 1);
strncpy(title, help_text, length);
title = measured_copy(help_text, length + 1);
title[length] = '\0';
titlebar(title);
@@ -247,7 +246,6 @@ void do_help(void)
inhelp = FALSE;
curs_set(0);
refresh_needed = TRUE;
if (ISSET(NO_HELP)) {
currmenu = oldmenu;
@@ -262,7 +260,10 @@ void do_help(void)
browser_refresh();
else
#endif
{
titlebar(NULL);
edit_refresh();
}
}
/* Allocate space for the help text for the current menu, and concatenate
@@ -547,7 +548,6 @@ functionptrtype parse_help_input(int *kbinput)
{
if (!meta_key) {
switch (*kbinput) {
case BS_CODE:
case '-':
return do_page_up;
case ' ':

View File

@@ -21,11 +21,11 @@
#include "proto.h"
#ifdef ENABLE_HISTORIES
#include <errno.h>
#include <string.h>
#ifdef ENABLE_HISTORIES
#ifndef SEARCH_HISTORY
#define SEARCH_HISTORY "search_history"
#endif
@@ -48,17 +48,17 @@ static poshiststruct *position_history = NULL;
void history_init(void)
{
search_history = make_new_node(NULL);
search_history->data = mallocstrcpy(NULL, "");
search_history->data = copy_of("");
searchtop = search_history;
searchbot = search_history;
replace_history = make_new_node(NULL);
replace_history->data = mallocstrcpy(NULL, "");
replace_history->data = copy_of("");
replacetop = replace_history;
replacebot = replace_history;
execute_history = make_new_node(NULL);
execute_history->data = mallocstrcpy(NULL, "");
execute_history->data = copy_of("");
executetop = execute_history;
executebot = execute_history;
}
@@ -136,7 +136,7 @@ void update_history(linestruct **item, const char *text)
(*hbot)->data = mallocstrcpy((*hbot)->data, text);
splice_node(*hbot, make_new_node(*hbot));
*hbot = (*hbot)->next;
(*hbot)->data = mallocstrcpy(NULL, "");
(*hbot)->data = copy_of("");
/* Indicate that the history needs to be saved on exit. */
history_changed = TRUE;
@@ -229,19 +229,6 @@ char *get_history_completion(linestruct **h, char *s, size_t len)
}
#endif /* ENABLE_TABCOMP */
void history_error(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, _(msg), ap);
va_end(ap);
fprintf(stderr, _("\nPress Enter to continue\n"));
while (getchar() != '\n')
;
}
/* Check whether we have or could make a directory for history files. */
bool have_statedir(void)
{
@@ -280,14 +267,14 @@ bool have_statedir(void)
free(statepath);
}
if (mkdir(statedir, S_IRWXU) == -1) {
history_error(N_("Unable to create directory %s: %s\n"
jot_error(N_("Unable to create directory %s: %s\n"
"It is required for saving/loading "
"search history or cursor positions.\n"),
statedir, strerror(errno));
return FALSE;
}
} else if (!S_ISDIR(dirstat.st_mode)) {
history_error(N_("Path %s is not a directory and needs to be.\n"
jot_error(N_("Path %s is not a directory and needs to be.\n"
"Nano will be unable to load or save "
"search history or cursor positions.\n"),
statedir);
@@ -308,7 +295,7 @@ void load_history(void)
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(HISTORYLOG);
history_error(N_("Error reading %s: %s"), histname,
jot_error(N_("Error reading %s: %s"), histname,
strerror(errno));
}
} else {
@@ -404,7 +391,7 @@ void load_poshistory(void)
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(POSITIONLOG);
history_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
jot_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
}
} else {
char *line = NULL, *lineptr, *xptr;
@@ -414,7 +401,7 @@ void load_poshistory(void)
/* Read and parse each line, and store the extracted data. */
while ((read = getline(&line, &buf_len, hisfile)) > 5) {
/* Decode nulls as embedded newlines. */
/* Decode NULs as embedded newlines. */
unsunder(line, read);
/* Find where the x index and line number are in the line. */
@@ -431,7 +418,7 @@ void load_poshistory(void)
/* Create a new position record. */
newrecord = (poshiststruct *)nmalloc(sizeof(poshiststruct));
newrecord->filename = mallocstrcpy(NULL, line);
newrecord->filename = copy_of(line);
newrecord->lineno = atoi(lineptr);
newrecord->xno = atoi(xptr);
newrecord->next = NULL;
@@ -484,7 +471,7 @@ void save_poshistory(void)
posptr->filename, posptr->lineno, posptr->xno);
length = strlen(path_and_place);
/* Encode newlines in filenames as nulls. */
/* Encode newlines in filenames as NULs. */
sunder(path_and_place);
/* Restore the terminating newline. */
path_and_place[length - 1] = '\n';
@@ -563,7 +550,7 @@ void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos)
* not at the end, move the matching one to the end. */
if (theone == NULL) {
theone = (poshiststruct *)nmalloc(sizeof(poshiststruct));
theone->filename = mallocstrcpy(NULL, fullpath);
theone->filename = copy_of(fullpath);
if (position_history == NULL)
position_history = theone;
else

View File

@@ -100,7 +100,7 @@ linestruct *copy_node(const linestruct *src)
{
linestruct *dst = nmalloc(sizeof(linestruct));
dst->data = mallocstrcpy(NULL, src->data);
dst->data = copy_of(src->data);
dst->next = src->next;
dst->prev = src->prev;
dst->lineno = src->lineno;
@@ -127,33 +127,33 @@ void splice_node(linestruct *afterthis, linestruct *newnode)
}
/* Disconnect a node from a linked list of linestructs and delete it. */
void unlink_node(linestruct *fileptr)
void unlink_node(linestruct *line)
{
if (fileptr->prev != NULL)
fileptr->prev->next = fileptr->next;
if (fileptr->next != NULL)
fileptr->next->prev = fileptr->prev;
if (line->prev != NULL)
line->prev->next = line->next;
if (line->next != NULL)
line->next->prev = line->prev;
/* Update filebot when removing a node at the end of file. */
if (openfile && openfile->filebot == fileptr)
openfile->filebot = fileptr->prev;
if (openfile && openfile->filebot == line)
openfile->filebot = line->prev;
delete_node(fileptr);
delete_node(line);
}
/* Free the data structures in the given node. */
void delete_node(linestruct *fileptr)
void delete_node(linestruct *line)
{
#ifdef ENABLE_WRAPPING
/* If the spill-over line for hard-wrapping is deleted... */
if (fileptr == openfile->spillage_line)
if (line == openfile->spillage_line)
openfile->spillage_line = NULL;
#endif
free(fileptr->data);
free(line->data);
#ifdef ENABLE_COLOR
free(fileptr->multidata);
free(line->multidata);
#endif
free(fileptr);
free(line);
}
/* Duplicate an entire linked list of linestructs. */
@@ -226,14 +226,14 @@ void partition_buffer(linestruct *top, size_t top_x,
* top of the partition from it, and save the text before top_x. */
foreline = top->prev;
top->prev = NULL;
antedata = mallocstrncpy(NULL, top->data, top_x + 1);
antedata = measured_copy(top->data, top_x + 1);
antedata[top_x] = '\0';
/* Remember which line is below the bottom of the partition, detach the
* bottom of the partition from it, and save the text after bot_x. */
hindline = bot->next;
bot->next = NULL;
postdata = mallocstrcpy(NULL, bot->data + bot_x);
postdata = copy_of(bot->data + bot_x);
/* At the end of the partition, remove all text after bot_x. */
bot->data[bot_x] = '\0';
@@ -342,7 +342,7 @@ void extract(linestruct *top, size_t top_x, linestruct *bot, size_t bot_x)
/* Since the text has now been saved, remove it from the file buffer. */
openfile->filetop = make_new_node(NULL);
openfile->filetop->data = mallocstrcpy(NULL, "");
openfile->filetop->data = copy_of("");
openfile->filebot = openfile->filetop;
/* Restore the current line and cursor position. If the mark begins
@@ -463,11 +463,15 @@ void print_view_warning(void)
statusbar(_("Key is invalid in view mode"));
}
/* Indicate that something is disabled in restricted mode. */
void show_restricted_warning(void)
/* When in restricted mode, show a warning and return TRUE. */
bool in_restricted_mode(void)
{
statusbar(_("This function is disabled in restricted mode"));
beep();
if (ISSET(RESTRICTED)) {
statusbar(_("This function is disabled in restricted mode"));
beep();
return TRUE;
} else
return FALSE;
}
#ifndef ENABLE_HELP
@@ -500,7 +504,7 @@ void finish(void)
/* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &original_state);
#ifdef ENABLE_NANORC
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
display_rcfile_errors();
#endif
@@ -1340,10 +1344,8 @@ void do_toggle(int flag)
{
bool enabled;
if (flag == SUSPEND && ISSET(RESTRICTED)) {
show_restricted_warning();
if (flag == SUSPEND && in_restricted_mode())
return;
}
TOGGLE(flag);
focusing = FALSE;
@@ -1811,7 +1813,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
output[i] = '\n';
/* Get the next multibyte character. */
charlen = parse_mbchar(output + i, onechar, NULL);
charlen = collect_char(output + i, onechar);
i += charlen;
@@ -1837,7 +1839,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
if (openfile->last_action != ADD ||
openfile->current_undo->mark_begin_lineno != openfile->current->lineno ||
openfile->current_undo->mark_begin_x != openfile->current_x)
add_undo(ADD);
add_undo(ADD, NULL);
/* Note that current_x has not yet been incremented. */
if (openfile->current == openfile->mark &&
@@ -2442,11 +2444,11 @@ int main(int argc, char **argv)
#ifdef ENABLE_JUSTIFY
/* Set the default value for things that weren't specified. */
if (punct == NULL)
punct = mallocstrcpy(NULL, "!.?");
punct = copy_of("!.?");
if (brackets == NULL)
brackets = mallocstrcpy(NULL, "\"')>]}");
brackets = copy_of("\"')>]}");
if (quotestr == NULL)
quotestr = mallocstrcpy(NULL, "^([ \t]*([!#%:;>|}]|/{2}))+");
quotestr = copy_of("^([ \t]*([!#%:;>|}]|/{2}))+");
/* Compile the quoting regex, and exit when it's invalid. */
quoterc = regcomp(&quotereg, quotestr, NANO_REG_EXTENDED);
@@ -2470,14 +2472,14 @@ int main(int argc, char **argv)
const char *spellenv = getenv("SPELL");
if (spellenv != NULL)
alt_speller = mallocstrcpy(NULL, spellenv);
alt_speller = copy_of(spellenv);
}
#endif
#ifndef NANO_TINY
/* If matchbrackets wasn't specified, set its default value. */
if (matchbrackets == NULL)
matchbrackets = mallocstrcpy(NULL, "(<[{)>]}");
matchbrackets = copy_of("(<[{)>]}");
/* If the whitespace option wasn't specified, set its default value. */
if (whitespace == NULL) {
@@ -2485,13 +2487,13 @@ int main(int argc, char **argv)
if (using_utf8()) {
/* A tab is shown as a Right-Pointing Double Angle Quotation Mark
* (U+00BB), and a space as a Middle Dot (U+00B7). */
whitespace = mallocstrcpy(NULL, "\xC2\xBB\xC2\xB7");
whitespace = copy_of("\xC2\xBB\xC2\xB7");
whitelen[0] = 2;
whitelen[1] = 2;
} else
#endif
{
whitespace = mallocstrcpy(NULL, ">.");
whitespace = copy_of(">.");
whitelen[0] = 1;
whitelen[1] = 1;
}
@@ -2499,7 +2501,7 @@ int main(int argc, char **argv)
#endif /* !NANO_TINY */
/* Initialize the search string. */
last_search = mallocstrcpy(NULL, "");
last_search = copy_of("");
UNSET(BACKWARDS_SEARCH);
/* If tabsize wasn't specified, set its default value. */
@@ -2607,7 +2609,7 @@ int main(int argc, char **argv)
if (argv[optind][n] == '/' || argv[optind][n] == '?') {
if (argv[optind][n + 1]) {
searchstring = mallocstrcpy(NULL, &argv[optind][n + 1]);
searchstring = copy_of(&argv[optind][n + 1]);
if (argv[optind][n] == '?')
SET(BACKWARDS_SEARCH);
} else if (n == 1)
@@ -2683,8 +2685,8 @@ int main(int argc, char **argv)
prepare_for_display();
#ifdef ENABLE_NANORC
if (rcfile_with_errors != NULL)
statusline(ALERT, _("Mistakes in '%s'"), rcfile_with_errors);
if (startup_problem != NULL)
statusline(ALERT, startup_problem);
#endif
#ifdef ENABLE_HELP

View File

@@ -19,9 +19,6 @@
* *
**************************************************************************/
#ifndef NANO_H
#define NANO_H 1
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -234,6 +231,8 @@ typedef struct syntaxtype {
/* The list of libmagic results that this syntax applies to. */
char *linter;
/* The command with which to lint this type of file. */
char *formatter;
/* The command with which to format/modify/arrange this type of file. */
char *tab;
/* What the Tab key should produce; NULL for default behavior. */
#ifdef ENABLE_COMMENT
@@ -650,5 +649,3 @@ enum
/* The largest size_t number that doesn't have the high bit set. */
#define HIGHEST_POSITIVE ((~(size_t)0) >> 1)
#endif /* !NANO_H */

View File

@@ -203,7 +203,7 @@ void do_statusbar_output(int *the_input, size_t input_len,
output[j] = '\n';
/* Interpret the next multibyte character. */
charlen = parse_mbchar(output + j, onechar, NULL);
charlen = collect_char(output + j, onechar);
j += charlen;
@@ -581,10 +581,10 @@ functionptrtype acquire_an_answer(int *actual, bool allow_tabs,
*
* The allow_tabs parameter indicates whether tab completion is allowed,
* and allow_files indicates whether all files (and not just directories)
* can be tab completed. The curranswer parameter is the default answer
* can be tab completed. The 'provided' parameter is the default answer
* for when simply Enter is typed. */
int do_prompt(bool allow_tabs, bool allow_files,
int menu, const char *curranswer, linestruct **history_list,
int menu, const char *provided, linestruct **history_list,
void (*refresh_func)(void), const char *msg, ...)
{
va_list ap;
@@ -597,8 +597,8 @@ int do_prompt(bool allow_tabs, bool allow_files,
bottombars(menu);
if (answer != curranswer || answer == NULL)
answer = mallocstrcpy(answer, curranswer);
if (answer != provided)
answer = mallocstrcpy(answer, provided);
#ifndef NANO_TINY
redo_theprompt:

View File

@@ -18,9 +18,6 @@
* *
**************************************************************************/
#ifndef PROTO_H
#define PROTO_H 1
#include "nano.h"
/* All external variables. See global.c for their descriptions. */
@@ -176,8 +173,8 @@ extern int interface_color_pair[NUMBER_OF_ELEMENTS];
extern char *homedir;
extern char *statedir;
#ifdef ENABLE_NANORC
extern char *rcfile_with_errors;
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
extern char *startup_problem;
#endif
extern bool spotlighted;
@@ -219,7 +216,8 @@ int mbwidth(const char *c);
char *make_mbchar(long chr, int *chr_mb_len);
int char_length(const char *pointer);
size_t mbstrlen(const char *s);
int parse_mbchar(const char *buf, char *chr, size_t *col);
int collect_char(const char *buf, char *chr);
int advance_over(const char *string, size_t *column);
size_t step_left(const char *buf, size_t pos);
size_t step_right(const char *buf, size_t pos);
int mbstrcasecmp(const char *s1, const char *s2);
@@ -276,7 +274,8 @@ void make_new_buffer(void);
void set_modified(void);
bool open_buffer(const char *filename, bool new_buffer);
#ifdef ENABLE_SPELLER
bool replace_buffer(const char *filename, undo_type action, bool marked);
bool replace_buffer(const char *filename, undo_type action, bool marked,
const char *operation);
#endif
void prepare_for_display(void);
#ifdef ENABLE_MULTIBUFFER
@@ -408,7 +407,7 @@ void extract(linestruct *top, size_t top_x, linestruct *bot, size_t bot_x);
void ingraft_buffer(linestruct *somebuffer);
void copy_from_buffer(linestruct *somebuffer);
void print_view_warning(void);
void show_restricted_warning(void);
bool in_restricted_mode(void);
#ifndef ENABLE_HELP
void say_there_is_no_help(void);
#endif
@@ -471,8 +470,11 @@ int do_prompt(bool allow_tabs, bool allow_files,
int do_yesno_prompt(bool all, const char *msg);
/* Most functions in rcfile.c. */
#ifdef ENABLE_NANORC
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
void display_rcfile_errors(void);
void jot_error(const char *msg, ...);
#endif
#ifdef ENABLE_NANORC
#ifdef ENABLE_COLOR
void parse_one_include(char *file, syntaxtype *syntax);
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
@@ -525,7 +527,7 @@ void do_enter(void);
RETSIGTYPE cancel_command(int signal);
bool execute_command(const char *command);
void discard_until(const undostruct *thisitem, openfilestruct *thefile, bool keep);
void add_undo(undo_type action);
void add_undo(undo_type action, const char *message);
void update_multiline_undo(ssize_t lineno, char *indentation);
void update_undo(undo_type action);
#endif /* !NANO_TINY */
@@ -551,6 +553,7 @@ void do_spell(void);
#endif
#ifdef ENABLE_COLOR
void do_linter(void);
void do_formatter(void);
#endif
#ifndef NANO_TINY
void do_wordlinechar_count(void);
@@ -567,8 +570,8 @@ int digits(ssize_t n);
#endif
bool parse_num(const char *str, ssize_t *val);
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column);
void unsunder(char *str, size_t true_len);
void sunder(char *str);
void unsunder(char *string, size_t length);
void sunder(char *string);
#if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
void free_chararray(char **array, size_t len);
#endif
@@ -579,8 +582,9 @@ 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 *mallocstrncpy(char *dest, const char *src, size_t n);
char *measured_copy(const char *src, size_t n);
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 xplustabs(void);
@@ -629,9 +633,9 @@ void check_statusblank(void);
char *display_string(const char *buf, size_t column, size_t span,
bool isdata, bool isprompt);
void titlebar(const char *path);
void statusline(message_type importance, const char *msg, ...);
void statusbar(const char *msg);
void warn_and_shortly_pause(const char *msg);
void statusline(message_type importance, const char *msg, ...);
void bottombars(int menu);
void post_one_key(const char *keystroke, const char *tag, int width);
void place_the_cursor(void);
@@ -698,5 +702,3 @@ void flip_newbuffer(void);
#endif
void discard_buffer(void);
void do_cancel(void);
#endif /* !PROTO_H */

View File

@@ -23,14 +23,14 @@
#include "proto.h"
#ifdef ENABLE_NANORC
#include <ctype.h>
#include <errno.h>
#include <glob.h>
#include <string.h>
#include <unistd.h>
#ifdef ENABLE_NANORC
#ifndef RCFILE_NAME
#define HOME_RC_NAME ".nanorc"
#define RCFILE_NAME "nanorc"
@@ -67,7 +67,7 @@ static const rcoption rcopts[] = {
#endif
{"nohelp", NO_HELP},
{"nonewlines", NO_NEWLINES},
{"nopauses", NO_PAUSES},
{"nopauses", NO_PAUSES}, /* Obsolete; remove in 2021. */
#ifdef ENABLE_WRAPPING
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2021. */
#endif
@@ -146,7 +146,9 @@ static bool seen_color_command = FALSE;
static colortype *lastcolor = NULL;
/* The end of the color list for the current syntax. */
#endif
#endif /* ENABLE_NANORC */
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
static linestruct *errors_head = NULL;
static linestruct *errors_tail = NULL;
/* Beginning and end of a list of errors in rcfiles, if any. */
@@ -174,13 +176,20 @@ void jot_error(const char *msg, ...)
errors_tail->next = error;
errors_tail = error;
if (rcfile_with_errors == NULL)
rcfile_with_errors = strdup(nanorc);
if (startup_problem == NULL) {
#ifdef ENABLE_NANORC
if (nanorc != NULL) {
snprintf(textbuf, MAXSIZE, _("Mistakes in '%s'"), nanorc);
startup_problem = copy_of(textbuf);
} else
#endif
startup_problem = copy_of(_("Problems with history file"));
}
#ifdef ENABLE_NANORC
if (lineno > 0)
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);
va_end(ap);
@@ -188,7 +197,9 @@ void jot_error(const char *msg, ...)
error->data = nmalloc(length + 1);
sprintf(error->data, "%s", textbuf);
}
#endif /* ENABLE_NANORC || ENABLE_HISTORIES */
#ifdef ENABLE_NANORC
/* 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. */
@@ -325,17 +336,18 @@ void begin_new_syntax(char *ptr)
/* Initialize a new syntax struct. */
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
live_syntax->name = mallocstrcpy(NULL, nameptr);
live_syntax->filename = strdup(nanorc);
live_syntax->name = copy_of(nameptr);
live_syntax->filename = copy_of(nanorc);
live_syntax->lineno = lineno;
live_syntax->augmentations = NULL;
live_syntax->extensions = NULL;
live_syntax->headers = NULL;
live_syntax->magics = NULL;
live_syntax->linter = NULL;
live_syntax->formatter = NULL;
live_syntax->tab = NULL;
#ifdef ENABLE_COMMENT
live_syntax->comment = mallocstrcpy(NULL, GENERAL_COMMENT_CHARACTER);
live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER);
#endif
live_syntax->color = NULL;
live_syntax->nmultis = 0;
@@ -405,7 +417,7 @@ void parse_binding(char *ptr, bool dobind)
keyptr = ptr;
ptr = parse_next_word(ptr);
keycopy = mallocstrcpy(NULL, keyptr);
keycopy = copy_of(keyptr);
if (strlen(keycopy) < 2) {
jot_error(N_("Key name is too short"));
@@ -463,7 +475,7 @@ void parse_binding(char *ptr, bool dobind)
if (*funcptr == '"') {
newsc = nmalloc(sizeof(keystruct));
newsc->func = (functionptrtype)implant;
newsc->expansion = mallocstrcpy(NULL, funcptr + 1);
newsc->expansion = copy_of(funcptr + 1);
#ifndef NANO_TINY
newsc->toggle = 0;
#endif
@@ -501,13 +513,12 @@ void parse_binding(char *ptr, bool dobind)
if (newsc->func == do_toggle_void)
mask = MMAIN;
#endif
#ifdef ENABLE_NANORC
/* Handle the special case of a key defined as a string. */
if (newsc->func == (functionptrtype)implant)
mask = MMOST | MHELP;
#endif
mask = MMOST|MBROWSER|MHELP;
/* Now limit the given menu to those where the function exists. */
menu = menu & (is_universal(newsc->func) ? MMOST : mask);
menu = menu & (is_universal(newsc->func) ? (MMOST|MBROWSER) : mask);
if (!menu) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
@@ -900,7 +911,7 @@ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
/* Copy the regex into a struct, and hook this in at the end. */
newthing = (regexlisttype *)nmalloc(sizeof(regexlisttype));
newthing->full_regex = mallocstrcpy(NULL, regexstring);
newthing->full_regex = copy_of(regexstring);
newthing->next = NULL;
if (lastthing == NULL)
@@ -955,6 +966,8 @@ bool parse_syntax_commands(char *keyword, char *ptr)
#endif
} else if (strcasecmp(keyword, "linter") == 0)
pick_up_name("linter", ptr, &live_syntax->linter);
else if (strcasecmp(keyword, "formatter") == 0)
pick_up_name("formatter", ptr, &live_syntax->formatter);
else
return FALSE;
@@ -1000,7 +1013,10 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
size_t size = 0;
while ((len = getline(&buffer, &size, rcstream)) > 0) {
char *ptr, *keyword, *option;
char *ptr, *keyword, *option, *argument;
#ifdef ENABLE_COLOR
bool drop_open = FALSE;
#endif
int set = 0;
size_t i;
@@ -1047,23 +1063,35 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
continue;
}
newitem = nmalloc(sizeof(augmentstruct));;
keyword = ptr;
argument = copy_of(ptr);
ptr = parse_next_word(ptr);
/* Store the content of an 'extendsyntax', for later parsing. */
newitem->filename = strdup(nanorc);
newitem->lineno = lineno;
newitem->data = strdup(ptr);
newitem->next = NULL;
/* File-matching commands need to be processed immediately;
* other commands are stored for possible later processing. */
if (strcmp(keyword, "header") == 0 || strcmp(keyword, "magic") == 0) {
free(argument);
live_syntax = sint;
opensyntax = TRUE;
drop_open = TRUE;
} else {
newitem = nmalloc(sizeof(augmentstruct));;
if (sint->augmentations != NULL) {
extra = sint->augmentations;
while (extra->next != NULL)
extra = extra->next;
extra->next = newitem;
} else
sint->augmentations = newitem;
newitem->filename = copy_of(nanorc);
newitem->lineno = lineno;
newitem->data = argument;
newitem->next = NULL;
continue;
if (sint->augmentations != NULL) {
extra = sint->augmentations;
while (extra->next != NULL)
extra = extra->next;
extra->next = newitem;
} else
sint->augmentations = newitem;
continue;
}
}
/* Try to parse the keyword. */
@@ -1096,7 +1124,8 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
strcasecmp(keyword, "icolor") == 0 ||
strcasecmp(keyword, "comment") == 0 ||
strcasecmp(keyword, "tabgives") == 0 ||
strcasecmp(keyword, "linter") == 0)) {
strcasecmp(keyword, "linter") == 0 ||
strcasecmp(keyword, "formatter") == 0)) {
if (!opensyntax)
jot_error(N_("A '%s' command requires a preceding "
"'syntax' command"), keyword);
@@ -1120,6 +1149,10 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
else if (intros_only)
jot_error(N_("Command \"%s\" not understood"), keyword);
#ifdef ENABLE_COLOR
if (drop_open)
opensyntax = FALSE;
#endif
if (set == 0)
continue;
@@ -1155,125 +1188,125 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
/* An option that takes an argument cannot be unset. */
if (set == -1) {
jot_error(N_("Cannot unset option \"%s\""), rcopts[i].name);
jot_error(N_("Cannot unset option \"%s\""), option);
continue;
}
if (*ptr == '\0') {
jot_error(N_("Option \"%s\" requires an argument"), rcopts[i].name);
jot_error(N_("Option \"%s\" requires an argument"), option);
continue;
}
option = ptr;
if (*option == '"')
option++;
argument = ptr;
if (*argument == '"')
argument++;
ptr = parse_argument(ptr);
#ifdef ENABLE_UTF8
/* When in a UTF-8 locale, ignore arguments with invalid sequences. */
if (using_utf8() && mbstowcs(NULL, option, 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
option = mallocstrcpy(NULL, option);
argument = copy_of(argument);
#ifdef ENABLE_COLOR
if (strcasecmp(rcopts[i].name, "titlecolor") == 0)
color_combo[TITLE_BAR] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "numbercolor") == 0)
color_combo[LINE_NUMBER] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "stripecolor") == 0)
color_combo[GUIDE_STRIPE] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "selectedcolor") == 0)
color_combo[SELECTED_TEXT] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "statuscolor") == 0)
color_combo[STATUS_BAR] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "errorcolor") == 0)
color_combo[ERROR_MESSAGE] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "keycolor") == 0)
color_combo[KEY_COMBO] = parse_interface_color(option);
else if (strcasecmp(rcopts[i].name, "functioncolor") == 0)
color_combo[FUNCTION_TAG] = parse_interface_color(option);
if (strcasecmp(option, "titlecolor") == 0)
color_combo[TITLE_BAR] = parse_interface_color(argument);
else if (strcasecmp(option, "numbercolor") == 0)
color_combo[LINE_NUMBER] = parse_interface_color(argument);
else if (strcasecmp(option, "stripecolor") == 0)
color_combo[GUIDE_STRIPE] = parse_interface_color(argument);
else if (strcasecmp(option, "selectedcolor") == 0)
color_combo[SELECTED_TEXT] = parse_interface_color(argument);
else if (strcasecmp(option, "statuscolor") == 0)
color_combo[STATUS_BAR] = parse_interface_color(argument);
else if (strcasecmp(option, "errorcolor") == 0)
color_combo[ERROR_MESSAGE] = parse_interface_color(argument);
else if (strcasecmp(option, "keycolor") == 0)
color_combo[KEY_COMBO] = parse_interface_color(argument);
else if (strcasecmp(option, "functioncolor") == 0)
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
else
#endif
#ifdef ENABLE_OPERATINGDIR
if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
operating_dir = option;
if (strcasecmp(option, "operatingdir") == 0)
operating_dir = argument;
else
#endif
#ifdef ENABLED_WRAPORJUSTIFY
if (strcasecmp(rcopts[i].name, "fill") == 0) {
if (!parse_num(option, &fill)) {
jot_error(N_("Requested fill size \"%s\" is invalid"), option);
if (strcasecmp(option, "fill") == 0) {
if (!parse_num(argument, &fill)) {
jot_error(N_("Requested fill size \"%s\" is invalid"), argument);
fill = -COLUMNS_FROM_EOL;
}
free(option);
free(argument);
} else
#endif
#ifndef NANO_TINY
if (strcasecmp(rcopts[i].name, "guidestripe") == 0) {
if (!parse_num(option, &stripe_column) || stripe_column <= 0) {
jot_error(N_("Guide column \"%s\" is invalid"), option);
if (strcasecmp(option, "guidestripe") == 0) {
if (!parse_num(argument, &stripe_column) || stripe_column <= 0) {
jot_error(N_("Guide column \"%s\" is invalid"), argument);
stripe_column = 0;
}
free(option);
} else if (strcasecmp(rcopts[i].name, "matchbrackets") == 0) {
if (has_blank_char(option)) {
free(argument);
} else if (strcasecmp(option, "matchbrackets") == 0) {
if (has_blank_char(argument)) {
jot_error(N_("Non-blank characters required"));
free(option);
} else if (mbstrlen(option) % 2 != 0) {
free(argument);
} else if (mbstrlen(argument) % 2 != 0) {
jot_error(N_("Even number of characters required"));
free(option);
free(argument);
} else
matchbrackets = option;
} else if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
if (mbstrlen(option) != 2 || breadth(option) != 2) {
matchbrackets = argument;
} else if (strcasecmp(option, "whitespace") == 0) {
if (mbstrlen(argument) != 2 || breadth(argument) != 2) {
jot_error(N_("Two single-column characters required"));
free(option);
free(argument);
} else {
whitespace = option;
whitespace = argument;
whitelen[0] = char_length(whitespace);
whitelen[1] = char_length(whitespace + whitelen[0]);
}
} else
#endif
#ifdef ENABLE_JUSTIFY
if (strcasecmp(rcopts[i].name, "punct") == 0) {
if (has_blank_char(option)) {
if (strcasecmp(option, "punct") == 0) {
if (has_blank_char(argument)) {
jot_error(N_("Non-blank characters required"));
free(option);
free(argument);
} else
punct = option;
} else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
if (has_blank_char(option)) {
punct = argument;
} else if (strcasecmp(option, "brackets") == 0) {
if (has_blank_char(argument)) {
jot_error(N_("Non-blank characters required"));
free(option);
free(argument);
} else
brackets = option;
} else if (strcasecmp(rcopts[i].name, "quotestr") == 0)
quotestr = option;
brackets = argument;
} else if (strcasecmp(option, "quotestr") == 0)
quotestr = argument;
else
#endif
#ifndef NANO_TINY
if (strcasecmp(rcopts[i].name, "backupdir") == 0)
backup_dir = option;
if (strcasecmp(option, "backupdir") == 0)
backup_dir = argument;
else
if (strcasecmp(rcopts[i].name, "wordchars") == 0)
word_chars = option;
if (strcasecmp(option, "wordchars") == 0)
word_chars = argument;
else
#endif
#ifdef ENABLE_SPELLER
if (strcasecmp(rcopts[i].name, "speller") == 0)
alt_speller = option;
if (strcasecmp(option, "speller") == 0)
alt_speller = argument;
else
#endif
if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
if (!parse_num(option, &tabsize) || tabsize <= 0) {
jot_error(N_("Requested tab size \"%s\" is invalid"), option);
if (strcasecmp(option, "tabsize") == 0) {
if (!parse_num(argument, &tabsize) || tabsize <= 0) {
jot_error(N_("Requested tab size \"%s\" is invalid"), argument);
tabsize = -1;
}
free(option);
free(argument);
}
}
@@ -1336,6 +1369,7 @@ void do_rcfiles(void)
check_vitals_mapped();
free(nanorc);
nanorc = NULL;
}
#endif /* ENABLE_NANORC */

View File

@@ -76,7 +76,7 @@ void search_init(bool replacing, bool keep_the_answer)
/* When starting a new search, clear the current answer. */
if (!keep_the_answer)
answer = mallocstrcpy(answer, NULL);
answer = mallocstrcpy(answer, "");
/* If something was searched for earlier, include it in the prompt. */
if (*last_search != '\0') {
@@ -88,7 +88,7 @@ void search_init(bool replacing, bool keep_the_answer)
(breadth(last_search) > COLS / 3) ? "..." : "");
free(disp);
} else
thedefault = mallocstrcpy(NULL, "");
thedefault = copy_of("");
while (TRUE) {
functionptrtype func;
@@ -598,7 +598,7 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
size_t length_change;
#ifndef NANO_TINY
add_undo(REPLACE);
add_undo(REPLACE, NULL);
#endif
copy = replace_line(needle);
@@ -699,7 +699,7 @@ void ask_for_replacement(void)
linestruct *edittop_save, *begin;
size_t firstcolumn_save, begin_x;
ssize_t numreplaced;
int response = do_prompt(FALSE, FALSE, MREPLACEWITH, NULL,
int response = do_prompt(FALSE, FALSE, MREPLACEWITH, "",
/* TRANSLATORS: This is a prompt. */
&replace_history, edit_refresh, _("Replace with"));
@@ -758,7 +758,7 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
if (interactive) {
/* Ask for the line and column. */
int response = do_prompt(FALSE, FALSE, MGOTOLINE,
use_answer ? answer : NULL, NULL, edit_refresh,
use_answer ? answer : "", NULL, edit_refresh,
/* TRANSLATORS: This is a prompt. */
_("Enter line number, column number"));

View File

@@ -59,19 +59,6 @@ void do_mark(void)
}
#endif /* !NANO_TINY */
#if defined(ENABLE_COLOR) || defined(ENABLE_SPELLER)
/* Return an error message about invoking the given name. The message
* should not be freed; this leak is not worth the trouble avoiding. */
const char *invocation_error(const char *name)
{
char *message, *invoke_error = _("Error invoking \"%s\"");
message = charalloc(strlen(invoke_error) + strlen(name) + 1);
sprintf(message, invoke_error, name);
return message;
}
#endif
/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
* of spaces that a tab would normally take up. */
void do_tab(void)
@@ -159,7 +146,7 @@ void do_indent(void)
indentation[1] = '\0';
}
add_undo(INDENT);
add_undo(INDENT, NULL);
/* Go through each of the lines, adding an indent to the non-empty ones,
* and recording whatever was added in the undo item. */
@@ -264,13 +251,13 @@ void do_unindent(void)
if (top == bot->next)
return;
add_undo(UNINDENT);
add_undo(UNINDENT, NULL);
/* Go through each of the lines, removing their leading indent where
* possible, and saving the removed whitespace in the undo item. */
for (line = top; line != bot->next; line = line->next) {
size_t indent_len = length_of_white(line->data);
char *indentation = mallocstrncpy(NULL, line->data, indent_len + 1);
char *indentation = measured_copy(line->data, indent_len + 1);
indentation[indent_len] = '\0';
@@ -424,11 +411,11 @@ void do_comment(void)
/* If all selected lines are blank, we comment them. */
action = all_empty ? COMMENT : action;
add_undo(action);
add_undo(action, NULL);
/* Store the comment sequence used for the operation, because it could
* change when the file name changes; we need to know what it was. */
openfile->current_undo->strdata = mallocstrcpy(NULL, comment_seq);
openfile->current_undo->strdata = copy_of(comment_seq);
/* Comment/uncomment each of the selected lines when possible, and
* store undo data when a line changed. */
@@ -586,8 +573,8 @@ void do_undo(void)
break;
}
t = make_new_node(f);
t->data = mallocstrcpy(NULL, u->strdata);
data = mallocstrncpy(NULL, f->data, u->mark_begin_x + 1);
t->data = copy_of(u->strdata);
data = measured_copy(f->data, u->mark_begin_x + 1);
data[u->mark_begin_x] = '\0';
free(f->data);
f->data = data;
@@ -609,6 +596,7 @@ void do_undo(void)
while (openfile->current_undo->type != SPLIT_BEGIN)
do_undo();
u = openfile->current_undo;
/* Fall-through. */
case SPLIT_BEGIN:
undidmsg = _("addition");
break;
@@ -642,6 +630,8 @@ void do_undo(void)
case COUPLE_BEGIN:
undidmsg = u->strdata;
goto_line_posx(u->lineno, u->begin);
openfile->current_y = u->mark_begin_lineno;
adjust_viewport(STATIONARY);
break;
case COUPLE_END:
openfile->current_undo = openfile->current_undo->next;
@@ -724,8 +714,8 @@ void do_redo(void)
case ENTER:
redidmsg = _("line break");
shoveline = make_new_node(f);
shoveline->data = mallocstrcpy(NULL, u->strdata);
data = mallocstrncpy(NULL, f->data, u->begin + 1);
shoveline->data = copy_of(u->strdata);
data = measured_copy(f->data, u->begin + 1);
data[u->begin] = '\0';
free(f->data);
f->data = data;
@@ -773,6 +763,7 @@ void do_redo(void)
do_redo();
u = openfile->current_undo;
goto_line_posx(u->lineno, u->begin);
/* Fall-through. */
case SPLIT_END:
redidmsg = _("addition");
break;
@@ -806,6 +797,7 @@ void do_redo(void)
case COUPLE_END:
redidmsg = u->strdata;
goto_line_posx(u->lineno, u->begin);
adjust_viewport(STATIONARY);
break;
case INDENT:
handle_indent_action(u, FALSE, TRUE);
@@ -892,7 +884,7 @@ void do_enter(void)
openfile->current->data[openfile->current_x] = '\0';
#ifndef NANO_TINY
add_undo(ENTER);
add_undo(ENTER, NULL);
/* Adjust the mark if it was on the current line after the cursor. */
if (openfile->mark == openfile->current &&
@@ -952,10 +944,9 @@ void send_data(const linestruct *line, int fd)
bool execute_command(const char *command)
{
int from_fd[2], to_fd[2];
/* The pipes through which text will written and read. */
/* The pipes through which text will be written and read. */
const bool should_pipe = (command[0] == '|');
FILE *stream;
const char *shellenv;
struct sigaction oldaction, newaction;
/* Original and temporary handlers for SIGINT. */
@@ -966,13 +957,13 @@ bool execute_command(const char *command)
return FALSE;
}
/* Check which shell to use. If none is specified, use /bin/sh. */
shellenv = getenv("SHELL");
if (shellenv == NULL)
shellenv = (char *)"/bin/sh";
/* Fork a child process to run the command in. */
if ((pid_of_command = fork()) == 0) {
const char *theshell = getenv("SHELL");
if (theshell == NULL)
theshell = (char *)"/bin/sh";
/* Child: close the unused read end of the output pipe. */
close(from_fd[0]);
@@ -988,7 +979,7 @@ bool execute_command(const char *command)
}
/* Run the given command inside the preferred shell. */
execl(shellenv, tail(shellenv), "-c", should_pipe ? &command[1] : command, NULL);
execl(theshell, tail(theshell), "-c", should_pipe ? &command[1] : command, NULL);
/* If the exec call returns, there was an error. */
exit(1);
@@ -1018,13 +1009,12 @@ bool execute_command(const char *command)
} else
#endif
{
add_undo(COUPLE_BEGIN);
openfile->undotop->strdata = mallocstrcpy(NULL, _("filtering"));
add_undo(COUPLE_BEGIN, "filtering");
if (openfile->mark == NULL) {
openfile->current = openfile->filetop;
openfile->current_x = 0;
}
add_undo(CUT);
add_undo(CUT, NULL);
do_snip(FALSE, openfile->mark != NULL, openfile->mark == NULL, FALSE);
update_undo(CUT);
}
@@ -1063,8 +1053,8 @@ bool execute_command(const char *command)
read_file(stream, 0, "pipe", TRUE);
if (should_pipe && !ISSET(MULTIBUFFER)) {
add_undo(COUPLE_END);
openfile->undotop->strdata = mallocstrcpy(NULL, _("filtering"));
/* TRANSLATORS: The next two go with Undid/Redid messages. */
add_undo(COUPLE_END, N_("filtering"));
}
/* Wait for the external command (and possibly data sender) to terminate. */
@@ -1118,7 +1108,7 @@ void discard_until(const undostruct *thisitem, openfilestruct *thefile, bool kee
}
/* Add a new undo item of the given type to the top of the current pile. */
void add_undo(undo_type action)
void add_undo(undo_type action, const char *message)
{
undostruct *u = nmalloc(sizeof(undostruct));
@@ -1169,31 +1159,33 @@ void add_undo(undo_type action)
if (openfile->current->next == openfile->filebot &&
openfile->current->data[0] != '\0')
u->xflags |= WAS_FINAL_BACKSPACE;
/* Fall-through. */
case DEL:
/* When not at the end of a line, store the deleted character,
* else purposely fall into the line-joining code. */
if (openfile->current->data[openfile->current_x] != '\0') {
char *char_buf = charalloc(MAXCHARLEN + 1);
int charlen = parse_mbchar(&openfile->current->data[u->begin],
char_buf, NULL);
int charlen = collect_char(&openfile->current->data[u->begin],
char_buf);
char_buf[charlen] = '\0';
u->strdata = char_buf;
if (u->type == BACK)
u->mark_begin_x += charlen;
break;
}
/* Fall-through. */
case JOIN:
if (openfile->current->next) {
if (u->type == BACK) {
u->lineno = openfile->current->next->lineno;
u->begin = 0;
}
u->strdata = mallocstrcpy(NULL, openfile->current->next->data);
u->strdata = copy_of(openfile->current->next->data);
}
action = u->type = JOIN;
break;
case REPLACE:
u->strdata = mallocstrcpy(NULL, openfile->current->data);
u->strdata = copy_of(openfile->current->data);
break;
#ifdef ENABLE_WRAPPING
case SPLIT_BEGIN:
@@ -1225,16 +1217,18 @@ void add_undo(undo_type action)
u->lineno += cutbottom->lineno - cutbuffer->lineno;
break;
case INSERT:
break;
case COUPLE_BEGIN:
u->mark_begin_lineno = openfile->current_y;
/* Fall-through. */
case COUPLE_END:
u->strdata = copy_of(_(message));
break;
case INDENT:
case UNINDENT:
break;
#ifdef ENABLE_COMMENT
case COMMENT:
case UNCOMMENT:
break;
#endif
default:
break;
@@ -1260,8 +1254,7 @@ void update_multiline_undo(ssize_t lineno, char *indentation)
number_of_lines = u->grouping->bottom_line - u->grouping->top_line + 1;
u->grouping->indentations = (char **)nrealloc(u->grouping->indentations,
number_of_lines * sizeof(char *));
u->grouping->indentations[number_of_lines - 1] = mallocstrcpy(NULL,
indentation);
u->grouping->indentations[number_of_lines - 1] = copy_of(indentation);
} else {
groupstruct *born = nmalloc(sizeof(groupstruct));
@@ -1271,7 +1264,7 @@ void update_multiline_undo(ssize_t lineno, char *indentation)
born->bottom_line = lineno;
u->grouping->indentations = (char **)nmalloc(sizeof(char *));
u->grouping->indentations[0] = mallocstrcpy(NULL, indentation);
u->grouping->indentations[0] = copy_of(indentation);
}
/* Store the file size after the change, to be used when redoing. */
@@ -1294,22 +1287,22 @@ void update_undo(undo_type action)
switch (u->type) {
case ADD:
char_buf = charalloc(MAXCHARLEN);
charlen = parse_mbchar(&openfile->current->data[u->mark_begin_x],
char_buf, NULL);
charlen = collect_char(&openfile->current->data[u->mark_begin_x],
char_buf);
u->strdata = addstrings(u->strdata, u->strdata ? strlen(u->strdata) : 0,
char_buf, charlen);
u->mark_begin_lineno = openfile->current->lineno;
u->mark_begin_x = openfile->current_x;
break;
case ENTER:
u->strdata = mallocstrcpy(NULL, openfile->current->data);
u->strdata = copy_of(openfile->current->data);
u->mark_begin_x = openfile->current_x;
break;
case BACK:
case DEL:
char_buf = charalloc(MAXCHARLEN);
charlen = parse_mbchar(&openfile->current->data[openfile->current_x],
char_buf, NULL);
charlen = collect_char(&openfile->current->data[openfile->current_x],
char_buf);
if (openfile->current_x == u->begin) {
/* They deleted more: add removed character after earlier stuff. */
u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, charlen);
@@ -1321,7 +1314,7 @@ void update_undo(undo_type action)
} else {
/* They deleted *elsewhere* on the line: start a new undo item. */
free(char_buf);
add_undo(u->type);
add_undo(u->type, NULL);
return;
}
break;
@@ -1385,6 +1378,7 @@ void update_undo(undo_type action)
case INSERT:
u->mark_begin_lineno = openfile->current->lineno;
u->mark_begin_x = openfile->current_x;
break;
case COUPLE_BEGIN:
break;
case COUPLE_END:
@@ -1435,7 +1429,7 @@ bool do_wrap(void)
if (ISSET(AUTOINDENT) && wrap_loc == indent_length(line->data))
return FALSE;
add_undo(SPLIT_BEGIN);
add_undo(SPLIT_BEGIN, NULL);
#endif
#ifdef ENABLE_JUSTIFY
bool autowhite = ISSET(AUTOINDENT);
@@ -1460,7 +1454,7 @@ bool do_wrap(void)
/* If the remainder doesn't end in a blank, add a space. */
if (!is_blank_mbchar(remainder + step_left(remainder, rest_length))) {
#ifndef NANO_TINY
add_undo(ADD);
add_undo(ADD, NULL);
#endif
line->data = charealloc(line->data, line_len + 2);
line->data[line_len] = ' ';
@@ -1539,7 +1533,7 @@ bool do_wrap(void)
openfile->placewewant = xplustabs();
#ifndef NANO_TINY
add_undo(SPLIT_END);
add_undo(SPLIT_END, NULL);
#endif
return TRUE;
@@ -1572,7 +1566,7 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl)
break;
}
charlen = parse_mbchar(line, NULL, &column);
charlen = advance_over(line, &column);
line += charlen;
index += charlen;
}
@@ -1630,7 +1624,7 @@ size_t indent_length(const char *line)
int charlen;
while (*line != '\0') {
charlen = parse_mbchar(line, onechar, NULL);
charlen = collect_char(line, onechar);
if (!is_blank_mbchar(onechar))
break;
@@ -1895,7 +1889,7 @@ void justify_paragraph(linestruct **line, size_t par_len)
/* Copy the leading part (quoting + indentation) of the sample line. */
quote_len = quote_length(sampleline->data);
lead_len = quote_len + indent_length(sampleline->data + quote_len);
lead_string = mallocstrncpy(NULL, sampleline->data, lead_len + 1);
lead_string = measured_copy(sampleline->data, lead_len + 1);
lead_string[lead_len] = '\0';
/* Concatenate all lines of the paragraph into a single line. */
@@ -1977,7 +1971,7 @@ void do_justify(bool full_justify)
/* Copy the leading part that is to be used for the new paragraph. */
quote_len = quote_length(first_par_line->data);
lead_len = quote_len + indent_length(first_par_line->data + quote_len);
the_lead = mallocstrncpy(the_lead, first_par_line->data, lead_len + 1);
the_lead = measured_copy(first_par_line->data, lead_len + 1);
the_lead[lead_len] = '\0';
/* Copy the leading part that is to be used for the new paragraph after
@@ -2039,14 +2033,13 @@ void do_justify(bool full_justify)
}
#ifndef NANO_TINY
add_undo(COUPLE_BEGIN);
openfile->undotop->strdata = mallocstrcpy(NULL, _("justification"));
add_undo(COUPLE_BEGIN, N_("justification"));
/* Store the original cursor position, in case we unjustify. */
openfile->undotop->lineno = was_lineno;
openfile->undotop->begin = was_current_x;
add_undo(CUT);
add_undo(CUT, NULL);
#endif
/* Do the equivalent of a marked cut into an empty cutbuffer. */
@@ -2112,7 +2105,7 @@ void do_justify(bool full_justify)
strlen(cutbuffer->data) - needed_top_extra + 1);
else {
cutbuffer->prev = make_new_node(NULL);
cutbuffer->prev->data = mallocstrcpy(NULL, "");
cutbuffer->prev->data = copy_of("");
cutbuffer->prev->next = cutbuffer;
cutbuffer = cutbuffer->prev;
}
@@ -2125,7 +2118,7 @@ void do_justify(bool full_justify)
* region is "pasted" back. */
if (bot_x > 0 && !ends_at_eol) {
line->next = make_new_node(line);
line->next->data = mallocstrcpy(NULL, the_lead + needed_bot_extra);
line->next->data = copy_of(the_lead + needed_bot_extra);
}
free(the_lead);
@@ -2150,15 +2143,14 @@ void do_justify(bool full_justify)
}
#ifndef NANO_TINY
add_undo(PASTE);
add_undo(PASTE, NULL);
#endif
/* Do the equivalent of a paste of the justified text. */
ingraft_buffer(cutbuffer);
#ifndef NANO_TINY
update_undo(PASTE);
add_undo(COUPLE_END);
openfile->undotop->strdata = mallocstrcpy(NULL, _("justification"));
add_undo(COUPLE_END, "justification");
/* If we justified marked text, restore mark or cursor position. */
if (openfile->mark) {
@@ -2212,7 +2204,7 @@ void do_full_justify(void)
/* Set up an argument list for executing the given command. */
void construct_argument_list(char ***arguments, char *command, char *filename)
{
char *copy_of_command = mallocstrcpy(NULL, command);
char *copy_of_command = copy_of(command);
char *element = strtok(copy_of_command, " ");
int count = 2;
@@ -2251,7 +2243,7 @@ bool fix_spello(const char *word)
/* Save the current search string, then set it to the misspelled word. */
save_search = last_search;
last_search = mallocstrcpy(NULL, word);
last_search = copy_of(word);
#ifndef NANO_TINY
/* If the mark is on, start at the beginning of the marked region. */
@@ -2344,9 +2336,10 @@ bool fix_spello(const char *word)
return proceed;
}
/* Internal (integrated) spell checking using the spell program,
* filtered through the sort and uniq programs. Return NULL for normal
* termination, and the error string otherwise. */
/* 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. Return NULL when okay, and the error string otherwise. */
const char *do_int_speller(const char *tempfile_name)
{
char *misspellings, *pointer, *oneword;
@@ -2362,89 +2355,79 @@ const char *do_int_speller(const char *tempfile_name)
statusbar(_("Creating misspelled word list, please wait..."));
/* A new process to run spell in. */
/* Fork a process to run spell in. */
if ((pid_spell = fork()) == 0) {
/* Child continues (i.e. future spell process). */
close(spell_fd[0]);
/* Replace the standard input with the temp file. */
/* Child: open the temporary file that holds the text to be checked. */
if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
goto close_pipes_and_exit;
exit(6);
if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
close(tempfile_fd);
goto close_pipes_and_exit;
}
/* Connect standard input to the temporary file. */
if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
exit(7);
/* Connect standard output to the write end of the first pipe. */
if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
exit(8);
close(tempfile_fd);
/* Send spell's standard output to the pipe. */
if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
goto close_pipes_and_exit;
close(spell_fd[0]);
close(spell_fd[1]);
/* Start the spell program; we are using $PATH. */
/* Try to run 'hunspell'; if that fails, fall back to 'spell'. */
execlp("hunspell", "hunspell", "-l", NULL);
execlp("spell", "spell", NULL);
/* This should not be reached if spell is found. */
exit(1);
/* Indicate failure when neither speller was found. */
exit(9);
}
/* Parent continues here. */
/* Parent: close the unused write end of the first pipe. */
close(spell_fd[1]);
/* A new process to run sort in. */
/* Fork a process to run sort in. */
if ((pid_sort = fork()) == 0) {
/* Child continues (i.e. future sort process). Replace the
* standard input with the standard output of the old pipe. */
/* Connect standard input to the read end of the first pipe. */
if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
goto close_pipes_and_exit;
exit(7);
/* Connect standard output to the write end of the second pipe. */
if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
exit(8);
close(spell_fd[0]);
/* Send sort's standard output to the new pipe. */
if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
goto close_pipes_and_exit;
close(sort_fd[0]);
close(sort_fd[1]);
/* Start the sort program. Use -f to ignore case. */
/* Now run the sort program. Use -f to mix upper and lower case. */
execlp("sort", "sort", "-f", NULL);
/* This should not be reached if sort is found. */
exit(1);
exit(9);
}
close(spell_fd[0]);
close(sort_fd[1]);
/* A new process to run uniq in. */
/* Fork a process to run uniq in. */
if ((pid_uniq = fork()) == 0) {
/* Child continues (i.e. future uniq process). Replace the
* standard input with the standard output of the old pipe. */
if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
goto close_pipes_and_exit;
exit(7);
if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
exit(8);
close(sort_fd[0]);
/* Send uniq's standard output to the new pipe. */
if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
goto close_pipes_and_exit;
close(uniq_fd[0]);
close(uniq_fd[1]);
/* Start the uniq program; we are using PATH. */
execlp("uniq", "uniq", NULL);
/* This should not be reached if uniq is found. */
exit(1);
exit(9);
}
close(sort_fd[0]);
close(uniq_fd[1]);
/* The child process was not forked successfully. */
/* When some child process was not forked successfully... */
if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
close(uniq_fd[0]);
return _("Could not fork");
@@ -2458,7 +2441,7 @@ const char *do_int_speller(const char *tempfile_name)
return _("Could not get size of pipe buffer");
}
/* Block SIGWINCHes while reading misspelled words from the pipe. */
/* Block SIGWINCHes while reading misspelled words from the third pipe. */
block_sigwinch(TRUE);
totalread = 0;
@@ -2478,7 +2461,7 @@ const char *do_int_speller(const char *tempfile_name)
block_sigwinch(FALSE);
/* Do any replacements case sensitive, forward, and without regexes. */
/* Do any replacements case-sensitively, forward, and without regexes. */
SET(CASE_SENSITIVE);
UNSET(BACKWARDS_SEARCH);
UNSET(USE_REGEXP);
@@ -2523,109 +2506,114 @@ const char *do_int_speller(const char *tempfile_name)
return _("Error invoking \"spell\"");
/* When all went okay. */
statusbar(_("Finished checking spelling"));
return NULL;
close_pipes_and_exit:
/* Don't leak any handles. */
close(spell_fd[0]);
close(spell_fd[1]);
close(sort_fd[0]);
close(sort_fd[1]);
close(uniq_fd[0]);
close(uniq_fd[1]);
exit(1);
}
/* External (alternate) spell checking. Return NULL for normal
* termination, and the error string otherwise. */
const char *do_alt_speller(char *tempfile_name)
/* Execute the given program, with the given temp file as last argument. */
const char *treat(char *tempfile_name, char *theprogram, bool spelling)
{
int alt_spell_status;
ssize_t lineno_save = openfile->current->lineno;
size_t current_x_save = openfile->current_x;
size_t pww_save = openfile->placewewant;
ssize_t lineno_save = openfile->current->lineno;
bool was_at_eol = (openfile->current->data[openfile->current_x] == '\0');
struct stat fileinfo;
long timestamp_sec, timestamp_nsec;
static char **arguments = NULL;
pid_t thepid;
int program_status;
bool replaced = FALSE;
struct stat spellfileinfo;
time_t timestamp;
pid_t pid_spell;
static char **spellargs = NULL;
/* Get the timestamp and the size of the temporary file. */
stat(tempfile_name, &spellfileinfo);
timestamp = spellfileinfo.st_mtime;
stat(tempfile_name, &fileinfo);
timestamp_sec = (long)fileinfo.st_mtim.tv_sec;
timestamp_nsec = (long)fileinfo.st_mtim.tv_nsec;
/* If the number of bytes to check is zero, get out. */
if (spellfileinfo.st_size == 0)
if (fileinfo.st_size == 0)
return NULL;
/* Exit from curses mode. */
/* Exit from curses mode to give the program control of the terminal. */
endwin();
construct_argument_list(&spellargs, alt_speller, tempfile_name);
construct_argument_list(&arguments, theprogram, tempfile_name);
/* Fork a child process and run the alternate spell program in it. */
if ((pid_spell = fork()) == 0) {
execvp(spellargs[0], spellargs);
/* Fork a child process and run the given program in it. */
if ((thepid = fork()) == 0) {
execvp(arguments[0], arguments);
/* Terminate the child process if no alternate speller is found. */
exit(1);
} else if (pid_spell < 0)
/* Terminate the child if the program is not found. */
exit(9);
} else if (thepid < 0)
return _("Could not fork");
/* Block SIGWINCHes while waiting for the alternate spell checker's end,
/* Block SIGWINCHes while waiting for the program to end,
* so nano doesn't get pushed past the wait(). */
block_sigwinch(TRUE);
wait(&alt_spell_status);
wait(&program_status);
block_sigwinch(FALSE);
/* Set the desired terminal state again, and reenter curses mode. */
/* Restore the terminal state and reenter curses mode. */
terminal_init();
doupdate();
if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0)
return invocation_error(alt_speller);
if (!WIFEXITED(program_status) || WEXITSTATUS(program_status) > 2) {
statusline(ALERT, _("Error invoking '%s'"), arguments[0]);
return NULL;
} else if (WEXITSTATUS(program_status) != 0)
statusline(ALERT, _("Program '%s' complained"), arguments[0]);
/* Stat the temporary file again. */
stat(tempfile_name, &spellfileinfo);
stat(tempfile_name, &fileinfo);
/* Use the spell-checked file only when it changed. */
if (spellfileinfo.st_mtime != timestamp) {
#ifndef NANO_TINY
/* Replace the marked text (or entire text) with the corrected text. */
if (openfile->mark) {
bool upright = (openfile->mark->lineno < openfile->current->lineno ||
(openfile->mark == openfile->current &&
openfile->mark_x < openfile->current_x));
ssize_t was_mark_lineno = openfile->mark->lineno;
replaced = replace_buffer(tempfile_name, CUT, TRUE);
/* Adjust the end point of the marked region for any change in
* length of the region's last line. */
if (upright)
current_x_save = openfile->current_x;
else
openfile->mark_x = openfile->current_x;
/* Restore the mark. */
openfile->mark = line_from_number(was_mark_lineno);
} else
#endif
replaced = replace_buffer(tempfile_name, CUT_TO_EOF, FALSE);
/* Go back to the old position. */
goto_line_posx(lineno_save, current_x_save);
if (was_at_eol || openfile->current_x > strlen(openfile->current->data))
openfile->current_x = strlen(openfile->current->data);
#ifndef NANO_TINY
if (replaced)
update_undo(COUPLE_END);
#endif
openfile->placewewant = pww_save;
adjust_viewport(STATIONARY);
/* When the temporary file wasn't touched, say so and leave. */
if ((long)fileinfo.st_mtim.tv_sec == timestamp_sec &&
(long)fileinfo.st_mtim.tv_nsec == timestamp_nsec) {
statusbar(_("Nothing changed"));
return NULL;
}
#ifndef NANO_TINY
/* Replace the marked text (or entire text) with the corrected text. */
if (spelling && openfile->mark) {
bool upright = (openfile->mark->lineno < openfile->current->lineno ||
(openfile->mark == openfile->current &&
openfile->mark_x < openfile->current_x));
ssize_t was_mark_lineno = openfile->mark->lineno;
replaced = replace_buffer(tempfile_name, CUT, TRUE, "spelling correction");
/* Adjust the end point of the marked region for any change in
* length of the region's last line. */
if (upright)
current_x_save = openfile->current_x;
else
openfile->mark_x = openfile->current_x;
/* Restore the mark. */
openfile->mark = line_from_number(was_mark_lineno);
} else
#endif
replaced = replace_buffer(tempfile_name, CUT_TO_EOF, FALSE,
/* TRANSLATORS: The next two go with Undid/Redid messages. */
(spelling ? N_("spelling correction") : N_("formatting")));
/* Go back to the old position. */
goto_line_posx(lineno_save, current_x_save);
if (was_at_eol || openfile->current_x > strlen(openfile->current->data))
openfile->current_x = strlen(openfile->current->data);
#ifndef NANO_TINY
if (replaced)
update_undo(COUPLE_END);
#endif
openfile->placewewant = pww_save;
adjust_viewport(STATIONARY);
if (spelling)
statusbar(_("Finished checking spelling"));
else
statusbar(_("Buffer has been processed"));
return NULL;
}
@@ -2633,21 +2621,18 @@ const char *do_alt_speller(char *tempfile_name)
* specified, use it. Otherwise, use the internal spell checker. */
void do_spell(void)
{
bool status;
FILE *temp_file;
char *temp;
FILE *stream;
char *temp_name;
unsigned stash[sizeof(flags) / sizeof(flags[0])];
/* A storage place for the current flag settings. */
const char *result_msg;
bool okay;
if (ISSET(RESTRICTED)) {
show_restricted_warning();
if (in_restricted_mode())
return;
}
temp = safe_tempfile(&temp_file);
temp_name = safe_tempfile(&stream);
if (temp == NULL) {
if (temp_name == NULL) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
return;
}
@@ -2660,23 +2645,26 @@ void do_spell(void)
#ifndef NANO_TINY
if (openfile->mark)
status = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
okay = write_marked_file(temp_name, stream, TRUE, OVERWRITE);
else
#endif
status = write_file(temp, temp_file, TRUE, OVERWRITE, TRUE);
okay = write_file(temp_name, stream, TRUE, OVERWRITE, TRUE);
if (!status) {
if (!okay) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
free(temp);
free(temp_name);
return;
}
blank_bottombars();
result_msg = (alt_speller ? do_alt_speller(temp) : do_int_speller(temp));
if (alt_speller)
result_msg = treat(temp_name, alt_speller, TRUE);
else
result_msg = do_int_speller(temp_name);
unlink(temp);
free(temp);
unlink(temp_name);
free(temp_name);
/* Restore the settings of the global flags. */
memcpy(flags, stash, sizeof(flags));
@@ -2691,20 +2679,18 @@ void do_spell(void)
statusline(ALERT, result_msg);
else
statusline(ALERT, _("%s: %s"), result_msg, strerror(errno));
} else
statusbar(_("Finished checking spelling"));
}
}
#endif /* ENABLE_SPELLER */
#ifdef ENABLE_COLOR
/* Run a linting program on the current buffer. Return NULL for normal
* termination, and the error string otherwise. */
/* Run a linting program on the current buffer. */
void do_linter(void)
{
char *lintings, *pointer, *onelint;
long pipesize;
size_t buffersize, bytesread, totalread;
size_t parsesuccess = 0;
bool parsesuccess = FALSE;
int lint_status, lint_fd[2];
pid_t pid_lint;
bool helpless = ISSET(NO_HELP);
@@ -2712,13 +2698,11 @@ void do_linter(void)
lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL;
time_t last_wait = 0;
if (ISSET(RESTRICTED)) {
show_restricted_warning();
if (in_restricted_mode())
return;
}
if (!openfile->syntax || !openfile->syntax->linter) {
statusbar(_("No linter defined for this type of file!"));
statusbar(_("No linter is defined for this type of file"));
return;
}
@@ -2749,18 +2733,15 @@ void do_linter(void)
construct_argument_list(&lintargs, openfile->syntax->linter, openfile->filename);
/* Start a new process to run the linter in. */
/* Fork a process to run the linter in. */
if ((pid_lint = fork()) == 0) {
/* Child continues here (i.e. the future linting process). */
close(lint_fd[0]);
/* Send the linter's standard output + err to the pipe. */
/* Redirect standard output and standard error into the pipe. */
if (dup2(lint_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
exit(9);
exit(7);
if (dup2(lint_fd[1], STDERR_FILENO) != STDERR_FILENO)
exit(9);
exit(8);
close(lint_fd[0]);
close(lint_fd[1]);
/* Start the linter program; we are using $PATH. */
@@ -2814,7 +2795,7 @@ void do_linter(void)
*pointer = '\0';
if (onelint != pointer) {
char *filename = NULL, *linestr = NULL, *maybecol = NULL;
char *message = mallocstrcpy(NULL, onelint);
char *message = copy_of(onelint);
/* At the moment we handle the following formats:
*
@@ -2846,17 +2827,17 @@ void do_linter(void)
}
/* Nice. We have a lint message we can use. */
parsesuccess++;
parsesuccess = TRUE;
tmplint = curlint;
curlint = nmalloc(sizeof(lintstruct));
curlint->next = NULL;
curlint->prev = tmplint;
if (curlint->prev != NULL)
curlint->prev->next = curlint;
curlint->msg = mallocstrcpy(NULL, message);
curlint->msg = copy_of(message);
curlint->lineno = tmplineno;
curlint->colno = tmpcolno;
curlint->filename = mallocstrcpy(NULL, filename);
curlint->filename = copy_of(filename);
if (lints == NULL)
lints = curlint;
@@ -2876,11 +2857,11 @@ void do_linter(void)
waitpid(pid_lint, &lint_status, 0);
if (!WIFEXITED(lint_status) || WEXITSTATUS(lint_status) > 2) {
statusbar(invocation_error(openfile->syntax->linter));
statusline(ALERT, _("Error invoking '%s'"), openfile->syntax->linter);
return;
}
if (parsesuccess == 0) {
if (!parsesuccess) {
statusline(HUSH, _("Got 0 parsable lines from command: %s"),
openfile->syntax->linter);
return;
@@ -2932,7 +2913,7 @@ void do_linter(void)
open_buffer(curlint->filename, TRUE);
} else {
#endif
char *dontwantfile = mallocstrcpy(NULL, curlint->filename);
char *dontwantfile = copy_of(curlint->filename);
lintstruct *restlint = NULL;
while (curlint != NULL) {
@@ -3039,6 +3020,44 @@ void do_linter(void)
currmenu = MMOST;
titlebar(NULL);
}
#ifdef ENABLE_SPELLER
/* Run a manipulation program on the contents of the buffer. */
void do_formatter(void)
{
FILE *stream;
char *temp_name;
bool okay = FALSE;
const char *result_msg;
if (in_restricted_mode())
return;
if (!openfile->syntax || !openfile->syntax->formatter) {
statusbar(_("No formatter is defined for this type of file"));
return;
}
temp_name = safe_tempfile(&stream);
if (temp_name != NULL)
okay = write_file(temp_name, stream, TRUE, OVERWRITE, TRUE);
if (!okay) {
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
free(temp_name);
return;
}
result_msg = treat(temp_name, openfile->syntax->formatter, FALSE);
if (result_msg != NULL)
statusline(ALERT, result_msg);
unlink(temp_name);
free(temp_name);
}
#endif /* ENABLE_SPELLER */
#endif /* ENABLE_COLOR */
#ifndef NANO_TINY

View File

@@ -49,7 +49,7 @@ void get_homedir(void)
/* Only set homedir if some home directory could be determined,
* otherwise keep homedir NULL. */
if (homenv != NULL && *homenv != '\0')
homedir = mallocstrcpy(NULL, homenv);
homedir = copy_of(homenv);
}
}
@@ -149,7 +149,7 @@ bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
if (comma == str)
return retval;
firstpart = mallocstrcpy(NULL, str);
firstpart = copy_of(str);
firstpart[comma - str] = '\0';
retval = parse_num(firstpart, line) && retval;
@@ -159,23 +159,24 @@ bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
return retval;
}
/* For non-null-terminated lines. A line, by definition, shouldn't
* normally have newlines in it, so encode its nulls as newlines. */
void unsunder(char *str, size_t true_len)
/* In the given string, recode each embedded NUL as a newline. */
void unsunder(char *string, size_t length)
{
for (; true_len > 0; true_len--, str++) {
if (*str == '\0')
*str = '\n';
while (length > 0) {
if (*string == '\0')
*string = '\n';
length--;
string++;
}
}
/* For non-null-terminated lines. A line, by definition, shouldn't
* normally have newlines in it, so decode its newlines as nulls. */
void sunder(char *str)
/* In the given string, recode each embedded newline as a NUL. */
void sunder(char *string)
{
for (; *str != '\0'; str++) {
if (*str == '\n')
*str = '\0';
while (*string != '\0') {
if (*string == '\n')
*string = '\0';
string++;
}
}
@@ -202,8 +203,8 @@ bool is_separate_word(size_t position, size_t length, const char *buf)
size_t word_end = position + length;
/* Get the characters before and after the word, if any. */
parse_mbchar(buf + step_left(buf, position), before, NULL);
parse_mbchar(buf + word_end, after, NULL);
collect_char(buf + step_left(buf, position), before);
collect_char(buf + word_end, after);
/* 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
@@ -311,24 +312,32 @@ void *nrealloc(void *ptr, size_t howmuch)
return r;
}
/* Allocate and copy the first n characters of the given src string, after
* freeing the destination. Usage: "dest = mallocstrncpy(dest, src, n);". */
char *mallocstrncpy(char *dest, const char *src, size_t n)
/* Return an appropriately reallocated dest string holding a copy of src.
* Usage: "dest = mallocstrcpy(dest, src);". */
char *mallocstrcpy(char *dest, const char *src)
{
if (src == NULL)
src = "";
size_t count = strlen(src) + 1;
dest = charealloc(dest, n);
strncpy(dest, src, n);
dest = charealloc(dest, count);
strncpy(dest, src, count);
return dest;
}
/* Free the dest string and return a malloc'ed copy of src. Should be used as:
* "dest = mallocstrcpy(dest, src);". */
char *mallocstrcpy(char *dest, const char *src)
/* Return an allocated copy of the first count characters of the given string. */
char *measured_copy(const char *string, size_t count)
{
return mallocstrncpy(dest, src, (src == NULL) ? 1 : strlen(src) + 1);
char *thecopy = charalloc(count);
strncpy(thecopy, string, count);
return thecopy;
}
/* Return an allocated copy of the given string. */
char *copy_of(const char *string)
{
return measured_copy(string, strlen(string) + 1);
}
/* Free the string at dest and return the string at src. */
@@ -370,7 +379,7 @@ size_t actual_x(const char *text, size_t column)
/* The current accumulated span, in columns. */
while (*text != '\0') {
int charlen = parse_mbchar(text, NULL, &width);
int charlen = advance_over(text, &width);
if (width > column)
break;
@@ -391,7 +400,7 @@ size_t wideness(const char *text, size_t maxlen)
return 0;
while (*text != '\0') {
size_t charlen = parse_mbchar(text, NULL, &width);
size_t charlen = advance_over(text, &width);
if (maxlen <= charlen)
break;
@@ -409,7 +418,7 @@ size_t breadth(const char *text)
size_t span = 0;
while (*text != '\0')
text += parse_mbchar(text, NULL, &span);
text += advance_over(text, &span);
return span;
}
@@ -418,7 +427,7 @@ size_t breadth(const char *text)
void new_magicline(void)
{
openfile->filebot->next = make_new_node(openfile->filebot);
openfile->filebot->next->data = mallocstrcpy(NULL, "");
openfile->filebot->next->data = copy_of("");
openfile->filebot = openfile->filebot->next;
openfile->totsize++;
}

View File

@@ -2094,8 +2094,8 @@ void titlebar(const char *path)
state = _("View");
else if (ISSET(RESTRICTED))
state = _("Restricted");
pluglen = breadth(_("Modified")) + 1;
else
pluglen = breadth(_("Modified")) + 1;
}
/* Determine the widths of the four elements, including their padding. */
@@ -2105,10 +2105,8 @@ void titlebar(const char *path)
prefixlen++;
pathlen = breadth(path);
statelen = breadth(state) + 2;
if (statelen > 2) {
if (statelen > 2)
pathlen++;
pluglen = 0;
}
/* Only print the version message when there is room for it. */
if (verlen + prefixlen + pathlen + pluglen + statelen <= COLS)
@@ -2164,30 +2162,15 @@ void titlebar(const char *path)
wrefresh(topwin);
}
/* Display a normal message on the statusbar, quietly. */
void statusbar(const char *msg)
{
statusline(HUSH, msg);
}
/* Warn the user on the statusbar and pause for a moment, so that the
* message can be noticed and read. */
void warn_and_shortly_pause(const char *msg)
{
statusline(ALERT, msg);
napms(1800);
}
/* Display a message on the statusbar, and set suppress_cursorpos to
* TRUE, so that the message won't be immediately overwritten if
* constant cursor position display is on. */
void statusline(message_type importance, const char *msg, ...)
{
va_list ap;
static int alerts = 0;
int colorpair;
char *compound, *message;
size_t start_col;
static size_t start_col = 0;
bool bracketed;
#ifndef NANO_TINY
bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
@@ -2210,20 +2193,23 @@ void statusline(message_type importance, const char *msg, ...)
}
#endif
/* If the ALERT status has been reset, reset the counter. */
if (lastmessage == HUSH)
alerts = 0;
/* Shortly pause after each of the first three alert messages,
* to give the user time to read them. */
if (lastmessage == ALERT && alerts < 4 && !ISSET(NO_PAUSES))
napms(1200);
/* If there are multiple alert messages, add trailing dots to the first. */
if (lastmessage == ALERT) {
if (start_col > 4) {
wmove(bottomwin, 0, COLS + 2 - start_col);
wattron(bottomwin, interface_color_pair[ERROR_MESSAGE]);
waddstr(bottomwin, "...");
wattroff(bottomwin, interface_color_pair[ERROR_MESSAGE]);
wnoutrefresh(bottomwin);
start_col = 0;
napms(100);
beep();
}
return;
}
if (importance == ALERT) {
if (++alerts > 3 && !ISSET(NO_PAUSES))
msg = _("Further warnings were suppressed");
else if (alerts < 4)
beep();
beep();
colorpair = interface_color_pair[ERROR_MESSAGE];
} else if (importance == NOTICE)
colorpair = interface_color_pair[SELECTED_TEXT];
@@ -2277,6 +2263,20 @@ void statusline(message_type importance, const char *msg, ...)
statusblank = 26;
}
/* Display a normal message on the statusbar, quietly. */
void statusbar(const char *msg)
{
statusline(HUSH, msg);
}
/* Warn the user on the statusbar and pause for a moment, so that the
* message can be noticed and read. */
void warn_and_shortly_pause(const char *msg)
{
statusline(ALERT, msg);
napms(1800);
}
/* Display the shortcut list corresponding to menu on the last two rows
* of the bottom portion of the window. */
void bottombars(int menu)
@@ -2684,7 +2684,7 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
size_t charlen = 1;
if (*(converted + target_x) != '\0') {
charlen = parse_mbchar(converted + target_x, striped_char, NULL);
charlen = collect_char(converted + target_x, striped_char);
target_column = wideness(converted, target_x);
} else if (target_column + 1 == editwincols) {
/* Defeat a VTE bug -- see https://sv.gnu.org/bugs/?55896. */
@@ -3043,7 +3043,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
/* First find the place in text where the current chunk starts. */
while (*text != '\0' && column < leftedge)
text += parse_mbchar(text, NULL, &column);
text += advance_over(text, &column);
/* Now find the place in text where this chunk should end. */
while (*text != '\0' && column <= goal_column) {
@@ -3054,7 +3054,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
}
breaking_col = (*text == '\t' ? goal_column : column);
text += parse_mbchar(text, NULL, &column);
text += advance_over(text, &column);
}
/* If we didn't overshoot the limit, we've found a breaking point;
@@ -3067,7 +3067,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
/* If we're softwrapping at blanks and we found at least one blank, break
* after that blank -- if it doesn't overshoot the screen's edge. */
if (farthest_blank != NULL) {
parse_mbchar(farthest_blank, NULL, &last_blank_col);
advance_over(farthest_blank, &last_blank_col);
if (last_blank_col <= goal_column)
return last_blank_col;
@@ -3431,7 +3431,7 @@ void spotlight(size_t from_col, size_t to_col)
/* This is so we can show zero-length matches. */
if (to_col == from_col) {
word = mallocstrcpy(NULL, " ");
word = copy_of(" ");
to_col++;
} else
word = display_string(openfile->current->data, from_col,
@@ -3474,7 +3474,7 @@ void spotlight_softwrapped(size_t from_col, size_t to_col)
/* This is so we can show zero-length matches. */
if (break_col == from_col) {
word = mallocstrcpy(NULL, " ");
word = copy_of(" ");
break_col++;
} else
word = display_string(openfile->current->data, from_col,

View File

@@ -1,6 +1,7 @@
## Here is an example for C/C++.
syntax c "\.([ch](pp|xx)?|C|cc|c\+\+|cu|H|hh|ii?)$"
header "-\*-.*\<C(\+\+)?((;|\s).*)?-\*-"
magic "^(C|C\+\+) (source|program)"
comment "//"

View File

@@ -17,4 +17,4 @@ color brightred "(GNU )?[Nn]ano [1-4]\.[0-9][-.[:alnum:]]*\>"
color magenta "<[[:alnum:].%_+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}>"
# Bracketed captions in certain config files.
color brightgreen "^\[.*\]$"
color brightgreen "^\[[^][]+\]$"

View File

@@ -17,7 +17,7 @@ color green "-(eq|ne|gt|lt|ge|le)\>"
## Variables... official portage ones in red, all others in bright red:
color brightred "\$[-0-9@*#?$!]" "\$[[:alpha:]_][[:alnum:]_]*"
color brightred "\$\{[#!]?([-@*#?$!]|[0-9]+|[[:alpha:]_][[:alnum:]_]*)(\[([[:digit:]]|@)+\])?(([#%/]|:?[-=?+])[^}]*\}|\[|\})"
color red "\<(EAPI|ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|[HPR]?DEPEND|PROVIDE|PROPERTIES|REQUIRED_USE|RESTRICT|USERLAND)\>"
color red "\<(EAPI|ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|[BHPR]?DEPEND|PROVIDE|PROPERTIES|REQUIRED_USE|RESTRICT|USERLAND)\>"
color red "\<(S|E?D|T|PV|PF|P|PN|PR|PVR|A|CATEGORY|DISTDIR|FILESDIR|EPREFIX|E?ROOT|WORKDIR)\>"
color red "\<(AS|C(PP|XX)?|LD)FLAGS\>" "\<C(HOST|TARGET|BUILD)\>" "\<(MERGE_TYPE|REPLACING_VERSIONS|REPLACED_BY_VERSION)\>"
color red "\<EBUILD_PHASE(_FUNC)?\>"

View File

@@ -3,6 +3,8 @@
syntax go "\.go$"
comment "//"
formatter gofmt -w
# Types.
color green "\<(bool|u?int(8|16|32|64)?|float(32|64)|complex(64|128)|byte|rune|uintptr|string|error)\>"
color green "\<((<-[[:space:]]*)chan|chan[[:space:]]*<-|const|func|interface|map|struct|type|var)\>"

View File

@@ -4,6 +4,8 @@ syntax html "\.html?$"
magic "HTML document"
comment "<!--|-->"
formatter tidy -m -q
# Tags:
color cyan "<[[:alpha:]/!?][^>]*>"
# Bold, italic, and underlined:
@@ -11,18 +13,19 @@ color brightmagenta "</?[biu]>"
# Named character references:
color red "&[^;[:space:]]*;"
# Attributes:
color red "\<(abbr|accept(-charset)?|accesskey|action|alink|align|alt|archive|axis|background|bgcolor|border)="
color red "\<(cell(padding|spacing)|char(off|set)?|checked|cite|class(id)?|compact|code(base|tag)?|cols(pan)?)="
color red "\<(content(editable)?|contextmenu|coords|data|datetime|declare|defer|dir|disabled|enctype)="
color red "\<(for|frame(border)?|headers|height|hidden|href(lang)?|hspace|http-equiv|id|ismap)="
color red "\<(label|lang|link|longdesc|margin(height|width)|maxlength|media|method|multiple)="
color red "\<(name|nohref|noresize|noshade|object|onclick|onfocus|onload|onmouseover|profile|readonly|rel|rev)="
color red "\<(rows(pan)?|rules|scheme|scope|scrolling|selected|shape|size|span|src|standby|start|style|summary)="
color red "\<(tabindex|target|text|title|type|usemap|valign|value(type)?|vlink|vspace|width|xmlns|xml:space)="
# Strings:
color green ""(\\.|[^"])*""
# Attributes:
color red "(abbr|accept(-charset)?|accesskey|action|alink|align|alt|archive|axis|background|bgcolor|border)="
color red "(cell(padding|spacing)|char(off|set)?|checked|cite|class(id)?|compact|code(base|tag)?|cols(pan)?)="
color red "(content(editable)?|contextmenu|coords|data|datetime|declare|defer|dir|disabled|enctype)="
color red "(for|frame(border)?|headers|height|hidden|href(lang)?|hspace|http-equiv|id|ismap)="
color red "(label|lang|link|longdesc|margin(height|width)|maxlength|media|method|multiple)="
color red "(name|nohref|noresize|noshade|object|onclick|onfocus|onload|onmouseover|profile|readonly|rel|rev)="
color red "(rows(pan)?|rules|scheme|scope|scrolling|selected|shape|size|span|src|standby|start|style|summary)="
color red "(tabindex|target|text|title|type|usemap|valign|value(type)?|vlink|vspace|width|xmlns|xml:space)="
# Comments:
color yellow start="<!--" end="-->"

View File

@@ -12,7 +12,9 @@ color brightyellow "\<(await|export|import|throw|try|catch|finally|new|delete)\>
color magenta "\<(break|continue|return|yield)\>"
# Octal/decimal and hexadecimal numbers.
color cyan "\<[0-9]+\>" "\<0x[0-9A-Fa-f]+\>"
color cyan "\<([0-9]+|0x[0-9A-Fa-f]+)\>"
# Special values.
color cyan "\<(true|false|null|undefined)\>"
# Strings.
color brightmagenta ""(\\.|[^"])*"" "'(\\.|[^'])*'" "`(\\.|[^`])*`"

View File

@@ -5,9 +5,10 @@
syntax lua "\.lua$"
magic "Lua script"
linter "luacheck --no-color"
comment "--"
linter luacheck --no-color
color brightwhite "\[\[.*\]\]"
# Operators

View File

@@ -3,26 +3,26 @@
syntax nanorc "\.?nanorc$"
comment "#"
# Possible errors and parameters
icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|linter|tabgives|i?color|extendsyntax).*"
# Everything that does not get recolored is invalid
color brightred ".*"
# Keywords
icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(afterends|allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|breaklonglines|casesensitive|constantshow|cutfromcursor|emptyline|finalnewline|historylog|jumpyscrolling|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabstospaces|tempfile|trimblanks|unix|view|wordbounds|zap)\>"
icolor yellow "^[[:space:]]*set[[:space:]]+((error|function|key|number|selected|status|stripe|title)color)[[:space:]]+(bright)?(white|black|red|blue|green|yellow|magenta|cyan|normal)?(,(white|black|red|blue|green|yellow|magenta|cyan|normal))?\>"
icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|errorcolor|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|selectedcolor|speller|statuscolor|stripecolor|titlecolor|whitespace|wordchars)[[:space:]]+"
icolor brightgreen "^[[:space:]]*set[[:space:]]+(fill[[:space:]]+-?[[:digit:]]+|(guidestripe|tabsize)[[:space:]]+[1-9][0-9]*)\>"
icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^([[:alpha:]]|[]@\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+([[:alpha:]]+|".*")[[:space:]]+(all|main|search|replace(with)?|yesno|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
icolor brightgreen "^[[:space:]]*unbind[[:space:]]+((\^([[:alpha:]]|[]@\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+(all|main|search|replace(with)?|yesno|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|comment|linter|tabgives)[[:space:]]+.*"
icolor brightgreen "^[[:space:]]*(syntax|linter)[[:space:]]+[^[:blank:]]+"
icolor green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|linter|tabgives|extendsyntax)\>"
color brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(afterends|allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|breaklonglines|casesensitive|constantshow|cutfromcursor|emptyline|finalnewline|historylog|jumpyscrolling|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabstospaces|tempfile|trimblanks|unix|view|wordbounds|zap)\>"
color yellow "^[[:space:]]*set[[:space:]]+((error|function|key|number|selected|status|stripe|title)color)[[:space:]]+(bright)?(white|black|red|blue|green|yellow|magenta|cyan|normal)?(,(white|black|red|blue|green|yellow|magenta|cyan|normal))?\>"
color brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|errorcolor|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|selectedcolor|speller|statuscolor|stripecolor|titlecolor|whitespace|wordchars)[[:space:]]+"
color brightgreen "^[[:space:]]*set[[:space:]]+(fill[[:space:]]+-?[[:digit:]]+|(guidestripe|tabsize)[[:space:]]+[1-9][0-9]*)\>"
color brightgreen "^[[:space:]]*bind[[:space:]]+((\^([[:alpha:]]|[]/@\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:space:]]+([[:alpha:]]+|".*")[[:space:]]+(all|main|search|replace(with)?|yesno|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
color brightgreen "^[[:space:]]*unbind[[:space:]]+((\^([[:alpha:]]|[]/@\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:space:]]+(all|main|search|replace(with)?|yesno|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
color brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|comment|formatter|linter|tabgives)[[:space:]]+.*"
color brightgreen "^[[:space:]]*(syntax[[:space:]]+[^[:blank:]]+|(formatter|linter)[[:space:]]+.+)"
color green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|formatter|linter|tabgives|extendsyntax)\>"
# Strings
color brightmagenta "([[:space:]]|(start|end)=)".+"([[:space:]]|$)"
# Colors
icolor yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan|normal)?(,(white|black|red|blue|green|yellow|magenta|cyan|normal))?\>"
icolor magenta "^[[:space:]]*i?color\>" "\<(start|end)="
color yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan|normal)?(,(white|black|red|blue|green|yellow|magenta|cyan|normal))?\>"
color magenta "^[[:space:]]*i?color\>" "\<(start|end)="
# Comments
color brightblue "(^|[[:space:]]+)#.*"

View File

@@ -3,9 +3,10 @@
syntax python "\.py$"
header "^#!.*python"
magic "Python script"
linter pyflakes
comment "#"
linter pyflakes
# Function definitions.
color brightblue "def [0-9A-Za-z_]+"
# Keywords.

View File

@@ -6,11 +6,11 @@ magic "Ruby script"
linter ruby -w -c
comment "#"
# Constants.
color brightblue "\<[A-Z]+[0-9A-Z_a-z]*|(\$|@|@@)[0-9A-Z_a-z]+"
# Reserved words.
color yellow "\<(BEGIN|END|alias|and|begin|break|case|class|def|defined\?|do|else|elsif|end|ensure|false|for|if|in|module)\>"
color yellow "\<(next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)\>"
# Constants.
color brightblue "(\$|@|@@)?\<[A-Z]+[0-9A-Z_a-z]*"
# Ruby "symbols".
color magenta "([ ]|^):[0-9A-Za-z_]+\>"
# Some unique things we want to stand out.

View File

@@ -3,9 +3,10 @@
syntax sh "(\.sh|\.(a|ba|c|da|k|mk|pdk|tc|z)(sh|shrc|sh_profile)|/(etc/|\.)profile)$"
header "^#!.*/(((a|ba|c|da|k|mk|pdk|tc|z)?sh)|(busybox|env) +sh|openrc-run|runscript)"
magic "(POSIX|Bourne-Again) shell script.*text"
linter dash -n
comment "#"
linter dash -n
# Function declarations.
color brightgreen "^[A-Za-z0-9_-]+\(\)"

View File

@@ -2,9 +2,10 @@
syntax tex "\.tex$"
magic "(La)?TeX document"
linter chktex -v0 -q -I
comment "%"
linter chktex -v0 -q -I
color green "\\.|\\[A-Za-z]*"
color magenta "[{}]"
color blue "(^|[^\])%.*"