Skip to content

setup() auto-runs from plugin/gemini.vim, causing double execution and a startup-blocking prompt under lazy.nvim #173

Description

@arisc1994

Environment

  • Neovim: v0.12.3
  • Plugin manager: lazy.nvim
  • gemini-cli.nvim commit: 887fc46979e0a1e4e05035bcc83deb76164e91a2 (branch main)
  • OS: Linux (WSL2)

Summary

plugin/gemini.vim automatically calls require('gemini').setup() as soon as the plugin is loaded:

" plugin/gemini.vim
if !exists('g:gemini_loaded')
  lua require('gemini').setup()
  let g:gemini_loaded = 1
endif

This conflicts with the standard lazy.nvim convention where the user is expected to call setup() themselves from their plugin spec's config function, e.g.:

return {
  "jonroosevelt/gemini-cli.nvim",
  config = function()
    require("gemini").setup()
  end,
}

Following that (very common) pattern results in setup() running twice on every startup — once automatically via plugin/gemini.vim, and once via the user's own config function.

Why this matters

M.setup() calls vim.fn.executable("gemini"), and if the gemini CLI binary isn't on $PATH, it falls into a branch that calls the blocking vim.fn.input("Gemini CLI not found. Install it now? (y/n): "). Since this executes automatically at plugin-load time (i.e. during Neovim startup), it:

  1. Blocks Neovim startup on a synchronous prompt before the UI is even fully drawn, rather than failing gracefully or deferring to a user command.
  2. Can be triggered twice in a row when the user also has a config = function() require("gemini").setup() end in their lazy.nvim spec (a natural thing to write, since nothing in the README says not to), producing two sequential blocking prompts.
  3. In headless/scripted Neovim invocations (e.g. nvim --headless -c '...', useful for CI, nvim -l scripts, or automation), this prompt has no way to be answered and hangs indefinitely until the process is killed.

Steps to reproduce

  1. Install with lazy.nvim using the "normal" pattern:
    return {
      "jonroosevelt/gemini-cli.nvim",
      config = function()
        require("gemini").setup()
      end,
    }
  2. Make sure the gemini CLI binary is not installed / not on $PATH.
  3. Start Neovim.

Expected behavior

  • setup() should only run once, regardless of whether the user also calls it explicitly from their lazy.nvim config function (or it should not be auto-invoked from plugin/gemini.vim at all, leaving that entirely up to the user's config/lazy-loading setup, per standard plugin conventions).
  • Missing the gemini CLI shouldn't block Neovim startup with a synchronous prompt. Consider:
    • Using vim.notify(...) (non-blocking) instead of vim.fn.input(...), and/or
    • Exposing an explicit :GeminiInstall user command instead of prompting automatically, and/or
    • Deferring the check with vim.schedule() / VimEnter so it doesn't block startup, and skipping the interactive prompt entirely when running headless (#vim.api.nvim_list_uis() == 0).

Suggested fix

Remove the automatic require('gemini').setup() call from plugin/gemini.vim and let the plugin's own M.setup() be the single entry point that users call once from their plugin manager config (standard lazy.nvim convention). Alternatively, guard plugin/gemini.vim's auto-call so that if the user's own config already called setup(), it's a no-op (e.g. track an internal "already set up" flag inside M.setup() itself, not just via the vimscript-side g:gemini_loaded guard which doesn't protect against the lua-side call from config).

Separately, please consider not blocking on vim.fn.input() for the CLI-install prompt — it can hang indefinitely in headless/non-interactive Neovim sessions with no way to respond.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions