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/nano.h =================================================================== --- src/nano.h (revision 5049) +++ src/nano.h (working copy) @@ -191,6 +191,9 @@ #ifndef DISABLE_WRAPPING SPLIT_BEGIN, SPLIT_END, #endif +#ifndef DISABLE_JUSTIFY + JUSTIFY_BEGIN, JUSTIFY_END, +#endif JOIN, PASTE, INSERT, ENTER, OTHER } undo_type; 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,9 +665,9 @@ #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); size_t quote_length(const char *line); bool quotes_match(const char *a_line, size_t a_quote, const char *b_line); @@ -672,8 +675,7 @@ *b_line, size_t b_indent); bool begpar(const filestruct *const foo); bool inpar(const filestruct *const foo); -void backup_lines(filestruct *first_line, size_t par_len); -bool find_paragraph(size_t *const quote, size_t *const par); +bool find_paragraph(size_t *const quote, filestruct **const last_par_line); void do_justify(bool full_justify); void do_justify_void(void); void do_full_justify(void); Index: src/text.c =================================================================== --- src/text.c (revision 5049) +++ src/text.c (working copy) @@ -36,14 +36,6 @@ /* 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. */ -#endif #ifndef NANO_TINY /* Toggle the mark. */ @@ -465,6 +457,19 @@ f->data = data; goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); break; +#ifndef DISABLE_JUSTIFY + case JUSTIFY_END: + undidmsg = _("text justify"); + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = openfile->current_undo->next; + openfile->last_action = OTHER; + while (openfile->current_undo->type != JUSTIFY_BEGIN) + do_undo(); + u = openfile->current_undo; + f = openfile->current; + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); + break; +#endif #ifndef DISABLE_WRAPPING case SPLIT_END: undidmsg = _("line wrap"); @@ -607,8 +612,20 @@ 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_JUSTIFY + case JUSTIFY_BEGIN: + redidmsg = _("text justify"); + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = u; + openfile->last_action = OTHER; + while (openfile->current_undo->type != JUSTIFY_END) + do_redo(); + u = openfile->current_undo; + goto_line_posx(u->lineno, u->begin); + break; +#endif /*DISABLE_JUSTIFY*/ #ifndef DISABLE_WRAPPING case SPLIT_BEGIN: redidmsg = _("line wrap"); @@ -672,7 +689,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 +701,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 +715,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 +750,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 @@ -916,6 +942,11 @@ } current_action = u->type = JOIN; break; +#ifndef DISABLE_JUSTIFY + case JUSTIFY_BEGIN: + case JUSTIFY_END: + break; +#endif #ifndef DISABLE_WRAPPING case SPLIT_BEGIN: current_action = fs->undotop->type; @@ -1082,6 +1113,11 @@ case ENTER: u->mark_begin_x = fs->current_x; break; +#ifndef DISABLE_JUSTIFY + case JUSTIFY_BEGIN: + case JUSTIFY_END: + break; +#endif #ifndef DISABLE_WRAPPING case SPLIT_BEGIN: case SPLIT_END: @@ -1099,114 +1135,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 +1208,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 +1216,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 +1372,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 +1384,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,190 +1454,37 @@ } #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 */ -#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 - * followed by a character in brackets, and removes all from the end). - * - * justify_format() might make paragraph->data shorter, and change the - * actual pointer with null_at(). - * - * justify_format() will not look at the first skip characters of - * paragraph. skip should be at most strlen(paragraph->data). The - * character at paragraph[skip + 1] must not be blank. */ -void justify_format(filestruct *paragraph, size_t skip) +/* Test if the line contains only blank chars */ +inline bool is_empty(filestruct *line) { - char *end, *new_end, *new_paragraph_data; - size_t shift = 0; -#ifndef NANO_TINY - size_t mark_shift = 0; -#endif - - /* These four asserts are assumptions about the input data. */ - assert(paragraph != NULL); - assert(paragraph->data != NULL); - assert(skip < strlen(paragraph->data)); - assert(!is_blank_mbchar(paragraph->data + skip)); - - end = paragraph->data + skip; - new_paragraph_data = charalloc(strlen(paragraph->data) + 1); - strncpy(new_paragraph_data, paragraph->data, skip); - new_end = new_paragraph_data + skip; - - while (*end != '\0') { - int end_len; - - /* If this character is blank, change it to a space if - * necessary, and skip over all blanks after it. */ - if (is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); - - *new_end = ' '; - new_end++; - end += end_len; - - while (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); - - end += end_len; - shift += end_len; - -#ifndef NANO_TINY - /* Keep track of the change in the current line. */ - if (openfile->mark_set && openfile->mark_begin == - paragraph && openfile->mark_begin_x >= end - - paragraph->data) - mark_shift += end_len; -#endif + return indent_length(line->data) == strlen(line->data); } - /* If this character is punctuation optionally followed by a - * bracket and then followed by blanks, change no more than two - * of the blanks to spaces if necessary, and skip over all - * blanks after them. */ - } else if (mbstrchr(punct, end) != NULL) { - end_len = parse_mbchar(end, NULL, NULL); +#endif /* !NANO_TINY || !DISABLE_JUSTIFY || !DISABLE_WRAPPING || !DISABLE_WRAPJUSTIFY */ - while (end_len > 0) { - *new_end = *end; - new_end++; - end++; - end_len--; - } - - if (*end != '\0' && mbstrchr(brackets, end) != NULL) { - end_len = parse_mbchar(end, NULL, NULL); - - while (end_len > 0) { - *new_end = *end; - new_end++; - end++; - end_len--; - } - } - - if (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); - - *new_end = ' '; - new_end++; - end += end_len; - } - - if (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); - - *new_end = ' '; - new_end++; - end += end_len; - } - - while (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); - - end += end_len; - shift += end_len; - -#ifndef NANO_TINY - /* Keep track of the change in the current line. */ - if (openfile->mark_set && openfile->mark_begin == - paragraph && openfile->mark_begin_x >= end - - paragraph->data) - mark_shift += end_len; -#endif - } - /* If this character is neither blank nor punctuation, leave it - * unchanged. */ - } else { - end_len = parse_mbchar(end, NULL, NULL); - - while (end_len > 0) { - *new_end = *end; - new_end++; - end++; - end_len--; - } - } - } - - assert(*end == '\0'); - - *new_end = *end; - - /* If there are spaces at the end of the line, remove them. */ - while (new_end > new_paragraph_data + skip && - *(new_end - 1) == ' ') { - new_end--; - shift++; - } - - if (shift > 0) { - openfile->totsize -= shift; - null_at(&new_paragraph_data, new_end - new_paragraph_data); - free(paragraph->data); - paragraph->data = new_paragraph_data; - -#ifndef NANO_TINY - /* Adjust the mark coordinates to compensate for the change in - * the current line. */ - if (openfile->mark_set && openfile->mark_begin == paragraph) { - openfile->mark_begin_x -= mark_shift; - if (openfile->mark_begin_x > new_end - new_paragraph_data) - openfile->mark_begin_x = new_end - new_paragraph_data; - } -#endif - } else - free(new_paragraph_data); -} - +#ifndef DISABLE_JUSTIFY /* The "quote part" of a line is the largest initial substring matching * the quote string. This function returns the length of the quote part * of the given line. @@ -1671,112 +1611,24 @@ quote_len)] != '\0'); } -/* Move the next par_len lines, starting with first_line, into the - * justify buffer, leaving copies of those lines in place. Assume that - * par_len is greater than zero, and that there are enough lines after - * first_line. */ -void backup_lines(filestruct *first_line, size_t par_len) -{ - 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 = openfile->current_x; - ssize_t fl_lineno_save = first_line->lineno; - ssize_t edittop_lineno_save = openfile->edittop->lineno; - ssize_t current_lineno_save = openfile->current->lineno; -#ifndef NANO_TINY - bool old_mark_set = openfile->mark_set; - ssize_t mb_lineno_save = 0; - size_t mark_begin_x_save = 0; - - if (old_mark_set) { - mb_lineno_save = openfile->mark_begin->lineno; - mark_begin_x_save = openfile->mark_begin_x; - } -#endif - - /* par_len will be one greater than the number of lines between - * current and filebot if filebot is the last line in the - * paragraph. */ - assert(par_len > 0 && openfile->current->lineno + par_len <= - openfile->filebot->lineno + 1); - - /* Move bot down par_len lines to the line after the last line of - * the paragraph, if there is one. */ - for (i = par_len; i > 0 && bot != openfile->filebot; i--) - bot = bot->next; - - /* Move the paragraph from the current buffer's filestruct to the - * justify buffer. */ - move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot, - (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0); - - /* Copy the paragraph back to the current buffer's filestruct from - * the justify buffer. */ - copy_from_filestruct(jusbuffer); - - /* Move upward from the last line of the paragraph to the first - * line, putting first_line, edittop, current, and mark_begin at the - * same lines in the copied paragraph that they had in the original - * paragraph. */ - if (openfile->current != openfile->fileage) { - top = openfile->current->prev; -#ifndef NANO_TINY - if (old_mark_set && - openfile->current->lineno == mb_lineno_save) { - openfile->mark_begin = openfile->current; - openfile->mark_begin_x = mark_begin_x_save; - } -#endif - } else - top = openfile->current; - for (i = par_len; i > 0 && top != NULL; i--) { - if (top->lineno == fl_lineno_save) - first_line = top; - if (top->lineno == edittop_lineno_save) - openfile->edittop = top; - if (top->lineno == current_lineno_save) - openfile->current = top; -#ifndef NANO_TINY - if (old_mark_set && top->lineno == mb_lineno_save) { - openfile->mark_begin = top; - openfile->mark_begin_x = mark_begin_x_save; - } -#endif - top = top->prev; - } - - /* Put current_x at the same place in the copied paragraph that it - * had in the original paragraph. */ - openfile->current_x = current_x_save; - - set_modified(); -} - /* Find the beginning of the current paragraph if we're in one, or the * beginning of the next paragraph if we're not. Afterwards, save the - * quote length and paragraph length in *quote and *par. Return TRUE if - * we found a paragraph, and FALSE if there was an error or we didn't - * find a paragraph. + * quote length and the last line of the paragraph in *quote and + * *last_par_line. Return TRUE if we found a paragraph, and FALSE if + * there was an error or we didn't find a paragraph. * * See the comment at begpar() for more about when a line is the * beginning of a paragraph. */ -bool find_paragraph(size_t *const quote, size_t *const par) +bool find_paragraph(size_t *const quote, filestruct **const last_par_line) { - size_t quote_len; - /* Length of the initial quotation of the paragraph we search - * for. */ - size_t par_len; - /* Number of lines in the paragraph we search for. */ filestruct *current_save; /* The line at the beginning of the paragraph we search for. */ ssize_t current_y_save; /* The y-coordinate at the beginning of the paragraph we search * for. */ + assert(quote != NULL && last_par_line != NULL); + #ifdef HAVE_REGEX_H if (quoterc != 0) { statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr); @@ -1822,27 +1674,21 @@ /* Now current is the first line of the paragraph. Set quote_len to * the quotation length of that line, and set par_len to the number * of lines in this paragraph. */ - quote_len = quote_length(openfile->current->data); + *quote = quote_length(openfile->current->data); current_save = openfile->current; current_y_save = openfile->current_y; do_para_end(FALSE); - par_len = openfile->current->lineno - current_save->lineno; /* If we end up past the beginning of the line, it means that we're * at the end of the last line of the file, and the line isn't * blank, in which case the last line of the file is part of the * paragraph. */ - if (openfile->current_x > 0) - par_len++; + *last_par_line = (openfile->current_x > 0)? + openfile->current : openfile->current->prev; + openfile->current = current_save; openfile->current_y = current_y_save; - /* Save the values of quote_len and par_len. */ - assert(quote != NULL && par != NULL); - - *quote = quote_len; - *par = par_len; - return TRUE; } @@ -1850,32 +1696,16 @@ * the current paragraph. */ void do_justify(bool full_justify) { - filestruct *first_par_line = NULL; - /* Will be the first line of the justified paragraph(s), if any. - * For restoring after unjustify. */ - filestruct *last_par_line = NULL; - /* Will be the line after the last line of the justified - * paragraph(s), if any. Also for restoring after unjustify. */ - bool filebot_inpar = FALSE; - /* Whether the text at filebot is part of the current + filestruct *curr_last_par_line = NULL; + /* The last line of the current paragraph. */ + size_t quote_len; + /* Length of the initial quotation of the current * paragraph. */ + filestruct *line_after_par = NULL; + /* The next line after the end of the current paragraph. */ - /* We save these variables to be restored if the user - * unjustifies. */ - filestruct *edittop_save = openfile->edittop; - filestruct *current_save = openfile->current; - size_t current_x_save = openfile->current_x; - size_t pww_save = openfile->placewewant; - size_t totsize_save = openfile->totsize; -#ifndef NANO_TINY - filestruct *mark_begin_save = openfile->mark_begin; - size_t mark_begin_x_save = openfile->mark_begin_x; -#endif - bool modified_save = openfile->modified; + add_undo(JUSTIFY_BEGIN); - int kbinput; - const sc *s; - /* Move to the beginning of the current line, so that justifying at * the end of the last line of the file, if that line isn't blank, * will work the first time through. */ @@ -1885,386 +1715,31 @@ if (full_justify) openfile->current = openfile->fileage; -#ifndef NANO_TINY - allow_pending_sigwinch(FALSE); -#endif - while (TRUE) { - size_t i; - /* Generic loop variable. */ - filestruct *curr_first_par_line; - /* The first line of the current paragraph. */ - size_t quote_len; - /* Length of the initial quotation of the current - * paragraph. */ - size_t indent_len; - /* Length of the initial indentation of the current - * paragraph. */ - size_t par_len; - /* Number of lines in the current paragraph. */ - ssize_t break_pos; - /* Where we will break lines. */ - char *indent_string; - /* The first indentation that doesn't match the initial - * indentation of the current paragraph. This is put at the - * beginning of every line broken off the first justified - * line of the paragraph. Note that this works because a - * paragraph can only contain two indentations at most: the - * initial one, and a different one starting on a line after - * the first. See the comment at begpar() for more about - * when a line is part of a paragraph. */ - /* Find the first line of the paragraph to be justified. That - * is the start of this paragraph if we're in one, or the start - * of the next otherwise. Save the quote length and paragraph - * length (number of lines). Don't refresh the screen yet, - * since we'll do that after we justify. - * - * If the search failed, we do one of two things. If we're - * justifying the whole file, and we've found at least one - * paragraph, it means that we should justify all the way to the - * last line of the file, so set the last line of the text to be - * justified to the last line of the file and break out of the - * loop. Otherwise, it means that there are no paragraph(s) to - * justify, so refresh the screen and get out. */ - if (!find_paragraph("e_len, &par_len)) { - if (full_justify && first_par_line != NULL) { - last_par_line = openfile->filebot; + if (!find_paragraph("e_len, &curr_last_par_line) ) break; - } else { - edit_refresh_needed = TRUE; - return; - } - } + line_after_par = (curr_last_par_line == openfile->filebot)? + curr_last_par_line : curr_last_par_line->next; + /* openfile->current will have been set to the first line + * of the current paragraph */ + do_wrap(openfile->current, curr_last_par_line->lineno, quote_len, TRUE); - /* par_len will be one greater than the number of lines between - * current and filebot if filebot is the last line in the - * paragraph. Set filebot_inpar to TRUE if this is the case. */ - filebot_inpar = (openfile->current->lineno + par_len == - openfile->filebot->lineno + 1); - - /* If we haven't already done it, move the original paragraph(s) - * to the justify buffer, splice a copy of the original - * paragraph(s) into the file in the same place, and set - * first_par_line to the first line of the copy. */ - if (first_par_line == NULL) { - backup_lines(openfile->current, full_justify ? - openfile->filebot->lineno - openfile->current->lineno + - ((openfile->filebot->data[0] != '\0') ? 1 : 0) : - par_len); - first_par_line = openfile->current; - } - - /* Set curr_first_par_line to the first line of the current - * paragraph. */ - curr_first_par_line = openfile->current; - - /* Initialize indent_string to a blank string. */ - indent_string = mallocstrcpy(NULL, ""); - - /* Find the first indentation in the paragraph that doesn't - * match the indentation of the first line, and save it in - * indent_string. If all the indentations are the same, save - * the indentation of the first line in indent_string. */ - { - const filestruct *indent_line = openfile->current; - bool past_first_line = FALSE; - - for (i = 0; i < par_len; i++) { - indent_len = quote_len + - indent_length(indent_line->data + quote_len); - - if (indent_len != strlen(indent_string)) { - indent_string = mallocstrncpy(indent_string, - indent_line->data, indent_len + 1); - indent_string[indent_len] = '\0'; - - if (past_first_line) - break; - } - - if (indent_line == openfile->current) - past_first_line = TRUE; - - indent_line = indent_line->next; - } - } - - /* Now tack all the lines of the paragraph together, skipping - * the quoting and indentation on all lines after the first. */ - for (i = 0; i < par_len - 1; i++) { - filestruct *next_line = openfile->current->next; - size_t line_len = strlen(openfile->current->data); - size_t next_line_len = - strlen(openfile->current->next->data); - - indent_len = quote_len + - indent_length(openfile->current->next->data + - quote_len); - - next_line_len -= indent_len; - openfile->totsize -= indent_len; - - /* We're just about to tack the next line onto this one. If - * this line isn't empty, make sure it ends in a space. */ - if (line_len > 0 && - openfile->current->data[line_len - 1] != ' ') { - line_len++; - openfile->current->data = - charealloc(openfile->current->data, - line_len + 1); - openfile->current->data[line_len - 1] = ' '; - openfile->current->data[line_len] = '\0'; - openfile->totsize++; - } - - openfile->current->data = - charealloc(openfile->current->data, line_len + - next_line_len + 1); - strcat(openfile->current->data, next_line->data + - indent_len); - - /* Don't destroy edittop or filebot! */ - if (next_line == openfile->edittop) - openfile->edittop = openfile->current; - if (next_line == openfile->filebot) - openfile->filebot = openfile->current; - -#ifndef NANO_TINY - /* Adjust the mark coordinates to compensate for the change - * in the next line. */ - if (openfile->mark_set && openfile->mark_begin == - next_line) { - openfile->mark_begin = openfile->current; - openfile->mark_begin_x += line_len - indent_len; - } -#endif - - unlink_node(next_line); - delete_node(next_line); - - /* If we've removed the next line, we need to go through - * this line again. */ - i--; - - par_len--; - openfile->totsize--; - } - - /* Call justify_format() on the paragraph, which will remove - * excess spaces from it and change all blank characters to - * spaces. */ - justify_format(openfile->current, quote_len + - indent_length(openfile->current->data + quote_len)); - - while (par_len > 0 && strlenpt(openfile->current->data) > - fill) { - size_t line_len = strlen(openfile->current->data); - - indent_len = strlen(indent_string); - - /* If this line is too long, try to wrap it to the next line - * to make it short enough. */ - break_pos = break_line(openfile->current->data + indent_len, - fill - strnlenpt(openfile->current->data, indent_len) -#ifndef DISABLE_HELP - , FALSE -#endif - ); - - /* We can't break the line, or don't need to, so get out. */ - if (break_pos == -1 || break_pos + indent_len == line_len) - break; - - /* Move forward to the character after the indentation and - * just after the space. */ - break_pos += indent_len + 1; - - assert(break_pos <= line_len); - - /* Make a new line, and copy the text after where we're - * going to break this line to the beginning of the new - * line. */ - splice_node(openfile->current, - make_new_node(openfile->current), - openfile->current->next); - - /* If this paragraph is non-quoted, and autoindent isn't - * turned on, set the indentation length to zero so that the - * indentation is treated as part of the line. */ - if (quote_len == 0 -#ifndef NANO_TINY - && !ISSET(AUTOINDENT) -#endif - ) - indent_len = 0; - - /* Copy the text after where we're going to break the - * current line to the next line. */ - openfile->current->next->data = charalloc(indent_len + 1 + - line_len - break_pos); - strncpy(openfile->current->next->data, indent_string, - indent_len); - strcpy(openfile->current->next->data + indent_len, - openfile->current->data + break_pos); - - par_len++; - openfile->totsize += indent_len + 1; - -#ifndef NANO_TINY - /* Adjust the mark coordinates to compensate for the change - * in the current line. */ - if (openfile->mark_set && openfile->mark_begin == - openfile->current && openfile->mark_begin_x > - break_pos) { - openfile->mark_begin = openfile->current->next; - openfile->mark_begin_x -= break_pos - indent_len; - } -#endif - - /* Break the current line. */ - null_at(&openfile->current->data, break_pos); - - /* 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->filebot->next; - - /* Go to the next line. */ - par_len--; - openfile->current_y++; - openfile->current = openfile->current->next; - } - - /* We're done breaking lines, so we don't need indent_string - * anymore. */ - free(indent_string); - /* Go to the next line, if possible. If there is no next line, * move to the end of the current line. */ - if (openfile->current != openfile->filebot) { - openfile->current_y++; - openfile->current = openfile->current->next; - } else - openfile->current_x = strlen(openfile->current->data); + openfile->current = line_after_par; + openfile->current_x = (openfile->current == openfile->filebot)? + strlen(openfile->current->data) : 0; - /* Renumber the lines of the now-justified current paragraph, - * since both find_paragraph() and edit_refresh() need the line - * numbers to be right. */ - renumber(curr_first_par_line); - - /* We've just finished justifying the paragraph. If we're not - * justifying the entire file, break out of the loop. - * Otherwise, continue the loop so that we justify all the - * paragraphs in the file. */ - if (!full_justify) + /* if the filebot is found, break, the current line will be empty */ + if (!full_justify || openfile->current == openfile->filebot) break; } - /* We are now done justifying the paragraph or the file, so clean - * up. current_y and totsize have been maintained above. If we - * actually justified something, set last_par_line to the new end of - * the paragraph. */ - if (first_par_line != NULL) - last_par_line = openfile->current; - + add_undo(JUSTIFY_END); edit_refresh(); - -#ifndef NANO_TINY - /* We're going to set jump_buf so that we return here after a - * SIGWINCH instead of to main(). Indicate this. */ - jump_buf_main = FALSE; - - /* Return here after a SIGWINCH. */ - sigsetjmp(jump_buf, 1); -#endif - - statusbar(_("Can now UnJustify!")); - - /* If constant cursor position display is on, make sure the current - * cursor position will be properly displayed on the statusbar. */ - if (ISSET(CONST_UPDATE)) - do_cursorpos(TRUE); - - /* Display the shortcut list with UnJustify. */ - uncutfunc->desc = unjust_tag; - currmenu = MMAIN; - display_main_list(); - - /* Now get a keystroke and see if it's unjustify. If not, put back - * the keystroke and return. */ - kbinput = do_input(FALSE); - s = get_shortcut(&kbinput); - - if (s && s->scfunc == do_uncut_text) { - /* Splice the justify buffer back into the file, but only if we - * actually justified something. */ - if (first_par_line != NULL) { - filestruct *top_save; - - /* Partition the filestruct so that it contains only the - * text of the justified paragraph. */ - filepart = partition_filestruct(first_par_line, 0, - last_par_line, filebot_inpar ? - strlen(last_par_line->data) : 0); - - /* Remove the text of the justified paragraph, and - * replace it with the text in the justify buffer. */ - free_filestruct(openfile->fileage); - openfile->fileage = jusbuffer; - openfile->filebot = jusbottom; - - top_save = openfile->fileage; - - /* 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 beginning line of the old - * partition. */ - renumber(top_save); - - /* Restore the justify we just did (ungrateful user!). */ - openfile->edittop = edittop_save; - openfile->current = current_save; - openfile->current_x = current_x_save; - openfile->placewewant = pww_save; - openfile->totsize = totsize_save; -#ifndef NANO_TINY - if (openfile->mark_set) { - openfile->mark_begin = mark_begin_save; - openfile->mark_begin_x = mark_begin_x_save; } -#endif - openfile->modified = modified_save; - /* Clear the justify buffer. */ - jusbuffer = NULL; - - if (!openfile->modified) - titlebar(NULL); - edit_refresh_needed = TRUE; - } - } else { - unget_kbinput(kbinput, meta_key, func_key); - - /* Blow away the text in the justify buffer. */ - free_filestruct(jusbuffer); - jusbuffer = NULL; - } - - blank_statusbar(); - - /* Display the shortcut list with UnCut. */ - uncutfunc->desc = uncut_tag; - display_main_list(); - -#ifndef NANO_TINY - allow_pending_sigwinch(TRUE); -#endif -} - /* Justify the current paragraph. */ void do_justify_void(void) {