1
0
forked from aniani/vim

patch 8.1.0105: all tab stops are the same

Problem:    All tab stops are the same.
Solution:   Add the variable tabstop feature. (Christian Brabandt,
            closes #2711)
This commit is contained in:
Bram Moolenaar
2018-06-23 19:23:02 +02:00
parent 5ec7414a1c
commit 04958cbaf2
31 changed files with 1750 additions and 173 deletions

View File

@@ -182,6 +182,10 @@
# define PV_UDF OPT_BUF(BV_UDF)
#endif
#define PV_WM OPT_BUF(BV_WM)
#ifdef FEAT_VARTABS
# define PV_VSTS OPT_BUF(BV_VSTS)
# define PV_VTS OPT_BUF(BV_VTS)
#endif
/*
* Definition of the PV_ values for window-local options.
@@ -371,6 +375,10 @@ static int p_tx;
static int p_udf;
#endif
static long p_wm;
#ifdef FEAT_VARTABS
static char_u *p_vsts;
static char_u *p_vts;
#endif
#ifdef FEAT_KEYMAP
static char_u *p_keymap;
#endif
@@ -390,6 +398,9 @@ static int p_et_nopaste;
static long p_sts_nopaste;
static long p_tw_nopaste;
static long p_wm_nopaste;
#ifdef FEAT_VARTABS
static char_u *p_vsts_nopaste;
#endif
struct vimoption
{
@@ -2925,6 +2936,24 @@ static struct vimoption options[] =
{"updatetime", "ut", P_NUM|P_VI_DEF,
(char_u *)&p_ut, PV_NONE,
{(char_u *)4000L, (char_u *)0L} SCRIPTID_INIT},
{"varsofttabstop", "vsts", P_STRING|P_VI_DEF|P_VIM|P_COMMA,
#ifdef FEAT_VARTABS
(char_u *)&p_vsts, PV_VSTS,
{(char_u *)"", (char_u *)0L}
#else
(char_u *)NULL, PV_NONE,
{(char_u *)"", (char_u *)NULL}
#endif
SCRIPTID_INIT},
{"vartabstop", "vts", P_STRING|P_VI_DEF|P_VIM|P_RBUF|P_COMMA,
#ifdef FEAT_VARTABS
(char_u *)&p_vts, PV_VTS,
{(char_u *)"", (char_u *)0L}
#else
(char_u *)NULL, PV_NONE,
{(char_u *)"", (char_u *)NULL}
#endif
SCRIPTID_INIT},
{"verbose", "vbs", P_NUM|P_VI_DEF,
(char_u *)&p_verbose, PV_NONE,
{(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
@@ -5608,6 +5637,10 @@ didset_options2(void)
/* Parse default for 'clipboard' */
(void)check_clipboard_option();
#endif
#ifdef FEAT_VARTABS
tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array);
tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array);
#endif
}
/*
@@ -5725,6 +5758,10 @@ check_buf_options(buf_T *buf)
#ifdef FEAT_MBYTE
check_string_option(&buf->b_p_menc);
#endif
#ifdef FEAT_VARTABS
check_string_option(&buf->b_p_vsts);
check_string_option(&buf->b_p_vts);
#endif
}
/*
@@ -7472,6 +7509,88 @@ did_set_string_option(
}
#endif
#ifdef FEAT_VARTABS
/* 'varsofttabstop' */
else if (varp == &(curbuf->b_p_vsts))
{
char_u *cp;
if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
{
if (curbuf->b_p_vsts_array)
{
vim_free(curbuf->b_p_vsts_array);
curbuf->b_p_vsts_array = 0;
}
}
else
{
for (cp = *varp; *cp; ++cp)
{
if (vim_isdigit(*cp))
continue;
if (*cp == ',' && cp > *varp && *(cp-1) != ',')
continue;
errmsg = e_invarg;
break;
}
if (errmsg == NULL)
{
int *oldarray = curbuf->b_p_vsts_array;
if (tabstop_set(*varp, &(curbuf->b_p_vsts_array)))
{
if (oldarray)
vim_free(oldarray);
}
else
errmsg = e_invarg;
}
}
}
/* 'vartabstop' */
else if (varp == &(curbuf->b_p_vts))
{
char_u *cp;
if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
{
if (curbuf->b_p_vts_array)
{
vim_free(curbuf->b_p_vts_array);
curbuf->b_p_vts_array = NULL;
}
}
else
{
for (cp = *varp; *cp; ++cp)
{
if (vim_isdigit(*cp))
continue;
if (*cp == ',' && cp > *varp && *(cp-1) != ',')
continue;
errmsg = e_invarg;
break;
}
if (errmsg == NULL)
{
int *oldarray = curbuf->b_p_vts_array;
if (tabstop_set(*varp, &(curbuf->b_p_vts_array)))
{
if (oldarray)
vim_free(oldarray);
#ifdef FEAT_FOLDING
if (foldmethodIsIndent(curwin))
foldUpdateAll(curwin);
#endif /* FEAT_FOLDING */
}
else
errmsg = e_invarg;
}
}
}
#endif
/* Options that are a list of flags. */
else
{
@@ -8780,7 +8899,14 @@ set_num_option(
if (curbuf->b_p_sw < 0)
{
errmsg = e_positive;
#ifdef FEAT_VARTABS
// Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
curbuf->b_p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
? tabstop_first(curbuf->b_p_vts_array)
: curbuf->b_p_ts;
#else
curbuf->b_p_sw = curbuf->b_p_ts;
#endif
}
/*
@@ -10813,6 +10939,10 @@ get_varp(struct vimoption *p)
#endif
#ifdef FEAT_SIGNS
case PV_SCL: return (char_u *)&(curwin->w_p_scl);
#endif
#ifdef FEAT_VARTABS
case PV_VSTS: return (char_u *)&(curbuf->b_p_vsts);
case PV_VTS: return (char_u *)&(curbuf->b_p_vts);
#endif
default: IEMSG(_("E356: get_varp ERROR"));
}
@@ -11138,6 +11268,15 @@ buf_copy_options(buf_T *buf, int flags)
#endif
buf->b_p_sts = p_sts;
buf->b_p_sts_nopaste = p_sts_nopaste;
#ifdef FEAT_VARTABS
buf->b_p_vsts = vim_strsave(p_vsts);
if (p_vsts && p_vsts != empty_option)
tabstop_set(p_vsts, &buf->b_p_vsts_array);
else
buf->b_p_vsts_array = 0;
buf->b_p_vsts_nopaste = p_vsts_nopaste
? vim_strsave(p_vsts_nopaste) : NULL;
#endif
buf->b_p_sn = p_sn;
#ifdef FEAT_COMMENTS
buf->b_p_com = vim_strsave(p_com);
@@ -11259,12 +11398,27 @@ buf_copy_options(buf_T *buf, int flags)
* or to a help buffer.
*/
if (dont_do_help)
{
buf->b_p_isk = save_p_isk;
#ifdef FEAT_VARTABS
if (p_vts && p_vts != empty_option && !buf->b_p_vts_array)
tabstop_set(p_vts, &buf->b_p_vts_array);
else
buf->b_p_vts_array = NULL;
#endif
}
else
{
buf->b_p_isk = vim_strsave(p_isk);
did_isk = TRUE;
buf->b_p_ts = p_ts;
#ifdef FEAT_VARTABS
buf->b_p_vts = vim_strsave(p_vts);
if (p_vts && p_vts != empty_option && !buf->b_p_vts_array)
tabstop_set(p_vts, &buf->b_p_vts_array);
else
buf->b_p_vts_array = NULL;
#endif
buf->b_help = FALSE;
if (buf->b_p_bt[0] == 'h')
clear_string_option(&buf->b_p_bt);
@@ -12084,6 +12238,12 @@ paste_option_changed(void)
buf->b_p_sts_nopaste = buf->b_p_sts;
buf->b_p_ai_nopaste = buf->b_p_ai;
buf->b_p_et_nopaste = buf->b_p_et;
#ifdef FEAT_VARTABS
if (buf->b_p_vsts_nopaste)
vim_free(buf->b_p_vsts_nopaste);
buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option
? vim_strsave(buf->b_p_vsts) : NULL;
#endif
}
/* save global options */
@@ -12102,6 +12262,11 @@ paste_option_changed(void)
p_sts_nopaste = p_sts;
p_tw_nopaste = p_tw;
p_wm_nopaste = p_wm;
#ifdef FEAT_VARTABS
if (p_vsts_nopaste)
vim_free(p_vsts_nopaste);
p_vsts_nopaste = p_vsts && p_vsts != empty_option ? vim_strsave(p_vsts) : NULL;
#endif
}
/*
@@ -12116,6 +12281,14 @@ paste_option_changed(void)
buf->b_p_sts = 0; /* softtabstop is 0 */
buf->b_p_ai = 0; /* no auto-indent */
buf->b_p_et = 0; /* no expandtab */
#ifdef FEAT_VARTABS
if (buf->b_p_vsts)
free_string_option(buf->b_p_vsts);
buf->b_p_vsts = empty_option;
if (buf->b_p_vsts_array)
vim_free(buf->b_p_vsts_array);
buf->b_p_vsts_array = 0;
#endif
}
/* set global options */
@@ -12135,6 +12308,11 @@ paste_option_changed(void)
p_wm = 0;
p_sts = 0;
p_ai = 0;
#ifdef FEAT_VARTABS
if (p_vsts)
free_string_option(p_vsts);
p_vsts = empty_option;
#endif
}
/*
@@ -12150,6 +12328,18 @@ paste_option_changed(void)
buf->b_p_sts = buf->b_p_sts_nopaste;
buf->b_p_ai = buf->b_p_ai_nopaste;
buf->b_p_et = buf->b_p_et_nopaste;
#ifdef FEAT_VARTABS
if (buf->b_p_vsts)
free_string_option(buf->b_p_vsts);
buf->b_p_vsts = buf->b_p_vsts_nopaste
? vim_strsave(buf->b_p_vsts_nopaste) : empty_option;
if (buf->b_p_vsts_array)
vim_free(buf->b_p_vsts_array);
if (buf->b_p_vsts && buf->b_p_vsts != empty_option)
tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array);
else
buf->b_p_vsts_array = 0;
#endif
}
/* restore global options */
@@ -12170,6 +12360,11 @@ paste_option_changed(void)
p_sts = p_sts_nopaste;
p_tw = p_tw_nopaste;
p_wm = p_wm_nopaste;
#ifdef FEAT_VARTABS
if (p_vsts)
free_string_option(p_vsts);
p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option;
#endif
}
old_p_paste = p_paste;
@@ -12510,6 +12705,295 @@ check_ff_value(char_u *p)
return check_opt_strings(p, p_ff_values, FALSE);
}
#ifdef FEAT_VARTABS
/*
* Set the integer values corresponding to the string setting of 'vartabstop'.
*/
int
tabstop_set(char_u *var, int **array)
{
int valcount = 1;
int t;
char_u *cp;
if ((!var[0] || (var[0] == '0' && !var[1])))
{
*array = NULL;
return TRUE;
}
for (cp = var; *cp; ++cp)
{
if (cp == var || *(cp - 1) == ',')
{
char_u *end;
if (strtol((char *)cp, (char **)&end, 10) <= 0)
{
if (cp != end)
EMSG(_(e_positive));
else
EMSG(_(e_invarg));
return FALSE;
}
}
if (VIM_ISDIGIT(*cp))
continue;
if (*cp == ',' && cp > var && *(cp - 1) != ',')
{
++valcount;
continue;
}
EMSG(_(e_invarg));
return FALSE;
}
*array = (int *) alloc((unsigned) ((valcount + 1) * sizeof(int)));
(*array)[0] = valcount;
t = 1;
for (cp = var; *cp;)
{
(*array)[t++] = atoi((char *)cp);
while (*cp && *cp != ',')
++cp;
if (*cp)
++cp;
}
return TRUE;
}
/*
* Calculate the number of screen spaces a tab will occupy.
* If "vts" is set then the tab widths are taken from that array,
* otherwise the value of ts is used.
*/
int
tabstop_padding(colnr_T col, int ts_arg, int *vts)
{
int ts = ts_arg == 0 ? 8 : ts_arg;
int tabcount;
colnr_T tabcol = 0;
int t;
int padding = 0;
if (vts == NULL || vts[0] == 0)
return ts - (col % ts);
tabcount = vts[0];
for (t = 1; t <= tabcount; ++t)
{
tabcol += vts[t];
if (tabcol > col)
{
padding = (int)(tabcol - col);
break;
}
}
if (t > tabcount)
padding = vts[tabcount] - (int)((col - tabcol) % vts[tabcount]);
return padding;
}
/*
* Find the size of the tab that covers a particular column.
*/
int
tabstop_at(colnr_T col, int ts, int *vts)
{
int tabcount;
colnr_T tabcol = 0;
int t;
int tab_size = 0;
if (vts == 0 || vts[0] == 0)
return ts;
tabcount = vts[0];
for (t = 1; t <= tabcount; ++t)
{
tabcol += vts[t];
if (tabcol > col)
{
tab_size = vts[t];
break;
}
}
if (t > tabcount)
tab_size = vts[tabcount];
return tab_size;
}
/*
* Find the column on which a tab starts.
*/
colnr_T
tabstop_start(colnr_T col, int ts, int *vts)
{
int tabcount;
colnr_T tabcol = 0;
int t;
int excess;
if (vts == 0 || vts[0] == 0)
return (col / ts) * ts;
tabcount = vts[0];
for (t = 1; t <= tabcount; ++t)
{
tabcol += vts[t];
if (tabcol > col)
return tabcol - vts[t];
}
excess = tabcol % vts[tabcount];
return excess + ((col - excess) / vts[tabcount]) * vts[tabcount];
}
/*
* Find the number of tabs and spaces necessary to get from one column
* to another.
*/
void
tabstop_fromto(
colnr_T start_col,
colnr_T end_col,
int ts,
int *vts,
int *ntabs,
int *nspcs)
{
int spaces = end_col - start_col;
colnr_T tabcol = 0;
int padding = 0;
int tabcount;
int t;
if (vts == 0 || vts[0] == 0)
{
int tabs = 0;
int initspc = ts - (start_col % ts);
if (spaces >= initspc)
{
spaces -= initspc;
tabs++;
}
tabs += spaces / ts;
spaces -= (spaces / ts) * ts;
*ntabs = tabs;
*nspcs = spaces;
return;
}
/* Find the padding needed to reach the next tabstop. */
tabcount = vts[0];
for (t = 1; t <= tabcount; ++t)
{
tabcol += vts[t];
if (tabcol > start_col)
{
padding = (int)(tabcol - start_col);
break;
}
}
if (t > tabcount)
padding = vts[tabcount] - (int)((start_col - tabcol) % vts[tabcount]);
/* If the space needed is less than the padding no tabs can be used. */
if (spaces < padding)
{
*ntabs = 0;
*nspcs = spaces;
return;
}
*ntabs = 1;
spaces -= padding;
/* At least one tab has been used. See if any more will fit. */
while (spaces != 0 && ++t <= tabcount)
{
padding = vts[t];
if (spaces < padding)
{
*nspcs = spaces;
return;
}
++*ntabs;
spaces -= padding;
}
*ntabs += spaces / vts[tabcount];
*nspcs = spaces % vts[tabcount];
}
/*
* See if two tabstop arrays contain the same values.
*/
int
tabstop_eq(int *ts1, int *ts2)
{
int t;
if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0))
return FALSE;
if (ts1 == ts2)
return TRUE;
if (ts1[0] != ts2[0])
return FALSE;
for (t = 1; t <= ts1[0]; ++t)
if (ts1[t] != ts2[t])
return FALSE;
return TRUE;
}
/*
* Copy a tabstop array, allocating space for the new array.
*/
int *
tabstop_copy(int *oldts)
{
int *newts;
int t;
if (oldts == 0)
return 0;
newts = (int *) alloc((unsigned) ((oldts[0] + 1) * sizeof(int)));
for (t = 0; t <= oldts[0]; ++t)
newts[t] = oldts[t];
return newts;
}
/*
* Return a count of the number of tabstops.
*/
int
tabstop_count(int *ts)
{
return ts != NULL ? ts[0] : 0;
}
/*
* Return the first tabstop, or 8 if there are no tabstops defined.
*/
int
tabstop_first(int *ts)
{
return ts != NULL ? ts[1] : 8;
}
#endif
/*
* Return the effective shiftwidth value for current buffer, using the
* 'tabstop' value when 'shiftwidth' is zero.