| /* 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) |
| { |
| int empty_bufname; |
| |
| #ifdef FEAT_BROWSE |
| // May get file name, when there is none |
| browse_save_fname(buf); |
| #endif |
| empty_bufname = buf->b_fname == NULL ? TRUE : FALSE; |
| if (empty_bufname) |
| buf_set_name(buf->b_fnum, (char_u *)"Untitled"); |
| |
| if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, FALSE) == OK) |
| { |
| // didn't hit Cancel |
| if (buf_write_all(buf, FALSE) == OK) |
| return; |
| } |
| |
| // restore to empty when write failed |
| if (empty_bufname) |
| { |
| VIM_CLEAR(buf->b_fname); |
| VIM_CLEAR(buf->b_ffname); |
| VIM_CLEAR(buf->b_sfname); |
| unchanged(buf, TRUE, 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 (curwin->w_p_wfb) |
| { |
| if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && |
| !eap->forceit) |
| { |
| // Disallow :ldo if 'winfixbuf' is applied |
| emsg(_(e_winfixbuf_cannot_go_to_buffer)); |
| return; |
| } |
| |
| if (win_valid(prevwin) && !prevwin->w_p_wfb) |
| // 'winfixbuf' is set; attempt to change to a window without it. |
| win_goto(prevwin); |
| if (curwin->w_p_wfb) |
| { |
| // Split the window, which will be 'nowinfixbuf', and set curwin to |
| // that |
| (void)win_split(0, 0); |
| |
| if (curwin->w_p_wfb) |
| { |
| // Autocommands set 'winfixbuf' or sent us to another window |
| // with it set, or we failed to split the window. Give up. |
| emsg(_(e_winfixbuf_cannot_go_to_buffer)); |
| return; |
| } |
| } |
| } |
| |
| #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->ea_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; |
| } |