cut.c (23592B)
1 /************************************************************************** 2 * cut.c -- This file is part of GNU nano. * 3 * * 4 * Copyright (C) 1999-2011, 2013-2025 Free Software Foundation, Inc. * 5 * Copyright (C) 2014 Mark Majeres * 6 * Copyright (C) 2016, 2018-2020 Benno Schulenberg * 7 * * 8 * GNU nano is free software: you can redistribute it and/or modify * 9 * it under the terms of the GNU General Public License as published * 10 * by the Free Software Foundation, either version 3 of the License, * 11 * or (at your option) any later version. * 12 * * 13 * GNU nano is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty * 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * 16 * See the GNU General Public License for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License * 19 * along with this program. If not, see https://gnu.org/licenses/. * 20 * * 21 **************************************************************************/ 22 23 #include "prototypes.h" 24 25 #include <string.h> 26 27 /* Delete the character at the current position, and 28 * add or update an undo item for the given action. */ 29 void expunge(undo_type action) 30 { 31 openfile->placewewant = xplustabs(); 32 33 /* When in the middle of a line, delete the current character. */ 34 if (openfile->current->data[openfile->current_x] != '\0') { 35 int charlen = char_length(openfile->current->data + openfile->current_x); 36 size_t line_len = strlen(openfile->current->data + openfile->current_x); 37 #ifndef NANO_TINY 38 size_t old_amount = ISSET(SOFTWRAP) ? extra_chunks_in(openfile->current) : 0; 39 40 /* If the type of action changed or the cursor moved to a different 41 * line, create a new undo item, otherwise update the existing item. */ 42 if (action != openfile->last_action || 43 openfile->current->lineno != openfile->current_undo->head_lineno) 44 add_undo(action, NULL); 45 else 46 update_undo(action); 47 #endif 48 /* Move the remainder of the line "in", over the current character. */ 49 memmove(&openfile->current->data[openfile->current_x], 50 &openfile->current->data[openfile->current_x + charlen], 51 line_len - charlen + 1); 52 #ifndef NANO_TINY 53 /* When softwrapping, a changed number of chunks requires a refresh. */ 54 if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount) 55 refresh_needed = TRUE; 56 57 /* Adjust the mark if it is after the cursor on the current line. */ 58 if (openfile->mark == openfile->current && 59 openfile->mark_x > openfile->current_x) 60 openfile->mark_x -= charlen; 61 #endif 62 /* Otherwise, when not at end of buffer, join this line with the next. */ 63 } else if (openfile->current != openfile->filebot) { 64 linestruct *joining = openfile->current->next; 65 66 /* If there is a magic line, and we're before it: don't eat it. */ 67 if (joining == openfile->filebot && openfile->current_x != 0 && 68 !ISSET(NO_NEWLINES)) { 69 #ifndef NANO_TINY 70 if (action == BACK) 71 add_undo(BACK, NULL); 72 #endif 73 return; 74 } 75 76 #ifndef NANO_TINY 77 add_undo(action, NULL); 78 79 /* Adjust the mark if it is on the line that will be "eaten". */ 80 if (openfile->mark == joining) { 81 openfile->mark = openfile->current; 82 openfile->mark_x += openfile->current_x; 83 } 84 85 openfile->current->has_anchor |= joining->has_anchor; 86 #endif 87 /* Add the content of the next line to that of the current one. */ 88 openfile->current->data = nrealloc(openfile->current->data, 89 strlen(openfile->current->data) + strlen(joining->data) + 1); 90 strcat(openfile->current->data, joining->data); 91 92 unlink_node(joining); 93 94 /* Two lines were joined, so do a renumbering and refresh the screen. */ 95 renumber_from(openfile->current); 96 refresh_needed = TRUE; 97 } else 98 /* We're at the end-of-file: nothing to do. */ 99 return; 100 101 #ifdef ENABLE_COLOR 102 if (!refresh_needed) 103 check_the_multis(openfile->current); 104 #endif 105 if (!refresh_needed) 106 update_line(openfile->current, openfile->current_x); 107 108 /* Adjust the file size, and remember it for a possible redo. */ 109 openfile->totsize--; 110 #ifndef NANO_TINY 111 openfile->current_undo->newsize = openfile->totsize; 112 #endif 113 set_modified(); 114 } 115 116 /* Delete the character under the cursor plus any succeeding zero-widths, 117 * or, when the mark is on and --zap is active, delete the marked region. */ 118 void do_delete(void) 119 { 120 #ifndef NANO_TINY 121 if (openfile->mark && ISSET(LET_THEM_ZAP)) 122 zap_text(); 123 else 124 #endif 125 { 126 expunge(DEL); 127 #ifdef ENABLE_UTF8 128 while (openfile->current->data[openfile->current_x] != '\0' && 129 is_zerowidth(openfile->current->data + openfile->current_x)) 130 expunge(DEL); 131 #endif 132 } 133 } 134 135 /* Backspace over one character. That is, move the cursor left one 136 * character, and then delete the character under the cursor. Or, 137 * when mark is on and --zap is active, delete the marked region. */ 138 void do_backspace(void) 139 { 140 #ifndef NANO_TINY 141 if (openfile->mark && ISSET(LET_THEM_ZAP)) 142 zap_text(); 143 else 144 #endif 145 if (openfile->current_x > 0) { 146 openfile->current_x = step_left(openfile->current->data, openfile->current_x); 147 expunge(BACK); 148 } else if (openfile->current != openfile->filetop) { 149 do_left(); 150 expunge(BACK); 151 } 152 } 153 154 /* Return FALSE when a cut command would not actually cut anything: when 155 * on an empty line at EOF, or when the mark covers zero characters, or 156 * (when test_cliff is TRUE) when the magic line would be cut. */ 157 bool is_cuttable(bool test_cliff) 158 { 159 size_t from = (test_cliff) ? openfile->current_x : 0; 160 161 if ((openfile->current->next == NULL && openfile->current->data[from] == '\0' 162 #ifndef NANO_TINY 163 && openfile->mark == NULL) || 164 (openfile->mark == openfile->current && 165 openfile->mark_x == openfile->current_x) || 166 (from > 0 && !ISSET(NO_NEWLINES) && 167 openfile->current->data[from] == '\0' && 168 openfile->current->next == openfile->filebot 169 #endif 170 )) { 171 #ifndef NANO_TINY 172 statusbar(_("Nothing was cut")); 173 openfile->mark = NULL; 174 #endif 175 return FALSE; 176 } else 177 return TRUE; 178 } 179 180 #ifndef NANO_TINY 181 /* Delete text from the cursor until the first start of a word to 182 * the left, or to the right when forward is TRUE. */ 183 void chop_word(bool forward) 184 { 185 /* Remember the current cursor position. */ 186 linestruct *is_current = openfile->current; 187 size_t is_current_x = openfile->current_x; 188 /* Remember where the cutbuffer is, then make it seem blank. */ 189 linestruct *is_cutbuffer = cutbuffer; 190 191 cutbuffer = NULL; 192 193 /* Move the cursor to a word start, to the left or to the right. 194 * If that word is on another line and the cursor was not already 195 * on the edge of the original line, then put the cursor on that 196 * edge instead, so that lines will not be joined unexpectedly. */ 197 if (!forward) { 198 do_prev_word(); 199 if (openfile->current != is_current) { 200 if (is_current_x > 0) { 201 openfile->current = is_current; 202 openfile->current_x = 0; 203 } else 204 openfile->current_x = strlen(openfile->current->data); 205 } 206 } else { 207 do_next_word(ISSET(AFTER_ENDS)); 208 if (openfile->current != is_current && 209 is_current->data[is_current_x] != '\0') { 210 openfile->current = is_current; 211 openfile->current_x = strlen(is_current->data); 212 } 213 } 214 215 /* Set the mark at the start of that word. */ 216 openfile->mark = openfile->current; 217 openfile->mark_x = openfile->current_x; 218 219 /* Put the cursor back where it was, so an undo will put it there too. */ 220 openfile->current = is_current; 221 openfile->current_x = is_current_x; 222 223 /* Now kill the marked region and a word is gone. */ 224 add_undo(CUT, NULL); 225 do_snip(TRUE, FALSE, FALSE); 226 update_undo(CUT); 227 228 /* Discard the cut word and restore the cutbuffer. */ 229 free_lines(cutbuffer); 230 cutbuffer = is_cutbuffer; 231 } 232 233 /* Delete a word leftward. */ 234 void chop_previous_word(void) 235 { 236 if (openfile->current->prev == NULL && openfile->current_x == 0) 237 statusbar(_("Nothing was cut")); 238 else 239 chop_word(BACKWARD); 240 } 241 242 /* Delete a word rightward. */ 243 void chop_next_word(void) 244 { 245 openfile->mark = NULL; 246 247 if (is_cuttable(TRUE)) 248 chop_word(FORWARD); 249 } 250 #endif /* !NANO_TINY */ 251 252 /* Excise the text between the given two points and add it to the cutbuffer. */ 253 void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_x) 254 { 255 linestruct *taken, *last; 256 bool edittop_inside = (openfile->edittop->lineno >= top->lineno && 257 openfile->edittop->lineno <= bot->lineno); 258 #ifndef NANO_TINY 259 bool same_line = (openfile->mark == top); 260 bool post_marked = (openfile->mark && (openfile->mark->lineno > top->lineno || 261 (same_line && openfile->mark_x > top_x))); 262 static bool inherited_anchor = FALSE; 263 bool had_anchor = top->has_anchor; 264 265 if (top == bot && top_x == bot_x) 266 return; 267 268 if (top != bot) 269 for (linestruct *line = top->next; line != bot->next; line = line->next) 270 had_anchor |= line->has_anchor; 271 #endif 272 273 if (top == bot) { 274 taken = make_new_node(NULL); 275 taken->data = measured_copy(top->data + top_x, bot_x - top_x); 276 memmove(top->data + top_x, top->data + bot_x, strlen(top->data + bot_x) + 1); 277 last = taken; 278 } else if (top_x == 0 && bot_x == 0) { 279 taken = top; 280 last = make_new_node(NULL); 281 last->data = copy_of(""); 282 #ifndef NANO_TINY 283 last->has_anchor = bot->has_anchor; 284 #endif 285 last->prev = bot->prev; 286 bot->prev->next = last; 287 last->next = NULL; 288 289 bot->prev = top->prev; 290 if (top->prev) 291 top->prev->next = bot; 292 else 293 openfile->filetop = bot; 294 295 openfile->current = bot; 296 } else { 297 taken = make_new_node(NULL); 298 taken->data = copy_of(top->data + top_x); 299 taken->next = top->next; 300 top->next->prev = taken; 301 302 top->next = bot->next; 303 if (bot->next) 304 bot->next->prev = top; 305 306 top->data = nrealloc(top->data, top_x + strlen(bot->data + bot_x) + 1); 307 strcpy(top->data + top_x, bot->data + bot_x); 308 309 last = bot; 310 last->data[bot_x] = '\0'; 311 last->next = NULL; 312 313 openfile->current = top; 314 } 315 316 /* Subtract the size of the excised text from the buffer size. */ 317 openfile->totsize -= number_of_characters_in(taken, last); 318 319 /* If the cutbuffer is currently empty, just move all the text directly 320 * into it; otherwise, append the text to what is already there. */ 321 if (cutbuffer == NULL) { 322 cutbuffer = taken; 323 cutbottom = last; 324 #ifndef NANO_TINY 325 inherited_anchor = taken->has_anchor; 326 #endif 327 } else { 328 cutbottom->data = nrealloc(cutbottom->data, 329 strlen(cutbottom->data) + strlen(taken->data) + 1); 330 strcat(cutbottom->data, taken->data); 331 #ifndef NANO_TINY 332 cutbottom->has_anchor = taken->has_anchor && !inherited_anchor; 333 inherited_anchor |= taken->has_anchor; 334 #endif 335 cutbottom->next = taken->next; 336 delete_node(taken); 337 338 if (cutbottom->next != NULL) { 339 cutbottom->next->prev = cutbottom; 340 cutbottom = last; 341 } 342 } 343 344 openfile->current_x = top_x; 345 346 #ifndef NANO_TINY 347 openfile->current->has_anchor = had_anchor; 348 349 if (post_marked || same_line) 350 openfile->mark = openfile->current; 351 if (post_marked) 352 openfile->mark_x = openfile->current_x; 353 #endif 354 if (openfile->filebot == bot) 355 openfile->filebot = openfile->current; 356 357 renumber_from(openfile->current); 358 359 /* When the beginning of the viewport was inside the excision, adjust. */ 360 if (edittop_inside) { 361 adjust_viewport(STATIONARY); 362 refresh_needed = TRUE; 363 } 364 365 /* If the text doesn't end with a newline, and it should, add one. */ 366 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') 367 new_magicline(); 368 } 369 370 /* Meld the buffer that starts at topline into the current file buffer 371 * at the current cursor position. */ 372 void ingraft_buffer(linestruct *topline) 373 { 374 linestruct *line = openfile->current; 375 size_t length = strlen(line->data); 376 size_t extralen = strlen(topline->data); 377 size_t xpos = openfile->current_x; 378 char *tailtext = copy_of(line->data + xpos); 379 #ifndef NANO_TINY 380 bool mark_follows = (openfile->mark == line && !mark_is_before_cursor()); 381 #endif 382 linestruct *botline = topline; 383 384 while (botline->next != NULL) 385 botline = botline->next; 386 387 /* Add the size of the text to be grafted to the buffer size. */ 388 openfile->totsize += number_of_characters_in(topline, botline); 389 390 if (topline != botline) 391 length = xpos; 392 393 if (extralen > 0) { 394 /* Insert the text of topline at the current cursor position. */ 395 line->data = nrealloc(line->data, length + extralen + 1); 396 memmove(line->data + xpos + extralen, line->data + xpos, length - xpos + 1); 397 strncpy(line->data + xpos, topline->data, extralen); 398 } 399 400 if (topline != botline) { 401 /* When inserting at end-of-buffer, update the relevant pointer. */ 402 if (line->next == NULL) 403 openfile->filebot = botline; 404 405 line->data[xpos + extralen] = '\0'; 406 407 /* Hook the grafted lines in after the current one. */ 408 botline->next = openfile->current->next; 409 if (botline->next) 410 botline->next->prev = botline; 411 openfile->current->next = topline->next; 412 topline->next->prev = openfile->current; 413 414 /* Add the text after the cursor position at the end of botline. */ 415 length = strlen(botline->data); 416 extralen = strlen(tailtext); 417 botline->data = nrealloc(botline->data, length + extralen + 1); 418 strcpy(botline->data + length, tailtext); 419 420 /* Put the cursor at the end of the grafted text. */ 421 openfile->current = botline; 422 openfile->current_x = length; 423 } else 424 openfile->current_x += extralen; 425 426 #ifndef NANO_TINY 427 /* When needed, update the mark's pointer and position. */ 428 if (mark_follows && topline != botline) { 429 openfile->mark = botline; 430 openfile->mark_x += length - xpos; 431 } else if (mark_follows) 432 openfile->mark_x += extralen; 433 #endif 434 435 delete_node(topline); 436 free(tailtext); 437 438 renumber_from(line); 439 440 /* If the text doesn't end with a newline, and it should, add one. */ 441 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') 442 new_magicline(); 443 } 444 445 /* Meld a copy of the given buffer into the current file buffer. */ 446 void copy_from_buffer(linestruct *somebuffer) 447 { 448 #ifdef ENABLE_COLOR 449 size_t threshold = openfile->edittop->lineno + editwinrows - 1; 450 #endif 451 linestruct *the_copy = copy_buffer(somebuffer); 452 453 ingraft_buffer(the_copy); 454 455 #ifdef ENABLE_COLOR 456 if (openfile->current->lineno > threshold || ISSET(SOFTWRAP)) 457 recook = TRUE; 458 else 459 perturbed = TRUE; 460 #endif 461 } 462 463 #ifndef NANO_TINY 464 /* Move all marked text from the current buffer into the cutbuffer. */ 465 void cut_marked_region(void) 466 { 467 linestruct *top, *bot; 468 size_t top_x, bot_x; 469 470 get_region(&top, &top_x, &bot, &bot_x); 471 472 extract_segment(top, top_x, bot, bot_x); 473 474 openfile->placewewant = xplustabs(); 475 } 476 #endif 477 478 /* Move text from the current buffer into the cutbuffer. 479 * If until_eof is TRUE, move all text from the current cursor 480 * position to the end of the file into the cutbuffer. If append 481 * is TRUE (when zapping), always append the cut to the cutbuffer. */ 482 void do_snip(bool marked, bool until_eof, bool append) 483 { 484 linestruct *line = openfile->current; 485 486 #ifndef NANO_TINY 487 keep_cutbuffer &= (openfile->last_action != COPY); 488 #endif 489 490 /* If cuts were not continuous, or when cutting a region, clear the slate. */ 491 if ((marked || until_eof || !keep_cutbuffer) && !append) { 492 free_lines(cutbuffer); 493 cutbuffer = NULL; 494 } 495 496 #ifndef NANO_TINY 497 /* Now move the relevant piece of text into the cutbuffer. */ 498 if (until_eof) 499 extract_segment(openfile->current, openfile->current_x, 500 openfile->filebot, strlen(openfile->filebot->data)); 501 else if (openfile->mark) { 502 cut_marked_region(); 503 openfile->mark = NULL; 504 } else if (ISSET(CUT_FROM_CURSOR)) { 505 /* When not at the end of a line, move the rest of this line into 506 * the cutbuffer. Otherwise, when not at the end of the buffer, 507 * move just the "line separator" into the cutbuffer. */ 508 if (line->data[openfile->current_x] != '\0') 509 extract_segment(line, openfile->current_x, line, strlen(line->data)); 510 else if (openfile->current != openfile->filebot) { 511 extract_segment(line, openfile->current_x, line->next, 0); 512 openfile->placewewant = xplustabs(); 513 } 514 } else 515 #endif 516 { 517 /* When not at end-of-buffer, move one full line into the cutbuffer; 518 * otherwise, move all text until end-of-line into the cutbuffer. */ 519 if (openfile->current != openfile->filebot) 520 extract_segment(line, 0, line->next, 0); 521 else 522 extract_segment(line, 0, line, strlen(line->data)); 523 524 openfile->placewewant = 0; 525 } 526 527 /* After a line operation, future ones should add to the cutbuffer. */ 528 keep_cutbuffer = !marked && !until_eof; 529 530 set_modified(); 531 refresh_needed = TRUE; 532 #ifdef ENABLE_COLOR 533 perturbed = TRUE; 534 #endif 535 } 536 537 /* Move text from the current buffer into the cutbuffer. */ 538 void cut_text(void) 539 { 540 #ifndef NANO_TINY 541 if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL)) 542 return; 543 544 /* Only add a new undo item when the current item is not a CUT or when 545 * the current cut is not contiguous with the previous cutting. */ 546 if (openfile->last_action != CUT || !keep_cutbuffer) { 547 keep_cutbuffer = FALSE; 548 add_undo(CUT, NULL); 549 } 550 551 do_snip(openfile->mark != NULL, FALSE, FALSE); 552 553 update_undo(CUT); 554 #else 555 if (is_cuttable(FALSE)) 556 do_snip(FALSE, FALSE, FALSE); 557 #endif 558 wipe_statusbar(); 559 } 560 561 #ifndef NANO_TINY 562 /* Cut from the current cursor position to the end of the file. */ 563 void cut_till_eof(void) 564 { 565 ran_a_tool = TRUE; 566 567 if (openfile->current->data[openfile->current_x] == '\0' && 568 (openfile->current->next == NULL || 569 (!ISSET(NO_NEWLINES) && openfile->current_x > 0 && 570 openfile->current->next == openfile->filebot))) { 571 statusbar(_("Nothing was cut")); 572 return; 573 } 574 575 add_undo(CUT_TO_EOF, NULL); 576 do_snip(FALSE, TRUE, FALSE); 577 update_undo(CUT_TO_EOF); 578 wipe_statusbar(); 579 } 580 581 /* Erase text (current line or marked region), sending it into oblivion. */ 582 void zap_text(void) 583 { 584 /* Remember the current cutbuffer so it can be restored after the zap. */ 585 linestruct *was_cutbuffer = cutbuffer; 586 587 if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL)) 588 return; 589 590 /* Add a new undo item only when the current item is not a ZAP or when 591 * the current zap is not contiguous with the previous zapping. */ 592 if (openfile->last_action != ZAP || !keep_cutbuffer) 593 add_undo(ZAP, NULL); 594 595 /* Use the cutbuffer from the ZAP undo item, so the cut can be undone. */ 596 cutbuffer = openfile->current_undo->cutbuffer; 597 598 do_snip(openfile->mark != NULL, FALSE, TRUE); 599 600 update_undo(ZAP); 601 wipe_statusbar(); 602 603 cutbuffer = was_cutbuffer; 604 } 605 606 /* Make a copy of the marked region, putting it in the cutbuffer. */ 607 void copy_marked_region(void) 608 { 609 linestruct *topline, *botline, *afterline; 610 char *was_datastart, saved_byte; 611 size_t top_x, bot_x; 612 613 get_region(&topline, &top_x, &botline, &bot_x); 614 615 openfile->last_action = OTHER; 616 keep_cutbuffer = FALSE; 617 openfile->mark = NULL; 618 refresh_needed = TRUE; 619 620 if (topline == botline && top_x == bot_x) { 621 statusbar(_("Copied nothing")); 622 return; 623 } 624 625 /* Make the area that was marked look like a separate buffer. */ 626 afterline = botline->next; 627 botline->next = NULL; 628 saved_byte = botline->data[bot_x]; 629 botline->data[bot_x] = '\0'; 630 was_datastart = topline->data; 631 topline->data += top_x; 632 633 cutbuffer = copy_buffer(topline); 634 635 /* Restore the proper state of the buffer. */ 636 topline->data = was_datastart; 637 botline->data[bot_x] = saved_byte; 638 botline->next = afterline; 639 } 640 #endif /* !NANO_TINY */ 641 642 /* Copy text from the current buffer into the cutbuffer. The text is either 643 * the marked region, the whole line, the text from cursor to end-of-line, 644 * just the line break, or nothing, depending on mode and cursor position. */ 645 void copy_text(void) 646 { 647 bool at_eol = (openfile->current->data[openfile->current_x] == '\0'); 648 bool sans_newline = (ISSET(NO_NEWLINES) && openfile->current->next == NULL); 649 size_t from_x = (ISSET(CUT_FROM_CURSOR)) ? openfile->current_x : 0; 650 linestruct *was_current = openfile->current; 651 linestruct *addition; 652 653 #ifndef NANO_TINY 654 if (openfile->mark || openfile->last_action != COPY) 655 keep_cutbuffer = FALSE; 656 #endif 657 658 if (!keep_cutbuffer) { 659 free_lines(cutbuffer); 660 cutbuffer = NULL; 661 } 662 663 wipe_statusbar(); 664 665 #ifndef NANO_TINY 666 if (openfile->mark) { 667 copy_marked_region(); 668 return; 669 } 670 #endif 671 672 /* When at the very end of the buffer, there is nothing to do. */ 673 if (openfile->current->next == NULL && at_eol && (ISSET(CUT_FROM_CURSOR) || 674 openfile->current_x == 0 || cutbuffer)) { 675 statusbar(_("Copied nothing")); 676 return; 677 } 678 679 addition = make_new_node(NULL); 680 addition->data = copy_of(openfile->current->data + from_x); 681 682 if (ISSET(CUT_FROM_CURSOR)) 683 sans_newline = !at_eol; 684 685 /* Create the cutbuffer OR add to it, depending on the mode, the position 686 * of the cursor, and whether or not the cutbuffer is currently empty. */ 687 if (cutbuffer == NULL && sans_newline) { 688 cutbuffer = addition; 689 cutbottom = addition; 690 } else if (cutbuffer == NULL) { 691 cutbuffer = addition; 692 cutbottom = make_new_node(cutbuffer); 693 cutbottom->data = copy_of(""); 694 cutbuffer->next = cutbottom; 695 } else if (sans_newline) { 696 addition->prev = cutbottom->prev; 697 addition->prev->next = addition; 698 delete_node(cutbottom); 699 cutbottom = addition; 700 } else if (ISSET(CUT_FROM_CURSOR)) { 701 addition->prev = cutbottom; 702 cutbottom->next = addition; 703 cutbottom = addition; 704 } else { 705 addition->prev = cutbottom->prev; 706 addition->prev->next = addition; 707 addition->next = cutbottom; 708 cutbottom->prev = addition; 709 } 710 711 /* When needed and possible, move the cursor to the next line. */ 712 if ((!ISSET(CUT_FROM_CURSOR) || at_eol) && openfile->current->next) { 713 openfile->current = openfile->current->next; 714 openfile->current_x = 0; 715 } else 716 openfile->current_x = strlen(openfile->current->data); 717 718 edit_redraw(was_current, FLOWING); 719 720 #ifndef NANO_TINY 721 openfile->last_action = COPY; 722 #endif 723 keep_cutbuffer = TRUE; 724 } 725 726 /* Copy text from the cutbuffer into the current buffer. */ 727 void paste_text(void) 728 { 729 #if defined(ENABLE_WRAPPING) || !defined(NANO_TINY) 730 /* Remember where the paste started. */ 731 linestruct *was_current = openfile->current; 732 #endif 733 #ifndef NANO_TINY 734 bool had_anchor = was_current->has_anchor; 735 #endif 736 ssize_t was_lineno = openfile->current->lineno; 737 size_t was_leftedge = 0; 738 739 if (cutbuffer == NULL) { 740 statusline(AHEM, _("Cutbuffer is empty")); 741 return; 742 } 743 744 #ifndef NANO_TINY 745 add_undo(PASTE, NULL); 746 747 if (ISSET(SOFTWRAP)) 748 was_leftedge = leftedge_for(xplustabs(), openfile->current); 749 #endif 750 751 /* Add a copy of the text in the cutbuffer to the current buffer 752 * at the current cursor position. */ 753 copy_from_buffer(cutbuffer); 754 755 #ifndef NANO_TINY 756 /* Wipe any anchors in the pasted text, so that they don't proliferate. */ 757 for (linestruct *line = was_current; line != openfile->current->next; line = line->next) 758 line->has_anchor = FALSE; 759 760 was_current->has_anchor = had_anchor; 761 762 update_undo(PASTE); 763 #endif 764 765 #ifdef ENABLE_WRAPPING 766 /* When still on the same line and doing hard-wrapping, limit the width. */ 767 if (openfile->current == was_current && ISSET(BREAK_LONG_LINES)) 768 do_wrap(); 769 #endif 770 771 /* If we pasted less than a screenful, don't center the cursor. */ 772 if (less_than_a_screenful(was_lineno, was_leftedge)) 773 focusing = FALSE; 774 #ifdef ENABLE_COLOR 775 else 776 precalc_multicolorinfo(); 777 #endif 778 779 /* Set the desired x position to where the pasted text ends. */ 780 openfile->placewewant = xplustabs(); 781 782 set_modified(); 783 wipe_statusbar(); 784 refresh_needed = TRUE; 785 }