ruby-lsp-ree 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1d126a7d0c8462f33b63113cf86ae134f8cb029da147273bdb2f8cb76cb448e
4
- data.tar.gz: dbb25c53fc012b487a3ed9555ad470c10445603e808aa3f44442070b4fc57851
3
+ metadata.gz: 3814d8a258c4c291c8c2a858e5bf23094086e25162435b956bae4401bd456109
4
+ data.tar.gz: a8ae59abe162776aba2356dc2a3c9b607703ac9d5012fac2c843ab84c7e12e96
5
5
  SHA512:
6
- metadata.gz: 50d85fbda0c61e33709823c7e8b5f263d94eba2d6822b1e84f011ad0b058adf6d5766a5fe27b6613c537b2e36f878a8ef50ddf7fad7dd41cfd954011fe90c156
7
- data.tar.gz: 66c76a82263258d76fcc7cc604e6aa499deb209ae80c6ae8a5bad1dd486f7ee70c9e0af896277c0cc01631ad99c91f5b5b827e18337b0d95e4d18622d1c2c389
6
+ metadata.gz: 4ab9db29ce9ed0fc7ee54721826ee1933308511c3f07ddce31c53504dde5d422a131dcb6421bb428c9694ddbbc6cdab83b5f96315d9195e97e2bac11a5bad2e2
7
+ data.tar.gz: f6dcffe5363c8acb0481b9c8adbd1d6a5b6322833dc0fe1d8001188d7daf796aa68008ae648d3b99a4ad7f9f9e281b0fbdab4efec80a88b362cd18865dbd829c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [0.1.6] - 2025-03-04
2
+
3
+ - file rename triggers class name change
4
+ - add documentation string to hover
5
+ - add hover on link section beans
6
+
7
+ ## [0.1.5] - 2025-02-28
8
+
9
+ - improved hover format
10
+ - basic support for ree templates
11
+
1
12
  ## [0.1.4] - 2025-02-25
2
13
 
3
14
  - autocompletion in spec files
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp-ree (0.1.4)
4
+ ruby-lsp-ree (0.1.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -5,6 +5,8 @@ require_relative "listeners/hover_listener"
5
5
  require_relative "ree_indexing_enhancement"
6
6
  require_relative "utils/ree_lsp_utils"
7
7
  require_relative "ree_formatter"
8
+ require_relative "ree_template_applicator"
9
+ require_relative "ree_rename_handler"
8
10
  require_relative "parsing/parsed_document_builder"
9
11
 
10
12
  module RubyLsp
@@ -13,8 +15,10 @@ module RubyLsp
13
15
  def activate(global_state, message_queue)
14
16
  @global_state = global_state
15
17
  @message_queue = message_queue
18
+ @template_applicator = RubyLsp::Ree::ReeTemplateApplicator.new
16
19
 
17
20
  global_state.register_formatter("ree_formatter", RubyLsp::Ree::ReeFormatter.new)
21
+ register_additional_file_watchers(global_state, message_queue)
18
22
  end
19
23
 
20
24
  def deactivate
@@ -38,6 +42,46 @@ module RubyLsp
38
42
  index = @global_state.index
39
43
  RubyLsp::Ree::HoverListener.new(response_builder, node_context, index, dispatcher)
40
44
  end
45
+
46
+ def register_additional_file_watchers(global_state, message_queue)
47
+ # Clients are not required to implement this capability
48
+ return unless global_state.supports_watching_files
49
+
50
+ message_queue << Request.new(
51
+ id: "ruby-lsp-ree-file-create-watcher",
52
+ method: "client/registerCapability",
53
+ params: Interface::RegistrationParams.new(
54
+ registrations: [
55
+ Interface::Registration.new(
56
+ id: "workspace/didCreateWatchedFilesRee",
57
+ method: "workspace/didChangeWatchedFiles",
58
+ register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
59
+ watchers: [
60
+ Interface::FileSystemWatcher.new(
61
+ glob_pattern: "**/*.rb",
62
+ kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE,
63
+ ),
64
+ ],
65
+ ),
66
+ ),
67
+ ],
68
+ ),
69
+ )
70
+ end
71
+
72
+ def workspace_did_change_watched_files(changes)
73
+ if changes.size == 1 && changes[0][:type] == Constant::FileChangeType::CREATED
74
+ $stderr.puts("file created #{changes[0][:uri]}")
75
+
76
+ return unless @template_applicator.template_dir_exists?
77
+
78
+ @template_applicator.apply(changes[0])
79
+ elsif changes.size == 2 && changes.any?{ _1[:type] == Constant::FileChangeType::CREATED } && changes.any?{ _1[:type] == Constant::FileChangeType::DELETED }
80
+ $stderr.puts("file renamed #{changes[0][:uri]} #{changes[1][:uri]}")
81
+
82
+ RubyLsp::Ree::ReeRenameHandler.call(changes)
83
+ end
84
+ end
41
85
  end
42
86
  end
43
87
  end
@@ -110,7 +110,7 @@ module RubyLsp
110
110
  def get_enum_values_completion_items(enum_obj, location)
111
111
  enum_node = RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(enum_obj.uri, :enum)
112
112
 
113
- class_name = enum_node.get_class_name
113
+ class_name = enum_node.full_class_name
114
114
 
115
115
  label_details = Interface::CompletionItemLabelDetails.new(
116
116
  description: "from: #{class_name}",
@@ -20,19 +20,36 @@ module RubyLsp
20
20
 
21
21
  return [] unless ree_object
22
22
 
23
- documentation = <<~DOC
24
- Ree object, type: :#{@finder.object_type(ree_object)}
23
+ documentation = get_object_documentation(ree_object)
25
24
 
26
- usage: #{node.name.to_s}#{get_detail_string(ree_object)}
27
-
28
- package: #{package_name_from_uri(ree_object.uri)}
25
+ [documentation]
26
+ end
29
27
 
30
- file: #{path_from_package_folder(ree_object.uri)}
31
- DOC
28
+ def get_linked_object_hover_items(node)
29
+ parent_node = @node_context.parent
30
+ return [] unless parent_node.name == :link
31
+
32
+ ree_object = @finder.find_object(node.unescaped)
33
+
34
+ return [] unless ree_object
35
+
36
+ documentation = get_object_documentation(ree_object)
32
37
 
33
38
  [documentation]
34
39
  end
35
40
 
41
+ def get_object_documentation(ree_object)
42
+ <<~DOC
43
+ \`\`\`ruby
44
+ #{ree_object.name}#{get_detail_string(ree_object)}
45
+ \`\`\`
46
+ ---
47
+ #{@finder.object_documentation(ree_object)}
48
+
49
+ [#{path_from_package_folder(ree_object.uri)}](#{ree_object.uri})
50
+ DOC
51
+ end
52
+
36
53
  def get_detail_string(ree_object)
37
54
  return '' if ree_object.signatures.size == 0
38
55
 
@@ -9,8 +9,12 @@ module RubyLsp
9
9
  @response_builder = response_builder
10
10
  @handler = RubyLsp::Ree::HoverHandler.new(index, node_context)
11
11
 
12
- dispatcher.register(self, :on_call_node_enter)
13
- dispatcher.register(self, :on_constant_read_node_enter)
12
+ dispatcher.register(
13
+ self,
14
+ :on_call_node_enter,
15
+ :on_symbol_node_enter,
16
+ :on_constant_read_node_enter
17
+ )
14
18
  end
15
19
 
16
20
  def on_constant_read_node_enter(node)
@@ -32,6 +36,13 @@ module RubyLsp
32
36
  $stderr.puts("error in hover listener(on_call_node_enter): #{e.message} : #{e.backtrace.first}")
33
37
  end
34
38
 
39
+ def on_symbol_node_enter(node)
40
+ hover_items = @handler.get_linked_object_hover_items(node)
41
+ put_items_into_response(hover_items)
42
+ rescue => e
43
+ $stderr.puts("error in hover listener(on_symbol_node_enter): #{e.message} : #{e.backtrace.first}")
44
+ end
45
+
35
46
  def put_items_into_response(items)
36
47
  items.each do |item|
37
48
  @response_builder.push(item, category: :documentation)
@@ -175,11 +175,19 @@ class RubyLsp::Ree::ParsedDocument
175
175
  [RubyIndexer::Entry::Signature.new(signature_params)]
176
176
  end
177
177
 
178
- def get_class_name
178
+ def class_name
179
+ class_node.constant_path.name.to_s
180
+ end
181
+
182
+ def full_class_name
179
183
  name_parts = [class_node.constant_path&.parent&.name, class_node.constant_path.name]
180
184
  name_parts.compact.map(&:to_s).join('::')
181
185
  end
182
186
 
187
+ def links_container_node_name
188
+ links_container_node.arguments.arguments.first.unescaped
189
+ end
190
+
183
191
  def node_name(node)
184
192
  return nil unless node.respond_to?(:name)
185
193
 
@@ -18,9 +18,14 @@ module RubyLsp
18
18
  obj_name = node.arguments.child_nodes.first.unescaped
19
19
  return unless current_filename == obj_name
20
20
 
21
+ source = @listener.instance_variable_get(:@source_lines).join
22
+ ast = Prism.parse(source).value # TODO use doc builder
23
+
21
24
  location = node.location
22
- signatures = parse_signatures(obj_name)
23
- comments = "ree_object\ntype: :#{node.name}"
25
+ signatures = parse_signatures(obj_name, ast)
26
+ documentation = parse_documentation(obj_name, ast)
27
+
28
+ comments = "ree_object\ntype: :#{node.name}\n#{documentation}"
24
29
 
25
30
  @listener.add_method(
26
31
  obj_name,
@@ -32,10 +37,7 @@ module RubyLsp
32
37
 
33
38
  private
34
39
 
35
- def parse_signatures(fn_name)
36
- source = @listener.instance_variable_get(:@source_lines).join
37
- ast = Prism.parse(source).value
38
-
40
+ def parse_signatures(fn_name, ast)
39
41
  class_node = ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
40
42
  return [] unless class_node
41
43
 
@@ -47,6 +49,28 @@ module RubyLsp
47
49
  [RubyIndexer::Entry::Signature.new(signature_params)]
48
50
  end
49
51
 
52
+ def parse_documentation(fn_name, ast)
53
+ class_node = ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
54
+ return '' unless class_node
55
+
56
+ doc_node = class_node.body.body.detect{ |node| node.respond_to?(:name) && node.name == :doc }
57
+ return '' unless doc_node
58
+
59
+ str_node = doc_node.arguments.arguments.first
60
+
61
+ case str_node
62
+ when Prism::StringNode
63
+ str_node.unescaped
64
+ when Prism::InterpolatedStringNode
65
+ str_node.parts.map(&:unescaped).join
66
+ else
67
+ ''
68
+ end
69
+ rescue => e
70
+ $stderr.puts("error parsing documentation for #{fn_name}: #{e.message} : #{e.backtrace.first}")
71
+ return ''
72
+ end
73
+
50
74
  def current_filename
51
75
  uri = @listener.instance_variable_get(:@uri)
52
76
  File.basename(uri.path, '.rb')
@@ -71,21 +71,14 @@ module RubyLsp
71
71
  end
72
72
 
73
73
  def object_type(ree_object)
74
- # TODO rewrite to use string split
75
- case ree_object.comments.lines[1]&.chomp
76
- when DAO_TYPE_STRING
77
- :dao
78
- when BEAN_TYPE_STRING
79
- :bean
80
- when ENUM_TYPE_STRING
81
- :enum
82
- when MAPPER_TYPE_STRING
83
- :mapper
84
- when AGGREGATE_TYPE_STRING
85
- :aggregate
86
- else
87
- nil
88
- end
74
+ type_str = ree_object.comments.lines[1]&.chomp
75
+ return unless type_str
76
+
77
+ type_str.split(' ').last[1..-1].to_sym
78
+ end
79
+
80
+ def object_documentation(ree_object)
81
+ ree_object.comments.lines[2..-1].join("\n").chomp
89
82
  end
90
83
  end
91
84
  end
@@ -0,0 +1,39 @@
1
+ module RubyLsp
2
+ module Ree
3
+ class ReeRenameHandler
4
+ include RubyLsp::Ree::ReeLspUtils
5
+
6
+ def self.call(changes)
7
+ old_uri = URI.parse(changes.detect{ _1[:type] == Constant::FileChangeType::DELETED }[:uri])
8
+ new_uri = URI.parse(changes.detect{ _1[:type] == Constant::FileChangeType::CREATED }[:uri])
9
+
10
+ old_file_name = File.basename(old_uri, '.rb')
11
+ new_file_name = File.basename(new_uri, '.rb')
12
+
13
+ return if old_file_name == new_file_name
14
+
15
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(new_uri)
16
+ return if !parsed_doc || !parsed_doc.class_node
17
+
18
+ old_class_name = old_file_name.split('_').collect(&:capitalize).join
19
+ new_class_name = new_file_name.split('_').collect(&:capitalize).join
20
+
21
+ return unless parsed_doc.class_name == old_class_name
22
+
23
+ file_content_lines = File.read(new_uri.path).lines
24
+
25
+ class_line = parsed_doc.class_node.location.start_line - 1
26
+
27
+ file_content_lines[class_line].gsub!(/\b#{old_class_name}\b/, new_class_name)
28
+
29
+ if parsed_doc.links_container_node
30
+ links_container_node_line = parsed_doc.links_container_node.location.start_line - 1
31
+
32
+ file_content_lines[links_container_node_line].gsub!(/\b#{old_file_name}\b/, new_file_name)
33
+ end
34
+
35
+ File.write(new_uri.path, file_content_lines.join)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,100 @@
1
+ module RubyLsp
2
+ module Ree
3
+ class ReeTemplateApplicator
4
+ include RubyLsp::Ree::ReeLspUtils
5
+
6
+ TEMPLATES_FOLDER = '.vscode-ree/templates'
7
+ DEFAULT_TEMPLATE_FILENAME = 'default.rb'
8
+ RSPEC_TEMPLATE_PATH = 'spec_template.rb'
9
+
10
+ def initialize
11
+ return unless template_dir_exists?
12
+
13
+ @template_types = Dir
14
+ .entries(TEMPLATES_FOLDER)
15
+ .select{ |entry|
16
+ File.directory? File.join(TEMPLATES_FOLDER,entry) and !(entry =='.' || entry == '..')
17
+ }
18
+ end
19
+
20
+ def template_dir_exists?
21
+ File.exist?(TEMPLATES_FOLDER)
22
+ end
23
+
24
+ def apply(change_item)
25
+ uri = change_item[:uri]
26
+ path = URI.parse(uri).path
27
+
28
+ file_content = File.read(path)
29
+ return if file_content.size > 0
30
+
31
+ if path.end_with?('_spec.rb')
32
+ template_str = fetch_rspec_template
33
+ template_info = fetch_rspec_template_info(uri)
34
+ else
35
+ template_type = get_template_type_from_uri(uri)
36
+ return unless template_type
37
+
38
+ template_str = fetch_template(template_type)
39
+ template_info = fetch_template_info(uri)
40
+ end
41
+
42
+ template_content = replace_placeholders(template_str, template_info)
43
+
44
+ File.write(path, template_content)
45
+ end
46
+
47
+ def get_template_type_from_uri(uri)
48
+ uri_parts = File.dirname(uri).split('/')
49
+
50
+ uri_parts.reverse.detect{ @template_types.include?(_1) }
51
+ end
52
+
53
+ def fetch_template(template_type)
54
+ File.read(File.join(TEMPLATES_FOLDER, template_type, DEFAULT_TEMPLATE_FILENAME))
55
+ end
56
+
57
+ def fetch_rspec_template
58
+ File.read(File.join(TEMPLATES_FOLDER, RSPEC_TEMPLATE_PATH))
59
+ end
60
+
61
+ def fetch_template_info(uri)
62
+ object_name = File.basename(uri, '.rb')
63
+ object_class = object_name.split('_').collect(&:capitalize).join
64
+ package_name = package_name_from_uri(uri)
65
+ package_class = package_name.split('_').collect(&:capitalize).join
66
+
67
+ {
68
+ 'PACKAGE_MODULE' => package_class,
69
+ 'PACKAGE_NAME' => package_name,
70
+ 'OBJECT_CLASS' => object_class,
71
+ 'OBJECT_NAME' => object_name,
72
+ }
73
+ end
74
+
75
+ def fetch_rspec_template_info(uri)
76
+ object_name = File.basename(uri, '.rb')
77
+ object_class = object_name.split('_').collect(&:capitalize).join
78
+ package_name = package_name_from_spec_uri(uri)
79
+ package_class = package_name.split('_').collect(&:capitalize).join
80
+ file_path = spec_relative_file_path_from_uri(URI(uri))&.delete_suffix('_spec')
81
+
82
+ {
83
+ 'RELATIVE_FILE_PATH' => file_path,
84
+ 'MODULE_NAME' => package_class,
85
+ 'CLASS_NAME' => object_class,
86
+ 'OBJECT_NAME' => object_name,
87
+ 'PACKAGE_NAME' => package_name,
88
+ }
89
+ end
90
+
91
+ def replace_placeholders(template_str, template_info)
92
+ template_info.each do |k,v|
93
+ template_str.gsub!(k, v)
94
+ end
95
+
96
+ template_str
97
+ end
98
+ end
99
+ end
100
+ end
@@ -17,8 +17,17 @@ module RubyLsp
17
17
  uri_parts[package_folder_index + 1]
18
18
  end
19
19
 
20
+ def package_name_from_spec_uri(uri)
21
+ uri_parts = uri.to_s.split('/')
22
+
23
+ spec_folder_index = uri_parts.find_index('spec')
24
+ return unless spec_folder_index
25
+
26
+ uri_parts[spec_folder_index + 1]
27
+ end
28
+
20
29
  def path_from_package_folder(uri)
21
- uri_parts = uri.to_s.chomp(File.extname(uri)).split('/')
30
+ uri_parts = uri.to_s.chomp(File.extname(uri.to_s)).split('/')
22
31
 
23
32
  package_folder_index = uri_parts.index('package')
24
33
  return unless package_folder_index
@@ -26,6 +35,14 @@ module RubyLsp
26
35
  uri_parts.drop(package_folder_index+1).join('/')
27
36
  end
28
37
 
38
+ def spec_relative_file_path_from_uri(uri)
39
+ uri_parts = uri.path.split('/')
40
+ spec_folder_index = uri_parts.index('spec')
41
+ return unless spec_folder_index
42
+
43
+ uri_parts[spec_folder_index+1..-1].join('/').chomp('.rb')
44
+ end
45
+
29
46
  def get_ree_type(ree_object)
30
47
  type_comment = ree_object.comments.to_s.lines[1]
31
48
  return unless type_comment
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLsp
4
4
  module Ree
5
- VERSION = "0.1.4"
5
+ VERSION = "0.1.6"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-ree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-25 00:00:00.000000000 Z
11
+ date: 2025-03-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby LSP addon that adds extra editor functionality for Ree applications
14
14
  email:
@@ -39,6 +39,8 @@ files:
39
39
  - lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb
40
40
  - lib/ruby_lsp/ruby_lsp_ree/ree_indexing_enhancement.rb
41
41
  - lib/ruby_lsp/ruby_lsp_ree/ree_object_finder.rb
42
+ - lib/ruby_lsp/ruby_lsp_ree/ree_rename_handler.rb
43
+ - lib/ruby_lsp/ruby_lsp_ree/ree_template_applicator.rb
42
44
  - lib/ruby_lsp/ruby_lsp_ree/utils/ree_lsp_utils.rb
43
45
  - lib/ruby_lsp_ree.rb
44
46
  - lib/ruby_lsp_ree/version.rb