Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25ba7712f7 | ||
|
|
a6b534d760 | ||
|
|
494b191d55 | ||
|
|
450bfa7a75 | ||
|
|
a52ac1375a | ||
|
|
4990713e9e | ||
|
|
c022c4cc6d | ||
|
|
6257dec0a7 | ||
|
|
ea9d49b9d8 | ||
|
|
42c7bfcf8a | ||
|
|
e67d1bfeb8 | ||
|
|
e2f444cfdf | ||
|
|
03b85df4eb | ||
|
|
7db5c2f225 | ||
|
|
603ce231d0 | ||
|
|
940b5eaad1 | ||
|
|
fdd946c02c | ||
|
|
81e5b57d74 | ||
|
|
b568705eec | ||
|
|
fe42eb7a1a | ||
|
|
df7b0a6d97 | ||
|
|
fcf598e797 | ||
|
|
d9cb12f6e3 | ||
|
|
0f23729253 | ||
|
|
3def429290 | ||
|
|
803ea0d7a0 | ||
|
|
9b014876cd | ||
|
|
9ccf85eaa8 | ||
|
|
93fa53c3e8 | ||
|
|
eea3e1f0b2 | ||
|
|
e6e22ea976 | ||
|
|
80c2000f87 | ||
|
|
15a0a129c8 | ||
|
|
51bd04b541 | ||
|
|
18ba7f60c1 | ||
|
|
5c3e00d70a | ||
|
|
6c4c77971e | ||
|
|
67adef8f6c | ||
|
|
ed60e16974 | ||
|
|
47c11ae83d | ||
|
|
8173b1bfbe | ||
|
|
93400ec8a1 | ||
|
|
0d85a798e5 |
50
ChangeLog
50
ChangeLog
@@ -1,3 +1,53 @@
|
||||
Changes between v6.2 and v6.3:
|
||||
------------------------------
|
||||
|
||||
Benno Schulenberg (41):
|
||||
build: add the --disable-maintainer-mode option to ./configure
|
||||
build: fix compilation for --enable-{tiny,nanorc,color}
|
||||
build: fix compilation when configured with --disable-color
|
||||
build: remove an obsolete check -- the dependent code was deleted
|
||||
bump version numbers and add a news item for the 6.3 release
|
||||
display: suppress spotlight yellow and error red when NO_COLOR is set
|
||||
docs: add an example binding for copying text to the system clipboard
|
||||
execute: clear an anchor only when the whole buffer gets filtered
|
||||
execute: don't crash when an empty buffer is piped through a command
|
||||
execute: stay on the same line number when filtering the whole buffer
|
||||
feedback: show extra warning when writing failed due to "No space left"
|
||||
files: do not change to a higher directory when the working one is gone
|
||||
files: show a warning when the working directory is gone (when used)
|
||||
files: when the working directory exists, still check its accessibility
|
||||
filtering: close all output descriptors, so that 'xsel' will terminate
|
||||
formatting: change cursor position only after saving it in the undo item
|
||||
gnulib: pull in the workaround for a build problem on NetBSD
|
||||
gnulib: update to its current upstream state
|
||||
justify: stay at the same line number when doing a full justification
|
||||
painting: colorize text also after an unterminated start match
|
||||
painting: look for another start match only after the actual end match
|
||||
painting: recalculate the multidata when making large strides or changes
|
||||
painting: stop coloring an extremely long line after 2000 bytes
|
||||
painting: tighten the check for a lacking end match on a colored line
|
||||
syntax: xml: colorize /> properly, and colorize prolog tags differently
|
||||
syntax: xml: colorize user-defined entities differently
|
||||
tweaks: avoid a function call when two plain assignments will do
|
||||
tweaks: change the indentation of a list, to match other indentations
|
||||
tweaks: don't leave an orphaned temporary file behind when writing fails
|
||||
tweaks: elide an unneeded call of strlen()
|
||||
tweaks: exclude the extra truncation warning from the tiny version
|
||||
tweaks: make the triggering of the recalculation of multidata less eager
|
||||
tweaks: move the saving and restoring of flags to where it is needed
|
||||
tweaks: normalize the indentation after the previous change
|
||||
tweaks: prevent the adding of an unwanted newline in a different way
|
||||
tweaks: remove redundant braces, and add two translator hints
|
||||
tweaks: remove some stray spaces before a comma
|
||||
tweaks: simplify a bit of code, eliding two labels and three gotos
|
||||
tweaks: simplify a fragment of code, and fold two lines together
|
||||
tweaks: trim a few comments, rename a function, and reshuffle some code
|
||||
verbatim: with --zero, keep cursor in viewport when it was on bottom row
|
||||
|
||||
Mike Frysinger (1):
|
||||
general: fix building for Windows
|
||||
|
||||
|
||||
Changes between v6.1 and v6.2:
|
||||
------------------------------
|
||||
|
||||
|
||||
13
NEWS
13
NEWS
@@ -1,3 +1,16 @@
|
||||
2022.04.28 - GNU nano 6.3 "Wat zullen we drinken? Wat een dorst!"
|
||||
• For multiline regexes, text is now colored as soon a start match
|
||||
is found, also when there is no end match at all.
|
||||
• The colorizing of any line is stopped after two thousand bytes,
|
||||
to avoid frustrating delays.
|
||||
• When environment variable NO_COLOR is set, the two default colors
|
||||
(yellow for the spotlight, red for error messages) are suppressed
|
||||
when no interface colors are specified in a nanorc file.
|
||||
• Full justification and piping the whole buffer through a command
|
||||
now keep the cursor at the same line number.
|
||||
• Utility 'xsel' can be used to copy a marked region to the system's
|
||||
clipboard. See doc/sample.nanorc for an example.
|
||||
|
||||
2022.02.18 - GNU nano 6.2 "Kamperfoelie"
|
||||
• The file browser clears the prompt bar also when using --minibar.
|
||||
• Linting now works also with a newer 'pyflakes'.
|
||||
|
||||
2
README
2
README
@@ -15,7 +15,7 @@ Appearance
|
||||
In rough ASCII graphics, this is what nano's screen looks like:
|
||||
|
||||
____________________________________________________________________
|
||||
| GNU nano 6.2 filename Modified |
|
||||
| GNU nano 6.3 filename Modified |
|
||||
--------------------------------------------------------------------
|
||||
| This is the text window, displaying the contents of a 'buffer', |
|
||||
| the contents of the file you are editing. |
|
||||
|
||||
30
README.GIT
30
README.GIT
@@ -8,19 +8,18 @@ building this needs a bit more care than the official tarballs.
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
To successfully compile GNU nano from git, you'll need the following
|
||||
packages:
|
||||
To successfully compile GNU nano from git, you'll need the following:
|
||||
|
||||
- autoconf (version >= 2.69)
|
||||
- automake (version >= 1.14)
|
||||
- autopoint (version >= 0.18.3)
|
||||
- gcc (version >= 5.0)
|
||||
- gettext (version >= 0.18.3)
|
||||
- git (version >= 2.7.4)
|
||||
- groff (version >= 1.12)
|
||||
- make (any version)
|
||||
- pkg-config (version >= 0.22)
|
||||
- texinfo (version >= 4.0)
|
||||
autoconf (version >= 2.69)
|
||||
automake (version >= 1.14)
|
||||
autopoint (version >= 0.18.3)
|
||||
gcc (version >= 5.0)
|
||||
gettext (version >= 0.18.3)
|
||||
git (version >= 2.7.4)
|
||||
groff (version >= 1.12)
|
||||
make (any version)
|
||||
pkg-config (version >= 0.22)
|
||||
texinfo (version >= 4.0)
|
||||
|
||||
You will also need to have the header files for ncurses installed,
|
||||
from libncurses-dev on Debian, ncurses-devel on Fedora, or similar.
|
||||
@@ -29,14 +28,14 @@ These should all be available in your distro's package manager or
|
||||
software center, or otherwise on any GNU mirror.
|
||||
|
||||
|
||||
Download the source
|
||||
-------------------
|
||||
Clone the source
|
||||
----------------
|
||||
|
||||
To obtain the current nano development branch (called 'master'), use the
|
||||
following command. It will create in your current working directory a
|
||||
subdirectory called 'nano' containing a copy of all of the files:
|
||||
|
||||
$ git clone git://git.savannah.gnu.org/nano.git nano
|
||||
$ git clone git://git.savannah.gnu.org/nano.git
|
||||
|
||||
|
||||
Generate the configure script
|
||||
@@ -84,6 +83,7 @@ Problems?
|
||||
Please submit any bugs you find in the code in git via the bug tracker
|
||||
on Savannah (https://savannah.gnu.org/bugs/?group=nano).
|
||||
|
||||
|
||||
Contributing something
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Generate configure & friends for GIT users.
|
||||
|
||||
gnulib_url="git://git.sv.gnu.org/gnulib.git"
|
||||
gnulib_hash="6ef3d783333346333f35bb181ba90f5bc46c0b29"
|
||||
gnulib_hash="34a93be8aa8a15f5959a1b671ad1285a5d552f4b"
|
||||
|
||||
modules="
|
||||
futimens
|
||||
|
||||
21
configure.ac
21
configure.ac
@@ -16,10 +16,11 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
AC_INIT([GNU nano], [6.2], [nano-devel@gnu.org], [nano])
|
||||
AC_INIT([GNU nano], [6.3], [nano-devel@gnu.org], [nano])
|
||||
AC_CONFIG_SRCDIR([src/nano.c])
|
||||
AC_CANONICAL_HOST
|
||||
AM_INIT_AUTOMAKE([1.14])
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
dnl Make sure the ONCE macros are available.
|
||||
@@ -353,6 +354,9 @@ if test "x$enable_utf8" != xno; then
|
||||
AC_CHECK_FUNCS(iswalpha iswalnum iswpunct mbstowcs wctomb)
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS_ONCE(chmod chown fchmod fchown flockfile funlockfile
|
||||
fork fsync geteuid pipe wait waitpid)
|
||||
|
||||
dnl Checks for available flags.
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"], [], [])
|
||||
@@ -510,21 +514,6 @@ int main(void)
|
||||
*** Can't check need for _XOPEN_SOURCE_EXTENDED when cross-compiling.]))
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether LINES and COLS can be redefined])
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <curses.h>
|
||||
int main(void)
|
||||
{
|
||||
LINES = 80;
|
||||
COLS = 25;
|
||||
return 0;
|
||||
}]])],
|
||||
AC_DEFINE(REDEFINING_MACROS_OK, 1, [Define this if you know your curses library allows LINES and COLS to be redefined to deal with a resizing bug.])
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no),
|
||||
AC_MSG_WARN([
|
||||
*** Can't check for macro redefinability when cross-compiling.]))
|
||||
|
||||
AS_IF([test "x$enable_libmagic" != "xno"], [
|
||||
AC_CHECK_HEADERS([magic.h])
|
||||
AC_CHECK_LIB(magic, magic_open)
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
|
||||
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program "establishes a full duplex terminal connection to a remote host", and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
|
||||
<h3><a name="1.4"></a>1.4. What is the current version of nano?</h3>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>6.2</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>6.3</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%">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <https://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH NANO 1 "version 6.2" "February 2022"
|
||||
.TH NANO 1 "version 6.3" "April 2022"
|
||||
|
||||
.SH NAME
|
||||
nano \- Nano's ANOther editor, inspired by Pico
|
||||
|
||||
@@ -13,8 +13,8 @@ The complete manual for the GNU nano text editor.
|
||||
|
||||
@smallbook
|
||||
@set EDITION 0.6
|
||||
@set VERSION 6.2
|
||||
@set UPDATED February 2022
|
||||
@set VERSION 6.3
|
||||
@set UPDATED April 2022
|
||||
|
||||
@dircategory Editors
|
||||
@direntry
|
||||
@@ -29,7 +29,7 @@ The complete manual for the GNU nano text editor.
|
||||
|
||||
@title GNU @command{nano}
|
||||
@subtitle a small and friendly text editor
|
||||
@subtitle version 6.2
|
||||
@subtitle version 6.3
|
||||
|
||||
@author Chris Allegretta
|
||||
|
||||
@@ -76,7 +76,7 @@ For suggesting improvements: @email{nano-devel@@gnu.org}
|
||||
@node Top
|
||||
@top
|
||||
|
||||
This manual documents GNU @command{nano}, version 6.2.
|
||||
This manual documents GNU @command{nano}, version 6.3.
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <https://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH NANORC 5 "version 6.2" "February 2022"
|
||||
.TH NANORC 5 "version 6.3" "April 2022"
|
||||
|
||||
.SH NAME
|
||||
nanorc \- GNU nano's configuration file
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <https://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH RNANO 1 "version 6.2" "February 2022"
|
||||
.TH RNANO 1 "version 6.3" "April 2022"
|
||||
|
||||
.SH NAME
|
||||
rnano \- a restricted nano
|
||||
|
||||
@@ -291,6 +291,9 @@
|
||||
# bind Sh-M-U "Oc[1;6D|sed 's/.*/\U&/'
|
||||
" main
|
||||
# bind Sh-M-L "Oc[1;6D|sed 's/.*/\L&/'
|
||||
" main
|
||||
|
||||
## For copying a marked region to the system clipboard:
|
||||
# bind Sh-M-T "|xsel -ib
|
||||
u" main
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# List of available languages.
|
||||
bg ca cs da de eo es eu fi fr ga gl hr hu id is it ja ko ms nb nl pl pt pt_BR ro ru sk sl sr sv tr uk vi zh_CN zh_TW
|
||||
bg ca cs da de eo es eu fi fr ga gl hr hu id is it ja ko ms nb nl pl pt pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_TW
|
||||
|
||||
862
po/nano.pot
862
po/nano.pot
File diff suppressed because it is too large
Load Diff
854
po/pt_BR.po
854
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
864
po/zh_CN.po
864
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
860
po/zh_TW.po
860
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION="6.2"
|
||||
VERSION="6.3"
|
||||
|
||||
./configure -C --enable-tiny && make && ./configure -C &&
|
||||
|
||||
|
||||
@@ -47,9 +47,10 @@ static size_t selected = 0;
|
||||
* files that can be displayed per screen row. And sort the list too. */
|
||||
void read_the_list(const char *path, DIR *dir)
|
||||
{
|
||||
size_t path_len = strlen(path), index = 0;
|
||||
size_t path_len = strlen(path);
|
||||
const struct dirent *entry;
|
||||
size_t widest = 0;
|
||||
size_t index = 0;
|
||||
|
||||
/* Find the width of the widest filename in the current folder. */
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
@@ -91,9 +92,8 @@ void read_the_list(const char *path, DIR *dir)
|
||||
index++;
|
||||
}
|
||||
|
||||
/* Maybe the number of files in the directory decreased between the
|
||||
* first time we scanned and the second time. index is the actual
|
||||
* length of the file list, so record it. */
|
||||
/* Maybe the number of files in the directory decreased between
|
||||
* the first time we scanned and the second time. */
|
||||
list_length = index;
|
||||
|
||||
/* Sort the list of names. */
|
||||
@@ -107,28 +107,23 @@ void read_the_list(const char *path, DIR *dir)
|
||||
usable_rows = editwinrows - (ISSET(ZERO) && LINES > 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Look for needle. If we find it, set selected to its location.
|
||||
* Note that needle must be an exact match for a file in the list. */
|
||||
void browser_select_dirname(const char *needle)
|
||||
/* Reselect the given file or directory name, if it still exists. */
|
||||
void reselect(const char *name)
|
||||
{
|
||||
size_t looking_at = 0;
|
||||
|
||||
for (; looking_at < list_length; looking_at++) {
|
||||
if (strcmp(filelist[looking_at], needle) == 0) {
|
||||
selected = looking_at;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (looking_at < list_length && strcmp(filelist[looking_at], name) != 0)
|
||||
looking_at++;
|
||||
|
||||
/* If the sought name isn't found, move the highlight so that the
|
||||
* changed selection will be noticed. */
|
||||
if (looking_at == list_length) {
|
||||
/* If the sought name was found, select it; otherwise, just move
|
||||
* the highlight so that the changed selection will be noticed,
|
||||
* but make sure to stay within the current available range. */
|
||||
if (looking_at < list_length)
|
||||
selected = looking_at;
|
||||
else if (selected > list_length)
|
||||
selected = list_length - 1;
|
||||
else
|
||||
--selected;
|
||||
|
||||
/* Make sure we stay within the available range. */
|
||||
if (selected >= list_length)
|
||||
selected = list_length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Display at most a screenful of filenames from the gleaned filelist. */
|
||||
@@ -450,13 +445,12 @@ char *browse(char *path)
|
||||
dir = NULL;
|
||||
}
|
||||
|
||||
/* If given, reselect the present_name and then discard it. */
|
||||
/* If something was selected before, reselect it;
|
||||
* otherwise, just select the first item (..). */
|
||||
if (present_name != NULL) {
|
||||
browser_select_dirname(present_name);
|
||||
|
||||
reselect(present_name);
|
||||
free(present_name);
|
||||
present_name = NULL;
|
||||
/* Otherwise, select the first file or directory in the list. */
|
||||
} else
|
||||
selected = 0;
|
||||
|
||||
@@ -715,14 +709,10 @@ char *browse_in(const char *inpath)
|
||||
path = free_and_assign(path, strip_last_component(path));
|
||||
|
||||
if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
|
||||
char *currentdir = nmalloc(PATH_MAX + 1);
|
||||
|
||||
path = free_and_assign(path, getcwd(currentdir, PATH_MAX + 1));
|
||||
path = free_and_assign(path, realpath(".", NULL));
|
||||
|
||||
if (path == NULL) {
|
||||
statusline(MILD, _("The working directory has disappeared"));
|
||||
free(currentdir);
|
||||
beep();
|
||||
statusline(ALERT, _("The working directory has disappeared"));
|
||||
napms(1200);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
31
src/color.c
31
src/color.c
@@ -53,6 +53,7 @@ void set_interface_colorpairs(void)
|
||||
}
|
||||
init_pair(index + 1, combo->fg, combo->bg);
|
||||
interface_color_pair[index] = COLOR_PAIR(index + 1) | combo->attributes;
|
||||
rescind_colors = FALSE;
|
||||
} else {
|
||||
if (index == FUNCTION_TAG || index == SCROLL_BAR)
|
||||
interface_color_pair[index] = A_NORMAL;
|
||||
@@ -72,6 +73,11 @@ void set_interface_colorpairs(void)
|
||||
|
||||
free(color_combo[index]);
|
||||
}
|
||||
|
||||
if (rescind_colors) {
|
||||
interface_color_pair[SPOTLIGHTED] = A_REVERSE;
|
||||
interface_color_pair[ERROR_MESSAGE] = A_REVERSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign a pair number to each of the foreground/background color combinations
|
||||
@@ -255,12 +261,14 @@ void check_the_multis(linestruct *line)
|
||||
if (line->multidata[ink->id] == NOTHING) {
|
||||
if (!astart)
|
||||
continue;
|
||||
} else if (line->multidata[ink->id] & (WHOLELINE|WOULDBE)) {
|
||||
if (!astart && !anend)
|
||||
} else if (line->multidata[ink->id] == WHOLELINE) {
|
||||
/* Ensure that a detected start match is not actually an end match. */
|
||||
if (!anend && (!astart || regexec(ink->end, line->data, 1,
|
||||
&endmatch, 0) != 0))
|
||||
continue;
|
||||
} else if (line->multidata[ink->id] == JUSTONTHIS) {
|
||||
if (astart && anend && regexec(ink->start, line->data + endmatch.rm_eo,
|
||||
1, &startmatch, 0) != 0)
|
||||
if (astart && anend && regexec(ink->start, line->data + startmatch.rm_eo +
|
||||
endmatch.rm_eo, 1, &startmatch, 0) != 0)
|
||||
continue;
|
||||
} else if (line->multidata[ink->id] == STARTSHERE) {
|
||||
if (astart && !anend)
|
||||
@@ -272,6 +280,7 @@ void check_the_multis(linestruct *line)
|
||||
|
||||
/* There is a mismatch, so something changed: repaint. */
|
||||
refresh_needed = TRUE;
|
||||
perturbed = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -342,21 +351,17 @@ void precalc_multicolorinfo(void)
|
||||
1, &endmatch, 0) != 0)
|
||||
tailline = tailline->next;
|
||||
|
||||
/* When there is no end match, mark relevant lines as such. */
|
||||
if (tailline == NULL) {
|
||||
for (; line->next != NULL; line = line->next)
|
||||
line->multidata[ink->id] = WOULDBE;
|
||||
line->multidata[ink->id] = WOULDBE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We found it, we found it, la lala lala. Mark the lines. */
|
||||
line->multidata[ink->id] = STARTSHERE;
|
||||
|
||||
// Note that this also advances the line in the main loop.
|
||||
for (line = line->next; line != tailline; line = line->next)
|
||||
line->multidata[ink->id] = WHOLELINE;
|
||||
|
||||
if (tailline == NULL) {
|
||||
line = openfile->filebot;
|
||||
break;
|
||||
}
|
||||
|
||||
tailline->multidata[ink->id] = ENDSHERE;
|
||||
|
||||
/* Look for a possible new start after the end match. */
|
||||
|
||||
15
src/cut.c
15
src/cut.c
@@ -435,9 +435,19 @@ void ingraft_buffer(linestruct *topline)
|
||||
/* Meld a copy of the given buffer into the current file buffer. */
|
||||
void copy_from_buffer(linestruct *somebuffer)
|
||||
{
|
||||
#ifdef ENABLE_COLOR
|
||||
size_t threshold = openfile->edittop->lineno + editwinrows - 1;
|
||||
#endif
|
||||
linestruct *the_copy = copy_buffer(somebuffer);
|
||||
|
||||
ingraft_buffer(the_copy);
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (openfile->current->lineno > threshold || ISSET(SOFTWRAP))
|
||||
recook = TRUE;
|
||||
else
|
||||
perturbed = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
@@ -485,7 +495,7 @@ void do_snip(bool marked, bool until_eof, bool append)
|
||||
/* When not at the end of a line, move the rest of this line into
|
||||
* the cutbuffer. Otherwise, when not at the end of the buffer,
|
||||
* move just the "line separator" into the cutbuffer. */
|
||||
if (openfile->current_x < strlen(openfile->current->data))
|
||||
if (line->data[openfile->current_x] != '\0')
|
||||
extract_segment(line, openfile->current_x, line, strlen(line->data));
|
||||
else if (openfile->current != openfile->filebot) {
|
||||
extract_segment(line, openfile->current_x, line->next, 0);
|
||||
@@ -509,6 +519,9 @@ void do_snip(bool marked, bool until_eof, bool append)
|
||||
|
||||
set_modified();
|
||||
refresh_needed = TRUE;
|
||||
#ifdef ENABLE_COLOR
|
||||
perturbed = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Move text from the current buffer into the cutbuffer. */
|
||||
|
||||
@@ -170,8 +170,6 @@
|
||||
/* The start regex matches on an earlier line, the end regex on this one. */
|
||||
#define JUSTONTHIS (1<<5)
|
||||
/* Both the start and end regexes match within this line. */
|
||||
#define WOULDBE (1<<6)
|
||||
/* An unpaired start match is on or before this line. */
|
||||
#endif
|
||||
|
||||
/* Basic control codes. */
|
||||
|
||||
176
src/files.c
176
src/files.c
@@ -33,6 +33,10 @@
|
||||
|
||||
#define RW_FOR_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
|
||||
|
||||
#ifndef HAVE_FSYNC
|
||||
# define fsync(...) 0
|
||||
#endif
|
||||
|
||||
/* Add an item to the circular list of openfile structs. */
|
||||
void make_new_buffer(void)
|
||||
{
|
||||
@@ -143,7 +147,7 @@ const char *locking_suffix = ".swp";
|
||||
* existing version of that file. Return TRUE on success; FALSE otherwise. */
|
||||
bool write_lockfile(const char *lockfilename, const char *filename, bool modified)
|
||||
{
|
||||
#ifdef HAVE_PWD_H
|
||||
#if defined(HAVE_PWD_H) && defined(HAVE_GETEUID)
|
||||
pid_t mypid = getpid();
|
||||
uid_t myuid = geteuid();
|
||||
struct passwd *mypwuid = getpwuid(myuid);
|
||||
@@ -346,8 +350,18 @@ bool has_valid_path(const char *filename)
|
||||
char *parentdir = dirname(namecopy);
|
||||
struct stat parentinfo;
|
||||
bool validity = FALSE;
|
||||
bool gone = FALSE;
|
||||
|
||||
if (stat(parentdir, &parentinfo) == -1) {
|
||||
if (strcmp(parentdir, ".") == 0) {
|
||||
char *currentdir = realpath(".", NULL);
|
||||
|
||||
gone = (currentdir == NULL && errno == ENOENT);
|
||||
free(currentdir);
|
||||
}
|
||||
|
||||
if (gone)
|
||||
statusline(ALERT, _("The working directory has disappeared"));
|
||||
else if (stat(parentdir, &parentinfo) == -1) {
|
||||
if (errno == ENOENT)
|
||||
/* TRANSLATORS: Keep the next ten messages at most 76 characters. */
|
||||
statusline(ALERT, _("Directory '%s' does not exist"), parentdir);
|
||||
@@ -411,7 +425,7 @@ bool open_buffer(const char *filename, bool new_one)
|
||||
free(realname);
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
#elif defined(HAVE_GETEUID)
|
||||
if (new_one && !(fileinfo.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) &&
|
||||
geteuid() == ROOT_UID)
|
||||
statusline(ALERT, _("%s is meant to be read-only"), realname);
|
||||
@@ -675,9 +689,13 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
||||
block_sigwinch(TRUE);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FLOCKFILE
|
||||
/* Lock the file before starting to read it, to avoid the overhead
|
||||
* of locking it for each single byte that we read from it. */
|
||||
flockfile(f);
|
||||
#else
|
||||
# define getc_unlocked getc
|
||||
#endif
|
||||
|
||||
control_C_was_pressed = FALSE;
|
||||
|
||||
@@ -741,8 +759,10 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
||||
|
||||
errornumber = errno;
|
||||
|
||||
#ifdef HAVE_FUNLOCKFILE
|
||||
/* We are done with the file, unlock it. */
|
||||
funlockfile(f);
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
block_sigwinch(FALSE);
|
||||
@@ -826,12 +846,14 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
||||
report_size = TRUE;
|
||||
|
||||
/* If we inserted less than a screenful, don't center the cursor. */
|
||||
if (undoable && less_than_a_screenful(was_lineno, was_leftedge))
|
||||
if (undoable && less_than_a_screenful(was_lineno, was_leftedge)) {
|
||||
focusing = FALSE;
|
||||
#ifdef ENABLE_COLOR
|
||||
else if (undoable)
|
||||
precalc_multicolorinfo();
|
||||
perturbed = TRUE;
|
||||
} else if (undoable) {
|
||||
recook = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (undoable)
|
||||
@@ -950,7 +972,9 @@ static pid_t pid_of_command = -1;
|
||||
/* Send an unconditional kill signal to the running external command. */
|
||||
void cancel_the_command(int signal)
|
||||
{
|
||||
#ifdef SIGKILL
|
||||
kill(pid_of_command, SIGKILL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Send the text that starts at the given line to file descriptor fd. */
|
||||
@@ -973,10 +997,12 @@ void send_data(const linestruct *line, int fd)
|
||||
/* Execute the given command in a shell. Return TRUE on success. */
|
||||
bool execute_command(const char *command)
|
||||
{
|
||||
#if defined(HAVE_FORK) && defined(HAVE_PIPE) && defined(HAVE_WAIT)
|
||||
int from_fd[2], to_fd[2];
|
||||
/* The pipes through which text will be written and read. */
|
||||
struct sigaction oldaction, newaction = {{0}};
|
||||
/* Original and temporary handlers for SIGINT. */
|
||||
ssize_t was_lineno = (openfile->mark ? 0 : openfile->current->lineno);
|
||||
const bool should_pipe = (command[0] == '|');
|
||||
FILE *stream;
|
||||
|
||||
@@ -1008,6 +1034,7 @@ bool execute_command(const char *command)
|
||||
if (should_pipe) {
|
||||
if (dup2(to_fd[0], STDIN_FILENO) < 0)
|
||||
exit(5);
|
||||
close(from_fd[1]);
|
||||
close(to_fd[1]);
|
||||
}
|
||||
|
||||
@@ -1054,7 +1081,8 @@ bool execute_command(const char *command)
|
||||
}
|
||||
add_undo(CUT, NULL);
|
||||
do_snip(openfile->mark != NULL, openfile->mark == NULL, FALSE);
|
||||
openfile->filetop->has_anchor = FALSE;
|
||||
if (openfile->filetop->next == NULL)
|
||||
openfile->filetop->has_anchor = FALSE;
|
||||
update_undo(CUT);
|
||||
}
|
||||
|
||||
@@ -1090,8 +1118,11 @@ bool execute_command(const char *command)
|
||||
else
|
||||
read_file(stream, 0, "pipe", TRUE);
|
||||
|
||||
if (should_pipe && !ISSET(MULTIBUFFER))
|
||||
if (should_pipe && !ISSET(MULTIBUFFER)) {
|
||||
if (was_lineno)
|
||||
goto_line_posx(was_lineno, 0);
|
||||
add_undo(COUPLE_END, N_("filtering"));
|
||||
}
|
||||
|
||||
/* Wait for the external command (and possibly data sender) to terminate. */
|
||||
wait(NULL);
|
||||
@@ -1106,6 +1137,9 @@ bool execute_command(const char *command)
|
||||
terminal_init();
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
#endif /* NANO_TINY */
|
||||
|
||||
@@ -1322,106 +1356,36 @@ void do_execute(void)
|
||||
* absolute path (plus filename) when the path exists, and NULL when not. */
|
||||
char *get_full_path(const char *origpath)
|
||||
{
|
||||
char *allocation, *here, *target, *last_slash;
|
||||
char *just_filename = NULL;
|
||||
int attempts = 0;
|
||||
char *untilded, *target, *slash;
|
||||
struct stat fileinfo;
|
||||
bool path_only;
|
||||
|
||||
if (origpath == NULL)
|
||||
return NULL;
|
||||
|
||||
allocation = nmalloc(PATH_MAX + 1);
|
||||
here = getcwd(allocation, PATH_MAX + 1);
|
||||
untilded = real_dir_from_tilde(origpath);
|
||||
target = realpath(untilded, NULL);
|
||||
slash = strrchr(untilded, '/');
|
||||
|
||||
/* If getting the current directory failed, go up one level and try again,
|
||||
* until we find an existing directory, and use that as the current one. */
|
||||
while (here == NULL && attempts < 20) {
|
||||
IGNORE_CALL_RESULT(chdir(".."));
|
||||
here = getcwd(allocation, PATH_MAX + 1);
|
||||
attempts++;
|
||||
}
|
||||
/* If realpath() returned NULL, try without the last component,
|
||||
* as this can be a file that does not exist yet. */
|
||||
if (!target && slash && slash[1]) {
|
||||
*slash = '\0';
|
||||
target = realpath(untilded, NULL);
|
||||
|
||||
/* If we found a directory, make sure its path ends in a slash. */
|
||||
if (here != NULL) {
|
||||
if (strcmp(here, "/") != 0) {
|
||||
here = nrealloc(here, strlen(here) + 2);
|
||||
strcat(here, "/");
|
||||
}
|
||||
} else {
|
||||
here = copy_of("");
|
||||
free(allocation);
|
||||
}
|
||||
|
||||
target = real_dir_from_tilde(origpath);
|
||||
|
||||
/* Determine whether the target path refers to a directory. If statting
|
||||
* target fails, however, assume that it refers to a new, unsaved buffer. */
|
||||
path_only = (stat(target, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode));
|
||||
|
||||
/* If the target is a directory, make sure its path ends in a slash. */
|
||||
if (path_only) {
|
||||
size_t length = strlen(target);
|
||||
|
||||
if (target[length - 1] != '/') {
|
||||
target = nrealloc(target, length + 2);
|
||||
strcat(target, "/");
|
||||
/* Upon success, re-add the last component of the original path. */
|
||||
if (target) {
|
||||
target = nrealloc(target, strlen(target) + strlen(slash + 1) + 1);
|
||||
strcat(target, slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
last_slash = strrchr(target, '/');
|
||||
|
||||
/* If the target path does not contain a slash, then it is a bare filename
|
||||
* and must therefore be located in the working directory. */
|
||||
if (last_slash == NULL) {
|
||||
just_filename = target;
|
||||
target = here;
|
||||
} else {
|
||||
/* If target contains a filename, separate the two. */
|
||||
if (!path_only) {
|
||||
just_filename = copy_of(last_slash + 1);
|
||||
*(last_slash + 1) = '\0';
|
||||
}
|
||||
|
||||
/* If we can't change to the target directory, give up. Otherwise,
|
||||
* get the canonical path to this target directory. */
|
||||
if (chdir(target) == -1) {
|
||||
free(target);
|
||||
target = NULL;
|
||||
} else {
|
||||
free(target);
|
||||
|
||||
allocation = nmalloc(PATH_MAX + 1);
|
||||
target = getcwd(allocation, PATH_MAX + 1);
|
||||
|
||||
/* If we got a result, make sure it ends in a slash.
|
||||
* Otherwise, ensure that we return NULL. */
|
||||
if (target != NULL) {
|
||||
if (strcmp(target, "/") != 0) {
|
||||
target = nrealloc(target, strlen(target) + 2);
|
||||
strcat(target, "/");
|
||||
}
|
||||
} else {
|
||||
path_only = TRUE;
|
||||
free(allocation);
|
||||
}
|
||||
|
||||
/* Finally, go back to where we were before. We don't check
|
||||
* for an error, since we can't do anything if we get one. */
|
||||
IGNORE_CALL_RESULT(chdir(here));
|
||||
}
|
||||
|
||||
free(here);
|
||||
/* Ensure that a directory path ends with a slash. */
|
||||
if (target && stat(target, &fileinfo) == 0 && S_ISDIR(fileinfo.st_mode)) {
|
||||
target = nrealloc(target, strlen(target) + 2);
|
||||
strcat(target, "/");
|
||||
}
|
||||
|
||||
/* If we were given more than a bare path, concatenate the target path
|
||||
* with the filename portion to get the full, absolute file path. */
|
||||
if (!path_only && target != NULL) {
|
||||
target = nrealloc(target, strlen(target) + strlen(just_filename) + 1);
|
||||
strcat(target, just_filename);
|
||||
}
|
||||
|
||||
free(just_filename);
|
||||
free(untilded);
|
||||
|
||||
return target;
|
||||
}
|
||||
@@ -1653,6 +1617,7 @@ bool make_backup_of(char *realname)
|
||||
if (backup_file == NULL)
|
||||
goto problem;
|
||||
|
||||
#ifdef HAVE_FCHOWN
|
||||
/* Try to change owner and group to those of the original file;
|
||||
* ignore permission errors, as a normal user cannot change the owner. */
|
||||
if (fchown(descriptor, openfile->statinfo->st_uid,
|
||||
@@ -1660,7 +1625,8 @@ bool make_backup_of(char *realname)
|
||||
fclose(backup_file);
|
||||
goto problem;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_FCHMOD
|
||||
/* Set the backup's permissions to those of the original file.
|
||||
* It is not a security issue if this fails, as we have created
|
||||
* the file with just read and write permission for the owner. */
|
||||
@@ -1668,6 +1634,7 @@ bool make_backup_of(char *realname)
|
||||
fclose(backup_file);
|
||||
goto problem;
|
||||
}
|
||||
#endif
|
||||
|
||||
original = fopen(realname, "rb");
|
||||
|
||||
@@ -1974,6 +1941,19 @@ bool write_file(const char *name, FILE *thefile, bool normal,
|
||||
statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
|
||||
|
||||
cleanup_and_exit:
|
||||
#ifndef NANO_TINY
|
||||
if (errno == ENOSPC && normal) {
|
||||
napms(3200); lastmessage = VACUUM;
|
||||
/* TRANSLATORS: This warns for data loss when the disk is full. */
|
||||
statusline(ALERT, _("File on disk has been truncated!"));
|
||||
napms(3200); lastmessage = VACUUM;
|
||||
/* TRANSLATORS: This is a suggestion to the user,
|
||||
* where "resume" means resuming from suspension.
|
||||
* Try to keep this at most 76 characters. */
|
||||
statusline(ALERT, _("Maybe ^T^Z, make room on disk, resume, then ^S^X"));
|
||||
stat_with_alloc(realname, &openfile->statinfo);
|
||||
}
|
||||
#endif
|
||||
free(tempname);
|
||||
free(realname);
|
||||
return FALSE;
|
||||
@@ -2055,7 +2035,7 @@ bool write_region_to_file(const char *name, FILE *stream, bool normal,
|
||||
get_region(&topline, &top_x, &botline, &bot_x);
|
||||
|
||||
/* When needed, prepare a magic end line for the region. */
|
||||
if (bot_x > 0 && !ISSET(NO_NEWLINES)) {
|
||||
if (normal && bot_x > 0 && !ISSET(NO_NEWLINES)) {
|
||||
stopper = make_new_node(botline);
|
||||
stopper->data = copy_of("");
|
||||
} else
|
||||
|
||||
@@ -201,6 +201,12 @@ char *syntaxstr = NULL;
|
||||
/* The color syntax name specified on the command line. */
|
||||
bool have_palette = FALSE;
|
||||
/* Whether the colors for the current syntax have been initialized. */
|
||||
bool rescind_colors = FALSE;
|
||||
/* Becomes TRUE when NO_COLOR is set in the environment. */
|
||||
bool perturbed = FALSE;
|
||||
/* Whether the multiline-coloring situation has changed. */
|
||||
bool recook = FALSE;
|
||||
/* Whether the multidata should be recalculated. */
|
||||
#endif
|
||||
|
||||
int currmenu = MMOST;
|
||||
|
||||
@@ -44,6 +44,9 @@ void to_last_line(void)
|
||||
openfile->current_y = editwinrows - 1;
|
||||
|
||||
refresh_needed = TRUE;
|
||||
#ifdef ENABLE_COLOR
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
focusing = FALSE;
|
||||
}
|
||||
|
||||
@@ -222,6 +225,9 @@ void to_para_end(void)
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
|
||||
edit_redraw(was_current, CENTERING);
|
||||
#ifdef ENABLE_COLOR
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
}
|
||||
#endif /* ENABLE_JUSTIFY */
|
||||
|
||||
@@ -263,6 +269,9 @@ void to_next_block(void)
|
||||
|
||||
openfile->current_x = 0;
|
||||
edit_redraw(was_current, CENTERING);
|
||||
#ifdef ENABLE_COLOR
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Move to the previous word. */
|
||||
|
||||
18
src/nano.c
18
src/nano.c
@@ -26,7 +26,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#if defined(__linux__) || !defined(NANO_TINY)
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef ENABLE_UTF8
|
||||
@@ -339,7 +339,7 @@ void emergency_save(const char *filename)
|
||||
fprintf(stderr, _("\nToo many .save files\n"));
|
||||
else if (write_file(targetname, NULL, SPECIAL, OVERWRITE, NONOTES)) {
|
||||
fprintf(stderr, _("\nBuffer written to %s\n"), targetname);
|
||||
#ifndef NANO_TINY
|
||||
#if !defined(NANO_TINY) && defined(HAVE_CHMOD) && defined(HAVE_CHOWN)
|
||||
/* Try to chmod/chown the saved file to the values of the original file,
|
||||
* but ignore any failure as we are in a hurry to get out. */
|
||||
if (openfile->statinfo) {
|
||||
@@ -894,10 +894,11 @@ void signal_init(void)
|
||||
sigaction(SIGTERM, &deed, NULL);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
#ifdef SIGWINCH
|
||||
/* Trap SIGWINCH because we want to handle window resizes. */
|
||||
deed.sa_handler = handle_sigwinch;
|
||||
sigaction(SIGWINCH, &deed, NULL);
|
||||
|
||||
#endif
|
||||
#ifdef SIGTSTP
|
||||
/* Prevent the suspend handler from getting interrupted. */
|
||||
sigfillset(&deed.sa_mask);
|
||||
@@ -998,11 +999,13 @@ void continue_nano(int signal)
|
||||
/* Block or unblock the SIGWINCH signal, depending on the blockit parameter. */
|
||||
void block_sigwinch(bool blockit)
|
||||
{
|
||||
#ifdef SIGWINCH
|
||||
sigset_t winch;
|
||||
|
||||
sigemptyset(&winch);
|
||||
sigaddset(&winch, SIGWINCH);
|
||||
sigprocmask(blockit ? SIG_BLOCK : SIG_UNBLOCK, &winch, NULL);
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (the_window_resized)
|
||||
@@ -1786,10 +1789,12 @@ int main(int argc, char **argv)
|
||||
/* Back up the terminal settings so that they can be restored. */
|
||||
tcgetattr(STDIN_FILENO, &original_state);
|
||||
|
||||
#if defined(F_GETFL) && defined(F_SETFL)
|
||||
/* Get the state of standard input and ensure it uses blocking mode. */
|
||||
stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
if (stdin_flags != -1)
|
||||
fcntl(STDIN_FILENO, F_SETFL, stdin_flags & ~O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UTF8
|
||||
/* If setting the locale is successful and it uses UTF-8, we will
|
||||
@@ -2072,7 +2077,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Curses needs TERM; if it is unset, try falling back to a VT220. */
|
||||
if (getenv("TERM") == NULL)
|
||||
setenv("TERM", "vt220", 0);
|
||||
putenv("TERM=vt220");
|
||||
|
||||
/* Enter into curses mode. Abort if this fails. */
|
||||
if (initscr() == NULL)
|
||||
@@ -2082,6 +2087,9 @@ int main(int argc, char **argv)
|
||||
/* If the terminal can do colors, tell ncurses to switch them on. */
|
||||
if (has_colors())
|
||||
start_color();
|
||||
|
||||
/* When requested, suppress the default spotlight and error colors. */
|
||||
rescind_colors = (getenv("NO_COLOR") != NULL);
|
||||
#endif
|
||||
|
||||
/* Set up the function and shortcut lists. This needs to be done
|
||||
@@ -2558,7 +2566,7 @@ int main(int argc, char **argv)
|
||||
edit_scroll(FORWARD);
|
||||
wnoutrefresh(midwin);
|
||||
}
|
||||
wredrawln(footwin, 0 ,1);
|
||||
wredrawln(footwin, 0, 1);
|
||||
wnoutrefresh(footwin);
|
||||
place_the_cursor();
|
||||
} else if (ISSET(ZERO) && lastmessage > VACUUM)
|
||||
|
||||
@@ -229,7 +229,7 @@ void inject_into_answer(char *burst, size_t count)
|
||||
answer = nrealloc(answer, strlen(answer) + count + 1);
|
||||
memmove(answer + typing_x + count, answer + typing_x,
|
||||
strlen(answer) - typing_x + 1);
|
||||
strncpy(answer + typing_x, burst , count);
|
||||
strncpy(answer + typing_x, burst, count);
|
||||
|
||||
typing_x += count;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,9 @@ extern char *alt_speller;
|
||||
extern syntaxtype *syntaxes;
|
||||
extern char *syntaxstr;
|
||||
extern bool have_palette;
|
||||
extern bool rescind_colors;
|
||||
extern bool perturbed;
|
||||
extern bool recook;
|
||||
#endif
|
||||
|
||||
extern bool refresh_needed;
|
||||
|
||||
24
src/search.c
24
src/search.c
@@ -65,6 +65,9 @@ void tidy_up_after_search(void)
|
||||
if (openfile->mark)
|
||||
refresh_needed = TRUE;
|
||||
#endif
|
||||
#ifdef ENABLE_COLOR
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Prepare the prompt and ask the user what to search for. Keep looping
|
||||
@@ -657,6 +660,10 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
|
||||
free(openfile->current->data);
|
||||
openfile->current->data = altered;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
check_the_multis(openfile->current);
|
||||
refresh_needed = FALSE;
|
||||
#endif
|
||||
set_modified();
|
||||
as_an_at = TRUE;
|
||||
numreplaced++;
|
||||
@@ -732,6 +739,12 @@ void ask_for_and_do_replacements(void)
|
||||
/* Go to the specified line and x position. */
|
||||
void goto_line_posx(ssize_t line, size_t pos_x)
|
||||
{
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
|
||||
for (openfile->current = openfile->filetop; line > 1 &&
|
||||
openfile->current != openfile->filebot; line--)
|
||||
openfile->current = openfile->current->next;
|
||||
@@ -790,6 +803,12 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
||||
if (line < 1)
|
||||
line = 1;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
|
||||
/* Iterate to the requested line. */
|
||||
for (openfile->current = openfile->filetop; line > 1 &&
|
||||
openfile->current != openfile->filebot; line--)
|
||||
@@ -992,6 +1011,11 @@ void go_to_and_confirm(linestruct *line)
|
||||
if (line != openfile->current) {
|
||||
openfile->current = line;
|
||||
openfile->current_x = 0;
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line->lineno > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
edit_redraw(was_current, CENTERING);
|
||||
statusbar(_("Jumped to anchor"));
|
||||
} else if (openfile->current->has_anchor)
|
||||
|
||||
82
src/text.c
82
src/text.c
@@ -558,7 +558,8 @@ void do_undo(void)
|
||||
* and the nonewlines flag isn't set, do not re-add a newline that
|
||||
* wasn't actually deleted; just position the cursor. */
|
||||
if ((u->xflags & WAS_BACKSPACE_AT_EOF) && !ISSET(NO_NEWLINES)) {
|
||||
goto_line_posx(openfile->filebot->lineno, 0);
|
||||
openfile->current = openfile->filebot;
|
||||
openfile->current_x = 0;
|
||||
break;
|
||||
}
|
||||
line->data[u->tail_x] = '\0';
|
||||
@@ -665,6 +666,13 @@ void do_undo(void)
|
||||
|
||||
openfile->totsize = u->wassize;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (u->type <= REPLACE)
|
||||
check_the_multis(openfile->current);
|
||||
else if (u->type == INSERT)
|
||||
perturbed = TRUE;
|
||||
#endif
|
||||
|
||||
/* When at the point where the buffer was last saved, unset "Modified". */
|
||||
if (openfile->current_undo == openfile->last_saved) {
|
||||
openfile->modified = FALSE;
|
||||
@@ -825,6 +833,13 @@ void do_redo(void)
|
||||
|
||||
openfile->totsize = u->newsize;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (u->type <= REPLACE)
|
||||
check_the_multis(openfile->current);
|
||||
else if (u->type == INSERT)
|
||||
recook = TRUE;
|
||||
#endif
|
||||
|
||||
/* When at the point where the buffer was last saved, unset "Modified". */
|
||||
if (openfile->current_undo == openfile->last_saved) {
|
||||
openfile->modified = FALSE;
|
||||
@@ -1177,7 +1192,8 @@ void update_undo(undo_type action)
|
||||
else if (cutbuffer != NULL) {
|
||||
free_lines(u->cutbuffer);
|
||||
u->cutbuffer = copy_buffer(cutbuffer);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
if (!(u->xflags & MARK_WAS_SET)) {
|
||||
linestruct *bottomline = u->cutbuffer;
|
||||
size_t count = 0;
|
||||
@@ -1745,6 +1761,8 @@ void justify_text(bool whole_buffer)
|
||||
/* The leading part for lines after the first one. */
|
||||
size_t secondary_len = 0;
|
||||
/* The length of that later lead. */
|
||||
ssize_t was_the_linenumber = openfile->current->lineno;
|
||||
/* The line to return to after a full justification. */
|
||||
|
||||
/* TRANSLATORS: This one goes with Undid/Redid messages. */
|
||||
add_undo(COUPLE_BEGIN, N_("justification"));
|
||||
@@ -1961,7 +1979,8 @@ void justify_text(bool whole_buffer)
|
||||
openfile->current_x = openfile->mark_x;
|
||||
openfile->mark = bottom;
|
||||
openfile->mark_x = bottom_x;
|
||||
}
|
||||
} else if (whole_buffer && !openfile->mark)
|
||||
goto_line_posx(was_the_linenumber, 0);
|
||||
|
||||
add_undo(COUPLE_END, N_("justification"));
|
||||
|
||||
@@ -2031,11 +2050,19 @@ bool replace_buffer(const char *filename, undo_type action, const char *operatio
|
||||
if (descriptor < 0)
|
||||
return FALSE;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_undo(COUPLE_BEGIN, operation);
|
||||
#endif
|
||||
|
||||
/* When replacing the whole buffer, start cutting at the top. */
|
||||
if (action == CUT_TO_EOF) {
|
||||
openfile->current = openfile->filetop;
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
|
||||
cutbuffer = NULL;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_undo(COUPLE_BEGIN, operation);
|
||||
|
||||
/* Cut either the marked region or the whole buffer. */
|
||||
add_undo(action, NULL);
|
||||
do_snip(openfile->mark != NULL, openfile->mark == NULL, FALSE);
|
||||
@@ -2060,6 +2087,7 @@ bool replace_buffer(const char *filename, undo_type action, const char *operatio
|
||||
/* Execute the given program, with the given temp file as last argument. */
|
||||
void treat(char *tempfile_name, char *theprogram, bool spelling)
|
||||
{
|
||||
#if defined(HAVE_FORK) && defined(HAVE_WAIT)
|
||||
ssize_t was_lineno = openfile->current->lineno;
|
||||
size_t was_pww = openfile->placewewant;
|
||||
size_t was_x = openfile->current_x;
|
||||
@@ -2154,14 +2182,9 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
|
||||
openfile->mark = line_from_number(was_mark_lineno);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
openfile->current = openfile->filetop;
|
||||
openfile->current_x = 0;
|
||||
|
||||
replaced = replace_buffer(tempfile_name, CUT_TO_EOF,
|
||||
/* TRANSLATORS: The next two go with Undid/Redid messages. */
|
||||
(spelling ? N_("spelling correction") : N_("formatting")));
|
||||
}
|
||||
|
||||
/* Go back to the old position. */
|
||||
goto_line_posx(was_lineno, was_x);
|
||||
@@ -2182,6 +2205,7 @@ void treat(char *tempfile_name, char *theprogram, bool spelling)
|
||||
statusline(REMARK, _("Finished checking spelling"));
|
||||
else
|
||||
statusline(REMARK, _("Buffer has been processed"));
|
||||
#endif
|
||||
}
|
||||
#endif /* ENABLE_SPELLER || ENABLE_COLOR */
|
||||
|
||||
@@ -2294,12 +2318,14 @@ bool fix_spello(const char *word)
|
||||
* correction. */
|
||||
void do_int_speller(const char *tempfile_name)
|
||||
{
|
||||
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
|
||||
char *misspellings, *pointer, *oneword;
|
||||
long pipesize;
|
||||
size_t buffersize, bytesread, totalread;
|
||||
int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
|
||||
pid_t pid_spell, pid_sort, pid_uniq;
|
||||
int spell_status, sort_status, uniq_status;
|
||||
unsigned stash[sizeof(flags) / sizeof(flags[0])];
|
||||
|
||||
/* Create all three pipes up front. */
|
||||
if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1) {
|
||||
@@ -2424,6 +2450,9 @@ void do_int_speller(const char *tempfile_name)
|
||||
terminal_init();
|
||||
doupdate();
|
||||
|
||||
/* Save the settings of the global flags. */
|
||||
memcpy(stash, flags, sizeof(flags));
|
||||
|
||||
/* Do any replacements case-sensitively, forward, and without regexes. */
|
||||
SET(CASE_SENSITIVE);
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
@@ -2454,6 +2483,9 @@ void do_int_speller(const char *tempfile_name)
|
||||
free(misspellings);
|
||||
refresh_needed = TRUE;
|
||||
|
||||
/* Restore the settings of the global flags. */
|
||||
memcpy(flags, stash, sizeof(flags));
|
||||
|
||||
/* Process the end of the three processes. */
|
||||
waitpid(pid_spell, &spell_status, 0);
|
||||
waitpid(pid_sort, &sort_status, 0);
|
||||
@@ -2467,6 +2499,7 @@ void do_int_speller(const char *tempfile_name)
|
||||
statusline(ALERT, _("Error invoking \"spell\""));
|
||||
else
|
||||
statusline(REMARK, _("Finished checking spelling"));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Spell check the current file. If an alternate spell checker is
|
||||
@@ -2475,7 +2508,6 @@ void do_spell(void)
|
||||
{
|
||||
FILE *stream;
|
||||
char *temp_name;
|
||||
unsigned stash[sizeof(flags) / sizeof(flags[0])];
|
||||
bool okay;
|
||||
|
||||
ran_a_tool = TRUE;
|
||||
@@ -2490,12 +2522,6 @@ void do_spell(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save the settings of the global flags. */
|
||||
memcpy(stash, flags, sizeof(flags));
|
||||
|
||||
/* Don't add an extra newline when writing out the (selected) text. */
|
||||
SET(NO_NEWLINES);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (openfile->mark)
|
||||
okay = write_region_to_file(temp_name, stream, TEMPORARY, OVERWRITE);
|
||||
@@ -2505,6 +2531,7 @@ void do_spell(void)
|
||||
|
||||
if (!okay) {
|
||||
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
|
||||
unlink(temp_name);
|
||||
free(temp_name);
|
||||
return;
|
||||
}
|
||||
@@ -2519,9 +2546,6 @@ void do_spell(void)
|
||||
unlink(temp_name);
|
||||
free(temp_name);
|
||||
|
||||
/* Restore the settings of the global flags. */
|
||||
memcpy(flags, stash, sizeof(flags));
|
||||
|
||||
/* Ensure the help lines will be redrawn and a selection is retained. */
|
||||
currmenu = MMOST;
|
||||
shift_held = TRUE;
|
||||
@@ -2532,6 +2556,7 @@ void do_spell(void)
|
||||
/* Run a linting program on the current buffer. */
|
||||
void do_linter(void)
|
||||
{
|
||||
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
|
||||
char *lintings, *pointer, *onelint;
|
||||
long pipesize;
|
||||
size_t buffersize, bytesread, totalread;
|
||||
@@ -2871,6 +2896,7 @@ void do_linter(void)
|
||||
lastmessage = VACUUM;
|
||||
currmenu = MMOST;
|
||||
titlebar(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Run a manipulation program on the contents of the buffer. */
|
||||
@@ -2899,13 +2925,10 @@ void do_formatter(void)
|
||||
if (temp_name != NULL)
|
||||
okay = write_file(temp_name, stream, TEMPORARY, OVERWRITE, NONOTES);
|
||||
|
||||
if (!okay) {
|
||||
if (!okay)
|
||||
statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
|
||||
free(temp_name);
|
||||
return;
|
||||
}
|
||||
|
||||
treat(temp_name, openfile->syntax->formatter, FALSE);
|
||||
else
|
||||
treat(temp_name, openfile->syntax->formatter, FALSE);
|
||||
|
||||
unlink(temp_name);
|
||||
free(temp_name);
|
||||
@@ -2977,6 +3000,13 @@ void do_verbatim_input(void)
|
||||
size_t count = 1;
|
||||
char *bytes;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* When barless and with cursor on bottom row, make room for the feedback. */
|
||||
if (ISSET(ZERO) && openfile->current_y == editwinrows - 1 && LINES > 1) {
|
||||
edit_scroll(FORWARD);
|
||||
edit_refresh();
|
||||
}
|
||||
#endif
|
||||
/* TRANSLATORS: Shown when the next keystroke will be inserted verbatim. */
|
||||
statusline(INFO, _("Verbatim Input"));
|
||||
place_the_cursor();
|
||||
|
||||
166
src/winio.c
166
src/winio.c
@@ -219,7 +219,7 @@ void read_keys_from(WINDOW *frame)
|
||||
if (input == ERR) {
|
||||
if (spotlighted || ISSET(ZERO) || LINES == 1) {
|
||||
if (ISSET(ZERO) && lastmessage > VACUUM)
|
||||
wredrawln(midwin, editwinrows - 1 , 1);
|
||||
wredrawln(midwin, editwinrows - 1, 1);
|
||||
lastmessage = VACUUM;
|
||||
spotlighted = FALSE;
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
@@ -2475,6 +2475,9 @@ void place_the_cursor(void)
|
||||
openfile->current_y = row;
|
||||
}
|
||||
|
||||
/* The number of bytes after which to stop painting, to avoid major slowdowns. */
|
||||
#define PAINT_LIMIT 2000
|
||||
|
||||
/* Draw the given text on the given row of the edit window. line is the
|
||||
* line to be drawn, and converted is the actual string to be written with
|
||||
* tabs and control characters replaced by strings of regular characters.
|
||||
@@ -2543,14 +2546,12 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
/* The match positions of a single-line regex. */
|
||||
const linestruct *start_line = line->prev;
|
||||
/* The first line before line that matches 'start'. */
|
||||
linestruct *end_line = line;
|
||||
/* The line that matches 'end'. */
|
||||
regmatch_t startmatch, endmatch;
|
||||
/* The match positions of the start and end regexes. */
|
||||
|
||||
/* First case: varnish is a single-line expression. */
|
||||
if (varnish->end == NULL) {
|
||||
while (index < till_x) {
|
||||
while (index < PAINT_LIMIT && index < till_x) {
|
||||
/* If there is no match, go on to the next line. */
|
||||
if (regexec(varnish->start, &line->data[index], 1,
|
||||
&match, (index == 0) ? 0 : REG_NOTBOL) != 0)
|
||||
@@ -2598,117 +2599,41 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
/* Assume nothing gets painted until proven otherwise below. */
|
||||
line->multidata[varnish->id] = NOTHING;
|
||||
|
||||
/* Apart from the first row, check the multidata of the preceding line:
|
||||
* it tells us about the situation so far, and thus what to do here. */
|
||||
if (row > 0 && start_line != NULL && start_line->multidata != NULL) {
|
||||
if (start_line->multidata[varnish->id] == WHOLELINE ||
|
||||
start_line->multidata[varnish->id] == STARTSHERE ||
|
||||
start_line->multidata[varnish->id] == WOULDBE)
|
||||
goto seek_an_end;
|
||||
if (start_line->multidata[varnish->id] == NOTHING ||
|
||||
start_line->multidata[varnish->id] == ENDSHERE ||
|
||||
start_line->multidata[varnish->id] == JUSTONTHIS)
|
||||
goto step_two;
|
||||
}
|
||||
if (start_line && !start_line->multidata)
|
||||
statusline(ALERT, "Missing multidata -- please report a bug");
|
||||
else
|
||||
|
||||
/* The preceding line has no precalculated multidata.
|
||||
* So, do some backtracking to find out what to paint. */
|
||||
|
||||
/* First step: see if there is a line before current that
|
||||
* matches 'start' and is not complemented by an 'end'. */
|
||||
while (start_line != NULL && regexec(varnish->start,
|
||||
start_line->data, 1, &startmatch, 0) == REG_NOMATCH) {
|
||||
/* There is no start on this line; but if there is an end,
|
||||
* there is no need to look for starts on earlier lines. */
|
||||
if (regexec(varnish->end, start_line->data, 0, NULL, 0) == 0)
|
||||
goto step_two;
|
||||
start_line = start_line->prev;
|
||||
}
|
||||
|
||||
/* If no start was found, skip to the next step. */
|
||||
if (start_line == NULL)
|
||||
goto step_two;
|
||||
|
||||
/* If the start has been qualified as an end earlier, believe it. */
|
||||
if (start_line->multidata != NULL &&
|
||||
(start_line->multidata[varnish->id] == ENDSHERE ||
|
||||
start_line->multidata[varnish->id] == JUSTONTHIS))
|
||||
goto step_two;
|
||||
|
||||
/* Maybe there is an end on that same line? If yes, maybe
|
||||
* there is another start after it? And so on, until EOL. */
|
||||
while (TRUE) {
|
||||
/* Begin searching for an end after the start match. */
|
||||
index += startmatch.rm_eo;
|
||||
/* If there is no end after this last start, good. */
|
||||
if (regexec(varnish->end, start_line->data + index, 1, &endmatch,
|
||||
(index == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH)
|
||||
break;
|
||||
/* Begin searching for a new start after the end match. */
|
||||
index += endmatch.rm_eo;
|
||||
/* If both start and end match are mere anchors, advance. */
|
||||
if (startmatch.rm_so == startmatch.rm_eo &&
|
||||
endmatch.rm_so == endmatch.rm_eo) {
|
||||
if (start_line->data[index] == '\0')
|
||||
goto step_two;
|
||||
index = step_right(start_line->data, index);
|
||||
/* If there is an unterminated start match before the current line,
|
||||
* we need to look for an end match first. */
|
||||
if (start_line && (start_line->multidata[varnish->id] == WHOLELINE ||
|
||||
start_line->multidata[varnish->id] == STARTSHERE)) {
|
||||
/* If there is no end on this line, paint whole line, and be done. */
|
||||
if (regexec(varnish->end, line->data, 1, &endmatch, 0) == REG_NOMATCH) {
|
||||
wattron(midwin, varnish->attributes);
|
||||
mvwaddnstr(midwin, row, margin, converted, -1);
|
||||
wattroff(midwin, varnish->attributes);
|
||||
line->multidata[varnish->id] = WHOLELINE;
|
||||
continue;
|
||||
}
|
||||
/* If there is no later start on this line, next step. */
|
||||
if (regexec(varnish->start, start_line->data + index,
|
||||
1, &startmatch, REG_NOTBOL) == REG_NOMATCH)
|
||||
goto step_two;
|
||||
|
||||
/* Only if it is visible, paint the part to be coloured. */
|
||||
if (endmatch.rm_eo > from_x) {
|
||||
paintlen = actual_x(converted, wideness(line->data,
|
||||
endmatch.rm_eo) - from_col);
|
||||
wattron(midwin, varnish->attributes);
|
||||
mvwaddnstr(midwin, row, margin, converted, paintlen);
|
||||
wattroff(midwin, varnish->attributes);
|
||||
}
|
||||
|
||||
line->multidata[varnish->id] = ENDSHERE;
|
||||
}
|
||||
|
||||
seek_an_end:
|
||||
/* We've already checked that there is no end between the start
|
||||
* and the current line. But is there an end after the start
|
||||
* at all? Because we don't paint unterminated starts. */
|
||||
if (row == 0) {
|
||||
while (end_line != NULL && regexec(varnish->end, end_line->data,
|
||||
1, &endmatch, 0) == REG_NOMATCH)
|
||||
end_line = end_line->next;
|
||||
} else if (regexec(varnish->end, line->data, 1, &endmatch, 0) != 0)
|
||||
end_line = line->next;
|
||||
|
||||
/* If there is no end, there is nothing to paint. */
|
||||
if (end_line == NULL) {
|
||||
line->multidata[varnish->id] = WOULDBE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If it was already determined that there is no end... */
|
||||
if (end_line != line && line->prev == start_line && line->prev->multidata &&
|
||||
line->prev->multidata[varnish->id] == WOULDBE) {
|
||||
line->multidata[varnish->id] = WOULDBE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the end is on a later line, paint whole line, and be done. */
|
||||
if (end_line != line) {
|
||||
wattron(midwin, varnish->attributes);
|
||||
mvwaddnstr(midwin, row, margin, converted, -1);
|
||||
wattroff(midwin, varnish->attributes);
|
||||
line->multidata[varnish->id] = WHOLELINE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only if it is visible, paint the part to be coloured. */
|
||||
if (endmatch.rm_eo > from_x) {
|
||||
paintlen = actual_x(converted, wideness(line->data,
|
||||
endmatch.rm_eo) - from_col);
|
||||
wattron(midwin, varnish->attributes);
|
||||
mvwaddnstr(midwin, row, margin, converted, paintlen);
|
||||
wattroff(midwin, varnish->attributes);
|
||||
}
|
||||
line->multidata[varnish->id] = ENDSHERE;
|
||||
|
||||
step_two:
|
||||
/* Second step: look for starts on this line, but begin
|
||||
* looking only after an end match, if there is one. */
|
||||
index = (paintlen == 0) ? 0 : endmatch.rm_eo;
|
||||
|
||||
while (regexec(varnish->start, line->data + index, 1, &startmatch,
|
||||
(index == 0) ? 0 : REG_NOTBOL) == 0) {
|
||||
while (index < PAINT_LIMIT && regexec(varnish->start, line->data + index,
|
||||
1, &startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
|
||||
/* Make the match relative to the beginning of the line. */
|
||||
startmatch.rm_so += index;
|
||||
startmatch.rm_eo += index;
|
||||
@@ -2746,33 +2671,12 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* There is no end on this line. But maybe on later lines? */
|
||||
end_line = line->next;
|
||||
|
||||
while (end_line && regexec(varnish->end, end_line->data,
|
||||
0, NULL, 0) == REG_NOMATCH)
|
||||
end_line = end_line->next;
|
||||
|
||||
/* If there is no end, we're done with this regex. */
|
||||
if (end_line == NULL) {
|
||||
line->multidata[varnish->id] = WOULDBE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Paint the rest of the line, and we're done. */
|
||||
wattron(midwin, varnish->attributes);
|
||||
mvwaddnstr(midwin, row, margin + start_col, thetext, -1);
|
||||
wattroff(midwin, varnish->attributes);
|
||||
|
||||
line->multidata[varnish->id] = STARTSHERE;
|
||||
|
||||
if (end_line->multidata == NULL) {
|
||||
end_line->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
|
||||
for (short item = 0; item < openfile->syntax->nmultis; item++)
|
||||
end_line->multidata[item] = 0;
|
||||
}
|
||||
end_line->multidata[varnish->id] = ENDSHERE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3403,6 +3307,12 @@ void edit_refresh(void)
|
||||
/* When needed and useful, initialize the colors for the current syntax. */
|
||||
if (openfile->syntax && !have_palette && !ISSET(NO_SYNTAX) && has_colors())
|
||||
prepare_palette();
|
||||
|
||||
if (recook) {
|
||||
precalc_multicolorinfo();
|
||||
perturbed = FALSE;
|
||||
recook = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the current line is out of view, get it back on screen. */
|
||||
|
||||
@@ -5,18 +5,22 @@ header "<\?xml.*version=.*\?>"
|
||||
magic "(XML|SGML) (sub)?document"
|
||||
comment "<!--|-->"
|
||||
|
||||
# The entire content of the tag:
|
||||
# First the entire content of the tag (for the attributes):
|
||||
color green start="<" end=">"
|
||||
|
||||
# The angled brackets and the name of the tag:
|
||||
color cyan "<[^> ]+|>"
|
||||
color cyan "<[^> ]+|/?>"
|
||||
|
||||
# The strings inside the tag:
|
||||
color magenta ""[^"]*""
|
||||
|
||||
# Prolog stuff:
|
||||
color #888 "<\?.+\?>|<!DOCTYPE[^>]+>|\]>"
|
||||
color #888 start="<!DOCTYPE[^>]*$" end="^[^<]*>"
|
||||
|
||||
# Comments:
|
||||
color yellow start="<!DOCTYPE" end="[/]?>"
|
||||
color yellow start="<!--" end="-->"
|
||||
|
||||
# Escapes:
|
||||
color red "&[^;]*;"
|
||||
# Entities (custom and predefined):
|
||||
color pink "&[^; ]+;"
|
||||
color red "&(amp|apos|gt|lt|quot);"
|
||||
|
||||
Reference in New Issue
Block a user