mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
@@ -18,24 +18,17 @@
|
|||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
#include "nvim/eval/typval.h"
|
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/garray.h"
|
#include "nvim/garray.h"
|
||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/grid_defs.h"
|
#include "nvim/grid_defs.h"
|
||||||
#include "nvim/indent.h"
|
|
||||||
#include "nvim/keycodes.h"
|
#include "nvim/keycodes.h"
|
||||||
#include "nvim/macros.h"
|
#include "nvim/macros.h"
|
||||||
#include "nvim/mark.h"
|
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/move.h"
|
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
#include "nvim/plines.h"
|
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
#include "nvim/state.h"
|
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
|
|
||||||
@@ -921,298 +914,6 @@ bool vim_isprintc_strict(int c)
|
|||||||
return c > 0 && (g_chartab[c] & CT_PRINT_CHAR);
|
return c > 0 && (g_chartab[c] & CT_PRINT_CHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that virtual column "vcol" is in the rightmost column of window "wp".
|
|
||||||
///
|
|
||||||
/// @param wp window
|
|
||||||
/// @param vcol column number
|
|
||||||
bool in_win_border(win_T *wp, colnr_T vcol)
|
|
||||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
|
|
||||||
{
|
|
||||||
if (wp->w_width_inner == 0) {
|
|
||||||
// there is no border
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int width1 = wp->w_width_inner - win_col_off(wp); // width of first line (after line number)
|
|
||||||
|
|
||||||
if ((int)vcol < width1 - 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((int)vcol == width1 - 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
int width2 = width1 + win_col_off2(wp); // width of further lines
|
|
||||||
|
|
||||||
if (width2 <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (vcol - width1) % width2 == width2 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get virtual column number of pos.
|
|
||||||
/// start: on the first position of this character (TAB, ctrl)
|
|
||||||
/// cursor: where the cursor is on this character (first char, except for TAB)
|
|
||||||
/// end: on the last position of this character (TAB, ctrl)
|
|
||||||
///
|
|
||||||
/// This is used very often, keep it fast!
|
|
||||||
///
|
|
||||||
/// @param wp
|
|
||||||
/// @param pos
|
|
||||||
/// @param start
|
|
||||||
/// @param cursor
|
|
||||||
/// @param end
|
|
||||||
void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
|
|
||||||
{
|
|
||||||
char *ptr; // points to current char
|
|
||||||
char *posptr; // points to char at pos->col
|
|
||||||
int incr;
|
|
||||||
int head;
|
|
||||||
long *vts = wp->w_buffer->b_p_vts_array;
|
|
||||||
int ts = (int)wp->w_buffer->b_p_ts;
|
|
||||||
|
|
||||||
colnr_T vcol = 0;
|
|
||||||
char *line = ptr = ml_get_buf(wp->w_buffer, pos->lnum); // start of the line
|
|
||||||
|
|
||||||
if (pos->col == MAXCOL) {
|
|
||||||
// continue until the NUL
|
|
||||||
posptr = NULL;
|
|
||||||
} else {
|
|
||||||
// In a few cases the position can be beyond the end of the line.
|
|
||||||
for (colnr_T i = 0; i < pos->col; i++) {
|
|
||||||
if (ptr[i] == NUL) {
|
|
||||||
pos->col = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
posptr = ptr + pos->col;
|
|
||||||
posptr -= utf_head_off(line, posptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
chartabsize_T cts;
|
|
||||||
bool on_NUL = false;
|
|
||||||
init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
|
|
||||||
cts.cts_max_head_vcol = -1;
|
|
||||||
|
|
||||||
// This function is used very often, do some speed optimizations.
|
|
||||||
// When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
|
|
||||||
// and there are no virtual text use a simple loop.
|
|
||||||
// Also use this when 'list' is set but tabs take their normal size.
|
|
||||||
if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL))
|
|
||||||
&& !wp->w_p_lbr
|
|
||||||
&& *get_showbreak_value(wp) == NUL
|
|
||||||
&& !wp->w_p_bri
|
|
||||||
&& !cts.cts_has_virt_text) {
|
|
||||||
while (true) {
|
|
||||||
head = 0;
|
|
||||||
int c = (uint8_t)(*ptr);
|
|
||||||
|
|
||||||
// make sure we don't go past the end of the line
|
|
||||||
if (c == NUL) {
|
|
||||||
// NUL at end of line only takes one column
|
|
||||||
incr = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A tab gets expanded, depending on the current column
|
|
||||||
if (c == TAB) {
|
|
||||||
incr = tabstop_padding(vcol, ts, vts);
|
|
||||||
} else {
|
|
||||||
// For utf-8, if the byte is >= 0x80, need to look at
|
|
||||||
// further bytes to find the cell width.
|
|
||||||
if (c >= 0x80) {
|
|
||||||
incr = utf_ptr2cells(ptr);
|
|
||||||
} else {
|
|
||||||
incr = g_chartab[c] & CT_CELL_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a double-cell char doesn't fit at the end of a line
|
|
||||||
// it wraps to the next line, it's like this char is three
|
|
||||||
// cells wide.
|
|
||||||
if ((incr == 2)
|
|
||||||
&& wp->w_p_wrap
|
|
||||||
&& (MB_BYTE2LEN((uint8_t)(*ptr)) > 1)
|
|
||||||
&& in_win_border(wp, vcol)) {
|
|
||||||
incr++;
|
|
||||||
head = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((posptr != NULL) && (ptr >= posptr)) {
|
|
||||||
// character at pos->col
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vcol += incr;
|
|
||||||
MB_PTR_ADV(ptr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (true) {
|
|
||||||
// A tab gets expanded, depending on the current column
|
|
||||||
// Other things also take up space.
|
|
||||||
head = 0;
|
|
||||||
incr = win_lbr_chartabsize(&cts, &head);
|
|
||||||
|
|
||||||
// make sure we don't go past the end of the line
|
|
||||||
if (*cts.cts_ptr == NUL) {
|
|
||||||
// NUL at end of line only takes one column, unless there is virtual text
|
|
||||||
incr = MAX(1, cts.cts_cur_text_width_left + cts.cts_cur_text_width_right);
|
|
||||||
on_NUL = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((posptr != NULL) && (cts.cts_ptr >= posptr)) {
|
|
||||||
// character at pos->col
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cts.cts_vcol += incr;
|
|
||||||
MB_PTR_ADV(cts.cts_ptr);
|
|
||||||
}
|
|
||||||
vcol = cts.cts_vcol;
|
|
||||||
ptr = cts.cts_ptr;
|
|
||||||
}
|
|
||||||
clear_chartabsize_arg(&cts);
|
|
||||||
|
|
||||||
if (start != NULL) {
|
|
||||||
*start = vcol + head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end != NULL) {
|
|
||||||
*end = vcol + incr - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != NULL) {
|
|
||||||
if ((*ptr == TAB)
|
|
||||||
&& (State & MODE_NORMAL)
|
|
||||||
&& !wp->w_p_list
|
|
||||||
&& !virtual_active()
|
|
||||||
&& !(VIsual_active && ((*p_sel == 'e') || ltoreq(*pos, VIsual)))) {
|
|
||||||
// cursor at end
|
|
||||||
*cursor = vcol + incr - 1;
|
|
||||||
} else {
|
|
||||||
if (!on_NUL || !(State & MODE_NORMAL)) {
|
|
||||||
vcol += cts.cts_cur_text_width_left;
|
|
||||||
}
|
|
||||||
if (!on_NUL && (State & MODE_NORMAL)) {
|
|
||||||
vcol += cts.cts_cur_text_width_right;
|
|
||||||
}
|
|
||||||
// cursor at start
|
|
||||||
*cursor = vcol + head;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get virtual cursor column in the current window, pretending 'list' is off.
|
|
||||||
///
|
|
||||||
/// @param posp
|
|
||||||
///
|
|
||||||
/// @retujrn The virtual cursor column.
|
|
||||||
colnr_T getvcol_nolist(pos_T *posp)
|
|
||||||
{
|
|
||||||
int list_save = curwin->w_p_list;
|
|
||||||
colnr_T vcol;
|
|
||||||
|
|
||||||
curwin->w_p_list = false;
|
|
||||||
if (posp->coladd) {
|
|
||||||
getvvcol(curwin, posp, NULL, &vcol, NULL);
|
|
||||||
} else {
|
|
||||||
getvcol(curwin, posp, NULL, &vcol, NULL);
|
|
||||||
}
|
|
||||||
curwin->w_p_list = list_save;
|
|
||||||
return vcol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get virtual column in virtual mode.
|
|
||||||
///
|
|
||||||
/// @param wp
|
|
||||||
/// @param pos
|
|
||||||
/// @param start
|
|
||||||
/// @param cursor
|
|
||||||
/// @param end
|
|
||||||
void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
|
|
||||||
{
|
|
||||||
colnr_T col;
|
|
||||||
|
|
||||||
if (virtual_active()) {
|
|
||||||
// For virtual mode, only want one value
|
|
||||||
getvcol(wp, pos, &col, NULL, NULL);
|
|
||||||
|
|
||||||
colnr_T coladd = pos->coladd;
|
|
||||||
colnr_T endadd = 0;
|
|
||||||
|
|
||||||
// Cannot put the cursor on part of a wide character.
|
|
||||||
char *ptr = ml_get_buf(wp->w_buffer, pos->lnum);
|
|
||||||
|
|
||||||
if (pos->col < (colnr_T)strlen(ptr)) {
|
|
||||||
int c = utf_ptr2char(ptr + pos->col);
|
|
||||||
if ((c != TAB) && vim_isprintc(c)) {
|
|
||||||
endadd = (colnr_T)(char2cells(c) - 1);
|
|
||||||
if (coladd > endadd) {
|
|
||||||
// past end of line
|
|
||||||
endadd = 0;
|
|
||||||
} else {
|
|
||||||
coladd = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
col += coladd;
|
|
||||||
|
|
||||||
if (start != NULL) {
|
|
||||||
*start = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != NULL) {
|
|
||||||
*cursor = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end != NULL) {
|
|
||||||
*end = col + endadd;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getvcol(wp, pos, start, cursor, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the leftmost and rightmost virtual column of pos1 and pos2.
|
|
||||||
/// Used for Visual block mode.
|
|
||||||
///
|
|
||||||
/// @param wp
|
|
||||||
/// @param pos1
|
|
||||||
/// @param pos2
|
|
||||||
/// @param left
|
|
||||||
/// @param right
|
|
||||||
void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right)
|
|
||||||
{
|
|
||||||
colnr_T from1;
|
|
||||||
colnr_T from2;
|
|
||||||
colnr_T to1;
|
|
||||||
colnr_T to2;
|
|
||||||
|
|
||||||
if (lt(*pos1, *pos2)) {
|
|
||||||
getvvcol(wp, pos1, &from1, NULL, &to1);
|
|
||||||
getvvcol(wp, pos2, &from2, NULL, &to2);
|
|
||||||
} else {
|
|
||||||
getvvcol(wp, pos2, &from1, NULL, &to1);
|
|
||||||
getvvcol(wp, pos1, &from2, NULL, &to2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from2 < from1) {
|
|
||||||
*left = from2;
|
|
||||||
} else {
|
|
||||||
*left = from1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to2 > to1) {
|
|
||||||
if ((*p_sel == 'e') && (from2 - 1 >= to1)) {
|
|
||||||
*right = from2 - 1;
|
|
||||||
} else {
|
|
||||||
*right = to2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*right = to1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// skipwhite: skip over ' ' and '\t'.
|
/// skipwhite: skip over ' ' and '\t'.
|
||||||
///
|
///
|
||||||
/// @param[in] p String to skip in.
|
/// @param[in] p String to skip in.
|
||||||
|
@@ -2,13 +2,12 @@
|
|||||||
#define NVIM_CHARSET_H
|
#define NVIM_CHARSET_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/option_defs.h"
|
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/types.h"
|
|
||||||
|
|
||||||
/// Return the folded-case equivalent of the given character
|
/// Return the folded-case equivalent of the given character
|
||||||
///
|
///
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
|
#include "nvim/plines.h"
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
#include "nvim/search.h"
|
#include "nvim/search.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
// plines.c: calculate the vertical and horizontal size of text in a window
|
// plines.c: calculate the vertical and horizontal size of text in a window
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -17,214 +16,21 @@
|
|||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/macros.h"
|
#include "nvim/macros.h"
|
||||||
|
#include "nvim/mark.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/plines.h"
|
#include "nvim/plines.h"
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
|
#include "nvim/state.h"
|
||||||
|
#include "nvim/types.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "plines.c.generated.h"
|
# include "plines.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Functions calculating vertical size of text when displayed inside a window.
|
|
||||||
/// Calls horizontal size functions defined below.
|
|
||||||
|
|
||||||
/// Return the number of window lines occupied by buffer line "lnum".
|
|
||||||
/// Includes any filler lines.
|
|
||||||
///
|
|
||||||
/// @param limit_winheight when true limit to window height
|
|
||||||
int plines_win(win_T *wp, linenr_T lnum, bool limit_winheight)
|
|
||||||
{
|
|
||||||
// Check for filler lines above this buffer line.
|
|
||||||
return plines_win_nofill(wp, lnum, limit_winheight) + win_get_fill(wp, lnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the number of filler lines above "lnum".
|
|
||||||
///
|
|
||||||
/// @param wp
|
|
||||||
/// @param lnum
|
|
||||||
///
|
|
||||||
/// @return Number of filler lines above lnum
|
|
||||||
int win_get_fill(win_T *wp, linenr_T lnum)
|
|
||||||
{
|
|
||||||
int virt_lines = decor_virt_lines(wp, lnum, NULL, kNone);
|
|
||||||
|
|
||||||
// be quick when there are no filler lines
|
|
||||||
if (diffopt_filler()) {
|
|
||||||
int n = diff_check(wp, lnum);
|
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
return virt_lines + n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return virt_lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool win_may_fill(win_T *wp)
|
|
||||||
{
|
|
||||||
return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the number of window lines occupied by buffer line "lnum".
|
|
||||||
/// Does not include filler lines.
|
|
||||||
///
|
|
||||||
/// @param limit_winheight when true limit to window height
|
|
||||||
int plines_win_nofill(win_T *wp, linenr_T lnum, bool limit_winheight)
|
|
||||||
{
|
|
||||||
if (!wp->w_p_wrap) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wp->w_width_inner == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folded lines are handled just like an empty line.
|
|
||||||
if (lineFolded(wp, lnum)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int lines = plines_win_nofold(wp, lnum);
|
|
||||||
if (limit_winheight && lines > wp->w_height_inner) {
|
|
||||||
return wp->w_height_inner;
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get number of window lines physical line "lnum" will occupy in window "wp".
|
|
||||||
/// Does not care about folding, 'wrap' or filler lines.
|
|
||||||
int plines_win_nofold(win_T *wp, linenr_T lnum)
|
|
||||||
{
|
|
||||||
char *s = ml_get_buf(wp->w_buffer, lnum);
|
|
||||||
chartabsize_T cts;
|
|
||||||
init_chartabsize_arg(&cts, wp, lnum, 0, s, s);
|
|
||||||
if (*s == NUL && !cts.cts_has_virt_text) {
|
|
||||||
return 1; // be quick for an empty line
|
|
||||||
}
|
|
||||||
win_linetabsize_cts(&cts, (colnr_T)MAXCOL);
|
|
||||||
clear_chartabsize_arg(&cts);
|
|
||||||
int64_t col = cts.cts_vcol;
|
|
||||||
|
|
||||||
// If list mode is on, then the '$' at the end of the line may take up one
|
|
||||||
// extra column.
|
|
||||||
if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) {
|
|
||||||
col += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
|
|
||||||
int width = wp->w_width_inner - win_col_off(wp);
|
|
||||||
if (width <= 0) {
|
|
||||||
return 32000; // bigger than the number of screen lines
|
|
||||||
}
|
|
||||||
if (col <= width) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
col -= width;
|
|
||||||
width += win_col_off2(wp);
|
|
||||||
const int64_t lines = (col + (width - 1)) / width + 1;
|
|
||||||
return (lines > 0 && lines <= INT_MAX) ? (int)lines : INT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like plines_win(), but only reports the number of physical screen lines
|
|
||||||
/// used from the start of the line to the given column number.
|
|
||||||
int plines_win_col(win_T *wp, linenr_T lnum, long column)
|
|
||||||
{
|
|
||||||
// Check for filler lines above this buffer line.
|
|
||||||
int lines = win_get_fill(wp, lnum);
|
|
||||||
|
|
||||||
if (!wp->w_p_wrap) {
|
|
||||||
return lines + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wp->w_width_inner == 0) {
|
|
||||||
return lines + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *line = ml_get_buf(wp->w_buffer, lnum);
|
|
||||||
|
|
||||||
colnr_T col = 0;
|
|
||||||
chartabsize_T cts;
|
|
||||||
|
|
||||||
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
|
|
||||||
while (*cts.cts_ptr != NUL && --column >= 0) {
|
|
||||||
cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
|
|
||||||
MB_PTR_ADV(cts.cts_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If *cts.cts_ptr is a TAB, and the TAB is not displayed as ^I, and we're not
|
|
||||||
// in MODE_INSERT state, then col must be adjusted so that it represents the
|
|
||||||
// last screen position of the TAB. This only fixes an error when the TAB
|
|
||||||
// wraps from one screen line to the next (when 'columns' is not a multiple
|
|
||||||
// of 'ts') -- webb.
|
|
||||||
col = cts.cts_vcol;
|
|
||||||
if (*cts.cts_ptr == TAB && (State & MODE_NORMAL)
|
|
||||||
&& (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
|
|
||||||
col += win_lbr_chartabsize(&cts, NULL) - 1;
|
|
||||||
}
|
|
||||||
clear_chartabsize_arg(&cts);
|
|
||||||
|
|
||||||
// Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
|
|
||||||
int width = wp->w_width_inner - win_col_off(wp);
|
|
||||||
if (width <= 0) {
|
|
||||||
return 9999;
|
|
||||||
}
|
|
||||||
|
|
||||||
lines += 1;
|
|
||||||
if (col > width) {
|
|
||||||
lines += (col - width) / (width + win_col_off2(wp)) + 1;
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the number of screen lines buffer line "lnum" will take in window "wp".
|
|
||||||
/// This takes care of both folds and topfill.
|
|
||||||
///
|
|
||||||
/// XXX: Because of topfill, this only makes sense when lnum >= wp->w_topline.
|
|
||||||
///
|
|
||||||
/// @param[in] wp window the line is in
|
|
||||||
/// @param[in] lnum line number
|
|
||||||
/// @param[out] nextp if not NULL, the line after a fold
|
|
||||||
/// @param[out] foldedp if not NULL, whether lnum is on a fold
|
|
||||||
/// @param[in] cache whether to use the window's cache for folds
|
|
||||||
/// @param[in] limit_winheight when true limit to window height
|
|
||||||
///
|
|
||||||
/// @return the total number of screen lines
|
|
||||||
int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const foldedp,
|
|
||||||
const bool cache, const bool limit_winheight)
|
|
||||||
{
|
|
||||||
bool folded = hasFoldingWin(wp, lnum, &lnum, nextp, cache, NULL);
|
|
||||||
if (foldedp != NULL) {
|
|
||||||
*foldedp = folded;
|
|
||||||
}
|
|
||||||
return ((folded ? 1 : plines_win_nofill(wp, lnum, limit_winheight)) +
|
|
||||||
(lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the number of screen lines a range of buffer lines will take in window "wp".
|
|
||||||
/// This takes care of both folds and topfill.
|
|
||||||
///
|
|
||||||
/// XXX: Because of topfill, this only makes sense when first >= wp->w_topline.
|
|
||||||
///
|
|
||||||
/// @param first first line number
|
|
||||||
/// @param last last line number
|
|
||||||
/// @param limit_winheight when true limit each line to window height
|
|
||||||
///
|
|
||||||
/// @see win_text_height
|
|
||||||
int plines_m_win(win_T *wp, linenr_T first, linenr_T last, bool limit_winheight)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while (first <= last) {
|
|
||||||
linenr_T next = first;
|
|
||||||
count += plines_win_full(wp, first, &next, NULL, false, limit_winheight);
|
|
||||||
first = next + 1;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Functions calculating horizontal size of text, when displayed in a window.
|
/// Functions calculating horizontal size of text, when displayed in a window.
|
||||||
|
|
||||||
/// Return the number of characters 'c' will take on the screen, taking
|
/// Return the number of characters 'c' will take on the screen, taking
|
||||||
@@ -563,13 +369,7 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
|
|||||||
head += (max_head_vcol - (vcol + head_prev + prev_rem)
|
head += (max_head_vcol - (vcol + head_prev + prev_rem)
|
||||||
+ width2 - 1) / width2 * head_mid;
|
+ width2 - 1) / width2 * head_mid;
|
||||||
} else if (max_head_vcol < 0) {
|
} else if (max_head_vcol < 0) {
|
||||||
int off = 0;
|
int off = virt_text_cursor_off(cts, c == NUL);
|
||||||
if (c != NUL || !(State & MODE_NORMAL)) {
|
|
||||||
off += cts->cts_cur_text_width_left;
|
|
||||||
}
|
|
||||||
if (c != NUL && (State & MODE_NORMAL)) {
|
|
||||||
off += cts->cts_cur_text_width_right;
|
|
||||||
}
|
|
||||||
if (off >= prev_rem) {
|
if (off >= prev_rem) {
|
||||||
head += (1 + (off - prev_rem) / width) * head_mid;
|
head += (1 + (off - prev_rem) / width) * head_mid;
|
||||||
}
|
}
|
||||||
@@ -619,6 +419,507 @@ static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that virtual column "vcol" is in the rightmost column of window "wp".
|
||||||
|
///
|
||||||
|
/// @param wp window
|
||||||
|
/// @param vcol column number
|
||||||
|
static bool in_win_border(win_T *wp, colnr_T vcol)
|
||||||
|
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
|
||||||
|
{
|
||||||
|
if (wp->w_width_inner == 0) {
|
||||||
|
// there is no border
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int width1 = wp->w_width_inner - win_col_off(wp); // width of first line (after line number)
|
||||||
|
|
||||||
|
if ((int)vcol < width1 - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)vcol == width1 - 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int width2 = width1 + win_col_off2(wp); // width of further lines
|
||||||
|
|
||||||
|
if (width2 <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (vcol - width1) % width2 == width2 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get how many virtual columns inline virtual text should offset the cursor.
|
||||||
|
///
|
||||||
|
/// @param cts should contain information stored by win_lbr_chartabsize()
|
||||||
|
/// about widths of left and right gravity virtual text
|
||||||
|
/// @param on_NUL whether this is the end of the line
|
||||||
|
static int virt_text_cursor_off(chartabsize_T *cts, bool on_NUL)
|
||||||
|
{
|
||||||
|
int off = 0;
|
||||||
|
if (!on_NUL || !(State & MODE_NORMAL)) {
|
||||||
|
off += cts->cts_cur_text_width_left;
|
||||||
|
}
|
||||||
|
if (!on_NUL && (State & MODE_NORMAL)) {
|
||||||
|
off += cts->cts_cur_text_width_right;
|
||||||
|
}
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get virtual column number of pos.
|
||||||
|
/// start: on the first position of this character (TAB, ctrl)
|
||||||
|
/// cursor: where the cursor is on this character (first char, except for TAB)
|
||||||
|
/// end: on the last position of this character (TAB, ctrl)
|
||||||
|
///
|
||||||
|
/// This is used very often, keep it fast!
|
||||||
|
///
|
||||||
|
/// @param wp
|
||||||
|
/// @param pos
|
||||||
|
/// @param start
|
||||||
|
/// @param cursor
|
||||||
|
/// @param end
|
||||||
|
void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
|
||||||
|
{
|
||||||
|
char *ptr; // points to current char
|
||||||
|
char *posptr; // points to char at pos->col
|
||||||
|
int incr;
|
||||||
|
int head;
|
||||||
|
long *vts = wp->w_buffer->b_p_vts_array;
|
||||||
|
int ts = (int)wp->w_buffer->b_p_ts;
|
||||||
|
|
||||||
|
colnr_T vcol = 0;
|
||||||
|
char *line = ptr = ml_get_buf(wp->w_buffer, pos->lnum); // start of the line
|
||||||
|
|
||||||
|
if (pos->col == MAXCOL) {
|
||||||
|
// continue until the NUL
|
||||||
|
posptr = NULL;
|
||||||
|
} else {
|
||||||
|
// In a few cases the position can be beyond the end of the line.
|
||||||
|
for (colnr_T i = 0; i < pos->col; i++) {
|
||||||
|
if (ptr[i] == NUL) {
|
||||||
|
pos->col = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
posptr = ptr + pos->col;
|
||||||
|
posptr -= utf_head_off(line, posptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
chartabsize_T cts;
|
||||||
|
bool on_NUL = false;
|
||||||
|
init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
|
||||||
|
cts.cts_max_head_vcol = -1;
|
||||||
|
|
||||||
|
// This function is used very often, do some speed optimizations.
|
||||||
|
// When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
|
||||||
|
// and there are no virtual text use a simple loop.
|
||||||
|
// Also use this when 'list' is set but tabs take their normal size.
|
||||||
|
if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL))
|
||||||
|
&& !wp->w_p_lbr
|
||||||
|
&& *get_showbreak_value(wp) == NUL
|
||||||
|
&& !wp->w_p_bri
|
||||||
|
&& !cts.cts_has_virt_text) {
|
||||||
|
while (true) {
|
||||||
|
head = 0;
|
||||||
|
int c = (uint8_t)(*ptr);
|
||||||
|
|
||||||
|
// make sure we don't go past the end of the line
|
||||||
|
if (c == NUL) {
|
||||||
|
// NUL at end of line only takes one column
|
||||||
|
incr = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A tab gets expanded, depending on the current column
|
||||||
|
if (c == TAB) {
|
||||||
|
incr = tabstop_padding(vcol, ts, vts);
|
||||||
|
} else {
|
||||||
|
// For utf-8, if the byte is >= 0x80, need to look at
|
||||||
|
// further bytes to find the cell width.
|
||||||
|
if (c >= 0x80) {
|
||||||
|
incr = utf_ptr2cells(ptr);
|
||||||
|
} else {
|
||||||
|
incr = byte2cells(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a double-cell char doesn't fit at the end of a line
|
||||||
|
// it wraps to the next line, it's like this char is three
|
||||||
|
// cells wide.
|
||||||
|
if ((incr == 2)
|
||||||
|
&& wp->w_p_wrap
|
||||||
|
&& (MB_BYTE2LEN((uint8_t)(*ptr)) > 1)
|
||||||
|
&& in_win_border(wp, vcol)) {
|
||||||
|
incr++;
|
||||||
|
head = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((posptr != NULL) && (ptr >= posptr)) {
|
||||||
|
// character at pos->col
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcol += incr;
|
||||||
|
MB_PTR_ADV(ptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
// A tab gets expanded, depending on the current column
|
||||||
|
// Other things also take up space.
|
||||||
|
head = 0;
|
||||||
|
incr = win_lbr_chartabsize(&cts, &head);
|
||||||
|
|
||||||
|
// make sure we don't go past the end of the line
|
||||||
|
if (*cts.cts_ptr == NUL) {
|
||||||
|
// NUL at end of line only takes one column, unless there is virtual text
|
||||||
|
incr = MAX(1, cts.cts_cur_text_width_left + cts.cts_cur_text_width_right);
|
||||||
|
on_NUL = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((posptr != NULL) && (cts.cts_ptr >= posptr)) {
|
||||||
|
// character at pos->col
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.cts_vcol += incr;
|
||||||
|
MB_PTR_ADV(cts.cts_ptr);
|
||||||
|
}
|
||||||
|
vcol = cts.cts_vcol;
|
||||||
|
ptr = cts.cts_ptr;
|
||||||
|
}
|
||||||
|
clear_chartabsize_arg(&cts);
|
||||||
|
|
||||||
|
if (start != NULL) {
|
||||||
|
*start = vcol + head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end != NULL) {
|
||||||
|
*end = vcol + incr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != NULL) {
|
||||||
|
if ((*ptr == TAB)
|
||||||
|
&& (State & MODE_NORMAL)
|
||||||
|
&& !wp->w_p_list
|
||||||
|
&& !virtual_active()
|
||||||
|
&& !(VIsual_active && ((*p_sel == 'e') || ltoreq(*pos, VIsual)))) {
|
||||||
|
// cursor at end
|
||||||
|
*cursor = vcol + incr - 1;
|
||||||
|
} else {
|
||||||
|
vcol += virt_text_cursor_off(&cts, on_NUL);
|
||||||
|
// cursor at start
|
||||||
|
*cursor = vcol + head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get virtual cursor column in the current window, pretending 'list' is off.
|
||||||
|
///
|
||||||
|
/// @param posp
|
||||||
|
///
|
||||||
|
/// @retujrn The virtual cursor column.
|
||||||
|
colnr_T getvcol_nolist(pos_T *posp)
|
||||||
|
{
|
||||||
|
int list_save = curwin->w_p_list;
|
||||||
|
colnr_T vcol;
|
||||||
|
|
||||||
|
curwin->w_p_list = false;
|
||||||
|
if (posp->coladd) {
|
||||||
|
getvvcol(curwin, posp, NULL, &vcol, NULL);
|
||||||
|
} else {
|
||||||
|
getvcol(curwin, posp, NULL, &vcol, NULL);
|
||||||
|
}
|
||||||
|
curwin->w_p_list = list_save;
|
||||||
|
return vcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get virtual column in virtual mode.
|
||||||
|
///
|
||||||
|
/// @param wp
|
||||||
|
/// @param pos
|
||||||
|
/// @param start
|
||||||
|
/// @param cursor
|
||||||
|
/// @param end
|
||||||
|
void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
|
||||||
|
{
|
||||||
|
colnr_T col;
|
||||||
|
|
||||||
|
if (virtual_active()) {
|
||||||
|
// For virtual mode, only want one value
|
||||||
|
getvcol(wp, pos, &col, NULL, NULL);
|
||||||
|
|
||||||
|
colnr_T coladd = pos->coladd;
|
||||||
|
colnr_T endadd = 0;
|
||||||
|
|
||||||
|
// Cannot put the cursor on part of a wide character.
|
||||||
|
char *ptr = ml_get_buf(wp->w_buffer, pos->lnum);
|
||||||
|
|
||||||
|
if (pos->col < (colnr_T)strlen(ptr)) {
|
||||||
|
int c = utf_ptr2char(ptr + pos->col);
|
||||||
|
if ((c != TAB) && vim_isprintc(c)) {
|
||||||
|
endadd = (colnr_T)(char2cells(c) - 1);
|
||||||
|
if (coladd > endadd) {
|
||||||
|
// past end of line
|
||||||
|
endadd = 0;
|
||||||
|
} else {
|
||||||
|
coladd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col += coladd;
|
||||||
|
|
||||||
|
if (start != NULL) {
|
||||||
|
*start = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != NULL) {
|
||||||
|
*cursor = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end != NULL) {
|
||||||
|
*end = col + endadd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getvcol(wp, pos, start, cursor, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the leftmost and rightmost virtual column of pos1 and pos2.
|
||||||
|
/// Used for Visual block mode.
|
||||||
|
///
|
||||||
|
/// @param wp
|
||||||
|
/// @param pos1
|
||||||
|
/// @param pos2
|
||||||
|
/// @param left
|
||||||
|
/// @param right
|
||||||
|
void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right)
|
||||||
|
{
|
||||||
|
colnr_T from1;
|
||||||
|
colnr_T from2;
|
||||||
|
colnr_T to1;
|
||||||
|
colnr_T to2;
|
||||||
|
|
||||||
|
if (lt(*pos1, *pos2)) {
|
||||||
|
getvvcol(wp, pos1, &from1, NULL, &to1);
|
||||||
|
getvvcol(wp, pos2, &from2, NULL, &to2);
|
||||||
|
} else {
|
||||||
|
getvvcol(wp, pos2, &from1, NULL, &to1);
|
||||||
|
getvvcol(wp, pos1, &from2, NULL, &to2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from2 < from1) {
|
||||||
|
*left = from2;
|
||||||
|
} else {
|
||||||
|
*left = from1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to2 > to1) {
|
||||||
|
if ((*p_sel == 'e') && (from2 - 1 >= to1)) {
|
||||||
|
*right = from2 - 1;
|
||||||
|
} else {
|
||||||
|
*right = to2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*right = to1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Functions calculating vertical size of text when displayed inside a window.
|
||||||
|
/// Calls horizontal size functions defined above.
|
||||||
|
|
||||||
|
/// Check the there may be filler inlines anywhere in window "wp"
|
||||||
|
bool win_may_fill(win_T *wp)
|
||||||
|
{
|
||||||
|
return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of filler lines above "lnum".
|
||||||
|
///
|
||||||
|
/// @param wp
|
||||||
|
/// @param lnum
|
||||||
|
///
|
||||||
|
/// @return Number of filler lines above lnum
|
||||||
|
int win_get_fill(win_T *wp, linenr_T lnum)
|
||||||
|
{
|
||||||
|
int virt_lines = decor_virt_lines(wp, lnum, NULL, kNone);
|
||||||
|
|
||||||
|
// be quick when there are no filler lines
|
||||||
|
if (diffopt_filler()) {
|
||||||
|
int n = diff_check(wp, lnum);
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
return virt_lines + n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return virt_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of window lines occupied by buffer line "lnum".
|
||||||
|
/// Includes any filler lines.
|
||||||
|
///
|
||||||
|
/// @param limit_winheight when true limit to window height
|
||||||
|
int plines_win(win_T *wp, linenr_T lnum, bool limit_winheight)
|
||||||
|
{
|
||||||
|
// Check for filler lines above this buffer line.
|
||||||
|
return plines_win_nofill(wp, lnum, limit_winheight) + win_get_fill(wp, lnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of window lines occupied by buffer line "lnum".
|
||||||
|
/// Does not include filler lines.
|
||||||
|
///
|
||||||
|
/// @param limit_winheight when true limit to window height
|
||||||
|
int plines_win_nofill(win_T *wp, linenr_T lnum, bool limit_winheight)
|
||||||
|
{
|
||||||
|
if (!wp->w_p_wrap) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp->w_width_inner == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folded lines are handled just like an empty line.
|
||||||
|
if (lineFolded(wp, lnum)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int lines = plines_win_nofold(wp, lnum);
|
||||||
|
if (limit_winheight && lines > wp->w_height_inner) {
|
||||||
|
return wp->w_height_inner;
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get number of window lines physical line "lnum" will occupy in window "wp".
|
||||||
|
/// Does not care about folding, 'wrap' or filler lines.
|
||||||
|
int plines_win_nofold(win_T *wp, linenr_T lnum)
|
||||||
|
{
|
||||||
|
char *s = ml_get_buf(wp->w_buffer, lnum);
|
||||||
|
chartabsize_T cts;
|
||||||
|
init_chartabsize_arg(&cts, wp, lnum, 0, s, s);
|
||||||
|
if (*s == NUL && !cts.cts_has_virt_text) {
|
||||||
|
return 1; // be quick for an empty line
|
||||||
|
}
|
||||||
|
win_linetabsize_cts(&cts, (colnr_T)MAXCOL);
|
||||||
|
clear_chartabsize_arg(&cts);
|
||||||
|
int64_t col = cts.cts_vcol;
|
||||||
|
|
||||||
|
// If list mode is on, then the '$' at the end of the line may take up one
|
||||||
|
// extra column.
|
||||||
|
if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) {
|
||||||
|
col += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
|
||||||
|
int width = wp->w_width_inner - win_col_off(wp);
|
||||||
|
if (width <= 0) {
|
||||||
|
return 32000; // bigger than the number of screen lines
|
||||||
|
}
|
||||||
|
if (col <= width) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
col -= width;
|
||||||
|
width += win_col_off2(wp);
|
||||||
|
const int64_t lines = (col + (width - 1)) / width + 1;
|
||||||
|
return (lines > 0 && lines <= INT_MAX) ? (int)lines : INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like plines_win(), but only reports the number of physical screen lines
|
||||||
|
/// used from the start of the line to the given column number.
|
||||||
|
int plines_win_col(win_T *wp, linenr_T lnum, long column)
|
||||||
|
{
|
||||||
|
// Check for filler lines above this buffer line.
|
||||||
|
int lines = win_get_fill(wp, lnum);
|
||||||
|
|
||||||
|
if (!wp->w_p_wrap) {
|
||||||
|
return lines + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp->w_width_inner == 0) {
|
||||||
|
return lines + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line = ml_get_buf(wp->w_buffer, lnum);
|
||||||
|
|
||||||
|
colnr_T col = 0;
|
||||||
|
chartabsize_T cts;
|
||||||
|
|
||||||
|
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
|
||||||
|
while (*cts.cts_ptr != NUL && --column >= 0) {
|
||||||
|
cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
|
||||||
|
MB_PTR_ADV(cts.cts_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If *cts.cts_ptr is a TAB, and the TAB is not displayed as ^I, and we're not
|
||||||
|
// in MODE_INSERT state, then col must be adjusted so that it represents the
|
||||||
|
// last screen position of the TAB. This only fixes an error when the TAB
|
||||||
|
// wraps from one screen line to the next (when 'columns' is not a multiple
|
||||||
|
// of 'ts') -- webb.
|
||||||
|
col = cts.cts_vcol;
|
||||||
|
if (*cts.cts_ptr == TAB && (State & MODE_NORMAL)
|
||||||
|
&& (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
|
||||||
|
col += win_lbr_chartabsize(&cts, NULL) - 1;
|
||||||
|
}
|
||||||
|
clear_chartabsize_arg(&cts);
|
||||||
|
|
||||||
|
// Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
|
||||||
|
int width = wp->w_width_inner - win_col_off(wp);
|
||||||
|
if (width <= 0) {
|
||||||
|
return 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines += 1;
|
||||||
|
if (col > width) {
|
||||||
|
lines += (col - width) / (width + win_col_off2(wp)) + 1;
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the number of screen lines buffer line "lnum" will take in window "wp".
|
||||||
|
/// This takes care of both folds and topfill.
|
||||||
|
///
|
||||||
|
/// XXX: Because of topfill, this only makes sense when lnum >= wp->w_topline.
|
||||||
|
///
|
||||||
|
/// @param[in] wp window the line is in
|
||||||
|
/// @param[in] lnum line number
|
||||||
|
/// @param[out] nextp if not NULL, the line after a fold
|
||||||
|
/// @param[out] foldedp if not NULL, whether lnum is on a fold
|
||||||
|
/// @param[in] cache whether to use the window's cache for folds
|
||||||
|
/// @param[in] limit_winheight when true limit to window height
|
||||||
|
///
|
||||||
|
/// @return the total number of screen lines
|
||||||
|
int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const foldedp,
|
||||||
|
const bool cache, const bool limit_winheight)
|
||||||
|
{
|
||||||
|
bool folded = hasFoldingWin(wp, lnum, &lnum, nextp, cache, NULL);
|
||||||
|
if (foldedp != NULL) {
|
||||||
|
*foldedp = folded;
|
||||||
|
}
|
||||||
|
return ((folded ? 1 : plines_win_nofill(wp, lnum, limit_winheight)) +
|
||||||
|
(lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the number of screen lines a range of buffer lines will take in window "wp".
|
||||||
|
/// This takes care of both folds and topfill.
|
||||||
|
///
|
||||||
|
/// XXX: Because of topfill, this only makes sense when first >= wp->w_topline.
|
||||||
|
///
|
||||||
|
/// @param first first line number
|
||||||
|
/// @param last last line number
|
||||||
|
/// @param limit_winheight when true limit each line to window height
|
||||||
|
///
|
||||||
|
/// @see win_text_height
|
||||||
|
int plines_m_win(win_T *wp, linenr_T first, linenr_T last, bool limit_winheight)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (first <= last) {
|
||||||
|
linenr_T next = first;
|
||||||
|
count += plines_win_full(wp, first, &next, NULL, false, limit_winheight);
|
||||||
|
first = next + 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the number of screen lines a range of text will take in window "wp".
|
/// Get the number of screen lines a range of text will take in window "wp".
|
||||||
///
|
///
|
||||||
/// @param[in] start_lnum Starting line number, 1-based inclusive.
|
/// @param[in] start_lnum Starting line number, 1-based inclusive.
|
||||||
|
@@ -2,9 +2,11 @@
|
|||||||
#define NVIM_PLINES_H
|
#define NVIM_PLINES_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/marktree.h"
|
||||||
|
#include "nvim/pos.h"
|
||||||
|
|
||||||
/// Argument for lbr_chartabsize().
|
/// Argument for lbr_chartabsize().
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
|
#include "nvim/plines.h"
|
||||||
#include "nvim/profile.h"
|
#include "nvim/profile.h"
|
||||||
#include "nvim/regexp.h"
|
#include "nvim/regexp.h"
|
||||||
#include "nvim/search.h"
|
#include "nvim/search.h"
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "nvim/optionstr.h"
|
#include "nvim/optionstr.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
|
#include "nvim/plines.h"
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
#include "nvim/sign.h"
|
#include "nvim/sign.h"
|
||||||
#include "nvim/statusline.h"
|
#include "nvim/statusline.h"
|
||||||
|
Reference in New Issue
Block a user