Skip to content

Indexing exclusions are ignored with the Rubydex indexer (0.27.0.beta5) #4253

Open

Description

@itisbryan

Summary

With the Rubydex indexer (0.27.0.beta5), there is no working way to reduce what
gets indexed. The documented initializationOptions.indexing settings
(excludedGems, excludedPatterns, includedPatterns) have no effect, and
because indexing now covers every locked gem, startup is dominated by vendored
gem code.

Environment

  • Ruby LSP 0.27.0.beta5 (--beta), gem rubydex 0.4.4
  • Neovim 0.12.4, launched through a per-project Ruby (rv), composed .ruby-lsp bundle
  • Project: Rails 8.1 app, Ruby 4.0.0, bundle at vendor/bundle, 189 gems

Reproduction

  1. Launch the server against a project with a vendored bundle.
  2. Send initialize with initializationOptions: { indexing: { excludedGems: ["<gem>"] } }.
  3. Compare the index contents with a run that omits the option — identical.

An excluded gem is still indexed, so exclusion cannot be used to cut startup time.

Expected

excludedGems / excludedPatterns from the documented initialization options
removes those files from the index, as they did with RubyIndexer.

Actual

The options are ignored entirely with the Rubydex indexer.

Evidence

  1. Nothing in ruby_lsp/ under 0.27.0.beta5 reads the indexing options. The
    only occurrences are progress notifications and
    perform_initial_indexing, which calls graph.index_workspace unconditionally:
    benchmark("index_workspace") { @global_state.graph.index_workspace }
    benchmark("full_resolve") { @global_state.graph.resolve }
  2. rubydex.toml has no index section; adding one fails:
    Rubydex::ConfigError: Invalid config file .../rubydex.toml: unknown section `index`
    
    The Ruby config API only models [linter].
  3. Rubydex::Graph exposes no setter in 0.4.4:
    NoMethodError: undefined method 'exclude_patterns=' for an instance of Rubydex::Graph
    
  4. Graph#workspace_paths seeds the index from every top-level workspace
    directory plus each locked gem's require paths, with no group filtering:
    specs = Bundler.locked_gems&.specs
    specs.each do |lazy_spec|
      spec = Gem::Specification.find_by_name(lazy_spec.name)
      spec.require_paths.each { |path| paths << File.join(spec.full_gem_path, path) }
    end
    This also means development and test gems are indexed again, whereas Automatically exclude transitive test dependencies from indexing #1078
    excluded development and transitive development dependencies.

Measured impact

On a Rails 8 project with a vendored bundle:

Observation Result
index_workspace 1.7 s
resolve 0.9 s
Indexed documents 48,826 total: 2,276 app, 46,549 vendored gem
First request after startup 4.1–4.8 s
Subsequent requests 3–7 ms

The cost is paid once per server process, since the graph is not cached to disk
(see #1009), and 95% of it is gem code from vendor/bundle.

Suggestion

Either honor initializationOptions.indexing.excludedGems / excludedPatterns
in the Rubydex path, or restore the previous behavior of skipping development
and test groups. Both would cut startup substantially for vendored bundles.

Activity

  1. jadibdev commented on Nov 3, 2026

    @jadibdev

    Hi @itisbryan, rubydex does support exclusions, just not under the names in the issue. The section is [graph] rather than [index], and the Ruby method is Graph#exclude_patterns(patterns) (there's no = setter, hence the NoMethodError).

    I tried this on a fresh Rails 8.1 app (Ruby 4.0.5, 142 gems vendored in vendor/bundle, rubydex 0.4.4):

    [graph]
    exclude = ["vendor/bundle"]

    index_workspace went from 1.57s to 0.76s. The document count only dropped from 7,570 to 6,317, though, because gem lib/ code is still indexed through the require paths. Watch out for vendor/bundle/** instead: it matches the require paths too and dropped every gem for me (22 documents left).

    @vinistock, most of what's left is gem code, and there's no config for that. The old indexer skipped development-only gems and honored excludedGems, and here the rubocop gems alone were 1,276 of the 7,570 documents. Excluding a gem's directory through exclude_patterns does drop it (I checked with a rubocop* pattern), so ruby-lsp could do this today, applying it after load_rubydex_config since load_config replaces the patterns. Would you rather have that in ruby-lsp, or a gem filter in rubydex? Happy to put up a PR for whichever you prefer.

    Scripts: https://github.com/jadibdev/ruby-lsp/tree/4253-verification/verification-4253

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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