lsp_router 0.1.1 → 0.1.3

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: c3ba53e8db9e41cea66c0d4f935517fe4f3e4e8e24a6173794e53ea409556847
4
- data.tar.gz: 984ea810f99d29a70efbb798b76c5d9f161b5bb5433ab0b96c52ed015529699c
3
+ metadata.gz: 5b81686d10b1edcb9c6b6ab51eedd3f8bd4ca71c3bd3d44b820fd416f2a48f0e
4
+ data.tar.gz: 85e81047822d36218ac021ccccb240af5fdc896dcb0218a8c835f613343dea1a
5
5
  SHA512:
6
- metadata.gz: 40903c06994c73209c64535f12b417c913e59db4a7b856eae9504aac1e86102a273656e6f3a4148b3fa54e8c862855cd846e5e29d00f457b6a8e691b727ee919
7
- data.tar.gz: bde44dd17b4288879bf96dee727320241ebf143d13e4e5ee8fadbf562223db6a0c5214c584847369a6ff97f20b2048192dc2faaea076fbfc7f213b68b479818c
6
+ metadata.gz: 289f4683fc2aead84ac11c7655b1faeb142f3692d26af1683d62181a3fb6ea7ac345f016e1e27946c5229dd755c9e49afed0ef4d00b5b28a481e42b6763dc933
7
+ data.tar.gz: c1e65b91db8a71ba1ebfacd134dc2b3a133d569a7ae67346fcc7a004502a4eff1fba2924d755f9f14420f3ff6369e89bb36f60a60a01f014f5249aba160f7e02
data/README.md CHANGED
@@ -17,7 +17,7 @@ logfile '/tmp/lsp_router'
17
17
  loglevel :info
18
18
 
19
19
  server :rubocop do
20
- command 'rubocop-lsp'
20
+ command 'rubocop --lsp'
21
21
  mode :stdio
22
22
  end
23
23
 
@@ -27,7 +27,7 @@ server :solargraph do
27
27
  end
28
28
  ```
29
29
 
30
- この例では、`rubocop-lsp` と `solargraph stdio` を起動して、クライアントからの処理を振り分ける。
30
+ この例では、`rubocop --lsp` と `solargraph stdio` を起動して、クライアントからの処理を振り分ける。
31
31
  最初に各サーバーの capabilities を確認して、各サーバーにどの機能があるかを確認し、クライアントからの REQUEST は対応しているサーバーに渡す。複数のサーバーが同じ機能を持っていれば上に書いたサーバーが優先される。NOTIFICATION は全サーバーに渡す。
32
32
 
33
33
  ## Example
@@ -37,3 +37,7 @@ Emacs の Eglot の場合はこんな感じに設定するといいっぽい。
37
37
  ```
38
38
  (add-to-list 'eglot-server-programs '((ruby-mode ruby-ts-mode) . ("lsp_router" "--error=lsp_router.err" "lsp_router.conf")))
39
39
  ```
40
+
41
+ ## License
42
+
43
+ GPLv3
@@ -16,6 +16,7 @@ class LspRouter
16
16
  @command = server.attr[:command]
17
17
  @stdin, @stdout, @stderr = Open3.popen3(@command)
18
18
  @capabilities = {}
19
+ @terminated = false
19
20
  end
20
21
 
21
22
  # @param req [Hash]
@@ -31,6 +32,7 @@ class LspRouter
31
32
 
32
33
  # @param data [Hash]
33
34
  def write(data)
35
+ return if @terminated
34
36
  log("#{name}<", data)
35
37
  json = data.to_json
36
38
  @stdin.puts "Content-Length: #{json.bytesize}\r\n\r\n"
@@ -40,8 +42,12 @@ class LspRouter
40
42
 
41
43
  # @return [Hash]
42
44
  def read
45
+ return nil if @terminated
43
46
  header = @stdout.gets("\r\n\r\n")
44
- return unless header
47
+ unless header
48
+ @terminated = true
49
+ return nil
50
+ end
45
51
  fields = header.lines.map do |line|
46
52
  n, v = line.chomp.split(/: */, 2)
47
53
  [n.downcase, v] if n
@@ -1,3 +1,3 @@
1
1
  class LspRouter
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.3'
3
3
  end
data/lib/lsp_router.rb CHANGED
@@ -42,13 +42,21 @@ class LspRouter
42
42
  end
43
43
 
44
44
  def loop
45
- req = @client.read
46
- servers = @config.servers.map{LspRouter::ServerSide.new(_1, logger: @logger)}
47
- primary = servers.first
45
+ @servers = @config.servers.map{LspRouter::ServerSide.new(_1, logger: @logger)}
46
+ @primary = @servers.first
47
+ @server_map = @servers.map.to_h{[_1.name.to_s, _1]}
48
+ @capa_server = {}
49
+
50
+ initial_packet
51
+ threads = server_loop
52
+ threads.push client_loop
53
+ threads.each(&:join)
54
+ end
48
55
 
56
+ def initial_packet
57
+ req = @client.read
49
58
  res = nil
50
- capa_server = {}
51
- servers.each do |server|
59
+ @servers.each do |server|
52
60
  data = server.init(req)
53
61
  if res
54
62
  res['result']['capabilities'].update(data.dig('result', 'capabilities')){|_, v, _| v}
@@ -56,40 +64,58 @@ class LspRouter
56
64
  res = data
57
65
  end
58
66
  server.capabilities.each_key do |key|
59
- capa_server[key] ||= server
67
+ @capa_server[key] ||= server
60
68
  end
61
69
  end
62
70
  @client.write(res)
71
+ end
63
72
 
64
- thr = Thread.new do
73
+ def client_loop
74
+ Thread.new do
65
75
  Thread.abort_on_exception = true
66
76
  while true
67
77
  data = @client.read
68
78
  break unless data
69
- if data['id']
70
- # request
79
+ if data['method'] == 'shutdown' || data['method'] == 'exit'
80
+ @servers.each{_1.write(data)}
81
+ break if data['method'] == 'exit'
82
+ next
83
+ end
84
+ if data['id'] # request or response
71
85
  method = data['method']&.split('/')&.last
72
- server = capa_server[method] || primary
73
- server.write(data)
74
- else
75
- # notification
76
- servers.each do |server|
77
- server.write(data)
86
+ if data['method'] # request
87
+ server = @capa_server[method] || @primary
88
+ data['id'] = [server.name, data['id']].to_json
89
+ else # response
90
+ server_name, id = JSON.parse(data['id'])
91
+ data['id'] = id
92
+ server = @server_map[server_name]
78
93
  end
94
+ server.write(data)
95
+ else # notification
96
+ @servers.each{_1.write(data)}
79
97
  end
80
98
  end
99
+ @logger.info "client: end"
81
100
  end
101
+ end
82
102
 
83
- servers.each do |server|
103
+ def server_loop
104
+ @servers.map do |server|
84
105
  Thread.new do
85
106
  Thread.abort_on_exception = true
86
107
  while true
87
108
  data = server.read
88
109
  break unless data
110
+ if data['id'] && data['method'] # request
111
+ data['id'] = [server.name, data['id']].to_json
112
+ elsif data['id'] # response
113
+ data['id'] = JSON.parse(data['id']).last rescue data['id']
114
+ end
89
115
  @client.write(data)
90
116
  end
117
+ @logger.info "server: [#{server.name}] end"
91
118
  end
92
119
  end
93
- thr.join
94
120
  end
95
121
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lsp_router
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOMITA Masahiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-20 00:00:00.000000000 Z
11
+ date: 2023-12-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: routing multiple LSP server by capability
14
14
  email: