/* * Return appropriate space number for breakindent, taking influencing * parameters into account. Window must be specified, since it is not * necessarily always the current one. */ int get_breakindent_win(win_T *wp, char_u *line) { static int prev_indent = 0; /* cached indent value */ static int prev_ts = 0L; /* cached tabstop value */ static char_u *prev_line = NULL; /* cached pointer to line */ int bri = 0; /* window width minus window margin space, i.e. what rests for text */ const int eff_wwidth = wp->w_width - ((wp->w_p_nu || wp->w_p_rnu) && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) ? number_width(wp) + 1 : 0); /* used cached indent, unless pointer or 'tabstop' changed */ if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts) { prev_line = line; prev_ts = wp->w_buffer->b_p_ts; prev_indent = get_indent_str(line, (int)wp->w_buffer->b_p_ts, wp->w_p_list); } bri = prev_indent + wp->w_p_brishift; /* indent minus the length of the showbreak string */ if (wp->w_p_brisbr) bri -= vim_strsize(p_sbr); /* Add offset for number column, if 'n' is in 'cpoptions' */ bri += win_col_off2(wp); /* never indent past left window margin */ if (bri < 0) bri = 0; /* always leave at least bri_min characters on the left, * if text width is sufficient */ else if (bri > eff_wwidth - wp->w_p_brimin) bri = (eff_wwidth - wp->w_p_brimin < 0) ? 0 : eff_wwidth - wp->w_p_brimin; return bri; }
// Compute the position in the buffer line from the posn on the screen in // window "win". // Returns true if the position is below the last line. bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) { int col = *colp; int row = *rowp; linenr_T lnum; bool retval = false; int off; int count; if (win->w_p_rl) col = win->w_width - 1 - col; lnum = win->w_topline; while (row > 0) { // Don't include filler lines in "count" if (win->w_p_diff && !hasFoldingWin(win, lnum, NULL, NULL, true, NULL)) { if (lnum == win->w_topline) { row -= win->w_topfill; } else { row -= diff_check_fill(win, lnum); } count = plines_win_nofill(win, lnum, true); } else { count = plines_win(win, lnum, true); } if (count > row) { break; // Position is in this buffer line. } (void)hasFoldingWin(win, lnum, NULL, &lnum, true, NULL); if (lnum == win->w_buffer->b_ml.ml_line_count) { retval = true; break; // past end of file } row -= count; ++lnum; } if (!retval) { // Compute the column without wrapping. off = win_col_off(win) - win_col_off2(win); if (col < off) col = off; col += row * (win->w_width - off); // add skip column (for long wrapping line) col += win->w_skipcol; } if (!win->w_p_wrap) { col += win->w_leftcol; } // skip line number and fold column in front of the line col -= win_col_off(win); if (col < 0) { col = 0; } *colp = col; *rowp = row; *lnump = lnum; return retval; }
// Adjust the clicked column position if there are concealed characters // before the current column. But only when it's absolutely necessary. static int mouse_adjust_click(win_T *wp, int row, int col) { if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0 && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) { return col; } int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum)); int vend = getviscol2(end, 0); if (col >= vend) { return col; } int i = wp->w_leftcol; if (row > 0) { i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - wp->w_leftcol) + wp->w_skipcol; } int start_col = i; int matchid; int last_matchid; int bcol = end - (vend - col); while (i < bcol) { matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); if (matchid != 0) { if (wp->w_p_cole == 3) { bcol++; } else { if (row > 0 && i == start_col) { // Check if the current concealed character is actually part of // the previous wrapped row's conceal group. last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i - 1); if (last_matchid == matchid) { bcol++; } } else if (wp->w_p_cole == 1 || (wp->w_p_cole == 2 && (lcs_conceal != NUL || syn_get_sub_char() != NUL))) { // At least one placeholder character will be displayed. bcol--; } last_matchid = matchid; // Adjust for concealed text that spans more than one character. do { i++; bcol++; matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); } while (last_matchid == matchid); continue; } } i++; } return getviscol2(bcol, 0); }
/// Adjusts the clicked column position when 'conceallevel' > 0 static int mouse_adjust_click(win_T *wp, int row, int col) { if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0 && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) { return col; } // `col` is the position within the current line that is highlighted by the // cursor without consideration for concealed characters. The current line is // scanned *up to* `col`, nudging it left or right when concealed characters // are encountered. // // chartabsize() is used to keep track of the virtual column position relative // to the line's bytes. For example: if col == 9 and the line starts with a // tab that's 8 columns wide, we would want the cursor to be highlighting the // second byte, not the ninth. linenr_T lnum = wp->w_cursor.lnum; char_u *line = ml_get(lnum); char_u *ptr = line; char_u *ptr_end = line; char_u *ptr_row_offset = line; // Where we begin adjusting `ptr_end` // Find the offset where scanning should begin. int offset = wp->w_leftcol; if (row > 0) { offset += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - wp->w_leftcol + wp->w_skipcol); } int vcol; if (offset) { // Skip everything up to an offset since nvim takes care of displaying the // correct portion of the line when horizontally scrolling. // When 'wrap' is enabled, only the row (of the wrapped line) needs to be // checked for concealed characters. vcol = 0; while (vcol < offset && *ptr != NUL) { vcol += chartabsize(ptr, vcol); ptr += utfc_ptr2len(ptr); } ptr_row_offset = ptr; } // Align `ptr_end` with `col` vcol = offset; ptr_end = ptr_row_offset; while (vcol < col && *ptr_end != NUL) { vcol += chartabsize(ptr_end, vcol); ptr_end += utfc_ptr2len(ptr_end); } int matchid; int prev_matchid; int nudge = 0; int cwidth = 0; vcol = offset; #define incr() nudge++; ptr_end += utfc_ptr2len(ptr_end) #define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end && *ptr != NUL) { cwidth = chartabsize(ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. cwidth = MIN(cwidth, nudge); while (cwidth > 0) { decr(); cwidth--; } } matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); if (matchid != 0) { if (wp->w_p_cole == 3) { incr(); } else { if (!(row > 0 && ptr == ptr_row_offset) && (wp->w_p_cole == 1 || (wp->w_p_cole == 2 && (lcs_conceal != NUL || syn_get_sub_char() != NUL)))) { // At least one placeholder character will be displayed. decr(); } prev_matchid = matchid; while (prev_matchid == matchid && *ptr != NUL) { incr(); ptr += utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); } continue; } } ptr += utfc_ptr2len(ptr); } return col + nudge; }