diff --git a/spec/scry/implementations_spec.cr b/spec/scry/implementations_spec.cr index cd56e83aa41..191d527134d 100644 --- a/spec/scry/implementations_spec.cr +++ b/spec/scry/implementations_spec.cr @@ -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 diff --git a/spec/scry/response_spec.cr b/spec/scry/response_spec.cr index 6a762f58898..361e610c92b 100644 --- a/spec/scry/response_spec.cr +++ b/spec/scry/response_spec.cr @@ -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 diff --git a/src/scry/context.cr b/src/scry/context.cr index 82ed6448719..e9aaa473b83 100644 --- a/src/scry/context.cr +++ b/src/scry/context.cr @@ -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 diff --git a/src/scry/implementations.cr b/src/scry/implementations.cr index de141eea7a4..62dc34e56bb 100644 --- a/src/scry/implementations.cr +++ b/src/scry/implementations.cr @@ -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 @@ -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 diff --git a/src/scry/protocol/diagnostic.cr b/src/scry/protocol/diagnostic.cr index c0d928d4c70..cebc7dade7b 100644 --- a/src/scry/protocol/diagnostic.cr +++ b/src/scry/protocol/diagnostic.cr @@ -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