solargraph 0.29.5 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +1 -0
  3. data/lib/solargraph/api_map.rb +22 -13
  4. data/lib/solargraph/language_server/host.rb +121 -33
  5. data/lib/solargraph/language_server/host/cataloger.rb +5 -4
  6. data/lib/solargraph/language_server/message.rb +3 -0
  7. data/lib/solargraph/language_server/message/extended.rb +5 -4
  8. data/lib/solargraph/language_server/message/extended/document.rb +1 -1
  9. data/lib/solargraph/language_server/message/extended/environment.rb +20 -0
  10. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  11. data/lib/solargraph/language_server/message/initialize.rb +28 -4
  12. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  13. data/lib/solargraph/language_server/message/text_document.rb +1 -0
  14. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -0
  15. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  16. data/lib/solargraph/language_server/message/workspace.rb +4 -3
  17. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +1 -0
  18. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +3 -6
  19. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
  20. data/lib/solargraph/language_server/transport.rb +1 -2
  21. data/lib/solargraph/language_server/transport/{socket.rb → adapter.rb} +8 -10
  22. data/lib/solargraph/library.rb +29 -3
  23. data/lib/solargraph/logging.rb +25 -0
  24. data/lib/solargraph/page.rb +14 -4
  25. data/lib/solargraph/pin/documenting.rb +1 -1
  26. data/lib/solargraph/shell.rb +9 -10
  27. data/lib/solargraph/source.rb +59 -5
  28. data/lib/solargraph/source/encoding_fixes.rb +1 -1
  29. data/lib/solargraph/source_map/mapper.rb +14 -8
  30. data/lib/solargraph/version.rb +1 -1
  31. data/lib/solargraph/views/_method.erb +3 -0
  32. data/lib/solargraph/views/environment.erb +50 -0
  33. data/lib/solargraph/views/layout.erb +6 -0
  34. data/lib/solargraph/yard_map.rb +8 -8
  35. metadata +11 -13
  36. data/lib/solargraph/language_server/transport/stdio.rb +0 -63
@@ -12,8 +12,8 @@ module Solargraph
12
12
  # Notify the Cataloger that changes are pending.
13
13
  #
14
14
  # @return [void]
15
- def ping
16
- mutex.synchronize { pings.push nil }
15
+ def ping lib
16
+ mutex.synchronize { pings.push lib }
17
17
  end
18
18
 
19
19
  def synchronizing?
@@ -45,8 +45,9 @@ module Solargraph
45
45
  sleep 0.1
46
46
  next if pings.empty?
47
47
  mutex.synchronize do
48
- host.catalog
49
- pings.clear
48
+ lib = pings.shift
49
+ next if pings.include?(lib)
50
+ host.catalog lib
50
51
  end
51
52
  end
52
53
  end
@@ -70,8 +70,10 @@ module Solargraph
70
70
  register 'textDocument/documentSymbol', TextDocument::DocumentSymbol
71
71
  register 'textDocument/references', TextDocument::References
72
72
  register 'textDocument/rename', TextDocument::Rename
73
+ register 'textDocument/foldingRange', TextDocument::FoldingRange
73
74
  register 'workspace/didChangeWatchedFiles', Workspace::DidChangeWatchedFiles
74
75
  register 'workspace/didChangeConfiguration', Workspace::DidChangeConfiguration
76
+ register 'workspace/didChangeWorkspaceFolders', Workspace::DidChangeWorkspaceFolders
75
77
  register 'workspace/symbol', Workspace::WorkspaceSymbol
76
78
  register '$/cancelRequest', CancelRequest
77
79
  register '$/solargraph/document', Extended::Document
@@ -79,6 +81,7 @@ module Solargraph
79
81
  register '$/solargraph/checkGemVersion', Extended::CheckGemVersion
80
82
  register '$/solargraph/documentGems', Extended::DocumentGems
81
83
  register '$/solargraph/downloadCore', Extended::DownloadCore
84
+ register '$/solargraph/environment', Extended::Environment
82
85
  register 'shutdown', Shutdown
83
86
  register 'exit', ExitNotification
84
87
  end
@@ -7,11 +7,12 @@ module Solargraph
7
7
  # ignore them, as per the LSP specification.
8
8
  #
9
9
  module Extended
10
- autoload :Document, 'solargraph/language_server/message/extended/document'
11
- autoload :Search, 'solargraph/language_server/message/extended/search'
10
+ autoload :Document, 'solargraph/language_server/message/extended/document'
11
+ autoload :Search, 'solargraph/language_server/message/extended/search'
12
12
  autoload :CheckGemVersion, 'solargraph/language_server/message/extended/check_gem_version'
13
- autoload :DocumentGems, 'solargraph/language_server/message/extended/document_gems'
14
- autoload :DownloadCore, 'solargraph/language_server/message/extended/download_core'
13
+ autoload :DocumentGems, 'solargraph/language_server/message/extended/document_gems'
14
+ autoload :DownloadCore, 'solargraph/language_server/message/extended/download_core'
15
+ autoload :Environment, 'solargraph/language_server/message/extended/environment'
15
16
  end
16
17
  end
17
18
  end
@@ -6,7 +6,7 @@ module Solargraph
6
6
  def process
7
7
  objects = host.document(params['query'])
8
8
  page = Solargraph::Page.new(host.options['viewsPath'])
9
- content = page.render('document', locals: {objects: objects})
9
+ content = page.render('document', layout: true, locals: {objects: objects})
10
10
  set_result(
11
11
  content: content
12
12
  )
@@ -0,0 +1,20 @@
1
+ module Solargraph
2
+ module LanguageServer
3
+ module Message
4
+ module Extended
5
+ # Update YARD documentation for installed gems. If the `rebuild`
6
+ # parameter is true, rebuild existing yardocs.
7
+ #
8
+ class Environment < Base
9
+ def process
10
+ page = Solargraph::Page.new(host.options['viewsPath'])
11
+ content = page.render('environment', layout: true, locals: { config: host.options, folders: host.folders })
12
+ set_result(
13
+ content: content
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -6,7 +6,7 @@ module Solargraph
6
6
  def process
7
7
  results = host.search(params['query'])
8
8
  page = Solargraph::Page.new(host.options['viewsPath'])
9
- content = page.render('search', locals: {query: params['query'], results: results})
9
+ content = page.render('search', layout: true, locals: {query: params['query'], results: results})
10
10
  set_result(
11
11
  content: content
12
12
  )
@@ -4,7 +4,10 @@ module Solargraph
4
4
  class Initialize < Base
5
5
  def process
6
6
  host.configure params['initializationOptions']
7
- if params['rootUri']
7
+ if support_workspace_folders?
8
+ # @todo Prepare multiple folders
9
+ host.prepare_folders params['workspaceFolders']
10
+ elsif params['rootUri']
8
11
  host.prepare UriHelpers.uri_to_file(params['rootUri'])
9
12
  else
10
13
  host.prepare params['rootPath']
@@ -30,11 +33,18 @@ module Solargraph
30
33
  result[:capabilities].merge! static_rename unless dynamic_registration_for?('textDocument', 'rename')
31
34
  result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
32
35
  result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
36
+ result[:capabilities].merge! static_folding_range unless dynamic_registration_for?('textDocument', 'foldingRange')
33
37
  set_result result
34
38
  end
35
39
 
36
40
  private
37
41
 
42
+ def support_workspace_folders?
43
+ params['capabilities'] &&
44
+ params['capabilities']['workspace'] &&
45
+ params['capabilities']['workspace']['workspaceFolders']
46
+ end
47
+
38
48
  def static_completion
39
49
  {
40
50
  completionProvider: {
@@ -103,11 +113,25 @@ module Solargraph
103
113
  }
104
114
  end
105
115
 
116
+ def static_references
117
+ {
118
+ referencesProvider: true
119
+ }
120
+ end
121
+
122
+ def static_folding_range
123
+ {
124
+ foldingRangeProvider: true
125
+ }
126
+ end
127
+
128
+ # @param section [String]
129
+ # @param capability [String]
106
130
  # @return [Boolean]
107
131
  def dynamic_registration_for? section, capability
108
- result = (params['capabilities'] and
109
- params['capabilities'][section] and
110
- params['capabilities'][section][capability] and
132
+ result = (params['capabilities'] &&
133
+ params['capabilities'][section] &&
134
+ params['capabilities'][section][capability] &&
111
135
  params['capabilities'][section][capability]['dynamicRegistration'])
112
136
  host.allow_registration("#{section}/#{capability}") if result
113
137
  result
@@ -12,6 +12,7 @@ module Solargraph
12
12
  textDocument/definition
13
13
  textDocument/references
14
14
  textDocument/rename
15
+ textDocument/foldingRange
15
16
  workspace/symbol
16
17
  ]
17
18
  end
@@ -17,6 +17,7 @@ module Solargraph
17
17
  autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
18
18
  autoload :References, 'solargraph/language_server/message/text_document/references'
19
19
  autoload :Rename, 'solargraph/language_server/message/text_document/rename'
20
+ autoload :FoldingRange, 'solargraph/language_server/message/text_document/folding_range'
20
21
  end
21
22
  end
22
23
  end
@@ -0,0 +1,24 @@
1
+ require 'open3'
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ module Message
6
+ module TextDocument
7
+ class FoldingRange < Base
8
+ def process
9
+ result = host.folding_ranges(params['textDocument']['uri']).map do |range|
10
+ {
11
+ startLine: range.start.line,
12
+ startCharacter: 0,
13
+ endLine: range.ending.line - 1,
14
+ endCharacter: 0,
15
+ kind: 'region'
16
+ }
17
+ end
18
+ set_result result
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,4 +1,5 @@
1
1
  require 'open3'
2
+ require 'shellwords'
2
3
 
3
4
  module Solargraph
4
5
  module LanguageServer
@@ -2,9 +2,10 @@ module Solargraph
2
2
  module LanguageServer
3
3
  module Message
4
4
  module Workspace
5
- autoload :DidChangeWatchedFiles, 'solargraph/language_server/message/workspace/did_change_watched_files'
6
- autoload :WorkspaceSymbol, 'solargraph/language_server/message/workspace/workspace_symbol'
7
- autoload :DidChangeConfiguration, 'solargraph/language_server/message/workspace/did_change_configuration'
5
+ autoload :DidChangeWatchedFiles, 'solargraph/language_server/message/workspace/did_change_watched_files'
6
+ autoload :WorkspaceSymbol, 'solargraph/language_server/message/workspace/workspace_symbol'
7
+ autoload :DidChangeConfiguration, 'solargraph/language_server/message/workspace/did_change_configuration'
8
+ autoload :DidChangeWorkspaceFolders, 'solargraph/language_server/message/workspace/did_change_workspace_folders'
8
9
  end
9
10
  end
10
11
  end
@@ -20,6 +20,7 @@ module Solargraph::LanguageServer::Message::Workspace
20
20
  (host.options['symbols'] ? y : n).push('textDocument/documentSymbol', 'workspace/symbol')
21
21
  (host.options['definitions'] ? y : n).push('textDocument/definition')
22
22
  (host.options['references'] ? y : n).push('textDocument/references')
23
+ (host.options['folding'] ? y : n).push('textDocument/folding')
23
24
  host.register_capabilities y
24
25
  host.unregister_capabilities n
25
26
  end
@@ -11,14 +11,11 @@ module Solargraph::LanguageServer::Message::Workspace
11
11
  def process
12
12
  # @param change [Hash]
13
13
  params['changes'].each do |change|
14
+ # @todo Changes might need to be handled here even if the file is open
14
15
  if change['type'] == CREATED
15
- # It's only necessary to create the file from if the file isn't open
16
- # in the client
17
- host.create change['uri'] unless host.open?(change['uri'])
16
+ host.create change['uri'] #unless host.open?(change['uri'])
18
17
  elsif change['type'] == CHANGED
19
- # It's only necessary to update from here if the file isn't open in
20
- # the client
21
- host.create change['uri'] unless host.open?(change['uri'])
18
+ host.create change['uri'] #unless host.open?(change['uri'])
22
19
  elsif change['type'] == DELETED
23
20
  host.delete change['uri']
24
21
  else
@@ -0,0 +1,24 @@
1
+ require 'uri'
2
+
3
+ module Solargraph::LanguageServer::Message::Workspace
4
+ class DidChangeWorkspaceFolders < Solargraph::LanguageServer::Message::Base
5
+ def process
6
+ add_folders
7
+ remove_folders
8
+ end
9
+
10
+ private
11
+
12
+ def add_folders
13
+ return unless params['event'] && params['event']['added']
14
+ host.prepare_folders params['event']['added']
15
+ end
16
+
17
+ def remove_folders
18
+ return unless params['event'] && params['event']['removed']
19
+ params['event']['removed'].each do |folder|
20
+ host.remove_folders params['event']['removed']
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,9 +4,8 @@ module Solargraph
4
4
  # communication protocols for language servers.
5
5
  #
6
6
  module Transport
7
+ autoload :Adapter, 'solargraph/language_server/transport/adapter'
7
8
  autoload :DataReader, 'solargraph/language_server/transport/data_reader'
8
- autoload :Socket, 'solargraph/language_server/transport/socket'
9
- autoload :Stdio, 'solargraph/language_server/transport/stdio'
10
9
  end
11
10
  end
12
11
  end
@@ -1,12 +1,10 @@
1
- require 'thread'
2
-
3
1
  module Solargraph
4
2
  module LanguageServer
5
3
  module Transport
6
- # A module for running language servers in EventMachine.
4
+ # A common module for running language servers in Backport.
7
5
  #
8
- module Socket
9
- def post_init
6
+ module Adapter
7
+ def opening
10
8
  @host = Solargraph::LanguageServer::Host.new
11
9
  @data_reader = Solargraph::LanguageServer::Transport::DataReader.new
12
10
  @data_reader.set_message_handler do |message|
@@ -19,25 +17,25 @@ module Solargraph
19
17
  message = @host.start(request)
20
18
  message.send_response
21
19
  tmp = @host.flush
22
- send_data tmp unless tmp.empty?
20
+ write tmp unless tmp.empty?
23
21
  end
24
22
 
25
23
  # @param data [String]
26
- def receive_data data
24
+ def sending data
27
25
  @data_reader.receive data
28
26
  end
29
27
 
30
28
  private
31
29
 
32
30
  def start_timers
33
- EventMachine.add_periodic_timer 0.1 do
31
+ Backport.prepare_interval 0.1 do
34
32
  tmp = @host.flush
35
- send_data tmp unless tmp.empty?
33
+ write tmp unless tmp.empty?
36
34
  if @host.stopped?
37
35
  if @host.options['transport'] == 'external'
38
36
  @host = Solargraph::LanguageServer::Host.new
39
37
  else
40
- EventMachine.stop
38
+ Backport.stop
41
39
  end
42
40
  end
43
41
  end
@@ -2,12 +2,18 @@ module Solargraph
2
2
  # A Library handles coordination between a Workspace and an ApiMap.
3
3
  #
4
4
  class Library
5
+ include Logging
6
+
5
7
  # @return [Solargraph::Workspace]
6
8
  attr_reader :workspace
7
9
 
10
+ # @return [String, nil]
11
+ attr_reader :name
12
+
8
13
  # @param workspace [Solargraph::Workspace]
9
- def initialize workspace = Solargraph::Workspace.new
14
+ def initialize workspace = Solargraph::Workspace.new, name = nil
10
15
  @workspace = workspace
16
+ @name = name
11
17
  api_map.catalog bundle
12
18
  @synchronized = true
13
19
  end
@@ -37,6 +43,16 @@ module Solargraph
37
43
  end
38
44
  end
39
45
 
46
+ def open_from_disk filename
47
+ mutex.synchronize do
48
+ source = Solargraph::Source.load(filename)
49
+ workspace.merge source
50
+ open_file_hash[filename] = source
51
+ checkout filename
52
+ catalog
53
+ end
54
+ end
55
+
40
56
  # True if the specified file is currently open.
41
57
  #
42
58
  # @param filename [String]
@@ -318,16 +334,26 @@ module Solargraph
318
334
  #
319
335
  # @return [void]
320
336
  def catalog
337
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
321
338
  api_map.catalog bundle
322
339
  @synchronized = true
323
340
  end
324
341
 
342
+ def folding_ranges filename
343
+ read(filename).folding_ranges
344
+ end
345
+
346
+ # @return [Array<Source>]
347
+ def open_sources
348
+ open_file_hash.values
349
+ end
350
+
325
351
  # Create a library from a directory.
326
352
  #
327
353
  # @param directory [String] The path to be used for the workspace
328
354
  # @return [Solargraph::Library]
329
- def self.load directory = ''
330
- Solargraph::Library.new(Solargraph::Workspace.new(directory))
355
+ def self.load directory = '', name = nil
356
+ Solargraph::Library.new(Solargraph::Workspace.new(directory), name)
331
357
  end
332
358
 
333
359
  private
@@ -0,0 +1,25 @@
1
+ require 'logger'
2
+
3
+ module Solargraph
4
+ module Logging
5
+ DEFAULT_LOG_LEVEL = Logger::WARN
6
+
7
+ LOG_LEVELS = {
8
+ 'warn' => Logger::WARN,
9
+ 'info' => Logger::INFO,
10
+ 'debug' => Logger::DEBUG
11
+ }
12
+
13
+ @@logger = Logger.new(STDERR, level: DEFAULT_LOG_LEVEL)
14
+ @@logger.formatter = proc do |severity, datetime, progname, msg|
15
+ "[#{severity}] #{msg}\n"
16
+ end
17
+
18
+ module_function
19
+
20
+ # @return [Logger]
21
+ def logger
22
+ @@logger
23
+ end
24
+ end
25
+ end
@@ -2,7 +2,7 @@ require 'ostruct'
2
2
  require 'tilt'
3
3
  require 'kramdown'
4
4
  require 'htmlentities'
5
- require 'reverse_markdown'
5
+ require 'cgi'
6
6
 
7
7
  module Solargraph
8
8
  class Page
@@ -39,14 +39,16 @@ module Solargraph
39
39
 
40
40
  def initialize directory = VIEWS_PATH
41
41
  directory = VIEWS_PATH if directory.nil? or !File.directory?(directory)
42
+ directories = [directory]
43
+ directories.push VIEWS_PATH if directory != VIEWS_PATH
42
44
  @render_method = proc { |template, layout: false, locals: {}|
43
45
  binder = Binder.new(locals, @render_method)
44
46
  if layout
45
- Tilt::ERBTemplate.new(File.join(directory, 'layout.erb')).render(binder) do
46
- Tilt::ERBTemplate.new(File.join(directory, "#{template}.erb")).render(binder)
47
+ Tilt::ERBTemplate.new(Page.select_template(directories, 'layout')).render(binder) do
48
+ Tilt::ERBTemplate.new(Page.select_template(directories, template)).render(binder)
47
49
  end
48
50
  else
49
- Tilt::ERBTemplate.new(File.join(directory, "#{template}.erb")).render(binder)
51
+ Tilt::ERBTemplate.new(Page.select_template(directories, template)).render(binder)
50
52
  end
51
53
  }
52
54
  end
@@ -54,5 +56,13 @@ module Solargraph
54
56
  def render template, layout: true, locals: {}
55
57
  @render_method.call(template, layout: layout, locals: locals)
56
58
  end
59
+
60
+ def self.select_template directories, name
61
+ directories.each do |dir|
62
+ path = File.join(dir, "#{name}.erb")
63
+ return path if File.file?(path)
64
+ end
65
+ raise FileNotFoundError, "Template not found: #{name}"
66
+ end
57
67
  end
58
68
  end