Repository: neovim/neovim
File: src/nvim/ex_docmd.c (C)

Code before:

  // Parse arguments.
  if (!IS_USER_CMDIDX(eap->cmdidx)) {
    eap->argt = cmdnames[(int)eap->cmdidx].cmd_argt;
  }
  // Skip to start of argument.
  // Don't do this for the ":!" command, because ":!! -l" needs the space.
  eap->arg = eap->cmdidx == CMD_bang ? p : skipwhite(p);

  // Don't treat ":r! filter" like a bang
  if (eap->cmdidx == CMD_read && eap->forceit) {
    eap->forceit = false;  // :r! filter
  }

  // Check for '|' to separate commands and '"' to start comments.
  // Don't do this for ":read !cmd" and ":write !cmd".
  if ((eap->argt & EX_TRLBAR)) {
    separate_nextcmd(eap);
  } else if (eap->cmdidx == CMD_execute
             || eap->cmdidx == CMD_echo
             || eap->cmdidx == CMD_echomsg
             || eap->cmdidx == CMD_echoerr) {
    // For commands without EX_TRLBAR, check for '|' separator
    // by skipping over expressions (including string literals)
    char *arg = eap->arg;
    while (*arg != NUL && *arg != '|' && *arg != '\n') {
      char *start = arg;
      skip_expr(&arg, NULL);
      // If skip_expr didn't advance, move forward to avoid infinite loop
      if (arg == start) {
        arg++;
      }
    }
    if (*arg == '|' || *arg == '\n') {
      eap->nextcmd = check_nextcmd(arg);
      *arg = NUL;
    }
  }
  // Fail if command doesn't support bang but is used with a bang
  if (!(eap->argt & EX_BANG) && eap->forceit) {
    *errormsg = _(e_nobang);
    goto end;
  }
  // Fail if command doesn't support a range but it is given a range
  if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
    *errormsg = _(e_norange);
    goto end;
  }
  // Set default range for command if required
  if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) {
    set_cmd_dflall_range(eap);

Review comment (suggestion):
this feels rather hacky. if `parse_cmdline` or `nvim_parse_cmd` were used as the central codepath (https://github.com/neovim/neovim/issues/34398) then at least the "hacks" would be in one place. but that isn't currently the case.


Code after:
  if (eap->cmdidx == CMD_SIZE) {
    xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE);
    // If the modifier was parsed OK the error must be in the following command
    char *cmdname = after_modifier ? after_modifier : *cmdline;
    append_command(cmdname);
    *errormsg = IObuff;
    goto end;
  }

  // Correctly set 'forceit' for commands
  eap->forceit = parse_bang(eap, &p);

  // Parse arguments.
  if (!IS_USER_CMDIDX(eap->cmdidx)) {
    eap->argt = cmdnames[(int)eap->cmdidx].cmd_argt;
  }
  // Skip to start of argument.
  // Don't do this for the ":!" command, because ":!! -l" needs the space.
  eap->arg = eap->cmdidx == CMD_bang ? p : skipwhite(p);

  // Don't treat ":r! filter" like a bang
  if (eap->cmdidx == CMD_read && eap->forceit) {
    eap->forceit = false;  // :r! filter
  }

  // Check for '|' to separate commands and '"' to start comments.
  // Don't do this for ":read !cmd" and ":write !cmd".
  if ((eap->argt & EX_TRLBAR)) {
    separate_nextcmd(eap);
  } else if (cmd_has_expr_args(eap->cmdidx)) {
    // For commands without EX_TRLBAR, check for '|' separator
    // by skipping over expressions (including string literals)
    char *arg = eap->arg;
    while (*arg != NUL && *arg != '|' && *arg != '\n') {
      char *start = arg;
      skip_expr(&arg, NULL);
      // If skip_expr didn't advance, move forward to avoid infinite loop
      if (arg == start) {
        arg++;
      }
    }
    if (*arg == '|' || *arg == '\n') {
      eap->nextcmd = check_nextcmd(arg);
      *arg = NUL;
    }
  }
  // Fail if command doesn't support bang but is used with a bang
  if (!(eap->argt & EX_BANG) && eap->forceit) {
    *errormsg = _(e_nobang);
    goto end;
  }