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
master
Benno Schulenberg 2014-06-09 10:01:54 +00:00
parent 64896ba2ff
commit be10c2a48c
5 changed files with 75 additions and 164 deletions

View File

@ -1,3 +1,9 @@
2014-06-09 Mark Majeres <mark@engine12.com>
* 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 <mark@engine12.com> 2014-06-08 Mark Majeres <mark@engine12.com>
* src/text.c (do_delete, do_deletion, do_undo, do_redo, update_undo): * src/text.c (do_delete, do_deletion, do_undo, do_redo, update_undo):
Differentiate between undoing a Delete and undoing a Backspace -- the Differentiate between undoing a Delete and undoing a Backspace -- the

View File

@ -2037,7 +2037,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
/* If we're wrapping text, we need to call edit_refresh(). */ /* If we're wrapping text, we need to call edit_refresh(). */
if (!ISSET(NO_WRAP)) if (!ISSET(NO_WRAP))
if (do_wrap(openfile->current, FALSE)) if (do_wrap(openfile->current))
edit_refresh_needed = TRUE; edit_refresh_needed = TRUE;
#endif #endif

View File

@ -187,7 +187,7 @@ typedef enum {
} function_type; } function_type;
typedef enum { 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; } undo_type;
typedef struct color_pair { typedef struct color_pair {
@ -571,7 +571,7 @@ enum
/* Extra bits for the undo function. */ /* Extra bits for the undo function. */
#define UNdel_del (1<<0) #define UNdel_del (1<<0)
#define UNdel_backspace (1<<1) #define UNdel_backspace (1<<1)
#define UNsplit_madenew (1<<2) #define UNsplit_completed (1<<2)
#define UNcut_cutline (1<<3) #define UNcut_cutline (1<<3)
#endif /* !NANO_TINY */ #endif /* !NANO_TINY */

View File

@ -647,7 +647,7 @@ bool execute_command(const char *command);
#endif #endif
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
void wrap_reset(void); void wrap_reset(void);
bool do_wrap(filestruct *line, bool undoing); bool do_wrap(filestruct *line);
#endif #endif
#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY) #if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
ssize_t break_line(const char *line, ssize_t goal ssize_t break_line(const char *line, ssize_t goal

View File

@ -477,19 +477,15 @@ void do_undo(void)
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
break; break;
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
case SPLIT: case SPLIT_END:
undidmsg = _("line wrap"); undidmsg = _("line wrap");
f->data = charealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1); goto_line_posx(u->lineno, u->begin);
strcpy(&f->data[strlen(f->data) - 1], u->strdata); openfile->current_undo = openfile->current_undo->next;
if (u->strdata2 != NULL) openfile->last_action = OTHER;
f->next->data = mallocstrcpy(f->next->data, u->strdata2); while (openfile->current_undo->type != SPLIT_BEGIN)
else { do_undo();
filestruct *foo = openfile->current->next; u = openfile->current_undo;
unlink_node(foo); f = openfile->current;
delete_node(foo);
}
renumber(f);
gotolinecolumn = TRUE;
break; break;
#endif /* !DISABLE_WRAPPING */ #endif /* !DISABLE_WRAPPING */
case UNSPLIT: case UNSPLIT:
@ -622,13 +618,15 @@ void do_redo(void)
do_enter(TRUE); do_enter(TRUE);
break; break;
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
case SPLIT: case SPLIT_BEGIN:
undidmsg = _("line wrap"); undidmsg = _("line wrap");
if (u->xflags & UNsplit_madenew) goto_line_posx(u->lineno, u->begin);
prepend_wrap = TRUE; openfile->current_undo = u;
do_wrap(f, TRUE); openfile->last_action = OTHER;
renumber(f); while (openfile->current_undo->type != SPLIT_END)
gotolinecolumn = TRUE; do_redo();
u = openfile->current_undo;
goto_line_posx(u->lineno, u->begin);
break; break;
#endif /* !DISABLE_WRAPPING */ #endif /* !DISABLE_WRAPPING */
case UNSPLIT: case UNSPLIT:
@ -850,8 +848,6 @@ void add_undo(undo_type current_action)
char *data; char *data;
openfilestruct *fs = openfile; openfilestruct *fs = openfile;
/* Last thing we cut to set up the undo for uncut. */ /* Last thing we cut to set up the undo for uncut. */
ssize_t wrap_loc;
/* For calculating split beginning. */
if (!ISSET(UNDOABLE)) if (!ISSET(UNDOABLE))
return; return;
@ -880,9 +876,17 @@ void add_undo(undo_type current_action)
u->type = current_action; u->type = current_action;
u->lineno = fs->current->lineno; u->lineno = fs->current->lineno;
u->begin = fs->current_x; u->begin = fs->current_x;
u->next = fs->undotop; if (u->type == SPLIT_BEGIN) {
fs->undotop = u; /* Some action, most likely an ADD, was performed that invoked
fs->current_undo = u; * 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->strdata = NULL;
u->strdata2 = NULL; u->strdata2 = NULL;
u->cutbuffer = NULL; u->cutbuffer = NULL;
@ -922,18 +926,10 @@ void add_undo(undo_type current_action)
current_action = u->type = UNSPLIT; current_action = u->type = UNSPLIT;
break; break;
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
case SPLIT: case SPLIT_BEGIN:
wrap_loc = break_line(openfile->current->data, fill current_action = fs->undotop->type;
#ifndef DISABLE_HELP break;
, FALSE case SPLIT_END:
#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;
break; break;
#endif /* !DISABLE_WRAPPING */ #endif /* !DISABLE_WRAPPING */
case INSERT: 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 /* Change to an add if we're not using the same undo struct
* that we should be using. */ * that we should be using. */
if (action != fs->last_action 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)) { && openfile->current->lineno != fs->current_undo->lineno)) {
add_undo(action); add_undo(action);
return; return;
@ -1096,10 +1092,8 @@ void update_undo(undo_type action)
u->mark_begin_x = fs->current_x; u->mark_begin_x = fs->current_x;
break; break;
#ifndef DISABLE_WRAPPING #ifndef DISABLE_WRAPPING
case SPLIT: case SPLIT_BEGIN:
/* This will only be called if we made a completely new line, case SPLIT_END:
* and as such we should note that so we can destroy it later. */
u->xflags = UNsplit_madenew;
break; break;
#endif /* !DISABLE_WRAPPING */ #endif /* !DISABLE_WRAPPING */
case UNSPLIT: case UNSPLIT:
@ -1124,10 +1118,8 @@ void wrap_reset(void)
prepend_wrap = FALSE; prepend_wrap = FALSE;
} }
/* We wrap the given line. Precondition: we assume the cursor has been /* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */
* moved forward since the last typed character. Return TRUE if we bool do_wrap(filestruct *line)
* wrapped, and FALSE otherwise. */
bool do_wrap(filestruct *line, bool undoing)
{ {
size_t line_len; size_t line_len;
/* The length of the line we wrap. */ /* The length of the line we wrap. */
@ -1143,16 +1135,10 @@ bool do_wrap(filestruct *line, bool undoing)
/* The text after the wrap point. */ /* The text after the wrap point. */
size_t after_break_len; size_t after_break_len;
/* The length of after_break. */ /* The length of after_break. */
bool prepending = FALSE;
/* Do we prepend to the next line? */
const char *next_line = NULL; const char *next_line = NULL;
/* The next line, minus indentation. */ /* The next line, minus indentation. */
size_t next_line_len = 0; size_t next_line_len = 0;
/* The length of next_line. */ /* 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 /* There are three steps. First, we decide where to wrap. Then, we
* create the new wrap line. Finally, we clean up. */ * create the new wrap line. Finally, we clean up. */
@ -1192,9 +1178,6 @@ bool do_wrap(filestruct *line, bool undoing)
return FALSE; return FALSE;
#ifndef NANO_TINY #ifndef NANO_TINY
if (!undoing)
add_undo(SPLIT);
/* If autoindent is turned on, and we're on the character just after /* If autoindent is turned on, and we're on the character just after
* the indentation, we don't wrap. */ * the indentation, we don't wrap. */
if (ISSET(AUTOINDENT)) { if (ISSET(AUTOINDENT)) {
@ -1205,8 +1188,14 @@ bool do_wrap(filestruct *line, bool undoing)
if (wrap_loc == indent_len) if (wrap_loc == indent_len)
return FALSE; return FALSE;
} }
add_undo(SPLIT_BEGIN);
#endif #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 /* Step 2, making the new wrap line. It will consist of indentation
* followed by the text after the wrap point, optionally followed by * 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) * 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, const char *end = after_break + move_mbleft(after_break,
after_break_len); 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 /* If after_break doesn't end in a blank, make sure it ends in a
* space. */ * space. */
if (!is_blank_mbchar(end)) { if (!is_blank_mbchar(end)) {
add_undo(ADD);
line_len++; line_len++;
line->data = charealloc(line->data, line_len + 1); line->data = charealloc(line->data, line_len + 1);
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 = line->data + wrap_loc;
after_break_len++; after_break_len++;
openfile->totsize++; openfile->totsize++;
openfile->current_x++;
update_undo(ADD);
} }
next_line = line->next->data; next_line = line->next->data;
next_line_len = strlen(next_line); next_line_len = strlen(next_line);
if (after_break_len + next_line_len <= fill) { if (after_break_len + next_line_len <= fill) {
prepending = TRUE; /* Delete the LF to join the two lines. */
new_line_len += next_line_len; 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 /* Go to the wrap location and split the line there. */
* to the next line, plus (if we're prepending to it) the length of openfile->current_x = wrap_loc;
* the text of the next line. */ do_enter(FALSE);
new_line_len += after_break_len;
#ifndef NANO_TINY if (old_x < wrap_loc) {
if (ISSET(AUTOINDENT)) { openfile->current_x = old_x;
if (prepending) { openfile->current = oldLine;
/* If we're prepending, the indentation will come from the prepend_wrap = TRUE;
* 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;
/* 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();
} else { } else {
/* Otherwise, make a new line and copy the text after where we openfile->current_x += (old_x - wrap_loc);
* 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) {
prepend_wrap = FALSE; 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 #ifndef NANO_TINY
/* If the mark was on this line after the wrap point, we move it add_undo(SPLIT_END);
* 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;
}
#endif #endif
return TRUE; return TRUE;