/* 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); }
/* 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 first line of the file. */ void do_first_line(void) { filestruct *current_save = openfile->current; size_t pww_save = openfile->placewewant; openfile->current = openfile->fileage; openfile->current_x = 0; openfile->placewewant = 0; edit_redraw(current_save, pww_save); }
/* 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 next block of text in the file. */ void do_next_block(void) { filestruct *was_current = openfile->current; bool is_white = white_string(openfile->current->data); bool seen_white = is_white; /* Skip forward until first nonblank line after some blank line(s). */ while (openfile->current->next != NULL && (!seen_white || is_white)) { openfile->current = openfile->current->next; is_white = white_string(openfile->current->data); seen_white = seen_white || is_white; } openfile->current_x = 0; edit_redraw(was_current); }
/* Move up to the beginning of the last beginning-of-paragraph line * before the current line. If allow_update is TRUE, update the screen * afterwards. */ void do_para_begin(bool allow_update) { filestruct *was_current = openfile->current; if (openfile->current != openfile->fileage) { do { openfile->current = openfile->current->prev; openfile->current_y--; } while (!begpar(openfile->current)); } openfile->current_x = 0; if (allow_update) edit_redraw(was_current); }
/* 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 up to the beginning of the last beginning-of-paragraph line * before the current line. If allow_update is TRUE, update the screen * afterwards. */ void do_para_begin(bool allow_update) { filestruct *current_save = openfile->current; const size_t pww_save = openfile->placewewant; if (openfile->current != openfile->fileage) { do { openfile->current = openfile->current->prev; openfile->current_y--; } while (!begpar(openfile->current)); } openfile->current_x = 0; openfile->placewewant = 0; if (allow_update) edit_redraw(current_save, pww_save); }
/* 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(); }
/* 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) { filestruct *was_current = openfile->current; bool started_on_word = is_word_mbchar(openfile->current->data + openfile->current_x, allow_punct); bool seen_space = !started_on_word; assert(openfile->current != NULL && openfile->current->data != NULL); /* Move forward until we reach the start of a word. */ while (TRUE) { /* If at the end of a line, move to the beginning of the next one. */ if (openfile->current->data[openfile->current_x] == '\0') { /* If at the end of the file, stop. */ if (openfile->current->next == NULL) break; openfile->current = openfile->current->next; openfile->current_x = 0; seen_space = TRUE; } else { /* Step forward one character. */ openfile->current_x = move_mbright(openfile->current->data, openfile->current_x); } /* If this is not a word character, then it's a separator; else * if we've already seen a separator, then it's a word start. */ if (!is_word_mbchar(openfile->current->data + openfile->current_x, allow_punct)) seen_space = TRUE; else if (seen_space) break; } /* If allow_update is TRUE, update the screen. */ if (allow_update) { focusing = FALSE; edit_redraw(was_current); } /* Return whether we started on a word. */ return started_on_word; }
/* Move to the preceding block of text in the file. */ void do_prev_block(void) { filestruct *was_current = openfile->current; bool is_text = FALSE, seen_text = FALSE; /* Skip backward until first blank line after some nonblank line(s). */ while (openfile->current->prev != NULL && (!seen_text || is_text)) { openfile->current = openfile->current->prev; is_text = !white_string(openfile->current->data); seen_text = seen_text || is_text; } /* Step forward one line again if this one is blank. */ if (openfile->current->next != NULL && white_string(openfile->current->data)) openfile->current = openfile->current->next; openfile->current_x = 0; edit_redraw(was_current); }
/* 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 *was_current = openfile->current; 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; } else openfile->current_x = strlen(openfile->current->data); if (allow_update) edit_redraw(was_current); }
/* 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; }
/* 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; }
/* Search for a match to the bracket at the current cursor position, if * there is one. */ void do_find_bracket(void) { linestruct *current_save; size_t current_x_save, pww_save; const char *ch; /* The location in matchbrackets of the bracket at the current * cursor position. */ int ch_len; /* The length of ch in bytes. */ const char *wanted_ch; /* The location in matchbrackets of the bracket complementing * the bracket at the current cursor position. */ int wanted_ch_len; /* The length of wanted_ch in bytes. */ char *bracket_set; /* The pair of characters in ch and wanted_ch. */ size_t i; /* Generic loop variable. */ size_t matchhalf; /* The number of single-byte characters in one half of * matchbrackets. */ size_t mbmatchhalf; /* The number of multibyte characters in one half of * matchbrackets. */ size_t count = 1; /* The initial bracket count. */ bool reverse; /* The direction we search. */ char *found_ch; /* The character we find. */ assert(mbstrlen(matchbrackets) % 2 == 0); ch = openfile->current->data + openfile->current_x; if (ch == '\0' || (ch = mbstrchr(matchbrackets, ch)) == NULL) { statusbar(_("Not a bracket")); return; } /* Save where we are. */ current_save = openfile->current; current_x_save = openfile->current_x; pww_save = openfile->placewewant; /* If we're on an opening bracket, which must be in the first half * of matchbrackets, we want to search forwards for a closing * bracket. If we're on a closing bracket, which must be in the * second half of matchbrackets, we want to search backwards for an * opening bracket. */ matchhalf = 0; mbmatchhalf = mbstrlen(matchbrackets) / 2; for (i = 0; i < mbmatchhalf; i++) matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, NULL); reverse = ((ch - matchbrackets) >= matchhalf); /* If we're on an opening bracket, set wanted_ch to the character * that's matchhalf characters after ch. If we're on a closing * bracket, set wanted_ch to the character that's matchhalf * characters before ch. */ wanted_ch = ch; while (mbmatchhalf > 0) { if (reverse) wanted_ch = matchbrackets + move_mbleft(matchbrackets, wanted_ch - matchbrackets); else wanted_ch += move_mbright(wanted_ch, 0); mbmatchhalf--; } ch_len = parse_mbchar(ch, NULL, NULL); wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL); /* Fill bracket_set in with the values of ch and wanted_ch. */ bracket_set = charalloc((mb_cur_max() * 2) + 1); strncpy(bracket_set, ch, ch_len); strncpy(bracket_set + ch_len, wanted_ch, wanted_ch_len); null_at(&bracket_set, ch_len + wanted_ch_len); found_ch = charalloc(mb_cur_max() + 1); while (TRUE) { if (find_bracket_match(reverse, bracket_set)) { /* If we found an identical bracket, increment count. If we * found a complementary bracket, decrement it. */ parse_mbchar(openfile->current->data + openfile->current_x, found_ch, NULL); count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1; /* If count is zero, we've found a matching bracket. Update * the screen and get out. */ if (count == 0) { edit_redraw(current_save, pww_save); break; } } else { /* We didn't find either an opening or closing bracket. * Indicate this, restore where we were, and get out. */ statusbar(_("No matching bracket")); openfile->current = current_save; openfile->current_x = current_x_save; openfile->placewewant = pww_save; break; } } /* Clean up. */ free(bracket_set); free(found_ch); }