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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions