nrepl-lazuli 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrepl-lazuli/connection.rb +24 -13
- data/lib/nrepl-lazuli/fake_stdout.rb +2 -1
- data/lib/nrepl-lazuli/server.rb +52 -12
- data/lib/nrepl-lazuli.rb +10 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35d0ce415821f889b64d53b1ea8f88b11a96d43a8932e00108d991b3bfc7a7fb
|
4
|
+
data.tar.gz: 6b72192793c3bc68883c1396c4c86d1a1dbed7976692f75e1dfc1f3a0fecf938
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e6639603de1e57633eb29742732ffedb483d6c101cc96c2cb9c1d3a2940e2d2aa0a49c5510d8ac3eaceccc1ed69bea56dd0e20693813ef0714e9d5ecc3f1cad
|
7
|
+
data.tar.gz: bc667ae67a50840cab449027e7b6d1e990303e2986809823effec71d278811399ddc53aee3a561c3fc4dd3c0fa75ca81bcc40401b0301b0ce49f1a97f9de9f4d
|
@@ -4,17 +4,18 @@ module NREPL
|
|
4
4
|
|
5
5
|
def initialize(
|
6
6
|
input, debug: false, out: input,
|
7
|
-
|
8
|
-
|
7
|
+
binding: nil,
|
8
|
+
bindings: {},
|
9
|
+
bindings_by_id: {}
|
9
10
|
)
|
10
11
|
@debug = debug
|
11
12
|
@in = input
|
12
13
|
@out = out
|
13
14
|
@pending_evals = {}
|
14
|
-
@watches = watches
|
15
15
|
@counter = 0
|
16
16
|
@binding = binding
|
17
|
-
@
|
17
|
+
@bindings = bindings
|
18
|
+
@bindings_by_id = bindings_by_id
|
18
19
|
end
|
19
20
|
|
20
21
|
def treat_messages!
|
@@ -27,6 +28,8 @@ module NREPL
|
|
27
28
|
treat_msg(msg)
|
28
29
|
end
|
29
30
|
@pending_evals.each { |(i, _)| clear_eval!(i) }
|
31
|
+
rescue Errno::ECONNRESET
|
32
|
+
@pending_evals.each { |(i, _)| clear_eval!(i) }
|
30
33
|
end
|
31
34
|
|
32
35
|
def treat_msg(msg)
|
@@ -39,6 +42,9 @@ module NREPL
|
|
39
42
|
eval_op(msg, false)
|
40
43
|
when 'eval_pause'
|
41
44
|
eval_op(msg, true)
|
45
|
+
when 'last_exception'
|
46
|
+
ex = Server.class_variable_get(:@@last_exception)
|
47
|
+
send_msg(response_for(msg, { 'result' => ex.inspect, 'status' => ['done'] }))
|
42
48
|
when 'eval_resume'
|
43
49
|
msg['id'] ||= "eval_#{@counter += 1}"
|
44
50
|
stop_id = msg['stop_id']
|
@@ -51,7 +57,14 @@ module NREPL
|
|
51
57
|
when 'unwatch'
|
52
58
|
msg['id'] ||= "eval_#{@counter += 1}"
|
53
59
|
watch_id = msg['watch_id']
|
54
|
-
@
|
60
|
+
info = @bindings_by_id.delete(watch_id)
|
61
|
+
if(info)
|
62
|
+
file_info = @bindings.fetch(info[:file], {})
|
63
|
+
content = file_info.fetch(info[:row], {})
|
64
|
+
content.delete(watch_id)
|
65
|
+
file_info.delete(info[:row]) if(content.empty?)
|
66
|
+
@bindings.delete(info[:file]) if(file_info.empty?)
|
67
|
+
end
|
55
68
|
|
56
69
|
send_msg(response_for(msg, {
|
57
70
|
'status' => ['done'],
|
@@ -84,7 +97,7 @@ module NREPL
|
|
84
97
|
when 'watches_for_file'
|
85
98
|
msg['id'] ||= "eval_#{@counter += 1}"
|
86
99
|
file = msg['file']
|
87
|
-
rows_bindings = @
|
100
|
+
rows_bindings = @bindings[file] || {}
|
88
101
|
send_msg(response_for(msg, {
|
89
102
|
'status' => ['done'],
|
90
103
|
'rows' => rows_bindings.keys.sort,
|
@@ -148,7 +161,7 @@ module NREPL
|
|
148
161
|
original_bind = if msg['stop_id']
|
149
162
|
@pending_evals.fetch(msg['stop_id'], {})[:binding]
|
150
163
|
elsif msg['watch_id']
|
151
|
-
@
|
164
|
+
@bindings_by_id.fetch(msg['watch_id'], {})[:binding]
|
152
165
|
else
|
153
166
|
find_row_based_binding(msg) || @binding
|
154
167
|
end
|
@@ -165,10 +178,10 @@ module NREPL
|
|
165
178
|
row = msg['line']
|
166
179
|
return if !file || !row
|
167
180
|
|
168
|
-
rows_bindings = @
|
181
|
+
rows_bindings = @bindings[file]
|
169
182
|
return unless rows_bindings
|
170
183
|
found_row = row.downto(-1).find { |k| rows_bindings[k] }
|
171
|
-
rows_bindings[found_row]
|
184
|
+
rows_bindings[found_row].values[-1] if found_row
|
172
185
|
end
|
173
186
|
|
174
187
|
private def define_stop_function!(msg, method_name)
|
@@ -226,9 +239,6 @@ module NREPL
|
|
226
239
|
send_msg(response_for(msg, { 'versions' => versions }))
|
227
240
|
end
|
228
241
|
|
229
|
-
# @param [TCPSocket] client
|
230
|
-
# @param [Hash] msg
|
231
|
-
# @param [Exception] e
|
232
242
|
def send_exception(msg, e)
|
233
243
|
send_msg(response_for(msg, { 'ex' => e.message, 'status' => ['done', 'error'] }))
|
234
244
|
end
|
@@ -245,5 +255,6 @@ end
|
|
245
255
|
b = binding
|
246
256
|
define_method(:evaluate_code) do |code, file, line, bind|
|
247
257
|
bind ||= b
|
248
|
-
|
258
|
+
line = line ? line + 1 : 1
|
259
|
+
eval(code, bind, file || "EVAL", line).inspect
|
249
260
|
end
|
data/lib/nrepl-lazuli/server.rb
CHANGED
@@ -13,6 +13,14 @@ module NREPL
|
|
13
13
|
attr_reader :debug, :port, :host
|
14
14
|
alias debug? debug
|
15
15
|
|
16
|
+
def self.spawn(args)
|
17
|
+
t = Thread.new {
|
18
|
+
new(**args).start
|
19
|
+
}
|
20
|
+
sleep 0.1
|
21
|
+
t[:nrepl_server]
|
22
|
+
end
|
23
|
+
|
16
24
|
def self.start(**kwargs)
|
17
25
|
new(**kwargs).start
|
18
26
|
end
|
@@ -21,15 +29,27 @@ module NREPL
|
|
21
29
|
new(**kwargs.merge(binding: binding)).start
|
22
30
|
end
|
23
31
|
|
24
|
-
def initialize(
|
32
|
+
def initialize(
|
33
|
+
port: DEFAULT_PORT,
|
34
|
+
host: DEFAULT_HOST,
|
35
|
+
debug: false,
|
36
|
+
binding: nil,
|
37
|
+
pwd: Dir.pwd,
|
38
|
+
tracing: true
|
39
|
+
)
|
25
40
|
@port = port
|
26
41
|
@pwd = pwd
|
27
42
|
@host = host
|
28
43
|
@debug = debug
|
29
44
|
@connections = Set.new
|
30
45
|
@binding = binding
|
31
|
-
@
|
46
|
+
@bindings = {}
|
47
|
+
@bindings_by_id = {}
|
48
|
+
@tracing = tracing
|
49
|
+
Thread.current[:nrepl_server] = self
|
32
50
|
NREPL.class_variable_set(:@@connections, @connections)
|
51
|
+
NREPL.class_variable_set(:@@bindings, @bindings)
|
52
|
+
NREPL.class_variable_set(:@@bindings_by_id, @bindings_by_id)
|
33
53
|
end
|
34
54
|
|
35
55
|
private def record_port
|
@@ -43,33 +63,46 @@ module NREPL
|
|
43
63
|
puts "Running in debug mode" if debug?
|
44
64
|
record_port
|
45
65
|
|
66
|
+
@old_out, @old_err = $stdout, $stderr
|
46
67
|
$stdout = FakeStdout.new(@connections, STDOUT, "out")
|
47
68
|
$stderr = FakeStdout.new(@connections, STDERR, "err")
|
48
|
-
auto_create_bindings!
|
69
|
+
auto_create_bindings! if @tracing
|
49
70
|
|
50
71
|
Signal.trap("INT") { stop }
|
51
72
|
Signal.trap("TERM") { stop }
|
52
73
|
|
53
|
-
|
74
|
+
@socket = TCPServer.new(host, port)
|
54
75
|
loop do
|
55
|
-
|
56
|
-
|
76
|
+
break if @socket.closed?
|
77
|
+
Thread.start(@socket.accept) do |client|
|
78
|
+
connection = Connection.new(
|
79
|
+
client,
|
80
|
+
debug: debug?,
|
81
|
+
binding: @binding,
|
82
|
+
bindings_by_id: @bindings_by_id,
|
83
|
+
bindings: @bindings
|
84
|
+
)
|
57
85
|
@connections << connection
|
58
86
|
connection.treat_messages!
|
59
87
|
@connections.delete(connection)
|
60
88
|
end
|
61
89
|
end
|
90
|
+
rescue IOError
|
91
|
+
puts "Server closed" if debug?
|
62
92
|
ensure
|
63
93
|
File.unlink(PORT_FILENAME)
|
64
94
|
end
|
65
95
|
|
66
96
|
def auto_create_bindings!
|
67
97
|
dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
|
68
|
-
@call_trace = TracePoint.new(:call) do |tp|
|
69
|
-
|
70
|
-
|
98
|
+
@call_trace = TracePoint.new(:class, :call) do |tp|
|
99
|
+
id = "#{tp.path}:#{tp.lineno}"
|
100
|
+
b = tp.binding
|
101
|
+
@bindings_by_id[id] = {binding: b, file: tp.path, row: tp.lineno-1}
|
102
|
+
@bindings[tp.path] ||= {}
|
103
|
+
@bindings[tp.path][tp.lineno-1] ||= {}
|
104
|
+
@bindings[tp.path][tp.lineno-1][id] = b
|
71
105
|
if tp.path =~ dir_regex
|
72
|
-
# puts "Tracing #{tp.path}:#{tp.lineno}"
|
73
106
|
@connections.each do |connection|
|
74
107
|
connection.send_msg(
|
75
108
|
'op' => 'hit_auto_watch',
|
@@ -81,11 +114,18 @@ module NREPL
|
|
81
114
|
end
|
82
115
|
end
|
83
116
|
@call_trace.enable
|
117
|
+
|
118
|
+
@ex_trace = TracePoint.new(:raise) do |tp|
|
119
|
+
e = tp.raised_exception
|
120
|
+
@@last_exception = [:error, e.inspect.sub(/\>$/, ' stack=' + e.backtrace.inspect+'>')]
|
121
|
+
end
|
122
|
+
@ex_trace.enable
|
84
123
|
end
|
85
124
|
|
86
125
|
def stop
|
87
|
-
|
88
|
-
|
126
|
+
@connections = []
|
127
|
+
$stdout, $stderr = @old_out, @old_err
|
128
|
+
@socket.close
|
89
129
|
end
|
90
130
|
end
|
91
131
|
|
data/lib/nrepl-lazuli.rb
CHANGED
@@ -7,15 +7,21 @@ module NREPL
|
|
7
7
|
PORT_FILENAME = '.nrepl-port'
|
8
8
|
|
9
9
|
require_relative 'nrepl-lazuli/server'
|
10
|
-
@@
|
10
|
+
@@bindings = {}
|
11
|
+
@@bindings_by_id = {}
|
11
12
|
@@connections = Set.new
|
12
13
|
|
13
14
|
def self.watch!(binding, id=nil)
|
14
|
-
|
15
|
+
loc = caller_locations[0]
|
16
|
+
file = loc.path
|
17
|
+
row = loc.lineno
|
15
18
|
id ||= "#{file}:#{row}"
|
16
|
-
row = row.to_i
|
17
19
|
|
18
|
-
@@
|
20
|
+
@@bindings_by_id[id] = {binding: binding, file: file, row: loc.lineno-1}
|
21
|
+
@@bindings[file] ||= {}
|
22
|
+
@@bindings[file][loc.lineno-1] ||= {}
|
23
|
+
@@bindings[file][loc.lineno-1][id] = binding
|
24
|
+
|
19
25
|
@@connections.each do |connection|
|
20
26
|
connection.send_msg(
|
21
27
|
'op' => 'hit_watch',
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nrepl-lazuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maurício Szabo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bencode
|
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
requirements: []
|
57
|
-
rubygems_version: 3.5.
|
57
|
+
rubygems_version: 3.5.9
|
58
58
|
signing_key:
|
59
59
|
specification_version: 4
|
60
60
|
summary: A Ruby nREPL server
|