changeset 17940:079e10a49ea1 v8.1.1966

patch 8.1.1966: some code in options.c fits better elsewhere Commit: https://github.com/vim/vim/commit/e677df8d93772a705f40a94f3c871aee78fe4d99 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Sep 2 22:31:11 2019 +0200 patch 8.1.1966: some code in options.c fits better elsewhere Problem: Some code in options.c fits better elsewhere. Solution: Move functions from options.c to other files. (Yegappan Lakshmanan, closes #4889)
author Bram Moolenaar <Bram@vim.org>
date Mon, 02 Sep 2019 22:45:05 +0200
parents 252ad11554ff
children d64d967b1e35
files src/evalfunc.c src/globals.h src/indent.c src/map.c src/option.c src/proto/map.pro src/proto/option.pro src/proto/quickfix.pro src/proto/screen.pro src/proto/spell.pro src/proto/window.pro src/quickfix.c src/screen.c src/spell.c src/version.c src/window.c
diffstat 16 files changed, 1066 insertions(+), 1071 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -25,7 +25,6 @@
 #endif
 
 static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
-static char *e_stringreq = N_("E928: String required");
 
 #ifdef FEAT_FLOAT
 static void f_abs(typval_T *argvars, typval_T *rettv);
@@ -141,11 +140,9 @@ static void f_getftime(typval_T *argvars
 static void f_getftype(typval_T *argvars, typval_T *rettv);
 static void f_getjumplist(typval_T *argvars, typval_T *rettv);
 static void f_getline(typval_T *argvars, typval_T *rettv);
-static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
 static void f_getpid(typval_T *argvars, typval_T *rettv);
 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
 static void f_getpos(typval_T *argvars, typval_T *rettv);
-static void f_getqflist(typval_T *argvars, typval_T *rettv);
 static void f_getreg(typval_T *argvars, typval_T *rettv);
 static void f_getregtype(typval_T *argvars, typval_T *rettv);
 static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
@@ -279,9 +276,7 @@ static void f_setcmdpos(typval_T *argvar
 static void f_setenv(typval_T *argvars, typval_T *rettv);
 static void f_setfperm(typval_T *argvars, typval_T *rettv);
 static void f_setline(typval_T *argvars, typval_T *rettv);
-static void f_setloclist(typval_T *argvars, typval_T *rettv);
 static void f_setpos(typval_T *argvars, typval_T *rettv);
-static void f_setqflist(typval_T *argvars, typval_T *rettv);
 static void f_setreg(typval_T *argvars, typval_T *rettv);
 static void f_settagstack(typval_T *argvars, typval_T *rettv);
 #ifdef FEAT_CRYPT
@@ -4771,49 +4766,6 @@ f_getline(typval_T *argvars, typval_T *r
     get_buffer_lines(curbuf, lnum, end, retlist, rettv);
 }
 
-#ifdef FEAT_QUICKFIX
-    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)
-    {
-	if (rettv_list_alloc(rettv) == OK)
-	    if (is_qf || wp != NULL)
-		(void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
-    }
-    else
-    {
-	if (rettv_dict_alloc(rettv) == OK)
-	    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));
-	    }
-    }
-}
-#endif
-
-/*
- * "getloclist()" function
- */
-    static void
-f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
-{
-#ifdef FEAT_QUICKFIX
-    win_T	*wp;
-
-    wp = find_win_by_nr_or_id(&argvars[0]);
-    get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
-#endif
-}
-
 /*
  * "getpid()" function
  */
@@ -4895,17 +4847,6 @@ f_getpos(typval_T *argvars, typval_T *re
 }
 
 /*
- * "getqflist()" function
- */
-    static void
-f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
-{
-#ifdef FEAT_QUICKFIX
-    get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
-#endif
-}
-
-/*
  * "getreg()" function
  */
     static void
@@ -9626,90 +9567,6 @@ f_setline(typval_T *argvars, typval_T *r
 }
 
 /*
- * Used by "setqflist()" and "setloclist()" functions
- */
-    static void
-set_qf_ll_list(
-    win_T	*wp UNUSED,
-    typval_T	*list_arg UNUSED,
-    typval_T	*action_arg UNUSED,
-    typval_T	*what_arg UNUSED,
-    typval_T	*rettv)
-{
-#ifdef FEAT_QUICKFIX
-    static char *e_invact = N_("E927: Invalid action: '%s'");
-    char_u	*act;
-    int		action = 0;
-    static int	recursive = 0;
-#endif
-
-    rettv->vval.v_number = -1;
-
-#ifdef FEAT_QUICKFIX
-    if (list_arg->v_type != VAR_LIST)
-	emsg(_(e_listreq));
-    else if (recursive != 0)
-	emsg(_(e_au_recursive));
-    else
-    {
-	list_T  *l = list_arg->vval.v_list;
-	dict_T	*d = NULL;
-	int	valid_dict = TRUE;
-
-	if (action_arg->v_type == VAR_STRING)
-	{
-	    act = tv_get_string_chk(action_arg);
-	    if (act == NULL)
-		return;		/* type error; errmsg already given */
-	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
-		    act[1] == NUL)
-		action = *act;
-	    else
-		semsg(_(e_invact), act);
-	}
-	else if (action_arg->v_type == VAR_UNKNOWN)
-	    action = ' ';
-	else
-	    emsg(_(e_stringreq));
-
-	if (action_arg->v_type != VAR_UNKNOWN
-		&& what_arg->v_type != VAR_UNKNOWN)
-	{
-	    if (what_arg->v_type == VAR_DICT)
-		d = what_arg->vval.v_dict;
-	    else
-	    {
-		emsg(_(e_dictreq));
-		valid_dict = FALSE;
-	    }
-	}
-
-	++recursive;
-	if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
-		     (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
-		     d) == OK)
-	    rettv->vval.v_number = 0;
-	--recursive;
-    }
-#endif
-}
-
-/*
- * "setloclist()" function
- */
-    static void
-f_setloclist(typval_T *argvars, typval_T *rettv)
-{
-    win_T	*win;
-
-    rettv->vval.v_number = -1;
-
-    win = find_win_by_nr_or_id(&argvars[0]);
-    if (win != NULL)
-	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
-}
-
-/*
  * "setpos()" function
  */
     static void
@@ -9753,15 +9610,6 @@ f_setpos(typval_T *argvars, typval_T *re
 }
 
 /*
- * "setqflist()" function
- */
-    static void
-f_setqflist(typval_T *argvars, typval_T *rettv)
-{
-    set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
-}
-
-/*
  * "setreg()" function
  */
     static void
--- a/src/globals.h
+++ b/src/globals.h
@@ -1550,6 +1550,7 @@ EXTERN char e_illvar[]		INIT(= N_("E461:
 EXTERN char e_cannot_mod[]	INIT(= N_("E995: Cannot modify existing variable"));
 EXTERN char e_readonlyvar[]	INIT(= N_("E46: Cannot change read-only variable \"%s\""));
 EXTERN char e_readonlysbx[]	INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
+EXTERN char e_stringreq[]	INIT(= N_("E928: String required"));
 EXTERN char e_emptykey[]	INIT(= N_("E713: Cannot use empty key for Dictionary"));
 EXTERN char e_dictreq[]	INIT(= N_("E715: Dictionary required"));
 EXTERN char e_listidx[]	INIT(= N_("E684: list index out of range: %ld"));
--- a/src/indent.c
+++ b/src/indent.c
@@ -4457,3 +4457,361 @@ fix_indent(void)
 }
 
 #endif
+
+#if defined(FEAT_VARTABS) || defined(PROTO)
+
+/*
+ * Set the integer values corresponding to the string setting of 'vartabstop'.
+ * "array" will be set, caller must free it if needed.
+ */
+    int
+tabstop_set(char_u *var, int **array)
+{
+    int 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_u *end;
+
+	    if (strtol((char *)cp, (char **)&end, 10) <= 0)
+	    {
+		if (cp != end)
+		    emsg(_(e_positive));
+		else
+		    emsg(_(e_invarg));
+		return FALSE;
+	    }
+	}
+
+	if (VIM_ISDIGIT(*cp))
+	    continue;
+	if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL)
+	{
+	    ++valcount;
+	    continue;
+	}
+	emsg(_(e_invarg));
+	return FALSE;
+    }
+
+    *array = ALLOC_MULT(int, valcount + 1);
+    if (*array == NULL)
+	return FALSE;
+    (*array)[0] = valcount;
+
+    t = 1;
+    for (cp = var; *cp != NUL;)
+    {
+	(*array)[t++] = atoi((char *)cp);
+	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, int ts_arg, int *vts)
+{
+    int		ts = ts_arg == 0 ? 8 : ts_arg;
+    int		tabcount;
+    colnr_T	tabcol = 0;
+    int		t;
+    int		padding = 0;
+
+    if (vts == NULL || vts[0] == 0)
+	return ts - (col % ts);
+
+    tabcount = vts[0];
+
+    for (t = 1; t <= tabcount; ++t)
+    {
+	tabcol += vts[t];
+	if (tabcol > col)
+	{
+	    padding = (int)(tabcol - col);
+	    break;
+	}
+    }
+    if (t > tabcount)
+	padding = vts[tabcount] - (int)((col - tabcol) % vts[tabcount]);
+
+    return padding;
+}
+
+/*
+ * Find the size of the tab that covers a particular column.
+ */
+    int
+tabstop_at(colnr_T col, int ts, int *vts)
+{
+    int		tabcount;
+    colnr_T	tabcol = 0;
+    int		t;
+    int		tab_size = 0;
+
+    if (vts == 0 || vts[0] == 0)
+	return ts;
+
+    tabcount = vts[0];
+    for (t = 1; t <= tabcount; ++t)
+    {
+	tabcol += vts[t];
+	if (tabcol > col)
+	{
+	    tab_size = vts[t];
+	    break;
+	}
+    }
+    if (t > tabcount)
+	tab_size = vts[tabcount];
+
+    return tab_size;
+}
+
+/*
+ * Find the column on which a tab starts.
+ */
+    colnr_T
+tabstop_start(colnr_T col, int ts, int *vts)
+{
+    int		tabcount;
+    colnr_T	tabcol = 0;
+    int		t;
+    int         excess;
+
+    if (vts == NULL || vts[0] == 0)
+	return (col / ts) * ts;
+
+    tabcount = vts[0];
+    for (t = 1; t <= tabcount; ++t)
+    {
+	tabcol += vts[t];
+	if (tabcol > col)
+	    return tabcol - vts[t];
+    }
+
+    excess = tabcol % vts[tabcount];
+    return excess + ((col - excess) / vts[tabcount]) * vts[tabcount];
+}
+
+/*
+ * Find the number of tabs and spaces necessary to get from one column
+ * to another.
+ */
+    void
+tabstop_fromto(
+	colnr_T start_col,
+	colnr_T end_col,
+	int	ts_arg,
+	int	*vts,
+	int	*ntabs,
+	int	*nspcs)
+{
+    int		spaces = end_col - start_col;
+    colnr_T	tabcol = 0;
+    int		padding = 0;
+    int		tabcount;
+    int		t;
+    int		ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
+
+    if (vts == NULL || vts[0] == 0)
+    {
+	int tabs = 0;
+	int initspc = 0;
+
+	initspc = ts - (start_col % ts);
+	if (spaces >= initspc)
+	{
+	    spaces -= initspc;
+	    tabs++;
+	}
+	tabs += spaces / ts;
+	spaces -= (spaces / ts) * ts;
+
+	*ntabs = tabs;
+	*nspcs = spaces;
+	return;
+    }
+
+    // Find the padding needed to reach the next tabstop.
+    tabcount = vts[0];
+    for (t = 1; t <= tabcount; ++t)
+    {
+	tabcol += vts[t];
+	if (tabcol > start_col)
+	{
+	    padding = (int)(tabcol - start_col);
+	    break;
+	}
+    }
+    if (t > tabcount)
+	padding = vts[tabcount] - (int)((start_col - tabcol) % vts[tabcount]);
+
+    // If the space needed is less than the padding no tabs can be used.
+    if (spaces < padding)
+    {
+	*ntabs = 0;
+	*nspcs = spaces;
+	return;
+    }
+
+    *ntabs = 1;
+    spaces -= padding;
+
+    // At least one tab has been used. See if any more will fit.
+    while (spaces != 0 && ++t <= tabcount)
+    {
+	padding = vts[t];
+	if (spaces < padding)
+	{
+	    *nspcs = spaces;
+	    return;
+	}
+	++*ntabs;
+	spaces -= padding;
+    }
+
+    *ntabs += spaces / vts[tabcount];
+    *nspcs =  spaces % vts[tabcount];
+}
+
+/*
+ * See if two tabstop arrays contain the same values.
+ */
+    int
+tabstop_eq(int *ts1, int *ts2)
+{
+    int		t;
+
+    if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0))
+	return FALSE;
+    if (ts1 == ts2)
+	return TRUE;
+    if (ts1[0] != ts2[0])
+	return FALSE;
+
+    for (t = 1; t <= ts1[0]; ++t)
+	if (ts1[t] != ts2[t])
+	    return FALSE;
+
+    return TRUE;
+}
+
+#if defined(FEAT_BEVAL) || defined(PROTO)
+/*
+ * Copy a tabstop array, allocating space for the new array.
+ */
+    int *
+tabstop_copy(int *oldts)
+{
+    int		*newts;
+    int		t;
+
+    if (oldts == NULL)
+	return NULL;
+    newts = ALLOC_MULT(int, oldts[0] + 1);
+    if (newts != NULL)
+	for (t = 0; t <= oldts[0]; ++t)
+	    newts[t] = oldts[t];
+    return newts;
+}
+#endif
+
+/*
+ * Return a count of the number of tabstops.
+ */
+    int
+tabstop_count(int *ts)
+{
+    return ts != NULL ? ts[0] : 0;
+}
+
+/*
+ * Return the first tabstop, or 8 if there are no tabstops defined.
+ */
+    int
+tabstop_first(int *ts)
+{
+    return ts != NULL ? ts[1] : 8;
+}
+
+#endif
+
+/*
+ * Return the effective shiftwidth value for current buffer, using the
+ * 'tabstop' value when 'shiftwidth' is zero.
+ */
+    long
+get_sw_value(buf_T *buf)
+{
+    return get_sw_value_col(buf, 0);
+}
+
+/*
+ * Idem, using "pos".
+ */
+    static 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 = 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 UNUSED)
+{
+    return buf->b_p_sw ? buf->b_p_sw :
+ #ifdef FEAT_VARTABS
+	tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ #else
+	buf->b_p_ts;
+ #endif
+}
+
+/*
+ * Return the effective softtabstop value for the current buffer, using the
+ * 'shiftwidth' value when 'softtabstop' is negative.
+ */
+    long
+get_sts_value(void)
+{
+    return curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
+}
--- a/src/map.c
+++ b/src/map.c
@@ -2193,6 +2193,197 @@ add_map(char_u *map, int mode)
 }
 #endif
 
+#if defined(FEAT_LANGMAP) || defined(PROTO)
+/*
+ * Any character has an equivalent 'langmap' character.  This is used for
+ * keyboards that have a special language mode that sends characters above
+ * 128 (although other characters can be translated too).  The "to" field is a
+ * Vim command character.  This avoids having to switch the keyboard back to
+ * ASCII mode when leaving Insert mode.
+ *
+ * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
+ * commands.
+ * langmap_mapga.ga_data is a sorted table of langmap_entry_T.  This does the
+ * same as langmap_mapchar[] for characters >= 256.
+ *
+ * Use growarray for 'langmap' chars >= 256
+ */
+typedef struct
+{
+    int	    from;
+    int     to;
+} langmap_entry_T;
+
+static garray_T langmap_mapga;
+
+/*
+ * Search for an entry in "langmap_mapga" for "from".  If found set the "to"
+ * field.  If not found insert a new entry at the appropriate location.
+ */
+    static void
+langmap_set_entry(int from, int to)
+{
+    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+    int		    a = 0;
+    int		    b = langmap_mapga.ga_len;
+
+    // Do a binary search for an existing entry.
+    while (a != b)
+    {
+	int i = (a + b) / 2;
+	int d = entries[i].from - from;
+
+	if (d == 0)
+	{
+	    entries[i].to = to;
+	    return;
+	}
+	if (d < 0)
+	    a = i + 1;
+	else
+	    b = i;
+    }
+
+    if (ga_grow(&langmap_mapga, 1) != OK)
+	return;  // out of memory
+
+    // insert new entry at position "a"
+    entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
+    mch_memmove(entries + 1, entries,
+			(langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
+    ++langmap_mapga.ga_len;
+    entries[0].from = from;
+    entries[0].to = to;
+}
+
+/*
+ * Apply 'langmap' to multi-byte character "c" and return the result.
+ */
+    int
+langmap_adjust_mb(int c)
+{
+    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+    int a = 0;
+    int b = langmap_mapga.ga_len;
+
+    while (a != b)
+    {
+	int i = (a + b) / 2;
+	int d = entries[i].from - c;
+
+	if (d == 0)
+	    return entries[i].to;  // found matching entry
+	if (d < 0)
+	    a = i + 1;
+	else
+	    b = i;
+    }
+    return c;  // no entry found, return "c" unmodified
+}
+
+    void
+langmap_init(void)
+{
+    int i;
+
+    for (i = 0; i < 256; i++)
+	langmap_mapchar[i] = i;	 // we init with a one-to-one map
+    ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8);
+}
+
+/*
+ * Called when langmap option is set; the language map can be
+ * changed at any time!
+ */
+    void
+langmap_set(void)
+{
+    char_u  *p;
+    char_u  *p2;
+    int	    from, to;
+
+    ga_clear(&langmap_mapga);		    // clear the previous map first
+    langmap_init();			    // back to one-to-one map
+
+    for (p = p_langmap; p[0] != NUL; )
+    {
+	for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
+							       MB_PTR_ADV(p2))
+	{
+	    if (p2[0] == '\\' && p2[1] != NUL)
+		++p2;
+	}
+	if (p2[0] == ';')
+	    ++p2;	    // abcd;ABCD form, p2 points to A
+	else
+	    p2 = NULL;	    // aAbBcCdD form, p2 is NULL
+	while (p[0])
+	{
+	    if (p[0] == ',')
+	    {
+		++p;
+		break;
+	    }
+	    if (p[0] == '\\' && p[1] != NUL)
+		++p;
+	    from = (*mb_ptr2char)(p);
+	    to = NUL;
+	    if (p2 == NULL)
+	    {
+		MB_PTR_ADV(p);
+		if (p[0] != ',')
+		{
+		    if (p[0] == '\\')
+			++p;
+		    to = (*mb_ptr2char)(p);
+		}
+	    }
+	    else
+	    {
+		if (p2[0] != ',')
+		{
+		    if (p2[0] == '\\')
+			++p2;
+		    to = (*mb_ptr2char)(p2);
+		}
+	    }
+	    if (to == NUL)
+	    {
+		semsg(_("E357: 'langmap': Matching character missing for %s"),
+							     transchar(from));
+		return;
+	    }
+
+	    if (from >= 256)
+		langmap_set_entry(from, to);
+	    else
+		langmap_mapchar[from & 255] = to;
+
+	    // Advance to next pair
+	    MB_PTR_ADV(p);
+	    if (p2 != NULL)
+	    {
+		MB_PTR_ADV(p2);
+		if (*p == ';')
+		{
+		    p = p2;
+		    if (p[0] != NUL)
+		    {
+			if (p[0] != ',')
+			{
+			    semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p);
+			    return;
+			}
+			++p;
+		    }
+		    break;
+		}
+	    }
+	}
+    }
+}
+#endif
+
     static void
 do_exmap(exarg_T *eap, int isabbrev)
 {
--- a/src/option.c
+++ b/src/option.c
@@ -3244,17 +3244,12 @@ static long_u *insecure_flag(int opt_idx
 #endif
 static void set_string_option_global(int opt_idx, char_u **varp);
 static char *did_set_string_option(int opt_idx, char_u **varp, int new_value_alloced, char_u *oldval, char *errbuf, int opt_flags, int *value_checked);
-static char *set_chars_option(char_u **varp);
 #ifdef FEAT_STL_OPT
 static char *check_stl_option(char_u *s);
 #endif
 #ifdef FEAT_CLIPBOARD
 static char *check_clipboard_option(void);
 #endif
-#ifdef FEAT_SPELL
-static char *did_set_spell_option(int is_spellfile);
-static char *compile_cap_prog(synblock_T *synblock);
-#endif
 #ifdef FEAT_EVAL
 static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx);
 #endif
@@ -3276,10 +3271,6 @@ static void check_win_options(win_T *win
 static void option_value2string(struct vimoption *, int opt_flags);
 static void check_winopt(winopt_T *wop);
 static int wc_use_keyname(char_u *varp, long *wcp);
-#ifdef FEAT_LANGMAP
-static void langmap_init(void);
-static void langmap_set(void);
-#endif
 static void paste_option_changed(void);
 static void compatible_set(void);
 #ifdef FEAT_LINEBREAK
@@ -6158,7 +6149,7 @@ set_string_option(
  * Return TRUE if "val" is a valid name: only consists of alphanumeric ASCII
  * characters or characters in "allowed".
  */
-    static int
+    int
 valid_name(char_u *val, char *allowed)
 {
     char_u *s;
@@ -6179,31 +6170,6 @@ valid_filetype(char_u *val)
     return valid_name(val, ".-_");
 }
 
-#if defined(FEAT_SPELL) || defined(PROTO)
-/*
- * Return TRUE if "val" is a valid 'spellang' value.
- */
-    int
-valid_spellang(char_u *val)
-{
-    return valid_name(val, ".-_,@");
-}
-
-/*
- * Return TRUE if "val" is a valid 'spellfile' value.
- */
-    static int
-valid_spellfile(char_u *val)
-{
-    char_u *s;
-
-    for (s = val; *s != NUL; ++s)
-	if (!vim_isfilec(*s) && *s != ',')
-	    return FALSE;
-    return TRUE;
-}
-#endif
-
 /*
  * Handle string options that need some action to perform when changed.
  * Returns NULL for success, or an error message for an error.
@@ -8000,217 +7966,6 @@ did_set_string_option(
     return errmsg;
 }
 
-#if defined(FEAT_SYN_HL) || defined(PROTO)
-/*
- * 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".
- * Returns error message, NULL if it's OK.
- */
-    char *
-check_colorcolumn(win_T *wp)
-{
-    char_u	*s;
-    int		col;
-    int		count = 0;
-    int		color_cols[256];
-    int		i;
-    int		j = 0;
-
-    if (wp->w_buffer == NULL)
-	return NULL;  /* buffer was closed */
-
-    for (s = wp->w_p_cc; *s != NUL && count < 255;)
-    {
-	if (*s == '-' || *s == '+')
-	{
-	    /* -N and +N: add to 'textwidth' */
-	    col = (*s == '-') ? -1 : 1;
-	    ++s;
-	    if (!VIM_ISDIGIT(*s))
-		return e_invarg;
-	    col = col * getdigits(&s);
-	    if (wp->w_buffer->b_p_tw == 0)
-		goto skip;  /* 'textwidth' not set, skip this item */
-	    col += wp->w_buffer->b_p_tw;
-	    if (col < 0)
-		goto skip;
-	}
-	else if (VIM_ISDIGIT(*s))
-	    col = getdigits(&s);
-	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," */
-    }
-
-    vim_free(wp->w_p_cc_cols);
-    if (count == 0)
-	wp->w_p_cc_cols = NULL;
-    else
-    {
-	wp->w_p_cc_cols = ALLOC_MULT(int, count + 1);
-	if (wp->w_p_cc_cols != NULL)
-	{
-	    /* sort the columns for faster usage on screen redraw inside
-	     * win_line() */
-	    qsort(color_cols, count, sizeof(int), int_cmp);
-
-	    for (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 */
-}
-#endif
-
-/*
- * Handle setting 'listchars' or 'fillchars'.
- * Returns error message, NULL if it's OK.
- */
-    static char *
-set_chars_option(char_u **varp)
-{
-    int		round, i, len, entries;
-    char_u	*p, *s;
-    int		c1 = 0, c2 = 0, c3 = 0;
-    struct charstab
-    {
-	int	*cp;
-	char	*name;
-    };
-    static struct charstab filltab[] =
-    {
-	{&fill_stl,	"stl"},
-	{&fill_stlnc,	"stlnc"},
-	{&fill_vert,	"vert"},
-	{&fill_fold,	"fold"},
-	{&fill_diff,	"diff"},
-    };
-    static struct charstab lcstab[] =
-    {
-	{&lcs_eol,	"eol"},
-	{&lcs_ext,	"extends"},
-	{&lcs_nbsp,	"nbsp"},
-	{&lcs_prec,	"precedes"},
-	{&lcs_space,	"space"},
-	{&lcs_tab2,	"tab"},
-	{&lcs_trail,	"trail"},
-#ifdef FEAT_CONCEAL
-	{&lcs_conceal,	"conceal"},
-#else
-	{NULL,		"conceal"},
-#endif
-    };
-    struct charstab *tab;
-
-    if (varp == &p_lcs)
-    {
-	tab = lcstab;
-	entries = sizeof(lcstab) / sizeof(struct charstab);
-    }
-    else
-    {
-	tab = filltab;
-	entries = sizeof(filltab) / sizeof(struct charstab);
-    }
-
-    /* first round: check for valid value, second round: assign values */
-    for (round = 0; round <= 1; ++round)
-    {
-	if (round > 0)
-	{
-	    /* After checking that the value is valid: set defaults: space for
-	     * 'fillchars', NUL for 'listchars' */
-	    for (i = 0; i < entries; ++i)
-		if (tab[i].cp != NULL)
-		    *(tab[i].cp) = (varp == &p_lcs ? NUL : ' ');
-
-	    if (varp == &p_lcs)
-	    {
-		lcs_tab1 = NUL;
-		lcs_tab3 = NUL;
-	    }
-	    else
-		fill_diff = '-';
-	}
-	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 = mb_ptr2char_adv(&s);
-		    if (mb_char2cells(c1) > 1)
-			continue;
-		    if (tab[i].cp == &lcs_tab2)
-		    {
-			if (*s == NUL)
-			    continue;
-			c2 = mb_ptr2char_adv(&s);
-			if (mb_char2cells(c2) > 1)
-			    continue;
-			if (!(*s == ',' || *s == NUL))
-			{
-			    c3 = mb_ptr2char_adv(&s);
-			    if (mb_char2cells(c3) > 1)
-				continue;
-			}
-		    }
-
-		    if (*s == ',' || *s == NUL)
-		    {
-			if (round)
-			{
-			    if (tab[i].cp == &lcs_tab2)
-			    {
-				lcs_tab1 = c1;
-				lcs_tab2 = c2;
-				lcs_tab3 = c3;
-			    }
-			    else if (tab[i].cp != NULL)
-				*(tab[i].cp) = c1;
-
-			}
-			p = s;
-			break;
-		    }
-		}
-	    }
-
-	    if (i == entries)
-		return e_invarg;
-	    if (*p == ',')
-		++p;
-	}
-    }
-
-    return NULL;	/* no error */
-}
-
 #ifdef FEAT_STL_OPT
 /*
  * Check validity of options with the 'statusline' format.
@@ -8376,71 +8131,6 @@ check_clipboard_option(void)
 }
 #endif
 
-#ifdef FEAT_SPELL
-/*
- * Handle side effects of setting 'spell'.
- * Return an error message or NULL for success.
- */
-    static char *
-did_set_spell_option(int is_spellfile)
-{
-    char    *errmsg = NULL;
-    win_T   *wp;
-    int	    l;
-
-    if (is_spellfile)
-    {
-	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(wp)
-	    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)
-{
-    regprog_T   *rp = synblock->b_cap_prog;
-    char_u	*re;
-
-    if (*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);
-	if (re != NULL)
-	{
-	    synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC);
-	    vim_free(re);
-	    if (synblock->b_cap_prog == NULL)
-	    {
-		synblock->b_cap_prog = rp; /* restore the previous program */
-		return e_invarg;
-	    }
-	}
-    }
-
-    vim_regfree(rp);
-    return NULL;
-}
-#endif
-
 #if defined(FEAT_EVAL) || defined(PROTO)
 /*
  * Set the script_ctx for an option, taking care of setting the buffer- or
@@ -10839,55 +10529,6 @@ istermoption(struct vimoption *p)
     return (p->fullname[0] == 't' && p->fullname[1] == '_');
 }
 
-/*
- * 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)
-{
-#if defined(FEAT_CMDL_INFO)
-    int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
-
-    sc_col = 0;
-    ru_col = 0;
-    if (p_ru)
-    {
-# ifdef FEAT_STL_OPT
-	ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
-# else
-	ru_col = COL_RULER + 1;
-# endif
-	/* 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;
-    }
-    sc_col = Columns - sc_col;
-    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;
-#else
-    sc_col = Columns;
-    ru_col = Columns;
-#endif
-#ifdef FEAT_EVAL
-    set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
-#endif
-}
-
 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
 /*
  * Unset local option value, similar to ":set opt<".
@@ -12307,197 +11948,6 @@ wc_use_keyname(char_u *varp, long *wcp)
     return FALSE;
 }
 
-#if defined(FEAT_LANGMAP) || defined(PROTO)
-/*
- * Any character has an equivalent 'langmap' character.  This is used for
- * keyboards that have a special language mode that sends characters above
- * 128 (although other characters can be translated too).  The "to" field is a
- * Vim command character.  This avoids having to switch the keyboard back to
- * ASCII mode when leaving Insert mode.
- *
- * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
- * commands.
- * langmap_mapga.ga_data is a sorted table of langmap_entry_T.  This does the
- * same as langmap_mapchar[] for characters >= 256.
- *
- * Use growarray for 'langmap' chars >= 256
- */
-typedef struct
-{
-    int	    from;
-    int     to;
-} langmap_entry_T;
-
-static garray_T langmap_mapga;
-
-/*
- * Search for an entry in "langmap_mapga" for "from".  If found set the "to"
- * field.  If not found insert a new entry at the appropriate location.
- */
-    static void
-langmap_set_entry(int from, int to)
-{
-    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
-    int		    a = 0;
-    int		    b = langmap_mapga.ga_len;
-
-    /* Do a binary search for an existing entry. */
-    while (a != b)
-    {
-	int i = (a + b) / 2;
-	int d = entries[i].from - from;
-
-	if (d == 0)
-	{
-	    entries[i].to = to;
-	    return;
-	}
-	if (d < 0)
-	    a = i + 1;
-	else
-	    b = i;
-    }
-
-    if (ga_grow(&langmap_mapga, 1) != OK)
-	return;  /* out of memory */
-
-    /* insert new entry at position "a" */
-    entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
-    mch_memmove(entries + 1, entries,
-			(langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
-    ++langmap_mapga.ga_len;
-    entries[0].from = from;
-    entries[0].to = to;
-}
-
-/*
- * Apply 'langmap' to multi-byte character "c" and return the result.
- */
-    int
-langmap_adjust_mb(int c)
-{
-    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
-    int a = 0;
-    int b = langmap_mapga.ga_len;
-
-    while (a != b)
-    {
-	int i = (a + b) / 2;
-	int d = entries[i].from - c;
-
-	if (d == 0)
-	    return entries[i].to;  /* found matching entry */
-	if (d < 0)
-	    a = i + 1;
-	else
-	    b = i;
-    }
-    return c;  /* no entry found, return "c" unmodified */
-}
-
-    static void
-langmap_init(void)
-{
-    int i;
-
-    for (i = 0; i < 256; i++)
-	langmap_mapchar[i] = i;	 /* we init with a one-to-one map */
-    ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8);
-}
-
-/*
- * Called when langmap option is set; the language map can be
- * changed at any time!
- */
-    static void
-langmap_set(void)
-{
-    char_u  *p;
-    char_u  *p2;
-    int	    from, to;
-
-    ga_clear(&langmap_mapga);		    /* clear the previous map first */
-    langmap_init();			    /* back to one-to-one map */
-
-    for (p = p_langmap; p[0] != NUL; )
-    {
-	for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
-							       MB_PTR_ADV(p2))
-	{
-	    if (p2[0] == '\\' && p2[1] != NUL)
-		++p2;
-	}
-	if (p2[0] == ';')
-	    ++p2;	    /* abcd;ABCD form, p2 points to A */
-	else
-	    p2 = NULL;	    /* aAbBcCdD form, p2 is NULL */
-	while (p[0])
-	{
-	    if (p[0] == ',')
-	    {
-		++p;
-		break;
-	    }
-	    if (p[0] == '\\' && p[1] != NUL)
-		++p;
-	    from = (*mb_ptr2char)(p);
-	    to = NUL;
-	    if (p2 == NULL)
-	    {
-		MB_PTR_ADV(p);
-		if (p[0] != ',')
-		{
-		    if (p[0] == '\\')
-			++p;
-		    to = (*mb_ptr2char)(p);
-		}
-	    }
-	    else
-	    {
-		if (p2[0] != ',')
-		{
-		    if (p2[0] == '\\')
-			++p2;
-		    to = (*mb_ptr2char)(p2);
-		}
-	    }
-	    if (to == NUL)
-	    {
-		semsg(_("E357: 'langmap': Matching character missing for %s"),
-							     transchar(from));
-		return;
-	    }
-
-	    if (from >= 256)
-		langmap_set_entry(from, to);
-	    else
-		langmap_mapchar[from & 255] = to;
-
-	    /* Advance to next pair */
-	    MB_PTR_ADV(p);
-	    if (p2 != NULL)
-	    {
-		MB_PTR_ADV(p2);
-		if (*p == ';')
-		{
-		    p = p2;
-		    if (p[0] != NUL)
-		    {
-			if (p[0] != ',')
-			{
-			    semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p);
-			    return;
-			}
-			++p;
-		    }
-		    break;
-		}
-	    }
-	}
-    }
-}
-#endif
-
 /*
  * Return TRUE if format option 'x' is in effect.
  * Take care of no formatting when 'paste' is set.
@@ -13012,364 +12462,6 @@ check_ff_value(char_u *p)
     return check_opt_strings(p, p_ff_values, FALSE);
 }
 
-#if defined(FEAT_VARTABS) || defined(PROTO)
-
-/*
- * Set the integer values corresponding to the string setting of 'vartabstop'.
- * "array" will be set, caller must free it if needed.
- */
-    int
-tabstop_set(char_u *var, int **array)
-{
-    int 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_u *end;
-
-	    if (strtol((char *)cp, (char **)&end, 10) <= 0)
-	    {
-		if (cp != end)
-		    emsg(_(e_positive));
-		else
-		    emsg(_(e_invarg));
-		return FALSE;
-	    }
-	}
-
-	if (VIM_ISDIGIT(*cp))
-	    continue;
-	if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL)
-	{
-	    ++valcount;
-	    continue;
-	}
-	emsg(_(e_invarg));
-	return FALSE;
-    }
-
-    *array = ALLOC_MULT(int, valcount + 1);
-    if (*array == NULL)
-	return FALSE;
-    (*array)[0] = valcount;
-
-    t = 1;
-    for (cp = var; *cp != NUL;)
-    {
-	(*array)[t++] = atoi((char *)cp);
-	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, int ts_arg, int *vts)
-{
-    int		ts = ts_arg == 0 ? 8 : ts_arg;
-    int		tabcount;
-    colnr_T	tabcol = 0;
-    int		t;
-    int		padding = 0;
-
-    if (vts == NULL || vts[0] == 0)
-	return ts - (col % ts);
-
-    tabcount = vts[0];
-
-    for (t = 1; t <= tabcount; ++t)
-    {
-	tabcol += vts[t];
-	if (tabcol > col)
-	{
-	    padding = (int)(tabcol - col);
-	    break;
-	}
-    }
-    if (t > tabcount)
-	padding = vts[tabcount] - (int)((col - tabcol) % vts[tabcount]);
-
-    return padding;
-}
-
-/*
- * Find the size of the tab that covers a particular column.
- */
-    int
-tabstop_at(colnr_T col, int ts, int *vts)
-{
-    int		tabcount;
-    colnr_T	tabcol = 0;
-    int		t;
-    int		tab_size = 0;
-
-    if (vts == 0 || vts[0] == 0)
-	return ts;
-
-    tabcount = vts[0];
-    for (t = 1; t <= tabcount; ++t)
-    {
-	tabcol += vts[t];
-	if (tabcol > col)
-	{
-	    tab_size = vts[t];
-	    break;
-	}
-    }
-    if (t > tabcount)
-	tab_size = vts[tabcount];
-
-    return tab_size;
-}
-
-/*
- * Find the column on which a tab starts.
- */
-    colnr_T
-tabstop_start(colnr_T col, int ts, int *vts)
-{
-    int		tabcount;
-    colnr_T	tabcol = 0;
-    int		t;
-    int         excess;
-
-    if (vts == NULL || vts[0] == 0)
-	return (col / ts) * ts;
-
-    tabcount = vts[0];
-    for (t = 1; t <= tabcount; ++t)
-    {
-	tabcol += vts[t];
-	if (tabcol > col)
-	    return tabcol - vts[t];
-    }
-
-    excess = tabcol % vts[tabcount];
-    return excess + ((col - excess) / vts[tabcount]) * vts[tabcount];
-}
-
-/*
- * Find the number of tabs and spaces necessary to get from one column
- * to another.
- */
-    void
-tabstop_fromto(
-	colnr_T start_col,
-	colnr_T end_col,
-	int	ts_arg,
-	int	*vts,
-	int	*ntabs,
-	int	*nspcs)
-{
-    int		spaces = end_col - start_col;
-    colnr_T	tabcol = 0;
-    int		padding = 0;
-    int		tabcount;
-    int		t;
-    int		ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
-
-    if (vts == NULL || vts[0] == 0)
-    {
-	int tabs = 0;
-	int initspc = 0;
-
-	initspc = ts - (start_col % ts);
-	if (spaces >= initspc)
-	{
-	    spaces -= initspc;
-	    tabs++;
-	}
-	tabs += spaces / ts;
-	spaces -= (spaces / ts) * ts;
-
-	*ntabs = tabs;
-	*nspcs = spaces;
-	return;
-    }
-
-    /* Find the padding needed to reach the next tabstop. */
-    tabcount = vts[0];
-    for (t = 1; t <= tabcount; ++t)
-    {
-	tabcol += vts[t];
-	if (tabcol > start_col)
-	{
-	    padding = (int)(tabcol - start_col);
-	    break;
-	}
-    }
-    if (t > tabcount)
-	padding = vts[tabcount] - (int)((start_col - tabcol) % vts[tabcount]);
-
-    /* If the space needed is less than the padding no tabs can be used. */
-    if (spaces < padding)
-    {
-	*ntabs = 0;
-	*nspcs = spaces;
-	return;
-    }
-
-    *ntabs = 1;
-    spaces -= padding;
-
-    /* At least one tab has been used. See if any more will fit. */
-    while (spaces != 0 && ++t <= tabcount)
-    {
-	padding = vts[t];
-	if (spaces < padding)
-	{
-	    *nspcs = spaces;
-	    return;
-	}
-	++*ntabs;
-	spaces -= padding;
-    }
-
-    *ntabs += spaces / vts[tabcount];
-    *nspcs =  spaces % vts[tabcount];
-}
-
-/*
- * See if two tabstop arrays contain the same values.
- */
-    int
-tabstop_eq(int *ts1, int *ts2)
-{
-    int		t;
-
-    if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0))
-	return FALSE;
-    if (ts1 == ts2)
-	return TRUE;
-    if (ts1[0] != ts2[0])
-	return FALSE;
-
-    for (t = 1; t <= ts1[0]; ++t)
-	if (ts1[t] != ts2[t])
-	    return FALSE;
-
-    return TRUE;
-}
-
-#if defined(FEAT_BEVAL) || defined(PROTO)
-/*
- * Copy a tabstop array, allocating space for the new array.
- */
-    int *
-tabstop_copy(int *oldts)
-{
-    int		*newts;
-    int		t;
-
-    if (oldts == NULL)
-	return NULL;
-    newts = ALLOC_MULT(int, oldts[0] + 1);
-    if (newts != NULL)
-	for (t = 0; t <= oldts[0]; ++t)
-	    newts[t] = oldts[t];
-    return newts;
-}
-#endif
-
-/*
- * Return a count of the number of tabstops.
- */
-    int
-tabstop_count(int *ts)
-{
-    return ts != NULL ? ts[0] : 0;
-}
-
-/*
- * Return the first tabstop, or 8 if there are no tabstops defined.
- */
-    int
-tabstop_first(int *ts)
-{
-    return ts != NULL ? ts[1] : 8;
-}
-
-#endif
-
-/*
- * Return the effective shiftwidth value for current buffer, using the
- * 'tabstop' value when 'shiftwidth' is zero.
- */
-    long
-get_sw_value(buf_T *buf)
-{
-    return get_sw_value_col(buf, 0);
-}
-
-/*
- * Idem, using "pos".
- */
-    static 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 = 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 UNUSED)
-{
-    return buf->b_p_sw ? buf->b_p_sw :
- #ifdef FEAT_VARTABS
-	tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
- #else
-	buf->b_p_ts;
- #endif
-}
-
-/*
- * Return the effective softtabstop value for the current buffer, using the
- * 'shiftwidth' value when 'softtabstop' is negative.
- */
-    long
-get_sts_value(void)
-{
-    return curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
-}
-
 /*
  * Return the effective 'scrolloff' value for the current window, using the
  * global value when appropriate.
--- a/src/proto/map.pro
+++ b/src/proto/map.pro
@@ -19,6 +19,9 @@ char_u *check_map(char_u *keys, int mode
 void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
 void init_mappings(void);
 void add_map(char_u *map, int mode);
+int langmap_adjust_mb(int c);
+void langmap_init(void);
+void langmap_set(void);
 void ex_abbreviate(exarg_T *eap);
 void ex_map(exarg_T *eap);
 void ex_unmap(exarg_T *eap);
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -22,8 +22,7 @@ int was_set_insecurely(char_u *opt, int 
 void set_string_option_direct(char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
 void set_string_option_direct_in_win(win_T *wp, char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
 void set_string_option_direct_in_buf(buf_T *buf, char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
-int valid_spellang(char_u *val);
-char *check_colorcolumn(win_T *wp);
+int valid_name(char_u *val, char *allowed);
 void set_term_option_sctx_idx(char *name, int opt_idx);
 int get_option_value(char_u *name, long *numval, char_u **stringval, int opt_flags);
 int get_option_value_strict(char_u *name, long *numval, char_u **stringval, int opt_type, void *from);
@@ -38,7 +37,6 @@ void clear_termoptions(void);
 void free_termoptions(void);
 void free_one_termoption(char_u *var);
 void set_term_defaults(void);
-void comp_col(void);
 void unset_global_local_option(char_u *name, void *from);
 char_u *get_equalprg(void);
 void win_copy_options(win_T *wp_from, win_T *wp_to);
@@ -51,7 +49,6 @@ void set_imsearch_global(void);
 void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags);
 int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
 int ExpandOldSetting(int *num_file, char_u ***file);
-int langmap_adjust_mb(int c);
 int has_format_option(int x);
 int shortmess(int x);
 void vimrc_found(char_u *fname, char_u *envname);
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -26,11 +26,13 @@ void ex_cnext(exarg_T *eap);
 void ex_cbelow(exarg_T *eap);
 void ex_cfile(exarg_T *eap);
 void ex_vimgrep(exarg_T *eap);
-int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list);
-int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict);
 int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what);
 int set_ref_in_quickfix(int copyID);
 void ex_cbuffer(exarg_T *eap);
 void ex_cexpr(exarg_T *eap);
 void ex_helpgrep(exarg_T *eap);
+void f_getloclist(typval_T *argvars, typval_T *rettv);
+void f_getqflist(typval_T *argvars, typval_T *rettv);
+void f_setloclist(typval_T *argvars, typval_T *rettv);
+void f_setqflist(typval_T *argvars, typval_T *rettv);
 /* vim: set ft=c : */
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -59,7 +59,9 @@ void get_trans_bufname(buf_T *buf);
 int redrawing(void);
 int messaging(void);
 void showruler(int always);
+void comp_col(void);
 int number_width(win_T *wp);
 int screen_screencol(void);
 int screen_screenrow(void);
+char *set_chars_option(char_u **varp);
 /* vim: set ft=c : */
--- a/src/proto/spell.pro
+++ b/src/proto/spell.pro
@@ -34,4 +34,8 @@ char_u *spell_to_word_end(char_u *start,
 int spell_word_start(int startcol);
 void spell_expand_check_cap(colnr_T col);
 int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp);
+int valid_spellang(char_u *val);
+int valid_spellfile(char_u *val);
+char *did_set_spell_option(int is_spellfile);
+char *compile_cap_prog(synblock_T *synblock);
 /* vim: set ft=c : */
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -82,6 +82,7 @@ void restore_buffer(bufref_T *save_curbu
 int win_hasvertsplit(void);
 int get_win_number(win_T *wp, win_T *first_win);
 int get_tab_number(tabpage_T *tp);
+char *check_colorcolumn(win_T *wp);
 int win_getid(typval_T *argvars);
 int win_gotoid(typval_T *argvars);
 void win_id2tabwin(typval_T *argvars, list_T *list);
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -6305,7 +6305,7 @@ get_qfline_items(qfline_T *qfp, list_T *
  * Add each quickfix error to list "list" as a dictionary.
  * If qf_idx is -1, use the current list. Otherwise, use the specified list.
  */
-    int
+    static int
 get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
 {
     qf_info_T	*qi = qi_arg;
@@ -6678,7 +6678,7 @@ qf_getprop_idx(qf_list_T *qfl, dict_T *r
  * dictionary. 'what' contains the details to return. If 'list_idx' is -1,
  * then current list is used. Otherwise the specified list is used.
  */
-    int
+    static int
 qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
 {
     qf_info_T	*qi = &ql_info;
@@ -7824,5 +7824,153 @@ ex_helpgrep(exarg_T *eap)
 	    curwin->w_llist = qi;
     }
 }
-
 #endif /* FEAT_QUICKFIX */
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+# ifdef FEAT_QUICKFIX
+    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)
+    {
+	if (rettv_list_alloc(rettv) == OK)
+	    if (is_qf || wp != NULL)
+		(void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
+    }
+    else
+    {
+	if (rettv_dict_alloc(rettv) == OK)
+	    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));
+	    }
+    }
+}
+# endif
+
+/*
+ * "getloclist()" function
+ */
+    void
+f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+# ifdef FEAT_QUICKFIX
+    win_T	*wp;
+
+    wp = find_win_by_nr_or_id(&argvars[0]);
+    get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
+# endif
+}
+
+/*
+ * "getqflist()" function
+ */
+    void
+f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+# ifdef FEAT_QUICKFIX
+    get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
+# endif
+}
+
+/*
+ * Used by "setqflist()" and "setloclist()" functions
+ */
+    static void
+set_qf_ll_list(
+    win_T	*wp UNUSED,
+    typval_T	*list_arg UNUSED,
+    typval_T	*action_arg UNUSED,
+    typval_T	*what_arg UNUSED,
+    typval_T	*rettv)
+{
+# ifdef FEAT_QUICKFIX
+    static char *e_invact = N_("E927: Invalid action: '%s'");
+    char_u	*act;
+    int		action = 0;
+    static int	recursive = 0;
+# endif
+
+    rettv->vval.v_number = -1;
+
+# ifdef FEAT_QUICKFIX
+    if (list_arg->v_type != VAR_LIST)
+	emsg(_(e_listreq));
+    else if (recursive != 0)
+	emsg(_(e_au_recursive));
+    else
+    {
+	list_T  *l = list_arg->vval.v_list;
+	dict_T	*d = NULL;
+	int	valid_dict = TRUE;
+
+	if (action_arg->v_type == VAR_STRING)
+	{
+	    act = tv_get_string_chk(action_arg);
+	    if (act == NULL)
+		return;		// type error; errmsg already given
+	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
+		    act[1] == NUL)
+		action = *act;
+	    else
+		semsg(_(e_invact), act);
+	}
+	else if (action_arg->v_type == VAR_UNKNOWN)
+	    action = ' ';
+	else
+	    emsg(_(e_stringreq));
+
+	if (action_arg->v_type != VAR_UNKNOWN
+		&& what_arg->v_type != VAR_UNKNOWN)
+	{
+	    if (what_arg->v_type == VAR_DICT)
+		d = what_arg->vval.v_dict;
+	    else
+	    {
+		emsg(_(e_dictreq));
+		valid_dict = FALSE;
+	    }
+	}
+
+	++recursive;
+	if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
+		     (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
+		     d) == OK)
+	    rettv->vval.v_number = 0;
+	--recursive;
+    }
+# endif
+}
+
+/*
+ * "setloclist()" function
+ */
+    void
+f_setloclist(typval_T *argvars, typval_T *rettv)
+{
+    win_T	*win;
+
+    rettv->vval.v_number = -1;
+
+    win = find_win_by_nr_or_id(&argvars[0]);
+    if (win != NULL)
+	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
+}
+
+/*
+ * "setqflist()" function
+ */
+    void
+f_setqflist(typval_T *argvars, typval_T *rettv)
+{
+    set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
+}
+#endif
--- a/src/screen.c
+++ b/src/screen.c
@@ -10771,6 +10771,55 @@ win_redr_ruler(win_T *wp, int always, in
 }
 #endif
 
+/*
+ * 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)
+{
+#if defined(FEAT_CMDL_INFO)
+    int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
+
+    sc_col = 0;
+    ru_col = 0;
+    if (p_ru)
+    {
+# ifdef FEAT_STL_OPT
+	ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
+# else
+	ru_col = COL_RULER + 1;
+# endif
+	// 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;
+    }
+    sc_col = Columns - sc_col;
+    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;
+#else
+    sc_col = Columns;
+    ru_col = Columns;
+#endif
+#ifdef FEAT_EVAL
+    set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
+#endif
+}
+
 #if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
  * Return the width of the 'number' and 'relativenumber' column.
@@ -10840,3 +10889,133 @@ screen_screenrow(void)
     return screen_cur_row;
 }
 #endif
+
+/*
+ * Handle setting 'listchars' or 'fillchars'.
+ * Returns error message, NULL if it's OK.
+ */
+    char *
+set_chars_option(char_u **varp)
+{
+    int		round, i, len, entries;
+    char_u	*p, *s;
+    int		c1 = 0, c2 = 0, c3 = 0;
+    struct charstab
+    {
+	int	*cp;
+	char	*name;
+    };
+    static struct charstab filltab[] =
+    {
+	{&fill_stl,	"stl"},
+	{&fill_stlnc,	"stlnc"},
+	{&fill_vert,	"vert"},
+	{&fill_fold,	"fold"},
+	{&fill_diff,	"diff"},
+    };
+    static struct charstab lcstab[] =
+    {
+	{&lcs_eol,	"eol"},
+	{&lcs_ext,	"extends"},
+	{&lcs_nbsp,	"nbsp"},
+	{&lcs_prec,	"precedes"},
+	{&lcs_space,	"space"},
+	{&lcs_tab2,	"tab"},
+	{&lcs_trail,	"trail"},
+#ifdef FEAT_CONCEAL
+	{&lcs_conceal,	"conceal"},
+#else
+	{NULL,		"conceal"},
+#endif
+    };
+    struct charstab *tab;
+
+    if (varp == &p_lcs)
+    {
+	tab = lcstab;
+	entries = sizeof(lcstab) / sizeof(struct charstab);
+    }
+    else
+    {
+	tab = filltab;
+	entries = sizeof(filltab) / sizeof(struct charstab);
+    }
+
+    // first round: check for valid value, second round: assign values
+    for (round = 0; round <= 1; ++round)
+    {
+	if (round > 0)
+	{
+	    // After checking that the value is valid: set defaults: space for
+	    // 'fillchars', NUL for 'listchars'
+	    for (i = 0; i < entries; ++i)
+		if (tab[i].cp != NULL)
+		    *(tab[i].cp) = (varp == &p_lcs ? NUL : ' ');
+
+	    if (varp == &p_lcs)
+	    {
+		lcs_tab1 = NUL;
+		lcs_tab3 = NUL;
+	    }
+	    else
+		fill_diff = '-';
+	}
+	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 = mb_ptr2char_adv(&s);
+		    if (mb_char2cells(c1) > 1)
+			continue;
+		    if (tab[i].cp == &lcs_tab2)
+		    {
+			if (*s == NUL)
+			    continue;
+			c2 = mb_ptr2char_adv(&s);
+			if (mb_char2cells(c2) > 1)
+			    continue;
+			if (!(*s == ',' || *s == NUL))
+			{
+			    c3 = mb_ptr2char_adv(&s);
+			    if (mb_char2cells(c3) > 1)
+				continue;
+			}
+		    }
+
+		    if (*s == ',' || *s == NUL)
+		    {
+			if (round)
+			{
+			    if (tab[i].cp == &lcs_tab2)
+			    {
+				lcs_tab1 = c1;
+				lcs_tab2 = c2;
+				lcs_tab3 = c3;
+			    }
+			    else if (tab[i].cp != NULL)
+				*(tab[i].cp) = c1;
+
+			}
+			p = s;
+			break;
+		    }
+		}
+	    }
+
+	    if (i == entries)
+		return e_invarg;
+	    if (*p == ',')
+		++p;
+	}
+    }
+
+    return NULL;	// no error
+}
--- a/src/spell.c
+++ b/src/spell.c
@@ -8833,4 +8833,90 @@ expand_spelling(
     return ga.ga_len;
 }
 
-#endif  /* FEAT_SPELL */
+/*
+ * Return TRUE if "val" is a valid 'spellang' value.
+ */
+    int
+valid_spellang(char_u *val)
+{
+    return valid_name(val, ".-_,@");
+}
+
+/*
+ * Return TRUE if "val" is a valid 'spellfile' value.
+ */
+    int
+valid_spellfile(char_u *val)
+{
+    char_u *s;
+
+    for (s = val; *s != NUL; ++s)
+	if (!vim_isfilec(*s) && *s != ',')
+	    return FALSE;
+    return TRUE;
+}
+
+/*
+ * Handle side effects of setting 'spell'.
+ * Return an error message or NULL for success.
+ */
+    char *
+did_set_spell_option(int is_spellfile)
+{
+    char    *errmsg = NULL;
+    win_T   *wp;
+    int	    l;
+
+    if (is_spellfile)
+    {
+	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(wp)
+	    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)
+{
+    regprog_T   *rp = synblock->b_cap_prog;
+    char_u	*re;
+
+    if (*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);
+	if (re != NULL)
+	{
+	    synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC);
+	    vim_free(re);
+	    if (synblock->b_cap_prog == NULL)
+	    {
+		synblock->b_cap_prog = rp; // restore the previous program
+		return e_invarg;
+	    }
+	}
+    }
+
+    vim_regfree(rp);
+    return NULL;
+}
+
+#endif  // FEAT_SPELL
--- a/src/version.c
+++ b/src/version.c
@@ -762,6 +762,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1966,
+/**/
     1965,
 /**/
     1964,
--- a/src/window.c
+++ b/src/window.c
@@ -6816,6 +6816,87 @@ frame_check_width(frame_T *topfrp, int w
     return TRUE;
 }
 
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * 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".
+ * Returns error message, NULL if it's OK.
+ */
+    char *
+check_colorcolumn(win_T *wp)
+{
+    char_u	*s;
+    int		col;
+    int		count = 0;
+    int		color_cols[256];
+    int		i;
+    int		j = 0;
+
+    if (wp->w_buffer == NULL)
+	return NULL;  // buffer was closed
+
+    for (s = wp->w_p_cc; *s != NUL && count < 255;)
+    {
+	if (*s == '-' || *s == '+')
+	{
+	    // -N and +N: add to 'textwidth'
+	    col = (*s == '-') ? -1 : 1;
+	    ++s;
+	    if (!VIM_ISDIGIT(*s))
+		return e_invarg;
+	    col = col * getdigits(&s);
+	    if (wp->w_buffer->b_p_tw == 0)
+		goto skip;  // 'textwidth' not set, skip this item
+	    col += wp->w_buffer->b_p_tw;
+	    if (col < 0)
+		goto skip;
+	}
+	else if (VIM_ISDIGIT(*s))
+	    col = getdigits(&s);
+	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,"
+    }
+
+    vim_free(wp->w_p_cc_cols);
+    if (count == 0)
+	wp->w_p_cc_cols = NULL;
+    else
+    {
+	wp->w_p_cc_cols = ALLOC_MULT(int, count + 1);
+	if (wp->w_p_cc_cols != NULL)
+	{
+	    // sort the columns for faster usage on screen redraw inside
+	    // win_line()
+	    qsort(color_cols, count, sizeof(int), int_cmp);
+
+	    for (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
+}
+#endif
+
 #if defined(FEAT_EVAL) || defined(PROTO)
     int
 win_getid(typval_T *argvars)