From 25d171f2b31a30161462363836319776a123f34e Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 13:50:23 -0500 Subject: [PATCH 01/12] Add support for workspace symbols --- src/scry/context.cr | 12 ++++++++++ src/scry/protocol/server_capabilities.cr | 22 ++++++++----------- src/scry/protocol/workspace_symbol_params.cr | 9 ++++++++ src/scry/symbol.cr | 23 ++++++++++++++++++++ 4 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 src/scry/protocol/workspace_symbol_params.cr diff --git a/src/scry/context.cr b/src/scry/context.cr index c1039403e3e..bf09ff793a6 100644 --- a/src/scry/context.cr +++ b/src/scry/context.cr @@ -100,6 +100,18 @@ module Scry end end + private def dispatch_request(params : WorkspaceSymbolParams, msg) + case msg.method + when "workspace/symbol" + query = params.query + root_path = TextDocument.uri_to_filename(@workspace.root_uri) + workspace_symbol_processor = WorkspaceSymbolProcessor.new(msg.id, root_path, query) + response = workspace_symbol_processor.run + Log.logger.debug(response) + response + end + end + private def dispatch_request(params : CompletionItem, msg) case msg.method when "completionItem/resolve" diff --git a/src/scry/protocol/server_capabilities.cr b/src/scry/protocol/server_capabilities.cr index 7d86a7fe0fa..5c33c937903 100644 --- a/src/scry/protocol/server_capabilities.cr +++ b/src/scry/protocol/server_capabilities.cr @@ -19,32 +19,27 @@ module Scry end end - # Specify Sever capabilities supported, - # Currently Crystal supports: + # Specify supported sever capabilities: # - # - Go to definition or Implementation (WIP) + # - Go to Implementation (WIP) # - Diagnostics (WIP) # - Formatting (WIP) - # - Symbols https://github.com/crystal-lang/crystal/blob/1f3e8b0e742b55c1feb5584dc932e87034365f48/samples/compiler/visitor_example.cr - # - Rename https://github.com/crystal-lang/crystal/blob/1f3e8b0e742b55c1feb5584dc932e87034365f48/samples/compiler/transformer_example.cr - # - Completion https://github.com/TechMagister/cracker - # - Hover - # - Code Actions - # - Signature Help - # - Range Formatting + # - Symbols (WIP) + # - Completion (WIP) + # - Hover (WIP) + # - Code Actions (WIP) # # Features not supported by Crystal yet: # - # - CodeLens + # - Rename # - Find References - # - # To enable more capabilities, See: https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md struct ServerCapabilities JSON.mapping( textDocumentSync: TextDocumentSyncKind, documentFormattingProvider: Bool, definitionProvider: Bool, documentSymbolProvider: Bool, + workspaceSymbolProvider: Bool, completionProvider: CompletionOptions ) @@ -53,6 +48,7 @@ module Scry @documentFormattingProvider = true @definitionProvider = true @documentSymbolProvider = true + @workspaceSymbolProvider = true @completionProvider = CompletionOptions.new end end diff --git a/src/scry/protocol/workspace_symbol_params.cr b/src/scry/protocol/workspace_symbol_params.cr new file mode 100644 index 00000000000..bee7e4877d1 --- /dev/null +++ b/src/scry/protocol/workspace_symbol_params.cr @@ -0,0 +1,9 @@ +require "json" + +module Scry + struct WorkspaceSymbolParams + JSON.mapping({ + query: String, + }, true) + end +end diff --git a/src/scry/symbol.cr b/src/scry/symbol.cr index f119032fcee..716adc138d0 100644 --- a/src/scry/symbol.cr +++ b/src/scry/symbol.cr @@ -1,4 +1,5 @@ require "compiler/crystal/syntax" +require "./protocol/workspace_symbol_params" module Scry class SymbolVisitor < Crystal::Visitor @@ -115,4 +116,26 @@ module Scry ResponseMessage.new(@text_document.id, visitor.symbols) end end + + class WorkspaceSymbolProcessor + def initialize(@msg_id : Int32 | String, @root_path : String, @query : String) + @all_files = Dir.glob("#{root_path}/**/*.cr") + end + + def run + symbols = [] of SymbolInformation + unless @query.empty? + @all_files.each do |file| + visitor = SymbolVisitor.new("file://#{file}") + parser = Crystal::Parser.new(File.read(file)) + parser.filename = file + node = parser.parse + node.accept(visitor) + symbols.concat visitor.symbols.select(&.name.match(Regex.new(@query))) + end + end + + ResponseMessage.new(@msg_id, symbols) + end + end end From 3c6f673a807a64b7c0c64bd1d2173641d85628ba Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 13:50:37 -0500 Subject: [PATCH 02/12] Add spec for workspace symbols --- spec/scry/symbol_spec.cr | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/scry/symbol_spec.cr b/spec/scry/symbol_spec.cr index 7636c0f2ac3..99503b1fe57 100644 --- a/spec/scry/symbol_spec.cr +++ b/spec/scry/symbol_spec.cr @@ -98,5 +98,21 @@ module Scry result.kind.is_a?(SymbolKind::Constant).should be_true end end + + describe "WorkspaceSymbols" do + it "return empty Symbols list if no query" do + processor = WorkspaceSymbolProcessor.new(0, ROOT_PATH, "") + response = processor.run + result = response.result.as(Array(SymbolInformation)) + result.empty?.should be_true + end + + it "return Symbols list with query match" do + processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "salut") + response = processor.run + result = response.result.as(Array(SymbolInformation)).try(&.first) + result.kind.is_a?(SymbolKind::Method).should be_true + end + end end end From d46052bdb6a078b93da5bb7c21d07fc00b6de74f Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 15:59:02 -0500 Subject: [PATCH 03/12] Remove try and add regex query spec for workspace symbols --- spec/scry/symbol_spec.cr | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/spec/scry/symbol_spec.cr b/spec/scry/symbol_spec.cr index 99503b1fe57..e16278031a5 100644 --- a/spec/scry/symbol_spec.cr +++ b/spec/scry/symbol_spec.cr @@ -19,7 +19,7 @@ module Scry text_document = TextDocument.new("uri", ["class Test; end"]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Class).should be_true end @@ -27,7 +27,7 @@ module Scry text_document = TextDocument.new("uri", ["struct Test; end"]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Class).should be_true end @@ -35,7 +35,7 @@ module Scry text_document = TextDocument.new("uri", ["module Test; end"]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Module).should be_true end @@ -43,7 +43,7 @@ module Scry text_document = TextDocument.new("uri", ["def test; end"]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true end @@ -51,7 +51,7 @@ module Scry text_document = TextDocument.new("uri", ["@bar = nil"]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.as(SymbolInformation).kind.is_a?(SymbolKind::Variable).should be_true end @@ -86,7 +86,7 @@ module Scry text_document = TextDocument.new("uri", [%(HELLO = "world")]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Constant).should be_true end @@ -94,7 +94,7 @@ module Scry text_document = TextDocument.new("uri", [%(alias Hello = World)]) processor = SymbolProcessor.new(text_document) response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Constant).should be_true end end @@ -110,7 +110,14 @@ module Scry it "return Symbols list with query match" do processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "salut") response = processor.run - result = response.result.as(Array(SymbolInformation)).try(&.first) + result = response.result.as(Array(SymbolInformation)).first + result.kind.is_a?(SymbolKind::Method).should be_true + end + + it "return Symbols list with regex query match" do + processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "sal*") + response = processor.run + result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true end end From 10830b1612e1b3d91d3928e21f2f7a3427f3c554 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 16:05:58 -0500 Subject: [PATCH 04/12] Fix spec --- spec/scry/response_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/scry/response_spec.cr b/spec/scry/response_spec.cr index 361e610c92b..5e608579af8 100644 --- a/spec/scry/response_spec.cr +++ b/spec/scry/response_spec.cr @@ -38,7 +38,7 @@ module Scry io = IO::Memory.new response = Response.new(results) response.write(io) - io.to_s.should eq(%(Content-Length: 245\r\n\r\n{"jsonrpc":"2.0","id":32,"result":{"capabilities":{"textDocumentSync":1,"documentFormattingProvider":true,"definitionProvider":true,"documentSymbolProvider":true,"completionProvider":{"resolveProvider":true,"triggerCharacters":[".","\\\"","/"]}}}})) + io.to_s.should eq(%(Content-Length: 276\r\n\r\n{"jsonrpc":"2.0","id":32,"result":{"capabilities":{"textDocumentSync":1,"documentFormattingProvider":true,"definitionProvider":true,"documentSymbolProvider":true,"workspaceSymbolProvider":true,"completionProvider":{"resolveProvider":true,"triggerCharacters":[".","\\\"","/"]}}}})) end end end From c3ba087bca4baf5aa34fcd7a70b70cf27771369a Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 18:11:57 -0500 Subject: [PATCH 05/12] Add missing RequestType --- src/scry/protocol/request_message.cr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scry/protocol/request_message.cr b/src/scry/protocol/request_message.cr index 1d3bc0cb946..cd35e1a9f9a 100644 --- a/src/scry/protocol/request_message.cr +++ b/src/scry/protocol/request_message.cr @@ -1,5 +1,6 @@ require "./initialize_params" require "./text_document_position_params" +require "./workspace_symbol_params" module Scry struct RequestMessage @@ -7,6 +8,7 @@ module Scry InitializeParams | DocumentFormattingParams | TextDocumentParams | + WorkspaceSymbolParams | CompletionItem)? JSON.mapping({ From 93704f56df91b826d54f4c6ff76132f41063b812 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 18:13:11 -0500 Subject: [PATCH 06/12] Add stdlib (momoized) to workspace symbols --- src/scry/symbol.cr | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/scry/symbol.cr b/src/scry/symbol.cr index 716adc138d0..c1ab55f277c 100644 --- a/src/scry/symbol.cr +++ b/src/scry/symbol.cr @@ -114,28 +114,44 @@ module Scry node.accept(visitor) ResponseMessage.new(@text_document.id, visitor.symbols) + rescue + ResponseMessage.new(@text_document.id, [] of SymbolInformation) end end class WorkspaceSymbolProcessor + @@crystal_path_files = [] of SymbolInformation + def initialize(@msg_id : Int32 | String, @root_path : String, @query : String) - @all_files = Dir.glob("#{root_path}/**/*.cr") + @workspace_files = Dir.glob(File.join(root_path, "**", "*.cr")) + if @@crystal_path_files.empty? + # Memoize crystal stdlib + @@crystal_path_files = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), ".*") + end end def run symbols = [] of SymbolInformation unless @query.empty? - @all_files.each do |file| - visitor = SymbolVisitor.new("file://#{file}") - parser = Crystal::Parser.new(File.read(file)) - parser.filename = file - node = parser.parse - node.accept(visitor) - symbols.concat visitor.symbols.select(&.name.match(Regex.new(@query))) - end + symbols.concat search_symbols(@workspace_files, @query) + symbols.concat @@crystal_path_files.select(&.name.match(Regex.new(@query))) end - ResponseMessage.new(@msg_id, symbols) end + + def search_symbols(files, query) + symbols = [] of SymbolInformation + files.each do |file| + visitor = SymbolVisitor.new("file://#{file}") + parser = Crystal::Parser.new(File.read(file)) + parser.filename = file + node = parser.parse + node.accept(visitor) + symbols.concat visitor.symbols.select(&.name.match(Regex.new(query))) + rescue + next + end + symbols + end end end From 0675f496643c35d2a4c7a7dd78b9e1e77e13c2bb Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 18:13:39 -0500 Subject: [PATCH 07/12] Add specs for stdlib symbols --- spec/scry/symbol_spec.cr | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/scry/symbol_spec.cr b/spec/scry/symbol_spec.cr index e16278031a5..34feabe5d77 100644 --- a/spec/scry/symbol_spec.cr +++ b/spec/scry/symbol_spec.cr @@ -120,6 +120,20 @@ module Scry result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true end + + it "return stdlib Symbol with regex query match for File" do + processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "Fil*") + response = processor.run + result = response.result.as(Array(SymbolInformation)).first + result.kind.is_a?(SymbolKind::Class).should be_true + end + + it "return stdlib symbol with regex query match for puts" do + processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "put*") + response = processor.run + result = response.result.as(Array(SymbolInformation)).first + result.kind.is_a?(SymbolKind::Function).should be_true + end end end end From 81ccecf7b9e2b89fd579820457f1b0454111cd70 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 18:40:26 -0500 Subject: [PATCH 08/12] Fix specs --- spec/scry/symbol_spec.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/scry/symbol_spec.cr b/spec/scry/symbol_spec.cr index 34feabe5d77..483f577dc7e 100644 --- a/spec/scry/symbol_spec.cr +++ b/spec/scry/symbol_spec.cr @@ -128,11 +128,11 @@ module Scry result.kind.is_a?(SymbolKind::Class).should be_true end - it "return stdlib symbol with regex query match for puts" do - processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "put*") + it "return stdlib symbol with regex query match for initialize" do + processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "initializ*") response = processor.run result = response.result.as(Array(SymbolInformation)).first - result.kind.is_a?(SymbolKind::Function).should be_true + result.kind.is_a?(SymbolKind::Method).should be_true end end end From df9bc43ab0ba84b45a2df0600bc563d7b216bd46 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 19:06:43 -0500 Subject: [PATCH 09/12] Rename crystal_path_files to crystal_path_symbols --- src/scry/symbol.cr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scry/symbol.cr b/src/scry/symbol.cr index c1ab55f277c..16933644536 100644 --- a/src/scry/symbol.cr +++ b/src/scry/symbol.cr @@ -120,13 +120,13 @@ module Scry end class WorkspaceSymbolProcessor - @@crystal_path_files = [] of SymbolInformation + @@crystal_path_symbols = [] of SymbolInformation def initialize(@msg_id : Int32 | String, @root_path : String, @query : String) @workspace_files = Dir.glob(File.join(root_path, "**", "*.cr")) - if @@crystal_path_files.empty? + if @@crystal_path_symbols.empty? # Memoize crystal stdlib - @@crystal_path_files = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), ".*") + @@crystal_path_symbols = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), ".*") end end @@ -134,7 +134,7 @@ module Scry symbols = [] of SymbolInformation unless @query.empty? symbols.concat search_symbols(@workspace_files, @query) - symbols.concat @@crystal_path_files.select(&.name.match(Regex.new(@query))) + symbols.concat @@crystal_path_symbols.select(&.name.match(Regex.new(@query))) end ResponseMessage.new(@msg_id, symbols) end From a0db775f97071e4aecd76c2eb061c52fe0056dd2 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 19:13:11 -0500 Subject: [PATCH 10/12] Store query regex on initializer --- src/scry/symbol.cr | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/scry/symbol.cr b/src/scry/symbol.cr index 16933644536..f0c189eb31d 100644 --- a/src/scry/symbol.cr +++ b/src/scry/symbol.cr @@ -121,25 +121,27 @@ module Scry class WorkspaceSymbolProcessor @@crystal_path_symbols = [] of SymbolInformation + @query_regex : Regex def initialize(@msg_id : Int32 | String, @root_path : String, @query : String) @workspace_files = Dir.glob(File.join(root_path, "**", "*.cr")) if @@crystal_path_symbols.empty? # Memoize crystal stdlib - @@crystal_path_symbols = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), ".*") + @@crystal_path_symbols = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), Regex.new(".*")) end + @query_regex = Regex.new(@query) end def run symbols = [] of SymbolInformation unless @query.empty? - symbols.concat search_symbols(@workspace_files, @query) - symbols.concat @@crystal_path_symbols.select(&.name.match(Regex.new(@query))) + symbols.concat search_symbols(@workspace_files, @query_regex) + symbols.concat @@crystal_path_symbols.select(&.name.match(@query_regex)) end ResponseMessage.new(@msg_id, symbols) end - def search_symbols(files, query) + def search_symbols(files, query_regex) symbols = [] of SymbolInformation files.each do |file| visitor = SymbolVisitor.new("file://#{file}") @@ -147,7 +149,7 @@ module Scry parser.filename = file node = parser.parse node.accept(visitor) - symbols.concat visitor.symbols.select(&.name.match(Regex.new(query))) + symbols.concat visitor.symbols.select(&.name.match(query_regex)) rescue next end From 719c354f5896767407e6e28ee41488ea99f9be63 Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sat, 5 May 2018 23:51:44 -0500 Subject: [PATCH 11/12] Use class variables and class methods --- src/scry/symbol.cr | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/scry/symbol.cr b/src/scry/symbol.cr index f0c189eb31d..26d714d40f6 100644 --- a/src/scry/symbol.cr +++ b/src/scry/symbol.cr @@ -120,28 +120,31 @@ module Scry end class WorkspaceSymbolProcessor - @@crystal_path_symbols = [] of SymbolInformation + @@crystal_path_symbols : Array(SymbolInformation)? @query_regex : Regex def initialize(@msg_id : Int32 | String, @root_path : String, @query : String) @workspace_files = Dir.glob(File.join(root_path, "**", "*.cr")) - if @@crystal_path_symbols.empty? - # Memoize crystal stdlib - @@crystal_path_symbols = search_symbols(Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")), Regex.new(".*")) - end @query_regex = Regex.new(@query) end def run symbols = [] of SymbolInformation unless @query.empty? - symbols.concat search_symbols(@workspace_files, @query_regex) - symbols.concat @@crystal_path_symbols.select(&.name.match(@query_regex)) + symbols.concat self.class.search_symbols(@workspace_files, @query_regex) + symbols.concat self.class.crystal_path_symbols.select(&.name.match(@query_regex)) end ResponseMessage.new(@msg_id, symbols) end - def search_symbols(files, query_regex) + def self.crystal_path_symbols + @@crystal_path_symbols ||= begin + crystal_path_files = Dir.glob(File.join(Scry.default_crystal_path, "**", "*.cr")) + search_symbols(crystal_path_files, Regex.new(".*")) + end + end + + def self.search_symbols(files, query_regex) symbols = [] of SymbolInformation files.each do |file| visitor = SymbolVisitor.new("file://#{file}") From c2543fd3c6ce1eb0ccef5f88b9c6c9add78b1aba Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Sun, 6 May 2018 02:02:22 -0500 Subject: [PATCH 12/12] Use full ROOT_PATH on spec to rest invalid files --- spec/scry/symbol_spec.cr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/scry/symbol_spec.cr b/spec/scry/symbol_spec.cr index 483f577dc7e..9fc54924eb8 100644 --- a/spec/scry/symbol_spec.cr +++ b/spec/scry/symbol_spec.cr @@ -108,28 +108,28 @@ module Scry end it "return Symbols list with query match" do - processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "salut") + processor = WorkspaceSymbolProcessor.new(0, ROOT_PATH, "salut") response = processor.run result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true end it "return Symbols list with regex query match" do - processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "sal*") + processor = WorkspaceSymbolProcessor.new(0, ROOT_PATH, "sal*") response = processor.run result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true end it "return stdlib Symbol with regex query match for File" do - processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "Fil*") + processor = WorkspaceSymbolProcessor.new(0, ROOT_PATH, "Fil*") response = processor.run result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Class).should be_true end it "return stdlib symbol with regex query match for initialize" do - processor = WorkspaceSymbolProcessor.new(0, "#{ROOT_PATH}/src", "initializ*") + processor = WorkspaceSymbolProcessor.new(0, ROOT_PATH, "initializ*") response = processor.run result = response.result.as(Array(SymbolInformation)).first result.kind.is_a?(SymbolKind::Method).should be_true