Skip to content

Commit

Permalink
Move locate_first_within_range to RubyDocument
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Aug 13, 2024
1 parent ac928e0 commit 8dfcb85
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 35 deletions.
34 changes: 0 additions & 34 deletions lib/ruby_lsp/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,40 +213,6 @@ def locate(node, char_position, node_types: [])
NodeContext.new(closest, parent, nesting_nodes, call_node)
end

sig do
params(
range: T::Hash[Symbol, T.untyped],
node_types: T::Array[T.class_of(Prism::Node)],
).returns(T.nilable(Prism::Node))
end
def locate_first_within_range(range, node_types: [])
scanner = create_scanner
start_position = scanner.find_char_position(range[:start])
end_position = scanner.find_char_position(range[:end])
desired_range = (start_position...end_position)
queue = T.let(@parse_result.value.child_nodes.compact, T::Array[T.nilable(Prism::Node)])

until queue.empty?
candidate = queue.shift

# Skip nil child nodes
next if candidate.nil?

# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
# sibling
T.unsafe(queue).unshift(*candidate.child_nodes)

# Skip if the current node doesn't cover the desired position
loc = candidate.location

if desired_range.cover?(loc.start_offset...loc.end_offset) &&
(node_types.empty? || node_types.any? { |type| candidate.class == type })
return candidate
end
end
end

class Scanner
extend T::Sig

Expand Down
2 changes: 1 addition & 1 deletion lib/ruby_lsp/requests/code_action_resolve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Error < ::T::Enum
end
end

sig { params(document: Document, code_action: T::Hash[Symbol, T.untyped]).void }
sig { params(document: RubyDocument, code_action: T::Hash[Symbol, T.untyped]).void }
def initialize(document, code_action)
super()
@document = document
Expand Down
34 changes: 34 additions & 0 deletions lib/ruby_lsp/ruby_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,39 @@ def sorbet_level
SorbetLevel::None
end
end

sig do
params(
range: T::Hash[Symbol, T.untyped],
node_types: T::Array[T.class_of(Prism::Node)],
).returns(T.nilable(Prism::Node))
end
def locate_first_within_range(range, node_types: [])
scanner = create_scanner
start_position = scanner.find_char_position(range[:start])
end_position = scanner.find_char_position(range[:end])
desired_range = (start_position...end_position)
queue = T.let(@parse_result.value.child_nodes.compact, T::Array[T.nilable(Prism::Node)])

until queue.empty?
candidate = queue.shift

# Skip nil child nodes
next if candidate.nil?

# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
# sibling
T.unsafe(queue).unshift(*candidate.child_nodes)

# Skip if the current node doesn't cover the desired position
loc = candidate.location

if desired_range.cover?(loc.start_offset...loc.end_offset) &&
(node_types.empty? || node_types.any? { |type| candidate.class == type })
return candidate
end
end
end
end
end
6 changes: 6 additions & 0 deletions lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,12 @@ def code_action_resolve(message)
params = message[:params]
uri = URI(params.dig(:data, :uri))
document = @store.get(uri)

unless document.is_a?(RubyDocument)
send_message(Notification.window_show_error("Code actions are currently only available for Ruby documents"))
raise Requests::CodeActionResolve::CodeActionError
end

result = Requests::CodeActionResolve.new(document, params).perform

case result
Expand Down

0 comments on commit 8dfcb85

Please sign in to comment.