Index: src/cut.c =================================================================== --- src/cut.c (revision 5049) +++ src/cut.c (working copy) @@ -275,8 +275,10 @@ } #endif /* !NANO_TINY */ + + /* Copy text from the cutbuffer into the current filestruct. */ -void do_uncut_text(void) +void paste_text(void) { assert(openfile->current != NULL && openfile->current->data != NULL); @@ -314,3 +316,40 @@ dump_filestruct_reverse(); #endif } + +/* Copy text from the cutbuffer into the current filestruct + * If needed, wrap the pasted text */ +void do_uncut_text(void) +{ + /* If the cutbuffer is empty, get out. */ + if (cutbuffer == NULL) + return; + +#ifndef DISABLE_WRAPPING + ssize_t startline = openfile->current->lineno; +#endif + + paste_text(); + +#ifndef DISABLE_WRAPPING + if (!ISSET(NO_WRAP)){ + +#ifndef NANO_TINY + add_undo(SPLIT_BEGIN); +#endif + + if(xplustabs() == 0){ + openfile->current = openfile->current->prev; + join_currentline(NULL); + } + + do_wrap( fsfromline(startline), openfile->current->lineno, 0, FALSE); + + openfile->placewewant = xplustabs(); + +#ifndef NANO_TINY + add_undo(SPLIT_END); +#endif + } +#endif +} Index: src/nano.c =================================================================== --- src/nano.c (revision 5049) +++ src/nano.c (working copy) @@ -1657,12 +1657,6 @@ * empty. Note that it should be empty if we're in view * mode. */ if (have_shortcut || get_key_buffer_len() == 0) { -#ifndef DISABLE_WRAPPING - /* If we got a shortcut or toggle, and it's not the shortcut - * for verbatim input, turn off prepending of wrapped text. */ - if (have_shortcut && s->scfunc != do_verbatim_input) - wrap_reset(); -#endif if (kbinput != NULL) { /* Display all the characters in the input buffer at @@ -2004,7 +1998,7 @@ output[i] = '\n'; /* Newline to Enter, if needed. */ else if (output[i] == '\n') { - do_enter(FALSE); + do_enter_void(); i++; continue; } @@ -2062,8 +2056,7 @@ #ifndef DISABLE_WRAPPING /* If we're wrapping text, we need to call edit_refresh(). */ if (!ISSET(NO_WRAP)) - if (do_wrap(openfile->current)) - edit_refresh_needed = TRUE; + do_wrap_void(); #endif #ifndef DISABLE_COLOR Index: src/proto.h =================================================================== --- src/proto.h (revision 5049) +++ src/proto.h (working copy) @@ -270,6 +270,7 @@ void do_cut_till_eof(void); #endif void do_uncut_text(void); +void paste_text(void); /* All functions in files.c. */ void make_new_buffer(void); @@ -643,15 +644,17 @@ void do_undo(void); void do_redo(void); #endif -void do_enter(bool undoing); +size_t do_enter(bool undoing, bool indent_newline, ssize_t const indent_len); void do_enter_void(void); +void add_break(bool undoing, ssize_t const indent_len); #ifndef NANO_TINY RETSIGTYPE cancel_command(int signal); bool execute_command(const char *command); #endif #ifndef DISABLE_WRAPPING -void wrap_reset(void); -bool do_wrap(filestruct *line); +void do_wrap_void(void); +void do_wrap(filestruct *line, ssize_t until_lineno, const size_t quote_len, bool justify_paragraph); +void join_currentline(size_t *old_x); #endif #if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY) ssize_t break_line(const char *line, ssize_t goal @@ -662,6 +665,7 @@ #endif #if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY) size_t indent_length(const char *line); +bool is_empty(filestruct *line); #endif #ifndef DISABLE_JUSTIFY void justify_format(filestruct *paragraph, size_t skip); Index: src/text.c =================================================================== --- src/text.c (revision 5049) +++ src/text.c (working copy) @@ -36,10 +36,7 @@ /* The PID of the forked process in execute_command(), for use * with the cancel_command() signal handler. */ #endif -#ifndef DISABLE_WRAPPING -static bool prepend_wrap = FALSE; - /* Should we prepend wrapped text to the next line? */ -#endif + #ifndef DISABLE_JUSTIFY static filestruct *jusbottom = NULL; /* Pointer to the end of the justify buffer. */ @@ -607,7 +604,7 @@ case ENTER: redidmsg = _("line break"); goto_line_posx(u->lineno, u->begin); - do_enter(TRUE); + add_break(TRUE, u->mark_begin_x); break; #ifndef DISABLE_WRAPPING case SPLIT_BEGIN: @@ -672,7 +669,7 @@ #endif /* !NANO_TINY */ /* Someone hits Enter *gasp!* */ -void do_enter(bool undoing) +size_t do_enter(bool undoing, bool indent_newline, ssize_t const indent_len) { filestruct *newnode = make_new_node(openfile->current); size_t extra = 0; @@ -684,11 +681,11 @@ add_undo(ENTER); /* Do auto-indenting, like the neolithic Turbo Pascal editor. */ - if (ISSET(AUTOINDENT)) { + if (indent_newline) { /* If we are breaking the line in the indentation, the new * indentation should have only current_x characters, and * current_x should not change. */ - extra = indent_length(openfile->current->data); + extra = (indent_len == -1)? indent_length(openfile->current->data) : indent_len; if (extra > openfile->current_x) extra = openfile->current_x; } @@ -698,7 +695,7 @@ strcpy(&newnode->data[extra], openfile->current->data + openfile->current_x); #ifndef NANO_TINY - if (ISSET(AUTOINDENT)) { + if (indent_newline) { strncpy(newnode->data, openfile->current->data, extra); openfile->totsize += extra; } @@ -733,12 +730,21 @@ #endif edit_refresh_needed = TRUE; + + return indent_newline? extra : indent_len; } +/* add a break to the current line at current_x and + and prepend the new line with current->data[indent_len] */ +inline void add_break(bool undoing, ssize_t const indent_len) +{ + do_enter(undoing, TRUE, indent_len); +} + /* Need this again... */ -void do_enter_void(void) +inline void do_enter_void(void) { - do_enter(FALSE); + do_enter(FALSE, ISSET(AUTOINDENT), -1); } #ifndef NANO_TINY @@ -1099,114 +1105,70 @@ #endif /* !NANO_TINY */ #ifndef DISABLE_WRAPPING -/* Unset the prepend_wrap flag. We need to do this as soon as we do - * something other than type text. */ -void wrap_reset(void) -{ - prepend_wrap = FALSE; -} -/* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */ -bool do_wrap(filestruct *line) +/* Return the index where the given line should be broken, or 0 if the + * line should not be broken. */ +ssize_t get_wrap_index(filestruct const *const line , ssize_t indent_len) { - size_t line_len; - /* The length of the line we wrap. */ - ssize_t wrap_loc; - /* The index of line->data where we wrap. */ -#ifndef NANO_TINY - const char *indent_string = NULL; - /* Indentation to prepend to the new line. */ - size_t indent_len = 0; - /* The length of indent_string. */ -#endif - const char *after_break; - /* The text after the wrap point. */ - size_t after_break_len; - /* The length of after_break. */ - const char *next_line = NULL; - /* The next line, minus indentation. */ - size_t next_line_len = 0; - /* The length of next_line. */ + if(indent_len < 0) + indent_len = 0; - /* There are three steps. First, we decide where to wrap. Then, we - * create the new wrap line. Finally, we clean up. */ + ssize_t wrap_loc = -1; + size_t leading_spaces_len = 0; + char const *buf = line->data + indent_len; + size_t line_len = strlen(line->data); - /* Step 1, finding where to wrap. We are going to add a new line - * after a blank character. In this step, we call break_line() to - * get the location of the last blank we can break the line at, and - * set wrap_loc to the location of the character after it, so that - * the blank is preserved at the end of the line. - * - * If there is no legal wrap point, or we reach the last character - * of the line while trying to find one, we should return without - * wrapping. Note that if autoindent is turned on, we don't break - * at the end of it! */ - assert(line != NULL && line->data != NULL); + assert(line_len > indent_len); - /* Save the length of the line. */ - line_len = strlen(line->data); - - /* Find the last blank where we can break the line. */ - wrap_loc = break_line(line->data, fill + /* Find the last blank where we can break the line. + * but do not consider leading spaces as a location */ + while( *buf != '\0' && (wrap_loc = break_line(buf, fill - (indent_len + leading_spaces_len) #ifndef DISABLE_HELP , FALSE #endif - ); + )) == 0 ){ + leading_spaces_len += parse_mbchar(buf, NULL, NULL); + buf = line->data + indent_len + leading_spaces_len; + } - /* If we couldn't break the line, or we've reached the end of it, we - * don't wrap. */ - if (wrap_loc == -1 || line->data[wrap_loc] == '\0') - return FALSE; + /* , we don't wrap. */ + if (wrap_loc == -1) + return 0; + wrap_loc += (indent_len + leading_spaces_len); + + if (wrap_loc >= line_len){ + size_t wrap_column = strnlenpt(line->data, wrap_loc); + if( wrap_column <= fill) + return 0; + } + /* Otherwise, move forward to the character just after the blank. */ wrap_loc += move_mbright(line->data + wrap_loc, 0); - /* If we've reached the end of the line, we don't wrap. */ - if (line->data[wrap_loc] == '\0') - return FALSE; + /* After the move, check again. If we've reached the end of the line, + * we don't wrap. */ + if (wrap_loc >= line_len) + return line_len; -#ifndef NANO_TINY - /* If autoindent is turned on, and we're on the character just after - * the indentation, we don't wrap. */ - if (ISSET(AUTOINDENT)) { - /* Get the indentation of this line. */ - indent_string = line->data; - indent_len = indent_length(indent_string); - - if (wrap_loc == indent_len) - return FALSE; + return wrap_loc; } - add_undo(SPLIT_BEGIN); -#endif +/* join line with line->next + old_x represents the x_location of line->next + adjusted for the new location that results from + the join with line */ +void join_currentline(size_t *old_x){ + filestruct *line = openfile->current; + if(line == openfile->filebot) return; - size_t old_x = openfile->current_x; - filestruct * oldLine = openfile->current; - openfile->current = line; + size_t line_len = strlen(line->data); + const char *end = line->data + move_mbleft(line->data, line_len); - /* 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) - * and the text of the next line, if they can fit without wrapping, - * the next line exists, and the prepend_wrap flag is set. */ - - /* after_break is the text that will be wrapped to the next line. */ - after_break = line->data + wrap_loc; - after_break_len = line_len - wrap_loc; - - assert(strlen(after_break) == after_break_len); - - /* We prepend the wrapped text to the next line, if the prepend_wrap - * flag is set, there is a next line, and prepending would not make - * the line too long. */ - if (prepend_wrap && line != openfile->filebot) { - 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 + /* If the line doesn't end in a blank, make sure it ends in a * space. */ if (!is_blank_mbchar(end)) { #ifndef NANO_TINY @@ -1216,8 +1178,7 @@ line->data = charealloc(line->data, line_len + 1); line->data[line_len - 1] = ' '; line->data[line_len] = '\0'; - after_break = line->data + wrap_loc; - after_break_len++; + openfile->totsize++; openfile->current_x++; #ifndef NANO_TINY @@ -1225,39 +1186,138 @@ #endif } - next_line = line->next->data; - next_line_len = strlen(next_line); + if(old_x != NULL) + *old_x += line_len; - if (after_break_len + next_line_len <= fill) { /* 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])) + while (is_blank_mbchar(&line->data[openfile->current_x])){ + if(old_x != NULL) + *old_x -= parse_mbchar(&line->data[openfile->current_x], NULL, NULL); do_delete(); + } renumber(line); } + + +ssize_t copy_indent_string(filestruct *line, const size_t quote_len, bool cut_indent) +{ + ssize_t indent_len = quote_len + indent_length(line->data + quote_len); + size_t old_x = openfile->current_x; + filestruct *oldline = openfile->current; + + openfile->mark_set = TRUE; + openfile->mark_begin = line; + openfile->mark_begin_x = 0; + openfile->current = line; + openfile->current_x = indent_len; + + if(cut_indent){ + do_cut_text_void(); + openfile->current = oldline; + } else + do_copy_text(); + + openfile->current_x = old_x; + + return indent_len; } +/* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */ +void do_wrap(filestruct *line, ssize_t until_lineno, const size_t quote_len, bool justify_paragraph) +{ + ssize_t wrap_loc; + /* The index of line->data where we wrap. */ + + size_t old_x = openfile->current_x; + filestruct *oldline = openfile->current; + ssize_t indent_len = -1; + + bool prepend_wrap = FALSE; + bool next_line_inpar = TRUE; + + assert(line != NULL && line->data != NULL); + + while (line->lineno <= until_lineno){ + + openfile->current = line; + + /* Find the last blank where we can break the line. */ + wrap_loc = get_wrap_index(line, indent_len); + + if (line->lineno == until_lineno){ + /* If we couldn't break the line, or we've reached the end of it, we + * don't wrap. */ + if (wrap_loc == 0 || line->data[wrap_loc] == '\0') + goto Exit; + + next_line_inpar = line->next && !begpar(line->next) && !is_empty(line->next); + } + + if (justify_paragraph) + indent_len = copy_indent_string(next_line_inpar? line->next : line, quote_len, next_line_inpar); + + if (next_line_inpar){ + + if (oldline == line->next){ + join_currentline(&old_x); + oldline = line; + } else + join_currentline(NULL); + + until_lineno--; + } else /* update the line we're pointing at, it may be invalid after the call to copy_indent_string */ + line = openfile->current; + + if (wrap_loc == 0) + wrap_loc = get_wrap_index(line, indent_len); + + while (wrap_loc > indent_len) { + prepend_wrap = prepend_wrap || (old_x < wrap_loc && oldline == line); /* Go to the wrap location and split the line there. */ openfile->current_x = wrap_loc; - do_enter(FALSE); + /* If indent_len is -1 and justify_paragraph is FALSE then indent_len will be determined + in the call to do_enter and stored for subsequent iterations of the loop. + If justify_paragraph is TRUE then indent_len will not be used or effected by do_enter */ + indent_len = do_enter(FALSE, !justify_paragraph, indent_len); + until_lineno++; - if (old_x < wrap_loc) { - openfile->current_x = old_x; - openfile->current = oldLine; - prepend_wrap = TRUE; - } else { - openfile->current_x += (old_x - wrap_loc); - prepend_wrap = FALSE; + /* paste the cutbuffer -- it contains the indent string */ + if (justify_paragraph) + paste_text(); + + if (!prepend_wrap && oldline == line){ + old_x = openfile->current_x + old_x - wrap_loc; + oldline = openfile->current; } + line = openfile->current; + assert(line != NULL && line->data != NULL); + /* Find the last blank where we can break the line. */ + wrap_loc = get_wrap_index(line, indent_len); + } + } + +Exit: + openfile->current = oldline; + openfile->current_x = old_x; openfile->placewewant = xplustabs(); +} +void do_wrap_void(void) +{ #ifndef NANO_TINY + add_undo(SPLIT_BEGIN); +#endif + + do_wrap(openfile->current, openfile->current->lineno, 0, FALSE); + +#ifndef NANO_TINY add_undo(SPLIT_END); #endif - return TRUE; + edit_refresh(); } #endif /* !DISABLE_WRAPPING */ @@ -1282,6 +1342,7 @@ /* Current column position in line. */ int char_len = 0; /* Length of current character, in bytes. */ + bool non_blank_found = FALSE; assert(line != NULL); @@ -1293,13 +1354,15 @@ || (newln && *line == '\n') #endif ) { + if(non_blank_found) blank_loc = cur_loc; #ifndef DISABLE_HELP if (newln && *line == '\n') break; #endif - } + } else + non_blank_found = TRUE; line += char_len; cur_loc += char_len; @@ -1361,35 +1424,36 @@ } #endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */ -#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY) +#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY) || !defined(DISABLE_WRAPPING) || !defined(DISABLE_WRAPJUSTIFY) /* The "indentation" of a line is the whitespace between the quote part * and the non-whitespace of the line. */ size_t indent_length(const char *line) { size_t len = 0; - char *blank_mb; int blank_mb_len; assert(line != NULL); - blank_mb = charalloc(mb_cur_max()); - while (*line != '\0') { - blank_mb_len = parse_mbchar(line, blank_mb, NULL); + blank_mb_len = parse_mbchar(line, NULL, NULL); - if (!is_blank_mbchar(blank_mb)) + if (!is_blank_mbchar(line)) break; line += blank_mb_len; len += blank_mb_len; } - free(blank_mb); - return len; } -#endif /* !NANO_TINY || !DISABLE_JUSTIFY */ +/* Test if the line contains only blank chars */ +inline bool is_empty(filestruct *line) +{ + return indent_length(line->data) == strlen(line->data); + } +#endif /* !NANO_TINY || !DISABLE_JUSTIFY || !DISABLE_WRAPPING || !DISABLE_WRAPJUSTIFY */ + #ifndef DISABLE_JUSTIFY /* justify_format() replaces blanks with spaces and multiple spaces by 1 * (except it maintains up to 2 after a character in punct optionally