comparison src/ex_docmd.c @ 14505:3f1a17863b73 v8.1.0266

patch 8.1.0266: parsing Ex address range is not a separate function commit https://github.com/vim/vim/commit/ee8415bc5998792fab6f4dcf289d027856e05b89 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Aug 10 23:13:12 2018 +0200 patch 8.1.0266: parsing Ex address range is not a separate function Problem: Parsing Ex address range is not a separate function. Solution: Refactor do_one_cmd() to separate address parsing.
author Christian Brabandt <cb@256bit.org>
date Fri, 10 Aug 2018 23:15:04 +0200
parents 3375a8cbb442
children 4caa51067cb8
comparison
equal deleted inserted replaced
14504:89b3aabf0a95 14505:3f1a17863b73
1717 int did_sandbox = FALSE; 1717 int did_sandbox = FALSE;
1718 #endif 1718 #endif
1719 cmdmod_T save_cmdmod; 1719 cmdmod_T save_cmdmod;
1720 int ni; /* set when Not Implemented */ 1720 int ni; /* set when Not Implemented */
1721 char_u *cmd; 1721 char_u *cmd;
1722 int address_count = 1;
1723 1722
1724 vim_memset(&ea, 0, sizeof(ea)); 1723 vim_memset(&ea, 0, sizeof(ea));
1725 ea.line1 = 1; 1724 ea.line1 = 1;
1726 ea.line2 = 1; 1725 ea.line2 = 1;
1727 #ifdef FEAT_EVAL 1726 #ifdef FEAT_EVAL
2043 /* :wincmd range depends on the argument. */ 2042 /* :wincmd range depends on the argument. */
2044 if (ea.cmdidx == CMD_wincmd && p != NULL) 2043 if (ea.cmdidx == CMD_wincmd && p != NULL)
2045 get_wincmd_addr_type(skipwhite(p), &ea); 2044 get_wincmd_addr_type(skipwhite(p), &ea);
2046 } 2045 }
2047 2046
2048 /* repeat for all ',' or ';' separated addresses */
2049 ea.cmd = cmd; 2047 ea.cmd = cmd;
2050 for (;;) 2048 if (parse_cmd_address(&ea, &errormsg) == FAIL)
2051 { 2049 goto doend;
2052 ea.line1 = ea.line2;
2053 switch (ea.addr_type)
2054 {
2055 case ADDR_LINES:
2056 /* default is current line number */
2057 ea.line2 = curwin->w_cursor.lnum;
2058 break;
2059 case ADDR_WINDOWS:
2060 ea.line2 = CURRENT_WIN_NR;
2061 break;
2062 case ADDR_ARGUMENTS:
2063 ea.line2 = curwin->w_arg_idx + 1;
2064 if (ea.line2 > ARGCOUNT)
2065 ea.line2 = ARGCOUNT;
2066 break;
2067 case ADDR_LOADED_BUFFERS:
2068 case ADDR_BUFFERS:
2069 ea.line2 = curbuf->b_fnum;
2070 break;
2071 case ADDR_TABS:
2072 ea.line2 = CURRENT_TAB_NR;
2073 break;
2074 case ADDR_TABS_RELATIVE:
2075 ea.line2 = 1;
2076 break;
2077 #ifdef FEAT_QUICKFIX
2078 case ADDR_QUICKFIX:
2079 ea.line2 = qf_get_cur_valid_idx(&ea);
2080 break;
2081 #endif
2082 }
2083 ea.cmd = skipwhite(ea.cmd);
2084 lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip,
2085 ea.addr_count == 0, address_count++);
2086 if (ea.cmd == NULL) /* error detected */
2087 goto doend;
2088 if (lnum == MAXLNUM)
2089 {
2090 if (*ea.cmd == '%') /* '%' - all lines */
2091 {
2092 ++ea.cmd;
2093 switch (ea.addr_type)
2094 {
2095 case ADDR_LINES:
2096 ea.line1 = 1;
2097 ea.line2 = curbuf->b_ml.ml_line_count;
2098 break;
2099 case ADDR_LOADED_BUFFERS:
2100 {
2101 buf_T *buf = firstbuf;
2102
2103 while (buf->b_next != NULL
2104 && buf->b_ml.ml_mfp == NULL)
2105 buf = buf->b_next;
2106 ea.line1 = buf->b_fnum;
2107 buf = lastbuf;
2108 while (buf->b_prev != NULL
2109 && buf->b_ml.ml_mfp == NULL)
2110 buf = buf->b_prev;
2111 ea.line2 = buf->b_fnum;
2112 break;
2113 }
2114 case ADDR_BUFFERS:
2115 ea.line1 = firstbuf->b_fnum;
2116 ea.line2 = lastbuf->b_fnum;
2117 break;
2118 case ADDR_WINDOWS:
2119 case ADDR_TABS:
2120 if (IS_USER_CMDIDX(ea.cmdidx))
2121 {
2122 ea.line1 = 1;
2123 ea.line2 = ea.addr_type == ADDR_WINDOWS
2124 ? LAST_WIN_NR : LAST_TAB_NR;
2125 }
2126 else
2127 {
2128 /* there is no Vim command which uses '%' and
2129 * ADDR_WINDOWS or ADDR_TABS */
2130 errormsg = (char_u *)_(e_invrange);
2131 goto doend;
2132 }
2133 break;
2134 case ADDR_TABS_RELATIVE:
2135 errormsg = (char_u *)_(e_invrange);
2136 goto doend;
2137 break;
2138 case ADDR_ARGUMENTS:
2139 if (ARGCOUNT == 0)
2140 ea.line1 = ea.line2 = 0;
2141 else
2142 {
2143 ea.line1 = 1;
2144 ea.line2 = ARGCOUNT;
2145 }
2146 break;
2147 #ifdef FEAT_QUICKFIX
2148 case ADDR_QUICKFIX:
2149 ea.line1 = 1;
2150 ea.line2 = qf_get_size(&ea);
2151 if (ea.line2 == 0)
2152 ea.line2 = 1;
2153 break;
2154 #endif
2155 }
2156 ++ea.addr_count;
2157 }
2158 /* '*' - visual area */
2159 else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
2160 {
2161 pos_T *fp;
2162
2163 if (ea.addr_type != ADDR_LINES)
2164 {
2165 errormsg = (char_u *)_(e_invrange);
2166 goto doend;
2167 }
2168
2169 ++ea.cmd;
2170 if (!ea.skip)
2171 {
2172 fp = getmark('<', FALSE);
2173 if (check_mark(fp) == FAIL)
2174 goto doend;
2175 ea.line1 = fp->lnum;
2176 fp = getmark('>', FALSE);
2177 if (check_mark(fp) == FAIL)
2178 goto doend;
2179 ea.line2 = fp->lnum;
2180 ++ea.addr_count;
2181 }
2182 }
2183 }
2184 else
2185 ea.line2 = lnum;
2186 ea.addr_count++;
2187
2188 if (*ea.cmd == ';')
2189 {
2190 if (!ea.skip)
2191 {
2192 curwin->w_cursor.lnum = ea.line2;
2193 /* don't leave the cursor on an illegal line or column */
2194 check_cursor();
2195 }
2196 }
2197 else if (*ea.cmd != ',')
2198 break;
2199 ++ea.cmd;
2200 }
2201
2202 /* One address given: set start and end lines */
2203 if (ea.addr_count == 1)
2204 {
2205 ea.line1 = ea.line2;
2206 /* ... but only implicit: really no address given */
2207 if (lnum == MAXLNUM)
2208 ea.addr_count = 0;
2209 }
2210 2050
2211 /* 2051 /*
2212 * 5. Parse the command. 2052 * 5. Parse the command.
2213 */ 2053 */
2214 2054
2987 #if (_MSC_VER == 1200) 2827 #if (_MSC_VER == 1200)
2988 #pragma optimize( "", on ) 2828 #pragma optimize( "", on )
2989 #endif 2829 #endif
2990 2830
2991 /* 2831 /*
2832 * Parse the address range, if any, in "eap".
2833 * Return FAIL and set "errormsg" or return OK.
2834 */
2835 int
2836 parse_cmd_address(exarg_T *eap, char_u **errormsg)
2837 {
2838 int address_count = 1;
2839 linenr_T lnum;
2840
2841 // Repeat for all ',' or ';' separated addresses.
2842 for (;;)
2843 {
2844 eap->line1 = eap->line2;
2845 switch (eap->addr_type)
2846 {
2847 case ADDR_LINES:
2848 // default is current line number
2849 eap->line2 = curwin->w_cursor.lnum;
2850 break;
2851 case ADDR_WINDOWS:
2852 eap->line2 = CURRENT_WIN_NR;
2853 break;
2854 case ADDR_ARGUMENTS:
2855 eap->line2 = curwin->w_arg_idx + 1;
2856 if (eap->line2 > ARGCOUNT)
2857 eap->line2 = ARGCOUNT;
2858 break;
2859 case ADDR_LOADED_BUFFERS:
2860 case ADDR_BUFFERS:
2861 eap->line2 = curbuf->b_fnum;
2862 break;
2863 case ADDR_TABS:
2864 eap->line2 = CURRENT_TAB_NR;
2865 break;
2866 case ADDR_TABS_RELATIVE:
2867 eap->line2 = 1;
2868 break;
2869 #ifdef FEAT_QUICKFIX
2870 case ADDR_QUICKFIX:
2871 eap->line2 = qf_get_cur_valid_idx(eap);
2872 break;
2873 #endif
2874 }
2875 eap->cmd = skipwhite(eap->cmd);
2876 lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip,
2877 eap->addr_count == 0, address_count++);
2878 if (eap->cmd == NULL) // error detected
2879 return FAIL;
2880 if (lnum == MAXLNUM)
2881 {
2882 if (*eap->cmd == '%') // '%' - all lines
2883 {
2884 ++eap->cmd;
2885 switch (eap->addr_type)
2886 {
2887 case ADDR_LINES:
2888 eap->line1 = 1;
2889 eap->line2 = curbuf->b_ml.ml_line_count;
2890 break;
2891 case ADDR_LOADED_BUFFERS:
2892 {
2893 buf_T *buf = firstbuf;
2894
2895 while (buf->b_next != NULL
2896 && buf->b_ml.ml_mfp == NULL)
2897 buf = buf->b_next;
2898 eap->line1 = buf->b_fnum;
2899 buf = lastbuf;
2900 while (buf->b_prev != NULL
2901 && buf->b_ml.ml_mfp == NULL)
2902 buf = buf->b_prev;
2903 eap->line2 = buf->b_fnum;
2904 break;
2905 }
2906 case ADDR_BUFFERS:
2907 eap->line1 = firstbuf->b_fnum;
2908 eap->line2 = lastbuf->b_fnum;
2909 break;
2910 case ADDR_WINDOWS:
2911 case ADDR_TABS:
2912 if (IS_USER_CMDIDX(eap->cmdidx))
2913 {
2914 eap->line1 = 1;
2915 eap->line2 = eap->addr_type == ADDR_WINDOWS
2916 ? LAST_WIN_NR : LAST_TAB_NR;
2917 }
2918 else
2919 {
2920 // there is no Vim command which uses '%' and
2921 // ADDR_WINDOWS or ADDR_TABS
2922 *errormsg = (char_u *)_(e_invrange);
2923 return FAIL;
2924 }
2925 break;
2926 case ADDR_TABS_RELATIVE:
2927 *errormsg = (char_u *)_(e_invrange);
2928 return FAIL;
2929 case ADDR_ARGUMENTS:
2930 if (ARGCOUNT == 0)
2931 eap->line1 = eap->line2 = 0;
2932 else
2933 {
2934 eap->line1 = 1;
2935 eap->line2 = ARGCOUNT;
2936 }
2937 break;
2938 #ifdef FEAT_QUICKFIX
2939 case ADDR_QUICKFIX:
2940 eap->line1 = 1;
2941 eap->line2 = qf_get_size(eap);
2942 if (eap->line2 == 0)
2943 eap->line2 = 1;
2944 break;
2945 #endif
2946 }
2947 ++eap->addr_count;
2948 }
2949 else if (*eap->cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
2950 {
2951 pos_T *fp;
2952
2953 // '*' - visual area
2954 if (eap->addr_type != ADDR_LINES)
2955 {
2956 *errormsg = (char_u *)_(e_invrange);
2957 return FAIL;
2958 }
2959
2960 ++eap->cmd;
2961 if (!eap->skip)
2962 {
2963 fp = getmark('<', FALSE);
2964 if (check_mark(fp) == FAIL)
2965 return FAIL;
2966 eap->line1 = fp->lnum;
2967 fp = getmark('>', FALSE);
2968 if (check_mark(fp) == FAIL)
2969 return FAIL;
2970 eap->line2 = fp->lnum;
2971 ++eap->addr_count;
2972 }
2973 }
2974 }
2975 else
2976 eap->line2 = lnum;
2977 eap->addr_count++;
2978
2979 if (*eap->cmd == ';')
2980 {
2981 if (!eap->skip)
2982 {
2983 curwin->w_cursor.lnum = eap->line2;
2984 // don't leave the cursor on an illegal line or column
2985 check_cursor();
2986 }
2987 }
2988 else if (*eap->cmd != ',')
2989 break;
2990 ++eap->cmd;
2991 }
2992
2993 // One address given: set start and end lines.
2994 if (eap->addr_count == 1)
2995 {
2996 eap->line1 = eap->line2;
2997 // ... but only implicit: really no address given
2998 if (lnum == MAXLNUM)
2999 eap->addr_count = 0;
3000 }
3001 return OK;
3002 }
3003
3004 /*
2992 * Check for an Ex command with optional tail. 3005 * Check for an Ex command with optional tail.
2993 * If there is a match advance "pp" to the argument and return TRUE. 3006 * If there is a match advance "pp" to the argument and return TRUE.
2994 */ 3007 */
2995 int 3008 int
2996 checkforcmd( 3009 checkforcmd(
4290 } 4303 }
4291 return NULL; 4304 return NULL;
4292 } 4305 }
4293 4306
4294 /* 4307 /*
4295 * skip a range specifier of the form: addr [,addr] [;addr] .. 4308 * Skip a range specifier of the form: addr [,addr] [;addr] ..
4296 * 4309 *
4297 * Backslashed delimiters after / or ? will be skipped, and commands will 4310 * Backslashed delimiters after / or ? will be skipped, and commands will
4298 * not be expanded between /'s and ?'s or after "'". 4311 * not be expanded between /'s and ?'s or after "'".
4299 * 4312 *
4300 * Also skip white space and ":" characters. 4313 * Also skip white space and ":" characters.