Change folding behavior when no lines are selected as suggested by the nano dev

This commit is contained in:
rexy712 2022-07-11 15:11:19 -07:00
parent 05fa7110ec
commit 01b30a5a0e
3 changed files with 106 additions and 33 deletions

View File

@ -21,6 +21,9 @@
#include "prototypes.h" #include "prototypes.h"
#include <string.h> #include <string.h>
/* strlen */
#include <ctype.h>
/* isspace */
#ifdef ENABLE_FOLDING #ifdef ENABLE_FOLDING
@ -80,18 +83,10 @@ bool do_unfold_segments(linestruct *top, linestruct *bot)
if (top != bot) if (top != bot)
return FALSE; return FALSE;
linestruct *match_line = openfile->current; /* Attempt to find a bracketed region first.
size_t match_x = openfile->current_x; * If not, top is unmodified. */
if (!top->folded)
if (!top->folded && !find_matching_bracket_pos(&match_line, &match_x)){ find_bracketed_region(openfile->current, &top, &bot);
if (openfile->current->lineno > match_line->lineno) {
top = match_line->next;
bot = openfile->current->prev;
} else {
top = openfile->current->next;
bot = match_line->prev;
}
}
if (top->folded) { if (top->folded) {
unfold_folded_segment(top); unfold_folded_segment(top);
@ -112,35 +107,26 @@ void do_fold_segment(void)
if (do_unfold_segments(top, bot)) { if (do_unfold_segments(top, bot)) {
return; return;
} }
if (top == bot) {
linestruct *match_line = openfile->current;
size_t match_x = openfile->current_x;
if (!find_matching_bracket_pos(&match_line, &match_x)){ /* When not selecting multiple lines, try to find bounding
int linedist = openfile->current->lineno - match_line->lineno; * brackets to act as top and bot. */
linedist = linedist < 0 ? -linedist : linedist; if (top == bot)
if (!find_bracketed_region(openfile->current, &top, &bot)) {
statusline(AHEM, _("No valid region found for automatic fold"));
return;
}
if (linedist >= 2) {
if (openfile->current->lineno > match_line->lineno) {
top = match_line->next;
bot = openfile->current->prev;
} else {
top = openfile->current->next;
bot = match_line->prev;
}
}
}
}
for (linestruct* line = top;line != bot->next;line = line->next) for (linestruct* line = top;line != bot->next;line = line->next)
line->folded = TRUE; line->folded = TRUE;
if (top->lineno < openfile->edittop->lineno && if (top->lineno < openfile->edittop->lineno &&
bot->lineno > openfile->edittop->lineno) bot->lineno > openfile->edittop->lineno)
openfile->edittop = top->next; openfile->edittop = top;
/* Place the cursor at the start of the fold segment. /* Place the cursor at the start of the fold segment.
* Anywhere else within the segment is invalid. */ * Anywhere else within the segment is invalid. */
openfile->current = get_start_of_folded_segment(openfile->current); openfile->current = get_start_of_folded_segment(openfile->current);
openfile->mark = NULL;
refresh_needed = TRUE; refresh_needed = TRUE;
} }

View File

@ -472,6 +472,8 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
void do_gotolinecolumn(void); void do_gotolinecolumn(void);
#ifndef NANO_TINY #ifndef NANO_TINY
int find_matching_bracket_pos(linestruct **line, size_t *xpos); 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);

View File

@ -880,6 +880,92 @@ 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. */
@ -997,8 +1083,7 @@ int find_matching_bracket_pos(linestruct **line, size_t *xpos)
bool reversed; bool reversed;
/* The direction we search. */ /* The direction we search. */
br_ch = mbstrchr(matchbrackets, br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
openfile->current->data + openfile->current_x);
if (br_ch == NULL) if (br_ch == NULL)
return NOT_A_BRACKET; return NOT_A_BRACKET;