ronantakizawa/codereview-bench huggingface dataset:
Repository: neovim/neovim
File: src/nvim/shada.c (C)

Code before:
            .can_free_entry = cur_entry->can_free_entry,
          }, max_kbyte) == kSDWriteFailed) {
            ret = kSDWriteFailed;
            break;
          }
        })
        if (ret == kSDWriteFailed) {
          goto shada_write_exit;
        }
      }
    }
  }

shada_write_exit:
  for (int i = 0; i < HIST_COUNT; i++) {
    if (dump_one_history[i]) {
      hms_dealloc(&wms->hms[i]);
    }
  }
  map_foreach_value(&wms->file_marks, val, {
    xfree(val);
  })
  const char *stored_key = NULL;
  map_foreach_key(&wms->file_marks, stored_key, {
    xfree((char *)stored_key);
  })
  map_destroy(cstr_t, &wms->file_marks);
  set_destroy(ptr_t, &removable_bufs);
  packer.packer_flush(&packer);
  set_destroy(cstr_t, &wms->dumped_variables);
  xfree(wms);
  return ret;
}

#undef PACK_KEY

/// Write ShaDa file to a given location
///
/// @param[in]  fname    File to write to. If it is NULL or empty then default
///                      location is used.
/// @param[in]  nomerge  If true then old file is ignored.
///
/// @return OK if writing was successful, FAIL otherwise.
int shada_write_file(const char *const file, bool nomerge)
{
  char *const fname = shada_filename(file);
  if (fname == NULL) {
    return FAIL;
  }

  char *tempname = NULL;

Review comment (suggestion):
```suggestion
  const char *stored_key = NULL;
  map_foreach(&wms->file_marks, stored_key, val, {
    xfree((char *)stored_key);
    xfree(val);
  })
```

Code after:
            .can_free_entry = cur_entry->can_free_entry,
          }, max_kbyte) == kSDWriteFailed) {
            ret = kSDWriteFailed;
            break;
          }
        })
        if (ret == kSDWriteFailed) {
          goto shada_write_exit;
        }
      }
    }
  }

shada_write_exit:
  for (int i = 0; i < HIST_COUNT; i++) {
    if (dump_one_history[i]) {
      hms_dealloc(&wms->hms[i]);
    }
  }
  const char *stored_key = NULL;
  map_foreach(&wms->file_marks, stored_key, val, {
    xfree((char *)stored_key);
    xfree(val);
  })
  map_destroy(cstr_t, &wms->file_marks);
  set_destroy(ptr_t, &removable_bufs);
  packer.packer_flush(&packer);
  set_destroy(cstr_t, &wms->dumped_variables);
  xfree(wms);
  return ret;
}

#undef PACK_KEY

/// Write ShaDa file to a given location
///
/// @param[in]  fname    File to write to. If it is NULL or empty then default
///                      location is used.
/// @param[in]  nomerge  If true then old file is ignored.
///
/// @return OK if writing was successful, FAIL otherwise.
int shada_write_file(const char *const file, bool nomerge)
{
  char *const fname = shada_filename(file);
  if (fname == NULL) {
    return FAIL;
  }

  char *tempname = NULL;
  FileDescriptor sd_writer;
  FileDescriptor sd_reader;
Repository: neovim/neovim
File: runtime/lua/vim/lsp/_folding_range.lua (Lua)

Code before:
local util = require('vim.lsp.util')
local log = require('vim.lsp.log')
local ms = require('vim.lsp.protocol').Methods
local api = vim.api

local M = {}

---@class (private) FRProvider
---
---@field active table<integer, FRProvider?>
---@field bufnr integer
---@field augroup integer
---@field version? integer
---
--- Never use this directly, `renew()` the cached foldinfo
--- then use on demand via `row_*` fields.
---
--- Index In the form of client_id -> ranges
---@field client_ranges table<integer, lsp.FoldingRange[]?>
---
--- Index in the form of row -> [foldlevel, mark]
---@field row_level table<integer, [integer, ">" | "<"?]?>
---
--- Index in the form of start_row -> kinds
---@field row_kinds table<integer, table<lsp.FoldingRangeKind, true?>?>>
---
--- Index in the form of start_row -> collapsed_text
---@field row_text table<integer, string?>
local FRProvider = { active = {} }

--- Renew the cached foldinfo in the buffer.
function FRProvider:renew()
  ---@type table<integer, [integer, ">" | "<"?]?>

Review comment (suggestion):
We can make the definition of `FRProvider` the type annotation in line 29 instead of having a separate type definition.

Code after:
local util = require('vim.lsp.util')
local log = require('vim.lsp.log')
local ms = require('vim.lsp.protocol').Methods
local api = vim.api

---@type table<lsp.FoldingRangeKind, true>
local supported_fold_kinds = {
  ['comment'] = true,
  ['imports'] = true,
  ['region'] = true,
}

local M = {}

---@class (private) vim.lsp.folding_range.State
---
---@field active table<integer, vim.lsp.folding_range.State?>
---@field bufnr integer
---@field augroup integer
---@field version? integer
---
--- Never use this directly, `renew()` the cached foldinfo
--- then use on demand via `row_*` fields.
---
--- Index In the form of client_id -> ranges
---@field client_ranges table<integer, lsp.FoldingRange[]?>
---
--- Index in the form of row -> [foldlevel, mark]
---@field row_level table<integer, [integer, ">" | "<"?]?>
---
--- Index in the form of start_row -> kinds
---@field row_kinds table<integer, table<lsp.FoldingRangeKind, true?>?>>
---
Repository: neovim/neovim
File: runtime/lua/vim/lsp/_folding_range.lua (Lua)

Code before:
  then
    return
  end

  vim.lsp.buf_request_all(self.bufnr, ms.textDocument_foldingRange, params, function(...)
    self:multi_handler(...)
  end)
end

function FRProvider:reset()
  self.client_ranges = {}
  self.row_level = {}
  self.row_kinds = {}
  self.row_text = {}
end

--- Initialize `provider` and event hooks, then request folding ranges.
---@param bufnr integer
---@return vim.lsp.folding_range.Provider
function FRProvider.new(bufnr)
  local self = setmetatable({}, { __index = FRProvider })
  self.bufnr = bufnr
  self.augroup = api.nvim_create_augroup('nvim.lsp.folding_range:' .. bufnr, { clear = true })
  self:reset()

  FRProvider.active[bufnr] = self

  api.nvim_buf_attach(bufnr, false, {
    -- `on_detach` also runs on buffer reload (`:e`).
    -- Ensure `provider` and hooks are cleared to avoid duplication or leftover states.
    on_detach = function()
      util._cancel_requests({
        bufnr = bufnr,
        method = ms.textDocument_foldingRange,
        type = 'pending',
      })
      local provider = FRProvider.active[bufnr]
      if provider then
        provider:destroy()
      end
    end,
    -- Reset `bufstate` and request folding ranges.
    on_reload = function()
      local provider = FRProvider.active[bufnr]
      if provider then
        provider:reset()
        provider:request()
      end
    end,
    --- Sync changed rows with their previous foldlevels before applying new ones.
    on_bytes = function(_, _, _, start_row, _, _, old_row, _, _, new_row, _, _)

Review comment (suggestion):
is the comment dropped because the new design handles this and makes it obvious? if so, that's a good sign :)

Code after:
  ---@type lsp.FoldingRangeParams
  local params = { textDocument = util.make_text_document_params(self.bufnr) }

  if client then
    client:request(ms.textDocument_foldingRange, params, function(...)
      self:handler(...)
    end, self.bufnr)
    return
  end

  if
    not next(vim.lsp.get_clients({ bufnr = self.bufnr, method = ms.textDocument_foldingRange }))
  then
    return
  end

  vim.lsp.buf_request_all(self.bufnr, ms.textDocument_foldingRange, params, function(...)
    self:multi_handler(...)
  end)
end

function State:reset()
  self.client_ranges = {}
  self.row_level = {}
  self.row_kinds = {}
  self.row_text = {}
end

--- Initialize `state` and event hooks, then request folding ranges.
---@param bufnr integer
---@return vim.lsp.folding_range.State
function State.new(bufnr)
  local self = setmetatable({}, { __index = State })
  self.bufnr = bufnr
  self.augroup = api.nvim_create_augroup('nvim.lsp.folding_range:' .. bufnr, { clear = true })
  self:reset()

  State.active[bufnr] = self

  api.nvim_buf_attach(bufnr, false, {
    -- `on_detach` also runs on buffer reload (`:e`).
    -- Ensure `state` and hooks are cleared to avoid duplication or leftover states.
    on_detach = function()
      util._cancel_requests({
        bufnr = bufnr,
        method = ms.textDocument_foldingRange,
        type = 'pending',
      })
      local state = State.active[bufnr]
      if state then
        state:destroy()
Repository: neovim/neovim
File: runtime/lua/vim/_meta/builtin.lua (Lua)

Code before:
--- ns = vim.api.nvim_create_namespace('my_fancy_pum')
---
--- vim.ui_attach(ns, {ext_popupmenu=true}, function(event, ...)
---   if event == 'popupmenu_show' then
---     local items, selected, row, col, grid = ...
---     print('display pum ', #items)
---   elseif event == 'popupmenu_select' then
---     local selected = ...
---     print('selected', selected)
---   elseif event == 'popupmenu_hide' then
---     print('FIN')
---   end
--- end)
--- ```
---
--- @since 0
---
--- @param ns integer Namespace ID
--- @param opts table<string, any> Optional parameters.
---             - {ext_…}? (`boolean`) Any of |ui-ext-options|, if true
---               enable events for the respective UI element.
---             - {set_cmdheight}? (`boolean`) If false, avoid setting
---               'cmdheight' to 0 when `ext_messages` is enabled.
--- @param callback fun(event: string, ...) Function called for each UI event
--- @return boolean A truthy value indicates `callback` handled the event.
---                 Nvim will not send the event to remote UIs.
function vim.ui_attach(ns, opts, callback) end

--- Detach a callback previously attached with |vim.ui_attach()| for the
--- given namespace {ns}.
--- @param ns integer Namespace ID
function vim.ui_detach(ns) end


Review comment (suggestion):
if the callback returns truthy, is it fair to say the callback canceled (or silenced) the event?

```suggestion
--- @return boolean Truthy if `callback` canceled the event (Nvim will not send the event to remote UIs).
```

Code after:
--- ns = vim.api.nvim_create_namespace('my_fancy_pum')
---
--- vim.ui_attach(ns, {ext_popupmenu=true}, function(event, ...)
---   if event == 'popupmenu_show' then
---     local items, selected, row, col, grid = ...
---     print('display pum ', #items)
---   elseif event == 'popupmenu_select' then
---     local selected = ...
---     print('selected', selected)
---   elseif event == 'popupmenu_hide' then
---     print('FIN')
---   end
--- end)
--- ```
---
--- @since 0
---
--- @param ns integer Namespace ID
--- @param opts table<string, any> Optional parameters.
---             - {ext_…}? (`boolean`) Any of |ui-ext-options|, if true
---               enable events for the respective UI element.
---             - {set_cmdheight}? (`boolean`) If false, avoid setting
---               'cmdheight' to 0 when `ext_messages` is enabled.
--- @param callback fun(event: string, ...): any Function called for each UI event.
---                 A truthy return value signals to Nvim that the event is handled,
---                 in which case it is not propagated to remote UIs.
function vim.ui_attach(ns, opts, callback) end

--- Detach a callback previously attached with |vim.ui_attach()| for the
--- given namespace {ns}.
--- @param ns integer Namespace ID
function vim.ui_detach(ns) end
Repository: neovim/neovim
File: src/nvim/eval.c (C)

Code before:

  if (ok) {
    // Call() must be defined if provider claims to be working.
    snprintf(buf, sizeof(buf), "provider#%s#Call", name);
    if (!find_func(buf)) {
      semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
            name, name, buf);
      ok = false;
    }
  }

  return ok;
}

/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
void eval_fmt_source_name_line(char *buf, size_t bufsize)
{
  if (SOURCING_NAME) {
    snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM);
  } else {
    snprintf(buf, bufsize, "?");
  }
}

/// Returns the current user input to the prompt in prompt buffer 'buf'
///         if 'buf' is not a prompt buffer then returns NULL.
char *prompt_current_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

void invoke_prompt_callback(void)

Review comment (suggestion):
single-quotes usually mean "option". avoid single quotes. These days backticks are usually used for symbols.

```suggestion
/// Gets the current user-input in prompt buffer `buf`, or NULL if buffer is not a prompt buffer.
```

Code after:

  if (ok) {
    // Call() must be defined if provider claims to be working.
    snprintf(buf, sizeof(buf), "provider#%s#Call", name);
    if (!find_func(buf)) {
      semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
            name, name, buf);
      ok = false;
    }
  }

  return ok;
}

/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
void eval_fmt_source_name_line(char *buf, size_t bufsize)
{
  if (SOURCING_NAME) {
    snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM);
  } else {
    snprintf(buf, bufsize, "?");
  }
}

/// Gets the current user-input in prompt buffer `buf`, or NULL if buffer is not a prompt buffer.
char *prompt_get_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

/// Invokes the user-defined callback defined for the current prompt-buffer.
void prompt_invoke_callback(void)
Repository: neovim/neovim
File: src/nvim/eval.c (C)

Code before:
///         if 'buf' is not a prompt buffer then returns NULL.
char *prompt_current_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

void invoke_prompt_callback(void)
{
  typval_T rettv;
  typval_T argv[2];
  linenr_T lnum = curbuf->b_ml.ml_line_count;

  char *current_prompt_text = prompt_current_input(curbuf);

  if (!current_prompt_text) {
    return;
  }

  // Add a new line for the prompt before invoking the callback, so that
  // text can always be inserted above the last line.
  ml_append(lnum, "", 0, false);
  appended_lines_mark(lnum, 1);
  curwin->w_cursor.lnum = lnum + 1;
  curwin->w_cursor.col = 0;

  if (curbuf->b_prompt_callback.type == kCallbackNone) {
    goto theend;
  }

  argv[0].v_type = VAR_STRING;
  argv[0].vval.v_string = current_prompt_text;
  argv[1].v_type = VAR_UNKNOWN;

Review comment (suggestion):
let's try to use a consistent prefix. also this could be static ?

```suggestion
/// Invokes the user-defined callback defined for the current prompt-buffer.
void prompt_invoke_callback(void)
```

Code after:
char *prompt_get_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

/// Invokes the user-defined callback defined for the current prompt-buffer.
void prompt_invoke_callback(void)
{
  typval_T rettv;
  typval_T argv[2];
  linenr_T lnum = curbuf->b_ml.ml_line_count;

  char *user_input = prompt_get_input(curbuf);

  if (!user_input) {
    return;
  }

  // Add a new line for the prompt before invoking the callback, so that
  // text can always be inserted above the last line.
  ml_append(lnum, "", 0, false);
  appended_lines_mark(lnum, 1);
  curwin->w_cursor.lnum = lnum + 1;
  curwin->w_cursor.col = 0;

  if (curbuf->b_prompt_callback.type == kCallbackNone) {
    xfree(user_input);
    goto theend;
  }

  argv[0].v_type = VAR_STRING;
  argv[0].vval.v_string = user_input;
Repository: neovim/neovim
File: src/nvim/eval.c (C)

Code before:
  if (ok) {
    // Call() must be defined if provider claims to be working.
    snprintf(buf, sizeof(buf), "provider#%s#Call", name);
    if (!find_func(buf)) {
      semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
            name, name, buf);
      ok = false;
    }
  }

  return ok;
}

/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
void eval_fmt_source_name_line(char *buf, size_t bufsize)
{
  if (SOURCING_NAME) {
    snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM);
  } else {
    snprintf(buf, bufsize, "?");
  }
}

/// Returns the current user input to the prompt in prompt buffer 'buf'
///         if 'buf' is not a prompt buffer then returns NULL.
char *prompt_current_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

void invoke_prompt_callback(void)
{

Review comment (suggestion):
```suggestion
char *prompt_get_input(buf_T *buf)
```

Code after:
  if (ok) {
    // Call() must be defined if provider claims to be working.
    snprintf(buf, sizeof(buf), "provider#%s#Call", name);
    if (!find_func(buf)) {
      semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
            name, name, buf);
      ok = false;
    }
  }

  return ok;
}

/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
void eval_fmt_source_name_line(char *buf, size_t bufsize)
{
  if (SOURCING_NAME) {
    snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM);
  } else {
    snprintf(buf, bufsize, "?");
  }
}

/// Gets the current user-input in prompt buffer `buf`, or NULL if buffer is not a prompt buffer.
char *prompt_get_input(buf_T *buf)
{
  if (!bt_prompt(buf)) {
    return NULL;
  }
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

/// Invokes the user-defined callback defined for the current prompt-buffer.
void prompt_invoke_callback(void)
{
Repository: neovim/neovim
File: src/nvim/eval.c (C)

Code before:
  linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

void invoke_prompt_callback(void)
{
  typval_T rettv;
  typval_T argv[2];
  linenr_T lnum = curbuf->b_ml.ml_line_count;

  char *current_prompt_text = prompt_current_input(curbuf);

  if (!current_prompt_text) {
    return;
  }

  // Add a new line for the prompt before invoking the callback, so that
  // text can always be inserted above the last line.
  ml_append(lnum, "", 0, false);
  appended_lines_mark(lnum, 1);
  curwin->w_cursor.lnum = lnum + 1;
  curwin->w_cursor.col = 0;

  if (curbuf->b_prompt_callback.type == kCallbackNone) {
    goto theend;
  }

  argv[0].v_type = VAR_STRING;
  argv[0].vval.v_string = current_prompt_text;
  argv[1].v_type = VAR_UNKNOWN;

  callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
  tv_clear(&argv[0]);
  tv_clear(&rettv);

theend:

Review comment (suggestion):
```suggestion
  char *user_input = prompt_current_input(curbuf);
```

Code after:
  linenr_T lnum_last = buf->b_ml.ml_line_count;

  char *text = ml_get_buf(buf, lnum_start);
  char *prompt = prompt_text();
  if (strlen(text) >= strlen(prompt)) {
    text += strlen(prompt);
  }

  char *full_text = xstrdup(text);
  for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
    char *half_text = concat_str(full_text, "\n");
    xfree(full_text);
    full_text = concat_str(half_text, ml_get_buf(buf, i));
    xfree(half_text);
  }
  return full_text;
}

/// Invokes the user-defined callback defined for the current prompt-buffer.
void prompt_invoke_callback(void)
{
  typval_T rettv;
  typval_T argv[2];
  linenr_T lnum = curbuf->b_ml.ml_line_count;

  char *user_input = prompt_get_input(curbuf);

  if (!user_input) {
    return;
  }

  // Add a new line for the prompt before invoking the callback, so that
  // text can always be inserted above the last line.
  ml_append(lnum, "", 0, false);
  appended_lines_mark(lnum, 1);
  curwin->w_cursor.lnum = lnum + 1;
  curwin->w_cursor.col = 0;

  if (curbuf->b_prompt_callback.type == kCallbackNone) {
    xfree(user_input);
    goto theend;
  }

  argv[0].v_type = VAR_STRING;
  argv[0].vval.v_string = user_input;
  argv[1].v_type = VAR_UNKNOWN;

  callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
  tv_clear(&argv[0]);
  tv_clear(&rettv);