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

Code before:
        win_setwidth_win(fconfig.width, win);
      }
      if (HAS_KEY_X(config, height)) {
        win_setheight_win(fconfig.height, win);
      }
      redraw_later(win, UPD_NOT_VALID);
      return;
    }

    if (!check_split_disallowed_err(win, err)) {
      return;  // error already set
    }

    bool to_split_ok = false;
    int dir = 0;
    // If we are moving curwin to another tabpage, switch windows *before* we remove it from the
    // window list or remove its frame (if non-floating), so it's valid for autocommands.
    const bool curwin_moving_tp = win == curwin && parent && win_tp != parent_tp;
    if (curwin_moving_tp) {
      win_T *target_wp = was_split ? winframe_find_altwin(win, &dir, NULL,
                                                          NULL) : win_float_find_altwin(win, NULL);
      if (!target_wp) {
        return;
      }
      dir = 0;
      win_goto(target_wp);

      // Autocommands may have been a real nuisance and messed things up...
      if (curwin == win) {
        api_set_error(err, kErrorTypeException, "Failed to switch away from window %d",
                      win->handle);
        return;
      }
      win_tp = win_find_tabpage(win);
      if (!win_tp || !win_valid_any_tab(parent)) {
        api_set_error(err, kErrorTypeException, "Windows to split were closed");
        goto restore_curwin;
      }
      if (was_split == win->w_floating || parent->w_floating) {
        api_set_error(err, kErrorTypeException, "Floating state of windows to split changed");
        goto restore_curwin;
      }
    }

    frame_T *unflat_altfr = NULL;
    win_T *altwin = NULL;
    if (was_split) {
      // If the window is the last in the tabpage or `fconfig.win` is
      // a handle to itself, we can't split it.
      if (win->w_frame->fr_parent == NULL) {
        // FIXME(willothy): if the window is the last in the tabpage but there is another tabpage

Review comment (bug):
Rather than a silent failure, make this error with something like `Failed to switch away from window %d` below. (Actually maybe this should be an `assert` if handling `Cannot move last window` instead)

Code after:
        win_setwidth_win(fconfig.width, win);
      }
      if (HAS_KEY_X(config, height)) {
        win_setheight_win(fconfig.height, win);
      }
      redraw_later(win, UPD_NOT_VALID);
      return;
    }

    if (!check_split_disallowed_err(win, err)) {
      return;  // error already set
    }

    bool to_split_ok = false;
    // If we are moving curwin to another tabpage, switch windows *before* we remove it from the
    // window list or remove its frame (if non-floating), so it's valid for autocommands.
    const bool curwin_moving_tp = win == curwin && parent && win_tp != parent_tp;
    if (curwin_moving_tp) {
      if (was_split) {
        int dir;
        win_T *altwin = winframe_find_altwin(win, &dir, NULL, NULL);
        // Autocommands may still make this the last non-float after this check.
        // That case will be caught later when trying to move the window.
        if (!altwin) {
          api_set_error(err, kErrorTypeException, "Cannot move last non-floating window");
          return;
        }
        win_goto(altwin);
      } else {
        win_goto(win_float_find_altwin(win, NULL));
      }

      // Autocommands may have been a real nuisance and messed things up...
      if (curwin == win) {
        api_set_error(err, kErrorTypeException, "Failed to switch away from window %d",
                      win->handle);
        return;
      }
      win_tp = win_find_tabpage(win);
      if (!win_tp || !win_valid_any_tab(parent)) {
        api_set_error(err, kErrorTypeException, "Windows to split were closed");
        goto restore_curwin;
      }
      if (was_split == win->w_floating || parent->w_floating) {
        api_set_error(err, kErrorTypeException, "Floating state of windows to split changed");
        goto restore_curwin;
      }
    }

    int dir = 0;
    frame_T *unflat_altfr = NULL;