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

Code before:
    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 {
    // 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;

Review comment (suggestion):
This isn't correct if the command doesn't expect an expression (e.g. `:terminal` and `:lua` which take `|` as part of argument, or `:syntax` which has a different rule for each subcommand)

Code after:
  // Skip colon and whitespace
  eap->cmd = skip_colon_white(eap->cmd, true);
  // Fail if command is a comment or if command doesn't exist
  if (*eap->cmd == NUL || *eap->cmd == '"') {
    goto end;
  }
  // Fail if command is invalid
  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;