Compare commits

...

37 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Problem existed since version 6.0, since --zero was introduced.
2023-04-12 09:58:28 +02:00
1c4bfb6446 Merge branch 'master' into rexy712 2023-03-30 17:30:43 -07:00
070b784a49 Merge branch 'master' into rexy712 2023-02-28 15:34:34 -08:00
18eb6bae01 Merge branch 'master' into rexy712 2023-01-21 09:26:20 -08:00
b5809f3793 Merge branch 'master' into rexy712 2022-12-19 13:04:14 -08:00
9980a98607 Merge branch 'master' into rexy712 2022-12-04 04:32:02 -08:00
442bd49137 Merge branch 'master' into rexy712 2022-11-10 16:37:54 -08:00
263c7fefbf Merge branch 'master' into rexy712 2022-10-04 16:06:16 -07:00
02249f1655 Merge changes in master 2022-08-24 13:03:13 -07:00
ac58a97a92 Merge branch 'master' of https://git.savannah.gnu.org/git/nano into rexy712 2022-07-22 13:09:24 -07:00
140f2d72cb Fix cutting selection containing a folded segment not unfolding before adding to cutbuffer 2022-07-22 13:06:05 -07:00
b81dca5014 Merge branch 'master' into rexy712 2022-07-15 16:39:56 -07:00
0ac593a9ce Cleanup some folding.c 2022-07-13 12:19:08 -07:00
8daf175b09 Remove color support 2022-07-13 11:58:38 -07:00
49935c0456 Fix tiny build. Rename things to hopefully be more fitting 2022-07-12 12:33:41 -07:00
b145ce016b Fix undoing an enter would not always properly unfold 2022-07-11 15:33:30 -07:00
226108a59f Fix do_find_bracket 2022-07-11 15:23:49 -07:00
01b30a5a0e Change folding behavior when no lines are selected as suggested by the nano dev 2022-07-11 15:11:19 -07:00
05fa7110ec Add initial folding line support
This has not been approved to be merged into master by any means but
I need to be able to track the status of my patch. So I'm starting
this branch and self hosted repository for myself.

Signed-off-by: rexy712 <rexy712@protonmail.com>
2022-07-10 20:42:01 -07:00
20 changed files with 874 additions and 181 deletions

View File

@ -128,6 +128,20 @@ if test "x$enable_color" != xno; then
color_support=yes
fi
AC_ARG_ENABLE(folding,
AS_HELP_STRING([--disable-folding], [Disable line folding support]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_folding" = xyes; then
AC_MSG_ERROR([
*** --enable-folding cannot work with --enable-tiny])
else
enable_folding=no
fi
fi
if test "x$enable_folding" != xno; then
AC_DEFINE(ENABLE_FOLDING, 1, [Define this to have line folding support.])
fi
AC_ARG_ENABLE(comment,
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
if test "x$enable_tiny" = xyes; then

View File

@ -222,10 +222,10 @@
<blockquote><p>Try holding down the Shift key and selecting or pasting the text as you normally would.</p></blockquote>
<h3><a name="4.6"></a>4.6. When I paste text into a document, each line gets indented further than the last. Why? And how can I stop this?</h3>
<blockquote><p>You have the <i>autoindent</i> feature turned on. Hit <b>Meta-I</b> to turn it off, paste your text, and then hit <b>Meta-I</b> again to turn it back on.</p>
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste, so you no longer need to toggle it off and on manually.</p></blockquote>
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need to toggle it off and on manually.</p></blockquote>
<h3><a name="4.7"></a>4.7. When I paste from Windows into a remote nano, nano rewraps the lines. What gives?</h3>
<blockquote><p>When pasting from Windows, in some situations linefeeds are sent instead of carriage returns (Enters). And linefeeds are <b>^J</b>s, which make nano justify (rewrap) the current paragraph. To prevent these linefeeds from causing these unwanted justifications, add this line to your .nanorc on the remote Linux box: <b>unbind ^J main</b> or <b>bind ^J enter main</b>, depending on whether the paste contains CR + LF or only LF.</p>
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste, so you no longer need the above workaround.</p></blockquote>
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need the above workaround.</p></blockquote>
<h3><a name="4.8"></a>4.8. I've compiled nano with color support, but I don't see any color when I run it!</h3>
<blockquote><p>If you want nano to actually use color, you have to specify the color configurations you want it to use in your .nanorc. Several example configurations are in the <b>syntax/</b> subdirectory of the nano source, which are normally installed to <b>/usr/local/share/nano/</b>. To enable all of them, uncomment the line <b># include "/usr/local/share/nano/*.nanorc"</b> in your nanorc. See also section <a href="#3.9">3.9</a>.</p></blockquote>
<h3><a name="4.9"></a>4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</h3>

View File

@ -19,7 +19,7 @@
.TH NANO 1 "version 7.2" "January 2023"
.SH NAME
nano \- Nano's ANOther editor, inspired by Pico
nano \- Nano's ANOther text editor, inspired by Pico
.SH SYNOPSIS
.B nano
@ -28,10 +28,10 @@ nano \- Nano's ANOther editor, inspired by Pico
.B nano
.RI [ options "] [" file [\fB: line [\fB: column "]]]..."
.sp
.BR nano " [" \fIoptions "] [[" + [ crCR ]( / | ? ) \fIstring "] " \fIfile ]...
.BR nano " [" \fIoptions "] [[" + [ crCR ]{ / | ? } \fIstring "] " \fIfile ]...
.SH DESCRIPTION
\fBnano\fP is a small and friendly editor. It copies the look and feel
\fBnano\fP is a small and friendly text editor. It copies the look and feel
of Pico, but is free software, and implements several features that Pico
lacks, such as: opening multiple files, scrolling per line, undo/redo,
syntax coloring, line numbering, and soft-wrapping overlong lines.

View File

@ -35,7 +35,7 @@ The complete manual for the GNU nano text editor.
@page
This manual documents the GNU @command{nano} editor.
This manual documents the GNU @command{nano} text editor.
@sp 1
The contents of this manual are part of the GNU @command{nano} distribution.
@ -163,7 +163,7 @@ A more complete command synopsis thus is:
@blankline
@example
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR](/|?)STRING] FILE]@dots{}}
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR]@{/|?@}STRING] FILE]@dots{}}
@end example
@blankline

View File

@ -23,7 +23,7 @@ nanorc \- GNU nano's configuration file
.SH DESCRIPTION
The \fInanorc\fP files contain the default settings for \fBnano\fP,
a small and friendly editor. During startup, if \fB\-\-rcfile\fR
a small and friendly text editor. During startup, if \fB\-\-rcfile\fR
is not given, \fBnano\fR will read two files: first the
system-wide settings, from \fI/etc/nanorc\fP (the exact path might be
different on your system), and then the user-specific settings, either

View File

@ -32,15 +32,19 @@ access to the filesystem nor to a command shell.
.sp
In restricted mode, \fBnano\fR will:
.IP \[bu] 2
not make backups;
.IP \[bu]
not allow suspending;
.IP \[bu]
not allow spell checking;
.IP \[bu]
not read nor write the history files;
.IP \[bu]
not allow saving the current buffer under a different name;
.IP \[bu]
not allow inserting another file or opening a new buffer;
.IP \[bu]
not allow appending or prepending to any file;
.IP \[bu]
not make backup files nor do spell checking.
not allow appending or prepending to any file.
.SH OPTIONS
.TP

View File

@ -30,6 +30,7 @@ nano_SOURCES = \
color.c \
cut.c \
files.c \
folding.c \
global.c \
help.c \
history.c \

View File

@ -436,7 +436,10 @@ char *browse(char *path)
titlebar(path);
while (TRUE) {
if (list_length == 0) {
statusline(ALERT, _("No entries"));
napms(1200);
} else while (TRUE) {
functionptrtype function;
int kbinput;

View File

@ -48,6 +48,7 @@ void do_deletion(undo_type action)
memmove(&openfile->current->data[openfile->current_x],
&openfile->current->data[openfile->current_x + charlen],
line_len - charlen + 1);
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
/* When softwrapping, a changed number of chunks requires a refresh. */
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
@ -62,6 +63,9 @@ void do_deletion(undo_type action)
} else if (openfile->current != openfile->filebot) {
linestruct *joining = openfile->current->next;
UNFOLD_SEGMENT(openfile->current);
UNFOLD_SEGMENT(joining);
/* If there is a magic line, and we're before it: don't eat it. */
if (joining == openfile->filebot && openfile->current_x != 0 &&
!ISSET(NO_NEWLINES)) {
@ -143,7 +147,8 @@ void do_backspace(void)
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
do_deletion(BACK);
} else if (openfile->current != openfile->filetop) {
do_left();
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
do_deletion(BACK);
}
}
@ -192,7 +197,7 @@ void chop_word(bool forward)
* on the edge of the original line, then put the cursor on that
* edge instead, so that lines will not be joined unexpectedly. */
if (!forward) {
do_prev_word();
do_prev_word(ALLOW_FOLDED);
if (openfile->current != is_current) {
if (is_current_x > 0) {
openfile->current = is_current;
@ -201,13 +206,14 @@ void chop_word(bool forward)
openfile->current_x = strlen(openfile->current->data);
}
} else {
do_next_word(ISSET(AFTER_ENDS));
do_next_word(ISSET(AFTER_ENDS), ALLOW_FOLDED);
if (openfile->current != is_current &&
is_current->data[is_current_x] != '\0') {
openfile->current = is_current;
openfile->current_x = strlen(is_current->data);
}
}
UNFOLD_SEGMENT(openfile->current);
/* Set the mark at the start of that word. */
openfile->mark = openfile->current;
@ -262,9 +268,20 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
if (top == bot && top_x == bot_x)
return;
/* In case bot is the start of a folded segment.
* Folds within [top, bot] are taken care of in the following loop */
UNFOLD_SEGMENT(bot);
if (top != bot)
for (linestruct *line = top->next; line != bot->next; line = line->next)
#ifdef ENABLE_FOLDING
top->folded = FALSE;
#endif
for (linestruct *line = top->next; line != bot->next; line = line->next){
had_anchor |= line->has_anchor;
#ifdef ENABLE_FOLDING
line->folded = FALSE;
#endif
}
#endif
if (top == bot) {
@ -378,6 +395,8 @@ void ingraft_buffer(linestruct *topline)
#endif
linestruct *botline = topline;
UNFOLD_SEGMENT(line);
while (botline->next != NULL)
botline = botline->next;
@ -728,6 +747,7 @@ void paste_text(void)
statusline(AHEM, _("Cutbuffer is empty"));
return;
}
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
add_undo(PASTE, NULL);

View File

@ -214,12 +214,15 @@
#define SHIFT_DELETE 0x45D
#define SHIFT_TAB 0x45F
#define FOCUS_IN 0x491
#define FOCUS_OUT 0x499
/* Special keycodes for when a string bind has been partially implanted
* or has an unpaired opening brace, or when a function in a string bind
* needs execution or a specified function name is invalid. */
#define MORE_PLANTS 0x4EA
#define MISSING_BRACE 0x4EB
#define PLANTED_COMMAND 0x4EC
#define PLANTED_A_COMMAND 0x4EC
#define NO_SUCH_FUNCTION 0x4EF
/* A special keycode for when <Tab> is pressed while the mark is on. */
@ -273,6 +276,15 @@
#define MSOME MMAIN|MBROWSER
#endif
#ifdef ENABLE_FOLDING
#define UNFOLD_SEGMENT(line) unfold_folded_segment(line)
#else
#define UNFOLD_SEGMENT(line)
#endif
#define ALLOW_FOLDED TRUE
#define DISALLOW_FOLDED FALSE
/* Enumeration types. */
typedef enum {
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
@ -374,6 +386,12 @@ enum {
ZERO
};
typedef enum {
FOUND_BRACKET = 0,
NOT_FOUND_BRACKET,
NOT_A_BRACKET
} bracket_search_result;
/* Structure types. */
#ifdef ENABLE_COLOR
typedef struct colortype {
@ -480,6 +498,10 @@ typedef struct linestruct {
bool has_anchor;
/* Whether the user has placed an anchor at this line. */
#endif
#ifdef ENABLE_FOLDING
bool folded;
/* Whether or not this line is in a fold segment */
#endif
} linestruct;
#ifndef NANO_TINY

View File

@ -535,7 +535,8 @@ void mention_name_and_linecount(void)
if (ISSET(MINIBAR)) {
report_size = TRUE;
return;
}
} else if (ISSET(ZERO))
return;
if (openfile->fmt > NIX_FILE)
/* TRANSLATORS: First %s is file name, second %s is file format. */
@ -681,6 +682,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
if (ISSET(SOFTWRAP))
was_leftedge = leftedge_for(xplustabs(), openfile->current);
#endif
UNFOLD_SEGMENT(openfile->current);
/* Create an empty buffer. */
topline = make_new_node(NULL);

138
src/folding.c Normal file
View File

@ -0,0 +1,138 @@
/**************************************************************************
* folding.c -- This file is part of GNU nano. *
* *
* Copyright (C) 2022 rexy712 *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, either version 3 of the License, *
* or (at your option) any later version. *
* *
* GNU nano is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty *
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
#include "prototypes.h"
#include <ctype.h>
/* isspace */
#ifdef ENABLE_FOLDING
/* Remove a folded segment from the given line until end of segment */
void unfold_folded_segment_from(linestruct *line)
{
if (line != NULL)
refresh_needed = TRUE;
for(;line != NULL && line->folded;line = line->next)
line->folded = FALSE;
}
/* Remove a folded segment containing the given line */
void unfold_folded_segment(linestruct *line)
{
unfold_folded_segment_from(get_start_of_folded_segment(line));
}
/* Get the first member of the folded segment */
linestruct *get_start_of_folded_segment(linestruct *line)
{
if (!line->folded)
return line;
while (line->prev != NULL && line->prev->folded)
line = line->prev;
return line;
}
/* Get the last member of the folded segment */
linestruct *get_end_of_folded_segment(linestruct *line)
{
if (!line->folded)
return line;
while (line->next != NULL && line->next->folded)
line = line->next;
return line;
}
/* Get the span length of a folded_segment */
int get_folded_segment_length(linestruct *line)
{
int i = 1;
if (!line->folded)
return 0;
line = get_start_of_folded_segment(line);
for (;line->next != NULL && line->next->folded;line = line->next)
++i;
return i;
}
/* Remove any folded_segments within the range [top, bottom].
* Returns true if any segments are removed. */
bool do_unfold_segment(linestruct *line)
{
/* Attempt to find a bracketed region first.
* If not, top is unmodified. */
if (!line->folded) {
linestruct *bot;
find_bracketed_region(openfile->current, &line, &bot);
}
if (line->folded) {
unfold_folded_segment(line);
move_cursor_to_proper_column();
return TRUE;
}
return FALSE;
}
/* Fold the currently selected lines unless the current selection
* already contains a folded_segment. In that case, remove any
* segments that are selected. */
void do_fold_segment(void)
{
linestruct *top, *bot;
get_range(&top, &bot);
if (top == bot) {
/* First try to unfold if this line/bracketed region is folded */
if (do_unfold_segment(top))
return;
/* When not selecting multiple lines, try to find bounding
* brackets to act as top and bot. */
if (!find_bracketed_region(openfile->current, &top, &bot)) {
statusline(AHEM, _("No valid region found for automatic fold"));
return;
}
}
for (linestruct* line = top;line != bot->next;line = line->next)
line->folded = TRUE;
if (top->lineno < openfile->edittop->lineno &&
bot->lineno > openfile->edittop->lineno)
openfile->edittop = top;
/* Place the cursor at the start of the fold segment.
* Anywhere else within the segment is invalid. */
if (openfile->current->folded)
openfile->current = get_start_of_folded_segment(top);
openfile->mark = NULL;
refresh_needed = TRUE;
}
#endif /* ENABLE_FOLDING */

View File

@ -107,6 +107,7 @@ int altpageup, altpagedown;
int altinsert, altdelete;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif
int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
ssize_t fill = -COLUMNS_FROM_EOL;
@ -266,9 +267,12 @@ char *startup_problem = NULL;
#endif
#ifdef ENABLE_NANORC
char *custom_nanorc = NULL;
/* The argument of the --rcfile option, when given. */
char *commandname = NULL;
/* The name (of a function) between braces in a string bind. */
keystruct *planted_shortcut = NULL;
/* The function that the above name resolves to, if any. */
#endif
bool spotlighted = FALSE;
@ -464,7 +468,7 @@ const keystruct *get_shortcut(const int keycode)
return NULL;
#endif
#ifdef ENABLE_NANORC
if (keycode == PLANTED_COMMAND)
if (keycode == PLANTED_A_COMMAND)
return planted_shortcut;
#endif
@ -642,6 +646,9 @@ void shortcut_init(void)
const char *savefile_gist = N_("Save file without prompting");
const char *findprev_gist = N_("Search next occurrence backward");
const char *findnext_gist = N_("Search next occurrence forward");
#ifdef ENABLE_FOLDING
const char *fold_gist = N_("Fold/unfold the currently selected lines");
#endif
#ifndef NANO_TINY
const char *recordmacro_gist = N_("Start/stop recording a macro");
const char *runmacro_gist = N_("Run the last recorded macro");
@ -978,7 +985,10 @@ void shortcut_init(void)
add_to_funcs(do_verbatim_input, MMAIN,
N_("Verbatim"), WHENHELP(verbatim_gist), BLANKAFTER);
#ifndef NANO_TINY
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
#else
add_to_funcs(do_indent, MMAIN,
N_("Indent"), WHENHELP(indent_gist), TOGETHER);
add_to_funcs(do_unindent, MMAIN,
@ -998,7 +1008,14 @@ void shortcut_init(void)
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
add_to_funcs(run_macro, MMAIN,
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
#endif
#ifdef ENABLE_FOLDING
add_to_funcs(do_fold_segment, MMAIN, N_("Fold"),
WHENHELP(fold_gist), BLANKAFTER);
#endif
#ifndef NANO_TINY
add_to_funcs(zap_text, MMAIN,
/* TRANSLATORS: This refers to deleting a line or marked region. */
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
@ -1010,29 +1027,27 @@ void shortcut_init(void)
add_to_funcs(to_next_anchor, MMAIN,
N_("Down to anchor"), WHENHELP(nextanchor_gist), BLANKAFTER);
if (!ISSET(RESTRICTED)) {
#ifdef ENABLE_SPELLER
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
add_to_funcs(do_spell, MMAIN,
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
#endif
#ifdef ENABLE_LINTER
add_to_funcs(do_linter, MMAIN,
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
add_to_funcs(do_linter, MMAIN,
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
#endif
#ifdef ENABLE_FORMATTER
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
add_to_funcs(do_formatter, MMAIN,
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
#endif
}
#endif /* !NANO_TINY */
/* Although not allowed in restricted mode, keep execution rebindable. */
if (ISSET(RESTRICTED))
add_to_funcs(do_execute, MMAIN,
N_("Execute"), WHENHELP(execute_gist), TOGETHER);
#ifdef NANO_TINY
add_to_funcs(do_search_backward, MMAIN,
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
#else
add_to_funcs(do_suspend, MMAIN,
N_("Suspend"), WHENHELP(suspend_gist), TOGETHER);
#endif
#endif /* !NANO_TINY */
#ifdef ENABLE_HELP
add_to_funcs(full_refresh, MMAIN,
N_("Refresh"), WHENHELP(refresh_gist), TOGETHER);
@ -1103,16 +1118,15 @@ void shortcut_init(void)
N_("No Conversion"), WHENHELP(convert_gist), BLANKAFTER);
/* Command execution is only available when not in restricted mode. */
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
add_to_funcs(flip_execute, MINSERTFILE,
N_("Execute Command"), WHENHELP(execute_gist), BLANKAFTER);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
add_to_funcs(cut_till_eof, MEXECUTE,
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
add_to_funcs(do_suspend, MEXECUTE,
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
}
add_to_funcs(do_suspend, MEXECUTE,
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
#endif /* !NANO_TINY */
#ifdef ENABLE_BROWSER
@ -1208,6 +1222,9 @@ void shortcut_init(void)
#ifdef ENABLE_FORMATTER
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0);
#endif
#ifdef ENABLE_FOLDING
add_to_sclist(MMAIN, "M-[", 0, do_fold_segment, 0);
#endif
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
add_to_sclist(MMAIN, SLASH_OR_DASH, 0, do_gotolinecolumn, 0);
@ -1341,10 +1358,10 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
#endif
#ifdef ENABLE_MULTIBUFFER
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
#endif
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
#ifndef NANO_TINY
@ -1462,24 +1479,22 @@ void shortcut_init(void)
#endif
}
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
#ifdef ENABLE_BROWSER
/* Only when not in restricted mode, allow entering the file browser. */
if (!ISSET(RESTRICTED))
add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", 0, to_files, 0);
#endif
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
/* Allow exiting from the file browser and the help viewer with
* the same key as they were entered. */
#ifdef ENABLE_BROWSER
/* Allow exiting the file browser with the same key as used for entry. */
add_to_sclist(MBROWSER, "^T", 0, do_exit, 0);
#endif
#ifdef ENABLE_HELP
/* Allow exiting the help viewer with the same keys as used for entry. */
add_to_sclist(MHELP, "^G", 0, do_exit, 0);
add_to_sclist(MHELP, "F1", KEY_F(1), do_exit, 0);
add_to_sclist(MHELP, "Home", KEY_HOME, to_first_line, 0);
add_to_sclist(MHELP, "End", KEY_END, to_last_line, 0);
#endif
#ifdef ENABLE_COLOR
#ifdef ENABLE_LINTER
add_to_sclist(MLINTER, "^X", 0, do_cancel, 0);
#endif
add_to_sclist(MMOST & ~MFINDINHELP, "F1", KEY_F(1), do_help, 0);

View File

@ -37,7 +37,13 @@ void to_first_line(void)
void to_last_line(void)
{
openfile->current = openfile->filebot;
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
openfile->current = get_start_of_folded_segment(openfile->current);
openfile->current_x = 0;
} else
#endif
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
openfile->placewewant = xplustabs();
/* Set the last line of the screen as the target for the cursor. */
@ -112,6 +118,15 @@ void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
openfile->placewewant = *leftedge + target;
}
/* Move the cursor position on the current line to the desired column */
void move_cursor_to_proper_column(void)
{
size_t leftedge;
size_t target_column;
get_edge_and_target(&leftedge, &target_column);
set_proper_index_and_pww(&leftedge, target_column, TRUE);
}
/* Move up almost one screenful. */
void do_page_up(void)
{
@ -235,19 +250,28 @@ void to_para_end(void)
void to_prev_block(void)
{
linestruct *was_current = openfile->current;
linestruct *line_step = get_prev_visible_line(openfile->current);
bool is_text = FALSE, seen_text = FALSE;
/* Skip backward until first blank line after some nonblank line(s). */
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
openfile->current = openfile->current->prev;
while (line_step != NULL && (!seen_text || is_text)) {
openfile->current = line_step;
line_step = get_prev_visible_line(line_step);
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
continue;
#endif
is_text = !white_string(openfile->current->data);
seen_text = seen_text || is_text;
}
/* Step forward one line again if we passed text but this line is blank. */
if (seen_text && openfile->current->next != NULL &&
white_string(openfile->current->data))
openfile->current = openfile->current->next;
line_step = get_next_visible_line(openfile->current);
if (seen_text && line_step != NULL &&
white_string(openfile->current->data)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
}
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
@ -257,12 +281,18 @@ void to_prev_block(void)
void to_next_block(void)
{
linestruct *was_current = openfile->current;
linestruct *line_step = get_next_visible_line(openfile->current);
bool is_white = white_string(openfile->current->data);
bool seen_white = is_white;
/* Skip forward until first nonblank line after some blank line(s). */
while (openfile->current->next != NULL && (!seen_white || is_white)) {
openfile->current = openfile->current->next;
while (line_step != NULL && (!seen_white || is_white)) {
openfile->current = line_step;
line_step = get_next_visible_line(line_step);
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
continue;
#endif
is_white = white_string(openfile->current->data);
seen_white = seen_white || is_white;
}
@ -274,19 +304,34 @@ void to_next_block(void)
#endif
}
/* Move to the previous word. */
void do_prev_word(void)
/* Move to the previous word.
* when allow_folded as true, will move to previous word even if inside
* a folded segment */
void do_prev_word(bool allow_folded)
{
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
bool seen_a_word = FALSE, step_forward = FALSE;
#ifdef ENABLE_FOLDING
if (!allow_folded && openfile->current->folded) {
openfile->current = get_prev_visible_line(openfile->current);
openfile->current_x = strlen(openfile->current->data);
}
#endif
/* Move backward until we pass over the start of a word. */
while (TRUE) {
/* If at the head of a line, move to the end of the preceding one. */
if (openfile->current_x == 0) {
if (openfile->current->prev == NULL)
break;
openfile->current = openfile->current->prev;
#ifdef ENABLE_FOLDING
if (!allow_folded) {
openfile->current = get_prev_visible_line(openfile->current);
if (openfile->current->folded)
openfile->current = openfile->current->prev;
} else
#endif
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
}
@ -315,11 +360,14 @@ void do_prev_word(void)
/* Move one character forward again to sit on the start of the word. */
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
UNFOLD_SEGMENT(openfile->current);
}
/* Move to the next word. If after_ends is TRUE, stop at the ends of words
* instead of at their beginnings. Return TRUE if we started on a word. */
bool do_next_word(bool after_ends)
* instead of at their beginnings. If allow_folded is true, go to next word
* even if it's inside a folded segment.
* Return TRUE if we started on a word. */
bool do_next_word(bool after_ends, bool allow_folded)
{
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
bool started_on_word = is_word_char(openfile->current->data +
@ -329,6 +377,12 @@ bool do_next_word(bool after_ends)
bool seen_word = started_on_word;
#endif
#ifdef ENABLE_FOLDING
if (!allow_folded && openfile->current->folded) {
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}
#endif
/* Move forward until we reach the start of a word. */
while (TRUE) {
/* If at the end of a line, move to the beginning of the next one. */
@ -336,7 +390,17 @@ bool do_next_word(bool after_ends)
/* When at end of file, stop. */
if (openfile->current->next == NULL)
break;
openfile->current = openfile->current->next;
#ifdef ENABLE_FOLDING
if (!allow_folded) {
openfile->current = get_next_visible_line(openfile->current);
if (openfile->current->folded) {
/* get_next_visible_line() gives the start of a segment, so skip to the end */
openfile->current = get_end_of_folded_segment(openfile->current);
openfile->current = openfile->current->next;
}
} else
#endif
openfile->current = openfile->current->next;
openfile->current_x = 0;
seen_space = TRUE;
} else {
@ -376,6 +440,8 @@ bool do_next_word(bool after_ends)
}
}
UNFOLD_SEGMENT(openfile->current);
return started_on_word;
}
@ -384,7 +450,7 @@ void to_prev_word(void)
{
linestruct *was_current = openfile->current;
do_prev_word();
do_prev_word(DISALLOW_FOLDED);
edit_redraw(was_current, FLOWING);
}
@ -395,7 +461,7 @@ void to_next_word(void)
{
linestruct *was_current = openfile->current;
do_next_word(ISSET(AFTER_ENDS));
do_next_word(ISSET(AFTER_ENDS), DISALLOW_FOLDED);
edit_redraw(was_current, FLOWING);
}
@ -413,6 +479,11 @@ void do_home(void)
size_t leftedge = 0;
size_t left_x = 0;
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
return;
#endif
if (ISSET(SOFTWRAP)) {
leftedge = leftedge_for(was_column, openfile->current);
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
@ -470,6 +541,11 @@ void do_end(void)
size_t line_len = strlen(openfile->current->data);
bool moved_off_chunk = TRUE;
#ifdef ENABLE_FOLDING
if (openfile->current->folded)
return;
#endif
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool kickoff = TRUE;
@ -612,7 +688,7 @@ void do_left(void)
openfile->current_x);
#endif
} else if (openfile->current != openfile->filetop) {
openfile->current = openfile->current->prev;
openfile->current = get_prev_visible_line(openfile->current);
openfile->current_x = strlen(openfile->current->data);
}
@ -624,6 +700,13 @@ void do_right(void)
{
linestruct *was_current = openfile->current;
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
openfile->current = get_next_visible_line(openfile->current);
if (openfile->current == NULL)
openfile->current = was_current;
} else
#endif
if (openfile->current->data[openfile->current_x] != '\0') {
openfile->current_x = step_right(openfile->current->data,
openfile->current_x);
@ -634,7 +717,7 @@ void do_right(void)
openfile->current_x);
#endif
} else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}

View File

@ -78,6 +78,9 @@ linestruct *make_new_node(linestruct *prevnode)
#ifndef NANO_TINY
newnode->has_anchor = FALSE;
#endif
#ifdef ENABLE_FOLDING
newnode->folded = FALSE;
#endif
return newnode;
}
@ -117,6 +120,7 @@ void delete_node(linestruct *line)
/* Disconnect a node from a linked list of linestructs and delete it. */
void unlink_node(linestruct *line)
{
UNFOLD_SEGMENT(line);
if (line->prev != NULL)
line->prev->next = line->next;
if (line->next != NULL)
@ -156,6 +160,9 @@ linestruct *copy_node(const linestruct *src)
#ifndef NANO_TINY
dst->has_anchor = src->has_anchor;
#endif
#ifdef ENABLE_FOLDING
dst->folded = src->folded;
#endif
return dst;
}
@ -1461,6 +1468,7 @@ void inject(char *burst, size_t count)
#ifndef NANO_TINY
size_t original_row = 0;
size_t old_amount = 0;
UNFOLD_SEGMENT(thisline);
if (ISSET(SOFTWRAP)) {
if (openfile->current_y == editwinrows - 1)
@ -2426,6 +2434,8 @@ int main(int argc, char **argv)
shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
#endif
mousefocusin = get_keycode("kxIN", FOCUS_IN);
mousefocusout = get_keycode("kxOUT", FOCUS_OUT);
#ifdef HAVE_SET_ESCDELAY
/* Tell ncurses to pass the Esc key quickly. */

View File

@ -80,6 +80,7 @@ extern int altinsert, altdelete;
extern int shiftaltleft, shiftaltright;
extern int shiftaltup, shiftaltdown;
#endif
extern int mousefocusin, mousefocusout;
#ifdef ENABLED_WRAPORJUSTIFY
extern ssize_t fill;
@ -365,8 +366,8 @@ void to_para_end(void);
#endif
void to_prev_block(void);
void to_next_block(void);
void do_prev_word(void);
bool do_next_word(bool after_ends);
void do_prev_word(bool allow_folded);
bool do_next_word(bool after_ends, bool allow_folded);
void to_prev_word(void);
void to_next_word(void);
void do_home(void);
@ -380,6 +381,7 @@ void do_center(void);
#endif
void do_left(void);
void do_right(void);
void move_cursor_to_proper_column(void);
/* Most functions in nano.c. */
linestruct *make_new_node(linestruct *prevnode);
@ -476,6 +478,9 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
bool interactive);
void do_gotolinecolumn(void);
#ifndef NANO_TINY
int find_matching_bracket_pos(linestruct **line, size_t *xpos);
bool find_bracketed_region(linestruct *in_region,
linestruct **top, linestruct **bot);
void do_find_bracket(void);
void put_or_lift_anchor(void);
void to_prev_anchor(void);
@ -579,6 +584,8 @@ linestruct *line_from_number(ssize_t number);
#endif
/* Most functions in winio.c. */
linestruct *get_next_visible_line(linestruct *line);
linestruct *get_prev_visible_line(linestruct *line);
#ifndef NANO_TINY
void record_macro(void);
void run_macro(void);
@ -610,6 +617,7 @@ void warn_and_briefly_pause(const char *msg);
void bottombars(int menu);
void post_one_key(const char *keystroke, const char *tag, int width);
void place_the_cursor(void);
int update_line_at(linestruct *line, size_t index, int row);
int update_line(linestruct *line, size_t index);
#ifndef NANO_TINY
int update_softwrapped_line(linestruct *line);
@ -674,3 +682,13 @@ void flip_newbuffer(void);
#endif
void discard_buffer(void);
void do_cancel(void);
/* Most functions in folding.c. */
#ifdef ENABLE_FOLDING
void do_fold_segment(void);
void unfold_folded_segment(linestruct *line);
void unfold_folded_segment_from(linestruct *line);
linestruct *get_start_of_folded_segment(linestruct* line);
linestruct *get_end_of_folded_segment(linestruct* line);
int get_folded_segment_length(linestruct *line);
#endif

View File

@ -991,16 +991,22 @@ void parse_includes(char *ptr)
}
/* Return the index of the color that is closest to the given RGB levels,
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color.
* When red == green == blue, return an index in the xterm gray scale. */
short closest_index_color(short red, short green, short blue)
{
/* Translation table, from 16 intended levels to 6 available levels. */
/* Translation table, from 16 intended color levels to 6 available levels. */
static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
if (COLORS == 256)
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
else
/* Translation table, from 14 intended gray levels to 24 available levels. */
static const short gray[] = { 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 18, 21, 23 };
if (COLORS != 256)
return THE_DEFAULT;
else if (red == green && green == blue && 0 < red && red < 0xF)
return 232 + gray[red - 1];
else
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
}
#define COLORCOUNT 34

View File

@ -308,6 +308,8 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
}
}
UNFOLD_SEGMENT(line);
found_x = found - line->data;
nodelay(midwin, FALSE);
@ -754,6 +756,7 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
openfile->current_x = pos_x;
openfile->placewewant = xplustabs();
UNFOLD_SEGMENT(openfile->current);
refresh_needed = TRUE;
}
@ -808,16 +811,25 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
line = 1;
#ifdef ENABLE_COLOR
if (line > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
recook |= perturbed;
#ifndef NANO_TINY
linestruct *edit_bottom = openfile->edittop;
for (int i = 0;edit_bottom != openfile->filebot && i < editwinrows;++i)
edit_bottom = get_next_visible_line(edit_bottom);
if (line > edit_bottom->lineno ||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
#else
if (line > openfile->edittop->lineno + editwinrows)
#endif
recook |= perturbed;
#endif /* ENABLE_COLOR */
/* Iterate to the requested line. */
for (openfile->current = openfile->filetop; line > 1 &&
openfile->current != openfile->filebot; line--)
openfile->current = openfile->current->next;
UNFOLD_SEGMENT(openfile->current);
/* Take a negative column number to mean: from the end of the line. */
if (column < 0)
column = breadth(openfile->current->data) + column + 2;
@ -872,23 +884,110 @@ void do_gotolinecolumn(void)
}
#ifndef NANO_TINY
/* Search backwards for a line ending with a bracket, including the current line.
* top is an in/out parameter. The passed value is the start line for searching.
* xpos is an out parameter. It is the position in the line where the bracket is
* found. bracket_half is the halfway mark in the matchbrackets array. This way in
* a loop the halfway value isn't recomputed. */
bool find_start_of_bracketed_region(linestruct **top, size_t *xpos, size_t bracket_half)
{
/* Search backwards for a line ending with a bracket, including the current line */
for (;(*top) != NULL;*top = (*top)->prev) {
char *found;
const char *bracket;
int len = strlen((*top)->data);
/* Find the last bracket on the search line */
found = mbrevstrpbrk((*top)->data, matchbrackets, (*top)->data + len);
if (found == NULL)
continue;
*xpos = found - (*top)->data;
bracket = mbstrchr(matchbrackets, found);
/* We're looking for opening braces, not closing */
if (bracket >= matchbrackets + bracket_half)
continue;
/* Check if this is the last character in the line */
char *next = (*top)->data + step_right((*top)->data, *xpos);
if (*next == '\0')
return TRUE;
}
*xpos = 0;
return FALSE;
}
/* Get the halfway point in matchbrackets, where open and close
* brackets meet. */
size_t get_matchbrackets_halfway(void)
{
size_t charcount = mbstrlen(matchbrackets) / 2;
size_t halfway = 0;
for (size_t i = 0;i < charcount;++i)
halfway += char_length(matchbrackets + halfway);
return halfway;
}
/* Get a region surrounding the line in_region. A region here is defined
* as a block of text starting with an opening bracket at the end of a line,
* and ending with a matching closing bracket.
* top and bot are out parameters. Returns the top/bottom line of the region.
* top_pos and bot_pos are out parameters. Returns the position within the
* top and bottom lines where the brackets are found. */
bool find_bracketed_region(linestruct *in_region,
linestruct **top, linestruct **bot)
{
size_t bracket_half = get_matchbrackets_halfway();
size_t top_pos;
size_t bot_pos;
linestruct *was_top = *top;
linestruct *was_bot = *bot;
*top = in_region;
for (;find_start_of_bracketed_region(top, &top_pos, bracket_half)
;*top = (*top)->prev)
{
*bot = *top;
bot_pos = top_pos;
if (!find_matching_bracket_pos(bot, &bot_pos)) {
if ((*bot)->lineno < in_region->lineno)
continue;
int linedist = (*bot)->lineno - (*top)->lineno;
if (linedist >= 2) {
*top = (*top)->next;
*bot = (*bot)->prev;
return TRUE;
}
}
}
*top = was_top;
*bot = was_bot;
return FALSE;
}
/* Search, starting from the current position, for any of the two characters
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
bool find_a_bracket(bool reverse, const char *bracket_pair)
bool find_a_bracket(bool reverse, const char *bracket_pair,
linestruct **inout_line, size_t *xpos)
{
linestruct *line = openfile->current;
linestruct *line = *inout_line;
const char *pointer, *found;
if (reverse) {
/* First step away from the current bracket. */
if (openfile->current_x == 0) {
if (*xpos == 0) {
line = line->prev;
if (line == NULL)
return FALSE;
pointer = line->data + strlen(line->data);
} else
pointer = line->data + step_left(line->data, openfile->current_x);
pointer = line->data + step_left(line->data, *xpos);
/* Now seek for any of the two brackets we are interested in. */
while (!(found = mbrevstrpbrk(line->data, bracket_pair, pointer))) {
@ -898,7 +997,7 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
pointer = line->data + strlen(line->data);
}
} else {
pointer = line->data + step_right(line->data, openfile->current_x);
pointer = line->data + step_right(line->data, *xpos);
while (!(found = mbstrpbrk(pointer, bracket_pair))) {
line = line->next;
@ -908,45 +1007,24 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
}
}
/* Set the current position to the found bracket. */
openfile->current = line;
openfile->current_x = found - line->data;
/* Set the found position to the found bracket. */
*inout_line = line;
*xpos = found - line->data;
return TRUE;
}
/* Search for a match to the bracket at the current cursor position, if
* there is one. */
void do_find_bracket(void)
/* Search for the given bracket's compliment within matchbrackets.
* ch must be a pointer to within matchbrackets.
* reverse is true if the found compliment came before ch in matchbrackets. */
const char *get_bracket_compliment(const char *ch, bool *reverse)
{
linestruct *was_current = openfile->current;
size_t was_current_x = openfile->current_x;
/* The current cursor position, in case we don't find a complement. */
const char *ch;
/* The location in matchbrackets of the bracket under the cursor. */
int ch_len;
/* The length of ch in bytes. */
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
int wanted_ch_len;
/* The length of wanted_ch in bytes. */
char bracket_pair[MAXCHARLEN * 2 + 1];
/* The pair of characters in ch and wanted_ch. */
size_t halfway = 0;
/* The index in matchbrackets where the closing brackets start. */
size_t charcount = mbstrlen(matchbrackets) / 2;
/* Half the number of characters in matchbrackets. */
size_t balance = 1;
/* The initial bracket count. */
bool reverse;
/* The direction we search. */
ch = mbstrchr(matchbrackets, openfile->current->data + openfile->current_x);
if (ch == NULL) {
statusline(AHEM, _("Not a bracket"));
return;
}
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
size_t halfway = 0;
/* The index in matchbrackets where the closing brackets start. */
/* Find the halfway point in matchbrackets, where the closing ones start. */
for (size_t i = 0; i < charcount; i++)
@ -954,19 +1032,35 @@ void do_find_bracket(void)
/* When on a closing bracket, we have to search backwards for a matching
* opening bracket; otherwise, forward for a matching closing bracket. */
reverse = (ch >= (matchbrackets + halfway));
*reverse = (ch >= (matchbrackets + halfway));
/* Step half the number of total characters either backwards or forwards
* through matchbrackets to find the wanted complementary bracket. */
wanted_ch = ch;
while (charcount-- > 0) {
if (reverse)
if (*reverse)
wanted_ch = matchbrackets + step_left(matchbrackets,
wanted_ch - matchbrackets);
else
wanted_ch += char_length(wanted_ch);
}
return wanted_ch;
}
/* Create a bracket pair string from the given bracket in ch, assigning
* the result to bracket_pair. Reverse is set to true if we need to
* search backward for a match. */
void create_bracket_pair(char *bracket_pair, const char *ch,
int ch_len, bool* reverse)
{
const char *wanted_ch;
/* The location in matchbrackets of the complementing bracket. */
int wanted_ch_len;
/* The length of wanted_ch in bytes. */
wanted_ch = get_bracket_compliment(ch, reverse);
ch_len = char_length(ch);
wanted_ch_len = char_length(wanted_ch);
@ -974,24 +1068,65 @@ void do_find_bracket(void)
strncpy(bracket_pair, ch, ch_len);
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
bracket_pair[ch_len + wanted_ch_len] = '\0';
}
while (find_a_bracket(reverse, bracket_pair)) {
/* Increment/decrement balance for an identical/other bracket. */
balance += (strncmp(openfile->current->data + openfile->current_x,
ch, ch_len) == 0) ? 1 : -1;
/* Get the bracket match position for the character currently under the cursor.
* If there is no bracket beneath the cursor, return NOT_A_BRACKET. If there is
* no match found, return NOT_FOUND_BRACKET. Otherwise returns FOUND_BRACKET
* and sets line and xpos to the found line and offset respectively. */
int find_matching_bracket_pos(linestruct **line, size_t *xpos)
{
const char *br_ch;
/* The location in matchbrackets of the bracket under the cursor. */
int br_ch_len;
/* The length of br_ch in bytes. */
char bracket_pair[MAXCHARLEN * 2 + 1];
/* The pair of characters in ch and wanted_ch. */
size_t balance = 1;
/* The initial bracket count. */
bool reversed;
/* The direction we search. */
/* When balance reached zero, we've found the complementary bracket. */
if (balance == 0) {
edit_redraw(was_current, FLOWING);
return;
}
br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
if (br_ch == NULL)
return NOT_A_BRACKET;
br_ch_len = char_length(br_ch);
create_bracket_pair(bracket_pair, br_ch, br_ch_len, &reversed);
while (find_a_bracket(reversed, bracket_pair, line, xpos)) {
balance += (strncmp((*line)->data + *xpos,
br_ch, br_ch_len) == 0) ? 1 : -1;
if (balance == 0)
return FOUND_BRACKET;
}
return NOT_FOUND_BRACKET;
}
/* Search for a match to the bracket at the current cursor position, if
* there is one. */
void do_find_bracket(void)
{
linestruct *was_current = openfile->current;
size_t was_current_x = openfile->current_x;
int res = find_matching_bracket_pos(&openfile->current,
&openfile->current_x);
if (res == FOUND_BRACKET) {
UNFOLD_SEGMENT(openfile->current);
edit_redraw(was_current, FLOWING);
return;
}
statusline(AHEM, _("No matching bracket"));
/* Restore the cursor position. */
openfile->current = was_current;
openfile->current_x = was_current_x;
statusline(AHEM, res == NOT_FOUND_BRACKET ?
_("No matching bracket") :
_("Not a bracket"));
}
/* Place an anchor at the current line when none exists, otherwise remove it. */
@ -1015,6 +1150,7 @@ void go_to_and_confirm(linestruct *line)
if (line != openfile->current) {
openfile->current = line;
openfile->current_x = 0;
UNFOLD_SEGMENT(openfile->current);
#ifdef ENABLE_COLOR
if (line->lineno > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))

View File

@ -96,6 +96,8 @@ void indent_a_line(linestruct *line, char *indentation)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Add the fabricated indentation to the beginning of the line. */
line->data = nrealloc(line->data, length + indent_len + 1);
memmove(line->data + indent_len, line->data, length + 1);
@ -226,6 +228,8 @@ void unindent_a_line(linestruct *line, size_t indent_len)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Remove the first tab's worth of whitespace from this line. */
memmove(line->data, line->data + indent_len, length - indent_len + 1);
@ -317,6 +321,8 @@ bool comment_line(undo_type action, linestruct *line, const char *comment_seq)
/* Length of postfix. */
size_t line_len = strlen(line->data);
UNFOLD_SEGMENT(line);
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
return FALSE;
@ -416,8 +422,9 @@ void do_comment(void)
/* Comment/uncomment each of the selected lines when possible, and
* store undo data when a line changed. */
for (line = top; line != bot->next; line = line->next)
if (comment_line(action, line, comment_seq))
if (comment_line(action, line, comment_seq)) {
update_multiline_undo(line->lineno, "");
}
set_modified();
ensure_firstcolumn_is_aligned();
@ -859,6 +866,13 @@ void do_enter(void)
{
linestruct *newnode = make_new_node(openfile->current);
size_t extra = 0;
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
newnode->folded = TRUE;
openfile->current->folded = FALSE;
}
#endif
#ifndef NANO_TINY
linestruct *sampleline = openfile->current;
bool allblanks = FALSE;
@ -1585,6 +1599,7 @@ void concat_paragraph(linestruct *line, size_t count)
line->data = nrealloc(line->data,
line_len + next_line_len - next_lead_len + 1);
strcat(line->data, next_line->data + next_lead_len);
UNFOLD_SEGMENT(line);
#ifndef NANO_TINY
line->has_anchor |= next_line->has_anchor;
#endif
@ -2852,6 +2867,7 @@ void do_linter(void)
/* Place the cursor to indicate the affected line. */
place_the_cursor();
UNFOLD_SEGMENT(openfile->current);
wnoutrefresh(midwin);
kbinput = get_kbinput(footwin, VISIBLE);
@ -2993,7 +3009,7 @@ void count_lines_words_and_characters(void)
* incrementing the word count for each successful step. */
while (openfile->current->lineno < botline->lineno ||
(openfile->current == botline && openfile->current_x < bot_x)) {
if (do_next_word(FALSE))
if (do_next_word(FALSE, ALLOW_FOLDED))
words++;
}

View File

@ -140,6 +140,55 @@ void run_macro(void)
}
#endif /* !NANO_TINY */
/* Return the current offset of target from openfile->edittop */
int get_row_from_edittop(linestruct *target)
{
#ifdef ENABLE_FOLDING
linestruct *line = openfile->edittop;
int row = 0;
while (line != NULL && line != target && row < editwinrows) {
line = get_end_of_folded_segment(line);
line = line->next;
++row;
}
return row;
#else
return target->lineno - openfile->edittop->lineno;
#endif
}
/* Return the next line, taking fold segments into account */
linestruct *get_next_visible_line(linestruct *line)
{
if (!line)
return NULL;
#ifdef ENABLE_FOLDING
line = get_end_of_folded_segment(line);
if (line == NULL)
return NULL;
#endif
return line->next;
}
/* Return the previous line, taking fold segments into account */
linestruct *get_prev_visible_line(linestruct *line)
{
if (!line)
return NULL;
#ifdef ENABLE_FOLDING
if (line->folded) {
line = get_start_of_folded_segment(line);
return line == NULL ? NULL : line->prev;
}
if (line->prev != NULL && line->prev->folded)
return get_start_of_folded_segment(line->prev);
#endif
return line->prev;
}
/* Allocate the requested space for the keystroke buffer. */
void reserve_space_for(size_t newsize)
{
@ -380,7 +429,7 @@ int get_code_from_plantation(void)
if (*plants_pointer != '\0')
put_back(MORE_PLANTS);
return PLANTED_COMMAND;
return PLANTED_A_COMMAND;
} else {
char *opening = strchr(plants_pointer, '{');
char firstbyte = *plants_pointer;
@ -1245,6 +1294,10 @@ int parse_kbinput(WINDOW *frame)
return INDENT_KEY;
#endif
/* Spurious codes from VTE -- see https://sv.gnu.org/bugs/?64578. */
if (keycode == mousefocusin || keycode == mousefocusout)
return ERR;
switch (keycode) {
case KEY_SLEFT:
shift_held = TRUE;
@ -2489,20 +2542,37 @@ void place_the_cursor(void)
/* Calculate how many rows the lines from edittop to current use. */
while (line != NULL && line != openfile->current) {
row += 1 + extra_chunks_in(line);
#ifdef ENABLE_FOLDING
if (line->folded) {
line = get_end_of_folded_segment(line);
++row;
} else
#endif
row += 1 + extra_chunks_in(line);
line = line->next;
}
/* Add the number of wraps in the current line before the cursor. */
row += get_chunk_and_edge(column, openfile->current, &leftedge);
column -= leftedge;
} else
#ifdef ENABLE_FOLDING
if (!openfile->current->folded)
#endif
{
/* Add the number of wraps in the current line before the cursor. */
row += get_chunk_and_edge(column, openfile->current, &leftedge);
column -= leftedge;
}
} else
#endif /* !NANO_TINY */
{
row = openfile->current->lineno - openfile->edittop->lineno;
row = get_row_from_edittop(openfile->current);
column -= get_page_start(column);
}
#ifdef ENABLE_FOLDING
if (openfile->current->folded) {
openfile->current_x = 0;
column = 0;
}
#endif
if (row < editwinrows)
wmove(midwin, row, margin + column);
#ifndef NANO_TINY
@ -2516,17 +2586,20 @@ void place_the_cursor(void)
/* 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.
* from_col is the column number of the first character of this "page". */
void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
{
#ifdef ENABLE_LINENUMBERS
/* Draw the line number for the given line, but only if line numbering is on.
* For folded segments, draws a '-' instead of a line number.
* Also draws a mark indicating where anchors are set. */
void draw_linenumber(int row, const linestruct* line, size_t from_col){
/* If line numbering is switched on, put a line number in front of
* the text -- but only for the parts that are not softwrapped. */
if (margin > 0) {
wattron(midwin, interface_color_pair[LINE_NUMBER]);
#ifdef ENABLE_FOLDING
if (line->folded)
mvwprintw(midwin, row, 0, "%*c", margin - 1, '-');
else
#endif
#ifndef NANO_TINY
if (ISSET(SOFTWRAP) && from_col != 0)
mvwprintw(midwin, row, 0, "%*s", margin - 1, " ");
@ -2546,8 +2619,20 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
#endif
wprintw(midwin, " ");
}
}
#endif /* ENABLE_LINENUMBERS */
/* 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.
* from_col is the column number of the first character of this "page". */
void draw_row(int row, const char *converted, linestruct *line,
size_t from_col)
{
#ifdef ENABLE_LINENUMBERS
draw_linenumber(row, line, from_col);
#endif
/* First simply write the converted line -- afterward we'll add colors
* and the marking highlight on just the pieces that need it. */
mvwaddstr(midwin, row, margin, converted);
@ -2801,18 +2886,50 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
#endif /* !NANO_TINY */
}
/* Redraw the given line so that the character at the given index is visible
* -- if necessary, scroll the line horizontally (when not softwrapping).
* Return the number of rows "consumed" (relevant when softwrapping). */
int update_line(linestruct *line, size_t index)
#ifdef ENABLE_FOLDING
/* Draw a folded segment at the given row. */
int update_folded_line(linestruct *line, int row)
{
const int seg_len = get_folded_segment_length(line);
const int string_len = snprintf(NULL, 0, "%d lines folded", seg_len);
const int fill_length = (editwincols > string_len) ?
(editwincols - string_len) : 0;
const int half_fill = fill_length / 2;
char *string = nmalloc(editwincols + 1);
memset(string, '-', half_fill);
snprintf(string+half_fill, editwincols, "%d lines folded", seg_len);
memset(string+half_fill+string_len, '-', fill_length - half_fill);
string[editwincols] = '\0';
#ifdef ENABLE_LINENUMBERS
draw_linenumber(row, line, 0);
#endif
mvwaddstr(midwin, row, margin, string);
free(string);
return 1;
}
#endif /* ENABLE_FOLDING */
/* Redraw the given line at the given row so that the character at the
* given index is visible -- if necessary, scroll the line horizontally
* (when not softwrapping). Return the number of rows "consumed"
* (relevant when softwrapping). */
int update_line_at(linestruct *line, size_t index, int row)
{
int row;
/* The row in the edit window we will be updating. */
char *converted;
/* The data of the line with tabs and control characters expanded. */
size_t from_col;
/* From which column a horizontally scrolled line is displayed. */
#ifdef ENABLE_FOLDING
if (line->folded)
return update_folded_line(line, row);
#endif
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
return update_softwrapped_line(line);
@ -2820,7 +2937,6 @@ int update_line(linestruct *line, size_t index)
sequel_column = 0;
#endif
row = line->lineno - openfile->edittop->lineno;
from_col = get_page_start(wideness(line->data, index));
/* Expand the piece to be drawn to its representable form, and draw it. */
@ -2843,6 +2959,15 @@ int update_line(linestruct *line, size_t index)
spotlight(light_from_col, light_to_col);
return 1;
}
/* Redraw the given line so that the character at the given index is visible
* -- if necessary, scroll the line horizontally (when not softwrapping).
* Return the number of rows "consumed" (relevant when softwrapping). */
int update_line(linestruct *line, size_t index)
{
return update_line_at(line, index, get_row_from_edittop(line));
}
#ifndef NANO_TINY
@ -2875,8 +3000,13 @@ int update_softwrapped_line(linestruct *line)
/* Find out on which screen row the target line should be shown. */
while (someline != line && someline != NULL) {
row += 1 + extra_chunks_in(someline);
someline = someline->next;
#ifdef ENABLE_FOLDING
if (someline->folded)
++row;
else
#endif
row += 1 + extra_chunks_in(someline);
someline = get_next_visible_line(someline);
}
/* If the first chunk is offscreen, don't even try to display it. */
@ -2888,6 +3018,11 @@ int update_softwrapped_line(linestruct *line)
starting_row = row;
#ifdef ENABLE_FOLDING
if (line->folded)
return update_folded_line(line, row);
#endif
while (!end_of_line && row < editwinrows) {
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
@ -2934,7 +3069,14 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
if (ISSET(SOFTWRAP)) {
/* Recede through the requested number of chunks. */
for (i = nrows; i > 0; i--) {
size_t chunk = chunk_for(*leftedge, *line);
size_t chunk;
#ifdef ENABLE_FOLDING
if ((*line)->folded)
chunk = 0;
else
#endif
chunk = chunk_for(*leftedge, *line);
*leftedge = 0;
@ -2945,16 +3087,25 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
break;
i -= chunk;
*line = (*line)->prev;
*line = get_prev_visible_line(*line);
*leftedge = HIGHEST_POSITIVE;
}
#ifdef ENABLE_FOLDING
if ((*line)->folded)
*leftedge = 0;
else
#endif
if (*leftedge == HIGHEST_POSITIVE)
*leftedge = leftedge_for(*leftedge, *line);
} else
#endif
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
*line = (*line)->prev;
#endif /* !NANO_TINY */
{
linestruct *prev = get_prev_visible_line(*line);
for (i = nrows; i > 0 && prev != NULL; i--) {
*line = prev;
prev = get_prev_visible_line(prev);
}
}
return i;
}
@ -2974,6 +3125,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
/* Advance through the requested number of chunks. */
for (i = nrows; i > 0; i--) {
#ifdef ENABLE_FOLDING
if ((*line)->folded) {
*line = get_next_visible_line(*line);
current_leftedge = 0;
continue;
}
#endif
bool end_of_line = FALSE;
current_leftedge = get_softwrap_breakpoint((*line)->data,
@ -2994,9 +3153,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
if (i < nrows)
*leftedge = current_leftedge;
} else
#endif
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
*line = (*line)->next;
#endif /* !NANO_TINY */
{
linestruct *next = get_next_visible_line(*line);
for (i = nrows; i > 0 && next != NULL; i--) {
*line = next;
next = get_next_visible_line(*line);
}
}
return i;
}
@ -3023,20 +3187,47 @@ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge)
/* Draw a scroll bar on the righthand side of the screen. */
void draw_scrollbar(void)
{
int fromline = openfile->edittop->lineno - 1;
int totallines = openfile->filebot->lineno;
int coveredlines = editwinrows;
int fromline = openfile->edittop->lineno - 1;
int coveredlines = 0;
linestruct *line = openfile->edittop;
if (ISSET(SOFTWRAP)) {
linestruct *line = openfile->edittop;
int extras = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
while (line->lineno + extras < fromline + editwinrows && line->next) {
line = line->next;
extras += extra_chunks_in(line);
int i = 0;
#ifdef ENABLE_FOLDING
if (line->folded)
coveredlines += get_folded_segment_length(line);
else
#endif
{
i = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
coveredlines = i;
}
coveredlines = line->lineno - fromline;
for (;i < editwinrows && line->next != NULL;++i) {
line = get_next_visible_line(line);
#ifdef ENABLE_FOLDING
if (line->folded)
coveredlines += get_folded_segment_length(line);
else
#endif
{
i += extra_chunks_in(line);
++coveredlines;
}
}
} else {
#ifdef ENABLE_FOLDING
for (int i = 0;i < editwinrows && line->next != NULL;++i) {
if (line->folded)
coveredlines += get_folded_segment_length(line);
else
++coveredlines;
line = get_next_visible_line(line);
}
#else
coveredlines = editwinrows;
#endif /* ENABLE_FOLDING */
}
int lowest = (fromline * editwinrows) / totallines;
@ -3089,7 +3280,12 @@ void edit_scroll(bool direction)
if (thebar)
draw_scrollbar();
if (ISSET(SOFTWRAP)) {
#ifdef ENABLE_FOLDING
if (ISSET(SOFTWRAP) && !line->folded)
#else
if (ISSET(SOFTWRAP))
#endif
{
/* Compensate for the earlier chunks of a softwrapped line. */
nrows += chunk_for(leftedge, line);
@ -3101,10 +3297,11 @@ void edit_scroll(bool direction)
/* Draw new content on the blank row (and on the bordering row too
* when it was deemed necessary). */
int row = get_row_from_edittop(line);
while (nrows > 0 && line != NULL) {
nrows -= update_line(line, (line == openfile->current) ?
openfile->current_x : 0);
line = line->next;
nrows -= update_line_at(line, (line == openfile->current) ?
openfile->current_x : 0, row++);
line = get_next_visible_line(line);
}
}
@ -3301,8 +3498,7 @@ bool current_is_below_screen(void)
leftedge < leftedge_for(xplustabs(), openfile->current))));
} else
#endif
return (openfile->current->lineno >=
openfile->edittop->lineno + editwinrows - SHIM);
return (get_row_from_edittop(openfile->current) >= editwinrows - SHIM);
}
/* Return TRUE if current[current_x] is outside the viewport. */
@ -3330,12 +3526,17 @@ void edit_redraw(linestruct *old_current, update_type manner)
/* If the mark is on, update all lines between old_current and current. */
if (openfile->mark) {
linestruct *line = old_current;
int row = get_row_from_edittop(line);
while (line != openfile->current) {
update_line(line, 0);
update_line_at(line, 0, row);
line = (line->lineno > openfile->current->lineno) ?
line->prev : line->next;
if (line->lineno > openfile->current->lineno) {
line = get_prev_visible_line(line);
--row;
} else {
line = get_next_visible_line(line);
++row;
}
}
} else
#endif
@ -3390,9 +3591,13 @@ void edit_refresh(void)
while (row < editwinrows && line != NULL) {
if (line == openfile->current)
row += update_line(line, openfile->current_x);
row += update_line_at(line, openfile->current_x, row);
else
row += update_line(line, 0);
row += update_line_at(line, 0, row);
#ifdef ENABLE_FOLDING
line = get_end_of_folded_segment(line);
#endif
line = line->next;
}