3 changes

This commit is contained in:
rexy712 2023-04-01 12:33:42 -07:00
parent fdcafb83e3
commit e13b24e0ce
9 changed files with 289 additions and 43 deletions

View File

@ -48,6 +48,7 @@ void do_deletion(undo_type action)
memmove(&openfile->current->data[openfile->current_x],
&openfile->current->data[openfile->current_x + charlen],
line_len - charlen + 1);
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
/* When softwrapping, a changed number of chunks requires a refresh. */
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
@ -62,6 +63,9 @@ void do_deletion(undo_type action)
} else if (openfile->current != openfile->filebot) {
linestruct *joining = openfile->current->next;
UNFOLD_SEGMENT(openfile->current);
UNFOLD_SEGMENT(joining);
/* If there is a magic line, and we're before it: don't eat it. */
if (joining == openfile->filebot && openfile->current_x != 0 &&
!ISSET(NO_NEWLINES)) {
@ -192,7 +196,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 +205,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 +267,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 +387,8 @@ void ingraft_buffer(linestruct *topline)
#endif
linestruct *botline = topline;
UNFOLD_SEGMENT(line);
while (botline->next != NULL)
botline = botline->next;
@ -728,6 +739,7 @@ void paste_text(void)
statusline(AHEM, _("Cutbuffer is empty"));
return;
}
UNFOLD_SEGMENT(openfile->current);
#ifndef NANO_TINY
add_undo(PASTE, NULL);

View File

@ -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

View File

@ -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);

View File

@ -235,19 +235,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 +267,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 +291,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 +348,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 +364,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 +377,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 +428,8 @@ bool do_next_word(bool after_ends)
}
}
UNFOLD_SEGMENT(openfile->current);
return started_on_word;
}
@ -384,7 +438,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 +449,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 +467,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 +529,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 +676,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 +688,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 +705,7 @@ void do_right(void)
openfile->current_x);
#endif
} else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current = get_next_visible_line(openfile->current);
openfile->current_x = 0;
}

View File

@ -78,6 +78,9 @@ linestruct *make_new_node(linestruct *prevnode)
#ifndef NANO_TINY
newnode->has_anchor = FALSE;
#endif
#ifdef ENABLE_FOLDING
newnode->folded = FALSE;
#endif
return newnode;
}
@ -117,6 +120,7 @@ void delete_node(linestruct *line)
/* Disconnect a node from a linked list of linestructs and delete it. */
void unlink_node(linestruct *line)
{
UNFOLD_SEGMENT(line);
if (line->prev != NULL)
line->prev->next = line->next;
if (line->next != NULL)
@ -156,6 +160,9 @@ linestruct *copy_node(const linestruct *src)
#ifndef NANO_TINY
dst->has_anchor = src->has_anchor;
#endif
#ifdef ENABLE_FOLDING
dst->folded = src->folded;
#endif
return dst;
}
@ -1461,6 +1468,7 @@ void inject(char *burst, size_t count)
#ifndef NANO_TINY
size_t original_row = 0;
size_t old_amount = 0;
UNFOLD_SEGMENT(thisline);
if (ISSET(SOFTWRAP)) {
if (openfile->current_y == editwinrows - 1)

View File

@ -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);
@ -579,6 +579,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);
@ -674,3 +676,13 @@ void flip_newbuffer(void);
#endif
void discard_buffer(void);
void do_cancel(void);
/* Most functions in folding.c. */
#ifdef ENABLE_FOLDING
void do_fold_segment(void);
void unfold_folded_segment(linestruct *line);
void unfold_folded_segment_from(linestruct *line);
linestruct *get_start_of_folded_segment(linestruct* line);
linestruct *get_end_of_folded_segment(linestruct* line);
int get_folded_segment_length(linestruct *line);
#endif

View File

@ -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;
@ -982,6 +996,7 @@ void do_find_bracket(void)
/* When balance reached zero, we've found the complementary bracket. */
if (balance == 0) {
UNFOLD_SEGMENT(openfile->current);
edit_redraw(was_current, FLOWING);
return;
}
@ -1015,6 +1030,7 @@ void go_to_and_confirm(linestruct *line)
if (line != openfile->current) {
openfile->current = line;
openfile->current_x = 0;
UNFOLD_SEGMENT(openfile->current);
#ifdef ENABLE_COLOR
if (line->lineno > openfile->edittop->lineno + editwinrows ||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))

View File

@ -96,6 +96,8 @@ void indent_a_line(linestruct *line, char *indentation)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Add the fabricated indentation to the beginning of the line. */
line->data = nrealloc(line->data, length + indent_len + 1);
memmove(line->data + indent_len, line->data, length + 1);
@ -226,6 +228,8 @@ void unindent_a_line(linestruct *line, size_t indent_len)
if (indent_len == 0)
return;
UNFOLD_SEGMENT(line);
/* Remove the first tab's worth of whitespace from this line. */
memmove(line->data, line->data + indent_len, length - indent_len + 1);
@ -317,6 +321,8 @@ bool comment_line(undo_type action, linestruct *line, const char *comment_seq)
/* Length of postfix. */
size_t line_len = strlen(line->data);
UNFOLD_SEGMENT(line);
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
return FALSE;
@ -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++;
}

View File

@ -140,6 +140,55 @@ void run_macro(void)
}
#endif /* !NANO_TINY */
/* Return the current offset of target from openfile->edittop */
int get_row_from_edittop(linestruct *target)
{
#ifdef ENABLE_FOLDING
linestruct *line = openfile->edittop;
int row = 0;
while (line != NULL && line != target && row < editwinrows) {
line = get_end_of_folded_segment(line);
line = line->next;
++row;
}
return row;
#else
return target->lineno - openfile->edittop->lineno;
#endif
}
/* Return the next line, taking fold segments into account */
linestruct *get_next_visible_line(linestruct *line)
{
if (!line)
return NULL;
#ifdef ENABLE_FOLDING
line = get_end_of_folded_segment(line);
if (line == NULL)
return NULL;
#endif
return line->next;
}
/* Return the previous line, taking fold segments into account */
linestruct *get_prev_visible_line(linestruct *line)
{
if (!line)
return NULL;
#ifdef ENABLE_FOLDING
if (line->folded) {
line = get_start_of_folded_segment(line);
return line == NULL ? NULL : line->prev;
}
if (line->prev != NULL && line->prev->folded)
return get_start_of_folded_segment(line->prev);
#endif
return line->prev;
}
/* Allocate the requested space for the keystroke buffer. */
void reserve_space_for(size_t newsize)
{
@ -2875,8 +2924,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. */
@ -2945,7 +2999,7 @@ 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;
}
@ -2953,8 +3007,13 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
*leftedge = leftedge_for(*leftedge, *line);
} else
#endif
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;
}
@ -2995,8 +3054,13 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
*leftedge = current_leftedge;
} else
#endif
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;
}
@ -3025,18 +3089,44 @@ 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;
}
#else
coveredlines = editwinrows;
#endif /* ENABLE_FOLDING */
}
int lowest = (fromline * editwinrows) / totallines;
@ -3104,7 +3194,7 @@ void edit_scroll(bool direction)
while (nrows > 0 && line != NULL) {
nrows -= update_line(line, (line == openfile->current) ?
openfile->current_x : 0);
line = line->next;
line = get_next_visible_line(line);
}
}
@ -3334,8 +3424,11 @@ void edit_redraw(linestruct *old_current, update_type manner)
while (line != openfile->current) {
update_line(line, 0);
line = (line->lineno > openfile->current->lineno) ?
line->prev : line->next;
if (line->lineno > openfile->current->lineno) {
line = get_prev_visible_line(line);
} else {
line = get_next_visible_line(line);
}
}
} else
#endif