NeoCodeium Documentation

repository·main·Indexed 19 days ago

https://github.com/monkoose/neocodeium

A Neovim plugin providing AI-powered code completions using the Windsurf (formerly Codeium) engine. It features improved stability over the official plugin, addressing multi-line virtual text flickering and supporting repeatable completions via the `.` command. Includes a Lua API for programmatic control, integration guides for nvim-cmp and blink.cmp, and a set of user commands for authentication and server management.

Tokens
3.8K
Snippets
9
Records
13
Agent score
17%

What's inside NeoCodeium

  1. Install NeoCodeium via lazy.nvim

    main

    To install NeoCodeium using the lazy.nvim plugin manager, add the following configuration to your plugin setup. This example includes a default keymap for accepting suggestions using Alt-f in insert mode.

    -- add this to the file where you setup your other plugins:
    {
      "monkoose/neocodeium",
      event = "VeryLazy",
      config = function()
        local neocodeium = require("neocodeium")
        neocodeium.setup()
        vim.keymap.set("i", "<A-f>", neocodeium.accept)
      end,
    }
  2. Integrate NeoCodeium with nvim-cmp

    main

    To prevent conflicts between NeoCodeium and nvim-cmp, use one of these two patterns:

    Pattern 1: NeoCodeium as primary (manual cmp)

    Set nvim-cmp to manual completion and clear NeoCodeium suggestions when the cmp menu opens. Use manual = false for NeoCodeium.

    local cmp = require("cmp")
    local neocodeium = require("neocodeium")
    
    cmp.event:on("menu_opened", function()
        neocodeium.clear()
    end)
    
    neocodeium.setup({
        filter = function() 
            return not cmp.visible() 
        end,
    })
    
    cmp.setup({
        completion = {
            autocomplete = false,
        },
    })

    Pattern 2: nvim-cmp as primary (manual NeoCodeium)

    Set NeoCodeium to manual = true. Create an autocommand to abort cmp when NeoCodeium completions are displayed.

    local neocodeium = require("neocodeium")
    
    neocodeium.setup({
      manual = true,
    })
    
    -- close cmp when ai completions are displayed
    vim.api.nvim_create_autocmd("User", {
      pattern = "NeoCodeiumCompletionDisplayed",
      callback = function() require("cmp").abort() end,
    })
    -- Pattern 1: Manual cmp
    local cmp = require("cmp")
    local neocodeium = require("neocodeium")
    
    cmp.event:on("menu_opened", function()
        neocodeium.clear()
    end)
    
    neocodeium.setup({
        filter = function()
            return not cmp.visible()
        end,
    })
    
    cmp.setup({
        completion = {
            autocomplete = false,
        },
    })
  3. Integrate NeoCodeium with blink.cmp

    main

    When using blink.cmp, configure blink.cmp to disable auto-show in default mode. Then, clear NeoCodeium suggestions when the BlinkCmpMenuOpen event is triggered and ensure NeoCodeium only shows suggestions when blink is not visible.

    -- blink.cmp config
    completion = {
        menu = {
            auto_show = function(ctx)
                return ctx.mode ~= 'default'
            end,
        }
    }
    
    -- integration
    local neocodeium = require('neocodeium')
    local blink = require('blink.cmp')
    
    vim.api.nvim_create_autocmd('User', {
      pattern = 'BlinkCmpMenuOpen',
      callback = function()
        neocodeium.clear()
      end,
    })
    
    neocodeium.setup({
      filter = function()
        return not blink.is_visible()
      end,
    })
  4. How the NeoCodeium server connects and communicates

    main

    The NeoCodeium server operates as a background process that communicates with Neovim via a local TCP port.

    1. Process Spawning: The server is spawned with a manager_dir (created in the system temp directory).
    2. Port Discovery: The server writes a file named after its port (e.g., 12345) into the manager_dir. The client uses find_port_file to scan this directory and identify the active port.
    3. Connection: Once the port is found, the client establishes a TCP connection to 127.0.0.1:{port}.
    4. Heartbeat: After a successful connection, the client automatically starts a heartbeat loop, sending a Heartbeat request every 10 seconds to keep the connection alive and monitor server health.
    5. Events: The server lifecycle triggers several events that consumers can listen to:
      • NeoCodeiumServerConnecting
      • NeoCodeiumServerConnected
      • NeoCodeiumServerStopped
  5. Configure NeoCodeium for Enterprise users

    main

    Enterprise users should provide the Windsurf portal and API URLs provided by their company to ensure :NeoCodeium auth authenticates against the correct portal.

    {
      "monkoose/neocodeium",
      event = "VeryLazy",
      opts = {
        server = {
          api_url = 'https://codeium.company.net/_route/api_server',
          portal_url = 'https://codeium.company.net',
        },
      }
    }
  6. Configure NeoCodeium options

    main

    Use require("neocodeium").setup(options) to configure the plugin. Key options include:

    • enabled (boolean): Whether the plugin is active. If false, the windsurf server won't start.
    • bin (string|nil): Path to a custom windsurf server binary.
    • manual (boolean): If true, autosuggestions are disabled; use cycle_or_complete() to show them manually.
    • server (table): Contains api_url and portal_url for Enterprise mode.
    • show_label (boolean): Whether to show the suggestion count in the line number column.
    • debounce (boolean): If true, enables suggestions debounce.
    • max_lines (number): Max lines parsed from loaded buffers (0 to disable non-current buffer parsing, -1 for all).
    • silent (boolean): If true, suppresses non-important messages.
    • disable_in_special_buftypes (boolean): If true, disables suggestions in special buftypes (e.g., nofile).
    • log_level (string): One of "trace", "debug", "info", "warn", "error".
    • single_line (table): Configuration for single-line mode. enabled (boolean) collapses multi-line suggestions into one line.
    • filter (function): A function function(bufnr) end that returns true to enable or false to disable suggestions for a buffer.
    • filetypes (table): A list of filetypes to disable suggestions for (e.g., { help = false, gitcommit = false }).
    • root_dir (table): List of patterns to detect the workspace root directory.
    -- NeoCodeium Configuration
    require("neocodeium").setup({
      enabled = true,
      bin = nil,
      manual = false,
      server = {
        api_url = nil,
        portal_url = nil,
      },
      show_label = true,
      debounce = false,
      max_lines = 10000,
      silent = false,
      disable_in_special_buftypes = true,
      log_level = "warn",
      single_line = {
        enabled = false,
        label = "...",
      },
      filter = function(bufnr) return true end,
      filetypes = {
        help = false,
        gitcommit = false,
        gitrebase = false,
        ["."] = false,
      },
      root_dir = { ".bzr", ".git", ".hg", ".svn", "_FOSSIL_", "package.json" }
    })
  7. Get NeoCodeium Status for Statusline

    main

    Use require("neocodeium").get_status() to retrieve the current state of the plugin and server. This returns two numbers:

    1. Plugin Status:

    • 0: Enabled
    • 1: Globally disabled
    • 2: Buffer is disabled
    • 3: Buffer disabled by filetype
    • 4: Buffer disabled by filter function
    • 5: Buffer has wrong encoding (requires UTF-8 or LATIN-1)
    • 6: Buffer is a special type

    2. Server Status:

    • 0: Server is on (running)
    • 1: Connecting to the server
    • 2: Server is off (stopped)

    To ensure the statusline updates in real-time, invoke this function within an autocmd listening to NeoCodeiumServer* or NeoCodeium*Enabled/Disabled events.

    local neocodeium = require("neocodeium")
    local function get_neocodeium_status(ev) 
        local status, server_status = neocodeium.get_status()
        -- process data...
        if status == 0 then
            vim.api.nvim_buf_set_var(ev.buf, "neocodeium_status", "OK")
        else
            vim.api.nvim_buf_set_var(ev.buf, "neocodeium_status", "OFF")
        end
        vim.cmd.redrawstatus()
    end
    
    vim.api.nvim_create_autocmd("User", {
        pattern = {"NeoCodeiumServer*", "NeoCodeium*Enabled", "NeoCodeium*Disabled"}
        callback = get_neocodeium_status,
    })
  8. Use NeoCodeium Lua API

    main

    The neocodeium module provides several functions for controlling completions programmatically:

    • accept(): Accepts the current suggestion.
    • accept_word(): Accepts only the current word of the suggestion.
    • accept_line(): Accepts only the current line of the suggestion.
    • clear(): Clears the current suggestion.
    • cycle(n): Cycles through suggestions by n items (use negative for reverse).
    • cycle_or_complete(n): Cycles through suggestions; if none are visible, it attempts to show one (useful in manual mode).
    • visible(): Returns whether the suggestion's virtual text is currently visible.
    local neocodeium = require("neocodeium")
    
    -- Accepts the suggestion
    neocodeium.accept()
    
    -- Accepts only part of the suggestion if the full suggestion doesn't make sense
    neocodeium.accept_word()
    neocodeium.accept_line()
    
    -- Clears the current suggestion
    neocodeium.clear()
    
    -- Cycles through suggestions by `n` (1 by default). 
    -- Use a negative value to cycle in reverse order
    neocodeium.cycle(n)
    
    -- Same as `cycle()`, but also tries to show a suggestion if none is visible.
    -- Mostly useful with the enabled `manual` option
    neocodeium.cycle_or_complete(n)
    
    -- Checks if a suggestion's virtual text is visible or not (useful for some complex mappings)
    neocodeium.visible()
  9. Monitor NeoCodeium via User Events

    main

    NeoCodeium triggers several User events that can be used for statusline updates or custom logic:

    • NeoCodeiumServerConnecting: Connection to windsurf server is starting.
    • NeoCodeiumServerConnected: Successful connection made.
    • NeoCodeiumServerStopped: Windsurf server is stopped.
    • NeoCodeiumEnabled: Plugin enabled globally.
    • NeoCodeiumDisabled: Plugin disabled globally.
    • NeoCodeiumBufEnabled: Plugin enabled for a buffer.
    • NeoCodeiumBufDisabled: Plugin disabled for a buffer.
    • NeoCodeiumCompletionDisplayed: Completion item displayed as virtual text.
    • NeoCodeiumCompletionCleared: Virtual text and completions cleared.
    • NeoCodeiumLabelUpdated: Suggestion count label changed. This event carries the label text in ev.data (e.g., "1/6", " 0 ", " * ").
  10. Use NeoCodeium Commands

    main

    NeoCodeium provides several user commands:

    • :NeoCodeium auth: Authenticates the user and saves the API token.
    • :NeoCodeium disable: Disables completions.
    • :NeoCodeium! disable: Disables completions and stops the windsurf server.
    • :NeoCodeium enable: Enables NeoCodeium completion.
    • :NeoCodeium toggle: Toggles NeoCodeium completion.
    • :NeoCodeium! toggle: Toggles NeoCodeium completion (with bang to disable).
    • :NeoCodeium disable_buffer: Disables NeoCodeium in the current buffer.
    • :NeoCodeium enable_buffer: Enables NeoCodeium in the current buffer.
    • :NeoCodeium toggle_buffer: Toggles NeoCodeium in the current buffer.
    • :NeoCodeium open_log: Opens a new tab with the log output.
    • :NeoCodeium chat: Opens the browser with Windsurf Chat.
    • :NeoCodeium restart: Restarts the server.
  11. Configure NeoCodeium Highlight Groups

    main

    You can customize the appearance of NeoCodeium using the following highlight groups:

    • NeoCodeiumSuggestion: Color of the virtual text suggestions (default: #808080).
    • NeoCodeiumLabel: Color of the suggestion count label (default: inverted DiagnosticInfo).
    • NeoCodeiumSingleLineLabel: Color of the multi-line suggestion label in single-line mode (default: bold #808080).
  12. Send requests to the NeoCodeium server

    main

    The Server:request method allows sending JSON-encoded requests to the backend via a TCP connection. The server uses a specific URI pattern based on the request type: POST /exa.language_server_pb.LanguageServerService/{type}.

    Signature

    Server:request(type, data, on_exit)

    • type (string): The specific service method name (e.g., Heartbeat).
    • data (table): The JSON-serializable payload for the request.
    • on_exit (function, optional): A callback function that receives the parsed JSON response string once the connection reaches EOF.

    Usage Example

    Server:request("Heartbeat", { some_key = "value" }, function(response)
      print("Server response:", response)
    end)
    Server:request("Heartbeat", { some_key = "value" }, function(response)
      print("Server response:", response)
    end)