Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Search implementations in files with implicit requires #78

Merged
merged 3 commits into from
Apr 9, 2018
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
3 changes: 2 additions & 1 deletion spec/scry/implementations_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module Scry
it "check implementation response type" do
params = TextDocumentPositionParams.from_json(TEXTDOCUMENT_POSITION_PARAM_EXAMPLE)
text_document = TextDocument.new(params, 0)
impl = Implementations.new(text_document)
workspace = Workspace.new("root_uri", 0, 10)
impl = Implementations.new(workspace, text_document)
impl.run.is_a?(ResponseMessage).should eq(true)
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/scry/response_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module Scry
io = IO::Memory.new
response = Response.new(results)
response.write(io)
io.to_s[0...19].should eq("Content-Length: 278")
io.to_s[0...19].should eq("Content-Length: 268")
end

it "responds with server capabilities" do
Expand Down
2 changes: 1 addition & 1 deletion src/scry/context.cr
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module Scry
case msg.method
when "textDocument/definition"
text_document = TextDocument.new(params, msg.id)
definitions = Implementations.new(text_document)
definitions = Implementations.new(@workspace, text_document)
response = definitions.run
Log.logger.debug(response)
response
Expand Down
62 changes: 47 additions & 15 deletions src/scry/implementations.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require "./protocol/location"
module Scry
# Using Crystal implementation to emulate GoTo Definition.
struct Implementations
def initialize(@text_document : TextDocument)
def initialize(@workspace : Workspace, @text_document : TextDocument)
end

def run
Expand All @@ -17,29 +17,61 @@ module Scry
end
end

def get_scope
root_uri = @workspace.root_uri
if Dir.exists?("#{root_uri}/src")
Dir.glob("#{root_uri}/src/*.cr")
else
Dir.glob("#{root_uri}/**/*.cr").reject(&.=~(/\/spec\/|\/lib\//))
end
end

# NOTE: compiler is a bit heavy in some projects.
def search(filename, source, position)
response = crystal_tool(filename, position)
scope = get_scope
result = analyze(filename, position, scope)
case result
when ResponseMessage
result
when JSON::Any
response_with(result)
end
end

private def crystal_tool(filename, position, scope)
location = "#{filename}:#{position.line + 1}:#{position.character + 1}"
String.build do |io|
args = ["tool", "implementations", "--no-color", "--error-trace", "-f", "json", "-c", "#{location}"] + scope
Process.run("crystal", args, output: io, error: io)
end
end

private def analyze(filename, position, scope)
response = crystal_tool(filename, position, scope)
Log.logger.debug("response: #{response}")
parsed_response = JSON.parse(response)
impls = parsed_response["implementations"]?
if impls
locations = impls.map do |impl|
pos = Position.new(impl["line"].as_i, impl["column"].as_i)
range = Range.new(pos, pos)
Location.new("file://" + impl["filename"].as_s, range)
end
ResponseMessage.new(@text_document.id, locations)
implementations = parsed_response["implementations"]?
if implementations
implementations
else
implementation_response
end
rescue ex
Log.logger.error("A error was found while searching definitions\n#{ex}")
nil
implementation_response
end

private def crystal_tool(filename, position)
location = "#{filename}:#{position.line + 1}:#{position.character + 1}"
String.build do |io|
Process.run("crystal", ["tool", "implementations", "--no-color", "--error-trace", "-f", "json", "-c", "#{location}", filename], output: io, error: io)
def implementation_response(locations = [] of Location)
ResponseMessage.new(@text_document.id, locations)
end

private def response_with(implementations)
locations = implementations.map do |item|
pos = Position.new(item["line"].as_i - 1, item["column"].as_i - 1)
range = Range.new(pos, pos)
Location.new("file://" + item["filename"].as_s, range)
end
implementation_response(locations)
end
end
end
2 changes: 1 addition & 1 deletion src/scry/protocol/diagnostic.cr
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module Scry
Position.new(line - 1, column + size - 1)
)
@severity = DiagnosticSeverity::Error.value
@source = "Scry [Crystal]"
@source = "Scry"
end
end
end