diff --git a/src/proto.h b/src/proto.h index f2246fa7ea5f978568cc0a91ed1eaa1d8a0b6868..d6837c498afefe230da15091287292ee2d1392bf 100644 --- a/src/proto.h +++ b/src/proto.h @@ -663,6 +663,9 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge); bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge); void edit_scroll(scroll_dir direction, int nrows); #ifndef NANO_TINY +size_t get_softwrap_breakpoint(const char *text, size_t leftedge, + bool *end_of_line); +size_t get_chunk(filestruct *line, size_t column, size_t *leftedge); void ensure_firstcolumn_is_aligned(void); #endif void edit_redraw(filestruct *old_current); diff --git a/src/winio.c b/src/winio.c index afce1136919148e9f3ebc8a2b154491e9611febf..deb25be315a9394140ea04a9d4aa57f826470afc 100644 --- a/src/winio.c +++ b/src/winio.c @@ -2974,6 +2974,71 @@ void edit_scroll(scroll_dir direction, int nrows) } #ifndef NANO_TINY +/* Get the column number after leftedge where we can break the given text, and + * return it. This will always be editwincols or less after leftedge. Set + * end_of_line to TRUE if we reach the end of the line while searching the + * text. Assume leftedge is the leftmost column of a softwrapped chunk. */ +size_t get_softwrap_breakpoint(const char *text, size_t leftedge, + bool *end_of_line) +{ + size_t column = 0; + /* Current column position in text. */ + size_t prev_column = 0; + /* Previous column position in text. */ + size_t goal_column; + /* Column of the last character where we can break the text. */ + int char_len = 0; + /* Length of current character, in bytes. */ + + *end_of_line = FALSE; + + while (*text != '\0' && column < leftedge) + text += parse_mbchar(text, NULL, &column); + + /* Use a full screen row for text. */ + goal_column = column + editwincols; + + while (*text != '\0' && column <= goal_column) { + prev_column = column; + char_len = parse_mbchar(text, NULL, &column); + text += char_len; + } + + /* If the text displays within goal_column, we've reached the end of the + * line, and we're done. */ + if (column <= goal_column) { + *end_of_line = TRUE; + return column; + } + + /* Otherwise, return the column of the last character before goal_column, + * since we can't break the text anywhere else. */ + return (editwincols > 2) ? prev_column : column - 1; +} + +/* Get the row of the softwrapped chunk of the given line that column is on, + * relative to the first row (zero-based), and return it. If leftedge isn't + * NULL, return the leftmost column of the chunk in it. */ +size_t get_chunk(filestruct *line, size_t column, size_t *leftedge) +{ + size_t current_chunk = 0, start_col = 0, end_col; + bool end_of_line; + + while (TRUE) { + end_col = get_softwrap_breakpoint(line->data, start_col, &end_of_line); + + /* We reached the end of the line and/or found column, so get out. */ + if (end_of_line || (column >= start_col && column < end_col)) { + if (leftedge != NULL) + *leftedge = start_col; + return current_chunk; + } + + current_chunk++; + start_col = end_col; + } +} + /* Ensure that firstcolumn is at the starting column of the softwrapped chunk * it's on. We need to do this when the number of columns of the edit window * has changed, because then the width of softwrapped chunks has changed. */