nrepl-lazuli 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9806d1a707607c97f52c191fe34e6027fd58740ada2692d5f998e5d81e9e2e2
4
- data.tar.gz: fbaa80613144afaa7cd5c0d56db8d0655819008895fc10a59904a1980dae033c
3
+ metadata.gz: 2deef62506da60f639206583fc37504630c3fdefcab9013a1ef25b354f51221c
4
+ data.tar.gz: 8374c37e1eae4d69479137163f10242ea0f287c9ffd099830b1d3d361b6c344c
5
5
  SHA512:
6
- metadata.gz: fa9bbcfed7f0fb97e91805297589ab1341553d82372caf318e1118332bf1e74e4e39898cce008af093f10e2678f75505d82e4502c8b42f887ef6d75823f0cf36
7
- data.tar.gz: 1fc41134491cd81daa30bf1148c9c1ce09644922d4342e4745cc48b56ab009be68784874d0e6ef34d946ae43dd90b237d7910bf60c4198fb125860987d196cc5
6
+ metadata.gz: c81e136417a9d6dac29f007a2539011baebc83d6975f1715eaa3f6f0799b4e63d4484bf834e729c0b53f65b0dcff09c917443f41c1f50edb1104cf3efb740390
7
+ data.tar.gz: a6293282dc353c2cfa998fd557a1c84a7482224009ea905f08f82c3615e38e64b4507f5927630be9f6e4e7a2d6a00a05d02e735f59b357249ccab0d7840e4a6c
@@ -2,13 +2,19 @@ module NREPL
2
2
  class Connection
3
3
  @@debug_counter = 0
4
4
 
5
- def initialize(input, debug: false, out: input, watches: NREPL.class_variable_get(:@@watches))
5
+ def initialize(
6
+ input, debug: false, out: input,
7
+ watches: NREPL.class_variable_get(:@@watches), binding: nil,
8
+ auto_bindings: {}
9
+ )
6
10
  @debug = debug
7
11
  @in = input
8
12
  @out = out
9
13
  @pending_evals = {}
10
14
  @watches = watches
11
15
  @counter = 0
16
+ @binding = binding
17
+ @auto_bindings = auto_bindings
12
18
  end
13
19
 
14
20
  def treat_messages!
@@ -75,7 +81,15 @@ module NREPL
75
81
  'op' => msg['op']
76
82
  }))
77
83
  end
78
-
84
+ when 'watches_for_file'
85
+ msg['id'] ||= "eval_#{@counter += 1}"
86
+ file = msg['file']
87
+ rows_bindings = @auto_bindings[file] || {}
88
+ send_msg(response_for(msg, {
89
+ 'status' => ['done'],
90
+ 'rows' => rows_bindings.keys.sort,
91
+ 'op' => msg['op']
92
+ }))
79
93
  else
80
94
  send_msg(response_for(msg, {
81
95
  'op' => msg['op'],
@@ -135,6 +149,8 @@ module NREPL
135
149
  @pending_evals.fetch(msg['stop_id'], {})[:binding]
136
150
  elsif msg['watch_id']
137
151
  @watches.fetch(msg['watch_id'], {})[:binding]
152
+ else
153
+ find_row_based_binding(msg) || @binding
138
154
  end
139
155
  evaluate_code(code, msg['file'], msg['line'], original_bind)
140
156
  end
@@ -144,6 +160,17 @@ module NREPL
144
160
  end
145
161
  end
146
162
 
163
+ private def find_row_based_binding(msg)
164
+ file = msg['file']
165
+ row = msg['line']
166
+ return if !file || !row
167
+
168
+ rows_bindings = @auto_bindings[file]
169
+ return unless rows_bindings
170
+ found_row = row.downto(-1).find { |k| rows_bindings[k] }
171
+ rows_bindings[found_row]
172
+ end
173
+
147
174
  private def define_stop_function!(msg, method_name)
148
175
  out, inp = IO.pipe
149
176
  send_stopped = proc do |ctx_binding, original_msg, caller|
@@ -1,9 +1,12 @@
1
+ require "delegate"
2
+
1
3
  module NREPL
2
- class FakeStdout
4
+ class FakeStdout < SimpleDelegator
3
5
  def initialize(connections, io, kind)
4
6
  @connections = connections
5
7
  @io = io
6
8
  @kind = kind
9
+ super(io)
7
10
  end
8
11
 
9
12
  def <<(text)
@@ -21,33 +24,13 @@ module NREPL
21
24
  nil
22
25
  end
23
26
 
24
- def method_missing(method, *)
25
- @io.send(method, *)
26
- end
27
-
28
27
  def write(text)
29
- @io.write(text)
30
28
  @connections.each do |conn|
31
29
  conn.send_msg(
32
30
  @kind => text
33
31
  )
34
32
  end
35
- end
36
-
37
- def flush
38
- @io.flush
39
- end
40
-
41
- def close
42
- @io.close
43
- end
44
-
45
- def sync
46
- @io.sync
47
- end
48
-
49
- def sync=(val)
50
- @io.sync = val
33
+ @io.write(text)
51
34
  end
52
35
  end
53
36
  end
data/lib/nrepl/server.rb CHANGED
@@ -17,11 +17,18 @@ module NREPL
17
17
  new(**kwargs).start
18
18
  end
19
19
 
20
- def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false)
20
+ def self.bind!(binding, **kwargs)
21
+ new(**kwargs.merge(binding: binding)).start
22
+ end
23
+
24
+ def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false, binding: nil, pwd: Dir.pwd)
21
25
  @port = port
26
+ @pwd = pwd
22
27
  @host = host
23
28
  @debug = debug
24
29
  @connections = Set.new
30
+ @binding = binding
31
+ @auto_bindings = {}
25
32
  NREPL.class_variable_set(:@@connections, @connections)
26
33
  end
27
34
 
@@ -38,6 +45,7 @@ module NREPL
38
45
 
39
46
  $stdout = FakeStdout.new(@connections, STDOUT, "out")
40
47
  $stderr = FakeStdout.new(@connections, STDERR, "err")
48
+ auto_create_bindings!
41
49
 
42
50
  Signal.trap("INT") { stop }
43
51
  Signal.trap("TERM") { stop }
@@ -45,7 +53,7 @@ module NREPL
45
53
  s = TCPServer.new(host, port)
46
54
  loop do
47
55
  Thread.start(s.accept) do |client|
48
- connection = Connection.new(client, debug: debug?)
56
+ connection = Connection.new(client, debug: debug?, binding: @binding, auto_bindings: @auto_bindings)
49
57
  @connections << connection
50
58
  connection.treat_messages!
51
59
  @connections.delete(connection)
@@ -55,23 +63,80 @@ module NREPL
55
63
  File.unlink(PORT_FILENAME)
56
64
  end
57
65
 
66
+ def auto_create_bindings!
67
+ dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
68
+ @call_trace = TracePoint.new(:call) do |tp|
69
+ @auto_bindings[tp.path] ||= {}
70
+ @auto_bindings[tp.path][tp.lineno-1] = tp.binding
71
+ if tp.path =~ dir_regex
72
+ # puts "Tracing #{tp.path}:#{tp.lineno}"
73
+ @connections.each do |connection|
74
+ connection.send_msg(
75
+ 'op' => 'hit_auto_watch',
76
+ 'file' => tp.path,
77
+ 'line' => tp.lineno-1,
78
+ 'status' => ['done']
79
+ )
80
+ end
81
+ end
82
+ end
83
+ @call_trace.enable
84
+ end
85
+
58
86
  def stop
59
87
  Thread.exit
60
88
  exit(0)
61
89
  end
62
90
  end
63
- end
64
91
 
65
- # Sorry, no other way...
66
- module ThreadPatch
67
- def initialize(*args, &b)
68
- @parent = Thread.current
69
- super
92
+ # Sorry, no other way...
93
+ module ThreadPatch
94
+ def initialize(*args, &b)
95
+ @parent = Thread.current
96
+ super
97
+ end
98
+
99
+ def parent
100
+ @parent
101
+ end
102
+ end
103
+
104
+ Thread.prepend(ThreadPatch)
105
+
106
+ # Also...
107
+ module MethodLocationFixer
108
+ def __lazuli_source_location
109
+ @__lazuli_source_location || source_location
110
+ end
70
111
  end
71
112
 
72
- def parent
73
- @parent
113
+ module DefinitionFixer
114
+ @@definitions = {}
115
+
116
+ def __lazuli_source_location(method)
117
+ ancestors.each do |klass|
118
+ loc = (klass.instance_variable_get(:@__lazuli_methods) || {})[method]
119
+ return loc if loc
120
+ end
121
+ return instance_method(method).source_location
122
+ end
123
+
124
+ def method_added(method_name)
125
+ return if method_name == :__lazuli_source_location
126
+ # puts "Thing added #{method_name}"
127
+ path = caller.reject { |x| x =~ /gems.*gems/ }[0]
128
+ if path
129
+ (file, row) = path.split(/:/)
130
+
131
+ known = instance_variable_get(:@__lazuli_methods)
132
+ if !known
133
+ known = {}
134
+ instance_variable_set(:@__lazuli_methods, known)
135
+ end
136
+ known[method_name] = [file, row.to_i]
137
+ end
138
+ end
139
+
140
+ Module.prepend(DefinitionFixer)
74
141
  end
75
142
  end
76
-
77
- Thread.prepend(ThreadPatch)
data/lib/nrepl.rb CHANGED
@@ -25,5 +25,6 @@ module NREPL
25
25
  'status' => ['done']
26
26
  )
27
27
  end
28
+ nil
28
29
  end
29
30
  end
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.1.2
4
+ version: 0.2.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-03-22 00:00:00.000000000 Z
11
+ date: 2024-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bencode