Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 960ff2f3bf | |||
| 75f480ba10 | |||
| 1e08853a8b | |||
| c47c742e88 | |||
| cb1507bdd4 | |||
| e13b24e0ce |
14
configure.ac
14
configure.ac
@ -128,6 +128,20 @@ if test "x$enable_color" != xno; then
|
||||
color_support=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(folding,
|
||||
AS_HELP_STRING([--disable-folding], [Disable line folding support]))
|
||||
if test "x$enable_tiny" = xyes; then
|
||||
if test "x$enable_folding" = xyes; then
|
||||
AC_MSG_ERROR([
|
||||
*** --enable-folding cannot work with --enable-tiny])
|
||||
else
|
||||
enable_folding=no
|
||||
fi
|
||||
fi
|
||||
if test "x$enable_folding" != xno; then
|
||||
AC_DEFINE(ENABLE_FOLDING, 1, [Define this to have line folding support.])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(comment,
|
||||
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
|
||||
if test "x$enable_tiny" = xyes; then
|
||||
|
||||
@ -30,6 +30,7 @@ nano_SOURCES = \
|
||||
color.c \
|
||||
cut.c \
|
||||
files.c \
|
||||
folding.c \
|
||||
global.c \
|
||||
help.c \
|
||||
history.c \
|
||||
|
||||
23
src/cut.c
23
src/cut.c
@ -48,6 +48,7 @@ void do_deletion(undo_type action)
|
||||
memmove(&openfile->current->data[openfile->current_x],
|
||||
&openfile->current->data[openfile->current_x + charlen],
|
||||
line_len - charlen + 1);
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
#ifndef NANO_TINY
|
||||
/* When softwrapping, a changed number of chunks requires a refresh. */
|
||||
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
|
||||
@ -62,6 +63,9 @@ void do_deletion(undo_type action)
|
||||
} else if (openfile->current != openfile->filebot) {
|
||||
linestruct *joining = openfile->current->next;
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
UNFOLD_SEGMENT(joining);
|
||||
|
||||
/* If there is a magic line, and we're before it: don't eat it. */
|
||||
if (joining == openfile->filebot && openfile->current_x != 0 &&
|
||||
!ISSET(NO_NEWLINES)) {
|
||||
@ -143,7 +147,8 @@ void do_backspace(void)
|
||||
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
|
||||
do_deletion(BACK);
|
||||
} else if (openfile->current != openfile->filetop) {
|
||||
do_left();
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
do_deletion(BACK);
|
||||
}
|
||||
}
|
||||
@ -192,7 +197,7 @@ void chop_word(bool forward)
|
||||
* on the edge of the original line, then put the cursor on that
|
||||
* edge instead, so that lines will not be joined unexpectedly. */
|
||||
if (!forward) {
|
||||
do_prev_word();
|
||||
do_prev_word(ALLOW_FOLDED);
|
||||
if (openfile->current != is_current) {
|
||||
if (is_current_x > 0) {
|
||||
openfile->current = is_current;
|
||||
@ -201,13 +206,14 @@ void chop_word(bool forward)
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
} else {
|
||||
do_next_word(ISSET(AFTER_ENDS));
|
||||
do_next_word(ISSET(AFTER_ENDS), ALLOW_FOLDED);
|
||||
if (openfile->current != is_current &&
|
||||
is_current->data[is_current_x] != '\0') {
|
||||
openfile->current = is_current;
|
||||
openfile->current_x = strlen(is_current->data);
|
||||
}
|
||||
}
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Set the mark at the start of that word. */
|
||||
openfile->mark = openfile->current;
|
||||
@ -262,9 +268,13 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
|
||||
if (top == bot && top_x == bot_x)
|
||||
return;
|
||||
|
||||
if (top != bot)
|
||||
for (linestruct *line = top->next; line != bot->next; line = line->next)
|
||||
if (top != bot) {
|
||||
UNFOLD_SEGMENT(top);
|
||||
for (linestruct *line = top->next; line != bot->next; line = line->next) {
|
||||
UNFOLD_SEGMENT(line);
|
||||
had_anchor |= line->has_anchor;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (top == bot) {
|
||||
@ -378,6 +388,8 @@ void ingraft_buffer(linestruct *topline)
|
||||
#endif
|
||||
linestruct *botline = topline;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
while (botline->next != NULL)
|
||||
botline = botline->next;
|
||||
|
||||
@ -728,6 +740,7 @@ void paste_text(void)
|
||||
statusline(AHEM, _("Cutbuffer is empty"));
|
||||
return;
|
||||
}
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_undo(PASTE, NULL);
|
||||
|
||||
@ -273,6 +273,15 @@
|
||||
#define MSOME MMAIN|MBROWSER
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
#define UNFOLD_SEGMENT(line) unfold_folded_segment(line)
|
||||
#else
|
||||
#define UNFOLD_SEGMENT(line)
|
||||
#endif
|
||||
|
||||
#define ALLOW_FOLDED TRUE
|
||||
#define DISALLOW_FOLDED FALSE
|
||||
|
||||
/* Enumeration types. */
|
||||
typedef enum {
|
||||
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
|
||||
@ -374,6 +383,12 @@ enum {
|
||||
ZERO
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
FOUND_BRACKET = 0,
|
||||
NOT_FOUND_BRACKET,
|
||||
NOT_A_BRACKET
|
||||
} bracket_search_result;
|
||||
|
||||
/* Structure types. */
|
||||
#ifdef ENABLE_COLOR
|
||||
typedef struct colortype {
|
||||
@ -480,6 +495,10 @@ typedef struct linestruct {
|
||||
bool has_anchor;
|
||||
/* Whether the user has placed an anchor at this line. */
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
bool folded;
|
||||
/* Whether or not this line is in a fold segment */
|
||||
#endif
|
||||
} linestruct;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
|
||||
@ -681,6 +681,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
||||
if (ISSET(SOFTWRAP))
|
||||
was_leftedge = leftedge_for(xplustabs(), openfile->current);
|
||||
#endif
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Create an empty buffer. */
|
||||
topline = make_new_node(NULL);
|
||||
|
||||
138
src/folding.c
Normal file
138
src/folding.c
Normal file
@ -0,0 +1,138 @@
|
||||
/**************************************************************************
|
||||
* folding.c -- This file is part of GNU nano. *
|
||||
* *
|
||||
* Copyright (C) 2022 rexy712 *
|
||||
* *
|
||||
* GNU nano is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published *
|
||||
* by the Free Software Foundation, either version 3 of the License, *
|
||||
* or (at your option) any later version. *
|
||||
* *
|
||||
* GNU nano is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* See the GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "prototypes.h"
|
||||
|
||||
#include <ctype.h>
|
||||
/* isspace */
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
|
||||
/* Remove a folded segment from the given line until end of segment */
|
||||
void unfold_folded_segment_from(linestruct *line)
|
||||
{
|
||||
if (line != NULL)
|
||||
refresh_needed = TRUE;
|
||||
for(;line != NULL && line->folded;line = line->next)
|
||||
line->folded = FALSE;
|
||||
}
|
||||
|
||||
/* Remove a folded segment containing the given line */
|
||||
void unfold_folded_segment(linestruct *line)
|
||||
{
|
||||
unfold_folded_segment_from(get_start_of_folded_segment(line));
|
||||
}
|
||||
|
||||
/* Get the first member of the folded segment */
|
||||
linestruct *get_start_of_folded_segment(linestruct *line)
|
||||
{
|
||||
if (!line->folded)
|
||||
return line;
|
||||
|
||||
while (line->prev != NULL && line->prev->folded)
|
||||
line = line->prev;
|
||||
|
||||
return line;
|
||||
}
|
||||
/* Get the last member of the folded segment */
|
||||
linestruct *get_end_of_folded_segment(linestruct *line)
|
||||
{
|
||||
if (!line->folded)
|
||||
return line;
|
||||
|
||||
while (line->next != NULL && line->next->folded)
|
||||
line = line->next;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Get the span length of a folded_segment */
|
||||
int get_folded_segment_length(linestruct *line)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
if (!line->folded)
|
||||
return 0;
|
||||
|
||||
line = get_start_of_folded_segment(line);
|
||||
for (;line->next != NULL && line->next->folded;line = line->next)
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* Remove any folded_segments within the range [top, bottom].
|
||||
* Returns true if any segments are removed. */
|
||||
bool do_unfold_segment(linestruct *line)
|
||||
{
|
||||
/* Attempt to find a bracketed region first.
|
||||
* If not, top is unmodified. */
|
||||
if (!line->folded) {
|
||||
linestruct *bot;
|
||||
find_bracketed_region(openfile->current, &line, &bot);
|
||||
}
|
||||
|
||||
if (line->folded) {
|
||||
unfold_folded_segment(line);
|
||||
move_cursor_to_proper_column();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Fold the currently selected lines unless the current selection
|
||||
* already contains a folded_segment. In that case, remove any
|
||||
* segments that are selected. */
|
||||
void do_fold_segment(void)
|
||||
{
|
||||
linestruct *top, *bot;
|
||||
get_range(&top, &bot);
|
||||
|
||||
if (top == bot) {
|
||||
/* First try to unfold if this line/bracketed region is folded */
|
||||
if (do_unfold_segment(top))
|
||||
return;
|
||||
|
||||
/* When not selecting multiple lines, try to find bounding
|
||||
* brackets to act as top and bot. */
|
||||
if (!find_bracketed_region(openfile->current, &top, &bot)) {
|
||||
statusline(AHEM, _("No valid region found for automatic fold"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (linestruct* line = top;line != bot->next;line = line->next)
|
||||
line->folded = TRUE;
|
||||
|
||||
if (top->lineno < openfile->edittop->lineno &&
|
||||
bot->lineno > openfile->edittop->lineno)
|
||||
openfile->edittop = top;
|
||||
|
||||
/* Place the cursor at the start of the fold segment.
|
||||
* Anywhere else within the segment is invalid. */
|
||||
if (openfile->current->folded)
|
||||
openfile->current = get_start_of_folded_segment(top);
|
||||
openfile->mark = NULL;
|
||||
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_FOLDING */
|
||||
17
src/global.c
17
src/global.c
@ -642,6 +642,9 @@ void shortcut_init(void)
|
||||
const char *savefile_gist = N_("Save file without prompting");
|
||||
const char *findprev_gist = N_("Search next occurrence backward");
|
||||
const char *findnext_gist = N_("Search next occurrence forward");
|
||||
#ifdef ENABLE_FOLDING
|
||||
const char *fold_gist = N_("Fold/unfold the currently selected lines");
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
const char *recordmacro_gist = N_("Start/stop recording a macro");
|
||||
const char *runmacro_gist = N_("Run the last recorded macro");
|
||||
@ -998,7 +1001,14 @@ void shortcut_init(void)
|
||||
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
|
||||
add_to_funcs(run_macro, MMAIN,
|
||||
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
add_to_funcs(do_fold_segment, MMAIN, N_("Fold"),
|
||||
WHENHELP(fold_gist), BLANKAFTER);
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_to_funcs(zap_text, MMAIN,
|
||||
/* TRANSLATORS: This refers to deleting a line or marked region. */
|
||||
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
|
||||
@ -1208,6 +1218,9 @@ void shortcut_init(void)
|
||||
#ifdef ENABLE_FORMATTER
|
||||
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
|
||||
add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
add_to_sclist(MMAIN, "M-[", 0, do_fold_segment, 0);
|
||||
#endif
|
||||
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
|
||||
add_to_sclist(MMAIN, SLASH_OR_DASH, 0, do_gotolinecolumn, 0);
|
||||
@ -1341,10 +1354,10 @@ void shortcut_init(void)
|
||||
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
|
||||
#endif
|
||||
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
|
||||
#ifndef NANO_TINY
|
||||
|
||||
122
src/move.c
122
src/move.c
@ -37,7 +37,13 @@ void to_first_line(void)
|
||||
void to_last_line(void)
|
||||
{
|
||||
openfile->current = openfile->filebot;
|
||||
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current = get_start_of_folded_segment(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
} else
|
||||
#endif
|
||||
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
|
||||
openfile->placewewant = xplustabs();
|
||||
|
||||
/* Set the last line of the screen as the target for the cursor. */
|
||||
@ -112,6 +118,15 @@ void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
|
||||
openfile->placewewant = *leftedge + target;
|
||||
}
|
||||
|
||||
/* Move the cursor position on the current line to the desired column */
|
||||
void move_cursor_to_proper_column(void)
|
||||
{
|
||||
size_t leftedge;
|
||||
size_t target_column;
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
set_proper_index_and_pww(&leftedge, target_column, TRUE);
|
||||
}
|
||||
|
||||
/* Move up almost one screenful. */
|
||||
void do_page_up(void)
|
||||
{
|
||||
@ -235,19 +250,29 @@ void to_para_end(void)
|
||||
void to_prev_block(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
linestruct *line_step = get_prev_visible_line(openfile->current);
|
||||
bool is_text = FALSE, seen_text = FALSE;
|
||||
|
||||
/* Skip backward until first blank line after some nonblank line(s). */
|
||||
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
|
||||
openfile->current = openfile->current->prev;
|
||||
while (line_step != NULL && (!seen_text || is_text)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_prev_visible_line(line_step);
|
||||
#ifdef ENABLE_FOLDING
|
||||
/* Skip over the visibly drawn line of the folded segment */
|
||||
if (openfile->current->folded)
|
||||
continue;
|
||||
#endif
|
||||
is_text = !white_string(openfile->current->data);
|
||||
seen_text = seen_text || is_text;
|
||||
}
|
||||
|
||||
/* Step forward one line again if we passed text but this line is blank. */
|
||||
if (seen_text && openfile->current->next != NULL &&
|
||||
white_string(openfile->current->data))
|
||||
openfile->current = openfile->current->next;
|
||||
line_step = get_next_visible_line(openfile->current);
|
||||
if (seen_text && line_step != NULL &&
|
||||
white_string(openfile->current->data)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_next_visible_line(line_step);
|
||||
}
|
||||
|
||||
openfile->current_x = 0;
|
||||
edit_redraw(was_current, CENTERING);
|
||||
@ -257,12 +282,19 @@ void to_prev_block(void)
|
||||
void to_next_block(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
linestruct *line_step = get_next_visible_line(openfile->current);
|
||||
bool is_white = white_string(openfile->current->data);
|
||||
bool seen_white = is_white;
|
||||
|
||||
/* Skip forward until first nonblank line after some blank line(s). */
|
||||
while (openfile->current->next != NULL && (!seen_white || is_white)) {
|
||||
openfile->current = openfile->current->next;
|
||||
while (line_step != NULL && (!seen_white || is_white)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_next_visible_line(line_step);
|
||||
#ifdef ENABLE_FOLDING
|
||||
/* Skip over the visibly drawn line of the folded segment */
|
||||
if (openfile->current->folded)
|
||||
continue;
|
||||
#endif
|
||||
is_white = white_string(openfile->current->data);
|
||||
seen_white = seen_white || is_white;
|
||||
}
|
||||
@ -274,19 +306,35 @@ void to_next_block(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Move to the previous word. */
|
||||
void do_prev_word(void)
|
||||
/* Move to the previous word.
|
||||
* when allow_folded is true, will move to previous word even if inside
|
||||
* a folded segment */
|
||||
void do_prev_word(bool allow_folded)
|
||||
{
|
||||
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||
bool seen_a_word = FALSE, step_forward = FALSE;
|
||||
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded && openfile->current->folded) {
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
#endif
|
||||
/* Move backward until we pass over the start of a word. */
|
||||
while (TRUE) {
|
||||
/* If at the head of a line, move to the end of the preceding one. */
|
||||
if (openfile->current_x == 0) {
|
||||
if (openfile->current->prev == NULL)
|
||||
break;
|
||||
openfile->current = openfile->current->prev;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded) {
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
if (openfile->current->folded)
|
||||
openfile->current = openfile->current->prev;
|
||||
} else
|
||||
#endif
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
|
||||
@ -315,11 +363,13 @@ void do_prev_word(void)
|
||||
/* Move one character forward again to sit on the start of the word. */
|
||||
openfile->current_x = step_right(openfile->current->data,
|
||||
openfile->current_x);
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
}
|
||||
|
||||
/* Move to the next word. If after_ends is TRUE, stop at the ends of words
|
||||
* instead of at their beginnings. Return TRUE if we started on a word. */
|
||||
bool do_next_word(bool after_ends)
|
||||
* instead of at their beginnings. If allow_folded is true, go to next word
|
||||
* even if it's inside a folded segment. Return TRUE if we started on a word. */
|
||||
bool do_next_word(bool after_ends, bool allow_folded)
|
||||
{
|
||||
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||
bool started_on_word = is_word_char(openfile->current->data +
|
||||
@ -329,6 +379,12 @@ bool do_next_word(bool after_ends)
|
||||
bool seen_word = started_on_word;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded && openfile->current->folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
#endif
|
||||
/* Move forward until we reach the start of a word. */
|
||||
while (TRUE) {
|
||||
/* If at the end of a line, move to the beginning of the next one. */
|
||||
@ -336,7 +392,18 @@ bool do_next_word(bool after_ends)
|
||||
/* When at end of file, stop. */
|
||||
if (openfile->current->next == NULL)
|
||||
break;
|
||||
openfile->current = openfile->current->next;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
if (openfile->current->folded) {
|
||||
/* get_next_visible_line() gives the start of a folded segment,
|
||||
* so skip to the end */
|
||||
openfile->current = get_end_of_folded_segment(openfile->current);
|
||||
openfile->current = openfile->current->next;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
openfile->current = openfile->current->next;
|
||||
openfile->current_x = 0;
|
||||
seen_space = TRUE;
|
||||
} else {
|
||||
@ -376,6 +443,8 @@ bool do_next_word(bool after_ends)
|
||||
}
|
||||
}
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
return started_on_word;
|
||||
}
|
||||
|
||||
@ -384,7 +453,7 @@ void to_prev_word(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
do_prev_word();
|
||||
do_prev_word(DISALLOW_FOLDED);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
@ -395,7 +464,7 @@ void to_next_word(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
do_next_word(ISSET(AFTER_ENDS));
|
||||
do_next_word(ISSET(AFTER_ENDS), DISALLOW_FOLDED);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
@ -413,6 +482,11 @@ void do_home(void)
|
||||
size_t leftedge = 0;
|
||||
size_t left_x = 0;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
leftedge = leftedge_for(was_column, openfile->current);
|
||||
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
|
||||
@ -470,6 +544,11 @@ void do_end(void)
|
||||
size_t line_len = strlen(openfile->current->data);
|
||||
bool moved_off_chunk = TRUE;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
bool kickoff = TRUE;
|
||||
@ -612,7 +691,7 @@ void do_left(void)
|
||||
openfile->current_x);
|
||||
#endif
|
||||
} else if (openfile->current != openfile->filetop) {
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
|
||||
@ -624,6 +703,13 @@ void do_right(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
if (openfile->current == NULL)
|
||||
openfile->current = was_current;
|
||||
} else
|
||||
#endif
|
||||
if (openfile->current->data[openfile->current_x] != '\0') {
|
||||
openfile->current_x = step_right(openfile->current->data,
|
||||
openfile->current_x);
|
||||
@ -634,7 +720,7 @@ void do_right(void)
|
||||
openfile->current_x);
|
||||
#endif
|
||||
} else if (openfile->current != openfile->filebot) {
|
||||
openfile->current = openfile->current->next;
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -78,6 +78,9 @@ linestruct *make_new_node(linestruct *prevnode)
|
||||
#ifndef NANO_TINY
|
||||
newnode->has_anchor = FALSE;
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
newnode->folded = FALSE;
|
||||
#endif
|
||||
|
||||
return newnode;
|
||||
}
|
||||
@ -117,6 +120,7 @@ void delete_node(linestruct *line)
|
||||
/* Disconnect a node from a linked list of linestructs and delete it. */
|
||||
void unlink_node(linestruct *line)
|
||||
{
|
||||
UNFOLD_SEGMENT(line);
|
||||
if (line->prev != NULL)
|
||||
line->prev->next = line->next;
|
||||
if (line->next != NULL)
|
||||
@ -156,6 +160,9 @@ linestruct *copy_node(const linestruct *src)
|
||||
#ifndef NANO_TINY
|
||||
dst->has_anchor = src->has_anchor;
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
dst->folded = src->folded;
|
||||
#endif
|
||||
|
||||
return dst;
|
||||
}
|
||||
@ -1461,6 +1468,7 @@ void inject(char *burst, size_t count)
|
||||
#ifndef NANO_TINY
|
||||
size_t original_row = 0;
|
||||
size_t old_amount = 0;
|
||||
UNFOLD_SEGMENT(thisline);
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
if (openfile->current_y == editwinrows - 1)
|
||||
|
||||
@ -365,8 +365,8 @@ void to_para_end(void);
|
||||
#endif
|
||||
void to_prev_block(void);
|
||||
void to_next_block(void);
|
||||
void do_prev_word(void);
|
||||
bool do_next_word(bool after_ends);
|
||||
void do_prev_word(bool allow_folded);
|
||||
bool do_next_word(bool after_ends, bool allow_folded);
|
||||
void to_prev_word(void);
|
||||
void to_next_word(void);
|
||||
void do_home(void);
|
||||
@ -380,6 +380,7 @@ void do_center(void);
|
||||
#endif
|
||||
void do_left(void);
|
||||
void do_right(void);
|
||||
void move_cursor_to_proper_column(void);
|
||||
|
||||
/* Most functions in nano.c. */
|
||||
linestruct *make_new_node(linestruct *prevnode);
|
||||
@ -476,6 +477,9 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
||||
bool interactive);
|
||||
void do_gotolinecolumn(void);
|
||||
#ifndef NANO_TINY
|
||||
int find_matching_bracket_pos(linestruct **line, size_t *xpos);
|
||||
bool find_bracketed_region(linestruct *in_region,
|
||||
linestruct **top, linestruct **bot);
|
||||
void do_find_bracket(void);
|
||||
void put_or_lift_anchor(void);
|
||||
void to_prev_anchor(void);
|
||||
@ -579,6 +583,8 @@ linestruct *line_from_number(ssize_t number);
|
||||
#endif
|
||||
|
||||
/* Most functions in winio.c. */
|
||||
linestruct *get_next_visible_line(linestruct *line);
|
||||
linestruct *get_prev_visible_line(linestruct *line);
|
||||
#ifndef NANO_TINY
|
||||
void record_macro(void);
|
||||
void run_macro(void);
|
||||
@ -610,6 +616,7 @@ void warn_and_briefly_pause(const char *msg);
|
||||
void bottombars(int menu);
|
||||
void post_one_key(const char *keystroke, const char *tag, int width);
|
||||
void place_the_cursor(void);
|
||||
int update_line_at(linestruct *line, size_t index, int row);
|
||||
int update_line(linestruct *line, size_t index);
|
||||
#ifndef NANO_TINY
|
||||
int update_softwrapped_line(linestruct *line);
|
||||
@ -674,3 +681,13 @@ void flip_newbuffer(void);
|
||||
#endif
|
||||
void discard_buffer(void);
|
||||
void do_cancel(void);
|
||||
|
||||
/* Most functions in folding.c. */
|
||||
#ifdef ENABLE_FOLDING
|
||||
void do_fold_segment(void);
|
||||
void unfold_folded_segment(linestruct *line);
|
||||
void unfold_folded_segment_from(linestruct *line);
|
||||
linestruct *get_start_of_folded_segment(linestruct* line);
|
||||
linestruct *get_end_of_folded_segment(linestruct* line);
|
||||
int get_folded_segment_length(linestruct *line);
|
||||
#endif
|
||||
|
||||
242
src/search.c
242
src/search.c
@ -308,6 +308,8 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
|
||||
}
|
||||
}
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
found_x = found - line->data;
|
||||
|
||||
nodelay(midwin, FALSE);
|
||||
@ -754,6 +756,7 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
|
||||
|
||||
openfile->current_x = pos_x;
|
||||
openfile->placewewant = xplustabs();
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
@ -808,16 +811,27 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
||||
line = 1;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
#ifdef ENABLE_FOLDING
|
||||
linestruct *edit_bottom = openfile->edittop;
|
||||
for (int i = 0;edit_bottom != openfile->filebot && i < editwinrows;++i)
|
||||
edit_bottom = get_next_visible_line(edit_bottom);
|
||||
if (line > edit_bottom->lineno ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
recook |= perturbed;
|
||||
#else
|
||||
if (line > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
recook |= perturbed;
|
||||
#endif
|
||||
#endif /* ENABLE_FOLDING */
|
||||
#endif /* ENABLE_COLOR */
|
||||
|
||||
/* Iterate to the requested line. */
|
||||
for (openfile->current = openfile->filetop; line > 1 &&
|
||||
openfile->current != openfile->filebot; line--)
|
||||
openfile->current = openfile->current->next;
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Take a negative column number to mean: from the end of the line. */
|
||||
if (column < 0)
|
||||
column = breadth(openfile->current->data) + column + 2;
|
||||
@ -872,23 +886,110 @@ void do_gotolinecolumn(void)
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Search backwards for a line ending with a bracket, including the current line.
|
||||
* top is an in/out parameter. The passed value is the start line for searching.
|
||||
* xpos is an out parameter. It is the position in the line where the bracket is
|
||||
* found. bracket_half is the halfway mark in the matchbrackets array. This way in
|
||||
* a loop the halfway value isn't recomputed. */
|
||||
bool find_start_of_bracketed_region(linestruct **top, size_t *xpos, size_t bracket_half)
|
||||
{
|
||||
/* Search backwards for a line ending with a bracket, including the current line */
|
||||
for (;(*top) != NULL;*top = (*top)->prev) {
|
||||
char *found;
|
||||
const char *bracket;
|
||||
int len = strlen((*top)->data);
|
||||
|
||||
/* Find the last bracket on the search line */
|
||||
found = mbrevstrpbrk((*top)->data, matchbrackets, (*top)->data + len);
|
||||
if (found == NULL)
|
||||
continue;
|
||||
|
||||
*xpos = found - (*top)->data;
|
||||
bracket = mbstrchr(matchbrackets, found);
|
||||
|
||||
/* We're looking for opening braces, not closing */
|
||||
if (bracket >= matchbrackets + bracket_half)
|
||||
continue;
|
||||
|
||||
/* Check if this is the last character in the line */
|
||||
char *next = (*top)->data + step_right((*top)->data, *xpos);
|
||||
if (*next == '\0')
|
||||
return TRUE;
|
||||
}
|
||||
*xpos = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get the halfway point in matchbrackets, where open and close
|
||||
* brackets meet. */
|
||||
size_t get_matchbrackets_halfway(void)
|
||||
{
|
||||
size_t charcount = mbstrlen(matchbrackets) / 2;
|
||||
size_t halfway = 0;
|
||||
|
||||
for (size_t i = 0;i < charcount;++i)
|
||||
halfway += char_length(matchbrackets + halfway);
|
||||
return halfway;
|
||||
}
|
||||
/* Get a region surrounding the line in_region. A region here is defined
|
||||
* as a block of text starting with an opening bracket at the end of a line,
|
||||
* and ending with a matching closing bracket.
|
||||
* top and bot are out parameters. Returns the top/bottom line of the region.
|
||||
* top_pos and bot_pos are out parameters. Returns the position within the
|
||||
* top and bottom lines where the brackets are found. */
|
||||
bool find_bracketed_region(linestruct *in_region,
|
||||
linestruct **top, linestruct **bot)
|
||||
{
|
||||
size_t bracket_half = get_matchbrackets_halfway();
|
||||
size_t top_pos;
|
||||
size_t bot_pos;
|
||||
linestruct *was_top = *top;
|
||||
linestruct *was_bot = *bot;
|
||||
*top = in_region;
|
||||
|
||||
for (;find_start_of_bracketed_region(top, &top_pos, bracket_half)
|
||||
;*top = (*top)->prev)
|
||||
{
|
||||
*bot = *top;
|
||||
bot_pos = top_pos;
|
||||
|
||||
if (!find_matching_bracket_pos(bot, &bot_pos)) {
|
||||
if ((*bot)->lineno < in_region->lineno)
|
||||
continue;
|
||||
|
||||
int linedist = (*bot)->lineno - (*top)->lineno;
|
||||
|
||||
if (linedist >= 2) {
|
||||
*top = (*top)->next;
|
||||
*bot = (*bot)->prev;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
*top = was_top;
|
||||
*bot = was_bot;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* Search, starting from the current position, for any of the two characters
|
||||
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
|
||||
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
|
||||
bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
bool find_a_bracket(bool reverse, const char *bracket_pair,
|
||||
linestruct **inout_line, size_t *xpos)
|
||||
{
|
||||
linestruct *line = openfile->current;
|
||||
linestruct *line = *inout_line;
|
||||
const char *pointer, *found;
|
||||
|
||||
if (reverse) {
|
||||
/* First step away from the current bracket. */
|
||||
if (openfile->current_x == 0) {
|
||||
if (*xpos == 0) {
|
||||
line = line->prev;
|
||||
if (line == NULL)
|
||||
return FALSE;
|
||||
pointer = line->data + strlen(line->data);
|
||||
} else
|
||||
pointer = line->data + step_left(line->data, openfile->current_x);
|
||||
pointer = line->data + step_left(line->data, *xpos);
|
||||
|
||||
/* Now seek for any of the two brackets we are interested in. */
|
||||
while (!(found = mbrevstrpbrk(line->data, bracket_pair, pointer))) {
|
||||
@ -898,7 +999,7 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
pointer = line->data + strlen(line->data);
|
||||
}
|
||||
} else {
|
||||
pointer = line->data + step_right(line->data, openfile->current_x);
|
||||
pointer = line->data + step_right(line->data, *xpos);
|
||||
|
||||
while (!(found = mbstrpbrk(pointer, bracket_pair))) {
|
||||
line = line->next;
|
||||
@ -908,45 +1009,24 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the current position to the found bracket. */
|
||||
openfile->current = line;
|
||||
openfile->current_x = found - line->data;
|
||||
/* Set the found position to the found bracket. */
|
||||
*inout_line = line;
|
||||
*xpos = found - line->data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Search for a match to the bracket at the current cursor position, if
|
||||
* there is one. */
|
||||
void do_find_bracket(void)
|
||||
/* Search for the given bracket's compliment within matchbrackets.
|
||||
* ch must be a pointer to within matchbrackets.
|
||||
* reverse is true if the found compliment came before ch in matchbrackets. */
|
||||
const char *get_bracket_compliment(const char *ch, bool *reverse)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
size_t was_current_x = openfile->current_x;
|
||||
/* The current cursor position, in case we don't find a complement. */
|
||||
const char *ch;
|
||||
/* The location in matchbrackets of the bracket under the cursor. */
|
||||
int ch_len;
|
||||
/* The length of ch in bytes. */
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
int wanted_ch_len;
|
||||
/* The length of wanted_ch in bytes. */
|
||||
char bracket_pair[MAXCHARLEN * 2 + 1];
|
||||
/* The pair of characters in ch and wanted_ch. */
|
||||
size_t halfway = 0;
|
||||
/* The index in matchbrackets where the closing brackets start. */
|
||||
size_t charcount = mbstrlen(matchbrackets) / 2;
|
||||
/* Half the number of characters in matchbrackets. */
|
||||
size_t balance = 1;
|
||||
/* The initial bracket count. */
|
||||
bool reverse;
|
||||
/* The direction we search. */
|
||||
|
||||
ch = mbstrchr(matchbrackets, openfile->current->data + openfile->current_x);
|
||||
|
||||
if (ch == NULL) {
|
||||
statusline(AHEM, _("Not a bracket"));
|
||||
return;
|
||||
}
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
size_t halfway = 0;
|
||||
/* The index in matchbrackets where the closing brackets start. */
|
||||
|
||||
/* Find the halfway point in matchbrackets, where the closing ones start. */
|
||||
for (size_t i = 0; i < charcount; i++)
|
||||
@ -954,19 +1034,35 @@ void do_find_bracket(void)
|
||||
|
||||
/* When on a closing bracket, we have to search backwards for a matching
|
||||
* opening bracket; otherwise, forward for a matching closing bracket. */
|
||||
reverse = (ch >= (matchbrackets + halfway));
|
||||
*reverse = (ch >= (matchbrackets + halfway));
|
||||
|
||||
/* Step half the number of total characters either backwards or forwards
|
||||
* through matchbrackets to find the wanted complementary bracket. */
|
||||
wanted_ch = ch;
|
||||
while (charcount-- > 0) {
|
||||
if (reverse)
|
||||
if (*reverse)
|
||||
wanted_ch = matchbrackets + step_left(matchbrackets,
|
||||
wanted_ch - matchbrackets);
|
||||
else
|
||||
wanted_ch += char_length(wanted_ch);
|
||||
}
|
||||
|
||||
return wanted_ch;
|
||||
}
|
||||
|
||||
/* Create a bracket pair string from the given bracket in ch, assigning
|
||||
* the result to bracket_pair. Reverse is set to true if we need to
|
||||
* search backward for a match. */
|
||||
void create_bracket_pair(char *bracket_pair, const char *ch,
|
||||
int ch_len, bool* reverse)
|
||||
{
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
int wanted_ch_len;
|
||||
/* The length of wanted_ch in bytes. */
|
||||
|
||||
wanted_ch = get_bracket_compliment(ch, reverse);
|
||||
|
||||
ch_len = char_length(ch);
|
||||
wanted_ch_len = char_length(wanted_ch);
|
||||
|
||||
@ -974,24 +1070,65 @@ void do_find_bracket(void)
|
||||
strncpy(bracket_pair, ch, ch_len);
|
||||
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
|
||||
bracket_pair[ch_len + wanted_ch_len] = '\0';
|
||||
}
|
||||
|
||||
while (find_a_bracket(reverse, bracket_pair)) {
|
||||
/* Increment/decrement balance for an identical/other bracket. */
|
||||
balance += (strncmp(openfile->current->data + openfile->current_x,
|
||||
ch, ch_len) == 0) ? 1 : -1;
|
||||
/* Get the bracket match position for the character currently under the cursor.
|
||||
* If there is no bracket beneath the cursor, return NOT_A_BRACKET. If there is
|
||||
* no match found, return NOT_FOUND_BRACKET. Otherwise returns FOUND_BRACKET
|
||||
* and sets line and xpos to the found line and offset respectively. */
|
||||
int find_matching_bracket_pos(linestruct **line, size_t *xpos)
|
||||
{
|
||||
const char *br_ch;
|
||||
/* The location in matchbrackets of the bracket under the cursor. */
|
||||
int br_ch_len;
|
||||
/* The length of br_ch in bytes. */
|
||||
char bracket_pair[MAXCHARLEN * 2 + 1];
|
||||
/* The pair of characters in ch and wanted_ch. */
|
||||
size_t balance = 1;
|
||||
/* The initial bracket count. */
|
||||
bool reversed;
|
||||
/* The direction we search. */
|
||||
|
||||
/* When balance reached zero, we've found the complementary bracket. */
|
||||
if (balance == 0) {
|
||||
edit_redraw(was_current, FLOWING);
|
||||
return;
|
||||
}
|
||||
br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
|
||||
|
||||
if (br_ch == NULL)
|
||||
return NOT_A_BRACKET;
|
||||
|
||||
br_ch_len = char_length(br_ch);
|
||||
create_bracket_pair(bracket_pair, br_ch, br_ch_len, &reversed);
|
||||
|
||||
|
||||
while (find_a_bracket(reversed, bracket_pair, line, xpos)) {
|
||||
balance += (strncmp((*line)->data + *xpos,
|
||||
br_ch, br_ch_len) == 0) ? 1 : -1;
|
||||
if (balance == 0)
|
||||
return FOUND_BRACKET;
|
||||
|
||||
}
|
||||
return NOT_FOUND_BRACKET;
|
||||
}
|
||||
|
||||
/* Search for a match to the bracket at the current cursor position, if
|
||||
* there is one. */
|
||||
void do_find_bracket(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
size_t was_current_x = openfile->current_x;
|
||||
|
||||
int res = find_matching_bracket_pos(&openfile->current,
|
||||
&openfile->current_x);
|
||||
if (res == FOUND_BRACKET) {
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
edit_redraw(was_current, FLOWING);
|
||||
return;
|
||||
}
|
||||
|
||||
statusline(AHEM, _("No matching bracket"));
|
||||
|
||||
/* Restore the cursor position. */
|
||||
openfile->current = was_current;
|
||||
openfile->current_x = was_current_x;
|
||||
|
||||
statusline(AHEM, res == NOT_FOUND_BRACKET ?
|
||||
_("No matching bracket") :
|
||||
_("Not a bracket"));
|
||||
}
|
||||
|
||||
/* Place an anchor at the current line when none exists, otherwise remove it. */
|
||||
@ -1015,6 +1152,7 @@ void go_to_and_confirm(linestruct *line)
|
||||
if (line != openfile->current) {
|
||||
openfile->current = line;
|
||||
openfile->current_x = 0;
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line->lineno > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))
|
||||
|
||||
16
src/text.c
16
src/text.c
@ -96,6 +96,8 @@ void indent_a_line(linestruct *line, char *indentation)
|
||||
if (indent_len == 0)
|
||||
return;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
/* Add the fabricated indentation to the beginning of the line. */
|
||||
line->data = nrealloc(line->data, length + indent_len + 1);
|
||||
memmove(line->data + indent_len, line->data, length + 1);
|
||||
@ -226,6 +228,8 @@ void unindent_a_line(linestruct *line, size_t indent_len)
|
||||
if (indent_len == 0)
|
||||
return;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
/* Remove the first tab's worth of whitespace from this line. */
|
||||
memmove(line->data, line->data + indent_len, length - indent_len + 1);
|
||||
|
||||
@ -317,6 +321,8 @@ bool comment_line(undo_type action, linestruct *line, const char *comment_seq)
|
||||
/* Length of postfix. */
|
||||
size_t line_len = strlen(line->data);
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
|
||||
return FALSE;
|
||||
|
||||
@ -859,6 +865,12 @@ void do_enter(void)
|
||||
{
|
||||
linestruct *newnode = make_new_node(openfile->current);
|
||||
size_t extra = 0;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
newnode->folded = TRUE;
|
||||
openfile->current->folded = FALSE;
|
||||
}
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
linestruct *sampleline = openfile->current;
|
||||
bool allblanks = FALSE;
|
||||
@ -1585,6 +1597,7 @@ void concat_paragraph(linestruct *line, size_t count)
|
||||
line->data = nrealloc(line->data,
|
||||
line_len + next_line_len - next_lead_len + 1);
|
||||
strcat(line->data, next_line->data + next_lead_len);
|
||||
UNFOLD_SEGMENT(line);
|
||||
#ifndef NANO_TINY
|
||||
line->has_anchor |= next_line->has_anchor;
|
||||
#endif
|
||||
@ -2852,6 +2865,7 @@ void do_linter(void)
|
||||
|
||||
/* Place the cursor to indicate the affected line. */
|
||||
place_the_cursor();
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
wnoutrefresh(midwin);
|
||||
|
||||
kbinput = get_kbinput(footwin, VISIBLE);
|
||||
@ -2993,7 +3007,7 @@ void count_lines_words_and_characters(void)
|
||||
* incrementing the word count for each successful step. */
|
||||
while (openfile->current->lineno < botline->lineno ||
|
||||
(openfile->current == botline && openfile->current_x < bot_x)) {
|
||||
if (do_next_word(FALSE))
|
||||
if (do_next_word(FALSE, ALLOW_FOLDED))
|
||||
words++;
|
||||
}
|
||||
|
||||
|
||||
301
src/winio.c
301
src/winio.c
@ -140,6 +140,55 @@ void run_macro(void)
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
/* Return the current offset of target from openfile->edittop */
|
||||
int get_row_from_edittop(linestruct *target)
|
||||
{
|
||||
#ifdef ENABLE_FOLDING
|
||||
linestruct *line = openfile->edittop;
|
||||
int row = 0;
|
||||
while (line != NULL && line != target && row < editwinrows) {
|
||||
line = get_end_of_folded_segment(line);
|
||||
line = line->next;
|
||||
++row;
|
||||
}
|
||||
return row;
|
||||
#else
|
||||
return target->lineno - openfile->edittop->lineno;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the next line, taking fold segments into account */
|
||||
linestruct *get_next_visible_line(linestruct *line)
|
||||
{
|
||||
if (!line)
|
||||
return NULL;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
line = get_end_of_folded_segment(line);
|
||||
if (line == NULL)
|
||||
return NULL;
|
||||
#endif
|
||||
return line->next;
|
||||
}
|
||||
|
||||
/* Return the previous line, taking fold segments into account */
|
||||
linestruct *get_prev_visible_line(linestruct *line)
|
||||
{
|
||||
if (!line)
|
||||
return NULL;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded) {
|
||||
line = get_start_of_folded_segment(line);
|
||||
return line == NULL ? NULL : line->prev;
|
||||
}
|
||||
if (line->prev != NULL && line->prev->folded)
|
||||
return get_start_of_folded_segment(line->prev);
|
||||
|
||||
#endif
|
||||
return line->prev;
|
||||
}
|
||||
|
||||
/* Allocate the requested space for the keystroke buffer. */
|
||||
void reserve_space_for(size_t newsize)
|
||||
{
|
||||
@ -2489,20 +2538,37 @@ void place_the_cursor(void)
|
||||
|
||||
/* Calculate how many rows the lines from edittop to current use. */
|
||||
while (line != NULL && line != openfile->current) {
|
||||
row += 1 + extra_chunks_in(line);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded) {
|
||||
line = get_end_of_folded_segment(line);
|
||||
++row;
|
||||
} else
|
||||
#endif
|
||||
row += 1 + extra_chunks_in(line);
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
/* Add the number of wraps in the current line before the cursor. */
|
||||
row += get_chunk_and_edge(column, openfile->current, &leftedge);
|
||||
column -= leftedge;
|
||||
} else
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!openfile->current->folded)
|
||||
#endif
|
||||
{
|
||||
/* Add the number of wraps in the current line before the cursor. */
|
||||
row += get_chunk_and_edge(column, openfile->current, &leftedge);
|
||||
column -= leftedge;
|
||||
}
|
||||
} else
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
row = openfile->current->lineno - openfile->edittop->lineno;
|
||||
row = get_row_from_edittop(openfile->current);
|
||||
column -= get_page_start(column);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current_x = 0;
|
||||
column = 0;
|
||||
}
|
||||
#endif
|
||||
if (row < editwinrows)
|
||||
wmove(midwin, row, margin + column);
|
||||
#ifndef NANO_TINY
|
||||
@ -2516,17 +2582,20 @@ void place_the_cursor(void)
|
||||
/* The number of bytes after which to stop painting, to avoid major slowdowns. */
|
||||
#define PAINT_LIMIT 2000
|
||||
|
||||
/* Draw the given text on the given row of the edit window. line is the
|
||||
* line to be drawn, and converted is the actual string to be written with
|
||||
* tabs and control characters replaced by strings of regular characters.
|
||||
* from_col is the column number of the first character of this "page". */
|
||||
void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
{
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
/* Draw the line number for the given line, but only if line numbering is on.
|
||||
* For folded segments, draws a '-' instead of a line number.
|
||||
* Also draws a mark indicating where anchors are set. */
|
||||
void draw_linenumber(int row, const linestruct* line, size_t from_col){
|
||||
/* If line numbering is switched on, put a line number in front of
|
||||
* the text -- but only for the parts that are not softwrapped. */
|
||||
if (margin > 0) {
|
||||
wattron(midwin, interface_color_pair[LINE_NUMBER]);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
mvwprintw(midwin, row, 0, "%*c", margin - 1, '-');
|
||||
else
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP) && from_col != 0)
|
||||
mvwprintw(midwin, row, 0, "%*s", margin - 1, " ");
|
||||
@ -2546,8 +2615,20 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
#endif
|
||||
wprintw(midwin, " ");
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* ENABLE_LINENUMBERS */
|
||||
|
||||
/* Draw the given text on the given row of the edit window. line is the
|
||||
* line to be drawn, and converted is the actual string to be written with
|
||||
* tabs and control characters replaced by strings of regular characters.
|
||||
* from_col is the column number of the first character of this "page". */
|
||||
void draw_row(int row, const char *converted, linestruct *line,
|
||||
size_t from_col)
|
||||
{
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
draw_linenumber(row, line, from_col);
|
||||
#endif
|
||||
/* First simply write the converted line -- afterward we'll add colors
|
||||
* and the marking highlight on just the pieces that need it. */
|
||||
mvwaddstr(midwin, row, margin, converted);
|
||||
@ -2801,18 +2882,50 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
#endif /* !NANO_TINY */
|
||||
}
|
||||
|
||||
/* Redraw the given line so that the character at the given index is visible
|
||||
* -- if necessary, scroll the line horizontally (when not softwrapping).
|
||||
* Return the number of rows "consumed" (relevant when softwrapping). */
|
||||
int update_line(linestruct *line, size_t index)
|
||||
#ifdef ENABLE_FOLDING
|
||||
/* Draw a folded segment at the given row. */
|
||||
int update_folded_line(linestruct *line, int row)
|
||||
{
|
||||
const int seg_len = get_folded_segment_length(line);
|
||||
const int string_len = snprintf(NULL, 0, "%d lines folded", seg_len);
|
||||
const int fill_length = (editwincols > string_len) ?
|
||||
(editwincols - string_len) : 0;
|
||||
const int half_fill = fill_length / 2;
|
||||
|
||||
char *string = nmalloc(editwincols + 1);
|
||||
|
||||
memset(string, '-', half_fill);
|
||||
snprintf(string+half_fill, editwincols, "%d lines folded", seg_len);
|
||||
memset(string+half_fill+string_len, '-', fill_length - half_fill);
|
||||
string[editwincols] = '\0';
|
||||
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
draw_linenumber(row, line, 0);
|
||||
#endif
|
||||
|
||||
mvwaddstr(midwin, row, margin, string);
|
||||
|
||||
free(string);
|
||||
return 1;
|
||||
}
|
||||
#endif /* ENABLE_FOLDING */
|
||||
|
||||
|
||||
/* Redraw the given line at the given row so that the character at the
|
||||
* given index is visible -- if necessary, scroll the line horizontally
|
||||
* (when not softwrapping). Return the number of rows "consumed"
|
||||
* (relevant when softwrapping). */
|
||||
int update_line_at(linestruct *line, size_t index, int row)
|
||||
{
|
||||
int row;
|
||||
/* The row in the edit window we will be updating. */
|
||||
char *converted;
|
||||
/* The data of the line with tabs and control characters expanded. */
|
||||
size_t from_col;
|
||||
/* From which column a horizontally scrolled line is displayed. */
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
return update_folded_line(line, row);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP))
|
||||
return update_softwrapped_line(line);
|
||||
@ -2820,7 +2933,6 @@ int update_line(linestruct *line, size_t index)
|
||||
sequel_column = 0;
|
||||
#endif
|
||||
|
||||
row = line->lineno - openfile->edittop->lineno;
|
||||
from_col = get_page_start(wideness(line->data, index));
|
||||
|
||||
/* Expand the piece to be drawn to its representable form, and draw it. */
|
||||
@ -2843,6 +2955,15 @@ int update_line(linestruct *line, size_t index)
|
||||
spotlight(light_from_col, light_to_col);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Redraw the given line so that the character at the given index is visible
|
||||
* -- if necessary, scroll the line horizontally (when not softwrapping).
|
||||
* Return the number of rows "consumed" (relevant when softwrapping). */
|
||||
int update_line(linestruct *line, size_t index)
|
||||
{
|
||||
return update_line_at(line, index, get_row_from_edittop(line));
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
@ -2875,8 +2996,13 @@ int update_softwrapped_line(linestruct *line)
|
||||
|
||||
/* Find out on which screen row the target line should be shown. */
|
||||
while (someline != line && someline != NULL) {
|
||||
row += 1 + extra_chunks_in(someline);
|
||||
someline = someline->next;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (someline->folded)
|
||||
++row;
|
||||
else
|
||||
#endif
|
||||
row += 1 + extra_chunks_in(someline);
|
||||
someline = get_next_visible_line(someline);
|
||||
}
|
||||
|
||||
/* If the first chunk is offscreen, don't even try to display it. */
|
||||
@ -2888,6 +3014,11 @@ int update_softwrapped_line(linestruct *line)
|
||||
|
||||
starting_row = row;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
return update_folded_line(line, row);
|
||||
#endif
|
||||
|
||||
while (!end_of_line && row < editwinrows) {
|
||||
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
|
||||
|
||||
@ -2934,7 +3065,14 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
/* Recede through the requested number of chunks. */
|
||||
for (i = nrows; i > 0; i--) {
|
||||
size_t chunk = chunk_for(*leftedge, *line);
|
||||
size_t chunk;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded)
|
||||
chunk = 0;
|
||||
else
|
||||
#endif
|
||||
chunk = chunk_for(*leftedge, *line);
|
||||
|
||||
*leftedge = 0;
|
||||
|
||||
@ -2945,16 +3083,25 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
break;
|
||||
|
||||
i -= chunk;
|
||||
*line = (*line)->prev;
|
||||
*line = get_prev_visible_line(*line);
|
||||
*leftedge = HIGHEST_POSITIVE;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded)
|
||||
*leftedge = 0;
|
||||
else
|
||||
#endif
|
||||
if (*leftedge == HIGHEST_POSITIVE)
|
||||
*leftedge = leftedge_for(*leftedge, *line);
|
||||
} else
|
||||
#endif
|
||||
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
|
||||
*line = (*line)->prev;
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
linestruct *prev = get_prev_visible_line(*line);
|
||||
for (i = nrows; i > 0 && prev != NULL; i--) {
|
||||
*line = prev;
|
||||
prev = get_prev_visible_line(prev);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -2974,6 +3121,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
|
||||
/* Advance through the requested number of chunks. */
|
||||
for (i = nrows; i > 0; i--) {
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded) {
|
||||
*line = get_next_visible_line(*line);
|
||||
current_leftedge = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool end_of_line = FALSE;
|
||||
|
||||
current_leftedge = get_softwrap_breakpoint((*line)->data,
|
||||
@ -2994,9 +3149,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
if (i < nrows)
|
||||
*leftedge = current_leftedge;
|
||||
} else
|
||||
#endif
|
||||
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
|
||||
*line = (*line)->next;
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
linestruct *next = get_next_visible_line(*line);
|
||||
for (i = nrows; i > 0 && next != NULL; i--) {
|
||||
*line = next;
|
||||
next = get_next_visible_line(*line);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -3025,18 +3185,45 @@ void draw_scrollbar(void)
|
||||
{
|
||||
int fromline = openfile->edittop->lineno - 1;
|
||||
int totallines = openfile->filebot->lineno;
|
||||
int coveredlines = editwinrows;
|
||||
int coveredlines = 0;
|
||||
linestruct *line = openfile->edittop;
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
linestruct *line = openfile->edittop;
|
||||
int extras = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
|
||||
|
||||
while (line->lineno + extras < fromline + editwinrows && line->next) {
|
||||
line = line->next;
|
||||
extras += extra_chunks_in(line);
|
||||
int i = 0;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
|
||||
coveredlines = i;
|
||||
}
|
||||
|
||||
coveredlines = line->lineno - fromline;
|
||||
for (;i < editwinrows && line->next != NULL;++i) {
|
||||
line = get_next_visible_line(line);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i += extra_chunks_in(line);
|
||||
++coveredlines;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ENABLE_FOLDING
|
||||
for (int i = 0;i < editwinrows && line->next != NULL;++i) {
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
++coveredlines;
|
||||
line = get_next_visible_line(line);
|
||||
}
|
||||
#else
|
||||
coveredlines = editwinrows;
|
||||
#endif /* ENABLE_FOLDING */
|
||||
}
|
||||
|
||||
int lowest = (fromline * editwinrows) / totallines;
|
||||
@ -3089,7 +3276,12 @@ void edit_scroll(bool direction)
|
||||
if (thebar)
|
||||
draw_scrollbar();
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (ISSET(SOFTWRAP) && !line->folded)
|
||||
#else
|
||||
if (ISSET(SOFTWRAP))
|
||||
#endif
|
||||
{
|
||||
/* Compensate for the earlier chunks of a softwrapped line. */
|
||||
nrows += chunk_for(leftedge, line);
|
||||
|
||||
@ -3101,10 +3293,11 @@ void edit_scroll(bool direction)
|
||||
|
||||
/* Draw new content on the blank row (and on the bordering row too
|
||||
* when it was deemed necessary). */
|
||||
int row = get_row_from_edittop(line);
|
||||
while (nrows > 0 && line != NULL) {
|
||||
nrows -= update_line(line, (line == openfile->current) ?
|
||||
openfile->current_x : 0);
|
||||
line = line->next;
|
||||
nrows -= update_line_at(line, (line == openfile->current) ?
|
||||
openfile->current_x : 0, row++);
|
||||
line = get_next_visible_line(line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3301,8 +3494,7 @@ bool current_is_below_screen(void)
|
||||
leftedge < leftedge_for(xplustabs(), openfile->current))));
|
||||
} else
|
||||
#endif
|
||||
return (openfile->current->lineno >=
|
||||
openfile->edittop->lineno + editwinrows - SHIM);
|
||||
return (get_row_from_edittop(openfile->current) >= editwinrows - SHIM);
|
||||
}
|
||||
|
||||
/* Return TRUE if current[current_x] is outside the viewport. */
|
||||
@ -3330,12 +3522,17 @@ void edit_redraw(linestruct *old_current, update_type manner)
|
||||
/* If the mark is on, update all lines between old_current and current. */
|
||||
if (openfile->mark) {
|
||||
linestruct *line = old_current;
|
||||
|
||||
int row = get_row_from_edittop(line);
|
||||
while (line != openfile->current) {
|
||||
update_line(line, 0);
|
||||
update_line_at(line, 0, row);
|
||||
|
||||
line = (line->lineno > openfile->current->lineno) ?
|
||||
line->prev : line->next;
|
||||
if (line->lineno > openfile->current->lineno) {
|
||||
line = get_prev_visible_line(line);
|
||||
--row;
|
||||
} else {
|
||||
line = get_next_visible_line(line);
|
||||
++row;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
@ -3390,9 +3587,13 @@ void edit_refresh(void)
|
||||
|
||||
while (row < editwinrows && line != NULL) {
|
||||
if (line == openfile->current)
|
||||
row += update_line(line, openfile->current_x);
|
||||
row += update_line_at(line, openfile->current_x, row);
|
||||
else
|
||||
row += update_line(line, 0);
|
||||
row += update_line_at(line, 0, row);
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
line = get_end_of_folded_segment(line);
|
||||
#endif
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user