kapusta 0.12.0 → 0.13.0
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 +4 -4
- data/README.md +1 -0
- data/examples/bst-iterator.kap +2 -2
- data/examples/zoo-animal-1.kap +1 -1
- data/examples/zoo-animal-inheritance-2.kap +1 -1
- data/lib/kapusta/compiler/emitter/bindings.rb +17 -5
- data/lib/kapusta/compiler/emitter/interop.rb +12 -3
- data/lib/kapusta/compiler/emitter/support.rb +64 -11
- data/lib/kapusta/compiler/emitter.rb +1 -0
- data/lib/kapusta/env.rb +1 -0
- data/lib/kapusta/lsp/definition.rb +1 -1
- data/lib/kapusta/lsp/rename.rb +19 -3
- data/lib/kapusta/lsp/scope_walker.rb +19 -5
- data/lib/kapusta/version.rb +1 -1
- data/spec/lsp_spec.rb +55 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b547075d7dcb73121e61dc17577cb8262265eaffb6ee0d74b88a74ce83c8e09a
|
|
4
|
+
data.tar.gz: 877f490eca3f0d4419e38b4619f77470aff18ddd8fede555f2963beb8db5994f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cddc220382f4c7f59788f4624f9e86f55bc58fe2b3fa6978f4e6d8bebaa870ff73be57786ecf2db94f14d6db460b3f485b6f82195e7fd21e255c7a7612ab50c2
|
|
7
|
+
data.tar.gz: 6c653e095b1c3d406f95e7f1659b615a2a59eaa21ef77e709cfc2dfc398d3526fb493f5054cb541acd36b203e690dbc28626e951e3e8f9d5e27366c0d5885834
|
data/README.md
CHANGED
data/examples/bst-iterator.kap
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
(fn initialize [root]
|
|
17
17
|
(set @stack [])
|
|
18
|
-
(
|
|
18
|
+
(push-left root))
|
|
19
19
|
|
|
20
20
|
(fn push-left [node]
|
|
21
21
|
(var n node)
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
(fn next []
|
|
28
28
|
(let [stack @stack
|
|
29
29
|
node (stack.pop)]
|
|
30
|
-
(
|
|
30
|
+
(push-left (node.right))
|
|
31
31
|
(node.val)))
|
|
32
32
|
|
|
33
33
|
(fn has-next? []
|
data/examples/zoo-animal-1.kap
CHANGED
|
@@ -81,9 +81,21 @@ module Kapusta
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def emit_definition_form(form, env, current_scope)
|
|
84
|
-
return
|
|
84
|
+
return emit_toplevel_method_definition(form, env) if current_scope == :toplevel
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
code = emit_method_definition(form, env)
|
|
87
|
+
register_self_method_binding(form, env)
|
|
88
|
+
[code, env]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def register_self_method_binding(form, env)
|
|
92
|
+
name_sym = form.items[1]
|
|
93
|
+
return unless name_sym.is_a?(Sym) && !name_sym.dotted?
|
|
94
|
+
|
|
95
|
+
ruby_name = Kapusta.kebab_to_snake(name_sym.name)
|
|
96
|
+
return unless direct_method_name?(ruby_name)
|
|
97
|
+
|
|
98
|
+
env.define(name_sym.name, Env::SelfMethodBinding.new(ruby_name))
|
|
87
99
|
end
|
|
88
100
|
|
|
89
101
|
def emit_toplevel_method_definition(form, env)
|
|
@@ -234,7 +246,7 @@ module Kapusta
|
|
|
234
246
|
|
|
235
247
|
binding = env.lookup_if_defined(name)
|
|
236
248
|
return false if binding.nil?
|
|
237
|
-
return false if
|
|
249
|
+
return false if callable_method_binding?(binding)
|
|
238
250
|
return false if constant_binding?(binding)
|
|
239
251
|
|
|
240
252
|
true
|
|
@@ -385,7 +397,7 @@ module Kapusta
|
|
|
385
397
|
binding = env.lookup_if_defined(target.name)
|
|
386
398
|
ruby_name =
|
|
387
399
|
if binding
|
|
388
|
-
emit_error!(:cannot_set_method_binding, name: target.name) if
|
|
400
|
+
emit_error!(:cannot_set_method_binding, name: target.name) if callable_method_binding?(binding)
|
|
389
401
|
|
|
390
402
|
binding
|
|
391
403
|
else
|
|
@@ -429,7 +441,7 @@ module Kapusta
|
|
|
429
441
|
end
|
|
430
442
|
else
|
|
431
443
|
binding = env.lookup(target.name)
|
|
432
|
-
emit_error!(:cannot_set_method_binding, name: target.name) if
|
|
444
|
+
emit_error!(:cannot_set_method_binding, name: target.name) if callable_method_binding?(binding)
|
|
433
445
|
emit_error!(:expected_var, name: target.name) unless mutable_binding?(env, target.name)
|
|
434
446
|
|
|
435
447
|
emit_assignment(binding, value_code)
|
|
@@ -80,13 +80,17 @@ module Kapusta
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def emit_module_expr(args, env)
|
|
83
|
-
body =
|
|
83
|
+
body = with_class_body do
|
|
84
|
+
emit_sequence(args[1..], env.child, :module, allow_method_definitions: true, result: false).first
|
|
85
|
+
end
|
|
84
86
|
emit_module_wrapper(args[0], body)
|
|
85
87
|
end
|
|
86
88
|
|
|
87
89
|
def emit_class_expr(args, env)
|
|
88
90
|
name_sym, supers, body_forms = split_class_args(args)
|
|
89
|
-
body =
|
|
91
|
+
body = with_class_body do
|
|
92
|
+
emit_sequence(body_forms, env.child, :class, allow_method_definitions: true, result: false).first
|
|
93
|
+
end
|
|
90
94
|
emit_class_wrapper(name_sym, supers, env,
|
|
91
95
|
body)
|
|
92
96
|
end
|
|
@@ -298,7 +302,7 @@ module Kapusta
|
|
|
298
302
|
end
|
|
299
303
|
|
|
300
304
|
def emit_bound_call(binding, args, env, current_scope)
|
|
301
|
-
return emit_self_method_binding_call(binding, args, env, current_scope) if
|
|
305
|
+
return emit_self_method_binding_call(binding, args, env, current_scope) if callable_method_binding?(binding)
|
|
302
306
|
|
|
303
307
|
emit_error!(:cannot_call_constant, name: binding) if constant_binding?(binding)
|
|
304
308
|
|
|
@@ -438,10 +442,15 @@ module Kapusta
|
|
|
438
442
|
return emit_multisym_value(sym, env) if sym.dotted?
|
|
439
443
|
return 'ARGV' if name == 'ARGV'
|
|
440
444
|
return name if name.match?(/\A[A-Z]/)
|
|
445
|
+
return Kapusta.kebab_to_snake(name) if implicit_self_method?(name)
|
|
441
446
|
|
|
442
447
|
emit_error!(:undefined_symbol, name:)
|
|
443
448
|
end
|
|
444
449
|
|
|
450
|
+
def implicit_self_method?(name)
|
|
451
|
+
in_class_body? && direct_method_name?(Kapusta.kebab_to_snake(name))
|
|
452
|
+
end
|
|
453
|
+
|
|
445
454
|
def emit_gvar(sym)
|
|
446
455
|
"$#{global_name(sym.name)}"
|
|
447
456
|
end
|
|
@@ -41,29 +41,29 @@ module Kapusta
|
|
|
41
41
|
|
|
42
42
|
def emit_form_run(forms, start, env, current_scope, header_form: nil)
|
|
43
43
|
i = start
|
|
44
|
-
|
|
44
|
+
entries = []
|
|
45
45
|
while i < forms.length
|
|
46
46
|
form = forms[i]
|
|
47
47
|
if end_form?(form)
|
|
48
48
|
validate_end_form!(form)
|
|
49
49
|
with_current_form(form) { emit_error!(:end_outside_header) } unless header_form
|
|
50
|
-
return [
|
|
50
|
+
return [join_definition_aware(entries, current_scope), i + 1]
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
if bodyless_header?(form)
|
|
54
54
|
header_code, i = emit_bodyless_header(form, forms, i + 1, env)
|
|
55
|
-
|
|
55
|
+
entries << [form, header_code]
|
|
56
56
|
next
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
code, env = emit_form_in_sequence(form, env, current_scope,
|
|
60
60
|
allow_method_definitions: true,
|
|
61
61
|
result_needed: false)
|
|
62
|
-
|
|
62
|
+
entries << [form, code]
|
|
63
63
|
i += 1
|
|
64
64
|
end
|
|
65
65
|
with_current_form(header_form) { emit_error!(:unclosed_header) } if header_form
|
|
66
|
-
[
|
|
66
|
+
[join_definition_aware(entries, current_scope), i]
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def end_form?(form)
|
|
@@ -109,12 +109,16 @@ module Kapusta
|
|
|
109
109
|
inner_code, next_i = emit_bodyless_header(inner[0], forms, body_start, env)
|
|
110
110
|
[emit_direct_module_header(name_sym, inner_code) || emit_module_wrapper(name_sym, inner_code), next_i]
|
|
111
111
|
else
|
|
112
|
-
body, next_i =
|
|
112
|
+
body, next_i = with_class_body do
|
|
113
|
+
emit_form_run(forms, body_start, env.child, :module, header_form: form)
|
|
114
|
+
end
|
|
113
115
|
[emit_direct_module_header(name_sym, body) || emit_module_wrapper(name_sym, body), next_i]
|
|
114
116
|
end
|
|
115
117
|
else
|
|
116
118
|
name_sym, supers, = split_class_args(form.items[1..])
|
|
117
|
-
body, next_i =
|
|
119
|
+
body, next_i = with_class_body do
|
|
120
|
+
emit_form_run(forms, body_start, env.child, :class, header_form: form)
|
|
121
|
+
end
|
|
118
122
|
code = emit_direct_class_header(name_sym, supers, body, env) ||
|
|
119
123
|
emit_class_wrapper(name_sym, supers, env, body)
|
|
120
124
|
[code, next_i]
|
|
@@ -170,14 +174,41 @@ module Kapusta
|
|
|
170
174
|
|
|
171
175
|
def emit_sequence(forms, env, current_scope, allow_method_definitions:, result: true)
|
|
172
176
|
current_env = env
|
|
173
|
-
|
|
177
|
+
entries = []
|
|
174
178
|
forms.each_with_index do |form, index|
|
|
175
179
|
code, current_env = emit_form_in_sequence(form, current_env, current_scope,
|
|
176
180
|
allow_method_definitions:,
|
|
177
181
|
result_needed: result && index == forms.length - 1)
|
|
178
|
-
|
|
182
|
+
entries << [form, code] unless code.empty?
|
|
183
|
+
end
|
|
184
|
+
[join_definition_aware(entries, current_scope), current_env]
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def join_definition_aware(entries, current_scope)
|
|
188
|
+
return '' if entries.empty?
|
|
189
|
+
|
|
190
|
+
result = +entries.first[1]
|
|
191
|
+
entries.each_cons(2) do |(prev_form, _), (curr_form, curr_code)|
|
|
192
|
+
sep = blank_between_definitions?(prev_form, curr_form, current_scope) ? "\n\n" : "\n"
|
|
193
|
+
result << sep << curr_code
|
|
194
|
+
end
|
|
195
|
+
result
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def blank_between_definitions?(prev_form, curr_form, current_scope)
|
|
199
|
+
return false unless %i[toplevel module class].include?(current_scope)
|
|
200
|
+
|
|
201
|
+
definition_form?(prev_form) || definition_form?(curr_form)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def definition_form?(form)
|
|
205
|
+
return false unless form.is_a?(List) && !form.empty? && form.head.is_a?(Sym)
|
|
206
|
+
|
|
207
|
+
case form.head.name
|
|
208
|
+
when 'defn', 'class', 'module' then true
|
|
209
|
+
when 'fn', 'lambda', 'λ' then form.items[1].is_a?(Sym)
|
|
210
|
+
else false
|
|
179
211
|
end
|
|
180
|
-
[codes.join("\n"), current_env]
|
|
181
212
|
end
|
|
182
213
|
|
|
183
214
|
def sequence_statement_form?(form)
|
|
@@ -313,8 +344,30 @@ module Kapusta
|
|
|
313
344
|
binding.is_a?(Env::MethodBinding)
|
|
314
345
|
end
|
|
315
346
|
|
|
347
|
+
def in_class_body?
|
|
348
|
+
@class_body_depth.positive?
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def with_class_body
|
|
352
|
+
@class_body_depth += 1
|
|
353
|
+
yield
|
|
354
|
+
ensure
|
|
355
|
+
@class_body_depth -= 1
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def self_method_binding?(binding)
|
|
359
|
+
binding.is_a?(Env::SelfMethodBinding)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def callable_method_binding?(binding)
|
|
363
|
+
method_binding?(binding) || self_method_binding?(binding)
|
|
364
|
+
end
|
|
365
|
+
|
|
316
366
|
def binding_value_code(binding)
|
|
317
|
-
|
|
367
|
+
return "method(#{binding.ruby_name.to_sym.inspect})" if method_binding?(binding)
|
|
368
|
+
return binding.ruby_name if self_method_binding?(binding)
|
|
369
|
+
|
|
370
|
+
binding
|
|
318
371
|
end
|
|
319
372
|
|
|
320
373
|
def parse_counted_for_bindings(bindings, env, current_scope)
|
data/lib/kapusta/env.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Kapusta
|
|
|
17
17
|
return unless target
|
|
18
18
|
|
|
19
19
|
case target.kind
|
|
20
|
-
when :local, :toplevel_fn, :constant
|
|
20
|
+
when :local, :toplevel_fn, :constant, :method
|
|
21
21
|
location_for_binding(uri, target.binding) if target.binding
|
|
22
22
|
when :macro
|
|
23
23
|
locations_for_macro(uri, target.binding, workspace_index)
|
data/lib/kapusta/lsp/rename.rb
CHANGED
|
@@ -32,6 +32,8 @@ module Kapusta
|
|
|
32
32
|
case target.kind
|
|
33
33
|
when :local
|
|
34
34
|
rename_local(uri, target, new_name)
|
|
35
|
+
when :method
|
|
36
|
+
rename_method(uri, target, new_name)
|
|
35
37
|
when :toplevel_fn, :free_toplevel
|
|
36
38
|
return error('cross-file rename requires a workspace') unless workspace_index
|
|
37
39
|
|
|
@@ -128,8 +130,6 @@ module Kapusta
|
|
|
128
130
|
end
|
|
129
131
|
|
|
130
132
|
if binding
|
|
131
|
-
return if binding.kind == :method
|
|
132
|
-
|
|
133
133
|
return constant_target(walker, binding, seg) if %i[module class].include?(binding.kind)
|
|
134
134
|
|
|
135
135
|
return local_target(walker, binding, seg)
|
|
@@ -138,7 +138,6 @@ module Kapusta
|
|
|
138
138
|
if reference
|
|
139
139
|
target = reference.target
|
|
140
140
|
if target
|
|
141
|
-
return if target.kind == :method
|
|
142
141
|
return constant_target(walker, target, seg, sym:) if %i[module class].include?(target.kind)
|
|
143
142
|
|
|
144
143
|
return local_target(walker, target, seg, sym:)
|
|
@@ -164,6 +163,7 @@ module Kapusta
|
|
|
164
163
|
kind = case binding.kind
|
|
165
164
|
when :toplevel_fn then :toplevel_fn
|
|
166
165
|
when :macro, :macro_import then :macro
|
|
166
|
+
when :method then :method
|
|
167
167
|
else :local
|
|
168
168
|
end
|
|
169
169
|
Target.new(
|
|
@@ -207,6 +207,22 @@ module Kapusta
|
|
|
207
207
|
}
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
+
def rename_method(uri, target, new_name)
|
|
211
|
+
return error("invalid identifier: #{new_name}") unless Identifier.valid_local?(new_name)
|
|
212
|
+
return error('cannot resolve binding') unless target.binding
|
|
213
|
+
|
|
214
|
+
walker = target.walker
|
|
215
|
+
binding = target.binding
|
|
216
|
+
|
|
217
|
+
occs = [binding]
|
|
218
|
+
walker.references.each do |r|
|
|
219
|
+
occs << r if r.target.equal?(binding)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
edits = occs.map { |o| text_edit_first_segment(o, new_name) }
|
|
223
|
+
{ changes: { uri => edits } }
|
|
224
|
+
end
|
|
225
|
+
|
|
210
226
|
def rename_local(uri, target, new_name)
|
|
211
227
|
return error("invalid identifier: #{new_name}") unless Identifier.valid_local?(new_name)
|
|
212
228
|
return error('cannot resolve binding') unless target.binding
|
|
@@ -76,6 +76,17 @@ module Kapusta
|
|
|
76
76
|
|
|
77
77
|
def walk_top(forms)
|
|
78
78
|
walk_form_run(forms, 0, @root_scope)
|
|
79
|
+
resolve_late_references
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def resolve_late_references
|
|
83
|
+
@references.each do |r|
|
|
84
|
+
next if r.target
|
|
85
|
+
next unless r.scope
|
|
86
|
+
|
|
87
|
+
target = r.scope.lookup(r.name)
|
|
88
|
+
r.target = target if target
|
|
89
|
+
end
|
|
79
90
|
end
|
|
80
91
|
|
|
81
92
|
def walk_form_run(forms, start, scope, header_target: nil)
|
|
@@ -164,7 +175,8 @@ module Kapusta
|
|
|
164
175
|
if body.length == 1 && bodyless_header?(body[0])
|
|
165
176
|
walk_bodyless_header(body[0], forms, body_start, scope)
|
|
166
177
|
else
|
|
167
|
-
|
|
178
|
+
body_scope = make_scope(scope, :module)
|
|
179
|
+
walk_form_run(forms, body_start, body_scope, header_target: binding)
|
|
168
180
|
end
|
|
169
181
|
end
|
|
170
182
|
when 'class'
|
|
@@ -172,7 +184,8 @@ module Kapusta
|
|
|
172
184
|
supers&.items&.each { |item| walk_form(item, scope) }
|
|
173
185
|
binding = name_sym.is_a?(Sym) ? add_constant_binding(name_sym, scope, :class) : nil
|
|
174
186
|
inside_class do
|
|
175
|
-
|
|
187
|
+
body_scope = make_scope(scope, :class)
|
|
188
|
+
walk_form_run(forms, body_start, body_scope, header_target: binding)
|
|
176
189
|
end
|
|
177
190
|
end
|
|
178
191
|
end
|
|
@@ -406,7 +419,7 @@ module Kapusta
|
|
|
406
419
|
else
|
|
407
420
|
(scope == @root_scope ? :toplevel_fn : :fn_local)
|
|
408
421
|
end
|
|
409
|
-
binding = add_binding(name_sym, scope, kind, lexical:
|
|
422
|
+
binding = add_binding(name_sym, scope, kind, lexical: true)
|
|
410
423
|
fn_scope.bindings[name_sym.name] = binding unless kind == :method
|
|
411
424
|
end
|
|
412
425
|
bind_param_vec(params, fn_scope)
|
|
@@ -558,10 +571,11 @@ module Kapusta
|
|
|
558
571
|
add_constant_binding(name_sym, scope, kind) if name_sym.is_a?(Sym)
|
|
559
572
|
|
|
560
573
|
body = list.items[body_start..] || []
|
|
574
|
+
body_scope = make_scope(scope, kind)
|
|
561
575
|
if kind == :class
|
|
562
|
-
inside_class { body.each { |form| walk_form(form,
|
|
576
|
+
inside_class { body.each { |form| walk_form(form, body_scope) } }
|
|
563
577
|
else
|
|
564
|
-
inside_module_or_class { body.each { |form| walk_form(form,
|
|
578
|
+
inside_module_or_class { body.each { |form| walk_form(form, body_scope) } }
|
|
565
579
|
end
|
|
566
580
|
end
|
|
567
581
|
|
data/lib/kapusta/version.rb
CHANGED
data/spec/lsp_spec.rb
CHANGED
|
@@ -234,7 +234,7 @@ RSpec.describe Kapusta::LSP do
|
|
|
234
234
|
end
|
|
235
235
|
end
|
|
236
236
|
|
|
237
|
-
it '
|
|
237
|
+
it 'offers rename for method definitions after a bodyless class header' do
|
|
238
238
|
text = "(class Counter)\n(fn initialize [start] start)\n"
|
|
239
239
|
responses = run(
|
|
240
240
|
frame_initialize,
|
|
@@ -242,7 +242,60 @@ RSpec.describe Kapusta::LSP do
|
|
|
242
242
|
frame_prepare_rename(uri: 'file:///x.kap', **cursor_at(text, 'initialize'))
|
|
243
243
|
)
|
|
244
244
|
|
|
245
|
-
expect(result_for(responses)['result']).to
|
|
245
|
+
expect(result_for(responses)['result']).to include('placeholder' => 'initialize')
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'renames a class method and its bare-self call sites within a file' do
|
|
249
|
+
text = "(class Greeter)\n" \
|
|
250
|
+
"(fn initialize [name] (set @name name))\n" \
|
|
251
|
+
"(fn greeting [] (.. \"Hello, \" (label)))\n" \
|
|
252
|
+
"(fn label [] @name)\n"
|
|
253
|
+
responses = run(
|
|
254
|
+
frame_initialize,
|
|
255
|
+
frame_did_open('file:///x.kap', text),
|
|
256
|
+
frame_rename(uri: 'file:///x.kap', **cursor_at(text, 'label'), new_name: 'who')
|
|
257
|
+
)
|
|
258
|
+
edits = result_for(responses)['result']['documentChanges'].first['edits']
|
|
259
|
+
|
|
260
|
+
expect(edits.map { |e| e['newText'] }).to all(eq('who'))
|
|
261
|
+
expect(edits.map { |e| [e['range']['start']['line'], e['range']['start']['character']] })
|
|
262
|
+
.to contain_exactly([2, 31], [3, 4])
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it 'jumps from a bare-self method call to the class method definition' do
|
|
266
|
+
text = "(class Greeter)\n" \
|
|
267
|
+
"(fn label [] 1)\n" \
|
|
268
|
+
"(fn greeting [] (label))\n"
|
|
269
|
+
responses = run(
|
|
270
|
+
frame_initialize,
|
|
271
|
+
frame_did_open('file:///x.kap', text),
|
|
272
|
+
frame_definition(uri: 'file:///x.kap', line: 2, character: 17)
|
|
273
|
+
)
|
|
274
|
+
result = result_for(responses)['result']
|
|
275
|
+
|
|
276
|
+
expect(result).to eq(
|
|
277
|
+
'uri' => 'file:///x.kap',
|
|
278
|
+
'range' => {
|
|
279
|
+
'start' => { 'line' => 1, 'character' => 4 },
|
|
280
|
+
'end' => { 'line' => 1, 'character' => 9 }
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it 'renames a class method when the cursor is on a bare-self call site' do
|
|
286
|
+
text = "(class Greeter)\n" \
|
|
287
|
+
"(fn label [] 1)\n" \
|
|
288
|
+
"(fn greeting [] (label))\n"
|
|
289
|
+
responses = run(
|
|
290
|
+
frame_initialize,
|
|
291
|
+
frame_did_open('file:///x.kap', text),
|
|
292
|
+
frame_rename(uri: 'file:///x.kap', line: 2, character: 17, new_name: 'who')
|
|
293
|
+
)
|
|
294
|
+
edits = result_for(responses)['result']['documentChanges'].first['edits']
|
|
295
|
+
|
|
296
|
+
expect(edits.map { |e| e['newText'] }).to all(eq('who'))
|
|
297
|
+
expect(edits.map { |e| [e['range']['start']['line'], e['range']['start']['character']] })
|
|
298
|
+
.to contain_exactly([1, 4], [2, 17])
|
|
246
299
|
end
|
|
247
300
|
|
|
248
301
|
it 'does not let class methods shadow top-level function references' do
|