nrepl-lazuli 0.2.6 → 0.3.1
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 +25 -15
- data/lib/nrepl-lazuli/server.rb +48 -14
- data/lib/nrepl-lazuli.rb +5 -2
- 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: 2439208ce1a3db5af7c886aa95b577bb713667461c92d129e997f378ca704926
|
4
|
+
data.tar.gz: 6aabf3d36d3996ff158a2c50ebaa6239570e4799614a8d7110d50df7ca1ede4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 755e29ac97e588baca03a48914cc968d23d96961c66c4a3778554bc29b2d14f05ac236f9d15a1b565318cab9a11c28bc1a07cf096911da656f1450c4ae52ac7f
|
7
|
+
data.tar.gz: a6fabeadef479c719f9fa60b53587e85d0d25fd88e96a03311103b0a5a581cccb54425ebd68c9e75cb01e69335dc755631699153bb44501ec51d756d0dc693a8
|
@@ -4,18 +4,18 @@ module NREPL
|
|
4
4
|
|
5
5
|
def initialize(
|
6
6
|
input, debug: false, out: input,
|
7
|
-
watches: NREPL.class_variable_get(:@@bindings),
|
8
7
|
binding: nil,
|
9
|
-
bindings: {}
|
8
|
+
bindings: {},
|
9
|
+
bindings_by_id: {}
|
10
10
|
)
|
11
11
|
@debug = debug
|
12
12
|
@in = input
|
13
13
|
@out = out
|
14
14
|
@pending_evals = {}
|
15
|
-
@watches = watches
|
16
15
|
@counter = 0
|
17
16
|
@binding = binding
|
18
17
|
@bindings = bindings
|
18
|
+
@bindings_by_id = bindings_by_id
|
19
19
|
end
|
20
20
|
|
21
21
|
def treat_messages!
|
@@ -28,6 +28,8 @@ module NREPL
|
|
28
28
|
treat_msg(msg)
|
29
29
|
end
|
30
30
|
@pending_evals.each { |(i, _)| clear_eval!(i) }
|
31
|
+
rescue Errno::ECONNRESET
|
32
|
+
@pending_evals.each { |(i, _)| clear_eval!(i) }
|
31
33
|
end
|
32
34
|
|
33
35
|
def treat_msg(msg)
|
@@ -40,6 +42,9 @@ module NREPL
|
|
40
42
|
eval_op(msg, false)
|
41
43
|
when 'eval_pause'
|
42
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'] }))
|
43
48
|
when 'eval_resume'
|
44
49
|
msg['id'] ||= "eval_#{@counter += 1}"
|
45
50
|
stop_id = msg['stop_id']
|
@@ -52,7 +57,14 @@ module NREPL
|
|
52
57
|
when 'unwatch'
|
53
58
|
msg['id'] ||= "eval_#{@counter += 1}"
|
54
59
|
watch_id = msg['watch_id']
|
55
|
-
@
|
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
|
56
68
|
|
57
69
|
send_msg(response_for(msg, {
|
58
70
|
'status' => ['done'],
|
@@ -110,7 +122,6 @@ module NREPL
|
|
110
122
|
begin
|
111
123
|
eval_msg(msg, stop)
|
112
124
|
rescue Exception => e
|
113
|
-
puts e.backtrace
|
114
125
|
send_exception(msg, e)
|
115
126
|
ensure
|
116
127
|
@pending_evals.delete(id) unless stop
|
@@ -150,7 +161,7 @@ module NREPL
|
|
150
161
|
original_bind = if msg['stop_id']
|
151
162
|
@pending_evals.fetch(msg['stop_id'], {})[:binding]
|
152
163
|
elsif msg['watch_id']
|
153
|
-
@
|
164
|
+
@bindings_by_id.fetch(msg['watch_id'], {})[:binding]
|
154
165
|
else
|
155
166
|
find_row_based_binding(msg) || @binding
|
156
167
|
end
|
@@ -162,6 +173,12 @@ module NREPL
|
|
162
173
|
end
|
163
174
|
end
|
164
175
|
|
176
|
+
private def evaluate_code(code, file, line, bind)
|
177
|
+
bind ||= @@binding
|
178
|
+
line = line ? line + 1 : 1
|
179
|
+
eval(code, bind, file || "EVAL", line).inspect
|
180
|
+
end
|
181
|
+
|
165
182
|
private def find_row_based_binding(msg)
|
166
183
|
file = msg['file']
|
167
184
|
row = msg['line']
|
@@ -170,7 +187,7 @@ module NREPL
|
|
170
187
|
rows_bindings = @bindings[file]
|
171
188
|
return unless rows_bindings
|
172
189
|
found_row = row.downto(-1).find { |k| rows_bindings[k] }
|
173
|
-
rows_bindings[found_row][
|
190
|
+
rows_bindings[found_row].values[-1] if found_row
|
174
191
|
end
|
175
192
|
|
176
193
|
private def define_stop_function!(msg, method_name)
|
@@ -228,9 +245,6 @@ module NREPL
|
|
228
245
|
send_msg(response_for(msg, { 'versions' => versions }))
|
229
246
|
end
|
230
247
|
|
231
|
-
# @param [TCPSocket] client
|
232
|
-
# @param [Hash] msg
|
233
|
-
# @param [Exception] e
|
234
248
|
def send_exception(msg, e)
|
235
249
|
send_msg(response_for(msg, { 'ex' => e.message, 'status' => ['done', 'error'] }))
|
236
250
|
end
|
@@ -244,8 +258,4 @@ module NREPL
|
|
244
258
|
end
|
245
259
|
|
246
260
|
# To avoid locally binding with the NREPL::Connection module
|
247
|
-
|
248
|
-
define_method(:evaluate_code) do |code, file, line, bind|
|
249
|
-
bind ||= b
|
250
|
-
eval(code, bind, file || "EVAL", line || 0).inspect
|
251
|
-
end
|
261
|
+
NREPL::Connection.class_variable_set(:@@binding, binding)
|
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,7 +29,14 @@ 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
|
@@ -29,8 +44,12 @@ module NREPL
|
|
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)
|
33
51
|
NREPL.class_variable_set(:@@bindings, @bindings)
|
52
|
+
NREPL.class_variable_set(:@@bindings_by_id, @bindings_by_id)
|
34
53
|
end
|
35
54
|
|
36
55
|
private def record_port
|
@@ -44,31 +63,45 @@ module NREPL
|
|
44
63
|
puts "Running in debug mode" if debug?
|
45
64
|
record_port
|
46
65
|
|
66
|
+
@old_out, @old_err = $stdout, $stderr
|
47
67
|
$stdout = FakeStdout.new(@connections, STDOUT, "out")
|
48
68
|
$stderr = FakeStdout.new(@connections, STDERR, "err")
|
49
|
-
auto_create_bindings!
|
69
|
+
auto_create_bindings! if @tracing
|
50
70
|
|
51
71
|
Signal.trap("INT") { stop }
|
52
72
|
Signal.trap("TERM") { stop }
|
53
73
|
|
54
|
-
|
74
|
+
@socket = TCPServer.new(host, port)
|
55
75
|
loop do
|
56
|
-
|
57
|
-
|
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
|
+
)
|
58
85
|
@connections << connection
|
59
86
|
connection.treat_messages!
|
60
87
|
@connections.delete(connection)
|
61
88
|
end
|
62
89
|
end
|
90
|
+
rescue IOError
|
91
|
+
puts "Server closed" if debug?
|
63
92
|
ensure
|
64
93
|
File.unlink(PORT_FILENAME)
|
65
94
|
end
|
66
95
|
|
67
96
|
def auto_create_bindings!
|
68
97
|
dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
|
69
|
-
@call_trace = TracePoint.new(:call) do |tp|
|
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}
|
70
102
|
@bindings[tp.path] ||= {}
|
71
|
-
@bindings[tp.path][tp.lineno-1]
|
103
|
+
@bindings[tp.path][tp.lineno-1] ||= {}
|
104
|
+
@bindings[tp.path][tp.lineno-1][id] = b
|
72
105
|
if tp.path =~ dir_regex
|
73
106
|
@connections.each do |connection|
|
74
107
|
connection.send_msg(
|
@@ -82,16 +115,17 @@ module NREPL
|
|
82
115
|
end
|
83
116
|
@call_trace.enable
|
84
117
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
90
123
|
end
|
91
124
|
|
92
125
|
def stop
|
93
|
-
|
94
|
-
|
126
|
+
@connections = []
|
127
|
+
$stdout, $stderr = @old_out, @old_err
|
128
|
+
@socket.close
|
95
129
|
end
|
96
130
|
end
|
97
131
|
|
data/lib/nrepl-lazuli.rb
CHANGED
@@ -8,16 +8,19 @@ module NREPL
|
|
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]
|
15
|
-
file = loc.
|
16
|
+
file = loc.path
|
16
17
|
row = loc.lineno
|
17
18
|
id ||= "#{file}:#{row}"
|
18
19
|
|
20
|
+
@@bindings_by_id[id] = {binding: binding, file: file, row: loc.lineno-1}
|
19
21
|
@@bindings[file] ||= {}
|
20
|
-
@@bindings[file][loc.lineno-1]
|
22
|
+
@@bindings[file][loc.lineno-1] ||= {}
|
23
|
+
@@bindings[file][loc.lineno-1][id] = binding
|
21
24
|
|
22
25
|
@@connections.each do |connection|
|
23
26
|
connection.send_msg(
|
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.1
|
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-07-11 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
|