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:
484
src/option.c
484
src/option.c
@@ -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.
|
||||
|
Reference in New Issue
Block a user