Mercurial > vim
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. |