Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store the parsed tree to avoid unnecessary re-parsing #13

Merged
merged 2 commits into from Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 4 additions & 5 deletions lib/ruby/lsp/requests/folding_ranges.rb
Expand Up @@ -4,13 +4,12 @@ module Ruby
module Lsp
module Requests
class FoldingRanges
def self.run(source)
new(source).run
def self.run(item)
new(item).run
end

def initialize(source)
@parser = SyntaxTree.new(source)
@queue = [@parser.parse]
def initialize(item)
@queue = [item.tree]
@ranges = []
end

Expand Down
24 changes: 22 additions & 2 deletions lib/ruby/lsp/store.rb
Expand Up @@ -11,11 +11,17 @@ def initialize
end

def [](uri)
@state[uri] || File.binread(CGI.unescape(URI.parse(uri).path))
item = @state[uri]
return item unless item.nil?

self[uri] = File.binread(CGI.unescape(URI.parse(uri).path))
@state[uri]
end

def []=(uri, content)
@state[uri] = content
@state[uri] = Item.new(content)
rescue SyntaxTree::ParseError
# Do not update the store if there are syntax errors
end

def clear
Expand All @@ -25,6 +31,20 @@ def clear
def delete(uri)
@state.delete(uri)
end

class Item
vinistock marked this conversation as resolved.
Show resolved Hide resolved
attr_reader :tree, :parser, :source

def initialize(source)
@source = source
@parser = SyntaxTree.new(source)
@tree = @parser.parse
end

def ==(other)
@source == other.source
end
end
end
end
end
3 changes: 2 additions & 1 deletion test/requests/folding_ranges_test.rb
Expand Up @@ -16,7 +16,8 @@ def foo
private

def assert_ranges(source, expected_ranges)
actual = Ruby::Lsp::Requests::FoldingRanges.run(source)
item = Ruby::Lsp::Store::Item.new(source)
actual = Ruby::Lsp::Requests::FoldingRanges.run(item)
assert_equal(expected_ranges, JSON.parse(actual.to_json, symbolize_names: true))
end
end
20 changes: 14 additions & 6 deletions test/store_test.rb
Expand Up @@ -5,35 +5,43 @@
class StoreTest < Minitest::Test
def test_hash_accessors
store = Ruby::Lsp::Store.new
store["/foo/bar.rb"] = "foo"
store["/foo/bar.rb"] = "def foo; end"

assert_equal("foo", store["/foo/bar.rb"])
assert_equal(Ruby::Lsp::Store::Item.new("def foo; end"), store["/foo/bar.rb"])
end

def test_reads_from_file_if_missing_in_store
store = Ruby::Lsp::Store.new

file = Tempfile.new("foo.rb")
file.write("some great code")
file.write("def great_code; end")
file.rewind

assert_equal("some great code", store[file.path])
assert_equal(Ruby::Lsp::Store::Item.new("def great_code; end"), store[file.path])
ensure
file.close
file.unlink
end

def test_store_ignores_syntax_errors
store = Ruby::Lsp::Store.new
store["/foo/bar.rb"] = "def foo; end"
store["/foo/bar.rb"] = "def bar; end; end"

assert_equal(Ruby::Lsp::Store::Item.new("def foo; end"), store["/foo/bar.rb"])
end

def test_clear
store = Ruby::Lsp::Store.new
store["/foo/bar.rb"] = "foo"
store["/foo/bar.rb"] = "def foo; end"
store.clear

assert_empty(store.instance_variable_get(:@state))
end

def test_delete
store = Ruby::Lsp::Store.new
store["/foo/bar.rb"] = "foo"
store["/foo/bar.rb"] = "def foo; end"
store.delete("/foo/bar.rb")

assert_empty(store.instance_variable_get(:@state))
Expand Down