aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelipe Morales <hel.sheep@gmail.com>2014-06-26 00:21:57 -0400
committerFelipe Morales <hel.sheep@gmail.com>2014-08-20 05:19:49 -0400
commit47391b18e2084f2747b10aa6158bc40e03f01528 (patch)
treec4964c57901313d4067f80325d320cc94a579b49 /src
parentbbefc73c553d681f78f40df9d97ec89ae9b06520 (diff)
downloadrneovim-47391b18e2084f2747b10aa6158bc40e03f01528.tar.gz
rneovim-47391b18e2084f2747b10aa6158bc40e03f01528.tar.bz2
rneovim-47391b18e2084f2747b10aa6158bc40e03f01528.zip
Port vim's patch 7.4.338 ('breakindent')
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h7
-rw-r--r--src/nvim/charset.c56
-rw-r--r--src/nvim/cursor.c2
-rw-r--r--src/nvim/edit.c22
-rw-r--r--src/nvim/ex_getln.c8
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/indent.c75
-rw-r--r--src/nvim/misc1.c11
-rw-r--r--src/nvim/ops.c20
-rw-r--r--src/nvim/option.c63
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/screen.c42
-rw-r--r--src/nvim/testdir/test_breakindent.in79
-rw-r--r--src/nvim/testdir/test_breakindent.ok55
14 files changed, 381 insertions, 63 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 9f5d7b86eb..4162df63ab 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -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))
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index baf6895b4c..3392cceb9f 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -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,12 +963,13 @@ 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 colmax;
@@ -975,8 +980,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);
}
@@ -1039,11 +1044,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 +1062,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 +1168,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 +1185,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 +1243,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) {
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 64a3b73f15..cd84d7014c 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -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;
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 93e127394b..6158176e56 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -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;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 28048c933c..74f3edc8d9 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -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);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index e98bb2744c..6c772a8a66 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -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);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index d4c6b36177..7673a297f6 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -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) + wp->w_p_brishift;
+ }
+
+ /* indent minus the length of the showbreak string */
+ bri = prev_indent;
+ 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++;
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index f0c4ee492e..986374b352 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -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.
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 0bf338947b..0b0a913a95 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -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
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 63ea2ee338..7d40fb3d6b 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -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,44 @@ void find_mps_values(int *initc, int *findc, int *backwards, int switchit)
++ptr;
}
}
+
+/* This is called when 'breakindentopt' is changed and whenn a window is
+ initialized */
+int briopt_check() {
+ 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;
+}
+
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index d862ab2761..555e9166d6 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -726,6 +726,8 @@ enum {
, WV_COCU
, WV_COLE
, WV_CRBIND
+ , WV_BRI
+ , WV_BRIOPT
, WV_DIFF
, WV_FDC
, WV_FEN
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 03c59bf584..61e783f2b1 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -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"
@@ -2283,7 +2284,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 +2542,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 +2819,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) {
@@ -3380,9 +3410,11 @@ win_line (
*/
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;
+ 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, p, p, (colnr_T)vcol, NULL) - 1;
c_extra = ' ';
if (vim_iswhite(c)) {
if (c == TAB)
diff --git a/src/nvim/testdir/test_breakindent.in b/src/nvim/testdir/test_breakindent.in
new file mode 100644
index 0000000000..8f40e4f7e5
--- /dev/null
+++ b/src/nvim/testdir/test_breakindent.in
@@ -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
diff --git a/src/nvim/testdir/test_breakindent.ok b/src/nvim/testdir/test_breakindent.ok
new file mode 100644
index 0000000000..723cb25012
--- /dev/null
+++ b/src/nvim/testdir/test_breakindent.ok
@@ -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