Aliou Diallo

nvim-fim

FIM completion extension for Neovim with pluggable providers.

nvim-fim

Provider-agnostic Fill-In-Middle (FIM) completion plugin for Neovim with inline ghost text.

Note: This plugin was entirely vibe-coded as an experiment to explore Mistral’s Codestral FIM API. It’s a playground for testing inline completion capabilities and the provider-agnostic architecture.

Features

Installation

Using lazy.nvim

{
  'aliou/nvim-fim',
  config = function()
    require('fim').setup({
      provider = 'codestral',
      codestral = {
        api_key_provider = function()
          return os.getenv("CODESTRAL_API_KEY")
        end,
      },
    })
  end
}

Configuration

Full configuration with defaults:

require('fim').setup({
  -- Provider selection (required)
  provider = 'codestral',
  
  -- Provider-specific configuration
  codestral = {
    api_key_provider = function()
      return os.getenv("CODESTRAL_API_KEY")
    end,
    -- Free tier endpoint (requires phone-verified API key)
    endpoint = "https://codestral.mistral.ai/v1/fim/completions",
    -- Or use paid endpoint: "https://api.mistral.ai/v1/fim/completions"
    model = "codestral-latest",
    max_tokens = 256,
    stop = nil,
  },
  
  -- Universal settings (apply to all providers)
  context = {
    prefix_lines = 100,
    suffix_lines = 30,
    max_prefix_chars = 4000,
    max_suffix_chars = 1000,
  },
  debounce_ms = 50,
  highlight = "Comment",
  keymaps = {
    accept = "<Tab>",
    accept_word = "<C-Right>",
    accept_line = "<C-e>",
    dismiss = "<C-]>",
    trigger = "<C-Space>",
  },
  disabled_filetypes = {},
})

Codestral API Key

Free API Key: Get a free Codestral API key at console.mistral.ai. The free tier (codestral.mistral.ai endpoint) is designed for individual users and plugin developers. Phone verification is required.

For more details, see the Codestral FIM documentation.

Option 1: Use :FimLogin command (easiest)

:FimLogin

This saves your key to ~/.local/share/nvim/fim/codestral/api_key (the default location).

Option 2: Environment variable

export CODESTRAL_API_KEY="your-key-here"
codestral = {
  api_key_provider = function()
    return os.getenv("CODESTRAL_API_KEY")
  end,
}

Option 3: Custom file location

codestral = {
  api_key_provider = function()
    return vim.fn.readfile(vim.fn.expand("~/.secrets/codestral"))[1]
  end,
}

Option 4: Use default file location

By default, if you don’t specify api_key_provider, it reads from:

~/.local/share/nvim/fim/codestral/api_key

Just create this file with your key, or use :FimLogin to set it up.

Usage

How It Works

Type in insert mode

Debounced trigger (50ms)

Extract context (prefix/suffix around cursor)

Request completion from active provider

Render ghost text via extmarks

Accept (Tab), partial accept (C-Right/C-e), or dismiss (C-])

Testing

Run tests with:

nix-shell --run "busted"

CI runs automatically on push/PR.

Architecture

Provider-agnostic core engine with pluggable providers:

lua/fim/
├── init.lua           # Entry point, setup(), autocommands
├── config.lua         # Configuration management
├── context.lua        # Buffer context extraction
├── suggestion.lua     # State management
├── render.lua         # Ghost text rendering
├── keymaps.lua        # Keybindings
└── providers/         # Provider implementations
    ├── init.lua       # Provider interface/registry
    └── codestral.lua  # Mistral Codestral implementation

Future providers (OpenAI, Anthropic, DeepSeek, etc.) can be added by implementing the provider interface.

References

Inspired by:

License

MIT