Merge pull request #691 from fmoralesc/master

Port vim's breakindent patch to neovim's codebase. (vim patches 7.4.338, 7.4.346, 7.4.352, 7.4.353, 7.4.370, 7.4.371, 7.4.388)
This commit is contained in:
Justin M. Keyes 2014-08-20 12:24:34 -04:00
commit 118a31c24c
20 changed files with 613 additions and 85 deletions

View File

@ -136,6 +136,10 @@ struct buffheader {
typedef struct {
int wo_arab;
# define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */
int wo_bri;
# define w_p_bri w_onebuf_opt.wo_bri /* 'breakindent' */
char_u *wo_briopt;
# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
int wo_diff;
# define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */
long wo_fdc;
@ -1069,6 +1073,9 @@ struct window_S {
long_u w_p_fde_flags; /* flags for 'foldexpr' */
long_u w_p_fdt_flags; /* flags for 'foldtext' */
int *w_p_cc_cols; /* array of columns to highlight or NULL */
int w_p_brimin; /* minimum width for breakindent */
int w_p_brishift; /* additional shift for breakindent */
bool w_p_brisbr; /* sbr in 'briopt' */
/* transform a pointer to a "onebuf" option into a "allbuf" option */
#define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T))

View File

@ -13,6 +13,7 @@
#include "nvim/charset.h"
#include "nvim/farsi.h"
#include "nvim/func_attr.h"
#include "nvim/indent.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@ -775,9 +776,10 @@ int linetabsize(char_u *s)
int linetabsize_col(int startcol, char_u *s)
{
colnr_T col = startcol;
char_u *line = s; /* pointer to start of line, for breakindent */
while (*s != NUL) {
col += lbr_chartabsize_adv(&s, col);
col += lbr_chartabsize_adv(line, &s, col);
}
return (int)col;
}
@ -785,17 +787,17 @@ int linetabsize_col(int startcol, char_u *s)
/// Like linetabsize(), but for a given window instead of the current one.
///
/// @param wp
/// @param p
/// @param line
/// @param len
///
/// @return Number of characters the string will take on the screen.
int win_linetabsize(win_T *wp, char_u *p, colnr_T len)
int win_linetabsize(win_T *wp, char_u *line, colnr_T len)
{
colnr_T col = 0;
char_u *s;
for (s = p; *s != NUL && (len == MAXCOL || s < p + len); mb_ptr_adv(s)) {
col += win_lbr_chartabsize(wp, s, col, NULL);
for (s = line; *s != NUL && (len == MAXCOL || s < line + len); mb_ptr_adv(s)) {
col += win_lbr_chartabsize(wp, line, s, col, NULL);
}
return (int)col;
}
@ -922,32 +924,34 @@ int vim_isprintc_strict(int c)
/// like chartabsize(), but also check for line breaks on the screen
///
/// @param line
/// @param s
/// @param col
///
/// @return The number of characters taken up on the screen.
int lbr_chartabsize(unsigned char *s, colnr_T col)
int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col)
{
if (!curwin->w_p_lbr && (*p_sbr == NUL)) {
if (!curwin->w_p_lbr && (*p_sbr == NUL) && !curwin->w_p_bri) {
if (curwin->w_p_wrap) {
return win_nolbr_chartabsize(curwin, s, col, NULL);
}
RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
}
return win_lbr_chartabsize(curwin, s, col, NULL);
return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL);
}
/// Call lbr_chartabsize() and advance the pointer.
///
/// @param line
/// @param s
/// @param col
///
/// @return The number of characters take up on the screen.
int lbr_chartabsize_adv(char_u **s, colnr_T col)
int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col)
{
int retval;
retval = lbr_chartabsize(*s, col);
retval = lbr_chartabsize(line, *s, col);
mb_ptr_adv(*s);
return retval;
}
@ -959,14 +963,16 @@ int lbr_chartabsize_adv(char_u **s, colnr_T col)
/// value, init to 0 before calling.
///
/// @param wp
/// @param line
/// @param s
/// @param col
/// @param headp
///
/// @return The number of characters taken up on the screen.
int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp)
{
colnr_T col2;
colnr_T col_adj = 0; /* col + screen size of tab */
colnr_T colmax;
int added;
int mb_added = 0;
@ -975,8 +981,8 @@ int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
int tab_corr = (*s == TAB);
int n;
// No 'linebreak' and 'showbreak': return quickly.
if (!wp->w_p_lbr && (*p_sbr == NUL)) {
// No 'linebreak', 'showbreak' and 'breakindent': return quickly.
if (!wp->w_p_lbr && !wp->w_p_bri && (*p_sbr == NUL)) {
if (wp->w_p_wrap) {
return win_nolbr_chartabsize(wp, s, col, headp);
}
@ -986,26 +992,29 @@ int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
// First get normal size, without 'linebreak'
int size = win_chartabsize(wp, s, col);
int c = *s;
if (tab_corr) {
col_adj = size - 1;
}
// If 'linebreak' set check at a blank before a non-blank if the line
// needs a break here
if (wp->w_p_lbr
&& vim_isbreak(c)
&& !vim_isbreak(s[1])
&& !wp->w_p_list
&& wp->w_p_wrap
&& (wp->w_width != 0)) {
// Count all characters from first non-blank after a blank up to next
// non-blank after a blank.
numberextra = win_col_off(wp);
col2 = col;
colmax = (colnr_T)(wp->w_width - numberextra);
colmax = (colnr_T)(wp->w_width - numberextra - col_adj);
if (col >= colmax) {
n = colmax + win_col_off2(wp);
colmax += col_adj;
n = colmax + win_col_off2(wp);
if (n > 0) {
colmax += (((col - colmax) / n) + 1) * n;
colmax += (((col - colmax) / n) + 1) * n - col_adj;
}
}
@ -1024,7 +1033,7 @@ int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
col2 += win_chartabsize(wp, s, col2);
if (col2 >= colmax) { /* doesn't fit */
size = colmax - col;
size = colmax - col + col_adj;
tab_corr = FALSE;
break;
}
@ -1039,11 +1048,12 @@ int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
mb_added = 1;
}
// May have to add something for 'showbreak' string at start of line
// May have to add something for 'breakindent' and/or 'showbreak'
// string at start of line.
// Set *headp to the size of what we add.
added = 0;
if ((*p_sbr != NUL) && wp->w_p_wrap && (col != 0)) {
if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && (col != 0)) {
numberextra = win_col_off(wp);
col += numberextra + mb_added;
@ -1056,7 +1066,12 @@ int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
}
if ((col == 0) || (col + size > (colnr_T)wp->w_width)) {
added = vim_strsize(p_sbr);
added = 0;
if (*p_sbr != NUL)
added += vim_strsize(p_sbr);
if (wp->w_p_bri)
added += get_breakindent_win(wp, line);
if (tab_corr) {
size += (added / wp->w_buffer->b_p_ts) * wp->w_buffer->b_p_ts;
} else {
@ -1157,13 +1172,14 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
colnr_T vcol;
char_u *ptr; // points to current char
char_u *posptr; // points to char at pos->col
char_u *line; // start of the line
int incr;
int head;
int ts = wp->w_buffer->b_p_ts;
int c;
vcol = 0;
ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
if (pos->col == MAXCOL) {
// continue until the NUL
@ -1173,11 +1189,13 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
}
// This function is used very often, do some speed optimizations.
// When 'list', 'linebreak' and 'showbreak' are not set use a simple loop.
// Also use this when 'list' is set but tabs take their normal size.
// When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
// use a simple loop.
// Also use this when 'list' is set but tabs take their normal size.
if ((!wp->w_p_list || (lcs_tab1 != NUL))
&& !wp->w_p_lbr
&& (*p_sbr == NUL)) {
&& (*p_sbr == NUL)
&& !wp->w_p_bri ) {
for (;;) {
head = 0;
c = *ptr;
@ -1229,7 +1247,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
for (;;) {
// A tab gets expanded, depending on the current column
head = 0;
incr = win_lbr_chartabsize(wp, ptr, vcol, &head);
incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head);
// make sure we don't go past the end of the line
if (*ptr == NUL) {

View File

@ -138,7 +138,7 @@ static int coladvance2(
ptr = line;
while (col <= wcol && *ptr != NUL) {
/* Count a tab for what it's worth (if list mode not on) */
csize = win_lbr_chartabsize(curwin, ptr, col, &head);
csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
mb_ptr_adv(ptr);
col += csize;
}

View File

@ -1551,7 +1551,7 @@ change_indent (
new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
else
++new_cursor_col;
vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
}
vcol = last_vcol;
@ -5898,9 +5898,11 @@ int oneleft(void)
width = 1;
for (;; ) {
coladvance(v - width);
/* getviscol() is slow, skip it when 'showbreak' is empty and
* there are no multi-byte characters */
/* getviscol() is slow, skip it when 'showbreak' is empty,
'breakindent' is not set and there are no multi-byte
characters */
if ((*p_sbr == NUL
&& !curwin->w_p_bri
&& !has_mbyte
) || getviscol() < v)
break;
@ -7914,10 +7916,10 @@ static int ins_tab(void)
getvcol(curwin, &fpos, &vcol, NULL, NULL);
getvcol(curwin, cursor, &want_vcol, NULL, NULL);
/* Use as many TABs as possible. Beware of 'showbreak' and
* 'linebreak' adding extra virtual columns. */
/* Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
and 'linebreak' adding extra virtual columns. */
while (vim_iswhite(*ptr)) {
i = lbr_chartabsize((char_u *)"\t", vcol);
i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
if (vcol + i > want_vcol)
break;
if (*ptr != TAB) {
@ -7936,10 +7938,11 @@ static int ins_tab(void)
if (change_col >= 0) {
int repl_off = 0;
char_u *line = ptr;
/* Skip over the spaces we need. */
while (vcol < want_vcol && *ptr == ' ') {
vcol += lbr_chartabsize(ptr, vcol);
vcol += lbr_chartabsize(line, ptr, vcol);
++ptr;
++repl_off;
}
@ -8126,6 +8129,7 @@ int ins_copychar(linenr_T lnum)
int c;
int temp;
char_u *ptr, *prev_ptr;
char_u *line;
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
vim_beep();
@ -8134,12 +8138,12 @@ int ins_copychar(linenr_T lnum)
/* try to advance to the cursor column */
temp = 0;
ptr = ml_get(lnum);
line = ptr = ml_get(lnum);
prev_ptr = ptr;
validate_virtcol();
while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) {
prev_ptr = ptr;
temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
}
if ((colnr_T)temp > curwin->w_virtcol)
ptr = prev_ptr;

View File

@ -1817,10 +1817,10 @@ getexmodeline (
p = (char_u *)line_ga.ga_data;
p[line_ga.ga_len] = NUL;
indent = get_indent_str(p, 8);
indent = get_indent_str(p, 8, FALSE);
indent += sw - indent % sw;
add_indent:
while (get_indent_str(p, 8) < indent) {
while (get_indent_str(p, 8, FALSE) < indent) {
char_u *s = skipwhite(p);
ga_grow(&line_ga, 1);
@ -1858,11 +1858,11 @@ redraw:
p[--line_ga.ga_len] = NUL;
} else {
p[line_ga.ga_len] = NUL;
indent = get_indent_str(p, 8);
indent = get_indent_str(p, 8, FALSE);
--indent;
indent -= indent % get_sw_value(curbuf);
}
while (get_indent_str(p, 8) > indent) {
while (get_indent_str(p, 8, FALSE) > indent) {
char_u *s = skipwhite(p);
memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);

View File

@ -2163,7 +2163,7 @@ static int vgetorpeek(int advance)
while (col < curwin->w_cursor.col) {
if (!vim_iswhite(ptr[col]))
curwin->w_wcol = vcol;
vcol += lbr_chartabsize(ptr + col,
vcol += lbr_chartabsize(ptr, ptr + col,
(colnr_T)vcol);
if (has_mbyte)
col += (*mb_ptr2len)(ptr + col);

View File

@ -10,8 +10,10 @@
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
@ -24,14 +26,14 @@
// Count the size (in window cells) of the indent in the current line.
int get_indent(void)
{
return get_indent_str(get_cursor_line_ptr(), (int)curbuf->b_p_ts);
return get_indent_str(get_cursor_line_ptr(), (int)curbuf->b_p_ts, false);
}
// Count the size (in window cells) of the indent in line "lnum".
int get_indent_lnum(linenr_T lnum)
{
return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts);
return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, false);
}
@ -39,20 +41,27 @@ int get_indent_lnum(linenr_T lnum)
// "buf".
int get_indent_buf(buf_T *buf, linenr_T lnum)
{
return get_indent_str(ml_get_buf(buf, lnum, false), (int)buf->b_p_ts);
return get_indent_str(ml_get_buf(buf, lnum, false), (int)buf->b_p_ts, false);
}
// Count the size (in window cells) of the indent in line "ptr", with
// 'tabstop' at "ts".
int get_indent_str(char_u *ptr, int ts)
// If @param list is TRUE, count only screen size for tabs.
int get_indent_str(char_u *ptr, int ts, int list)
{
int count = 0;
for (; *ptr; ++ptr) {
// Count a tab for what it is worth.
if (*ptr == TAB) {
count += ts - (count % ts);
if (!list || lcs_tab1) { // count a tab for what it is worth
count += ts - (count % ts);
} else {
// in list mode, when tab is not set, count screen char width for Tab:
// ^I
count += ptr2cells(ptr);
}
} else if (*ptr == ' ') {
// Count a space for one.
count++;
@ -433,6 +442,50 @@ int get_number_indent(linenr_T lnum)
return (int)col;
}
/*
* 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;
}
// When extra == 0: Return true if the cursor is before or on the first
// non-blank in the line.
@ -608,10 +661,12 @@ int get_lisp_indent(void)
if (vi_lisp && (get_indent() == 0)) {
amount = 2;
} else {
char_u *line = that;
amount = 0;
while (*that && col) {
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
col--;
}
@ -628,7 +683,7 @@ int get_lisp_indent(void)
firsttry = amount;
while (vim_iswhite(*that)) {
amount += lbr_chartabsize(that, (colnr_T)amount);
amount += lbr_chartabsize(line, that, (colnr_T)amount);
that++;
}
@ -658,15 +713,15 @@ int get_lisp_indent(void)
parencount--;
}
if ((*that == '\\') && (*(that + 1) != NUL)) {
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
}
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
}
}
while (vim_iswhite(*that)) {
amount += lbr_chartabsize(that, (colnr_T)amount);
amount += lbr_chartabsize(line, that, (colnr_T)amount);
that++;
}

View File

@ -194,7 +194,7 @@ open_line (
/*
* count white space on current line
*/
newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts);
newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE);
if (newindent == 0 && !(flags & OPENLINE_COM_LIST))
newindent = second_line_indent; /* for ^^D command in insert mode */
@ -631,7 +631,7 @@ open_line (
if (curbuf->b_p_ai
|| do_si
)
newindent = get_indent_str(leader, (int)curbuf->b_p_ts);
newindent = get_indent_str(leader, (int)curbuf->b_p_ts, FALSE);
/* Add the indent offset */
if (newindent + off < 0) {
@ -1306,6 +1306,7 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
char_u *s;
int lines = 0;
int width;
char_u *line;
/* Check for filler lines above this buffer line. When folded the result
* is one line anyway. */
@ -1317,11 +1318,11 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
if (wp->w_width == 0)
return lines + 1;
s = ml_get_buf(wp->w_buffer, lnum, FALSE);
line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
col = 0;
while (*s != NUL && --column >= 0) {
col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL);
col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
mb_ptr_adv(s);
}
@ -1333,7 +1334,7 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
* 'ts') -- webb.
*/
if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL) - 1;
col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
/*
* Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.

View File

@ -350,7 +350,8 @@ static void shift_block(oparg_T *oap, int amount)
++bd.textstart;
}
for (; vim_iswhite(*bd.textstart); ) {
incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol));
// TODO: is passing bd.textstart for start of the line OK?
incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, (colnr_T)(bd.start_vcol));
total += incr;
bd.start_vcol += incr;
}
@ -405,7 +406,7 @@ static void shift_block(oparg_T *oap, int amount)
non_white_col = bd.start_vcol;
while (vim_iswhite(*non_white)) {
incr = lbr_chartabsize_adv(&non_white, non_white_col);
incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
non_white_col += incr;
}
@ -429,7 +430,10 @@ static void shift_block(oparg_T *oap, int amount)
if (bd.startspaces)
verbatim_copy_width -= bd.start_char_vcols;
while (verbatim_copy_width < destination_col) {
incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width);
char_u *line = verbatim_copy_end;
// TODO: is passing verbatim_copy_end for start of the line OK?
incr = lbr_chartabsize(line, verbatim_copy_end, verbatim_copy_width);
if (verbatim_copy_width + incr > destination_col)
break;
verbatim_copy_width += incr;
@ -2824,7 +2828,7 @@ do_put (
oldlen = (int)STRLEN(oldp);
for (ptr = oldp; vcol < col && *ptr; ) {
/* Count a tab for what it's worth (if list mode not on) */
incr = lbr_chartabsize_adv(&ptr, (colnr_T)vcol);
incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
vcol += incr;
}
bd.textcol = (colnr_T)(ptr - oldp);
@ -2854,7 +2858,7 @@ do_put (
/* calculate number of spaces required to fill right side of block*/
spaces = y_width + 1;
for (j = 0; j < yanklen; j++)
spaces -= lbr_chartabsize(&y_array[i][j], 0);
spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
if (spaces < 0)
spaces = 0;
@ -4114,7 +4118,7 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
prev_pstart = line;
while (bdp->start_vcol < oap->start_vcol && *pstart) {
/* Count a tab for what it's worth (if list mode not on) */
incr = lbr_chartabsize(pstart, (colnr_T)bdp->start_vcol);
incr = lbr_chartabsize(line, pstart, (colnr_T)bdp->start_vcol);
bdp->start_vcol += incr;
if (vim_iswhite(*pstart)) {
bdp->pre_whitesp += incr;
@ -4163,7 +4167,9 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
while (bdp->end_vcol <= oap->end_vcol && *pend != NUL) {
/* Count a tab for what it's worth (if list mode not on) */
prev_pend = pend;
incr = lbr_chartabsize_adv(&pend, (colnr_T)bdp->end_vcol);
// TODO: is passing prev_pend for start of the line OK?
// prehaps it should be "line"
incr = lbr_chartabsize_adv(prev_pend, &pend, (colnr_T)bdp->end_vcol);
bdp->end_vcol += incr;
}
if (bdp->end_vcol <= oap->end_vcol

View File

@ -176,6 +176,8 @@
*/
#define PV_LIST OPT_WIN(WV_LIST)
# define PV_ARAB OPT_WIN(WV_ARAB)
# define PV_BRI OPT_WIN(WV_BRI)
# define PV_BRIOPT OPT_WIN(WV_BRIOPT)
# define PV_DIFF OPT_WIN(WV_DIFF)
# define PV_FDC OPT_WIN(WV_FDC)
# define PV_FEN OPT_WIN(WV_FEN)
@ -471,6 +473,14 @@ static struct vimoption
(char_u *)&p_breakat, PV_NONE,
{(char_u *)" \t!@*-+;:,./?", (char_u *)0L}
SCRIPTID_INIT},
{"breakindent", "bri", P_BOOL|P_VI_DEF|P_VIM|P_RWIN,
(char_u *)VAR_WIN, PV_BRI,
{(char_u *)FALSE, (char_u *)0L}
SCRIPTID_INIT},
{"breakindentopt", "briopt", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_COMMA|P_NODUP,
(char_u *)VAR_WIN, PV_BRIOPT,
{(char_u *)"", (char_u *)NULL}
SCRIPTID_INIT},
{"browsedir", "bsdir",P_STRING|P_VI_DEF,
(char_u *)NULL, PV_NONE,
{(char_u *)0L, (char_u *)0L}
@ -3481,6 +3491,7 @@ static void didset_options(void)
(void)compile_cap_prog(curwin->w_s);
/* set cedit_key */
(void)check_cedit();
briopt_check();
}
/*
@ -3815,6 +3826,11 @@ did_set_string_option (
*p_pm == '.' ? p_pm + 1 : p_pm) == 0)
errmsg = (char_u *)N_("E589: 'backupext' and 'patchmode' are equal");
}
/* 'breakindentopt' */
else if (varp == &curwin->w_p_briopt) {
if (briopt_check() == FAIL)
errmsg = e_invarg;
}
/*
* 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[]
* If the new option is invalid, use old value. 'lisp' option: refill
@ -6681,6 +6697,8 @@ static char_u *get_varp(struct vimoption *p)
case PV_SCROLL: return (char_u *)&(curwin->w_p_scr);
case PV_WRAP: return (char_u *)&(curwin->w_p_wrap);
case PV_LBR: return (char_u *)&(curwin->w_p_lbr);
case PV_BRI: return (char_u *)&(curwin->w_p_bri);
case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
@ -6788,6 +6806,8 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_wrap = from->wo_wrap;
to->wo_wrap_save = from->wo_wrap_save;
to->wo_lbr = from->wo_lbr;
to->wo_bri = from->wo_bri;
to->wo_briopt = vim_strsave(from->wo_briopt);
to->wo_scb = from->wo_scb;
to->wo_scb_save = from->wo_scb_save;
to->wo_crb = from->wo_crb;
@ -6842,6 +6862,7 @@ void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_stl);
check_string_option(&wop->wo_cc);
check_string_option(&wop->wo_cocu);
check_string_option(&wop->wo_briopt);
}
/*
@ -6859,6 +6880,7 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_stl);
clear_string_option(&wop->wo_cc);
clear_string_option(&wop->wo_cocu);
clear_string_option(&wop->wo_briopt);
}
/*
@ -8134,3 +8156,45 @@ void find_mps_values(int *initc, int *findc, int *backwards, int switchit)
++ptr;
}
}
/* This is called when 'breakindentopt' is changed and when a window is
initialized */
int briopt_check(void)
{
char_u *p;
int bri_shift = 0;
long bri_min = 20;
bool bri_sbr = false;
p = curwin->w_p_briopt;
while (*p != NUL)
{
if (STRNCMP(p, "shift:", 6) == 0
&& ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6])))
{
p += 6;
bri_shift = getdigits(&p);
}
else if (STRNCMP(p, "min:", 4) == 0 && VIM_ISDIGIT(p[4]))
{
p += 4;
bri_min = getdigits(&p);
}
else if (STRNCMP(p, "sbr", 3) == 0)
{
p += 3;
bri_sbr = true;
}
if (*p != ',' && *p != NUL)
return FAIL;
if (*p == ',')
++p;
}
curwin->w_p_brishift = bri_shift;
curwin->w_p_brimin = bri_min;
curwin->w_p_brisbr = bri_sbr;
return OK;
}

View File

@ -726,6 +726,8 @@ enum {
, WV_COCU
, WV_COLE
, WV_CRBIND
, WV_BRI
, WV_BRIOPT
, WV_DIFF
, WV_FDC
, WV_FEN

View File

@ -106,6 +106,7 @@
#include "nvim/farsi.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/indent.h"
#include "nvim/getchar.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
@ -2196,6 +2197,7 @@ win_line (
char_u extra[18]; /* line number and 'fdc' must fit in here */
int n_extra = 0; /* number of extra chars */
char_u *p_extra = NULL; /* string of extra chars, plus NUL */
char_u *p_extra_free = NULL; /* p_extra needs to be freed */
int c_extra = NUL; /* extra chars, all the same */
int extra_attr = 0; /* attributes when n_extra != 0 */
static char_u *at_end_str = (char_u *)""; /* used for p_extra when
@ -2283,7 +2285,8 @@ win_line (
# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
# define WL_SIGN WL_FOLD + 1 /* column for signs */
#define WL_NR WL_SIGN + 1 /* line number */
# define WL_SBR WL_NR + 1 /* 'showbreak' or 'diff' */
# define WL_BRI WL_NR + 1 /* 'breakindent' */
# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
#define WL_LINE WL_SBR + 1 /* text in the line */
int draw_state = WL_START; /* what to draw next */
@ -2540,7 +2543,7 @@ win_line (
if (v > 0) {
char_u *prev_ptr = ptr;
while (vcol < v && *ptr != NUL) {
c = win_lbr_chartabsize(wp, ptr, (colnr_T)vcol, NULL);
c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
vcol += c;
prev_ptr = ptr;
mb_ptr_adv(ptr);
@ -2817,6 +2820,34 @@ win_line (
}
}
if (wp->w_p_brisbr && draw_state == WL_BRI - 1
&& n_extra == 0 && *p_sbr != NUL) {
// draw indent after showbreak value
draw_state = WL_BRI;
} else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0) {
// after the showbreak, draw the breakindent
draw_state = WL_BRI - 1;
}
// draw 'breakindent': indent wrapped text accodringly
if (draw_state == WL_BRI - 1 && n_extra == 0) {
draw_state = WL_BRI;
if (wp->w_p_bri && n_extra == 0 && row != startrow && filler_lines == 0) {
char_attr = 0; // was: hl_attr(HLF_AT);
if (diff_hlf != (hlf_T)0)
char_attr = hl_attr(diff_hlf);
p_extra = NULL;
c_extra = ' ';
n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, FALSE));
/* Correct end of highlighted area for 'breakindent',
required wen 'linebreak' is also set. */
if (tocol == vcol)
tocol += n_extra;
}
}
if (draw_state == WL_SBR - 1 && n_extra == 0) {
draw_state = WL_SBR;
if (filler_todo > 0) {
@ -3078,6 +3109,10 @@ win_line (
}
--n_extra;
} else {
if (p_extra_free != NULL) {
free(p_extra_free);
p_extra_free = NULL;
}
/*
* Get a character from the line itself.
*/
@ -3378,17 +3413,20 @@ win_line (
/*
* Found last space before word: check for line break.
*/
if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
&& !wp->w_p_list) {
n_extra = win_lbr_chartabsize(wp, ptr - (
has_mbyte ? mb_l :
1), (colnr_T)vcol, NULL) - 1;
if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)) {
char_u *p = ptr - (
has_mbyte ? mb_l :
1);
// TODO: is passing p for start of the line OK?
n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1;
c_extra = ' ';
if (vim_iswhite(c)) {
if (c == TAB)
/* See "Tab alignment" below. */
FIX_FOR_BOGUSCOLS;
c = ' ';
if (!wp->w_p_list) {
c = ' ';
}
}
}
@ -3419,9 +3457,36 @@ win_line (
* into "ScreenLines".
*/
if (c == TAB && (!wp->w_p_list || lcs_tab1)) {
int tab_len = 0;
/* tab amount depends on current column */
n_extra = (int)wp->w_buffer->b_p_ts
tab_len = (int)wp->w_buffer->b_p_ts
- vcol % (int)wp->w_buffer->b_p_ts - 1;
if (!wp->w_p_lbr || !wp->w_p_list) {
n_extra = tab_len;
} else {
char_u *p;
int len = n_extra;
int i;
int saved_nextra = n_extra;
/* if n_extra > 0, it gives the number of chars to use for
* a tab, else we need to calculate the width for a tab */
len = (tab_len * mb_char2len(lcs_tab2));
if (n_extra > 0) {
len += n_extra - tab_len;
}
c = lcs_tab1;
p = xmalloc(len + 1);
memset(p, ' ', len);
p[len] = NUL;
p_extra_free = p;
for (i = 0; i < tab_len; i++) {
mb_char2bytes(lcs_tab2, p);
p += mb_char2len(lcs_tab2);
n_extra += mb_char2len(lcs_tab2) - (saved_nextra > 0 ? 1: 0);
}
p_extra = p_extra_free;
}
/* Tab alignment should be identical regardless of
* 'conceallevel' value. So tab compensates of all
* previous concealed characters, and thus resets vcol_off
@ -3432,8 +3497,12 @@ win_line (
mb_utf8 = FALSE; /* don't draw as UTF-8 */
if (wp->w_p_list) {
c = lcs_tab1;
c_extra = lcs_tab2;
n_attr = n_extra + 1;
if (wp->w_p_lbr) {
c_extra = NUL; /* using p_extra from above */
} else {
c_extra = lcs_tab2;
}
n_attr = tab_len + 1;
extra_attr = hl_attr(HLF_8);
saved_attr2 = char_attr; /* save current attr */
mb_c = c;
@ -3493,11 +3562,25 @@ win_line (
mb_utf8 = FALSE; /* don't draw as UTF-8 */
} else if (c != NUL) {
p_extra = transchar(c);
if (n_extra == 0) {
n_extra = byte2cells(c);
}
if ((dy_flags & DY_UHEX) && wp->w_p_rl)
rl_mirror(p_extra); /* reverse "<12>" */
n_extra = byte2cells(c) - 1;
c_extra = NUL;
c = *p_extra++;
if (wp->w_p_lbr) {
char_u *p;
c = *p_extra;
p = xmalloc(n_extra + 1);
memset(p, ' ', n_extra);
STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
p[n_extra] = NUL;
p_extra_free = p_extra = p;
} else {
n_extra = byte2cells(c) - 1;
c = *p_extra++;
}
if (!attr_pri) {
n_attr = n_extra + 1;
extra_attr = hl_attr(HLF_8);

View File

@ -30,8 +30,10 @@ SCRIPTS := test_autoformat_join.out \
test91.out test92.out test93.out test94.out test95.out \
test96.out test97.out test98.out test99.out test100.out \
test101.out test102.out test103.out test104.out test105.out \
test106.out test107.out \
test_options.out
test106.out test107.out \
test_options.out \
test_listlbr.out test_listlbr_utf8.out \
test_breakindent.out
SCRIPTS_GUI := test16.out

View File

@ -0,0 +1,79 @@
Test for breakindent
STARTTEST
:so small.vim
:if !exists("+breakindent") | e! test.ok | w! test.out | qa! | endif
:10new|:vsp|:vert resize 20
:put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"
:set ts=4 sw=4 sts=4 breakindent
:fu! ScreenChar(width)
: let c=''
: for i in range(1,a:width)
: let c.=nr2char(screenchar(line('.'), i))
: endfor
: let c.="\n"
: for i in range(1,a:width)
: let c.=nr2char(screenchar(line('.')+1, i))
: endfor
: let c.="\n"
: for i in range(1,a:width)
: let c.=nr2char(screenchar(line('.')+2, i))
: endfor
: return c
:endfu
:fu DoRecordScreen()
: wincmd l
: $put =printf(\"\n%s\", g:test)
: $put =g:line1
: wincmd p
:endfu
:let g:test="Test 1: Simple breakindent"
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test="Test 2: Simple breakindent + sbr=>>"
:set sbr=>>
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test ="Test 3: Simple breakindent + briopt:sbr"
:set briopt=sbr,min:0 sbr=++
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test ="Test 4: Simple breakindent + min width: 18"
:set sbr= briopt=min:18
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test =" Test 5: Simple breakindent + shift by 2"
:set briopt=shift:2,min:0
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test=" Test 6: Simple breakindent + shift by -1"
:set briopt=shift:-1,min:0
:let line1=ScreenChar(8)
:call DoRecordScreen()
:let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"
:set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4
:let line1=ScreenChar(10)
:call DoRecordScreen()
:let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"
:set briopt=shift:1,sbr,min:0 nu sbr=# list
:let line1=ScreenChar(10)
:call DoRecordScreen()
:let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"
:set briopt-=sbr
:let line1=ScreenChar(10)
:call DoRecordScreen()
:let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"
:set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0
:let line1=ScreenChar(10)
:call DoRecordScreen()
:wincmd p
:let g:test="\n Test 11: strdisplaywidth when breakindent is on"
:set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4
:let text=getline(2) "skip leading tab when calculating text width
:let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3 " text wraps 3 times
:$put =g:test
:$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)
:%w! test.out
:qa!
ENDTEST
dummy text

View File

@ -0,0 +1,55 @@
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
Test 1: Simple breakindent
abcd
qrst
GHIJ
Test 2: Simple breakindent + sbr=>>
abcd
>>qr
>>EF
Test 3: Simple breakindent + briopt:sbr
abcd
++ qrst
++ GHIJ
Test 4: Simple breakindent + min width: 18
abcd
qrstuv
IJKLMN
Test 5: Simple breakindent + shift by 2
abcd
qr
EF
Test 6: Simple breakindent + shift by -1
abcd
qrstu
HIJKL
Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr
2 ab
? m
? x
Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr
2 ^Iabcd
# opq
# BCD
Test 9: breakindent + shift by +1 + 'nu' + sbr=# list
2 ^Iabcd
#op
#AB
Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n
2 ab
~ mn
~ yz
Test 11: strdisplaywidth when breakindent is on
strdisplaywidth: 46 == calculated: 64

View File

@ -0,0 +1,52 @@
Test for linebreak and list option (non-utf8)
STARTTEST
:so small.vim
:if !exists("+linebreak") | e! test.ok | w! test.out | qa! | endif
:10new|:vsp|:vert resize 20
:put =\"\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP \"
:norm! zt
:set ts=4 sw=4 sts=4 linebreak sbr=+ wrap
:fu! ScreenChar(width)
: let c=''
: for j in range(1,4)
: for i in range(1,a:width)
: let c.=nr2char(screenchar(j, i))
: endfor
: let c.="\n"
: endfor
: return c
:endfu
:fu! DoRecordScreen()
: wincmd l
: $put =printf(\"\n%s\", g:test)
: $put =g:line
: wincmd p
:endfu
:let g:test="Test 1: set linebreak"
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:let g:test="Test 2: set linebreak + set list"
:set linebreak list listchars=
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:let g:test ="Test 3: set linebreak nolist"
:set nolist linebreak
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:let g:test ="Test 4: set linebreak with tab and 1 line as long as screen: should break!"
:set nolist linebreak ts=8
:let line="1\t".repeat('a', winwidth(0)-2)
:$put =line
:$
:norm! zt
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:%w! test.out
:qa!
ENDTEST
dummy text

View File

@ -0,0 +1,27 @@
abcdef hijklmn pqrstuvwxyz_1060ABCDEFGHIJKLMNOP
Test 1: set linebreak
abcdef
+hijklmn
+pqrstuvwxyz_1060ABC
+DEFGHIJKLMNOP
Test 2: set linebreak + set list
^Iabcdef hijklmn^I
+pqrstuvwxyz_1060ABC
+DEFGHIJKLMNOP
Test 3: set linebreak nolist
abcdef
+hijklmn
+pqrstuvwxyz_1060ABC
+DEFGHIJKLMNOP
1 aaaaaaaaaaaaaaaaaa
Test 4: set linebreak with tab and 1 line as long as screen: should break!
1
+aaaaaaaaaaaaaaaaaa
~
~

View File

@ -0,0 +1,52 @@
Test for linebreak and list option in utf-8 mode
STARTTEST
:so small.vim
:if !exists("+linebreak") | e! test.ok | w! test.out | qa! | endif
:so mbyte.vim
:if &enc !=? 'utf-8'|:e! test.ok|:w! test.out|qa!|endif
:10new|:vsp|:vert resize 20
:put =\"\tabcdef hijklmn\tpqrstuvwxyz\u00a01060ABCDEFGHIJKLMNOP \"
:norm! zt
:set ts=4 sw=4 sts=4 linebreak sbr=+ wrap
:fu! ScreenChar(width)
: let c=''
: for j in range(1,4)
: for i in range(1,a:width)
: let c.=nr2char(screenchar(j, i))
: endfor
: let c.="\n"
: endfor
: return c
:endfu
:fu! DoRecordScreen()
: wincmd l
: $put =printf(\"\n%s\", g:test)
: $put =g:line
: wincmd p
:endfu
:let g:test ="Test 1: set linebreak + set list + fancy listchars"
:exe "set linebreak list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6"
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:"
:let g:test ="Test 2: set nolinebreak list"
:set list nolinebreak
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:"
:let g:test ="Test 3: set linebreak nolist"
:$put =\"\t*mask = nil;\"
:$
:norm! zt
:set nolist linebreak
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:"
:%w! test.out
:qa!
ENDTEST
dummy text

View File

@ -0,0 +1,21 @@
abcdef hijklmn pqrstuvwxyz 1060ABCDEFGHIJKLMNOP
Test 1: set linebreak + set list + fancy listchars
▕———abcdef
+hijklmn▕———
+pqrstuvwxyz␣1060ABC
+DEFGHIJKLMNOPˑ¶
Test 2: set nolinebreak list
▕———abcdef hijklmn▕—
+pqrstuvwxyz␣1060ABC
+DEFGHIJKLMNOPˑ¶
*mask = nil;
Test 3: set linebreak nolist
*mask = nil;
~
~
~

View File

@ -207,7 +207,7 @@ static int included_patches[] = {
//391,
//390,
//389,
//388,
388,
//387,
//386,
//385,
@ -224,8 +224,8 @@ static int included_patches[] = {
//374,
//373,
//372,
//371,
//370,
371,
370,
//369,
//368,
//367,
@ -242,14 +242,14 @@ static int included_patches[] = {
//356 NA
//355,
//354,
//353,
//352,
353,
352,
//351,
//350,
//349,
//348,
//347,
//346,
346,
//345,
//344,
//343,
@ -257,7 +257,7 @@ static int included_patches[] = {
//341,
//340 NA
//339,
//338,
338,
//337,
//336,
335,