Mercurial > vim
annotate src/ex_docmd.c @ 4213:0a3fab86f34d v7.3.858
updated for version 7.3.858
Problem: "gv" selects the wrong area after some operators.
Solution: Save and restore the type of selection. (Christian Brabandt)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 13 Mar 2013 19:02:41 +0100 |
parents | 4905e038b105 |
children | 23ce9a61bdc2 |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * | |
5 * Do ":help uganda" in Vim to read copying and usage conditions. | |
6 * Do ":help credits" in Vim to see a list of people who contributed. | |
7 * See README.txt for an overview of the Vim source code. | |
8 */ | |
9 | |
10 /* | |
11 * ex_docmd.c: functions for executing an Ex command line. | |
12 */ | |
13 | |
14 #include "vim.h" | |
15 | |
16 static int quitmore = 0; | |
17 static int ex_pressedreturn = FALSE; | |
18 #ifndef FEAT_PRINTER | |
19 # define ex_hardcopy ex_ni | |
20 #endif | |
21 | |
22 #ifdef FEAT_USR_CMDS | |
23 typedef struct ucmd | |
24 { | |
25 char_u *uc_name; /* The command name */ | |
26 long_u uc_argt; /* The argument type */ | |
27 char_u *uc_rep; /* The command's replacement string */ | |
28 long uc_def; /* The default value for a range/count */ | |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
29 int uc_compl; /* completion type */ |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
30 # ifdef FEAT_EVAL |
7 | 31 scid_T uc_scriptID; /* SID where the command was defined */ |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
32 # ifdef FEAT_CMDL_COMPL |
7 | 33 char_u *uc_compl_arg; /* completion argument if any */ |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
34 # endif |
7 | 35 # endif |
36 } ucmd_T; | |
37 | |
38 #define UC_BUFFER 1 /* -buffer: local to current buffer */ | |
39 | |
296 | 40 static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; |
7 | 41 |
42 #define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) | |
43 #define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) | |
44 | |
45 static void do_ucmd __ARGS((exarg_T *eap)); | |
46 static void ex_command __ARGS((exarg_T *eap)); | |
47 static void ex_delcommand __ARGS((exarg_T *eap)); | |
48 # ifdef FEAT_CMDL_COMPL | |
49 static char_u *get_user_command_name __ARGS((int idx)); | |
50 # endif | |
51 | |
52 #else | |
53 # define ex_command ex_ni | |
54 # define ex_comclear ex_ni | |
55 # define ex_delcommand ex_ni | |
56 #endif | |
57 | |
58 #ifdef FEAT_EVAL | |
944 | 59 static char_u *do_one_cmd __ARGS((char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie)); |
7 | 60 #else |
944 | 61 static char_u *do_one_cmd __ARGS((char_u **, int, char_u *(*fgetline)(int, void *, int), void *cookie)); |
7 | 62 static int if_level = 0; /* depth in :if */ |
63 #endif | |
3097 | 64 static void append_command __ARGS((char_u *cmd)); |
7 | 65 static char_u *find_command __ARGS((exarg_T *eap, int *full)); |
66 | |
67 static void ex_abbreviate __ARGS((exarg_T *eap)); | |
68 static void ex_map __ARGS((exarg_T *eap)); | |
69 static void ex_unmap __ARGS((exarg_T *eap)); | |
70 static void ex_mapclear __ARGS((exarg_T *eap)); | |
71 static void ex_abclear __ARGS((exarg_T *eap)); | |
72 #ifndef FEAT_MENU | |
73 # define ex_emenu ex_ni | |
74 # define ex_menu ex_ni | |
75 # define ex_menutranslate ex_ni | |
76 #endif | |
77 #ifdef FEAT_AUTOCMD | |
78 static void ex_autocmd __ARGS((exarg_T *eap)); | |
79 static void ex_doautocmd __ARGS((exarg_T *eap)); | |
80 #else | |
81 # define ex_autocmd ex_ni | |
82 # define ex_doautocmd ex_ni | |
83 # define ex_doautoall ex_ni | |
84 #endif | |
85 #ifdef FEAT_LISTCMDS | |
86 static void ex_bunload __ARGS((exarg_T *eap)); | |
87 static void ex_buffer __ARGS((exarg_T *eap)); | |
88 static void ex_bmodified __ARGS((exarg_T *eap)); | |
89 static void ex_bnext __ARGS((exarg_T *eap)); | |
90 static void ex_bprevious __ARGS((exarg_T *eap)); | |
91 static void ex_brewind __ARGS((exarg_T *eap)); | |
92 static void ex_blast __ARGS((exarg_T *eap)); | |
93 #else | |
94 # define ex_bunload ex_ni | |
95 # define ex_buffer ex_ni | |
96 # define ex_bmodified ex_ni | |
97 # define ex_bnext ex_ni | |
98 # define ex_bprevious ex_ni | |
99 # define ex_brewind ex_ni | |
100 # define ex_blast ex_ni | |
101 # define buflist_list ex_ni | |
102 # define ex_checktime ex_ni | |
103 #endif | |
104 #if !defined(FEAT_LISTCMDS) || !defined(FEAT_WINDOWS) | |
105 # define ex_buffer_all ex_ni | |
106 #endif | |
107 static char_u *getargcmd __ARGS((char_u **)); | |
108 static char_u *skip_cmd_arg __ARGS((char_u *p, int rembs)); | |
109 static int getargopt __ARGS((exarg_T *eap)); | |
110 #ifndef FEAT_QUICKFIX | |
111 # define ex_make ex_ni | |
41 | 112 # define ex_cbuffer ex_ni |
7 | 113 # define ex_cc ex_ni |
114 # define ex_cnext ex_ni | |
115 # define ex_cfile ex_ni | |
116 # define qf_list ex_ni | |
117 # define qf_age ex_ni | |
118 # define ex_helpgrep ex_ni | |
41 | 119 # define ex_vimgrep ex_ni |
7 | 120 #endif |
121 #if !defined(FEAT_QUICKFIX) || !defined(FEAT_WINDOWS) | |
122 # define ex_cclose ex_ni | |
123 # define ex_copen ex_ni | |
124 # define ex_cwindow ex_ni | |
125 #endif | |
532 | 126 #if !defined(FEAT_QUICKFIX) || !defined(FEAT_EVAL) |
127 # define ex_cexpr ex_ni | |
128 #endif | |
7 | 129 |
130 static int check_more __ARGS((int, int)); | |
131 static linenr_T get_address __ARGS((char_u **, int skip, int to_other_file)); | |
167 | 132 static void get_flags __ARGS((exarg_T *eap)); |
2333
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
133 #if !defined(FEAT_PERL) \ |
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
134 || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \ |
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
135 || !defined(FEAT_TCL) \ |
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
136 || !defined(FEAT_RUBY) \ |
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
137 || !defined(FEAT_LUA) \ |
aee7e1e5e0ce
Build problem when using all interfaces except Lua.
Bram Moolenaar <bram@vim.org>
parents:
2330
diff
changeset
|
138 || !defined(FEAT_MZSCHEME) |
1315 | 139 # define HAVE_EX_SCRIPT_NI |
7 | 140 static void ex_script_ni __ARGS((exarg_T *eap)); |
141 #endif | |
142 static char_u *invalid_range __ARGS((exarg_T *eap)); | |
143 static void correct_range __ARGS((exarg_T *eap)); | |
344 | 144 #ifdef FEAT_QUICKFIX |
145 static char_u *replace_makeprg __ARGS((exarg_T *eap, char_u *p, char_u **cmdlinep)); | |
146 #endif | |
7 | 147 static char_u *repl_cmdline __ARGS((exarg_T *eap, char_u *src, int srclen, char_u *repl, char_u **cmdlinep)); |
148 static void ex_highlight __ARGS((exarg_T *eap)); | |
149 static void ex_colorscheme __ARGS((exarg_T *eap)); | |
150 static void ex_quit __ARGS((exarg_T *eap)); | |
151 static void ex_cquit __ARGS((exarg_T *eap)); | |
152 static void ex_quit_all __ARGS((exarg_T *eap)); | |
153 #ifdef FEAT_WINDOWS | |
154 static void ex_close __ARGS((exarg_T *eap)); | |
671 | 155 static void ex_win_close __ARGS((int forceit, win_T *win, tabpage_T *tp)); |
7 | 156 static void ex_only __ARGS((exarg_T *eap)); |
157 static void ex_resize __ARGS((exarg_T *eap)); | |
158 static void ex_stag __ARGS((exarg_T *eap)); | |
667 | 159 static void ex_tabclose __ARGS((exarg_T *eap)); |
672 | 160 static void ex_tabonly __ARGS((exarg_T *eap)); |
682 | 161 static void ex_tabnext __ARGS((exarg_T *eap)); |
162 static void ex_tabmove __ARGS((exarg_T *eap)); | |
667 | 163 static void ex_tabs __ARGS((exarg_T *eap)); |
7 | 164 #else |
165 # define ex_close ex_ni | |
166 # define ex_only ex_ni | |
167 # define ex_all ex_ni | |
168 # define ex_resize ex_ni | |
169 # define ex_splitview ex_ni | |
170 # define ex_stag ex_ni | |
682 | 171 # define ex_tabnext ex_ni |
172 # define ex_tabmove ex_ni | |
667 | 173 # define ex_tabs ex_ni |
174 # define ex_tabclose ex_ni | |
672 | 175 # define ex_tabonly ex_ni |
7 | 176 #endif |
177 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) | |
178 static void ex_pclose __ARGS((exarg_T *eap)); | |
179 static void ex_ptag __ARGS((exarg_T *eap)); | |
180 static void ex_pedit __ARGS((exarg_T *eap)); | |
181 #else | |
182 # define ex_pclose ex_ni | |
183 # define ex_ptag ex_ni | |
184 # define ex_pedit ex_ni | |
185 #endif | |
186 static void ex_hide __ARGS((exarg_T *eap)); | |
187 static void ex_stop __ARGS((exarg_T *eap)); | |
188 static void ex_exit __ARGS((exarg_T *eap)); | |
189 static void ex_print __ARGS((exarg_T *eap)); | |
190 #ifdef FEAT_BYTEOFF | |
191 static void ex_goto __ARGS((exarg_T *eap)); | |
192 #else | |
193 # define ex_goto ex_ni | |
194 #endif | |
195 static void ex_shell __ARGS((exarg_T *eap)); | |
196 static void ex_preserve __ARGS((exarg_T *eap)); | |
197 static void ex_recover __ARGS((exarg_T *eap)); | |
198 #ifndef FEAT_LISTCMDS | |
199 # define ex_argedit ex_ni | |
200 # define ex_argadd ex_ni | |
201 # define ex_argdelete ex_ni | |
202 # define ex_listdo ex_ni | |
203 #endif | |
204 static void ex_mode __ARGS((exarg_T *eap)); | |
205 static void ex_wrongmodifier __ARGS((exarg_T *eap)); | |
206 static void ex_find __ARGS((exarg_T *eap)); | |
167 | 207 static void ex_open __ARGS((exarg_T *eap)); |
7 | 208 static void ex_edit __ARGS((exarg_T *eap)); |
209 #if !defined(FEAT_GUI) && !defined(FEAT_CLIENTSERVER) | |
210 # define ex_drop ex_ni | |
211 #endif | |
212 #ifndef FEAT_GUI | |
213 # define ex_gui ex_nogui | |
214 static void ex_nogui __ARGS((exarg_T *eap)); | |
215 #endif | |
216 #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF) | |
217 static void ex_tearoff __ARGS((exarg_T *eap)); | |
218 #else | |
219 # define ex_tearoff ex_ni | |
220 #endif | |
573 | 221 #if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)) && defined(FEAT_MENU) |
7 | 222 static void ex_popup __ARGS((exarg_T *eap)); |
223 #else | |
224 # define ex_popup ex_ni | |
225 #endif | |
226 #ifndef FEAT_GUI_MSWIN | |
227 # define ex_simalt ex_ni | |
228 #endif | |
573 | 229 #if !defined(FEAT_GUI_MSWIN) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) |
7 | 230 # define gui_mch_find_dialog ex_ni |
231 # define gui_mch_replace_dialog ex_ni | |
232 #endif | |
573 | 233 #if !defined(FEAT_GUI_GTK) |
7 | 234 # define ex_helpfind ex_ni |
235 #endif | |
236 #ifndef FEAT_CSCOPE | |
237 # define do_cscope ex_ni | |
238 # define do_scscope ex_ni | |
239 # define do_cstag ex_ni | |
240 #endif | |
241 #ifndef FEAT_SYN_HL | |
242 # define ex_syntax ex_ni | |
2250
1bac28a53fae
Add the conceal patch from Vince Negri.
Bram Moolenaar <bram@vim.org>
parents:
2238
diff
changeset
|
243 # define ex_ownsyntax ex_ni |
737 | 244 #endif |
245 #ifndef FEAT_SPELL | |
310 | 246 # define ex_spell ex_ni |
236 | 247 # define ex_mkspell ex_ni |
351 | 248 # define ex_spelldump ex_ni |
714 | 249 # define ex_spellinfo ex_ni |
372 | 250 # define ex_spellrepall ex_ni |
236 | 251 #endif |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
252 #ifndef FEAT_PERSISTENT_UNDO |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
253 # define ex_rundo ex_ni |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
254 # define ex_wundo ex_ni |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
255 #endif |
2320
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
256 #ifndef FEAT_LUA |
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
257 # define ex_lua ex_script_ni |
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
258 # define ex_luado ex_ni |
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
259 # define ex_luafile ex_ni |
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
260 #endif |
14 | 261 #ifndef FEAT_MZSCHEME |
262 # define ex_mzscheme ex_script_ni | |
263 # define ex_mzfile ex_ni | |
264 #endif | |
7 | 265 #ifndef FEAT_PERL |
266 # define ex_perl ex_script_ni | |
267 # define ex_perldo ex_ni | |
268 #endif | |
269 #ifndef FEAT_PYTHON | |
270 # define ex_python ex_script_ni | |
271 # define ex_pyfile ex_ni | |
272 #endif | |
2329
ad2889f48843
Added support for Python 3. (Roland Puntaier)
Bram Moolenaar <bram@vim.org>
parents:
2320
diff
changeset
|
273 #ifndef FEAT_PYTHON3 |
2350
06feaf4fe36a
Rename some "python3" symbols to "py3", as the command name.
Bram Moolenaar <bram@vim.org>
parents:
2340
diff
changeset
|
274 # define ex_py3 ex_script_ni |
2329
ad2889f48843
Added support for Python 3. (Roland Puntaier)
Bram Moolenaar <bram@vim.org>
parents:
2320
diff
changeset
|
275 # define ex_py3file ex_ni |
ad2889f48843
Added support for Python 3. (Roland Puntaier)
Bram Moolenaar <bram@vim.org>
parents:
2320
diff
changeset
|
276 #endif |
7 | 277 #ifndef FEAT_TCL |
278 # define ex_tcl ex_script_ni | |
279 # define ex_tcldo ex_ni | |
280 # define ex_tclfile ex_ni | |
281 #endif | |
282 #ifndef FEAT_RUBY | |
283 # define ex_ruby ex_script_ni | |
284 # define ex_rubydo ex_ni | |
285 # define ex_rubyfile ex_ni | |
286 #endif | |
287 #ifndef FEAT_SNIFF | |
288 # define ex_sniff ex_ni | |
289 #endif | |
290 #ifndef FEAT_KEYMAP | |
291 # define ex_loadkeymap ex_ni | |
292 #endif | |
293 static void ex_swapname __ARGS((exarg_T *eap)); | |
294 static void ex_syncbind __ARGS((exarg_T *eap)); | |
295 static void ex_read __ARGS((exarg_T *eap)); | |
296 static void ex_pwd __ARGS((exarg_T *eap)); | |
297 static void ex_equal __ARGS((exarg_T *eap)); | |
298 static void ex_sleep __ARGS((exarg_T *eap)); | |
299 static void do_exmap __ARGS((exarg_T *eap, int isabbrev)); | |
300 static void ex_winsize __ARGS((exarg_T *eap)); | |
301 #ifdef FEAT_WINDOWS | |
302 static void ex_wincmd __ARGS((exarg_T *eap)); | |
303 #else | |
304 # define ex_wincmd ex_ni | |
305 #endif | |
11 | 306 #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN) |
7 | 307 static void ex_winpos __ARGS((exarg_T *eap)); |
308 #else | |
309 # define ex_winpos ex_ni | |
310 #endif | |
311 static void ex_operators __ARGS((exarg_T *eap)); | |
312 static void ex_put __ARGS((exarg_T *eap)); | |
313 static void ex_copymove __ARGS((exarg_T *eap)); | |
167 | 314 static void ex_may_print __ARGS((exarg_T *eap)); |
7 | 315 static void ex_submagic __ARGS((exarg_T *eap)); |
316 static void ex_join __ARGS((exarg_T *eap)); | |
317 static void ex_at __ARGS((exarg_T *eap)); | |
318 static void ex_bang __ARGS((exarg_T *eap)); | |
319 static void ex_undo __ARGS((exarg_T *eap)); | |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
320 #ifdef FEAT_PERSISTENT_UNDO |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
321 static void ex_wundo __ARGS((exarg_T *eap)); |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
322 static void ex_rundo __ARGS((exarg_T *eap)); |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
323 #endif |
7 | 324 static void ex_redo __ARGS((exarg_T *eap)); |
756 | 325 static void ex_later __ARGS((exarg_T *eap)); |
7 | 326 static void ex_redir __ARGS((exarg_T *eap)); |
327 static void ex_redraw __ARGS((exarg_T *eap)); | |
328 static void ex_redrawstatus __ARGS((exarg_T *eap)); | |
329 static void close_redir __ARGS((void)); | |
330 static void ex_mkrc __ARGS((exarg_T *eap)); | |
331 static void ex_mark __ARGS((exarg_T *eap)); | |
332 #ifdef FEAT_USR_CMDS | |
333 static char_u *uc_fun_cmd __ARGS((void)); | |
184 | 334 static char_u *find_ucmd __ARGS((exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl)); |
7 | 335 #endif |
336 #ifdef FEAT_EX_EXTRA | |
337 static void ex_normal __ARGS((exarg_T *eap)); | |
338 static void ex_startinsert __ARGS((exarg_T *eap)); | |
339 static void ex_stopinsert __ARGS((exarg_T *eap)); | |
340 #else | |
341 # define ex_normal ex_ni | |
342 # define ex_align ex_ni | |
343 # define ex_retab ex_ni | |
344 # define ex_startinsert ex_ni | |
345 # define ex_stopinsert ex_ni | |
346 # define ex_helptags ex_ni | |
280 | 347 # define ex_sort ex_ni |
7 | 348 #endif |
349 #ifdef FEAT_FIND_ID | |
350 static void ex_checkpath __ARGS((exarg_T *eap)); | |
351 static void ex_findpat __ARGS((exarg_T *eap)); | |
352 #else | |
353 # define ex_findpat ex_ni | |
354 # define ex_checkpath ex_ni | |
355 #endif | |
356 #if defined(FEAT_FIND_ID) && defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) | |
357 static void ex_psearch __ARGS((exarg_T *eap)); | |
358 #else | |
359 # define ex_psearch ex_ni | |
360 #endif | |
361 static void ex_tag __ARGS((exarg_T *eap)); | |
362 static void ex_tag_cmd __ARGS((exarg_T *eap, char_u *name)); | |
363 #ifndef FEAT_EVAL | |
364 # define ex_scriptnames ex_ni | |
365 # define ex_finish ex_ni | |
366 # define ex_echo ex_ni | |
367 # define ex_echohl ex_ni | |
368 # define ex_execute ex_ni | |
369 # define ex_call ex_ni | |
370 # define ex_if ex_ni | |
371 # define ex_endif ex_ni | |
372 # define ex_else ex_ni | |
373 # define ex_while ex_ni | |
374 # define ex_continue ex_ni | |
375 # define ex_break ex_ni | |
376 # define ex_endwhile ex_ni | |
377 # define ex_throw ex_ni | |
378 # define ex_try ex_ni | |
379 # define ex_catch ex_ni | |
380 # define ex_finally ex_ni | |
381 # define ex_endtry ex_ni | |
382 # define ex_endfunction ex_ni | |
383 # define ex_let ex_ni | |
384 # define ex_unlet ex_ni | |
146 | 385 # define ex_lockvar ex_ni |
386 # define ex_unlockvar ex_ni | |
7 | 387 # define ex_function ex_ni |
388 # define ex_delfunction ex_ni | |
389 # define ex_return ex_ni | |
1733 | 390 # define ex_oldfiles ex_ni |
7 | 391 #endif |
392 static char_u *arg_all __ARGS((void)); | |
393 #ifdef FEAT_SESSION | |
394 static int makeopens __ARGS((FILE *fd, char_u *dirnow)); | |
1467 | 395 static int put_view __ARGS((FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int current_arg_idx)); |
7 | 396 static void ex_loadview __ARGS((exarg_T *eap)); |
397 static char_u *get_view_file __ARGS((int c)); | |
1113 | 398 static int did_lcd; /* whether ":lcd" was produced for a session */ |
7 | 399 #else |
400 # define ex_loadview ex_ni | |
401 #endif | |
402 #ifndef FEAT_EVAL | |
403 # define ex_compiler ex_ni | |
404 #endif | |
405 #ifdef FEAT_VIMINFO | |
406 static void ex_viminfo __ARGS((exarg_T *eap)); | |
407 #else | |
408 # define ex_viminfo ex_ni | |
409 #endif | |
410 static void ex_behave __ARGS((exarg_T *eap)); | |
411 #ifdef FEAT_AUTOCMD | |
412 static void ex_filetype __ARGS((exarg_T *eap)); | |
413 static void ex_setfiletype __ARGS((exarg_T *eap)); | |
414 #else | |
415 # define ex_filetype ex_ni | |
416 # define ex_setfiletype ex_ni | |
417 #endif | |
418 #ifndef FEAT_DIFF | |
16 | 419 # define ex_diffoff ex_ni |
7 | 420 # define ex_diffpatch ex_ni |
421 # define ex_diffgetput ex_ni | |
422 # define ex_diffsplit ex_ni | |
423 # define ex_diffthis ex_ni | |
424 # define ex_diffupdate ex_ni | |
425 #endif | |
426 static void ex_digraphs __ARGS((exarg_T *eap)); | |
427 static void ex_set __ARGS((exarg_T *eap)); | |
428 #if !defined(FEAT_EVAL) || !defined(FEAT_AUTOCMD) | |
429 # define ex_options ex_ni | |
430 #endif | |
431 #ifdef FEAT_SEARCH_EXTRA | |
432 static void ex_nohlsearch __ARGS((exarg_T *eap)); | |
433 static void ex_match __ARGS((exarg_T *eap)); | |
434 #else | |
435 # define ex_nohlsearch ex_ni | |
436 # define ex_match ex_ni | |
437 #endif | |
438 #ifdef FEAT_CRYPT | |
439 static void ex_X __ARGS((exarg_T *eap)); | |
440 #else | |
441 # define ex_X ex_ni | |
442 #endif | |
443 #ifdef FEAT_FOLDING | |
444 static void ex_fold __ARGS((exarg_T *eap)); | |
445 static void ex_foldopen __ARGS((exarg_T *eap)); | |
446 static void ex_folddo __ARGS((exarg_T *eap)); | |
447 #else | |
448 # define ex_fold ex_ni | |
449 # define ex_foldopen ex_ni | |
450 # define ex_folddo ex_ni | |
451 #endif | |
452 #if !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ | |
453 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) | |
454 # define ex_language ex_ni | |
455 #endif | |
456 #ifndef FEAT_SIGNS | |
457 # define ex_sign ex_ni | |
458 #endif | |
459 #ifndef FEAT_SUN_WORKSHOP | |
460 # define ex_wsverb ex_ni | |
461 #endif | |
33 | 462 #ifndef FEAT_NETBEANS_INTG |
2210 | 463 # define ex_nbclose ex_ni |
33 | 464 # define ex_nbkey ex_ni |
2210 | 465 # define ex_nbstart ex_ni |
33 | 466 #endif |
7 | 467 |
468 #ifndef FEAT_EVAL | |
469 # define ex_debug ex_ni | |
470 # define ex_breakadd ex_ni | |
471 # define ex_debuggreedy ex_ni | |
472 # define ex_breakdel ex_ni | |
473 # define ex_breaklist ex_ni | |
474 #endif | |
475 | |
476 #ifndef FEAT_CMDHIST | |
477 # define ex_history ex_ni | |
478 #endif | |
479 #ifndef FEAT_JUMPLIST | |
480 # define ex_jumps ex_ni | |
481 # define ex_changes ex_ni | |
482 #endif | |
483 | |
170 | 484 #ifndef FEAT_PROFILE |
485 # define ex_profile ex_ni | |
486 #endif | |
487 | |
7 | 488 /* |
489 * Declare cmdnames[]. | |
490 */ | |
491 #define DO_DECLARE_EXCMD | |
492 #include "ex_cmds.h" | |
493 | |
494 /* | |
495 * Table used to quickly search for a command, based on its first character. | |
496 */ | |
296 | 497 static cmdidx_T cmdidxs[27] = |
7 | 498 { |
499 CMD_append, | |
500 CMD_buffer, | |
501 CMD_change, | |
502 CMD_delete, | |
503 CMD_edit, | |
504 CMD_file, | |
505 CMD_global, | |
506 CMD_help, | |
507 CMD_insert, | |
508 CMD_join, | |
509 CMD_k, | |
510 CMD_list, | |
511 CMD_move, | |
512 CMD_next, | |
513 CMD_open, | |
514 CMD_print, | |
515 CMD_quit, | |
516 CMD_read, | |
517 CMD_substitute, | |
518 CMD_t, | |
519 CMD_undo, | |
520 CMD_vglobal, | |
521 CMD_write, | |
522 CMD_xit, | |
523 CMD_yank, | |
524 CMD_z, | |
525 CMD_bang | |
526 }; | |
527 | |
528 static char_u dollar_command[2] = {'$', 0}; | |
529 | |
530 | |
531 #ifdef FEAT_EVAL | |
72 | 532 /* Struct for storing a line inside a while/for loop */ |
7 | 533 typedef struct |
534 { | |
535 char_u *line; /* command line */ | |
536 linenr_T lnum; /* sourcing_lnum of the line */ | |
537 } wcmd_T; | |
538 | |
539 /* | |
72 | 540 * Structure used to store info for line position in a while or for loop. |
7 | 541 * This is required, because do_one_cmd() may invoke ex_function(), which |
72 | 542 * reads more lines that may come from the while/for loop. |
543 */ | |
544 struct loop_cookie | |
7 | 545 { |
546 garray_T *lines_gap; /* growarray with line info */ | |
547 int current_line; /* last read line from growarray */ | |
548 int repeating; /* TRUE when looping a second time */ | |
549 /* When "repeating" is FALSE use "getline" and "cookie" to get lines */ | |
550 char_u *(*getline) __ARGS((int, void *, int)); | |
551 void *cookie; | |
552 }; | |
553 | |
72 | 554 static char_u *get_loop_line __ARGS((int c, void *cookie, int indent)); |
555 static int store_loop_line __ARGS((garray_T *gap, char_u *line)); | |
7 | 556 static void free_cmdlines __ARGS((garray_T *gap)); |
8 | 557 |
558 /* Struct to save a few things while debugging. Used in do_cmdline() only. */ | |
559 struct dbg_stuff | |
560 { | |
561 int trylevel; | |
562 int force_abort; | |
563 except_T *caught_stack; | |
564 char_u *vv_exception; | |
565 char_u *vv_throwpoint; | |
566 int did_emsg; | |
567 int got_int; | |
568 int did_throw; | |
569 int need_rethrow; | |
570 int check_cstack; | |
571 except_T *current_exception; | |
572 }; | |
573 | |
574 static void save_dbg_stuff __ARGS((struct dbg_stuff *dsp)); | |
575 static void restore_dbg_stuff __ARGS((struct dbg_stuff *dsp)); | |
576 | |
577 static void | |
578 save_dbg_stuff(dsp) | |
579 struct dbg_stuff *dsp; | |
580 { | |
581 dsp->trylevel = trylevel; trylevel = 0; | |
582 dsp->force_abort = force_abort; force_abort = FALSE; | |
583 dsp->caught_stack = caught_stack; caught_stack = NULL; | |
584 dsp->vv_exception = v_exception(NULL); | |
585 dsp->vv_throwpoint = v_throwpoint(NULL); | |
586 | |
587 /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */ | |
588 dsp->did_emsg = did_emsg; did_emsg = FALSE; | |
589 dsp->got_int = got_int; got_int = FALSE; | |
590 dsp->did_throw = did_throw; did_throw = FALSE; | |
591 dsp->need_rethrow = need_rethrow; need_rethrow = FALSE; | |
592 dsp->check_cstack = check_cstack; check_cstack = FALSE; | |
593 dsp->current_exception = current_exception; current_exception = NULL; | |
594 } | |
595 | |
596 static void | |
597 restore_dbg_stuff(dsp) | |
598 struct dbg_stuff *dsp; | |
599 { | |
600 suppress_errthrow = FALSE; | |
601 trylevel = dsp->trylevel; | |
602 force_abort = dsp->force_abort; | |
603 caught_stack = dsp->caught_stack; | |
604 (void)v_exception(dsp->vv_exception); | |
605 (void)v_throwpoint(dsp->vv_throwpoint); | |
606 did_emsg = dsp->did_emsg; | |
607 got_int = dsp->got_int; | |
608 did_throw = dsp->did_throw; | |
609 need_rethrow = dsp->need_rethrow; | |
610 check_cstack = dsp->check_cstack; | |
611 current_exception = dsp->current_exception; | |
612 } | |
7 | 613 #endif |
614 | |
615 | |
616 /* | |
617 * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi" | |
618 * command is given. | |
619 */ | |
620 void | |
621 do_exmode(improved) | |
622 int improved; /* TRUE for "improved Ex" mode */ | |
623 { | |
624 int save_msg_scroll; | |
625 int prev_msg_row; | |
626 linenr_T prev_line; | |
167 | 627 int changedtick; |
628 | |
629 if (improved) | |
630 exmode_active = EXMODE_VIM; | |
631 else | |
632 exmode_active = EXMODE_NORMAL; | |
633 State = NORMAL; | |
634 | |
635 /* When using ":global /pat/ visual" and then "Q" we return to continue | |
636 * the :global command. */ | |
637 if (global_busy) | |
638 return; | |
7 | 639 |
640 save_msg_scroll = msg_scroll; | |
641 ++RedrawingDisabled; /* don't redisplay the window */ | |
642 ++no_wait_return; /* don't wait for return */ | |
643 #ifdef FEAT_GUI | |
644 /* Ignore scrollbar and mouse events in Ex mode */ | |
645 ++hold_gui_events; | |
646 #endif | |
647 #ifdef FEAT_SNIFF | |
648 want_sniff_request = 0; /* No K_SNIFF wanted */ | |
649 #endif | |
650 | |
651 MSG(_("Entering Ex mode. Type \"visual\" to go to Normal mode.")); | |
652 while (exmode_active) | |
653 { | |
161 | 654 #ifdef FEAT_EX_EXTRA |
655 /* Check for a ":normal" command and no more characters left. */ | |
656 if (ex_normal_busy > 0 && typebuf.tb_len == 0) | |
657 { | |
658 exmode_active = FALSE; | |
659 break; | |
660 } | |
661 #endif | |
7 | 662 msg_scroll = TRUE; |
663 need_wait_return = FALSE; | |
664 ex_pressedreturn = FALSE; | |
665 ex_no_reprint = FALSE; | |
167 | 666 changedtick = curbuf->b_changedtick; |
7 | 667 prev_msg_row = msg_row; |
668 prev_line = curwin->w_cursor.lnum; | |
669 #ifdef FEAT_SNIFF | |
670 ProcessSniffRequests(); | |
671 #endif | |
672 if (improved) | |
673 { | |
674 cmdline_row = msg_row; | |
675 do_cmdline(NULL, getexline, NULL, 0); | |
676 } | |
677 else | |
678 do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT); | |
679 lines_left = Rows - 1; | |
680 | |
167 | 681 if ((prev_line != curwin->w_cursor.lnum |
682 || changedtick != curbuf->b_changedtick) && !ex_no_reprint) | |
683 { | |
684 if (curbuf->b_ml.ml_flags & ML_EMPTY) | |
685 EMSG(_(e_emptybuf)); | |
686 else | |
687 { | |
688 if (ex_pressedreturn) | |
689 { | |
690 /* go up one line, to overwrite the ":<CR>" line, so the | |
1441 | 691 * output doesn't contain empty lines. */ |
167 | 692 msg_row = prev_msg_row; |
693 if (prev_msg_row == Rows - 1) | |
694 msg_row--; | |
695 } | |
696 msg_col = 0; | |
697 print_line_no_prefix(curwin->w_cursor.lnum, FALSE, FALSE); | |
698 msg_clr_eos(); | |
699 } | |
700 } | |
701 else if (ex_pressedreturn && !ex_no_reprint) /* must be at EOF */ | |
702 { | |
703 if (curbuf->b_ml.ml_flags & ML_EMPTY) | |
704 EMSG(_(e_emptybuf)); | |
705 else | |
706 EMSG(_("E501: At end-of-file")); | |
707 } | |
7 | 708 } |
709 | |
710 #ifdef FEAT_GUI | |
711 --hold_gui_events; | |
712 #endif | |
713 --RedrawingDisabled; | |
714 --no_wait_return; | |
715 update_screen(CLEAR); | |
716 need_wait_return = FALSE; | |
717 msg_scroll = save_msg_scroll; | |
718 } | |
719 | |
720 /* | |
721 * Execute a simple command line. Used for translated commands like "*". | |
722 */ | |
723 int | |
724 do_cmdline_cmd(cmd) | |
725 char_u *cmd; | |
726 { | |
727 return do_cmdline(cmd, NULL, NULL, | |
728 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); | |
729 } | |
730 | |
731 /* | |
732 * do_cmdline(): execute one Ex command line | |
733 * | |
734 * 1. Execute "cmdline" when it is not NULL. | |
2635 | 735 * If "cmdline" is NULL, or more lines are needed, fgetline() is used. |
7 | 736 * 2. Split up in parts separated with '|'. |
737 * | |
738 * This function can be called recursively! | |
739 * | |
740 * flags: | |
741 * DOCMD_VERBOSE - The command will be included in the error message. | |
742 * DOCMD_NOWAIT - Don't call wait_return() and friends. | |
2635 | 743 * DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. |
7 | 744 * DOCMD_KEYTYPED - Don't reset KeyTyped. |
745 * DOCMD_EXCRESET - Reset the exception environment (used for debugging). | |
746 * DOCMD_KEEPLINE - Store first typed line (for repeating with "."). | |
747 * | |
748 * return FAIL if cmdline could not be executed, OK otherwise | |
749 */ | |
750 int | |
2635 | 751 do_cmdline(cmdline, fgetline, cookie, flags) |
7 | 752 char_u *cmdline; |
2635 | 753 char_u *(*fgetline) __ARGS((int, void *, int)); |
754 void *cookie; /* argument for fgetline() */ | |
7 | 755 int flags; |
756 { | |
757 char_u *next_cmdline; /* next cmd to execute */ | |
758 char_u *cmdline_copy = NULL; /* copy of cmd line */ | |
2635 | 759 int used_getline = FALSE; /* used "fgetline" to obtain command */ |
7 | 760 static int recursive = 0; /* recursive depth */ |
761 int msg_didout_before_start = 0; | |
762 int count = 0; /* line number count */ | |
763 int did_inc = FALSE; /* incremented RedrawingDisabled */ | |
764 int retval = OK; | |
765 #ifdef FEAT_EVAL | |
766 struct condstack cstack; /* conditional stack */ | |
72 | 767 garray_T lines_ga; /* keep lines for ":while"/":for" */ |
7 | 768 int current_line = 0; /* active line in lines_ga */ |
769 char_u *fname = NULL; /* function or script name */ | |
770 linenr_T *breakpoint = NULL; /* ptr to breakpoint field in cookie */ | |
771 int *dbg_tick = NULL; /* ptr to dbg_tick field in cookie */ | |
8 | 772 struct dbg_stuff debug_saved; /* saved things for debug mode */ |
7 | 773 int initial_trylevel; |
774 struct msglist **saved_msg_list = NULL; | |
775 struct msglist *private_msg_list; | |
776 | |
2635 | 777 /* "fgetline" and "cookie" passed to do_one_cmd() */ |
7 | 778 char_u *(*cmd_getline) __ARGS((int, void *, int)); |
779 void *cmd_cookie; | |
72 | 780 struct loop_cookie cmd_loop_cookie; |
7 | 781 void *real_cookie; |
170 | 782 int getline_is_func; |
7 | 783 #else |
2635 | 784 # define cmd_getline fgetline |
7 | 785 # define cmd_cookie cookie |
786 #endif | |
787 static int call_depth = 0; /* recursiveness */ | |
788 | |
789 #ifdef FEAT_EVAL | |
790 /* For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory | |
791 * location for storing error messages to be converted to an exception. | |
84 | 792 * This ensures that the do_errthrow() call in do_one_cmd() does not |
793 * combine the messages stored by an earlier invocation of do_one_cmd() | |
794 * with the command name of the later one. This would happen when | |
795 * BufWritePost autocommands are executed after a write error. */ | |
7 | 796 saved_msg_list = msg_list; |
797 msg_list = &private_msg_list; | |
798 private_msg_list = NULL; | |
799 #endif | |
800 | |
801 /* It's possible to create an endless loop with ":execute", catch that | |
802 * here. The value of 200 allows nested function calls, ":source", etc. */ | |
803 if (call_depth == 200) | |
804 { | |
805 EMSG(_("E169: Command too recursive")); | |
806 #ifdef FEAT_EVAL | |
807 /* When converting to an exception, we do not include the command name | |
808 * since this is not an error of the specific command. */ | |
809 do_errthrow((struct condstack *)NULL, (char_u *)NULL); | |
810 msg_list = saved_msg_list; | |
811 #endif | |
812 return FAIL; | |
813 } | |
814 ++call_depth; | |
815 | |
816 #ifdef FEAT_EVAL | |
817 cstack.cs_idx = -1; | |
72 | 818 cstack.cs_looplevel = 0; |
7 | 819 cstack.cs_trylevel = 0; |
820 cstack.cs_emsg_silent_list = NULL; | |
72 | 821 cstack.cs_lflags = 0; |
7 | 822 ga_init2(&lines_ga, (int)sizeof(wcmd_T), 10); |
823 | |
2635 | 824 real_cookie = getline_cookie(fgetline, cookie); |
7 | 825 |
826 /* Inside a function use a higher nesting level. */ | |
2635 | 827 getline_is_func = getline_equal(fgetline, cookie, get_func_line); |
170 | 828 if (getline_is_func && ex_nesting_level == func_level(real_cookie)) |
7 | 829 ++ex_nesting_level; |
830 | |
831 /* Get the function or script name and the address where the next breakpoint | |
832 * line and the debug tick for a function or script are stored. */ | |
170 | 833 if (getline_is_func) |
7 | 834 { |
835 fname = func_name(real_cookie); | |
836 breakpoint = func_breakpoint(real_cookie); | |
837 dbg_tick = func_dbg_tick(real_cookie); | |
838 } | |
2635 | 839 else if (getline_equal(fgetline, cookie, getsourceline)) |
7 | 840 { |
841 fname = sourcing_name; | |
842 breakpoint = source_breakpoint(real_cookie); | |
843 dbg_tick = source_dbg_tick(real_cookie); | |
844 } | |
845 | |
846 /* | |
847 * Initialize "force_abort" and "suppress_errthrow" at the top level. | |
848 */ | |
849 if (!recursive) | |
850 { | |
851 force_abort = FALSE; | |
852 suppress_errthrow = FALSE; | |
853 } | |
854 | |
855 /* | |
856 * If requested, store and reset the global values controlling the | |
944 | 857 * exception handling (used when debugging). Otherwise clear it to avoid |
858 * a bogus compiler warning when the optimizer uses inline functions... | |
7 | 859 */ |
878 | 860 if (flags & DOCMD_EXCRESET) |
8 | 861 save_dbg_stuff(&debug_saved); |
944 | 862 else |
2215
cccb71c2c5c1
Fix uninit memory read in undo code. Fix uint32_t in proto file.
Bram Moolenaar <bram@vim.org>
parents:
2214
diff
changeset
|
863 vim_memset(&debug_saved, 0, 1); |
7 | 864 |
865 initial_trylevel = trylevel; | |
866 | |
867 /* | |
868 * "did_throw" will be set to TRUE when an exception is being thrown. | |
869 */ | |
870 did_throw = FALSE; | |
871 #endif | |
872 /* | |
873 * "did_emsg" will be set to TRUE when emsg() is used, in which case we | |
72 | 874 * cancel the whole command line, and any if/endif or loop. |
7 | 875 * If force_abort is set, we cancel everything. |
876 */ | |
877 did_emsg = FALSE; | |
878 | |
879 /* | |
880 * KeyTyped is only set when calling vgetc(). Reset it here when not | |
881 * calling vgetc() (sourced command lines). | |
882 */ | |
2635 | 883 if (!(flags & DOCMD_KEYTYPED) |
884 && !getline_equal(fgetline, cookie, getexline)) | |
7 | 885 KeyTyped = FALSE; |
886 | |
887 /* | |
888 * Continue executing command lines: | |
72 | 889 * - when inside an ":if", ":while" or ":for" |
7 | 890 * - for multiple commands on one line, separated with '|' |
891 * - when repeating until there are no more lines (for ":source") | |
892 */ | |
893 next_cmdline = cmdline; | |
894 do | |
895 { | |
170 | 896 #ifdef FEAT_EVAL |
2635 | 897 getline_is_func = getline_equal(fgetline, cookie, get_func_line); |
170 | 898 #endif |
899 | |
72 | 900 /* stop skipping cmds for an error msg after all endif/while/for */ |
7 | 901 if (next_cmdline == NULL |
902 #ifdef FEAT_EVAL | |
903 && !force_abort | |
904 && cstack.cs_idx < 0 | |
170 | 905 && !(getline_is_func && func_has_abort(real_cookie)) |
7 | 906 #endif |
907 ) | |
908 did_emsg = FALSE; | |
909 | |
910 /* | |
72 | 911 * 1. If repeating a line in a loop, get a line from lines_ga. |
2635 | 912 * 2. If no line given: Get an allocated line with fgetline(). |
7 | 913 * 3. If a line is given: Make a copy, so we can mess with it. |
914 */ | |
915 | |
916 #ifdef FEAT_EVAL | |
917 /* 1. If repeating, get a previous line from lines_ga. */ | |
72 | 918 if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) |
7 | 919 { |
920 /* Each '|' separated command is stored separately in lines_ga, to | |
921 * be able to jump to it. Don't use next_cmdline now. */ | |
922 vim_free(cmdline_copy); | |
923 cmdline_copy = NULL; | |
924 | |
925 /* Check if a function has returned or, unless it has an unclosed | |
926 * try conditional, aborted. */ | |
170 | 927 if (getline_is_func) |
928 { | |
929 # ifdef FEAT_PROFILE | |
788 | 930 if (do_profiling == PROF_YES) |
170 | 931 func_line_end(real_cookie); |
932 # endif | |
933 if (func_has_ended(real_cookie)) | |
934 { | |
935 retval = FAIL; | |
936 break; | |
937 } | |
938 } | |
939 #ifdef FEAT_PROFILE | |
788 | 940 else if (do_profiling == PROF_YES |
2635 | 941 && getline_equal(fgetline, cookie, getsourceline)) |
170 | 942 script_line_end(); |
943 #endif | |
7 | 944 |
945 /* Check if a sourced file hit a ":finish" command. */ | |
2635 | 946 if (source_finished(fgetline, cookie)) |
7 | 947 { |
948 retval = FAIL; | |
949 break; | |
950 } | |
951 | |
952 /* If breakpoints have been added/deleted need to check for it. */ | |
953 if (breakpoint != NULL && dbg_tick != NULL | |
954 && *dbg_tick != debug_tick) | |
955 { | |
956 *breakpoint = dbg_find_breakpoint( | |
2635 | 957 getline_equal(fgetline, cookie, getsourceline), |
7 | 958 fname, sourcing_lnum); |
959 *dbg_tick = debug_tick; | |
960 } | |
961 | |
962 next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line; | |
963 sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; | |
964 | |
965 /* Did we encounter a breakpoint? */ | |
966 if (breakpoint != NULL && *breakpoint != 0 | |
967 && *breakpoint <= sourcing_lnum) | |
968 { | |
969 dbg_breakpoint(fname, sourcing_lnum); | |
970 /* Find next breakpoint. */ | |
971 *breakpoint = dbg_find_breakpoint( | |
2635 | 972 getline_equal(fgetline, cookie, getsourceline), |
7 | 973 fname, sourcing_lnum); |
974 *dbg_tick = debug_tick; | |
975 } | |
170 | 976 # ifdef FEAT_PROFILE |
788 | 977 if (do_profiling == PROF_YES) |
170 | 978 { |
979 if (getline_is_func) | |
980 func_line_start(real_cookie); | |
2635 | 981 else if (getline_equal(fgetline, cookie, getsourceline)) |
170 | 982 script_line_start(); |
983 } | |
984 # endif | |
7 | 985 } |
986 | |
72 | 987 if (cstack.cs_looplevel > 0) |
988 { | |
989 /* Inside a while/for loop we need to store the lines and use them | |
2635 | 990 * again. Pass a different "fgetline" function to do_one_cmd() |
7 | 991 * below, so that it stores lines in or reads them from |
992 * "lines_ga". Makes it possible to define a function inside a | |
72 | 993 * while/for loop. */ |
994 cmd_getline = get_loop_line; | |
995 cmd_cookie = (void *)&cmd_loop_cookie; | |
996 cmd_loop_cookie.lines_gap = &lines_ga; | |
997 cmd_loop_cookie.current_line = current_line; | |
2635 | 998 cmd_loop_cookie.getline = fgetline; |
72 | 999 cmd_loop_cookie.cookie = cookie; |
1000 cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); | |
7 | 1001 } |
1002 else | |
1003 { | |
2635 | 1004 cmd_getline = fgetline; |
7 | 1005 cmd_cookie = cookie; |
1006 } | |
1007 #endif | |
1008 | |
2635 | 1009 /* 2. If no line given, get an allocated line with fgetline(). */ |
7 | 1010 if (next_cmdline == NULL) |
1011 { | |
1012 /* | |
1013 * Need to set msg_didout for the first line after an ":if", | |
1014 * otherwise the ":if" will be overwritten. | |
1015 */ | |
2635 | 1016 if (count == 1 && getline_equal(fgetline, cookie, getexline)) |
7 | 1017 msg_didout = TRUE; |
2635 | 1018 if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, |
7 | 1019 #ifdef FEAT_EVAL |
1020 cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2 | |
1021 #else | |
1022 0 | |
1023 #endif | |
1024 )) == NULL) | |
1025 { | |
1026 /* Don't call wait_return for aborted command line. The NULL | |
1027 * returned for the end of a sourced file or executed function | |
1028 * doesn't do this. */ | |
1029 if (KeyTyped && !(flags & DOCMD_REPEAT)) | |
1030 need_wait_return = FALSE; | |
1031 retval = FAIL; | |
1032 break; | |
1033 } | |
1034 used_getline = TRUE; | |
1035 | |
1036 /* | |
1037 * Keep the first typed line. Clear it when more lines are typed. | |
1038 */ | |
1039 if (flags & DOCMD_KEEPLINE) | |
1040 { | |
1041 vim_free(repeat_cmdline); | |
1042 if (count == 0) | |
1043 repeat_cmdline = vim_strsave(next_cmdline); | |
1044 else | |
1045 repeat_cmdline = NULL; | |
1046 } | |
1047 } | |
1048 | |
1049 /* 3. Make a copy of the command so we can mess with it. */ | |
1050 else if (cmdline_copy == NULL) | |
1051 { | |
1052 next_cmdline = vim_strsave(next_cmdline); | |
1053 if (next_cmdline == NULL) | |
1054 { | |
1055 EMSG(_(e_outofmem)); | |
1056 retval = FAIL; | |
1057 break; | |
1058 } | |
1059 } | |
1060 cmdline_copy = next_cmdline; | |
1061 | |
1062 #ifdef FEAT_EVAL | |
1063 /* | |
72 | 1064 * Save the current line when inside a ":while" or ":for", and when |
1065 * the command looks like a ":while" or ":for", because we may need it | |
1066 * later. When there is a '|' and another command, it is stored | |
1067 * separately, because we need to be able to jump back to it from an | |
1068 * :endwhile/:endfor. | |
7 | 1069 */ |
72 | 1070 if (current_line == lines_ga.ga_len |
1071 && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) | |
1072 { | |
1073 if (store_loop_line(&lines_ga, next_cmdline) == FAIL) | |
7 | 1074 { |
1075 retval = FAIL; | |
1076 break; | |
1077 } | |
1078 } | |
1079 did_endif = FALSE; | |
1080 #endif | |
1081 | |
1082 if (count++ == 0) | |
1083 { | |
1084 /* | |
1085 * All output from the commands is put below each other, without | |
1086 * waiting for a return. Don't do this when executing commands | |
1087 * from a script or when being called recursive (e.g. for ":e | |
1088 * +command file"). | |
1089 */ | |
1090 if (!(flags & DOCMD_NOWAIT) && !recursive) | |
1091 { | |
1092 msg_didout_before_start = msg_didout; | |
1093 msg_didany = FALSE; /* no output yet */ | |
1094 msg_start(); | |
1095 msg_scroll = TRUE; /* put messages below each other */ | |
1096 ++no_wait_return; /* dont wait for return until finished */ | |
1097 ++RedrawingDisabled; | |
1098 did_inc = TRUE; | |
1099 } | |
1100 } | |
1101 | |
1102 if (p_verbose >= 15 && sourcing_name != NULL) | |
1103 { | |
1104 ++no_wait_return; | |
291 | 1105 verbose_enter_scroll(); |
1106 | |
7 | 1107 smsg((char_u *)_("line %ld: %s"), |
1108 (long)sourcing_lnum, cmdline_copy); | |
291 | 1109 if (msg_silent == 0) |
1110 msg_puts((char_u *)"\n"); /* don't overwrite this */ | |
1111 | |
1112 verbose_leave_scroll(); | |
7 | 1113 --no_wait_return; |
1114 } | |
1115 | |
1116 /* | |
1117 * 2. Execute one '|' separated command. | |
1118 * do_one_cmd() will return NULL if there is no trailing '|'. | |
1119 * "cmdline_copy" can change, e.g. for '%' and '#' expansion. | |
1120 */ | |
1121 ++recursive; | |
1122 next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE, | |
1123 #ifdef FEAT_EVAL | |
1124 &cstack, | |
1125 #endif | |
1126 cmd_getline, cmd_cookie); | |
1127 --recursive; | |
1128 | |
1129 #ifdef FEAT_EVAL | |
72 | 1130 if (cmd_cookie == (void *)&cmd_loop_cookie) |
1131 /* Use "current_line" from "cmd_loop_cookie", it may have been | |
7 | 1132 * incremented when defining a function. */ |
72 | 1133 current_line = cmd_loop_cookie.current_line; |
7 | 1134 #endif |
1135 | |
1136 if (next_cmdline == NULL) | |
1137 { | |
1138 vim_free(cmdline_copy); | |
1139 cmdline_copy = NULL; | |
1140 #ifdef FEAT_CMDHIST | |
1141 /* | |
1142 * If the command was typed, remember it for the ':' register. | |
1143 * Do this AFTER executing the command to make :@: work. | |
1144 */ | |
2635 | 1145 if (getline_equal(fgetline, cookie, getexline) |
7 | 1146 && new_last_cmdline != NULL) |
1147 { | |
1148 vim_free(last_cmdline); | |
1149 last_cmdline = new_last_cmdline; | |
1150 new_last_cmdline = NULL; | |
1151 } | |
1152 #endif | |
1153 } | |
1154 else | |
1155 { | |
1156 /* need to copy the command after the '|' to cmdline_copy, for the | |
1157 * next do_one_cmd() */ | |
1619 | 1158 STRMOVE(cmdline_copy, next_cmdline); |
7 | 1159 next_cmdline = cmdline_copy; |
1160 } | |
1161 | |
1162 | |
1163 #ifdef FEAT_EVAL | |
1164 /* reset did_emsg for a function that is not aborted by an error */ | |
1165 if (did_emsg && !force_abort | |
2635 | 1166 && getline_equal(fgetline, cookie, get_func_line) |
7 | 1167 && !func_has_abort(real_cookie)) |
1168 did_emsg = FALSE; | |
1169 | |
72 | 1170 if (cstack.cs_looplevel > 0) |
7 | 1171 { |
1172 ++current_line; | |
1173 | |
1174 /* | |
72 | 1175 * An ":endwhile", ":endfor" and ":continue" is handled here. |
1176 * If we were executing commands, jump back to the ":while" or | |
1177 * ":for". | |
1178 * If we were not executing commands, decrement cs_looplevel. | |
7 | 1179 */ |
72 | 1180 if (cstack.cs_lflags & (CSL_HAD_CONT | CSL_HAD_ENDLOOP)) |
1181 { | |
1182 cstack.cs_lflags &= ~(CSL_HAD_CONT | CSL_HAD_ENDLOOP); | |
1183 | |
1184 /* Jump back to the matching ":while" or ":for". Be careful | |
1185 * not to use a cs_line[] from an entry that isn't a ":while" | |
1186 * or ":for": It would make "current_line" invalid and can | |
1187 * cause a crash. */ | |
7 | 1188 if (!did_emsg && !got_int && !did_throw |
1189 && cstack.cs_idx >= 0 | |
72 | 1190 && (cstack.cs_flags[cstack.cs_idx] |
1191 & (CSF_WHILE | CSF_FOR)) | |
7 | 1192 && cstack.cs_line[cstack.cs_idx] >= 0 |
1193 && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE)) | |
1194 { | |
1195 current_line = cstack.cs_line[cstack.cs_idx]; | |
72 | 1196 /* remember we jumped there */ |
1197 cstack.cs_lflags |= CSL_HAD_LOOP; | |
7 | 1198 line_breakcheck(); /* check if CTRL-C typed */ |
1199 | |
72 | 1200 /* Check for the next breakpoint at or after the ":while" |
1201 * or ":for". */ | |
7 | 1202 if (breakpoint != NULL) |
1203 { | |
1204 *breakpoint = dbg_find_breakpoint( | |
2635 | 1205 getline_equal(fgetline, cookie, getsourceline), |
7 | 1206 fname, |
1207 ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1); | |
1208 *dbg_tick = debug_tick; | |
1209 } | |
1210 } | |
72 | 1211 else |
7 | 1212 { |
72 | 1213 /* can only get here with ":endwhile" or ":endfor" */ |
7 | 1214 if (cstack.cs_idx >= 0) |
77 | 1215 rewind_conditionals(&cstack, cstack.cs_idx - 1, |
1216 CSF_WHILE | CSF_FOR, &cstack.cs_looplevel); | |
7 | 1217 } |
1218 } | |
1219 | |
1220 /* | |
72 | 1221 * For a ":while" or ":for" we need to remember the line number. |
7 | 1222 */ |
72 | 1223 else if (cstack.cs_lflags & CSL_HAD_LOOP) |
1224 { | |
1225 cstack.cs_lflags &= ~CSL_HAD_LOOP; | |
7 | 1226 cstack.cs_line[cstack.cs_idx] = current_line - 1; |
1227 } | |
1228 } | |
1229 | |
1230 /* | |
1231 * When not inside any ":while" loop, clear remembered lines. | |
1232 */ | |
72 | 1233 if (cstack.cs_looplevel == 0) |
7 | 1234 { |
1235 if (lines_ga.ga_len > 0) | |
1236 { | |
1237 sourcing_lnum = | |
1238 ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; | |
1239 free_cmdlines(&lines_ga); | |
1240 } | |
1241 current_line = 0; | |
1242 } | |
1243 | |
1244 /* | |
72 | 1245 * A ":finally" makes did_emsg, got_int, and did_throw pending for |
1246 * being restored at the ":endtry". Reset them here and set the | |
1247 * ACTIVE and FINALLY flags, so that the finally clause gets executed. | |
1248 * This includes the case where a missing ":endif", ":endwhile" or | |
1249 * ":endfor" was detected by the ":finally" itself. | |
7 | 1250 */ |
72 | 1251 if (cstack.cs_lflags & CSL_HAD_FINA) |
1252 { | |
1253 cstack.cs_lflags &= ~CSL_HAD_FINA; | |
1254 report_make_pending(cstack.cs_pending[cstack.cs_idx] | |
1255 & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW), | |
7 | 1256 did_throw ? (void *)current_exception : NULL); |
1257 did_emsg = got_int = did_throw = FALSE; | |
1258 cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY; | |
1259 } | |
1260 | |
1261 /* Update global "trylevel" for recursive calls to do_cmdline() from | |
1262 * within this loop. */ | |
1263 trylevel = initial_trylevel + cstack.cs_trylevel; | |
1264 | |
1265 /* | |
1190 | 1266 * If the outermost try conditional (across function calls and sourced |
7 | 1267 * files) is aborted because of an error, an interrupt, or an uncaught |
1268 * exception, cancel everything. If it is left normally, reset | |
1269 * force_abort to get the non-EH compatible abortion behavior for | |
1270 * the rest of the script. | |
1271 */ | |
1272 if (trylevel == 0 && !did_emsg && !got_int && !did_throw) | |
1273 force_abort = FALSE; | |
1274 | |
1275 /* Convert an interrupt to an exception if appropriate. */ | |
1276 (void)do_intthrow(&cstack); | |
1277 #endif /* FEAT_EVAL */ | |
1278 | |
1279 } | |
1280 /* | |
1281 * Continue executing command lines when: | |
1282 * - no CTRL-C typed, no aborting error, no exception thrown or try | |
1283 * conditionals need to be checked for executing finally clauses or | |
1284 * catching an interrupt exception | |
1285 * - didn't get an error message or lines are not typed | |
72 | 1286 * - there is a command after '|', inside a :if, :while, :for or :try, or |
7 | 1287 * looping for ":source" command or function call. |
1288 */ | |
1289 while (!((got_int | |
1290 #ifdef FEAT_EVAL | |
1291 || (did_emsg && force_abort) || did_throw | |
1292 #endif | |
1293 ) | |
1294 #ifdef FEAT_EVAL | |
1295 && cstack.cs_trylevel == 0 | |
1296 #endif | |
1297 ) | |
3757 | 1298 && !(did_emsg |
1299 #ifdef FEAT_EVAL | |
1300 /* Keep going when inside try/catch, so that the error can be | |
1301 * dealth with, except when it is a syntax error, it may cause | |
1302 * the :endtry to be missed. */ | |
1303 && (cstack.cs_trylevel == 0 || did_emsg_syntax) | |
1304 #endif | |
1305 && used_getline | |
2635 | 1306 && (getline_equal(fgetline, cookie, getexmodeline) |
1307 || getline_equal(fgetline, cookie, getexline))) | |
7 | 1308 && (next_cmdline != NULL |
1309 #ifdef FEAT_EVAL | |
1310 || cstack.cs_idx >= 0 | |
1311 #endif | |
1312 || (flags & DOCMD_REPEAT))); | |
1313 | |
1314 vim_free(cmdline_copy); | |
3757 | 1315 did_emsg_syntax = FALSE; |
7 | 1316 #ifdef FEAT_EVAL |
1317 free_cmdlines(&lines_ga); | |
1318 ga_clear(&lines_ga); | |
1319 | |
1320 if (cstack.cs_idx >= 0) | |
1321 { | |
1322 /* | |
1323 * If a sourced file or executed function ran to its end, report the | |
1324 * unclosed conditional. | |
1325 */ | |
1326 if (!got_int && !did_throw | |
2635 | 1327 && ((getline_equal(fgetline, cookie, getsourceline) |
1328 && !source_finished(fgetline, cookie)) | |
1329 || (getline_equal(fgetline, cookie, get_func_line) | |
7 | 1330 && !func_has_ended(real_cookie)))) |
1331 { | |
1332 if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY) | |
1333 EMSG(_(e_endtry)); | |
1334 else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE) | |
1335 EMSG(_(e_endwhile)); | |
72 | 1336 else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR) |
1337 EMSG(_(e_endfor)); | |
7 | 1338 else |
1339 EMSG(_(e_endif)); | |
1340 } | |
1341 | |
1342 /* | |
1343 * Reset "trylevel" in case of a ":finish" or ":return" or a missing | |
1344 * ":endtry" in a sourced file or executed function. If the try | |
1345 * conditional is in its finally clause, ignore anything pending. | |
1346 * If it is in a catch clause, finish the caught exception. | |
77 | 1347 * Also cleanup any "cs_forinfo" structures. |
7 | 1348 */ |
1349 do | |
77 | 1350 { |
1351 int idx = cleanup_conditionals(&cstack, 0, TRUE); | |
1352 | |
111 | 1353 if (idx >= 0) |
1354 --idx; /* remove try block not in its finally clause */ | |
77 | 1355 rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR, |
1356 &cstack.cs_looplevel); | |
1357 } | |
1358 while (cstack.cs_idx >= 0); | |
7 | 1359 trylevel = initial_trylevel; |
1360 } | |
1361 | |
72 | 1362 /* If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory |
1363 * lack was reported above and the error message is to be converted to an | |
7 | 1364 * exception, do this now after rewinding the cstack. */ |
2635 | 1365 do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line) |
7 | 1366 ? (char_u *)"endfunction" : (char_u *)NULL); |
1367 | |
1368 if (trylevel == 0) | |
1369 { | |
1370 /* | |
1371 * When an exception is being thrown out of the outermost try | |
1372 * conditional, discard the uncaught exception, disable the conversion | |
1373 * of interrupts or errors to exceptions, and ensure that no more | |
1374 * commands are executed. | |
1375 */ | |
1376 if (did_throw) | |
1377 { | |
1378 void *p = NULL; | |
1379 char_u *saved_sourcing_name; | |
1380 int saved_sourcing_lnum; | |
1381 struct msglist *messages = NULL, *next; | |
1382 | |
1383 /* | |
1384 * If the uncaught exception is a user exception, report it as an | |
1385 * error. If it is an error exception, display the saved error | |
1386 * message now. For an interrupt exception, do nothing; the | |
1387 * interrupt message is given elsewhere. | |
1388 */ | |
1389 switch (current_exception->type) | |
1390 { | |
1391 case ET_USER: | |
272 | 1392 vim_snprintf((char *)IObuff, IOSIZE, |
1393 _("E605: Exception not caught: %s"), | |
7 | 1394 current_exception->value); |
1395 p = vim_strsave(IObuff); | |
1396 break; | |
1397 case ET_ERROR: | |
1398 messages = current_exception->messages; | |
1399 current_exception->messages = NULL; | |
1400 break; | |
1401 case ET_INTERRUPT: | |
1402 break; | |
1403 default: | |
1404 p = vim_strsave((char_u *)_(e_internal)); | |
1405 } | |
1406 | |
1407 saved_sourcing_name = sourcing_name; | |
1408 saved_sourcing_lnum = sourcing_lnum; | |
1409 sourcing_name = current_exception->throw_name; | |
1410 sourcing_lnum = current_exception->throw_lnum; | |
1411 current_exception->throw_name = NULL; | |
1412 | |
1413 discard_current_exception(); /* uses IObuff if 'verbose' */ | |
1414 suppress_errthrow = TRUE; | |
1415 force_abort = TRUE; | |
1416 | |
1417 if (messages != NULL) | |
1418 { | |
1419 do | |
1420 { | |
1421 next = messages->next; | |
1422 emsg(messages->msg); | |
1423 vim_free(messages->msg); | |
1424 vim_free(messages); | |
1425 messages = next; | |
1426 } | |
1427 while (messages != NULL); | |
1428 } | |
1429 else if (p != NULL) | |
1430 { | |
1431 emsg(p); | |
1432 vim_free(p); | |
1433 } | |
1434 vim_free(sourcing_name); | |
1435 sourcing_name = saved_sourcing_name; | |
1436 sourcing_lnum = saved_sourcing_lnum; | |
1437 } | |
1438 | |
1439 /* | |
1440 * On an interrupt or an aborting error not converted to an exception, | |
1441 * disable the conversion of errors to exceptions. (Interrupts are not | |
1442 * converted any more, here.) This enables also the interrupt message | |
1443 * when force_abort is set and did_emsg unset in case of an interrupt | |
1444 * from a finally clause after an error. | |
1445 */ | |
1446 else if (got_int || (did_emsg && force_abort)) | |
1447 suppress_errthrow = TRUE; | |
1448 } | |
1449 | |
1450 /* | |
1451 * The current cstack will be freed when do_cmdline() returns. An uncaught | |
1452 * exception will have to be rethrown in the previous cstack. If a function | |
1453 * has just returned or a script file was just finished and the previous | |
1454 * cstack belongs to the same function or, respectively, script file, it | |
1455 * will have to be checked for finally clauses to be executed due to the | |
1456 * ":return" or ":finish". This is done in do_one_cmd(). | |
1457 */ | |
1458 if (did_throw) | |
1459 need_rethrow = TRUE; | |
2635 | 1460 if ((getline_equal(fgetline, cookie, getsourceline) |
7 | 1461 && ex_nesting_level > source_level(real_cookie)) |
2635 | 1462 || (getline_equal(fgetline, cookie, get_func_line) |
7 | 1463 && ex_nesting_level > func_level(real_cookie) + 1)) |
1464 { | |
1465 if (!did_throw) | |
1466 check_cstack = TRUE; | |
1467 } | |
1468 else | |
1469 { | |
1470 /* When leaving a function, reduce nesting level. */ | |
2635 | 1471 if (getline_equal(fgetline, cookie, get_func_line)) |
7 | 1472 --ex_nesting_level; |
1473 /* | |
1474 * Go to debug mode when returning from a function in which we are | |
1475 * single-stepping. | |
1476 */ | |
2635 | 1477 if ((getline_equal(fgetline, cookie, getsourceline) |
1478 || getline_equal(fgetline, cookie, get_func_line)) | |
7 | 1479 && ex_nesting_level + 1 <= debug_break_level) |
2635 | 1480 do_debug(getline_equal(fgetline, cookie, getsourceline) |
7 | 1481 ? (char_u *)_("End of sourced file") |
1482 : (char_u *)_("End of function")); | |
1483 } | |
1484 | |
1485 /* | |
1486 * Restore the exception environment (done after returning from the | |
1487 * debugger). | |
1488 */ | |
1489 if (flags & DOCMD_EXCRESET) | |
8 | 1490 restore_dbg_stuff(&debug_saved); |
7 | 1491 |
1492 msg_list = saved_msg_list; | |
1493 #endif /* FEAT_EVAL */ | |
1494 | |
1495 /* | |
1496 * If there was too much output to fit on the command line, ask the user to | |
1497 * hit return before redrawing the screen. With the ":global" command we do | |
1498 * this only once after the command is finished. | |
1499 */ | |
1500 if (did_inc) | |
1501 { | |
1502 --RedrawingDisabled; | |
1503 --no_wait_return; | |
1504 msg_scroll = FALSE; | |
1505 | |
1506 /* | |
1507 * When just finished an ":if"-":else" which was typed, no need to | |
1508 * wait for hit-return. Also for an error situation. | |
1509 */ | |
1510 if (retval == FAIL | |
1511 #ifdef FEAT_EVAL | |
1512 || (did_endif && KeyTyped && !did_emsg) | |
1513 #endif | |
1514 ) | |
1515 { | |
1516 need_wait_return = FALSE; | |
1517 msg_didany = FALSE; /* don't wait when restarting edit */ | |
1518 } | |
1519 else if (need_wait_return) | |
1520 { | |
1521 /* | |
1522 * The msg_start() above clears msg_didout. The wait_return we do | |
1523 * here should not overwrite the command that may be shown before | |
1524 * doing that. | |
1525 */ | |
1526 msg_didout |= msg_didout_before_start; | |
1527 wait_return(FALSE); | |
1528 } | |
1529 } | |
1530 | |
3976 | 1531 #ifdef FEAT_EVAL |
1532 did_endif = FALSE; /* in case do_cmdline used recursively */ | |
1533 #else | |
7 | 1534 /* |
1535 * Reset if_level, in case a sourced script file contains more ":if" than | |
1536 * ":endif" (could be ":if x | foo | endif"). | |
1537 */ | |
1538 if_level = 0; | |
3972 | 1539 #endif |
3963 | 1540 |
7 | 1541 --call_depth; |
1542 return retval; | |
1543 } | |
1544 | |
1545 #ifdef FEAT_EVAL | |
1546 /* | |
72 | 1547 * Obtain a line when inside a ":while" or ":for" loop. |
7 | 1548 */ |
1549 static char_u * | |
72 | 1550 get_loop_line(c, cookie, indent) |
7 | 1551 int c; |
1552 void *cookie; | |
1553 int indent; | |
1554 { | |
72 | 1555 struct loop_cookie *cp = (struct loop_cookie *)cookie; |
7 | 1556 wcmd_T *wp; |
1557 char_u *line; | |
1558 | |
1559 if (cp->current_line + 1 >= cp->lines_gap->ga_len) | |
1560 { | |
1561 if (cp->repeating) | |
72 | 1562 return NULL; /* trying to read past ":endwhile"/":endfor" */ |
1563 | |
1564 /* First time inside the ":while"/":for": get line normally. */ | |
7 | 1565 if (cp->getline == NULL) |
1566 line = getcmdline(c, 0L, indent); | |
1567 else | |
1568 line = cp->getline(c, cp->cookie, indent); | |
857 | 1569 if (line != NULL && store_loop_line(cp->lines_gap, line) == OK) |
7 | 1570 ++cp->current_line; |
1571 | |
1572 return line; | |
1573 } | |
1574 | |
1575 KeyTyped = FALSE; | |
1576 ++cp->current_line; | |
1577 wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line; | |
1578 sourcing_lnum = wp->lnum; | |
1579 return vim_strsave(wp->line); | |
1580 } | |
1581 | |
1582 /* | |
1583 * Store a line in "gap" so that a ":while" loop can execute it again. | |
1584 */ | |
1585 static int | |
72 | 1586 store_loop_line(gap, line) |
7 | 1587 garray_T *gap; |
1588 char_u *line; | |
1589 { | |
1590 if (ga_grow(gap, 1) == FAIL) | |
1591 return FAIL; | |
1592 ((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line); | |
1593 ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum; | |
1594 ++gap->ga_len; | |
1595 return OK; | |
1596 } | |
1597 | |
1598 /* | |
72 | 1599 * Free the lines stored for a ":while" or ":for" loop. |
7 | 1600 */ |
1601 static void | |
1602 free_cmdlines(gap) | |
1603 garray_T *gap; | |
1604 { | |
1605 while (gap->ga_len > 0) | |
1606 { | |
1607 vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line); | |
1608 --gap->ga_len; | |
1609 } | |
1610 } | |
1611 #endif | |
1612 | |
1613 /* | |
944 | 1614 * If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals |
1615 * "func". * Otherwise return TRUE when "fgetline" equals "func". | |
7 | 1616 */ |
1617 int | |
944 | 1618 getline_equal(fgetline, cookie, func) |
1619 char_u *(*fgetline) __ARGS((int, void *, int)); | |
1877 | 1620 void *cookie UNUSED; /* argument for fgetline() */ |
7 | 1621 char_u *(*func) __ARGS((int, void *, int)); |
1622 { | |
1623 #ifdef FEAT_EVAL | |
1624 char_u *(*gp) __ARGS((int, void *, int)); | |
72 | 1625 struct loop_cookie *cp; |
1626 | |
944 | 1627 /* When "fgetline" is "get_loop_line()" use the "cookie" to find the |
1190 | 1628 * function that's originally used to obtain the lines. This may be |
1629 * nested several levels. */ | |
944 | 1630 gp = fgetline; |
72 | 1631 cp = (struct loop_cookie *)cookie; |
1632 while (gp == get_loop_line) | |
7 | 1633 { |
1634 gp = cp->getline; | |
1635 cp = cp->cookie; | |
1636 } | |
1637 return gp == func; | |
1638 #else | |
944 | 1639 return fgetline == func; |
7 | 1640 #endif |
1641 } | |
1642 | |
1643 #if defined(FEAT_EVAL) || defined(FEAT_MBYTE) || defined(PROTO) | |
1644 /* | |
944 | 1645 * If "fgetline" is get_loop_line(), return the cookie used by the original |
7 | 1646 * getline function. Otherwise return "cookie". |
1647 */ | |
1648 void * | |
944 | 1649 getline_cookie(fgetline, cookie) |
1877 | 1650 char_u *(*fgetline) __ARGS((int, void *, int)) UNUSED; |
944 | 1651 void *cookie; /* argument for fgetline() */ |
7 | 1652 { |
1653 # ifdef FEAT_EVAL | |
1654 char_u *(*gp) __ARGS((int, void *, int)); | |
72 | 1655 struct loop_cookie *cp; |
1656 | |
944 | 1657 /* When "fgetline" is "get_loop_line()" use the "cookie" to find the |
1190 | 1658 * cookie that's originally used to obtain the lines. This may be nested |
7 | 1659 * several levels. */ |
944 | 1660 gp = fgetline; |
72 | 1661 cp = (struct loop_cookie *)cookie; |
1662 while (gp == get_loop_line) | |
7 | 1663 { |
1664 gp = cp->getline; | |
1665 cp = cp->cookie; | |
1666 } | |
1667 return cp; | |
1668 # else | |
1669 return cookie; | |
1670 # endif | |
1671 } | |
1672 #endif | |
1673 | |
1674 /* | |
1675 * Execute one Ex command. | |
1676 * | |
1677 * If 'sourcing' is TRUE, the command will be included in the error message. | |
1678 * | |
1679 * 1. skip comment lines and leading space | |
1680 * 2. handle command modifiers | |
1681 * 3. parse range | |
1682 * 4. parse command | |
1683 * 5. parse arguments | |
1684 * 6. switch on command name | |
1685 * | |
944 | 1686 * Note: "fgetline" can be NULL. |
7 | 1687 * |
1688 * This function may be called recursively! | |
1689 */ | |
1690 #if (_MSC_VER == 1200) | |
1691 /* | |
8 | 1692 * Avoid optimisation bug in VC++ version 6.0 |
7 | 1693 */ |
128 | 1694 #pragma optimize( "g", off ) |
7 | 1695 #endif |
1696 static char_u * | |
1697 do_one_cmd(cmdlinep, sourcing, | |
1698 #ifdef FEAT_EVAL | |
1699 cstack, | |
1700 #endif | |
944 | 1701 fgetline, cookie) |
7 | 1702 char_u **cmdlinep; |
1703 int sourcing; | |
1704 #ifdef FEAT_EVAL | |
1705 struct condstack *cstack; | |
1706 #endif | |
944 | 1707 char_u *(*fgetline) __ARGS((int, void *, int)); |
1708 void *cookie; /* argument for fgetline() */ | |
7 | 1709 { |
1710 char_u *p; | |
1711 linenr_T lnum; | |
1712 long n; | |
1713 char_u *errormsg = NULL; /* error message */ | |
1714 exarg_T ea; /* Ex command arguments */ | |
1715 long verbose_save = -1; | |
1926 | 1716 int save_msg_scroll = msg_scroll; |
1717 int save_msg_silent = -1; | |
7 | 1718 int did_esilent = 0; |
28 | 1719 #ifdef HAVE_SANDBOX |
1720 int did_sandbox = FALSE; | |
1721 #endif | |
7 | 1722 cmdmod_T save_cmdmod; |
1723 int ni; /* set when Not Implemented */ | |
1724 | |
1725 vim_memset(&ea, 0, sizeof(ea)); | |
1726 ea.line1 = 1; | |
1727 ea.line2 = 1; | |
1728 #ifdef FEAT_EVAL | |
1729 ++ex_nesting_level; | |
1730 #endif | |
1731 | |
3997 | 1732 /* When the last file has not been edited :q has to be typed twice. */ |
7 | 1733 if (quitmore |
1734 #ifdef FEAT_EVAL | |
1735 /* avoid that a function call in 'statusline' does this */ | |
944 | 1736 && !getline_equal(fgetline, cookie, get_func_line) |
4133 | 1737 #endif |
1738 #ifdef FEAT_AUTOCMD | |
3997 | 1739 /* avoid that an autocommand, e.g. QuitPre, does this */ |
1740 && !getline_equal(fgetline, cookie, getnextac) | |
7 | 1741 #endif |
1742 ) | |
1743 --quitmore; | |
1744 | |
1745 /* | |
1746 * Reset browse, confirm, etc.. They are restored when returning, for | |
1747 * recursive calls. | |
1748 */ | |
1749 save_cmdmod = cmdmod; | |
1750 vim_memset(&cmdmod, 0, sizeof(cmdmod)); | |
1751 | |
930 | 1752 /* "#!anything" is handled like a comment. */ |
1753 if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') | |
1754 goto doend; | |
1755 | |
7 | 1756 /* |
1757 * Repeat until no more command modifiers are found. | |
1758 */ | |
1759 ea.cmd = *cmdlinep; | |
1760 for (;;) | |
1761 { | |
1762 /* | |
1763 * 1. skip comment lines and leading white space and colons | |
1764 */ | |
1765 while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') | |
1766 ++ea.cmd; | |
1767 | |
1768 /* in ex mode, an empty line works like :+ */ | |
1769 if (*ea.cmd == NUL && exmode_active | |
944 | 1770 && (getline_equal(fgetline, cookie, getexmodeline) |
1771 || getline_equal(fgetline, cookie, getexline)) | |
167 | 1772 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) |
7 | 1773 { |
1774 ea.cmd = (char_u *)"+"; | |
1775 ex_pressedreturn = TRUE; | |
1776 } | |
1777 | |
1778 /* ignore comment and empty lines */ | |
1442 | 1779 if (*ea.cmd == '"') |
1780 goto doend; | |
1781 if (*ea.cmd == NUL) | |
167 | 1782 { |
1783 ex_pressedreturn = TRUE; | |
7 | 1784 goto doend; |
167 | 1785 } |
7 | 1786 |
1787 /* | |
1788 * 2. handle command modifiers. | |
1789 */ | |
1790 p = ea.cmd; | |
1791 if (VIM_ISDIGIT(*ea.cmd)) | |
1792 p = skipwhite(skipdigits(ea.cmd)); | |
1793 switch (*p) | |
1794 { | |
1795 /* When adding an entry, also modify cmd_exists(). */ | |
1796 case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) | |
1797 break; | |
1798 #ifdef FEAT_WINDOWS | |
1799 cmdmod.split |= WSP_ABOVE; | |
1800 #endif | |
1801 continue; | |
1802 | |
1803 case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) | |
1804 { | |
1805 #ifdef FEAT_WINDOWS | |
1806 cmdmod.split |= WSP_BELOW; | |
1807 #endif | |
1808 continue; | |
1809 } | |
1810 if (checkforcmd(&ea.cmd, "browse", 3)) | |
1811 { | |
1733 | 1812 #ifdef FEAT_BROWSE_CMD |
7 | 1813 cmdmod.browse = TRUE; |
1814 #endif | |
1815 continue; | |
1816 } | |
1817 if (!checkforcmd(&ea.cmd, "botright", 2)) | |
1818 break; | |
1819 #ifdef FEAT_WINDOWS | |
1820 cmdmod.split |= WSP_BOT; | |
1821 #endif | |
1822 continue; | |
1823 | |
1824 case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) | |
1825 break; | |
1826 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) | |
1827 cmdmod.confirm = TRUE; | |
1828 #endif | |
1829 continue; | |
1830 | |
1831 case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) | |
1832 { | |
1833 cmdmod.keepmarks = TRUE; | |
1834 continue; | |
1835 } | |
22 | 1836 if (checkforcmd(&ea.cmd, "keepalt", 5)) |
1837 { | |
1838 cmdmod.keepalt = TRUE; | |
1839 continue; | |
1840 } | |
7 | 1841 if (!checkforcmd(&ea.cmd, "keepjumps", 5)) |
1842 break; | |
1843 cmdmod.keepjumps = TRUE; | |
1844 continue; | |
1845 | |
1846 /* ":hide" and ":hide | cmd" are not modifiers */ | |
1847 case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) | |
1848 || *p == NUL || ends_excmd(*p)) | |
1849 break; | |
1850 ea.cmd = p; | |
1851 cmdmod.hide = TRUE; | |
1852 continue; | |
1853 | |
1854 case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) | |
1855 { | |
1856 cmdmod.lockmarks = TRUE; | |
1857 continue; | |
1858 } | |
1859 | |
1860 if (!checkforcmd(&ea.cmd, "leftabove", 5)) | |
1861 break; | |
1862 #ifdef FEAT_WINDOWS | |
1863 cmdmod.split |= WSP_ABOVE; | |
1864 #endif | |
1865 continue; | |
1866 | |
588 | 1867 case 'n': if (!checkforcmd(&ea.cmd, "noautocmd", 3)) |
1868 break; | |
1869 #ifdef FEAT_AUTOCMD | |
1870 if (cmdmod.save_ei == NULL) | |
1871 { | |
844 | 1872 /* Set 'eventignore' to "all". Restore the |
1873 * existing option value later. */ | |
588 | 1874 cmdmod.save_ei = vim_strsave(p_ei); |
1875 set_string_option_direct((char_u *)"ei", -1, | |
694 | 1876 (char_u *)"all", OPT_FREE, SID_NONE); |
588 | 1877 } |
1878 #endif | |
1879 continue; | |
1880 | |
7 | 1881 case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) |
1882 break; | |
1883 #ifdef FEAT_WINDOWS | |
1884 cmdmod.split |= WSP_BELOW; | |
1885 #endif | |
1886 continue; | |
1887 | |
28 | 1888 case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) |
1889 { | |
1890 #ifdef HAVE_SANDBOX | |
1891 if (!did_sandbox) | |
1892 ++sandbox; | |
1893 did_sandbox = TRUE; | |
1894 #endif | |
1895 continue; | |
1896 } | |
1897 if (!checkforcmd(&ea.cmd, "silent", 3)) | |
7 | 1898 break; |
1926 | 1899 if (save_msg_silent == -1) |
1900 save_msg_silent = msg_silent; | |
7 | 1901 ++msg_silent; |
1902 if (*ea.cmd == '!' && !vim_iswhite(ea.cmd[-1])) | |
1903 { | |
1904 /* ":silent!", but not "silent !cmd" */ | |
1905 ea.cmd = skipwhite(ea.cmd + 1); | |
1906 ++emsg_silent; | |
1907 ++did_esilent; | |
1908 } | |
1909 continue; | |
1910 | |
682 | 1911 case 't': if (checkforcmd(&p, "tab", 3)) |
1912 { | |
1913 #ifdef FEAT_WINDOWS | |
1914 if (vim_isdigit(*ea.cmd)) | |
1915 cmdmod.tab = atoi((char *)ea.cmd) + 1; | |
1916 else | |
685 | 1917 cmdmod.tab = tabpage_index(curtab) + 1; |
682 | 1918 ea.cmd = p; |
1919 #endif | |
1920 continue; | |
1921 } | |
1922 if (!checkforcmd(&ea.cmd, "topleft", 2)) | |
7 | 1923 break; |
1924 #ifdef FEAT_WINDOWS | |
1925 cmdmod.split |= WSP_TOP; | |
1926 #endif | |
1927 continue; | |
1928 | |
1926 | 1929 case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) |
1930 break; | |
1931 if (save_msg_silent == -1) | |
1932 save_msg_silent = msg_silent; | |
1933 msg_silent = 0; | |
1934 continue; | |
1935 | |
7 | 1936 case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) |
1937 { | |
1938 #ifdef FEAT_VERTSPLIT | |
1939 cmdmod.split |= WSP_VERT; | |
1940 #endif | |
1941 continue; | |
1942 } | |
1943 if (!checkforcmd(&p, "verbose", 4)) | |
1944 break; | |
1945 if (verbose_save < 0) | |
1946 verbose_save = p_verbose; | |
8 | 1947 if (vim_isdigit(*ea.cmd)) |
1948 p_verbose = atoi((char *)ea.cmd); | |
1949 else | |
7 | 1950 p_verbose = 1; |
1951 ea.cmd = p; | |
1952 continue; | |
1953 } | |
1954 break; | |
1955 } | |
1956 | |
1957 #ifdef FEAT_EVAL | |
1958 ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0 | |
1959 && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)); | |
1960 #else | |
1961 ea.skip = (if_level > 0); | |
1962 #endif | |
1963 | |
1964 #ifdef FEAT_EVAL | |
170 | 1965 # ifdef FEAT_PROFILE |
1966 /* Count this line for profiling if ea.skip is FALSE. */ | |
788 | 1967 if (do_profiling == PROF_YES && !ea.skip) |
170 | 1968 { |
944 | 1969 if (getline_equal(fgetline, cookie, get_func_line)) |
1970 func_line_exec(getline_cookie(fgetline, cookie)); | |
1971 else if (getline_equal(fgetline, cookie, getsourceline)) | |
170 | 1972 script_line_exec(); |
1973 } | |
1974 #endif | |
1975 | |
7 | 1976 /* May go to debug mode. If this happens and the ">quit" debug command is |
1977 * used, throw an interrupt exception and skip the next command. */ | |
1978 dbg_check_breakpoint(&ea); | |
1979 if (!ea.skip && got_int) | |
1980 { | |
1981 ea.skip = TRUE; | |
1982 (void)do_intthrow(cstack); | |
1983 } | |
1984 #endif | |
1985 | |
1986 /* | |
1987 * 3. parse a range specifier of the form: addr [,addr] [;addr] .. | |
1988 * | |
1989 * where 'addr' is: | |
1990 * | |
1991 * % (entire file) | |
1992 * $ [+-NUM] | |
1993 * 'x [+-NUM] (where x denotes a currently defined mark) | |
1994 * . [+-NUM] | |
1995 * [+-NUM].. | |
1996 * NUM | |
1997 * | |
1998 * The ea.cmd pointer is updated to point to the first character following the | |
1999 * range spec. If an initial address is found, but no second, the upper bound | |
2000 * is equal to the lower. | |
2001 */ | |
2002 | |
2003 /* repeat for all ',' or ';' separated addresses */ | |
2004 for (;;) | |
2005 { | |
2006 ea.line1 = ea.line2; | |
2007 ea.line2 = curwin->w_cursor.lnum; /* default is current line number */ | |
2008 ea.cmd = skipwhite(ea.cmd); | |
2009 lnum = get_address(&ea.cmd, ea.skip, ea.addr_count == 0); | |
2010 if (ea.cmd == NULL) /* error detected */ | |
2011 goto doend; | |
2012 if (lnum == MAXLNUM) | |
2013 { | |
2014 if (*ea.cmd == '%') /* '%' - all lines */ | |
2015 { | |
2016 ++ea.cmd; | |
2017 ea.line1 = 1; | |
2018 ea.line2 = curbuf->b_ml.ml_line_count; | |
2019 ++ea.addr_count; | |
2020 } | |
2021 /* '*' - visual area */ | |
2022 else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) | |
2023 { | |
2024 pos_T *fp; | |
2025 | |
2026 ++ea.cmd; | |
2027 if (!ea.skip) | |
2028 { | |
2029 fp = getmark('<', FALSE); | |
2030 if (check_mark(fp) == FAIL) | |
2031 goto doend; | |
2032 ea.line1 = fp->lnum; | |
2033 fp = getmark('>', FALSE); | |
2034 if (check_mark(fp) == FAIL) | |
2035 goto doend; | |
2036 ea.line2 = fp->lnum; | |
2037 ++ea.addr_count; | |
2038 } | |
2039 } | |
2040 } | |
2041 else | |
2042 ea.line2 = lnum; | |
2043 ea.addr_count++; | |
2044 | |
2045 if (*ea.cmd == ';') | |
2046 { | |
2047 if (!ea.skip) | |
2048 curwin->w_cursor.lnum = ea.line2; | |
2049 } | |
2050 else if (*ea.cmd != ',') | |
2051 break; | |
2052 ++ea.cmd; | |
2053 } | |
2054 | |
2055 /* One address given: set start and end lines */ | |
2056 if (ea.addr_count == 1) | |
2057 { | |
2058 ea.line1 = ea.line2; | |
2059 /* ... but only implicit: really no address given */ | |
2060 if (lnum == MAXLNUM) | |
2061 ea.addr_count = 0; | |
2062 } | |
2063 | |
2064 /* Don't leave the cursor on an illegal line (caused by ';') */ | |
2065 check_cursor_lnum(); | |
2066 | |
2067 /* | |
2068 * 4. parse command | |
2069 */ | |
2070 | |
2071 /* | |
2072 * Skip ':' and any white space | |
2073 */ | |
2074 ea.cmd = skipwhite(ea.cmd); | |
2075 while (*ea.cmd == ':') | |
2076 ea.cmd = skipwhite(ea.cmd + 1); | |
2077 | |
2078 /* | |
2079 * If we got a line, but no command, then go to the line. | |
2080 * If we find a '|' or '\n' we set ea.nextcmd. | |
2081 */ | |
2082 if (*ea.cmd == NUL || *ea.cmd == '"' || | |
2083 (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) | |
2084 { | |
2085 /* | |
2086 * strange vi behaviour: | |
2087 * ":3" jumps to line 3 | |
2088 * ":3|..." prints line 3 | |
2089 * ":|" prints current line | |
2090 */ | |
2091 if (ea.skip) /* skip this if inside :if */ | |
2092 goto doend; | |
167 | 2093 if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) |
7 | 2094 { |
2095 ea.cmdidx = CMD_print; | |
2096 ea.argt = RANGE+COUNT+TRLBAR; | |
2097 if ((errormsg = invalid_range(&ea)) == NULL) | |
2098 { | |
2099 correct_range(&ea); | |
2100 ex_print(&ea); | |
2101 } | |
2102 } | |
2103 else if (ea.addr_count != 0) | |
2104 { | |
631 | 2105 if (ea.line2 > curbuf->b_ml.ml_line_count) |
2106 { | |
2107 /* With '-' in 'cpoptions' a line number past the file is an | |
2108 * error, otherwise put it at the end of the file. */ | |
2109 if (vim_strchr(p_cpo, CPO_MINUS) != NULL) | |
2110 ea.line2 = -1; | |
2111 else | |
2112 ea.line2 = curbuf->b_ml.ml_line_count; | |
2113 } | |
2114 | |
2115 if (ea.line2 < 0) | |
167 | 2116 errormsg = (char_u *)_(e_invrange); |
7 | 2117 else |
2118 { | |
2119 if (ea.line2 == 0) | |
2120 curwin->w_cursor.lnum = 1; | |
2121 else | |
2122 curwin->w_cursor.lnum = ea.line2; | |
2123 beginline(BL_SOL | BL_FIX); | |
2124 } | |
2125 } | |
2126 goto doend; | |
2127 } | |
2128 | |
2129 /* Find the command and let "p" point to after it. */ | |
2130 p = find_command(&ea, NULL); | |
2131 | |
2132 #ifdef FEAT_USR_CMDS | |
2133 if (p == NULL) | |
2134 { | |
2135 if (!ea.skip) | |
2136 errormsg = (char_u *)_("E464: Ambiguous use of user-defined command"); | |
2137 goto doend; | |
2138 } | |
2139 /* Check for wrong commands. */ | |
2140 if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78) | |
2141 { | |
2142 errormsg = uc_fun_cmd(); | |
2143 goto doend; | |
2144 } | |
2145 #endif | |
2146 if (ea.cmdidx == CMD_SIZE) | |
2147 { | |
2148 if (!ea.skip) | |
2149 { | |
2150 STRCPY(IObuff, _("E492: Not an editor command")); | |
2151 if (!sourcing) | |
3097 | 2152 append_command(*cmdlinep); |
7 | 2153 errormsg = IObuff; |
3757 | 2154 did_emsg_syntax = TRUE; |
7 | 2155 } |
2156 goto doend; | |
2157 } | |
2158 | |
2159 ni = ( | |
2160 #ifdef FEAT_USR_CMDS | |
2161 !USER_CMDIDX(ea.cmdidx) && | |
2162 #endif | |
1305 | 2163 (cmdnames[ea.cmdidx].cmd_func == ex_ni |
1315 | 2164 #ifdef HAVE_EX_SCRIPT_NI |
2165 || cmdnames[ea.cmdidx].cmd_func == ex_script_ni | |
2166 #endif | |
2167 )); | |
7 | 2168 |
2169 #ifndef FEAT_EVAL | |
2170 /* | |
2171 * When the expression evaluation is disabled, recognize the ":if" and | |
2172 * ":endif" commands and ignore everything in between it. | |
2173 */ | |
2174 if (ea.cmdidx == CMD_if) | |
2175 ++if_level; | |
2176 if (if_level) | |
2177 { | |
2178 if (ea.cmdidx == CMD_endif) | |
2179 --if_level; | |
2180 goto doend; | |
2181 } | |
2182 | |
2183 #endif | |
2184 | |
1613 | 2185 /* forced commands */ |
2186 if (*p == '!' && ea.cmdidx != CMD_substitute | |
2187 && ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic) | |
7 | 2188 { |
2189 ++p; | |
2190 ea.forceit = TRUE; | |
2191 } | |
2192 else | |
2193 ea.forceit = FALSE; | |
2194 | |
2195 /* | |
2196 * 5. parse arguments | |
2197 */ | |
2198 #ifdef FEAT_USR_CMDS | |
2199 if (!USER_CMDIDX(ea.cmdidx)) | |
2200 #endif | |
835 | 2201 ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt; |
7 | 2202 |
2203 if (!ea.skip) | |
2204 { | |
2205 #ifdef HAVE_SANDBOX | |
2206 if (sandbox != 0 && !(ea.argt & SBOXOK)) | |
2207 { | |
2208 /* Command not allowed in sandbox. */ | |
2209 errormsg = (char_u *)_(e_sandbox); | |
2210 goto doend; | |
2211 } | |
2212 #endif | |
2213 if (!curbuf->b_p_ma && (ea.argt & MODIFY)) | |
2214 { | |
2215 /* Command not allowed in non-'modifiable' buffer */ | |
2216 errormsg = (char_u *)_(e_modifiable); | |
2217 goto doend; | |
2218 } | |
631 | 2219 |
633 | 2220 if (text_locked() && !(ea.argt & CMDWIN) |
7 | 2221 # ifdef FEAT_USR_CMDS |
2222 && !USER_CMDIDX(ea.cmdidx) | |
2223 # endif | |
2224 ) | |
2225 { | |
631 | 2226 /* Command not allowed when editing the command line. */ |
2227 #ifdef FEAT_CMDWIN | |
2228 if (cmdwin_type != 0) | |
2229 errormsg = (char_u *)_(e_cmdwin); | |
2230 else | |
2231 #endif | |
2232 errormsg = (char_u *)_(e_secure); | |
7 | 2233 goto doend; |
2234 } | |
819 | 2235 #ifdef FEAT_AUTOCMD |
822 | 2236 /* Disallow editing another buffer when "curbuf_lock" is set. |
2237 * Do allow ":edit" (check for argument later). | |
2238 * Do allow ":checktime" (it's postponed). */ | |
819 | 2239 if (!(ea.argt & CMDWIN) |
822 | 2240 && ea.cmdidx != CMD_edit |
2241 && ea.cmdidx != CMD_checktime | |
819 | 2242 # ifdef FEAT_USR_CMDS |
2243 && !USER_CMDIDX(ea.cmdidx) | |
2244 # endif | |
2245 && curbuf_locked()) | |
2246 goto doend; | |
2247 #endif | |
7 | 2248 |
2249 if (!ni && !(ea.argt & RANGE) && ea.addr_count > 0) | |
2250 { | |
2251 /* no range allowed */ | |
2252 errormsg = (char_u *)_(e_norange); | |
2253 goto doend; | |
2254 } | |
2255 } | |
2256 | |
2257 if (!ni && !(ea.argt & BANG) && ea.forceit) /* no <!> allowed */ | |
2258 { | |
2259 errormsg = (char_u *)_(e_nobang); | |
2260 goto doend; | |
2261 } | |
2262 | |
2263 /* | |
2264 * Don't complain about the range if it is not used | |
2265 * (could happen if line_count is accidentally set to 0). | |
2266 */ | |
2267 if (!ea.skip && !ni) | |
2268 { | |
2269 /* | |
2270 * If the range is backwards, ask for confirmation and, if given, swap | |
2271 * ea.line1 & ea.line2 so it's forwards again. | |
2272 * When global command is busy, don't ask, will fail below. | |
2273 */ | |
2274 if (!global_busy && ea.line1 > ea.line2) | |
2275 { | |
557 | 2276 if (msg_silent == 0) |
2277 { | |
2278 if (sourcing || exmode_active) | |
2279 { | |
2280 errormsg = (char_u *)_("E493: Backwards range given"); | |
2281 goto doend; | |
2282 } | |
7 | 2283 if (ask_yesno((char_u *) |
2284 _("Backwards range given, OK to swap"), FALSE) != 'y') | |
557 | 2285 goto doend; |
7 | 2286 } |
2287 lnum = ea.line1; | |
2288 ea.line1 = ea.line2; | |
2289 ea.line2 = lnum; | |
2290 } | |
2291 if ((errormsg = invalid_range(&ea)) != NULL) | |
2292 goto doend; | |
2293 } | |
2294 | |
2295 if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */ | |
2296 ea.line2 = 1; | |
2297 | |
2298 correct_range(&ea); | |
2299 | |
2300 #ifdef FEAT_FOLDING | |
2301 if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy) | |
2302 { | |
2303 /* Put the first line at the start of a closed fold, put the last line | |
2304 * at the end of a closed fold. */ | |
2305 (void)hasFolding(ea.line1, &ea.line1, NULL); | |
2306 (void)hasFolding(ea.line2, NULL, &ea.line2); | |
2307 } | |
2308 #endif | |
2309 | |
2310 #ifdef FEAT_QUICKFIX | |
2311 /* | |
41 | 2312 * For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' |
7 | 2313 * option here, so things like % get expanded. |
2314 */ | |
344 | 2315 p = replace_makeprg(&ea, p, cmdlinep); |
2316 if (p == NULL) | |
2317 goto doend; | |
7 | 2318 #endif |
2319 | |
2320 /* | |
2321 * Skip to start of argument. | |
2322 * Don't do this for the ":!" command, because ":!! -l" needs the space. | |
2323 */ | |
2324 if (ea.cmdidx == CMD_bang) | |
2325 ea.arg = p; | |
2326 else | |
2327 ea.arg = skipwhite(p); | |
2328 | |
2329 /* | |
2330 * Check for "++opt=val" argument. | |
2331 * Must be first, allow ":w ++enc=utf8 !cmd" | |
2332 */ | |
2333 if (ea.argt & ARGOPT) | |
2334 while (ea.arg[0] == '+' && ea.arg[1] == '+') | |
2335 if (getargopt(&ea) == FAIL && !ni) | |
2336 { | |
2337 errormsg = (char_u *)_(e_invarg); | |
2338 goto doend; | |
2339 } | |
2340 | |
2341 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) | |
2342 { | |
2343 if (*ea.arg == '>') /* append */ | |
2344 { | |
2345 if (*++ea.arg != '>') /* typed wrong */ | |
2346 { | |
2347 errormsg = (char_u *)_("E494: Use w or w>>"); | |
2348 goto doend; | |
2349 } | |
2350 ea.arg = skipwhite(ea.arg + 1); | |
2351 ea.append = TRUE; | |
2352 } | |
2353 else if (*ea.arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */ | |
2354 { | |
2355 ++ea.arg; | |
2356 ea.usefilter = TRUE; | |
2357 } | |
2358 } | |
2359 | |
2360 if (ea.cmdidx == CMD_read) | |
2361 { | |
2362 if (ea.forceit) | |
2363 { | |
2364 ea.usefilter = TRUE; /* :r! filter if ea.forceit */ | |
2365 ea.forceit = FALSE; | |
2366 } | |
2367 else if (*ea.arg == '!') /* :r !filter */ | |
2368 { | |
2369 ++ea.arg; | |
2370 ea.usefilter = TRUE; | |
2371 } | |
2372 } | |
2373 | |
2374 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) | |
2375 { | |
2376 ea.amount = 1; | |
2377 while (*ea.arg == *ea.cmd) /* count number of '>' or '<' */ | |
2378 { | |
2379 ++ea.arg; | |
2380 ++ea.amount; | |
2381 } | |
2382 ea.arg = skipwhite(ea.arg); | |
2383 } | |
2384 | |
2385 /* | |
2386 * Check for "+command" argument, before checking for next command. | |
2387 * Don't do this for ":read !cmd" and ":write !cmd". | |
2388 */ | |
2389 if ((ea.argt & EDITCMD) && !ea.usefilter) | |
2390 ea.do_ecmd_cmd = getargcmd(&ea.arg); | |
2391 | |
2392 /* | |
2393 * Check for '|' to separate commands and '"' to start comments. | |
2394 * Don't do this for ":read !cmd" and ":write !cmd". | |
2395 */ | |
2396 if ((ea.argt & TRLBAR) && !ea.usefilter) | |
2397 separate_nextcmd(&ea); | |
2398 | |
2399 /* | |
2400 * Check for <newline> to end a shell command. | |
167 | 2401 * Also do this for ":read !cmd", ":write !cmd" and ":global". |
2402 * Any others? | |
7 | 2403 */ |
167 | 2404 else if (ea.cmdidx == CMD_bang |
2405 || ea.cmdidx == CMD_global | |
2406 || ea.cmdidx == CMD_vglobal | |
2407 || ea.usefilter) | |
7 | 2408 { |
2409 for (p = ea.arg; *p; ++p) | |
2410 { | |
2411 /* Remove one backslash before a newline, so that it's possible to | |
2412 * pass a newline to the shell and also a newline that is preceded | |
2413 * with a backslash. This makes it impossible to end a shell | |
2414 * command in a backslash, but that doesn't appear useful. | |
2415 * Halving the number of backslashes is incompatible with previous | |
2416 * versions. */ | |
2417 if (*p == '\\' && p[1] == '\n') | |
1619 | 2418 STRMOVE(p, p + 1); |
7 | 2419 else if (*p == '\n') |
2420 { | |
2421 ea.nextcmd = p + 1; | |
2422 *p = NUL; | |
2423 break; | |
2424 } | |
2425 } | |
2426 } | |
2427 | |
2428 if ((ea.argt & DFLALL) && ea.addr_count == 0) | |
2429 { | |
2430 ea.line1 = 1; | |
2431 ea.line2 = curbuf->b_ml.ml_line_count; | |
2432 } | |
2433 | |
2434 /* accept numbered register only when no count allowed (:put) */ | |
2435 if ( (ea.argt & REGSTR) | |
2436 && *ea.arg != NUL | |
2437 #ifdef FEAT_USR_CMDS | |
2438 /* Do not allow register = for user commands */ | |
2439 && (!USER_CMDIDX(ea.cmdidx) || *ea.arg != '=') | |
2440 #endif | |
2441 && !((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg))) | |
2442 { | |
2791 | 2443 #ifndef FEAT_CLIPBOARD |
2444 /* check these explicitly for a more specific error message */ | |
2445 if (*ea.arg == '*' || *ea.arg == '+') | |
2446 { | |
2447 errormsg = (char_u *)_(e_invalidreg); | |
2448 goto doend; | |
2449 } | |
2450 #endif | |
2451 if ( | |
2452 #ifdef FEAT_USR_CMDS | |
2453 valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put | |
2454 && USER_CMDIDX(ea.cmdidx))) | |
2455 #else | |
2456 valid_yank_reg(*ea.arg, ea.cmdidx != CMD_put) | |
2457 #endif | |
2458 ) | |
2459 { | |
2460 ea.regname = *ea.arg++; | |
7 | 2461 #ifdef FEAT_EVAL |
2791 | 2462 /* for '=' register: accept the rest of the line as an expression */ |
2463 if (ea.arg[-1] == '=' && ea.arg[0] != NUL) | |
2464 { | |
2465 set_expr_line(vim_strsave(ea.arg)); | |
2466 ea.arg += STRLEN(ea.arg); | |
2467 } | |
2468 #endif | |
2469 ea.arg = skipwhite(ea.arg); | |
2470 } | |
7 | 2471 } |
2472 | |
2473 /* | |
2474 * Check for a count. When accepting a BUFNAME, don't use "123foo" as a | |
2475 * count, it's a buffer name. | |
2476 */ | |
2477 if ((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg) | |
2478 && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL | |
2479 || vim_iswhite(*p))) | |
2480 { | |
2481 n = getdigits(&ea.arg); | |
2482 ea.arg = skipwhite(ea.arg); | |
682 | 2483 if (n <= 0 && !ni && (ea.argt & ZEROR) == 0) |
7 | 2484 { |
2485 errormsg = (char_u *)_(e_zerocount); | |
2486 goto doend; | |
2487 } | |
2488 if (ea.argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */ | |
2489 { | |
2490 ea.line2 = n; | |
2491 if (ea.addr_count == 0) | |
2492 ea.addr_count = 1; | |
2493 } | |
2494 else | |
2495 { | |
2496 ea.line1 = ea.line2; | |
2497 ea.line2 += n - 1; | |
2498 ++ea.addr_count; | |
2499 /* | |
2500 * Be vi compatible: no error message for out of range. | |
2501 */ | |
2502 if (ea.line2 > curbuf->b_ml.ml_line_count) | |
2503 ea.line2 = curbuf->b_ml.ml_line_count; | |
2504 } | |
2505 } | |
167 | 2506 |
2507 /* | |
2508 * Check for flags: 'l', 'p' and '#'. | |
2509 */ | |
2510 if (ea.argt & EXFLAGS) | |
2511 get_flags(&ea); | |
7 | 2512 /* no arguments allowed */ |
9 | 2513 if (!ni && !(ea.argt & EXTRA) && *ea.arg != NUL |
715 | 2514 && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & TRLBAR) == 0)) |
7 | 2515 { |
2516 errormsg = (char_u *)_(e_trailing); | |
2517 goto doend; | |
2518 } | |
2519 | |
2520 if (!ni && (ea.argt & NEEDARG) && *ea.arg == NUL) | |
2521 { | |
2522 errormsg = (char_u *)_(e_argreq); | |
2523 goto doend; | |
2524 } | |
2525 | |
2526 #ifdef FEAT_EVAL | |
2527 /* | |
2528 * Skip the command when it's not going to be executed. | |
2529 * The commands like :if, :endif, etc. always need to be executed. | |
2530 * Also make an exception for commands that handle a trailing command | |
2531 * themselves. | |
2532 */ | |
2533 if (ea.skip) | |
2534 { | |
2535 switch (ea.cmdidx) | |
2536 { | |
2537 /* commands that need evaluation */ | |
2538 case CMD_while: | |
2539 case CMD_endwhile: | |
72 | 2540 case CMD_for: |
2541 case CMD_endfor: | |
7 | 2542 case CMD_if: |
2543 case CMD_elseif: | |
2544 case CMD_else: | |
2545 case CMD_endif: | |
2546 case CMD_try: | |
2547 case CMD_catch: | |
2548 case CMD_finally: | |
2549 case CMD_endtry: | |
2550 case CMD_function: | |
2551 break; | |
2552 | |
2553 /* Commands that handle '|' themselves. Check: A command should | |
2554 * either have the TRLBAR flag, appear in this list or appear in | |
2555 * the list at ":help :bar". */ | |
2556 case CMD_aboveleft: | |
2557 case CMD_and: | |
2558 case CMD_belowright: | |
2559 case CMD_botright: | |
2560 case CMD_browse: | |
2561 case CMD_call: | |
2562 case CMD_confirm: | |
2563 case CMD_delfunction: | |
2564 case CMD_djump: | |
2565 case CMD_dlist: | |
2566 case CMD_dsearch: | |
2567 case CMD_dsplit: | |
2568 case CMD_echo: | |
2569 case CMD_echoerr: | |
2570 case CMD_echomsg: | |
2571 case CMD_echon: | |
2572 case CMD_execute: | |
2573 case CMD_help: | |
2574 case CMD_hide: | |
2575 case CMD_ijump: | |
2576 case CMD_ilist: | |
2577 case CMD_isearch: | |
2578 case CMD_isplit: | |
22 | 2579 case CMD_keepalt: |
7 | 2580 case CMD_keepjumps: |
2581 case CMD_keepmarks: | |
2582 case CMD_leftabove: | |
2583 case CMD_let: | |
2584 case CMD_lockmarks: | |
2320
966a5609669e
Added Lua interfae. (Luis Carvalho)
Bram Moolenaar <bram@vim.org>
parents:
2311
diff
changeset
|
2585 case CMD_lua: |
7 | 2586 case CMD_match: |
14 | 2587 case CMD_mzscheme: |
7 | 2588 case CMD_perl: |
2589 case CMD_psearch: | |
2590 case CMD_python: | |
2350
06feaf4fe36a
Rename some "python3" symbols to "py3", as the command name.
Bram Moolenaar <bram@vim.org>
parents:
2340
diff
changeset
|
2591 case CMD_py3: |
2366
7a57fe6a5157
Fix that :py3file was not working.
Bram Moolenaar <bram@vim.org>
parents:
2360
diff
changeset
|
2592 case CMD_python3: |
7 | 2593 case CMD_return: |
2594 case CMD_rightbelow: | |
2595 case CMD_ruby: | |
2596 case CMD_silent: | |
2597 case CMD_smagic: | |
2598 case CMD_snomagic: | |
2599 case CMD_substitute: | |
2600 case CMD_syntax: | |
690 | 2601 case CMD_tab: |
7 | 2602 case CMD_tcl: |
2603 case CMD_throw: | |
2604 case CMD_tilde: | |
2605 case CMD_topleft: | |
2606 case CMD_unlet: | |
2607 case CMD_verbose: | |
2608 case CMD_vertical: | |
2887 | 2609 case CMD_wincmd: |
7 | 2610 break; |
2611 | |
2612 default: goto doend; | |
2613 } | |
2614 } | |
2615 #endif | |
2616 | |
2617 if (ea.argt & XFILE) | |
2618 { | |
2619 if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) | |
2620 goto doend; | |
2621 } | |
2622 | |
2623 #ifdef FEAT_LISTCMDS | |
2624 /* | |
2625 * Accept buffer name. Cannot be used at the same time with a buffer | |
2626 * number. Don't do this for a user command. | |
2627 */ | |
2628 if ((ea.argt & BUFNAME) && *ea.arg != NUL && ea.addr_count == 0 | |
2629 # ifdef FEAT_USR_CMDS | |
2630 && !USER_CMDIDX(ea.cmdidx) | |
2631 # endif | |
2632 ) | |
2633 { | |
2634 /* | |
2635 * :bdelete, :bwipeout and :bunload take several arguments, separated | |
2636 * by spaces: find next space (skipping over escaped characters). | |
2637 * The others take one argument: ignore trailing spaces. | |
2638 */ | |
2639 if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout | |
2640 || ea.cmdidx == CMD_bunload) | |
2641 p = skiptowhite_esc(ea.arg); | |
2642 else | |
2643 { | |
2644 p = ea.arg + STRLEN(ea.arg); | |
2645 while (p > ea.arg && vim_iswhite(p[-1])) | |
2646 --p; | |
2647 } | |
2648 ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & BUFUNL) != 0, FALSE); | |
2649 if (ea.line2 < 0) /* failed */ | |
2650 goto doend; | |
2651 ea.addr_count = 1; | |
2652 ea.arg = skipwhite(p); | |
2653 } | |
2654 #endif | |
2655 | |
2656 /* | |
2657 * 6. switch on command name | |
2658 * | |
2659 * The "ea" structure holds the arguments that can be used. | |
2660 */ | |
2661 ea.cmdlinep = cmdlinep; | |
944 | 2662 ea.getline = fgetline; |
7 | 2663 ea.cookie = cookie; |
2664 #ifdef FEAT_EVAL | |
2665 ea.cstack = cstack; | |
2666 #endif | |
2667 | |
2668 #ifdef FEAT_USR_CMDS | |
2669 if (USER_CMDIDX(ea.cmdidx)) | |
2670 { | |
2671 /* | |
2672 * Execute a user-defined command. | |
2673 */ | |
2674 do_ucmd(&ea); | |
2675 } | |
2676 else | |
2677 #endif | |
2678 { | |
2679 /* | |
2680 * Call the function to execute the command. | |
2681 */ | |
2682 ea.errmsg = NULL; | |
2683 (cmdnames[ea.cmdidx].cmd_func)(&ea); | |
2684 if (ea.errmsg != NULL) | |
2685 errormsg = (char_u *)_(ea.errmsg); | |
2686 } | |
2687 | |
2688 #ifdef FEAT_EVAL | |
2689 /* | |
2690 * If the command just executed called do_cmdline(), any throw or ":return" | |
2691 * or ":finish" encountered there must also check the cstack of the still | |
2692 * active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught | |
2693 * exception, or reanimate a returned function or finished script file and | |
2694 * return or finish it again. | |
2695 */ | |
2696 if (need_rethrow) | |
2697 do_throw(cstack); | |
2698 else if (check_cstack) | |
2699 { | |
944 | 2700 if (source_finished(fgetline, cookie)) |
7 | 2701 do_finish(&ea, TRUE); |
944 | 2702 else if (getline_equal(fgetline, cookie, get_func_line) |
7 | 2703 && current_func_returned()) |
2704 do_return(&ea, TRUE, FALSE, NULL); | |
2705 } | |
2706 need_rethrow = check_cstack = FALSE; | |
2707 #endif | |
2708 | |
2709 doend: | |
2710 if (curwin->w_cursor.lnum == 0) /* can happen with zero line number */ | |
2711 curwin->w_cursor.lnum = 1; | |
2712 | |
2713 if (errormsg != NULL && *errormsg != NUL && !did_emsg) | |
2714 { | |
2715 if (sourcing) | |
2716 { | |
2717 if (errormsg != IObuff) | |
2718 { | |
2719 STRCPY(IObuff, errormsg); | |
2720 errormsg = IObuff; | |
2721 } | |
3097 | 2722 append_command(*cmdlinep); |
7 | 2723 } |
2724 emsg(errormsg); | |
2725 } | |
2726 #ifdef FEAT_EVAL | |
2727 do_errthrow(cstack, | |
2728 (ea.cmdidx != CMD_SIZE | |
2729 # ifdef FEAT_USR_CMDS | |
2730 && !USER_CMDIDX(ea.cmdidx) | |
2731 # endif | |
2732 ) ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); | |
2733 #endif | |
2734 | |
2735 if (verbose_save >= 0) | |
2736 p_verbose = verbose_save; | |
588 | 2737 #ifdef FEAT_AUTOCMD |
2738 if (cmdmod.save_ei != NULL) | |
2739 { | |
2740 /* Restore 'eventignore' to the value before ":noautocmd". */ | |
694 | 2741 set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, |
2742 OPT_FREE, SID_NONE); | |
588 | 2743 free_string_option(cmdmod.save_ei); |
2744 } | |
2745 #endif | |
7 | 2746 |
2747 cmdmod = save_cmdmod; | |
2748 | |
1926 | 2749 if (save_msg_silent != -1) |
7 | 2750 { |
2751 /* messages could be enabled for a serious error, need to check if the | |
2752 * counters don't become negative */ | |
1968 | 2753 if (!did_emsg || msg_silent > save_msg_silent) |
1926 | 2754 msg_silent = save_msg_silent; |
7 | 2755 emsg_silent -= did_esilent; |
2756 if (emsg_silent < 0) | |
2757 emsg_silent = 0; | |
2758 /* Restore msg_scroll, it's set by file I/O commands, even when no | |
2759 * message is actually displayed. */ | |
2760 msg_scroll = save_msg_scroll; | |
1854 | 2761 |
2762 /* "silent reg" or "silent echo x" inside "redir" leaves msg_col | |
2763 * somewhere in the line. Put it back in the first column. */ | |
2764 if (redirecting()) | |
2765 msg_col = 0; | |
7 | 2766 } |
2767 | |
28 | 2768 #ifdef HAVE_SANDBOX |
2769 if (did_sandbox) | |
2770 --sandbox; | |
2771 #endif | |
2772 | |
7 | 2773 if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */ |
2774 ea.nextcmd = NULL; | |
2775 | |
2776 #ifdef FEAT_EVAL | |
2777 --ex_nesting_level; | |
2778 #endif | |
2779 | |
2780 return ea.nextcmd; | |
2781 } | |
2782 #if (_MSC_VER == 1200) | |
128 | 2783 #pragma optimize( "", on ) |
7 | 2784 #endif |
2785 | |
2786 /* | |
93 | 2787 * Check for an Ex command with optional tail. |
7 | 2788 * If there is a match advance "pp" to the argument and return TRUE. |
2789 */ | |
93 | 2790 int |
7 | 2791 checkforcmd(pp, cmd, len) |
93 | 2792 char_u **pp; /* start of command */ |
7 | 2793 char *cmd; /* name of command */ |
2794 int len; /* required length */ | |
2795 { | |
2796 int i; | |
2797 | |
2798 for (i = 0; cmd[i] != NUL; ++i) | |
1872 | 2799 if (((char_u *)cmd)[i] != (*pp)[i]) |
7 | 2800 break; |
2801 if (i >= len && !isalpha((*pp)[i])) | |
2802 { | |
2803 *pp = skipwhite(*pp + i); | |
2804 return TRUE; | |
2805 } | |
2806 return FALSE; | |
2807 } | |
2808 | |
2809 /* | |
3097 | 2810 * Append "cmd" to the error message in IObuff. |
2811 * Takes care of limiting the length and handling 0xa0, which would be | |
2812 * invisible otherwise. | |
2813 */ | |
2814 static void | |
2815 append_command(cmd) | |
2816 char_u *cmd; | |
2817 { | |
2818 char_u *s = cmd; | |
2819 char_u *d; | |
2820 | |
2821 STRCAT(IObuff, ": "); | |
2822 d = IObuff + STRLEN(IObuff); | |
2823 while (*s != NUL && d - IObuff < IOSIZE - 7) | |
2824 { | |
2825 if ( | |
2826 #ifdef FEAT_MBYTE | |
2827 enc_utf8 ? (s[0] == 0xc2 && s[1] == 0xa0) : | |
2828 #endif | |
2829 *s == 0xa0) | |
2830 { | |
2831 s += | |
2832 #ifdef FEAT_MBYTE | |
2833 enc_utf8 ? 2 : | |
2834 #endif | |
2835 1; | |
2836 STRCPY(d, "<a0>"); | |
2837 d += 4; | |
2838 } | |
2839 else | |
2840 MB_COPY_CHAR(s, d); | |
2841 } | |
2842 *d = NUL; | |
2843 } | |
2844 | |
2845 /* | |
7 | 2846 * Find an Ex command by its name, either built-in or user. |
184 | 2847 * Start of the name can be found at eap->cmd. |
7 | 2848 * Returns pointer to char after the command name. |
184 | 2849 * "full" is set to TRUE if the whole command name matched. |
7 | 2850 * Returns NULL for an ambiguous user command. |
2851 */ | |
2852 static char_u * | |
2853 find_command(eap, full) | |
2854 exarg_T *eap; | |
1877 | 2855 int *full UNUSED; |
7 | 2856 { |
2857 int len; | |
2858 char_u *p; | |
167 | 2859 int i; |
7 | 2860 |
2861 /* | |
2862 * Isolate the command and search for it in the command table. | |
1441 | 2863 * Exceptions: |
7 | 2864 * - the 'k' command can directly be followed by any character. |
2865 * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' | |
2866 * but :sre[wind] is another command, as are :scrip[tnames], | |
2867 * :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. | |
167 | 2868 * - the "d" command can directly be followed by 'l' or 'p' flag. |
7 | 2869 */ |
2870 p = eap->cmd; | |
2871 if (*p == 'k') | |
2872 { | |
2873 eap->cmdidx = CMD_k; | |
2874 ++p; | |
2875 } | |
2876 else if (p[0] == 's' | |
184 | 2877 && ((p[1] == 'c' && p[2] != 's' && p[2] != 'r' |
2878 && p[3] != 'i' && p[4] != 'p') | |
7 | 2879 || p[1] == 'g' |
2880 || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') | |
2881 || p[1] == 'I' | |
2882 || (p[1] == 'r' && p[2] != 'e'))) | |
2883 { | |
2884 eap->cmdidx = CMD_substitute; | |
2885 ++p; | |
2886 } | |
2887 else | |
2888 { | |
2889 while (ASCII_ISALPHA(*p)) | |
2890 ++p; | |
2366
7a57fe6a5157
Fix that :py3file was not working.
Bram Moolenaar <bram@vim.org>
parents:
2360
diff
changeset
|
2891 /* for python 3.x support ":py3", ":python3", ":py3file", etc. */ |
2330 | 2892 if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y') |
2366
7a57fe6a5157
Fix that :py3file was not working.
Bram Moolenaar <bram@vim.org>
parents:
2360
diff
changeset
|
2893 while (ASCII_ISALNUM(*p)) |
7a57fe6a5157
Fix that :py3file was not working.
Bram Moolenaar <bram@vim.org>
parents:
2360
diff
changeset
|
2894 ++p; |
2329
ad2889f48843
Added support for Python 3. (Roland Puntaier)
Bram Moolenaar <bram@vim.org>
parents:
2320
diff
changeset
|
2895 |
7 | 2896 /* check for non-alpha command */ |
2897 if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) | |
2898 ++p; | |
2899 len = (int)(p - eap->cmd); | |
167 | 2900 if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) |
2901 { | |
2902 /* Check for ":dl", ":dell", etc. to ":deletel": that's | |
2903 * :delete with the 'l' flag. Same for 'p'. */ | |
2904 for (i = 0; i < len; ++i) | |
1872 | 2905 if (eap->cmd[i] != ((char_u *)"delete")[i]) |
167 | 2906 break; |
2907 if (i == len - 1) | |
2908 { | |
2909 --len; | |
2910 if (p[-1] == 'l') | |
2911 eap->flags |= EXFLAG_LIST; | |
2912 else | |
2913 eap->flags |= EXFLAG_PRINT; | |
2914 } | |
2915 } | |
7 | 2916 |
2917 if (ASCII_ISLOWER(*eap->cmd)) | |
2918 eap->cmdidx = cmdidxs[CharOrdLow(*eap->cmd)]; | |
2919 else | |
2920 eap->cmdidx = cmdidxs[26]; | |
2921 | |
2922 for ( ; (int)eap->cmdidx < (int)CMD_SIZE; | |
2923 eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) | |
2924 if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd, | |
2925 (size_t)len) == 0) | |
2926 { | |
2927 #ifdef FEAT_EVAL | |
2928 if (full != NULL | |
2929 && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) | |
2930 *full = TRUE; | |
2931 #endif | |
2932 break; | |
2933 } | |
2934 | |
2935 #ifdef FEAT_USR_CMDS | |
2633 | 2936 /* Look for a user defined command as a last resort. Let ":Print" be |
2937 * overruled by a user defined command. */ | |
2938 if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print) | |
2939 && *eap->cmd >= 'A' && *eap->cmd <= 'Z') | |
7 | 2940 { |
184 | 2941 /* User defined commands may contain digits. */ |
7 | 2942 while (ASCII_ISALNUM(*p)) |
2943 ++p; | |
184 | 2944 p = find_ucmd(eap, p, full, NULL, NULL); |
2945 } | |
2946 #endif | |
2947 if (p == eap->cmd) | |
7 | 2948 eap->cmdidx = CMD_SIZE; |
2949 } | |
2950 | |
2951 return p; | |
2952 } | |
2953 | |
184 | 2954 #ifdef FEAT_USR_CMDS |
2955 /* | |
2956 * Search for a user command that matches "eap->cmd". | |
2957 * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". | |
2958 * Return a pointer to just after the command. | |
2959 * Return NULL if there is no matching command. | |
2960 */ | |
2961 static char_u * | |
2962 find_ucmd(eap, p, full, xp, compl) | |
2963 exarg_T *eap; | |
2964 char_u *p; /* end of the command (possibly including count) */ | |
2965 int *full; /* set to TRUE for a full match */ | |
2966 expand_T *xp; /* used for completion, NULL otherwise */ | |
2967 int *compl; /* completion flags or NULL */ | |
2968 { | |
2969 int len = (int)(p - eap->cmd); | |
2970 int j, k, matchlen = 0; | |
2971 ucmd_T *uc; | |
2972 int found = FALSE; | |
2973 int possible = FALSE; | |
2974 char_u *cp, *np; /* Point into typed cmd and test name */ | |
2975 garray_T *gap; | |
2976 int amb_local = FALSE; /* Found ambiguous buffer-local command, | |
2977 only full match global is accepted. */ | |
2978 | |
2979 /* | |
2980 * Look for buffer-local user commands first, then global ones. | |
2981 */ | |
2982 gap = &curbuf->b_ucmds; | |
2983 for (;;) | |
2984 { | |
2985 for (j = 0; j < gap->ga_len; ++j) | |
2986 { | |
2987 uc = USER_CMD_GA(gap, j); | |
2988 cp = eap->cmd; | |
2989 np = uc->uc_name; | |
2990 k = 0; | |
2991 while (k < len && *np != NUL && *cp++ == *np++) | |
2992 k++; | |
2993 if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k]))) | |
2994 { | |
2995 /* If finding a second match, the command is ambiguous. But | |
2996 * not if a buffer-local command wasn't a full match and a | |
2997 * global command is a full match. */ | |
2998 if (k == len && found && *np != NUL) | |
2999 { | |
3000 if (gap == &ucmds) | |
3001 return NULL; | |
3002 amb_local = TRUE; | |
3003 } | |
3004 | |
3005 if (!found || (k == len && *np == NUL)) | |
3006 { | |
3007 /* If we matched up to a digit, then there could | |
3008 * be another command including the digit that we | |
3009 * should use instead. | |
3010 */ | |
3011 if (k == len) | |
3012 found = TRUE; | |
3013 else | |
3014 possible = TRUE; | |
3015 | |
3016 if (gap == &ucmds) | |
3017 eap->cmdidx = CMD_USER; | |
3018 else | |
3019 eap->cmdidx = CMD_USER_BUF; | |
835 | 3020 eap->argt = (long)uc->uc_argt; |
184 | 3021 eap->useridx = j; |
3022 | |
3023 # ifdef FEAT_CMDL_COMPL | |
3024 if (compl != NULL) | |
3025 *compl = uc->uc_compl; | |
3026 # ifdef FEAT_EVAL | |
3027 if (xp != NULL) | |
3028 { | |
3029 xp->xp_arg = uc->uc_compl_arg; | |
3030 xp->xp_scriptID = uc->uc_scriptID; | |
3031 } | |
3032 # endif | |
3033 # endif | |
3034 /* Do not search for further abbreviations | |
3035 * if this is an exact match. */ | |
3036 matchlen = k; | |
3037 if (k == len && *np == NUL) | |
3038 { | |
3039 if (full != NULL) | |
3040 *full = TRUE; | |
3041 amb_local = FALSE; | |
3042 break; | |
3043 } | |
3044 } | |
3045 } | |
3046 } | |
3047 | |
3048 /* Stop if we found a full match or searched all. */ | |
3049 if (j < gap->ga_len || gap == &ucmds) | |
3050 break; | |
3051 gap = &ucmds; | |
3052 } | |
3053 | |
3054 /* Only found ambiguous matches. */ | |
3055 if (amb_local) | |
3056 { | |
3057 if (xp != NULL) | |
3058 xp->xp_context = EXPAND_UNSUCCESSFUL; | |
3059 return NULL; | |
3060 } | |
3061 | |
3062 /* The match we found may be followed immediately by a number. Move "p" | |
3063 * back to point to it. */ | |
3064 if (found || possible) | |
3065 return p + (matchlen - len); | |
3066 return p; | |
3067 } | |
3068 #endif | |
3069 | |
7 | 3070 #if defined(FEAT_EVAL) || defined(PROTO) |
1447 | 3071 static struct cmdmod |
3072 { | |
3073 char *name; | |
3074 int minlen; | |
3075 int has_count; /* :123verbose :3tab */ | |
3076 } cmdmods[] = { | |
3077 {"aboveleft", 3, FALSE}, | |
3078 {"belowright", 3, FALSE}, | |
3079 {"botright", 2, FALSE}, | |
3080 {"browse", 3, FALSE}, | |
3081 {"confirm", 4, FALSE}, | |
3082 {"hide", 3, FALSE}, | |
3083 {"keepalt", 5, FALSE}, | |
3084 {"keepjumps", 5, FALSE}, | |
3085 {"keepmarks", 3, FALSE}, | |
3086 {"leftabove", 5, FALSE}, | |
3087 {"lockmarks", 3, FALSE}, | |
1721 | 3088 {"noautocmd", 3, FALSE}, |
1447 | 3089 {"rightbelow", 6, FALSE}, |
3090 {"sandbox", 3, FALSE}, | |
3091 {"silent", 3, FALSE}, | |
3092 {"tab", 3, TRUE}, | |
3093 {"topleft", 2, FALSE}, | |
1926 | 3094 {"unsilent", 3, FALSE}, |
1447 | 3095 {"verbose", 4, TRUE}, |
3096 {"vertical", 4, FALSE}, | |
3097 }; | |
3098 | |
3099 /* | |
3100 * Return length of a command modifier (including optional count). | |
3101 * Return zero when it's not a modifier. | |
3102 */ | |
3103 int | |
3104 modifier_len(cmd) | |
3105 char_u *cmd; | |
3106 { | |
3107 int i, j; | |
3108 char_u *p = cmd; | |
3109 | |
3110 if (VIM_ISDIGIT(*cmd)) | |
3111 p = skipwhite(skipdigits(cmd)); | |
1880 | 3112 for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) |
1447 | 3113 { |
3114 for (j = 0; p[j] != NUL; ++j) | |
3115 if (p[j] != cmdmods[i].name[j]) | |
3116 break; | |
3117 if (!isalpha(p[j]) && j >= cmdmods[i].minlen | |
3118 && (p == cmd || cmdmods[i].has_count)) | |
1570 | 3119 return j + (int)(p - cmd); |
1447 | 3120 } |
3121 return 0; | |
3122 } | |
3123 | |
7 | 3124 /* |
3125 * Return > 0 if an Ex command "name" exists. | |
3126 * Return 2 if there is an exact match. | |
3127 * Return 3 if there is an ambiguous match. | |
3128 */ | |
3129 int | |
3130 cmd_exists(name) | |
3131 char_u *name; | |
3132 { | |
3133 exarg_T ea; | |
3134 int full = FALSE; | |
3135 int i; | |
3136 int j; | |
866 | 3137 char_u *p; |
7 | 3138 |
3139 /* Check command modifiers. */ | |
1880 | 3140 for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) |
7 | 3141 { |
3142 for (j = 0; name[j] != NUL; ++j) | |
3143 if (name[j] != cmdmods[i].name[j]) | |
3144 break; | |
3145 if (name[j] == NUL && j >= cmdmods[i].minlen) | |
3146 return (cmdmods[i].name[j] == NUL ? 2 : 1); | |
3147 } | |
3148 | |
862 | 3149 /* Check built-in commands and user defined commands. |
3150 * For ":2match" and ":3match" we need to skip the number. */ | |
3151 ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; | |
7 | 3152 ea.cmdidx = (cmdidx_T)0; |
866 | 3153 p = find_command(&ea, &full); |
3154 if (p == NULL) | |
7 | 3155 return 3; |
862 | 3156 if (vim_isdigit(*name) && ea.cmdidx != CMD_match) |
3157 return 0; | |
866 | 3158 if (*skipwhite(p) != NUL) |
3159 return 0; /* trailing garbage */ | |
7 | 3160 return (ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1)); |
3161 } | |
3162 #endif | |
3163 | |
3164 /* | |
3165 * This is all pretty much copied from do_one_cmd(), with all the extra stuff | |
3166 * we don't need/want deleted. Maybe this could be done better if we didn't | |
3167 * repeat all this stuff. The only problem is that they may not stay | |
3168 * perfectly compatible with each other, but then the command line syntax | |
3169 * probably won't change that much -- webb. | |
3170 */ | |
3171 char_u * | |
3172 set_one_cmd_context(xp, buff) | |
3173 expand_T *xp; | |
3174 char_u *buff; /* buffer for command string */ | |
3175 { | |
3176 char_u *p; | |
3177 char_u *cmd, *arg; | |
184 | 3178 int len = 0; |
3179 exarg_T ea; | |
7 | 3180 #if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) |
3181 int compl = EXPAND_NOTHING; | |
3182 #endif | |
3183 #ifdef FEAT_CMDL_COMPL | |
3184 int delim; | |
3185 #endif | |
3186 int forceit = FALSE; | |
3187 int usefilter = FALSE; /* filter instead of file name */ | |
3188 | |
631 | 3189 ExpandInit(xp); |
7 | 3190 xp->xp_pattern = buff; |
3191 xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */ | |
184 | 3192 ea.argt = 0; |
7 | 3193 |
3194 /* | |
3195 * 2. skip comment lines and leading space, colons or bars | |
3196 */ | |
3197 for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++) | |
3198 ; | |
3199 xp->xp_pattern = cmd; | |
3200 | |
3201 if (*cmd == NUL) | |
3202 return NULL; | |
3203 if (*cmd == '"') /* ignore comment lines */ | |
3204 { | |
3205 xp->xp_context = EXPAND_NOTHING; | |
3206 return NULL; | |
3207 } | |
3208 | |
3209 /* | |
3210 * 3. parse a range specifier of the form: addr [,addr] [;addr] .. | |
3211 */ | |
3212 cmd = skip_range(cmd, &xp->xp_context); | |
3213 | |
3214 /* | |
3215 * 4. parse command | |
3216 */ | |
3217 xp->xp_pattern = cmd; | |
3218 if (*cmd == NUL) | |
3219 return NULL; | |
3220 if (*cmd == '"') | |
3221 { | |
3222 xp->xp_context = EXPAND_NOTHING; | |
3223 return NULL; | |
3224 } | |
3225 | |
3226 if (*cmd == '|' || *cmd == '\n') | |
3227 return cmd + 1; /* There's another command */ | |
3228 | |
3229 /* | |
3230 * Isolate the command and search for it in the command table. | |
3231 * Exceptions: | |
3232 * - the 'k' command can directly be followed by any character, but | |
22 | 3233 * do accept "keepmarks", "keepalt" and "keepjumps". |
7 | 3234 * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' |
3235 */ | |
3236 if (*cmd == 'k' && cmd[1] != 'e') | |
3237 { | |
184 | 3238 ea.cmdidx = CMD_k; |
7 | 3239 p = cmd + 1; |
3240 } | |
3241 else | |
3242 { | |
3243 p = cmd; | |
3244 while (ASCII_ISALPHA(*p) || *p == '*') /* Allow * wild card */ | |
3245 ++p; | |
3246 /* check for non-alpha command */ | |
3247 if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) | |
3248 ++p; | |
184 | 3249 len = (int)(p - cmd); |
3250 | |
3251 if (len == 0) | |
7 | 3252 { |
3253 xp->xp_context = EXPAND_UNSUCCESSFUL; | |
3254 return NULL; | |
3255 } | |
184 | 3256 for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE; |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3257 ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3258 if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3259 (size_t)len) == 0) |
7 | 3260 break; |
3261 | |
3262 #ifdef FEAT_USR_CMDS | |
3263 if (cmd[0] >= 'A' && cmd[0] <= 'Z') | |
3264 while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ | |
3265 ++p; | |
3266 #endif | |
3267 } | |
3268 | |
3269 /* | |
3270 * If the cursor is touching the command, and it ends in an alpha-numeric | |
3271 * character, complete the command name. | |
3272 */ | |
3273 if (*p == NUL && ASCII_ISALNUM(p[-1])) | |
3274 return NULL; | |
3275 | |
184 | 3276 if (ea.cmdidx == CMD_SIZE) |
7 | 3277 { |
3278 if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) | |
3279 { | |
184 | 3280 ea.cmdidx = CMD_substitute; |
7 | 3281 p = cmd + 1; |
3282 } | |
3283 #ifdef FEAT_USR_CMDS | |
3284 else if (cmd[0] >= 'A' && cmd[0] <= 'Z') | |
3285 { | |
184 | 3286 ea.cmd = cmd; |
3287 p = find_ucmd(&ea, p, NULL, xp, | |
3288 # if defined(FEAT_CMDL_COMPL) | |
3289 &compl | |
3290 # else | |
3291 NULL | |
7 | 3292 # endif |
184 | 3293 ); |
620 | 3294 if (p == NULL) |
3295 ea.cmdidx = CMD_SIZE; /* ambiguous user command */ | |
184 | 3296 } |
3297 #endif | |
3298 } | |
3299 if (ea.cmdidx == CMD_SIZE) | |
7 | 3300 { |
3301 /* Not still touching the command and it was an illegal one */ | |
3302 xp->xp_context = EXPAND_UNSUCCESSFUL; | |
3303 return NULL; | |
3304 } | |
3305 | |
3306 xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */ | |
3307 | |
3308 if (*p == '!') /* forced commands */ | |
3309 { | |
3310 forceit = TRUE; | |
3311 ++p; | |
3312 } | |
3313 | |
3314 /* | |
3315 * 5. parse arguments | |
3316 */ | |
3317 #ifdef FEAT_USR_CMDS | |
184 | 3318 if (!USER_CMDIDX(ea.cmdidx)) |
3319 #endif | |
835 | 3320 ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt; |
7 | 3321 |
3322 arg = skipwhite(p); | |
3323 | |
184 | 3324 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) |
7 | 3325 { |
3326 if (*arg == '>') /* append */ | |
3327 { | |
3328 if (*++arg == '>') | |
3329 ++arg; | |
3330 arg = skipwhite(arg); | |
3331 } | |
184 | 3332 else if (*arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */ |
7 | 3333 { |
3334 ++arg; | |
3335 usefilter = TRUE; | |
3336 } | |
3337 } | |
3338 | |
184 | 3339 if (ea.cmdidx == CMD_read) |
7 | 3340 { |
3341 usefilter = forceit; /* :r! filter if forced */ | |
3342 if (*arg == '!') /* :r !filter */ | |
3343 { | |
3344 ++arg; | |
3345 usefilter = TRUE; | |
3346 } | |
3347 } | |
3348 | |
184 | 3349 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) |
7 | 3350 { |
3351 while (*arg == *cmd) /* allow any number of '>' or '<' */ | |
3352 ++arg; | |
3353 arg = skipwhite(arg); | |
3354 } | |
3355 | |
3356 /* Does command allow "+command"? */ | |
184 | 3357 if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') |
7 | 3358 { |
3359 /* Check if we're in the +command */ | |
3360 p = arg + 1; | |
3361 arg = skip_cmd_arg(arg, FALSE); | |
3362 | |
3363 /* Still touching the command after '+'? */ | |
3364 if (*arg == NUL) | |
3365 return p; | |
3366 | |
3367 /* Skip space(s) after +command to get to the real argument */ | |
3368 arg = skipwhite(arg); | |
3369 } | |
3370 | |
3371 /* | |
3372 * Check for '|' to separate commands and '"' to start comments. | |
3373 * Don't do this for ":read !cmd" and ":write !cmd". | |
3374 */ | |
184 | 3375 if ((ea.argt & TRLBAR) && !usefilter) |
7 | 3376 { |
3377 p = arg; | |
3378 /* ":redir @" is not the start of a comment */ | |
184 | 3379 if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') |
7 | 3380 p += 2; |
3381 while (*p) | |
3382 { | |
3383 if (*p == Ctrl_V) | |
3384 { | |
3385 if (p[1] != NUL) | |
3386 ++p; | |
3387 } | |
184 | 3388 else if ( (*p == '"' && !(ea.argt & NOTRLCOM)) |
7 | 3389 || *p == '|' || *p == '\n') |
3390 { | |
3391 if (*(p - 1) != '\\') | |
3392 { | |
3393 if (*p == '|' || *p == '\n') | |
3394 return p + 1; | |
3395 return NULL; /* It's a comment */ | |
3396 } | |
3397 } | |
39 | 3398 mb_ptr_adv(p); |
7 | 3399 } |
3400 } | |
3401 | |
3402 /* no arguments allowed */ | |
184 | 3403 if (!(ea.argt & EXTRA) && *arg != NUL && |
7 | 3404 vim_strchr((char_u *)"|\"", *arg) == NULL) |
3405 return NULL; | |
3406 | |
3407 /* Find start of last argument (argument just before cursor): */ | |
3711 | 3408 p = buff; |
7 | 3409 xp->xp_pattern = p; |
3724 | 3410 len = (int)STRLEN(buff); |
3711 | 3411 while (*p && p < buff + len) |
3412 { | |
3413 if (*p == ' ' || *p == TAB) | |
3414 { | |
3415 /* argument starts after a space */ | |
3416 xp->xp_pattern = ++p; | |
3417 } | |
3418 else | |
3419 { | |
3420 if (*p == '\\' && *(p + 1) != NUL) | |
3421 ++p; /* skip over escaped character */ | |
3422 mb_ptr_adv(p); | |
3423 } | |
3424 } | |
7 | 3425 |
184 | 3426 if (ea.argt & XFILE) |
7 | 3427 { |
1367 | 3428 int c; |
3429 int in_quote = FALSE; | |
3430 char_u *bow = NULL; /* Beginning of word */ | |
7 | 3431 |
3432 /* | |
3433 * Allow spaces within back-quotes to count as part of the argument | |
3434 * being expanded. | |
3435 */ | |
3436 xp->xp_pattern = skipwhite(arg); | |
1367 | 3437 p = xp->xp_pattern; |
3438 while (*p != NUL) | |
3439 { | |
3440 #ifdef FEAT_MBYTE | |
3441 if (has_mbyte) | |
3442 c = mb_ptr2char(p); | |
3443 else | |
3444 #endif | |
3445 c = *p; | |
3446 if (c == '\\' && p[1] != NUL) | |
7 | 3447 ++p; |
1367 | 3448 else if (c == '`') |
7 | 3449 { |
3450 if (!in_quote) | |
3451 { | |
3452 xp->xp_pattern = p; | |
3453 bow = p + 1; | |
3454 } | |
3455 in_quote = !in_quote; | |
3456 } | |
1511 | 3457 /* An argument can contain just about everything, except |
3458 * characters that end the command and white space. */ | |
3459 else if (c == '|' || c == '\n' || c == '"' || (vim_iswhite(c) | |
1367 | 3460 #ifdef SPACE_IN_FILENAME |
1511 | 3461 && (!(ea.argt & NOSPC) || usefilter) |
3462 #endif | |
3463 )) | |
1367 | 3464 { |
1551 | 3465 len = 0; /* avoid getting stuck when space is in 'isfname' */ |
1367 | 3466 while (*p != NUL) |
3467 { | |
3468 #ifdef FEAT_MBYTE | |
3469 if (has_mbyte) | |
3470 c = mb_ptr2char(p); | |
3471 else | |
3472 #endif | |
3473 c = *p; | |
1369 | 3474 if (c == '`' || vim_isfilec_or_wc(c)) |
1367 | 3475 break; |
3476 #ifdef FEAT_MBYTE | |
3477 if (has_mbyte) | |
3478 len = (*mb_ptr2len)(p); | |
3479 else | |
3480 #endif | |
3481 len = 1; | |
3482 mb_ptr_adv(p); | |
3483 } | |
3484 if (in_quote) | |
3485 bow = p; | |
3486 else | |
3487 xp->xp_pattern = p; | |
3488 p -= len; | |
3489 } | |
39 | 3490 mb_ptr_adv(p); |
7 | 3491 } |
3492 | |
3493 /* | |
3494 * If we are still inside the quotes, and we passed a space, just | |
3495 * expand from there. | |
3496 */ | |
3497 if (bow != NULL && in_quote) | |
3498 xp->xp_pattern = bow; | |
3499 xp->xp_context = EXPAND_FILES; | |
714 | 3500 |
631 | 3501 /* For a shell command more chars need to be escaped. */ |
3502 if (usefilter || ea.cmdidx == CMD_bang) | |
714 | 3503 { |
2511
2f5b709a6470
Fixed: on MS-Windows completion of shell commands didn't work.
Bram Moolenaar <bram@vim.org>
parents:
2444
diff
changeset
|
3504 #ifndef BACKSLASH_IN_FILENAME |
631 | 3505 xp->xp_shell = TRUE; |
2511
2f5b709a6470
Fixed: on MS-Windows completion of shell commands didn't work.
Bram Moolenaar <bram@vim.org>
parents:
2444
diff
changeset
|
3506 #endif |
714 | 3507 /* When still after the command name expand executables. */ |
3508 if (xp->xp_pattern == skipwhite(arg)) | |
1132 | 3509 xp->xp_context = EXPAND_SHELLCMD; |
714 | 3510 } |
7 | 3511 |
3512 /* Check for environment variable */ | |
3513 if (*xp->xp_pattern == '$' | |
3514 #if defined(MSDOS) || defined(MSWIN) || defined(OS2) | |
3515 || *xp->xp_pattern == '%' | |
3516 #endif | |
3517 ) | |
3518 { | |
3519 for (p = xp->xp_pattern + 1; *p != NUL; ++p) | |
3520 if (!vim_isIDc(*p)) | |
3521 break; | |
3522 if (*p == NUL) | |
3523 { | |
3524 xp->xp_context = EXPAND_ENV_VARS; | |
3525 ++xp->xp_pattern; | |
17 | 3526 #if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) |
3527 /* Avoid that the assignment uses EXPAND_FILES again. */ | |
406 | 3528 if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) |
17 | 3529 compl = EXPAND_ENV_VARS; |
3530 #endif | |
7 | 3531 } |
3532 } | |
3744 | 3533 #if defined(FEAT_CMDL_COMPL) |
3534 /* Check for user names */ | |
3535 if (*xp->xp_pattern == '~') | |
3536 { | |
3537 for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) | |
3538 ; | |
3539 /* Complete ~user only if it partially matches a user name. | |
3540 * A full match ~user<Tab> will be replaced by user's home | |
3541 * directory i.e. something like ~user<Tab> -> /home/user/ */ | |
3542 if (*p == NUL && p > xp->xp_pattern + 1 | |
3543 && match_user(xp->xp_pattern + 1) == 1) | |
3544 { | |
3545 xp->xp_context = EXPAND_USER; | |
3546 ++xp->xp_pattern; | |
3547 } | |
3548 } | |
3549 #endif | |
7 | 3550 } |
3551 | |
3552 /* | |
3553 * 6. switch on command name | |
3554 */ | |
184 | 3555 switch (ea.cmdidx) |
7 | 3556 { |
2311
ccda151dde4e
Support completion for ":find". (Nazri Ramliy)
Bram Moolenaar <bram@vim.org>
parents:
2294
diff
changeset
|
3557 case CMD_find: |
ccda151dde4e
Support completion for ":find". (Nazri Ramliy)
Bram Moolenaar <bram@vim.org>
parents:
2294
diff
changeset
|
3558 case CMD_sfind: |
ccda151dde4e
Support completion for ":find". (Nazri Ramliy)
Bram Moolenaar <bram@vim.org>
parents:
2294
diff
changeset
|
3559 case CMD_tabfind: |
2575 | 3560 if (xp->xp_context == EXPAND_FILES) |
3561 xp->xp_context = EXPAND_FILES_IN_PATH; | |
2311
ccda151dde4e
Support completion for ":find". (Nazri Ramliy)
Bram Moolenaar <bram@vim.org>
parents:
2294
diff
changeset
|
3562 break; |
7 | 3563 case CMD_cd: |
3564 case CMD_chdir: | |
3565 case CMD_lcd: | |
3566 case CMD_lchdir: | |
3567 if (xp->xp_context == EXPAND_FILES) | |
3568 xp->xp_context = EXPAND_DIRECTORIES; | |
3569 break; | |
3570 case CMD_help: | |
3571 xp->xp_context = EXPAND_HELP; | |
3572 xp->xp_pattern = arg; | |
3573 break; | |
3574 | |
198 | 3575 /* Command modifiers: return the argument. |
3576 * Also for commands with an argument that is a command. */ | |
7 | 3577 case CMD_aboveleft: |
198 | 3578 case CMD_argdo: |
7 | 3579 case CMD_belowright: |
3580 case CMD_botright: | |
3581 case CMD_browse: | |
198 | 3582 case CMD_bufdo: |
7 | 3583 case CMD_confirm: |
167 | 3584 case CMD_debug: |
7 | 3585 case CMD_folddoclosed: |
3586 case CMD_folddoopen: | |
3587 case CMD_hide: | |
22 | 3588 case CMD_keepalt: |
7 | 3589 case CMD_keepjumps: |
3590 case CMD_keepmarks: | |
3591 case CMD_leftabove: | |
3592 case CMD_lockmarks: | |
3593 case CMD_rightbelow: | |
198 | 3594 case CMD_sandbox: |
7 | 3595 case CMD_silent: |
690 | 3596 case CMD_tab: |
7 | 3597 case CMD_topleft: |
3598 case CMD_verbose: | |
3599 case CMD_vertical: | |
198 | 3600 case CMD_windo: |
7 | 3601 return arg; |
3602 | |
1322 | 3603 #ifdef FEAT_CMDL_COMPL |
3604 # ifdef FEAT_SEARCH_EXTRA | |
7 | 3605 case CMD_match: |
3606 if (*arg == NUL || !ends_excmd(*arg)) | |
3607 { | |
1322 | 3608 /* also complete "None" */ |
3609 set_context_in_echohl_cmd(xp, arg); | |
7 | 3610 arg = skipwhite(skiptowhite(arg)); |
3611 if (*arg != NUL) | |
3612 { | |
3613 xp->xp_context = EXPAND_NOTHING; | |
3614 arg = skip_regexp(arg + 1, *arg, p_magic, NULL); | |
3615 } | |
3616 } | |
3617 return find_nextcmd(arg); | |
1322 | 3618 # endif |
3619 | |
7 | 3620 /* |
3621 * All completion for the +cmdline_compl feature goes here. | |
3622 */ | |
3623 | |
3624 # ifdef FEAT_USR_CMDS | |
3625 case CMD_command: | |
3626 /* Check for attributes */ | |
3627 while (*arg == '-') | |
3628 { | |
3629 arg++; /* Skip "-" */ | |
3630 p = skiptowhite(arg); | |
3631 if (*p == NUL) | |
3632 { | |
3633 /* Cursor is still in the attribute */ | |
3634 p = vim_strchr(arg, '='); | |
3635 if (p == NULL) | |
3636 { | |
3637 /* No "=", so complete attribute names */ | |
3638 xp->xp_context = EXPAND_USER_CMD_FLAGS; | |
3639 xp->xp_pattern = arg; | |
3640 return NULL; | |
3641 } | |
3642 | |
3643 /* For the -complete and -nargs attributes, we complete | |
3644 * their arguments as well. | |
3645 */ | |
3646 if (STRNICMP(arg, "complete", p - arg) == 0) | |
3647 { | |
3648 xp->xp_context = EXPAND_USER_COMPLETE; | |
3649 xp->xp_pattern = p + 1; | |
3650 return NULL; | |
3651 } | |
3652 else if (STRNICMP(arg, "nargs", p - arg) == 0) | |
3653 { | |
3654 xp->xp_context = EXPAND_USER_NARGS; | |
3655 xp->xp_pattern = p + 1; | |
3656 return NULL; | |
3657 } | |
3658 return NULL; | |
3659 } | |
3660 arg = skipwhite(p); | |
3661 } | |
3662 | |
3663 /* After the attributes comes the new command name */ | |
3664 p = skiptowhite(arg); | |
3665 if (*p == NUL) | |
3666 { | |
3667 xp->xp_context = EXPAND_USER_COMMANDS; | |
3668 xp->xp_pattern = arg; | |
3669 break; | |
3670 } | |
3671 | |
3672 /* And finally comes a normal command */ | |
3673 return skipwhite(p); | |
3674 | |
3675 case CMD_delcommand: | |
3676 xp->xp_context = EXPAND_USER_COMMANDS; | |
3677 xp->xp_pattern = arg; | |
3678 break; | |
3679 # endif | |
3680 | |
3681 case CMD_global: | |
3682 case CMD_vglobal: | |
3683 delim = *arg; /* get the delimiter */ | |
3684 if (delim) | |
3685 ++arg; /* skip delimiter if there is one */ | |
3686 | |
3687 while (arg[0] != NUL && arg[0] != delim) | |
3688 { | |
3689 if (arg[0] == '\\' && arg[1] != NUL) | |
3690 ++arg; | |
3691 ++arg; | |
3692 } | |
3693 if (arg[0] != NUL) | |
3694 return arg + 1; | |
3695 break; | |
3696 case CMD_and: | |
3697 case CMD_substitute: | |
3698 delim = *arg; | |
3699 if (delim) | |
3700 { | |
3701 /* skip "from" part */ | |
3702 ++arg; | |
3703 arg = skip_regexp(arg, delim, p_magic, NULL); | |
3704 } | |
3705 /* skip "to" part */ | |
3706 while (arg[0] != NUL && arg[0] != delim) | |
3707 { | |
3708 if (arg[0] == '\\' && arg[1] != NUL) | |
3709 ++arg; | |
3710 ++arg; | |
3711 } | |
3712 if (arg[0] != NUL) /* skip delimiter */ | |
3713 ++arg; | |
3714 while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL) | |
3715 ++arg; | |
3716 if (arg[0] != NUL) | |
3717 return arg; | |
3718 break; | |
3719 case CMD_isearch: | |
3720 case CMD_dsearch: | |
3721 case CMD_ilist: | |
3722 case CMD_dlist: | |
3723 case CMD_ijump: | |
3724 case CMD_psearch: | |
3725 case CMD_djump: | |
3726 case CMD_isplit: | |
3727 case CMD_dsplit: | |
3728 arg = skipwhite(skipdigits(arg)); /* skip count */ | |
3729 if (*arg == '/') /* Match regexp, not just whole words */ | |
3730 { | |
3731 for (++arg; *arg && *arg != '/'; arg++) | |
3732 if (*arg == '\\' && arg[1] != NUL) | |
3733 arg++; | |
3734 if (*arg) | |
3735 { | |
3736 arg = skipwhite(arg + 1); | |
3737 | |
3738 /* Check for trailing illegal characters */ | |
3739 if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL) | |
3740 xp->xp_context = EXPAND_NOTHING; | |
3741 else | |
3742 return arg; | |
3743 } | |
3744 } | |
3745 break; | |
3746 #ifdef FEAT_AUTOCMD | |
3747 case CMD_autocmd: | |
3748 return set_context_in_autocmd(xp, arg, FALSE); | |
3749 | |
3750 case CMD_doautocmd: | |
1731 | 3751 case CMD_doautoall: |
7 | 3752 return set_context_in_autocmd(xp, arg, TRUE); |
3753 #endif | |
3754 case CMD_set: | |
3755 set_context_in_set_cmd(xp, arg, 0); | |
3756 break; | |
3757 case CMD_setglobal: | |
3758 set_context_in_set_cmd(xp, arg, OPT_GLOBAL); | |
3759 break; | |
3760 case CMD_setlocal: | |
3761 set_context_in_set_cmd(xp, arg, OPT_LOCAL); | |
3762 break; | |
3763 case CMD_tag: | |
3764 case CMD_stag: | |
3765 case CMD_ptag: | |
649 | 3766 case CMD_ltag: |
7 | 3767 case CMD_tselect: |
3768 case CMD_stselect: | |
3769 case CMD_ptselect: | |
3770 case CMD_tjump: | |
3771 case CMD_stjump: | |
3772 case CMD_ptjump: | |
40 | 3773 if (*p_wop != NUL) |
3774 xp->xp_context = EXPAND_TAGS_LISTFILES; | |
3775 else | |
3776 xp->xp_context = EXPAND_TAGS; | |
7 | 3777 xp->xp_pattern = arg; |
3778 break; | |
3779 case CMD_augroup: | |
3780 xp->xp_context = EXPAND_AUGROUP; | |
3781 xp->xp_pattern = arg; | |
3782 break; | |
3783 #ifdef FEAT_SYN_HL | |
3784 case CMD_syntax: | |
3785 set_context_in_syntax_cmd(xp, arg); | |
3786 break; | |
3787 #endif | |
3788 #ifdef FEAT_EVAL | |
3789 case CMD_let: | |
3790 case CMD_if: | |
3791 case CMD_elseif: | |
3792 case CMD_while: | |
72 | 3793 case CMD_for: |
7 | 3794 case CMD_echo: |
3795 case CMD_echon: | |
3796 case CMD_execute: | |
3797 case CMD_echomsg: | |
3798 case CMD_echoerr: | |
3799 case CMD_call: | |
3800 case CMD_return: | |
184 | 3801 set_context_for_expression(xp, arg, ea.cmdidx); |
7 | 3802 break; |
3803 | |
3804 case CMD_unlet: | |
3805 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) | |
3806 arg = xp->xp_pattern + 1; | |
3807 xp->xp_context = EXPAND_USER_VARS; | |
3808 xp->xp_pattern = arg; | |
3809 break; | |
3810 | |
3811 case CMD_function: | |
3812 case CMD_delfunction: | |
3813 xp->xp_context = EXPAND_USER_FUNC; | |
3814 xp->xp_pattern = arg; | |
3815 break; | |
3816 | |
3817 case CMD_echohl: | |
1322 | 3818 set_context_in_echohl_cmd(xp, arg); |
7 | 3819 break; |
3820 #endif | |
3821 case CMD_highlight: | |
3822 set_context_in_highlight_cmd(xp, arg); | |
3823 break; | |
1845 | 3824 #ifdef FEAT_CSCOPE |
3825 case CMD_cscope: | |
1858 | 3826 case CMD_lcscope: |
3827 case CMD_scscope: | |
3828 set_context_in_cscope_cmd(xp, arg, ea.cmdidx); | |
1845 | 3829 break; |
3830 #endif | |
1868 | 3831 #ifdef FEAT_SIGNS |
3832 case CMD_sign: | |
3833 set_context_in_sign_cmd(xp, arg); | |
3834 break; | |
3835 #endif | |
7 | 3836 #ifdef FEAT_LISTCMDS |
3837 case CMD_bdelete: | |
3838 case CMD_bwipeout: | |
3839 case CMD_bunload: | |
3840 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) | |
3841 arg = xp->xp_pattern + 1; | |
3842 /*FALLTHROUGH*/ | |
3843 case CMD_buffer: | |
3844 case CMD_sbuffer: | |
3845 case CMD_checktime: | |
3846 xp->xp_context = EXPAND_BUFFERS; | |
3847 xp->xp_pattern = arg; | |
3848 break; | |
3849 #endif | |
3850 #ifdef FEAT_USR_CMDS | |
3851 case CMD_USER: | |
3852 case CMD_USER_BUF: | |
3853 if (compl != EXPAND_NOTHING) | |
3854 { | |
3855 /* XFILE: file names are handled above */ | |
184 | 3856 if (!(ea.argt & XFILE)) |
7 | 3857 { |
3858 # ifdef FEAT_MENU | |
3859 if (compl == EXPAND_MENUS) | |
3860 return set_context_in_menu_cmd(xp, cmd, arg, forceit); | |
3861 # endif | |
3862 if (compl == EXPAND_COMMANDS) | |
3863 return arg; | |
3864 if (compl == EXPAND_MAPPINGS) | |
3865 return set_context_in_map_cmd(xp, (char_u *)"map", | |
3866 arg, forceit, FALSE, FALSE, CMD_map); | |
3711 | 3867 /* Find start of last argument. */ |
3868 p = arg; | |
3869 while (*p) | |
3870 { | |
3871 if (*p == ' ') | |
3872 /* argument starts after a space */ | |
3873 arg = p + 1; | |
3716 | 3874 else if (*p == '\\' && *(p + 1) != NUL) |
3875 ++p; /* skip over escaped character */ | |
3876 mb_ptr_adv(p); | |
3711 | 3877 } |
7 | 3878 xp->xp_pattern = arg; |
3879 } | |
3880 xp->xp_context = compl; | |
3881 } | |
3882 break; | |
3883 #endif | |
3884 case CMD_map: case CMD_noremap: | |
3885 case CMD_nmap: case CMD_nnoremap: | |
3886 case CMD_vmap: case CMD_vnoremap: | |
3887 case CMD_omap: case CMD_onoremap: | |
3888 case CMD_imap: case CMD_inoremap: | |
3889 case CMD_cmap: case CMD_cnoremap: | |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3890 case CMD_lmap: case CMD_lnoremap: |
7 | 3891 return set_context_in_map_cmd(xp, cmd, arg, forceit, |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3892 FALSE, FALSE, ea.cmdidx); |
7 | 3893 case CMD_unmap: |
3894 case CMD_nunmap: | |
3895 case CMD_vunmap: | |
3896 case CMD_ounmap: | |
3897 case CMD_iunmap: | |
3898 case CMD_cunmap: | |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3899 case CMD_lunmap: |
7 | 3900 return set_context_in_map_cmd(xp, cmd, arg, forceit, |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3901 FALSE, TRUE, ea.cmdidx); |
7 | 3902 case CMD_abbreviate: case CMD_noreabbrev: |
3903 case CMD_cabbrev: case CMD_cnoreabbrev: | |
3904 case CMD_iabbrev: case CMD_inoreabbrev: | |
3905 return set_context_in_map_cmd(xp, cmd, arg, forceit, | |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3906 TRUE, FALSE, ea.cmdidx); |
7 | 3907 case CMD_unabbreviate: |
3908 case CMD_cunabbrev: | |
3909 case CMD_iunabbrev: | |
3910 return set_context_in_map_cmd(xp, cmd, arg, forceit, | |
2405
84c9bf950ed4
Add completion for :lmap and :lunmap.
Bram Moolenaar <bram@vim.org>
parents:
2366
diff
changeset
|
3911 TRUE, TRUE, ea.cmdidx); |
7 | 3912 #ifdef FEAT_MENU |
3913 case CMD_menu: case CMD_noremenu: case CMD_unmenu: | |
3914 case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: | |
3915 case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: | |
3916 case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu: | |
3917 case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu: | |
3918 case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu: | |
3919 case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu: | |
3920 case CMD_tmenu: case CMD_tunmenu: | |
3921 case CMD_popup: case CMD_tearoff: case CMD_emenu: | |
3922 return set_context_in_menu_cmd(xp, cmd, arg, forceit); | |
3923 #endif | |
3924 | |
3925 case CMD_colorscheme: | |
3926 xp->xp_context = EXPAND_COLORS; | |
3927 xp->xp_pattern = arg; | |
3928 break; | |
3929 | |
3930 case CMD_compiler: | |
3931 xp->xp_context = EXPAND_COMPILER; | |
3932 xp->xp_pattern = arg; | |
3933 break; | |
3934 | |
2433
98b9a6b9e7d5
Add completion for ":ownsyntax" and improve completion for ":filetype".
Bram Moolenaar <bram@vim.org>
parents:
2406
diff
changeset
|
3935 case CMD_ownsyntax: |
98b9a6b9e7d5
Add completion for ":ownsyntax" and improve completion for ":filetype".
Bram Moolenaar <bram@vim.org>
parents:
2406
diff
changeset
|
3936 xp->xp_context = EXPAND_OWNSYNTAX; |
98b9a6b9e7d5
Add completion for ":ownsyntax" and improve completion for ":filetype".
Bram Moolenaar <bram@vim.org>
parents:
2406
diff
changeset
|
3937 xp->xp_pattern = arg; |
98b9a6b9e7d5
Add completion for ":ownsyntax" and improve completion for ":filetype".
Bram Moolenaar <bram@vim.org>
parents:
2406
diff
changeset
|
3938 break; |
98b9a6b9e7d5
Add completion for ":ownsyntax" and improve completion for ":filetype".
Bram Moolenaar <bram@vim.org>
parents:
2406
diff
changeset
|
3939 |
2406
bbff28ebfc7a
Add completion for :setfiletype. (Dominique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
2405
diff
changeset
|
3940 case CMD_setfiletype: |
2268
aafed4a4866f
Command line completion for :ownsyntax. (Dominique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
2250
diff
changeset
|
3941 xp->xp_context = EXPAND_FILETYPE; |
aafed4a4866f
Command line completion for :ownsyntax. (Dominique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
2250
diff
changeset
|
3942 xp->xp_pattern = arg; |
aafed4a4866f
Command line completion for :ownsyntax. (Dominique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
2250
diff
changeset
|
3943 break; |
aafed4a4866f
Command line completion for :ownsyntax. (Dominique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
2250
diff
changeset
|
3944 |
7 | 3945 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ |
3946 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) | |
3947 case CMD_language: | |
2853 | 3948 p = skiptowhite(arg); |
3949 if (*p == NUL) | |
7 | 3950 { |
3951 xp->xp_context = EXPAND_LANGUAGE; | |
3952 xp->xp_pattern = arg; | |
3953 } | |
3954 else | |
2853 | 3955 { |
3956 if ( STRNCMP(arg, "messages", p - arg) == 0 | |
3957 || STRNCMP(arg, "ctype", p - arg) == 0 | |
3958 || STRNCMP(arg, "time", p - arg) == 0) | |
3959 { | |
3960 xp->xp_context = EXPAND_LOCALES; | |
3961 xp->xp_pattern = skipwhite(p); | |
3962 } | |
3963 else | |
3964 xp->xp_context = EXPAND_NOTHING; | |
3965 } | |
7 | 3966 break; |
3967 #endif | |
2068
98a2a6e6b966
updated for version 7.2.353
Bram Moolenaar <bram@zimbu.org>
parents:
1973
diff
changeset
|
3968 #if defined(FEAT_PROFILE) |
98a2a6e6b966
updated for version 7.2.353
Bram Moolenaar <bram@zimbu.org>
parents:
1973
diff
changeset
|
3969 case CMD_profile: |
98a2a6e6b966
updated for version 7.2.353
Bram Moolenaar <bram@zimbu.org>
parents:
1973
diff
changeset
|
3970 set_context_in_profile_cmd(xp, arg); |
98a2a6e6b966
updated for version 7.2.353
Bram Moolenaar <bram@zimbu.org>
parents:
1973
diff
changeset
|
3971 break; |
98a2a6e6b966
updated for version 7.2.353
Bram Moolenaar <bram@zimbu.org>
parents:
1973
diff
changeset
|
3972 #endif |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3973 case CMD_behave: |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3974 xp->xp_context = EXPAND_BEHAVE; |
3503 | 3975 xp->xp_pattern = arg; |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
3976 break; |
7 | 3977 |
3503 | 3978 #if defined(FEAT_CMDHIST) |
3979 case CMD_history: | |
3980 xp->xp_context = EXPAND_HISTORY; | |
3981 xp->xp_pattern = arg; | |
3982 break; | |
3983 #endif | |
3984 | |
7 | 3985 #endif /* FEAT_CMDL_COMPL */ |
3986 | |
3987 default: | |
3988 break; | |
3989 } | |
3990 return NULL; | |
3991 } | |
3992 | |
3993 /* | |
3994 * skip a range specifier of the form: addr [,addr] [;addr] .. | |
3995 * | |
3996 * Backslashed delimiters after / or ? will be skipped, and commands will | |
3997 * not be expanded between /'s and ?'s or after "'". | |
3998 * | |
167 | 3999 * Also skip white space and ":" characters. |
7 | 4000 * Returns the "cmd" pointer advanced to beyond the range. |
4001 */ | |
4002 char_u * | |
4003 skip_range(cmd, ctx) | |
4004 char_u *cmd; | |
4005 int *ctx; /* pointer to xp_context or NULL */ | |
4006 { | |
1872 | 4007 unsigned delim; |
7 | 4008 |
167 | 4009 while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;", *cmd) != NULL) |
7 | 4010 { |
4011 if (*cmd == '\'') | |
4012 { | |
4013 if (*++cmd == NUL && ctx != NULL) | |
4014 *ctx = EXPAND_NOTHING; | |
4015 } | |
4016 else if (*cmd == '/' || *cmd == '?') | |
4017 { | |
4018 delim = *cmd++; | |
4019 while (*cmd != NUL && *cmd != delim) | |
4020 if (*cmd++ == '\\' && *cmd != NUL) | |
4021 ++cmd; | |
4022 if (*cmd == NUL && ctx != NULL) | |
4023 *ctx = EXPAND_NOTHING; | |
4024 } | |
4025 if (*cmd != NUL) | |
4026 ++cmd; | |
4027 } | |
167 | 4028 |
4029 /* Skip ":" and white space. */ | |
4030 while (*cmd == ':') | |
4031 cmd = skipwhite(cmd + 1); | |
4032 | |
7 | 4033 return cmd; |
4034 } | |
4035 | |
4036 /* | |
4037 * get a single EX address | |
4038 * | |
4039 * Set ptr to the next character after the part that was interpreted. | |
4040 * Set ptr to NULL when an error is encountered. | |
4041 * | |
4042 * Return MAXLNUM when no Ex address was found. | |
4043 */ | |
4044 static linenr_T | |
4045 get_address(ptr, skip, to_other_file) | |
4046 char_u **ptr; | |
4047 int skip; /* only skip the address, don't use it */ | |
4048 int to_other_file; /* flag: may jump to other file */ | |
4049 { | |
4050 int c; | |
4051 int i; | |
4052 long n; | |
4053 char_u *cmd; | |
4054 pos_T pos; | |
4055 pos_T *fp; | |
4056 linenr_T lnum; | |
4057 | |
4058 cmd = skipwhite(*ptr); | |
4059 lnum = MAXLNUM; | |
4060 do | |
4061 { | |
4062 switch (*cmd) | |
4063 { | |
4064 case '.': /* '.' - Cursor position */ | |
4065 ++cmd; | |
4066 lnum = curwin->w_cursor.lnum; | |
4067 break; | |
4068 | |
4069 case '$': /* '$' - last line */ | |
4070 ++cmd; | |
4071 lnum = curbuf->b_ml.ml_line_count; | |
4072 break; | |
4073 | |
4074 case '\'': /* ''' - mark */ | |
4075 if (*++cmd == NUL) | |
4076 { | |
4077 cmd = NULL; | |
4078 goto error; | |
4079 } | |
4080 if (skip) | |
4081 ++cmd; | |
4082 else | |
4083 { | |
4084 /* Only accept a mark in another file when it is | |
4085 * used by itself: ":'M". */ | |
4086 fp = getmark(*cmd, to_other_file && cmd[1] == NUL); | |
4087 ++cmd; | |
4088 if (fp == (pos_T *)-1) | |
4089 /* Jumped to another file. */ | |
4090 lnum = curwin->w_cursor.lnum; | |
4091 else | |
4092 { | |
4093 if (check_mark(fp) == FAIL) | |
4094 { | |
4095 cmd = NULL; | |
4096 goto error; | |
4097 } | |
4098 lnum = fp->lnum; | |
4099 } | |
4100 } | |
4101 break; | |
4102 | |
4103 case '/': | |
4104 case '?': /* '/' or '?' - search */ | |
4105 c = *cmd++; | |
4106 if (skip) /* skip "/pat/" */ | |
4107 { | |
4108 cmd = skip_regexp(cmd, c, (int)p_magic, NULL); | |
4109 if (*cmd == c) | |
4110 ++cmd; | |
4111 } | |
4112 else | |
4113 { | |
4114 pos = curwin->w_cursor; /* save curwin->w_cursor */ | |
4115 /* | |
4116 * When '/' or '?' follows another address, start | |
4117 * from there. | |
4118 */ | |
4119 if (lnum != MAXLNUM) | |
4120 curwin->w_cursor.lnum = lnum; | |
4121 /* | |
4122 * Start a forward search at the end of the line. | |
4123 * Start a backward search at the start of the line. | |
4124 * This makes sure we never match in the current | |
4125 * line, and can match anywhere in the | |
4126 * next/previous line. | |
4127 */ | |
4128 if (c == '/') | |
4129 curwin->w_cursor.col = MAXCOL; | |
4130 else | |
4131 curwin->w_cursor.col = 0; | |
4132 searchcmdlen = 0; | |
4133 if (!do_search(NULL, c, cmd, 1L, | |
1557 | 4134 SEARCH_HIS | SEARCH_MSG, NULL)) |
7 | 4135 { |
4136 curwin->w_cursor = pos; | |
4137 cmd = NULL; | |
4138 goto error; | |
4139 } | |
4140 lnum = curwin->w_cursor.lnum; | |
4141 curwin->w_cursor = pos; | |
4142 /* adjust command string pointer */ | |
4143 cmd += searchcmdlen; | |
4144 } | |
4145 break; | |
4146 | |
4147 case '\\': /* "\?", "\/" or "\&", repeat search */ | |
4148 ++cmd; | |
4149 if (*cmd == '&') | |
4150 i = RE_SUBST; | |
4151 else if (*cmd == '?' || *cmd == '/') | |
4152 i = RE_SEARCH; | |
4153 else | |
4154 { | |
4155 EMSG(_(e_backslash)); | |
4156 cmd = NULL; | |
4157 goto error; | |
4158 } | |
4159 | |
4160 if (!skip) | |
4161 { | |
4162 /* | |
4163 * When search follows another address, start from | |
4164 * there. | |
4165 */ | |
4166 if (lnum != MAXLNUM) | |
4167 pos.lnum = lnum; | |
4168 else | |
4169 pos.lnum = curwin->w_cursor.lnum; | |
4170 | |
4171 /* | |
4172 * Start the search just like for the above | |
4173 * do_search(). | |
4174 */ | |
4175 if (*cmd != '?') | |
4176 pos.col = MAXCOL; | |
4177 else | |
4178 pos.col = 0; | |
4179 if (searchit(curwin, curbuf, &pos, | |
4180 *cmd == '?' ? BACKWARD : FORWARD, | |
1557 | 4181 (char_u *)"", 1L, SEARCH_MSG, |
1496 | 4182 i, (linenr_T)0, NULL) != FAIL) |
7 | 4183 lnum = pos.lnum; |
4184 else | |
4185 { | |
4186 cmd = NULL; | |
4187 goto error; | |
4188 } | |
4189 } | |
4190 ++cmd; | |
4191 break; | |
4192 | |
4193 default: | |
4194 if (VIM_ISDIGIT(*cmd)) /* absolute line number */ | |
4195 lnum = getdigits(&cmd); | |
4196 } | |
4197 | |
4198 for (;;) | |
4199 { | |
4200 cmd = skipwhite(cmd); | |
4201 if (*cmd != '-' && *cmd != '+' && !VIM_ISDIGIT(*cmd)) | |
4202 break; | |
4203 | |
4204 if (lnum == MAXLNUM) | |
4205 lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ | |
4206 if (VIM_ISDIGIT(*cmd)) | |
4207 i = '+'; /* "number" is same as "+number" */ | |
4208 else | |
4209 i = *cmd++; | |
4210 if (!VIM_ISDIGIT(*cmd)) /* '+' is '+1', but '+0' is not '+1' */ | |
4211 n = 1; | |
4212 else | |
4213 n = getdigits(&cmd); | |
4214 if (i == '-') | |
4215 lnum -= n; | |
4216 else | |
4217 lnum += n; | |
4218 } | |
4219 } while (*cmd == '/' || *cmd == '?'); | |
4220 | |
4221 error: | |
4222 *ptr = cmd; | |
4223 return lnum; | |
4224 } | |
4225 | |
4226 /* | |
167 | 4227 * Get flags from an Ex command argument. |
4228 */ | |
4229 static void | |
4230 get_flags(eap) | |
4231 exarg_T *eap; | |
4232 { | |
4233 while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL) | |
4234 { | |
4235 if (*eap->arg == 'l') | |
4236 eap->flags |= EXFLAG_LIST; | |
4237 else if (*eap->arg == 'p') | |
4238 eap->flags |= EXFLAG_PRINT; | |
4239 else | |
4240 eap->flags |= EXFLAG_NR; | |
4241 eap->arg = skipwhite(eap->arg + 1); | |
4242 } | |
4243 } | |
4244 | |
4245 /* | |
7 | 4246 * Function called for command which is Not Implemented. NI! |
4247 */ | |
4248 void | |
4249 ex_ni(eap) | |
4250 exarg_T *eap; | |
4251 { | |
4252 if (!eap->skip) | |
4253 eap->errmsg = (char_u *)N_("E319: Sorry, the command is not available in this version"); | |
4254 } | |
4255 | |
1315 | 4256 #ifdef HAVE_EX_SCRIPT_NI |
7 | 4257 /* |
4258 * Function called for script command which is Not Implemented. NI! | |
4259 * Skips over ":perl <<EOF" constructs. | |
4260 */ | |
4261 static void | |
4262 ex_script_ni(eap) | |
4263 exarg_T *eap; | |
4264 { | |
4265 if (!eap->skip) | |
4266 ex_ni(eap); | |
4267 else | |
4268 vim_free(script_get(eap, eap->arg)); | |
4269 } | |
4270 #endif | |
4271 | |
4272 /* | |
4273 * Check range in Ex command for validity. | |
4274 * Return NULL when valid, error message when invalid. | |
4275 */ | |
4276 static char_u * | |
4277 invalid_range(eap) | |
4278 exarg_T *eap; | |
4279 { | |
4280 if ( eap->line1 < 0 | |
4281 || eap->line2 < 0 | |
4282 || eap->line1 > eap->line2 | |
4283 || ((eap->argt & RANGE) | |
4284 && !(eap->argt & NOTADR) | |
4285 && eap->line2 > curbuf->b_ml.ml_line_count | |
4286 #ifdef FEAT_DIFF | |
4287 + (eap->cmdidx == CMD_diffget) | |
4288 #endif | |
4289 )) | |
4290 return (char_u *)_(e_invrange); | |
4291 return NULL; | |
4292 } | |
4293 | |
4294 /* | |
4295 * Correct the range for zero line number, if required. | |
4296 */ | |
4297 static void | |
4298 correct_range(eap) | |
4299 exarg_T *eap; | |
4300 { | |
4301 if (!(eap->argt & ZEROR)) /* zero in range not allowed */ | |
4302 { | |
4303 if (eap->line1 == 0) | |
4304 eap->line1 = 1; | |
4305 if (eap->line2 == 0) | |
4306 eap->line2 = 1; | |
4307 } | |
4308 } | |
4309 | |
153 | 4310 #ifdef FEAT_QUICKFIX |
4311 static char_u *skip_grep_pat __ARGS((exarg_T *eap)); | |
4312 | |
4313 /* | |
4314 * For a ":vimgrep" or ":vimgrepadd" command return a pointer past the | |
4315 * pattern. Otherwise return eap->arg. | |
4316 */ | |
4317 static char_u * | |
4318 skip_grep_pat(eap) | |
4319 exarg_T *eap; | |
4320 { | |
4321 char_u *p = eap->arg; | |
4322 | |
655 | 4323 if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep |
4324 || eap->cmdidx == CMD_vimgrepadd | |
4325 || eap->cmdidx == CMD_lvimgrepadd | |
4326 || grep_internal(eap->cmdidx))) | |
153 | 4327 { |
170 | 4328 p = skip_vimgrep_pat(p, NULL, NULL); |
153 | 4329 if (p == NULL) |
4330 p = eap->arg; | |
4331 } | |
4332 return p; | |
4333 } | |
344 | 4334 |
4335 /* | |
4336 * For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option | |
4337 * in the command line, so that things like % get expanded. | |
4338 */ | |
4339 static char_u * | |
4340 replace_makeprg(eap, p, cmdlinep) | |
4341 exarg_T *eap; | |
4342 char_u *p; | |
4343 char_u **cmdlinep; | |
4344 { | |
4345 char_u *new_cmdline; | |
4346 char_u *program; | |
4347 char_u *pos; | |
4348 char_u *ptr; | |
4349 int len; | |
4350 int i; | |
4351 | |
4352 /* | |
4353 * Don't do it when ":vimgrep" is used for ":grep". | |
4354 */ | |
655 | 4355 if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake |
4356 || eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep | |
4357 || eap->cmdidx == CMD_grepadd | |
4358 || eap->cmdidx == CMD_lgrepadd) | |
344 | 4359 && !grep_internal(eap->cmdidx)) |
4360 { | |
655 | 4361 if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep |
4362 || eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) | |
344 | 4363 { |
4364 if (*curbuf->b_p_gp == NUL) | |
4365 program = p_gp; | |
4366 else | |
4367 program = curbuf->b_p_gp; | |
4368 } | |
4369 else | |
4370 { | |
4371 if (*curbuf->b_p_mp == NUL) | |
4372 program = p_mp; | |
4373 else | |
4374 program = curbuf->b_p_mp; | |
4375 } | |
4376 | |
4377 p = skipwhite(p); | |
4378 | |
4379 if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) | |
4380 { | |
4381 /* replace $* by given arguments */ | |
4382 i = 1; | |
4383 while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL) | |
4384 ++i; | |
4385 len = (int)STRLEN(p); | |
4386 new_cmdline = alloc((int)(STRLEN(program) + i * (len - 2) + 1)); | |
4387 if (new_cmdline == NULL) | |
4388 return NULL; /* out of memory */ | |
4389 ptr = new_cmdline; | |
4390 while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) | |
4391 { | |
4392 i = (int)(pos - program); | |
4393 STRNCPY(ptr, program, i); | |
4394 STRCPY(ptr += i, p); | |
4395 ptr += len; | |
4396 program = pos + 2; | |
4397 } | |
4398 STRCPY(ptr, program); | |
4399 } | |
4400 else | |
4401 { | |
4402 new_cmdline = alloc((int)(STRLEN(program) + STRLEN(p) + 2)); | |
4403 if (new_cmdline == NULL) | |
4404 return NULL; /* out of memory */ | |
4405 STRCPY(new_cmdline, program); | |
4406 STRCAT(new_cmdline, " "); | |
4407 STRCAT(new_cmdline, p); | |
4408 } | |
4409 msg_make(p); | |
4410 | |
4411 /* 'eap->cmd' is not set here, because it is not used at CMD_make */ | |
4412 vim_free(*cmdlinep); | |
4413 *cmdlinep = new_cmdline; | |
4414 p = new_cmdline; | |
4415 } | |
4416 return p; | |
4417 } | |
153 | 4418 #endif |
4419 | |
7 | 4420 /* |
4421 * Expand file name in Ex command argument. | |
4422 * Return FAIL for failure, OK otherwise. | |
4423 */ | |
4424 int | |
4425 expand_filename(eap, cmdlinep, errormsgp) | |
4426 exarg_T *eap; | |
4427 char_u **cmdlinep; | |
4428 char_u **errormsgp; | |
4429 { | |
4430 int has_wildcards; /* need to expand wildcards */ | |
4431 char_u *repl; | |
4432 int srclen; | |
4433 char_u *p; | |
4434 int n; | |
1098 | 4435 int escaped; |
7 | 4436 |
153 | 4437 #ifdef FEAT_QUICKFIX |
4438 /* Skip a regexp pattern for ":vimgrep[add] pat file..." */ | |
4439 p = skip_grep_pat(eap); | |
4440 #else | |
4441 p = eap->arg; | |
4442 #endif | |
4443 | |
7 | 4444 /* |
4445 * Decide to expand wildcards *before* replacing '%', '#', etc. If | |
4446 * the file name contains a wildcard it should not cause expanding. | |
4447 * (it will be expanded anyway if there is a wildcard before replacing). | |
4448 */ | |
153 | 4449 has_wildcards = mch_has_wildcard(p); |
4450 while (*p != NUL) | |
7 | 4451 { |
9 | 4452 #ifdef FEAT_EVAL |
4453 /* Skip over `=expr`, wildcards in it are not expanded. */ | |
4454 if (p[0] == '`' && p[1] == '=') | |
4455 { | |
4456 p += 2; | |
4457 (void)skip_expr(&p); | |
4458 if (*p == '`') | |
4459 ++p; | |
4460 continue; | |
4461 } | |
4462 #endif | |
7 | 4463 /* |
4464 * Quick check if this cannot be the start of a special string. | |
4465 * Also removes backslash before '%', '#' and '<'. | |
4466 */ | |
4467 if (vim_strchr((char_u *)"%#<", *p) == NULL) | |
4468 { | |
4469 ++p; | |
4470 continue; | |
4471 } | |
4472 | |
4473 /* | |
4474 * Try to find a match at this position. | |
4475 */ | |
1098 | 4476 repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum), |
4477 errormsgp, &escaped); | |
7 | 4478 if (*errormsgp != NULL) /* error detected */ |
4479 return FAIL; | |
4480 if (repl == NULL) /* no match found */ | |
4481 { | |
4482 p += srclen; | |
4483 continue; | |
4484 } | |
4485 | |
37 | 4486 /* Wildcards won't be expanded below, the replacement is taken |
4487 * literally. But do expand "~/file", "~user/file" and "$HOME/file". */ | |
4488 if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL) | |
4489 { | |
4490 char_u *l = repl; | |
4491 | |
4492 repl = expand_env_save(repl); | |
4493 vim_free(l); | |
4494 } | |
4495 | |
1098 | 4496 /* Need to escape white space et al. with a backslash. |
4497 * Don't do this for: | |
4498 * - replacement that already has been escaped: "##" | |
4499 * - shell commands (may have to use quotes instead). | |
4500 * - non-unix systems when there is a single argument (spaces don't | |
4501 * separate arguments then). | |
4502 */ | |
7 | 4503 if (!eap->usefilter |
1098 | 4504 && !escaped |
7 | 4505 && eap->cmdidx != CMD_bang |
4506 && eap->cmdidx != CMD_make | |
655 | 4507 && eap->cmdidx != CMD_lmake |
7 | 4508 && eap->cmdidx != CMD_grep |
655 | 4509 && eap->cmdidx != CMD_lgrep |
7 | 4510 && eap->cmdidx != CMD_grepadd |
655 | 4511 && eap->cmdidx != CMD_lgrepadd |
7 | 4512 #ifndef UNIX |
4513 && !(eap->argt & NOSPC) | |
4514 #endif | |
4515 ) | |
4516 { | |
4517 char_u *l; | |
4518 #ifdef BACKSLASH_IN_FILENAME | |
4519 /* Don't escape a backslash here, because rem_backslash() doesn't | |
4520 * remove it later. */ | |
4521 static char_u *nobslash = (char_u *)" \t\"|"; | |
4522 # define ESCAPE_CHARS nobslash | |
4523 #else | |
4524 # define ESCAPE_CHARS escape_chars | |
4525 #endif | |
4526 | |
4527 for (l = repl; *l; ++l) | |
4528 if (vim_strchr(ESCAPE_CHARS, *l) != NULL) | |
4529 { | |
4530 l = vim_strsave_escaped(repl, ESCAPE_CHARS); | |
4531 if (l != NULL) | |
4532 { | |
4533 vim_free(repl); | |
4534 repl = l; | |
4535 } | |
4536 break; | |
4537 } | |
4538 } | |
4539 | |
4540 /* For a shell command a '!' must be escaped. */ | |
4541 if ((eap->usefilter || eap->cmdidx == CMD_bang) | |
631 | 4542 && vim_strpbrk(repl, (char_u *)"!&;()<>") != NULL) |
7 | 4543 { |
4544 char_u *l; | |
4545 | |
631 | 4546 l = vim_strsave_escaped(repl, (char_u *)"!&;()<>"); |
7 | 4547 if (l != NULL) |
4548 { | |
4549 vim_free(repl); | |
4550 repl = l; | |
631 | 4551 /* For a sh-like shell escape "!" another time. */ |
7 | 4552 if (strstr((char *)p_sh, "sh") != NULL) |
4553 { | |
4554 l = vim_strsave_escaped(repl, (char_u *)"!"); | |
4555 if (l != NULL) | |
4556 { | |
4557 vim_free(repl); | |
4558 repl = l; | |
4559 } | |
4560 } | |
4561 } | |
4562 } | |
4563 | |
4564 p = repl_cmdline(eap, p, srclen, repl, cmdlinep); | |
4565 vim_free(repl); | |
4566 if (p == NULL) | |
4567 return FAIL; | |
4568 } | |
4569 | |
4570 /* | |
4571 * One file argument: Expand wildcards. | |
4572 * Don't do this with ":r !command" or ":w !command". | |
4573 */ | |
4574 if ((eap->argt & NOSPC) && !eap->usefilter) | |
4575 { | |
4576 /* | |
4577 * May do this twice: | |
4578 * 1. Replace environment variables. | |
4579 * 2. Replace any other wildcards, remove backslashes. | |
4580 */ | |
4581 for (n = 1; n <= 2; ++n) | |
4582 { | |
4583 if (n == 2) | |
4584 { | |
4585 #ifdef UNIX | |
4586 /* | |
4587 * Only for Unix we check for more than one file name. | |
4588 * For other systems spaces are considered to be part | |
4589 * of the file name. | |
4590 * Only check here if there is no wildcard, otherwise | |
4591 * ExpandOne() will check for errors. This allows | |
4592 * ":e `ls ve*.c`" on Unix. | |
4593 */ | |
4594 if (!has_wildcards) | |
4595 for (p = eap->arg; *p; ++p) | |
4596 { | |
4597 /* skip escaped characters */ | |
4598 if (p[1] && (*p == '\\' || *p == Ctrl_V)) | |
4599 ++p; | |
4600 else if (vim_iswhite(*p)) | |
4601 { | |
4602 *errormsgp = (char_u *)_("E172: Only one file name allowed"); | |
4603 return FAIL; | |
4604 } | |
4605 } | |
4606 #endif | |
4607 | |
4608 /* | |
4609 * Halve the number of backslashes (this is Vi compatible). | |
4610 * For Unix and OS/2, when wildcards are expanded, this is | |
4611 * done by ExpandOne() below. | |
4612 */ | |
4613 #if defined(UNIX) || defined(OS2) | |
4614 if (!has_wildcards) | |
4615 #endif | |
4616 backslash_halve(eap->arg); | |
4617 } | |
4618 | |
4619 if (has_wildcards) | |
4620 { | |
4621 if (n == 1) | |
4622 { | |
4623 /* | |
4624 * First loop: May expand environment variables. This | |
4625 * can be done much faster with expand_env() than with | |
4626 * something else (e.g., calling a shell). | |
4627 * After expanding environment variables, check again | |
4628 * if there are still wildcards present. | |
4629 */ | |
4630 if (vim_strchr(eap->arg, '$') != NULL | |
4631 || vim_strchr(eap->arg, '~') != NULL) | |
4632 { | |
372 | 4633 expand_env_esc(eap->arg, NameBuff, MAXPATHL, |
1408 | 4634 TRUE, TRUE, NULL); |
7 | 4635 has_wildcards = mch_has_wildcard(NameBuff); |
4636 p = NameBuff; | |
4637 } | |
4638 else | |
4639 p = NULL; | |
4640 } | |
4641 else /* n == 2 */ | |
4642 { | |
4643 expand_T xpc; | |
2652 | 4644 int options = WILD_LIST_NOTFOUND|WILD_ADD_SLASH; |
7 | 4645 |
4646 ExpandInit(&xpc); | |
4647 xpc.xp_context = EXPAND_FILES; | |
2652 | 4648 if (p_wic) |
4649 options += WILD_ICASE; | |
7 | 4650 p = ExpandOne(&xpc, eap->arg, NULL, |
2652 | 4651 options, WILD_EXPAND_FREE); |
7 | 4652 if (p == NULL) |
4653 return FAIL; | |
4654 } | |
4655 if (p != NULL) | |
4656 { | |
4657 (void)repl_cmdline(eap, eap->arg, (int)STRLEN(eap->arg), | |
4658 p, cmdlinep); | |
4659 if (n == 2) /* p came from ExpandOne() */ | |
4660 vim_free(p); | |
4661 } | |
4662 } | |
4663 } | |
4664 } | |
4665 return OK; | |
4666 } | |
4667 | |
4668 /* | |
4669 * Replace part of the command line, keeping eap->cmd, eap->arg and | |
4670 * eap->nextcmd correct. | |
4671 * "src" points to the part that is to be replaced, of length "srclen". | |
4672 * "repl" is the replacement string. | |
4673 * Returns a pointer to the character after the replaced string. | |
4674 * Returns NULL for failure. | |
4675 */ | |
4676 static char_u * | |
4677 repl_cmdline(eap, src, srclen, repl, cmdlinep) | |
4678 exarg_T *eap; | |
4679 char_u *src; | |
4680 int srclen; | |
4681 char_u *repl; | |
4682 char_u **cmdlinep; | |
4683 { | |
4684 int len; | |
4685 int i; | |
4686 char_u *new_cmdline; | |
4687 | |
4688 /* | |
4689 * The new command line is build in new_cmdline[]. | |
4690 * First allocate it. | |
4691 * Careful: a "+cmd" argument may have been NUL terminated. | |
4692 */ | |
4693 len = (int)STRLEN(repl); | |
4694 i = (int)(src - *cmdlinep) + (int)STRLEN(src + srclen) + len + 3; | |
698 | 4695 if (eap->nextcmd != NULL) |
7 | 4696 i += (int)STRLEN(eap->nextcmd);/* add space for next command */ |
4697 if ((new_cmdline = alloc((unsigned)i)) == NULL) | |
4698 return NULL; /* out of memory! */ | |
4699 | |
4700 /* | |
4701 * Copy the stuff before the expanded part. | |
4702 * Copy the expanded stuff. | |
4703 * Copy what came after the expanded part. | |
4704 * Copy the next commands, if there are any. | |
4705 */ | |
4706 i = (int)(src - *cmdlinep); /* length of part before match */ | |
4707 mch_memmove(new_cmdline, *cmdlinep, (size_t)i); | |
434 | 4708 |
7 | 4709 mch_memmove(new_cmdline + i, repl, (size_t)len); |
4710 i += len; /* remember the end of the string */ | |
4711 STRCPY(new_cmdline + i, src + srclen); | |
4712 src = new_cmdline + i; /* remember where to continue */ | |
4713 | |
698 | 4714 if (eap->nextcmd != NULL) /* append next command */ |
7 | 4715 { |
4716 i = (int)STRLEN(new_cmdline) + 1; | |
4717 STRCPY(new_cmdline + i, eap->nextcmd); | |
4718 eap->nextcmd = new_cmdline + i; | |
4719 } | |
4720 eap->cmd = new_cmdline + (eap->cmd - *cmdlinep); | |
4721 eap->arg = new_cmdline + (eap->arg - *cmdlinep); | |
4722 if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) | |
4723 eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep); | |
4724 vim_free(*cmdlinep); | |
4725 *cmdlinep = new_cmdline; | |
4726 | |
4727 return src; | |
4728 } | |
4729 | |
4730 /* | |
4731 * Check for '|' to separate commands and '"' to start comments. | |
4732 */ | |
4733 void | |
4734 separate_nextcmd(eap) | |
4735 exarg_T *eap; | |
4736 { | |
4737 char_u *p; | |
4738 | |
153 | 4739 #ifdef FEAT_QUICKFIX |
4740 p = skip_grep_pat(eap); | |
4741 #else | |
41 | 4742 p = eap->arg; |
4743 #endif | |
4744 | |
4745 for ( ; *p; mb_ptr_adv(p)) | |
7 | 4746 { |
4747 if (*p == Ctrl_V) | |
4748 { | |
4749 if (eap->argt & (USECTRLV | XFILE)) | |
4750 ++p; /* skip CTRL-V and next char */ | |
4751 else | |
1362 | 4752 /* remove CTRL-V and skip next char */ |
1619 | 4753 STRMOVE(p, p + 1); |
7 | 4754 if (*p == NUL) /* stop at NUL after CTRL-V */ |
4755 break; | |
4756 } | |
9 | 4757 |
4758 #ifdef FEAT_EVAL | |
4759 /* Skip over `=expr` when wildcards are expanded. */ | |
167 | 4760 else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) |
9 | 4761 { |
4762 p += 2; | |
4763 (void)skip_expr(&p); | |
4764 } | |
4765 #endif | |
4766 | |
7 | 4767 /* Check for '"': start of comment or '|': next command */ |
4768 /* :@" and :*" do not start a comment! | |
4769 * :redir @" doesn't either. */ | |
4770 else if ((*p == '"' && !(eap->argt & NOTRLCOM) | |
4771 && ((eap->cmdidx != CMD_at && eap->cmdidx != CMD_star) | |
4772 || p != eap->arg) | |
4773 && (eap->cmdidx != CMD_redir | |
4774 || p != eap->arg + 1 || p[-1] != '@')) | |
4775 || *p == '|' || *p == '\n') | |
4776 { | |
4777 /* | |
4778 * We remove the '\' before the '|', unless USECTRLV is used | |
4779 * AND 'b' is present in 'cpoptions'. | |
4780 */ | |
4781 if ((vim_strchr(p_cpo, CPO_BAR) == NULL | |
4782 || !(eap->argt & USECTRLV)) && *(p - 1) == '\\') | |
4783 { | |
1619 | 4784 STRMOVE(p - 1, p); /* remove the '\' */ |
7 | 4785 --p; |
4786 } | |
4787 else | |
4788 { | |
4789 eap->nextcmd = check_nextcmd(p); | |
4790 *p = NUL; | |
4791 break; | |
4792 } | |
4793 } | |
41 | 4794 } |
4795 | |
7 | 4796 if (!(eap->argt & NOTRLCOM)) /* remove trailing spaces */ |
4797 del_trailing_spaces(eap->arg); | |
4798 } | |
4799 | |
4800 /* | |
4801 * get + command from ex argument | |
4802 */ | |
4803 static char_u * | |
4804 getargcmd(argp) | |
4805 char_u **argp; | |
4806 { | |
4807 char_u *arg = *argp; | |
4808 char_u *command = NULL; | |
4809 | |
4810 if (*arg == '+') /* +[command] */ | |
4811 { | |
4812 ++arg; | |
4813 if (vim_isspace(*arg)) | |
4814 command = dollar_command; | |
4815 else | |
4816 { | |
4817 command = arg; | |
4818 arg = skip_cmd_arg(command, TRUE); | |
4819 if (*arg != NUL) | |
4820 *arg++ = NUL; /* terminate command with NUL */ | |
4821 } | |
4822 | |
4823 arg = skipwhite(arg); /* skip over spaces */ | |
4824 *argp = arg; | |
4825 } | |
4826 return command; | |
4827 } | |
4828 | |
4829 /* | |
4830 * Find end of "+command" argument. Skip over "\ " and "\\". | |
4831 */ | |
4832 static char_u * | |
4833 skip_cmd_arg(p, rembs) | |
4834 char_u *p; | |
4835 int rembs; /* TRUE to halve the number of backslashes */ | |
4836 { | |
4837 while (*p && !vim_isspace(*p)) | |
4838 { | |
4839 if (*p == '\\' && p[1] != NUL) | |
4840 { | |
4841 if (rembs) | |
1619 | 4842 STRMOVE(p, p + 1); |
7 | 4843 else |
4844 ++p; | |
4845 } | |
39 | 4846 mb_ptr_adv(p); |
7 | 4847 } |
4848 return p; | |
4849 } | |
4850 | |
4851 /* | |
4852 * Get "++opt=arg" argument. | |
4853 * Return FAIL or OK. | |
4854 */ | |
4855 static int | |
4856 getargopt(eap) | |
4857 exarg_T *eap; | |
4858 { | |
4859 char_u *arg = eap->arg + 2; | |
4860 int *pp = NULL; | |
4861 #ifdef FEAT_MBYTE | |
2168 | 4862 int bad_char_idx; |
7 | 4863 char_u *p; |
4864 #endif | |
4865 | |
4866 /* ":edit ++[no]bin[ary] file" */ | |
4867 if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0) | |
4868 { | |
4869 if (*arg == 'n') | |
4870 { | |
4871 arg += 2; | |
4872 eap->force_bin = FORCE_NOBIN; | |
4873 } | |
4874 else | |
4875 eap->force_bin = FORCE_BIN; | |
4876 if (!checkforcmd(&arg, "binary", 3)) | |
4877 return FAIL; | |
4878 eap->arg = skipwhite(arg); | |
4879 return OK; | |
4880 } | |
4881 | |
819 | 4882 /* ":read ++edit file" */ |
4883 if (STRNCMP(arg, "edit", 4) == 0) | |
4884 { | |
4885 eap->read_edit = TRUE; | |
4886 eap->arg = skipwhite(arg + 4); | |
4887 return OK; | |
4888 } | |
4889 | |
7 | 4890 if (STRNCMP(arg, "ff", 2) == 0) |
4891 { | |
4892 arg += 2; | |
4893 pp = &eap->force_ff; | |
4894 } | |
4895 else if (STRNCMP(arg, "fileformat", 10) == 0) | |
4896 { | |
4897 arg += 10; | |
4898 pp = &eap->force_ff; | |
4899 } | |
4900 #ifdef FEAT_MBYTE | |
4901 else if (STRNCMP(arg, "enc", 3) == 0) | |
4902 { | |
3208 | 4903 if (STRNCMP(arg, "encoding", 8) == 0) |
4904 arg += 8; | |
4905 else | |
4906 arg += 3; | |
7 | 4907 pp = &eap->force_enc; |
4908 } | |
595 | 4909 else if (STRNCMP(arg, "bad", 3) == 0) |
4910 { | |
4911 arg += 3; | |
2168 | 4912 pp = &bad_char_idx; |
595 | 4913 } |
7 | 4914 #endif |
4915 | |
4916 if (pp == NULL || *arg != '=') | |
4917 return FAIL; | |
4918 | |
4919 ++arg; | |
4920 *pp = (int)(arg - eap->cmd); | |
4921 arg = skip_cmd_arg(arg, FALSE); | |
4922 eap->arg = skipwhite(arg); | |
4923 *arg = NUL; | |
4924 | |
4925 #ifdef FEAT_MBYTE | |
4926 if (pp == &eap->force_ff) | |
4927 { | |
4928 #endif | |
4929 if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) | |
4930 return FAIL; | |
4931 #ifdef FEAT_MBYTE | |
4932 } | |
595 | 4933 else if (pp == &eap->force_enc) |
7 | 4934 { |
4935 /* Make 'fileencoding' lower case. */ | |
4936 for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) | |
4937 *p = TOLOWER_ASC(*p); | |
4938 } | |
595 | 4939 else |
4940 { | |
4941 /* Check ++bad= argument. Must be a single-byte character, "keep" or | |
4942 * "drop". */ | |
2168 | 4943 p = eap->cmd + bad_char_idx; |
595 | 4944 if (STRICMP(p, "keep") == 0) |
4945 eap->bad_char = BAD_KEEP; | |
4946 else if (STRICMP(p, "drop") == 0) | |
4947 eap->bad_char = BAD_DROP; | |
4948 else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) | |
4949 eap->bad_char = *p; | |
4950 else | |
4951 return FAIL; | |
4952 } | |
7 | 4953 #endif |
4954 | |
4955 return OK; | |
4956 } | |
4957 | |
4958 /* | |
4959 * ":abbreviate" and friends. | |
4960 */ | |
4961 static void | |
4962 ex_abbreviate(eap) | |
4963 exarg_T *eap; | |
4964 { | |
4965 do_exmap(eap, TRUE); /* almost the same as mapping */ | |
4966 } | |
4967 | |
4968 /* | |
4969 * ":map" and friends. | |
4970 */ | |
4971 static void | |
4972 ex_map(eap) | |
4973 exarg_T *eap; | |
4974 { | |
4975 /* | |
4976 * If we are sourcing .exrc or .vimrc in current directory we | |
4977 * print the mappings for security reasons. | |
4978 */ | |
4979 if (secure) | |
4980 { | |
4981 secure = 2; | |
4982 msg_outtrans(eap->cmd); | |
4983 msg_putchar('\n'); | |
4984 } | |
4985 do_exmap(eap, FALSE); | |
4986 } | |
4987 | |
4988 /* | |
4989 * ":unmap" and friends. | |
4990 */ | |
4991 static void | |
4992 ex_unmap(eap) | |
4993 exarg_T *eap; | |
4994 { | |
4995 do_exmap(eap, FALSE); | |
4996 } | |
4997 | |
4998 /* | |
4999 * ":mapclear" and friends. | |
5000 */ | |
5001 static void | |
5002 ex_mapclear(eap) | |
5003 exarg_T *eap; | |
5004 { | |
5005 map_clear(eap->cmd, eap->arg, eap->forceit, FALSE); | |
5006 } | |
5007 | |
5008 /* | |
5009 * ":abclear" and friends. | |
5010 */ | |
5011 static void | |
5012 ex_abclear(eap) | |
5013 exarg_T *eap; | |
5014 { | |
5015 map_clear(eap->cmd, eap->arg, TRUE, TRUE); | |
5016 } | |
5017 | |
3350 | 5018 #if defined(FEAT_AUTOCMD) || defined(PROTO) |
7 | 5019 static void |
5020 ex_autocmd(eap) | |
5021 exarg_T *eap; | |
5022 { | |
5023 /* | |
5024 * Disallow auto commands from .exrc and .vimrc in current | |
5025 * directory for security reasons. | |
5026 */ | |
5027 if (secure) | |
5028 { | |
5029 secure = 2; | |
5030 eap->errmsg = e_curdir; | |
5031 } | |
5032 else if (eap->cmdidx == CMD_autocmd) | |
5033 do_autocmd(eap->arg, eap->forceit); | |
5034 else | |
5035 do_augroup(eap->arg, eap->forceit); | |
5036 } | |
5037 | |
5038 /* | |
5039 * ":doautocmd": Apply the automatic commands to the current buffer. | |
5040 */ | |
5041 static void | |
5042 ex_doautocmd(eap) | |
5043 exarg_T *eap; | |
5044 { | |
3350 | 5045 char_u *arg = eap->arg; |
5046 int call_do_modelines = check_nomodeline(&arg); | |
5047 | |
5048 (void)do_doautocmd(arg, TRUE); | |
5049 if (call_do_modelines) /* Only when there is no <nomodeline>. */ | |
5050 do_modelines(0); | |
7 | 5051 } |
5052 #endif | |
5053 | |
5054 #ifdef FEAT_LISTCMDS | |
5055 /* | |
5056 * :[N]bunload[!] [N] [bufname] unload buffer | |
5057 * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list | |
5058 * :[N]bwipeout[!] [N] [bufname] delete buffer really | |
5059 */ | |
5060 static void | |
5061 ex_bunload(eap) | |
5062 exarg_T *eap; | |
5063 { | |
5064 eap->errmsg = do_bufdel( | |
5065 eap->cmdidx == CMD_bdelete ? DOBUF_DEL | |
5066 : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE | |
5067 : DOBUF_UNLOAD, eap->arg, | |
5068 eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit); | |
5069 } | |
5070 | |
5071 /* | |
5072 * :[N]buffer [N] to buffer N | |
5073 * :[N]sbuffer [N] to buffer N | |
5074 */ | |
5075 static void | |
5076 ex_buffer(eap) | |
5077 exarg_T *eap; | |
5078 { | |
5079 if (*eap->arg) | |
5080 eap->errmsg = e_trailing; | |
5081 else | |
5082 { | |
5083 if (eap->addr_count == 0) /* default is current buffer */ | |
5084 goto_buffer(eap, DOBUF_CURRENT, FORWARD, 0); | |
5085 else | |
5086 goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2); | |
5087 } | |
5088 } | |
5089 | |
5090 /* | |
5091 * :[N]bmodified [N] to next mod. buffer | |
5092 * :[N]sbmodified [N] to next mod. buffer | |
5093 */ | |
5094 static void | |
5095 ex_bmodified(eap) | |
5096 exarg_T *eap; | |
5097 { | |
5098 goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2); | |
5099 } | |
5100 | |
5101 /* | |
5102 * :[N]bnext [N] to next buffer | |
5103 * :[N]sbnext [N] split and to next buffer | |
5104 */ | |
5105 static void | |
5106 ex_bnext(eap) | |
5107 exarg_T *eap; | |
5108 { | |
5109 goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2); | |
5110 } | |
5111 | |
5112 /* | |
5113 * :[N]bNext [N] to previous buffer | |
5114 * :[N]bprevious [N] to previous buffer | |
5115 * :[N]sbNext [N] split and to previous buffer | |
5116 * :[N]sbprevious [N] split and to previous buffer | |
5117 */ | |
5118 static void | |
5119 ex_bprevious(eap) | |
5120 exarg_T *eap; | |
5121 { | |
5122 goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2); | |
5123 } | |
5124 | |
5125 /* | |
5126 * :brewind to first buffer | |
5127 * :bfirst to first buffer | |
5128 * :sbrewind split and to first buffer | |
5129 * :sbfirst split and to first buffer | |
5130 */ | |
5131 static void | |
5132 ex_brewind(eap) | |
5133 exarg_T *eap; | |
5134 { | |
5135 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); | |
5136 } | |
5137 | |
5138 /* | |
5139 * :blast to last buffer | |
5140 * :sblast split and to last buffer | |
5141 */ | |
5142 static void | |
5143 ex_blast(eap) | |
5144 exarg_T *eap; | |
5145 { | |
5146 goto_buffer(eap, DOBUF_LAST, BACKWARD, 0); | |
5147 } | |
5148 #endif | |
5149 | |
5150 int | |
5151 ends_excmd(c) | |
5152 int c; | |
5153 { | |
5154 return (c == NUL || c == '|' || c == '"' || c == '\n'); | |
5155 } | |
5156 | |
5157 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) || defined(FEAT_EVAL) \ | |
5158 || defined(PROTO) | |
5159 /* | |
5160 * Return the next command, after the first '|' or '\n'. | |
5161 * Return NULL if not found. | |
5162 */ | |
5163 char_u * | |
5164 find_nextcmd(p) | |
5165 char_u *p; | |
5166 { | |
5167 while (*p != '|' && *p != '\n') | |
5168 { | |
5169 if (*p == NUL) | |
5170 return NULL; | |
5171 ++p; | |
5172 } | |
5173 return (p + 1); | |
5174 } | |
5175 #endif | |
5176 | |
5177 /* | |
5178 * Check if *p is a separator between Ex commands. | |
5179 * Return NULL if it isn't, (p + 1) if it is. | |
5180 */ | |
5181 char_u * | |
5182 check_nextcmd(p) | |
5183 char_u *p; | |
5184 { | |
5185 p = skipwhite(p); | |
5186 if (*p == '|' || *p == '\n') | |
5187 return (p + 1); | |
5188 else | |
5189 return NULL; | |
5190 } | |
5191 | |
5192 /* | |
5193 * - if there are more files to edit | |
5194 * - and this is the last window | |
5195 * - and forceit not used | |
5196 * - and not repeated twice on a row | |
5197 * return FAIL and give error message if 'message' TRUE | |
5198 * return OK otherwise | |
5199 */ | |
5200 static int | |
5201 check_more(message, forceit) | |
5202 int message; /* when FALSE check only, no messages */ | |
5203 int forceit; | |
5204 { | |
5205 int n = ARGCOUNT - curwin->w_arg_idx - 1; | |
5206 | |
672 | 5207 if (!forceit && only_one_window() |
5208 && ARGCOUNT > 1 && !arg_had_last && n >= 0 && quitmore == 0) | |
7 | 5209 { |
5210 if (message) | |
5211 { | |
5212 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) | |
5213 if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL) | |
5214 { | |
2770 | 5215 char_u buff[DIALOG_MSG_SIZE]; |
7 | 5216 |
5217 if (n == 1) | |
2768 | 5218 vim_strncpy(buff, |
5219 (char_u *)_("1 more file to edit. Quit anyway?"), | |
2770 | 5220 DIALOG_MSG_SIZE - 1); |
7 | 5221 else |
2770 | 5222 vim_snprintf((char *)buff, DIALOG_MSG_SIZE, |
7 | 5223 _("%d more files to edit. Quit anyway?"), n); |
5224 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) | |
5225 return OK; | |
5226 return FAIL; | |
5227 } | |
5228 #endif | |
5229 if (n == 1) | |
5230 EMSG(_("E173: 1 more file to edit")); | |
5231 else | |
5232 EMSGN(_("E173: %ld more files to edit"), n); | |
5233 quitmore = 2; /* next try to quit is allowed */ | |
5234 } | |
5235 return FAIL; | |
5236 } | |
5237 return OK; | |
5238 } | |
5239 | |
5240 #ifdef FEAT_CMDL_COMPL | |
5241 /* | |
5242 * Function given to ExpandGeneric() to obtain the list of command names. | |
5243 */ | |
5244 char_u * | |
5245 get_command_name(xp, idx) | |
1877 | 5246 expand_T *xp UNUSED; |
7 | 5247 int idx; |
5248 { | |
5249 if (idx >= (int)CMD_SIZE) | |
5250 # ifdef FEAT_USR_CMDS | |
5251 return get_user_command_name(idx); | |
5252 # else | |
5253 return NULL; | |
5254 # endif | |
5255 return cmdnames[idx].cmd_name; | |
5256 } | |
5257 #endif | |
5258 | |
5259 #if defined(FEAT_USR_CMDS) || defined(PROTO) | |
5260 static int uc_add_command __ARGS((char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, char_u *compl_arg, int force)); | |
5261 static void uc_list __ARGS((char_u *name, size_t name_len)); | |
5262 static int uc_scan_attr __ARGS((char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl, char_u **compl_arg)); | |
5263 static char_u *uc_split_args __ARGS((char_u *arg, size_t *lenp)); | |
5264 static size_t uc_check_code __ARGS((char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap, char_u **split_buf, size_t *split_len)); | |
5265 | |
5266 static int | |
5267 uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, force) | |
5268 char_u *name; | |
5269 size_t name_len; | |
5270 char_u *rep; | |
5271 long argt; | |
5272 long def; | |
5273 int flags; | |
5274 int compl; | |
5275 char_u *compl_arg; | |
5276 int force; | |
5277 { | |
5278 ucmd_T *cmd = NULL; | |
5279 char_u *p; | |
5280 int i; | |
5281 int cmp = 1; | |
5282 char_u *rep_buf = NULL; | |
5283 garray_T *gap; | |
5284 | |
859 | 5285 replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); |
7 | 5286 if (rep_buf == NULL) |
5287 { | |
5288 /* Can't replace termcodes - try using the string as is */ | |
5289 rep_buf = vim_strsave(rep); | |
5290 | |
5291 /* Give up if out of memory */ | |
5292 if (rep_buf == NULL) | |
5293 return FAIL; | |
5294 } | |
5295 | |
5296 /* get address of growarray: global or in curbuf */ | |
5297 if (flags & UC_BUFFER) | |
5298 { | |
5299 gap = &curbuf->b_ucmds; | |
5300 if (gap->ga_itemsize == 0) | |
5301 ga_init2(gap, (int)sizeof(ucmd_T), 4); | |
5302 } | |
5303 else | |
5304 gap = &ucmds; | |
5305 | |
5306 /* Search for the command in the already defined commands. */ | |
5307 for (i = 0; i < gap->ga_len; ++i) | |
5308 { | |
5309 size_t len; | |
5310 | |
5311 cmd = USER_CMD_GA(gap, i); | |
5312 len = STRLEN(cmd->uc_name); | |
5313 cmp = STRNCMP(name, cmd->uc_name, name_len); | |
5314 if (cmp == 0) | |
5315 { | |
5316 if (name_len < len) | |
5317 cmp = -1; | |
5318 else if (name_len > len) | |
5319 cmp = 1; | |
5320 } | |
5321 | |
5322 if (cmp == 0) | |
5323 { | |
5324 if (!force) | |
5325 { | |
5326 EMSG(_("E174: Command already exists: add ! to replace it")); | |
5327 goto fail; | |
5328 } | |
5329 | |
5330 vim_free(cmd->uc_rep); | |
1837 | 5331 cmd->uc_rep = NULL; |
5332 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
5333 vim_free(cmd->uc_compl_arg); | |
5334 cmd->uc_compl_arg = NULL; | |
5335 #endif | |
7 | 5336 break; |
5337 } | |
5338 | |
5339 /* Stop as soon as we pass the name to add */ | |
5340 if (cmp < 0) | |
5341 break; | |
5342 } | |
5343 | |
5344 /* Extend the array unless we're replacing an existing command */ | |
5345 if (cmp != 0) | |
5346 { | |
5347 if (ga_grow(gap, 1) != OK) | |
5348 goto fail; | |
5349 if ((p = vim_strnsave(name, (int)name_len)) == NULL) | |
5350 goto fail; | |
5351 | |
5352 cmd = USER_CMD_GA(gap, i); | |
5353 mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); | |
5354 | |
5355 ++gap->ga_len; | |
5356 | |
5357 cmd->uc_name = p; | |
5358 } | |
5359 | |
5360 cmd->uc_rep = rep_buf; | |
5361 cmd->uc_argt = argt; | |
5362 cmd->uc_def = def; | |
5363 cmd->uc_compl = compl; | |
5364 #ifdef FEAT_EVAL | |
5365 cmd->uc_scriptID = current_SID; | |
5366 # ifdef FEAT_CMDL_COMPL | |
5367 cmd->uc_compl_arg = compl_arg; | |
5368 # endif | |
5369 #endif | |
5370 | |
5371 return OK; | |
5372 | |
5373 fail: | |
5374 vim_free(rep_buf); | |
5375 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
5376 vim_free(compl_arg); | |
5377 #endif | |
5378 return FAIL; | |
5379 } | |
4133 | 5380 #endif |
5381 | |
5382 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) | |
7 | 5383 /* |
5384 * List of names for completion for ":command" with the EXPAND_ flag. | |
5385 * Must be alphabetical for completion. | |
5386 */ | |
5387 static struct | |
5388 { | |
5389 int expand; | |
5390 char *name; | |
5391 } command_complete[] = | |
5392 { | |
5393 {EXPAND_AUGROUP, "augroup"}, | |
3503 | 5394 {EXPAND_BEHAVE, "behave"}, |
7 | 5395 {EXPAND_BUFFERS, "buffer"}, |
2970 | 5396 {EXPAND_COLORS, "color"}, |
7 | 5397 {EXPAND_COMMANDS, "command"}, |
2970 | 5398 {EXPAND_COMPILER, "compiler"}, |
1845 | 5399 #if defined(FEAT_CSCOPE) |
5400 {EXPAND_CSCOPE, "cscope"}, | |
5401 #endif | |
7 | 5402 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) |
5403 {EXPAND_USER_DEFINED, "custom"}, | |
406 | 5404 {EXPAND_USER_LIST, "customlist"}, |
7 | 5405 #endif |
5406 {EXPAND_DIRECTORIES, "dir"}, | |
5407 {EXPAND_ENV_VARS, "environment"}, | |
5408 {EXPAND_EVENTS, "event"}, | |
5409 {EXPAND_EXPRESSION, "expression"}, | |
5410 {EXPAND_FILES, "file"}, | |
2970 | 5411 {EXPAND_FILES_IN_PATH, "file_in_path"}, |
2444
3fbd9bce03f1
Support syntax and filetype completion for user commands. (Christian Brabandt)
Bram Moolenaar <bram@vim.org>
parents:
2433
diff
changeset
|
5412 {EXPAND_FILETYPE, "filetype"}, |
7 | 5413 {EXPAND_FUNCTIONS, "function"}, |
5414 {EXPAND_HELP, "help"}, | |
5415 {EXPAND_HIGHLIGHT, "highlight"}, | |
3503 | 5416 #if defined(FEAT_CMDHIST) |
5417 {EXPAND_HISTORY, "history"}, | |
5418 #endif | |
2970 | 5419 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ |
3503 | 5420 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) |
2970 | 5421 {EXPAND_LOCALES, "locale"}, |
5422 #endif | |
7 | 5423 {EXPAND_MAPPINGS, "mapping"}, |
5424 {EXPAND_MENUS, "menu"}, | |
2444
3fbd9bce03f1
Support syntax and filetype completion for user commands. (Christian Brabandt)
Bram Moolenaar <bram@vim.org>
parents:
2433
diff
changeset
|
5425 {EXPAND_OWNSYNTAX, "syntax"}, |
7 | 5426 {EXPAND_SETTINGS, "option"}, |
714 | 5427 {EXPAND_SHELLCMD, "shellcmd"}, |
1868 | 5428 #if defined(FEAT_SIGNS) |
5429 {EXPAND_SIGN, "sign"}, | |
5430 #endif | |
7 | 5431 {EXPAND_TAGS, "tag"}, |
5432 {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, | |
3744 | 5433 {EXPAND_USER, "user"}, |
7 | 5434 {EXPAND_USER_VARS, "var"}, |
5435 {0, NULL} | |
5436 }; | |
4133 | 5437 #endif |
5438 | |
5439 #if defined(FEAT_USR_CMDS) || defined(PROTO) | |
7 | 5440 static void |
5441 uc_list(name, name_len) | |
5442 char_u *name; | |
5443 size_t name_len; | |
5444 { | |
5445 int i, j; | |
5446 int found = FALSE; | |
5447 ucmd_T *cmd; | |
5448 int len; | |
5449 long a; | |
5450 garray_T *gap; | |
5451 | |
5452 gap = &curbuf->b_ucmds; | |
5453 for (;;) | |
5454 { | |
5455 for (i = 0; i < gap->ga_len; ++i) | |
5456 { | |
5457 cmd = USER_CMD_GA(gap, i); | |
835 | 5458 a = (long)cmd->uc_argt; |
7 | 5459 |
5460 /* Skip commands which don't match the requested prefix */ | |
5461 if (STRNCMP(name, cmd->uc_name, name_len) != 0) | |
5462 continue; | |
5463 | |
5464 /* Put out the title first time */ | |
5465 if (!found) | |
5466 MSG_PUTS_TITLE(_("\n Name Args Range Complete Definition")); | |
5467 found = TRUE; | |
5468 msg_putchar('\n'); | |
5469 if (got_int) | |
5470 break; | |
5471 | |
5472 /* Special cases */ | |
5473 msg_putchar(a & BANG ? '!' : ' '); | |
5474 msg_putchar(a & REGSTR ? '"' : ' '); | |
5475 msg_putchar(gap != &ucmds ? 'b' : ' '); | |
5476 msg_putchar(' '); | |
5477 | |
5478 msg_outtrans_attr(cmd->uc_name, hl_attr(HLF_D)); | |
5479 len = (int)STRLEN(cmd->uc_name) + 4; | |
5480 | |
5481 do { | |
5482 msg_putchar(' '); | |
5483 ++len; | |
5484 } while (len < 16); | |
5485 | |
5486 len = 0; | |
5487 | |
5488 /* Arguments */ | |
5489 switch ((int)(a & (EXTRA|NOSPC|NEEDARG))) | |
5490 { | |
5491 case 0: IObuff[len++] = '0'; break; | |
5492 case (EXTRA): IObuff[len++] = '*'; break; | |
5493 case (EXTRA|NOSPC): IObuff[len++] = '?'; break; | |
5494 case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; | |
5495 case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; | |
5496 } | |
5497 | |
5498 do { | |
5499 IObuff[len++] = ' '; | |
5500 } while (len < 5); | |
5501 | |
5502 /* Range */ | |
5503 if (a & (RANGE|COUNT)) | |
5504 { | |
5505 if (a & COUNT) | |
5506 { | |
5507 /* -count=N */ | |
5508 sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); | |
5509 len += (int)STRLEN(IObuff + len); | |
5510 } | |
5511 else if (a & DFLALL) | |
5512 IObuff[len++] = '%'; | |
5513 else if (cmd->uc_def >= 0) | |
5514 { | |
5515 /* -range=N */ | |
5516 sprintf((char *)IObuff + len, "%ld", cmd->uc_def); | |
5517 len += (int)STRLEN(IObuff + len); | |
5518 } | |
5519 else | |
5520 IObuff[len++] = '.'; | |
5521 } | |
5522 | |
5523 do { | |
5524 IObuff[len++] = ' '; | |
5525 } while (len < 11); | |
5526 | |
5527 /* Completion */ | |
5528 for (j = 0; command_complete[j].expand != 0; ++j) | |
5529 if (command_complete[j].expand == cmd->uc_compl) | |
5530 { | |
5531 STRCPY(IObuff + len, command_complete[j].name); | |
5532 len += (int)STRLEN(IObuff + len); | |
5533 break; | |
5534 } | |
5535 | |
5536 do { | |
5537 IObuff[len++] = ' '; | |
5538 } while (len < 21); | |
5539 | |
5540 IObuff[len] = '\0'; | |
5541 msg_outtrans(IObuff); | |
5542 | |
5543 msg_outtrans_special(cmd->uc_rep, FALSE); | |
482 | 5544 #ifdef FEAT_EVAL |
5545 if (p_verbose > 0) | |
5546 last_set_msg(cmd->uc_scriptID); | |
5547 #endif | |
7 | 5548 out_flush(); |
5549 ui_breakcheck(); | |
5550 if (got_int) | |
5551 break; | |
5552 } | |
5553 if (gap == &ucmds || i < gap->ga_len) | |
5554 break; | |
5555 gap = &ucmds; | |
5556 } | |
5557 | |
5558 if (!found) | |
5559 MSG(_("No user-defined commands found")); | |
5560 } | |
5561 | |
5562 static char_u * | |
5563 uc_fun_cmd() | |
5564 { | |
5565 static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, | |
5566 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, | |
5567 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, | |
5568 0xb9, 0x7f, 0}; | |
5569 int i; | |
5570 | |
5571 for (i = 0; fcmd[i]; ++i) | |
5572 IObuff[i] = fcmd[i] - 0x40; | |
5573 IObuff[i] = 0; | |
5574 return IObuff; | |
5575 } | |
5576 | |
5577 static int | |
5578 uc_scan_attr(attr, len, argt, def, flags, compl, compl_arg) | |
5579 char_u *attr; | |
5580 size_t len; | |
5581 long *argt; | |
5582 long *def; | |
5583 int *flags; | |
5584 int *compl; | |
5585 char_u **compl_arg; | |
5586 { | |
5587 char_u *p; | |
5588 | |
5589 if (len == 0) | |
5590 { | |
5591 EMSG(_("E175: No attribute specified")); | |
5592 return FAIL; | |
5593 } | |
5594 | |
5595 /* First, try the simple attributes (no arguments) */ | |
5596 if (STRNICMP(attr, "bang", len) == 0) | |
5597 *argt |= BANG; | |
5598 else if (STRNICMP(attr, "buffer", len) == 0) | |
5599 *flags |= UC_BUFFER; | |
5600 else if (STRNICMP(attr, "register", len) == 0) | |
5601 *argt |= REGSTR; | |
5602 else if (STRNICMP(attr, "bar", len) == 0) | |
5603 *argt |= TRLBAR; | |
5604 else | |
5605 { | |
5606 int i; | |
5607 char_u *val = NULL; | |
5608 size_t vallen = 0; | |
5609 size_t attrlen = len; | |
5610 | |
5611 /* Look for the attribute name - which is the part before any '=' */ | |
5612 for (i = 0; i < (int)len; ++i) | |
5613 { | |
5614 if (attr[i] == '=') | |
5615 { | |
5616 val = &attr[i + 1]; | |
5617 vallen = len - i - 1; | |
5618 attrlen = i; | |
5619 break; | |
5620 } | |
5621 } | |
5622 | |
5623 if (STRNICMP(attr, "nargs", attrlen) == 0) | |
5624 { | |
5625 if (vallen == 1) | |
5626 { | |
5627 if (*val == '0') | |
5628 /* Do nothing - this is the default */; | |
5629 else if (*val == '1') | |
5630 *argt |= (EXTRA | NOSPC | NEEDARG); | |
5631 else if (*val == '*') | |
5632 *argt |= EXTRA; | |
5633 else if (*val == '?') | |
5634 *argt |= (EXTRA | NOSPC); | |
5635 else if (*val == '+') | |
5636 *argt |= (EXTRA | NEEDARG); | |
5637 else | |
5638 goto wrong_nargs; | |
5639 } | |
5640 else | |
5641 { | |
5642 wrong_nargs: | |
5643 EMSG(_("E176: Invalid number of arguments")); | |
5644 return FAIL; | |
5645 } | |
5646 } | |
5647 else if (STRNICMP(attr, "range", attrlen) == 0) | |
5648 { | |
5649 *argt |= RANGE; | |
5650 if (vallen == 1 && *val == '%') | |
5651 *argt |= DFLALL; | |
5652 else if (val != NULL) | |
5653 { | |
5654 p = val; | |
5655 if (*def >= 0) | |
5656 { | |
5657 two_count: | |
5658 EMSG(_("E177: Count cannot be specified twice")); | |
5659 return FAIL; | |
5660 } | |
5661 | |
5662 *def = getdigits(&p); | |
5663 *argt |= (ZEROR | NOTADR); | |
5664 | |
5665 if (p != val + vallen || vallen == 0) | |
5666 { | |
5667 invalid_count: | |
5668 EMSG(_("E178: Invalid default value for count")); | |
5669 return FAIL; | |
5670 } | |
5671 } | |
5672 } | |
5673 else if (STRNICMP(attr, "count", attrlen) == 0) | |
5674 { | |
171 | 5675 *argt |= (COUNT | ZEROR | RANGE | NOTADR); |
7 | 5676 |
5677 if (val != NULL) | |
5678 { | |
5679 p = val; | |
5680 if (*def >= 0) | |
5681 goto two_count; | |
5682 | |
5683 *def = getdigits(&p); | |
5684 | |
5685 if (p != val + vallen) | |
5686 goto invalid_count; | |
5687 } | |
5688 | |
5689 if (*def < 0) | |
5690 *def = 0; | |
5691 } | |
5692 else if (STRNICMP(attr, "complete", attrlen) == 0) | |
5693 { | |
5694 if (val == NULL) | |
5695 { | |
531 | 5696 EMSG(_("E179: argument required for -complete")); |
7 | 5697 return FAIL; |
5698 } | |
531 | 5699 |
5700 if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg) | |
5701 == FAIL) | |
7 | 5702 return FAIL; |
5703 } | |
5704 else | |
5705 { | |
5706 char_u ch = attr[len]; | |
5707 attr[len] = '\0'; | |
5708 EMSG2(_("E181: Invalid attribute: %s"), attr); | |
5709 attr[len] = ch; | |
5710 return FAIL; | |
5711 } | |
5712 } | |
5713 | |
5714 return OK; | |
5715 } | |
5716 | |
1792 | 5717 /* |
5718 * ":command ..." | |
5719 */ | |
7 | 5720 static void |
5721 ex_command(eap) | |
5722 exarg_T *eap; | |
5723 { | |
5724 char_u *name; | |
5725 char_u *end; | |
5726 char_u *p; | |
5727 long argt = 0; | |
5728 long def = -1; | |
5729 int flags = 0; | |
5730 int compl = EXPAND_NOTHING; | |
5731 char_u *compl_arg = NULL; | |
5732 int has_attr = (eap->arg[0] == '-'); | |
2633 | 5733 int name_len; |
7 | 5734 |
5735 p = eap->arg; | |
5736 | |
5737 /* Check for attributes */ | |
5738 while (*p == '-') | |
5739 { | |
5740 ++p; | |
5741 end = skiptowhite(p); | |
5742 if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, &compl_arg) | |
5743 == FAIL) | |
5744 return; | |
5745 p = skipwhite(end); | |
5746 } | |
5747 | |
5748 /* Get the name (if any) and skip to the following argument */ | |
5749 name = p; | |
5750 if (ASCII_ISALPHA(*p)) | |
5751 while (ASCII_ISALNUM(*p)) | |
5752 ++p; | |
5753 if (!ends_excmd(*p) && !vim_iswhite(*p)) | |
5754 { | |
5755 EMSG(_("E182: Invalid command name")); | |
5756 return; | |
5757 } | |
5758 end = p; | |
2633 | 5759 name_len = (int)(end - name); |
7 | 5760 |
5761 /* If there is nothing after the name, and no attributes were specified, | |
5762 * we are listing commands | |
5763 */ | |
5764 p = skipwhite(end); | |
5765 if (!has_attr && ends_excmd(*p)) | |
5766 { | |
5767 uc_list(name, end - name); | |
5768 } | |
5769 else if (!ASCII_ISUPPER(*name)) | |
5770 { | |
5771 EMSG(_("E183: User defined commands must start with an uppercase letter")); | |
5772 return; | |
5773 } | |
2633 | 5774 else if ((name_len == 1 && *name == 'X') |
5775 || (name_len <= 4 | |
5776 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) | |
5777 { | |
5778 EMSG(_("E841: Reserved name, cannot be used for user defined command")); | |
5779 return; | |
5780 } | |
7 | 5781 else |
5782 uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, | |
5783 eap->forceit); | |
5784 } | |
5785 | |
5786 /* | |
5787 * ":comclear" | |
355 | 5788 * Clear all user commands, global and for current buffer. |
7 | 5789 */ |
355 | 5790 void |
7 | 5791 ex_comclear(eap) |
1877 | 5792 exarg_T *eap UNUSED; |
7 | 5793 { |
5794 uc_clear(&ucmds); | |
5795 uc_clear(&curbuf->b_ucmds); | |
5796 } | |
5797 | |
5798 /* | |
5799 * Clear all user commands for "gap". | |
5800 */ | |
5801 void | |
5802 uc_clear(gap) | |
5803 garray_T *gap; | |
5804 { | |
5805 int i; | |
5806 ucmd_T *cmd; | |
5807 | |
5808 for (i = 0; i < gap->ga_len; ++i) | |
5809 { | |
5810 cmd = USER_CMD_GA(gap, i); | |
5811 vim_free(cmd->uc_name); | |
5812 vim_free(cmd->uc_rep); | |
5813 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
5814 vim_free(cmd->uc_compl_arg); | |
5815 # endif | |
5816 } | |
5817 ga_clear(gap); | |
5818 } | |
5819 | |
5820 static void | |
5821 ex_delcommand(eap) | |
5822 exarg_T *eap; | |
5823 { | |
5824 int i = 0; | |
5825 ucmd_T *cmd = NULL; | |
5826 int cmp = -1; | |
5827 garray_T *gap; | |
5828 | |
5829 gap = &curbuf->b_ucmds; | |
5830 for (;;) | |
5831 { | |
5832 for (i = 0; i < gap->ga_len; ++i) | |
5833 { | |
5834 cmd = USER_CMD_GA(gap, i); | |
5835 cmp = STRCMP(eap->arg, cmd->uc_name); | |
5836 if (cmp <= 0) | |
5837 break; | |
5838 } | |
5839 if (gap == &ucmds || cmp == 0) | |
5840 break; | |
5841 gap = &ucmds; | |
5842 } | |
5843 | |
5844 if (cmp != 0) | |
5845 { | |
5846 EMSG2(_("E184: No such user-defined command: %s"), eap->arg); | |
5847 return; | |
5848 } | |
5849 | |
5850 vim_free(cmd->uc_name); | |
5851 vim_free(cmd->uc_rep); | |
5852 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
5853 vim_free(cmd->uc_compl_arg); | |
5854 # endif | |
5855 | |
5856 --gap->ga_len; | |
5857 | |
5858 if (i < gap->ga_len) | |
5859 mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); | |
5860 } | |
5861 | |
1088 | 5862 /* |
5863 * split and quote args for <f-args> | |
5864 */ | |
7 | 5865 static char_u * |
5866 uc_split_args(arg, lenp) | |
5867 char_u *arg; | |
5868 size_t *lenp; | |
5869 { | |
5870 char_u *buf; | |
5871 char_u *p; | |
5872 char_u *q; | |
5873 int len; | |
5874 | |
5875 /* Precalculate length */ | |
5876 p = arg; | |
5877 len = 2; /* Initial and final quotes */ | |
5878 | |
5879 while (*p) | |
5880 { | |
1088 | 5881 if (p[0] == '\\' && p[1] == '\\') |
5882 { | |
5883 len += 2; | |
5884 p += 2; | |
5885 } | |
5886 else if (p[0] == '\\' && vim_iswhite(p[1])) | |
7 | 5887 { |
5888 len += 1; | |
5889 p += 2; | |
5890 } | |
5891 else if (*p == '\\' || *p == '"') | |
5892 { | |
5893 len += 2; | |
5894 p += 1; | |
5895 } | |
5896 else if (vim_iswhite(*p)) | |
5897 { | |
5898 p = skipwhite(p); | |
5899 if (*p == NUL) | |
5900 break; | |
5901 len += 3; /* "," */ | |
5902 } | |
5903 else | |
5904 { | |
3680 | 5905 #ifdef FEAT_MBYTE |
5906 int charlen = (*mb_ptr2len)(p); | |
5907 len += charlen; | |
5908 p += charlen; | |
5909 #else | |
7 | 5910 ++len; |
5911 ++p; | |
3680 | 5912 #endif |
7 | 5913 } |
5914 } | |
5915 | |
5916 buf = alloc(len + 1); | |
5917 if (buf == NULL) | |
5918 { | |
5919 *lenp = 0; | |
5920 return buf; | |
5921 } | |
5922 | |
5923 p = arg; | |
5924 q = buf; | |
5925 *q++ = '"'; | |
5926 while (*p) | |
5927 { | |
1088 | 5928 if (p[0] == '\\' && p[1] == '\\') |
5929 { | |
5930 *q++ = '\\'; | |
5931 *q++ = '\\'; | |
5932 p += 2; | |
5933 } | |
5934 else if (p[0] == '\\' && vim_iswhite(p[1])) | |
7 | 5935 { |
5936 *q++ = p[1]; | |
5937 p += 2; | |
5938 } | |
5939 else if (*p == '\\' || *p == '"') | |
5940 { | |
5941 *q++ = '\\'; | |
5942 *q++ = *p++; | |
5943 } | |
5944 else if (vim_iswhite(*p)) | |
5945 { | |
5946 p = skipwhite(p); | |
5947 if (*p == NUL) | |
5948 break; | |
5949 *q++ = '"'; | |
5950 *q++ = ','; | |
5951 *q++ = '"'; | |
5952 } | |
5953 else | |
5954 { | |
3680 | 5955 MB_COPY_CHAR(p, q); |
7 | 5956 } |
5957 } | |
5958 *q++ = '"'; | |
5959 *q = 0; | |
5960 | |
5961 *lenp = len; | |
5962 return buf; | |
5963 } | |
5964 | |
5965 /* | |
5966 * Check for a <> code in a user command. | |
5967 * "code" points to the '<'. "len" the length of the <> (inclusive). | |
5968 * "buf" is where the result is to be added. | |
5969 * "split_buf" points to a buffer used for splitting, caller should free it. | |
5970 * "split_len" is the length of what "split_buf" contains. | |
5971 * Returns the length of the replacement, which has been added to "buf". | |
5972 * Returns -1 if there was no match, and only the "<" has been copied. | |
5973 */ | |
5974 static size_t | |
5975 uc_check_code(code, len, buf, cmd, eap, split_buf, split_len) | |
5976 char_u *code; | |
5977 size_t len; | |
5978 char_u *buf; | |
5979 ucmd_T *cmd; /* the user command we're expanding */ | |
5980 exarg_T *eap; /* ex arguments */ | |
5981 char_u **split_buf; | |
5982 size_t *split_len; | |
5983 { | |
5984 size_t result = 0; | |
5985 char_u *p = code + 1; | |
5986 size_t l = len - 2; | |
5987 int quote = 0; | |
5988 enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_REGISTER, | |
5989 ct_LT, ct_NONE } type = ct_NONE; | |
5990 | |
5991 if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') | |
5992 { | |
5993 quote = (*p == 'q' || *p == 'Q') ? 1 : 2; | |
5994 p += 2; | |
5995 l -= 2; | |
5996 } | |
5997 | |
788 | 5998 ++l; |
5999 if (l <= 1) | |
7 | 6000 type = ct_NONE; |
788 | 6001 else if (STRNICMP(p, "args>", l) == 0) |
7 | 6002 type = ct_ARGS; |
788 | 6003 else if (STRNICMP(p, "bang>", l) == 0) |
7 | 6004 type = ct_BANG; |
788 | 6005 else if (STRNICMP(p, "count>", l) == 0) |
7 | 6006 type = ct_COUNT; |
788 | 6007 else if (STRNICMP(p, "line1>", l) == 0) |
7 | 6008 type = ct_LINE1; |
788 | 6009 else if (STRNICMP(p, "line2>", l) == 0) |
7 | 6010 type = ct_LINE2; |
788 | 6011 else if (STRNICMP(p, "lt>", l) == 0) |
7 | 6012 type = ct_LT; |
788 | 6013 else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) |
7 | 6014 type = ct_REGISTER; |
6015 | |
6016 switch (type) | |
6017 { | |
6018 case ct_ARGS: | |
6019 /* Simple case first */ | |
6020 if (*eap->arg == NUL) | |
6021 { | |
6022 if (quote == 1) | |
6023 { | |
6024 result = 2; | |
6025 if (buf != NULL) | |
6026 STRCPY(buf, "''"); | |
6027 } | |
6028 else | |
6029 result = 0; | |
6030 break; | |
6031 } | |
6032 | |
6033 /* When specified there is a single argument don't split it. | |
6034 * Works for ":Cmd %" when % is "a b c". */ | |
6035 if ((eap->argt & NOSPC) && quote == 2) | |
6036 quote = 1; | |
6037 | |
6038 switch (quote) | |
6039 { | |
6040 case 0: /* No quoting, no splitting */ | |
6041 result = STRLEN(eap->arg); | |
6042 if (buf != NULL) | |
6043 STRCPY(buf, eap->arg); | |
6044 break; | |
6045 case 1: /* Quote, but don't split */ | |
6046 result = STRLEN(eap->arg) + 2; | |
6047 for (p = eap->arg; *p; ++p) | |
6048 { | |
3304 | 6049 #ifdef FEAT_MBYTE |
6050 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) | |
6051 /* DBCS can contain \ in a trail byte, skip the | |
6052 * double-byte character. */ | |
6053 ++p; | |
6054 else | |
6055 #endif | |
6056 if (*p == '\\' || *p == '"') | |
7 | 6057 ++result; |
6058 } | |
6059 | |
6060 if (buf != NULL) | |
6061 { | |
6062 *buf++ = '"'; | |
6063 for (p = eap->arg; *p; ++p) | |
6064 { | |
3304 | 6065 #ifdef FEAT_MBYTE |
6066 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) | |
6067 /* DBCS can contain \ in a trail byte, copy the | |
6068 * double-byte character to avoid escaping. */ | |
6069 *buf++ = *p++; | |
6070 else | |
6071 #endif | |
6072 if (*p == '\\' || *p == '"') | |
7 | 6073 *buf++ = '\\'; |
6074 *buf++ = *p; | |
6075 } | |
6076 *buf = '"'; | |
6077 } | |
6078 | |
6079 break; | |
1088 | 6080 case 2: /* Quote and split (<f-args>) */ |
7 | 6081 /* This is hard, so only do it once, and cache the result */ |
6082 if (*split_buf == NULL) | |
6083 *split_buf = uc_split_args(eap->arg, split_len); | |
6084 | |
6085 result = *split_len; | |
6086 if (buf != NULL && result != 0) | |
6087 STRCPY(buf, *split_buf); | |
6088 | |
6089 break; | |
6090 } | |
6091 break; | |
6092 | |
6093 case ct_BANG: | |
6094 result = eap->forceit ? 1 : 0; | |
6095 if (quote) | |
6096 result += 2; | |
6097 if (buf != NULL) | |
6098 { | |
6099 if (quote) | |
6100 *buf++ = '"'; | |
6101 if (eap->forceit) | |
6102 *buf++ = '!'; | |
6103 if (quote) | |
6104 *buf = '"'; | |
6105 } | |
6106 break; | |
6107 | |
6108 case ct_LINE1: | |
6109 case ct_LINE2: | |
6110 case ct_COUNT: | |
6111 { | |
6112 char num_buf[20]; | |
6113 long num = (type == ct_LINE1) ? eap->line1 : | |
6114 (type == ct_LINE2) ? eap->line2 : | |
6115 (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; | |
6116 size_t num_len; | |
6117 | |
6118 sprintf(num_buf, "%ld", num); | |
6119 num_len = STRLEN(num_buf); | |
6120 result = num_len; | |
6121 | |
6122 if (quote) | |
6123 result += 2; | |
6124 | |
6125 if (buf != NULL) | |
6126 { | |
6127 if (quote) | |
6128 *buf++ = '"'; | |
6129 STRCPY(buf, num_buf); | |
6130 buf += num_len; | |
6131 if (quote) | |
6132 *buf = '"'; | |
6133 } | |
6134 | |
6135 break; | |
6136 } | |
6137 | |
6138 case ct_REGISTER: | |
6139 result = eap->regname ? 1 : 0; | |
6140 if (quote) | |
6141 result += 2; | |
6142 if (buf != NULL) | |
6143 { | |
6144 if (quote) | |
6145 *buf++ = '\''; | |
6146 if (eap->regname) | |
6147 *buf++ = eap->regname; | |
6148 if (quote) | |
6149 *buf = '\''; | |
6150 } | |
6151 break; | |
6152 | |
6153 case ct_LT: | |
6154 result = 1; | |
6155 if (buf != NULL) | |
6156 *buf = '<'; | |
6157 break; | |
6158 | |
6159 default: | |
6160 /* Not recognized: just copy the '<' and return -1. */ | |
6161 result = (size_t)-1; | |
6162 if (buf != NULL) | |
6163 *buf = '<'; | |
6164 break; | |
6165 } | |
6166 | |
6167 return result; | |
6168 } | |
6169 | |
6170 static void | |
6171 do_ucmd(eap) | |
6172 exarg_T *eap; | |
6173 { | |
6174 char_u *buf; | |
6175 char_u *p; | |
6176 char_u *q; | |
6177 | |
6178 char_u *start; | |
1812 | 6179 char_u *end = NULL; |
1792 | 6180 char_u *ksp; |
7 | 6181 size_t len, totlen; |
6182 | |
6183 size_t split_len = 0; | |
6184 char_u *split_buf = NULL; | |
6185 ucmd_T *cmd; | |
6186 #ifdef FEAT_EVAL | |
6187 scid_T save_current_SID = current_SID; | |
6188 #endif | |
6189 | |
6190 if (eap->cmdidx == CMD_USER) | |
6191 cmd = USER_CMD(eap->useridx); | |
6192 else | |
6193 cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); | |
6194 | |
6195 /* | |
6196 * Replace <> in the command by the arguments. | |
1792 | 6197 * First round: "buf" is NULL, compute length, allocate "buf". |
6198 * Second round: copy result into "buf". | |
7 | 6199 */ |
6200 buf = NULL; | |
6201 for (;;) | |
6202 { | |
1792 | 6203 p = cmd->uc_rep; /* source */ |
1837 | 6204 q = buf; /* destination */ |
7 | 6205 totlen = 0; |
1792 | 6206 |
6207 for (;;) | |
6208 { | |
6209 start = vim_strchr(p, '<'); | |
6210 if (start != NULL) | |
6211 end = vim_strchr(start + 1, '>'); | |
6212 if (buf != NULL) | |
6213 { | |
2722 | 6214 for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) |
6215 ; | |
6216 if (*ksp == K_SPECIAL | |
6217 && (start == NULL || ksp < start || end == NULL) | |
1792 | 6218 && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) |
6219 # ifdef FEAT_GUI | |
6220 || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) | |
6221 # endif | |
6222 )) | |
6223 { | |
2722 | 6224 /* K_SPECIAL has been put in the buffer as K_SPECIAL |
1792 | 6225 * KS_SPECIAL KE_FILLER, like for mappings, but |
6226 * do_cmdline() doesn't handle that, so convert it back. | |
6227 * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */ | |
6228 len = ksp - p; | |
6229 if (len > 0) | |
6230 { | |
6231 mch_memmove(q, p, len); | |
6232 q += len; | |
6233 } | |
6234 *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; | |
6235 p = ksp + 3; | |
6236 continue; | |
6237 } | |
6238 } | |
6239 | |
6240 /* break if there no <item> is found */ | |
6241 if (start == NULL || end == NULL) | |
6242 break; | |
6243 | |
7 | 6244 /* Include the '>' */ |
6245 ++end; | |
6246 | |
6247 /* Take everything up to the '<' */ | |
6248 len = start - p; | |
6249 if (buf == NULL) | |
6250 totlen += len; | |
6251 else | |
6252 { | |
6253 mch_memmove(q, p, len); | |
6254 q += len; | |
6255 } | |
6256 | |
6257 len = uc_check_code(start, end - start, q, cmd, eap, | |
6258 &split_buf, &split_len); | |
6259 if (len == (size_t)-1) | |
6260 { | |
6261 /* no match, continue after '<' */ | |
6262 p = start + 1; | |
6263 len = 1; | |
6264 } | |
6265 else | |
6266 p = end; | |
6267 if (buf == NULL) | |
6268 totlen += len; | |
6269 else | |
6270 q += len; | |
6271 } | |
6272 if (buf != NULL) /* second time here, finished */ | |
6273 { | |
6274 STRCPY(q, p); | |
6275 break; | |
6276 } | |
6277 | |
6278 totlen += STRLEN(p); /* Add on the trailing characters */ | |
6279 buf = alloc((unsigned)(totlen + 1)); | |
6280 if (buf == NULL) | |
6281 { | |
6282 vim_free(split_buf); | |
6283 return; | |
6284 } | |
6285 } | |
6286 | |
6287 #ifdef FEAT_EVAL | |
6288 current_SID = cmd->uc_scriptID; | |
6289 #endif | |
6290 (void)do_cmdline(buf, eap->getline, eap->cookie, | |
6291 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); | |
6292 #ifdef FEAT_EVAL | |
6293 current_SID = save_current_SID; | |
6294 #endif | |
6295 vim_free(buf); | |
6296 vim_free(split_buf); | |
6297 } | |
6298 | |
6299 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) | |
6300 static char_u * | |
6301 get_user_command_name(idx) | |
6302 int idx; | |
6303 { | |
6304 return get_user_commands(NULL, idx - (int)CMD_SIZE); | |
6305 } | |
6306 | |
6307 /* | |
6308 * Function given to ExpandGeneric() to obtain the list of user command names. | |
6309 */ | |
6310 char_u * | |
6311 get_user_commands(xp, idx) | |
1877 | 6312 expand_T *xp UNUSED; |
7 | 6313 int idx; |
6314 { | |
6315 if (idx < curbuf->b_ucmds.ga_len) | |
6316 return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; | |
6317 idx -= curbuf->b_ucmds.ga_len; | |
6318 if (idx < ucmds.ga_len) | |
6319 return USER_CMD(idx)->uc_name; | |
6320 return NULL; | |
6321 } | |
6322 | |
6323 /* | |
6324 * Function given to ExpandGeneric() to obtain the list of user command | |
6325 * attributes. | |
6326 */ | |
6327 char_u * | |
6328 get_user_cmd_flags(xp, idx) | |
1877 | 6329 expand_T *xp UNUSED; |
7 | 6330 int idx; |
6331 { | |
6332 static char *user_cmd_flags[] = | |
6333 {"bang", "bar", "buffer", "complete", "count", | |
6334 "nargs", "range", "register"}; | |
6335 | |
1880 | 6336 if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) |
7 | 6337 return NULL; |
6338 return (char_u *)user_cmd_flags[idx]; | |
6339 } | |
6340 | |
6341 /* | |
6342 * Function given to ExpandGeneric() to obtain the list of values for -nargs. | |
6343 */ | |
6344 char_u * | |
6345 get_user_cmd_nargs(xp, idx) | |
1877 | 6346 expand_T *xp UNUSED; |
7 | 6347 int idx; |
6348 { | |
6349 static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; | |
6350 | |
1880 | 6351 if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) |
7 | 6352 return NULL; |
6353 return (char_u *)user_cmd_nargs[idx]; | |
6354 } | |
6355 | |
6356 /* | |
6357 * Function given to ExpandGeneric() to obtain the list of values for -complete. | |
6358 */ | |
6359 char_u * | |
6360 get_user_cmd_complete(xp, idx) | |
1877 | 6361 expand_T *xp UNUSED; |
7 | 6362 int idx; |
6363 { | |
6364 return (char_u *)command_complete[idx].name; | |
6365 } | |
6366 # endif /* FEAT_CMDL_COMPL */ | |
6367 | |
6368 #endif /* FEAT_USR_CMDS */ | |
6369 | |
531 | 6370 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) |
6371 /* | |
6372 * Parse a completion argument "value[vallen]". | |
6373 * The detected completion goes in "*complp", argument type in "*argt". | |
6374 * When there is an argument, for function and user defined completion, it's | |
6375 * copied to allocated memory and stored in "*compl_arg". | |
6376 * Returns FAIL if something is wrong. | |
6377 */ | |
6378 int | |
6379 parse_compl_arg(value, vallen, complp, argt, compl_arg) | |
6380 char_u *value; | |
6381 int vallen; | |
6382 int *complp; | |
6383 long *argt; | |
4133 | 6384 char_u **compl_arg UNUSED; |
531 | 6385 { |
6386 char_u *arg = NULL; | |
4133 | 6387 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) |
531 | 6388 size_t arglen = 0; |
4133 | 6389 # endif |
531 | 6390 int i; |
6391 int valend = vallen; | |
6392 | |
6393 /* Look for any argument part - which is the part after any ',' */ | |
6394 for (i = 0; i < vallen; ++i) | |
6395 { | |
6396 if (value[i] == ',') | |
6397 { | |
6398 arg = &value[i + 1]; | |
4133 | 6399 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) |
531 | 6400 arglen = vallen - i - 1; |
4133 | 6401 # endif |
531 | 6402 valend = i; |
6403 break; | |
6404 } | |
6405 } | |
6406 | |
6407 for (i = 0; command_complete[i].expand != 0; ++i) | |
6408 { | |
534 | 6409 if ((int)STRLEN(command_complete[i].name) == valend |
531 | 6410 && STRNCMP(value, command_complete[i].name, valend) == 0) |
6411 { | |
6412 *complp = command_complete[i].expand; | |
6413 if (command_complete[i].expand == EXPAND_BUFFERS) | |
6414 *argt |= BUFNAME; | |
6415 else if (command_complete[i].expand == EXPAND_DIRECTORIES | |
6416 || command_complete[i].expand == EXPAND_FILES) | |
6417 *argt |= XFILE; | |
6418 break; | |
6419 } | |
6420 } | |
6421 | |
6422 if (command_complete[i].expand == 0) | |
6423 { | |
6424 EMSG2(_("E180: Invalid complete value: %s"), value); | |
6425 return FAIL; | |
6426 } | |
6427 | |
6428 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
6429 if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST | |
6430 && arg != NULL) | |
6431 # else | |
6432 if (arg != NULL) | |
6433 # endif | |
6434 { | |
6435 EMSG(_("E468: Completion argument only allowed for custom completion")); | |
6436 return FAIL; | |
6437 } | |
6438 | |
6439 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) | |
6440 if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) | |
6441 && arg == NULL) | |
6442 { | |
6443 EMSG(_("E467: Custom completion requires a function argument")); | |
6444 return FAIL; | |
6445 } | |
6446 | |
6447 if (arg != NULL) | |
6448 *compl_arg = vim_strnsave(arg, (int)arglen); | |
6449 # endif | |
6450 return OK; | |
6451 } | |
6452 #endif | |
6453 | |
7 | 6454 static void |
6455 ex_colorscheme(eap) | |
6456 exarg_T *eap; | |
6457 { | |
2142
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6458 if (*eap->arg == NUL) |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6459 { |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6460 #ifdef FEAT_EVAL |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6461 char_u *expr = vim_strsave((char_u *)"g:colors_name"); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6462 char_u *p = NULL; |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6463 |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6464 if (expr != NULL) |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6465 { |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6466 ++emsg_off; |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6467 p = eval_to_string(expr, NULL, FALSE); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6468 --emsg_off; |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6469 vim_free(expr); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6470 } |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6471 if (p != NULL) |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6472 { |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6473 MSG(p); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6474 vim_free(p); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6475 } |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6476 else |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6477 MSG("default"); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6478 #else |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6479 MSG(_("unknown")); |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6480 #endif |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6481 } |
c60d231453cf
updated for version 7.2.424
Bram Moolenaar <bram@zimbu.org>
parents:
2097
diff
changeset
|
6482 else if (load_colors(eap->arg) == FAIL) |
3810 | 6483 EMSG2(_("E185: Cannot find color scheme '%s'"), eap->arg); |
7 | 6484 } |
6485 | |
6486 static void | |
6487 ex_highlight(eap) | |
6488 exarg_T *eap; | |
6489 { | |
6490 if (*eap->arg == NUL && eap->cmd[2] == '!') | |
6491 MSG(_("Greetings, Vim user!")); | |
6492 do_highlight(eap->arg, eap->forceit, FALSE); | |
6493 } | |
6494 | |
6495 | |
6496 /* | |
6497 * Call this function if we thought we were going to exit, but we won't | |
6498 * (because of an error). May need to restore the terminal mode. | |
6499 */ | |
6500 void | |
6501 not_exiting() | |
6502 { | |
6503 exiting = FALSE; | |
6504 settmode(TMODE_RAW); | |
6505 } | |
6506 | |
6507 /* | |
6508 * ":quit": quit current window, quit Vim if closed the last window. | |
6509 */ | |
6510 static void | |
6511 ex_quit(eap) | |
6512 exarg_T *eap; | |
6513 { | |
6514 #ifdef FEAT_CMDWIN | |
6515 if (cmdwin_type != 0) | |
6516 { | |
6517 cmdwin_result = Ctrl_C; | |
6518 return; | |
6519 } | |
6520 #endif | |
631 | 6521 /* Don't quit while editing the command line. */ |
633 | 6522 if (text_locked()) |
6523 { | |
6524 text_locked_msg(); | |
631 | 6525 return; |
6526 } | |
819 | 6527 #ifdef FEAT_AUTOCMD |
3568 | 6528 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); |
4211 | 6529 /* Refuse to quit when locked or when the buffer in the last window is |
3570 | 6530 * being closed (can only happen in autocommands). */ |
6531 if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) | |
819 | 6532 return; |
6533 #endif | |
7 | 6534 |
6535 #ifdef FEAT_NETBEANS_INTG | |
6536 netbeansForcedQuit = eap->forceit; | |
6537 #endif | |
6538 | |
6539 /* | |
6540 * If there are more files or windows we won't exit. | |
6541 */ | |
6542 if (check_more(FALSE, eap->forceit) == OK && only_one_window()) | |
6543 exiting = TRUE; | |
6544 if ((!P_HID(curbuf) | |
6545 && check_changed(curbuf, p_awa, FALSE, eap->forceit, FALSE)) | |
6546 || check_more(TRUE, eap->forceit) == FAIL | |
6547 || (only_one_window() && check_changed_any(eap->forceit))) | |
6548 { | |
6549 not_exiting(); | |
6550 } | |
6551 else | |
6552 { | |
6553 #ifdef FEAT_WINDOWS | |
6554 if (only_one_window()) /* quit last window */ | |
6555 #endif | |
6556 getout(0); | |
6557 #ifdef FEAT_WINDOWS | |
6558 # ifdef FEAT_GUI | |
6559 need_mouse_correct = TRUE; | |
6560 # endif | |
6561 /* close window; may free buffer */ | |
6562 win_close(curwin, !P_HID(curwin->w_buffer) || eap->forceit); | |
6563 #endif | |
6564 } | |
6565 } | |
6566 | |
6567 /* | |
6568 * ":cquit". | |
6569 */ | |
6570 static void | |
6571 ex_cquit(eap) | |
1877 | 6572 exarg_T *eap UNUSED; |
7 | 6573 { |
6574 getout(1); /* this does not always pass on the exit code to the Manx | |
6575 compiler. why? */ | |
6576 } | |
6577 | |
6578 /* | |
6579 * ":qall": try to quit all windows | |
6580 */ | |
6581 static void | |
6582 ex_quit_all(eap) | |
6583 exarg_T *eap; | |
6584 { | |
6585 # ifdef FEAT_CMDWIN | |
6586 if (cmdwin_type != 0) | |
6587 { | |
6588 if (eap->forceit) | |
6589 cmdwin_result = K_XF1; /* ex_window() takes care of this */ | |
6590 else | |
6591 cmdwin_result = K_XF2; | |
6592 return; | |
6593 } | |
6594 # endif | |
631 | 6595 |
6596 /* Don't quit while editing the command line. */ | |
633 | 6597 if (text_locked()) |
6598 { | |
6599 text_locked_msg(); | |
631 | 6600 return; |
6601 } | |
819 | 6602 #ifdef FEAT_AUTOCMD |
4211 | 6603 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); |
6604 /* Refuse to quit when locked or when the buffer in the last window is | |
6605 * being closed (can only happen in autocommands). */ | |
6606 if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) | |
819 | 6607 return; |
6608 #endif | |
631 | 6609 |
7 | 6610 exiting = TRUE; |
6611 if (eap->forceit || !check_changed_any(FALSE)) | |
6612 getout(0); | |
6613 not_exiting(); | |
6614 } | |
6615 | |
727 | 6616 #if defined(FEAT_WINDOWS) || defined(PROTO) |
7 | 6617 /* |
6618 * ":close": close current window, unless it is the last one | |
6619 */ | |
6620 static void | |
6621 ex_close(eap) | |
6622 exarg_T *eap; | |
6623 { | |
6624 # ifdef FEAT_CMDWIN | |
6625 if (cmdwin_type != 0) | |
2839 | 6626 cmdwin_result = Ctrl_C; |
7 | 6627 else |
6628 # endif | |
819 | 6629 if (!text_locked() |
6630 #ifdef FEAT_AUTOCMD | |
6631 && !curbuf_locked() | |
6632 #endif | |
6633 ) | |
671 | 6634 ex_win_close(eap->forceit, curwin, NULL); |
667 | 6635 } |
6636 | |
727 | 6637 # ifdef FEAT_QUICKFIX |
667 | 6638 /* |
6639 * ":pclose": Close any preview window. | |
6640 */ | |
6641 static void | |
6642 ex_pclose(eap) | |
6643 exarg_T *eap; | |
6644 { | |
6645 win_T *win; | |
6646 | |
6647 for (win = firstwin; win != NULL; win = win->w_next) | |
6648 if (win->w_p_pvw) | |
6649 { | |
671 | 6650 ex_win_close(eap->forceit, win, NULL); |
667 | 6651 break; |
6652 } | |
6653 } | |
727 | 6654 # endif |
667 | 6655 |
671 | 6656 /* |
6657 * Close window "win" and take care of handling closing the last window for a | |
6658 * modified buffer. | |
6659 */ | |
6660 static void | |
6661 ex_win_close(forceit, win, tp) | |
667 | 6662 int forceit; |
7 | 6663 win_T *win; |
671 | 6664 tabpage_T *tp; /* NULL or the tab page "win" is in */ |
7 | 6665 { |
6666 int need_hide; | |
6667 buf_T *buf = win->w_buffer; | |
6668 | |
6669 need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); | |
667 | 6670 if (need_hide && !P_HID(buf) && !forceit) |
7 | 6671 { |
727 | 6672 # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) |
7 | 6673 if ((p_confirm || cmdmod.confirm) && p_write) |
6674 { | |
6675 dialog_changed(buf, FALSE); | |
6676 if (buf_valid(buf) && bufIsChanged(buf)) | |
6677 return; | |
6678 need_hide = FALSE; | |
6679 } | |
6680 else | |
727 | 6681 # endif |
7 | 6682 { |
6683 EMSG(_(e_nowrtmsg)); | |
6684 return; | |
6685 } | |
6686 } | |
6687 | |
727 | 6688 # ifdef FEAT_GUI |
7 | 6689 need_mouse_correct = TRUE; |
727 | 6690 # endif |
671 | 6691 |
7 | 6692 /* free buffer when not hiding it or when it's a scratch buffer */ |
671 | 6693 if (tp == NULL) |
6694 win_close(win, !need_hide && !P_HID(buf)); | |
6695 else | |
6696 win_close_othertab(win, !need_hide && !P_HID(buf), tp); | |
6697 } | |
6698 | |
6699 /* | |
6700 * ":tabclose": close current tab page, unless it is the last one. | |
6701 * ":tabclose N": close tab page N. | |
667 | 6702 */ |
6703 static void | |
6704 ex_tabclose(eap) | |
6705 exarg_T *eap; | |
6706 { | |
671 | 6707 tabpage_T *tp; |
6708 | |
667 | 6709 # ifdef FEAT_CMDWIN |
6710 if (cmdwin_type != 0) | |
6711 cmdwin_result = K_IGNORE; | |
6712 else | |
6713 # endif | |
671 | 6714 if (first_tabpage->tp_next == NULL) |
674 | 6715 EMSG(_("E784: Cannot close last tab page")); |
671 | 6716 else |
6717 { | |
6718 if (eap->addr_count > 0) | |
6719 { | |
6720 tp = find_tabpage((int)eap->line2); | |
6721 if (tp == NULL) | |
6722 { | |
6723 beep_flush(); | |
6724 return; | |
6725 } | |
674 | 6726 if (tp != curtab) |
671 | 6727 { |
6728 tabpage_close_other(tp, eap->forceit); | |
6729 return; | |
6730 } | |
6731 } | |
819 | 6732 if (!text_locked() |
6733 #ifdef FEAT_AUTOCMD | |
6734 && !curbuf_locked() | |
6735 #endif | |
6736 ) | |
671 | 6737 tabpage_close(eap->forceit); |
6738 } | |
672 | 6739 } |
6740 | |
6741 /* | |
6742 * ":tabonly": close all tab pages except the current one | |
6743 */ | |
6744 static void | |
6745 ex_tabonly(eap) | |
6746 exarg_T *eap; | |
6747 { | |
6748 tabpage_T *tp; | |
6749 int done; | |
6750 | |
6751 # ifdef FEAT_CMDWIN | |
6752 if (cmdwin_type != 0) | |
6753 cmdwin_result = K_IGNORE; | |
6754 else | |
6755 # endif | |
6756 if (first_tabpage->tp_next == NULL) | |
6757 MSG(_("Already only one tab page")); | |
6758 else | |
6759 { | |
6760 /* Repeat this up to a 1000 times, because autocommands may mess | |
6761 * up the lists. */ | |
6762 for (done = 0; done < 1000; ++done) | |
6763 { | |
6764 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) | |
6765 if (tp->tp_topframe != topframe) | |
6766 { | |
6767 tabpage_close_other(tp, eap->forceit); | |
6768 /* if we failed to close it quit */ | |
6769 if (valid_tabpage(tp)) | |
6770 done = 1000; | |
6771 /* start over, "tp" is now invalid */ | |
6772 break; | |
6773 } | |
6774 if (first_tabpage->tp_next == NULL) | |
6775 break; | |
6776 } | |
6777 } | |
671 | 6778 } |
6779 | |
6780 /* | |
6781 * Close the current tab page. | |
6782 */ | |
6783 void | |
6784 tabpage_close(forceit) | |
6785 int forceit; | |
6786 { | |
6787 /* First close all the windows but the current one. If that worked then | |
6788 * close the last window in this tab, that will close it. */ | |
675 | 6789 if (lastwin != firstwin) |
6790 close_others(TRUE, forceit); | |
671 | 6791 if (lastwin == firstwin) |
6792 ex_win_close(forceit, curwin, NULL); | |
6793 # ifdef FEAT_GUI | |
6794 need_mouse_correct = TRUE; | |
6795 # endif | |
6796 } | |
6797 | |
6798 /* | |
6799 * Close tab page "tp", which is not the current tab page. | |
6800 * Note that autocommands may make "tp" invalid. | |
971 | 6801 * Also takes care of the tab pages line disappearing when closing the |
6802 * last-but-one tab page. | |
671 | 6803 */ |
6804 void | |
6805 tabpage_close_other(tp, forceit) | |
6806 tabpage_T *tp; | |
6807 int forceit; | |
6808 { | |
6809 int done = 0; | |
672 | 6810 win_T *wp; |
971 | 6811 int h = tabline_height(); |
671 | 6812 |
6813 /* Limit to 1000 windows, autocommands may add a window while we close | |
6814 * one. OK, so I'm paranoid... */ | |
6815 while (++done < 1000) | |
6816 { | |
672 | 6817 wp = tp->tp_firstwin; |
6818 ex_win_close(forceit, wp, tp); | |
6819 | |
6820 /* Autocommands may delete the tab page under our fingers and we may | |
6821 * fail to close a window with a modified buffer. */ | |
6822 if (!valid_tabpage(tp) || tp->tp_firstwin == wp) | |
671 | 6823 break; |
6824 } | |
971 | 6825 |
672 | 6826 redraw_tabline = TRUE; |
971 | 6827 if (h != tabline_height()) |
6828 shell_new_rows(); | |
667 | 6829 } |
7 | 6830 |
6831 /* | |
6832 * ":only". | |
6833 */ | |
6834 static void | |
6835 ex_only(eap) | |
6836 exarg_T *eap; | |
6837 { | |
6838 # ifdef FEAT_GUI | |
6839 need_mouse_correct = TRUE; | |
6840 # endif | |
6841 close_others(TRUE, eap->forceit); | |
6842 } | |
6843 | |
6844 /* | |
6845 * ":all" and ":sall". | |
727 | 6846 * Also used for ":tab drop file ..." after setting the argument list. |
6847 */ | |
6848 void | |
7 | 6849 ex_all(eap) |
6850 exarg_T *eap; | |
6851 { | |
6852 if (eap->addr_count == 0) | |
6853 eap->line2 = 9999; | |
727 | 6854 do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop); |
7 | 6855 } |
6856 #endif /* FEAT_WINDOWS */ | |
6857 | |
6858 static void | |
6859 ex_hide(eap) | |
6860 exarg_T *eap; | |
6861 { | |
6862 if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) | |
6863 eap->errmsg = e_invarg; | |
6864 else | |
6865 { | |
6866 /* ":hide" or ":hide | cmd": hide current window */ | |
6867 eap->nextcmd = check_nextcmd(eap->arg); | |
6868 #ifdef FEAT_WINDOWS | |
6869 if (!eap->skip) | |
6870 { | |
6871 # ifdef FEAT_GUI | |
6872 need_mouse_correct = TRUE; | |
6873 # endif | |
6874 win_close(curwin, FALSE); /* don't free buffer */ | |
6875 } | |
6876 #endif | |
6877 } | |
6878 } | |
6879 | |
6880 /* | |
6881 * ":stop" and ":suspend": Suspend Vim. | |
6882 */ | |
6883 static void | |
6884 ex_stop(eap) | |
6885 exarg_T *eap; | |
6886 { | |
6887 /* | |
6888 * Disallow suspending for "rvim". | |
6889 */ | |
6890 if (!check_restricted() | |
6891 #ifdef WIN3264 | |
6892 /* | |
6893 * Check if external commands are allowed now. | |
6894 */ | |
6895 && can_end_termcap_mode(TRUE) | |
6896 #endif | |
6897 ) | |
6898 { | |
6899 if (!eap->forceit) | |
6900 autowrite_all(); | |
6901 windgoto((int)Rows - 1, 0); | |
6902 out_char('\n'); | |
6903 out_flush(); | |
6904 stoptermcap(); | |
6905 out_flush(); /* needed for SUN to restore xterm buffer */ | |
6906 #ifdef FEAT_TITLE | |
6907 mch_restore_title(3); /* restore window titles */ | |
6908 #endif | |
6909 ui_suspend(); /* call machine specific function */ | |
6910 #ifdef FEAT_TITLE | |
6911 maketitle(); | |
6912 resettitle(); /* force updating the title */ | |
6913 #endif | |
6914 starttermcap(); | |
6915 scroll_start(); /* scroll screen before redrawing */ | |
6916 redraw_later_clear(); | |
6917 shell_resized(); /* may have resized window */ | |
6918 } | |
6919 } | |
6920 | |
6921 /* | |
6922 * ":exit", ":xit" and ":wq": Write file and exit Vim. | |
6923 */ | |
6924 static void | |
6925 ex_exit(eap) | |
6926 exarg_T *eap; | |
6927 { | |
6928 #ifdef FEAT_CMDWIN | |
6929 if (cmdwin_type != 0) | |
6930 { | |
6931 cmdwin_result = Ctrl_C; | |
6932 return; | |
6933 } | |
6934 #endif | |
631 | 6935 /* Don't quit while editing the command line. */ |
633 | 6936 if (text_locked()) |
6937 { | |
6938 text_locked_msg(); | |
631 | 6939 return; |
6940 } | |
819 | 6941 #ifdef FEAT_AUTOCMD |
4211 | 6942 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); |
6943 /* Refuse to quit when locked or when the buffer in the last window is | |
6944 * being closed (can only happen in autocommands). */ | |
6945 if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) | |
819 | 6946 return; |
6947 #endif | |
7 | 6948 |
6949 /* | |
6950 * if more files or windows we won't exit | |
6951 */ | |
6952 if (check_more(FALSE, eap->forceit) == OK && only_one_window()) | |
6953 exiting = TRUE; | |
6954 if ( ((eap->cmdidx == CMD_wq | |
6955 || curbufIsChanged()) | |
6956 && do_write(eap) == FAIL) | |
6957 || check_more(TRUE, eap->forceit) == FAIL | |
6958 || (only_one_window() && check_changed_any(eap->forceit))) | |
6959 { | |
6960 not_exiting(); | |
6961 } | |
6962 else | |
6963 { | |
6964 #ifdef FEAT_WINDOWS | |
6965 if (only_one_window()) /* quit last window, exit Vim */ | |
6966 #endif | |
6967 getout(0); | |
6968 #ifdef FEAT_WINDOWS | |
6969 # ifdef FEAT_GUI | |
6970 need_mouse_correct = TRUE; | |
6971 # endif | |
6972 /* quit current window, may free buffer */ | |
6973 win_close(curwin, !P_HID(curwin->w_buffer)); | |
6974 #endif | |
6975 } | |
6976 } | |
6977 | |
6978 /* | |
6979 * ":print", ":list", ":number". | |
6980 */ | |
6981 static void | |
6982 ex_print(eap) | |
6983 exarg_T *eap; | |
6984 { | |
167 | 6985 if (curbuf->b_ml.ml_flags & ML_EMPTY) |
6986 EMSG(_(e_emptybuf)); | |
6987 else | |
6988 { | |
6989 for ( ;!got_int; ui_breakcheck()) | |
6990 { | |
6991 print_line(eap->line1, | |
6992 (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound | |
6993 || (eap->flags & EXFLAG_NR)), | |
6994 eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST)); | |
6995 if (++eap->line1 > eap->line2) | |
6996 break; | |
6997 out_flush(); /* show one line at a time */ | |
6998 } | |
6999 setpcmark(); | |
7000 /* put cursor at last line */ | |
7001 curwin->w_cursor.lnum = eap->line2; | |
7002 beginline(BL_SOL | BL_FIX); | |
7003 } | |
7 | 7004 |
7005 ex_no_reprint = TRUE; | |
7006 } | |
7007 | |
7008 #ifdef FEAT_BYTEOFF | |
7009 static void | |
7010 ex_goto(eap) | |
7011 exarg_T *eap; | |
7012 { | |
7013 goto_byte(eap->line2); | |
7014 } | |
7015 #endif | |
7016 | |
7017 /* | |
7018 * ":shell". | |
7019 */ | |
7020 static void | |
7021 ex_shell(eap) | |
1877 | 7022 exarg_T *eap UNUSED; |
7 | 7023 { |
7024 do_shell(NULL, 0); | |
7025 } | |
7026 | |
7027 #if (defined(FEAT_WINDOWS) && defined(HAVE_DROP_FILE)) \ | |
7028 || (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \ | |
621 | 7029 || defined(FEAT_GUI_MSWIN) \ |
7030 || defined(FEAT_GUI_MAC) \ | |
7 | 7031 || defined(PROTO) |
7032 | |
7033 /* | |
7034 * Handle a file drop. The code is here because a drop is *nearly* like an | |
7035 * :args command, but not quite (we have a list of exact filenames, so we | |
7036 * don't want to (a) parse a command line, or (b) expand wildcards. So the | |
7037 * code is very similar to :args and hence needs access to a lot of the static | |
7038 * functions in this file. | |
7039 * | |
7040 * The list should be allocated using alloc(), as should each item in the | |
7041 * list. This function takes over responsibility for freeing the list. | |
7042 * | |
1441 | 7043 * XXX The list is made into the argument list. This is freed using |
7 | 7044 * FreeWild(), which does a series of vim_free() calls, unless the two defines |
7045 * __EMX__ and __ALWAYS_HAS_TRAILING_NUL_POINTER are set. In this case, a | |
7046 * routine _fnexplodefree() is used. This may cause problems, but as the drop | |
7047 * file functionality is (currently) not in EMX this is not presently a | |
7048 * problem. | |
7049 */ | |
7050 void | |
7051 handle_drop(filec, filev, split) | |
7052 int filec; /* the number of files dropped */ | |
7053 char_u **filev; /* the list of files dropped */ | |
7054 int split; /* force splitting the window */ | |
7055 { | |
7056 exarg_T ea; | |
7057 int save_msg_scroll = msg_scroll; | |
7058 | |
631 | 7059 /* Postpone this while editing the command line. */ |
633 | 7060 if (text_locked()) |
7 | 7061 return; |
819 | 7062 #ifdef FEAT_AUTOCMD |
7063 if (curbuf_locked()) | |
7064 return; | |
7065 #endif | |
1668 | 7066 /* When the screen is being updated we should not change buffers and |
7067 * windows structures, it may cause freed memory to be used. */ | |
7068 if (updating_screen) | |
7069 return; | |
7 | 7070 |
7071 /* Check whether the current buffer is changed. If so, we will need | |
7072 * to split the current window or data could be lost. | |
7073 * We don't need to check if the 'hidden' option is set, as in this | |
7074 * case the buffer won't be lost. | |
7075 */ | |
7076 if (!P_HID(curbuf) && !split) | |
7077 { | |
7078 ++emsg_off; | |
7079 split = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE); | |
7080 --emsg_off; | |
7081 } | |
7082 if (split) | |
7083 { | |
7084 # ifdef FEAT_WINDOWS | |
7085 if (win_split(0, 0) == FAIL) | |
7086 return; | |
2583 | 7087 RESET_BINDING(curwin); |
7 | 7088 |
7089 /* When splitting the window, create a new alist. Otherwise the | |
7090 * existing one is overwritten. */ | |
7091 alist_unlink(curwin->w_alist); | |
7092 alist_new(); | |
7093 # else | |
7094 return; /* can't split, always fail */ | |
7095 # endif | |
7096 } | |
7097 | |
7098 /* | |
7099 * Set up the new argument list. | |
7100 */ | |
41 | 7101 alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0); |
7 | 7102 |
7103 /* | |
7104 * Move to the first file. | |
7105 */ | |
7106 /* Fake up a minimal "next" command for do_argfile() */ | |
7107 vim_memset(&ea, 0, sizeof(ea)); | |
7108 ea.cmd = (char_u *)"next"; | |
7109 do_argfile(&ea, 0); | |
7110 | |
7111 /* do_ecmd() may set need_start_insertmode, but since we never left Insert | |
7112 * mode that is not needed here. */ | |
7113 need_start_insertmode = FALSE; | |
7114 | |
7115 /* Restore msg_scroll, otherwise a following command may cause scrolling | |
7116 * unexpectedly. The screen will be redrawn by the caller, thus | |
7117 * msg_scroll being set by displaying a message is irrelevant. */ | |
7118 msg_scroll = save_msg_scroll; | |
7119 } | |
7120 #endif | |
7121 | |
7122 /* | |
7123 * Clear an argument list: free all file names and reset it to zero entries. | |
7124 */ | |
23 | 7125 void |
7 | 7126 alist_clear(al) |
7127 alist_T *al; | |
7128 { | |
7129 while (--al->al_ga.ga_len >= 0) | |
7130 vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); | |
7131 ga_clear(&al->al_ga); | |
7132 } | |
7133 | |
7134 /* | |
7135 * Init an argument list. | |
7136 */ | |
7137 void | |
7138 alist_init(al) | |
7139 alist_T *al; | |
7140 { | |
7141 ga_init2(&al->al_ga, (int)sizeof(aentry_T), 5); | |
7142 } | |
7143 | |
7144 #if defined(FEAT_WINDOWS) || defined(PROTO) | |
7145 | |
7146 /* | |
7147 * Remove a reference from an argument list. | |
7148 * Ignored when the argument list is the global one. | |
7149 * If the argument list is no longer used by any window, free it. | |
7150 */ | |
7151 void | |
7152 alist_unlink(al) | |
7153 alist_T *al; | |
7154 { | |
7155 if (al != &global_alist && --al->al_refcount <= 0) | |
7156 { | |
7157 alist_clear(al); | |
7158 vim_free(al); | |
7159 } | |
7160 } | |
7161 | |
7162 # if defined(FEAT_LISTCMDS) || defined(HAVE_DROP_FILE) || defined(PROTO) | |
7163 /* | |
7164 * Create a new argument list and use it for the current window. | |
7165 */ | |
7166 void | |
7167 alist_new() | |
7168 { | |
7169 curwin->w_alist = (alist_T *)alloc((unsigned)sizeof(alist_T)); | |
7170 if (curwin->w_alist == NULL) | |
7171 { | |
7172 curwin->w_alist = &global_alist; | |
7173 ++global_alist.al_refcount; | |
7174 } | |
7175 else | |
7176 { | |
7177 curwin->w_alist->al_refcount = 1; | |
7178 alist_init(curwin->w_alist); | |
7179 } | |
7180 } | |
7181 # endif | |
7182 #endif | |
7183 | |
7184 #if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) || defined(PROTO) | |
7185 /* | |
7186 * Expand the file names in the global argument list. | |
41 | 7187 * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer |
7188 * numbers to be re-used. | |
7 | 7189 */ |
7190 void | |
41 | 7191 alist_expand(fnum_list, fnum_len) |
7192 int *fnum_list; | |
7193 int fnum_len; | |
7 | 7194 { |
7195 char_u **old_arg_files; | |
41 | 7196 int old_arg_count; |
7 | 7197 char_u **new_arg_files; |
7198 int new_arg_file_count; | |
7199 char_u *save_p_su = p_su; | |
7200 int i; | |
7201 | |
7202 /* Don't use 'suffixes' here. This should work like the shell did the | |
7203 * expansion. Also, the vimrc file isn't read yet, thus the user | |
7204 * can't set the options. */ | |
7205 p_su = empty_option; | |
7206 old_arg_files = (char_u **)alloc((unsigned)(sizeof(char_u *) * GARGCOUNT)); | |
7207 if (old_arg_files != NULL) | |
7208 { | |
7209 for (i = 0; i < GARGCOUNT; ++i) | |
41 | 7210 old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname); |
7211 old_arg_count = GARGCOUNT; | |
7212 if (expand_wildcards(old_arg_count, old_arg_files, | |
7 | 7213 &new_arg_file_count, &new_arg_files, |
2966 | 7214 EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK |
7 | 7215 && new_arg_file_count > 0) |
7216 { | |
41 | 7217 alist_set(&global_alist, new_arg_file_count, new_arg_files, |
7218 TRUE, fnum_list, fnum_len); | |
7219 FreeWild(old_arg_count, old_arg_files); | |
23 | 7220 } |
7 | 7221 } |
7222 p_su = save_p_su; | |
7223 } | |
7224 #endif | |
7225 | |
7226 /* | |
7227 * Set the argument list for the current window. | |
7228 * Takes over the allocated files[] and the allocated fnames in it. | |
7229 */ | |
7230 void | |
41 | 7231 alist_set(al, count, files, use_curbuf, fnum_list, fnum_len) |
7 | 7232 alist_T *al; |
7233 int count; | |
7234 char_u **files; | |
7235 int use_curbuf; | |
41 | 7236 int *fnum_list; |
7237 int fnum_len; | |
7 | 7238 { |
7239 int i; | |
7240 | |
7241 alist_clear(al); | |
7242 if (ga_grow(&al->al_ga, count) == OK) | |
7243 { | |
7244 for (i = 0; i < count; ++i) | |
23 | 7245 { |
7246 if (got_int) | |
7247 { | |
7248 /* When adding many buffers this can take a long time. Allow | |
7249 * interrupting here. */ | |
7250 while (i < count) | |
7251 vim_free(files[i++]); | |
7252 break; | |
7253 } | |
41 | 7254 |
7255 /* May set buffer name of a buffer previously used for the | |
7256 * argument list, so that it's re-used by alist_add. */ | |
7257 if (fnum_list != NULL && i < fnum_len) | |
7258 buf_set_name(fnum_list[i], files[i]); | |
7259 | |
7 | 7260 alist_add(al, files[i], use_curbuf ? 2 : 1); |
23 | 7261 ui_breakcheck(); |
7262 } | |
7 | 7263 vim_free(files); |
7264 } | |
7265 else | |
7266 FreeWild(count, files); | |
7267 #ifdef FEAT_WINDOWS | |
7268 if (al == &global_alist) | |
7269 #endif | |
7270 arg_had_last = FALSE; | |
7271 } | |
7272 | |
7273 /* | |
7274 * Add file "fname" to argument list "al". | |
7275 * "fname" must have been allocated and "al" must have been checked for room. | |
7276 */ | |
7277 void | |
7278 alist_add(al, fname, set_fnum) | |
7279 alist_T *al; | |
7280 char_u *fname; | |
7281 int set_fnum; /* 1: set buffer number; 2: re-use curbuf */ | |
7282 { | |
7283 if (fname == NULL) /* don't add NULL file names */ | |
7284 return; | |
7285 #ifdef BACKSLASH_IN_FILENAME | |
7286 slash_adjust(fname); | |
7287 #endif | |
7288 AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; | |
7289 if (set_fnum > 0) | |
7290 AARGLIST(al)[al->al_ga.ga_len].ae_fnum = | |
7291 buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); | |
7292 ++al->al_ga.ga_len; | |
7293 } | |
7294 | |
7295 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) | |
7296 /* | |
7297 * Adjust slashes in file names. Called after 'shellslash' was set. | |
7298 */ | |
7299 void | |
7300 alist_slash_adjust() | |
7301 { | |
7302 int i; | |
7303 # ifdef FEAT_WINDOWS | |
7304 win_T *wp; | |
671 | 7305 tabpage_T *tp; |
7 | 7306 # endif |
7307 | |
7308 for (i = 0; i < GARGCOUNT; ++i) | |
7309 if (GARGLIST[i].ae_fname != NULL) | |
7310 slash_adjust(GARGLIST[i].ae_fname); | |
7311 # ifdef FEAT_WINDOWS | |
671 | 7312 FOR_ALL_TAB_WINDOWS(tp, wp) |
7 | 7313 if (wp->w_alist != &global_alist) |
7314 for (i = 0; i < WARGCOUNT(wp); ++i) | |
7315 if (WARGLIST(wp)[i].ae_fname != NULL) | |
7316 slash_adjust(WARGLIST(wp)[i].ae_fname); | |
7317 # endif | |
7318 } | |
7319 #endif | |
7320 | |
7321 /* | |
7322 * ":preserve". | |
7323 */ | |
7324 static void | |
7325 ex_preserve(eap) | |
1877 | 7326 exarg_T *eap UNUSED; |
7 | 7327 { |
164 | 7328 curbuf->b_flags |= BF_PRESERVED; |
7 | 7329 ml_preserve(curbuf, TRUE); |
7330 } | |
7331 | |
7332 /* | |
7333 * ":recover". | |
7334 */ | |
7335 static void | |
7336 ex_recover(eap) | |
7337 exarg_T *eap; | |
7338 { | |
7339 /* Set recoverymode right away to avoid the ATTENTION prompt. */ | |
7340 recoverymode = TRUE; | |
7341 if (!check_changed(curbuf, p_awa, TRUE, eap->forceit, FALSE) | |
7342 && (*eap->arg == NUL | |
7343 || setfname(curbuf, eap->arg, NULL, TRUE) == OK)) | |
7344 ml_recover(); | |
7345 recoverymode = FALSE; | |
7346 } | |
7347 | |
7348 /* | |
7349 * Command modifier used in a wrong way. | |
7350 */ | |
7351 static void | |
7352 ex_wrongmodifier(eap) | |
7353 exarg_T *eap; | |
7354 { | |
7355 eap->errmsg = e_invcmd; | |
7356 } | |
7357 | |
7358 #ifdef FEAT_WINDOWS | |
7359 /* | |
7360 * :sview [+command] file split window with new file, read-only | |
7361 * :split [[+command] file] split window with current or new file | |
7362 * :vsplit [[+command] file] split window vertically with current or new file | |
7363 * :new [[+command] file] split window with no or new file | |
7364 * :vnew [[+command] file] split vertically window with no or new file | |
7365 * :sfind [+command] file split window with file in 'path' | |
675 | 7366 * |
7367 * :tabedit open new Tab page with empty window | |
7368 * :tabedit [+command] file open new Tab page and edit "file" | |
7369 * :tabnew [[+command] file] just like :tabedit | |
7370 * :tabfind [+command] file open new Tab page and find "file" | |
7 | 7371 */ |
7372 void | |
7373 ex_splitview(eap) | |
7374 exarg_T *eap; | |
7375 { | |
675 | 7376 win_T *old_curwin = curwin; |
667 | 7377 # if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) |
7 | 7378 char_u *fname = NULL; |
667 | 7379 # endif |
7380 # ifdef FEAT_BROWSE | |
7 | 7381 int browse_flag = cmdmod.browse; |
667 | 7382 # endif |
7383 | |
7384 # ifndef FEAT_VERTSPLIT | |
7 | 7385 if (eap->cmdidx == CMD_vsplit || eap->cmdidx == CMD_vnew) |
7386 { | |
7387 ex_ni(eap); | |
7388 return; | |
7389 } | |
667 | 7390 # endif |
7 | 7391 |
667 | 7392 # ifdef FEAT_GUI |
7 | 7393 need_mouse_correct = TRUE; |
667 | 7394 # endif |
7395 | |
7396 # ifdef FEAT_QUICKFIX | |
7 | 7397 /* A ":split" in the quickfix window works like ":new". Don't want two |
1661 | 7398 * quickfix windows. But it's OK when doing ":tab split". */ |
7399 if (bt_quickfix(curbuf) && cmdmod.tab == 0) | |
7 | 7400 { |
7401 if (eap->cmdidx == CMD_split) | |
7402 eap->cmdidx = CMD_new; | |
667 | 7403 # ifdef FEAT_VERTSPLIT |
7 | 7404 if (eap->cmdidx == CMD_vsplit) |
7405 eap->cmdidx = CMD_vnew; | |
667 | 7406 # endif |
7407 } | |
7 | 7408 # endif |
667 | 7409 |
7410 # ifdef FEAT_SEARCHPATH | |
675 | 7411 if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) |
7 | 7412 { |
7413 fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), | |
7414 FNAME_MESS, TRUE, curbuf->b_ffname); | |
7415 if (fname == NULL) | |
7416 goto theend; | |
7417 eap->arg = fname; | |
7418 } | |
667 | 7419 # ifdef FEAT_BROWSE |
7 | 7420 else |
667 | 7421 # endif |
7 | 7422 # endif |
667 | 7423 # ifdef FEAT_BROWSE |
7 | 7424 if (cmdmod.browse |
667 | 7425 # ifdef FEAT_VERTSPLIT |
7 | 7426 && eap->cmdidx != CMD_vnew |
667 | 7427 # endif |
7 | 7428 && eap->cmdidx != CMD_new) |
7429 { | |
1683 | 7430 # ifdef FEAT_AUTOCMD |
461 | 7431 if ( |
1683 | 7432 # ifdef FEAT_GUI |
461 | 7433 !gui.in_use && |
1683 | 7434 # endif |
461 | 7435 au_has_group((char_u *)"FileExplorer")) |
7436 { | |
7437 /* No browsing supported but we do have the file explorer: | |
7438 * Edit the directory. */ | |
7439 if (*eap->arg == NUL || !mch_isdir(eap->arg)) | |
7440 eap->arg = (char_u *)"."; | |
7441 } | |
7442 else | |
1683 | 7443 # endif |
461 | 7444 { |
7445 fname = do_browse(0, (char_u *)_("Edit File in new window"), | |
7 | 7446 eap->arg, NULL, NULL, NULL, curbuf); |
461 | 7447 if (fname == NULL) |
7448 goto theend; | |
7449 eap->arg = fname; | |
7450 } | |
7 | 7451 } |
7452 cmdmod.browse = FALSE; /* Don't browse again in do_ecmd(). */ | |
667 | 7453 # endif |
7 | 7454 |
675 | 7455 /* |
7456 * Either open new tab page or split the window. | |
7457 */ | |
7458 if (eap->cmdidx == CMD_tabedit | |
7459 || eap->cmdidx == CMD_tabfind | |
7460 || eap->cmdidx == CMD_tabnew) | |
7461 { | |
820 | 7462 if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab |
7463 : eap->addr_count == 0 ? 0 | |
7464 : (int)eap->line2 + 1) != FAIL) | |
675 | 7465 { |
1498 | 7466 do_exedit(eap, old_curwin); |
675 | 7467 |
7468 /* set the alternate buffer for the window we came from */ | |
7469 if (curwin != old_curwin | |
7470 && win_valid(old_curwin) | |
7471 && old_curwin->w_buffer != curbuf | |
7472 && !cmdmod.keepalt) | |
7473 old_curwin->w_alt_fnum = curbuf->b_fnum; | |
7474 } | |
7475 } | |
7476 else if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0, | |
7 | 7477 *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) |
7478 { | |
667 | 7479 # ifdef FEAT_SCROLLBIND |
7 | 7480 /* Reset 'scrollbind' when editing another file, but keep it when |
7481 * doing ":split" without arguments. */ | |
7482 if (*eap->arg != NUL | |
667 | 7483 # ifdef FEAT_BROWSE |
7 | 7484 || cmdmod.browse |
667 | 7485 # endif |
7 | 7486 ) |
2583 | 7487 { |
7488 RESET_BINDING(curwin); | |
7489 } | |
7 | 7490 else |
7491 do_check_scrollbind(FALSE); | |
667 | 7492 # endif |
7 | 7493 do_exedit(eap, old_curwin); |
7494 } | |
7495 | |
667 | 7496 # ifdef FEAT_BROWSE |
7 | 7497 cmdmod.browse = browse_flag; |
667 | 7498 # endif |
7499 | |
7500 # if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) | |
7 | 7501 theend: |
7502 vim_free(fname); | |
667 | 7503 # endif |
7504 } | |
7505 | |
7506 /* | |
682 | 7507 * Open a new tab page. |
667 | 7508 */ |
7509 void | |
682 | 7510 tabpage_new() |
7511 { | |
7512 exarg_T ea; | |
7513 | |
7514 vim_memset(&ea, 0, sizeof(ea)); | |
7515 ea.cmdidx = CMD_tabnew; | |
7516 ea.cmd = (char_u *)"tabn"; | |
7517 ea.arg = (char_u *)""; | |
7518 ex_splitview(&ea); | |
7519 } | |
7520 | |
7521 /* | |
7522 * :tabnext command | |
7523 */ | |
7524 static void | |
7525 ex_tabnext(eap) | |
7526 exarg_T *eap; | |
7527 { | |
685 | 7528 switch (eap->cmdidx) |
7529 { | |
7530 case CMD_tabfirst: | |
7531 case CMD_tabrewind: | |
7532 goto_tabpage(1); | |
7533 break; | |
7534 case CMD_tablast: | |
7535 goto_tabpage(9999); | |
7536 break; | |
7537 case CMD_tabprevious: | |
7538 case CMD_tabNext: | |
7539 goto_tabpage(eap->addr_count == 0 ? -1 : -(int)eap->line2); | |
7540 break; | |
7541 default: /* CMD_tabnext */ | |
7542 goto_tabpage(eap->addr_count == 0 ? 0 : (int)eap->line2); | |
7543 break; | |
7544 } | |
682 | 7545 } |
7546 | |
7547 /* | |
7548 * :tabmove command | |
7549 */ | |
7550 static void | |
7551 ex_tabmove(eap) | |
7552 exarg_T *eap; | |
7553 { | |
3662 | 7554 int tab_number = 9999; |
7555 | |
7556 if (eap->arg && *eap->arg != NUL) | |
7557 { | |
7558 char_u *p = eap->arg; | |
7559 int relative = 0; /* argument +N/-N means: move N places to the | |
7560 * right/left relative to the current position. */ | |
7561 | |
7562 if (*eap->arg == '-') | |
7563 { | |
7564 relative = -1; | |
7565 p = eap->arg + 1; | |
7566 } | |
7567 else if (*eap->arg == '+') | |
7568 { | |
7569 relative = 1; | |
7570 p = eap->arg + 1; | |
7571 } | |
7572 else | |
7573 p = eap->arg; | |
7574 | |
7575 if (p == skipdigits(p)) | |
7576 { | |
7577 /* No numbers as argument. */ | |
7578 eap->errmsg = e_invarg; | |
7579 return; | |
7580 } | |
7581 | |
7582 tab_number = getdigits(&p); | |
7583 if (relative != 0) | |
7584 tab_number = tab_number * relative + tabpage_index(curtab) - 1;; | |
7585 } | |
7586 else if (eap->addr_count != 0) | |
7587 tab_number = eap->line2; | |
7588 | |
7589 tabpage_move(tab_number); | |
667 | 7590 } |
7591 | |
7592 /* | |
7593 * :tabs command: List tabs and their contents. | |
7594 */ | |
7595 static void | |
7596 ex_tabs(eap) | |
1877 | 7597 exarg_T *eap UNUSED; |
667 | 7598 { |
7599 tabpage_T *tp; | |
7600 win_T *wp; | |
7601 int tabcount = 1; | |
7602 | |
7603 msg_start(); | |
7604 msg_scroll = TRUE; | |
7605 for (tp = first_tabpage; tp != NULL && !got_int; tp = tp->tp_next) | |
7606 { | |
7607 msg_putchar('\n'); | |
7608 vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++); | |
7609 msg_outtrans_attr(IObuff, hl_attr(HLF_T)); | |
7610 out_flush(); /* output one line at a time */ | |
7611 ui_breakcheck(); | |
7612 | |
678 | 7613 if (tp == curtab) |
667 | 7614 wp = firstwin; |
7615 else | |
7616 wp = tp->tp_firstwin; | |
7617 for ( ; wp != NULL && !got_int; wp = wp->w_next) | |
7618 { | |
682 | 7619 msg_putchar('\n'); |
7620 msg_putchar(wp == curwin ? '>' : ' '); | |
7621 msg_putchar(' '); | |
672 | 7622 msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' '); |
7623 msg_putchar(' '); | |
667 | 7624 if (buf_spname(wp->w_buffer) != NULL) |
3839 | 7625 vim_strncpy(IObuff, buf_spname(wp->w_buffer), IOSIZE - 1); |
667 | 7626 else |
7627 home_replace(wp->w_buffer, wp->w_buffer->b_fname, | |
7628 IObuff, IOSIZE, TRUE); | |
7629 msg_outtrans(IObuff); | |
7630 out_flush(); /* output one line at a time */ | |
7631 ui_breakcheck(); | |
7632 } | |
7633 } | |
7634 } | |
7635 | |
7636 #endif /* FEAT_WINDOWS */ | |
7 | 7637 |
7638 /* | |
7639 * ":mode": Set screen mode. | |
7640 * If no argument given, just get the screen size and redraw. | |
7641 */ | |
7642 static void | |
7643 ex_mode(eap) | |
7644 exarg_T *eap; | |
7645 { | |
7646 if (*eap->arg == NUL) | |
7647 shell_resized(); | |
7648 else | |
7649 mch_screenmode(eap->arg); | |
7650 } | |
7651 | |
7652 #ifdef FEAT_WINDOWS | |
7653 /* | |
7654 * ":resize". | |
7655 * set, increment or decrement current window height | |
7656 */ | |
7657 static void | |
7658 ex_resize(eap) | |
7659 exarg_T *eap; | |
7660 { | |
7661 int n; | |
7662 win_T *wp = curwin; | |
7663 | |
7664 if (eap->addr_count > 0) | |
7665 { | |
7666 n = eap->line2; | |
7667 for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) | |
7668 ; | |
7669 } | |
7670 | |
7671 #ifdef FEAT_GUI | |
7672 need_mouse_correct = TRUE; | |
7673 #endif | |
7674 n = atol((char *)eap->arg); | |
7675 #ifdef FEAT_VERTSPLIT | |
7676 if (cmdmod.split & WSP_VERT) | |
7677 { | |
7678 if (*eap->arg == '-' || *eap->arg == '+') | |
7679 n += W_WIDTH(curwin); | |
7680 else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ | |
7681 n = 9999; | |
7682 win_setwidth_win((int)n, wp); | |
7683 } | |
7684 else | |
7685 #endif | |
7686 { | |
7687 if (*eap->arg == '-' || *eap->arg == '+') | |
7688 n += curwin->w_height; | |
7689 else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ | |
7690 n = 9999; | |
7691 win_setheight_win((int)n, wp); | |
7692 } | |
7693 } | |
7694 #endif | |
7695 | |
7696 /* | |
7697 * ":find [+command] <file>" command. | |
7698 */ | |
7699 static void | |
7700 ex_find(eap) | |
7701 exarg_T *eap; | |
7702 { | |
7703 #ifdef FEAT_SEARCHPATH | |
7704 char_u *fname; | |
7705 int count; | |
7706 | |
7707 fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, | |
7708 TRUE, curbuf->b_ffname); | |
7709 if (eap->addr_count > 0) | |
7710 { | |
7711 /* Repeat finding the file "count" times. This matters when it | |
7712 * appears several times in the path. */ | |
7713 count = eap->line2; | |
7714 while (fname != NULL && --count > 0) | |
7715 { | |
7716 vim_free(fname); | |
7717 fname = find_file_in_path(NULL, 0, FNAME_MESS, | |
7718 FALSE, curbuf->b_ffname); | |
7719 } | |
7720 } | |
7721 | |
7722 if (fname != NULL) | |
7723 { | |
7724 eap->arg = fname; | |
7725 #endif | |
7726 do_exedit(eap, NULL); | |
7727 #ifdef FEAT_SEARCHPATH | |
7728 vim_free(fname); | |
7729 } | |
7730 #endif | |
7731 } | |
7732 | |
7733 /* | |
167 | 7734 * ":open" simulation: for now just work like ":visual". |
7735 */ | |
7736 static void | |
7737 ex_open(eap) | |
7738 exarg_T *eap; | |
7739 { | |
7740 regmatch_T regmatch; | |
7741 char_u *p; | |
7742 | |
7743 curwin->w_cursor.lnum = eap->line2; | |
7744 beginline(BL_SOL | BL_FIX); | |
7745 if (*eap->arg == '/') | |
7746 { | |
7747 /* ":open /pattern/": put cursor in column found with pattern */ | |
7748 ++eap->arg; | |
7749 p = skip_regexp(eap->arg, '/', p_magic, NULL); | |
7750 *p = NUL; | |
7751 regmatch.regprog = vim_regcomp(eap->arg, p_magic ? RE_MAGIC : 0); | |
7752 if (regmatch.regprog != NULL) | |
7753 { | |
7754 regmatch.rm_ic = p_ic; | |
7755 p = ml_get_curline(); | |
7756 if (vim_regexec(®match, p, (colnr_T)0)) | |
835 | 7757 curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - p); |
167 | 7758 else |
7759 EMSG(_(e_nomatch)); | |
7760 vim_free(regmatch.regprog); | |
7761 } | |
7762 /* Move to the NUL, ignore any other arguments. */ | |
7763 eap->arg += STRLEN(eap->arg); | |
7764 } | |
7765 check_cursor(); | |
7766 | |
7767 eap->cmdidx = CMD_visual; | |
7768 do_exedit(eap, NULL); | |
7769 } | |
7770 | |
7771 /* | |
7772 * ":edit", ":badd", ":visual". | |
7 | 7773 */ |
7774 static void | |
7775 ex_edit(eap) | |
7776 exarg_T *eap; | |
7777 { | |
7778 do_exedit(eap, NULL); | |
7779 } | |
7780 | |
7781 /* | |
7782 * ":edit <file>" command and alikes. | |
7783 */ | |
7784 void | |
7785 do_exedit(eap, old_curwin) | |
7786 exarg_T *eap; | |
7787 win_T *old_curwin; /* curwin before doing a split or NULL */ | |
7788 { | |
7789 int n; | |
7790 #ifdef FEAT_WINDOWS | |
7791 int need_hide; | |
7792 #endif | |
167 | 7793 int exmode_was = exmode_active; |
7 | 7794 |
7795 /* | |
7796 * ":vi" command ends Ex mode. | |
7797 */ | |
7798 if (exmode_active && (eap->cmdidx == CMD_visual | |
7799 || eap->cmdidx == CMD_view)) | |
7800 { | |
7801 exmode_active = FALSE; | |
7802 if (*eap->arg == NUL) | |
167 | 7803 { |
7804 /* Special case: ":global/pat/visual\NLvi-commands" */ | |
7805 if (global_busy) | |
7806 { | |
7807 int rd = RedrawingDisabled; | |
7808 int nwr = no_wait_return; | |
7809 int ms = msg_scroll; | |
7810 #ifdef FEAT_GUI | |
7811 int he = hold_gui_events; | |
7812 #endif | |
7813 | |
7814 if (eap->nextcmd != NULL) | |
7815 { | |
7816 stuffReadbuff(eap->nextcmd); | |
7817 eap->nextcmd = NULL; | |
7818 } | |
7819 | |
7820 if (exmode_was != EXMODE_VIM) | |
7821 settmode(TMODE_RAW); | |
7822 RedrawingDisabled = 0; | |
7823 no_wait_return = 0; | |
7824 need_wait_return = FALSE; | |
7825 msg_scroll = 0; | |
7826 #ifdef FEAT_GUI | |
7827 hold_gui_events = 0; | |
7828 #endif | |
7829 must_redraw = CLEAR; | |
7830 | |
7831 main_loop(FALSE, TRUE); | |
7832 | |
7833 RedrawingDisabled = rd; | |
7834 no_wait_return = nwr; | |
7835 msg_scroll = ms; | |
7836 #ifdef FEAT_GUI | |
7837 hold_gui_events = he; | |
7838 #endif | |
7839 } | |
7 | 7840 return; |
167 | 7841 } |
7 | 7842 } |
7843 | |
7844 if ((eap->cmdidx == CMD_new | |
675 | 7845 || eap->cmdidx == CMD_tabnew |
7846 || eap->cmdidx == CMD_tabedit | |
7 | 7847 #ifdef FEAT_VERTSPLIT |
7848 || eap->cmdidx == CMD_vnew | |
7849 #endif | |
7850 ) && *eap->arg == NUL) | |
7851 { | |
675 | 7852 /* ":new" or ":tabnew" without argument: edit an new empty buffer */ |
7 | 7853 setpcmark(); |
7854 (void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE, | |
1743 | 7855 ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0), |
7856 old_curwin == NULL ? curwin : NULL); | |
7 | 7857 } |
7858 else if ((eap->cmdidx != CMD_split | |
7859 #ifdef FEAT_VERTSPLIT | |
7860 && eap->cmdidx != CMD_vsplit | |
7861 #endif | |
7862 ) | |
7863 || *eap->arg != NUL | |
7864 #ifdef FEAT_BROWSE | |
7865 || cmdmod.browse | |
7866 #endif | |
7867 ) | |
7868 { | |
822 | 7869 #ifdef FEAT_AUTOCMD |
7870 /* Can't edit another file when "curbuf_lock" is set. Only ":edit" | |
7871 * can bring us here, others are stopped earlier. */ | |
7872 if (*eap->arg != NUL && curbuf_locked()) | |
7873 return; | |
7874 #endif | |
7 | 7875 n = readonlymode; |
7876 if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) | |
7877 readonlymode = TRUE; | |
7878 else if (eap->cmdidx == CMD_enew) | |
7879 readonlymode = FALSE; /* 'readonly' doesn't make sense in an | |
7880 empty buffer */ | |
7881 setpcmark(); | |
7882 if (do_ecmd(0, (eap->cmdidx == CMD_enew ? NULL : eap->arg), | |
7883 NULL, eap, | |
7884 /* ":edit" goes to first line if Vi compatible */ | |
7885 (*eap->arg == NUL && eap->do_ecmd_lnum == 0 | |
7886 && vim_strchr(p_cpo, CPO_GOTO1) != NULL) | |
7887 ? ECMD_ONE : eap->do_ecmd_lnum, | |
7888 (P_HID(curbuf) ? ECMD_HIDE : 0) | |
7889 + (eap->forceit ? ECMD_FORCEIT : 0) | |
7890 #ifdef FEAT_LISTCMDS | |
7891 + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0 ) | |
7892 #endif | |
1743 | 7893 , old_curwin == NULL ? curwin : NULL) == FAIL) |
7 | 7894 { |
7895 /* Editing the file failed. If the window was split, close it. */ | |
7896 #ifdef FEAT_WINDOWS | |
7897 if (old_curwin != NULL) | |
7898 { | |
7899 need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); | |
7900 if (!need_hide || P_HID(curbuf)) | |
7901 { | |
24 | 7902 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) |
7903 cleanup_T cs; | |
7904 | |
7905 /* Reset the error/interrupt/exception state here so that | |
7906 * aborting() returns FALSE when closing a window. */ | |
7907 enter_cleanup(&cs); | |
7908 # endif | |
7 | 7909 # ifdef FEAT_GUI |
7910 need_mouse_correct = TRUE; | |
7911 # endif | |
7912 win_close(curwin, !need_hide && !P_HID(curbuf)); | |
24 | 7913 |
7914 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) | |
7915 /* Restore the error/interrupt/exception state if not | |
7916 * discarded by a new aborting error, interrupt, or | |
7917 * uncaught exception. */ | |
7918 leave_cleanup(&cs); | |
7919 # endif | |
7 | 7920 } |
7921 } | |
7922 #endif | |
7923 } | |
7924 else if (readonlymode && curbuf->b_nwindows == 1) | |
7925 { | |
7926 /* When editing an already visited buffer, 'readonly' won't be set | |
7927 * but the previous value is kept. With ":view" and ":sview" we | |
7928 * want the file to be readonly, except when another window is | |
7929 * editing the same buffer. */ | |
7930 curbuf->b_p_ro = TRUE; | |
7931 } | |
7932 readonlymode = n; | |
7933 } | |
7934 else | |
7935 { | |
7936 if (eap->do_ecmd_cmd != NULL) | |
7937 do_cmdline_cmd(eap->do_ecmd_cmd); | |
7938 #ifdef FEAT_TITLE | |
7939 n = curwin->w_arg_idx_invalid; | |
7940 #endif | |
7941 check_arg_idx(curwin); | |
7942 #ifdef FEAT_TITLE | |
7943 if (n != curwin->w_arg_idx_invalid) | |
7944 maketitle(); | |
7945 #endif | |
7946 } | |
7947 | |
7948 #ifdef FEAT_WINDOWS | |
7949 /* | |
7950 * if ":split file" worked, set alternate file name in old window to new | |
7951 * file | |
7952 */ | |
7953 if (old_curwin != NULL | |
7954 && *eap->arg != NUL | |
7955 && curwin != old_curwin | |
7956 && win_valid(old_curwin) | |
22 | 7957 && old_curwin->w_buffer != curbuf |
7958 && !cmdmod.keepalt) | |
7 | 7959 old_curwin->w_alt_fnum = curbuf->b_fnum; |
7960 #endif | |
7961 | |
7962 ex_no_reprint = TRUE; | |
7963 } | |
7964 | |
7965 #ifndef FEAT_GUI | |
7966 /* | |
7967 * ":gui" and ":gvim" when there is no GUI. | |
7968 */ | |
7969 static void | |
7970 ex_nogui(eap) | |
7971 exarg_T *eap; | |
7972 { | |
7973 eap->errmsg = e_nogvim; | |
7974 } | |
7975 #endif | |
7976 | |
7977 #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF) | |
7978 static void | |
7979 ex_tearoff(eap) | |
7980 exarg_T *eap; | |
7981 { | |
7982 gui_make_tearoff(eap->arg); | |
7983 } | |
7984 #endif | |
7985 | |
573 | 7986 #if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)) && defined(FEAT_MENU) |
7 | 7987 static void |
7988 ex_popup(eap) | |
7989 exarg_T *eap; | |
7990 { | |
398 | 7991 gui_make_popup(eap->arg, eap->forceit); |
7 | 7992 } |
7993 #endif | |
7994 | |
7995 static void | |
7996 ex_swapname(eap) | |
1877 | 7997 exarg_T *eap UNUSED; |
7 | 7998 { |
7999 if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) | |
8000 MSG(_("No swap file")); | |
8001 else | |
8002 msg(curbuf->b_ml.ml_mfp->mf_fname); | |
8003 } | |
8004 | |
8005 /* | |
8006 * ":syncbind" forces all 'scrollbind' windows to have the same relative | |
8007 * offset. | |
8008 * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) | |
8009 */ | |
8010 static void | |
8011 ex_syncbind(eap) | |
1877 | 8012 exarg_T *eap UNUSED; |
7 | 8013 { |
8014 #ifdef FEAT_SCROLLBIND | |
8015 win_T *wp; | |
8016 long topline; | |
8017 long y; | |
8018 linenr_T old_linenr = curwin->w_cursor.lnum; | |
8019 | |
8020 setpcmark(); | |
8021 | |
8022 /* | |
8023 * determine max topline | |
8024 */ | |
8025 if (curwin->w_p_scb) | |
8026 { | |
8027 topline = curwin->w_topline; | |
8028 for (wp = firstwin; wp; wp = wp->w_next) | |
8029 { | |
8030 if (wp->w_p_scb && wp->w_buffer) | |
8031 { | |
8032 y = wp->w_buffer->b_ml.ml_line_count - p_so; | |
8033 if (topline > y) | |
8034 topline = y; | |
8035 } | |
8036 } | |
8037 if (topline < 1) | |
8038 topline = 1; | |
8039 } | |
8040 else | |
8041 { | |
8042 topline = 1; | |
8043 } | |
8044 | |
8045 | |
8046 /* | |
8047 * set all scrollbind windows to the same topline | |
8048 */ | |
8049 wp = curwin; | |
8050 for (curwin = firstwin; curwin; curwin = curwin->w_next) | |
8051 { | |
8052 if (curwin->w_p_scb) | |
8053 { | |
8054 y = topline - curwin->w_topline; | |
8055 if (y > 0) | |
8056 scrollup(y, TRUE); | |
8057 else | |
8058 scrolldown(-y, TRUE); | |
8059 curwin->w_scbind_pos = topline; | |
8060 redraw_later(VALID); | |
8061 cursor_correct(); | |
8062 #ifdef FEAT_WINDOWS | |
8063 curwin->w_redr_status = TRUE; | |
8064 #endif | |
8065 } | |
8066 } | |
8067 curwin = wp; | |
8068 if (curwin->w_p_scb) | |
8069 { | |
8070 did_syncbind = TRUE; | |
8071 checkpcmark(); | |
8072 if (old_linenr != curwin->w_cursor.lnum) | |
8073 { | |
8074 char_u ctrl_o[2]; | |
8075 | |
8076 ctrl_o[0] = Ctrl_O; | |
8077 ctrl_o[1] = 0; | |
8078 ins_typebuf(ctrl_o, REMAP_NONE, 0, TRUE, FALSE); | |
8079 } | |
8080 } | |
8081 #endif | |
8082 } | |
8083 | |
8084 | |
8085 static void | |
8086 ex_read(eap) | |
8087 exarg_T *eap; | |
8088 { | |
167 | 8089 int i; |
8090 int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); | |
8091 linenr_T lnum; | |
7 | 8092 |
8093 if (eap->usefilter) /* :r!cmd */ | |
8094 do_bang(1, eap, FALSE, FALSE, TRUE); | |
8095 else | |
8096 { | |
8097 if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) | |
8098 return; | |
8099 | |
8100 #ifdef FEAT_BROWSE | |
8101 if (cmdmod.browse) | |
8102 { | |
8103 char_u *browseFile; | |
8104 | |
28 | 8105 browseFile = do_browse(0, (char_u *)_("Append File"), eap->arg, |
7 | 8106 NULL, NULL, NULL, curbuf); |
8107 if (browseFile != NULL) | |
8108 { | |
8109 i = readfile(browseFile, NULL, | |
8110 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); | |
8111 vim_free(browseFile); | |
8112 } | |
8113 else | |
8114 i = OK; | |
8115 } | |
8116 else | |
8117 #endif | |
8118 if (*eap->arg == NUL) | |
8119 { | |
8120 if (check_fname() == FAIL) /* check for no file name */ | |
8121 return; | |
8122 i = readfile(curbuf->b_ffname, curbuf->b_fname, | |
8123 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); | |
8124 } | |
8125 else | |
8126 { | |
8127 if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) | |
8128 (void)setaltfname(eap->arg, eap->arg, (linenr_T)1); | |
8129 i = readfile(eap->arg, NULL, | |
8130 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); | |
8131 | |
8132 } | |
8133 if (i == FAIL) | |
8134 { | |
8135 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) | |
8136 if (!aborting()) | |
8137 #endif | |
8138 EMSG2(_(e_notopen), eap->arg); | |
8139 } | |
8140 else | |
167 | 8141 { |
8142 if (empty && exmode_active) | |
8143 { | |
8144 /* Delete the empty line that remains. Historically ex does | |
8145 * this but vi doesn't. */ | |
8146 if (eap->line2 == 0) | |
8147 lnum = curbuf->b_ml.ml_line_count; | |
8148 else | |
8149 lnum = 1; | |
573 | 8150 if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) |
167 | 8151 { |
8152 ml_delete(lnum, FALSE); | |
573 | 8153 if (curwin->w_cursor.lnum > 1 |
8154 && curwin->w_cursor.lnum >= lnum) | |
167 | 8155 --curwin->w_cursor.lnum; |
1929 | 8156 deleted_lines_mark(lnum, 1L); |
167 | 8157 } |
8158 } | |
7 | 8159 redraw_curbuf_later(VALID); |
167 | 8160 } |
7 | 8161 } |
8162 } | |
8163 | |
358 | 8164 static char_u *prev_dir = NULL; |
8165 | |
8166 #if defined(EXITFREE) || defined(PROTO) | |
8167 void | |
8168 free_cd_dir() | |
8169 { | |
8170 vim_free(prev_dir); | |
1471 | 8171 prev_dir = NULL; |
1837 | 8172 |
8173 vim_free(globaldir); | |
8174 globaldir = NULL; | |
358 | 8175 } |
8176 #endif | |
8177 | |
8178 | |
7 | 8179 /* |
8180 * ":cd", ":lcd", ":chdir" and ":lchdir". | |
8181 */ | |
1411 | 8182 void |
7 | 8183 ex_cd(eap) |
8184 exarg_T *eap; | |
8185 { | |
8186 char_u *new_dir; | |
8187 char_u *tofree; | |
8188 | |
8189 new_dir = eap->arg; | |
8190 #if !defined(UNIX) && !defined(VMS) | |
8191 /* for non-UNIX ":cd" means: print current directory */ | |
8192 if (*new_dir == NUL) | |
8193 ex_pwd(NULL); | |
8194 else | |
8195 #endif | |
8196 { | |
1838 | 8197 #ifdef FEAT_AUTOCMD |
8198 if (allbuf_locked()) | |
8199 return; | |
8200 #endif | |
167 | 8201 if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged() |
8202 && !eap->forceit) | |
8203 { | |
1441 | 8204 EMSG(_("E747: Cannot change directory, buffer is modified (add ! to override)")); |
167 | 8205 return; |
8206 } | |
8207 | |
7 | 8208 /* ":cd -": Change to previous directory */ |
8209 if (STRCMP(new_dir, "-") == 0) | |
8210 { | |
8211 if (prev_dir == NULL) | |
8212 { | |
8213 EMSG(_("E186: No previous directory")); | |
8214 return; | |
8215 } | |
8216 new_dir = prev_dir; | |
8217 } | |
8218 | |
8219 /* Save current directory for next ":cd -" */ | |
8220 tofree = prev_dir; | |
8221 if (mch_dirname(NameBuff, MAXPATHL) == OK) | |
8222 prev_dir = vim_strsave(NameBuff); | |
8223 else | |
8224 prev_dir = NULL; | |
8225 | |
8226 #if defined(UNIX) || defined(VMS) | |
8227 /* for UNIX ":cd" means: go to home directory */ | |
8228 if (*new_dir == NUL) | |
8229 { | |
8230 /* use NameBuff for home directory name */ | |
8231 # ifdef VMS | |
8232 char_u *p; | |
8233 | |
8234 p = mch_getenv((char_u *)"SYS$LOGIN"); | |
8235 if (p == NULL || *p == NUL) /* empty is the same as not set */ | |
8236 NameBuff[0] = NUL; | |
8237 else | |
416 | 8238 vim_strncpy(NameBuff, p, MAXPATHL - 1); |
7 | 8239 # else |
8240 expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); | |
8241 # endif | |
8242 new_dir = NameBuff; | |
8243 } | |
8244 #endif | |
8245 if (new_dir == NULL || vim_chdir(new_dir)) | |
8246 EMSG(_(e_failed)); | |
8247 else | |
8248 { | |
8249 vim_free(curwin->w_localdir); | |
8250 if (eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir) | |
8251 { | |
8252 /* If still in global directory, need to remember current | |
8253 * directory as global directory. */ | |
8254 if (globaldir == NULL && prev_dir != NULL) | |
8255 globaldir = vim_strsave(prev_dir); | |
8256 /* Remember this local directory for the window. */ | |
8257 if (mch_dirname(NameBuff, MAXPATHL) == OK) | |
8258 curwin->w_localdir = vim_strsave(NameBuff); | |
8259 } | |
8260 else | |
8261 { | |
8262 /* We are now in the global directory, no need to remember its | |
8263 * name. */ | |
8264 vim_free(globaldir); | |
8265 globaldir = NULL; | |
8266 curwin->w_localdir = NULL; | |
8267 } | |
8268 | |
8269 shorten_fnames(TRUE); | |
8270 | |
8271 /* Echo the new current directory if the command was typed. */ | |
1930 | 8272 if (KeyTyped || p_verbose >= 5) |
7 | 8273 ex_pwd(eap); |
8274 } | |
8275 vim_free(tofree); | |
8276 } | |
8277 } | |
8278 | |
8279 /* | |
8280 * ":pwd". | |
8281 */ | |
8282 static void | |
8283 ex_pwd(eap) | |
1877 | 8284 exarg_T *eap UNUSED; |
7 | 8285 { |
8286 if (mch_dirname(NameBuff, MAXPATHL) == OK) | |
8287 { | |
8288 #ifdef BACKSLASH_IN_FILENAME | |
8289 slash_adjust(NameBuff); | |
8290 #endif | |
8291 msg(NameBuff); | |
8292 } | |
8293 else | |
8294 EMSG(_("E187: Unknown")); | |
8295 } | |
8296 | |
8297 /* | |
8298 * ":=". | |
8299 */ | |
8300 static void | |
8301 ex_equal(eap) | |
8302 exarg_T *eap; | |
8303 { | |
8304 smsg((char_u *)"%ld", (long)eap->line2); | |
167 | 8305 ex_may_print(eap); |
7 | 8306 } |
8307 | |
8308 static void | |
8309 ex_sleep(eap) | |
8310 exarg_T *eap; | |
8311 { | |
236 | 8312 int n; |
8313 long len; | |
7 | 8314 |
8315 if (cursor_valid()) | |
8316 { | |
8317 n = W_WINROW(curwin) + curwin->w_wrow - msg_scrolled; | |
8318 if (n >= 0) | |
8319 windgoto((int)n, curwin->w_wcol); | |
8320 } | |
236 | 8321 |
8322 len = eap->line2; | |
8323 switch (*eap->arg) | |
8324 { | |
8325 case 'm': break; | |
8326 case NUL: len *= 1000L; break; | |
8327 default: EMSG2(_(e_invarg2), eap->arg); return; | |
8328 } | |
8329 do_sleep(len); | |
7 | 8330 } |
8331 | |
8332 /* | |
8333 * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second. | |
8334 */ | |
8335 void | |
8336 do_sleep(msec) | |
8337 long msec; | |
8338 { | |
8339 long done; | |
8340 | |
8341 cursor_on(); | |
8342 out_flush(); | |
8343 for (done = 0; !got_int && done < msec; done += 1000L) | |
8344 { | |
8345 ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE); | |
8346 ui_breakcheck(); | |
3151 | 8347 #ifdef FEAT_NETBEANS_INTG |
8348 /* Process the netbeans messages that may have been received in the | |
8349 * call to ui_breakcheck() when the GUI is in use. This may occur when | |
8350 * running a test case. */ | |
8351 netbeans_parse_messages(); | |
8352 #endif | |
7 | 8353 } |
8354 } | |
8355 | |
8356 static void | |
8357 do_exmap(eap, isabbrev) | |
8358 exarg_T *eap; | |
8359 int isabbrev; | |
8360 { | |
8361 int mode; | |
8362 char_u *cmdp; | |
8363 | |
8364 cmdp = eap->cmd; | |
8365 mode = get_map_mode(&cmdp, eap->forceit || isabbrev); | |
8366 | |
8367 switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'), | |
8368 eap->arg, mode, isabbrev)) | |
8369 { | |
8370 case 1: EMSG(_(e_invarg)); | |
8371 break; | |
8372 case 2: EMSG(isabbrev ? _(e_noabbr) : _(e_nomap)); | |
8373 break; | |
8374 } | |
8375 } | |
8376 | |
8377 /* | |
8378 * ":winsize" command (obsolete). | |
8379 */ | |
8380 static void | |
8381 ex_winsize(eap) | |
8382 exarg_T *eap; | |
8383 { | |
8384 int w, h; | |
8385 char_u *arg = eap->arg; | |
8386 char_u *p; | |
8387 | |
8388 w = getdigits(&arg); | |
8389 arg = skipwhite(arg); | |
8390 p = arg; | |
8391 h = getdigits(&arg); | |
8392 if (*p != NUL && *arg == NUL) | |
8393 set_shellsize(w, h, TRUE); | |
8394 else | |
8395 EMSG(_("E465: :winsize requires two number arguments")); | |
8396 } | |
8397 | |
8398 #ifdef FEAT_WINDOWS | |
8399 static void | |
8400 ex_wincmd(eap) | |
8401 exarg_T *eap; | |
8402 { | |
8403 int xchar = NUL; | |
8404 char_u *p; | |
8405 | |
8406 if (*eap->arg == 'g' || *eap->arg == Ctrl_G) | |
8407 { | |
8408 /* CTRL-W g and CTRL-W CTRL-G have an extra command character */ | |
8409 if (eap->arg[1] == NUL) | |
8410 { | |
8411 EMSG(_(e_invarg)); | |
8412 return; | |
8413 } | |
8414 xchar = eap->arg[1]; | |
8415 p = eap->arg + 2; | |
8416 } | |
8417 else | |
8418 p = eap->arg + 1; | |
8419 | |
8420 eap->nextcmd = check_nextcmd(p); | |
8421 p = skipwhite(p); | |
8422 if (*p != NUL && *p != '"' && eap->nextcmd == NULL) | |
8423 EMSG(_(e_invarg)); | |
2887 | 8424 else if (!eap->skip) |
7 | 8425 { |
8426 /* Pass flags on for ":vertical wincmd ]". */ | |
8427 postponed_split_flags = cmdmod.split; | |
1090 | 8428 postponed_split_tab = cmdmod.tab; |
7 | 8429 do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar); |
8430 postponed_split_flags = 0; | |
1090 | 8431 postponed_split_tab = 0; |
7 | 8432 } |
8433 } | |
8434 #endif | |
8435 | |
11 | 8436 #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN) |
7 | 8437 /* |
8438 * ":winpos". | |
8439 */ | |
8440 static void | |
8441 ex_winpos(eap) | |
8442 exarg_T *eap; | |
8443 { | |
8444 int x, y; | |
8445 char_u *arg = eap->arg; | |
8446 char_u *p; | |
8447 | |
8448 if (*arg == NUL) | |
8449 { | |
11 | 8450 # if defined(FEAT_GUI) || defined(MSWIN) |
8451 # ifdef FEAT_GUI | |
7 | 8452 if (gui.in_use && gui_mch_get_winpos(&x, &y) != FAIL) |
11 | 8453 # else |
8454 if (mch_get_winpos(&x, &y) != FAIL) | |
8455 # endif | |
7 | 8456 { |
8457 sprintf((char *)IObuff, _("Window position: X %d, Y %d"), x, y); | |
8458 msg(IObuff); | |
8459 } | |
8460 else | |
8461 # endif | |
8462 EMSG(_("E188: Obtaining window position not implemented for this platform")); | |
8463 } | |
8464 else | |
8465 { | |
8466 x = getdigits(&arg); | |
8467 arg = skipwhite(arg); | |
8468 p = arg; | |
8469 y = getdigits(&arg); | |
8470 if (*p == NUL || *arg != NUL) | |
8471 { | |
8472 EMSG(_("E466: :winpos requires two number arguments")); | |
8473 return; | |
8474 } | |
8475 # ifdef FEAT_GUI | |
8476 if (gui.in_use) | |
8477 gui_mch_set_winpos(x, y); | |
8478 else if (gui.starting) | |
8479 { | |
8480 /* Remember the coordinates for when the window is opened. */ | |
8481 gui_win_x = x; | |
8482 gui_win_y = y; | |
8483 } | |
8484 # ifdef HAVE_TGETENT | |
8485 else | |
8486 # endif | |
11 | 8487 # else |
8488 # ifdef MSWIN | |
8489 mch_set_winpos(x, y); | |
8490 # endif | |
7 | 8491 # endif |
8492 # ifdef HAVE_TGETENT | |
8493 if (*T_CWP) | |
8494 term_set_winpos(x, y); | |
8495 # endif | |
8496 } | |
8497 } | |
8498 #endif | |
8499 | |
8500 /* | |
8501 * Handle command that work like operators: ":delete", ":yank", ":>" and ":<". | |
8502 */ | |
8503 static void | |
8504 ex_operators(eap) | |
8505 exarg_T *eap; | |
8506 { | |
8507 oparg_T oa; | |
8508 | |
8509 clear_oparg(&oa); | |
8510 oa.regname = eap->regname; | |
8511 oa.start.lnum = eap->line1; | |
8512 oa.end.lnum = eap->line2; | |
8513 oa.line_count = eap->line2 - eap->line1 + 1; | |
8514 oa.motion_type = MLINE; | |
8515 #ifdef FEAT_VIRTUALEDIT | |
8516 virtual_op = FALSE; | |
8517 #endif | |
8518 if (eap->cmdidx != CMD_yank) /* position cursor for undo */ | |
8519 { | |
8520 setpcmark(); | |
8521 curwin->w_cursor.lnum = eap->line1; | |
8522 beginline(BL_SOL | BL_FIX); | |
8523 } | |
8524 | |
8525 switch (eap->cmdidx) | |
8526 { | |
8527 case CMD_delete: | |
8528 oa.op_type = OP_DELETE; | |
8529 op_delete(&oa); | |
8530 break; | |
8531 | |
8532 case CMD_yank: | |
8533 oa.op_type = OP_YANK; | |
8534 (void)op_yank(&oa, FALSE, TRUE); | |
8535 break; | |
8536 | |
8537 default: /* CMD_rshift or CMD_lshift */ | |
8538 if ((eap->cmdidx == CMD_rshift) | |
8539 #ifdef FEAT_RIGHTLEFT | |
8540 ^ curwin->w_p_rl | |
8541 #endif | |
8542 ) | |
8543 oa.op_type = OP_RSHIFT; | |
8544 else | |
8545 oa.op_type = OP_LSHIFT; | |
8546 op_shift(&oa, FALSE, eap->amount); | |
8547 break; | |
8548 } | |
8549 #ifdef FEAT_VIRTUALEDIT | |
8550 virtual_op = MAYBE; | |
8551 #endif | |
167 | 8552 ex_may_print(eap); |
7 | 8553 } |
8554 | |
8555 /* | |
8556 * ":put". | |
8557 */ | |
8558 static void | |
8559 ex_put(eap) | |
8560 exarg_T *eap; | |
8561 { | |
8562 /* ":0put" works like ":1put!". */ | |
8563 if (eap->line2 == 0) | |
8564 { | |
8565 eap->line2 = 1; | |
8566 eap->forceit = TRUE; | |
8567 } | |
8568 curwin->w_cursor.lnum = eap->line2; | |
167 | 8569 do_put(eap->regname, eap->forceit ? BACKWARD : FORWARD, 1L, |
8570 PUT_LINE|PUT_CURSLINE); | |
7 | 8571 } |
8572 | |
8573 /* | |
8574 * Handle ":copy" and ":move". | |
8575 */ | |
8576 static void | |
8577 ex_copymove(eap) | |
8578 exarg_T *eap; | |
8579 { | |
8580 long n; | |
8581 | |
8582 n = get_address(&eap->arg, FALSE, FALSE); | |
8583 if (eap->arg == NULL) /* error detected */ | |
8584 { | |
8585 eap->nextcmd = NULL; | |
8586 return; | |
8587 } | |
167 | 8588 get_flags(eap); |
7 | 8589 |
8590 /* | |
8591 * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n' | |
8592 */ | |
8593 if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count) | |
8594 { | |
8595 EMSG(_(e_invaddr)); | |
8596 return; | |
8597 } | |
8598 | |
8599 if (eap->cmdidx == CMD_move) | |
8600 { | |
8601 if (do_move(eap->line1, eap->line2, n) == FAIL) | |
8602 return; | |
8603 } | |
8604 else | |
8605 ex_copy(eap->line1, eap->line2, n); | |
8606 u_clearline(); | |
8607 beginline(BL_SOL | BL_FIX); | |
167 | 8608 ex_may_print(eap); |
8609 } | |
8610 | |
8611 /* | |
8612 * Print the current line if flags were given to the Ex command. | |
8613 */ | |
8614 static void | |
8615 ex_may_print(eap) | |
8616 exarg_T *eap; | |
8617 { | |
8618 if (eap->flags != 0) | |
8619 { | |
8620 print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR), | |
8621 (eap->flags & EXFLAG_LIST)); | |
8622 ex_no_reprint = TRUE; | |
8623 } | |
7 | 8624 } |
8625 | |
8626 /* | |
8627 * ":smagic" and ":snomagic". | |
8628 */ | |
8629 static void | |
8630 ex_submagic(eap) | |
8631 exarg_T *eap; | |
8632 { | |
8633 int magic_save = p_magic; | |
8634 | |
8635 p_magic = (eap->cmdidx == CMD_smagic); | |
8636 do_sub(eap); | |
8637 p_magic = magic_save; | |
8638 } | |
8639 | |
8640 /* | |
8641 * ":join". | |
8642 */ | |
8643 static void | |
8644 ex_join(eap) | |
8645 exarg_T *eap; | |
8646 { | |
8647 curwin->w_cursor.lnum = eap->line1; | |
8648 if (eap->line1 == eap->line2) | |
8649 { | |
8650 if (eap->addr_count >= 2) /* :2,2join does nothing */ | |
8651 return; | |
8652 if (eap->line2 == curbuf->b_ml.ml_line_count) | |
8653 { | |
8654 beep_flush(); | |
8655 return; | |
8656 } | |
8657 ++eap->line2; | |
8658 } | |
3562 | 8659 (void)do_join(eap->line2 - eap->line1 + 1, !eap->forceit, TRUE, TRUE); |
7 | 8660 beginline(BL_WHITE | BL_FIX); |
167 | 8661 ex_may_print(eap); |
7 | 8662 } |
8663 | |
8664 /* | |
8665 * ":[addr]@r" or ":[addr]*r": execute register | |
8666 */ | |
8667 static void | |
8668 ex_at(eap) | |
8669 exarg_T *eap; | |
8670 { | |
8671 int c; | |
1973 | 8672 int prev_len = typebuf.tb_len; |
7 | 8673 |
8674 curwin->w_cursor.lnum = eap->line2; | |
8675 | |
8676 #ifdef USE_ON_FLY_SCROLL | |
8677 dont_scroll = TRUE; /* disallow scrolling here */ | |
8678 #endif | |
8679 | |
8680 /* get the register name. No name means to use the previous one */ | |
8681 c = *eap->arg; | |
8682 if (c == NUL || (c == '*' && *eap->cmd == '*')) | |
8683 c = '@'; | |
1034 | 8684 /* Put the register in the typeahead buffer with the "silent" flag. */ |
8685 if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, TRUE) | |
8686 == FAIL) | |
167 | 8687 { |
7 | 8688 beep_flush(); |
167 | 8689 } |
7 | 8690 else |
8691 { | |
8692 int save_efr = exec_from_reg; | |
8693 | |
8694 exec_from_reg = TRUE; | |
8695 | |
8696 /* | |
8697 * Execute from the typeahead buffer. | |
1973 | 8698 * Continue until the stuff buffer is empty and all added characters |
8699 * have been consumed. | |
7 | 8700 */ |
1973 | 8701 while (!stuff_empty() || typebuf.tb_len > prev_len) |
7 | 8702 (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE); |
8703 | |
8704 exec_from_reg = save_efr; | |
8705 } | |
8706 } | |
8707 | |
8708 /* | |
8709 * ":!". | |
8710 */ | |
8711 static void | |
8712 ex_bang(eap) | |
8713 exarg_T *eap; | |
8714 { | |
8715 do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE); | |
8716 } | |
8717 | |
8718 /* | |
8719 * ":undo". | |
8720 */ | |
8721 static void | |
8722 ex_undo(eap) | |
1877 | 8723 exarg_T *eap UNUSED; |
7 | 8724 { |
771 | 8725 if (eap->addr_count == 1) /* :undo 123 */ |
2281
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8726 undo_time(eap->line2, FALSE, FALSE, TRUE); |
771 | 8727 else |
8728 u_undo(1); | |
7 | 8729 } |
8730 | |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8731 #ifdef FEAT_PERSISTENT_UNDO |
2340
99c1eba60b2d
Make automatic prototype generation work with more interfaces.
Bram Moolenaar <bram@vim.org>
parents:
2333
diff
changeset
|
8732 static void |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8733 ex_wundo(eap) |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8734 exarg_T *eap; |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8735 { |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8736 char_u hash[UNDO_HASH_SIZE]; |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8737 |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8738 u_compute_hash(hash); |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8739 u_write_undo(eap->arg, eap->forceit, curbuf, hash); |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8740 } |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8741 |
2340
99c1eba60b2d
Make automatic prototype generation work with more interfaces.
Bram Moolenaar <bram@vim.org>
parents:
2333
diff
changeset
|
8742 static void |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8743 ex_rundo(eap) |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8744 exarg_T *eap; |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8745 { |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8746 char_u hash[UNDO_HASH_SIZE]; |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8747 |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8748 u_compute_hash(hash); |
2238
3d0a7beb0d75
Made reading/writing undo info a bit more robust.
Bram Moolenaar <bram@vim.org>
parents:
2215
diff
changeset
|
8749 u_read_undo(eap->arg, hash, NULL); |
2214
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8750 } |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8751 #endif |
f8222d1f9a73
Included patch for persistent undo. Lots of changes and added test.
Bram Moolenaar <bram@vim.org>
parents:
2210
diff
changeset
|
8752 |
7 | 8753 /* |
8754 * ":redo". | |
8755 */ | |
8756 static void | |
8757 ex_redo(eap) | |
1877 | 8758 exarg_T *eap UNUSED; |
7 | 8759 { |
8760 u_redo(1); | |
8761 } | |
8762 | |
8763 /* | |
756 | 8764 * ":earlier" and ":later". |
8765 */ | |
8766 static void | |
8767 ex_later(eap) | |
8768 exarg_T *eap; | |
8769 { | |
8770 long count = 0; | |
8771 int sec = FALSE; | |
2281
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8772 int file = FALSE; |
756 | 8773 char_u *p = eap->arg; |
8774 | |
8775 if (*p == NUL) | |
8776 count = 1; | |
8777 else if (isdigit(*p)) | |
8778 { | |
8779 count = getdigits(&p); | |
8780 switch (*p) | |
8781 { | |
8782 case 's': ++p; sec = TRUE; break; | |
8783 case 'm': ++p; sec = TRUE; count *= 60; break; | |
8784 case 'h': ++p; sec = TRUE; count *= 60 * 60; break; | |
2281
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8785 case 'd': ++p; sec = TRUE; count *= 24 * 60 * 60; break; |
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8786 case 'f': ++p; file = TRUE; break; |
756 | 8787 } |
8788 } | |
8789 | |
8790 if (*p != NUL) | |
8791 EMSG2(_(e_invarg2), eap->arg); | |
8792 else | |
2281
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8793 undo_time(eap->cmdidx == CMD_earlier ? -count : count, |
e41433ea71df
Added ":earlier 1f" and ":later 1f".
Bram Moolenaar <bram@vim.org>
parents:
2276
diff
changeset
|
8794 sec, file, FALSE); |
756 | 8795 } |
8796 | |
8797 /* | |
7 | 8798 * ":redir": start/stop redirection. |
8799 */ | |
8800 static void | |
8801 ex_redir(eap) | |
8802 exarg_T *eap; | |
8803 { | |
8804 char *mode; | |
8805 char_u *fname; | |
122 | 8806 char_u *arg = eap->arg; |
7 | 8807 |
8808 if (STRICMP(eap->arg, "END") == 0) | |
8809 close_redir(); | |
8810 else | |
8811 { | |
122 | 8812 if (*arg == '>') |
8813 { | |
8814 ++arg; | |
8815 if (*arg == '>') | |
8816 { | |
8817 ++arg; | |
7 | 8818 mode = "a"; |
8819 } | |
8820 else | |
8821 mode = "w"; | |
122 | 8822 arg = skipwhite(arg); |
7 | 8823 |
8824 close_redir(); | |
8825 | |
8826 /* Expand environment variables and "~/". */ | |
122 | 8827 fname = expand_env_save(arg); |
7 | 8828 if (fname == NULL) |
8829 return; | |
8830 #ifdef FEAT_BROWSE | |
8831 if (cmdmod.browse) | |
8832 { | |
8833 char_u *browseFile; | |
8834 | |
28 | 8835 browseFile = do_browse(BROWSE_SAVE, |
8836 (char_u *)_("Save Redirection"), | |
8837 fname, NULL, NULL, BROWSE_FILTER_ALL_FILES, curbuf); | |
7 | 8838 if (browseFile == NULL) |
8839 return; /* operation cancelled */ | |
8840 vim_free(fname); | |
8841 fname = browseFile; | |
8842 eap->forceit = TRUE; /* since dialog already asked */ | |
8843 } | |
8844 #endif | |
8845 | |
8846 redir_fd = open_exfile(fname, eap->forceit, mode); | |
8847 vim_free(fname); | |
8848 } | |
8849 #ifdef FEAT_EVAL | |
122 | 8850 else if (*arg == '@') |
7 | 8851 { |
8852 /* redirect to a register a-z (resp. A-Z for appending) */ | |
8853 close_redir(); | |
122 | 8854 ++arg; |
8855 if (ASCII_ISALPHA(*arg) | |
7 | 8856 # ifdef FEAT_CLIPBOARD |
122 | 8857 || *arg == '*' |
1038 | 8858 || *arg == '+' |
7 | 8859 # endif |
122 | 8860 || *arg == '"') |
8861 { | |
8862 redir_reg = *arg++; | |
1427 | 8863 if (*arg == '>' && arg[1] == '>') /* append */ |
268 | 8864 arg += 2; |
1427 | 8865 else |
7 | 8866 { |
1427 | 8867 /* Can use both "@a" and "@a>". */ |
296 | 8868 if (*arg == '>') |
8869 arg++; | |
1427 | 8870 /* Make register empty when not using @A-@Z and the |
8871 * command is valid. */ | |
8872 if (*arg == NUL && !isupper(redir_reg)) | |
8873 write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); | |
7 | 8874 } |
167 | 8875 } |
8876 if (*arg != NUL) | |
8877 { | |
268 | 8878 redir_reg = 0; |
167 | 8879 EMSG2(_(e_invarg2), eap->arg); |
8880 } | |
8881 } | |
8882 else if (*arg == '=' && arg[1] == '>') | |
8883 { | |
8884 int append; | |
8885 | |
8886 /* redirect to a variable */ | |
8887 close_redir(); | |
8888 arg += 2; | |
8889 | |
8890 if (*arg == '>') | |
8891 { | |
8892 ++arg; | |
8893 append = TRUE; | |
7 | 8894 } |
8895 else | |
167 | 8896 append = FALSE; |
8897 | |
8898 if (var_redir_start(skipwhite(arg), append) == OK) | |
8899 redir_vname = 1; | |
7 | 8900 } |
8901 #endif | |
8902 | |
8903 /* TODO: redirect to a buffer */ | |
8904 | |
8905 else | |
122 | 8906 EMSG2(_(e_invarg2), eap->arg); |
7 | 8907 } |
972 | 8908 |
8909 /* Make sure redirection is not off. Can happen for cmdline completion | |
8910 * that indirectly invokes a command to catch its output. */ | |
8911 if (redir_fd != NULL | |
8912 #ifdef FEAT_EVAL | |
8913 || redir_reg || redir_vname | |
8914 #endif | |
8915 ) | |
8916 redir_off = FALSE; | |
7 | 8917 } |
8918 | |
8919 /* | |
8920 * ":redraw": force redraw | |
8921 */ | |
8922 static void | |
8923 ex_redraw(eap) | |
8924 exarg_T *eap; | |
8925 { | |
8926 int r = RedrawingDisabled; | |
8927 int p = p_lz; | |
8928 | |
8929 RedrawingDisabled = 0; | |
8930 p_lz = FALSE; | |
8931 update_topline(); | |
8932 update_screen(eap->forceit ? CLEAR : | |
8933 #ifdef FEAT_VISUAL | |
8934 VIsual_active ? INVERTED : | |
8935 #endif | |
8936 0); | |
8937 #ifdef FEAT_TITLE | |
8938 if (need_maketitle) | |
8939 maketitle(); | |
8940 #endif | |
8941 RedrawingDisabled = r; | |
8942 p_lz = p; | |
8943 | |
8944 /* Reset msg_didout, so that a message that's there is overwritten. */ | |
8945 msg_didout = FALSE; | |
8946 msg_col = 0; | |
8947 | |
8948 out_flush(); | |
8949 } | |
8950 | |
8951 /* | |
8952 * ":redrawstatus": force redraw of status line(s) | |
8953 */ | |
8954 static void | |
8955 ex_redrawstatus(eap) | |
1877 | 8956 exarg_T *eap UNUSED; |
7 | 8957 { |
8958 #if defined(FEAT_WINDOWS) | |
8959 int r = RedrawingDisabled; | |
8960 int p = p_lz; | |
8961 | |
8962 RedrawingDisabled = 0; | |
8963 p_lz = FALSE; | |
8964 if (eap->forceit) | |
8965 status_redraw_all(); | |
8966 else | |
8967 status_redraw_curbuf(); | |
8968 update_screen( | |
8969 # ifdef FEAT_VISUAL | |
8970 VIsual_active ? INVERTED : | |
8971 # endif | |
8972 0); | |
8973 RedrawingDisabled = r; | |
8974 p_lz = p; | |
8975 out_flush(); | |
8976 #endif | |
8977 } | |
8978 | |
8979 static void | |
8980 close_redir() | |
8981 { | |
8982 if (redir_fd != NULL) | |
8983 { | |
8984 fclose(redir_fd); | |
8985 redir_fd = NULL; | |
8986 } | |
8987 #ifdef FEAT_EVAL | |
8988 redir_reg = 0; | |
167 | 8989 if (redir_vname) |
8990 { | |
8991 var_redir_stop(); | |
8992 redir_vname = 0; | |
8993 } | |
7 | 8994 #endif |
8995 } | |
8996 | |
8997 #if defined(FEAT_SESSION) && defined(USE_CRNL) | |
8998 # define MKSESSION_NL | |
8999 static int mksession_nl = FALSE; /* use NL only in put_eol() */ | |
9000 #endif | |
9001 | |
9002 /* | |
9003 * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". | |
9004 */ | |
9005 static void | |
9006 ex_mkrc(eap) | |
9007 exarg_T *eap; | |
9008 { | |
9009 FILE *fd; | |
9010 int failed = FALSE; | |
9011 char_u *fname; | |
9012 #ifdef FEAT_BROWSE | |
9013 char_u *browseFile = NULL; | |
9014 #endif | |
9015 #ifdef FEAT_SESSION | |
9016 int view_session = FALSE; | |
9017 int using_vdir = FALSE; /* using 'viewdir'? */ | |
9018 char_u *viewFile = NULL; | |
9019 unsigned *flagp; | |
9020 #endif | |
9021 | |
9022 if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) | |
9023 { | |
9024 #ifdef FEAT_SESSION | |
9025 view_session = TRUE; | |
9026 #else | |
9027 ex_ni(eap); | |
9028 return; | |
9029 #endif | |
9030 } | |
9031 | |
9032 #ifdef FEAT_SESSION | |
1925 | 9033 /* Use the short file name until ":lcd" is used. We also don't use the |
9034 * short file name when 'acd' is set, that is checked later. */ | |
1113 | 9035 did_lcd = FALSE; |
9036 | |
7 | 9037 /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */ |
9038 if (eap->cmdidx == CMD_mkview | |
9039 && (*eap->arg == NUL | |
9040 || (vim_isdigit(*eap->arg) && eap->arg[1] == NUL))) | |
9041 { | |
9042 eap->forceit = TRUE; | |
9043 fname = get_view_file(*eap->arg); | |
9044 if (fname == NULL) | |
9045 return; | |
9046 viewFile = fname; | |
9047 using_vdir = TRUE; | |
9048 } | |
9049 else | |
9050 #endif | |
9051 if (*eap->arg != NUL) | |
9052 fname = eap->arg; | |
9053 else if (eap->cmdidx == CMD_mkvimrc) | |
9054 fname = (char_u *)VIMRC_FILE; | |
9055 #ifdef FEAT_SESSION | |
9056 else if (eap->cmdidx == CMD_mksession) | |
9057 fname = (char_u *)SESSION_FILE; | |
9058 #endif | |
9059 else | |
9060 fname = (char_u *)EXRC_FILE; | |
9061 | |
9062 #ifdef FEAT_BROWSE | |
9063 if (cmdmod.browse) | |
9064 { | |
28 | 9065 browseFile = do_browse(BROWSE_SAVE, |
7 | 9066 # ifdef FEAT_SESSION |
9067 eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") : | |
9068 eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") : | |
9069 # endif | |
9070 (char_u *)_("Save Setup"), | |
9071 fname, (char_u *)"vim", NULL, BROWSE_FILTER_MACROS, NULL); | |
9072 if (browseFile == NULL) | |
9073 goto theend; | |
9074 fname = browseFile; | |
9075 eap->forceit = TRUE; /* since dialog already asked */ | |
9076 } | |
9077 #endif | |
9078 | |
9079 #if defined(FEAT_SESSION) && defined(vim_mkdir) | |
9080 /* When using 'viewdir' may have to create the directory. */ | |
9081 if (using_vdir && !mch_isdir(p_vdir)) | |
167 | 9082 vim_mkdir_emsg(p_vdir, 0755); |
7 | 9083 #endif |
9084 | |
9085 fd = open_exfile(fname, eap->forceit, WRITEBIN); | |
9086 if (fd != NULL) | |
9087 { | |
9088 #ifdef FEAT_SESSION | |
9089 if (eap->cmdidx == CMD_mkview) | |
9090 flagp = &vop_flags; | |
9091 else | |
9092 flagp = &ssop_flags; | |
9093 #endif | |
9094 | |
9095 #ifdef MKSESSION_NL | |
9096 /* "unix" in 'sessionoptions': use NL line separator */ | |
9097 if (view_session && (*flagp & SSOP_UNIX)) | |
9098 mksession_nl = TRUE; | |
9099 #endif | |
9100 | |
9101 /* Write the version command for :mkvimrc */ | |
9102 if (eap->cmdidx == CMD_mkvimrc) | |
9103 (void)put_line(fd, "version 6.0"); | |
9104 | |
9105 #ifdef FEAT_SESSION | |
573 | 9106 if (eap->cmdidx == CMD_mksession) |
9107 { | |
9108 if (put_line(fd, "let SessionLoad = 1") == FAIL) | |
9109 failed = TRUE; | |
9110 } | |
9111 | |
7 | 9112 if (eap->cmdidx != CMD_mkview) |
9113 #endif | |
9114 { | |
9115 /* Write setting 'compatible' first, because it has side effects. | |
9116 * For that same reason only do it when needed. */ | |
9117 if (p_cp) | |
9118 (void)put_line(fd, "if !&cp | set cp | endif"); | |
9119 else | |
9120 (void)put_line(fd, "if &cp | set nocp | endif"); | |
9121 } | |
9122 | |
9123 #ifdef FEAT_SESSION | |
9124 if (!view_session | |
9125 || (eap->cmdidx == CMD_mksession | |
9126 && (*flagp & SSOP_OPTIONS))) | |
9127 #endif | |
9128 failed |= (makemap(fd, NULL) == FAIL | |
9129 || makeset(fd, OPT_GLOBAL, FALSE) == FAIL); | |
9130 | |
9131 #ifdef FEAT_SESSION | |
9132 if (!failed && view_session) | |
9133 { | |
9134 if (put_line(fd, "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") == FAIL) | |
9135 failed = TRUE; | |
9136 if (eap->cmdidx == CMD_mksession) | |
9137 { | |
2770 | 9138 char_u *dirnow; /* current directory */ |
9139 | |
9140 dirnow = alloc(MAXPATHL); | |
9141 if (dirnow == NULL) | |
9142 failed = TRUE; | |
9143 else | |
9144 { | |
9145 /* | |
9146 * Change to session file's dir. | |
9147 */ | |
9148 if (mch_dirname(dirnow, MAXPATHL) == FAIL | |
7 | 9149 || mch_chdir((char *)dirnow) != 0) |
2770 | 9150 *dirnow = NUL; |
9151 if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) | |
9152 { | |
9153 if (vim_chdirfile(fname) == OK) | |
9154 shorten_fnames(TRUE); | |
9155 } | |
9156 else if (*dirnow != NUL | |
9157 && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) | |
9158 { | |
9159 if (mch_chdir((char *)globaldir) == 0) | |
9160 shorten_fnames(TRUE); | |
9161 } | |
9162 | |
9163 failed |= (makeopens(fd, dirnow) == FAIL); | |
9164 | |
9165 /* restore original dir */ | |
9166 if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) | |
9167 || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL))) | |
9168 { | |
9169 if (mch_chdir((char *)dirnow) != 0) | |
9170 EMSG(_(e_prev_dir)); | |
7 | 9171 shorten_fnames(TRUE); |
2770 | 9172 } |
9173 vim_free(dirnow); | |
7 | 9174 } |
9175 } | |
9176 else | |
9177 { | |
1467 | 9178 failed |= (put_view(fd, curwin, !using_vdir, flagp, |
9179 -1) == FAIL); | |
7 | 9180 } |
9181 if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save") | |
9182 == FAIL) | |
9183 failed = TRUE; | |
573 | 9184 if (put_line(fd, "doautoall SessionLoadPost") == FAIL) |
9185 failed = TRUE; | |
625 | 9186 if (eap->cmdidx == CMD_mksession) |
9187 { | |
9188 if (put_line(fd, "unlet SessionLoad") == FAIL) | |
9189 failed = TRUE; | |
9190 } | |
573 | 9191 } |
9192 #endif | |
9193 if (put_line(fd, "\" vim: set ft=vim :") == FAIL) | |
9194 failed = TRUE; | |
9195 | |
7 | 9196 failed |= fclose(fd); |
9197 | |
9198 if (failed) | |
9199 EMSG(_(e_write)); | |
9200 #if defined(FEAT_EVAL) && defined(FEAT_SESSION) | |
9201 else if (eap->cmdidx == CMD_mksession) | |
9202 { | |
9203 /* successful session write - set this_session var */ | |
2770 | 9204 char_u *tbuf; |
9205 | |
9206 tbuf = alloc(MAXPATHL); | |
9207 if (tbuf != NULL) | |
9208 { | |
9209 if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK) | |
9210 set_vim_var_string(VV_THIS_SESSION, tbuf, -1); | |
9211 vim_free(tbuf); | |
9212 } | |
7 | 9213 } |
9214 #endif | |
9215 #ifdef MKSESSION_NL | |
9216 mksession_nl = FALSE; | |
9217 #endif | |
9218 } | |
9219 | |
9220 #ifdef FEAT_BROWSE | |
9221 theend: | |
9222 vim_free(browseFile); | |
9223 #endif | |
9224 #ifdef FEAT_SESSION | |
9225 vim_free(viewFile); | |
9226 #endif | |
9227 } | |
9228 | |
167 | 9229 #if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \ |
9230 || defined(PROTO) | |
9231 int | |
9232 vim_mkdir_emsg(name, prot) | |
9233 char_u *name; | |
1877 | 9234 int prot UNUSED; |
167 | 9235 { |
9236 if (vim_mkdir(name, prot) != 0) | |
9237 { | |
9238 EMSG2(_("E739: Cannot create directory: %s"), name); | |
9239 return FAIL; | |
9240 } | |
9241 return OK; | |
9242 } | |
9243 #endif | |
9244 | |
7 | 9245 /* |
9246 * Open a file for writing for an Ex command, with some checks. | |
9247 * Return file descriptor, or NULL on failure. | |
9248 */ | |
9249 FILE * | |
9250 open_exfile(fname, forceit, mode) | |
9251 char_u *fname; | |
9252 int forceit; | |
9253 char *mode; /* "w" for create new file or "a" for append */ | |
9254 { | |
9255 FILE *fd; | |
9256 | |
9257 #ifdef UNIX | |
9258 /* with Unix it is possible to open a directory */ | |
9259 if (mch_isdir(fname)) | |
9260 { | |
9261 EMSG2(_(e_isadir2), fname); | |
9262 return NULL; | |
9263 } | |
9264 #endif | |
9265 if (!forceit && *mode != 'a' && vim_fexists(fname)) | |
9266 { | |
9267 EMSG2(_("E189: \"%s\" exists (add ! to override)"), fname); | |
9268 return NULL; | |
9269 } | |
9270 | |
9271 if ((fd = mch_fopen((char *)fname, mode)) == NULL) | |
9272 EMSG2(_("E190: Cannot open \"%s\" for writing"), fname); | |
9273 | |
9274 return fd; | |
9275 } | |
9276 | |
9277 /* | |
9278 * ":mark" and ":k". | |
9279 */ | |
9280 static void | |
9281 ex_mark(eap) | |
9282 exarg_T *eap; | |
9283 { | |
9284 pos_T pos; | |
9285 | |
9286 if (*eap->arg == NUL) /* No argument? */ | |
9287 EMSG(_(e_argreq)); | |
9288 else if (eap->arg[1] != NUL) /* more than one character? */ | |
9289 EMSG(_(e_trailing)); | |
9290 else | |
9291 { | |
9292 pos = curwin->w_cursor; /* save curwin->w_cursor */ | |
9293 curwin->w_cursor.lnum = eap->line2; | |
9294 beginline(BL_WHITE | BL_FIX); | |
9295 if (setmark(*eap->arg) == FAIL) /* set mark */ | |
9296 EMSG(_("E191: Argument must be a letter or forward/backward quote")); | |
9297 curwin->w_cursor = pos; /* restore curwin->w_cursor */ | |
9298 } | |
9299 } | |
9300 | |
9301 /* | |
9302 * Update w_topline, w_leftcol and the cursor position. | |
9303 */ | |
9304 void | |
9305 update_topline_cursor() | |
9306 { | |
9307 check_cursor(); /* put cursor on valid line */ | |
9308 update_topline(); | |
9309 if (!curwin->w_p_wrap) | |
9310 validate_cursor(); | |
9311 update_curswant(); | |
9312 } | |
9313 | |
9314 #ifdef FEAT_EX_EXTRA | |
9315 /* | |
9316 * ":normal[!] {commands}": Execute normal mode commands. | |
9317 */ | |
9318 static void | |
9319 ex_normal(eap) | |
9320 exarg_T *eap; | |
9321 { | |
9322 int save_msg_scroll = msg_scroll; | |
9323 int save_restart_edit = restart_edit; | |
9324 int save_msg_didout = msg_didout; | |
9325 int save_State = State; | |
9326 tasave_T tabuf; | |
9327 int save_insertmode = p_im; | |
9328 int save_finish_op = finish_op; | |
1689 | 9329 int save_opcount = opcount; |
7 | 9330 #ifdef FEAT_MBYTE |
9331 char_u *arg = NULL; | |
9332 int l; | |
9333 char_u *p; | |
9334 #endif | |
9335 | |
856 | 9336 if (ex_normal_lock > 0) |
9337 { | |
9338 EMSG(_(e_secure)); | |
9339 return; | |
9340 } | |
7 | 9341 if (ex_normal_busy >= p_mmd) |
9342 { | |
9343 EMSG(_("E192: Recursive use of :normal too deep")); | |
9344 return; | |
9345 } | |
9346 ++ex_normal_busy; | |
9347 | |
9348 msg_scroll = FALSE; /* no msg scrolling in Normal mode */ | |
9349 restart_edit = 0; /* don't go to Insert mode */ | |
9350 p_im = FALSE; /* don't use 'insertmode' */ | |
9351 | |
9352 #ifdef FEAT_MBYTE | |
9353 /* | |
9354 * vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do | |
9355 * this for the K_SPECIAL leading byte, otherwise special keys will not | |
9356 * work. | |
9357 */ | |
9358 if (has_mbyte) | |
9359 { | |
9360 int len = 0; | |
9361 | |
9362 /* Count the number of characters to be escaped. */ | |
9363 for (p = eap->arg; *p != NUL; ++p) | |
9364 { | |
9365 # ifdef FEAT_GUI | |
9366 if (*p == CSI) /* leadbyte CSI */ | |
9367 len += 2; | |
9368 # endif | |
474 | 9369 for (l = (*mb_ptr2len)(p) - 1; l > 0; --l) |
7 | 9370 if (*++p == K_SPECIAL /* trailbyte K_SPECIAL or CSI */ |
9371 # ifdef FEAT_GUI | |
9372 || *p == CSI | |
9373 # endif | |
9374 ) | |
9375 len += 2; | |
9376 } | |
9377 if (len > 0) | |
9378 { | |
9379 arg = alloc((unsigned)(STRLEN(eap->arg) + len + 1)); | |
9380 if (arg != NULL) | |
9381 { | |
9382 len = 0; | |
9383 for (p = eap->arg; *p != NUL; ++p) | |
9384 { | |
9385 arg[len++] = *p; | |
9386 # ifdef FEAT_GUI | |
9387 if (*p == CSI) | |
9388 { | |
9389 arg[len++] = KS_EXTRA; | |
9390 arg[len++] = (int)KE_CSI; | |
9391 } | |
9392 # endif | |
474 | 9393 for (l = (*mb_ptr2len)(p) - 1; l > 0; --l) |
7 | 9394 { |
9395 arg[len++] = *++p; | |
9396 if (*p == K_SPECIAL) | |
9397 { | |
9398 arg[len++] = KS_SPECIAL; | |
9399 arg[len++] = KE_FILLER; | |
9400 } | |
9401 # ifdef FEAT_GUI | |
9402 else if (*p == CSI) | |
9403 { | |
9404 arg[len++] = KS_EXTRA; | |
9405 arg[len++] = (int)KE_CSI; | |
9406 } | |
9407 # endif | |
9408 } | |
9409 arg[len] = NUL; | |
9410 } | |
9411 } | |
9412 } | |
9413 } | |
9414 #endif | |
9415 | |
9416 /* | |
9417 * Save the current typeahead. This is required to allow using ":normal" | |
9418 * from an event handler and makes sure we don't hang when the argument | |
9419 * ends with half a command. | |
9420 */ | |
9421 save_typeahead(&tabuf); | |
9422 if (tabuf.typebuf_valid) | |
9423 { | |
9424 /* | |
9425 * Repeat the :normal command for each line in the range. When no | |
9426 * range given, execute it just once, without positioning the cursor | |
9427 * first. | |
9428 */ | |
9429 do | |
9430 { | |
9431 if (eap->addr_count != 0) | |
9432 { | |
9433 curwin->w_cursor.lnum = eap->line1++; | |
9434 curwin->w_cursor.col = 0; | |
9435 } | |
9436 | |
36 | 9437 exec_normal_cmd( |
7 | 9438 #ifdef FEAT_MBYTE |
9439 arg != NULL ? arg : | |
9440 #endif | |
36 | 9441 eap->arg, eap->forceit ? REMAP_NONE : REMAP_YES, FALSE); |
7 | 9442 } |
9443 while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int); | |
9444 } | |
9445 | |
9446 /* Might not return to the main loop when in an event handler. */ | |
9447 update_topline_cursor(); | |
9448 | |
9449 /* Restore the previous typeahead. */ | |
9450 restore_typeahead(&tabuf); | |
9451 | |
9452 --ex_normal_busy; | |
9453 msg_scroll = save_msg_scroll; | |
9454 restart_edit = save_restart_edit; | |
9455 p_im = save_insertmode; | |
9456 finish_op = save_finish_op; | |
1689 | 9457 opcount = save_opcount; |
7 | 9458 msg_didout |= save_msg_didout; /* don't reset msg_didout now */ |
9459 | |
9460 /* Restore the state (needed when called from a function executed for | |
9461 * 'indentexpr'). */ | |
9462 State = save_State; | |
9463 #ifdef FEAT_MBYTE | |
9464 vim_free(arg); | |
9465 #endif | |
9466 } | |
9467 | |
9468 /* | |
598 | 9469 * ":startinsert", ":startreplace" and ":startgreplace" |
7 | 9470 */ |
9471 static void | |
9472 ex_startinsert(eap) | |
9473 exarg_T *eap; | |
9474 { | |
98 | 9475 if (eap->forceit) |
9476 { | |
9477 coladvance((colnr_T)MAXCOL); | |
9478 curwin->w_curswant = MAXCOL; | |
9479 curwin->w_set_curswant = FALSE; | |
9480 } | |
9481 | |
89 | 9482 /* Ignore the command when already in Insert mode. Inserting an |
9483 * expression register that invokes a function can do this. */ | |
9484 if (State & INSERT) | |
9485 return; | |
9486 | |
598 | 9487 if (eap->cmdidx == CMD_startinsert) |
9488 restart_edit = 'a'; | |
9489 else if (eap->cmdidx == CMD_startreplace) | |
9490 restart_edit = 'R'; | |
7 | 9491 else |
598 | 9492 restart_edit = 'V'; |
9493 | |
9494 if (!eap->forceit) | |
7 | 9495 { |
14 | 9496 if (eap->cmdidx == CMD_startinsert) |
9497 restart_edit = 'i'; | |
7 | 9498 curwin->w_curswant = 0; /* avoid MAXCOL */ |
9499 } | |
9500 } | |
9501 | |
9502 /* | |
9503 * ":stopinsert" | |
9504 */ | |
9505 static void | |
9506 ex_stopinsert(eap) | |
1880 | 9507 exarg_T *eap UNUSED; |
7 | 9508 { |
9509 restart_edit = 0; | |
9510 stop_insert_mode = TRUE; | |
9511 } | |
9512 #endif | |
9513 | |
36 | 9514 #if defined(FEAT_EX_EXTRA) || defined(FEAT_MENU) || defined(PROTO) |
9515 /* | |
9516 * Execute normal mode command "cmd". | |
9517 * "remap" can be REMAP_NONE or REMAP_YES. | |
9518 */ | |
9519 void | |
9520 exec_normal_cmd(cmd, remap, silent) | |
9521 char_u *cmd; | |
9522 int remap; | |
9523 int silent; | |
9524 { | |
9525 oparg_T oa; | |
9526 | |
9527 /* | |
9528 * Stuff the argument into the typeahead buffer. | |
9529 * Execute normal_cmd() until there is no typeahead left. | |
9530 */ | |
9531 clear_oparg(&oa); | |
9532 finish_op = FALSE; | |
9533 ins_typebuf(cmd, remap, 0, TRUE, silent); | |
9534 while ((!stuff_empty() || (!typebuf_typed() && typebuf.tb_len > 0)) | |
9535 && !got_int) | |
9536 { | |
9537 update_topline_cursor(); | |
2682 | 9538 normal_cmd(&oa, TRUE); /* execute a Normal mode cmd */ |
36 | 9539 } |
9540 } | |
9541 #endif | |
9542 | |
7 | 9543 #ifdef FEAT_FIND_ID |
9544 static void | |
9545 ex_checkpath(eap) | |
9546 exarg_T *eap; | |
9547 { | |
9548 find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L, | |
9549 eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, | |
9550 (linenr_T)1, (linenr_T)MAXLNUM); | |
9551 } | |
9552 | |
9553 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) | |
9554 /* | |
9555 * ":psearch" | |
9556 */ | |
9557 static void | |
9558 ex_psearch(eap) | |
9559 exarg_T *eap; | |
9560 { | |
9561 g_do_tagpreview = p_pvh; | |
9562 ex_findpat(eap); | |
9563 g_do_tagpreview = 0; | |
9564 } | |
9565 #endif | |
9566 | |
9567 static void | |
9568 ex_findpat(eap) | |
9569 exarg_T *eap; | |
9570 { | |
9571 int whole = TRUE; | |
9572 long n; | |
9573 char_u *p; | |
9574 int action; | |
9575 | |
9576 switch (cmdnames[eap->cmdidx].cmd_name[2]) | |
9577 { | |
9578 case 'e': /* ":psearch", ":isearch" and ":dsearch" */ | |
9579 if (cmdnames[eap->cmdidx].cmd_name[0] == 'p') | |
9580 action = ACTION_GOTO; | |
9581 else | |
9582 action = ACTION_SHOW; | |
9583 break; | |
9584 case 'i': /* ":ilist" and ":dlist" */ | |
9585 action = ACTION_SHOW_ALL; | |
9586 break; | |
9587 case 'u': /* ":ijump" and ":djump" */ | |
9588 action = ACTION_GOTO; | |
9589 break; | |
9590 default: /* ":isplit" and ":dsplit" */ | |
9591 action = ACTION_SPLIT; | |
9592 break; | |
9593 } | |
9594 | |
9595 n = 1; | |
9596 if (vim_isdigit(*eap->arg)) /* get count */ | |
9597 { | |
9598 n = getdigits(&eap->arg); | |
9599 eap->arg = skipwhite(eap->arg); | |
9600 } | |
9601 if (*eap->arg == '/') /* Match regexp, not just whole words */ | |
9602 { | |
9603 whole = FALSE; | |
9604 ++eap->arg; | |
9605 p = skip_regexp(eap->arg, '/', p_magic, NULL); | |
9606 if (*p) | |
9607 { | |
9608 *p++ = NUL; | |
9609 p = skipwhite(p); | |
9610 | |
9611 /* Check for trailing illegal characters */ | |
9612 if (!ends_excmd(*p)) | |
9613 eap->errmsg = e_trailing; | |
9614 else | |
9615 eap->nextcmd = check_nextcmd(p); | |
9616 } | |
9617 } | |
9618 if (!eap->skip) | |
9619 find_pattern_in_path(eap->arg, 0, (int)STRLEN(eap->arg), | |
9620 whole, !eap->forceit, | |
9621 *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, | |
9622 n, action, eap->line1, eap->line2); | |
9623 } | |
9624 #endif | |
9625 | |
9626 #ifdef FEAT_WINDOWS | |
9627 | |
9628 # ifdef FEAT_QUICKFIX | |
9629 /* | |
9630 * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc. | |
9631 */ | |
9632 static void | |
9633 ex_ptag(eap) | |
9634 exarg_T *eap; | |
9635 { | |
2633 | 9636 g_do_tagpreview = p_pvh; /* will be reset to 0 in ex_tag_cmd() */ |
7 | 9637 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); |
9638 } | |
9639 | |
9640 /* | |
9641 * ":pedit" | |
9642 */ | |
9643 static void | |
9644 ex_pedit(eap) | |
9645 exarg_T *eap; | |
9646 { | |
9647 win_T *curwin_save = curwin; | |
9648 | |
9649 g_do_tagpreview = p_pvh; | |
815 | 9650 prepare_tagpreview(TRUE); |
7 | 9651 keep_help_flag = curwin_save->w_buffer->b_help; |
9652 do_exedit(eap, NULL); | |
9653 keep_help_flag = FALSE; | |
9654 if (curwin != curwin_save && win_valid(curwin_save)) | |
9655 { | |
9656 /* Return cursor to where we were */ | |
9657 validate_cursor(); | |
9658 redraw_later(VALID); | |
9659 win_enter(curwin_save, TRUE); | |
9660 } | |
9661 g_do_tagpreview = 0; | |
9662 } | |
9663 # endif | |
9664 | |
9665 /* | |
9666 * ":stag", ":stselect" and ":stjump". | |
9667 */ | |
9668 static void | |
9669 ex_stag(eap) | |
9670 exarg_T *eap; | |
9671 { | |
9672 postponed_split = -1; | |
9673 postponed_split_flags = cmdmod.split; | |
1090 | 9674 postponed_split_tab = cmdmod.tab; |
7 | 9675 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); |
9676 postponed_split_flags = 0; | |
1090 | 9677 postponed_split_tab = 0; |
7 | 9678 } |
9679 #endif | |
9680 | |
9681 /* | |
9682 * ":tag", ":tselect", ":tjump", ":tnext", etc. | |
9683 */ | |
9684 static void | |
9685 ex_tag(eap) | |
9686 exarg_T *eap; | |
9687 { | |
9688 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name); | |
9689 } | |
9690 | |
9691 static void | |
9692 ex_tag_cmd(eap, name) | |
9693 exarg_T *eap; | |
9694 char_u *name; | |
9695 { | |
9696 int cmd; | |
9697 | |
9698 switch (name[1]) | |
9699 { | |
9700 case 'j': cmd = DT_JUMP; /* ":tjump" */ | |
9701 break; | |
9702 case 's': cmd = DT_SELECT; /* ":tselect" */ | |
9703 break; | |
9704 case 'p': cmd = DT_PREV; /* ":tprevious" */ | |
9705 break; | |
9706 case 'N': cmd = DT_PREV; /* ":tNext" */ | |
9707 break; | |
9708 case 'n': cmd = DT_NEXT; /* ":tnext" */ | |
9709 break; | |
9710 case 'o': cmd = DT_POP; /* ":pop" */ | |
9711 break; | |
9712 case 'f': /* ":tfirst" */ | |
9713 case 'r': cmd = DT_FIRST; /* ":trewind" */ | |
9714 break; | |
9715 case 'l': cmd = DT_LAST; /* ":tlast" */ | |
9716 break; | |
9717 default: /* ":tag" */ | |
9718 #ifdef FEAT_CSCOPE | |
1603 | 9719 if (p_cst && *eap->arg != NUL) |
7 | 9720 { |
9721 do_cstag(eap); | |
9722 return; | |
9723 } | |
9724 #endif | |
9725 cmd = DT_TAG; | |
9726 break; | |
9727 } | |
9728 | |
649 | 9729 if (name[0] == 'l') |
9730 { | |
9731 #ifndef FEAT_QUICKFIX | |
9732 ex_ni(eap); | |
9733 return; | |
9734 #else | |
9735 cmd = DT_LTAG; | |
9736 #endif | |
9737 } | |
9738 | |
7 | 9739 do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, |
9740 eap->forceit, TRUE); | |
9741 } | |
9742 | |
9743 /* | |
1661 | 9744 * Check "str" for starting with a special cmdline variable. |
9745 * If found return one of the SPEC_ values and set "*usedlen" to the length of | |
9746 * the variable. Otherwise return -1 and "*usedlen" is unchanged. | |
9747 */ | |
9748 int | |
9749 find_cmdline_var(src, usedlen) | |
9750 char_u *src; | |
9751 int *usedlen; | |
9752 { | |
9753 int len; | |
9754 int i; | |
1879 | 9755 static char *(spec_str[]) = { |
1661 | 9756 "%", |
9757 #define SPEC_PERC 0 | |
9758 "#", | |
9759 #define SPEC_HASH 1 | |
9760 "<cword>", /* cursor word */ | |
9761 #define SPEC_CWORD 2 | |
9762 "<cWORD>", /* cursor WORD */ | |
9763 #define SPEC_CCWORD 3 | |
9764 "<cfile>", /* cursor path name */ | |
9765 #define SPEC_CFILE 4 | |
9766 "<sfile>", /* ":so" file name */ | |
9767 #define SPEC_SFILE 5 | |
2645 | 9768 "<slnum>", /* ":so" file line number */ |
9769 #define SPEC_SLNUM 6 | |
1661 | 9770 #ifdef FEAT_AUTOCMD |
9771 "<afile>", /* autocommand file name */ | |
2645 | 9772 # define SPEC_AFILE 7 |
1661 | 9773 "<abuf>", /* autocommand buffer number */ |
2645 | 9774 # define SPEC_ABUF 8 |
1661 | 9775 "<amatch>", /* autocommand match name */ |
2645 | 9776 # define SPEC_AMATCH 9 |
1661 | 9777 #endif |
9778 #ifdef FEAT_CLIENTSERVER | |
9779 "<client>" | |
2645 | 9780 # ifdef FEAT_AUTOCMD |
9781 # define SPEC_CLIENT 10 | |
9782 # else | |
9783 # define SPEC_CLIENT 7 | |
9784 # endif | |
1661 | 9785 #endif |
9786 }; | |
1872 | 9787 |
9788 for (i = 0; i < (int)(sizeof(spec_str) / sizeof(char *)); ++i) | |
1661 | 9789 { |
9790 len = (int)STRLEN(spec_str[i]); | |
9791 if (STRNCMP(src, spec_str[i], len) == 0) | |
9792 { | |
9793 *usedlen = len; | |
9794 return i; | |
9795 } | |
9796 } | |
9797 return -1; | |
9798 } | |
9799 | |
9800 /* | |
7 | 9801 * Evaluate cmdline variables. |
9802 * | |
9803 * change '%' to curbuf->b_ffname | |
9804 * '#' to curwin->w_altfile | |
9805 * '<cword>' to word under the cursor | |
9806 * '<cWORD>' to WORD under the cursor | |
9807 * '<cfile>' to path name under the cursor | |
9808 * '<sfile>' to sourced file name | |
2645 | 9809 * '<slnum>' to sourced file line number |
7 | 9810 * '<afile>' to file name for autocommand |
9811 * '<abuf>' to buffer number for autocommand | |
9812 * '<amatch>' to matching name for autocommand | |
9813 * | |
9814 * When an error is detected, "errormsg" is set to a non-NULL pointer (may be | |
9815 * "" for error without a message) and NULL is returned. | |
9816 * Returns an allocated string if a valid match was found. | |
9817 * Returns NULL if no match was found. "usedlen" then still contains the | |
9818 * number of characters to skip. | |
9819 */ | |
9820 char_u * | |
1098 | 9821 eval_vars(src, srcstart, usedlen, lnump, errormsg, escaped) |
7 | 9822 char_u *src; /* pointer into commandline */ |
1098 | 9823 char_u *srcstart; /* beginning of valid memory for src */ |
7 | 9824 int *usedlen; /* characters after src that are used */ |
9825 linenr_T *lnump; /* line number for :e command, or NULL */ | |
9826 char_u **errormsg; /* pointer to error message */ | |
1098 | 9827 int *escaped; /* return value has escaped white space (can |
9828 * be NULL) */ | |
7 | 9829 { |
9830 int i; | |
9831 char_u *s; | |
9832 char_u *result; | |
9833 char_u *resultbuf = NULL; | |
9834 int resultlen; | |
9835 buf_T *buf; | |
9836 int valid = VALID_HEAD + VALID_PATH; /* assume valid result */ | |
9837 int spec_idx; | |
9838 #ifdef FEAT_MODIFY_FNAME | |
9839 int skip_mod = FALSE; | |
9840 #endif | |
9841 char_u strbuf[30]; | |
9842 | |
9843 *errormsg = NULL; | |
1098 | 9844 if (escaped != NULL) |
9845 *escaped = FALSE; | |
7 | 9846 |
9847 /* | |
9848 * Check if there is something to do. | |
9849 */ | |
1661 | 9850 spec_idx = find_cmdline_var(src, usedlen); |
9851 if (spec_idx < 0) /* no match */ | |
7 | 9852 { |
9853 *usedlen = 1; | |
9854 return NULL; | |
9855 } | |
9856 | |
9857 /* | |
9858 * Skip when preceded with a backslash "\%" and "\#". | |
9859 * Note: In "\\%" the % is also not recognized! | |
9860 */ | |
9861 if (src > srcstart && src[-1] == '\\') | |
9862 { | |
9863 *usedlen = 0; | |
1619 | 9864 STRMOVE(src - 1, src); /* remove backslash */ |
7 | 9865 return NULL; |
9866 } | |
9867 | |
9868 /* | |
9869 * word or WORD under cursor | |
9870 */ | |
9871 if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD) | |
9872 { | |
9873 resultlen = find_ident_under_cursor(&result, spec_idx == SPEC_CWORD ? | |
9874 (FIND_IDENT|FIND_STRING) : FIND_STRING); | |
9875 if (resultlen == 0) | |
9876 { | |
9877 *errormsg = (char_u *)""; | |
9878 return NULL; | |
9879 } | |
9880 } | |
9881 | |
9882 /* | |
9883 * '#': Alternate file name | |
9884 * '%': Current file name | |
9885 * File name under the cursor | |
9886 * File name for autocommand | |
9887 * and following modifiers | |
9888 */ | |
9889 else | |
9890 { | |
9891 switch (spec_idx) | |
9892 { | |
9893 case SPEC_PERC: /* '%': current file */ | |
9894 if (curbuf->b_fname == NULL) | |
9895 { | |
9896 result = (char_u *)""; | |
9897 valid = 0; /* Must have ":p:h" to be valid */ | |
9898 } | |
9899 else | |
9900 result = curbuf->b_fname; | |
9901 break; | |
9902 | |
9903 case SPEC_HASH: /* '#' or "#99": alternate file */ | |
9904 if (src[1] == '#') /* "##": the argument list */ | |
9905 { | |
9906 result = arg_all(); | |
9907 resultbuf = result; | |
9908 *usedlen = 2; | |
1098 | 9909 if (escaped != NULL) |
9910 *escaped = TRUE; | |
7 | 9911 #ifdef FEAT_MODIFY_FNAME |
9912 skip_mod = TRUE; | |
9913 #endif | |
9914 break; | |
9915 } | |
9916 s = src + 1; | |
1733 | 9917 if (*s == '<') /* "#<99" uses v:oldfiles */ |
9918 ++s; | |
7 | 9919 i = (int)getdigits(&s); |
9920 *usedlen = (int)(s - src); /* length of what we expand */ | |
9921 | |
1733 | 9922 if (src[1] == '<') |
7 | 9923 { |
1733 | 9924 if (*usedlen < 2) |
9925 { | |
9926 /* Should we give an error message for #<text? */ | |
9927 *usedlen = 1; | |
9928 return NULL; | |
9929 } | |
9930 #ifdef FEAT_EVAL | |
9931 result = list_find_str(get_vim_var_list(VV_OLDFILES), | |
9932 (long)i); | |
9933 if (result == NULL) | |
9934 { | |
9935 *errormsg = (char_u *)""; | |
9936 return NULL; | |
9937 } | |
9938 #else | |
9939 *errormsg = (char_u *)_("E809: #< is not available without the +eval feature"); | |
7 | 9940 return NULL; |
1733 | 9941 #endif |
7 | 9942 } |
9943 else | |
1733 | 9944 { |
9945 buf = buflist_findnr(i); | |
9946 if (buf == NULL) | |
9947 { | |
9948 *errormsg = (char_u *)_("E194: No alternate file name to substitute for '#'"); | |
9949 return NULL; | |
9950 } | |
9951 if (lnump != NULL) | |
9952 *lnump = ECMD_LAST; | |
9953 if (buf->b_fname == NULL) | |
9954 { | |
9955 result = (char_u *)""; | |
9956 valid = 0; /* Must have ":p:h" to be valid */ | |
9957 } | |
9958 else | |
9959 result = buf->b_fname; | |
9960 } | |
7 | 9961 break; |
9962 | |
9963 #ifdef FEAT_SEARCHPATH | |
9964 case SPEC_CFILE: /* file name under cursor */ | |
681 | 9965 result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL); |
7 | 9966 if (result == NULL) |
9967 { | |
9968 *errormsg = (char_u *)""; | |
9969 return NULL; | |
9970 } | |
9971 resultbuf = result; /* remember allocated string */ | |
9972 break; | |
9973 #endif | |
9974 | |
9975 #ifdef FEAT_AUTOCMD | |
9976 case SPEC_AFILE: /* file name for autocommand */ | |
9977 result = autocmd_fname; | |
1723 | 9978 if (result != NULL && !autocmd_fname_full) |
9979 { | |
9980 /* Still need to turn the fname into a full path. It is | |
9981 * postponed to avoid a delay when <afile> is not used. */ | |
9982 autocmd_fname_full = TRUE; | |
9983 result = FullName_save(autocmd_fname, FALSE); | |
9984 vim_free(autocmd_fname); | |
9985 autocmd_fname = result; | |
9986 } | |
7 | 9987 if (result == NULL) |
9988 { | |
9989 *errormsg = (char_u *)_("E495: no autocommand file name to substitute for \"<afile>\""); | |
9990 return NULL; | |
9991 } | |
1471 | 9992 result = shorten_fname1(result); |
7 | 9993 break; |
9994 | |
9995 case SPEC_ABUF: /* buffer number for autocommand */ | |
9996 if (autocmd_bufnr <= 0) | |
9997 { | |
9998 *errormsg = (char_u *)_("E496: no autocommand buffer number to substitute for \"<abuf>\""); | |
9999 return NULL; | |
10000 } | |
10001 sprintf((char *)strbuf, "%d", autocmd_bufnr); | |
10002 result = strbuf; | |
10003 break; | |
10004 | |
10005 case SPEC_AMATCH: /* match name for autocommand */ | |
10006 result = autocmd_match; | |
10007 if (result == NULL) | |
10008 { | |
10009 *errormsg = (char_u *)_("E497: no autocommand match name to substitute for \"<amatch>\""); | |
10010 return NULL; | |
10011 } | |
10012 break; | |
10013 | |
10014 #endif | |
10015 case SPEC_SFILE: /* file name for ":so" command */ | |
10016 result = sourcing_name; | |
10017 if (result == NULL) | |
10018 { | |
10019 *errormsg = (char_u *)_("E498: no :source file name to substitute for \"<sfile>\""); | |
10020 return NULL; | |
10021 } | |
10022 break; | |
2645 | 10023 case SPEC_SLNUM: /* line in file for ":so" command */ |
10024 if (sourcing_name == NULL || sourcing_lnum == 0) | |
10025 { | |
10026 *errormsg = (char_u *)_("E842: no line number to use for \"<slnum>\""); | |
10027 return NULL; | |
10028 } | |
10029 sprintf((char *)strbuf, "%ld", (long)sourcing_lnum); | |
10030 result = strbuf; | |
10031 break; | |
7 | 10032 #if defined(FEAT_CLIENTSERVER) |
10033 case SPEC_CLIENT: /* Source of last submitted input */ | |
840 | 10034 sprintf((char *)strbuf, PRINTF_HEX_LONG_U, |
10035 (long_u)clientWindow); | |
7 | 10036 result = strbuf; |
10037 break; | |
10038 #endif | |
10039 } | |
10040 | |
10041 resultlen = (int)STRLEN(result); /* length of new string */ | |
10042 if (src[*usedlen] == '<') /* remove the file name extension */ | |
10043 { | |
10044 ++*usedlen; | |
10045 if ((s = vim_strrchr(result, '.')) != NULL && s >= gettail(result)) | |
10046 resultlen = (int)(s - result); | |
10047 } | |
10048 #ifdef FEAT_MODIFY_FNAME | |
10049 else if (!skip_mod) | |
10050 { | |
10051 valid |= modify_fname(src, usedlen, &result, &resultbuf, | |
10052 &resultlen); | |
10053 if (result == NULL) | |
10054 { | |
10055 *errormsg = (char_u *)""; | |
10056 return NULL; | |
10057 } | |
10058 } | |
10059 #endif | |
10060 } | |
10061 | |
10062 if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH) | |
10063 { | |
10064 if (valid != VALID_HEAD + VALID_PATH) | |
10065 /* xgettext:no-c-format */ | |
10066 *errormsg = (char_u *)_("E499: Empty file name for '%' or '#', only works with \":p:h\""); | |
10067 else | |
10068 *errormsg = (char_u *)_("E500: Evaluates to an empty string"); | |
10069 result = NULL; | |
10070 } | |
10071 else | |
10072 result = vim_strnsave(result, resultlen); | |
10073 vim_free(resultbuf); | |
10074 return result; | |
10075 } | |
10076 | |
10077 /* | |
10078 * Concatenate all files in the argument list, separated by spaces, and return | |
10079 * it in one allocated string. | |
10080 * Spaces and backslashes in the file names are escaped with a backslash. | |
10081 * Returns NULL when out of memory. | |
10082 */ | |
10083 static char_u * | |
10084 arg_all() | |
10085 { | |
10086 int len; | |
10087 int idx; | |
10088 char_u *retval = NULL; | |
10089 char_u *p; | |
10090 | |
10091 /* | |
10092 * Do this loop two times: | |
10093 * first time: compute the total length | |
10094 * second time: concatenate the names | |
10095 */ | |
10096 for (;;) | |
10097 { | |
10098 len = 0; | |
10099 for (idx = 0; idx < ARGCOUNT; ++idx) | |
10100 { | |
10101 p = alist_name(&ARGLIST[idx]); | |
10102 if (p != NULL) | |
10103 { | |
10104 if (len > 0) | |
10105 { | |
10106 /* insert a space in between names */ | |
10107 if (retval != NULL) | |
10108 retval[len] = ' '; | |
10109 ++len; | |
10110 } | |
10111 for ( ; *p != NUL; ++p) | |
10112 { | |
10113 if (*p == ' ' || *p == '\\') | |
10114 { | |
10115 /* insert a backslash */ | |
10116 if (retval != NULL) | |
10117 retval[len] = '\\'; | |
10118 ++len; | |
10119 } | |
10120 if (retval != NULL) | |
10121 retval[len] = *p; | |
10122 ++len; | |
10123 } | |
10124 } | |
10125 } | |
10126 | |
10127 /* second time: break here */ | |
10128 if (retval != NULL) | |
10129 { | |
10130 retval[len] = NUL; | |
10131 break; | |
10132 } | |
10133 | |
10134 /* allocate memory */ | |
1872 | 10135 retval = alloc((unsigned)len + 1); |
7 | 10136 if (retval == NULL) |
10137 break; | |
10138 } | |
10139 | |
10140 return retval; | |
10141 } | |
10142 | |
10143 #if defined(FEAT_AUTOCMD) || defined(PROTO) | |
10144 /* | |
10145 * Expand the <sfile> string in "arg". | |
10146 * | |
10147 * Returns an allocated string, or NULL for any error. | |
10148 */ | |
10149 char_u * | |
10150 expand_sfile(arg) | |
10151 char_u *arg; | |
10152 { | |
10153 char_u *errormsg; | |
10154 int len; | |
10155 char_u *result; | |
10156 char_u *newres; | |
10157 char_u *repl; | |
10158 int srclen; | |
10159 char_u *p; | |
10160 | |
10161 result = vim_strsave(arg); | |
10162 if (result == NULL) | |
10163 return NULL; | |
10164 | |
10165 for (p = result; *p; ) | |
10166 { | |
10167 if (STRNCMP(p, "<sfile>", 7) != 0) | |
10168 ++p; | |
10169 else | |
10170 { | |
10171 /* replace "<sfile>" with the sourced file name, and do ":" stuff */ | |
1098 | 10172 repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL); |
7 | 10173 if (errormsg != NULL) |
10174 { | |
10175 if (*errormsg) | |
10176 emsg(errormsg); | |
10177 vim_free(result); | |
10178 return NULL; | |
10179 } | |
10180 if (repl == NULL) /* no match (cannot happen) */ | |
10181 { | |
10182 p += srclen; | |
10183 continue; | |
10184 } | |
10185 len = (int)STRLEN(result) - srclen + (int)STRLEN(repl) + 1; | |
10186 newres = alloc(len); | |
10187 if (newres == NULL) | |
10188 { | |
10189 vim_free(repl); | |
10190 vim_free(result); | |
10191 return NULL; | |
10192 } | |
10193 mch_memmove(newres, result, (size_t)(p - result)); | |
10194 STRCPY(newres + (p - result), repl); | |
10195 len = (int)STRLEN(newres); | |
10196 STRCAT(newres, p + srclen); | |
10197 vim_free(repl); | |
10198 vim_free(result); | |
10199 result = newres; | |
10200 p = newres + len; /* continue after the match */ | |
10201 } | |
10202 } | |
10203 | |
10204 return result; | |
10205 } | |
10206 #endif | |
10207 | |
10208 #ifdef FEAT_SESSION | |
1021 | 10209 static int ses_winsizes __ARGS((FILE *fd, int restore_size, |
10210 win_T *tab_firstwin)); | |
7 | 10211 static int ses_win_rec __ARGS((FILE *fd, frame_T *fr)); |
10212 static frame_T *ses_skipframe __ARGS((frame_T *fr)); | |
10213 static int ses_do_frame __ARGS((frame_T *fr)); | |
10214 static int ses_do_win __ARGS((win_T *wp)); | |
10215 static int ses_arglist __ARGS((FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp)); | |
10216 static int ses_put_fname __ARGS((FILE *fd, char_u *name, unsigned *flagp)); | |
10217 static int ses_fname __ARGS((FILE *fd, buf_T *buf, unsigned *flagp)); | |
10218 | |
10219 /* | |
10220 * Write openfile commands for the current buffers to an .exrc file. | |
10221 * Return FAIL on error, OK otherwise. | |
10222 */ | |
10223 static int | |
10224 makeopens(fd, dirnow) | |
10225 FILE *fd; | |
10226 char_u *dirnow; /* Current directory name */ | |
10227 { | |
10228 buf_T *buf; | |
10229 int only_save_windows = TRUE; | |
10230 int nr; | |
10231 int cnr = 1; | |
10232 int restore_size = TRUE; | |
10233 win_T *wp; | |
10234 char_u *sname; | |
10235 win_T *edited_win = NULL; | |
827 | 10236 int tabnr; |
1021 | 10237 win_T *tab_firstwin; |
1048 | 10238 frame_T *tab_topframe; |
1467 | 10239 int cur_arg_idx = 0; |
1485 | 10240 int next_arg_idx = 0; |
7 | 10241 |
10242 if (ssop_flags & SSOP_BUFFERS) | |
10243 only_save_windows = FALSE; /* Save ALL buffers */ | |
10244 | |
10245 /* | |
10246 * Begin by setting the this_session variable, and then other | |
10247 * sessionable variables. | |
10248 */ | |
10249 #ifdef FEAT_EVAL | |
10250 if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL) | |
10251 return FAIL; | |
10252 if (ssop_flags & SSOP_GLOBALS) | |
10253 if (store_session_globals(fd) == FAIL) | |
10254 return FAIL; | |
10255 #endif | |
10256 | |
10257 /* | |
10258 * Close all windows but one. | |
10259 */ | |
10260 if (put_line(fd, "silent only") == FAIL) | |
10261 return FAIL; | |
10262 | |
10263 /* | |
10264 * Now a :cd command to the session directory or the current directory | |
10265 */ | |
10266 if (ssop_flags & SSOP_SESDIR) | |
10267 { | |
534 | 10268 if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')") |
10269 == FAIL) | |
7 | 10270 return FAIL; |
10271 } | |
10272 else if (ssop_flags & SSOP_CURDIR) | |
10273 { | |
10274 sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); | |
10275 if (sname == NULL | |
534 | 10276 || fputs("cd ", fd) < 0 |
10277 || ses_put_fname(fd, sname, &ssop_flags) == FAIL | |
10278 || put_eol(fd) == FAIL) | |
10279 { | |
10280 vim_free(sname); | |
7 | 10281 return FAIL; |
534 | 10282 } |
7 | 10283 vim_free(sname); |
10284 } | |
10285 | |
10286 /* | |
36 | 10287 * If there is an empty, unnamed buffer we will wipe it out later. |
10288 * Remember the buffer number. | |
10289 */ | |
10290 if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL) | |
10291 return FAIL; | |
10292 if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL) | |
10293 return FAIL; | |
10294 if (put_line(fd, "endif") == FAIL) | |
10295 return FAIL; | |
10296 | |
10297 /* | |
7 | 10298 * Now save the current files, current buffer first. |
10299 */ | |
10300 if (put_line(fd, "set shortmess=aoO") == FAIL) | |
10301 return FAIL; | |
10302 | |
10303 /* Now put the other buffers into the buffer list */ | |
10304 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
10305 { | |
10306 if (!(only_save_windows && buf->b_nwindows == 0) | |
10307 && !(buf->b_help && !(ssop_flags & SSOP_HELP)) | |
10308 && buf->b_fname != NULL | |
10309 && buf->b_p_bl) | |
10310 { | |
10311 if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L | |
10312 : buf->b_wininfo->wi_fpos.lnum) < 0 | |
10313 || ses_fname(fd, buf, &ssop_flags) == FAIL) | |
10314 return FAIL; | |
10315 } | |
10316 } | |
10317 | |
10318 /* the global argument list */ | |
10319 if (ses_arglist(fd, "args", &global_alist.al_ga, | |
10320 !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) | |
10321 return FAIL; | |
10322 | |
10323 if (ssop_flags & SSOP_RESIZE) | |
10324 { | |
10325 /* Note: after the restore we still check it worked!*/ | |
10326 if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0 | |
10327 || put_eol(fd) == FAIL) | |
10328 return FAIL; | |
10329 } | |
10330 | |
10331 #ifdef FEAT_GUI | |
10332 if (gui.in_use && (ssop_flags & SSOP_WINPOS)) | |
10333 { | |
10334 int x, y; | |
10335 | |
10336 if (gui_mch_get_winpos(&x, &y) == OK) | |
10337 { | |
10338 /* Note: after the restore we still check it worked!*/ | |
10339 if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL) | |
10340 return FAIL; | |
10341 } | |
10342 } | |
10343 #endif | |
10344 | |
10345 /* | |
827 | 10346 * May repeat putting Windows for each tab, when "tabpages" is in |
10347 * 'sessionoptions'. | |
1021 | 10348 * Don't use goto_tabpage(), it may change directory and trigger |
10349 * autocommands. | |
7 | 10350 */ |
1021 | 10351 tab_firstwin = firstwin; /* first window in tab page "tabnr" */ |
1048 | 10352 tab_topframe = topframe; |
827 | 10353 for (tabnr = 1; ; ++tabnr) |
10354 { | |
1021 | 10355 int need_tabnew = FALSE; |
10356 | |
827 | 10357 if ((ssop_flags & SSOP_TABPAGES)) |
10358 { | |
1021 | 10359 tabpage_T *tp = find_tabpage(tabnr); |
10360 | |
10361 if (tp == NULL) | |
10362 break; /* done all tab pages */ | |
10363 if (tp == curtab) | |
1048 | 10364 { |
1021 | 10365 tab_firstwin = firstwin; |
1048 | 10366 tab_topframe = topframe; |
10367 } | |
1021 | 10368 else |
1048 | 10369 { |
1021 | 10370 tab_firstwin = tp->tp_firstwin; |
1048 | 10371 tab_topframe = tp->tp_topframe; |
10372 } | |
1021 | 10373 if (tabnr > 1) |
10374 need_tabnew = TRUE; | |
827 | 10375 } |
10376 | |
10377 /* | |
10378 * Before creating the window layout, try loading one file. If this | |
10379 * is aborted we don't end up with a number of useless windows. | |
10380 * This may have side effects! (e.g., compressed or network file). | |
10381 */ | |
1021 | 10382 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
827 | 10383 { |
10384 if (ses_do_win(wp) | |
10385 && wp->w_buffer->b_ffname != NULL | |
10386 && !wp->w_buffer->b_help | |
10387 #ifdef FEAT_QUICKFIX | |
10388 && !bt_nofile(wp->w_buffer) | |
10389 #endif | |
10390 ) | |
10391 { | |
1021 | 10392 if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0 |
827 | 10393 || ses_fname(fd, wp->w_buffer, &ssop_flags) == FAIL) |
10394 return FAIL; | |
1021 | 10395 need_tabnew = FALSE; |
827 | 10396 if (!wp->w_arg_idx_invalid) |
10397 edited_win = wp; | |
10398 break; | |
10399 } | |
10400 } | |
10401 | |
1021 | 10402 /* If no file got edited create an empty tab page. */ |
10403 if (need_tabnew && put_line(fd, "tabnew") == FAIL) | |
10404 return FAIL; | |
10405 | |
827 | 10406 /* |
10407 * Save current window layout. | |
10408 */ | |
10409 if (put_line(fd, "set splitbelow splitright") == FAIL) | |
10410 return FAIL; | |
1048 | 10411 if (ses_win_rec(fd, tab_topframe) == FAIL) |
827 | 10412 return FAIL; |
10413 if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) | |
10414 return FAIL; | |
10415 if (!p_spr && put_line(fd, "set nosplitright") == FAIL) | |
10416 return FAIL; | |
10417 | |
10418 /* | |
10419 * Check if window sizes can be restored (no windows omitted). | |
10420 * Remember the window number of the current window after restoring. | |
10421 */ | |
10422 nr = 0; | |
1021 | 10423 for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp)) |
827 | 10424 { |
10425 if (ses_do_win(wp)) | |
10426 ++nr; | |
10427 else | |
10428 restore_size = FALSE; | |
10429 if (curwin == wp) | |
10430 cnr = nr; | |
10431 } | |
10432 | |
10433 /* Go to the first window. */ | |
10434 if (put_line(fd, "wincmd t") == FAIL) | |
7 | 10435 return FAIL; |
827 | 10436 |
10437 /* | |
10438 * If more than one window, see if sizes can be restored. | |
10439 * First set 'winheight' and 'winwidth' to 1 to avoid the windows being | |
10440 * resized when moving between windows. | |
10441 * Do this before restoring the view, so that the topline and the | |
10442 * cursor can be set. This is done again below. | |
10443 */ | |
10444 if (put_line(fd, "set winheight=1 winwidth=1") == FAIL) | |
10445 return FAIL; | |
1021 | 10446 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) |
827 | 10447 return FAIL; |
10448 | |
10449 /* | |
10450 * Restore the view of the window (options, file, cursor, etc.). | |
10451 */ | |
1021 | 10452 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
827 | 10453 { |
10454 if (!ses_do_win(wp)) | |
10455 continue; | |
1467 | 10456 if (put_view(fd, wp, wp != edited_win, &ssop_flags, |
10457 cur_arg_idx) == FAIL) | |
827 | 10458 return FAIL; |
10459 if (nr > 1 && put_line(fd, "wincmd w") == FAIL) | |
10460 return FAIL; | |
1467 | 10461 next_arg_idx = wp->w_arg_idx; |
10462 } | |
10463 | |
10464 /* The argument index in the first tab page is zero, need to set it in | |
10465 * each window. For further tab pages it's the window where we do | |
10466 * "tabedit". */ | |
10467 cur_arg_idx = next_arg_idx; | |
827 | 10468 |
10469 /* | |
10470 * Restore cursor to the current window if it's not the first one. | |
10471 */ | |
10472 if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 | |
10473 || put_eol(fd) == FAIL)) | |
7 | 10474 return FAIL; |
827 | 10475 |
10476 /* | |
10477 * Restore window sizes again after jumping around in windows, because | |
10478 * the current window has a minimum size while others may not. | |
10479 */ | |
1021 | 10480 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) |
827 | 10481 return FAIL; |
10482 | |
10483 /* Don't continue in another tab page when doing only the current one | |
10484 * or when at the last tab page. */ | |
1021 | 10485 if (!(ssop_flags & SSOP_TABPAGES)) |
827 | 10486 break; |
10487 } | |
10488 | |
10489 if (ssop_flags & SSOP_TABPAGES) | |
10490 { | |
10491 if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0 | |
10492 || put_eol(fd) == FAIL) | |
10493 return FAIL; | |
10494 } | |
10495 | |
859 | 10496 /* |
10497 * Wipe out an empty unnamed buffer we started in. | |
10498 */ | |
10499 if (put_line(fd, "if exists('s:wipebuf')") == FAIL) | |
10500 return FAIL; | |
866 | 10501 if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL) |
859 | 10502 return FAIL; |
10503 if (put_line(fd, "endif") == FAIL) | |
10504 return FAIL; | |
10505 if (put_line(fd, "unlet! s:wipebuf") == FAIL) | |
10506 return FAIL; | |
10507 | |
10508 /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */ | |
10509 if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s", | |
10510 p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL) | |
10511 return FAIL; | |
7 | 10512 |
10513 /* | |
10514 * Lastly, execute the x.vim file if it exists. | |
10515 */ | |
10516 if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL | |
10517 || put_line(fd, "if file_readable(s:sx)") == FAIL | |
1769 | 10518 || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL |
7 | 10519 || put_line(fd, "endif") == FAIL) |
10520 return FAIL; | |
10521 | |
10522 return OK; | |
10523 } | |
10524 | |
10525 static int | |
1021 | 10526 ses_winsizes(fd, restore_size, tab_firstwin) |
7 | 10527 FILE *fd; |
10528 int restore_size; | |
1021 | 10529 win_T *tab_firstwin; |
7 | 10530 { |
10531 int n = 0; | |
10532 win_T *wp; | |
10533 | |
10534 if (restore_size && (ssop_flags & SSOP_WINSIZE)) | |
10535 { | |
1021 | 10536 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
7 | 10537 { |
10538 if (!ses_do_win(wp)) | |
10539 continue; | |
10540 ++n; | |
10541 | |
10542 /* restore height when not full height */ | |
10543 if (wp->w_height + wp->w_status_height < topframe->fr_height | |
10544 && (fprintf(fd, | |
10545 "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)", | |
10546 n, (long)wp->w_height, Rows / 2, Rows) < 0 | |
10547 || put_eol(fd) == FAIL)) | |
10548 return FAIL; | |
10549 | |
10550 /* restore width when not full width */ | |
10551 if (wp->w_width < Columns && (fprintf(fd, | |
10552 "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)", | |
10553 n, (long)wp->w_width, Columns / 2, Columns) < 0 | |
10554 || put_eol(fd) == FAIL)) | |
10555 return FAIL; | |
10556 } | |
10557 } | |
10558 else | |
10559 { | |
10560 /* Just equalise window sizes */ | |
10561 if (put_line(fd, "wincmd =") == FAIL) | |
10562 return FAIL; | |
10563 } | |
10564 return OK; | |
10565 } | |
10566 | |
10567 /* | |
10568 * Write commands to "fd" to recursively create windows for frame "fr", | |
10569 * horizontally and vertically split. | |
10570 * After the commands the last window in the frame is the current window. | |
10571 * Returns FAIL when writing the commands to "fd" fails. | |
10572 */ | |
10573 static int | |
10574 ses_win_rec(fd, fr) | |
10575 FILE *fd; | |
10576 frame_T *fr; | |
10577 { | |
10578 frame_T *frc; | |
10579 int count = 0; | |
10580 | |
10581 if (fr->fr_layout != FR_LEAF) | |
10582 { | |
10583 /* Find first frame that's not skipped and then create a window for | |
10584 * each following one (first frame is already there). */ | |
10585 frc = ses_skipframe(fr->fr_child); | |
10586 if (frc != NULL) | |
10587 while ((frc = ses_skipframe(frc->fr_next)) != NULL) | |
10588 { | |
10589 /* Make window as big as possible so that we have lots of room | |
10590 * to split. */ | |
10591 if (put_line(fd, "wincmd _ | wincmd |") == FAIL | |
10592 || put_line(fd, fr->fr_layout == FR_COL | |
10593 ? "split" : "vsplit") == FAIL) | |
10594 return FAIL; | |
10595 ++count; | |
10596 } | |
10597 | |
10598 /* Go back to the first window. */ | |
10599 if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL | |
10600 ? "%dwincmd k" : "%dwincmd h", count) < 0 | |
10601 || put_eol(fd) == FAIL)) | |
10602 return FAIL; | |
10603 | |
10604 /* Recursively create frames/windows in each window of this column or | |
10605 * row. */ | |
10606 frc = ses_skipframe(fr->fr_child); | |
10607 while (frc != NULL) | |
10608 { | |
10609 ses_win_rec(fd, frc); | |
10610 frc = ses_skipframe(frc->fr_next); | |
10611 /* Go to next window. */ | |
10612 if (frc != NULL && put_line(fd, "wincmd w") == FAIL) | |
10613 return FAIL; | |
10614 } | |
10615 } | |
10616 return OK; | |
10617 } | |
10618 | |
10619 /* | |
10620 * Skip frames that don't contain windows we want to save in the Session. | |
10621 * Returns NULL when there none. | |
10622 */ | |
10623 static frame_T * | |
10624 ses_skipframe(fr) | |
10625 frame_T *fr; | |
10626 { | |
10627 frame_T *frc; | |
10628 | |
10629 for (frc = fr; frc != NULL; frc = frc->fr_next) | |
10630 if (ses_do_frame(frc)) | |
10631 break; | |
10632 return frc; | |
10633 } | |
10634 | |
10635 /* | |
10636 * Return TRUE if frame "fr" has a window somewhere that we want to save in | |
10637 * the Session. | |
10638 */ | |
10639 static int | |
10640 ses_do_frame(fr) | |
10641 frame_T *fr; | |
10642 { | |
10643 frame_T *frc; | |
10644 | |
10645 if (fr->fr_layout == FR_LEAF) | |
10646 return ses_do_win(fr->fr_win); | |
10647 for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next) | |
10648 if (ses_do_frame(frc)) | |
10649 return TRUE; | |
10650 return FALSE; | |
10651 } | |
10652 | |
10653 /* | |
10654 * Return non-zero if window "wp" is to be stored in the Session. | |
10655 */ | |
10656 static int | |
10657 ses_do_win(wp) | |
10658 win_T *wp; | |
10659 { | |
10660 if (wp->w_buffer->b_fname == NULL | |
10661 #ifdef FEAT_QUICKFIX | |
10662 /* When 'buftype' is "nofile" can't restore the window contents. */ | |
10663 || bt_nofile(wp->w_buffer) | |
10664 #endif | |
10665 ) | |
10666 return (ssop_flags & SSOP_BLANK); | |
10667 if (wp->w_buffer->b_help) | |
10668 return (ssop_flags & SSOP_HELP); | |
10669 return TRUE; | |
10670 } | |
10671 | |
10672 /* | |
10673 * Write commands to "fd" to restore the view of a window. | |
10674 * Caller must make sure 'scrolloff' is zero. | |
10675 */ | |
10676 static int | |
1467 | 10677 put_view(fd, wp, add_edit, flagp, current_arg_idx) |
7 | 10678 FILE *fd; |
10679 win_T *wp; | |
10680 int add_edit; /* add ":edit" command to view */ | |
10681 unsigned *flagp; /* vop_flags or ssop_flags */ | |
1467 | 10682 int current_arg_idx; /* current argument index of the window, use |
10683 * -1 if unknown */ | |
7 | 10684 { |
10685 win_T *save_curwin; | |
10686 int f; | |
10687 int do_cursor; | |
280 | 10688 int did_next = FALSE; |
7 | 10689 |
10690 /* Always restore cursor position for ":mksession". For ":mkview" only | |
10691 * when 'viewoptions' contains "cursor". */ | |
10692 do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR); | |
10693 | |
10694 /* | |
10695 * Local argument list. | |
10696 */ | |
10697 if (wp->w_alist == &global_alist) | |
10698 { | |
10699 if (put_line(fd, "argglobal") == FAIL) | |
10700 return FAIL; | |
10701 } | |
10702 else | |
10703 { | |
10704 if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, | |
10705 flagp == &vop_flags | |
10706 || !(*flagp & SSOP_CURDIR) | |
10707 || wp->w_localdir != NULL, flagp) == FAIL) | |
10708 return FAIL; | |
10709 } | |
10710 | |
280 | 10711 /* Only when part of a session: restore the argument index. Some |
10712 * arguments may have been deleted, check if the index is valid. */ | |
2276
ebabd8a8b714
Fix that :mksession may generate "2argu" even though there is no such
Bram Moolenaar <bram@vim.org>
parents:
2268
diff
changeset
|
10713 if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) |
280 | 10714 && flagp == &ssop_flags) |
7 | 10715 { |
1467 | 10716 if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0 |
7 | 10717 || put_eol(fd) == FAIL) |
10718 return FAIL; | |
280 | 10719 did_next = TRUE; |
7 | 10720 } |
10721 | |
10722 /* Edit the file. Skip this when ":next" already did it. */ | |
280 | 10723 if (add_edit && (!did_next || wp->w_arg_idx_invalid)) |
7 | 10724 { |
10725 /* | |
10726 * Load the file. | |
10727 */ | |
10728 if (wp->w_buffer->b_ffname != NULL | |
10729 #ifdef FEAT_QUICKFIX | |
10730 && !bt_nofile(wp->w_buffer) | |
10731 #endif | |
10732 ) | |
10733 { | |
10734 /* | |
10735 * Editing a file in this buffer: use ":edit file". | |
10736 * This may have side effects! (e.g., compressed or network file). | |
10737 */ | |
10738 if (fputs("edit ", fd) < 0 | |
10739 || ses_fname(fd, wp->w_buffer, flagp) == FAIL) | |
10740 return FAIL; | |
10741 } | |
10742 else | |
10743 { | |
10744 /* No file in this buffer, just make it empty. */ | |
10745 if (put_line(fd, "enew") == FAIL) | |
10746 return FAIL; | |
10747 #ifdef FEAT_QUICKFIX | |
10748 if (wp->w_buffer->b_ffname != NULL) | |
10749 { | |
10750 /* The buffer does have a name, but it's not a file name. */ | |
10751 if (fputs("file ", fd) < 0 | |
10752 || ses_fname(fd, wp->w_buffer, flagp) == FAIL) | |
10753 return FAIL; | |
10754 } | |
10755 #endif | |
10756 do_cursor = FALSE; | |
10757 } | |
10758 } | |
10759 | |
10760 /* | |
10761 * Local mappings and abbreviations. | |
10762 */ | |
10763 if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) | |
10764 && makemap(fd, wp->w_buffer) == FAIL) | |
10765 return FAIL; | |
10766 | |
10767 /* | |
10768 * Local options. Need to go to the window temporarily. | |
10769 * Store only local values when using ":mkview" and when ":mksession" is | |
10770 * used and 'sessionoptions' doesn't include "options". | |
10771 * Some folding options are always stored when "folds" is included, | |
10772 * otherwise the folds would not be restored correctly. | |
10773 */ | |
10774 save_curwin = curwin; | |
10775 curwin = wp; | |
10776 curbuf = curwin->w_buffer; | |
10777 if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) | |
10778 f = makeset(fd, OPT_LOCAL, | |
10779 flagp == &vop_flags || !(*flagp & SSOP_OPTIONS)); | |
10780 #ifdef FEAT_FOLDING | |
10781 else if (*flagp & SSOP_FOLDS) | |
10782 f = makefoldset(fd); | |
10783 #endif | |
10784 else | |
10785 f = OK; | |
10786 curwin = save_curwin; | |
10787 curbuf = curwin->w_buffer; | |
10788 if (f == FAIL) | |
10789 return FAIL; | |
10790 | |
10791 #ifdef FEAT_FOLDING | |
10792 /* | |
10793 * Save Folds when 'buftype' is empty and for help files. | |
10794 */ | |
10795 if ((*flagp & SSOP_FOLDS) | |
10796 && wp->w_buffer->b_ffname != NULL | |
635 | 10797 # ifdef FEAT_QUICKFIX |
10798 && (*wp->w_buffer->b_p_bt == NUL || wp->w_buffer->b_help) | |
10799 # endif | |
10800 ) | |
7 | 10801 { |
10802 if (put_folds(fd, wp) == FAIL) | |
10803 return FAIL; | |
10804 } | |
10805 #endif | |
10806 | |
10807 /* | |
10808 * Set the cursor after creating folds, since that moves the cursor. | |
10809 */ | |
10810 if (do_cursor) | |
10811 { | |
10812 | |
10813 /* Restore the cursor line in the file and relatively in the | |
10814 * window. Don't use "G", it changes the jumplist. */ | |
10815 if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)", | |
10816 (long)wp->w_cursor.lnum, | |
10817 (long)(wp->w_cursor.lnum - wp->w_topline), | |
10818 (long)wp->w_height / 2, (long)wp->w_height) < 0 | |
10819 || put_eol(fd) == FAIL | |
10820 || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL | |
10821 || put_line(fd, "exe s:l") == FAIL | |
10822 || put_line(fd, "normal! zt") == FAIL | |
10823 || fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0 | |
10824 || put_eol(fd) == FAIL) | |
10825 return FAIL; | |
10826 /* Restore the cursor column and left offset when not wrapping. */ | |
10827 if (wp->w_cursor.col == 0) | |
10828 { | |
10829 if (put_line(fd, "normal! 0") == FAIL) | |
10830 return FAIL; | |
10831 } | |
10832 else | |
10833 { | |
10834 if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) | |
10835 { | |
10836 if (fprintf(fd, | |
10837 "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)", | |
4155 | 10838 (long)wp->w_virtcol + 1, |
10839 (long)(wp->w_virtcol - wp->w_leftcol), | |
7 | 10840 (long)wp->w_width / 2, (long)wp->w_width) < 0 |
10841 || put_eol(fd) == FAIL | |
10842 || put_line(fd, "if s:c > 0") == FAIL | |
10843 || fprintf(fd, | |
4155 | 10844 " exe 'normal! ' . s:c . '|zs' . %ld . '|'", |
10845 (long)wp->w_virtcol + 1) < 0 | |
7 | 10846 || put_eol(fd) == FAIL |
10847 || put_line(fd, "else") == FAIL | |
4172 | 10848 || fprintf(fd, " normal! 0%d|", wp->w_virtcol + 1) < 0 |
7 | 10849 || put_eol(fd) == FAIL |
10850 || put_line(fd, "endif") == FAIL) | |
10851 return FAIL; | |
10852 } | |
10853 else | |
10854 { | |
4155 | 10855 if (fprintf(fd, "normal! 0%d|", wp->w_virtcol + 1) < 0 |
7 | 10856 || put_eol(fd) == FAIL) |
10857 return FAIL; | |
10858 } | |
10859 } | |
10860 } | |
10861 | |
10862 /* | |
10863 * Local directory. | |
10864 */ | |
10865 if (wp->w_localdir != NULL) | |
10866 { | |
10867 if (fputs("lcd ", fd) < 0 | |
10868 || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL | |
10869 || put_eol(fd) == FAIL) | |
10870 return FAIL; | |
1113 | 10871 did_lcd = TRUE; |
7 | 10872 } |
10873 | |
10874 return OK; | |
10875 } | |
10876 | |
10877 /* | |
10878 * Write an argument list to the session file. | |
10879 * Returns FAIL if writing fails. | |
10880 */ | |
10881 static int | |
10882 ses_arglist(fd, cmd, gap, fullname, flagp) | |
10883 FILE *fd; | |
10884 char *cmd; | |
10885 garray_T *gap; | |
10886 int fullname; /* TRUE: use full path name */ | |
10887 unsigned *flagp; | |
10888 { | |
10889 int i; | |
2770 | 10890 char_u *buf = NULL; |
7 | 10891 char_u *s; |
10892 | |
10893 if (gap->ga_len == 0) | |
10894 return put_line(fd, "silent! argdel *"); | |
10895 if (fputs(cmd, fd) < 0) | |
10896 return FAIL; | |
10897 for (i = 0; i < gap->ga_len; ++i) | |
10898 { | |
10899 /* NULL file names are skipped (only happens when out of memory). */ | |
10900 s = alist_name(&((aentry_T *)gap->ga_data)[i]); | |
10901 if (s != NULL) | |
10902 { | |
10903 if (fullname) | |
10904 { | |
2770 | 10905 buf = alloc(MAXPATHL); |
10906 if (buf != NULL) | |
10907 { | |
10908 (void)vim_FullName(s, buf, MAXPATHL, FALSE); | |
10909 s = buf; | |
10910 } | |
7 | 10911 } |
10912 if (fputs(" ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL) | |
2770 | 10913 { |
10914 vim_free(buf); | |
7 | 10915 return FAIL; |
2770 | 10916 } |
10917 vim_free(buf); | |
7 | 10918 } |
10919 } | |
10920 return put_eol(fd); | |
10921 } | |
10922 | |
10923 /* | |
10924 * Write a buffer name to the session file. | |
10925 * Also ends the line. | |
10926 * Returns FAIL if writing fails. | |
10927 */ | |
10928 static int | |
10929 ses_fname(fd, buf, flagp) | |
10930 FILE *fd; | |
10931 buf_T *buf; | |
10932 unsigned *flagp; | |
10933 { | |
10934 char_u *name; | |
10935 | |
10936 /* Use the short file name if the current directory is known at the time | |
1113 | 10937 * the session file will be sourced. |
10938 * Don't do this for ":mkview", we don't know the current directory. | |
10939 * Don't do this after ":lcd", we don't keep track of what the current | |
10940 * directory is. */ | |
7 | 10941 if (buf->b_sfname != NULL |
10942 && flagp == &ssop_flags | |
1113 | 10943 && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) |
1925 | 10944 #ifdef FEAT_AUTOCHDIR |
10945 && !p_acd | |
10946 #endif | |
1113 | 10947 && !did_lcd) |
7 | 10948 name = buf->b_sfname; |
10949 else | |
10950 name = buf->b_ffname; | |
10951 if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL) | |
10952 return FAIL; | |
10953 return OK; | |
10954 } | |
10955 | |
10956 /* | |
10957 * Write a file name to the session file. | |
10958 * Takes care of the "slash" option in 'sessionoptions' and escapes special | |
10959 * characters. | |
2602 | 10960 * Returns FAIL if writing fails or out of memory. |
7 | 10961 */ |
10962 static int | |
10963 ses_put_fname(fd, name, flagp) | |
10964 FILE *fd; | |
10965 char_u *name; | |
10966 unsigned *flagp; | |
10967 { | |
10968 char_u *sname; | |
2602 | 10969 char_u *p; |
7 | 10970 int retval = OK; |
10971 | |
10972 sname = home_replace_save(NULL, name); | |
2602 | 10973 if (sname == NULL) |
10974 return FAIL; | |
10975 | |
10976 if (*flagp & SSOP_SLASH) | |
10977 { | |
10978 /* change all backslashes to forward slashes */ | |
10979 for (p = sname; *p != NUL; mb_ptr_adv(p)) | |
10980 if (*p == '\\') | |
10981 *p = '/'; | |
10982 } | |
10983 | |
10984 /* escapse special characters */ | |
10985 p = vim_strsave_fnameescape(sname, FALSE); | |
7 | 10986 vim_free(sname); |
2602 | 10987 if (p == NULL) |
10988 return FAIL; | |
10989 | |
10990 /* write the result */ | |
10991 if (fputs((char *)p, fd) < 0) | |
10992 retval = FAIL; | |
10993 | |
10994 vim_free(p); | |
7 | 10995 return retval; |
10996 } | |
10997 | |
10998 /* | |
10999 * ":loadview [nr]" | |
11000 */ | |
11001 static void | |
11002 ex_loadview(eap) | |
11003 exarg_T *eap; | |
11004 { | |
11005 char_u *fname; | |
11006 | |
11007 fname = get_view_file(*eap->arg); | |
11008 if (fname != NULL) | |
11009 { | |
819 | 11010 do_source(fname, FALSE, DOSO_NONE); |
7 | 11011 vim_free(fname); |
11012 } | |
11013 } | |
11014 | |
11015 /* | |
11016 * Get the name of the view file for the current buffer. | |
11017 */ | |
11018 static char_u * | |
11019 get_view_file(c) | |
11020 int c; | |
11021 { | |
11022 int len = 0; | |
11023 char_u *p, *s; | |
11024 char_u *retval; | |
11025 char_u *sname; | |
11026 | |
11027 if (curbuf->b_ffname == NULL) | |
11028 { | |
11029 EMSG(_(e_noname)); | |
11030 return NULL; | |
11031 } | |
11032 sname = home_replace_save(NULL, curbuf->b_ffname); | |
11033 if (sname == NULL) | |
11034 return NULL; | |
11035 | |
11036 /* | |
11037 * We want a file name without separators, because we're not going to make | |
11038 * a directory. | |
11039 * "normal" path separator -> "=+" | |
11040 * "=" -> "==" | |
11041 * ":" path separator -> "=-" | |
11042 */ | |
11043 for (p = sname; *p; ++p) | |
11044 if (*p == '=' || vim_ispathsep(*p)) | |
11045 ++len; | |
11046 retval = alloc((unsigned)(STRLEN(sname) + len + STRLEN(p_vdir) + 9)); | |
11047 if (retval != NULL) | |
11048 { | |
11049 STRCPY(retval, p_vdir); | |
11050 add_pathsep(retval); | |
11051 s = retval + STRLEN(retval); | |
11052 for (p = sname; *p; ++p) | |
11053 { | |
11054 if (*p == '=') | |
11055 { | |
11056 *s++ = '='; | |
11057 *s++ = '='; | |
11058 } | |
11059 else if (vim_ispathsep(*p)) | |
11060 { | |
11061 *s++ = '='; | |
2823 | 11062 #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS) |
7 | 11063 if (*p == ':') |
11064 *s++ = '-'; | |
11065 else | |
573 | 11066 #endif |
7 | 11067 *s++ = '+'; |
11068 } | |
11069 else | |
11070 *s++ = *p; | |
11071 } | |
11072 *s++ = '='; | |
11073 *s++ = c; | |
11074 STRCPY(s, ".vim"); | |
11075 } | |
11076 | |
11077 vim_free(sname); | |
11078 return retval; | |
11079 } | |
11080 | |
11081 #endif /* FEAT_SESSION */ | |
11082 | |
11083 /* | |
11084 * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". | |
11085 * Return FAIL for a write error. | |
11086 */ | |
11087 int | |
11088 put_eol(fd) | |
11089 FILE *fd; | |
11090 { | |
11091 if ( | |
11092 #ifdef USE_CRNL | |
11093 ( | |
11094 # ifdef MKSESSION_NL | |
11095 !mksession_nl && | |
11096 # endif | |
11097 (putc('\r', fd) < 0)) || | |
11098 #endif | |
11099 (putc('\n', fd) < 0)) | |
11100 return FAIL; | |
11101 return OK; | |
11102 } | |
11103 | |
11104 /* | |
11105 * Write a line to "fd". | |
11106 * Return FAIL for a write error. | |
11107 */ | |
11108 int | |
11109 put_line(fd, s) | |
11110 FILE *fd; | |
11111 char *s; | |
11112 { | |
11113 if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) | |
11114 return FAIL; | |
11115 return OK; | |
11116 } | |
11117 | |
11118 #ifdef FEAT_VIMINFO | |
11119 /* | |
11120 * ":rviminfo" and ":wviminfo". | |
11121 */ | |
11122 static void | |
11123 ex_viminfo(eap) | |
11124 exarg_T *eap; | |
11125 { | |
11126 char_u *save_viminfo; | |
11127 | |
11128 save_viminfo = p_viminfo; | |
11129 if (*p_viminfo == NUL) | |
11130 p_viminfo = (char_u *)"'100"; | |
11131 if (eap->cmdidx == CMD_rviminfo) | |
11132 { | |
1733 | 11133 if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS |
11134 | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL) | |
7 | 11135 EMSG(_("E195: Cannot open viminfo file for reading")); |
11136 } | |
11137 else | |
11138 write_viminfo(eap->arg, eap->forceit); | |
11139 p_viminfo = save_viminfo; | |
11140 } | |
11141 #endif | |
11142 | |
11143 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) | |
272 | 11144 /* |
2770 | 11145 * Make a dialog message in "buff[DIALOG_MSG_SIZE]". |
310 | 11146 * "format" must contain "%s". |
272 | 11147 */ |
7 | 11148 void |
11149 dialog_msg(buff, format, fname) | |
11150 char_u *buff; | |
11151 char *format; | |
11152 char_u *fname; | |
11153 { | |
11154 if (fname == NULL) | |
11155 fname = (char_u *)_("Untitled"); | |
2770 | 11156 vim_snprintf((char *)buff, DIALOG_MSG_SIZE, format, fname); |
7 | 11157 } |
11158 #endif | |
11159 | |
11160 /* | |
11161 * ":behave {mswin,xterm}" | |
11162 */ | |
11163 static void | |
11164 ex_behave(eap) | |
11165 exarg_T *eap; | |
11166 { | |
11167 if (STRCMP(eap->arg, "mswin") == 0) | |
11168 { | |
11169 set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0); | |
11170 set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0); | |
11171 set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0); | |
11172 set_option_value((char_u *)"keymodel", 0L, | |
11173 (char_u *)"startsel,stopsel", 0); | |
11174 } | |
11175 else if (STRCMP(eap->arg, "xterm") == 0) | |
11176 { | |
11177 set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0); | |
11178 set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0); | |
11179 set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0); | |
11180 set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0); | |
11181 } | |
11182 else | |
11183 EMSG2(_(e_invarg2), eap->arg); | |
11184 } | |
11185 | |
2097
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11186 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11187 /* |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11188 * Function given to ExpandGeneric() to obtain the possible arguments of the |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11189 * ":behave {mswin,xterm}" command. |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11190 */ |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11191 char_u * |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11192 get_behave_arg(xp, idx) |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11193 expand_T *xp UNUSED; |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11194 int idx; |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11195 { |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11196 if (idx == 0) |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11197 return (char_u *)"mswin"; |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11198 if (idx == 1) |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11199 return (char_u *)"xterm"; |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11200 return NULL; |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11201 } |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11202 #endif |
8f72e3512b43
updated for version 7.2.381
Bram Moolenaar <bram@zimbu.org>
parents:
2068
diff
changeset
|
11203 |
7 | 11204 #ifdef FEAT_AUTOCMD |
11205 static int filetype_detect = FALSE; | |
11206 static int filetype_plugin = FALSE; | |
11207 static int filetype_indent = FALSE; | |
11208 | |
11209 /* | |
11210 * ":filetype [plugin] [indent] {on,off,detect}" | |
11211 * on: Load the filetype.vim file to install autocommands for file types. | |
11212 * off: Load the ftoff.vim file to remove all autocommands for file types. | |
11213 * plugin on: load filetype.vim and ftplugin.vim | |
11214 * plugin off: load ftplugof.vim | |
11215 * indent on: load filetype.vim and indent.vim | |
11216 * indent off: load indoff.vim | |
11217 */ | |
11218 static void | |
11219 ex_filetype(eap) | |
11220 exarg_T *eap; | |
11221 { | |
11222 char_u *arg = eap->arg; | |
11223 int plugin = FALSE; | |
11224 int indent = FALSE; | |
11225 | |
11226 if (*eap->arg == NUL) | |
11227 { | |
11228 /* Print current status. */ | |
11229 smsg((char_u *)"filetype detection:%s plugin:%s indent:%s", | |
11230 filetype_detect ? "ON" : "OFF", | |
11231 filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF", | |
11232 filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF"); | |
11233 return; | |
11234 } | |
11235 | |
11236 /* Accept "plugin" and "indent" in any order. */ | |
11237 for (;;) | |
11238 { | |
11239 if (STRNCMP(arg, "plugin", 6) == 0) | |
11240 { | |
11241 plugin = TRUE; | |
11242 arg = skipwhite(arg + 6); | |
11243 continue; | |
11244 } | |
11245 if (STRNCMP(arg, "indent", 6) == 0) | |
11246 { | |
11247 indent = TRUE; | |
11248 arg = skipwhite(arg + 6); | |
11249 continue; | |
11250 } | |
11251 break; | |
11252 } | |
11253 if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) | |
11254 { | |
11255 if (*arg == 'o' || !filetype_detect) | |
11256 { | |
479 | 11257 source_runtime((char_u *)FILETYPE_FILE, TRUE); |
7 | 11258 filetype_detect = TRUE; |
11259 if (plugin) | |
11260 { | |
479 | 11261 source_runtime((char_u *)FTPLUGIN_FILE, TRUE); |
7 | 11262 filetype_plugin = TRUE; |
11263 } | |
11264 if (indent) | |
11265 { | |
479 | 11266 source_runtime((char_u *)INDENT_FILE, TRUE); |
7 | 11267 filetype_indent = TRUE; |
11268 } | |
11269 } | |
11270 if (*arg == 'd') | |
11271 { | |
11272 (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE); | |
717 | 11273 do_modelines(0); |
7 | 11274 } |
11275 } | |
11276 else if (STRCMP(arg, "off") == 0) | |
11277 { | |
11278 if (plugin || indent) | |
11279 { | |
11280 if (plugin) | |
11281 { | |
479 | 11282 source_runtime((char_u *)FTPLUGOF_FILE, TRUE); |
7 | 11283 filetype_plugin = FALSE; |
11284 } | |
11285 if (indent) | |
11286 { | |
479 | 11287 source_runtime((char_u *)INDOFF_FILE, TRUE); |
7 | 11288 filetype_indent = FALSE; |
11289 } | |
11290 } | |
11291 else | |
11292 { | |
479 | 11293 source_runtime((char_u *)FTOFF_FILE, TRUE); |
7 | 11294 filetype_detect = FALSE; |
11295 } | |
11296 } | |
11297 else | |
11298 EMSG2(_(e_invarg2), arg); | |
11299 } | |
11300 | |
11301 /* | |
11302 * ":setfiletype {name}" | |
11303 */ | |
11304 static void | |
11305 ex_setfiletype(eap) | |
11306 exarg_T *eap; | |
11307 { | |
11308 if (!did_filetype) | |
11309 set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL); | |
11310 } | |
11311 #endif | |
11312 | |
11313 static void | |
11314 ex_digraphs(eap) | |
1877 | 11315 exarg_T *eap UNUSED; |
7 | 11316 { |
11317 #ifdef FEAT_DIGRAPHS | |
11318 if (*eap->arg != NUL) | |
11319 putdigraph(eap->arg); | |
11320 else | |
11321 listdigraphs(); | |
11322 #else | |
11323 EMSG(_("E196: No digraphs in this version")); | |
11324 #endif | |
11325 } | |
11326 | |
11327 static void | |
11328 ex_set(eap) | |
11329 exarg_T *eap; | |
11330 { | |
11331 int flags = 0; | |
11332 | |
11333 if (eap->cmdidx == CMD_setlocal) | |
11334 flags = OPT_LOCAL; | |
11335 else if (eap->cmdidx == CMD_setglobal) | |
11336 flags = OPT_GLOBAL; | |
11337 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) && defined(FEAT_BROWSE) | |
11338 if (cmdmod.browse && flags == 0) | |
11339 ex_options(eap); | |
11340 else | |
11341 #endif | |
11342 (void)do_set(eap->arg, flags); | |
11343 } | |
11344 | |
11345 #ifdef FEAT_SEARCH_EXTRA | |
11346 /* | |
11347 * ":nohlsearch" | |
11348 */ | |
11349 static void | |
11350 ex_nohlsearch(eap) | |
1877 | 11351 exarg_T *eap UNUSED; |
7 | 11352 { |
11353 no_hlsearch = TRUE; | |
737 | 11354 redraw_all_later(SOME_VALID); |
7 | 11355 } |
11356 | |
11357 /* | |
698 | 11358 * ":[N]match {group} {pattern}" |
7 | 11359 * Sets nextcmd to the start of the next command, if any. Also called when |
11360 * skipping commands to find the next command. | |
11361 */ | |
11362 static void | |
11363 ex_match(eap) | |
11364 exarg_T *eap; | |
11365 { | |
11366 char_u *p; | |
1349 | 11367 char_u *g = NULL; |
7 | 11368 char_u *end; |
11369 int c; | |
1326 | 11370 int id; |
698 | 11371 |
11372 if (eap->line2 <= 3) | |
1326 | 11373 id = eap->line2; |
698 | 11374 else |
11375 { | |
11376 EMSG(e_invcmd); | |
11377 return; | |
11378 } | |
7 | 11379 |
11380 /* First clear any old pattern. */ | |
11381 if (!eap->skip) | |
1326 | 11382 match_delete(curwin, id, FALSE); |
7 | 11383 |
11384 if (ends_excmd(*eap->arg)) | |
11385 end = eap->arg; | |
11386 else if ((STRNICMP(eap->arg, "none", 4) == 0 | |
11387 && (vim_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) | |
11388 end = eap->arg + 4; | |
11389 else | |
11390 { | |
11391 p = skiptowhite(eap->arg); | |
11392 if (!eap->skip) | |
1326 | 11393 g = vim_strnsave(eap->arg, (int)(p - eap->arg)); |
7 | 11394 p = skipwhite(p); |
11395 if (*p == NUL) | |
11396 { | |
11397 /* There must be two arguments. */ | |
11398 EMSG2(_(e_invarg2), eap->arg); | |
11399 return; | |
11400 } | |
11401 end = skip_regexp(p + 1, *p, TRUE, NULL); | |
11402 if (!eap->skip) | |
11403 { | |
11404 if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) | |
11405 { | |
11406 eap->errmsg = e_trailing; | |
11407 return; | |
11408 } | |
674 | 11409 if (*end != *p) |
11410 { | |
11411 EMSG2(_(e_invarg2), p); | |
11412 return; | |
11413 } | |
7 | 11414 |
11415 c = *end; | |
11416 *end = NUL; | |
1326 | 11417 match_add(curwin, g, p + 1, 10, id); |
11418 vim_free(g); | |
819 | 11419 *end = c; |
7 | 11420 } |
11421 } | |
11422 eap->nextcmd = find_nextcmd(end); | |
11423 } | |
11424 #endif | |
11425 | |
11426 #ifdef FEAT_CRYPT | |
11427 /* | |
11428 * ":X": Get crypt key | |
11429 */ | |
11430 static void | |
11431 ex_X(eap) | |
1877 | 11432 exarg_T *eap UNUSED; |
7 | 11433 { |
2360
d8e4b27cef80
Change 'cryptmethod' from a number to a string option. Make it global-local.
Bram Moolenaar <bram@vim.org>
parents:
2350
diff
changeset
|
11434 if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK) |
2180
f60a0c9cbe6c
Add the blowfish encryption patch from Mohsin Ahmed. Needs more work.
Bram Moolenaar <bram@vim.org>
parents:
2168
diff
changeset
|
11435 (void)get_crypt_key(TRUE, TRUE); |
7 | 11436 } |
11437 #endif | |
11438 | |
11439 #ifdef FEAT_FOLDING | |
11440 static void | |
11441 ex_fold(eap) | |
11442 exarg_T *eap; | |
11443 { | |
11444 if (foldManualAllowed(TRUE)) | |
11445 foldCreate(eap->line1, eap->line2); | |
11446 } | |
11447 | |
11448 static void | |
11449 ex_foldopen(eap) | |
11450 exarg_T *eap; | |
11451 { | |
11452 opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen, | |
11453 eap->forceit, FALSE); | |
11454 } | |
11455 | |
11456 static void | |
11457 ex_folddo(eap) | |
11458 exarg_T *eap; | |
11459 { | |
11460 linenr_T lnum; | |
11461 | |
11462 /* First set the marks for all lines closed/open. */ | |
11463 for (lnum = eap->line1; lnum <= eap->line2; ++lnum) | |
11464 if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) | |
11465 ml_setmarked(lnum); | |
11466 | |
11467 /* Execute the command on the marked lines. */ | |
11468 global_exe(eap->arg); | |
11469 ml_clearmarked(); /* clear rest of the marks */ | |
11470 } | |
11471 #endif |