]> git.wh0rd.org Git - nano.git/commitdiff
overhaul the cutting and uncutting routines and the justify-related
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 23 Nov 2004 04:08:28 +0000 (04:08 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 23 Nov 2004 04:08:28 +0000 (04:08 +0000)
routines to back up and restore unjustified text to use the partitioning
code, as it greatly simplifies how they work; also back up and restore
unjustified text in its own buffer instead of the cutbuffer, and add a
few minor bug fixes to the overhauled routines

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2124 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/cut.c
src/global.c
src/nano.c
src/nano.h
src/proto.h
src/utils.c
src/winio.c

index e143a45f3ea9894868c4a21741c1ed0772b22c82..55296e37f408fa3bf78e34dab1fa7aba6ab6a375 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,40 @@
 CVS code -
+- General:
+       - Overhaul the cutting and uncutting routines to use the
+         partitioning code, as it greatly simplifies how they work.
+         New functions move_to_filestruct(), copy_from_filestruct(),
+         cut_line(), cut_marked(), and cut_to_eol(); changes to
+         add_to_cutbuffer(), do_cut_text(), do_uncut_text(), etc.;
+         removal of functions get_cutbottom(), add_to_cutbuffer(), and
+         cut_marked_segment(). (DLR)
+       - Overhaul the justify-related routines to back up and restore
+         unjustified text to use the partitioning code, as it greatly
+         simplifies how they work, and to store such text in its own
+         buffer rather than the cutbuffer.  Changes to backup_lines(),
+         do_justify(), etc. (DLR)
+- cut.c:
+  do_uncut_text()
+       - No longer duplicate Pico's adding an extra magicline to the
+         file if uncutting leaves the cursor on the current one, as
+         it's actually a bug. (DLR)
+- global.c:
+  thanks_for_all_the_fish()
+       - Free the justify buffer if it isn't empty. (DLR)
 - nano.c:
+  handle_sigwinch()
+       - If the justify buffer isn't empty, blow it away and don't
+         display "UnJustify" in the shortcut list anymore. (DLR)
   do_wrap()
        - Make wrap_loc and word_back ssize_t's, to match fill. (DLR)
+  do_justify()
+       - For consistency, preserve placewewant if we didn't unjustify
+         instead of setting it to 0. (DLR)
+- winio.c:
+  get_edit_input()
+       - Remove parameter allow_funcs, as it was only needed as a
+         workaround for when justified text was stored in the cutbuffer
+         and the cut shortcut was hit at the "Can now UnJustify!"
+         prompt. (DLR)
 
 GNU nano 1.3.5 - 2004.11.22
 - General:
index 3a7a8ab2e3051e5f839917100e247f9ed1cc2c8c..a90defa6c297b9fa99e6aa4c89c9504ffe318ab6 100644 (file)
--- a/src/cut.c
+++ b/src/cut.c
 
 static bool keep_cutbuffer = FALSE;
        /* Should we keep the contents of the cutbuffer? */
-static cut_type marked_cut = CUT_LINE;
-       /* What type of cut is in the cutbuffer? */
-#ifndef NANO_SMALL
-static bool concatenate_cut = FALSE;
-       /* Should we add this cut string to the end of the last one? */
-#endif
 static filestruct *cutbottom = NULL;
        /* Pointer to end of cutbuffer. */
 
@@ -46,444 +40,133 @@ void cutbuffer_reset(void)
     keep_cutbuffer = FALSE;
 }
 
-filestruct *get_cutbottom(void)
+/* If we're not on the magicline, move all the text of the current line,
+ * plus the newline at the end, to the cutbuffer. */
+void cut_line(void)
 {
-    return cutbottom;
-}
-
-void add_to_cutbuffer(filestruct *inptr, bool allow_concat)
-{
-#ifdef DEBUG
-    fprintf(stderr, "add_to_cutbuffer(): inptr->data = %s\n", inptr->data);
-#endif
-
-    if (cutbuffer == NULL)
-       cutbuffer = inptr;
-#ifndef NANO_SMALL
-    else if (allow_concat && concatenate_cut) {
-       /* If allow_concat is TRUE and we're concatenating, tack the
-        * text in inptr onto the text in cutbottom. */
-       cutbottom->data = charealloc(cutbottom->data,
-               strlen(cutbottom->data) + strlen(inptr->data) + 1);
-       strcat(cutbottom->data, inptr->data);
-       return;
-    }
-#endif
-    else {
-       cutbottom->next = inptr;
-       inptr->prev = cutbottom;
-    }
-    cutbottom = inptr;
-    cutbottom->next = NULL;
+    if (current->next != NULL)
+       move_to_filestruct(&cutbuffer, &cutbottom, current, 0,
+               current->next, 0);
 }
 
 #ifndef NANO_SMALL
-/* Cut a marked segment instead of a whole line.
- *
- * The first cut character is top->data[top_x].  Unless top == bot, the
- * last cut line has length bot_x.  That is, if bot_x > 0 then we cut to
- * bot->data[bot_x - 1].
- *
- * We maintain totsize, totlines, filebot, the magicline, and line
- * numbers.  Also, we set current and current_x so the cursor will be on
- * the first character after what was cut.  We do not do any screen
- * updates.
- *
- * Note cutbuffer might not be NULL if cut to end is used. */
-void cut_marked_segment(void)
+/* Move all currently marked text to the cutbuffer, and set the current
+ * place we want to where the text used to start. */
+void cut_marked(void)
 {
-    filestruct *top;
-    filestruct *bot;
-    filestruct *tmp;
-    size_t top_x;
-    size_t bot_x;
-    size_t newsize;
+    filestruct *top, *bot;
+    size_t top_x, bot_x;
 
-    /* If the mark doesn't cover any text, get out. */
-    if (current == mark_beginbuf && current_x == mark_beginx)
-       return;
-    assert(current != NULL && mark_beginbuf != NULL);
-
-    /* Set up the top and bottom lines and coordinates of the marked
-     * text. */
     mark_order((const filestruct **)&top, &top_x,
-               (const filestruct **)&bot, &bot_x, NULL);
-
-    /* Make the first cut line manually.  Move the cut part of the top
-     * line into tmp, and set newsize to that partial line's length. */
-    tmp = copy_node(top);
-    newsize = (top == bot ? bot_x - top_x : strlen(top->data + top_x));
-    charmove(tmp->data, tmp->data + top_x, newsize);
-    null_at(&tmp->data, newsize);
-
-    /* Add the contents of tmp to the cutbuffer.  Note that cutbuffer
-     * might be non-NULL if we have cut to end enabled. */
-    if (cutbuffer == NULL) {
-       cutbuffer = tmp;
-       cutbottom = tmp;
-    } else {
-       if (concatenate_cut) {
-           /* If we're concatenating, tack the text in the first line
-            * of tmp onto the text in the bottom of the cutbuffer, and
-            * move tmp one line down to where its next line begins. */
-           cutbottom->data = charealloc(cutbottom->data,
-               strlen(cutbottom->data) + strlen(tmp->data) + 1);
-           strcat(cutbottom->data, tmp->data);
-           tmp = tmp->next;
-       }
-
-       /* Put tmp on the line after the bottom of the cutbuffer. */
-       cutbottom->next = tmp;
-
-       if (!concatenate_cut) {
-           /* Tf we're not concatenating, attach tmp to the bottom of
-            * the cutbuffer, and then move the bottom of the cutbuffer
-            * one line down to where tmp is. */
-           tmp->prev = cutbottom;
-           cutbottom = tmp;
-       }
-    }
+       (const filestruct **)&bot, &bot_x, NULL);
 
-    /* And make the top remainder line manually too.  Update current_x
-     * and totlines to account for all the cut text, and update totsize
-     * to account for the length of the cut part of the first line. */
-    current_x = top_x;
-    totsize -= newsize;
-    totlines -= bot->lineno - top->lineno;
-
-    /* Now set newsize to be the length of the top remainder line plus
-     * the bottom remainder line, plus one for the null terminator. */
-    newsize = top_x + strlen(bot->data + bot_x) + 1;
-
-    if (top == bot) {
-       /* In this case, we're only cutting one line or part of one
-        * line, so the remainder line is shorter.  This means that we
-        * must move text from the end forward first. */
-       charmove(top->data + top_x, bot->data + bot_x, newsize - top_x);
-       top->data = charealloc(top->data, newsize);
-
-       cutbottom->next = NULL;
-#ifdef DEBUG
-       dump_buffer(cutbuffer);
+    move_to_filestruct(&cutbuffer, &cutbottom, top, top_x, bot, bot_x);
+    placewewant = xplustabs();
+}
 #endif
-       return;
-    }
-
-    /* Update totsize to account for the cut part of the last line. */
-    totsize -= bot_x + 1;
-
-    /* Here, the top remainder line might get longer (if the bottom
-     * remainder line is added to the end of it), so we realloc() it
-     * first. */
-    top->data = charealloc(top->data, newsize);
-    charmove(top->data + top_x, bot->data + bot_x, newsize - top_x);
-
-    assert(cutbottom != NULL && cutbottom->next != NULL);
-    /* We're cutting multiple lines, so in particular the next line is
-     * cut too. */
-    cutbottom->next->prev = cutbottom;
-
-    /* Update totsize to account for all the complete lines that have
-     * been cut.  After this, totsize is fully up to date. */
-    for (tmp = top->next; tmp != bot; tmp = tmp->next)
-       totsize -= strlen(tmp->data) + 1;
-
-    /* Make the last cut line manually. */
-    null_at(&bot->data, bot_x);
-
-    /* Move the rest of the cut text (other than the cut part of the top
-     * line) from the buffer to the end of the cutbuffer, and fix the
-     * edit buffer to account for the cut text. */
-    top->next = bot->next;
-    cutbottom = bot;
-    cutbottom->next = NULL;
-    if (top->next != NULL)
-       top->next->prev = top;
-    renumber(top);
-    current = top;
 
-    /* If the bottom line of the cut was the magicline, set filebot
-     * properly, and add a new magicline if the top remainder line
-     * (which is now the new bottom line) is non-blank. */
-    if (bot == filebot) {
-       filebot = top;
-       assert(bot_x == 0);
-       if (top_x > 0)
-           new_magicline();
+/* If we're not at the end of the current line, move all the text from
+ * the current cursor position to the end of the current line,
+ * not counting the newline at the end, to the cutbuffer.  If we are,
+ * and we're not on the magicline, move the newline at the end to the
+ * cutbuffer, and set the current place we want to where the newline
+ * used to be. */
+void cut_to_eol(void)
+{
+    size_t data_len = strlen(current->data);
+
+    assert(current_x <= data_len);
+
+    if (current_x < data_len)
+       /* If we're not at the end of the line, move all the text from
+        * the current position up to it, not counting the newline at
+        * the end, to the cutbuffer. */
+       move_to_filestruct(&cutbuffer, &cutbottom, current, current_x,
+               current, data_len);
+    else if (current->next != NULL) {
+       /* If we're at the end of the line, and the next line isn't the
+        * magicline, move all the text from the current position up to
+        * the beginning of the next line, i.e, the newline at the
+        * end, to the cutbuffer. */
+       move_to_filestruct(&cutbuffer, &cutbottom, current, current_x,
+               current->next, 0);
+       placewewant = xplustabs();
     }
-#ifdef DEBUG
-    dump_buffer(cutbuffer);
-#endif
 }
-#endif
 
+/* Move text from the current filestruct into the cutbuffer. */
 void do_cut_text(void)
 {
-    filestruct *fileptr;
-
     assert(current != NULL && current->data != NULL);
 
     check_statusblank();
 
+    /* If keep_cutbuffer is FALSE, blow away the text in the
+     * cutbuffer. */
     if (!keep_cutbuffer) {
        free_filestruct(cutbuffer);
        cutbuffer = NULL;
-       marked_cut = CUT_LINE;
-#ifndef NANO_SMALL
-       concatenate_cut = FALSE;
-#endif
 #ifdef DEBUG
        fprintf(stderr, "Blew away cutbuffer =)\n");
 #endif
     }
 
-    /* You can't cut the magicline except with the mark.  But trying
-     * does clear the cutbuffer if keep_cutbuffer is FALSE. */
-    if (current == filebot
-#ifndef NANO_SMALL
-               && !ISSET(MARK_ISSET)
-#endif
-               )
-       return;
-
+    /* Set keep_cutbuffer to TRUE, so that the text we're going to move
+     * into the cutbuffer will be added to the text already in the
+     * cutbuffer instead of replacing it. */
     keep_cutbuffer = TRUE;
 
 #ifndef NANO_SMALL
-    if (ISSET(CUT_TO_END) && !ISSET(MARK_ISSET)) {
-       assert(current_x <= strlen(current->data));
-
-       if (current->data[current_x] == '\0') {
-           /* If the line is empty and we didn't just cut a non-blank
-            * line, create a dummy blank line and add it to the
-            * cutbuffer. */
-           if (marked_cut != CUT_MARKED && current->next != filebot) {
-               filestruct *junk = make_new_node(current);
-
-               junk->data = mallocstrcpy(NULL, "");
-               add_to_cutbuffer(junk, TRUE);
-#ifdef DEBUG
-               dump_buffer(cutbuffer);
-#endif
-           }
-
-           do_delete();
-           marked_cut = CUT_TO_EOL;
-           return;
-       } else {
-           SET(MARK_ISSET);
-
-           mark_beginx = strlen(current->data);
-           mark_beginbuf = current;
-       }
-    }
-
     if (ISSET(MARK_ISSET)) {
-       cut_marked_segment();
-
-       placewewant = xplustabs();
+       /* If the mark is on, move the marked text to the cutbuffer and
+        * turn the mark off. */
+       cut_marked();
        UNSET(MARK_ISSET);
-
-       marked_cut = CUT_MARKED;
-       concatenate_cut = TRUE;
-
-       edit_refresh();
-       set_modified();
-       return;
-    }
-#endif /* !NANO_SMALL */
-
-    totlines--;
-    totsize -= strlen(current->data) + 1;
-    fileptr = current;
-    current = current->next;
-    current->prev = fileptr->prev;
-    add_to_cutbuffer(fileptr, TRUE);
-#ifdef DEBUG
-    dump_buffer(cutbuffer);
+    } else
 #endif
-
-    if (fileptr == fileage)
-       fileage = current;
+    if (ISSET(CUT_TO_END))
+       /* Otherwise, if the CUT_TO_END flag is set, move all text up to
+        * the end of the line into the cutbuffer. */
+       cut_to_eol();
     else
-       current->prev->next = current;
-
-    if (fileptr == edittop)
-       edittop = current;
+       /* Otherwise, move the entire line into the cutbuffer. */
+       cut_line();
 
-    renumber(current);
-    current_x = 0;
     edit_refresh();
     set_modified();
-    marked_cut = CUT_LINE;
-#ifndef NANO_SMALL
-    concatenate_cut = FALSE;
+
+#ifdef DEBUG
+    dump_buffer(cutbuffer);
 #endif
 }
 
+/* Copy text from the cutbuffer into the current filestruct. */
 void do_uncut_text(void)
 {
-    filestruct *tmp = current;
-    filestruct *newbuf = NULL;
-    filestruct *newend = NULL;
+    assert(current != NULL && current->data != NULL);
 
 #ifndef DISABLE_WRAPPING
     wrap_reset();
 #endif
-    check_statusblank();
-    if (cutbuffer == NULL || current == NULL)
-       return;                 /* AIEEEEEEEEEEEE */
-
-    /* If we're uncutting a previously non-marked block, uncut to end if
-     * we're not at the beginning of the line.  If we are at the
-     * beginning of the line, set placewewant to 0.  Pico does both of
-     * these. */
-    if (marked_cut == CUT_LINE) {
-       if (current_x > 0)
-           marked_cut = CUT_TO_EOL;
-       else
-           placewewant = 0;
-    }
-
-    /* If we're going to uncut on the magicline, always make a new
-     * magicline in advance, as Pico does. */
-    if (current->next == NULL)
-       new_magicline();
-
-    if (marked_cut == CUT_LINE || cutbuffer->next != NULL) {
-       newbuf = copy_filestruct(cutbuffer);
-       for (newend = newbuf; newend->next != NULL && newend != NULL;
-               newend = newend->next)
-           totlines++;
-    }
-
-    /* Hook newbuf in at current. */
-    if (marked_cut != CUT_LINE) {
-       filestruct *hold = current;
-
-       /* If there's only one line in the cutbuffer... */
-       if (cutbuffer->next == NULL) {
-           size_t buf_len = strlen(cutbuffer->data);
-           size_t cur_len = strlen(current->data);
-
-           current->data = charealloc(current->data, cur_len +
-               buf_len + 1);
-           charmove(current->data + current_x + buf_len,
-               current->data + current_x, cur_len - current_x + 1);
-           strncpy(current->data + current_x, cutbuffer->data,
-               buf_len);
-               /* Use strncpy() to not copy the null terminator. */
 
-           current_x += buf_len;
-           totsize += buf_len;
-
-           placewewant = xplustabs();
-       } else {                /* Yuck -- no kidding! */
-           char *tmpstr, *tmpstr2;
-
-           tmp = current->next;
-
-           /* New beginning. */
-           tmpstr = charalloc(current_x + strlen(newbuf->data) + 1);
-           strncpy(tmpstr, current->data, current_x);
-           strcpy(&tmpstr[current_x], newbuf->data);
-           totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
-
-           /* New end. */
-           tmpstr2 = charalloc(strlen(newend->data) +
-               strlen(&current->data[current_x]) + 1);
-           strcpy(tmpstr2, newend->data);
-           strcat(tmpstr2, &current->data[current_x]);
-
-           free(current->data);
-           current->data = tmpstr;
-           current->next = newbuf->next;
-           newbuf->next->prev = current;
-           delete_node(newbuf);
-
-           current_x = strlen(newend->data);
-           placewewant = xplustabs();
-           free(newend->data);
-           newend->data = tmpstr2;
-
-           newend->next = tmp;
-
-           /* If tmp isn't NULL, we're in the middle: update the
-            * prev pointer.  If it IS NULL, we're at the end; update
-            * the filebot pointer. */
-           if (tmp != NULL)
-               tmp->prev = newend;
-           else {
-               filebot = newend;
-               new_magicline();
-           }
-
-           /* Recalculate current_y and totsize. */
-           for (tmp = current->next; tmp != newend; tmp = tmp->next) {
-               current_y++;
-               totsize += strlen(tmp->data) + 1;
-           }
-
-           current = newend;
-       }
-
-       /* If we're doing a cut to end, we don't want anything else on
-        * the line, so we have to screw up all the work we just did and
-        * separate the line. */
-       if (marked_cut == CUT_TO_EOL) {
-           tmp = make_new_node(current);
-           tmp->data = mallocstrcpy(NULL, current->data + current_x);
-           splice_node(current, tmp, current->next);
-           null_at(&current->data, current_x);
-           current = current->next;
-           current_x = 0;
-           placewewant = 0;
-
-           /* Extra line added; update stuff. */
-           totlines++;
-           totsize++;
-       }
-
-       /* Renumber from BEFORE where we pasted ;) */
-       renumber(hold);
+    check_statusblank();
 
-#ifdef DEBUG
-       dump_buffer(fileage);
-       dump_buffer(cutbuffer);
-#endif
-       set_modified();
-       edit_refresh();
+    /* If the cutbuffer is empty, get out. */
+    if (cutbuffer == NULL)
        return;
-    }
-
-    if (current != fileage) {
-       tmp = current->prev;
-       tmp->next = newbuf;
-       newbuf->prev = tmp;
-    } else
-       fileage = newbuf;
 
-    totlines++;                /* Unmarked uncuts don't split lines. */
+    /* Add a copy of the text in the cutbuffer to the current filestruct
+     * at the current cursor position. */
+    copy_from_filestruct(cutbuffer, cutbottom);
 
-    /* This is so uncutting at the top of the buffer will work => */
-    if (current_y == 0)
-       edittop = newbuf;
+    /* Set the current place we want to where the text from the
+     * cutbuffer ends. */
+    placewewant = xplustabs();
 
-    /* Connect the end of the buffer to the filestruct. */
-    newend->next = current;
-    current->prev = newend;
-
-    /* Recalculate current_y and totsize. */
-    for (tmp = newbuf; tmp != current; tmp = tmp->next) {
-       current_y++;
-       totsize += strlen(tmp->data) + 1;
-    }
-
-    renumber(newbuf);
     edit_refresh();
+    set_modified();
 
 #ifdef DEBUG
     dump_buffer_reverse();
 #endif
-
-    set_modified();
 }
index 580d2e35d713f5d9523b9d8ae811c466a7369ab5..761d2e09691be90cafbf3b38393423abfc634399 100644 (file)
@@ -63,6 +63,9 @@ filestruct *edittop = NULL;   /* Pointer to the top of the edit
                                   file struct */
 filestruct *filebot = NULL;    /* Last node in the file struct */
 filestruct *cutbuffer = NULL;  /* A place to store cut text */
+#ifndef DISABLE_JUSTIFY
+filestruct *jusbuffer = NULL;  /* A place to store unjustified text */
+#endif
 partition *filepart = NULL;    /* A place to store a portion of the
                                   file struct */
 
@@ -1160,7 +1163,10 @@ void thanks_for_all_the_fish(void)
        free(answer);
     if (cutbuffer != NULL)
        free_filestruct(cutbuffer);
-
+#ifndef DISABLE_JUSTIFY
+    if (jusbuffer != NULL)
+       free_filestruct(jusbuffer);
+#endif
     free_shortcutage(&main_list);
     free_shortcutage(&whereis_list);
     free_shortcutage(&replace_list);
index 88c9ccb7f2aa8c518514b394d35c3a42e9e07a37..6268773a1cc07b8dc347c76109cda46d0af37a32 100644 (file)
@@ -78,6 +78,11 @@ static int pid;                      /* The PID of the newly forked process
                                 * it. */
 #endif
 
+#ifndef DISABLE_JUSTIFY
+static filestruct *jusbottom = NULL;
+       /* Pointer to end of justify buffer. */
+#endif
+
 /* What we do when we're all set to exit. */
 void finish(void)
 {
@@ -714,6 +719,169 @@ void unpartition_filestruct(partition **p)
     *p = NULL;
 }
 
+/* Move all the text between (top, top_x) and (bot, bot_x) in the
+ * current filestruct to a filestruct beginning with file_top and ending
+ * with file_bot.  If no text is between (top, top_x) and (bot, bot_x),
+ * don't do anything. */
+void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
+       filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
+{
+    filestruct *top_save;
+    long part_totsize;
+    bool at_edittop;
+#ifndef NANO_SMALL
+    bool mark_inside = FALSE;
+#endif
+
+    assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
+
+    /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
+    if (top == bot && top_x == bot_x)
+       return;
+
+    /* Partition the filestruct so that it contains only the text from
+     * (top, top_x) to (bot, bot_x), keep track of whether the top of
+     * the partition is the top of the edit window, and keep track of
+     * whether the mark begins inside the partition. */
+    filepart = partition_filestruct(top, top_x, bot, bot_x);
+    at_edittop = (fileage == edittop);
+#ifndef NANO_SMALL
+    if (ISSET(MARK_ISSET))
+       mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
+               mark_beginbuf->lineno <= filebot->lineno &&
+               (mark_beginbuf != fileage || mark_beginx >= top_x) &&
+               (mark_beginbuf != filebot || mark_beginx <= bot_x));
+#endif
+
+    /* Get the number of characters in the text, and subtract it from
+     * totsize. */
+    get_totals(top, bot, NULL, &part_totsize);
+    totsize -= part_totsize;
+
+    if (*file_top == NULL) {
+       /* If file_top is empty, just move all the text directly into
+        * it.  This is equivalent to tacking the text in top onto the
+        * (lack of) text at the end of file_top. */
+       *file_top = fileage;
+       *file_bot = filebot;
+    } else {
+       /* Otherwise, tack the text in top onto the text at the end of
+        * file_bot. */
+       (*file_bot)->data = charealloc((*file_bot)->data,
+               strlen((*file_bot)->data) + strlen(fileage->data) + 1);
+       strcat((*file_bot)->data, fileage->data);
+
+       /* Attach the line after top to the line after file_bot.  Then,
+        * if there's more than one line after top, move file_bot down
+        * to bot. */
+       (*file_bot)->next = fileage->next;
+       if ((*file_bot)->next != NULL) {
+           (*file_bot)->next->prev = *file_bot;
+           *file_bot = filebot;
+       }
+    }
+
+    /* Since the text has now been saved, remove it from the filestruct.
+     * If the top of the partition was the top of the edit window, set
+     * edittop to where the text used to start.  If the mark began
+     * inside the partition, set the beginning of the mark to where the
+     * text used to start. */
+    fileage = (filestruct *)nmalloc(sizeof(filestruct));
+    fileage->data = mallocstrcpy(NULL, "");
+    filebot = fileage;
+    if (at_edittop)
+       edittop = fileage;
+#ifndef NANO_SMALL
+    if (mark_inside) {
+       mark_beginbuf = fileage;
+       mark_beginx = top_x;
+    }
+#endif
+
+    /* Restore the current line and cursor position. */
+    current = fileage;
+    current_x = top_x;
+
+    top_save = fileage;
+
+    /* Unpartition the filestruct so that it contains all the text
+     * again, minus the saved text. */
+    unpartition_filestruct(&filepart);
+
+    /* Renumber starting with the beginning line of the old
+     * partition. */
+    renumber(top_save);
+
+    if (filebot->data[0] != '\0')
+       new_magicline();
+
+    /* Set totlines to the new number of lines in the file. */
+    totlines = filebot->lineno;
+}
+
+/* Copy all the text from the filestruct beginning with file_top and
+ * ending with file_bot to the current filestruct at the current cursor
+ * position. */
+void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
+{
+    filestruct *top_save;
+    int part_totlines;
+    long part_totsize;
+    bool at_edittop;
+
+    assert(file_top != NULL && file_bot != NULL);
+
+    /* Partition the filestruct so that it contains no text, and keep
+     * track of whether the top of the partition is the top of the edit
+     * window. */
+    filepart = partition_filestruct(current, current_x, current,
+       current_x);
+    at_edittop = (fileage == edittop);
+
+    /* Put the top and bottom of the filestruct at copies of file_top
+     * and file_bot. */
+    fileage = copy_filestruct(file_top);
+    filebot = fileage;
+    while (filebot->next != NULL)
+       filebot = filebot->next;
+
+    /* Restore the current line and cursor position. */
+    current = filebot;
+    current_x = strlen(filebot->data);
+    if (fileage == filebot)
+       current_x += strlen(filepart->top_data);
+
+    /* Get the number of lines and the number of characters in the saved
+     * text, and add the latter to totsize. */
+    get_totals(fileage, filebot, &part_totlines, &part_totsize);
+    totsize += part_totsize;
+
+    /* If the top of the partition was the top of the edit window, set
+     * edittop to where the saved text now starts, and update the
+     * current y-coordinate to account for the number of lines it
+     * has, less one since the first line will be tacked onto the
+     * current line. */
+    if (at_edittop)
+       edittop = fileage;
+    current_y += part_totlines - 1;
+
+    top_save = fileage;
+
+    /* Unpartition the filestruct so that it contains all the text
+     * again, minus the saved text. */
+    unpartition_filestruct(&filepart);
+
+    /* Renumber starting with the beginning line of the old
+     * partition. */
+    renumber(top_save);
+
+    if (filebot->data[0] != '\0')
+       new_magicline();
+
+    /* Set totlines to the new number of lines in the file. */
+    totlines = filebot->lineno;
+}
+
 void renumber_all(void)
 {
     filestruct *temp;
@@ -2342,39 +2510,69 @@ void do_para_end(void)
     edit_redraw(old_current, old_pww);
 }
 
-/* Put the next par_len lines, starting with first_line, in the
- * cutbuffer, not allowing them to be concatenated.  We assume there
- * are enough lines after first_line.  We leave copies of the lines in
- * place, too.  We return the new copy of first_line. */
+/* Put the next par_len lines, starting with first_line, into the
+ * justify buffer, leaving copies of those lines in place.  Assume there
+ * are enough lines after first_line.  Return the new copy of
+ * first_line. */
 filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
        quote_len)
 {
-    /* We put the original lines, not copies, into the cutbuffer, just
-     * out of a misguided sense of consistency, so if you uncut, you get
-     * the actual same paragraph back, not a copy. */
-    filestruct *alice = first_line;
+    filestruct *top = first_line;
+       /* The top of the paragraph we're backing up. */
+    filestruct *bot = first_line;
+       /* The bottom of the paragraph we're backing up. */
+    size_t i;
+       /* Generic loop variable. */
+    size_t current_x_save = current_x;
+    int fl_lineno_save = first_line->lineno;
+    int edittop_lineno_save = edittop->lineno;
+    int current_lineno_save = current->lineno;
+#ifndef NANO_SMALL
+    bool old_mark_set = ISSET(MARK_ISSET);
+    int mbb_lineno_save = 0;
 
-    set_modified();
-    cutbuffer = NULL;
-    for (; par_len > 0; par_len--) {
-       filestruct *bob = copy_node(alice);
+    if (old_mark_set)
+       mbb_lineno_save = mark_beginbuf->lineno;
+#endif
+
+    /* Move bot down par_len lines to the newline after the last line of
+     * the paragraph. */
+    for (i = par_len; i > 0; i--)
+       bot = bot->next;
+
+    /* Move the paragraph from the main filestruct to the justify
+     * buffer. */
+    move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot, 0);
+
+    /* Copy the paragraph from the justify buffer to the main
+     * filestruct. */
+    copy_from_filestruct(jusbuffer, jusbottom);
 
-       if (alice == first_line)
-           first_line = bob;
-       if (alice == current)
-           current = bob;
-       if (alice == edittop)
-           edittop = bob;
+    /* Move upward from the last line of the paragraph to the first
+     * line, putting first_line, edittop, current, and mark_beginbuf at
+     * the same lines in the copied paragraph that they had in the
+     * original paragraph. */
+    top = current->prev;
+    for (i = par_len; i > 0; i--) {
+       if (top->lineno == fl_lineno_save)
+           first_line = top;
+       if (top->lineno == edittop_lineno_save)
+           edittop = top;
+       if (top->lineno == current_lineno_save)
+           current = top;
 #ifndef NANO_SMALL
-       if (alice == mark_beginbuf)
-           mark_beginbuf = bob;
+       if (old_mark_set && top->lineno == mbb_lineno_save)
+           mark_beginbuf = top;
 #endif
-
-       assert(alice != NULL && bob != NULL);
-       add_to_cutbuffer(alice, FALSE);
-       splice_node(bob->prev, bob, bob->next);
-       alice = bob->next;
+       top = top->prev;
     }
+
+    /* Put current_x at the same place in the copied paragraph that it
+     * had in the original paragraph. */
+    current_x = current_x_save;
+
+    set_modified();
+
     return first_line;
 }
 
@@ -2561,13 +2759,10 @@ void do_justify(bool full_justify)
 {
     filestruct *first_par_line = NULL;
        /* Will be the first line of the resulting justified paragraph.
-        * For restoring after uncut. */
+        * For restoring after unjustify. */
     filestruct *last_par_line;
-       /* Will be the last line of the result, also for uncut. */
-    filestruct *cutbuffer_save = cutbuffer;
-       /* When the paragraph gets modified, all lines from the changed
-        * one down are stored in the cutbuffer.  We back up the
-        * original to restore it later. */
+       /* Will be the line containing the newline after the last line
+        * of the result.  Also for restoring after unjustify. */
     bool allow_respacing;
        /* Whether we should change the spacing at the end of a line
         * after justifying it.  This should be TRUE whenever we move
@@ -2611,10 +2806,7 @@ void do_justify(bool full_justify)
         * get out. */
        if (do_para_search(&quote_len, &par_len)) {
            if (full_justify) {
-               /* This should be safe in the event of filebot->prev's
-                * being NULL, since only last_par_line->next is used if
-                * we eventually unjustify. */
-               last_par_line = filebot->prev;
+               last_par_line = filebot;
                break;
            } else {
                edit_refresh();
@@ -2641,7 +2833,7 @@ void do_justify(bool full_justify)
                quote_len);
 
            /* If we haven't already done it, copy the original
-            * paragraph to the cutbuffer for unjustification. */
+            * paragraph to the justify buffer. */
            if (first_par_line == NULL)
                first_par_line = backup_lines(current, full_justify ?
                        filebot->lineno - current->lineno : par_len,
@@ -2829,7 +3021,7 @@ void do_justify(bool full_justify)
      * fileage, and renumber() since edit_refresh() needs the line
      * numbers to be right (but only do the last two if we actually
      * justified something). */
-    last_par_line = current->prev;
+    last_par_line = current;
     if (first_par_line != NULL) {
        if (first_par_line->prev == NULL)
            fileage = first_par_line;
@@ -2846,53 +3038,65 @@ void do_justify(bool full_justify)
 
     /* Now get a keystroke and see if it's unjustify; if not, unget the
      * keystroke and return. */
-    kbinput = get_edit_input(&meta_key, &func_key, FALSE);
+    kbinput = get_edit_input(&meta_key, &func_key);
 
     if (!meta_key && !func_key && kbinput == NANO_UNJUSTIFY_KEY) {
        /* Restore the justify we just did (ungrateful user!). */
-       filestruct *cutbottom = get_cutbottom();
-
        current = current_save;
        current_x = current_x_save;
        current_y = current_y_save;
        edittop = edittop_save;
 
-       /* Splice the cutbuffer back into the file, but only if we
+       /* Splice the justify buffer back into the file, but only if we
         * actually justified something. */
        if (first_par_line != NULL) {
-           cutbottom->next = last_par_line->next;
-           cutbottom->next->prev = cutbottom;
-           /* The line numbers after the end of the paragraph have been
-            * changed, so we change them back. */
-           renumber(cutbottom->next);
-           if (first_par_line->prev != NULL) {
-               cutbuffer->prev = first_par_line->prev;
-               cutbuffer->prev->next = cutbuffer;
-           } else
-               fileage = cutbuffer;
+           filestruct *bot_save;
 
-           last_par_line->next = NULL;
-           free_filestruct(first_par_line);
-       }
+           /* Partition the filestruct so that it contains only the
+            * text of the justified paragraph. */
+           filepart = partition_filestruct(first_par_line, 0,
+               last_par_line, 0);
 
-       /* Restore global variables from before the justify. */
-       totsize = totsize_save;
-       totlines = filebot->lineno;
+           /* Remove the text of the justified paragraph, and
+            * put the text in the justify buffer in its place. */
+           free_filestruct(fileage);
+           fileage = jusbuffer;
+           filebot = jusbottom;
+
+           bot_save = filebot;
+
+           /* Unpartition the filestruct so that it contains all the
+            * text again.  Note that the justified paragraph has been
+            * replaced with the unjustified paragraph. */
+           unpartition_filestruct(&filepart);
+
+            /* Renumber starting with the ending line of the old
+             * partition. */
+           if (bot_save->next != NULL)
+               renumber(bot_save->next);
+
+           /* Restore global variables from before the justify. */
+           totsize = totsize_save;
+           totlines = filebot->lineno;
 #ifndef NANO_SMALL
-       mark_beginbuf = mark_beginbuf_save;
-       mark_beginx = mark_beginx_save;
+           mark_beginbuf = mark_beginbuf_save;
+           mark_beginx = mark_beginx_save;
 #endif
-       flags = flags_save;
-       if (!ISSET(MODIFIED))
-           titlebar(NULL);
-       edit_refresh();
+           flags = flags_save;
+
+           /* Clear the justify buffer. */
+           jusbuffer = NULL;
+
+           if (!ISSET(MODIFIED))
+               titlebar(NULL);
+           edit_refresh();
+       }
     } else {
-       placewewant = 0;
-       unget_kbinput(kbinput, meta_key, func_key);
+       /* Blow away the justify buffer.*/
+       free_filestruct(jusbuffer);
+       jusbuffer = NULL;
     }
 
-    cutbuffer = cutbuffer_save;
-    /* Note that now cutbottom is invalid, but that's okay. */
     blank_statusbar();
 
     /* Display the shortcut list with UnCut. */
@@ -3060,6 +3264,16 @@ void handle_sigwinch(int s)
     if (filepart != NULL)
        unpartition_filestruct(&filepart);
 
+#ifndef DISABLE_JUSTIFY
+    /* If the justify buffer isn't empty, blow it away and display the
+     * shortcut list with UnCut. */
+    if (jusbuffer != NULL) {
+       free_filestruct(jusbuffer);
+       jusbuffer = NULL;
+       shortcut_init(FALSE);
+    }
+#endif
+
 #ifdef USE_SLANG
     /* Slang curses emulation brain damage, part 1: If we just do what
      * curses does here, it'll only work properly if the resize made the
@@ -3741,7 +3955,7 @@ int main(int argc, char **argv)
        currshortcut = main_list;
 #endif
 
-       kbinput = get_edit_input(&meta_key, &func_key, TRUE);
+       kbinput = get_edit_input(&meta_key, &func_key);
 
        /* Last gasp, stuff that's not in the main lists. */
        if (kbinput != ERR && !is_cntrl_char(kbinput)) {
index d2d55e18d35abff4843cb6e8508b6e9ce0386395..7e79053b5bf1fb1e5064b177ed19018afa78c7bc 100644 (file)
 #endif
 
 /* Enumeration types. */
-typedef enum {
-    CUT_LINE, CUT_MARKED, CUT_TO_EOL
-} cut_type;
-
 typedef enum {
     NIX_FILE, DOS_FILE, MAC_FILE
 } file_format;
index 094af605711311222514fa437ea5da7b752667db..4065da18581fccf89167560a5ba3bf902fc63c27 100644 (file)
@@ -86,6 +86,9 @@ extern char *alt_speller;
 extern struct stat fileinfo;
 extern filestruct *current, *fileage, *edittop, *filebot;
 extern filestruct *cutbuffer;
+#ifndef DISABLE_JUSTIFY
+extern filestruct *jusbuffer;
+#endif
 extern partition *filepart;
 #ifndef NANO_SMALL
 extern filestruct *mark_beginbuf;
@@ -158,11 +161,11 @@ void update_color(void);
 
 /* Public functions in cut.c. */
 void cutbuffer_reset(void);
-filestruct *get_cutbottom(void);
-void add_to_cutbuffer(filestruct *inptr, bool allow_concat);
+void cut_line(void);
 #ifndef NANO_SMALL
-void cut_marked_segment(void);
+void cut_marked(void);
 #endif
+void cut_to_eol(void);
 void do_cut_text(void);
 void do_uncut_text(void);
 
@@ -308,6 +311,9 @@ void free_filestruct(filestruct *src);
 partition *partition_filestruct(filestruct *top, size_t top_x,
        filestruct *bot, size_t bot_x);
 void unpartition_filestruct(partition **p);
+void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
+       filestruct *top, size_t top_x, filestruct *bot, size_t bot_x);
+void copy_from_filestruct(filestruct *file_top, filestruct *file_bot);
 void renumber_all(void);
 void renumber(filestruct *fileptr);
 void print1opt(const char *shortflag, const char *longflag, const char
@@ -504,11 +510,11 @@ char *mallocstrassn(char *dest, char *src);
 void new_magicline(void);
 #ifndef NANO_SMALL
 void remove_magicline(void);
-void get_totals(const filestruct *begin, const filestruct *end, int
-       *lines, long *size);
 void mark_order(const filestruct **top, size_t *top_x, const filestruct
        **bot, size_t *bot_x, bool *right_side_up);
 #endif
+void get_totals(const filestruct *begin, const filestruct *end, int
+       *lines, long *size);
 #ifndef DISABLE_TABCOMP
 int check_wildcard_match(const char *text, const char *pattern);
 #endif
@@ -549,7 +555,7 @@ const shortcut *get_shortcut(const shortcut *s_list, int kbinput, bool
 #ifndef NANO_SMALL
 const toggle *get_toggle(int kbinput, bool meta_key);
 #endif
-int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs);
+int get_edit_input(bool *meta_key, bool *func_key);
 #ifndef DISABLE_MOUSE
 bool get_edit_mouse(void);
 #endif
index 463bce99b62a7921b4282278f87af20a0d71175a..7ee72f1bb56954aaf42250a2cda46d6b835320ab 100644 (file)
@@ -456,6 +456,35 @@ void remove_magicline(void)
     }
 }
 
+/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
+ * respectively, based on the locations of top and bot.  If
+ * right_side_up isn't NULL, set it to TRUE If the mark begins with
+ * (mark_beginbuf, mark_beginx) and ends with (current, current_x), or
+ * FALSE otherwise. */
+void mark_order(const filestruct **top, size_t *top_x, const filestruct
+       **bot, size_t *bot_x, bool *right_side_up)
+{
+    assert(top != NULL && top_x != NULL && bot != NULL && bot_x != NULL);
+
+    if ((current->lineno == mark_beginbuf->lineno && current_x >
+        mark_beginx) || current->lineno > mark_beginbuf->lineno) {
+       *top = mark_beginbuf;
+       *top_x = mark_beginx;
+       *bot = current;
+       *bot_x = current_x;
+       if (right_side_up != NULL)
+           *right_side_up = TRUE;
+    } else {
+       *bot = mark_beginbuf;
+       *bot_x = mark_beginx;
+       *top = current;
+       *top_x = current_x;
+       if (right_side_up != NULL)
+           *right_side_up = FALSE;
+    }
+}
+#endif
+
 /* Calculate the number of lines and the number of characters between
  * begin and end, and return them in lines and size, respectively. */
 void get_totals(const filestruct *begin, const filestruct *end, int
@@ -501,35 +530,6 @@ void get_totals(const filestruct *begin, const filestruct *end, int
     }
 }
 
-/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
- * respectively, based on the locations of top and bot.  If
- * right_side_up isn't NULL, set it to TRUE If the mark begins with
- * (mark_beginbuf, mark_beginx) and ends with (current, current_x), or
- * FALSE otherwise. */
-void mark_order(const filestruct **top, size_t *top_x, const filestruct
-       **bot, size_t *bot_x, bool *right_side_up)
-{
-    assert(top != NULL && top_x != NULL && bot != NULL && bot_x != NULL);
-
-    if ((current->lineno == mark_beginbuf->lineno && current_x >
-        mark_beginx) || current->lineno > mark_beginbuf->lineno) {
-       *top = mark_beginbuf;
-       *top_x = mark_beginx;
-       *bot = current;
-       *bot_x = current_x;
-       if (right_side_up != NULL)
-           *right_side_up = TRUE;
-    } else {
-       *bot = mark_beginbuf;
-       *bot_x = mark_beginx;
-       *top = current;
-       *top_x = current_x;
-       if (right_side_up != NULL)
-           *right_side_up = FALSE;
-    }
-}
-#endif
-
 #ifndef DISABLE_TABCOMP
 /*
  * Routine to see if a text string is matched by a wildcard pattern.
index 7c8be1445e8e7eae102a541449dc943d2d02ee79..47b636f6b002c419f8cc66504e9e5b4b4de92eed 100644 (file)
@@ -1491,7 +1491,7 @@ const toggle *get_toggle(int kbinput, bool meta_key)
 }
 #endif /* !NANO_SMALL */
 
-int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs)
+int get_edit_input(bool *meta_key, bool *func_key)
 {
     bool keyhandled = FALSE;
     int kbinput, retval;
@@ -1536,12 +1536,10 @@ int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs)
        if (s->func != do_cut_text)
            cutbuffer_reset();
        if (s->func != NULL) {
-           if (allow_funcs) {
-               if (ISSET(VIEW_MODE) && !s->viewok)
-                   print_view_warning();
-               else
-                   s->func();
-           }
+           if (ISSET(VIEW_MODE) && !s->viewok)
+               print_view_warning();
+           else
+               s->func();
            keyhandled = TRUE;
        }
     }
@@ -1555,8 +1553,7 @@ int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs)
         * corresponding flag. */
        if (t != NULL) {
            cutbuffer_reset();
-           if (allow_funcs)
-               do_toggle(t);
+           do_toggle(t);
            keyhandled = TRUE;
        }
     }
@@ -1565,7 +1562,7 @@ int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs)
     /* If we got a shortcut with a corresponding function or a toggle,
      * reset meta_key and retval.  If we didn't, keep the value of
      * meta_key and return the key we got in retval. */
-    if (allow_funcs && keyhandled) {
+    if (keyhandled) {
        *meta_key = FALSE;
        retval = ERR;
     } else {