neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

ex_cmds2.c (25540B)


      1 /// @file ex_cmds2.c
      2 ///
      3 /// Some more functions for command line commands
      4 
      5 #include <assert.h>
      6 #include <inttypes.h>
      7 #include <stdbool.h>
      8 #include <stdio.h>
      9 #include <string.h>
     10 
     11 #include "nvim/arglist.h"
     12 #include "nvim/ascii_defs.h"
     13 #include "nvim/autocmd.h"
     14 #include "nvim/autocmd_defs.h"
     15 #include "nvim/buffer.h"
     16 #include "nvim/buffer_defs.h"
     17 #include "nvim/bufwrite.h"
     18 #include "nvim/change.h"
     19 #include "nvim/channel.h"
     20 #include "nvim/errors.h"
     21 #include "nvim/eval.h"
     22 #include "nvim/eval/typval.h"
     23 #include "nvim/eval/typval_defs.h"
     24 #include "nvim/eval/vars.h"
     25 #include "nvim/ex_cmds.h"
     26 #include "nvim/ex_cmds2.h"
     27 #include "nvim/ex_cmds_defs.h"
     28 #include "nvim/ex_docmd.h"
     29 #include "nvim/ex_getln.h"
     30 #include "nvim/fileio.h"
     31 #include "nvim/gettext_defs.h"
     32 #include "nvim/globals.h"
     33 #include "nvim/highlight_defs.h"
     34 #include "nvim/macros_defs.h"
     35 #include "nvim/mark.h"
     36 #include "nvim/memline_defs.h"
     37 #include "nvim/memory.h"
     38 #include "nvim/message.h"
     39 #include "nvim/move.h"
     40 #include "nvim/normal.h"
     41 #include "nvim/option_vars.h"
     42 #include "nvim/os/os_defs.h"
     43 #include "nvim/path.h"
     44 #include "nvim/pos_defs.h"
     45 #include "nvim/quickfix.h"
     46 #include "nvim/runtime.h"
     47 #include "nvim/types_defs.h"
     48 #include "nvim/undo.h"
     49 #include "nvim/vim_defs.h"
     50 #include "nvim/window.h"
     51 
     52 #include "ex_cmds2.c.generated.h"
     53 
     54 static const char e_compiler_not_supported_str[]
     55  = N_("E666: Compiler not supported: %s");
     56 
     57 void ex_ruby(exarg_T *eap)
     58 {
     59  script_host_execute("ruby", eap);
     60 }
     61 
     62 void ex_rubyfile(exarg_T *eap)
     63 {
     64  script_host_execute_file("ruby", eap);
     65 }
     66 
     67 void ex_rubydo(exarg_T *eap)
     68 {
     69  script_host_do_range("ruby", eap);
     70 }
     71 
     72 void ex_python3(exarg_T *eap)
     73 {
     74  script_host_execute("python3", eap);
     75 }
     76 
     77 void ex_py3file(exarg_T *eap)
     78 {
     79  script_host_execute_file("python3", eap);
     80 }
     81 
     82 void ex_pydo3(exarg_T *eap)
     83 {
     84  script_host_do_range("python3", eap);
     85 }
     86 
     87 void ex_perl(exarg_T *eap)
     88 {
     89  script_host_execute("perl", eap);
     90 }
     91 
     92 void ex_perlfile(exarg_T *eap)
     93 {
     94  script_host_execute_file("perl", eap);
     95 }
     96 
     97 void ex_perldo(exarg_T *eap)
     98 {
     99  script_host_do_range("perl", eap);
    100 }
    101 
    102 /// If 'autowrite' option set, try to write the file.
    103 /// Careful: autocommands may make "buf" invalid!
    104 ///
    105 /// @return FAIL for failure, OK otherwise
    106 int autowrite(buf_T *buf, bool forceit)
    107 {
    108  bufref_T bufref;
    109 
    110  if (!(p_aw || p_awa) || !p_write
    111      // never autowrite a "nofile" or "nowrite" buffer
    112      || bt_dontwrite(buf)
    113      || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) {
    114    return FAIL;
    115  }
    116  set_bufref(&bufref, buf);
    117  int r = buf_write_all(buf, forceit);
    118 
    119  // Writing may succeed but the buffer still changed, e.g., when there is a
    120  // conversion error.  We do want to return FAIL then.
    121  if (bufref_valid(&bufref) && bufIsChanged(buf)) {
    122    r = FAIL;
    123  }
    124  return r;
    125 }
    126 
    127 /// Flush all buffers, except the ones that are readonly or are never written.
    128 void autowrite_all(void)
    129 {
    130  if (!(p_aw || p_awa) || !p_write) {
    131    return;
    132  }
    133 
    134  FOR_ALL_BUFFERS(buf) {
    135    if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf)) {
    136      bufref_T bufref;
    137      set_bufref(&bufref, buf);
    138      buf_write_all(buf, false);
    139      // an autocommand may have deleted the buffer
    140      if (!bufref_valid(&bufref)) {
    141        buf = firstbuf;
    142      }
    143    }
    144  }
    145 }
    146 
    147 /// @return  true if buffer was changed and cannot be abandoned.
    148 /// For flags use the CCGD_ values.
    149 bool check_changed(buf_T *buf, int flags)
    150 {
    151  bool forceit = (flags & CCGD_FORCEIT);
    152  bufref_T bufref;
    153  set_bufref(&bufref, buf);
    154 
    155  if (!forceit
    156      && bufIsChanged(buf)
    157      && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
    158      && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) {
    159    if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) {
    160      int count = 0;
    161 
    162      if (flags & CCGD_ALLBUF) {
    163        FOR_ALL_BUFFERS(buf2) {
    164          if (bufIsChanged(buf2) && (buf2->b_ffname != NULL)) {
    165            count++;
    166          }
    167        }
    168      }
    169      if (!bufref_valid(&bufref)) {
    170        // Autocommand deleted buffer, oops!  It's not changed now.
    171        return false;
    172      }
    173      dialog_changed(buf, count > 1);
    174      if (!bufref_valid(&bufref)) {
    175        // Autocommand deleted buffer, oops!  It's not changed now.
    176        return false;
    177      }
    178      return bufIsChanged(buf);
    179    }
    180    if (flags & CCGD_EXCMD) {
    181      no_write_message();
    182    } else {
    183      no_write_message_nobang(curbuf);
    184    }
    185    return true;
    186  }
    187  return false;
    188 }
    189 
    190 /// Ask the user what to do when abandoning a changed buffer.
    191 /// Must check 'write' option first!
    192 ///
    193 /// @param buf
    194 /// @param checkall may abandon all changed buffers
    195 void dialog_changed(buf_T *buf, bool checkall)
    196 {
    197  char buff[DIALOG_MSG_SIZE];
    198  int ret;
    199  // Init ea pseudo-structure, this is needed for the check_overwrite()
    200  // function.
    201  exarg_T ea = {
    202    .append = false,
    203    .forceit = false,
    204  };
    205 
    206  dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
    207  if (checkall) {
    208    ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
    209  } else {
    210    ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
    211  }
    212 
    213  if (ret == VIM_YES) {
    214    bool empty_bufname = buf->b_fname == NULL;
    215    if (empty_bufname) {
    216      buf_set_name(buf->b_fnum, "Untitled");
    217    }
    218 
    219    if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, false) == OK) {
    220      // didn't hit Cancel
    221      if (buf_write_all(buf, false) == OK) {
    222        return;
    223      }
    224    }
    225 
    226    // restore to empty when write failed
    227    if (empty_bufname) {
    228      buf->b_fname = NULL;
    229      XFREE_CLEAR(buf->b_ffname);
    230      XFREE_CLEAR(buf->b_sfname);
    231      unchanged(buf, true, false);
    232    }
    233  } else if (ret == VIM_NO) {
    234    unchanged(buf, true, false);
    235  } else if (ret == VIM_ALL) {
    236    // Write all modified files that can be written.
    237    // Skip readonly buffers, these need to be confirmed
    238    // individually.
    239    FOR_ALL_BUFFERS(buf2) {
    240      if (bufIsChanged(buf2) && (buf2->b_ffname != NULL) && !buf2->b_p_ro) {
    241        bufref_T bufref;
    242        set_bufref(&bufref, buf2);
    243 
    244        if (buf2->b_fname != NULL
    245            && check_overwrite(&ea, buf2, buf2->b_fname, buf2->b_ffname, false) == OK) {
    246          // didn't hit Cancel
    247          buf_write_all(buf2, false);
    248        }
    249        // an autocommand may have deleted the buffer
    250        if (!bufref_valid(&bufref)) {
    251          buf2 = firstbuf;
    252        }
    253      }
    254    }
    255  } else if (ret == VIM_DISCARDALL) {
    256    // mark all buffers as unchanged
    257    FOR_ALL_BUFFERS(buf2) {
    258      unchanged(buf2, true, false);
    259    }
    260  }
    261 }
    262 
    263 /// Ask the user whether to close the terminal buffer or not.
    264 ///
    265 /// @param buf The terminal buffer.
    266 /// @return bool Whether to close the buffer or not.
    267 bool dialog_close_terminal(buf_T *buf)
    268 {
    269  char buff[DIALOG_MSG_SIZE];
    270 
    271  dialog_msg(buff, _("Close \"%s\"?"),
    272             (buf->b_fname != NULL) ? buf->b_fname : "?");
    273 
    274  int ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
    275 
    276  return ret == VIM_YES;
    277 }
    278 
    279 /// @return true if the buffer "buf" can be abandoned, either by making it
    280 /// hidden, autowriting it or unloading it.
    281 bool can_abandon(buf_T *buf, bool forceit)
    282 {
    283  return buf_hide(buf)
    284         || !bufIsChanged(buf)
    285         || buf->b_nwindows > 1
    286         || autowrite(buf, forceit) == OK
    287         || forceit;
    288 }
    289 
    290 /// Add a buffer number to "bufnrs", unless it's already there.
    291 static void add_bufnum(int *bufnrs, int *bufnump, int nr)
    292 {
    293  for (int i = 0; i < *bufnump; i++) {
    294    if (bufnrs[i] == nr) {
    295      return;
    296    }
    297  }
    298  bufnrs[*bufnump] = nr;
    299  *bufnump = *bufnump + 1;
    300 }
    301 
    302 /// Check if any buffer was changed and cannot be abandoned.
    303 /// That changed buffer becomes the current buffer.
    304 /// When "unload" is true the current buffer is unloaded instead of making it
    305 /// hidden.  This is used for ":q!".
    306 ///
    307 /// @param[in] hidden specifies whether to check only hidden buffers.
    308 /// @param[in] unload specifies whether to unload, instead of hide, the buffer.
    309 ///
    310 /// @returns          true if any buffer is changed and cannot be abandoned
    311 bool check_changed_any(bool hidden, bool unload)
    312 {
    313  bool ret = false;
    314  int i;
    315  int bufnum = 0;
    316  size_t bufcount = 0;
    317 
    318  // Make a list of all buffers, with the most important ones first.
    319  FOR_ALL_BUFFERS(buf) {
    320    bufcount++;
    321  }
    322 
    323  if (bufcount == 0) {
    324    return false;
    325  }
    326 
    327  int *bufnrs = xmalloc(sizeof(*bufnrs) * bufcount);
    328 
    329  // curbuf
    330  bufnrs[bufnum++] = curbuf->b_fnum;
    331 
    332  // buffers in current tab
    333  FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
    334    if (wp->w_buffer != curbuf) {
    335      add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
    336    }
    337  }
    338 
    339  // buffers in other tabs
    340  FOR_ALL_TABS(tp) {
    341    if (tp != curtab) {
    342      FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
    343        add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
    344      }
    345    }
    346  }
    347 
    348  // any other buffer
    349  FOR_ALL_BUFFERS(buf) {
    350    add_bufnum(bufnrs, &bufnum, buf->b_fnum);
    351  }
    352 
    353  buf_T *buf = NULL;
    354  for (i = 0; i < bufnum; i++) {
    355    buf = buflist_findnr(bufnrs[i]);
    356    if (buf == NULL) {
    357      continue;
    358    }
    359    if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) {
    360      bufref_T bufref;
    361      set_bufref(&bufref, buf);
    362 
    363      // Try auto-writing the buffer.  If this fails but the buffer no
    364      // longer exists it's not changed, that's OK.
    365      if (check_changed(buf, (p_awa ? CCGD_AW : 0)
    366                        | CCGD_MULTWIN
    367                        | CCGD_ALLBUF) && bufref_valid(&bufref)) {
    368        break;    // didn't save - still changes
    369      }
    370    }
    371  }
    372 
    373  if (i >= bufnum) {
    374    goto theend;
    375  }
    376 
    377  // Get here if "buf" cannot be abandoned.
    378  ret = true;
    379  exiting = false;
    380  // When ":confirm" used, don't give an error message.
    381  if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) {
    382    // There must be a wait_return() for this message, do_buffer()
    383    // may cause a redraw.  But wait_return() is a no-op when vgetc()
    384    // is busy (Quit used from window menu), then make sure we don't
    385    // cause a scroll up.
    386    if (vgetc_busy > 0) {
    387      msg_row = cmdline_row;
    388      msg_col = 0;
    389      msg_didout = false;
    390    }
    391    if (((buf->terminal && channel_job_running((uint64_t)buf->b_p_channel))
    392         ? semsg(_("E947: Job still running in buffer \"%s\""), buf->b_fname)
    393         : semsg(_("E162: No write since last change for buffer \"%s\""),
    394                 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
    395        // Only makes sense if error is shown, which cause_errthrow() may prevent.
    396        && msg_didany) {
    397      int save = no_wait_return;
    398      no_wait_return = false;
    399      wait_return(false);
    400      no_wait_return = save;
    401    }
    402  }
    403 
    404  // Try to find a window that contains the buffer.
    405  if (buf != curbuf) {
    406    FOR_ALL_TAB_WINDOWS(tp, wp) {
    407      if (wp->w_buffer == buf) {
    408        bufref_T bufref;
    409        set_bufref(&bufref, buf);
    410        goto_tabpage_win(tp, wp);
    411        // Paranoia: did autocmds wipe out the buffer with changes?
    412        if (!bufref_valid(&bufref)) {
    413          goto theend;
    414        }
    415        goto buf_found;
    416      }
    417    }
    418  }
    419 buf_found:
    420 
    421  // Open the changed buffer in the current window.
    422  if (buf != curbuf) {
    423    set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO, true);
    424  }
    425 
    426 theend:
    427  xfree(bufnrs);
    428  return ret;
    429 }
    430 
    431 /// @return  FAIL if there is no file name, OK if there is one.
    432 ///          Give error message for FAIL.
    433 int check_fname(void)
    434 {
    435  if (curbuf->b_ffname == NULL) {
    436    emsg(_(e_noname));
    437    return FAIL;
    438  }
    439  return OK;
    440 }
    441 
    442 /// Flush the contents of a buffer, unless it has no file name.
    443 ///
    444 /// @return  FAIL for failure, OK otherwise
    445 int buf_write_all(buf_T *buf, bool forceit)
    446 {
    447  buf_T *old_curbuf = curbuf;
    448 
    449  int retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
    450                          1, buf->b_ml.ml_line_count, NULL,
    451                          false, forceit, true, false));
    452  if (curbuf != old_curbuf) {
    453    msg_source(HLF_W);
    454    msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"), 0);
    455  }
    456  return retval;
    457 }
    458 
    459 /// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
    460 void ex_listdo(exarg_T *eap)
    461 {
    462  if (curwin->w_p_wfb) {
    463    if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && !eap->forceit) {
    464      // Disallow :ldo if 'winfixbuf' is applied
    465      emsg(_(e_winfixbuf_cannot_go_to_buffer));
    466      return;
    467    }
    468 
    469    if (win_valid(prevwin) && !prevwin->w_p_wfb) {
    470      // 'winfixbuf' is set; attempt to change to a window without it.
    471      win_goto(prevwin);
    472    }
    473    if (curwin->w_p_wfb) {
    474      // Split the window, which will be 'nowinfixbuf', and set curwin to that
    475      (void)win_split(0, 0);
    476 
    477      if (curwin->w_p_wfb) {
    478        // Autocommands set 'winfixbuf' or sent us to another window
    479        // with it set, or we failed to split the window. Give up.
    480        emsg(_(e_winfixbuf_cannot_go_to_buffer));
    481        return;
    482      }
    483    }
    484  }
    485 
    486  char *save_ei = NULL;
    487 
    488  // Temporarily override SHM_OVER and SHM_OVERALL to avoid that file
    489  // message overwrites output from the command.
    490  msg_listdo_overwrite++;
    491 
    492  if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) {
    493    // Don't do syntax HL autocommands.  Skipping the syntax file is a
    494    // great speed improvement.
    495    save_ei = au_event_disable(",Syntax");
    496 
    497    FOR_ALL_BUFFERS(buf) {
    498      buf->b_flags &= ~BF_SYN_SET;
    499    }
    500  }
    501 
    502  if (eap->cmdidx == CMD_windo
    503      || eap->cmdidx == CMD_tabdo
    504      || buf_hide(curbuf)
    505      || !check_changed(curbuf, CCGD_AW
    506                        | (eap->forceit ? CCGD_FORCEIT : 0)
    507                        | CCGD_EXCMD)) {
    508    int next_fnum = 0;
    509    int i = 0;
    510    // start at the eap->line1 argument/window/buffer
    511    win_T *wp = firstwin;
    512    tabpage_T *tp = first_tabpage;
    513    switch (eap->cmdidx) {
    514    case CMD_windo:
    515      for (; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) {
    516        i++;
    517      }
    518      break;
    519    case CMD_tabdo:
    520      for (; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) {
    521        i++;
    522      }
    523      break;
    524    case CMD_argdo:
    525      i = (int)eap->line1 - 1;
    526      break;
    527    default:
    528      break;
    529    }
    530 
    531    buf_T *buf = curbuf;
    532    size_t qf_size = 0;
    533 
    534    // set pcmark now
    535    if (eap->cmdidx == CMD_bufdo) {
    536      // Advance to the first listed buffer after "eap->line1".
    537      for (buf = firstbuf;
    538           buf != NULL && (buf->b_fnum < eap->line1 || !buf->b_p_bl);
    539           buf = buf->b_next) {
    540        if (buf->b_fnum > eap->line2) {
    541          buf = NULL;
    542          break;
    543        }
    544      }
    545      if (buf != NULL) {
    546        goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
    547      }
    548    } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
    549               || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
    550      qf_size = qf_get_valid_size(eap);
    551      assert(eap->line1 >= 0);
    552      if (qf_size == 0 || (size_t)eap->line1 > qf_size) {
    553        buf = NULL;
    554      } else {
    555        ex_cc(eap);
    556 
    557        buf = curbuf;
    558        i = (int)eap->line1 - 1;
    559        if (eap->addr_count <= 0) {
    560          // Default to all quickfix/location list entries.
    561          assert(qf_size < MAXLNUM);
    562          eap->line2 = (linenr_T)qf_size;
    563        }
    564      }
    565    } else {
    566      setpcmark();
    567    }
    568    listcmd_busy = true;            // avoids setting pcmark below
    569 
    570    while (!got_int && buf != NULL) {
    571      bool execute = true;
    572      if (eap->cmdidx == CMD_argdo) {
    573        // go to argument "i"
    574        if (i == ARGCOUNT) {
    575          break;
    576        }
    577        // Don't call do_argfile() when already there, it will try
    578        // reloading the file.
    579        if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) {
    580          // Clear 'shm' to avoid that the file message overwrites
    581          // any output from the command.
    582          do_argfile(eap, i);
    583        }
    584        if (curwin->w_arg_idx != i) {
    585          break;
    586        }
    587      } else if (eap->cmdidx == CMD_windo) {
    588        // go to window "wp"
    589        if (!win_valid(wp)) {
    590          break;
    591        }
    592        assert(wp);
    593        execute = !wp->w_floating || (!wp->w_config.hide && wp->w_config.focusable);
    594        if (execute) {
    595          win_goto(wp);
    596          if (curwin != wp) {
    597            break;    // something must be wrong
    598          }
    599        }
    600        wp = wp->w_next;
    601      } else if (eap->cmdidx == CMD_tabdo) {
    602        // go to window "tp"
    603        if (!valid_tabpage(tp)) {
    604          break;
    605        }
    606        assert(tp);
    607        goto_tabpage_tp(tp, true, true);
    608        tp = tp->tp_next;
    609      } else if (eap->cmdidx == CMD_bufdo) {
    610        // Remember the number of the next listed buffer, in case
    611        // ":bwipe" is used or autocommands do something strange.
    612        next_fnum = -1;
    613        for (buf_T *bp = curbuf->b_next; bp != NULL; bp = bp->b_next) {
    614          if (bp->b_p_bl) {
    615            next_fnum = bp->b_fnum;
    616            break;
    617          }
    618        }
    619      }
    620 
    621      i++;
    622      // execute the command
    623      if (execute) {
    624        do_cmdline(eap->arg, eap->ea_getline, eap->cookie, DOCMD_VERBOSE + DOCMD_NOWAIT);
    625      }
    626 
    627      if (eap->cmdidx == CMD_bufdo) {
    628        // Done?
    629        if (next_fnum < 0 || next_fnum > eap->line2) {
    630          break;
    631        }
    632 
    633        // Check if the buffer still exists.
    634        bool buf_still_exists = false;
    635        FOR_ALL_BUFFERS(bp) {
    636          if (bp->b_fnum == next_fnum) {
    637            buf_still_exists = true;
    638            break;
    639          }
    640        }
    641        if (!buf_still_exists) {
    642          break;
    643        }
    644 
    645        // Go to the next buffer.
    646        goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
    647 
    648        // If autocommands took us elsewhere, quit here.
    649        if (curbuf->b_fnum != next_fnum) {
    650          break;
    651        }
    652      }
    653 
    654      if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
    655          || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
    656        assert(i >= 0);
    657        if ((size_t)i >= qf_size || i >= eap->line2) {
    658          break;
    659        }
    660 
    661        size_t qf_idx = qf_get_cur_idx(eap);
    662 
    663        ex_cnext(eap);
    664 
    665        // If jumping to the next quickfix entry fails, quit here.
    666        if (qf_get_cur_idx(eap) == qf_idx) {
    667          break;
    668        }
    669      }
    670 
    671      if (eap->cmdidx == CMD_windo && execute) {
    672        validate_cursor(curwin);              // cursor may have moved
    673        // required when 'scrollbind' has been set
    674        if (curwin->w_p_scb) {
    675          do_check_scrollbind(true);
    676        }
    677      }
    678      if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo) {
    679        if (i + 1 > eap->line2) {
    680          break;
    681        }
    682      }
    683      if (eap->cmdidx == CMD_argdo && i >= eap->line2) {
    684        break;
    685      }
    686    }
    687    listcmd_busy = false;
    688  }
    689 
    690  msg_listdo_overwrite--;
    691  if (save_ei != NULL) {
    692    buf_T *bnext;
    693    aco_save_T aco;
    694 
    695    au_event_restore(save_ei);
    696 
    697    for (buf_T *buf = firstbuf; buf != NULL; buf = bnext) {
    698      bnext = buf->b_next;
    699      if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) {
    700        buf->b_flags &= ~BF_SYN_SET;
    701 
    702        // buffer was opened while Syntax autocommands were disabled,
    703        // need to trigger them now.
    704        if (buf == curbuf) {
    705          apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, true,
    706                         curbuf);
    707        } else {
    708          aucmd_prepbuf(&aco, buf);
    709          apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, true, buf);
    710          aucmd_restbuf(&aco);
    711        }
    712 
    713        // start over, in case autocommands messed things up.
    714        bnext = firstbuf;
    715      }
    716    }
    717  }
    718 }
    719 
    720 /// ":compiler[!] {name}"
    721 void ex_compiler(exarg_T *eap)
    722 {
    723  char *old_cur_comp = NULL;
    724 
    725  if (*eap->arg == NUL) {
    726    // List all compiler scripts.
    727    do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')");  // NOLINT
    728    do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.lua')");  // NOLINT
    729    return;
    730  }
    731 
    732  size_t bufsize = strlen(eap->arg) + 14;
    733  char *buf = xmalloc(bufsize);
    734 
    735  if (eap->forceit) {
    736    // ":compiler! {name}" sets global options
    737    do_cmdline_cmd("command -nargs=* -keepscript CompilerSet set <args>");
    738  } else {
    739    // ":compiler! {name}" sets local options.
    740    // To remain backwards compatible "current_compiler" is always
    741    // used.  A user's compiler plugin may set it, the distributed
    742    // plugin will then skip the settings.  Afterwards set
    743    // "b:current_compiler" and restore "current_compiler".
    744    // Explicitly prepend "g:" to make it work in a function.
    745    old_cur_comp = get_var_value("g:current_compiler");
    746    if (old_cur_comp != NULL) {
    747      old_cur_comp = xstrdup(old_cur_comp);
    748    }
    749    do_cmdline_cmd("command -nargs=* -keepscript CompilerSet setlocal <args>");
    750  }
    751  do_unlet(S_LEN("g:current_compiler"), true);
    752  do_unlet(S_LEN("b:current_compiler"), true);
    753 
    754  snprintf(buf, bufsize, "compiler/%s.*", eap->arg);
    755  if (source_runtime_vim_lua(buf, DIP_ALL) == FAIL) {
    756    semsg(_(e_compiler_not_supported_str), eap->arg);
    757  }
    758  xfree(buf);
    759 
    760  do_cmdline_cmd(":delcommand CompilerSet");
    761 
    762  // Set "b:current_compiler" from "current_compiler".
    763  char *p = get_var_value("g:current_compiler");
    764  if (p != NULL) {
    765    set_internal_string_var("b:current_compiler", p);
    766  }
    767 
    768  // Restore "current_compiler" for ":compiler {name}".
    769  if (!eap->forceit) {
    770    if (old_cur_comp != NULL) {
    771      set_internal_string_var("g:current_compiler", old_cur_comp);
    772      xfree(old_cur_comp);
    773    } else {
    774      do_unlet(S_LEN("g:current_compiler"), true);
    775    }
    776  }
    777 }
    778 
    779 /// ":checktime [buffer]"
    780 void ex_checktime(exarg_T *eap)
    781 {
    782  int save_no_check_timestamps = no_check_timestamps;
    783 
    784  no_check_timestamps = 0;
    785  if (eap->addr_count == 0) {    // default is all buffers
    786    check_timestamps(false);
    787  } else {
    788    buf_T *buf = buflist_findnr((int)eap->line2);
    789    if (buf != NULL) {           // cannot happen?
    790      buf_check_timestamp(buf);
    791    }
    792  }
    793  no_check_timestamps = save_no_check_timestamps;
    794 }
    795 
    796 static void script_host_execute(char *name, exarg_T *eap)
    797 {
    798  size_t len;
    799  char *const script = script_get(eap, &len);
    800 
    801  if (script != NULL) {
    802    list_T *const args = tv_list_alloc(3);
    803    // script
    804    tv_list_append_allocated_string(args, script);
    805    // current range
    806    tv_list_append_number(args, (int)eap->line1);
    807    tv_list_append_number(args, (int)eap->line2);
    808 
    809    eval_call_provider(name, "execute", args, true);
    810  }
    811 }
    812 
    813 static void script_host_execute_file(char *name, exarg_T *eap)
    814 {
    815  if (!eap->skip) {
    816    uint8_t buffer[MAXPATHL];
    817    vim_FullName(eap->arg, (char *)buffer, sizeof(buffer), false);
    818 
    819    list_T *args = tv_list_alloc(3);
    820    // filename
    821    tv_list_append_string(args, (const char *)buffer, -1);
    822    // current range
    823    tv_list_append_number(args, (int)eap->line1);
    824    tv_list_append_number(args, (int)eap->line2);
    825    eval_call_provider(name, "execute_file", args, true);
    826  }
    827 }
    828 
    829 static void script_host_do_range(char *name, exarg_T *eap)
    830 {
    831  if (!eap->skip) {
    832    list_T *args = tv_list_alloc(3);
    833    tv_list_append_number(args, (int)eap->line1);
    834    tv_list_append_number(args, (int)eap->line2);
    835    tv_list_append_string(args, eap->arg, -1);
    836    eval_call_provider(name, "do_range", args, true);
    837  }
    838 }
    839 
    840 /// ":drop"
    841 /// Opens the first argument in a window, and the argument list is redefined.
    842 void ex_drop(exarg_T *eap)
    843 {
    844  bool split = false;
    845 
    846  // Check if the first argument is already being edited in a window.  If
    847  // so, jump to that window.
    848  // We would actually need to check all arguments, but that's complicated
    849  // and mostly only one file is dropped.
    850  // This also ignores wildcards, since it is very unlikely the user is
    851  // editing a file name with a wildcard character.
    852  set_arglist(eap->arg);
    853 
    854  // Expanding wildcards may result in an empty argument list.  E.g. when
    855  // editing "foo.pyc" and ".pyc" is in 'wildignore'.  Assume that we
    856  // already did an error message for this.
    857  if (ARGCOUNT == 0) {
    858    return;
    859  }
    860 
    861  if (cmdmod.cmod_tab) {
    862    // ":tab drop file ...": open a tab for each argument that isn't
    863    // edited in a window yet.  It's like ":tab all" but without closing
    864    // windows or tabs.
    865    ex_all(eap);
    866    cmdmod.cmod_tab = 0;
    867    ex_rewind(eap);
    868    return;
    869  }
    870 
    871  // ":drop file ...": Edit the first argument.  Jump to an existing
    872  // window if possible, edit in current window if the current buffer
    873  // can be abandoned, otherwise open a new window.
    874  buf_T *buf = buflist_findnr(ARGLIST[0].ae_fnum);
    875 
    876  FOR_ALL_TAB_WINDOWS(tp, wp) {
    877    if (wp->w_buffer == buf) {
    878      goto_tabpage_win(tp, wp);
    879      curwin->w_arg_idx = 0;
    880      if (!bufIsChanged(curbuf)) {
    881        const int save_ar = curbuf->b_p_ar;
    882 
    883        // reload the file if it is newer
    884        curbuf->b_p_ar = true;
    885        buf_check_timestamp(curbuf);
    886        curbuf->b_p_ar = save_ar;
    887      }
    888      if (curbuf->b_ml.ml_flags & ML_EMPTY) {
    889        ex_rewind(eap);
    890      }
    891 
    892      // execute [+cmd]
    893      if (eap->do_ecmd_cmd) {
    894        bool did_set_swapcommand = set_swapcommand(eap->do_ecmd_cmd, 0);
    895        do_cmdline(eap->do_ecmd_cmd, NULL, NULL, DOCMD_VERBOSE);
    896        if (did_set_swapcommand) {
    897          set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
    898        }
    899      }
    900 
    901      // no need to execute [++opts] - they only apply for newly loaded buffers.
    902      return;
    903    }
    904  }
    905 
    906  // Check whether the current buffer is changed. If so, we will need
    907  // to split the current window or data could be lost.
    908  // Skip the check if the 'hidden' option is set, as in this case the
    909  // buffer won't be lost.
    910  if (!buf_hide(curbuf)) {
    911    emsg_off++;
    912    split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD);
    913    emsg_off--;
    914  }
    915 
    916  // Fake a ":sfirst" or ":first" command edit the first argument.
    917  if (split) {
    918    eap->cmdidx = CMD_sfirst;
    919    eap->cmd[0] = 's';
    920  } else {
    921    eap->cmdidx = CMD_first;
    922  }
    923  ex_rewind(eap);
    924 }