mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.1.1966: some code in options.c fits better elsewhere (#19840)
Problem: Some code in options.c fits better elsewhere.
Solution: Move functions from options.c to other files. (Yegappan
Lakshmanan, closes vim/vim#4889)
e677df8d93
This commit is contained in:
parent
5dc43265b1
commit
2af9be3db5
@ -5195,29 +5195,6 @@ linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf)
|
||||
return (linenr_T)tv_get_number_chk(tv, NULL);
|
||||
}
|
||||
|
||||
void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
|
||||
{
|
||||
if (what_arg->v_type == VAR_UNKNOWN) {
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
if (is_qf || wp != NULL) {
|
||||
(void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
|
||||
}
|
||||
} else {
|
||||
tv_dict_alloc_ret(rettv);
|
||||
if (is_qf || wp != NULL) {
|
||||
if (what_arg->v_type == VAR_DICT) {
|
||||
dict_T *d = what_arg->vval.v_dict;
|
||||
|
||||
if (d != NULL) {
|
||||
qf_get_properties(wp, d, rettv->vval.v_dict);
|
||||
}
|
||||
} else {
|
||||
emsg(_(e_dictreq));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @return information (variables, options, etc.) about a tab page
|
||||
/// as a dictionary.
|
||||
dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
|
||||
|
@ -3097,13 +3097,6 @@ static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
get_buffer_lines(curbuf, lnum, end, retlist, rettv);
|
||||
}
|
||||
|
||||
/// "getloclist()" function
|
||||
static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
get_qf_loc_list(false, wp, &argvars[1], rettv);
|
||||
}
|
||||
|
||||
/// "getmarklist()" function
|
||||
static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
@ -3186,12 +3179,6 @@ static void f_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
getpos_both(argvars, rettv, false, false);
|
||||
}
|
||||
|
||||
/// "getqflist()" functions
|
||||
static void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
get_qf_loc_list(true, NULL, &argvars[0], rettv);
|
||||
}
|
||||
|
||||
/// Common between getreg(), getreginfo() and getregtype(): get the register
|
||||
/// name from the first argument.
|
||||
/// Returns zero on error.
|
||||
@ -7761,110 +7748,12 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
|
||||
}
|
||||
|
||||
/// Create quickfix/location list from VimL values
|
||||
///
|
||||
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
|
||||
/// args argument in which case errors out, including VAR_UNKNOWN parameters.
|
||||
///
|
||||
/// @param[in,out] wp Window to create location list for. May be NULL in
|
||||
/// which case quickfix list will be created.
|
||||
/// @param[in] args [list, action, what]
|
||||
/// @param[in] args[0] Quickfix list contents.
|
||||
/// @param[in] args[1] Optional. Action to perform:
|
||||
/// append to an existing list, replace its content,
|
||||
/// or create a new one.
|
||||
/// @param[in] args[2] Optional. Quickfix list properties or title.
|
||||
/// Defaults to caller function name.
|
||||
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
|
||||
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(2, 3)
|
||||
{
|
||||
static char *e_invact = N_("E927: Invalid action: '%s'");
|
||||
const char *title = NULL;
|
||||
char action = ' ';
|
||||
static int recursive = 0;
|
||||
rettv->vval.v_number = -1;
|
||||
dict_T *what = NULL;
|
||||
|
||||
typval_T *list_arg = &args[0];
|
||||
if (list_arg->v_type != VAR_LIST) {
|
||||
emsg(_(e_listreq));
|
||||
return;
|
||||
} else if (recursive != 0) {
|
||||
emsg(_(e_au_recursive));
|
||||
return;
|
||||
}
|
||||
|
||||
typval_T *action_arg = &args[1];
|
||||
if (action_arg->v_type == VAR_UNKNOWN) {
|
||||
// Option argument was not given.
|
||||
goto skip_args;
|
||||
} else if (action_arg->v_type != VAR_STRING) {
|
||||
emsg(_(e_stringreq));
|
||||
return;
|
||||
}
|
||||
const char *const act = tv_get_string_chk(action_arg);
|
||||
if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f')
|
||||
&& act[1] == NUL) {
|
||||
action = *act;
|
||||
} else {
|
||||
semsg(_(e_invact), act);
|
||||
return;
|
||||
}
|
||||
|
||||
typval_T *const what_arg = &args[2];
|
||||
if (what_arg->v_type == VAR_UNKNOWN) {
|
||||
// Option argument was not given.
|
||||
goto skip_args;
|
||||
} else if (what_arg->v_type == VAR_STRING) {
|
||||
title = tv_get_string_chk(what_arg);
|
||||
if (!title) {
|
||||
// Type error. Error already printed by tv_get_string_chk().
|
||||
return;
|
||||
}
|
||||
} else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) {
|
||||
what = what_arg->vval.v_dict;
|
||||
} else {
|
||||
emsg(_(e_dictreq));
|
||||
return;
|
||||
}
|
||||
|
||||
skip_args:
|
||||
if (!title) {
|
||||
title = (wp ? ":setloclist()" : ":setqflist()");
|
||||
}
|
||||
|
||||
recursive++;
|
||||
list_T *const l = list_arg->vval.v_list;
|
||||
if (set_errorlist(wp, l, action, (char *)title, what) == OK) {
|
||||
rettv->vval.v_number = 0;
|
||||
}
|
||||
recursive--;
|
||||
}
|
||||
|
||||
/// "setloclist()" function
|
||||
static void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
rettv->vval.v_number = -1;
|
||||
|
||||
win_T *win = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (win != NULL) {
|
||||
set_qf_ll_list(win, &argvars[1], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// "setpos()" function
|
||||
static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
set_position(argvars, rettv, false);
|
||||
}
|
||||
|
||||
/// "setqflist()" function
|
||||
static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
set_qf_ll_list(NULL, argvars, rettv);
|
||||
}
|
||||
|
||||
/// Translate a register type string to the yank type and block length
|
||||
static int get_yank_type(char **const pp, MotionType *const yank_type, long *const block_len)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nvim/grid.h"
|
||||
#include "nvim/hardcopy.h"
|
||||
#include "nvim/highlight_group.h"
|
||||
#include "nvim/indent.h"
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/memline.h"
|
||||
#include "nvim/memory.h"
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/edit.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/extmark.h"
|
||||
#include "nvim/indent.h"
|
||||
@ -30,6 +31,313 @@
|
||||
# include "indent.c.generated.h"
|
||||
#endif
|
||||
|
||||
/// Set the integer values corresponding to the string setting of 'vartabstop'.
|
||||
/// "array" will be set, caller must free it if needed.
|
||||
/// Return false for an error.
|
||||
bool tabstop_set(char_u *var, long **array)
|
||||
{
|
||||
long valcount = 1;
|
||||
int t;
|
||||
char_u *cp;
|
||||
|
||||
if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) {
|
||||
*array = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (cp = var; *cp != NUL; cp++) {
|
||||
if (cp == var || cp[-1] == ',') {
|
||||
char *end;
|
||||
|
||||
if (strtol((char *)cp, &end, 10) <= 0) {
|
||||
if (cp != (char_u *)end) {
|
||||
emsg(_(e_positive));
|
||||
} else {
|
||||
semsg(_(e_invarg2), cp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ascii_isdigit(*cp)) {
|
||||
continue;
|
||||
}
|
||||
if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) {
|
||||
valcount++;
|
||||
continue;
|
||||
}
|
||||
semsg(_(e_invarg2), var);
|
||||
return false;
|
||||
}
|
||||
|
||||
*array = (long *)xmalloc((unsigned)(valcount + 1) * sizeof(long));
|
||||
(*array)[0] = valcount;
|
||||
|
||||
t = 1;
|
||||
for (cp = var; *cp != NUL;) {
|
||||
int n = atoi((char *)cp);
|
||||
|
||||
// Catch negative values, overflow and ridiculous big values.
|
||||
if (n <= 0 || n > TABSTOP_MAX) {
|
||||
semsg(_(e_invarg2), cp);
|
||||
XFREE_CLEAR(*array);
|
||||
return false;
|
||||
}
|
||||
(*array)[t++] = n;
|
||||
while (*cp != NUL && *cp != ',') {
|
||||
cp++;
|
||||
}
|
||||
if (*cp != NUL) {
|
||||
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, long ts_arg, long *vts)
|
||||
{
|
||||
long ts = ts_arg == 0 ? 8 : ts_arg;
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
long padding = 0;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)(ts - (col % ts));
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
padding = tabcol - col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]);
|
||||
}
|
||||
|
||||
return (int)padding;
|
||||
}
|
||||
|
||||
/// Find the size of the tab that covers a particular column.
|
||||
int tabstop_at(colnr_T col, long ts, long *vts)
|
||||
{
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
long tab_size = 0;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)ts;
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
tab_size = vts[t];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
tab_size = vts[tabcount];
|
||||
}
|
||||
|
||||
return (int)tab_size;
|
||||
}
|
||||
|
||||
/// Find the column on which a tab starts.
|
||||
colnr_T tabstop_start(colnr_T col, long ts, long *vts)
|
||||
{
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)((col / ts) * ts);
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
return (int)(tabcol - vts[t]);
|
||||
}
|
||||
}
|
||||
|
||||
const int excess = (int)(tabcol % vts[tabcount]);
|
||||
return (int)(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, long ts_arg, long *vts, int *ntabs,
|
||||
int *nspcs)
|
||||
{
|
||||
int spaces = end_col - start_col;
|
||||
colnr_T tabcol = 0;
|
||||
long padding = 0;
|
||||
int t;
|
||||
long ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
int tabs = 0;
|
||||
|
||||
const int initspc = (int)(ts - (start_col % ts));
|
||||
if (spaces >= initspc) {
|
||||
spaces -= initspc;
|
||||
tabs++;
|
||||
}
|
||||
tabs += (int)(spaces / ts);
|
||||
spaces -= (int)((spaces / ts) * ts);
|
||||
|
||||
*ntabs = tabs;
|
||||
*nspcs = spaces;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the padding needed to reach the next tabstop.
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > start_col) {
|
||||
padding = tabcol - start_col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
padding = vts[tabcount] - ((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 -= (int)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 += 1;
|
||||
spaces -= (int)padding;
|
||||
}
|
||||
|
||||
*ntabs += spaces / (int)vts[tabcount];
|
||||
*nspcs = spaces % (int)vts[tabcount];
|
||||
}
|
||||
|
||||
/// See if two tabstop arrays contain the same values.
|
||||
bool tabstop_eq(long *ts1, long *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(long *oldts)
|
||||
{
|
||||
long *newts;
|
||||
int t;
|
||||
|
||||
if (oldts == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
newts = xmalloc((unsigned)(oldts[0] + 1) * sizeof(long));
|
||||
for (t = 0; t <= oldts[0]; t++) {
|
||||
newts[t] = oldts[t];
|
||||
}
|
||||
|
||||
return (int *)newts;
|
||||
}
|
||||
|
||||
/// Return a count of the number of tabstops.
|
||||
int tabstop_count(long *ts)
|
||||
{
|
||||
return ts != NULL ? (int)ts[0] : 0;
|
||||
}
|
||||
|
||||
/// Return the first tabstop, or 8 if there are no tabstops defined.
|
||||
int tabstop_first(long *ts)
|
||||
{
|
||||
return ts != NULL ? (int)ts[1] : 8;
|
||||
}
|
||||
|
||||
/// Return the effective shiftwidth value for current buffer, using the
|
||||
/// 'tabstop' value when 'shiftwidth' is zero.
|
||||
int get_sw_value(buf_T *buf)
|
||||
{
|
||||
long result = get_sw_value_col(buf, 0);
|
||||
assert(result >= 0 && result <= INT_MAX);
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
/// Idem, using "pos".
|
||||
long get_sw_value_pos(buf_T *buf, pos_T *pos)
|
||||
{
|
||||
pos_T save_cursor = curwin->w_cursor;
|
||||
long sw_value;
|
||||
|
||||
curwin->w_cursor = *pos;
|
||||
sw_value = get_sw_value_col(buf, get_nolist_virtcol());
|
||||
curwin->w_cursor = save_cursor;
|
||||
return sw_value;
|
||||
}
|
||||
|
||||
/// Idem, using the first non-black in the current line.
|
||||
long get_sw_value_indent(buf_T *buf)
|
||||
{
|
||||
pos_T pos = curwin->w_cursor;
|
||||
|
||||
pos.col = (colnr_T)getwhitecols_curline();
|
||||
return get_sw_value_pos(buf, &pos);
|
||||
}
|
||||
|
||||
/// Idem, using virtual column "col".
|
||||
long get_sw_value_col(buf_T *buf, colnr_T col)
|
||||
{
|
||||
return buf->b_p_sw ? buf->b_p_sw
|
||||
: tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
|
||||
}
|
||||
|
||||
/// Return the effective softtabstop value for the current buffer,
|
||||
/// using the shiftwidth value when 'softtabstop' is negative.
|
||||
int get_sts_value(void)
|
||||
{
|
||||
long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
|
||||
assert(result >= 0 && result <= INT_MAX);
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
// Count the size (in window cells) of the indent in the current line.
|
||||
int get_indent(void)
|
||||
{
|
||||
|
@ -50,9 +50,9 @@
|
||||
#include "nvim/memline.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/option.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/spell.h"
|
||||
#include "nvim/strings.h"
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nvim/getchar.h"
|
||||
#include "nvim/grid.h"
|
||||
#include "nvim/highlight.h"
|
||||
#include "nvim/indent.h"
|
||||
#include "nvim/input.h"
|
||||
#include "nvim/keycodes.h"
|
||||
#include "nvim/main.h"
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "nvim/hardcopy.h"
|
||||
#include "nvim/highlight.h"
|
||||
#include "nvim/highlight_group.h"
|
||||
#include "nvim/indent.h"
|
||||
#include "nvim/indent_c.h"
|
||||
#include "nvim/insexpand.h"
|
||||
#include "nvim/keycodes.h"
|
||||
@ -72,6 +73,7 @@
|
||||
#include "nvim/popupmenu.h"
|
||||
#include "nvim/regexp.h"
|
||||
#include "nvim/runtime.h"
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/spell.h"
|
||||
#include "nvim/spellfile.h"
|
||||
#include "nvim/spellsuggest.h"
|
||||
@ -344,9 +346,6 @@ static char_u SHM_ALL[] = {
|
||||
static char e_unclosed_expression_sequence[] = N_("E540: Unclosed expression sequence");
|
||||
static char e_unbalanced_groups[] = N_("E542: unbalanced groups");
|
||||
|
||||
static char e_conflicts_with_value_of_listchars[] = N_("E834: Conflicts with value of 'listchars'");
|
||||
static char e_conflicts_with_value_of_fillchars[] = N_("E835: Conflicts with value of 'fillchars'");
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "option.c.generated.h"
|
||||
#endif
|
||||
@ -2317,7 +2316,7 @@ static char *set_string_option(const int opt_idx, const char *const value, const
|
||||
|
||||
/// Return true if "val" is a valid name: only consists of alphanumeric ASCII
|
||||
/// characters or characters in "allowed".
|
||||
static bool valid_name(const char_u *val, const char *allowed)
|
||||
bool valid_name(const char_u *val, const char *allowed)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
for (const char_u *s = val; *s != NUL; s++) {
|
||||
@ -2337,25 +2336,6 @@ static bool valid_filetype(const char_u *val)
|
||||
return valid_name(val, ".-_");
|
||||
}
|
||||
|
||||
/// Return true if "val" is a valid 'spelllang' value.
|
||||
bool valid_spelllang(const char_u *val)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return valid_name(val, ".-_,@");
|
||||
}
|
||||
|
||||
/// Return true if "val" is a valid 'spellfile' value.
|
||||
static bool valid_spellfile(const char_u *val)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
for (const char_u *s = val; *s != NUL; s++) {
|
||||
if (!vim_isfilec(*s) && *s != ',' && *s != ' ') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Handle setting 'mousescroll'.
|
||||
/// @return error message, NULL if it's OK.
|
||||
static char *check_mousescroll(char *string)
|
||||
@ -3432,12 +3412,6 @@ static char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, c
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/// Simple int comparison function for use with qsort()
|
||||
static int int_cmp(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
/// Handle setting 'signcolumn' for value 'val'
|
||||
///
|
||||
/// @return OK when the value is valid, FAIL otherwise
|
||||
@ -3468,366 +3442,12 @@ int check_signcolumn(char_u *val)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
|
||||
///
|
||||
/// @return error message, NULL if it's OK.
|
||||
char *check_colorcolumn(win_T *wp)
|
||||
{
|
||||
char *s;
|
||||
int col;
|
||||
unsigned int count = 0;
|
||||
int color_cols[256];
|
||||
int j = 0;
|
||||
|
||||
if (wp->w_buffer == NULL) {
|
||||
return NULL; // buffer was closed
|
||||
}
|
||||
|
||||
for (s = (char *)wp->w_p_cc; *s != NUL && count < 255;) {
|
||||
if (*s == '-' || *s == '+') {
|
||||
// -N and +N: add to 'textwidth'
|
||||
col = (*s == '-') ? -1 : 1;
|
||||
s++;
|
||||
if (!ascii_isdigit(*s)) {
|
||||
return e_invarg;
|
||||
}
|
||||
col = col * getdigits_int(&s, true, 0);
|
||||
if (wp->w_buffer->b_p_tw == 0) {
|
||||
goto skip; // 'textwidth' not set, skip this item
|
||||
}
|
||||
assert((col >= 0
|
||||
&& wp->w_buffer->b_p_tw <= INT_MAX - col
|
||||
&& wp->w_buffer->b_p_tw + col >= INT_MIN)
|
||||
|| (col < 0
|
||||
&& wp->w_buffer->b_p_tw >= INT_MIN - col
|
||||
&& wp->w_buffer->b_p_tw + col <= INT_MAX));
|
||||
col += (int)wp->w_buffer->b_p_tw;
|
||||
if (col < 0) {
|
||||
goto skip;
|
||||
}
|
||||
} else if (ascii_isdigit(*s)) {
|
||||
col = getdigits_int(&s, true, 0);
|
||||
} else {
|
||||
return e_invarg;
|
||||
}
|
||||
color_cols[count++] = col - 1; // 1-based to 0-based
|
||||
skip:
|
||||
if (*s == NUL) {
|
||||
break;
|
||||
}
|
||||
if (*s != ',') {
|
||||
return e_invarg;
|
||||
}
|
||||
if (*++s == NUL) {
|
||||
return e_invarg; // illegal trailing comma as in "set cc=80,"
|
||||
}
|
||||
}
|
||||
|
||||
xfree(wp->w_p_cc_cols);
|
||||
if (count == 0) {
|
||||
wp->w_p_cc_cols = NULL;
|
||||
} else {
|
||||
wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1));
|
||||
/* sort the columns for faster usage on screen redraw inside
|
||||
* win_line() */
|
||||
qsort(color_cols, count, sizeof(int), int_cmp);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
// skip duplicates
|
||||
if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) {
|
||||
wp->w_p_cc_cols[j++] = color_cols[i];
|
||||
}
|
||||
}
|
||||
wp->w_p_cc_cols[j] = -1; // end marker
|
||||
}
|
||||
|
||||
return NULL; // no error
|
||||
}
|
||||
|
||||
void check_blending(win_T *wp)
|
||||
{
|
||||
wp->w_grid_alloc.blending =
|
||||
wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow);
|
||||
}
|
||||
|
||||
/// Calls mb_cptr2char_adv(p) and returns the character.
|
||||
/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
|
||||
/// Returns 0 for invalid hex or invalid UTF-8 byte.
|
||||
static int get_encoded_char_adv(char_u **p)
|
||||
{
|
||||
char_u *s = *p;
|
||||
|
||||
if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
|
||||
int64_t num = 0;
|
||||
int bytes;
|
||||
int n;
|
||||
for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
|
||||
*p += 2;
|
||||
n = hexhex2nr(*p);
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
num = num * 256 + n;
|
||||
}
|
||||
*p += 2;
|
||||
return (int)num;
|
||||
}
|
||||
|
||||
// TODO(bfredl): use schar_T representation and utfc_ptr2len
|
||||
int clen = utf_ptr2len((char *)s);
|
||||
int c = mb_cptr2char_adv((const char_u **)p);
|
||||
if (clen == 1 && c > 127) { // Invalid UTF-8 byte
|
||||
return 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/// Handle setting 'listchars' or 'fillchars'.
|
||||
/// Assume monocell characters
|
||||
///
|
||||
/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs
|
||||
/// @return error message, NULL if it's OK.
|
||||
char *set_chars_option(win_T *wp, char_u **varp, bool set)
|
||||
{
|
||||
int round, i, len, len2, entries;
|
||||
char_u *p, *s;
|
||||
int c1;
|
||||
int c2 = 0;
|
||||
int c3 = 0;
|
||||
char_u *last_multispace = NULL; // Last occurrence of "multispace:"
|
||||
char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
|
||||
int multispace_len = 0; // Length of lcs-multispace string
|
||||
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
|
||||
|
||||
struct chars_tab {
|
||||
int *cp; ///< char value
|
||||
char *name; ///< char id
|
||||
int def; ///< default value
|
||||
};
|
||||
struct chars_tab *tab;
|
||||
|
||||
// XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
|
||||
struct chars_tab fcs_tab[] = {
|
||||
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
|
||||
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
|
||||
{ &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
|
||||
{ &wp->w_p_fcs_chars.horiz, "horiz", char2cells(0x2500) == 1 ? 0x2500 : '-' }, // ─
|
||||
{ &wp->w_p_fcs_chars.horizup, "horizup", char2cells(0x2534) == 1 ? 0x2534 : '-' }, // ┴
|
||||
{ &wp->w_p_fcs_chars.horizdown, "horizdown", char2cells(0x252c) == 1 ? 0x252c : '-' }, // ┬
|
||||
{ &wp->w_p_fcs_chars.vert, "vert", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
|
||||
{ &wp->w_p_fcs_chars.vertleft, "vertleft", char2cells(0x2524) == 1 ? 0x2524 : '|' }, // ┤
|
||||
{ &wp->w_p_fcs_chars.vertright, "vertright", char2cells(0x251c) == 1 ? 0x251c : '|' }, // ├
|
||||
{ &wp->w_p_fcs_chars.verthoriz, "verthoriz", char2cells(0x253c) == 1 ? 0x253c : '+' }, // ┼
|
||||
{ &wp->w_p_fcs_chars.fold, "fold", char2cells(0x00b7) == 1 ? 0x00b7 : '-' }, // ·
|
||||
{ &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
|
||||
{ &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
|
||||
{ &wp->w_p_fcs_chars.foldsep, "foldsep", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
|
||||
{ &wp->w_p_fcs_chars.diff, "diff", '-' },
|
||||
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
|
||||
{ &wp->w_p_fcs_chars.eob, "eob", '~' },
|
||||
};
|
||||
struct chars_tab lcs_tab[] = {
|
||||
{ &wp->w_p_lcs_chars.eol, "eol", NUL },
|
||||
{ &wp->w_p_lcs_chars.ext, "extends", NUL },
|
||||
{ &wp->w_p_lcs_chars.nbsp, "nbsp", NUL },
|
||||
{ &wp->w_p_lcs_chars.prec, "precedes", NUL },
|
||||
{ &wp->w_p_lcs_chars.space, "space", NUL },
|
||||
{ &wp->w_p_lcs_chars.tab2, "tab", NUL },
|
||||
{ &wp->w_p_lcs_chars.lead, "lead", NUL },
|
||||
{ &wp->w_p_lcs_chars.trail, "trail", NUL },
|
||||
{ &wp->w_p_lcs_chars.conceal, "conceal", NUL },
|
||||
};
|
||||
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
tab = lcs_tab;
|
||||
entries = ARRAY_SIZE(lcs_tab);
|
||||
if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
|
||||
varp = &p_lcs;
|
||||
}
|
||||
} else {
|
||||
tab = fcs_tab;
|
||||
entries = ARRAY_SIZE(fcs_tab);
|
||||
if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
|
||||
varp = &p_fcs;
|
||||
}
|
||||
}
|
||||
|
||||
// first round: check for valid value, second round: assign values
|
||||
for (round = 0; round <= (set ? 1 : 0); round++) {
|
||||
if (round > 0) {
|
||||
// After checking that the value is valid: set defaults
|
||||
for (i = 0; i < entries; i++) {
|
||||
if (tab[i].cp != NULL) {
|
||||
*(tab[i].cp) = tab[i].def;
|
||||
}
|
||||
}
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
wp->w_p_lcs_chars.tab1 = NUL;
|
||||
wp->w_p_lcs_chars.tab3 = NUL;
|
||||
|
||||
xfree(wp->w_p_lcs_chars.multispace);
|
||||
if (multispace_len > 0) {
|
||||
wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
|
||||
wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
|
||||
} else {
|
||||
wp->w_p_lcs_chars.multispace = NULL;
|
||||
}
|
||||
|
||||
xfree(wp->w_p_lcs_chars.leadmultispace);
|
||||
if (lead_multispace_len > 0) {
|
||||
wp->w_p_lcs_chars.leadmultispace
|
||||
= xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
|
||||
wp->w_p_lcs_chars.leadmultispace[lead_multispace_len] = NUL;
|
||||
} else {
|
||||
wp->w_p_lcs_chars.leadmultispace = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = *varp;
|
||||
while (*p) {
|
||||
for (i = 0; i < entries; i++) {
|
||||
len = (int)STRLEN(tab[i].name);
|
||||
if (STRNCMP(p, tab[i].name, len) == 0
|
||||
&& p[len] == ':'
|
||||
&& p[len + 1] != NUL) {
|
||||
c2 = c3 = 0;
|
||||
s = p + len + 1;
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||
if (*s == NUL) {
|
||||
return e_invarg;
|
||||
}
|
||||
c2 = get_encoded_char_adv(&s);
|
||||
if (c2 == 0 || char2cells(c2) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
if (!(*s == ',' || *s == NUL)) {
|
||||
c3 = get_encoded_char_adv(&s);
|
||||
if (c3 == 0 || char2cells(c3) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*s == ',' || *s == NUL) {
|
||||
if (round > 0) {
|
||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||
wp->w_p_lcs_chars.tab1 = c1;
|
||||
wp->w_p_lcs_chars.tab2 = c2;
|
||||
wp->w_p_lcs_chars.tab3 = c3;
|
||||
} else if (tab[i].cp != NULL) {
|
||||
*(tab[i].cp) = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == entries) {
|
||||
len = (int)STRLEN("multispace");
|
||||
len2 = (int)STRLEN("leadmultispace");
|
||||
if ((varp == &p_lcs || varp == &wp->w_p_lcs)
|
||||
&& STRNCMP(p, "multispace", len) == 0
|
||||
&& p[len] == ':'
|
||||
&& p[len + 1] != NUL) {
|
||||
s = p + len + 1;
|
||||
if (round == 0) {
|
||||
// Get length of lcs-multispace string in the first round
|
||||
last_multispace = p;
|
||||
multispace_len = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
multispace_len++;
|
||||
}
|
||||
if (multispace_len == 0) {
|
||||
// lcs-multispace cannot be an empty string
|
||||
return e_invarg;
|
||||
}
|
||||
p = s;
|
||||
} else {
|
||||
int multispace_pos = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (p == last_multispace) {
|
||||
wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
}
|
||||
} else if ((varp == &p_lcs || varp == &wp->w_p_lcs)
|
||||
&& STRNCMP(p, "leadmultispace", len2) == 0
|
||||
&& p[len2] == ':'
|
||||
&& p[len2 + 1] != NUL) {
|
||||
s = p + len2 + 1;
|
||||
if (round == 0) {
|
||||
// get length of lcs-leadmultispace string in first round
|
||||
last_lmultispace = p;
|
||||
lead_multispace_len = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
lead_multispace_len++;
|
||||
}
|
||||
if (lead_multispace_len == 0) {
|
||||
// lcs-leadmultispace cannot be an empty string
|
||||
return e_invarg;
|
||||
}
|
||||
p = s;
|
||||
} else {
|
||||
int multispace_pos = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (p == last_lmultispace) {
|
||||
wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
}
|
||||
} else {
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
if (*p == ',') {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // no error
|
||||
}
|
||||
|
||||
/// Check all global and local values of 'listchars' and 'fillchars'.
|
||||
/// May set different defaults in case character widths change.
|
||||
///
|
||||
/// @return an untranslated error message if any of them is invalid, NULL otherwise.
|
||||
char *check_chars_options(void)
|
||||
{
|
||||
if (set_chars_option(curwin, &p_lcs, false) != NULL) {
|
||||
return e_conflicts_with_value_of_listchars;
|
||||
}
|
||||
if (set_chars_option(curwin, &p_fcs, false) != NULL) {
|
||||
return e_conflicts_with_value_of_fillchars;
|
||||
}
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
|
||||
return e_conflicts_with_value_of_listchars;
|
||||
}
|
||||
if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
|
||||
return e_conflicts_with_value_of_fillchars;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Check validity of options with the 'statusline' format.
|
||||
/// Return an untranslated error message or NULL.
|
||||
char *check_stl_option(char *s)
|
||||
@ -3898,55 +3518,6 @@ char *check_stl_option(char *s)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *did_set_spell_option(bool is_spellfile)
|
||||
{
|
||||
char *errmsg = NULL;
|
||||
|
||||
if (is_spellfile) {
|
||||
int l = (int)STRLEN(curwin->w_s->b_p_spf);
|
||||
if (l > 0
|
||||
&& (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
|
||||
errmsg = e_invarg;
|
||||
}
|
||||
}
|
||||
|
||||
if (errmsg == NULL) {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_buffer == curbuf && wp->w_p_spell) {
|
||||
errmsg = did_set_spelllang(wp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/// Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
|
||||
/// Return error message when failed, NULL when OK.
|
||||
static char *compile_cap_prog(synblock_T *synblock)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
regprog_T *rp = synblock->b_cap_prog;
|
||||
char_u *re;
|
||||
|
||||
if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) {
|
||||
synblock->b_cap_prog = NULL;
|
||||
} else {
|
||||
// Prepend a ^ so that we only match at one column
|
||||
re = concat_str((char_u *)"^", synblock->b_p_spc);
|
||||
synblock->b_cap_prog = vim_regcomp((char *)re, RE_MAGIC);
|
||||
xfree(re);
|
||||
if (synblock->b_cap_prog == NULL) {
|
||||
synblock->b_cap_prog = rp; // restore the previous program
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
|
||||
vim_regfree(rp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Handle setting `winhighlight' in window "wp"
|
||||
bool parse_winhl_opt(win_T *wp)
|
||||
{
|
||||
@ -5767,47 +5338,6 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Compute columns for ruler and shown command. 'sc_col' is also used to
|
||||
/// decide what the maximum length of a message on the status line can be.
|
||||
/// If there is a status line for the last window, 'sc_col' is independent
|
||||
/// of 'ru_col'.
|
||||
|
||||
#define COL_RULER 17 // columns needed by standard ruler
|
||||
|
||||
void comp_col(void)
|
||||
{
|
||||
int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
|
||||
|
||||
sc_col = 0;
|
||||
ru_col = 0;
|
||||
if (p_ru) {
|
||||
ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
|
||||
// no last status line, adjust sc_col
|
||||
if (!last_has_status) {
|
||||
sc_col = ru_col;
|
||||
}
|
||||
}
|
||||
if (p_sc) {
|
||||
sc_col += SHOWCMD_COLS;
|
||||
if (!p_ru || last_has_status) { // no need for separating space
|
||||
sc_col++;
|
||||
}
|
||||
}
|
||||
assert(sc_col >= 0
|
||||
&& INT_MIN + sc_col <= Columns);
|
||||
sc_col = Columns - sc_col;
|
||||
assert(ru_col >= 0
|
||||
&& INT_MIN + ru_col <= Columns);
|
||||
ru_col = Columns - ru_col;
|
||||
if (sc_col <= 0) { // screen too narrow, will become a mess
|
||||
sc_col = 1;
|
||||
}
|
||||
if (ru_col <= 0) {
|
||||
ru_col = 1;
|
||||
}
|
||||
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
||||
}
|
||||
|
||||
// Unset local option value, similar to ":set opt<".
|
||||
void unset_global_local_option(char *name, void *from)
|
||||
{
|
||||
@ -7562,313 +7092,6 @@ int check_ff_value(char_u *p)
|
||||
return check_opt_strings(p, p_ff_values, false);
|
||||
}
|
||||
|
||||
// Set the integer values corresponding to the string setting of 'vartabstop'.
|
||||
// "array" will be set, caller must free it if needed.
|
||||
// Return false for an error.
|
||||
bool tabstop_set(char_u *var, long **array)
|
||||
{
|
||||
long valcount = 1;
|
||||
int t;
|
||||
char_u *cp;
|
||||
|
||||
if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) {
|
||||
*array = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (cp = var; *cp != NUL; cp++) {
|
||||
if (cp == var || cp[-1] == ',') {
|
||||
char *end;
|
||||
|
||||
if (strtol((char *)cp, &end, 10) <= 0) {
|
||||
if (cp != (char_u *)end) {
|
||||
emsg(_(e_positive));
|
||||
} else {
|
||||
semsg(_(e_invarg2), cp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ascii_isdigit(*cp)) {
|
||||
continue;
|
||||
}
|
||||
if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) {
|
||||
valcount++;
|
||||
continue;
|
||||
}
|
||||
semsg(_(e_invarg2), var);
|
||||
return false;
|
||||
}
|
||||
|
||||
*array = (long *)xmalloc((unsigned)(valcount + 1) * sizeof(long));
|
||||
(*array)[0] = valcount;
|
||||
|
||||
t = 1;
|
||||
for (cp = var; *cp != NUL;) {
|
||||
int n = atoi((char *)cp);
|
||||
|
||||
// Catch negative values, overflow and ridiculous big values.
|
||||
if (n <= 0 || n > TABSTOP_MAX) {
|
||||
semsg(_(e_invarg2), cp);
|
||||
XFREE_CLEAR(*array);
|
||||
return false;
|
||||
}
|
||||
(*array)[t++] = n;
|
||||
while (*cp != NUL && *cp != ',') {
|
||||
cp++;
|
||||
}
|
||||
if (*cp != NUL) {
|
||||
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, long ts_arg, long *vts)
|
||||
{
|
||||
long ts = ts_arg == 0 ? 8 : ts_arg;
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
long padding = 0;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)(ts - (col % ts));
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
padding = tabcol - col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]);
|
||||
}
|
||||
|
||||
return (int)padding;
|
||||
}
|
||||
|
||||
// Find the size of the tab that covers a particular column.
|
||||
int tabstop_at(colnr_T col, long ts, long *vts)
|
||||
{
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
long tab_size = 0;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)ts;
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
tab_size = vts[t];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
tab_size = vts[tabcount];
|
||||
}
|
||||
|
||||
return (int)tab_size;
|
||||
}
|
||||
|
||||
// Find the column on which a tab starts.
|
||||
colnr_T tabstop_start(colnr_T col, long ts, long *vts)
|
||||
{
|
||||
colnr_T tabcol = 0;
|
||||
int t;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
return (int)((col / ts) * ts);
|
||||
}
|
||||
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > col) {
|
||||
return (int)(tabcol - vts[t]);
|
||||
}
|
||||
}
|
||||
|
||||
const int excess = (int)(tabcol % vts[tabcount]);
|
||||
return (int)(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, long ts_arg, long *vts, int *ntabs,
|
||||
int *nspcs)
|
||||
{
|
||||
int spaces = end_col - start_col;
|
||||
colnr_T tabcol = 0;
|
||||
long padding = 0;
|
||||
int t;
|
||||
long ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
|
||||
|
||||
if (vts == NULL || vts[0] == 0) {
|
||||
int tabs = 0;
|
||||
|
||||
const int initspc = (int)(ts - (start_col % ts));
|
||||
if (spaces >= initspc) {
|
||||
spaces -= initspc;
|
||||
tabs++;
|
||||
}
|
||||
tabs += (int)(spaces / ts);
|
||||
spaces -= (int)((spaces / ts) * ts);
|
||||
|
||||
*ntabs = tabs;
|
||||
*nspcs = spaces;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the padding needed to reach the next tabstop.
|
||||
const long tabcount = vts[0];
|
||||
for (t = 1; t <= tabcount; t++) {
|
||||
tabcol += (colnr_T)vts[t];
|
||||
if (tabcol > start_col) {
|
||||
padding = tabcol - start_col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t > tabcount) {
|
||||
padding = vts[tabcount] - ((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 -= (int)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 += 1;
|
||||
spaces -= (int)padding;
|
||||
}
|
||||
|
||||
*ntabs += spaces / (int)vts[tabcount];
|
||||
*nspcs = spaces % (int)vts[tabcount];
|
||||
}
|
||||
|
||||
// See if two tabstop arrays contain the same values.
|
||||
bool tabstop_eq(long *ts1, long *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(long *oldts)
|
||||
{
|
||||
long *newts;
|
||||
int t;
|
||||
|
||||
if (oldts == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
newts = xmalloc((unsigned)(oldts[0] + 1) * sizeof(long));
|
||||
for (t = 0; t <= oldts[0]; t++) {
|
||||
newts[t] = oldts[t];
|
||||
}
|
||||
|
||||
return (int *)newts;
|
||||
}
|
||||
|
||||
// Return a count of the number of tabstops.
|
||||
int tabstop_count(long *ts)
|
||||
{
|
||||
return ts != NULL ? (int)ts[0] : 0;
|
||||
}
|
||||
|
||||
// Return the first tabstop, or 8 if there are no tabstops defined.
|
||||
int tabstop_first(long *ts)
|
||||
{
|
||||
return ts != NULL ? (int)ts[1] : 8;
|
||||
}
|
||||
|
||||
/// Return the effective shiftwidth value for current buffer, using the
|
||||
/// 'tabstop' value when 'shiftwidth' is zero.
|
||||
int get_sw_value(buf_T *buf)
|
||||
{
|
||||
long result = get_sw_value_col(buf, 0);
|
||||
assert(result >= 0 && result <= INT_MAX);
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
// Idem, using the first non-black in the current line.
|
||||
long get_sw_value_indent(buf_T *buf)
|
||||
{
|
||||
pos_T pos = curwin->w_cursor;
|
||||
|
||||
pos.col = (colnr_T)getwhitecols_curline();
|
||||
return get_sw_value_pos(buf, &pos);
|
||||
}
|
||||
|
||||
// Idem, using "pos".
|
||||
long get_sw_value_pos(buf_T *buf, pos_T *pos)
|
||||
{
|
||||
pos_T save_cursor = curwin->w_cursor;
|
||||
long sw_value;
|
||||
|
||||
curwin->w_cursor = *pos;
|
||||
sw_value = get_sw_value_col(buf, get_nolist_virtcol());
|
||||
curwin->w_cursor = save_cursor;
|
||||
return sw_value;
|
||||
}
|
||||
|
||||
// Idem, using virtual column "col".
|
||||
long get_sw_value_col(buf_T *buf, colnr_T col)
|
||||
{
|
||||
return buf->b_p_sw ? buf->b_p_sw
|
||||
: tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
|
||||
}
|
||||
|
||||
/// Return the effective softtabstop value for the current buffer,
|
||||
/// using the shiftwidth value when 'softtabstop' is negative.
|
||||
int get_sts_value(void)
|
||||
{
|
||||
long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
|
||||
assert(result >= 0 && result <= INT_MAX);
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
/// This is called when 'breakindentopt' is changed and when a window is
|
||||
/// initialized
|
||||
static bool briopt_check(win_T *wp)
|
||||
|
@ -5781,7 +5781,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
|
||||
/// If qf_idx is -1, use the current list. Otherwise, use the specified list.
|
||||
/// If eidx is not 0, then return only the specified entry. Otherwise return
|
||||
/// all the entries.
|
||||
int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx, list_T *list)
|
||||
static int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx, list_T *list)
|
||||
{
|
||||
qf_info_T *qi = qi_arg;
|
||||
|
||||
@ -6151,7 +6151,7 @@ static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
|
||||
/// Return quickfix/location list details (title) as a dictionary.
|
||||
/// 'what' contains the details to return. If 'list_idx' is -1,
|
||||
/// then current list is used. Otherwise the specified list is used.
|
||||
int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
||||
static int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
||||
{
|
||||
qf_info_T *qi = &ql_info;
|
||||
dictitem_T *di = NULL;
|
||||
@ -7159,3 +7159,137 @@ void ex_helpgrep(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
|
||||
{
|
||||
if (what_arg->v_type == VAR_UNKNOWN) {
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
if (is_qf || wp != NULL) {
|
||||
(void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
|
||||
}
|
||||
} else {
|
||||
tv_dict_alloc_ret(rettv);
|
||||
if (is_qf || wp != NULL) {
|
||||
if (what_arg->v_type == VAR_DICT) {
|
||||
dict_T *d = what_arg->vval.v_dict;
|
||||
|
||||
if (d != NULL) {
|
||||
qf_get_properties(wp, d, rettv->vval.v_dict);
|
||||
}
|
||||
} else {
|
||||
emsg(_(e_dictreq));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "getloclist()" function
|
||||
void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
get_qf_loc_list(false, wp, &argvars[1], rettv);
|
||||
}
|
||||
|
||||
/// "getqflist()" functions
|
||||
void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
get_qf_loc_list(true, NULL, &argvars[0], rettv);
|
||||
}
|
||||
|
||||
/// Create quickfix/location list from VimL values
|
||||
///
|
||||
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
|
||||
/// args argument in which case errors out, including VAR_UNKNOWN parameters.
|
||||
///
|
||||
/// @param[in,out] wp Window to create location list for. May be NULL in
|
||||
/// which case quickfix list will be created.
|
||||
/// @param[in] args [list, action, what]
|
||||
/// @param[in] args[0] Quickfix list contents.
|
||||
/// @param[in] args[1] Optional. Action to perform:
|
||||
/// append to an existing list, replace its content,
|
||||
/// or create a new one.
|
||||
/// @param[in] args[2] Optional. Quickfix list properties or title.
|
||||
/// Defaults to caller function name.
|
||||
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
|
||||
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(2, 3)
|
||||
{
|
||||
static char *e_invact = N_("E927: Invalid action: '%s'");
|
||||
const char *title = NULL;
|
||||
char action = ' ';
|
||||
static int recursive = 0;
|
||||
rettv->vval.v_number = -1;
|
||||
dict_T *what = NULL;
|
||||
|
||||
typval_T *list_arg = &args[0];
|
||||
if (list_arg->v_type != VAR_LIST) {
|
||||
emsg(_(e_listreq));
|
||||
return;
|
||||
} else if (recursive != 0) {
|
||||
emsg(_(e_au_recursive));
|
||||
return;
|
||||
}
|
||||
|
||||
typval_T *action_arg = &args[1];
|
||||
if (action_arg->v_type == VAR_UNKNOWN) {
|
||||
// Option argument was not given.
|
||||
goto skip_args;
|
||||
} else if (action_arg->v_type != VAR_STRING) {
|
||||
emsg(_(e_stringreq));
|
||||
return;
|
||||
}
|
||||
const char *const act = tv_get_string_chk(action_arg);
|
||||
if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f')
|
||||
&& act[1] == NUL) {
|
||||
action = *act;
|
||||
} else {
|
||||
semsg(_(e_invact), act);
|
||||
return;
|
||||
}
|
||||
|
||||
typval_T *const what_arg = &args[2];
|
||||
if (what_arg->v_type == VAR_UNKNOWN) {
|
||||
// Option argument was not given.
|
||||
goto skip_args;
|
||||
} else if (what_arg->v_type == VAR_STRING) {
|
||||
title = tv_get_string_chk(what_arg);
|
||||
if (!title) {
|
||||
// Type error. Error already printed by tv_get_string_chk().
|
||||
return;
|
||||
}
|
||||
} else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) {
|
||||
what = what_arg->vval.v_dict;
|
||||
} else {
|
||||
emsg(_(e_dictreq));
|
||||
return;
|
||||
}
|
||||
|
||||
skip_args:
|
||||
if (!title) {
|
||||
title = (wp ? ":setloclist()" : ":setqflist()");
|
||||
}
|
||||
|
||||
recursive++;
|
||||
list_T *const l = list_arg->vval.v_list;
|
||||
if (set_errorlist(wp, l, action, (char *)title, what) == OK) {
|
||||
rettv->vval.v_number = 0;
|
||||
}
|
||||
recursive--;
|
||||
}
|
||||
|
||||
/// "setloclist()" function
|
||||
void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
rettv->vval.v_number = -1;
|
||||
|
||||
win_T *win = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (win != NULL) {
|
||||
set_qf_ll_list(win, &argvars[1], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// "setqflist()" function
|
||||
void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
set_qf_ll_list(NULL, argvars, rettv);
|
||||
}
|
||||
|
@ -42,6 +42,9 @@
|
||||
# include "screen.c.generated.h"
|
||||
#endif
|
||||
|
||||
static char e_conflicts_with_value_of_listchars[] = N_("E834: Conflicts with value of 'listchars'");
|
||||
static char e_conflicts_with_value_of_fillchars[] = N_("E835: Conflicts with value of 'fillchars'");
|
||||
|
||||
/// Return true if the cursor line in window "wp" may be concealed, according
|
||||
/// to the 'concealcursor' option.
|
||||
bool conceal_cursor_line(const win_T *wp)
|
||||
@ -1599,6 +1602,46 @@ void win_redr_ruler(win_T *wp, bool always)
|
||||
}
|
||||
}
|
||||
|
||||
#define COL_RULER 17 // columns needed by standard ruler
|
||||
|
||||
/// Compute columns for ruler and shown command. 'sc_col' is also used to
|
||||
/// decide what the maximum length of a message on the status line can be.
|
||||
/// If there is a status line for the last window, 'sc_col' is independent
|
||||
/// of 'ru_col'.
|
||||
void comp_col(void)
|
||||
{
|
||||
int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
|
||||
|
||||
sc_col = 0;
|
||||
ru_col = 0;
|
||||
if (p_ru) {
|
||||
ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
|
||||
// no last status line, adjust sc_col
|
||||
if (!last_has_status) {
|
||||
sc_col = ru_col;
|
||||
}
|
||||
}
|
||||
if (p_sc) {
|
||||
sc_col += SHOWCMD_COLS;
|
||||
if (!p_ru || last_has_status) { // no need for separating space
|
||||
sc_col++;
|
||||
}
|
||||
}
|
||||
assert(sc_col >= 0
|
||||
&& INT_MIN + sc_col <= Columns);
|
||||
sc_col = Columns - sc_col;
|
||||
assert(ru_col >= 0
|
||||
&& INT_MIN + ru_col <= Columns);
|
||||
ru_col = Columns - ru_col;
|
||||
if (sc_col <= 0) { // screen too narrow, will become a mess
|
||||
sc_col = 1;
|
||||
}
|
||||
if (ru_col <= 0) {
|
||||
ru_col = 1;
|
||||
}
|
||||
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
||||
}
|
||||
|
||||
/// Return the width of the 'number' and 'relativenumber' column.
|
||||
/// Caller may need to check if 'number' or 'relativenumber' is set.
|
||||
/// Otherwise it depends on 'numberwidth' and the line count.
|
||||
@ -1642,6 +1685,284 @@ int number_width(win_T *wp)
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Calls mb_cptr2char_adv(p) and returns the character.
|
||||
/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
|
||||
/// Returns 0 for invalid hex or invalid UTF-8 byte.
|
||||
static int get_encoded_char_adv(char_u **p)
|
||||
{
|
||||
char_u *s = *p;
|
||||
|
||||
if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
|
||||
int64_t num = 0;
|
||||
int bytes;
|
||||
int n;
|
||||
for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
|
||||
*p += 2;
|
||||
n = hexhex2nr(*p);
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
num = num * 256 + n;
|
||||
}
|
||||
*p += 2;
|
||||
return (int)num;
|
||||
}
|
||||
|
||||
// TODO(bfredl): use schar_T representation and utfc_ptr2len
|
||||
int clen = utf_ptr2len((char *)s);
|
||||
int c = mb_cptr2char_adv((const char_u **)p);
|
||||
if (clen == 1 && c > 127) { // Invalid UTF-8 byte
|
||||
return 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/// Handle setting 'listchars' or 'fillchars'.
|
||||
/// Assume monocell characters
|
||||
///
|
||||
/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs
|
||||
/// @return error message, NULL if it's OK.
|
||||
char *set_chars_option(win_T *wp, char_u **varp, bool set)
|
||||
{
|
||||
int round, i, len, len2, entries;
|
||||
char_u *p, *s;
|
||||
int c1;
|
||||
int c2 = 0;
|
||||
int c3 = 0;
|
||||
char_u *last_multispace = NULL; // Last occurrence of "multispace:"
|
||||
char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
|
||||
int multispace_len = 0; // Length of lcs-multispace string
|
||||
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
|
||||
|
||||
struct chars_tab {
|
||||
int *cp; ///< char value
|
||||
char *name; ///< char id
|
||||
int def; ///< default value
|
||||
};
|
||||
struct chars_tab *tab;
|
||||
|
||||
// XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
|
||||
struct chars_tab fcs_tab[] = {
|
||||
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
|
||||
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
|
||||
{ &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
|
||||
{ &wp->w_p_fcs_chars.horiz, "horiz", char2cells(0x2500) == 1 ? 0x2500 : '-' }, // ─
|
||||
{ &wp->w_p_fcs_chars.horizup, "horizup", char2cells(0x2534) == 1 ? 0x2534 : '-' }, // ┴
|
||||
{ &wp->w_p_fcs_chars.horizdown, "horizdown", char2cells(0x252c) == 1 ? 0x252c : '-' }, // ┬
|
||||
{ &wp->w_p_fcs_chars.vert, "vert", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
|
||||
{ &wp->w_p_fcs_chars.vertleft, "vertleft", char2cells(0x2524) == 1 ? 0x2524 : '|' }, // ┤
|
||||
{ &wp->w_p_fcs_chars.vertright, "vertright", char2cells(0x251c) == 1 ? 0x251c : '|' }, // ├
|
||||
{ &wp->w_p_fcs_chars.verthoriz, "verthoriz", char2cells(0x253c) == 1 ? 0x253c : '+' }, // ┼
|
||||
{ &wp->w_p_fcs_chars.fold, "fold", char2cells(0x00b7) == 1 ? 0x00b7 : '-' }, // ·
|
||||
{ &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
|
||||
{ &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
|
||||
{ &wp->w_p_fcs_chars.foldsep, "foldsep", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
|
||||
{ &wp->w_p_fcs_chars.diff, "diff", '-' },
|
||||
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
|
||||
{ &wp->w_p_fcs_chars.eob, "eob", '~' },
|
||||
};
|
||||
struct chars_tab lcs_tab[] = {
|
||||
{ &wp->w_p_lcs_chars.eol, "eol", NUL },
|
||||
{ &wp->w_p_lcs_chars.ext, "extends", NUL },
|
||||
{ &wp->w_p_lcs_chars.nbsp, "nbsp", NUL },
|
||||
{ &wp->w_p_lcs_chars.prec, "precedes", NUL },
|
||||
{ &wp->w_p_lcs_chars.space, "space", NUL },
|
||||
{ &wp->w_p_lcs_chars.tab2, "tab", NUL },
|
||||
{ &wp->w_p_lcs_chars.lead, "lead", NUL },
|
||||
{ &wp->w_p_lcs_chars.trail, "trail", NUL },
|
||||
{ &wp->w_p_lcs_chars.conceal, "conceal", NUL },
|
||||
};
|
||||
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
tab = lcs_tab;
|
||||
entries = ARRAY_SIZE(lcs_tab);
|
||||
if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
|
||||
varp = &p_lcs;
|
||||
}
|
||||
} else {
|
||||
tab = fcs_tab;
|
||||
entries = ARRAY_SIZE(fcs_tab);
|
||||
if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
|
||||
varp = &p_fcs;
|
||||
}
|
||||
}
|
||||
|
||||
// first round: check for valid value, second round: assign values
|
||||
for (round = 0; round <= (set ? 1 : 0); round++) {
|
||||
if (round > 0) {
|
||||
// After checking that the value is valid: set defaults
|
||||
for (i = 0; i < entries; i++) {
|
||||
if (tab[i].cp != NULL) {
|
||||
*(tab[i].cp) = tab[i].def;
|
||||
}
|
||||
}
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
wp->w_p_lcs_chars.tab1 = NUL;
|
||||
wp->w_p_lcs_chars.tab3 = NUL;
|
||||
|
||||
xfree(wp->w_p_lcs_chars.multispace);
|
||||
if (multispace_len > 0) {
|
||||
wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
|
||||
wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
|
||||
} else {
|
||||
wp->w_p_lcs_chars.multispace = NULL;
|
||||
}
|
||||
|
||||
xfree(wp->w_p_lcs_chars.leadmultispace);
|
||||
if (lead_multispace_len > 0) {
|
||||
wp->w_p_lcs_chars.leadmultispace
|
||||
= xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
|
||||
wp->w_p_lcs_chars.leadmultispace[lead_multispace_len] = NUL;
|
||||
} else {
|
||||
wp->w_p_lcs_chars.leadmultispace = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = *varp;
|
||||
while (*p) {
|
||||
for (i = 0; i < entries; i++) {
|
||||
len = (int)STRLEN(tab[i].name);
|
||||
if (STRNCMP(p, tab[i].name, len) == 0
|
||||
&& p[len] == ':'
|
||||
&& p[len + 1] != NUL) {
|
||||
c2 = c3 = 0;
|
||||
s = p + len + 1;
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||
if (*s == NUL) {
|
||||
return e_invarg;
|
||||
}
|
||||
c2 = get_encoded_char_adv(&s);
|
||||
if (c2 == 0 || char2cells(c2) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
if (!(*s == ',' || *s == NUL)) {
|
||||
c3 = get_encoded_char_adv(&s);
|
||||
if (c3 == 0 || char2cells(c3) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*s == ',' || *s == NUL) {
|
||||
if (round > 0) {
|
||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||
wp->w_p_lcs_chars.tab1 = c1;
|
||||
wp->w_p_lcs_chars.tab2 = c2;
|
||||
wp->w_p_lcs_chars.tab3 = c3;
|
||||
} else if (tab[i].cp != NULL) {
|
||||
*(tab[i].cp) = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == entries) {
|
||||
len = (int)STRLEN("multispace");
|
||||
len2 = (int)STRLEN("leadmultispace");
|
||||
if ((varp == &p_lcs || varp == &wp->w_p_lcs)
|
||||
&& STRNCMP(p, "multispace", len) == 0
|
||||
&& p[len] == ':'
|
||||
&& p[len + 1] != NUL) {
|
||||
s = p + len + 1;
|
||||
if (round == 0) {
|
||||
// Get length of lcs-multispace string in the first round
|
||||
last_multispace = p;
|
||||
multispace_len = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
multispace_len++;
|
||||
}
|
||||
if (multispace_len == 0) {
|
||||
// lcs-multispace cannot be an empty string
|
||||
return e_invarg;
|
||||
}
|
||||
p = s;
|
||||
} else {
|
||||
int multispace_pos = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (p == last_multispace) {
|
||||
wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
}
|
||||
} else if ((varp == &p_lcs || varp == &wp->w_p_lcs)
|
||||
&& STRNCMP(p, "leadmultispace", len2) == 0
|
||||
&& p[len2] == ':'
|
||||
&& p[len2 + 1] != NUL) {
|
||||
s = p + len2 + 1;
|
||||
if (round == 0) {
|
||||
// get length of lcs-leadmultispace string in first round
|
||||
last_lmultispace = p;
|
||||
lead_multispace_len = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (c1 == 0 || char2cells(c1) > 1) {
|
||||
return e_invarg;
|
||||
}
|
||||
lead_multispace_len++;
|
||||
}
|
||||
if (lead_multispace_len == 0) {
|
||||
// lcs-leadmultispace cannot be an empty string
|
||||
return e_invarg;
|
||||
}
|
||||
p = s;
|
||||
} else {
|
||||
int multispace_pos = 0;
|
||||
while (*s != NUL && *s != ',') {
|
||||
c1 = get_encoded_char_adv(&s);
|
||||
if (p == last_lmultispace) {
|
||||
wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
}
|
||||
} else {
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
if (*p == ',') {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // no error
|
||||
}
|
||||
|
||||
/// Check all global and local values of 'listchars' and 'fillchars'.
|
||||
/// May set different defaults in case character widths change.
|
||||
///
|
||||
/// @return an untranslated error message if any of them is invalid, NULL otherwise.
|
||||
char *check_chars_options(void)
|
||||
{
|
||||
if (set_chars_option(curwin, &p_lcs, false) != NULL) {
|
||||
return e_conflicts_with_value_of_listchars;
|
||||
}
|
||||
if (set_chars_option(curwin, &p_fcs, false) != NULL) {
|
||||
return e_conflicts_with_value_of_fillchars;
|
||||
}
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
|
||||
return e_conflicts_with_value_of_listchars;
|
||||
}
|
||||
if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
|
||||
return e_conflicts_with_value_of_fillchars;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Check if the new Nvim application "screen" dimensions are valid.
|
||||
/// Correct it if it's too small or way too big.
|
||||
void check_screensize(void)
|
||||
|
@ -3607,3 +3607,71 @@ int expand_spelling(linenr_T lnum, char_u *pat, char ***matchp)
|
||||
*matchp = ga.ga_data;
|
||||
return ga.ga_len;
|
||||
}
|
||||
|
||||
/// Return true if "val" is a valid 'spelllang' value.
|
||||
bool valid_spelllang(const char_u *val)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return valid_name(val, ".-_,@");
|
||||
}
|
||||
|
||||
/// Return true if "val" is a valid 'spellfile' value.
|
||||
bool valid_spellfile(const char_u *val)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
for (const char_u *s = val; *s != NUL; s++) {
|
||||
if (!vim_isfilec(*s) && *s != ',' && *s != ' ') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char *did_set_spell_option(bool is_spellfile)
|
||||
{
|
||||
char *errmsg = NULL;
|
||||
|
||||
if (is_spellfile) {
|
||||
int l = (int)STRLEN(curwin->w_s->b_p_spf);
|
||||
if (l > 0
|
||||
&& (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
|
||||
errmsg = e_invarg;
|
||||
}
|
||||
}
|
||||
|
||||
if (errmsg == NULL) {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_buffer == curbuf && wp->w_p_spell) {
|
||||
errmsg = did_set_spelllang(wp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/// Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
|
||||
/// Return error message when failed, NULL when OK.
|
||||
char *compile_cap_prog(synblock_T *synblock)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
regprog_T *rp = synblock->b_cap_prog;
|
||||
char_u *re;
|
||||
|
||||
if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) {
|
||||
synblock->b_cap_prog = NULL;
|
||||
} else {
|
||||
// Prepend a ^ so that we only match at one column
|
||||
re = concat_str((char_u *)"^", synblock->b_p_spc);
|
||||
synblock->b_cap_prog = vim_regcomp((char *)re, RE_MAGIC);
|
||||
xfree(re);
|
||||
if (synblock->b_cap_prog == NULL) {
|
||||
synblock->b_cap_prog = rp; // restore the previous program
|
||||
return e_invarg;
|
||||
}
|
||||
}
|
||||
|
||||
vim_regfree(rp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -7269,6 +7269,88 @@ static bool frame_check_width(const frame_T *topfrp, int width)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simple int comparison function for use with qsort()
|
||||
static int int_cmp(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
|
||||
///
|
||||
/// @return error message, NULL if it's OK.
|
||||
char *check_colorcolumn(win_T *wp)
|
||||
{
|
||||
char *s;
|
||||
int col;
|
||||
unsigned int count = 0;
|
||||
int color_cols[256];
|
||||
int j = 0;
|
||||
|
||||
if (wp->w_buffer == NULL) {
|
||||
return NULL; // buffer was closed
|
||||
}
|
||||
|
||||
for (s = (char *)wp->w_p_cc; *s != NUL && count < 255;) {
|
||||
if (*s == '-' || *s == '+') {
|
||||
// -N and +N: add to 'textwidth'
|
||||
col = (*s == '-') ? -1 : 1;
|
||||
s++;
|
||||
if (!ascii_isdigit(*s)) {
|
||||
return e_invarg;
|
||||
}
|
||||
col = col * getdigits_int(&s, true, 0);
|
||||
if (wp->w_buffer->b_p_tw == 0) {
|
||||
goto skip; // 'textwidth' not set, skip this item
|
||||
}
|
||||
assert((col >= 0
|
||||
&& wp->w_buffer->b_p_tw <= INT_MAX - col
|
||||
&& wp->w_buffer->b_p_tw + col >= INT_MIN)
|
||||
|| (col < 0
|
||||
&& wp->w_buffer->b_p_tw >= INT_MIN - col
|
||||
&& wp->w_buffer->b_p_tw + col <= INT_MAX));
|
||||
col += (int)wp->w_buffer->b_p_tw;
|
||||
if (col < 0) {
|
||||
goto skip;
|
||||
}
|
||||
} else if (ascii_isdigit(*s)) {
|
||||
col = getdigits_int(&s, true, 0);
|
||||
} else {
|
||||
return e_invarg;
|
||||
}
|
||||
color_cols[count++] = col - 1; // 1-based to 0-based
|
||||
skip:
|
||||
if (*s == NUL) {
|
||||
break;
|
||||
}
|
||||
if (*s != ',') {
|
||||
return e_invarg;
|
||||
}
|
||||
if (*++s == NUL) {
|
||||
return e_invarg; // illegal trailing comma as in "set cc=80,"
|
||||
}
|
||||
}
|
||||
|
||||
xfree(wp->w_p_cc_cols);
|
||||
if (count == 0) {
|
||||
wp->w_p_cc_cols = NULL;
|
||||
} else {
|
||||
wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1));
|
||||
// sort the columns for faster usage on screen redraw inside
|
||||
// win_line()
|
||||
qsort(color_cols, count, sizeof(int), int_cmp);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
// skip duplicates
|
||||
if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) {
|
||||
wp->w_p_cc_cols[j++] = color_cols[i];
|
||||
}
|
||||
}
|
||||
wp->w_p_cc_cols[j] = -1; // end marker
|
||||
}
|
||||
|
||||
return NULL; // no error
|
||||
}
|
||||
|
||||
int win_getid(typval_T *argvars)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
|
30
test/unit/indent_spec.lua
Normal file
30
test/unit/indent_spec.lua
Normal file
@ -0,0 +1,30 @@
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local eq = helpers.eq
|
||||
|
||||
local indent = helpers.cimport("./src/nvim/indent.h")
|
||||
local globals = helpers.cimport("./src/nvim/globals.h")
|
||||
|
||||
describe('get_sts_value', function()
|
||||
itp([[returns 'softtabstop' when it is non-negative]], function()
|
||||
globals.curbuf.b_p_sts = 5
|
||||
eq(5, indent.get_sts_value())
|
||||
|
||||
globals.curbuf.b_p_sts = 0
|
||||
eq(0, indent.get_sts_value())
|
||||
end)
|
||||
|
||||
itp([[returns "effective shiftwidth" when 'softtabstop' is negative]], function()
|
||||
local shiftwidth = 2
|
||||
globals.curbuf.b_p_sw = shiftwidth
|
||||
local tabstop = 5
|
||||
globals.curbuf.b_p_ts = tabstop
|
||||
globals.curbuf.b_p_sts = -2
|
||||
eq(shiftwidth, indent.get_sts_value())
|
||||
|
||||
shiftwidth = 0
|
||||
globals.curbuf.b_p_sw = shiftwidth
|
||||
eq(tabstop, indent.get_sts_value())
|
||||
end)
|
||||
end)
|
@ -5,7 +5,6 @@ local to_cstr = helpers.to_cstr
|
||||
local eq = helpers.eq
|
||||
|
||||
local option = helpers.cimport("./src/nvim/option.h")
|
||||
local globals = helpers.cimport("./src/nvim/globals.h")
|
||||
|
||||
local check_ff_value = function(ff)
|
||||
return option.check_ff_value(to_cstr(ff))
|
||||
@ -27,26 +26,3 @@ describe('check_ff_value', function()
|
||||
eq(0, check_ff_value("foo"))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_sts_value', function()
|
||||
itp([[returns 'softtabstop' when it is non-negative]], function()
|
||||
globals.curbuf.b_p_sts = 5
|
||||
eq(5, option.get_sts_value())
|
||||
|
||||
globals.curbuf.b_p_sts = 0
|
||||
eq(0, option.get_sts_value())
|
||||
end)
|
||||
|
||||
itp([[returns "effective shiftwidth" when 'softtabstop' is negative]], function()
|
||||
local shiftwidth = 2
|
||||
globals.curbuf.b_p_sw = shiftwidth
|
||||
local tabstop = 5
|
||||
globals.curbuf.b_p_ts = tabstop
|
||||
globals.curbuf.b_p_sts = -2
|
||||
eq(shiftwidth, option.get_sts_value())
|
||||
|
||||
shiftwidth = 0
|
||||
globals.curbuf.b_p_sw = shiftwidth
|
||||
eq(tabstop, option.get_sts_value())
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user