aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval.c23
-rw-r--r--src/nvim/eval/funcs.c111
-rw-r--r--src/nvim/hardcopy.c1
-rw-r--r--src/nvim/indent.c308
-rw-r--r--src/nvim/mbyte.c2
-rw-r--r--src/nvim/message.c1
-rw-r--r--src/nvim/option.c783
-rw-r--r--src/nvim/quickfix.c138
-rw-r--r--src/nvim/screen.c321
-rw-r--r--src/nvim/spell.c68
-rw-r--r--src/nvim/window.c82
-rw-r--r--test/unit/indent_spec.lua30
-rw-r--r--test/unit/option_spec.lua24
13 files changed, 951 insertions, 941 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 4014f2dd22..21068e9101 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -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)
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8eaa9c1f72..456fd9fdf6 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -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
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index d811a78ca8..6a1bbcb089 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -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"
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 684c00b7e7..f18a6d7b32 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -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)
{
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 2b2baeacbc..af9e214d92 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -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"
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 95460e1aaf..6cc68edb82 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -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"
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 49c8bd3cd4..09793cbdcf 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -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)
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 504fb2464e..1c416a872b 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -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);
+}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 59ef3a76b1..2419a42a2a 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -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)
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index c8da6af9c9..1e44d328b3 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -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;
+}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 496bc13a37..564b5c4c51 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -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) {
diff --git a/test/unit/indent_spec.lua b/test/unit/indent_spec.lua
new file mode 100644
index 0000000000..ec86822b55
--- /dev/null
+++ b/test/unit/indent_spec.lua
@@ -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)
diff --git a/test/unit/option_spec.lua b/test/unit/option_spec.lua
index b8b8a435bc..b3c3718035 100644
--- a/test/unit/option_spec.lua
+++ b/test/unit/option_spec.lua
@@ -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)