Class: RubyLsp::Listeners::CodeLens

Inherits:
RubyLsp::Listener show all
Extended by:
T::Generic, T::Sig
Defined in:
lib/ruby_lsp/listeners/code_lens.rb

Constant Summary collapse

BASE_COMMAND =
T.let(
  begin
    Bundler.with_original_env { Bundler.default_lockfile }
    "bundle exec ruby"
  rescue Bundler::GemfileNotFound
    "ruby"
  end + " -Itest ",
  String,
)
ACCESS_MODIFIERS =
T.let([:public, :private, :protected], T::Array[Symbol])
SUPPORTED_TEST_LIBRARIES =
T.let(["minitest", "test-unit"], T::Array[String])
ResponseType =
type_member { { fixed: T::Array[Interface::CodeLens] } }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from RubyLsp::Listener

#response

Methods included from Requests::Support::Common

#create_code_lens, #markdown_from_index_entries, #not_in_dependencies?, #range_from_location, #range_from_node, #self_receiver?, #visible?

Constructor Details

#initialize(uri, lenses_configuration, dispatcher) ⇒ CodeLens

Returns a new instance of CodeLens.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 37

def initialize(uri, lenses_configuration, dispatcher)
  @uri = T.let(uri, URI::Generic)
  @_response = T.let([], ResponseType)
  @path = T.let(uri.to_standardized_path, T.nilable(String))
  # visibility_stack is a stack of [current_visibility, previous_visibility]
  @visibility_stack = T.let([[:public, :public]], T::Array[T::Array[T.nilable(Symbol)]])
  @class_stack = T.let([], T::Array[String])
  @group_id = T.let(1, Integer)
  @group_id_stack = T.let([], T::Array[Integer])
  @lenses_configuration = lenses_configuration

  super(dispatcher)

  dispatcher.register(
    self,
    :on_class_node_enter,
    :on_class_node_leave,
    :on_def_node_enter,
    :on_call_node_enter,
    :on_call_node_leave,
  )
end

Instance Attribute Details

#_responseObject (readonly)

Returns the value of attribute _response.



28
29
30
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 28

def _response
  @_response
end

Instance Method Details

#on_call_node_enter(node) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 106

def on_call_node_enter(node)
  name = node.name
  arguments = node.arguments

  # If we found `private` by itself or `private def foo`
  if ACCESS_MODIFIERS.include?(name)
    if arguments.nil?
      @visibility_stack.pop
      @visibility_stack.push([name, name])
    elsif arguments.arguments.first.is_a?(Prism::DefNode)
      visibility, _ = @visibility_stack.pop
      @visibility_stack.push([name, visibility])
    end

    return
  end

  if @path&.include?(GEMFILE_NAME) && name == :gem && arguments
    return unless @lenses_configuration.enabled?(:gemfileLinks)

    first_argument = arguments.arguments.first
    return unless first_argument.is_a?(Prism::StringNode)

    remote = resolve_gem_remote(first_argument)
    return unless remote

    add_open_gem_remote_code_lens(node, remote)
  end
end

#on_call_node_leave(node) ⇒ Object



137
138
139
140
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 137

def on_call_node_leave(node)
  _, prev_visibility = @visibility_stack.pop
  @visibility_stack.push([prev_visibility, prev_visibility])
end

#on_class_node_enter(node) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 61

def on_class_node_enter(node)
  @visibility_stack.push([:public, :public])
  class_name = node.constant_path.slice
  @class_stack.push(class_name)

  if @path && class_name.end_with?("Test")
    add_test_code_lens(
      node,
      name: class_name,
      command: generate_test_command(class_name: class_name),
      kind: :group,
    )
  end

  @group_id_stack.push(@group_id)
  @group_id += 1
end

#on_class_node_leave(node) ⇒ Object



80
81
82
83
84
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 80

def on_class_node_leave(node)
  @visibility_stack.pop
  @class_stack.pop
  @group_id_stack.pop
end

#on_def_node_enter(node) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ruby_lsp/listeners/code_lens.rb', line 87

def on_def_node_enter(node)
  class_name = @class_stack.last
  return unless class_name&.end_with?("Test")

  visibility, _ = @visibility_stack.last
  if visibility == :public
    method_name = node.name.to_s
    if @path && method_name.start_with?("test_")
      add_test_code_lens(
        node,
        name: method_name,
        command: generate_test_command(method_name: method_name, class_name: class_name),
        kind: :example,
      )
    end
  end
end