From: Benno Schulenberg Date: Mon, 9 Jun 2014 10:01:54 +0000 (+0000) Subject: Rewriting the line-wrapping code to make use of the existing line-break code. X-Git-Tag: v2.3.5~115 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=be10c2a48c7b17f0c256527aeb6558eaa953d053;p=nano.git Rewriting the line-wrapping code to make use of the existing line-break code. And undoing line wraps together with their causal text additions, and not as separate actions because the user did not make them. Patch by Mark Majeres. git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4945 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/ChangeLog b/ChangeLog index 68188b83..01a84eeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2014-06-09 Mark Majeres + * src/text.c (do_undo, do_redo, add_undo, update_undo, do-wrap): + Rewrite the line-wrapping code to make use of the existing line-break + code. And undo line wraps together with their causal text additions, + and not as separate actions because the user did not make them. + 2014-06-08 Mark Majeres * src/text.c (do_delete, do_deletion, do_undo, do_redo, update_undo): Differentiate between undoing a Delete and undoing a Backspace -- the diff --git a/src/nano.c b/src/nano.c index 9f782608..e45dc30a 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2037,7 +2037,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) #ifndef DISABLE_WRAPPING /* If we're wrapping text, we need to call edit_refresh(). */ if (!ISSET(NO_WRAP)) - if (do_wrap(openfile->current, FALSE)) + if (do_wrap(openfile->current)) edit_refresh_needed = TRUE; #endif diff --git a/src/nano.h b/src/nano.h index c509cc63..e5ecb008 100644 --- a/src/nano.h +++ b/src/nano.h @@ -187,7 +187,7 @@ typedef enum { } function_type; typedef enum { - ADD, DEL, BACK, REPLACE, SPLIT, UNSPLIT, CUT, CUT_EOF, PASTE, ENTER, INSERT, OTHER + ADD, DEL, BACK, REPLACE, SPLIT_BEGIN, SPLIT_END, UNSPLIT, CUT, CUT_EOF, PASTE, ENTER, INSERT, OTHER } undo_type; typedef struct color_pair { @@ -571,7 +571,7 @@ enum /* Extra bits for the undo function. */ #define UNdel_del (1<<0) #define UNdel_backspace (1<<1) -#define UNsplit_madenew (1<<2) +#define UNsplit_completed (1<<2) #define UNcut_cutline (1<<3) #endif /* !NANO_TINY */ diff --git a/src/proto.h b/src/proto.h index cb0c095c..18ce2345 100644 --- a/src/proto.h +++ b/src/proto.h @@ -647,7 +647,7 @@ bool execute_command(const char *command); #endif #ifndef DISABLE_WRAPPING void wrap_reset(void); -bool do_wrap(filestruct *line, bool undoing); +bool do_wrap(filestruct *line); #endif #if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY) ssize_t break_line(const char *line, ssize_t goal diff --git a/src/text.c b/src/text.c index 9ab3ae31..458bd7b1 100644 --- a/src/text.c +++ b/src/text.c @@ -477,19 +477,15 @@ void do_undo(void) goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); break; #ifndef DISABLE_WRAPPING - case SPLIT: + case SPLIT_END: undidmsg = _("line wrap"); - f->data = charealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1); - strcpy(&f->data[strlen(f->data) - 1], u->strdata); - if (u->strdata2 != NULL) - f->next->data = mallocstrcpy(f->next->data, u->strdata2); - else { - filestruct *foo = openfile->current->next; - unlink_node(foo); - delete_node(foo); - } - renumber(f); - gotolinecolumn = TRUE; + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = openfile->current_undo->next; + openfile->last_action = OTHER; + while (openfile->current_undo->type != SPLIT_BEGIN) + do_undo(); + u = openfile->current_undo; + f = openfile->current; break; #endif /* !DISABLE_WRAPPING */ case UNSPLIT: @@ -622,13 +618,15 @@ void do_redo(void) do_enter(TRUE); break; #ifndef DISABLE_WRAPPING - case SPLIT: + case SPLIT_BEGIN: undidmsg = _("line wrap"); - if (u->xflags & UNsplit_madenew) - prepend_wrap = TRUE; - do_wrap(f, TRUE); - renumber(f); - gotolinecolumn = TRUE; + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = u; + openfile->last_action = OTHER; + while (openfile->current_undo->type != SPLIT_END) + do_redo(); + u = openfile->current_undo; + goto_line_posx(u->lineno, u->begin); break; #endif /* !DISABLE_WRAPPING */ case UNSPLIT: @@ -850,8 +848,6 @@ void add_undo(undo_type current_action) char *data; openfilestruct *fs = openfile; /* Last thing we cut to set up the undo for uncut. */ - ssize_t wrap_loc; - /* For calculating split beginning. */ if (!ISSET(UNDOABLE)) return; @@ -880,9 +876,17 @@ void add_undo(undo_type current_action) u->type = current_action; u->lineno = fs->current->lineno; u->begin = fs->current_x; - u->next = fs->undotop; - fs->undotop = u; - fs->current_undo = u; + if (u->type == SPLIT_BEGIN) { + /* Some action, most likely an ADD, was performed that invoked + * do_wrap(). Rearrange the undo order so that this previous + * action is after the SPLIT_BEGIN undo. */ + u->next = fs->undotop->next ; + fs->undotop->next = u; + } else { + u->next = fs->undotop; + fs->undotop = u; + fs->current_undo = u; + } u->strdata = NULL; u->strdata2 = NULL; u->cutbuffer = NULL; @@ -922,18 +926,10 @@ void add_undo(undo_type current_action) current_action = u->type = UNSPLIT; break; #ifndef DISABLE_WRAPPING - case SPLIT: - wrap_loc = break_line(openfile->current->data, fill -#ifndef DISABLE_HELP - , FALSE -#endif - ); - u->strdata = mallocstrcpy(NULL, &openfile->current->data[wrap_loc]); - /* Don't bother saving the next line if we're not prepending, - * as a new line will be created. */ - if (prepend_wrap) - u->strdata2 = mallocstrcpy(NULL, fs->current->next->data); - u->begin = wrap_loc; + case SPLIT_BEGIN: + current_action = fs->undotop->type; + break; + case SPLIT_END: break; #endif /* !DISABLE_WRAPPING */ case INSERT: @@ -1007,7 +1003,7 @@ void update_undo(undo_type action) /* Change to an add if we're not using the same undo struct * that we should be using. */ if (action != fs->last_action - || (action != ENTER && action != CUT && action != INSERT && action != SPLIT + || (action != ENTER && action != CUT && action != INSERT && openfile->current->lineno != fs->current_undo->lineno)) { add_undo(action); return; @@ -1096,10 +1092,8 @@ void update_undo(undo_type action) u->mark_begin_x = fs->current_x; break; #ifndef DISABLE_WRAPPING - case SPLIT: - /* This will only be called if we made a completely new line, - * and as such we should note that so we can destroy it later. */ - u->xflags = UNsplit_madenew; + case SPLIT_BEGIN: + case SPLIT_END: break; #endif /* !DISABLE_WRAPPING */ case UNSPLIT: @@ -1124,10 +1118,8 @@ void wrap_reset(void) prepend_wrap = FALSE; } -/* We wrap the given line. Precondition: we assume the cursor has been - * moved forward since the last typed character. Return TRUE if we - * wrapped, and FALSE otherwise. */ -bool do_wrap(filestruct *line, bool undoing) +/* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */ +bool do_wrap(filestruct *line) { size_t line_len; /* The length of the line we wrap. */ @@ -1143,16 +1135,10 @@ bool do_wrap(filestruct *line, bool undoing) /* The text after the wrap point. */ size_t after_break_len; /* The length of after_break. */ - bool prepending = FALSE; - /* Do we prepend to the next line? */ const char *next_line = NULL; /* The next line, minus indentation. */ size_t next_line_len = 0; /* The length of next_line. */ - char *new_line = NULL; - /* The line we create. */ - size_t new_line_len = 0; - /* The eventual length of new_line. */ /* There are three steps. First, we decide where to wrap. Then, we * create the new wrap line. Finally, we clean up. */ @@ -1192,9 +1178,6 @@ bool do_wrap(filestruct *line, bool undoing) return FALSE; #ifndef NANO_TINY - if (!undoing) - add_undo(SPLIT); - /* If autoindent is turned on, and we're on the character just after * the indentation, we don't wrap. */ if (ISSET(AUTOINDENT)) { @@ -1205,8 +1188,14 @@ bool do_wrap(filestruct *line, bool undoing) if (wrap_loc == indent_len) return FALSE; } + + add_undo(SPLIT_BEGIN); #endif + size_t old_x = openfile->current_x; + filestruct * oldLine = openfile->current; + openfile->current = line; + /* Step 2, making the new wrap line. It will consist of indentation * followed by the text after the wrap point, optionally followed by * a space (if the text after the wrap point doesn't end in a blank) @@ -1226,9 +1215,13 @@ bool do_wrap(filestruct *line, bool undoing) const char *end = after_break + move_mbleft(after_break, after_break_len); + /* Go to the end of the line. */ + openfile->current_x = line_len; + /* If after_break doesn't end in a blank, make sure it ends in a * space. */ if (!is_blank_mbchar(end)) { + add_undo(ADD); line_len++; line->data = charealloc(line->data, line_len + 1); line->data[line_len - 1] = ' '; @@ -1236,128 +1229,40 @@ bool do_wrap(filestruct *line, bool undoing) after_break = line->data + wrap_loc; after_break_len++; openfile->totsize++; + openfile->current_x++; + update_undo(ADD); } next_line = line->next->data; next_line_len = strlen(next_line); if (after_break_len + next_line_len <= fill) { - prepending = TRUE; - new_line_len += next_line_len; + /* Delete the LF to join the two lines. */ + do_delete(); + /* Delete any leading blanks from the joined-on line. */ + while (is_blank_mbchar(&line->data[openfile->current_x])) + do_delete(); + renumber(line); } } - /* new_line_len is now the length of the text that will be wrapped - * to the next line, plus (if we're prepending to it) the length of - * the text of the next line. */ - new_line_len += after_break_len; - -#ifndef NANO_TINY - if (ISSET(AUTOINDENT)) { - if (prepending) { - /* If we're prepending, the indentation will come from the - * next line. */ - indent_string = next_line; - indent_len = indent_length(indent_string); - next_line += indent_len; - } else { - /* Otherwise, it will come from this line, in which case - * we should increase new_line_len to make room for it. */ - new_line_len += indent_len; - openfile->totsize += mbstrnlen(indent_string, indent_len); - } - } -#endif - - /* Now we allocate the new line and copy the text into it. */ - new_line = charalloc(new_line_len + 1); - new_line[0] = '\0'; - -#ifndef NANO_TINY - if (ISSET(AUTOINDENT)) { - /* Copy the indentation. */ - strncpy(new_line, indent_string, indent_len); - new_line[indent_len] = '\0'; - new_line_len += indent_len; - } -#endif - - /* Copy all the text after the wrap point of the current line. */ - strcat(new_line, after_break); - - /* Break the current line at the wrap point. */ - null_at(&line->data, wrap_loc); - - if (prepending) { -#ifndef NANO_TINY - if (!undoing) - update_undo(SPLIT); -#endif - /* If we're prepending, copy the text from the next line, minus - * the indentation that we already copied above. */ - strcat(new_line, next_line); - - free(line->next->data); - line->next->data = new_line; + /* Go to the wrap location and split the line there. */ + openfile->current_x = wrap_loc; + do_enter(FALSE); - /* If the NO_NEWLINES flag isn't set, and text has been added to - * the magicline, make a new magicline. */ - if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') - new_magicline(); + if (old_x < wrap_loc) { + openfile->current_x = old_x; + openfile->current = oldLine; + prepend_wrap = TRUE; } else { - /* Otherwise, make a new line and copy the text after where we - * broke this line to the beginning of the new line. */ - splice_node(openfile->current, make_new_node(openfile->current), - openfile->current->next); - - /* If the current line is the last line of the file, move the - * last line of the file down to the next line. */ - if (openfile->filebot == openfile->current) - openfile->filebot = openfile->current->next; - - openfile->current->next->data = new_line; - - openfile->totsize++; - } - - /* Step 3, clean up. Reposition the cursor and mark, and do some - * other sundry things. */ - - /* Set the prepend_wrap flag, so that later wraps of this line will - * be prepended to the next line. */ - prepend_wrap = TRUE; - - /* Each line knows its number. We recalculate these if we inserted - * a new line. */ - if (!prepending) - renumber(line); - - /* If the cursor was after the break point, we must move it. We - * also clear the prepend_wrap flag in this case. */ - if (openfile->current_x > wrap_loc) { + openfile->current_x += (old_x - wrap_loc); prepend_wrap = FALSE; - - openfile->current = openfile->current->next; - openfile->current_x -= wrap_loc -#ifndef NANO_TINY - - indent_len -#endif - ; - openfile->placewewant = xplustabs(); } + openfile->placewewant = xplustabs(); + #ifndef NANO_TINY - /* If the mark was on this line after the wrap point, we move it - * down. If it was on the next line and we prepended to that line, - * we move it right. */ - if (openfile->mark_set) { - if (openfile->mark_begin == line && openfile->mark_begin_x > - wrap_loc) { - openfile->mark_begin = line->next; - openfile->mark_begin_x -= wrap_loc - indent_len + 1; - } else if (prepending && openfile->mark_begin == line->next) - openfile->mark_begin_x += after_break_len; - } + add_undo(SPLIT_END); #endif return TRUE;