Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 070b784a49 | |||
|
|
7681090c12 | ||
|
|
866490c41f | ||
|
|
0662fc4d42 | ||
|
|
078d612b9e | ||
|
|
26025f79ce | ||
|
|
1c307bc1be | ||
|
|
7abddbd752 | ||
|
|
51c9f7270c | ||
|
|
b896670e85 | ||
|
|
69dd0c40bb | ||
|
|
c374c773ad | ||
| 18eb6bae01 | |||
|
|
2fd7888a51 | ||
| b5809f3793 | |||
| 9980a98607 | |||
| 442bd49137 | |||
| 263c7fefbf | |||
| 02249f1655 | |||
| ac58a97a92 | |||
| 140f2d72cb | |||
| b81dca5014 | |||
| 0ac593a9ce | |||
| 8daf175b09 | |||
| 49935c0456 | |||
| b145ce016b | |||
| 226108a59f | |||
| 01b30a5a0e | |||
| 05fa7110ec |
14
configure.ac
14
configure.ac
@ -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
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<title>The GNU nano editor FAQ</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="description" content="The genesis story of the nano editor, plus the solution to some common problems.">
|
||||
<style>
|
||||
<style type="text/css">
|
||||
.indented { margin-left: 2em; font-family: courier; font-size: 110%; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -112,6 +112,7 @@ nanorc file. See \fBnanorc\fR(5).
|
||||
.BR \-E ", " \-\-tabstospaces
|
||||
Convert each typed tab to spaces -- to the number of spaces
|
||||
that a tab at that position would take up.
|
||||
(Note: pasted tabs are not converted.)
|
||||
.TP
|
||||
.BR \-F ", " \-\-multibuffer
|
||||
Read a file into a new buffer by default.
|
||||
@ -391,6 +392,9 @@ Suspension is enabled by default, reachable via \fB^T^Z\fR.
|
||||
(If you want a plain \fB^Z\fR to suspend nano, add
|
||||
\fBbind ^Z suspend main\fR to your nanorc.)
|
||||
.sp
|
||||
When you want to copy marked text from \fBnano\fR to the system's clipboard,
|
||||
see one of the examples in the \fBnanorc\fR(5) man page.
|
||||
.sp
|
||||
If no alternative spell checker command is specified on the command
|
||||
line nor in one of the \fInanorc\fP files, \fBnano\fP will check the
|
||||
\fBSPELL\fP environment variable for one.
|
||||
@ -404,6 +408,9 @@ that name already exists in the current directory, it will add ".save"
|
||||
plus a number (e.g.\& ".save.1") to the current filename in order to make
|
||||
it unique. In multibuffer mode, \fBnano\fP will write all the open
|
||||
buffers to their respective emergency files.
|
||||
.sp
|
||||
If you have any question about how to use \fBnano\fR in some specific
|
||||
situation, you can ask on \fIhelp-nano@gnu.org\fR.
|
||||
|
||||
.SH BUGS
|
||||
The recording and playback of keyboard macros works correctly only on a
|
||||
|
||||
@ -123,6 +123,9 @@ following options: @option{--breaklonglines},
|
||||
@blankline
|
||||
Please report bugs via @url{https://savannah.gnu.org/bugs/?group=nano}.
|
||||
|
||||
@blankline
|
||||
Questions about using nano you can ask at @email{help-nano@@gnu.org}.
|
||||
|
||||
@blankline
|
||||
For background information see @url{https://nano-editor.org/}.
|
||||
|
||||
@ -406,6 +409,7 @@ nanorc file. @xref{@code{set keycolor}} for details.
|
||||
@itemx --tabstospaces
|
||||
Convert each typed tab to spaces --- to the number of spaces
|
||||
that a tab at that position would take up.
|
||||
(Note: pasted tabs are not converted.)
|
||||
|
||||
@item -F
|
||||
@itemx --multibuffer
|
||||
@ -1140,6 +1144,7 @@ greater than 0. The default value is @t{8}.
|
||||
@item set tabstospaces
|
||||
Convert each typed tab to spaces --- to the number of spaces
|
||||
that a tab at that position would take up.
|
||||
(Note: pasted tabs are not converted.)
|
||||
|
||||
@item set titlecolor [bold,][italic,]@var{fgcolor},@var{bgcolor}
|
||||
Use this color combination for the title bar.
|
||||
@ -1230,9 +1235,10 @@ will be added to this syntax, until a new @code{syntax}
|
||||
command is encountered.
|
||||
|
||||
When @command{nano} is run, this syntax will be automatically
|
||||
activated if the current filename matches the extended regular
|
||||
expression @var{fileregex}. Or the syntax can be explicitly
|
||||
activated by using the @option{-Y} or @option{--syntax}
|
||||
activated (for the relevant buffer) if the absolute filename
|
||||
matches the extended regular expression @var{fileregex}.
|
||||
Or the syntax can be explicitly activated (for all buffers)
|
||||
by using the @option{-Y} or @option{--syntax}
|
||||
command-line option followed by the @var{name}.
|
||||
|
||||
The @code{default} syntax is special: it takes no @var{fileregex},
|
||||
|
||||
28
doc/nanorc.5
28
doc/nanorc.5
@ -335,6 +335,7 @@ greater than 0. The default value is \fB8\fR.
|
||||
.B set tabstospaces
|
||||
Convert each typed tab to spaces -- to the number of spaces
|
||||
that a tab at that position would take up.
|
||||
(Note: pasted tabs are not converted.)
|
||||
.TP
|
||||
.B set titlecolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
|
||||
Use this color combination for the title bar.
|
||||
@ -398,12 +399,6 @@ and disappears after 1.5 seconds or upon the next keystroke.
|
||||
With \fBM\-Z\fR the title bar plus status bar can be toggled.
|
||||
With \fBM\-X\fR the help lines.
|
||||
|
||||
.SH NOTES
|
||||
Option \fBset suspendable\fR has been removed.
|
||||
Suspension is enabled by default, reachable via \fB^T^Z\fR.
|
||||
(If you want a plain \fB^Z\fR to suspend nano,
|
||||
add \fBbind ^Z suspend main\fR to your nanorc.)
|
||||
|
||||
.SH SYNTAX HIGHLIGHTING
|
||||
Coloring the different syntactic elements of a file
|
||||
is done via regular expressions (see the \fBcolor\fR command below).
|
||||
@ -444,9 +439,10 @@ will be added to this syntax, until a new \fBsyntax\fR
|
||||
command is encountered.
|
||||
.sp
|
||||
When \fBnano\fR is run, this syntax will be automatically
|
||||
activated if the current filename matches the extended regular
|
||||
expression \fIfileregex\fR. Or the syntax can be explicitly
|
||||
activated by using the \fB\-Y\fR or \fB\-\-syntax\fR
|
||||
activated (for the relevant buffer) if the absolute filename
|
||||
matches the extended regular expression \fIfileregex\fR.
|
||||
Or the syntax can be explicitly activated (for all buffers)
|
||||
by using the \fB\-Y\fR or \fB\-\-syntax\fR
|
||||
command-line option followed by the \fIname\fR.
|
||||
.sp
|
||||
The syntax \fBdefault\fP is special: it takes no \fIfileregex\fR,
|
||||
@ -1038,6 +1034,20 @@ For \fBbind\fR it means all menus where the specified \fIfunction\fR exists;
|
||||
for \fBunbind\fR it means all menus where the specified \fIkey\fR exists.
|
||||
.RE
|
||||
|
||||
.SH EXAMPLES
|
||||
To make \fBCtrl+Z\fR suspend nano:
|
||||
.sp
|
||||
.RS
|
||||
.B bind ^Z suspend main
|
||||
.RE
|
||||
.sp
|
||||
To make \fBShift+Alt+C\fR copy the marked region to the system's clipboard:
|
||||
.sp
|
||||
.RS
|
||||
.B bind Sh-M-C """{execute}| xsel -ib {enter}{undo}""" main
|
||||
.RE
|
||||
.sp
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
.I /etc/nanorc
|
||||
|
||||
@ -30,6 +30,7 @@ nano_SOURCES = \
|
||||
color.c \
|
||||
cut.c \
|
||||
files.c \
|
||||
folding.c \
|
||||
global.c \
|
||||
help.c \
|
||||
history.c \
|
||||
|
||||
28
src/cut.c
28
src/cut.c
@ -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);
|
||||
|
||||
@ -273,6 +273,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 +383,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 +495,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
|
||||
|
||||
@ -681,6 +681,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
138
src/folding.c
Normal 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 */
|
||||
19
src/global.c
19
src/global.c
@ -642,6 +642,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");
|
||||
@ -998,7 +1001,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);
|
||||
@ -1208,6 +1218,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 +1354,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
|
||||
@ -1404,7 +1417,7 @@ void shortcut_init(void)
|
||||
add_to_sclist(MWHEREIS|MREPLACE, "M-B", 0, backwards_void, 0);
|
||||
add_to_sclist(MWHEREIS|MREPLACE, "^R", 0, flip_replace, 0);
|
||||
add_to_sclist(MWHEREIS|MGOTOLINE, "^T", 0, flip_goto, 0);
|
||||
add_to_sclist(MWHEREIS|MGOTOLINE, "^/", 0, flip_goto, 0);
|
||||
add_to_sclist(MWHEREIS|MGOTOLINE, SLASH_OR_DASH, 0, flip_goto, 0);
|
||||
#ifdef ENABLE_HISTORIES
|
||||
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "^P", 0, get_older_item, 0);
|
||||
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "^N", 0, get_newer_item, 0);
|
||||
|
||||
17
src/help.c
17
src/help.c
@ -50,7 +50,7 @@ void help_init(void)
|
||||
char *ptr;
|
||||
|
||||
/* First, set up the initial help text for the current function. */
|
||||
if (currmenu & (MWHEREIS|MREPLACE|MREPLACEWITH)) {
|
||||
if (currmenu & (MWHEREIS|MREPLACE)) {
|
||||
htx[0] = N_("Search Command Help Text\n\n "
|
||||
"Enter the words or characters you would like to "
|
||||
"search for, and then press Enter. If there is a "
|
||||
@ -65,6 +65,13 @@ void help_init(void)
|
||||
"will be replaced.\n\n The following function keys are "
|
||||
"available in Search mode:\n\n");
|
||||
htx[2] = NULL;
|
||||
} else if (currmenu == MREPLACEWITH) {
|
||||
htx[0] = N_("=== Replacement ===\n\n "
|
||||
"Type the characters that should replace the characters that "
|
||||
"you typed at the previous prompt, and press Enter.\n\n");
|
||||
htx[1] = N_(" The following function keys "
|
||||
"are available at this prompt:\n\n");
|
||||
htx[2] = NULL;
|
||||
} else if (currmenu == MGOTOLINE) {
|
||||
htx[0] = N_("Go To Line Help Text\n\n "
|
||||
"Enter the line number that you wish to go to and hit "
|
||||
@ -126,8 +133,8 @@ void help_init(void)
|
||||
"shown in brackets after the search prompt. Hitting "
|
||||
"Enter without entering any text will perform the "
|
||||
"previous search.\n\n");
|
||||
htx[1] = N_(" The following function keys are available in "
|
||||
"Browser Search mode:\n\n");
|
||||
htx[1] = N_(" The following function keys "
|
||||
"are available at this prompt:\n\n");
|
||||
htx[2] = NULL;
|
||||
} else if (currmenu == MGOTODIR) {
|
||||
htx[0] = N_("Browser Go To Directory Help Text\n\n "
|
||||
@ -167,8 +174,8 @@ void help_init(void)
|
||||
htx[1] = N_("If you just need another blank buffer, do not enter any "
|
||||
"command.\n\n You can also pick one of four tools, or cut a "
|
||||
"large piece of the buffer, or put the editor to sleep.\n\n");
|
||||
htx[2] = N_(" The following function keys are "
|
||||
"available in Execute Command mode:\n\n");
|
||||
htx[2] = N_(" The following function keys "
|
||||
"are available at this prompt:\n\n");
|
||||
} else if (currmenu == MLINTER) {
|
||||
htx[0] = N_("=== Linter ===\n\n "
|
||||
"In this mode, the status bar shows an error message or "
|
||||
|
||||
119
src/move.c
119
src/move.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
10
src/nano.c
10
src/nano.c
@ -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;
|
||||
}
|
||||
@ -303,7 +310,7 @@ void do_exit(void)
|
||||
|
||||
/* When unmodified, simply close. Else, when doing automatic saving
|
||||
* and the file has a name, simply save. Otherwise, ask the user. */
|
||||
if (!openfile->modified)
|
||||
if (!openfile->modified || ISSET(VIEW_MODE))
|
||||
choice = NO;
|
||||
else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
|
||||
choice = YES;
|
||||
@ -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)
|
||||
|
||||
@ -365,8 +365,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 +380,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 +477,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 +583,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 +616,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 +681,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
|
||||
|
||||
244
src/search.c
244
src/search.c
@ -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))
|
||||
|
||||
20
src/text.c
20
src/text.c
@ -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++;
|
||||
}
|
||||
|
||||
|
||||
310
src/winio.c
310
src/winio.c
@ -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)
|
||||
{
|
||||
@ -350,7 +399,7 @@ void implant(const char *string)
|
||||
}
|
||||
|
||||
/* Continue processing an expansion string. Returns either an error code,
|
||||
* a plain keycode, or a placeholder for a command shortcut. */
|
||||
* a plain character byte, or a placeholder for a command shortcut. */
|
||||
int get_code_from_plantation(void)
|
||||
{
|
||||
if (*plants_pointer == '{') {
|
||||
@ -383,6 +432,7 @@ int get_code_from_plantation(void)
|
||||
return PLANTED_COMMAND;
|
||||
} else {
|
||||
char *opening = strchr(plants_pointer, '{');
|
||||
char firstbyte = *plants_pointer;
|
||||
int length;
|
||||
|
||||
if (opening) {
|
||||
@ -391,12 +441,12 @@ int get_code_from_plantation(void)
|
||||
} else
|
||||
length = strlen(plants_pointer);
|
||||
|
||||
for (int index = length - 1; index >= 0; index--)
|
||||
for (int index = length - 1; index > 0; index--)
|
||||
put_back((unsigned char)plants_pointer[index]);
|
||||
|
||||
plants_pointer += length;
|
||||
|
||||
return ERR;
|
||||
return (firstbyte) ? firstbyte : ERR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2488,20 +2538,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
|
||||
@ -2515,17 +2582,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, " ");
|
||||
@ -2545,8 +2615,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);
|
||||
@ -2800,18 +2882,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);
|
||||
@ -2819,7 +2933,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. */
|
||||
@ -2842,6 +2955,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
|
||||
@ -2874,8 +2996,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. */
|
||||
@ -2887,6 +3014,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);
|
||||
|
||||
@ -2933,7 +3065,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;
|
||||
|
||||
@ -2944,16 +3083,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;
|
||||
}
|
||||
@ -2973,6 +3121,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,
|
||||
@ -2993,9 +3149,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;
|
||||
}
|
||||
@ -3022,20 +3183,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;
|
||||
@ -3088,7 +3276,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);
|
||||
|
||||
@ -3100,10 +3293,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3300,8 +3494,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. */
|
||||
@ -3329,12 +3522,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
|
||||
@ -3389,9 +3587,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;
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,9 @@ color brightcyan "\<(exec|print)([[:blank:]]|$)"
|
||||
# Special values.
|
||||
color brightmagenta "\<(False|None|True)\>"
|
||||
|
||||
# Decorators.
|
||||
color cyan "@[[:alpha:]_][[:alnum:]_.]*"
|
||||
|
||||
# Mono-quoted strings.
|
||||
color brightgreen "'([^'\]|\\.)*'|"([^"\]|\\.)*"|'''|""""
|
||||
color normal "'''|""""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user