nrepl-lazuli 0.1.3 → 0.2.1

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: 3afa60bfeead6c887e8af4a6d6beb2e24e50b58984855794601d1c25cd0ba703
4
- data.tar.gz: 9a7001c799e5a0aa1d68899ed6c2e06698b2097f7d7518da515938aa9cb2ba95
3
+ metadata.gz: f4f4fa0597b301ec633b7a332a60a86ec773239fc9c199096249459c7567c0b1
4
+ data.tar.gz: ec2ce7297bd7351c1be0095af5e157b88c70a8f8ce434ea3e046cd3b97e8d1aa
5
5
  SHA512:
6
- metadata.gz: 9c60a0b98f239ee46b90400dd6a621d5ada13ef4da208c11749605fe528c1e4b1075b3e774aa6f487d8cee7b31e600a6ed410a46522764b04f638166a21ef548
7
- data.tar.gz: f34c1bc6932245fece695740be5f2211563161f7c3c4667748a0e152cb43dfaa78dd08a3dbbf57dfb2e363b6a1ad3ee44f9864eabbaba68f0e3a9b3939820900
6
+ metadata.gz: b813283650b6ef0a56d0e8a6372f5a5ffea33235322d62ddc1204cc0f696de4912be861752dac02f859ce4592f9c4c84e89c03b9050597c357f222bbe82dbf14
7
+ data.tar.gz: 5354de88865cded64e7aa9f22b1bebf43fae21d396bfe9cd212a7859d35eccb6a246b3ad273f4d08679fb485d56b75b383986ddb7c494c9a92869c5606d755bb
@@ -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, *args)
25
- @io.send(method, *args)
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
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # A Ruby port of ogion https://gitlab.com/technomancy/ogion &
4
+ # https://github.com/borkdude/nrepl-server/blob/master/src/borkdude/nrepl_server.clj
5
+
6
+ require 'bencode'
7
+ require 'socket'
8
+ require_relative 'connection'
9
+ require_relative 'fake_stdout'
10
+
11
+ module NREPL
12
+ class Server
13
+ attr_reader :debug, :port, :host
14
+ alias debug? debug
15
+
16
+ def self.start(**kwargs)
17
+ new(**kwargs).start
18
+ end
19
+
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)
25
+ @port = port
26
+ @pwd = pwd
27
+ @host = host
28
+ @debug = debug
29
+ @connections = Set.new
30
+ @binding = binding
31
+ @auto_bindings = {}
32
+ NREPL.class_variable_set(:@@connections, @connections)
33
+ end
34
+
35
+ private def record_port
36
+ File.open(PORT_FILENAME, 'w+') do |f|
37
+ f.write(port)
38
+ end
39
+ end
40
+
41
+ def start
42
+ puts "nREPL server started on port #{port} on host #{host} - nrepl://#{host}:#{port}"
43
+ puts "Running in debug mode" if debug?
44
+ record_port
45
+
46
+ $stdout = FakeStdout.new(@connections, STDOUT, "out")
47
+ $stderr = FakeStdout.new(@connections, STDERR, "err")
48
+ auto_create_bindings!
49
+
50
+ Signal.trap("INT") { stop }
51
+ Signal.trap("TERM") { stop }
52
+
53
+ s = TCPServer.new(host, port)
54
+ loop do
55
+ Thread.start(s.accept) do |client|
56
+ connection = Connection.new(client, debug: debug?, binding: @binding, auto_bindings: @auto_bindings)
57
+ @connections << connection
58
+ connection.treat_messages!
59
+ @connections.delete(connection)
60
+ end
61
+ end
62
+ ensure
63
+ File.unlink(PORT_FILENAME)
64
+ end
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
+
86
+ def stop
87
+ Thread.exit
88
+ exit(0)
89
+ end
90
+ end
91
+
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
111
+ end
112
+
113
+ module DefinitionFixer
114
+ @@definitions = {}
115
+
116
+ def __lazuli_source_location(method)
117
+ final_loc = nil
118
+ loc = ancestors.each do |klass|
119
+ loc = (klass.instance_variable_get(:@__lazuli_methods) || {})[method]
120
+ if loc
121
+ final_loc = loc
122
+ break
123
+ end
124
+ end
125
+
126
+ if(final_loc && File.exist?(final_loc[0]))
127
+ final_loc
128
+ else
129
+ instance_method(method).source_location
130
+ end
131
+ end
132
+
133
+ def method_added(method_name)
134
+ return if method_name == :__lazuli_source_location
135
+ path = caller.reject { |x| x =~ /gems.*gems/ }[0]
136
+ if path
137
+ (file, row) = path.split(/:/)
138
+
139
+ known = instance_variable_get(:@__lazuli_methods)
140
+ if !known
141
+ known = {}
142
+ instance_variable_set(:@__lazuli_methods, known)
143
+ end
144
+ known[method_name] = [file, row.to_i]
145
+ end
146
+ end
147
+
148
+ Module.prepend(DefinitionFixer)
149
+ end
150
+ end
@@ -6,7 +6,7 @@ module NREPL
6
6
  DEFAULT_HOST = '127.0.0.1'
7
7
  PORT_FILENAME = '.nrepl-port'
8
8
 
9
- require_relative 'nrepl/server'
9
+ require_relative 'nrepl-lazuli/server'
10
10
  @@watches = {}
11
11
  @@connections = Set.new
12
12
 
@@ -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.3
4
+ version: 0.2.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-03-22 00:00:00.000000000 Z
11
+ date: 2024-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bencode
@@ -31,11 +31,11 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - lib/nrepl.rb
35
- - lib/nrepl/connection.rb
36
- - lib/nrepl/fake_stdout.rb
37
- - lib/nrepl/server.rb
38
- homepage: https://rubygems.org/gems/nrepl-lazuli
34
+ - lib/nrepl-lazuli.rb
35
+ - lib/nrepl-lazuli/connection.rb
36
+ - lib/nrepl-lazuli/fake_stdout.rb
37
+ - lib/nrepl-lazuli/server.rb
38
+ homepage: https://gitlab.com/clj-editors/nrepl-lazuli
39
39
  licenses:
40
40
  - MIT
41
41
  metadata: {}
data/lib/nrepl/server.rb DELETED
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # A Ruby port of ogion https://gitlab.com/technomancy/ogion &
4
- # https://github.com/borkdude/nrepl-server/blob/master/src/borkdude/nrepl_server.clj
5
-
6
- require 'bencode'
7
- require 'socket'
8
- require_relative 'connection'
9
- require_relative 'fake_stdout'
10
-
11
- module NREPL
12
- class Server
13
- attr_reader :debug, :port, :host
14
- alias debug? debug
15
-
16
- def self.start(**kwargs)
17
- new(**kwargs).start
18
- end
19
-
20
- def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false)
21
- @port = port
22
- @host = host
23
- @debug = debug
24
- @connections = Set.new
25
- NREPL.class_variable_set(:@@connections, @connections)
26
- end
27
-
28
- private def record_port
29
- File.open(PORT_FILENAME, 'w+') do |f|
30
- f.write(port)
31
- end
32
- end
33
-
34
- def start
35
- puts "nREPL server started on port #{port} on host #{host} - nrepl://#{host}:#{port}"
36
- puts "Running in debug mode" if debug?
37
- record_port
38
-
39
- $stdout = FakeStdout.new(@connections, STDOUT, "out")
40
- $stderr = FakeStdout.new(@connections, STDERR, "err")
41
-
42
- Signal.trap("INT") { stop }
43
- Signal.trap("TERM") { stop }
44
-
45
- s = TCPServer.new(host, port)
46
- loop do
47
- Thread.start(s.accept) do |client|
48
- connection = Connection.new(client, debug: debug?)
49
- @connections << connection
50
- connection.treat_messages!
51
- @connections.delete(connection)
52
- end
53
- end
54
- ensure
55
- File.unlink(PORT_FILENAME)
56
- end
57
-
58
- def stop
59
- Thread.exit
60
- exit(0)
61
- end
62
- end
63
- end
64
-
65
- # Sorry, no other way...
66
- module ThreadPatch
67
- def initialize(*args, &b)
68
- @parent = Thread.current
69
- super
70
- end
71
-
72
- def parent
73
- @parent
74
- end
75
- end
76
-
77
- Thread.prepend(ThreadPatch)