Mercurial > vim
comparison src/option.c @ 31886:b741e5243e58 v9.0.1275
patch 9.0.1275: the code for setting options is too complicated
Commit: https://github.com/vim/vim/commit/78012f55faf7444e554c0a97a589d99fa215bea9
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Thu Feb 2 16:34:11 2023 +0000
patch 9.0.1275: the code for setting options is too complicated
Problem: The code for setting options is too complicated.
Solution: Refactor the do_set() function. (Yegappan Lakshmanan, Lewis
Russell, closes #11932)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 02 Feb 2023 17:45:05 +0100 |
parents | aec031683d61 |
children | 1c5ef864fe4c |
comparison
equal
deleted
inserted
replaced
31885:cc751d944b7e | 31886:b741e5243e58 |
---|---|
8 */ | 8 */ |
9 | 9 |
10 /* | 10 /* |
11 * Code to handle user-settable options. This is all pretty much table- | 11 * Code to handle user-settable options. This is all pretty much table- |
12 * driven. Checklist for adding a new option: | 12 * driven. Checklist for adding a new option: |
13 * - Put it in the options array below (copy an existing entry). | 13 * - Put it in the options array in optiondefs.h (copy an existing entry). |
14 * - For a global option: Add a variable for it in option.h. | 14 * - For a global option: Add a variable for it in option.h. |
15 * - For a buffer or window local option: | 15 * - For a buffer or window local option: |
16 * - Add a PV_XX entry to the enum below. | 16 * - Add a PV_XX macro definition to the optiondefs.h file. |
17 * - Add a variable to the window or buffer struct in structs.h. | 17 * - Add a variable to the window or buffer struct in structs.h. |
18 * - For a window option, add some code to copy_winopt(). | 18 * - For a window option, add some code to copy_winopt(). |
19 * - For a window string option, add code to check_win_options() and | |
20 * clear_winopt(). | |
19 * - For a buffer option, add some code to buf_copy_options(). | 21 * - For a buffer option, add some code to buf_copy_options(). |
20 * - For a buffer string option, add code to check_buf_options(). | 22 * - For a buffer string option, add code to check_buf_options(). |
21 * - If it's a numeric option, add any necessary bounds checks to do_set(). | 23 * - If it's a numeric option, add any necessary bounds checks to |
22 * - If it's a list of flags, add some code in do_set(), search for WW_ALL. | 24 * set_num_option(). |
25 * - If it's a list of flags, add some code in did_set_string_option(), search | |
26 * for WW_ALL. | |
23 * - When adding an option with expansion (P_EXPAND), but with a different | 27 * - When adding an option with expansion (P_EXPAND), but with a different |
24 * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP. | 28 * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP. |
25 * - Add documentation! One line in doc/quickref.txt, full description in | 29 * - Add documentation! One line in doc/quickref.txt, full description in |
26 * options.txt, and any other related places. | 30 * options.txt, and any other related places. |
27 * - Add an entry in runtime/optwin.vim. | 31 * - Add an entry in runtime/optwin.vim. |
1631 *argp = arg; | 1635 *argp = arg; |
1632 return *errmsg == NULL ? OK : FAIL; | 1636 return *errmsg == NULL ? OK : FAIL; |
1633 } | 1637 } |
1634 | 1638 |
1635 /* | 1639 /* |
1640 * Set an option to a new value. | |
1641 * Return NULL if OK, return an untranslated error message when something is | |
1642 * wrong. "errbuf[errbuflen]" can be used to create the error message. | |
1643 */ | |
1644 static char * | |
1645 do_set_option( | |
1646 int opt_flags, | |
1647 char_u **argp, | |
1648 char_u *arg_start, | |
1649 char_u **startarg, | |
1650 int *did_show, | |
1651 int *stopopteval, | |
1652 char *errbuf, | |
1653 size_t errbuflen) | |
1654 { | |
1655 char *errmsg = NULL; | |
1656 int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name | |
1657 int nextchar; // next non-white char after option name | |
1658 int afterchar; // character just after option name | |
1659 char_u *arg = *argp; | |
1660 int key; | |
1661 int opt_idx; | |
1662 int len; | |
1663 set_op_T op = 0; | |
1664 long_u flags; // flags for current option | |
1665 char_u *varp = NULL; // pointer to variable for current option | |
1666 char_u key_name[2]; | |
1667 int cp_val = 0; | |
1668 varnumber_T value; | |
1669 int i; | |
1670 | |
1671 prefix = 1; | |
1672 if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0) | |
1673 { | |
1674 prefix = 0; | |
1675 arg += 2; | |
1676 } | |
1677 else if (STRNCMP(arg, "inv", 3) == 0) | |
1678 { | |
1679 prefix = 2; | |
1680 arg += 3; | |
1681 } | |
1682 | |
1683 // find end of name | |
1684 key = 0; | |
1685 if (*arg == '<') | |
1686 { | |
1687 opt_idx = -1; | |
1688 // look out for <t_>;> | |
1689 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) | |
1690 len = 5; | |
1691 else | |
1692 { | |
1693 len = 1; | |
1694 while (arg[len] != NUL && arg[len] != '>') | |
1695 ++len; | |
1696 } | |
1697 if (arg[len] != '>') | |
1698 { | |
1699 errmsg = e_invalid_argument; | |
1700 goto skip; | |
1701 } | |
1702 arg[len] = NUL; // put NUL after name | |
1703 if (arg[1] == 't' && arg[2] == '_') // could be term code | |
1704 opt_idx = findoption(arg + 1); | |
1705 arg[len++] = '>'; // restore '>' | |
1706 if (opt_idx == -1) | |
1707 key = find_key_option(arg + 1, TRUE); | |
1708 } | |
1709 else | |
1710 { | |
1711 len = 0; | |
1712 /* | |
1713 * The two characters after "t_" may not be alphanumeric. | |
1714 */ | |
1715 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) | |
1716 len = 4; | |
1717 else | |
1718 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') | |
1719 ++len; | |
1720 nextchar = arg[len]; | |
1721 arg[len] = NUL; // put NUL after name | |
1722 opt_idx = findoption(arg); | |
1723 arg[len] = nextchar; // restore nextchar | |
1724 if (opt_idx == -1) | |
1725 key = find_key_option(arg, FALSE); | |
1726 } | |
1727 | |
1728 // remember character after option name | |
1729 afterchar = arg[len]; | |
1730 | |
1731 if (in_vim9script()) | |
1732 { | |
1733 char_u *p = skipwhite(arg + len); | |
1734 | |
1735 // disallow white space before =val, +=val, -=val, ^=val | |
1736 if (p > arg + len && (p[0] == '=' | |
1737 || (vim_strchr((char_u *)"+-^", p[0]) != NULL | |
1738 && p[1] == '='))) | |
1739 { | |
1740 errmsg = e_no_white_space_allowed_between_option_and; | |
1741 arg = p; | |
1742 *startarg = p; | |
1743 goto skip; | |
1744 } | |
1745 } | |
1746 else | |
1747 // skip white space, allow ":set ai ?", ":set hlsearch !" | |
1748 while (VIM_ISWHITE(arg[len])) | |
1749 ++len; | |
1750 | |
1751 op = OP_NONE; | |
1752 if (arg[len] != NUL && arg[len + 1] == '=') | |
1753 { | |
1754 if (arg[len] == '+') | |
1755 { | |
1756 op = OP_ADDING; // "+=" | |
1757 ++len; | |
1758 } | |
1759 else if (arg[len] == '^') | |
1760 { | |
1761 op = OP_PREPENDING; // "^=" | |
1762 ++len; | |
1763 } | |
1764 else if (arg[len] == '-') | |
1765 { | |
1766 op = OP_REMOVING; // "-=" | |
1767 ++len; | |
1768 } | |
1769 } | |
1770 nextchar = arg[len]; | |
1771 | |
1772 if (opt_idx == -1 && key == 0) // found a mismatch: skip | |
1773 { | |
1774 if (in_vim9script() && arg > arg_start | |
1775 && vim_strchr((char_u *)"!&<", *arg) != NULL) | |
1776 errmsg = e_no_white_space_allowed_between_option_and; | |
1777 else | |
1778 errmsg = e_unknown_option; | |
1779 goto skip; | |
1780 } | |
1781 | |
1782 if (opt_idx >= 0) | |
1783 { | |
1784 if (options[opt_idx].var == NULL) // hidden option: skip | |
1785 { | |
1786 // Only give an error message when requesting the value of | |
1787 // a hidden option, ignore setting it. | |
1788 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL | |
1789 && (!(options[opt_idx].flags & P_BOOL) | |
1790 || nextchar == '?')) | |
1791 errmsg = e_option_not_supported; | |
1792 goto skip; | |
1793 } | |
1794 | |
1795 flags = options[opt_idx].flags; | |
1796 varp = get_varp_scope(&(options[opt_idx]), opt_flags); | |
1797 } | |
1798 else | |
1799 { | |
1800 flags = P_STRING; | |
1801 if (key < 0) | |
1802 { | |
1803 key_name[0] = KEY2TERMCAP0(key); | |
1804 key_name[1] = KEY2TERMCAP1(key); | |
1805 } | |
1806 else | |
1807 { | |
1808 key_name[0] = KS_KEY; | |
1809 key_name[1] = (key & 0xff); | |
1810 } | |
1811 } | |
1812 | |
1813 // Skip all options that are not window-local (used when showing | |
1814 // an already loaded buffer in a window). | |
1815 if ((opt_flags & OPT_WINONLY) | |
1816 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) | |
1817 goto skip; | |
1818 | |
1819 // Skip all options that are window-local (used for :vimgrep). | |
1820 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 | |
1821 && options[opt_idx].var == VAR_WIN) | |
1822 goto skip; | |
1823 | |
1824 // Disallow changing some options from modelines. | |
1825 if (opt_flags & OPT_MODELINE) | |
1826 { | |
1827 if (flags & (P_SECURE | P_NO_ML)) | |
1828 { | |
1829 errmsg = e_not_allowed_in_modeline; | |
1830 goto skip; | |
1831 } | |
1832 if ((flags & P_MLE) && !p_mle) | |
1833 { | |
1834 errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; | |
1835 goto skip; | |
1836 } | |
1837 #ifdef FEAT_DIFF | |
1838 // In diff mode some options are overruled. This avoids that | |
1839 // 'foldmethod' becomes "marker" instead of "diff" and that | |
1840 // "wrap" gets set. | |
1841 if (curwin->w_p_diff | |
1842 && opt_idx >= 0 // shut up coverity warning | |
1843 && ( | |
1844 #ifdef FEAT_FOLDING | |
1845 options[opt_idx].indir == PV_FDM || | |
1846 #endif | |
1847 options[opt_idx].indir == PV_WRAP)) | |
1848 goto skip; | |
1849 #endif | |
1850 } | |
1851 | |
1852 #ifdef HAVE_SANDBOX | |
1853 // Disallow changing some options in the sandbox | |
1854 if (sandbox != 0 && (flags & P_SECURE)) | |
1855 { | |
1856 errmsg = e_not_allowed_in_sandbox; | |
1857 goto skip; | |
1858 } | |
1859 #endif | |
1860 | |
1861 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) | |
1862 { | |
1863 arg += len; | |
1864 cp_val = p_cp; | |
1865 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') | |
1866 { | |
1867 if (arg[3] == 'm') // "opt&vim": set to Vim default | |
1868 { | |
1869 cp_val = FALSE; | |
1870 arg += 3; | |
1871 } | |
1872 else // "opt&vi": set to Vi default | |
1873 { | |
1874 cp_val = TRUE; | |
1875 arg += 2; | |
1876 } | |
1877 } | |
1878 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL | |
1879 && arg[1] != NUL && !VIM_ISWHITE(arg[1])) | |
1880 { | |
1881 errmsg = e_trailing_characters; | |
1882 goto skip; | |
1883 } | |
1884 } | |
1885 | |
1886 /* | |
1887 * allow '=' and ':' for historical reasons (MSDOS command.com | |
1888 * allows only one '=' character per "set" command line. grrr. (jw) | |
1889 */ | |
1890 if (nextchar == '?' | |
1891 || (prefix == 1 | |
1892 && vim_strchr((char_u *)"=:&<", nextchar) == NULL | |
1893 && !(flags & P_BOOL))) | |
1894 { | |
1895 /* | |
1896 * print value | |
1897 */ | |
1898 if (*did_show) | |
1899 msg_putchar('\n'); // cursor below last one | |
1900 else | |
1901 { | |
1902 gotocmdline(TRUE); // cursor at status line | |
1903 *did_show = TRUE; // remember that we did a line | |
1904 } | |
1905 if (opt_idx >= 0) | |
1906 { | |
1907 showoneopt(&options[opt_idx], opt_flags); | |
1908 #ifdef FEAT_EVAL | |
1909 if (p_verbose > 0) | |
1910 { | |
1911 // Mention where the option was last set. | |
1912 if (varp == options[opt_idx].var) | |
1913 last_set_msg(options[opt_idx].script_ctx); | |
1914 else if ((int)options[opt_idx].indir & PV_WIN) | |
1915 last_set_msg(curwin->w_p_script_ctx[ | |
1916 (int)options[opt_idx].indir & PV_MASK]); | |
1917 else if ((int)options[opt_idx].indir & PV_BUF) | |
1918 last_set_msg(curbuf->b_p_script_ctx[ | |
1919 (int)options[opt_idx].indir & PV_MASK]); | |
1920 } | |
1921 #endif | |
1922 } | |
1923 else | |
1924 { | |
1925 char_u *p; | |
1926 | |
1927 p = find_termcode(key_name); | |
1928 if (p == NULL) | |
1929 { | |
1930 errmsg = e_key_code_not_set; | |
1931 goto skip; | |
1932 } | |
1933 else | |
1934 (void)show_one_termcode(key_name, p, TRUE); | |
1935 } | |
1936 if (nextchar != '?' | |
1937 && nextchar != NUL && !VIM_ISWHITE(afterchar)) | |
1938 errmsg = e_trailing_characters; | |
1939 } | |
1940 else | |
1941 { | |
1942 int value_checked = FALSE; | |
1943 | |
1944 if (flags & P_BOOL) // boolean | |
1945 { | |
1946 if (nextchar == '=' || nextchar == ':') | |
1947 { | |
1948 errmsg = e_invalid_argument; | |
1949 goto skip; | |
1950 } | |
1951 | |
1952 /* | |
1953 * ":set opt!": invert | |
1954 * ":set opt&": reset to default value | |
1955 * ":set opt<": reset to global value | |
1956 */ | |
1957 if (nextchar == '!') | |
1958 value = *(int *)(varp) ^ 1; | |
1959 else if (nextchar == '&') | |
1960 value = (int)(long)(long_i)options[opt_idx].def_val[ | |
1961 ((flags & P_VI_DEF) || cp_val) | |
1962 ? VI_DEFAULT : VIM_DEFAULT]; | |
1963 else if (nextchar == '<') | |
1964 { | |
1965 // For 'autoread' -1 means to use global value. | |
1966 if ((int *)varp == &curbuf->b_p_ar | |
1967 && opt_flags == OPT_LOCAL) | |
1968 value = -1; | |
1969 else | |
1970 value = *(int *)get_varp_scope(&(options[opt_idx]), | |
1971 OPT_GLOBAL); | |
1972 } | |
1973 else | |
1974 { | |
1975 /* | |
1976 * ":set invopt": invert | |
1977 * ":set opt" or ":set noopt": set or reset | |
1978 */ | |
1979 if (nextchar != NUL && !VIM_ISWHITE(afterchar)) | |
1980 { | |
1981 errmsg = e_trailing_characters; | |
1982 goto skip; | |
1983 } | |
1984 if (prefix == 2) // inv | |
1985 value = *(int *)(varp) ^ 1; | |
1986 else | |
1987 value = prefix; | |
1988 } | |
1989 | |
1990 errmsg = set_bool_option(opt_idx, varp, (int)value, | |
1991 opt_flags); | |
1992 } | |
1993 else // numeric or string | |
1994 { | |
1995 if (vim_strchr((char_u *)"=:&<", nextchar) == NULL | |
1996 || prefix != 1) | |
1997 { | |
1998 errmsg = e_invalid_argument; | |
1999 goto skip; | |
2000 } | |
2001 | |
2002 if (flags & P_NUM) // numeric | |
2003 { | |
2004 /* | |
2005 * Different ways to set a number option: | |
2006 * & set to default value | |
2007 * < set to global value | |
2008 * <xx> accept special key codes for 'wildchar' | |
2009 * c accept any non-digit for 'wildchar' | |
2010 * [-]0-9 set number | |
2011 * other error | |
2012 */ | |
2013 ++arg; | |
2014 if (nextchar == '&') | |
2015 value = (long)(long_i)options[opt_idx].def_val[ | |
2016 ((flags & P_VI_DEF) || cp_val) | |
2017 ? VI_DEFAULT : VIM_DEFAULT]; | |
2018 else if (nextchar == '<') | |
2019 { | |
2020 // For 'undolevels' NO_LOCAL_UNDOLEVEL means to | |
2021 // use the global value. | |
2022 if ((long *)varp == &curbuf->b_p_ul | |
2023 && opt_flags == OPT_LOCAL) | |
2024 value = NO_LOCAL_UNDOLEVEL; | |
2025 else | |
2026 value = *(long *)get_varp_scope( | |
2027 &(options[opt_idx]), OPT_GLOBAL); | |
2028 } | |
2029 else if (((long *)varp == &p_wc | |
2030 || (long *)varp == &p_wcm) | |
2031 && (*arg == '<' | |
2032 || *arg == '^' | |
2033 || (*arg != NUL | |
2034 && (!arg[1] || VIM_ISWHITE(arg[1])) | |
2035 && !VIM_ISDIGIT(*arg)))) | |
2036 { | |
2037 value = string_to_key(arg, FALSE); | |
2038 if (value == 0 && (long *)varp != &p_wcm) | |
2039 { | |
2040 errmsg = e_invalid_argument; | |
2041 goto skip; | |
2042 } | |
2043 } | |
2044 else if (*arg == '-' || VIM_ISDIGIT(*arg)) | |
2045 { | |
2046 // Allow negative (for 'undolevels'), octal and | |
2047 // hex numbers. | |
2048 vim_str2nr(arg, NULL, &i, STR2NR_ALL, | |
2049 &value, NULL, 0, TRUE); | |
2050 if (i == 0 || (arg[i] != NUL | |
2051 && !VIM_ISWHITE(arg[i]))) | |
2052 { | |
2053 errmsg = e_number_required_after_equal; | |
2054 goto skip; | |
2055 } | |
2056 } | |
2057 else | |
2058 { | |
2059 errmsg = e_number_required_after_equal; | |
2060 goto skip; | |
2061 } | |
2062 | |
2063 if (op == OP_ADDING) | |
2064 value = *(long *)varp + value; | |
2065 else if (op == OP_PREPENDING) | |
2066 value = *(long *)varp * value; | |
2067 else if (op == OP_REMOVING) | |
2068 value = *(long *)varp - value; | |
2069 errmsg = set_num_option(opt_idx, varp, value, | |
2070 errbuf, errbuflen, opt_flags); | |
2071 } | |
2072 else if (opt_idx >= 0) // string | |
2073 { | |
2074 if (do_set_string(opt_idx, opt_flags, &arg, nextchar, | |
2075 op, flags, cp_val, varp, errbuf, | |
2076 &value_checked, &errmsg) == FAIL) | |
2077 { | |
2078 if (errmsg != NULL) | |
2079 goto skip; | |
2080 *stopopteval = TRUE; | |
2081 goto skip; | |
2082 } | |
2083 } | |
2084 else // key code option | |
2085 { | |
2086 char_u *p; | |
2087 | |
2088 if (nextchar == '&') | |
2089 { | |
2090 if (add_termcap_entry(key_name, TRUE) == FAIL) | |
2091 errmsg = e_not_found_in_termcap; | |
2092 } | |
2093 else | |
2094 { | |
2095 ++arg; // jump to after the '=' or ':' | |
2096 for (p = arg; *p && !VIM_ISWHITE(*p); ++p) | |
2097 if (*p == '\\' && p[1] != NUL) | |
2098 ++p; | |
2099 nextchar = *p; | |
2100 *p = NUL; | |
2101 add_termcode(key_name, arg, FALSE); | |
2102 *p = nextchar; | |
2103 } | |
2104 if (full_screen) | |
2105 ttest(FALSE); | |
2106 redraw_all_later(UPD_CLEAR); | |
2107 } | |
2108 } | |
2109 | |
2110 if (opt_idx >= 0) | |
2111 did_set_option( | |
2112 opt_idx, opt_flags, op == OP_NONE, value_checked); | |
2113 } | |
2114 | |
2115 skip: | |
2116 *argp = arg; | |
2117 return errmsg; | |
2118 } | |
2119 | |
2120 /* | |
1636 * Parse 'arg' for option settings. | 2121 * Parse 'arg' for option settings. |
1637 * | 2122 * |
1638 * 'arg' may be IObuff, but only when no errors can be present and option | 2123 * 'arg' may be IObuff, but only when no errors can be present and option |
1639 * does not need to be expanded with option_expand(). | 2124 * does not need to be expanded with option_expand(). |
1640 * "opt_flags": | 2125 * "opt_flags": |
1644 * OPT_MODELINE for a modeline | 2129 * OPT_MODELINE for a modeline |
1645 * OPT_WINONLY to only set window-local options | 2130 * OPT_WINONLY to only set window-local options |
1646 * OPT_NOWIN to skip setting window-local options | 2131 * OPT_NOWIN to skip setting window-local options |
1647 * OPT_ONECOLUMN do not use multiple columns | 2132 * OPT_ONECOLUMN do not use multiple columns |
1648 * | 2133 * |
1649 * returns FAIL if an error is detected, OK otherwise | 2134 * Returns FAIL if an error is detected, OK otherwise. |
1650 */ | 2135 */ |
1651 int | 2136 int |
1652 do_set( | 2137 do_set( |
1653 char_u *arg_start, // option string (may be written to!) | 2138 char_u *arg_start, // option string (may be written to!) |
1654 int opt_flags) | 2139 int opt_flags) |
1655 { | 2140 { |
1656 char_u *arg = arg_start; | 2141 char_u *arg = arg_start; |
1657 int opt_idx; | |
1658 char *errmsg; | |
1659 char errbuf[80]; | |
1660 char_u *startarg; | |
1661 int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name | |
1662 int nextchar; // next non-white char after option name | |
1663 int afterchar; // character just after option name | |
1664 int len; | |
1665 int i; | 2142 int i; |
1666 varnumber_T value; | |
1667 int key; | |
1668 long_u flags; // flags for current option | |
1669 char_u *varp = NULL; // pointer to variable for current option | |
1670 int did_show = FALSE; // already showed one value | 2143 int did_show = FALSE; // already showed one value |
1671 set_op_T op = 0; | |
1672 int cp_val = 0; | |
1673 char_u key_name[2]; | |
1674 | 2144 |
1675 if (*arg == NUL) | 2145 if (*arg == NUL) |
1676 { | 2146 { |
1677 showoptions(0, opt_flags); | 2147 showoptions(0, opt_flags); |
1678 did_show = TRUE; | 2148 did_show = TRUE; |
1679 goto theend; | 2149 goto theend; |
1680 } | 2150 } |
1681 | 2151 |
1682 while (*arg != NUL) // loop to process all options | 2152 while (*arg != NUL) // loop to process all options |
1683 { | 2153 { |
1684 errmsg = NULL; | |
1685 startarg = arg; // remember for error message | |
1686 | |
1687 if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) | 2154 if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) |
1688 && !(opt_flags & OPT_MODELINE)) | 2155 && !(opt_flags & OPT_MODELINE)) |
1689 { | 2156 { |
1690 /* | 2157 /* |
1691 * ":set all" show all options. | 2158 * ":set all" show all options. |
1714 did_show = TRUE; | 2181 did_show = TRUE; |
1715 arg += 7; | 2182 arg += 7; |
1716 } | 2183 } |
1717 else | 2184 else |
1718 { | 2185 { |
1719 prefix = 1; | 2186 int stopopteval = FALSE; |
1720 if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0) | 2187 char *errmsg = NULL; |
1721 { | 2188 char errbuf[80]; |
1722 prefix = 0; | 2189 char_u *startarg = arg; |
1723 arg += 2; | 2190 |
1724 } | 2191 errmsg = do_set_option(opt_flags, &arg, arg_start, &startarg, |
1725 else if (STRNCMP(arg, "inv", 3) == 0) | 2192 &did_show, &stopopteval, errbuf, |
1726 { | 2193 sizeof(errbuf)); |
1727 prefix = 2; | 2194 if (stopopteval) |
1728 arg += 3; | 2195 break; |
1729 } | 2196 |
1730 | |
1731 // find end of name | |
1732 key = 0; | |
1733 if (*arg == '<') | |
1734 { | |
1735 opt_idx = -1; | |
1736 // look out for <t_>;> | |
1737 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) | |
1738 len = 5; | |
1739 else | |
1740 { | |
1741 len = 1; | |
1742 while (arg[len] != NUL && arg[len] != '>') | |
1743 ++len; | |
1744 } | |
1745 if (arg[len] != '>') | |
1746 { | |
1747 errmsg = e_invalid_argument; | |
1748 goto skip; | |
1749 } | |
1750 arg[len] = NUL; // put NUL after name | |
1751 if (arg[1] == 't' && arg[2] == '_') // could be term code | |
1752 opt_idx = findoption(arg + 1); | |
1753 arg[len++] = '>'; // restore '>' | |
1754 if (opt_idx == -1) | |
1755 key = find_key_option(arg + 1, TRUE); | |
1756 } | |
1757 else | |
1758 { | |
1759 len = 0; | |
1760 /* | |
1761 * The two characters after "t_" may not be alphanumeric. | |
1762 */ | |
1763 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) | |
1764 len = 4; | |
1765 else | |
1766 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') | |
1767 ++len; | |
1768 nextchar = arg[len]; | |
1769 arg[len] = NUL; // put NUL after name | |
1770 opt_idx = findoption(arg); | |
1771 arg[len] = nextchar; // restore nextchar | |
1772 if (opt_idx == -1) | |
1773 key = find_key_option(arg, FALSE); | |
1774 } | |
1775 | |
1776 // remember character after option name | |
1777 afterchar = arg[len]; | |
1778 | |
1779 if (in_vim9script()) | |
1780 { | |
1781 char_u *p = skipwhite(arg + len); | |
1782 | |
1783 // disallow white space before =val, +=val, -=val, ^=val | |
1784 if (p > arg + len && (p[0] == '=' | |
1785 || (vim_strchr((char_u *)"+-^", p[0]) != NULL | |
1786 && p[1] == '='))) | |
1787 { | |
1788 errmsg = e_no_white_space_allowed_between_option_and; | |
1789 arg = p; | |
1790 startarg = p; | |
1791 goto skip; | |
1792 } | |
1793 } | |
1794 else | |
1795 // skip white space, allow ":set ai ?", ":set hlsearch !" | |
1796 while (VIM_ISWHITE(arg[len])) | |
1797 ++len; | |
1798 | |
1799 op = OP_NONE; | |
1800 if (arg[len] != NUL && arg[len + 1] == '=') | |
1801 { | |
1802 if (arg[len] == '+') | |
1803 { | |
1804 op = OP_ADDING; // "+=" | |
1805 ++len; | |
1806 } | |
1807 else if (arg[len] == '^') | |
1808 { | |
1809 op = OP_PREPENDING; // "^=" | |
1810 ++len; | |
1811 } | |
1812 else if (arg[len] == '-') | |
1813 { | |
1814 op = OP_REMOVING; // "-=" | |
1815 ++len; | |
1816 } | |
1817 } | |
1818 nextchar = arg[len]; | |
1819 | |
1820 if (opt_idx == -1 && key == 0) // found a mismatch: skip | |
1821 { | |
1822 if (in_vim9script() && arg > arg_start | |
1823 && vim_strchr((char_u *)"!&<", *arg) != NULL) | |
1824 errmsg = e_no_white_space_allowed_between_option_and; | |
1825 else | |
1826 errmsg = e_unknown_option; | |
1827 goto skip; | |
1828 } | |
1829 | |
1830 if (opt_idx >= 0) | |
1831 { | |
1832 if (options[opt_idx].var == NULL) // hidden option: skip | |
1833 { | |
1834 // Only give an error message when requesting the value of | |
1835 // a hidden option, ignore setting it. | |
1836 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL | |
1837 && (!(options[opt_idx].flags & P_BOOL) | |
1838 || nextchar == '?')) | |
1839 errmsg = e_option_not_supported; | |
1840 goto skip; | |
1841 } | |
1842 | |
1843 flags = options[opt_idx].flags; | |
1844 varp = get_varp_scope(&(options[opt_idx]), opt_flags); | |
1845 } | |
1846 else | |
1847 { | |
1848 flags = P_STRING; | |
1849 if (key < 0) | |
1850 { | |
1851 key_name[0] = KEY2TERMCAP0(key); | |
1852 key_name[1] = KEY2TERMCAP1(key); | |
1853 } | |
1854 else | |
1855 { | |
1856 key_name[0] = KS_KEY; | |
1857 key_name[1] = (key & 0xff); | |
1858 } | |
1859 } | |
1860 | |
1861 // Skip all options that are not window-local (used when showing | |
1862 // an already loaded buffer in a window). | |
1863 if ((opt_flags & OPT_WINONLY) | |
1864 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) | |
1865 goto skip; | |
1866 | |
1867 // Skip all options that are window-local (used for :vimgrep). | |
1868 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 | |
1869 && options[opt_idx].var == VAR_WIN) | |
1870 goto skip; | |
1871 | |
1872 // Disallow changing some options from modelines. | |
1873 if (opt_flags & OPT_MODELINE) | |
1874 { | |
1875 if (flags & (P_SECURE | P_NO_ML)) | |
1876 { | |
1877 errmsg = e_not_allowed_in_modeline; | |
1878 goto skip; | |
1879 } | |
1880 if ((flags & P_MLE) && !p_mle) | |
1881 { | |
1882 errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; | |
1883 goto skip; | |
1884 } | |
1885 #ifdef FEAT_DIFF | |
1886 // In diff mode some options are overruled. This avoids that | |
1887 // 'foldmethod' becomes "marker" instead of "diff" and that | |
1888 // "wrap" gets set. | |
1889 if (curwin->w_p_diff | |
1890 && opt_idx >= 0 // shut up coverity warning | |
1891 && ( | |
1892 #ifdef FEAT_FOLDING | |
1893 options[opt_idx].indir == PV_FDM || | |
1894 #endif | |
1895 options[opt_idx].indir == PV_WRAP)) | |
1896 goto skip; | |
1897 #endif | |
1898 } | |
1899 | |
1900 #ifdef HAVE_SANDBOX | |
1901 // Disallow changing some options in the sandbox | |
1902 if (sandbox != 0 && (flags & P_SECURE)) | |
1903 { | |
1904 errmsg = e_not_allowed_in_sandbox; | |
1905 goto skip; | |
1906 } | |
1907 #endif | |
1908 | |
1909 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) | |
1910 { | |
1911 arg += len; | |
1912 cp_val = p_cp; | |
1913 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') | |
1914 { | |
1915 if (arg[3] == 'm') // "opt&vim": set to Vim default | |
1916 { | |
1917 cp_val = FALSE; | |
1918 arg += 3; | |
1919 } | |
1920 else // "opt&vi": set to Vi default | |
1921 { | |
1922 cp_val = TRUE; | |
1923 arg += 2; | |
1924 } | |
1925 } | |
1926 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL | |
1927 && arg[1] != NUL && !VIM_ISWHITE(arg[1])) | |
1928 { | |
1929 errmsg = e_trailing_characters; | |
1930 goto skip; | |
1931 } | |
1932 } | |
1933 | |
1934 /* | |
1935 * allow '=' and ':' for historical reasons (MSDOS command.com | |
1936 * allows only one '=' character per "set" command line. grrr. (jw) | |
1937 */ | |
1938 if (nextchar == '?' | |
1939 || (prefix == 1 | |
1940 && vim_strchr((char_u *)"=:&<", nextchar) == NULL | |
1941 && !(flags & P_BOOL))) | |
1942 { | |
1943 /* | |
1944 * print value | |
1945 */ | |
1946 if (did_show) | |
1947 msg_putchar('\n'); // cursor below last one | |
1948 else | |
1949 { | |
1950 gotocmdline(TRUE); // cursor at status line | |
1951 did_show = TRUE; // remember that we did a line | |
1952 } | |
1953 if (opt_idx >= 0) | |
1954 { | |
1955 showoneopt(&options[opt_idx], opt_flags); | |
1956 #ifdef FEAT_EVAL | |
1957 if (p_verbose > 0) | |
1958 { | |
1959 // Mention where the option was last set. | |
1960 if (varp == options[opt_idx].var) | |
1961 last_set_msg(options[opt_idx].script_ctx); | |
1962 else if ((int)options[opt_idx].indir & PV_WIN) | |
1963 last_set_msg(curwin->w_p_script_ctx[ | |
1964 (int)options[opt_idx].indir & PV_MASK]); | |
1965 else if ((int)options[opt_idx].indir & PV_BUF) | |
1966 last_set_msg(curbuf->b_p_script_ctx[ | |
1967 (int)options[opt_idx].indir & PV_MASK]); | |
1968 } | |
1969 #endif | |
1970 } | |
1971 else | |
1972 { | |
1973 char_u *p; | |
1974 | |
1975 p = find_termcode(key_name); | |
1976 if (p == NULL) | |
1977 { | |
1978 errmsg = e_key_code_not_set; | |
1979 goto skip; | |
1980 } | |
1981 else | |
1982 (void)show_one_termcode(key_name, p, TRUE); | |
1983 } | |
1984 if (nextchar != '?' | |
1985 && nextchar != NUL && !VIM_ISWHITE(afterchar)) | |
1986 errmsg = e_trailing_characters; | |
1987 } | |
1988 else | |
1989 { | |
1990 int value_checked = FALSE; | |
1991 | |
1992 if (flags & P_BOOL) // boolean | |
1993 { | |
1994 if (nextchar == '=' || nextchar == ':') | |
1995 { | |
1996 errmsg = e_invalid_argument; | |
1997 goto skip; | |
1998 } | |
1999 | |
2000 /* | |
2001 * ":set opt!": invert | |
2002 * ":set opt&": reset to default value | |
2003 * ":set opt<": reset to global value | |
2004 */ | |
2005 if (nextchar == '!') | |
2006 value = *(int *)(varp) ^ 1; | |
2007 else if (nextchar == '&') | |
2008 value = (int)(long)(long_i)options[opt_idx].def_val[ | |
2009 ((flags & P_VI_DEF) || cp_val) | |
2010 ? VI_DEFAULT : VIM_DEFAULT]; | |
2011 else if (nextchar == '<') | |
2012 { | |
2013 // For 'autoread' -1 means to use global value. | |
2014 if ((int *)varp == &curbuf->b_p_ar | |
2015 && opt_flags == OPT_LOCAL) | |
2016 value = -1; | |
2017 else | |
2018 value = *(int *)get_varp_scope(&(options[opt_idx]), | |
2019 OPT_GLOBAL); | |
2020 } | |
2021 else | |
2022 { | |
2023 /* | |
2024 * ":set invopt": invert | |
2025 * ":set opt" or ":set noopt": set or reset | |
2026 */ | |
2027 if (nextchar != NUL && !VIM_ISWHITE(afterchar)) | |
2028 { | |
2029 errmsg = e_trailing_characters; | |
2030 goto skip; | |
2031 } | |
2032 if (prefix == 2) // inv | |
2033 value = *(int *)(varp) ^ 1; | |
2034 else | |
2035 value = prefix; | |
2036 } | |
2037 | |
2038 errmsg = set_bool_option(opt_idx, varp, (int)value, | |
2039 opt_flags); | |
2040 } | |
2041 else // numeric or string | |
2042 { | |
2043 if (vim_strchr((char_u *)"=:&<", nextchar) == NULL | |
2044 || prefix != 1) | |
2045 { | |
2046 errmsg = e_invalid_argument; | |
2047 goto skip; | |
2048 } | |
2049 | |
2050 if (flags & P_NUM) // numeric | |
2051 { | |
2052 /* | |
2053 * Different ways to set a number option: | |
2054 * & set to default value | |
2055 * < set to global value | |
2056 * <xx> accept special key codes for 'wildchar' | |
2057 * c accept any non-digit for 'wildchar' | |
2058 * [-]0-9 set number | |
2059 * other error | |
2060 */ | |
2061 ++arg; | |
2062 if (nextchar == '&') | |
2063 value = (long)(long_i)options[opt_idx].def_val[ | |
2064 ((flags & P_VI_DEF) || cp_val) | |
2065 ? VI_DEFAULT : VIM_DEFAULT]; | |
2066 else if (nextchar == '<') | |
2067 { | |
2068 // For 'undolevels' NO_LOCAL_UNDOLEVEL means to | |
2069 // use the global value. | |
2070 if ((long *)varp == &curbuf->b_p_ul | |
2071 && opt_flags == OPT_LOCAL) | |
2072 value = NO_LOCAL_UNDOLEVEL; | |
2073 else | |
2074 value = *(long *)get_varp_scope( | |
2075 &(options[opt_idx]), OPT_GLOBAL); | |
2076 } | |
2077 else if (((long *)varp == &p_wc | |
2078 || (long *)varp == &p_wcm) | |
2079 && (*arg == '<' | |
2080 || *arg == '^' | |
2081 || (*arg != NUL | |
2082 && (!arg[1] || VIM_ISWHITE(arg[1])) | |
2083 && !VIM_ISDIGIT(*arg)))) | |
2084 { | |
2085 value = string_to_key(arg, FALSE); | |
2086 if (value == 0 && (long *)varp != &p_wcm) | |
2087 { | |
2088 errmsg = e_invalid_argument; | |
2089 goto skip; | |
2090 } | |
2091 } | |
2092 else if (*arg == '-' || VIM_ISDIGIT(*arg)) | |
2093 { | |
2094 // Allow negative (for 'undolevels'), octal and | |
2095 // hex numbers. | |
2096 vim_str2nr(arg, NULL, &i, STR2NR_ALL, | |
2097 &value, NULL, 0, TRUE); | |
2098 if (i == 0 || (arg[i] != NUL | |
2099 && !VIM_ISWHITE(arg[i]))) | |
2100 { | |
2101 errmsg = e_number_required_after_equal; | |
2102 goto skip; | |
2103 } | |
2104 } | |
2105 else | |
2106 { | |
2107 errmsg = e_number_required_after_equal; | |
2108 goto skip; | |
2109 } | |
2110 | |
2111 if (op == OP_ADDING) | |
2112 value = *(long *)varp + value; | |
2113 else if (op == OP_PREPENDING) | |
2114 value = *(long *)varp * value; | |
2115 else if (op == OP_REMOVING) | |
2116 value = *(long *)varp - value; | |
2117 errmsg = set_num_option(opt_idx, varp, value, | |
2118 errbuf, sizeof(errbuf), opt_flags); | |
2119 } | |
2120 else if (opt_idx >= 0) // string | |
2121 { | |
2122 if (do_set_string(opt_idx, opt_flags, &arg, nextchar, | |
2123 op, flags, cp_val, varp, errbuf, | |
2124 &value_checked, &errmsg) == FAIL) | |
2125 { | |
2126 if (errmsg != NULL) | |
2127 goto skip; | |
2128 break; | |
2129 } | |
2130 } | |
2131 else // key code option | |
2132 { | |
2133 char_u *p; | |
2134 | |
2135 if (nextchar == '&') | |
2136 { | |
2137 if (add_termcap_entry(key_name, TRUE) == FAIL) | |
2138 errmsg = e_not_found_in_termcap; | |
2139 } | |
2140 else | |
2141 { | |
2142 ++arg; // jump to after the '=' or ':' | |
2143 for (p = arg; *p && !VIM_ISWHITE(*p); ++p) | |
2144 if (*p == '\\' && p[1] != NUL) | |
2145 ++p; | |
2146 nextchar = *p; | |
2147 *p = NUL; | |
2148 add_termcode(key_name, arg, FALSE); | |
2149 *p = nextchar; | |
2150 } | |
2151 if (full_screen) | |
2152 ttest(FALSE); | |
2153 redraw_all_later(UPD_CLEAR); | |
2154 } | |
2155 } | |
2156 | |
2157 if (opt_idx >= 0) | |
2158 did_set_option( | |
2159 opt_idx, opt_flags, op == OP_NONE, value_checked); | |
2160 } | |
2161 | |
2162 skip: | |
2163 /* | 2197 /* |
2164 * Advance to next argument. | 2198 * Advance to next argument. |
2165 * - skip until a blank found, taking care of backslashes | 2199 * - skip until a blank found, taking care of backslashes |
2166 * - skip blanks | 2200 * - skip blanks |
2167 * - skip one "=val" argument (for hidden options ":set gfn =xx") | 2201 * - skip one "=val" argument (for hidden options ":set gfn =xx") |
2173 ++arg; | 2207 ++arg; |
2174 arg = skipwhite(arg); | 2208 arg = skipwhite(arg); |
2175 if (*arg != '=') | 2209 if (*arg != '=') |
2176 break; | 2210 break; |
2177 } | 2211 } |
2178 } | 2212 |
2179 | 2213 if (errmsg != NULL) |
2180 if (errmsg != NULL) | 2214 { |
2181 { | 2215 vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1); |
2182 vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1); | 2216 i = (int)STRLEN(IObuff) + 2; |
2183 i = (int)STRLEN(IObuff) + 2; | 2217 if (i + (arg - startarg) < IOSIZE) |
2184 if (i + (arg - startarg) < IOSIZE) | 2218 { |
2185 { | 2219 // append the argument with the error |
2186 // append the argument with the error | 2220 STRCAT(IObuff, ": "); |
2187 STRCAT(IObuff, ": "); | 2221 mch_memmove(IObuff + i, startarg, (arg - startarg)); |
2188 mch_memmove(IObuff + i, startarg, (arg - startarg)); | 2222 IObuff[i + (arg - startarg)] = NUL; |
2189 IObuff[i + (arg - startarg)] = NUL; | 2223 } |
2190 } | 2224 // make sure all characters are printable |
2191 // make sure all characters are printable | 2225 trans_characters(IObuff, IOSIZE); |
2192 trans_characters(IObuff, IOSIZE); | 2226 |
2193 | 2227 ++no_wait_return; // wait_return() done later |
2194 ++no_wait_return; // wait_return() done later | 2228 emsg((char *)IObuff); // show error highlighted |
2195 emsg((char *)IObuff); // show error highlighted | 2229 --no_wait_return; |
2196 --no_wait_return; | 2230 |
2197 | 2231 return FAIL; |
2198 return FAIL; | 2232 } |
2199 } | 2233 } |
2200 | 2234 |
2201 arg = skipwhite(arg); | 2235 arg = skipwhite(arg); |
2202 } | 2236 } |
2203 | 2237 |