Mercurial > vim
diff src/ex_cmds2.c @ 32670:695b50472e85
Fix line endings issue
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 26 Jun 2023 13:13:12 +0200 |
parents | 448aef880252 |
children | 7c30841c60a0 |
line wrap: on
line diff
--- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -1,998 +1,998 @@ -/* vi:set ts=8 sts=4 sw=4 noet: - * - * 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_cmds2.c: some more functions for command line commands - */ - -#include "vim.h" -#include "version.h" - -/* - * If 'autowrite' option set, try to write the file. - * Careful: autocommands may make "buf" invalid! - * - * return FAIL for failure, OK otherwise - */ - int -autowrite(buf_T *buf, int forceit) -{ - int r; - bufref_T bufref; - - if (!(p_aw || p_awa) || !p_write - // never autowrite a "nofile" or "nowrite" buffer - || bt_dontwrite(buf) - || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) - return FAIL; - set_bufref(&bufref, buf); - r = buf_write_all(buf, forceit); - - // Writing may succeed but the buffer still changed, e.g., when there is a - // conversion error. We do want to return FAIL then. - if (bufref_valid(&bufref) && bufIsChanged(buf)) - r = FAIL; - return r; -} - -/* - * Flush all buffers, except the ones that are readonly or are never written. - */ - void -autowrite_all(void) -{ - buf_T *buf; - - if (!(p_aw || p_awa) || !p_write) - return; - FOR_ALL_BUFFERS(buf) - if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf)) - { - bufref_T bufref; - - set_bufref(&bufref, buf); - - (void)buf_write_all(buf, FALSE); - - // an autocommand may have deleted the buffer - if (!bufref_valid(&bufref)) - buf = firstbuf; - } -} - -/* - * Return TRUE if buffer was changed and cannot be abandoned. - * For flags use the CCGD_ values. - */ - int -check_changed(buf_T *buf, int flags) -{ - int forceit = (flags & CCGD_FORCEIT); - bufref_T bufref; - - set_bufref(&bufref, buf); - - if ( !forceit - && bufIsChanged(buf) - && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1) - && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) - { -#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) - if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) - { -# ifdef FEAT_TERMINAL - if (term_job_running(buf->b_term)) - { - return term_confirm_stop(buf) == FAIL; - } -# endif - - buf_T *buf2; - int count = 0; - - if (flags & CCGD_ALLBUF) - FOR_ALL_BUFFERS(buf2) - if (bufIsChanged(buf2) - && (buf2->b_ffname != NULL -# ifdef FEAT_BROWSE - || (cmdmod.cmod_flags & CMOD_BROWSE) -# endif - )) - ++count; - if (!bufref_valid(&bufref)) - // Autocommand deleted buffer, oops! It's not changed now. - return FALSE; - - dialog_changed(buf, count > 1); - - if (!bufref_valid(&bufref)) - // Autocommand deleted buffer, oops! It's not changed now. - return FALSE; - return bufIsChanged(buf); - } -#endif - if (flags & CCGD_EXCMD) - no_write_message(); - else - no_write_message_nobang(curbuf); - return TRUE; - } - return FALSE; -} - -#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) - -#if defined(FEAT_BROWSE) || defined(PROTO) -/* - * When wanting to write a file without a file name, ask the user for a name. - */ - void -browse_save_fname(buf_T *buf) -{ - if (buf->b_fname != NULL) - return; - - char_u *fname; - - fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), - NULL, NULL, NULL, NULL, buf); - if (fname == NULL) - return; - - if (setfname(buf, fname, NULL, TRUE) == OK) - buf->b_flags |= BF_NOTEDITED; - vim_free(fname); -} -#endif - -/* - * Ask the user what to do when abandoning a changed buffer. - * Must check 'write' option first! - */ - void -dialog_changed( - buf_T *buf, - int checkall) // may abandon all changed buffers -{ - char_u buff[DIALOG_MSG_SIZE]; - int ret; - buf_T *buf2; - exarg_T ea; - - dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname); - if (checkall) - ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); - else - ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); - - // Init ea pseudo-structure, this is needed for the check_overwrite() - // function. - CLEAR_FIELD(ea); - - if (ret == VIM_YES) - { -#ifdef FEAT_BROWSE - // May get file name, when there is none - browse_save_fname(buf); -#endif - if (buf->b_fname != NULL && check_overwrite(&ea, buf, - buf->b_fname, buf->b_ffname, FALSE) == OK) - // didn't hit Cancel - (void)buf_write_all(buf, FALSE); - } - else if (ret == VIM_NO) - { - unchanged(buf, TRUE, FALSE); - } - else if (ret == VIM_ALL) - { - /* - * Write all modified files that can be written. - * Skip readonly buffers, these need to be confirmed - * individually. - */ - FOR_ALL_BUFFERS(buf2) - { - if (bufIsChanged(buf2) - && (buf2->b_ffname != NULL -#ifdef FEAT_BROWSE - || (cmdmod.cmod_flags & CMOD_BROWSE) -#endif - ) - && !bt_dontwrite(buf2) - && !buf2->b_p_ro) - { - bufref_T bufref; - - set_bufref(&bufref, buf2); -#ifdef FEAT_BROWSE - // May get file name, when there is none - browse_save_fname(buf2); -#endif - if (buf2->b_fname != NULL && check_overwrite(&ea, buf2, - buf2->b_fname, buf2->b_ffname, FALSE) == OK) - // didn't hit Cancel - (void)buf_write_all(buf2, FALSE); - - // an autocommand may have deleted the buffer - if (!bufref_valid(&bufref)) - buf2 = firstbuf; - } - } - } - else if (ret == VIM_DISCARDALL) - { - /* - * mark all buffers as unchanged - */ - FOR_ALL_BUFFERS(buf2) - unchanged(buf2, TRUE, FALSE); - } -} -#endif - -/* - * Return TRUE if the buffer "buf" can be abandoned, either by making it - * hidden, autowriting it or unloading it. - */ - int -can_abandon(buf_T *buf, int forceit) -{ - return ( buf_hide(buf) - || !bufIsChanged(buf) - || buf->b_nwindows > 1 - || autowrite(buf, forceit) == OK - || forceit); -} - -/* - * Add a buffer number to "bufnrs", unless it's already there. - */ - static void -add_bufnum(int *bufnrs, int *bufnump, int nr) -{ - int i; - - for (i = 0; i < *bufnump; ++i) - if (bufnrs[i] == nr) - return; - bufnrs[*bufnump] = nr; - *bufnump = *bufnump + 1; -} - -/* - * Return TRUE if any buffer was changed and cannot be abandoned. - * That changed buffer becomes the current buffer. - * When "unload" is TRUE the current buffer is unloaded instead of making it - * hidden. This is used for ":q!". - */ - int -check_changed_any( - int hidden, // Only check hidden buffers - int unload) -{ - int ret = FALSE; - buf_T *buf; - int save; - int i; - int bufnum = 0; - int bufcount = 0; - int *bufnrs; - tabpage_T *tp; - win_T *wp; - - // Make a list of all buffers, with the most important ones first. - FOR_ALL_BUFFERS(buf) - ++bufcount; - - if (bufcount == 0) - return FALSE; - - bufnrs = ALLOC_MULT(int, bufcount); - if (bufnrs == NULL) - return FALSE; - - // curbuf - bufnrs[bufnum++] = curbuf->b_fnum; - - // buffers in current tab - FOR_ALL_WINDOWS(wp) - if (wp->w_buffer != curbuf) - add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); - - // buffers in other tabs - FOR_ALL_TABPAGES(tp) - if (tp != curtab) - FOR_ALL_WINDOWS_IN_TAB(tp, wp) - add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); - - // any other buffer - FOR_ALL_BUFFERS(buf) - add_bufnum(bufnrs, &bufnum, buf->b_fnum); - - for (i = 0; i < bufnum; ++i) - { - buf = buflist_findnr(bufnrs[i]); - if (buf == NULL) - continue; - if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) - { - bufref_T bufref; - - set_bufref(&bufref, buf); -#ifdef FEAT_TERMINAL - if (term_job_running(buf->b_term)) - { - if (term_try_stop_job(buf) == FAIL) - break; - } - else -#endif - // Try auto-writing the buffer. If this fails but the buffer no - // longer exists it's not changed, that's OK. - if (check_changed(buf, (p_awa ? CCGD_AW : 0) - | CCGD_MULTWIN - | CCGD_ALLBUF) && bufref_valid(&bufref)) - break; // didn't save - still changes - } - } - - if (i >= bufnum) - goto theend; - - // Get here if "buf" cannot be abandoned. - ret = TRUE; - exiting = FALSE; -#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) - /* - * When ":confirm" used, don't give an error message. - */ - if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) -#endif - { - // There must be a wait_return() for this message, do_buffer() - // may cause a redraw. But wait_return() is a no-op when vgetc() - // is busy (Quit used from window menu), then make sure we don't - // cause a scroll up. - if (vgetc_busy > 0) - { - msg_row = cmdline_row; - msg_col = 0; - msg_didout = FALSE; - } - if ( -#ifdef FEAT_TERMINAL - term_job_running(buf->b_term) - ? semsg(_(e_job_still_running_in_buffer_str), buf->b_fname) - : -#endif - semsg(_(e_no_write_since_last_change_for_buffer_str), - buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) - { - save = no_wait_return; - no_wait_return = FALSE; - wait_return(FALSE); - no_wait_return = save; - } - } - - // Try to find a window that contains the buffer. - if (buf != curbuf) - FOR_ALL_TAB_WINDOWS(tp, wp) - if (wp->w_buffer == buf) - { - bufref_T bufref; - - set_bufref(&bufref, buf); - - goto_tabpage_win(tp, wp); - - // Paranoia: did autocmd wipe out the buffer with changes? - if (!bufref_valid(&bufref)) - goto theend; - goto buf_found; - } -buf_found: - - // Open the changed buffer in the current window. - if (buf != curbuf) - set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO); - -theend: - vim_free(bufnrs); - return ret; -} - -/* - * return FAIL if there is no file name, OK if there is one - * give error message for FAIL - */ - int -check_fname(void) -{ - if (curbuf->b_ffname == NULL) - { - emsg(_(e_no_file_name)); - return FAIL; - } - return OK; -} - -/* - * flush the contents of a buffer, unless it has no file name - * - * return FAIL for failure, OK otherwise - */ - int -buf_write_all(buf_T *buf, int forceit) -{ - int retval; - buf_T *old_curbuf = curbuf; - - retval = (buf_write(buf, buf->b_ffname, buf->b_fname, - (linenr_T)1, buf->b_ml.ml_line_count, NULL, - FALSE, forceit, TRUE, FALSE)); - if (curbuf != old_curbuf) - { - msg_source(HL_ATTR(HLF_W)); - msg(_("Warning: Entered other buffer unexpectedly (check autocommands)")); - } - return retval; -} - -/* - * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" - */ - void -ex_listdo(exarg_T *eap) -{ - int i; - win_T *wp; - tabpage_T *tp; - buf_T *buf = curbuf; - int next_fnum = 0; -#if defined(FEAT_SYN_HL) - char_u *save_ei = NULL; -#endif -#ifdef FEAT_QUICKFIX - int qf_size = 0; - int qf_idx; -#endif - -#ifndef FEAT_QUICKFIX - if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || - eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) - { - ex_ni(eap); - return; - } -#endif - -#if defined(FEAT_SYN_HL) - if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) - { - // Don't do syntax HL autocommands. Skipping the syntax file is a - // great speed improvement. - save_ei = au_event_disable(",Syntax"); - - FOR_ALL_BUFFERS(buf) - buf->b_flags &= ~BF_SYN_SET; - buf = curbuf; - } -#endif -#ifdef FEAT_CLIPBOARD - start_global_changes(); -#endif - - if (eap->cmdidx == CMD_windo - || eap->cmdidx == CMD_tabdo - || buf_hide(curbuf) - || !check_changed(curbuf, CCGD_AW - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) - { - i = 0; - // start at the eap->line1 argument/window/buffer - wp = firstwin; - tp = first_tabpage; - switch (eap->cmdidx) - { - case CMD_windo: - for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) - i++; - break; - case CMD_tabdo: - for ( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) - i++; - break; - case CMD_argdo: - i = eap->line1 - 1; - break; - default: - break; - } - // set pcmark now - if (eap->cmdidx == CMD_bufdo) - { - // Advance to the first listed buffer after "eap->line1". - for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1 - || !buf->b_p_bl); buf = buf->b_next) - if (buf->b_fnum > eap->line2) - { - buf = NULL; - break; - } - if (buf != NULL) - goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); - } -#ifdef FEAT_QUICKFIX - else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo - || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) - { - qf_size = qf_get_valid_size(eap); - if (qf_size <= 0 || eap->line1 > qf_size) - buf = NULL; - else - { - save_clear_shm_value(); - ex_cc(eap); - restore_shm_value(); - - buf = curbuf; - i = eap->line1 - 1; - if (eap->addr_count <= 0) - // default is all the quickfix/location list entries - eap->line2 = qf_size; - } - } -#endif - else - setpcmark(); - listcmd_busy = TRUE; // avoids setting pcmark below - - while (!got_int && buf != NULL) - { - if (eap->cmdidx == CMD_argdo) - { - // go to argument "i" - if (i == ARGCOUNT) - break; - // Don't call do_argfile() when already there, it will try - // reloading the file. - if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) - { - // Clear 'shm' to avoid that the file message overwrites - // any output from the command. - save_clear_shm_value(); - do_argfile(eap, i); - restore_shm_value(); - } - if (curwin->w_arg_idx != i) - break; - } - else if (eap->cmdidx == CMD_windo) - { - // go to window "wp" - if (!win_valid(wp)) - break; - win_goto(wp); - if (curwin != wp) - break; // something must be wrong - wp = curwin->w_next; - } - else if (eap->cmdidx == CMD_tabdo) - { - // go to window "tp" - if (!valid_tabpage(tp)) - break; - goto_tabpage_tp(tp, TRUE, TRUE); - tp = tp->tp_next; - } - else if (eap->cmdidx == CMD_bufdo) - { - // Remember the number of the next listed buffer, in case - // ":bwipe" is used or autocommands do something strange. - next_fnum = -1; - for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next) - if (buf->b_p_bl) - { - next_fnum = buf->b_fnum; - break; - } - } - - ++i; - - // execute the command - do_cmdline(eap->arg, eap->getline, eap->cookie, - DOCMD_VERBOSE + DOCMD_NOWAIT); - - if (eap->cmdidx == CMD_bufdo) - { - // Done? - if (next_fnum < 0 || next_fnum > eap->line2) - break; - // Check if the buffer still exists. - FOR_ALL_BUFFERS(buf) - if (buf->b_fnum == next_fnum) - break; - if (buf == NULL) - break; - - // Go to the next buffer. Clear 'shm' to avoid that the file - // message overwrites any output from the command. - save_clear_shm_value(); - goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); - restore_shm_value(); - - // If autocommands took us elsewhere, quit here. - if (curbuf->b_fnum != next_fnum) - break; - } - -#ifdef FEAT_QUICKFIX - if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo - || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) - { - if (i >= qf_size || i >= eap->line2) - break; - - qf_idx = qf_get_cur_idx(eap); - - save_clear_shm_value(); - ex_cnext(eap); - restore_shm_value(); - - // If jumping to the next quickfix entry fails, quit here - if (qf_get_cur_idx(eap) == qf_idx) - break; - } -#endif - - if (eap->cmdidx == CMD_windo) - { - validate_cursor(); // cursor may have moved - - // required when 'scrollbind' has been set - if (curwin->w_p_scb) - do_check_scrollbind(TRUE); - } - - if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo) - if (i+1 > eap->line2) - break; - if (eap->cmdidx == CMD_argdo && i >= eap->line2) - break; - } - listcmd_busy = FALSE; - } - -#if defined(FEAT_SYN_HL) - if (save_ei != NULL) - { - buf_T *bnext; - aco_save_T aco; - - au_event_restore(save_ei); - - for (buf = firstbuf; buf != NULL; buf = bnext) - { - bnext = buf->b_next; - if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) - { - buf->b_flags &= ~BF_SYN_SET; - - // buffer was opened while Syntax autocommands were disabled, - // need to trigger them now. - if (buf == curbuf) - apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, - curbuf->b_fname, TRUE, curbuf); - else - { - aucmd_prepbuf(&aco, buf); - if (curbuf == buf) - { - apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, - buf->b_fname, TRUE, buf); - aucmd_restbuf(&aco); - } - } - - // start over, in case autocommands messed things up. - bnext = firstbuf; - } - } - } -#endif -#ifdef FEAT_CLIPBOARD - end_global_changes(); -#endif -} - -#ifdef FEAT_EVAL -/* - * ":compiler[!] {name}" - */ - void -ex_compiler(exarg_T *eap) -{ - char_u *buf; - char_u *old_cur_comp = NULL; - char_u *p; - - if (*eap->arg == NUL) - { - // List all compiler scripts. - do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')"); - // ) keep the indenter happy... - return; - } - - buf = alloc(STRLEN(eap->arg) + 14); - if (buf == NULL) - return; - - if (eap->forceit) - { - // ":compiler! {name}" sets global options - do_cmdline_cmd((char_u *) - "command -nargs=* CompilerSet set <args>"); - } - else - { - // ":compiler! {name}" sets local options. - // To remain backwards compatible "current_compiler" is always - // used. A user's compiler plugin may set it, the distributed - // plugin will then skip the settings. Afterwards set - // "b:current_compiler" and restore "current_compiler". - // Explicitly prepend "g:" to make it work in a function. - old_cur_comp = get_var_value((char_u *)"g:current_compiler"); - if (old_cur_comp != NULL) - old_cur_comp = vim_strsave(old_cur_comp); - do_cmdline_cmd((char_u *) - "command -nargs=* -keepscript CompilerSet setlocal <args>"); - } - do_unlet((char_u *)"g:current_compiler", TRUE); - do_unlet((char_u *)"b:current_compiler", TRUE); - - sprintf((char *)buf, "compiler/%s.vim", eap->arg); - if (source_runtime(buf, DIP_ALL) == FAIL) - semsg(_(e_compiler_not_supported_str), eap->arg); - vim_free(buf); - - do_cmdline_cmd((char_u *)":delcommand CompilerSet"); - - // Set "b:current_compiler" from "current_compiler". - p = get_var_value((char_u *)"g:current_compiler"); - if (p != NULL) - set_internal_string_var((char_u *)"b:current_compiler", p); - - // Restore "current_compiler" for ":compiler {name}". - if (!eap->forceit) - { - if (old_cur_comp != NULL) - { - set_internal_string_var((char_u *)"g:current_compiler", - old_cur_comp); - vim_free(old_cur_comp); - } - else - do_unlet((char_u *)"g:current_compiler", TRUE); - } -} -#endif - -#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO) - -# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO) -/* - * Detect Python 3 or 2, and initialize 'pyxversion'. - */ - void -init_pyxversion(void) -{ - if (p_pyx == 0) - { - if (python3_enabled(FALSE)) - p_pyx = 3; - else if (python_enabled(FALSE)) - p_pyx = 2; - } -} -# endif - -/* - * Does a file contain one of the following strings at the beginning of any - * line? - * "#!(any string)python2" => returns 2 - * "#!(any string)python3" => returns 3 - * "# requires python 2.x" => returns 2 - * "# requires python 3.x" => returns 3 - * otherwise return 0. - */ - static int -requires_py_version(char_u *filename) -{ - FILE *file; - int requires_py_version = 0; - int i, lines; - - lines = (int)p_mls; - if (lines < 0) - lines = 5; - - file = mch_fopen((char *)filename, "r"); - if (file == NULL) - return 0; - - for (i = 0; i < lines; i++) - { - if (vim_fgets(IObuff, IOSIZE, file)) - break; - if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!') - { - // Check shebang. - if (strstr((char *)IObuff + 2, "python2") != NULL) - { - requires_py_version = 2; - break; - } - if (strstr((char *)IObuff + 2, "python3") != NULL) - { - requires_py_version = 3; - break; - } - } - IObuff[21] = '\0'; - if (STRCMP("# requires python 2.x", IObuff) == 0) - { - requires_py_version = 2; - break; - } - if (STRCMP("# requires python 3.x", IObuff) == 0) - { - requires_py_version = 3; - break; - } - } - fclose(file); - return requires_py_version; -} - - -/* - * Source a python file using the requested python version. - */ - static void -source_pyx_file(exarg_T *eap, char_u *fname) -{ - exarg_T ex; - int v = requires_py_version(fname); - -# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) - init_pyxversion(); -# endif - if (v == 0) - { -# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) - // user didn't choose a preference, 'pyx' is used - v = p_pyx; -# elif defined(FEAT_PYTHON) - v = 2; -# elif defined(FEAT_PYTHON3) - v = 3; -# endif - } - - /* - * now source, if required python version is not supported show - * unobtrusive message. - */ - if (eap == NULL) - CLEAR_FIELD(ex); - else - ex = *eap; - ex.arg = fname; - ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3"); - - if (v == 2) - { -# ifdef FEAT_PYTHON - ex_pyfile(&ex); -# else - vim_snprintf((char *)IObuff, IOSIZE, - _("W20: Required python version 2.x not supported, ignoring file: %s"), - fname); - msg((char *)IObuff); -# endif - return; - } - else - { -# ifdef FEAT_PYTHON3 - ex_py3file(&ex); -# else - vim_snprintf((char *)IObuff, IOSIZE, - _("W21: Required python version 3.x not supported, ignoring file: %s"), - fname); - msg((char *)IObuff); -# endif - return; - } -} - -/* - * ":pyxfile {fname}" - */ - void -ex_pyxfile(exarg_T *eap) -{ - source_pyx_file(eap, eap->arg); -} - -/* - * ":pyx" - */ - void -ex_pyx(exarg_T *eap) -{ -# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) - init_pyxversion(); - if (p_pyx == 2) - ex_python(eap); - else - ex_py3(eap); -# elif defined(FEAT_PYTHON) - ex_python(eap); -# elif defined(FEAT_PYTHON3) - ex_py3(eap); -# endif -} - -/* - * ":pyxdo" - */ - void -ex_pyxdo(exarg_T *eap) -{ -# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) - init_pyxversion(); - if (p_pyx == 2) - ex_pydo(eap); - else - ex_py3do(eap); -# elif defined(FEAT_PYTHON) - ex_pydo(eap); -# elif defined(FEAT_PYTHON3) - ex_py3do(eap); -# endif -} - -#endif - -/* - * ":checktime [buffer]" - */ - void -ex_checktime(exarg_T *eap) -{ - buf_T *buf; - int save_no_check_timestamps = no_check_timestamps; - - no_check_timestamps = 0; - if (eap->addr_count == 0) // default is all buffers - check_timestamps(FALSE); - else - { - buf = buflist_findnr((int)eap->line2); - if (buf != NULL) // cannot happen? - (void)buf_check_timestamp(buf, FALSE); - } - no_check_timestamps = save_no_check_timestamps; -} +/* vi:set ts=8 sts=4 sw=4 noet: + * + * 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_cmds2.c: some more functions for command line commands + */ + +#include "vim.h" +#include "version.h" + +/* + * If 'autowrite' option set, try to write the file. + * Careful: autocommands may make "buf" invalid! + * + * return FAIL for failure, OK otherwise + */ + int +autowrite(buf_T *buf, int forceit) +{ + int r; + bufref_T bufref; + + if (!(p_aw || p_awa) || !p_write + // never autowrite a "nofile" or "nowrite" buffer + || bt_dontwrite(buf) + || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) + return FAIL; + set_bufref(&bufref, buf); + r = buf_write_all(buf, forceit); + + // Writing may succeed but the buffer still changed, e.g., when there is a + // conversion error. We do want to return FAIL then. + if (bufref_valid(&bufref) && bufIsChanged(buf)) + r = FAIL; + return r; +} + +/* + * Flush all buffers, except the ones that are readonly or are never written. + */ + void +autowrite_all(void) +{ + buf_T *buf; + + if (!(p_aw || p_awa) || !p_write) + return; + FOR_ALL_BUFFERS(buf) + if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf)) + { + bufref_T bufref; + + set_bufref(&bufref, buf); + + (void)buf_write_all(buf, FALSE); + + // an autocommand may have deleted the buffer + if (!bufref_valid(&bufref)) + buf = firstbuf; + } +} + +/* + * Return TRUE if buffer was changed and cannot be abandoned. + * For flags use the CCGD_ values. + */ + int +check_changed(buf_T *buf, int flags) +{ + int forceit = (flags & CCGD_FORCEIT); + bufref_T bufref; + + set_bufref(&bufref, buf); + + if ( !forceit + && bufIsChanged(buf) + && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1) + && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) + { +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) + { +# ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + { + return term_confirm_stop(buf) == FAIL; + } +# endif + + buf_T *buf2; + int count = 0; + + if (flags & CCGD_ALLBUF) + FOR_ALL_BUFFERS(buf2) + if (bufIsChanged(buf2) + && (buf2->b_ffname != NULL +# ifdef FEAT_BROWSE + || (cmdmod.cmod_flags & CMOD_BROWSE) +# endif + )) + ++count; + if (!bufref_valid(&bufref)) + // Autocommand deleted buffer, oops! It's not changed now. + return FALSE; + + dialog_changed(buf, count > 1); + + if (!bufref_valid(&bufref)) + // Autocommand deleted buffer, oops! It's not changed now. + return FALSE; + return bufIsChanged(buf); + } +#endif + if (flags & CCGD_EXCMD) + no_write_message(); + else + no_write_message_nobang(curbuf); + return TRUE; + } + return FALSE; +} + +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) + +#if defined(FEAT_BROWSE) || defined(PROTO) +/* + * When wanting to write a file without a file name, ask the user for a name. + */ + void +browse_save_fname(buf_T *buf) +{ + if (buf->b_fname != NULL) + return; + + char_u *fname; + + fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), + NULL, NULL, NULL, NULL, buf); + if (fname == NULL) + return; + + if (setfname(buf, fname, NULL, TRUE) == OK) + buf->b_flags |= BF_NOTEDITED; + vim_free(fname); +} +#endif + +/* + * Ask the user what to do when abandoning a changed buffer. + * Must check 'write' option first! + */ + void +dialog_changed( + buf_T *buf, + int checkall) // may abandon all changed buffers +{ + char_u buff[DIALOG_MSG_SIZE]; + int ret; + buf_T *buf2; + exarg_T ea; + + dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname); + if (checkall) + ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); + else + ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); + + // Init ea pseudo-structure, this is needed for the check_overwrite() + // function. + CLEAR_FIELD(ea); + + if (ret == VIM_YES) + { +#ifdef FEAT_BROWSE + // May get file name, when there is none + browse_save_fname(buf); +#endif + if (buf->b_fname != NULL && check_overwrite(&ea, buf, + buf->b_fname, buf->b_ffname, FALSE) == OK) + // didn't hit Cancel + (void)buf_write_all(buf, FALSE); + } + else if (ret == VIM_NO) + { + unchanged(buf, TRUE, FALSE); + } + else if (ret == VIM_ALL) + { + /* + * Write all modified files that can be written. + * Skip readonly buffers, these need to be confirmed + * individually. + */ + FOR_ALL_BUFFERS(buf2) + { + if (bufIsChanged(buf2) + && (buf2->b_ffname != NULL +#ifdef FEAT_BROWSE + || (cmdmod.cmod_flags & CMOD_BROWSE) +#endif + ) + && !bt_dontwrite(buf2) + && !buf2->b_p_ro) + { + bufref_T bufref; + + set_bufref(&bufref, buf2); +#ifdef FEAT_BROWSE + // May get file name, when there is none + browse_save_fname(buf2); +#endif + if (buf2->b_fname != NULL && check_overwrite(&ea, buf2, + buf2->b_fname, buf2->b_ffname, FALSE) == OK) + // didn't hit Cancel + (void)buf_write_all(buf2, FALSE); + + // an autocommand may have deleted the buffer + if (!bufref_valid(&bufref)) + buf2 = firstbuf; + } + } + } + else if (ret == VIM_DISCARDALL) + { + /* + * mark all buffers as unchanged + */ + FOR_ALL_BUFFERS(buf2) + unchanged(buf2, TRUE, FALSE); + } +} +#endif + +/* + * Return TRUE if the buffer "buf" can be abandoned, either by making it + * hidden, autowriting it or unloading it. + */ + int +can_abandon(buf_T *buf, int forceit) +{ + return ( buf_hide(buf) + || !bufIsChanged(buf) + || buf->b_nwindows > 1 + || autowrite(buf, forceit) == OK + || forceit); +} + +/* + * Add a buffer number to "bufnrs", unless it's already there. + */ + static void +add_bufnum(int *bufnrs, int *bufnump, int nr) +{ + int i; + + for (i = 0; i < *bufnump; ++i) + if (bufnrs[i] == nr) + return; + bufnrs[*bufnump] = nr; + *bufnump = *bufnump + 1; +} + +/* + * Return TRUE if any buffer was changed and cannot be abandoned. + * That changed buffer becomes the current buffer. + * When "unload" is TRUE the current buffer is unloaded instead of making it + * hidden. This is used for ":q!". + */ + int +check_changed_any( + int hidden, // Only check hidden buffers + int unload) +{ + int ret = FALSE; + buf_T *buf; + int save; + int i; + int bufnum = 0; + int bufcount = 0; + int *bufnrs; + tabpage_T *tp; + win_T *wp; + + // Make a list of all buffers, with the most important ones first. + FOR_ALL_BUFFERS(buf) + ++bufcount; + + if (bufcount == 0) + return FALSE; + + bufnrs = ALLOC_MULT(int, bufcount); + if (bufnrs == NULL) + return FALSE; + + // curbuf + bufnrs[bufnum++] = curbuf->b_fnum; + + // buffers in current tab + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer != curbuf) + add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); + + // buffers in other tabs + FOR_ALL_TABPAGES(tp) + if (tp != curtab) + FOR_ALL_WINDOWS_IN_TAB(tp, wp) + add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); + + // any other buffer + FOR_ALL_BUFFERS(buf) + add_bufnum(bufnrs, &bufnum, buf->b_fnum); + + for (i = 0; i < bufnum; ++i) + { + buf = buflist_findnr(bufnrs[i]); + if (buf == NULL) + continue; + if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) + { + bufref_T bufref; + + set_bufref(&bufref, buf); +#ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + { + if (term_try_stop_job(buf) == FAIL) + break; + } + else +#endif + // Try auto-writing the buffer. If this fails but the buffer no + // longer exists it's not changed, that's OK. + if (check_changed(buf, (p_awa ? CCGD_AW : 0) + | CCGD_MULTWIN + | CCGD_ALLBUF) && bufref_valid(&bufref)) + break; // didn't save - still changes + } + } + + if (i >= bufnum) + goto theend; + + // Get here if "buf" cannot be abandoned. + ret = TRUE; + exiting = FALSE; +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + /* + * When ":confirm" used, don't give an error message. + */ + if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) +#endif + { + // There must be a wait_return() for this message, do_buffer() + // may cause a redraw. But wait_return() is a no-op when vgetc() + // is busy (Quit used from window menu), then make sure we don't + // cause a scroll up. + if (vgetc_busy > 0) + { + msg_row = cmdline_row; + msg_col = 0; + msg_didout = FALSE; + } + if ( +#ifdef FEAT_TERMINAL + term_job_running(buf->b_term) + ? semsg(_(e_job_still_running_in_buffer_str), buf->b_fname) + : +#endif + semsg(_(e_no_write_since_last_change_for_buffer_str), + buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) + { + save = no_wait_return; + no_wait_return = FALSE; + wait_return(FALSE); + no_wait_return = save; + } + } + + // Try to find a window that contains the buffer. + if (buf != curbuf) + FOR_ALL_TAB_WINDOWS(tp, wp) + if (wp->w_buffer == buf) + { + bufref_T bufref; + + set_bufref(&bufref, buf); + + goto_tabpage_win(tp, wp); + + // Paranoia: did autocmd wipe out the buffer with changes? + if (!bufref_valid(&bufref)) + goto theend; + goto buf_found; + } +buf_found: + + // Open the changed buffer in the current window. + if (buf != curbuf) + set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO); + +theend: + vim_free(bufnrs); + return ret; +} + +/* + * return FAIL if there is no file name, OK if there is one + * give error message for FAIL + */ + int +check_fname(void) +{ + if (curbuf->b_ffname == NULL) + { + emsg(_(e_no_file_name)); + return FAIL; + } + return OK; +} + +/* + * flush the contents of a buffer, unless it has no file name + * + * return FAIL for failure, OK otherwise + */ + int +buf_write_all(buf_T *buf, int forceit) +{ + int retval; + buf_T *old_curbuf = curbuf; + + retval = (buf_write(buf, buf->b_ffname, buf->b_fname, + (linenr_T)1, buf->b_ml.ml_line_count, NULL, + FALSE, forceit, TRUE, FALSE)); + if (curbuf != old_curbuf) + { + msg_source(HL_ATTR(HLF_W)); + msg(_("Warning: Entered other buffer unexpectedly (check autocommands)")); + } + return retval; +} + +/* + * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" + */ + void +ex_listdo(exarg_T *eap) +{ + int i; + win_T *wp; + tabpage_T *tp; + buf_T *buf = curbuf; + int next_fnum = 0; +#if defined(FEAT_SYN_HL) + char_u *save_ei = NULL; +#endif +#ifdef FEAT_QUICKFIX + int qf_size = 0; + int qf_idx; +#endif + +#ifndef FEAT_QUICKFIX + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || + eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) + { + ex_ni(eap); + return; + } +#endif + +#if defined(FEAT_SYN_HL) + if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) + { + // Don't do syntax HL autocommands. Skipping the syntax file is a + // great speed improvement. + save_ei = au_event_disable(",Syntax"); + + FOR_ALL_BUFFERS(buf) + buf->b_flags &= ~BF_SYN_SET; + buf = curbuf; + } +#endif +#ifdef FEAT_CLIPBOARD + start_global_changes(); +#endif + + if (eap->cmdidx == CMD_windo + || eap->cmdidx == CMD_tabdo + || buf_hide(curbuf) + || !check_changed(curbuf, CCGD_AW + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) + { + i = 0; + // start at the eap->line1 argument/window/buffer + wp = firstwin; + tp = first_tabpage; + switch (eap->cmdidx) + { + case CMD_windo: + for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) + i++; + break; + case CMD_tabdo: + for ( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) + i++; + break; + case CMD_argdo: + i = eap->line1 - 1; + break; + default: + break; + } + // set pcmark now + if (eap->cmdidx == CMD_bufdo) + { + // Advance to the first listed buffer after "eap->line1". + for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1 + || !buf->b_p_bl); buf = buf->b_next) + if (buf->b_fnum > eap->line2) + { + buf = NULL; + break; + } + if (buf != NULL) + goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); + } +#ifdef FEAT_QUICKFIX + else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) + { + qf_size = qf_get_valid_size(eap); + if (qf_size <= 0 || eap->line1 > qf_size) + buf = NULL; + else + { + save_clear_shm_value(); + ex_cc(eap); + restore_shm_value(); + + buf = curbuf; + i = eap->line1 - 1; + if (eap->addr_count <= 0) + // default is all the quickfix/location list entries + eap->line2 = qf_size; + } + } +#endif + else + setpcmark(); + listcmd_busy = TRUE; // avoids setting pcmark below + + while (!got_int && buf != NULL) + { + if (eap->cmdidx == CMD_argdo) + { + // go to argument "i" + if (i == ARGCOUNT) + break; + // Don't call do_argfile() when already there, it will try + // reloading the file. + if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) + { + // Clear 'shm' to avoid that the file message overwrites + // any output from the command. + save_clear_shm_value(); + do_argfile(eap, i); + restore_shm_value(); + } + if (curwin->w_arg_idx != i) + break; + } + else if (eap->cmdidx == CMD_windo) + { + // go to window "wp" + if (!win_valid(wp)) + break; + win_goto(wp); + if (curwin != wp) + break; // something must be wrong + wp = curwin->w_next; + } + else if (eap->cmdidx == CMD_tabdo) + { + // go to window "tp" + if (!valid_tabpage(tp)) + break; + goto_tabpage_tp(tp, TRUE, TRUE); + tp = tp->tp_next; + } + else if (eap->cmdidx == CMD_bufdo) + { + // Remember the number of the next listed buffer, in case + // ":bwipe" is used or autocommands do something strange. + next_fnum = -1; + for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next) + if (buf->b_p_bl) + { + next_fnum = buf->b_fnum; + break; + } + } + + ++i; + + // execute the command + do_cmdline(eap->arg, eap->getline, eap->cookie, + DOCMD_VERBOSE + DOCMD_NOWAIT); + + if (eap->cmdidx == CMD_bufdo) + { + // Done? + if (next_fnum < 0 || next_fnum > eap->line2) + break; + // Check if the buffer still exists. + FOR_ALL_BUFFERS(buf) + if (buf->b_fnum == next_fnum) + break; + if (buf == NULL) + break; + + // Go to the next buffer. Clear 'shm' to avoid that the file + // message overwrites any output from the command. + save_clear_shm_value(); + goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); + restore_shm_value(); + + // If autocommands took us elsewhere, quit here. + if (curbuf->b_fnum != next_fnum) + break; + } + +#ifdef FEAT_QUICKFIX + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) + { + if (i >= qf_size || i >= eap->line2) + break; + + qf_idx = qf_get_cur_idx(eap); + + save_clear_shm_value(); + ex_cnext(eap); + restore_shm_value(); + + // If jumping to the next quickfix entry fails, quit here + if (qf_get_cur_idx(eap) == qf_idx) + break; + } +#endif + + if (eap->cmdidx == CMD_windo) + { + validate_cursor(); // cursor may have moved + + // required when 'scrollbind' has been set + if (curwin->w_p_scb) + do_check_scrollbind(TRUE); + } + + if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo) + if (i+1 > eap->line2) + break; + if (eap->cmdidx == CMD_argdo && i >= eap->line2) + break; + } + listcmd_busy = FALSE; + } + +#if defined(FEAT_SYN_HL) + if (save_ei != NULL) + { + buf_T *bnext; + aco_save_T aco; + + au_event_restore(save_ei); + + for (buf = firstbuf; buf != NULL; buf = bnext) + { + bnext = buf->b_next; + if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) + { + buf->b_flags &= ~BF_SYN_SET; + + // buffer was opened while Syntax autocommands were disabled, + // need to trigger them now. + if (buf == curbuf) + apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, + curbuf->b_fname, TRUE, curbuf); + else + { + aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { + apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, + buf->b_fname, TRUE, buf); + aucmd_restbuf(&aco); + } + } + + // start over, in case autocommands messed things up. + bnext = firstbuf; + } + } + } +#endif +#ifdef FEAT_CLIPBOARD + end_global_changes(); +#endif +} + +#ifdef FEAT_EVAL +/* + * ":compiler[!] {name}" + */ + void +ex_compiler(exarg_T *eap) +{ + char_u *buf; + char_u *old_cur_comp = NULL; + char_u *p; + + if (*eap->arg == NUL) + { + // List all compiler scripts. + do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')"); + // ) keep the indenter happy... + return; + } + + buf = alloc(STRLEN(eap->arg) + 14); + if (buf == NULL) + return; + + if (eap->forceit) + { + // ":compiler! {name}" sets global options + do_cmdline_cmd((char_u *) + "command -nargs=* CompilerSet set <args>"); + } + else + { + // ":compiler! {name}" sets local options. + // To remain backwards compatible "current_compiler" is always + // used. A user's compiler plugin may set it, the distributed + // plugin will then skip the settings. Afterwards set + // "b:current_compiler" and restore "current_compiler". + // Explicitly prepend "g:" to make it work in a function. + old_cur_comp = get_var_value((char_u *)"g:current_compiler"); + if (old_cur_comp != NULL) + old_cur_comp = vim_strsave(old_cur_comp); + do_cmdline_cmd((char_u *) + "command -nargs=* -keepscript CompilerSet setlocal <args>"); + } + do_unlet((char_u *)"g:current_compiler", TRUE); + do_unlet((char_u *)"b:current_compiler", TRUE); + + sprintf((char *)buf, "compiler/%s.vim", eap->arg); + if (source_runtime(buf, DIP_ALL) == FAIL) + semsg(_(e_compiler_not_supported_str), eap->arg); + vim_free(buf); + + do_cmdline_cmd((char_u *)":delcommand CompilerSet"); + + // Set "b:current_compiler" from "current_compiler". + p = get_var_value((char_u *)"g:current_compiler"); + if (p != NULL) + set_internal_string_var((char_u *)"b:current_compiler", p); + + // Restore "current_compiler" for ":compiler {name}". + if (!eap->forceit) + { + if (old_cur_comp != NULL) + { + set_internal_string_var((char_u *)"g:current_compiler", + old_cur_comp); + vim_free(old_cur_comp); + } + else + do_unlet((char_u *)"g:current_compiler", TRUE); + } +} +#endif + +#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO) + +# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO) +/* + * Detect Python 3 or 2, and initialize 'pyxversion'. + */ + void +init_pyxversion(void) +{ + if (p_pyx == 0) + { + if (python3_enabled(FALSE)) + p_pyx = 3; + else if (python_enabled(FALSE)) + p_pyx = 2; + } +} +# endif + +/* + * Does a file contain one of the following strings at the beginning of any + * line? + * "#!(any string)python2" => returns 2 + * "#!(any string)python3" => returns 3 + * "# requires python 2.x" => returns 2 + * "# requires python 3.x" => returns 3 + * otherwise return 0. + */ + static int +requires_py_version(char_u *filename) +{ + FILE *file; + int requires_py_version = 0; + int i, lines; + + lines = (int)p_mls; + if (lines < 0) + lines = 5; + + file = mch_fopen((char *)filename, "r"); + if (file == NULL) + return 0; + + for (i = 0; i < lines; i++) + { + if (vim_fgets(IObuff, IOSIZE, file)) + break; + if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!') + { + // Check shebang. + if (strstr((char *)IObuff + 2, "python2") != NULL) + { + requires_py_version = 2; + break; + } + if (strstr((char *)IObuff + 2, "python3") != NULL) + { + requires_py_version = 3; + break; + } + } + IObuff[21] = '\0'; + if (STRCMP("# requires python 2.x", IObuff) == 0) + { + requires_py_version = 2; + break; + } + if (STRCMP("# requires python 3.x", IObuff) == 0) + { + requires_py_version = 3; + break; + } + } + fclose(file); + return requires_py_version; +} + + +/* + * Source a python file using the requested python version. + */ + static void +source_pyx_file(exarg_T *eap, char_u *fname) +{ + exarg_T ex; + int v = requires_py_version(fname); + +# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) + init_pyxversion(); +# endif + if (v == 0) + { +# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) + // user didn't choose a preference, 'pyx' is used + v = p_pyx; +# elif defined(FEAT_PYTHON) + v = 2; +# elif defined(FEAT_PYTHON3) + v = 3; +# endif + } + + /* + * now source, if required python version is not supported show + * unobtrusive message. + */ + if (eap == NULL) + CLEAR_FIELD(ex); + else + ex = *eap; + ex.arg = fname; + ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3"); + + if (v == 2) + { +# ifdef FEAT_PYTHON + ex_pyfile(&ex); +# else + vim_snprintf((char *)IObuff, IOSIZE, + _("W20: Required python version 2.x not supported, ignoring file: %s"), + fname); + msg((char *)IObuff); +# endif + return; + } + else + { +# ifdef FEAT_PYTHON3 + ex_py3file(&ex); +# else + vim_snprintf((char *)IObuff, IOSIZE, + _("W21: Required python version 3.x not supported, ignoring file: %s"), + fname); + msg((char *)IObuff); +# endif + return; + } +} + +/* + * ":pyxfile {fname}" + */ + void +ex_pyxfile(exarg_T *eap) +{ + source_pyx_file(eap, eap->arg); +} + +/* + * ":pyx" + */ + void +ex_pyx(exarg_T *eap) +{ +# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) + init_pyxversion(); + if (p_pyx == 2) + ex_python(eap); + else + ex_py3(eap); +# elif defined(FEAT_PYTHON) + ex_python(eap); +# elif defined(FEAT_PYTHON3) + ex_py3(eap); +# endif +} + +/* + * ":pyxdo" + */ + void +ex_pyxdo(exarg_T *eap) +{ +# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) + init_pyxversion(); + if (p_pyx == 2) + ex_pydo(eap); + else + ex_py3do(eap); +# elif defined(FEAT_PYTHON) + ex_pydo(eap); +# elif defined(FEAT_PYTHON3) + ex_py3do(eap); +# endif +} + +#endif + +/* + * ":checktime [buffer]" + */ + void +ex_checktime(exarg_T *eap) +{ + buf_T *buf; + int save_no_check_timestamps = no_check_timestamps; + + no_check_timestamps = 0; + if (eap->addr_count == 0) // default is all buffers + check_timestamps(FALSE); + else + { + buf = buflist_findnr((int)eap->line2); + if (buf != NULL) // cannot happen? + (void)buf_check_timestamp(buf, FALSE); + } + no_check_timestamps = save_no_check_timestamps; +}