diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 4556215f1..3de7288eb 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -118,9 +118,12 @@ jobs: - name: clone https://github.com/lekemula/solargraph-rspec/ run: | cd .. - git clone https://github.com/lekemula/solargraph-rspec.git + # git clone https://github.com/lekemula/solargraph-rspec.git + # pending https://github.com/lekemula/solargraph-rspec/pull/31 + git clone https://github.com/apiology/solargraph-rspec.git cd solargraph-rspec + git checkout test_solargraph_prereleases - name: Set up Ruby uses: ruby/setup-ruby@v1 with: 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/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/position.rb b/lib/solargraph/position.rb index 53c7b61ba..332ffa527 100644 --- a/lib/solargraph/position.rb +++ b/lib/solargraph/position.rb @@ -57,7 +57,24 @@ def inspect # @return [Integer] def self.to_offset text, position return 0 if text.empty? - text.lines[0...position.line].sum(&:length) + position.character + + newline_index = -1 + 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 # Get a numeric offset for the specified text and a position identified @@ -73,23 +90,24 @@ 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 - # @type [Integer, nil] - 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 + + # @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) raise InvalidOffsetError if character.nil? diff --git a/lib/solargraph/version.rb b/lib/solargraph/version.rb index bfe833039..00cc77b02 100755 --- a/lib/solargraph/version.rb +++ b/lib/solargraph/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Solargraph - VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.0.dev.1') + VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.0.dev.2') end diff --git a/spec/position_spec.rb b/spec/position_spec.rb index fa30cf7d9..e8dab1960 100644 --- a/spec/position_spec.rb +++ b/spec/position_spec.rb @@ -12,9 +12,38 @@ 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) + expect(Solargraph::Position.to_offset(text, Solargraph::Position.new(3, 8))).to eq(58) + 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') }.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