diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/ex_docmd.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/ex_docmd.c')
| -rw-r--r-- | src/ex_docmd.c | 9109 |
1 files changed, 0 insertions, 9109 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c deleted file mode 100644 index 87ce252434..0000000000 --- a/src/ex_docmd.c +++ /dev/null @@ -1,9109 +0,0 @@ -/* - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * ex_docmd.c: functions for executing an Ex command line. - */ - -#include <string.h> - -#include "vim.h" -#include "ex_docmd.h" -#include "blowfish.h" -#include "buffer.h" -#include "charset.h" -#include "diff.h" -#include "digraph.h" -#include "edit.h" -#include "eval.h" -#include "ex_cmds.h" -#include "ex_cmds2.h" -#include "ex_eval.h" -#include "ex_getln.h" -#include "fileio.h" -#include "fold.h" -#include "getchar.h" -#include "hardcopy.h" -#include "if_cscope.h" -#include "main.h" -#include "mark.h" -#include "mbyte.h" -#include "memline.h" -#include "memory.h" -#include "menu.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "keymap.h" -#include "crypt.h" -#include "file_search.h" -#include "garray.h" -#include "move.h" -#include "normal.h" -#include "ops.h" -#include "option.h" -#include "os_unix.h" -#include "path.h" -#include "quickfix.h" -#include "regexp.h" -#include "screen.h" -#include "search.h" -#include "spell.h" -#include "syntax.h" -#include "tag.h" -#include "term.h" -#include "ui.h" -#include "undo.h" -#include "version.h" -#include "window.h" -#include "os/os.h" - -static int quitmore = 0; -static int ex_pressedreturn = FALSE; - -typedef struct ucmd { - char_u *uc_name; /* The command name */ - long_u uc_argt; /* The argument type */ - char_u *uc_rep; /* The command's replacement string */ - long uc_def; /* The default value for a range/count */ - int uc_compl; /* completion type */ - scid_T uc_scriptID; /* SID where the command was defined */ - char_u *uc_compl_arg; /* completion argument if any */ -} ucmd_T; - -#define UC_BUFFER 1 /* -buffer: local to current buffer */ - -static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; - -#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) -#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) - -static void do_ucmd(exarg_T *eap); -static void ex_command(exarg_T *eap); -static void ex_delcommand(exarg_T *eap); -static char_u *get_user_command_name(int idx); - - -static char_u *do_one_cmd(char_u **, int, struct condstack *, - char_u *(*fgetline)(int, void *, int), - void *cookie); -static void append_command(char_u *cmd); -static char_u *find_command(exarg_T *eap, int *full); - -static void ex_abbreviate(exarg_T *eap); -static void ex_map(exarg_T *eap); -static void ex_unmap(exarg_T *eap); -static void ex_mapclear(exarg_T *eap); -static void ex_abclear(exarg_T *eap); -static void ex_autocmd(exarg_T *eap); -static void ex_doautocmd(exarg_T *eap); -static void ex_bunload(exarg_T *eap); -static void ex_buffer(exarg_T *eap); -static void ex_bmodified(exarg_T *eap); -static void ex_bnext(exarg_T *eap); -static void ex_bprevious(exarg_T *eap); -static void ex_brewind(exarg_T *eap); -static void ex_blast(exarg_T *eap); -static char_u *getargcmd(char_u **); -static char_u *skip_cmd_arg(char_u *p, int rembs); -static int getargopt(exarg_T *eap); - -static int check_more(int, int); -static linenr_T get_address(char_u **, int skip, int to_other_file); -static void get_flags(exarg_T *eap); -# define HAVE_EX_SCRIPT_NI -static void ex_script_ni(exarg_T *eap); -static char_u *invalid_range(exarg_T *eap); -static void correct_range(exarg_T *eap); -static char_u *replace_makeprg(exarg_T *eap, char_u *p, - char_u **cmdlinep); -static char_u *repl_cmdline(exarg_T *eap, char_u *src, int srclen, - char_u *repl, - char_u **cmdlinep); -static void ex_highlight(exarg_T *eap); -static void ex_colorscheme(exarg_T *eap); -static void ex_quit(exarg_T *eap); -static void ex_cquit(exarg_T *eap); -static void ex_quit_all(exarg_T *eap); -static void ex_close(exarg_T *eap); -static void ex_win_close(int forceit, win_T *win, tabpage_T *tp); -static void ex_only(exarg_T *eap); -static void ex_resize(exarg_T *eap); -static void ex_stag(exarg_T *eap); -static void ex_tabclose(exarg_T *eap); -static void ex_tabonly(exarg_T *eap); -static void ex_tabnext(exarg_T *eap); -static void ex_tabmove(exarg_T *eap); -static void ex_tabs(exarg_T *eap); -static void ex_pclose(exarg_T *eap); -static void ex_ptag(exarg_T *eap); -static void ex_pedit(exarg_T *eap); -static void ex_hide(exarg_T *eap); -static void ex_stop(exarg_T *eap); -static void ex_exit(exarg_T *eap); -static void ex_print(exarg_T *eap); -static void ex_goto(exarg_T *eap); -static void ex_preserve(exarg_T *eap); -static void ex_recover(exarg_T *eap); -static void ex_mode(exarg_T *eap); -static void ex_wrongmodifier(exarg_T *eap); -static void ex_find(exarg_T *eap); -static void ex_open(exarg_T *eap); -static void ex_edit(exarg_T *eap); -# define ex_drop ex_ni -# define ex_gui ex_nogui -static void ex_nogui(exarg_T *eap); -# define ex_tearoff ex_ni -# define ex_popup ex_ni -# define ex_simalt ex_ni -# define gui_mch_find_dialog ex_ni -# define gui_mch_replace_dialog ex_ni -# define ex_helpfind ex_ni -static void ex_swapname(exarg_T *eap); -static void ex_syncbind(exarg_T *eap); -static void ex_read(exarg_T *eap); -static void ex_pwd(exarg_T *eap); -static void ex_equal(exarg_T *eap); -static void ex_sleep(exarg_T *eap); -static void do_exmap(exarg_T *eap, int isabbrev); -static void ex_winsize(exarg_T *eap); -static void ex_wincmd(exarg_T *eap); -#if defined(FEAT_GUI) || defined(UNIX) || defined(MSWIN) -static void ex_winpos(exarg_T *eap); -#else -# define ex_winpos ex_ni -#endif -static void ex_operators(exarg_T *eap); -static void ex_put(exarg_T *eap); -static void ex_copymove(exarg_T *eap); -static void ex_submagic(exarg_T *eap); -static void ex_join(exarg_T *eap); -static void ex_at(exarg_T *eap); -static void ex_bang(exarg_T *eap); -static void ex_undo(exarg_T *eap); -static void ex_wundo(exarg_T *eap); -static void ex_rundo(exarg_T *eap); -static void ex_redo(exarg_T *eap); -static void ex_later(exarg_T *eap); -static void ex_redir(exarg_T *eap); -static void ex_redraw(exarg_T *eap); -static void ex_redrawstatus(exarg_T *eap); -static void close_redir(void); -static void ex_mkrc(exarg_T *eap); -static void ex_mark(exarg_T *eap); -static char_u *uc_fun_cmd(void); -static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, - expand_T *xp, - int *compl); -static void ex_normal(exarg_T *eap); -static void ex_startinsert(exarg_T *eap); -static void ex_stopinsert(exarg_T *eap); -static void ex_checkpath(exarg_T *eap); -static void ex_findpat(exarg_T *eap); -static void ex_psearch(exarg_T *eap); -static void ex_tag(exarg_T *eap); -static void ex_tag_cmd(exarg_T *eap, char_u *name); -static char_u *arg_all(void); -static int makeopens(FILE *fd, char_u *dirnow); -static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, - int current_arg_idx); -static void ex_loadview(exarg_T *eap); -static char_u *get_view_file(int c); -static int did_lcd; /* whether ":lcd" was produced for a session */ -static void ex_viminfo(exarg_T *eap); -static void ex_behave(exarg_T *eap); -static void ex_filetype(exarg_T *eap); -static void ex_setfiletype(exarg_T *eap); -static void ex_digraphs(exarg_T *eap); -static void ex_set(exarg_T *eap); -static void ex_nohlsearch(exarg_T *eap); -static void ex_match(exarg_T *eap); -static void ex_X(exarg_T *eap); -static void ex_fold(exarg_T *eap); -static void ex_foldopen(exarg_T *eap); -static void ex_folddo(exarg_T *eap); -#ifndef HAVE_WORKING_LIBINTL -# define ex_language ex_ni -#endif -# define ex_wsverb ex_ni -# define ex_nbclose ex_ni -# define ex_nbkey ex_ni -# define ex_nbstart ex_ni - - - - -/* - * Declare cmdnames[]. - */ -#define DO_DECLARE_EXCMD -#include "ex_cmds_defs.h" - -/* - * Table used to quickly search for a command, based on its first character. - */ -static cmdidx_T cmdidxs[27] = -{ - CMD_append, - CMD_buffer, - CMD_change, - CMD_delete, - CMD_edit, - CMD_file, - CMD_global, - CMD_help, - CMD_insert, - CMD_join, - CMD_k, - CMD_list, - CMD_move, - CMD_next, - CMD_open, - CMD_print, - CMD_quit, - CMD_read, - CMD_substitute, - CMD_t, - CMD_undo, - CMD_vglobal, - CMD_write, - CMD_xit, - CMD_yank, - CMD_z, - CMD_bang -}; - -static char_u dollar_command[2] = {'$', 0}; - - -/* Struct for storing a line inside a while/for loop */ -typedef struct { - char_u *line; /* command line */ - linenr_T lnum; /* sourcing_lnum of the line */ -} wcmd_T; - -/* - * Structure used to store info for line position in a while or for loop. - * This is required, because do_one_cmd() may invoke ex_function(), which - * reads more lines that may come from the while/for loop. - */ -struct loop_cookie { - garray_T *lines_gap; /* growarray with line info */ - int current_line; /* last read line from growarray */ - int repeating; /* TRUE when looping a second time */ - /* When "repeating" is FALSE use "getline" and "cookie" to get lines */ - char_u *(*getline)(int, void *, int); - void *cookie; -}; - -static char_u *get_loop_line(int c, void *cookie, int indent); -static void store_loop_line(garray_T *gap, char_u *line); -static void free_cmdlines(garray_T *gap); - -/* Struct to save a few things while debugging. Used in do_cmdline() only. */ -struct dbg_stuff { - int trylevel; - int force_abort; - except_T *caught_stack; - char_u *vv_exception; - char_u *vv_throwpoint; - int did_emsg; - int got_int; - int did_throw; - int need_rethrow; - int check_cstack; - except_T *current_exception; -}; - -static void save_dbg_stuff(struct dbg_stuff *dsp); -static void restore_dbg_stuff(struct dbg_stuff *dsp); - -static void save_dbg_stuff(struct dbg_stuff *dsp) -{ - dsp->trylevel = trylevel; trylevel = 0; - dsp->force_abort = force_abort; force_abort = FALSE; - dsp->caught_stack = caught_stack; caught_stack = NULL; - dsp->vv_exception = v_exception(NULL); - dsp->vv_throwpoint = v_throwpoint(NULL); - - /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */ - dsp->did_emsg = did_emsg; did_emsg = FALSE; - dsp->got_int = got_int; got_int = FALSE; - dsp->did_throw = did_throw; did_throw = FALSE; - dsp->need_rethrow = need_rethrow; need_rethrow = FALSE; - dsp->check_cstack = check_cstack; check_cstack = FALSE; - dsp->current_exception = current_exception; current_exception = NULL; -} - -static void restore_dbg_stuff(struct dbg_stuff *dsp) -{ - suppress_errthrow = FALSE; - trylevel = dsp->trylevel; - force_abort = dsp->force_abort; - caught_stack = dsp->caught_stack; - (void)v_exception(dsp->vv_exception); - (void)v_throwpoint(dsp->vv_throwpoint); - did_emsg = dsp->did_emsg; - got_int = dsp->got_int; - did_throw = dsp->did_throw; - need_rethrow = dsp->need_rethrow; - check_cstack = dsp->check_cstack; - current_exception = dsp->current_exception; -} - - -/* - * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi" - * command is given. - */ -void -do_exmode ( - int improved /* TRUE for "improved Ex" mode */ -) -{ - int save_msg_scroll; - int prev_msg_row; - linenr_T prev_line; - int changedtick; - - if (improved) - exmode_active = EXMODE_VIM; - else - exmode_active = EXMODE_NORMAL; - State = NORMAL; - - /* When using ":global /pat/ visual" and then "Q" we return to continue - * the :global command. */ - if (global_busy) - return; - - save_msg_scroll = msg_scroll; - ++RedrawingDisabled; /* don't redisplay the window */ - ++no_wait_return; /* don't wait for return */ - - MSG(_("Entering Ex mode. Type \"visual\" to go to Normal mode.")); - while (exmode_active) { - /* Check for a ":normal" command and no more characters left. */ - if (ex_normal_busy > 0 && typebuf.tb_len == 0) { - exmode_active = FALSE; - break; - } - msg_scroll = TRUE; - need_wait_return = FALSE; - ex_pressedreturn = FALSE; - ex_no_reprint = FALSE; - changedtick = curbuf->b_changedtick; - prev_msg_row = msg_row; - prev_line = curwin->w_cursor.lnum; - if (improved) { - cmdline_row = msg_row; - do_cmdline(NULL, getexline, NULL, 0); - } else - do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT); - lines_left = Rows - 1; - - if ((prev_line != curwin->w_cursor.lnum - || changedtick != curbuf->b_changedtick) && !ex_no_reprint) { - if (curbuf->b_ml.ml_flags & ML_EMPTY) - EMSG(_(e_emptybuf)); - else { - if (ex_pressedreturn) { - /* go up one line, to overwrite the ":<CR>" line, so the - * output doesn't contain empty lines. */ - msg_row = prev_msg_row; - if (prev_msg_row == Rows - 1) - msg_row--; - } - msg_col = 0; - print_line_no_prefix(curwin->w_cursor.lnum, FALSE, FALSE); - msg_clr_eos(); - } - } else if (ex_pressedreturn && !ex_no_reprint) { /* must be at EOF */ - if (curbuf->b_ml.ml_flags & ML_EMPTY) - EMSG(_(e_emptybuf)); - else - EMSG(_("E501: At end-of-file")); - } - } - - --RedrawingDisabled; - --no_wait_return; - update_screen(CLEAR); - need_wait_return = FALSE; - msg_scroll = save_msg_scroll; -} - -/* - * Execute a simple command line. Used for translated commands like "*". - */ -int do_cmdline_cmd(char_u *cmd) -{ - return do_cmdline(cmd, NULL, NULL, - DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); -} - -/* - * do_cmdline(): execute one Ex command line - * - * 1. Execute "cmdline" when it is not NULL. - * If "cmdline" is NULL, or more lines are needed, fgetline() is used. - * 2. Split up in parts separated with '|'. - * - * This function can be called recursively! - * - * flags: - * DOCMD_VERBOSE - The command will be included in the error message. - * DOCMD_NOWAIT - Don't call wait_return() and friends. - * DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. - * DOCMD_KEYTYPED - Don't reset KeyTyped. - * DOCMD_EXCRESET - Reset the exception environment (used for debugging). - * DOCMD_KEEPLINE - Store first typed line (for repeating with "."). - * - * return FAIL if cmdline could not be executed, OK otherwise - */ -int do_cmdline(cmdline, fgetline, cookie, flags) -char_u *cmdline; -char_u *(*fgetline)(int, void *, int); -void *cookie; /* argument for fgetline() */ -int flags; -{ - char_u *next_cmdline; /* next cmd to execute */ - char_u *cmdline_copy = NULL; /* copy of cmd line */ - int used_getline = FALSE; /* used "fgetline" to obtain command */ - static int recursive = 0; /* recursive depth */ - int msg_didout_before_start = 0; - int count = 0; /* line number count */ - int did_inc = FALSE; /* incremented RedrawingDisabled */ - int retval = OK; - struct condstack cstack; /* conditional stack */ - garray_T lines_ga; /* keep lines for ":while"/":for" */ - int current_line = 0; /* active line in lines_ga */ - char_u *fname = NULL; /* function or script name */ - linenr_T *breakpoint = NULL; /* ptr to breakpoint field in cookie */ - int *dbg_tick = NULL; /* ptr to dbg_tick field in cookie */ - struct dbg_stuff debug_saved; /* saved things for debug mode */ - int initial_trylevel; - struct msglist **saved_msg_list = NULL; - struct msglist *private_msg_list; - - /* "fgetline" and "cookie" passed to do_one_cmd() */ - char_u *(*cmd_getline)(int, void *, int); - void *cmd_cookie; - struct loop_cookie cmd_loop_cookie; - void *real_cookie; - int getline_is_func; - static int call_depth = 0; /* recursiveness */ - - /* For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory - * location for storing error messages to be converted to an exception. - * This ensures that the do_errthrow() call in do_one_cmd() does not - * combine the messages stored by an earlier invocation of do_one_cmd() - * with the command name of the later one. This would happen when - * BufWritePost autocommands are executed after a write error. */ - saved_msg_list = msg_list; - msg_list = &private_msg_list; - private_msg_list = NULL; - - /* It's possible to create an endless loop with ":execute", catch that - * here. The value of 200 allows nested function calls, ":source", etc. */ - if (call_depth == 200) { - EMSG(_("E169: Command too recursive")); - /* When converting to an exception, we do not include the command name - * since this is not an error of the specific command. */ - do_errthrow((struct condstack *)NULL, (char_u *)NULL); - msg_list = saved_msg_list; - return FAIL; - } - ++call_depth; - - cstack.cs_idx = -1; - cstack.cs_looplevel = 0; - cstack.cs_trylevel = 0; - cstack.cs_emsg_silent_list = NULL; - cstack.cs_lflags = 0; - ga_init(&lines_ga, (int)sizeof(wcmd_T), 10); - - real_cookie = getline_cookie(fgetline, cookie); - - /* Inside a function use a higher nesting level. */ - getline_is_func = getline_equal(fgetline, cookie, get_func_line); - if (getline_is_func && ex_nesting_level == func_level(real_cookie)) - ++ex_nesting_level; - - /* Get the function or script name and the address where the next breakpoint - * line and the debug tick for a function or script are stored. */ - if (getline_is_func) { - fname = func_name(real_cookie); - breakpoint = func_breakpoint(real_cookie); - dbg_tick = func_dbg_tick(real_cookie); - } else if (getline_equal(fgetline, cookie, getsourceline)) { - fname = sourcing_name; - breakpoint = source_breakpoint(real_cookie); - dbg_tick = source_dbg_tick(real_cookie); - } - - /* - * Initialize "force_abort" and "suppress_errthrow" at the top level. - */ - if (!recursive) { - force_abort = FALSE; - suppress_errthrow = FALSE; - } - - /* - * If requested, store and reset the global values controlling the - * exception handling (used when debugging). Otherwise clear it to avoid - * a bogus compiler warning when the optimizer uses inline functions... - */ - if (flags & DOCMD_EXCRESET) - save_dbg_stuff(&debug_saved); - else - memset(&debug_saved, 0, 1); - - initial_trylevel = trylevel; - - /* - * "did_throw" will be set to TRUE when an exception is being thrown. - */ - did_throw = FALSE; - /* - * "did_emsg" will be set to TRUE when emsg() is used, in which case we - * cancel the whole command line, and any if/endif or loop. - * If force_abort is set, we cancel everything. - */ - did_emsg = FALSE; - - /* - * KeyTyped is only set when calling vgetc(). Reset it here when not - * calling vgetc() (sourced command lines). - */ - if (!(flags & DOCMD_KEYTYPED) - && !getline_equal(fgetline, cookie, getexline)) - KeyTyped = FALSE; - - /* - * Continue executing command lines: - * - when inside an ":if", ":while" or ":for" - * - for multiple commands on one line, separated with '|' - * - when repeating until there are no more lines (for ":source") - */ - next_cmdline = cmdline; - do { - getline_is_func = getline_equal(fgetline, cookie, get_func_line); - - /* stop skipping cmds for an error msg after all endif/while/for */ - if (next_cmdline == NULL - && !force_abort - && cstack.cs_idx < 0 - && !(getline_is_func && func_has_abort(real_cookie)) - ) - did_emsg = FALSE; - - /* - * 1. If repeating a line in a loop, get a line from lines_ga. - * 2. If no line given: Get an allocated line with fgetline(). - * 3. If a line is given: Make a copy, so we can mess with it. - */ - - /* 1. If repeating, get a previous line from lines_ga. */ - if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) { - /* Each '|' separated command is stored separately in lines_ga, to - * be able to jump to it. Don't use next_cmdline now. */ - free(cmdline_copy); - cmdline_copy = NULL; - - /* Check if a function has returned or, unless it has an unclosed - * try conditional, aborted. */ - if (getline_is_func) { - if (do_profiling == PROF_YES) - func_line_end(real_cookie); - if (func_has_ended(real_cookie)) { - retval = FAIL; - break; - } - } else if (do_profiling == PROF_YES - && getline_equal(fgetline, cookie, getsourceline)) - script_line_end(); - - /* Check if a sourced file hit a ":finish" command. */ - if (source_finished(fgetline, cookie)) { - retval = FAIL; - break; - } - - /* If breakpoints have been added/deleted need to check for it. */ - if (breakpoint != NULL && dbg_tick != NULL - && *dbg_tick != debug_tick) { - *breakpoint = dbg_find_breakpoint( - getline_equal(fgetline, cookie, getsourceline), - fname, sourcing_lnum); - *dbg_tick = debug_tick; - } - - next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line; - sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; - - /* Did we encounter a breakpoint? */ - if (breakpoint != NULL && *breakpoint != 0 - && *breakpoint <= sourcing_lnum) { - dbg_breakpoint(fname, sourcing_lnum); - /* Find next breakpoint. */ - *breakpoint = dbg_find_breakpoint( - getline_equal(fgetline, cookie, getsourceline), - fname, sourcing_lnum); - *dbg_tick = debug_tick; - } - if (do_profiling == PROF_YES) { - if (getline_is_func) - func_line_start(real_cookie); - else if (getline_equal(fgetline, cookie, getsourceline)) - script_line_start(); - } - } - - if (cstack.cs_looplevel > 0) { - /* Inside a while/for loop we need to store the lines and use them - * again. Pass a different "fgetline" function to do_one_cmd() - * below, so that it stores lines in or reads them from - * "lines_ga". Makes it possible to define a function inside a - * while/for loop. */ - cmd_getline = get_loop_line; - cmd_cookie = (void *)&cmd_loop_cookie; - cmd_loop_cookie.lines_gap = &lines_ga; - cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; - cmd_loop_cookie.cookie = cookie; - cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); - } else { - cmd_getline = fgetline; - cmd_cookie = cookie; - } - - /* 2. If no line given, get an allocated line with fgetline(). */ - if (next_cmdline == NULL) { - /* - * Need to set msg_didout for the first line after an ":if", - * otherwise the ":if" will be overwritten. - */ - if (count == 1 && getline_equal(fgetline, cookie, getexline)) - msg_didout = TRUE; - if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, - cstack.cs_idx < - 0 ? 0 : (cstack.cs_idx + 1) * 2 - )) == NULL) { - /* Don't call wait_return for aborted command line. The NULL - * returned for the end of a sourced file or executed function - * doesn't do this. */ - if (KeyTyped && !(flags & DOCMD_REPEAT)) - need_wait_return = FALSE; - retval = FAIL; - break; - } - used_getline = TRUE; - - /* - * Keep the first typed line. Clear it when more lines are typed. - */ - if (flags & DOCMD_KEEPLINE) { - free(repeat_cmdline); - if (count == 0) - repeat_cmdline = vim_strsave(next_cmdline); - else - repeat_cmdline = NULL; - } - } - /* 3. Make a copy of the command so we can mess with it. */ - else if (cmdline_copy == NULL) { - next_cmdline = vim_strsave(next_cmdline); - if (next_cmdline == NULL) { - EMSG(_(e_outofmem)); - retval = FAIL; - break; - } - } - cmdline_copy = next_cmdline; - - /* - * Save the current line when inside a ":while" or ":for", and when - * the command looks like a ":while" or ":for", because we may need it - * later. When there is a '|' and another command, it is stored - * separately, because we need to be able to jump back to it from an - * :endwhile/:endfor. - */ - if (current_line == lines_ga.ga_len - && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) { - store_loop_line(&lines_ga, next_cmdline); - } - did_endif = FALSE; - - if (count++ == 0) { - /* - * All output from the commands is put below each other, without - * waiting for a return. Don't do this when executing commands - * from a script or when being called recursive (e.g. for ":e - * +command file"). - */ - if (!(flags & DOCMD_NOWAIT) && !recursive) { - msg_didout_before_start = msg_didout; - msg_didany = FALSE; /* no output yet */ - msg_start(); - msg_scroll = TRUE; /* put messages below each other */ - ++no_wait_return; /* don't wait for return until finished */ - ++RedrawingDisabled; - did_inc = TRUE; - } - } - - if (p_verbose >= 15 && sourcing_name != NULL) { - ++no_wait_return; - verbose_enter_scroll(); - - smsg((char_u *)_("line %" PRId64 ": %s"), - (int64_t)sourcing_lnum, cmdline_copy); - if (msg_silent == 0) - msg_puts((char_u *)"\n"); /* don't overwrite this */ - - verbose_leave_scroll(); - --no_wait_return; - } - - /* - * 2. Execute one '|' separated command. - * do_one_cmd() will return NULL if there is no trailing '|'. - * "cmdline_copy" can change, e.g. for '%' and '#' expansion. - */ - ++recursive; - next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE, - &cstack, - cmd_getline, cmd_cookie); - --recursive; - - if (cmd_cookie == (void *)&cmd_loop_cookie) - /* Use "current_line" from "cmd_loop_cookie", it may have been - * incremented when defining a function. */ - current_line = cmd_loop_cookie.current_line; - - if (next_cmdline == NULL) { - free(cmdline_copy); - cmdline_copy = NULL; - /* - * If the command was typed, remember it for the ':' register. - * Do this AFTER executing the command to make :@: work. - */ - if (getline_equal(fgetline, cookie, getexline) - && new_last_cmdline != NULL) { - free(last_cmdline); - last_cmdline = new_last_cmdline; - new_last_cmdline = NULL; - } - } else { - /* need to copy the command after the '|' to cmdline_copy, for the - * next do_one_cmd() */ - STRMOVE(cmdline_copy, next_cmdline); - next_cmdline = cmdline_copy; - } - - - /* reset did_emsg for a function that is not aborted by an error */ - if (did_emsg && !force_abort - && getline_equal(fgetline, cookie, get_func_line) - && !func_has_abort(real_cookie)) - did_emsg = FALSE; - - if (cstack.cs_looplevel > 0) { - ++current_line; - - /* - * An ":endwhile", ":endfor" and ":continue" is handled here. - * If we were executing commands, jump back to the ":while" or - * ":for". - * If we were not executing commands, decrement cs_looplevel. - */ - if (cstack.cs_lflags & (CSL_HAD_CONT | CSL_HAD_ENDLOOP)) { - cstack.cs_lflags &= ~(CSL_HAD_CONT | CSL_HAD_ENDLOOP); - - /* Jump back to the matching ":while" or ":for". Be careful - * not to use a cs_line[] from an entry that isn't a ":while" - * or ":for": It would make "current_line" invalid and can - * cause a crash. */ - if (!did_emsg && !got_int && !did_throw - && cstack.cs_idx >= 0 - && (cstack.cs_flags[cstack.cs_idx] - & (CSF_WHILE | CSF_FOR)) - && cstack.cs_line[cstack.cs_idx] >= 0 - && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE)) { - current_line = cstack.cs_line[cstack.cs_idx]; - /* remember we jumped there */ - cstack.cs_lflags |= CSL_HAD_LOOP; - line_breakcheck(); /* check if CTRL-C typed */ - - /* Check for the next breakpoint at or after the ":while" - * or ":for". */ - if (breakpoint != NULL) { - *breakpoint = dbg_find_breakpoint( - getline_equal(fgetline, cookie, getsourceline), - fname, - ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1); - *dbg_tick = debug_tick; - } - } else { - /* can only get here with ":endwhile" or ":endfor" */ - if (cstack.cs_idx >= 0) - rewind_conditionals(&cstack, cstack.cs_idx - 1, - CSF_WHILE | CSF_FOR, &cstack.cs_looplevel); - } - } - /* - * For a ":while" or ":for" we need to remember the line number. - */ - else if (cstack.cs_lflags & CSL_HAD_LOOP) { - cstack.cs_lflags &= ~CSL_HAD_LOOP; - cstack.cs_line[cstack.cs_idx] = current_line - 1; - } - } - - /* - * When not inside any ":while" loop, clear remembered lines. - */ - if (cstack.cs_looplevel == 0) { - if (lines_ga.ga_len > 0) { - sourcing_lnum = - ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; - free_cmdlines(&lines_ga); - } - current_line = 0; - } - - /* - * A ":finally" makes did_emsg, got_int, and did_throw pending for - * being restored at the ":endtry". Reset them here and set the - * ACTIVE and FINALLY flags, so that the finally clause gets executed. - * This includes the case where a missing ":endif", ":endwhile" or - * ":endfor" was detected by the ":finally" itself. - */ - if (cstack.cs_lflags & CSL_HAD_FINA) { - cstack.cs_lflags &= ~CSL_HAD_FINA; - report_make_pending(cstack.cs_pending[cstack.cs_idx] - & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW), - did_throw ? (void *)current_exception : NULL); - did_emsg = got_int = did_throw = FALSE; - cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY; - } - - /* Update global "trylevel" for recursive calls to do_cmdline() from - * within this loop. */ - trylevel = initial_trylevel + cstack.cs_trylevel; - - /* - * If the outermost try conditional (across function calls and sourced - * files) is aborted because of an error, an interrupt, or an uncaught - * exception, cancel everything. If it is left normally, reset - * force_abort to get the non-EH compatible abortion behavior for - * the rest of the script. - */ - if (trylevel == 0 && !did_emsg && !got_int && !did_throw) - force_abort = FALSE; - - /* Convert an interrupt to an exception if appropriate. */ - (void)do_intthrow(&cstack); - - } - /* - * Continue executing command lines when: - * - no CTRL-C typed, no aborting error, no exception thrown or try - * conditionals need to be checked for executing finally clauses or - * catching an interrupt exception - * - didn't get an error message or lines are not typed - * - there is a command after '|', inside a :if, :while, :for or :try, or - * looping for ":source" command or function call. - */ - while (!((got_int - || (did_emsg && force_abort) || did_throw - ) - && cstack.cs_trylevel == 0 - ) - && !(did_emsg - /* Keep going when inside try/catch, so that the error can be - * deal with, except when it is a syntax error, it may cause - * the :endtry to be missed. */ - && (cstack.cs_trylevel == 0 || did_emsg_syntax) - && used_getline - && (getline_equal(fgetline, cookie, getexmodeline) - || getline_equal(fgetline, cookie, getexline))) - && (next_cmdline != NULL - || cstack.cs_idx >= 0 - || (flags & DOCMD_REPEAT))); - - free(cmdline_copy); - did_emsg_syntax = FALSE; - free_cmdlines(&lines_ga); - ga_clear(&lines_ga); - - if (cstack.cs_idx >= 0) { - /* - * If a sourced file or executed function ran to its end, report the - * unclosed conditional. - */ - if (!got_int && !did_throw - && ((getline_equal(fgetline, cookie, getsourceline) - && !source_finished(fgetline, cookie)) - || (getline_equal(fgetline, cookie, get_func_line) - && !func_has_ended(real_cookie)))) { - if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY) - EMSG(_(e_endtry)); - else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE) - EMSG(_(e_endwhile)); - else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR) - EMSG(_(e_endfor)); - else - EMSG(_(e_endif)); - } - - /* - * Reset "trylevel" in case of a ":finish" or ":return" or a missing - * ":endtry" in a sourced file or executed function. If the try - * conditional is in its finally clause, ignore anything pending. - * If it is in a catch clause, finish the caught exception. - * Also cleanup any "cs_forinfo" structures. - */ - do { - int idx = cleanup_conditionals(&cstack, 0, TRUE); - - if (idx >= 0) - --idx; /* remove try block not in its finally clause */ - rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR, - &cstack.cs_looplevel); - } while (cstack.cs_idx >= 0); - trylevel = initial_trylevel; - } - - /* If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory - * lack was reported above and the error message is to be converted to an - * exception, do this now after rewinding the cstack. */ - do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line) - ? (char_u *)"endfunction" : (char_u *)NULL); - - if (trylevel == 0) { - /* - |