]> git.wh0rd.org Git - nano.git/commitdiff
Rewriting the line-wrapping code to make use of the existing line-break code.
authorBenno Schulenberg <bensberg@justemail.net>
Mon, 9 Jun 2014 10:01:54 +0000 (10:01 +0000)
committerBenno Schulenberg <bensberg@justemail.net>
Mon, 9 Jun 2014 10:01:54 +0000 (10:01 +0000)
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

ChangeLog
src/nano.c
src/nano.h
src/proto.h
src/text.c

index 68188b83e3425c768ef83533fb203957a5d49094..01a84eeb9c234fcdcea7b7401f2a999e1b9c2241 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
        * src/text.c (do_delete, do_deletion, do_undo, do_redo, update_undo):
        Differentiate between undoing a Delete and undoing a Backspace -- the
index 9f782608f94d37041127175b2026948fcfa72096..e45dc30ad8f87cb99bdcbfca6e49a77671b7b1af 100644 (file)
@@ -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
 
index c509cc63f9ea370514d80bc02e5a73bd91a1cd70..e5ecb008a1932316559f61d393c6dd3babb3e6c4 100644 (file)
@@ -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 */
 
index cb0c095ca39ba8820f4b785f8a52b1fb2af232aa..18ce2345b84d199501b216e746ac3fc3ffc36f61 100644 (file)
@@ -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
index 9ab3ae31af36771ee6ae13fa8e341130c3102b30..458bd7b1cc584fc0cd3bd9b143761c18d0b48279 100644 (file)
@@ -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;