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

LSP: Refactor definition to be similar to hover feature #595

Merged
merged 1 commit into from
May 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 34 additions & 75 deletions src/ls/definition.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,84 +15,26 @@ module Mint
stack =
server.nodes_at_cursor(params)

html_style(server, workspace, stack) ||
html_attribute(server, workspace, stack) ||
html_component(server, workspace, stack)
if node = stack[0]?
definition(node, server, workspace, stack)
end
end
end

def with_stack(stack : Array(Ast::Node), &)
yield StackReader.new(stack)
def definition(node : Ast::Node, server : Server, workspace : Workspace, stack : Array(Ast::Node))
nil
end

def selection(location : Ast::Node::Location) : LSP::Range
LSP::Range.new(
start: LSP::Position.new(
line: location.start[0] - 1,
character: location.start[1]
),
end: LSP::Position.new(
line: location.end[0] - 1,
character: location.end[1]
)
)
end

# Returns the range for the name part for a node
def selection(node : Ast::Node) : LSP::Range
selection(node.location)
end

def selection(node : Ast::Component) : LSP::Range
# Select only the name part of the component
# global component MintComponent {
# ^^^^^^^^^^^^^
selection(node.name)
end

def selection(node : Ast::HtmlAttribute) : LSP::Range
# Select only the name part of the attribute
# <Component attribute={value}>
# ^^^^^^^^^
selection(node.name)
end

def selection(node : Ast::HtmlComponent) : LSP::Range
# Select only the name part of the component
# <Component attribute={value}>
# ^^^^^^^^^
selection(node.component)
def cursor_intersects?(node : Ast::Node, position : LSP::Position) : Bool
node.location.contains?(position.line + 1, position.character)
gdotdesign marked this conversation as resolved.
Show resolved Hide resolved
end

def selection(node : Ast::HtmlStyle) : LSP::Range
# Select only the name part of the component
# <div::style>
# ^^^^^

start_line, start_column = node.location.start

# Skip the first two characters "::"
location = Ast::Node::Location.new(
filename: node.location.filename,
start: {start_line, start_column + 2},
end: node.location.end
)

selection(location)
def cursor_intersects?(node : Ast::Node, params : LSP::TextDocumentPositionParams) : Bool
cursor_intersects?(node, params.position)
end

def selection(node : Ast::Property) : LSP::Range
# Select only the name part of the property
# property size : String = "small"
# ^^^^
selection(node.name)
end

def selection(node : Ast::Style) : LSP::Range
# Select only the name part of the style
# style app {
# ^^^
selection(node.name)
def cursor_intersects?(node : Ast::Node) : Bool
cursor_intersects?(node, params)
end

def find_component(workspace : Workspace, name : String) : Ast::Component?
Expand All @@ -106,19 +48,36 @@ module Mint
!!(server.params.try &.capabilities.try &.text_document.try &.definition.try &.link_support)
end

def to_lsp_range(location : Ast::Node::Location) : LSP::Range
LSP::Range.new(
start: LSP::Position.new(
line: location.start[0] - 1,
character: location.start[1]
),
end: LSP::Position.new(
line: location.end[0] - 1,
character: location.end[1]
)
)
end

# Returns a `LSP::LocationLink` that links from *source* to the *target* node
# if the *server* has link support, otherwise it returns `LSP::Location`.
def location_link(server : Server, source : Ast::Node, target : Ast::Node) : LSP::LocationLink | LSP::Location
# if the language server client has link support, otherwise it returns `LSP::Location`.
#
# When returning a `LSP::LocationLink`, *parent* is used to provide the full range
# for the *target* node. For example, for a function, *target* would be the function name,
# and *parent* would be the whole node, including function body and any comments
def location_link(server : Server, source : Ast::Node, target : Ast::Node, parent : Ast::Node) : LSP::LocationLink | LSP::Location
if has_link_support?(server)
LSP::LocationLink.new(
origin_selection_range: selection(source),
origin_selection_range: to_lsp_range(source.location),
target_uri: "file://#{target.location.filename}",
target_range: selection(target.location),
target_selection_range: selection(target)
target_range: to_lsp_range(parent.location),
target_selection_range: to_lsp_range(target.location)
)
else
LSP::Location.new(
range: selection(target),
range: to_lsp_range(target.location),
uri: "file://#{target.location.filename}",
)
end
Expand Down
20 changes: 8 additions & 12 deletions src/ls/definition/html_attribute.cr
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
module Mint
module LS
class Definition < LSP::RequestMessage
def html_attribute(server : Server, workspace : Workspace, stack : Array(Ast::Node))
with_stack(stack) do |reader|
return unless variable = reader.find_next Ast::Variable
def definition(node : Ast::HtmlAttribute, server : Server, workspace : Workspace, stack : Array(Ast::Node))
return unless cursor_intersects?(node.name)

return unless reader.find_next Ast::HtmlAttribute
return unless html_component = stack.find(&.is_a?(Ast::HtmlComponent)).as?(Ast::HtmlComponent)

return unless html_component = reader.find_next Ast::HtmlComponent
return unless component =
find_component(workspace, html_component.component.value)

return unless component =
find_component(workspace, html_component.component.value)
return unless component_property =
component.properties.find(&.name.value.== node.name.value)

return unless component_property =
component.properties.find(&.name.value.== variable.value)

location_link server, variable, component_property
end
location_link server, node.name, component_property.name, component_property
end
end
end
Expand Down
14 changes: 5 additions & 9 deletions src/ls/definition/html_component.cr
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
module Mint
module LS
class Definition < LSP::RequestMessage
def html_component(server : Server, workspace : Workspace, stack : Array(Ast::Node))
with_stack(stack) do |reader|
return unless type_id = reader.find_next Ast::TypeId
def definition(node : Ast::HtmlComponent, server : Server, workspace : Workspace, stack : Array(Ast::Node))
return unless cursor_intersects?(node.component)

return unless html_component = reader.find_next Ast::HtmlComponent
return unless component =
find_component(workspace, node.component.value)

return unless component =
find_component(workspace, html_component.component.value)

location_link server, type_id, component
end
location_link server, node.component, component.name, component
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions src/ls/definition/html_element.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Mint
module LS
class Definition < LSP::RequestMessage
def definition(node : Ast::HtmlElement, server : Server, workspace : Workspace, stack : Array(Ast::Node))
node.styles.each do |style|
next unless cursor_intersects?(style)

return definition(style, server, workspace, stack)
end
end
end
end
end
16 changes: 6 additions & 10 deletions src/ls/definition/html_style.cr
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
module Mint
module LS
class Definition < LSP::RequestMessage
def html_style(server : Server, workspace : Workspace, stack : Array(Ast::Node))
with_stack(stack) do |reader|
return unless variable = reader.find_next Ast::Variable
def definition(node : Ast::HtmlStyle, server : Server, workspace : Workspace, stack : Array(Ast::Node))
return unless cursor_intersects?(node.name)

return unless reader.find_next Ast::HtmlStyle
return unless component = stack.find(&.is_a?(Ast::Component)).as?(Ast::Component)

return unless component = reader.find_anywhere Ast::Component
return unless component_style =
component.styles.find(&.name.value.== node.name.value)

return unless component_style =
component.styles.find(&.name.value.== variable.value)

location_link server, variable, component_style
end
location_link server, node.name, component_style.name, component_style
end
end
end
Expand Down
22 changes: 0 additions & 22 deletions src/ls/stack_reader.cr

This file was deleted.

2 changes: 1 addition & 1 deletion src/parsers/connect_variable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Mint

def connect_variable
start do |start_position|
value = variable || constant_variable
value = variable(track: false) || constant_variable

next unless value

Expand Down
2 changes: 1 addition & 1 deletion src/parsers/html_attribute.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Mint

def html_attribute(with_dashes : Bool = true, fixed_name : String? = nil) : Ast::HtmlAttribute?
start do |start_position|
name = with_dashes ? variable_attribute_name : variable
name = with_dashes ? variable_attribute_name : variable(track: false)

next unless name
next if fixed_name && name.value != fixed_name
Expand Down
1 change: 0 additions & 1 deletion src/parsers/html_component.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module Mint
end

next unless component
self << component

ref = start do
whitespace
Expand Down
4 changes: 2 additions & 2 deletions src/parsers/html_style.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Mint
start do |start_position|
name = start do
next unless keyword "::"
next unless value = variable_with_dashes track: true
next unless value = variable_with_dashes track: false
value
end

Expand All @@ -23,7 +23,7 @@ module Mint
char ')', HtmlStyleExpectedClosingParentheses
end

self << Ast::HtmlStyle.new(
Ast::HtmlStyle.new(
arguments: arguments,
from: start_position,
to: position,
Expand Down