/* If scroll_only is FALSE, move up one line. If scroll_only is TRUE, * scroll up one line without scrolling the cursor. */ void do_up(bool scroll_only) { size_t was_column = xplustabs(); /* If we're at the top of the file, or if scroll_only is TRUE and * the top of the file is onscreen, get out. */ if (openfile->current == openfile->fileage || (scroll_only && openfile->edittop == openfile->fileage)) return; assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno); /* Move the current line of the edit window up. */ openfile->current = openfile->current->prev; openfile->current_x = actual_x(openfile->current->data, openfile->placewewant); /* When the cursor was on the first line of the edit window (or when just * scrolling without moving the cursor), scroll the edit window up -- one * line if we're in smooth scrolling mode, and half a page otherwise. */ if (openfile->current->next == openfile->edittop || scroll_only) edit_scroll(UPWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ? 1 : editwinrows / 2 + 1); /* If the lines weren't already redrawn, see if they need to be. */ if (openfile->current_y > 0) { /* Redraw the prior line if it was horizontally scrolled. */ if (need_horizontal_scroll(was_column, 0)) update_line(openfile->current->next, 0); /* Redraw the current line if it needs to be horizontally scrolled. */ if (need_horizontal_scroll(0, xplustabs())) update_line(openfile->current, openfile->current_x); } }
/* Move right one character. */ void do_right(void) { size_t was_column = xplustabs(); assert(openfile->current_x <= strlen(openfile->current->data)); if (openfile->current->data[openfile->current_x] != '\0') openfile->current_x = move_mbright(openfile->current->data, openfile->current_x); else if (openfile->current != openfile->filebot) { openfile->current_x = 0; #ifndef NANO_TINY if (ISSET(SOFTWRAP)) openfile->current_y -= strlenpt(openfile->current->data) / editwincols; #endif } openfile->placewewant = xplustabs(); if (need_horizontal_scroll(was_column, openfile->placewewant)) update_line(openfile->current, openfile->current_x); if (openfile->current_x == 0) do_down_void(); else ensure_line_is_visible(); }
/* Reset current_y, based on the position of current, and put the cursor * in the edit window at (current_y, current_x). */ void reset_cursor(void) { size_t xpt; /* If we haven't opened any files yet, put the cursor in the top * left corner of the edit window and get out. */ if (openfiles.size() == 0) { wmove(edit, 0, 0); return; } xpt = xplustabs(); if (ISSET(SOFTWRAP)) { filestruct *tmp; openfile->current_y = 0; for (tmp = openfile->edittop; tmp && tmp != openfile->current; tmp = tmp->next) { openfile->current_y += 1 + strlenpt(tmp->data) / COLS; } openfile->current_y += xplustabs() / COLS; if (openfile->current_y < editwinrows) { wmove(edit, openfile->current_y, xpt % COLS); } } else { openfile->current_y = openfile->current->lineno - openfile->edittop->lineno; if (openfile->current_y < editwinrows) { wmove(edit, openfile->current_y, xpt - get_page_start(xpt)); } } }
/* Move to the end of the current line. */ void do_end(void) { size_t was_column = xplustabs(); openfile->current_x = strlen(openfile->current->data); openfile->placewewant = xplustabs(); if (need_horizontal_scroll(was_column, openfile->placewewant)) update_line(openfile->current, openfile->current_x); ensure_line_is_visible(); }
/* Copy text from the cutbuffer into the current filestruct. */ void do_uncut_text(void) { assert(openfile->current != NULL && openfile->current->data != NULL); /* If the cutbuffer is empty, get out. */ if (cutbuffer == NULL) return; add_undo(PASTE); /* Add a copy of the text in the cutbuffer to the current filestruct * at the current cursor position. */ copy_from_filestruct(cutbuffer); update_undo(PASTE); /* Set the current place we want to where the text from the * cutbuffer ends. */ openfile->placewewant = xplustabs(); /* Mark the file as modified. */ set_modified(); /* Update the screen. */ edit_refresh_needed = TRUE; #ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif #ifdef DEBUG dump_filestruct_reverse(); #endif }
/* Move to the beginning of the current line. If the SMART_HOME flag is * set, move to the first non-whitespace character of the current line * if we aren't already there, or to the beginning of the current line * if we are. */ void do_home(void) { size_t pww_save = openfile->placewewant; #ifndef NANO_TINY if (ISSET(SMART_HOME)) { size_t current_x_save = openfile->current_x; openfile->current_x = indent_length(openfile->current->data); if (openfile->current_x == current_x_save || openfile->current->data[openfile->current_x] == '\0') openfile->current_x = 0; openfile->placewewant = xplustabs(); } else { #endif openfile->current_x = 0; openfile->placewewant = 0; #ifndef NANO_TINY } #endif if (need_horizontal_update(pww_save)) update_line(openfile->current, openfile->current_x); }
/* Move down to the beginning of the last line of the current paragraph. * Then move down one line farther if there is such a line, or to the * end of the current line if not. If allow_update is TRUE, update the * screen afterwards. A line is the last line of a paragraph if it is * in a paragraph, and the next line either is the beginning line of a * paragraph or isn't in a paragraph. */ void do_para_end(bool allow_update) { filestruct *const current_save = openfile->current; const size_t pww_save = openfile->placewewant; while (openfile->current != openfile->filebot && !inpar(openfile->current)) openfile->current = openfile->current->next; while (openfile->current != openfile->filebot && inpar(openfile->current->next) && !begpar(openfile->current->next)) { openfile->current = openfile->current->next; openfile->current_y++; } if (openfile->current != openfile->filebot) { openfile->current = openfile->current->next; openfile->current_x = 0; openfile->placewewant = 0; } else { openfile->current_x = strlen(openfile->current->data); openfile->placewewant = xplustabs(); } if (allow_update) edit_redraw(current_save, pww_save); }
/* Move left one character. */ void do_left(void) { size_t was_column = xplustabs(); if (openfile->current_x > 0) openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); else if (openfile->current != openfile->fileage) { do_up_void(); openfile->current_x = strlen(openfile->current->data); } openfile->placewewant = xplustabs(); if (need_horizontal_scroll(was_column, openfile->placewewant)) update_line(openfile->current, openfile->current_x); }
/* Move to the last line of the file. */ void do_last_line(void) { openfile->current = openfile->filebot; openfile->current_x = strlen(openfile->filebot->data); openfile->placewewant = xplustabs(); openfile->current_y = editwinrows - 1; edit_refresh_needed = 1; }
/* Search for a string. */ void do_search(void) { linestruct *fileptr = openfile->current; size_t fileptr_x = openfile->current_x; size_t pww_save = openfile->placewewant; int i; bool didfind; i = search_init(FALSE, FALSE); if (i == -1) /* Cancel, Go to Line, blank search string, or regcomp() failed. */ search_replace_abort(); else if (i == -2) /* Replace. */ do_replace(); #if !defined(NANO_TINY) || defined(HAVE_REGEX_H) else if (i == 1) /* Case Sensitive, Backwards, or Regexp search toggle. */ do_search(); #endif if (i != 0) return; /* If answer is now "", copy last_search into answer. */ if (*answer == '\0') answer = mallocstrcpy(answer, last_search); else last_search = mallocstrcpy(last_search, answer); #ifndef DISABLE_HISTORIES /* If answer is not "", add this search string to the search history * list. */ if (answer[0] != '\0') update_history(&search_history, answer); #endif findnextstr_wrap_reset(); didfind = findnextstr( #ifndef DISABLE_SPELLER FALSE, #endif openfile->current, openfile->current_x, answer, NULL); /* If we found something, and we're back at the exact same spot where * we started searching, then this is the only occurrence. */ if (fileptr == openfile->current && fileptr_x == openfile->current_x && didfind) { statusbar(_("This is the only occurrence")); } openfile->placewewant = xplustabs(); edit_redraw(fileptr, pww_save); search_replace_abort(); }
/* Move to the end of the current line. */ void do_end(void) { size_t pww_save = openfile->placewewant; openfile->current_x = strlen(openfile->current->data); openfile->placewewant = xplustabs(); if (need_horizontal_update(pww_save)) update_line(openfile->current, openfile->current_x); }
/* Go to the specified line and x position. */ void goto_line_posx(ssize_t line, size_t pos_x) { for (openfile->current = openfile->fileage; openfile->current != openfile->filebot && openfile->current->next != NULL && line > 1; line--) openfile->current = openfile->current->next; openfile->current_x = pos_x; openfile->placewewant = xplustabs(); edit_refresh_needed = TRUE; }
/* Move all currently marked text into the cutbuffer, and set the * current place we want to where the text used to start. */ void cut_marked(void) { linestruct *top, *bot; size_t top_x, bot_x; mark_order((const linestruct **)&top, &top_x, (const linestruct **)&bot, &bot_x, NULL); move_to_filestruct(&cutbuffer, &cutbottom, top, top_x, bot, bot_x); openfile->placewewant = xplustabs(); }
/* Search for a match to one of the two characters in bracket_set. If * reverse is TRUE, search backwards for the leftmost bracket. * Otherwise, search forwards for the rightmost bracket. Return TRUE if * we found a match, and FALSE otherwise. */ bool find_bracket_match(bool reverse, const char *bracket_set) { linestruct *fileptr = openfile->current; const char *rev_start = NULL, *found = NULL; ssize_t current_y_find = openfile->current_y; assert(mbstrlen(bracket_set) == 2); /* rev_start might end up 1 character before the start or after the * end of the line. This won't be a problem because we'll skip over * it below in that case, and rev_start will be properly set when * the search continues on the previous or next line. */ rev_start = reverse ? fileptr->data + (openfile->current_x - 1) : fileptr->data + (openfile->current_x + 1); /* Look for either of the two characters in bracket_set. rev_start * can be 1 character before the start or after the end of the line. * In either case, just act as though no match is found. */ while (TRUE) { found = ((rev_start > fileptr->data && *(rev_start - 1) == '\0') || rev_start < fileptr->data) ? NULL : (reverse ? mbrevstrpbrk(fileptr->data, bracket_set, rev_start) : mbstrpbrk(rev_start, bracket_set)); if (found != NULL) /* We've found a potential match. */ break; if (reverse) { fileptr = fileptr->prev; current_y_find--; } else { fileptr = fileptr->next; current_y_find++; } if (fileptr == NULL) /* We've reached the start or end of the buffer, so get out. */ return FALSE; rev_start = fileptr->data; if (reverse) rev_start += strlen(fileptr->data); } /* We've definitely found something. */ openfile->current = fileptr; openfile->current_x = found - fileptr->data; openfile->placewewant = xplustabs(); openfile->current_y = current_y_find; return TRUE; }
/* Move to the last line of the file. */ void do_last_line(void) { filestruct *current_save = openfile->current; size_t pww_save = openfile->placewewant; openfile->current = openfile->filebot; openfile->current_x = strlen(openfile->filebot->data); openfile->placewewant = xplustabs(); openfile->current_y = editwinrows - 1; edit_redraw(current_save, pww_save); }
/* Move to the last line of the file. */ void do_last_line(void) { openfile->current = openfile->filebot; openfile->current_x = strlen(openfile->filebot->data); openfile->placewewant = xplustabs(); /* Set the last line of the screen as the target for the cursor. */ openfile->current_y = editwinrows - 1; refresh_needed = TRUE; focusing = FALSE; }
/* Move to the beginning of the current line. If the SMART_HOME flag is * set, move to the first non-whitespace character of the current line * if we aren't already there, or to the beginning of the current line * if we are. */ void do_home(void) { size_t was_column = xplustabs(); #ifndef NANO_TINY if (ISSET(SMART_HOME)) { size_t current_x_save = openfile->current_x; openfile->current_x = indent_length(openfile->current->data); if (openfile->current_x == current_x_save || openfile->current->data[openfile->current_x] == '\0') openfile->current_x = 0; } else #endif openfile->current_x = 0; openfile->placewewant = xplustabs(); if (need_horizontal_scroll(was_column, openfile->placewewant)) update_line(openfile->current, openfile->current_x); }
/* Move left one character. */ void do_left(void) { size_t pww_save = openfile->placewewant; if (openfile->current_x > 0) openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); else if (openfile->current != openfile->fileage) { do_up_void(); openfile->current_x = strlen(openfile->current->data); } openfile->placewewant = xplustabs(); if (need_horizontal_update(pww_save)) update_line(openfile->current, openfile->current_x); }
/* Move to the previous word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. */ void do_prev_word(bool allow_punct, bool allow_update) { size_t pww_save = openfile->placewewant; filestruct *current_save = openfile->current; bool seen_a_word = FALSE, step_forward = FALSE; assert(openfile->current != NULL && openfile->current->data != NULL); /* Move backward until we pass over the start of a word. */ while (TRUE) { /* If at the head of a line, move to the end of the preceding one. */ if (openfile->current_x == 0) { if (openfile->current->prev == NULL) break; openfile->current = openfile->current->prev; openfile->current_x = strlen(openfile->current->data); } /* Step back one character. */ openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); if (is_word_mbchar(openfile->current->data + openfile->current_x, allow_punct)) { seen_a_word = TRUE; /* If at the head of a line now, this surely is a word start. */ if (openfile->current_x == 0) break; } else if (seen_a_word) { /* This is space now: we've overshot the start of the word. */ step_forward = TRUE; break; } } if (step_forward) /* Move one character forward again to sit on the start of the word. */ openfile->current_x = move_mbright(openfile->current->data, openfile->current_x); openfile->placewewant = xplustabs(); /* If allow_update is TRUE, update the screen. */ if (allow_update) edit_redraw(current_save, pww_save); }
/* Move right one character. */ void do_right(void) { size_t pww_save = openfile->placewewant; assert(openfile->current_x <= strlen(openfile->current->data)); if (openfile->current->data[openfile->current_x] != '\0') openfile->current_x = move_mbright(openfile->current->data, openfile->current_x); else if (openfile->current != openfile->filebot) { do_down_void(); openfile->current_x = 0; } openfile->placewewant = xplustabs(); if (need_horizontal_update(pww_save)) update_line(openfile->current, openfile->current_x); }
/* Search for the last string without prompting. */ void do_research(void) { linestruct *fileptr = openfile->current; size_t fileptr_x = openfile->current_x; size_t pww_save = openfile->placewewant; bool didfind; focusing = TRUE; #ifndef DISABLE_HISTORIES /* If nothing was searched for yet during this run of nano, but * there is a search history, take the most recent item. */ if (last_search[0] == '\0' && searchbot->prev != NULL) last_search = mallocstrcpy(last_search, searchbot->prev->data); #endif if (last_search[0] != '\0') { #ifdef HAVE_REGEX_H /* Since answer is "", use last_search! */ if (ISSET(USE_REGEXP) && !regexp_init(last_search)) return; #endif findnextstr_wrap_reset(); didfind = findnextstr( #ifndef DISABLE_SPELLER FALSE, #endif openfile->current, openfile->current_x, last_search, NULL); /* If we found something, and we're back at the exact same spot * where we started searching, then this is the only occurrence. */ if (fileptr == openfile->current && fileptr_x == openfile->current_x && didfind) { statusbar(_("This is the only occurrence")); } } else statusbar(_("No current search pattern")); openfile->placewewant = xplustabs(); edit_redraw(fileptr, pww_save); search_replace_abort(); }
/* If constant is true, we display the current cursor position only if * disable_cursorpos is false. Otherwise, we display it * unconditionally and set disable_cursorpos to false. If constant is * true and disable_cursorpos is true, we also set disable_cursorpos to * false, so that we leave the current statusbar alone this time, and * display the current cursor position next time. */ void do_cursorpos(bool constant) { filestruct *f; char c; size_t i, cur_xpt = xplustabs() + 1; size_t cur_lenpt = strlenpt(openfile->current->data) + 1; int linepct, colpct, charpct; assert(openfile->fileage != NULL && openfile->current != NULL); f = openfile->current->next; c = openfile->current->data[openfile->current_x]; openfile->current->next = NULL; openfile->current->data[openfile->current_x] = '\0'; i = get_totsize(openfile->fileage, openfile->current); openfile->current->data[openfile->current_x] = c; openfile->current->next = f; if (constant && disable_cursorpos) { disable_cursorpos = false; return; } /* Display the current cursor position on the statusbar, and set * disable_cursorpos to false. */ linepct = 100 * openfile->current->lineno / openfile->filebot->lineno; colpct = 100 * cur_xpt / cur_lenpt; charpct = (openfile->totsize == 0) ? 0 : 100 * i / openfile->totsize; statusbar( _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%lu (%d%%)"), (long)openfile->current->lineno, (long)openfile->filebot->lineno, linepct, (unsigned long)cur_xpt, (unsigned long)cur_lenpt, colpct, (unsigned long)i, (unsigned long)openfile->totsize, charpct); disable_cursorpos = false; }
/* If we aren't 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, into the cutbuffer. If we are, and * we're not on the last line of the file, move the newline at the end * into 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(openfile->current->data); assert(openfile->current_x <= data_len); if (openfile->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, into the cutbuffer. */ move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, openfile->current_x, openfile->current, data_len); else if (openfile->current != openfile->filebot) { /* If we're at the end of the line, and it isn't the last line * of the file, move all the text from the current position up * to the beginning of the next line, i.e. the newline at the * end, into the cutbuffer. */ move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, openfile->current_x, openfile->current->next, 0); openfile->placewewant = xplustabs(); } }
/* Highlight the current word being replaced or spell checked. We * expect word to have tabs and control characters expanded. */ void do_replace_highlight(bool highlight, const char *word) { size_t y = xplustabs(), word_len = strlenpt(word); y = get_page_start(y) + COLS - y; /* Now y is the number of columns that we can display on this * line. */ assert(y > 0); if (word_len > y) { y--; } reset_cursor(); wnoutrefresh(edit); if (highlight) { wattron(edit, highlight_attribute); } /* This is so we can show zero-length matches. */ if (word_len == 0) { waddch(edit, ' '); } else { waddnstr(edit, word, actual_x(word, y)); } if (word_len > y) { waddch(edit, '$'); } if (highlight) { wattroff(edit, highlight_attribute); } }
/* Step through each replace word and prompt user before replacing. * Parameters real_current and real_current_x are needed in order to * allow the cursor position to be updated when a word before the cursor * is replaced by a shorter word. * * needle is the string to seek. We replace it with answer. Return -1 * if needle isn't found, else the number of replacements performed. If * canceled isn't NULL, set it to TRUE if we canceled. */ ssize_t do_replace_loop( #ifndef DISABLE_SPELLER bool whole_word_only, #endif bool *canceled, const linestruct *real_current, size_t *real_current_x, const char *needle) { ssize_t numreplaced = -1; size_t match_len; bool replaceall = FALSE; #ifndef NANO_TINY bool old_mark_set = openfile->mark_set; linestruct *top, *bot; size_t top_x, bot_x; bool right_side_up = FALSE; /* TRUE if (mark_begin, mark_begin_x) is the top of the mark, * FALSE if (current, current_x) is. */ if (old_mark_set) { /* If the mark is on, frame the region, and turn the mark off. */ mark_order((const linestruct **)&top, &top_x, (const linestruct **)&bot, &bot_x, &right_side_up); openfile->mark_set = FALSE; /* Start either at the top or the bottom of the marked region. */ if (!ISSET(BACKWARDS_SEARCH)) { openfile->current = top; openfile->current_x = (top_x == 0 ? 0 : top_x - 1); } else { openfile->current = bot; openfile->current_x = bot_x; } } #endif /* !NANO_TINY */ if (canceled != NULL) *canceled = FALSE; findnextstr_wrap_reset(); while (findnextstr( #ifndef DISABLE_SPELLER whole_word_only, #endif real_current, *real_current_x, needle, &match_len)) { int i = 0; #ifndef NANO_TINY if (old_mark_set) { /* When we've found an occurrence outside of the marked region, * stop the fanfare. */ if (openfile->current->lineno > bot->lineno || openfile->current->lineno < top->lineno || (openfile->current == bot && openfile->current_x > bot_x) || (openfile->current == top && openfile->current_x < top_x)) break; } #endif /* Indicate that we found the search string. */ if (numreplaced == -1) numreplaced = 0; if (!replaceall) { size_t xpt = xplustabs(); char *exp_word = display_string(openfile->current->data, xpt, strnlenpt(openfile->current->data, openfile->current_x + match_len) - xpt, FALSE); edit_refresh(); curs_set(0); do_replace_highlight(TRUE, exp_word); /* TRANSLATORS: This is a prompt. */ i = do_yesno_prompt(TRUE, _("Replace this instance?")); do_replace_highlight(FALSE, exp_word); free(exp_word); curs_set(1); if (i == -1) { /* We canceled the replace. */ if (canceled != NULL) *canceled = TRUE; break; } } if (i > 0 || replaceall) { /* Yes, replace it!!!! */ char *copy; size_t length_change; #ifndef NANO_TINY add_undo(REPLACE); #endif if (i == 2) replaceall = TRUE; copy = replace_line(needle); length_change = strlen(copy) - strlen(openfile->current->data); #ifndef NANO_TINY /* If the mark was on and (mark_begin, mark_begin_x) was the * top of it, don't change mark_begin_x. */ if (!old_mark_set || !right_side_up) { /* Keep mark_begin_x in sync with the text changes. */ if (openfile->current == openfile->mark_begin && openfile->mark_begin_x > openfile->current_x) { if (openfile->mark_begin_x < openfile->current_x + match_len) openfile->mark_begin_x = openfile->current_x; else openfile->mark_begin_x += length_change; bot_x = openfile->mark_begin_x; } } /* If the mark was on and (current, current_x) was the top * of it, don't change real_current_x. */ if (!old_mark_set || right_side_up) { #endif /* Keep real_current_x in sync with the text changes. */ if (openfile->current == real_current && openfile->current_x <= *real_current_x) { if (*real_current_x < openfile->current_x + match_len) *real_current_x = openfile->current_x + match_len; *real_current_x += length_change; #ifndef NANO_TINY bot_x = *real_current_x; } #endif } /* Set the cursor at the last character of the replacement * text, so searching will resume after the replacement * text. Note that current_x might be set to (size_t)-1 * here. */ #ifndef NANO_TINY if (!ISSET(BACKWARDS_SEARCH)) #endif openfile->current_x += match_len + length_change - 1; /* Clean up. */ openfile->totsize += mbstrlen(copy) - mbstrlen(openfile->current->data); free(openfile->current->data); openfile->current->data = copy; #ifndef DISABLE_COLOR /* Reset the precalculated multiline-regex hints only when * the first replacement has been made. */ if (numreplaced == 0) reset_multis(openfile->current, TRUE); #endif if (!replaceall) { #ifndef DISABLE_COLOR /* If color syntaxes are available and turned on, we * need to call edit_refresh(). */ if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) edit_refresh(); else #endif update_line(openfile->current, openfile->current_x); } set_modified(); numreplaced++; } } if (numreplaced == -1) not_found_msg(needle); #ifndef NANO_TINY if (old_mark_set) openfile->mark_set = TRUE; #endif /* If the NO_NEWLINES flag isn't set, and text has been added to the * magicline, make a new magicline. */ if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') new_magicline(); return numreplaced; }
/* If scroll_only is FALSE, move down one line. If scroll_only is TRUE, * scroll down one line without scrolling the cursor. */ void do_down(bool scroll_only) { #ifndef NANO_TINY int amount = 0, enough; filestruct *topline; #endif size_t was_column = xplustabs(); /* If we're at the bottom of the file, get out. */ if (openfile->current == openfile->filebot) return; assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno); assert(openfile->current->next != NULL); #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { /* Compute the number of lines to scroll. */ amount = strlenpt(openfile->current->data) / editwincols - xplustabs() / editwincols + strlenpt(openfile->current->next->data) / editwincols + openfile->current_y - editwinrows + 2; topline = openfile->edittop; /* Reduce the amount when there are overlong lines at the top. */ for (enough = 1; enough < amount; enough++) { amount -= strlenpt(topline->data) / editwincols; if (amount > 0) topline = topline->next; if (amount < enough) { amount = enough; break; } } } #endif /* Move to the next line in the file. */ openfile->current = openfile->current->next; openfile->current_x = actual_x(openfile->current->data, openfile->placewewant); /* If scroll_only is FALSE and if we're on the last line of the * edit window, scroll the edit window down one line if we're in * smooth scrolling mode, or down half a page if we're not. If * scroll_only is TRUE, scroll the edit window down one line * unconditionally. */ #ifndef NANO_TINY if (openfile->current_y == editwinrows - 1 || amount > 0 || scroll_only) { if (amount < 1 || scroll_only) amount = 1; edit_scroll(DOWNWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ? amount : editwinrows / 2 + 1); if (ISSET(SOFTWRAP)) { refresh_needed = TRUE; return; } } #else if (openfile->current_y == editwinrows - 1) edit_scroll(DOWNWARD, editwinrows / 2 + 1); #endif /* If the lines weren't already redrawn, see if they need to be. */ if (openfile->current_y < editwinrows - 1) { /* Redraw the prior line if it was horizontally scrolled. */ if (need_horizontal_scroll(was_column, 0)) update_line(openfile->current->prev, 0); /* Redraw the current line if it needs to be horizontally scrolled. */ if (need_horizontal_scroll(0, xplustabs())) update_line(openfile->current, openfile->current_x); } }
/* Move text from the current linestruct into the cutbuffer. If * copy_text is TRUE, copy the text back into the linestruct afterward. * If cut_till_eof is TRUE, move all text from the current cursor * position to the end of the file into the cutbuffer. */ void do_cut_text( #ifndef NANO_TINY bool copy_text, bool cut_till_eof, bool undoing #else void #endif ) { #ifndef NANO_TINY linestruct *cb_save = NULL; /* The current end of the cutbuffer, before we add text to * it. */ size_t cb_save_len = 0; /* The length of the string at the current end of the cutbuffer, * before we add text to it. */ bool old_no_newlines = ISSET(NO_NEWLINES); #endif assert(openfile->current != NULL && openfile->current->data != NULL); /* If keep_cutbuffer is FALSE and the cutbuffer isn't empty, blow * away the text in the cutbuffer. */ if (!keep_cutbuffer && cutbuffer != NULL) { free_filestruct(cutbuffer); cutbuffer = NULL; #ifdef DEBUG fprintf(stderr, "Blew away cutbuffer =)\n"); #endif } #ifndef NANO_TINY if (copy_text) { if (cutbuffer != NULL) { /* If the cutbuffer isn't empty, save where it currently * ends. This is where we'll add the new text. */ cb_save = cutbottom; cb_save_len = strlen(cutbottom->data); } /* Set NO_NEWLINES to TRUE, so that we don't disturb the last * line of the file when moving text to the cutbuffer. */ SET(NO_NEWLINES); } #endif /* 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_TINY if (cut_till_eof) { /* If cut_till_eof is TRUE, move all text up to the end of the * file into the cutbuffer. */ cut_to_eof(); } else if (openfile->mark_set) { /* If the mark is on, move the marked text to the cutbuffer, and * turn the mark off. */ cut_marked(); openfile->mark_set = FALSE; } else if (ISSET(CUT_TO_END)) /* 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 #endif /* Move the entire line into the cutbuffer. */ cut_line(); #ifndef NANO_TINY if (copy_text) { /* Copy the text in the cutbuffer, starting at its saved end if * there is one, back into the linestruct. This effectively * uncuts the text we just cut without marking the file as * modified. */ if (cutbuffer != NULL) { if (cb_save != NULL) { cb_save->data += cb_save_len; copy_from_filestruct(cb_save); cb_save->data -= cb_save_len; } else copy_from_filestruct(cutbuffer); /* Set the current place we want to where the text from the * cutbuffer ends. */ openfile->placewewant = xplustabs(); } /* Set NO_NEWLINES back to what it was before, since we're done * disturbing the text. */ if (!old_no_newlines) UNSET(NO_NEWLINES); } else if (!undoing) update_undo(cut_till_eof ? CUT_EOF : CUT); /* Leave the text in the cutbuffer, and mark the file as * modified. */ if (!copy_text) #endif /* !NANO_TINY */ set_modified(); /* Update the screen. */ edit_refresh_needed = TRUE; #ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif #ifdef DEBUG dump_filestruct(cutbuffer); #endif }
/* Look for needle, starting at (current, current_x). begin is the line * where we first started searching, at column begin_x. The return * value specifies whether we found anything. If we did, set needle_len * to the length of the string we found if it isn't NULL. */ bool findnextstr( #ifndef DISABLE_SPELLER bool whole_word_only, #endif const filestruct *begin, size_t begin_x, const char *needle, size_t *needle_len) { size_t found_len; /* The length of the match we find. */ size_t current_x_find = 0; /* The location in the current line of the match we find. */ ssize_t current_y_find = openfile->current_y; filestruct *fileptr = openfile->current; const char *rev_start = fileptr->data, *found = NULL; time_t lastkbcheck = time(NULL); /* rev_start might end up 1 character before the start or after the * end of the line. This won't be a problem because strstrwrapper() * will return immediately and say that no match was found, and * rev_start will be properly set when the search continues on the * previous or next line. */ rev_start += #ifndef NANO_TINY ISSET(BACKWARDS_SEARCH) ? ((openfile->current_x == 0) ? -1 : move_mbleft(fileptr->data, openfile->current_x)) : #endif move_mbright(fileptr->data, openfile->current_x); /* Look for needle in the current line we're searching. */ enable_nodelay(); while (TRUE) { if (time(NULL) - lastkbcheck > 1) { int input = parse_kbinput(edit); lastkbcheck = time(NULL); if (input && func_from_key(&input) == do_cancel) { statusbar(_("Cancelled")); return FALSE; } } found = strstrwrapper(fileptr->data, needle, rev_start); /* We've found a potential match. */ if (found != NULL) { #ifndef DISABLE_SPELLER bool found_whole = FALSE; /* Is this potential match a whole word? */ #endif /* Set found_len to the length of the potential match. */ found_len = #ifdef HAVE_REGEX_H ISSET(USE_REGEXP) ? regmatches[0].rm_eo - regmatches[0].rm_so : #endif strlen(needle); #ifndef DISABLE_SPELLER /* If we're searching for whole words, see if this potential * match is a whole word. */ if (whole_word_only) { char *word = mallocstrncpy(NULL, found, found_len + 1); word[found_len] = '\0'; found_whole = is_whole_word(found - fileptr->data, fileptr->data, word); free(word); } /* If we're searching for whole words and this potential * match isn't a whole word, continue searching. */ if (!whole_word_only || found_whole) #endif break; } if (search_last_line) { /* We've finished processing the file, so get out. */ not_found_msg(needle); disable_nodelay(); return FALSE; } /* Move to the previous or next line in the file. */ #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = fileptr->prev; current_y_find--; } else { #endif fileptr = fileptr->next; current_y_find++; #ifndef NANO_TINY } #endif if (fileptr == NULL) { /* We've reached the start or end of the buffer, so wrap around. */ #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = openfile->filebot; current_y_find = editwinrows - 1; } else { #endif fileptr = openfile->fileage; current_y_find = 0; #ifndef NANO_TINY } #endif statusbar(_("Search Wrapped")); } if (fileptr == begin) /* We've reached the original starting line. */ search_last_line = TRUE; rev_start = fileptr->data; #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) rev_start += strlen(fileptr->data); #endif } /* We found an instance. */ current_x_find = found - fileptr->data; /* Ensure we haven't wrapped around again! */ if (search_last_line && #ifndef NANO_TINY ((!ISSET(BACKWARDS_SEARCH) && current_x_find > begin_x) || (ISSET(BACKWARDS_SEARCH) && current_x_find < begin_x)) #else current_x_find > begin_x #endif ) { not_found_msg(needle); disable_nodelay(); return FALSE; } disable_nodelay(); /* We've definitely found something. */ openfile->current = fileptr; openfile->current_x = current_x_find; openfile->placewewant = xplustabs(); openfile->current_y = current_y_find; /* needle_len holds the length of needle. */ if (needle_len != NULL) *needle_len = found_len; return TRUE; }
/* Move to the next word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. Return TRUE if we started on a word, and FALSE * otherwise. */ bool do_next_word(bool allow_punct, bool allow_update) { size_t pww_save = openfile->placewewant; filestruct *current_save = openfile->current; char *char_mb; int char_mb_len; bool end_line = FALSE, started_on_word = FALSE; assert(openfile->current != NULL && openfile->current->data != NULL); char_mb = charalloc(mb_cur_max()); /* Move forward until we find the character after the last letter of * the current word. */ while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving forward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; } /* Move forward until we find the first letter of the next word. */ if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; for (; openfile->current != NULL; openfile->current = openfile->current->next) { while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving forward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; } /* If we've found it, stop moving forward to the beginnings of * subsequent lines. */ if (!end_line) break; if (openfile->current != openfile->filebot) { end_line = FALSE; openfile->current_x = 0; } } free(char_mb); /* If we haven't found it, move to the end of the file. */ if (openfile->current == NULL) openfile->current = openfile->filebot; openfile->placewewant = xplustabs(); /* If allow_update is TRUE, update the screen. */ if (allow_update) edit_redraw(current_save, pww_save); /* Return whether we started on a word. */ return started_on_word; }
/* Move to the previous word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. Return TRUE if we started on a word, and FALSE * otherwise. */ bool do_prev_word(bool allow_punct, bool allow_update) { size_t pww_save = openfile->placewewant; filestruct *current_save = openfile->current; char *char_mb; int char_mb_len; bool begin_line = FALSE, started_on_word = FALSE; assert(openfile->current != NULL && openfile->current->data != NULL); char_mb = charalloc(mb_cur_max()); /* Move backward until we find the character before the first letter * of the current word. */ while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* Move backward until we find the last letter of the previous * word. */ if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); for (; openfile->current != NULL; openfile->current = openfile->current->prev) { while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* If we've found it, stop moving backward to the ends of * previous lines. */ if (!begin_line) break; if (openfile->current != openfile->fileage) { begin_line = FALSE; openfile->current_x = strlen(openfile->current->prev->data); } } /* If we haven't found it, move to the beginning of the file. */ if (openfile->current == NULL) openfile->current = openfile->fileage; /* If we've found it, move backward until we find the character * before the first letter of the previous word. */ else if (!begin_line) { if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the * current line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* If we've found it, move forward to the first letter of the * previous word. */ if (!begin_line) openfile->current_x += char_mb_len; } free(char_mb); openfile->placewewant = xplustabs(); /* If allow_update is TRUE, update the screen. */ if (allow_update) edit_redraw(current_save, pww_save); /* Return whether we started on a word. */ return started_on_word; }