Compare commits
41 Commits
master
...
rexy712-co
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d087df732 | |||
| 070b784a49 | |||
|
|
7681090c12 | ||
|
|
866490c41f | ||
|
|
0662fc4d42 | ||
|
|
078d612b9e | ||
|
|
26025f79ce | ||
|
|
1c307bc1be | ||
|
|
7abddbd752 | ||
|
|
51c9f7270c | ||
|
|
b896670e85 | ||
|
|
69dd0c40bb | ||
|
|
c374c773ad | ||
| da9a59cd52 | |||
| 18eb6bae01 | |||
|
|
2fd7888a51 | ||
| d4e734b159 | |||
| b5809f3793 | |||
| 51144bd61f | |||
| 9980a98607 | |||
| 503f496215 | |||
| 442bd49137 | |||
| b0ca683ab3 | |||
| 263c7fefbf | |||
| 8a4c62dcd9 | |||
| 02249f1655 | |||
| 51a10296e8 | |||
| ac58a97a92 | |||
| db838f3256 | |||
| 140f2d72cb | |||
| f7fcc96a04 | |||
| b81dca5014 | |||
| a5c4a25c16 | |||
| 0ac593a9ce | |||
| 1dc2b31616 | |||
| 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
|
color_support=yes
|
||||||
fi
|
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,
|
AC_ARG_ENABLE(comment,
|
||||||
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
|
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
|
||||||
if test "x$enable_tiny" = xyes; then
|
if test "x$enable_tiny" = xyes; then
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<title>The GNU nano editor FAQ</title>
|
<title>The GNU nano editor FAQ</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<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.">
|
<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%; }
|
.indented { margin-left: 2em; font-family: courier; font-size: 110%; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@ -112,6 +112,7 @@ nanorc file. See \fBnanorc\fR(5).
|
|||||||
.BR \-E ", " \-\-tabstospaces
|
.BR \-E ", " \-\-tabstospaces
|
||||||
Convert each typed tab to spaces -- to the number of spaces
|
Convert each typed tab to spaces -- to the number of spaces
|
||||||
that a tab at that position would take up.
|
that a tab at that position would take up.
|
||||||
|
(Note: pasted tabs are not converted.)
|
||||||
.TP
|
.TP
|
||||||
.BR \-F ", " \-\-multibuffer
|
.BR \-F ", " \-\-multibuffer
|
||||||
Read a file into a new buffer by default.
|
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
|
(If you want a plain \fB^Z\fR to suspend nano, add
|
||||||
\fBbind ^Z suspend main\fR to your nanorc.)
|
\fBbind ^Z suspend main\fR to your nanorc.)
|
||||||
.sp
|
.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
|
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
|
line nor in one of the \fInanorc\fP files, \fBnano\fP will check the
|
||||||
\fBSPELL\fP environment variable for one.
|
\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
|
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
|
it unique. In multibuffer mode, \fBnano\fP will write all the open
|
||||||
buffers to their respective emergency files.
|
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
|
.SH BUGS
|
||||||
The recording and playback of keyboard macros works correctly only on a
|
The recording and playback of keyboard macros works correctly only on a
|
||||||
|
|||||||
@ -123,6 +123,9 @@ following options: @option{--breaklonglines},
|
|||||||
@blankline
|
@blankline
|
||||||
Please report bugs via @url{https://savannah.gnu.org/bugs/?group=nano}.
|
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
|
@blankline
|
||||||
For background information see @url{https://nano-editor.org/}.
|
For background information see @url{https://nano-editor.org/}.
|
||||||
|
|
||||||
@ -406,6 +409,7 @@ nanorc file. @xref{@code{set keycolor}} for details.
|
|||||||
@itemx --tabstospaces
|
@itemx --tabstospaces
|
||||||
Convert each typed tab to spaces --- to the number of spaces
|
Convert each typed tab to spaces --- to the number of spaces
|
||||||
that a tab at that position would take up.
|
that a tab at that position would take up.
|
||||||
|
(Note: pasted tabs are not converted.)
|
||||||
|
|
||||||
@item -F
|
@item -F
|
||||||
@itemx --multibuffer
|
@itemx --multibuffer
|
||||||
@ -1140,6 +1144,7 @@ greater than 0. The default value is @t{8}.
|
|||||||
@item set tabstospaces
|
@item set tabstospaces
|
||||||
Convert each typed tab to spaces --- to the number of spaces
|
Convert each typed tab to spaces --- to the number of spaces
|
||||||
that a tab at that position would take up.
|
that a tab at that position would take up.
|
||||||
|
(Note: pasted tabs are not converted.)
|
||||||
|
|
||||||
@item set titlecolor [bold,][italic,]@var{fgcolor},@var{bgcolor}
|
@item set titlecolor [bold,][italic,]@var{fgcolor},@var{bgcolor}
|
||||||
Use this color combination for the title bar.
|
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.
|
command is encountered.
|
||||||
|
|
||||||
When @command{nano} is run, this syntax will be automatically
|
When @command{nano} is run, this syntax will be automatically
|
||||||
activated if the current filename matches the extended regular
|
activated (for the relevant buffer) if the absolute filename
|
||||||
expression @var{fileregex}. Or the syntax can be explicitly
|
matches the extended regular expression @var{fileregex}.
|
||||||
activated by using the @option{-Y} or @option{--syntax}
|
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}.
|
command-line option followed by the @var{name}.
|
||||||
|
|
||||||
The @code{default} syntax is special: it takes no @var{fileregex},
|
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
|
.B set tabstospaces
|
||||||
Convert each typed tab to spaces -- to the number of spaces
|
Convert each typed tab to spaces -- to the number of spaces
|
||||||
that a tab at that position would take up.
|
that a tab at that position would take up.
|
||||||
|
(Note: pasted tabs are not converted.)
|
||||||
.TP
|
.TP
|
||||||
.B set titlecolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
|
.B set titlecolor \fR[\fBbold,\fR][\fBitalic,\fR]\fIfgcolor\fB,\fIbgcolor\fR
|
||||||
Use this color combination for the title bar.
|
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\-Z\fR the title bar plus status bar can be toggled.
|
||||||
With \fBM\-X\fR the help lines.
|
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
|
.SH SYNTAX HIGHLIGHTING
|
||||||
Coloring the different syntactic elements of a file
|
Coloring the different syntactic elements of a file
|
||||||
is done via regular expressions (see the \fBcolor\fR command below).
|
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.
|
command is encountered.
|
||||||
.sp
|
.sp
|
||||||
When \fBnano\fR is run, this syntax will be automatically
|
When \fBnano\fR is run, this syntax will be automatically
|
||||||
activated if the current filename matches the extended regular
|
activated (for the relevant buffer) if the absolute filename
|
||||||
expression \fIfileregex\fR. Or the syntax can be explicitly
|
matches the extended regular expression \fIfileregex\fR.
|
||||||
activated by using the \fB\-Y\fR or \fB\-\-syntax\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.
|
command-line option followed by the \fIname\fR.
|
||||||
.sp
|
.sp
|
||||||
The syntax \fBdefault\fP is special: it takes no \fIfileregex\fR,
|
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.
|
for \fBunbind\fR it means all menus where the specified \fIkey\fR exists.
|
||||||
.RE
|
.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
|
.SH FILES
|
||||||
.TP
|
.TP
|
||||||
.I /etc/nanorc
|
.I /etc/nanorc
|
||||||
|
|||||||
@ -30,6 +30,7 @@ nano_SOURCES = \
|
|||||||
color.c \
|
color.c \
|
||||||
cut.c \
|
cut.c \
|
||||||
files.c \
|
files.c \
|
||||||
|
folding.c \
|
||||||
global.c \
|
global.c \
|
||||||
help.c \
|
help.c \
|
||||||
history.c \
|
history.c \
|
||||||
|
|||||||
@ -67,8 +67,15 @@ void set_interface_colorpairs(void)
|
|||||||
else if (index == ERROR_MESSAGE) {
|
else if (index == ERROR_MESSAGE) {
|
||||||
init_pair(index + 1, COLOR_WHITE, COLOR_RED);
|
init_pair(index + 1, COLOR_WHITE, COLOR_RED);
|
||||||
interface_color_pair[index] = COLOR_PAIR(index + 1) | A_BOLD;
|
interface_color_pair[index] = COLOR_PAIR(index + 1) | A_BOLD;
|
||||||
} else
|
} else if(index == FOLDED_LINE) {
|
||||||
|
if(COLORS > 15)
|
||||||
|
init_pair(index + 1, COLOR_BLACK + 8, COLOR_BLACK);
|
||||||
|
else
|
||||||
|
init_pair(index + 1, COLOR_WHITE, COLOR_BLACK);
|
||||||
|
interface_color_pair[index] = COLOR_PAIR(index + 1);
|
||||||
|
} else {
|
||||||
interface_color_pair[index] = hilite_attribute;
|
interface_color_pair[index] = hilite_attribute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(color_combo[index]);
|
free(color_combo[index]);
|
||||||
|
|||||||
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],
|
memmove(&openfile->current->data[openfile->current_x],
|
||||||
&openfile->current->data[openfile->current_x + charlen],
|
&openfile->current->data[openfile->current_x + charlen],
|
||||||
line_len - charlen + 1);
|
line_len - charlen + 1);
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
/* When softwrapping, a changed number of chunks requires a refresh. */
|
/* When softwrapping, a changed number of chunks requires a refresh. */
|
||||||
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
|
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) {
|
} else if (openfile->current != openfile->filebot) {
|
||||||
linestruct *joining = openfile->current->next;
|
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 there is a magic line, and we're before it: don't eat it. */
|
||||||
if (joining == openfile->filebot && openfile->current_x != 0 &&
|
if (joining == openfile->filebot && openfile->current_x != 0 &&
|
||||||
!ISSET(NO_NEWLINES)) {
|
!ISSET(NO_NEWLINES)) {
|
||||||
@ -143,7 +147,8 @@ void do_backspace(void)
|
|||||||
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
|
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
|
||||||
do_deletion(BACK);
|
do_deletion(BACK);
|
||||||
} else if (openfile->current != openfile->filetop) {
|
} else if (openfile->current != openfile->filetop) {
|
||||||
do_left();
|
openfile->current = openfile->current->prev;
|
||||||
|
openfile->current_x = strlen(openfile->current->data);
|
||||||
do_deletion(BACK);
|
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
|
* on the edge of the original line, then put the cursor on that
|
||||||
* edge instead, so that lines will not be joined unexpectedly. */
|
* edge instead, so that lines will not be joined unexpectedly. */
|
||||||
if (!forward) {
|
if (!forward) {
|
||||||
do_prev_word();
|
do_prev_word(ALLOW_FOLDED);
|
||||||
if (openfile->current != is_current) {
|
if (openfile->current != is_current) {
|
||||||
if (is_current_x > 0) {
|
if (is_current_x > 0) {
|
||||||
openfile->current = is_current;
|
openfile->current = is_current;
|
||||||
@ -201,13 +206,14 @@ void chop_word(bool forward)
|
|||||||
openfile->current_x = strlen(openfile->current->data);
|
openfile->current_x = strlen(openfile->current->data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
do_next_word(ISSET(AFTER_ENDS));
|
do_next_word(ISSET(AFTER_ENDS), ALLOW_FOLDED);
|
||||||
if (openfile->current != is_current &&
|
if (openfile->current != is_current &&
|
||||||
is_current->data[is_current_x] != '\0') {
|
is_current->data[is_current_x] != '\0') {
|
||||||
openfile->current = is_current;
|
openfile->current = is_current;
|
||||||
openfile->current_x = strlen(is_current->data);
|
openfile->current_x = strlen(is_current->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
/* Set the mark at the start of that word. */
|
/* Set the mark at the start of that word. */
|
||||||
openfile->mark = openfile->current;
|
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)
|
if (top == bot && top_x == bot_x)
|
||||||
return;
|
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)
|
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;
|
had_anchor |= line->has_anchor;
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
line->folded = FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (top == bot) {
|
if (top == bot) {
|
||||||
@ -378,6 +395,8 @@ void ingraft_buffer(linestruct *topline)
|
|||||||
#endif
|
#endif
|
||||||
linestruct *botline = topline;
|
linestruct *botline = topline;
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
|
|
||||||
while (botline->next != NULL)
|
while (botline->next != NULL)
|
||||||
botline = botline->next;
|
botline = botline->next;
|
||||||
|
|
||||||
@ -728,6 +747,7 @@ void paste_text(void)
|
|||||||
statusline(AHEM, _("Cutbuffer is empty"));
|
statusline(AHEM, _("Cutbuffer is empty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
add_undo(PASTE, NULL);
|
add_undo(PASTE, NULL);
|
||||||
|
|||||||
@ -273,6 +273,15 @@
|
|||||||
#define MSOME MMAIN|MBROWSER
|
#define MSOME MMAIN|MBROWSER
|
||||||
#endif
|
#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. */
|
/* Enumeration types. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
|
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
|
||||||
@ -318,6 +327,7 @@ enum {
|
|||||||
ERROR_MESSAGE,
|
ERROR_MESSAGE,
|
||||||
KEY_COMBO,
|
KEY_COMBO,
|
||||||
FUNCTION_TAG,
|
FUNCTION_TAG,
|
||||||
|
FOLDED_LINE,
|
||||||
NUMBER_OF_ELEMENTS
|
NUMBER_OF_ELEMENTS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -374,6 +384,12 @@ enum {
|
|||||||
ZERO
|
ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FOUND_BRACKET = 0,
|
||||||
|
NOT_FOUND_BRACKET,
|
||||||
|
NOT_A_BRACKET
|
||||||
|
} bracket_search_result;
|
||||||
|
|
||||||
/* Structure types. */
|
/* Structure types. */
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
typedef struct colortype {
|
typedef struct colortype {
|
||||||
@ -480,6 +496,10 @@ typedef struct linestruct {
|
|||||||
bool has_anchor;
|
bool has_anchor;
|
||||||
/* Whether the user has placed an anchor at this line. */
|
/* Whether the user has placed an anchor at this line. */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
bool folded;
|
||||||
|
/* Whether or not this line is in a fold segment */
|
||||||
|
#endif
|
||||||
} linestruct;
|
} linestruct;
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
|
|||||||
@ -681,6 +681,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
|||||||
if (ISSET(SOFTWRAP))
|
if (ISSET(SOFTWRAP))
|
||||||
was_leftedge = leftedge_for(xplustabs(), openfile->current);
|
was_leftedge = leftedge_for(xplustabs(), openfile->current);
|
||||||
#endif
|
#endif
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
/* Create an empty buffer. */
|
/* Create an empty buffer. */
|
||||||
topline = make_new_node(NULL);
|
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 *savefile_gist = N_("Save file without prompting");
|
||||||
const char *findprev_gist = N_("Search next occurrence backward");
|
const char *findprev_gist = N_("Search next occurrence backward");
|
||||||
const char *findnext_gist = N_("Search next occurrence forward");
|
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
|
#ifndef NANO_TINY
|
||||||
const char *recordmacro_gist = N_("Start/stop recording a macro");
|
const char *recordmacro_gist = N_("Start/stop recording a macro");
|
||||||
const char *runmacro_gist = N_("Run the last recorded 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);
|
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
|
||||||
add_to_funcs(run_macro, MMAIN,
|
add_to_funcs(run_macro, MMAIN,
|
||||||
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
|
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,
|
add_to_funcs(zap_text, MMAIN,
|
||||||
/* TRANSLATORS: This refers to deleting a line or marked region. */
|
/* TRANSLATORS: This refers to deleting a line or marked region. */
|
||||||
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
|
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
|
||||||
@ -1208,6 +1218,9 @@ void shortcut_init(void)
|
|||||||
#ifdef ENABLE_FORMATTER
|
#ifdef ENABLE_FORMATTER
|
||||||
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
|
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
|
||||||
add_to_sclist(MEXECUTE, "^O", 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
|
#endif
|
||||||
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
|
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
|
||||||
add_to_sclist(MMAIN, SLASH_OR_DASH, 0, do_gotolinecolumn, 0);
|
add_to_sclist(MMAIN, 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);
|
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_MULTIBUFFER
|
#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_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);
|
||||||
|
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
|
||||||
#endif
|
#endif
|
||||||
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
|
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
|
||||||
#ifndef NANO_TINY
|
#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, "M-B", 0, backwards_void, 0);
|
||||||
add_to_sclist(MWHEREIS|MREPLACE, "^R", 0, flip_replace, 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, "^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
|
#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, "^P", 0, get_older_item, 0);
|
||||||
add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP|MEXECUTE, "^N", 0, get_newer_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;
|
char *ptr;
|
||||||
|
|
||||||
/* First, set up the initial help text for the current function. */
|
/* 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 "
|
htx[0] = N_("Search Command Help Text\n\n "
|
||||||
"Enter the words or characters you would like to "
|
"Enter the words or characters you would like to "
|
||||||
"search for, and then press Enter. If there is a "
|
"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 "
|
"will be replaced.\n\n The following function keys are "
|
||||||
"available in Search mode:\n\n");
|
"available in Search mode:\n\n");
|
||||||
htx[2] = NULL;
|
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) {
|
} else if (currmenu == MGOTOLINE) {
|
||||||
htx[0] = N_("Go To Line Help Text\n\n "
|
htx[0] = N_("Go To Line Help Text\n\n "
|
||||||
"Enter the line number that you wish to go to and hit "
|
"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 "
|
"shown in brackets after the search prompt. Hitting "
|
||||||
"Enter without entering any text will perform the "
|
"Enter without entering any text will perform the "
|
||||||
"previous search.\n\n");
|
"previous search.\n\n");
|
||||||
htx[1] = N_(" The following function keys are available in "
|
htx[1] = N_(" The following function keys "
|
||||||
"Browser Search mode:\n\n");
|
"are available at this prompt:\n\n");
|
||||||
htx[2] = NULL;
|
htx[2] = NULL;
|
||||||
} else if (currmenu == MGOTODIR) {
|
} else if (currmenu == MGOTODIR) {
|
||||||
htx[0] = N_("Browser Go To Directory Help Text\n\n "
|
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 "
|
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 "
|
"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");
|
"large piece of the buffer, or put the editor to sleep.\n\n");
|
||||||
htx[2] = N_(" The following function keys are "
|
htx[2] = N_(" The following function keys "
|
||||||
"available in Execute Command mode:\n\n");
|
"are available at this prompt:\n\n");
|
||||||
} else if (currmenu == MLINTER) {
|
} else if (currmenu == MLINTER) {
|
||||||
htx[0] = N_("=== Linter ===\n\n "
|
htx[0] = N_("=== Linter ===\n\n "
|
||||||
"In this mode, the status bar shows an error message or "
|
"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)
|
void to_last_line(void)
|
||||||
{
|
{
|
||||||
openfile->current = openfile->filebot;
|
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();
|
openfile->placewewant = xplustabs();
|
||||||
|
|
||||||
/* Set the last line of the screen as the target for the cursor. */
|
/* 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;
|
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. */
|
/* Move up almost one screenful. */
|
||||||
void do_page_up(void)
|
void do_page_up(void)
|
||||||
{
|
{
|
||||||
@ -235,19 +250,28 @@ void to_para_end(void)
|
|||||||
void to_prev_block(void)
|
void to_prev_block(void)
|
||||||
{
|
{
|
||||||
linestruct *was_current = openfile->current;
|
linestruct *was_current = openfile->current;
|
||||||
|
linestruct *line_step = get_prev_visible_line(openfile->current);
|
||||||
bool is_text = FALSE, seen_text = FALSE;
|
bool is_text = FALSE, seen_text = FALSE;
|
||||||
|
|
||||||
/* Skip backward until first blank line after some nonblank line(s). */
|
/* Skip backward until first blank line after some nonblank line(s). */
|
||||||
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
|
while (line_step != NULL && (!seen_text || is_text)) {
|
||||||
openfile->current = openfile->current->prev;
|
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);
|
is_text = !white_string(openfile->current->data);
|
||||||
seen_text = seen_text || is_text;
|
seen_text = seen_text || is_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step forward one line again if we passed text but this line is blank. */
|
/* Step forward one line again if we passed text but this line is blank. */
|
||||||
if (seen_text && openfile->current->next != NULL &&
|
line_step = get_next_visible_line(openfile->current);
|
||||||
white_string(openfile->current->data))
|
if (seen_text && line_step != NULL &&
|
||||||
openfile->current = openfile->current->next;
|
white_string(openfile->current->data)) {
|
||||||
|
openfile->current = line_step;
|
||||||
|
line_step = get_next_visible_line(line_step);
|
||||||
|
}
|
||||||
|
|
||||||
openfile->current_x = 0;
|
openfile->current_x = 0;
|
||||||
edit_redraw(was_current, CENTERING);
|
edit_redraw(was_current, CENTERING);
|
||||||
@ -257,12 +281,18 @@ void to_prev_block(void)
|
|||||||
void to_next_block(void)
|
void to_next_block(void)
|
||||||
{
|
{
|
||||||
linestruct *was_current = openfile->current;
|
linestruct *was_current = openfile->current;
|
||||||
|
linestruct *line_step = get_next_visible_line(openfile->current);
|
||||||
bool is_white = white_string(openfile->current->data);
|
bool is_white = white_string(openfile->current->data);
|
||||||
bool seen_white = is_white;
|
bool seen_white = is_white;
|
||||||
|
|
||||||
/* Skip forward until first nonblank line after some blank line(s). */
|
/* Skip forward until first nonblank line after some blank line(s). */
|
||||||
while (openfile->current->next != NULL && (!seen_white || is_white)) {
|
while (line_step != NULL && (!seen_white || is_white)) {
|
||||||
openfile->current = openfile->current->next;
|
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);
|
is_white = white_string(openfile->current->data);
|
||||||
seen_white = seen_white || is_white;
|
seen_white = seen_white || is_white;
|
||||||
}
|
}
|
||||||
@ -274,19 +304,34 @@ void to_next_block(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to the previous word. */
|
/* Move to the previous word.
|
||||||
void do_prev_word(void)
|
* 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 punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||||
bool seen_a_word = FALSE, step_forward = FALSE;
|
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. */
|
/* Move backward until we pass over the start of a word. */
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
/* If at the head of a line, move to the end of the preceding one. */
|
/* If at the head of a line, move to the end of the preceding one. */
|
||||||
if (openfile->current_x == 0) {
|
if (openfile->current_x == 0) {
|
||||||
if (openfile->current->prev == NULL)
|
if (openfile->current->prev == NULL)
|
||||||
break;
|
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);
|
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. */
|
/* Move one character forward again to sit on the start of the word. */
|
||||||
openfile->current_x = step_right(openfile->current->data,
|
openfile->current_x = step_right(openfile->current->data,
|
||||||
openfile->current_x);
|
openfile->current_x);
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to the next word. If after_ends is TRUE, stop at the ends of words
|
/* 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. */
|
* instead of at their beginnings. If allow_folded is true, go to next word
|
||||||
bool do_next_word(bool after_ends)
|
* 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 punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||||
bool started_on_word = is_word_char(openfile->current->data +
|
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;
|
bool seen_word = started_on_word;
|
||||||
#endif
|
#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. */
|
/* Move forward until we reach the start of a word. */
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
/* If at the end of a line, move to the beginning of the next one. */
|
/* 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. */
|
/* When at end of file, stop. */
|
||||||
if (openfile->current->next == NULL)
|
if (openfile->current->next == NULL)
|
||||||
break;
|
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;
|
openfile->current_x = 0;
|
||||||
seen_space = TRUE;
|
seen_space = TRUE;
|
||||||
} else {
|
} else {
|
||||||
@ -376,6 +440,8 @@ bool do_next_word(bool after_ends)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
return started_on_word;
|
return started_on_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +450,7 @@ void to_prev_word(void)
|
|||||||
{
|
{
|
||||||
linestruct *was_current = openfile->current;
|
linestruct *was_current = openfile->current;
|
||||||
|
|
||||||
do_prev_word();
|
do_prev_word(DISALLOW_FOLDED);
|
||||||
|
|
||||||
edit_redraw(was_current, FLOWING);
|
edit_redraw(was_current, FLOWING);
|
||||||
}
|
}
|
||||||
@ -395,7 +461,7 @@ void to_next_word(void)
|
|||||||
{
|
{
|
||||||
linestruct *was_current = openfile->current;
|
linestruct *was_current = openfile->current;
|
||||||
|
|
||||||
do_next_word(ISSET(AFTER_ENDS));
|
do_next_word(ISSET(AFTER_ENDS), DISALLOW_FOLDED);
|
||||||
|
|
||||||
edit_redraw(was_current, FLOWING);
|
edit_redraw(was_current, FLOWING);
|
||||||
}
|
}
|
||||||
@ -413,6 +479,11 @@ void do_home(void)
|
|||||||
size_t leftedge = 0;
|
size_t leftedge = 0;
|
||||||
size_t left_x = 0;
|
size_t left_x = 0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (openfile->current->folded)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
leftedge = leftedge_for(was_column, openfile->current);
|
leftedge = leftedge_for(was_column, openfile->current);
|
||||||
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
|
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);
|
size_t line_len = strlen(openfile->current->data);
|
||||||
bool moved_off_chunk = TRUE;
|
bool moved_off_chunk = TRUE;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (openfile->current->folded)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
bool kickoff = TRUE;
|
bool kickoff = TRUE;
|
||||||
@ -612,7 +688,7 @@ void do_left(void)
|
|||||||
openfile->current_x);
|
openfile->current_x);
|
||||||
#endif
|
#endif
|
||||||
} else if (openfile->current != openfile->filetop) {
|
} 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);
|
openfile->current_x = strlen(openfile->current->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,6 +700,13 @@ void do_right(void)
|
|||||||
{
|
{
|
||||||
linestruct *was_current = openfile->current;
|
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') {
|
if (openfile->current->data[openfile->current_x] != '\0') {
|
||||||
openfile->current_x = step_right(openfile->current->data,
|
openfile->current_x = step_right(openfile->current->data,
|
||||||
openfile->current_x);
|
openfile->current_x);
|
||||||
@ -634,7 +717,7 @@ void do_right(void)
|
|||||||
openfile->current_x);
|
openfile->current_x);
|
||||||
#endif
|
#endif
|
||||||
} else if (openfile->current != openfile->filebot) {
|
} else if (openfile->current != openfile->filebot) {
|
||||||
openfile->current = openfile->current->next;
|
openfile->current = get_next_visible_line(openfile->current);
|
||||||
openfile->current_x = 0;
|
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
|
#ifndef NANO_TINY
|
||||||
newnode->has_anchor = FALSE;
|
newnode->has_anchor = FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
newnode->folded = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
@ -117,6 +120,7 @@ void delete_node(linestruct *line)
|
|||||||
/* Disconnect a node from a linked list of linestructs and delete it. */
|
/* Disconnect a node from a linked list of linestructs and delete it. */
|
||||||
void unlink_node(linestruct *line)
|
void unlink_node(linestruct *line)
|
||||||
{
|
{
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
if (line->prev != NULL)
|
if (line->prev != NULL)
|
||||||
line->prev->next = line->next;
|
line->prev->next = line->next;
|
||||||
if (line->next != NULL)
|
if (line->next != NULL)
|
||||||
@ -156,6 +160,9 @@ linestruct *copy_node(const linestruct *src)
|
|||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
dst->has_anchor = src->has_anchor;
|
dst->has_anchor = src->has_anchor;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
dst->folded = src->folded;
|
||||||
|
#endif
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
@ -303,7 +310,7 @@ void do_exit(void)
|
|||||||
|
|
||||||
/* When unmodified, simply close. Else, when doing automatic saving
|
/* When unmodified, simply close. Else, when doing automatic saving
|
||||||
* and the file has a name, simply save. Otherwise, ask the user. */
|
* and the file has a name, simply save. Otherwise, ask the user. */
|
||||||
if (!openfile->modified)
|
if (!openfile->modified || ISSET(VIEW_MODE))
|
||||||
choice = NO;
|
choice = NO;
|
||||||
else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
|
else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
|
||||||
choice = YES;
|
choice = YES;
|
||||||
@ -1461,6 +1468,7 @@ void inject(char *burst, size_t count)
|
|||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
size_t original_row = 0;
|
size_t original_row = 0;
|
||||||
size_t old_amount = 0;
|
size_t old_amount = 0;
|
||||||
|
UNFOLD_SEGMENT(thisline);
|
||||||
|
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
if (openfile->current_y == editwinrows - 1)
|
if (openfile->current_y == editwinrows - 1)
|
||||||
|
|||||||
@ -365,8 +365,8 @@ void to_para_end(void);
|
|||||||
#endif
|
#endif
|
||||||
void to_prev_block(void);
|
void to_prev_block(void);
|
||||||
void to_next_block(void);
|
void to_next_block(void);
|
||||||
void do_prev_word(void);
|
void do_prev_word(bool allow_folded);
|
||||||
bool do_next_word(bool after_ends);
|
bool do_next_word(bool after_ends, bool allow_folded);
|
||||||
void to_prev_word(void);
|
void to_prev_word(void);
|
||||||
void to_next_word(void);
|
void to_next_word(void);
|
||||||
void do_home(void);
|
void do_home(void);
|
||||||
@ -380,6 +380,7 @@ void do_center(void);
|
|||||||
#endif
|
#endif
|
||||||
void do_left(void);
|
void do_left(void);
|
||||||
void do_right(void);
|
void do_right(void);
|
||||||
|
void move_cursor_to_proper_column(void);
|
||||||
|
|
||||||
/* Most functions in nano.c. */
|
/* Most functions in nano.c. */
|
||||||
linestruct *make_new_node(linestruct *prevnode);
|
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);
|
bool interactive);
|
||||||
void do_gotolinecolumn(void);
|
void do_gotolinecolumn(void);
|
||||||
#ifndef NANO_TINY
|
#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 do_find_bracket(void);
|
||||||
void put_or_lift_anchor(void);
|
void put_or_lift_anchor(void);
|
||||||
void to_prev_anchor(void);
|
void to_prev_anchor(void);
|
||||||
@ -579,6 +583,8 @@ linestruct *line_from_number(ssize_t number);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Most functions in winio.c. */
|
/* Most functions in winio.c. */
|
||||||
|
linestruct *get_next_visible_line(linestruct *line);
|
||||||
|
linestruct *get_prev_visible_line(linestruct *line);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
void record_macro(void);
|
void record_macro(void);
|
||||||
void run_macro(void);
|
void run_macro(void);
|
||||||
@ -610,6 +616,7 @@ void warn_and_briefly_pause(const char *msg);
|
|||||||
void bottombars(int menu);
|
void bottombars(int menu);
|
||||||
void post_one_key(const char *keystroke, const char *tag, int width);
|
void post_one_key(const char *keystroke, const char *tag, int width);
|
||||||
void place_the_cursor(void);
|
void place_the_cursor(void);
|
||||||
|
int update_line_at(linestruct *line, size_t index, int row);
|
||||||
int update_line(linestruct *line, size_t index);
|
int update_line(linestruct *line, size_t index);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
int update_softwrapped_line(linestruct *line);
|
int update_softwrapped_line(linestruct *line);
|
||||||
@ -674,3 +681,13 @@ void flip_newbuffer(void);
|
|||||||
#endif
|
#endif
|
||||||
void discard_buffer(void);
|
void discard_buffer(void);
|
||||||
void do_cancel(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
|
||||||
|
|||||||
@ -134,6 +134,7 @@ static const rcoption rcopts[] = {
|
|||||||
{"errorcolor", 0},
|
{"errorcolor", 0},
|
||||||
{"keycolor", 0},
|
{"keycolor", 0},
|
||||||
{"functioncolor", 0},
|
{"functioncolor", 0},
|
||||||
|
{"foldedcolor", 0},
|
||||||
#endif
|
#endif
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
@ -1593,6 +1594,8 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
|
|||||||
color_combo[KEY_COMBO] = parse_interface_color(argument);
|
color_combo[KEY_COMBO] = parse_interface_color(argument);
|
||||||
else if (strcmp(option, "functioncolor") == 0)
|
else if (strcmp(option, "functioncolor") == 0)
|
||||||
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
|
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
|
||||||
|
else if (strcmp(option, "foldedcolor") == 0)
|
||||||
|
color_combo[FOLDED_LINE] = parse_interface_color(argument);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_OPERATINGDIR
|
#ifdef ENABLE_OPERATINGDIR
|
||||||
|
|||||||
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;
|
found_x = found - line->data;
|
||||||
|
|
||||||
nodelay(midwin, FALSE);
|
nodelay(midwin, FALSE);
|
||||||
@ -754,6 +756,7 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
|
|||||||
|
|
||||||
openfile->current_x = pos_x;
|
openfile->current_x = pos_x;
|
||||||
openfile->placewewant = xplustabs();
|
openfile->placewewant = xplustabs();
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
refresh_needed = TRUE;
|
refresh_needed = TRUE;
|
||||||
}
|
}
|
||||||
@ -808,16 +811,25 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
|||||||
line = 1;
|
line = 1;
|
||||||
|
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
if (line > openfile->edittop->lineno + editwinrows ||
|
#ifndef NANO_TINY
|
||||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
linestruct *edit_bottom = openfile->edittop;
|
||||||
recook |= perturbed;
|
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
|
#endif
|
||||||
|
recook |= perturbed;
|
||||||
|
#endif /* ENABLE_COLOR */
|
||||||
|
|
||||||
/* Iterate to the requested line. */
|
/* Iterate to the requested line. */
|
||||||
for (openfile->current = openfile->filetop; line > 1 &&
|
for (openfile->current = openfile->filetop; line > 1 &&
|
||||||
openfile->current != openfile->filebot; line--)
|
openfile->current != openfile->filebot; line--)
|
||||||
openfile->current = openfile->current->next;
|
openfile->current = openfile->current->next;
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
|
|
||||||
/* Take a negative column number to mean: from the end of the line. */
|
/* Take a negative column number to mean: from the end of the line. */
|
||||||
if (column < 0)
|
if (column < 0)
|
||||||
column = breadth(openfile->current->data) + column + 2;
|
column = breadth(openfile->current->data) + column + 2;
|
||||||
@ -872,23 +884,110 @@ void do_gotolinecolumn(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#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
|
/* Search, starting from the current position, for any of the two characters
|
||||||
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
|
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
|
||||||
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
|
* 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;
|
const char *pointer, *found;
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
/* First step away from the current bracket. */
|
/* First step away from the current bracket. */
|
||||||
if (openfile->current_x == 0) {
|
if (*xpos == 0) {
|
||||||
line = line->prev;
|
line = line->prev;
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
pointer = line->data + strlen(line->data);
|
pointer = line->data + strlen(line->data);
|
||||||
} else
|
} 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. */
|
/* Now seek for any of the two brackets we are interested in. */
|
||||||
while (!(found = mbrevstrpbrk(line->data, bracket_pair, pointer))) {
|
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);
|
pointer = line->data + strlen(line->data);
|
||||||
}
|
}
|
||||||
} else {
|
} 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))) {
|
while (!(found = mbstrpbrk(pointer, bracket_pair))) {
|
||||||
line = line->next;
|
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. */
|
/* Set the found position to the found bracket. */
|
||||||
openfile->current = line;
|
*inout_line = line;
|
||||||
openfile->current_x = found - line->data;
|
*xpos = found - line->data;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for a match to the bracket at the current cursor position, if
|
/* Search for the given bracket's compliment within matchbrackets.
|
||||||
* there is one. */
|
* ch must be a pointer to within matchbrackets.
|
||||||
void do_find_bracket(void)
|
* 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;
|
size_t charcount = mbstrlen(matchbrackets) / 2;
|
||||||
/* Half the number of characters in matchbrackets. */
|
/* Half the number of characters in matchbrackets. */
|
||||||
size_t balance = 1;
|
const char *wanted_ch;
|
||||||
/* The initial bracket count. */
|
/* The location in matchbrackets of the complementing bracket. */
|
||||||
bool reverse;
|
size_t halfway = 0;
|
||||||
/* The direction we search. */
|
/* The index in matchbrackets where the closing brackets start. */
|
||||||
|
|
||||||
ch = mbstrchr(matchbrackets, openfile->current->data + openfile->current_x);
|
|
||||||
|
|
||||||
if (ch == NULL) {
|
|
||||||
statusline(AHEM, _("Not a bracket"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the halfway point in matchbrackets, where the closing ones start. */
|
/* Find the halfway point in matchbrackets, where the closing ones start. */
|
||||||
for (size_t i = 0; i < charcount; i++)
|
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
|
/* When on a closing bracket, we have to search backwards for a matching
|
||||||
* opening bracket; otherwise, forward for a matching closing bracket. */
|
* 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
|
/* Step half the number of total characters either backwards or forwards
|
||||||
* through matchbrackets to find the wanted complementary bracket. */
|
* through matchbrackets to find the wanted complementary bracket. */
|
||||||
wanted_ch = ch;
|
wanted_ch = ch;
|
||||||
while (charcount-- > 0) {
|
while (charcount-- > 0) {
|
||||||
if (reverse)
|
if (*reverse)
|
||||||
wanted_ch = matchbrackets + step_left(matchbrackets,
|
wanted_ch = matchbrackets + step_left(matchbrackets,
|
||||||
wanted_ch - matchbrackets);
|
wanted_ch - matchbrackets);
|
||||||
else
|
else
|
||||||
wanted_ch += char_length(wanted_ch);
|
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);
|
ch_len = char_length(ch);
|
||||||
wanted_ch_len = char_length(wanted_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, ch_len);
|
||||||
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
|
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
|
||||||
bracket_pair[ch_len + wanted_ch_len] = '\0';
|
bracket_pair[ch_len + wanted_ch_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
while (find_a_bracket(reverse, bracket_pair)) {
|
/* Get the bracket match position for the character currently under the cursor.
|
||||||
/* Increment/decrement balance for an identical/other bracket. */
|
* If there is no bracket beneath the cursor, return NOT_A_BRACKET. If there is
|
||||||
balance += (strncmp(openfile->current->data + openfile->current_x,
|
* no match found, return NOT_FOUND_BRACKET. Otherwise returns FOUND_BRACKET
|
||||||
ch, ch_len) == 0) ? 1 : -1;
|
* 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. */
|
br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
|
||||||
if (balance == 0) {
|
|
||||||
edit_redraw(was_current, FLOWING);
|
if (br_ch == NULL)
|
||||||
return;
|
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 = was_current;
|
||||||
openfile->current_x = was_current_x;
|
openfile->current_x = was_current_x;
|
||||||
|
|
||||||
|
statusline(AHEM, res == NOT_FOUND_BRACKET ?
|
||||||
|
_("No matching bracket") :
|
||||||
|
_("Not a bracket"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Place an anchor at the current line when none exists, otherwise remove it. */
|
/* 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) {
|
if (line != openfile->current) {
|
||||||
openfile->current = line;
|
openfile->current = line;
|
||||||
openfile->current_x = 0;
|
openfile->current_x = 0;
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
if (line->lineno > openfile->edittop->lineno + editwinrows ||
|
if (line->lineno > openfile->edittop->lineno + editwinrows ||
|
||||||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))
|
(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)
|
if (indent_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
|
|
||||||
/* Add the fabricated indentation to the beginning of the line. */
|
/* Add the fabricated indentation to the beginning of the line. */
|
||||||
line->data = nrealloc(line->data, length + indent_len + 1);
|
line->data = nrealloc(line->data, length + indent_len + 1);
|
||||||
memmove(line->data + indent_len, line->data, length + 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)
|
if (indent_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
|
|
||||||
/* Remove the first tab's worth of whitespace from this line. */
|
/* Remove the first tab's worth of whitespace from this line. */
|
||||||
memmove(line->data, line->data + indent_len, length - indent_len + 1);
|
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. */
|
/* Length of postfix. */
|
||||||
size_t line_len = strlen(line->data);
|
size_t line_len = strlen(line->data);
|
||||||
|
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
|
|
||||||
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
|
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -416,8 +422,9 @@ void do_comment(void)
|
|||||||
/* Comment/uncomment each of the selected lines when possible, and
|
/* Comment/uncomment each of the selected lines when possible, and
|
||||||
* store undo data when a line changed. */
|
* store undo data when a line changed. */
|
||||||
for (line = top; line != bot->next; line = line->next)
|
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, "");
|
update_multiline_undo(line->lineno, "");
|
||||||
|
}
|
||||||
|
|
||||||
set_modified();
|
set_modified();
|
||||||
ensure_firstcolumn_is_aligned();
|
ensure_firstcolumn_is_aligned();
|
||||||
@ -859,6 +866,13 @@ void do_enter(void)
|
|||||||
{
|
{
|
||||||
linestruct *newnode = make_new_node(openfile->current);
|
linestruct *newnode = make_new_node(openfile->current);
|
||||||
size_t extra = 0;
|
size_t extra = 0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (openfile->current->folded) {
|
||||||
|
newnode->folded = TRUE;
|
||||||
|
openfile->current->folded = FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
linestruct *sampleline = openfile->current;
|
linestruct *sampleline = openfile->current;
|
||||||
bool allblanks = FALSE;
|
bool allblanks = FALSE;
|
||||||
@ -1585,6 +1599,7 @@ void concat_paragraph(linestruct *line, size_t count)
|
|||||||
line->data = nrealloc(line->data,
|
line->data = nrealloc(line->data,
|
||||||
line_len + next_line_len - next_lead_len + 1);
|
line_len + next_line_len - next_lead_len + 1);
|
||||||
strcat(line->data, next_line->data + next_lead_len);
|
strcat(line->data, next_line->data + next_lead_len);
|
||||||
|
UNFOLD_SEGMENT(line);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
line->has_anchor |= next_line->has_anchor;
|
line->has_anchor |= next_line->has_anchor;
|
||||||
#endif
|
#endif
|
||||||
@ -2852,6 +2867,7 @@ void do_linter(void)
|
|||||||
|
|
||||||
/* Place the cursor to indicate the affected line. */
|
/* Place the cursor to indicate the affected line. */
|
||||||
place_the_cursor();
|
place_the_cursor();
|
||||||
|
UNFOLD_SEGMENT(openfile->current);
|
||||||
wnoutrefresh(midwin);
|
wnoutrefresh(midwin);
|
||||||
|
|
||||||
kbinput = get_kbinput(footwin, VISIBLE);
|
kbinput = get_kbinput(footwin, VISIBLE);
|
||||||
@ -2993,7 +3009,7 @@ void count_lines_words_and_characters(void)
|
|||||||
* incrementing the word count for each successful step. */
|
* incrementing the word count for each successful step. */
|
||||||
while (openfile->current->lineno < botline->lineno ||
|
while (openfile->current->lineno < botline->lineno ||
|
||||||
(openfile->current == botline && openfile->current_x < bot_x)) {
|
(openfile->current == botline && openfile->current_x < bot_x)) {
|
||||||
if (do_next_word(FALSE))
|
if (do_next_word(FALSE, ALLOW_FOLDED))
|
||||||
words++;
|
words++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
314
src/winio.c
314
src/winio.c
@ -140,6 +140,55 @@ void run_macro(void)
|
|||||||
}
|
}
|
||||||
#endif /* !NANO_TINY */
|
#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. */
|
/* Allocate the requested space for the keystroke buffer. */
|
||||||
void reserve_space_for(size_t newsize)
|
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,
|
/* 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)
|
int get_code_from_plantation(void)
|
||||||
{
|
{
|
||||||
if (*plants_pointer == '{') {
|
if (*plants_pointer == '{') {
|
||||||
@ -383,6 +432,7 @@ int get_code_from_plantation(void)
|
|||||||
return PLANTED_COMMAND;
|
return PLANTED_COMMAND;
|
||||||
} else {
|
} else {
|
||||||
char *opening = strchr(plants_pointer, '{');
|
char *opening = strchr(plants_pointer, '{');
|
||||||
|
char firstbyte = *plants_pointer;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
if (opening) {
|
if (opening) {
|
||||||
@ -391,12 +441,12 @@ int get_code_from_plantation(void)
|
|||||||
} else
|
} else
|
||||||
length = strlen(plants_pointer);
|
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]);
|
put_back((unsigned char)plants_pointer[index]);
|
||||||
|
|
||||||
plants_pointer += length;
|
plants_pointer += length;
|
||||||
|
|
||||||
return ERR;
|
return (firstbyte) ? firstbyte : ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2488,20 +2538,37 @@ void place_the_cursor(void)
|
|||||||
|
|
||||||
/* Calculate how many rows the lines from edittop to current use. */
|
/* Calculate how many rows the lines from edittop to current use. */
|
||||||
while (line != NULL && line != openfile->current) {
|
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;
|
line = line->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the number of wraps in the current line before the cursor. */
|
#ifdef ENABLE_FOLDING
|
||||||
row += get_chunk_and_edge(column, openfile->current, &leftedge);
|
if (!openfile->current->folded)
|
||||||
column -= leftedge;
|
|
||||||
} else
|
|
||||||
#endif
|
#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);
|
column -= get_page_start(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (openfile->current->folded) {
|
||||||
|
openfile->current_x = 0;
|
||||||
|
column = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (row < editwinrows)
|
if (row < editwinrows)
|
||||||
wmove(midwin, row, margin + column);
|
wmove(midwin, row, margin + column);
|
||||||
#ifndef NANO_TINY
|
#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. */
|
/* The number of bytes after which to stop painting, to avoid major slowdowns. */
|
||||||
#define PAINT_LIMIT 2000
|
#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
|
#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
|
/* If line numbering is switched on, put a line number in front of
|
||||||
* the text -- but only for the parts that are not softwrapped. */
|
* the text -- but only for the parts that are not softwrapped. */
|
||||||
if (margin > 0) {
|
if (margin > 0) {
|
||||||
wattron(midwin, interface_color_pair[LINE_NUMBER]);
|
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
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP) && from_col != 0)
|
if (ISSET(SOFTWRAP) && from_col != 0)
|
||||||
mvwprintw(midwin, row, 0, "%*s", margin - 1, " ");
|
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
|
#endif
|
||||||
wprintw(midwin, " ");
|
wprintw(midwin, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
#endif /* ENABLE_LINENUMBERS */
|
#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
|
/* First simply write the converted line -- afterward we'll add colors
|
||||||
* and the marking highlight on just the pieces that need it. */
|
* and the marking highlight on just the pieces that need it. */
|
||||||
mvwaddstr(midwin, row, margin, converted);
|
mvwaddstr(midwin, row, margin, converted);
|
||||||
@ -2800,18 +2882,54 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
|||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw the given line so that the character at the given index is visible
|
#ifdef ENABLE_FOLDING
|
||||||
* -- if necessary, scroll the line horizontally (when not softwrapping).
|
/* Draw a folded segment at the given row. */
|
||||||
* Return the number of rows "consumed" (relevant when softwrapping). */
|
int update_folded_line(linestruct *line, int row)
|
||||||
int update_line(linestruct *line, size_t index)
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
#ifdef ENABLE_COLOR
|
||||||
|
wattron(midwin, interface_color_pair[FOLDED_LINE]);
|
||||||
|
mvwaddstr(midwin, row, margin, string);
|
||||||
|
wattroff(midwin, interface_color_pair[FOLDED_LINE]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
char *converted;
|
||||||
/* The data of the line with tabs and control characters expanded. */
|
/* The data of the line with tabs and control characters expanded. */
|
||||||
size_t from_col;
|
size_t from_col;
|
||||||
/* From which column a horizontally scrolled line is displayed. */
|
/* 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
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP))
|
if (ISSET(SOFTWRAP))
|
||||||
return update_softwrapped_line(line);
|
return update_softwrapped_line(line);
|
||||||
@ -2819,7 +2937,6 @@ int update_line(linestruct *line, size_t index)
|
|||||||
sequel_column = 0;
|
sequel_column = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
row = line->lineno - openfile->edittop->lineno;
|
|
||||||
from_col = get_page_start(wideness(line->data, index));
|
from_col = get_page_start(wideness(line->data, index));
|
||||||
|
|
||||||
/* Expand the piece to be drawn to its representable form, and draw it. */
|
/* Expand the piece to be drawn to its representable form, and draw it. */
|
||||||
@ -2842,6 +2959,15 @@ int update_line(linestruct *line, size_t index)
|
|||||||
spotlight(light_from_col, light_to_col);
|
spotlight(light_from_col, light_to_col);
|
||||||
|
|
||||||
return 1;
|
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
|
#ifndef NANO_TINY
|
||||||
@ -2874,8 +3000,13 @@ int update_softwrapped_line(linestruct *line)
|
|||||||
|
|
||||||
/* Find out on which screen row the target line should be shown. */
|
/* Find out on which screen row the target line should be shown. */
|
||||||
while (someline != line && someline != NULL) {
|
while (someline != line && someline != NULL) {
|
||||||
row += 1 + extra_chunks_in(someline);
|
#ifdef ENABLE_FOLDING
|
||||||
someline = someline->next;
|
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. */
|
/* If the first chunk is offscreen, don't even try to display it. */
|
||||||
@ -2887,6 +3018,11 @@ int update_softwrapped_line(linestruct *line)
|
|||||||
|
|
||||||
starting_row = row;
|
starting_row = row;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (line->folded)
|
||||||
|
return update_folded_line(line, row);
|
||||||
|
#endif
|
||||||
|
|
||||||
while (!end_of_line && row < editwinrows) {
|
while (!end_of_line && row < editwinrows) {
|
||||||
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
|
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
|
||||||
|
|
||||||
@ -2933,7 +3069,14 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
|||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
/* Recede through the requested number of chunks. */
|
/* Recede through the requested number of chunks. */
|
||||||
for (i = nrows; i > 0; i--) {
|
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;
|
*leftedge = 0;
|
||||||
|
|
||||||
@ -2944,16 +3087,25 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
i -= chunk;
|
i -= chunk;
|
||||||
*line = (*line)->prev;
|
*line = get_prev_visible_line(*line);
|
||||||
*leftedge = HIGHEST_POSITIVE;
|
*leftedge = HIGHEST_POSITIVE;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_FOLDING
|
||||||
|
if ((*line)->folded)
|
||||||
|
*leftedge = 0;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
if (*leftedge == HIGHEST_POSITIVE)
|
if (*leftedge == HIGHEST_POSITIVE)
|
||||||
*leftedge = leftedge_for(*leftedge, *line);
|
*leftedge = leftedge_for(*leftedge, *line);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif /* !NANO_TINY */
|
||||||
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
|
{
|
||||||
*line = (*line)->prev;
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
@ -2973,6 +3125,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
|||||||
|
|
||||||
/* Advance through the requested number of chunks. */
|
/* Advance through the requested number of chunks. */
|
||||||
for (i = nrows; i > 0; i--) {
|
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;
|
bool end_of_line = FALSE;
|
||||||
|
|
||||||
current_leftedge = get_softwrap_breakpoint((*line)->data,
|
current_leftedge = get_softwrap_breakpoint((*line)->data,
|
||||||
@ -2993,9 +3153,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
|||||||
if (i < nrows)
|
if (i < nrows)
|
||||||
*leftedge = current_leftedge;
|
*leftedge = current_leftedge;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif /* !NANO_TINY */
|
||||||
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
|
{
|
||||||
*line = (*line)->next;
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
@ -3022,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. */
|
/* Draw a scroll bar on the righthand side of the screen. */
|
||||||
void draw_scrollbar(void)
|
void draw_scrollbar(void)
|
||||||
{
|
{
|
||||||
int fromline = openfile->edittop->lineno - 1;
|
|
||||||
int totallines = openfile->filebot->lineno;
|
int totallines = openfile->filebot->lineno;
|
||||||
int coveredlines = editwinrows;
|
int fromline = openfile->edittop->lineno - 1;
|
||||||
|
int coveredlines = 0;
|
||||||
|
linestruct *line = openfile->edittop;
|
||||||
|
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
linestruct *line = openfile->edittop;
|
int i = 0;
|
||||||
int extras = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
|
#ifdef ENABLE_FOLDING
|
||||||
|
if (line->folded)
|
||||||
while (line->lineno + extras < fromline + editwinrows && line->next) {
|
coveredlines += get_folded_segment_length(line);
|
||||||
line = line->next;
|
else
|
||||||
extras += extra_chunks_in(line);
|
#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;
|
int lowest = (fromline * editwinrows) / totallines;
|
||||||
@ -3088,7 +3280,12 @@ void edit_scroll(bool direction)
|
|||||||
if (thebar)
|
if (thebar)
|
||||||
draw_scrollbar();
|
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. */
|
/* Compensate for the earlier chunks of a softwrapped line. */
|
||||||
nrows += chunk_for(leftedge, line);
|
nrows += chunk_for(leftedge, line);
|
||||||
|
|
||||||
@ -3100,10 +3297,11 @@ void edit_scroll(bool direction)
|
|||||||
|
|
||||||
/* Draw new content on the blank row (and on the bordering row too
|
/* Draw new content on the blank row (and on the bordering row too
|
||||||
* when it was deemed necessary). */
|
* when it was deemed necessary). */
|
||||||
|
int row = get_row_from_edittop(line);
|
||||||
while (nrows > 0 && line != NULL) {
|
while (nrows > 0 && line != NULL) {
|
||||||
nrows -= update_line(line, (line == openfile->current) ?
|
nrows -= update_line_at(line, (line == openfile->current) ?
|
||||||
openfile->current_x : 0);
|
openfile->current_x : 0, row++);
|
||||||
line = line->next;
|
line = get_next_visible_line(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3300,8 +3498,7 @@ bool current_is_below_screen(void)
|
|||||||
leftedge < leftedge_for(xplustabs(), openfile->current))));
|
leftedge < leftedge_for(xplustabs(), openfile->current))));
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
return (openfile->current->lineno >=
|
return (get_row_from_edittop(openfile->current) >= editwinrows - SHIM);
|
||||||
openfile->edittop->lineno + editwinrows - SHIM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return TRUE if current[current_x] is outside the viewport. */
|
/* Return TRUE if current[current_x] is outside the viewport. */
|
||||||
@ -3329,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 the mark is on, update all lines between old_current and current. */
|
||||||
if (openfile->mark) {
|
if (openfile->mark) {
|
||||||
linestruct *line = old_current;
|
linestruct *line = old_current;
|
||||||
|
int row = get_row_from_edittop(line);
|
||||||
while (line != openfile->current) {
|
while (line != openfile->current) {
|
||||||
update_line(line, 0);
|
update_line_at(line, 0, row);
|
||||||
|
|
||||||
line = (line->lineno > openfile->current->lineno) ?
|
if (line->lineno > openfile->current->lineno) {
|
||||||
line->prev : line->next;
|
line = get_prev_visible_line(line);
|
||||||
|
--row;
|
||||||
|
} else {
|
||||||
|
line = get_next_visible_line(line);
|
||||||
|
++row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
@ -3389,9 +3591,13 @@ void edit_refresh(void)
|
|||||||
|
|
||||||
while (row < editwinrows && line != NULL) {
|
while (row < editwinrows && line != NULL) {
|
||||||
if (line == openfile->current)
|
if (line == openfile->current)
|
||||||
row += update_line(line, openfile->current_x);
|
row += update_line_at(line, openfile->current_x, row);
|
||||||
else
|
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;
|
line = line->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,9 @@ color brightcyan "\<(exec|print)([[:blank:]]|$)"
|
|||||||
# Special values.
|
# Special values.
|
||||||
color brightmagenta "\<(False|None|True)\>"
|
color brightmagenta "\<(False|None|True)\>"
|
||||||
|
|
||||||
|
# Decorators.
|
||||||
|
color cyan "@[[:alpha:]_][[:alnum:]_.]*"
|
||||||
|
|
||||||
# Mono-quoted strings.
|
# Mono-quoted strings.
|
||||||
color brightgreen "'([^'\]|\\.)*'|"([^"\]|\\.)*"|'''|""""
|
color brightgreen "'([^'\]|\\.)*'|"([^"\]|\\.)*"|'''|""""
|
||||||
color normal "'''|""""
|
color normal "'''|""""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user