syntax_tree 2.9.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -2
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/lib/syntax_tree/formatter.rb +3 -1
- data/lib/syntax_tree/language_server/inlay_hints.rb +39 -37
- data/lib/syntax_tree/language_server.rb +23 -52
- data/lib/syntax_tree/parser.rb +6 -6
- data/lib/syntax_tree/version.rb +1 -1
- 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: 28783cde4387bbc7d38d9de500564804cd885733abe59e017be73ce04981a854
|
4
|
+
data.tar.gz: 6a54750102b8978df75e7f8a7d611e596067bb69863f91d5a8daa9aec8509c31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2f61f01bfa53604686798c96a53d8c98abd30145038db3b7f73f92c5c6b282447f3fe355382f6b3325b3ee98ce60ddcc5c102234b78e9c8d1fe9cbf006cb38d
|
7
|
+
data.tar.gz: e5a63e7fdc4f7e70e354a5861e42b8c0dffbbd2ffde38754c0a1fca8a6033be2deecd52ea3ec5fb7a2aa05e0d07ab93d3b4d69762ca3c911f36a6e898ef2ffaf
|
data/CHANGELOG.md
CHANGED
@@ -6,8 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [3.0.0] - 2022-07-04
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- [#102](https://github.com/ruby-syntax-tree/syntax_tree/issues/102) - Handle requests to the language server for files that do not yet exist on disk.
|
14
|
+
|
15
|
+
### Removed
|
16
|
+
|
17
|
+
- [#108](https://github.com/ruby-syntax-tree/syntax_tree/pull/108) - Remove old inlay hints code.
|
18
|
+
|
9
19
|
## [2.9.0] - 2022-07-04
|
10
20
|
|
21
|
+
### Added
|
22
|
+
|
11
23
|
- [#106](https://github.com/ruby-syntax-tree/syntax_tree/pull/106) - Add inlay hint support to match the LSP specification.
|
12
24
|
|
13
25
|
## [2.8.0] - 2022-06-21
|
@@ -276,8 +288,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
276
288
|
|
277
289
|
- 🎉 Initial release! 🎉
|
278
290
|
|
279
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.
|
280
|
-
[2.
|
291
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.9.0...HEAD
|
292
|
+
[2.9.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.8.0...v2.9.0
|
281
293
|
[2.8.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.7.1...v2.8.0
|
282
294
|
[2.7.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.7.0...v2.7.1
|
283
295
|
[2.7.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.6.0...v2.7.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -35,7 +35,7 @@ It is built with only standard library dependencies. It additionally ships with
|
|
35
35
|
- [BasicVisitor](#basicvisitor)
|
36
36
|
- [Language server](#language-server)
|
37
37
|
- [textDocument/formatting](#textdocumentformatting)
|
38
|
-
- [textDocument/
|
38
|
+
- [textDocument/inlayHint](#textdocumentinlayhint)
|
39
39
|
- [syntaxTree/visualizing](#syntaxtreevisualizing)
|
40
40
|
- [Plugins](#plugins)
|
41
41
|
- [Configuration](#configuration)
|
@@ -402,7 +402,7 @@ By default, the language server is relatively minimal, mostly meant to provide a
|
|
402
402
|
|
403
403
|
As mentioned above, the language server responds to formatting requests with the formatted document. It typically responds on the order of tens of milliseconds, so it should be fast enough for any IDE.
|
404
404
|
|
405
|
-
### textDocument/
|
405
|
+
### textDocument/inlayHint
|
406
406
|
|
407
407
|
The language server also responds to the relatively new inlay hints request. This request allows the language server to define additional information that should exist in the source code as helpful hints to the developer. In our case we use it to display things like implicit parentheses. For example, if you had the following code:
|
408
408
|
|
@@ -410,7 +410,7 @@ The language server also responds to the relatively new inlay hints request. Thi
|
|
410
410
|
1 + 2 * 3
|
411
411
|
```
|
412
412
|
|
413
|
-
Implicity, the `2 * 3` is going to be executed first because the `*` operator has higher precedence than the `+` operator.
|
413
|
+
Implicity, the `2 * 3` is going to be executed first because the `*` operator has higher precedence than the `+` operator. To ease mental overhead, our language server includes small parentheses to make this explicit, as in:
|
414
414
|
|
415
415
|
```ruby
|
416
416
|
1 + ₍2 * 3₎
|
@@ -68,7 +68,9 @@ module SyntaxTree
|
|
68
68
|
# going to just print out the node as it was seen in the source.
|
69
69
|
doc =
|
70
70
|
if leading.last&.ignore?
|
71
|
-
|
71
|
+
range = source[node.location.start_char...node.location.end_char]
|
72
|
+
separator = -> { breakable(indent: false, force: true) }
|
73
|
+
seplist(range.split(/\r?\n/, -1), separator) { |line| text(line) }
|
72
74
|
else
|
73
75
|
node.format(self)
|
74
76
|
end
|
@@ -2,21 +2,37 @@
|
|
2
2
|
|
3
3
|
module SyntaxTree
|
4
4
|
class LanguageServer
|
5
|
-
# This class provides inlay hints for the language server.
|
6
|
-
#
|
7
|
-
# aligned with the spec (`#all`) and proprietary (`#before` and `#after`).
|
8
|
-
#
|
9
|
-
# For more information, see the spec here:
|
5
|
+
# This class provides inlay hints for the language server. For more
|
6
|
+
# information, see the spec here:
|
10
7
|
# https://github.com/microsoft/language-server-protocol/issues/956.
|
11
|
-
#
|
12
8
|
class InlayHints < Visitor
|
13
|
-
|
9
|
+
# This represents a hint that is going to be displayed in the editor.
|
10
|
+
class Hint
|
11
|
+
attr_reader :line, :character, :label
|
12
|
+
|
13
|
+
def initialize(line:, character:, label:)
|
14
|
+
@line = line
|
15
|
+
@character = character
|
16
|
+
@label = label
|
17
|
+
end
|
18
|
+
|
19
|
+
# This is the shape that the LSP expects.
|
20
|
+
def to_json(*opts)
|
21
|
+
{
|
22
|
+
position: {
|
23
|
+
line: line,
|
24
|
+
character: character
|
25
|
+
},
|
26
|
+
label: label
|
27
|
+
}.to_json(*opts)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :stack, :hints
|
14
32
|
|
15
33
|
def initialize
|
16
34
|
@stack = []
|
17
|
-
@
|
18
|
-
@before = Hash.new { |hash, key| hash[key] = +"" }
|
19
|
-
@after = Hash.new { |hash, key| hash[key] = +"" }
|
35
|
+
@hints = []
|
20
36
|
end
|
21
37
|
|
22
38
|
def visit(node)
|
@@ -98,14 +114,11 @@ module SyntaxTree
|
|
98
114
|
#
|
99
115
|
def visit_rescue(node)
|
100
116
|
if node.exception.nil?
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
line: node.location.start_line - 1,
|
105
|
-
character: node.location.start_column + "rescue".length
|
106
|
-
},
|
117
|
+
hints << Hint.new(
|
118
|
+
line: node.location.start_line - 1,
|
119
|
+
character: node.location.start_column + "rescue".length,
|
107
120
|
label: " StandardError"
|
108
|
-
|
121
|
+
)
|
109
122
|
end
|
110
123
|
|
111
124
|
super
|
@@ -128,31 +141,20 @@ module SyntaxTree
|
|
128
141
|
super
|
129
142
|
end
|
130
143
|
|
131
|
-
def self.find(program)
|
132
|
-
visitor = new
|
133
|
-
visitor.visit(program)
|
134
|
-
visitor
|
135
|
-
end
|
136
|
-
|
137
144
|
private
|
138
145
|
|
139
146
|
def parentheses(location)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
character: location.start_column
|
144
|
-
},
|
147
|
+
hints << Hint.new(
|
148
|
+
line: location.start_line - 1,
|
149
|
+
character: location.start_column,
|
145
150
|
label: "₍"
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
},
|
151
|
+
)
|
152
|
+
|
153
|
+
hints << Hint.new(
|
154
|
+
line: location.end_line - 1,
|
155
|
+
character: location.end_column,
|
152
156
|
label: "₎"
|
153
|
-
|
154
|
-
before[location.start_char] << "₍"
|
155
|
-
after[location.end_char] << "₎"
|
157
|
+
)
|
156
158
|
end
|
157
159
|
end
|
158
160
|
end
|
@@ -20,73 +20,51 @@ module SyntaxTree
|
|
20
20
|
@output = output.binmode
|
21
21
|
end
|
22
22
|
|
23
|
+
# rubocop:disable Layout/LineLength
|
23
24
|
def run
|
24
25
|
store =
|
25
26
|
Hash.new do |hash, uri|
|
26
|
-
|
27
|
+
filepath = CGI.unescape(URI.parse(uri).path)
|
28
|
+
File.exist?(filepath) ? (hash[uri] = File.read(filepath)) : nil
|
27
29
|
end
|
28
30
|
|
29
31
|
while (headers = input.gets("\r\n\r\n"))
|
30
32
|
source = input.read(headers[/Content-Length: (\d+)/i, 1].to_i)
|
31
33
|
request = JSON.parse(source, symbolize_names: true)
|
32
34
|
|
35
|
+
# stree-ignore
|
33
36
|
case request
|
34
37
|
in { method: "initialize", id: }
|
35
38
|
store.clear
|
36
39
|
write(id: id, result: { capabilities: capabilities })
|
37
|
-
in method: "initialized"
|
40
|
+
in { method: "initialized" }
|
38
41
|
# ignored
|
39
|
-
in method: "shutdown" # tolerate missing ID to be a good citizen
|
42
|
+
in { method: "shutdown" } # tolerate missing ID to be a good citizen
|
40
43
|
store.clear
|
41
44
|
write(id: request[:id], result: {})
|
42
45
|
return
|
43
|
-
in {
|
44
|
-
method: "textDocument/didChange",
|
45
|
-
params: { textDocument: { uri: }, contentChanges: [{ text: }, *] }
|
46
|
-
}
|
46
|
+
in { method: "textDocument/didChange", params: { textDocument: { uri: }, contentChanges: [{ text: }, *] } }
|
47
47
|
store[uri] = text
|
48
|
-
in {
|
49
|
-
method: "textDocument/didOpen",
|
50
|
-
params: { textDocument: { uri:, text: } }
|
51
|
-
}
|
48
|
+
in { method: "textDocument/didOpen", params: { textDocument: { uri:, text: } } }
|
52
49
|
store[uri] = text
|
53
|
-
in {
|
54
|
-
method: "textDocument/didClose", params: { textDocument: { uri: } }
|
55
|
-
}
|
50
|
+
in { method: "textDocument/didClose", params: { textDocument: { uri: } } }
|
56
51
|
store.delete(uri)
|
57
|
-
in {
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
write(id: id, result:
|
63
|
-
in {
|
64
|
-
# official RPC in LSP spec 3.17
|
65
|
-
method: "textDocument/inlayHint",
|
66
|
-
id:,
|
67
|
-
params: { textDocument: { uri: } }
|
68
|
-
}
|
69
|
-
write(id: id, result: inlay_hints(store[uri], false))
|
70
|
-
in {
|
71
|
-
# proprietary RPC (deprecated) between this gem and vscode-syntax-tree
|
72
|
-
method: "textDocument/inlayHints",
|
73
|
-
id:,
|
74
|
-
params: { textDocument: { uri: } }
|
75
|
-
}
|
76
|
-
write(id: id, result: inlay_hints(store[uri], true))
|
77
|
-
in {
|
78
|
-
method: "syntaxTree/visualizing",
|
79
|
-
id:,
|
80
|
-
params: { textDocument: { uri: } }
|
81
|
-
}
|
52
|
+
in { method: "textDocument/formatting", id:, params: { textDocument: { uri: } } }
|
53
|
+
contents = store[uri]
|
54
|
+
write(id: id, result: contents ? [format(store[uri])] : nil)
|
55
|
+
in { method: "textDocument/inlayHint", id:, params: { textDocument: { uri: } } }
|
56
|
+
contents = store[uri]
|
57
|
+
write(id: id, result: contents ? inlay_hints(store[uri]) : nil)
|
58
|
+
in { method: "syntaxTree/visualizing", id:, params: { textDocument: { uri: } } }
|
82
59
|
write(id: id, result: PP.pp(SyntaxTree.parse(store[uri]), +""))
|
83
|
-
in method: %r{\$/.+}
|
60
|
+
in { method: %r{\$/.+} }
|
84
61
|
# ignored
|
85
62
|
else
|
86
63
|
raise ArgumentError, "Unhandled: #{request}"
|
87
64
|
end
|
88
65
|
end
|
89
66
|
end
|
67
|
+
# rubocop:enable Layout/LineLength
|
90
68
|
|
91
69
|
private
|
92
70
|
|
@@ -119,21 +97,14 @@ module SyntaxTree
|
|
119
97
|
}
|
120
98
|
end
|
121
99
|
|
122
|
-
def inlay_hints(source
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
if proprietary
|
127
|
-
{
|
128
|
-
before: inlay_hints.before.map(&serialize),
|
129
|
-
after: inlay_hints.after.map(&serialize)
|
130
|
-
}
|
131
|
-
else
|
132
|
-
inlay_hints.all
|
133
|
-
end
|
100
|
+
def inlay_hints(source)
|
101
|
+
visitor = InlayHints.new
|
102
|
+
SyntaxTree.parse(source).accept(visitor)
|
103
|
+
visitor.hints
|
134
104
|
rescue Parser::ParseError
|
135
105
|
# If there is a parse error, then we're not going to return any inlay
|
136
106
|
# hints for this source.
|
107
|
+
[]
|
137
108
|
end
|
138
109
|
|
139
110
|
def write(value)
|
data/lib/syntax_tree/parser.rb
CHANGED
@@ -1641,12 +1641,12 @@ module SyntaxTree
|
|
1641
1641
|
heredoc = @heredocs[-1]
|
1642
1642
|
|
1643
1643
|
location =
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1644
|
+
Location.token(
|
1645
|
+
line: lineno,
|
1646
|
+
char: char_pos,
|
1647
|
+
column: current_column,
|
1648
|
+
size: value.size + 1
|
1649
|
+
)
|
1650
1650
|
|
1651
1651
|
heredoc_end = HeredocEnd.new(value: value.chomp, location: location)
|
1652
1652
|
|
data/lib/syntax_tree/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Newton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
11
|
+
date: 2022-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prettier_print
|
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
- !ruby/object:Gem::Version
|
161
161
|
version: '0'
|
162
162
|
requirements: []
|
163
|
-
rubygems_version: 3.
|
163
|
+
rubygems_version: 3.3.3
|
164
164
|
signing_key:
|
165
165
|
specification_version: 4
|
166
166
|
summary: A parser based on ripper
|