From 95ed300a4fceceaf4b0b95baef7701a1e0bc30aa Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Tue, 13 Jan 2026 05:08:14 -0500 Subject: [PATCH 01/10] Avoid rbs pollution (#1146) We were using the sig/shims directory for some internally helpful shims; unfortunately that exported them during gem installs, causing https://github.com/castwide/solargraph/issues/1144 --- {sig => rbs}/shims/ast/0/node.rbs | 0 {sig => rbs}/shims/ast/2.4/.rbs_meta.yaml | 0 {sig => rbs}/shims/ast/2.4/ast.rbs | 0 {sig => rbs}/shims/parser/3.2.0.1/builders/default.rbs | 0 {sig => rbs}/shims/parser/3.2.0.1/manifest.yaml | 0 {sig => rbs}/shims/parser/3.2.0.1/parser.rbs | 0 {sig => rbs}/shims/parser/3.2.0.1/polyfill.rbs | 0 {sig => rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml | 0 {sig => rbs}/shims/thor/1.2.0.1/manifest.yaml | 0 {sig => rbs}/shims/thor/1.2.0.1/thor.rbs | 0 rbs_collection.yaml | 2 +- 11 files changed, 1 insertion(+), 1 deletion(-) rename {sig => rbs}/shims/ast/0/node.rbs (100%) rename {sig => rbs}/shims/ast/2.4/.rbs_meta.yaml (100%) rename {sig => rbs}/shims/ast/2.4/ast.rbs (100%) rename {sig => rbs}/shims/parser/3.2.0.1/builders/default.rbs (100%) rename {sig => rbs}/shims/parser/3.2.0.1/manifest.yaml (100%) rename {sig => rbs}/shims/parser/3.2.0.1/parser.rbs (100%) rename {sig => rbs}/shims/parser/3.2.0.1/polyfill.rbs (100%) rename {sig => rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml (100%) rename {sig => rbs}/shims/thor/1.2.0.1/manifest.yaml (100%) rename {sig => rbs}/shims/thor/1.2.0.1/thor.rbs (100%) diff --git a/sig/shims/ast/0/node.rbs b/rbs/shims/ast/0/node.rbs similarity index 100% rename from sig/shims/ast/0/node.rbs rename to rbs/shims/ast/0/node.rbs diff --git a/sig/shims/ast/2.4/.rbs_meta.yaml b/rbs/shims/ast/2.4/.rbs_meta.yaml similarity index 100% rename from sig/shims/ast/2.4/.rbs_meta.yaml rename to rbs/shims/ast/2.4/.rbs_meta.yaml diff --git a/sig/shims/ast/2.4/ast.rbs b/rbs/shims/ast/2.4/ast.rbs similarity index 100% rename from sig/shims/ast/2.4/ast.rbs rename to rbs/shims/ast/2.4/ast.rbs diff --git a/sig/shims/parser/3.2.0.1/builders/default.rbs b/rbs/shims/parser/3.2.0.1/builders/default.rbs similarity index 100% rename from sig/shims/parser/3.2.0.1/builders/default.rbs rename to rbs/shims/parser/3.2.0.1/builders/default.rbs diff --git a/sig/shims/parser/3.2.0.1/manifest.yaml b/rbs/shims/parser/3.2.0.1/manifest.yaml similarity index 100% rename from sig/shims/parser/3.2.0.1/manifest.yaml rename to rbs/shims/parser/3.2.0.1/manifest.yaml diff --git a/sig/shims/parser/3.2.0.1/parser.rbs b/rbs/shims/parser/3.2.0.1/parser.rbs similarity index 100% rename from sig/shims/parser/3.2.0.1/parser.rbs rename to rbs/shims/parser/3.2.0.1/parser.rbs diff --git a/sig/shims/parser/3.2.0.1/polyfill.rbs b/rbs/shims/parser/3.2.0.1/polyfill.rbs similarity index 100% rename from sig/shims/parser/3.2.0.1/polyfill.rbs rename to rbs/shims/parser/3.2.0.1/polyfill.rbs diff --git a/sig/shims/thor/1.2.0.1/.rbs_meta.yaml b/rbs/shims/thor/1.2.0.1/.rbs_meta.yaml similarity index 100% rename from sig/shims/thor/1.2.0.1/.rbs_meta.yaml rename to rbs/shims/thor/1.2.0.1/.rbs_meta.yaml diff --git a/sig/shims/thor/1.2.0.1/manifest.yaml b/rbs/shims/thor/1.2.0.1/manifest.yaml similarity index 100% rename from sig/shims/thor/1.2.0.1/manifest.yaml rename to rbs/shims/thor/1.2.0.1/manifest.yaml diff --git a/sig/shims/thor/1.2.0.1/thor.rbs b/rbs/shims/thor/1.2.0.1/thor.rbs similarity index 100% rename from sig/shims/thor/1.2.0.1/thor.rbs rename to rbs/shims/thor/1.2.0.1/thor.rbs diff --git a/rbs_collection.yaml b/rbs_collection.yaml index 898239cac..d94e1c896 100644 --- a/rbs_collection.yaml +++ b/rbs_collection.yaml @@ -2,7 +2,7 @@ sources: - type: local name: shims - path: sig/shims + path: rbs/shims - type: git name: ruby/gem_rbs_collection From ce12a5f63cba2e72b04453c756751a3fafb2d0a0 Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Tue, 13 Jan 2026 05:11:44 -0500 Subject: [PATCH 02/10] Fix 'solargraph pin --references ClassName' private method call (#1150) --- lib/solargraph/api_map.rb | 12 ++++++------ spec/shell_spec.rb | 32 +++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/solargraph/api_map.rb b/lib/solargraph/api_map.rb index cc3031ea5..6c0da316e 100755 --- a/lib/solargraph/api_map.rb +++ b/lib/solargraph/api_map.rb @@ -711,6 +711,12 @@ def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scop methods end + # @param fq_sub_tag [String] + # @return [String, nil] + def qualify_superclass fq_sub_tag + store.qualify_superclass fq_sub_tag + end + private # A hash of source maps with filename keys. @@ -804,12 +810,6 @@ def path_macros @path_macros ||= {} end - # @param fq_sub_tag [String] - # @return [String, nil] - def qualify_superclass fq_sub_tag - store.qualify_superclass fq_sub_tag - end - # Get the namespace's type (Class or Module). # # @param fqns [String] A fully qualified namespace diff --git a/spec/shell_spec.rb b/spec/shell_spec.rb index b9dc6b327..3b8dc0426 100644 --- a/spec/shell_spec.rb +++ b/spec/shell_spec.rb @@ -57,7 +57,37 @@ def bundle_exec(*cmd) end end - describe 'pin' do + describe 'pin on a class' do + let(:api_map) { instance_double(Solargraph::ApiMap) } + let(:string_pin) { instance_double(Solargraph::Pin::Namespace, name: 'String') } + + before do + allow(Solargraph::ApiMap).to receive(:load_with_cache).and_return(api_map) + allow(Solargraph::Pin::Namespace).to receive(:===).with(string_pin).and_return(true) + allow(string_pin).to receive(:return_type).and_return(Solargraph::ComplexType.parse('String')) + allow(api_map).to receive(:get_path_pins).with('String').and_return([string_pin]) + end + + context 'with --references option' do + let(:object_pin) { instance_double(Solargraph::Pin::Namespace, name: 'Object') } + + before do + allow(Solargraph::Pin::Namespace).to receive(:===).with(object_pin).and_return(true) + allow(api_map).to receive(:qualify_superclass).with('String').and_return('Object') + allow(api_map).to receive(:get_path_pins).with('Object').and_return([object_pin]) + end + + it 'prints a pin with info' do + out = capture_both do + shell.options = { references: true } + shell.pin('String') + end + expect(out).to include('# Superclass:') + end + end + end + + describe 'pin on a method' do let(:api_map) { instance_double(Solargraph::ApiMap) } let(:to_s_pin) { instance_double(Solargraph::Pin::Method, return_type: Solargraph::ComplexType.parse('String')) } From 5ae55584e399822af0a12b386229acffdd9bd7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lek=C3=AB=20Mula?= Date: Wed, 14 Jan 2026 01:47:12 +0100 Subject: [PATCH 03/10] Improve memory efficiency of Position class (#1054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use each_line instead of text.lines Avoid allocating additional strings, instead use sliced substrings * gitignore vendor/cache * Remove redundant end_with? Co-authored-by: Jean Boussier * Remove benchamrks https://github.com/castwide/solargraph/pull/1054#discussion_r2312388042 * String#index(offset:) FTW 🚀 https://github.com/castwide/solargraph/pull/1054#issuecomment-3240029936 Co-authored-by: Jean Boussier * fix rubocop --------- Co-authored-by: Jean Boussier --- .gitignore | 1 + lib/solargraph/position.rb | 32 +++++++++++++++++++++----------- spec/position_spec.rb | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 2819165b1..75510d96b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ coverage /Makefile /.pryrc /.rspec-local +vendor/cache diff --git a/lib/solargraph/position.rb b/lib/solargraph/position.rb index 74606f142..e47ed8bc8 100644 --- a/lib/solargraph/position.rb +++ b/lib/solargraph/position.rb @@ -58,8 +58,22 @@ def inspect # @return [Integer] def self.to_offset text, position return 0 if text.empty? - # @sg-ignore Unresolved call to + on Integer - text.lines[0...position.line].sum(&:length) + position.character + newline_index = -1 + cursor = 0 + line = -1 + + last_line_index = 0 + while (newline_index = text.index("\n", newline_index + 1)) && line <= position.line + line += 1 + break if line == position.line + line_length = newline_index - last_line_index + + cursor += line_length.zero? ? 1 : line_length + + last_line_index = newline_index + end + + cursor + position.character end # Get a numeric offset for the specified text and a position identified @@ -81,16 +95,12 @@ def self.line_char_to_offset text, line, character def self.from_offset text, offset cursor = 0 line = 0 - character = nil - text.lines.each do |l| - line_length = l.length - char_length = l.chomp.length - if cursor + char_length >= offset - character = offset - cursor - break - end - cursor += line_length + character = offset + newline_index = -1 + + while (newline_index = text.index("\n", newline_index + 1)) && newline_index < offset line += 1 + character = offset - newline_index - 1 end character = 0 if character.nil? and (cursor - offset).between?(0, 1) raise InvalidOffsetError if character.nil? diff --git a/spec/position_spec.rb b/spec/position_spec.rb index fa30cf7d9..88dedcd26 100644 --- a/spec/position_spec.rb +++ b/spec/position_spec.rb @@ -12,6 +12,22 @@ expect(orig).to be(norm) end + it 'finds offset from position' do + text = "\n class Foo\n def bar baz, boo = 'boo'\n end\n end\n " + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(0, 0))).to eq(0) + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(0, 4))).to eq(4) + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(2, 12))).to eq(29) + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(2, 27))).to eq(44) + end + + it 'constructs position from offset' do + text = "\n class Foo\n def bar baz, boo = 'boo'\n end\n end\n " + expect(Solargraph::Position.from_offset(text, 0)).to eq(Solargraph::Position.new(0, 0)) + expect(Solargraph::Position.from_offset(text, 4)).to eq(Solargraph::Position.new(1, 3)) + expect(Solargraph::Position.from_offset(text, 29)).to eq(Solargraph::Position.new(2, 12)) + expect(Solargraph::Position.from_offset(text, 44)).to eq(Solargraph::Position.new(2, 27)) + end + it "raises an error for objects that cannot be normalized" do expect { Solargraph::Position.normalize('0, 1') From 4c05f2806078c3433b08ce3703eeb8a34e9325fc Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Wed, 14 Jan 2026 03:15:31 -0500 Subject: [PATCH 04/10] Raise InvalidOffsetError for offsets > text (#1155) * Raise InvalidOffsetError for offsets > text * Linting * Fix fencepost error * Additional fencepost test * Document exception --- lib/solargraph/position.rb | 15 +++++++++------ spec/position_spec.rb | 13 +++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/solargraph/position.rb b/lib/solargraph/position.rb index e47ed8bc8..a0d7bbc2e 100644 --- a/lib/solargraph/position.rb +++ b/lib/solargraph/position.rb @@ -58,22 +58,21 @@ def inspect # @return [Integer] def self.to_offset text, position return 0 if text.empty? + newline_index = -1 - cursor = 0 line = -1 - last_line_index = 0 + while (newline_index = text.index("\n", newline_index + 1)) && line <= position.line line += 1 break if line == position.line - line_length = newline_index - last_line_index - - cursor += line_length.zero? ? 1 : line_length + line_length = newline_index - last_line_index last_line_index = newline_index end - cursor + position.character + last_line_index += 1 if position.line > 0 + last_line_index + position.character end # Get a numeric offset for the specified text and a position identified @@ -89,10 +88,14 @@ def self.line_char_to_offset text, line, character # Get a position for the specified text and offset. # + # @raise [InvalidOffsetError] if the offset is outside the text range + # # @param text [String] # @param offset [Integer] # @return [Position] def self.from_offset text, offset + raise InvalidOffsetError if offset > text.length + cursor = 0 line = 0 character = offset diff --git a/spec/position_spec.rb b/spec/position_spec.rb index 88dedcd26..e8dab1960 100644 --- a/spec/position_spec.rb +++ b/spec/position_spec.rb @@ -18,6 +18,7 @@ expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(0, 4))).to eq(4) expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(2, 12))).to eq(29) expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(2, 27))).to eq(44) + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(3, 8))).to eq(58) end it 'constructs position from offset' do @@ -33,4 +34,16 @@ Solargraph::Position.normalize('0, 1') }.to raise_error(ArgumentError) end + + it 'avoids fencepost errors' do + text = " class Foo\n def bar baz, boo = 'boo'\n end\n end\n " + offset = Solargraph::Position.to_offset(text, Solargraph::Position.new(3, 6)) + expect(offset).to eq(67) + end + + it 'avoids fencepost errors with multiple blank lines' do + text = " class Foo\n def bar baz, boo = 'boo'\n\n end\n end\n " + offset = Solargraph::Position.to_offset(text, Solargraph::Position.new(4, 6)) + expect(offset).to eq(68) + end end From 676da4c4cec040d735a9a54265c91dc91ec462bb Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Mon, 19 Jan 2026 07:26:26 -0500 Subject: [PATCH 05/10] Release 0.58.2 --- CHANGELOG.md | 8 +++++++- lib/solargraph/version.rb | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 315ba0c73..e07381830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ +## 0.58.2 - January 19, 2026 +- Avoid rbs pollution (#1146) +- Fix 'solargraph pin --references ClassName' private method call (#1150) +- Improve memory efficiency of Position class (#1054) +- Raise InvalidOffsetError for offsets > text (#1155) + ## 0.58.1 - January 2, 2026 -- Normalize line endings to LF (#1142) +- Normalize line endings to LF (#1142) ## 0.58.0 - January 1, 2026 - Faster constant resolution (#1083) diff --git a/lib/solargraph/version.rb b/lib/solargraph/version.rb index 5bb8e52f8..11dd7e1ff 100755 --- a/lib/solargraph/version.rb +++ b/lib/solargraph/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Solargraph - VERSION = '0.58.1' + VERSION = '0.58.2' end From cbaf4af058908d2fc037323893d0976cb0ca8b7e Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Thu, 29 Jan 2026 07:22:28 -0500 Subject: [PATCH 06/10] Debug logging fixes --- spec/logging_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/logging_spec.rb b/spec/logging_spec.rb index eee59e606..7d38c087e 100644 --- a/spec/logging_spec.rb +++ b/spec/logging_spec.rb @@ -9,7 +9,7 @@ msg = file.read file.close file.unlink - Solargraph::Logging.logger.reopen STDERR + Solargraph::Logging.logger.reopen File::NULL expect(msg).to include('WARN') end end From 92a677fde005d2f3c882abba32d1e6a840f8073a Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Sat, 31 Jan 2026 11:46:21 -0500 Subject: [PATCH 07/10] Reproduce build problem with RBS pre-release --- .github/workflows/rspec.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index ad0d5c20b..2c9db01a0 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -1,3 +1,5 @@ +# https://github.com/ruby/rbs/pull/2833 + # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support From 3725fa92747b6a9d10169400c4475ffce816e353 Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Sat, 31 Jan 2026 11:55:40 -0500 Subject: [PATCH 08/10] Stop hard-coding bundler version --- .github/workflows/rspec.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 2c9db01a0..7e0b3e44f 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -1,5 +1,3 @@ -# https://github.com/ruby/rbs/pull/2833 - # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support @@ -72,10 +70,6 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - # see https://github.com/castwide/solargraph/actions/runs/19391419903/job/55485410493?pr=1119 - # - # match version in Gemfile.lock and use same version below - bundler: 2.5.23 bundler-cache: false - name: Set rbs version run: echo "gem 'rbs', '${{ matrix.rbs-version }}'" >> .Gemfile @@ -87,7 +81,7 @@ jobs: run: echo "gem 'tsort'" >> .Gemfile - name: Install gems run: | - bundle _2.5.23_ install + bundle install bundle update rbs # use latest available for this Ruby version - name: Update types run: bundle exec rbs collection update @@ -105,10 +99,6 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: '3.4' - # see https://github.com/castwide/solargraph/actions/runs/19391419903/job/55485410493?pr=1119 - # - # match version in Gemfile.lock and use same version below - bundler: 2.5.23 bundler-cache: false - name: Install gems run: bundle install From d68c9063ba72f2d7e8991c3c5a8d17d7dbc5698f Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Sat, 31 Jan 2026 12:15:58 -0500 Subject: [PATCH 09/10] Use bundler preferred by setup-ruby step --- .github/workflows/rspec.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 7e0b3e44f..174a1a6e3 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -70,7 +70,7 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: false + bundler-cache: true - name: Set rbs version run: echo "gem 'rbs', '${{ matrix.rbs-version }}'" >> .Gemfile # /home/runner/.rubies/ruby-head/lib/ruby/gems/3.5.0+2/gems/rbs-3.9.4/lib/rbs.rb:11: @@ -79,9 +79,8 @@ jobs: # starting from Ruby 3.6.0 - name: Work around legacy rbs deprecation on ruby > 3.4 run: echo "gem 'tsort'" >> .Gemfile - - name: Install gems + - name: Update gems run: | - bundle install bundle update rbs # use latest available for this Ruby version - name: Update types run: bundle exec rbs collection update @@ -99,9 +98,7 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: '3.4' - bundler-cache: false - - name: Install gems - run: bundle install + bundler-cache: true - name: Update types run: bundle exec rbs collection update - name: Run tests From 4512d019a543e9857df181ae12206f2cc7f96396 Mon Sep 17 00:00:00 2001 From: Vince Broz Date: Sat, 31 Jan 2026 12:36:00 -0500 Subject: [PATCH 10/10] Fix merge --- lib/solargraph/position.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/solargraph/position.rb b/lib/solargraph/position.rb index 368b7d812..332ffa527 100644 --- a/lib/solargraph/position.rb +++ b/lib/solargraph/position.rb @@ -62,15 +62,18 @@ def self.to_offset text, position line = -1 last_line_index = 0 + # @sg-ignore flow sensitive typing should be able to handle redefinition while (newline_index = text.index("\n", newline_index + 1)) && line <= position.line line += 1 break if line == position.line + # @sg-ignore oflow sensitive typing should be able to handle redefinition line_length = newline_index - last_line_index last_line_index = newline_index end last_line_index += 1 if position.line > 0 + # @sg-ignore flow sensitive typing should be able to handle redefinition last_line_index + position.character end @@ -100,8 +103,10 @@ def self.from_offset text, offset character = offset newline_index = -1 + # @sg-ignore flow sensitive typing should be able to handle redefinition while (newline_index = text.index("\n", newline_index + 1)) && newline_index < offset line += 1 + # @sg-ignore flow sensitive typing should be able to handle redefinition character = offset - newline_index - 1 end character = 0 if character.nil? and (cursor - offset).between?(0, 1)