syntax_tree 2.9.0 → 3.1.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 +29 -2
- data/Gemfile.lock +2 -2
- data/README.md +21 -3
- data/lib/syntax_tree/cli.rb +99 -58
- 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
- data/lib/syntax_tree.rb +6 -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: 3364d1c9d427dd3e40d76f2598569399f3099870f247e1fc740d0d5c06d72e36
|
4
|
+
data.tar.gz: 24272efb6a8272b32446a3865425ed74cbb223a64798611012732c102321dfd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b824e69bf60fbf5c0d4a77cb4981243913cdfd22b09bcfd88c0bdd758b92be9d89462cf106b1bce3098e777b811aa87bc076dc0eac3369f33009719381290135
|
7
|
+
data.tar.gz: 9a5dad257dd35c7a45fbef150c189e01823595ec079df9e09aafe70347a0e41278d9cca3cb5b184b49b789d9460d5332e9c516629122d08f529b0961d42a2284
|
data/CHANGELOG.md
CHANGED
@@ -6,8 +6,32 @@ 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.1.0] - 2022-07-19
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- [#115](https://github.com/ruby-syntax-tree/syntax_tree/pull/115) - Support the `--print-width` option in the CLI for the actions that support it.
|
14
|
+
|
15
|
+
## [3.0.1] - 2022-07-15
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
|
19
|
+
- [#112](https://github.com/ruby-syntax-tree/syntax_tree/pull/112) - Fix parallel CLI execution by not short-circuiting with the `||` operator.
|
20
|
+
|
21
|
+
## [3.0.0] - 2022-07-04
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- [#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.
|
26
|
+
|
27
|
+
### Removed
|
28
|
+
|
29
|
+
- [#108](https://github.com/ruby-syntax-tree/syntax_tree/pull/108) - Remove old inlay hints code.
|
30
|
+
|
9
31
|
## [2.9.0] - 2022-07-04
|
10
32
|
|
33
|
+
### Added
|
34
|
+
|
11
35
|
- [#106](https://github.com/ruby-syntax-tree/syntax_tree/pull/106) - Add inlay hint support to match the LSP specification.
|
12
36
|
|
13
37
|
## [2.8.0] - 2022-06-21
|
@@ -276,8 +300,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
276
300
|
|
277
301
|
- 🎉 Initial release! 🎉
|
278
302
|
|
279
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/
|
280
|
-
[
|
303
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.1.0...HEAD
|
304
|
+
[3.1.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.0.1...v3.1.0
|
305
|
+
[3.0.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.0.0...v3.0.1
|
306
|
+
[3.0.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.9.0...v3.0.0
|
307
|
+
[2.9.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.8.0...v2.9.0
|
281
308
|
[2.8.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.7.1...v2.8.0
|
282
309
|
[2.7.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.7.0...v2.7.1
|
283
310
|
[2.7.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.6.0...v2.7.0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree (
|
4
|
+
syntax_tree (3.1.0)
|
5
5
|
prettier_print
|
6
6
|
|
7
7
|
GEM
|
@@ -19,7 +19,7 @@ GEM
|
|
19
19
|
rake (13.0.6)
|
20
20
|
regexp_parser (2.5.0)
|
21
21
|
rexml (3.2.5)
|
22
|
-
rubocop (1.31.
|
22
|
+
rubocop (1.31.2)
|
23
23
|
json (~> 2.3)
|
24
24
|
parallel (~> 1.10)
|
25
25
|
parser (>= 3.1.0.0)
|
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)
|
@@ -118,6 +118,12 @@ If there are files with unformatted code, you will receive:
|
|
118
118
|
The listed files did not match the expected format.
|
119
119
|
```
|
120
120
|
|
121
|
+
To change the print width that you are checking against, specify the `--print-width` option, as in:
|
122
|
+
|
123
|
+
```sh
|
124
|
+
stree check --print-width=100 path/to/file.rb
|
125
|
+
```
|
126
|
+
|
121
127
|
### format
|
122
128
|
|
123
129
|
This command will output the formatted version of each of the listed files. Importantly, it will not write that content back to the source files. It is meant to display the formatted version only.
|
@@ -132,6 +138,12 @@ For a file that contains `1 + 1`, you will receive:
|
|
132
138
|
1 + 1
|
133
139
|
```
|
134
140
|
|
141
|
+
To change the print width that you are formatting with, specify the `--print-width` option, as in:
|
142
|
+
|
143
|
+
```sh
|
144
|
+
stree format --print-width=100 path/to/file.rb
|
145
|
+
```
|
146
|
+
|
135
147
|
### json
|
136
148
|
|
137
149
|
This command will output a JSON representation of the syntax tree that is functionally equivalent to the input. This is mostly used in contexts where you need to access the tree from JavaScript or serialize it over a network.
|
@@ -213,6 +225,12 @@ This will list every file that is being formatted. It will output light gray if
|
|
213
225
|
path/to/file.rb 0ms
|
214
226
|
```
|
215
227
|
|
228
|
+
To change the print width that you are writing with, specify the `--print-width` option, as in:
|
229
|
+
|
230
|
+
```sh
|
231
|
+
stree write --print-width=100 path/to/file.rb
|
232
|
+
```
|
233
|
+
|
216
234
|
## Library
|
217
235
|
|
218
236
|
Syntax Tree can be used as a library to access the syntax tree underlying Ruby source code.
|
@@ -402,7 +420,7 @@ By default, the language server is relatively minimal, mostly meant to provide a
|
|
402
420
|
|
403
421
|
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
422
|
|
405
|
-
### textDocument/
|
423
|
+
### textDocument/inlayHint
|
406
424
|
|
407
425
|
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
426
|
|
@@ -410,7 +428,7 @@ The language server also responds to the relatively new inlay hints request. Thi
|
|
410
428
|
1 + 2 * 3
|
411
429
|
```
|
412
430
|
|
413
|
-
Implicity, the `2 * 3` is going to be executed first because the `*` operator has higher precedence than the `+` operator.
|
431
|
+
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
432
|
|
415
433
|
```ruby
|
416
434
|
1 + ₍2 * 3₎
|
data/lib/syntax_tree/cli.rb
CHANGED
@@ -91,9 +91,17 @@ module SyntaxTree
|
|
91
91
|
class UnformattedError < StandardError
|
92
92
|
end
|
93
93
|
|
94
|
+
attr_reader :print_width
|
95
|
+
|
96
|
+
def initialize(print_width:)
|
97
|
+
@print_width = print_width
|
98
|
+
end
|
99
|
+
|
94
100
|
def run(item)
|
95
101
|
source = item.source
|
96
|
-
|
102
|
+
if source != item.handler.format(source, print_width)
|
103
|
+
raise UnformattedError
|
104
|
+
end
|
97
105
|
rescue StandardError
|
98
106
|
warn("[#{Color.yellow("warn")}] #{item.filepath}")
|
99
107
|
raise
|
@@ -114,13 +122,21 @@ module SyntaxTree
|
|
114
122
|
class NonIdempotentFormatError < StandardError
|
115
123
|
end
|
116
124
|
|
125
|
+
attr_reader :print_width
|
126
|
+
|
127
|
+
def initialize(print_width:)
|
128
|
+
@print_width = print_width
|
129
|
+
end
|
130
|
+
|
117
131
|
def run(item)
|
118
132
|
handler = item.handler
|
119
133
|
|
120
134
|
warning = "[#{Color.yellow("warn")}] #{item.filepath}"
|
121
|
-
formatted = handler.format(item.source)
|
135
|
+
formatted = handler.format(item.source, print_width)
|
122
136
|
|
123
|
-
|
137
|
+
if formatted != handler.format(formatted, print_width)
|
138
|
+
raise NonIdempotentFormatError
|
139
|
+
end
|
124
140
|
rescue StandardError
|
125
141
|
warn(warning)
|
126
142
|
raise
|
@@ -148,8 +164,14 @@ module SyntaxTree
|
|
148
164
|
|
149
165
|
# An action of the CLI that formats the input source and prints it out.
|
150
166
|
class Format < Action
|
167
|
+
attr_reader :print_width
|
168
|
+
|
169
|
+
def initialize(print_width:)
|
170
|
+
@print_width = print_width
|
171
|
+
end
|
172
|
+
|
151
173
|
def run(item)
|
152
|
-
puts item.handler.format(item.source)
|
174
|
+
puts item.handler.format(item.source, print_width)
|
153
175
|
end
|
154
176
|
end
|
155
177
|
|
@@ -173,12 +195,18 @@ module SyntaxTree
|
|
173
195
|
# An action of the CLI that formats the input source and writes the
|
174
196
|
# formatted output back to the file.
|
175
197
|
class Write < Action
|
198
|
+
attr_reader :print_width
|
199
|
+
|
200
|
+
def initialize(print_width:)
|
201
|
+
@print_width = print_width
|
202
|
+
end
|
203
|
+
|
176
204
|
def run(item)
|
177
205
|
filepath = item.filepath
|
178
206
|
start = Time.now
|
179
207
|
|
180
208
|
source = item.source
|
181
|
-
formatted = item.handler.format(source)
|
209
|
+
formatted = item.handler.format(source, print_width)
|
182
210
|
File.write(filepath, formatted) if filepath != :stdin
|
183
211
|
|
184
212
|
color = source == formatted ? Color.gray(filepath) : filepath
|
@@ -194,43 +222,44 @@ module SyntaxTree
|
|
194
222
|
# The help message displayed if the input arguments are not correctly
|
195
223
|
# ordered or formatted.
|
196
224
|
HELP = <<~HELP
|
197
|
-
#{Color.bold("stree ast [
|
225
|
+
#{Color.bold("stree ast [--plugins=...] [--print-width=NUMBER] FILE")}
|
198
226
|
Print out the AST corresponding to the given files
|
199
227
|
|
200
|
-
#{Color.bold("stree check [
|
228
|
+
#{Color.bold("stree check [--plugins=...] [--print-width=NUMBER] FILE")}
|
201
229
|
Check that the given files are formatted as syntax tree would format them
|
202
230
|
|
203
|
-
#{Color.bold("stree debug [
|
231
|
+
#{Color.bold("stree debug [--plugins=...] [--print-width=NUMBER] FILE")}
|
204
232
|
Check that the given files can be formatted idempotently
|
205
233
|
|
206
|
-
#{Color.bold("stree doc [
|
234
|
+
#{Color.bold("stree doc [--plugins=...] FILE")}
|
207
235
|
Print out the doc tree that would be used to format the given files
|
208
236
|
|
209
|
-
#{Color.bold("stree format [
|
237
|
+
#{Color.bold("stree format [--plugins=...] [--print-width=NUMBER] FILE")}
|
210
238
|
Print out the formatted version of the given files
|
211
239
|
|
212
|
-
#{Color.bold("stree json [
|
240
|
+
#{Color.bold("stree json [--plugins=...] FILE")}
|
213
241
|
Print out the JSON representation of the given files
|
214
242
|
|
215
|
-
#{Color.bold("stree match [
|
243
|
+
#{Color.bold("stree match [--plugins=...] FILE")}
|
216
244
|
Print out a pattern-matching Ruby expression that would match the given files
|
217
245
|
|
218
246
|
#{Color.bold("stree help")}
|
219
247
|
Display this help message
|
220
248
|
|
221
|
-
#{Color.bold("stree lsp [
|
249
|
+
#{Color.bold("stree lsp [--plugins=...]")}
|
222
250
|
Run syntax tree in language server mode
|
223
251
|
|
224
252
|
#{Color.bold("stree version")}
|
225
253
|
Output the current version of syntax tree
|
226
254
|
|
227
|
-
#{Color.bold("stree write [
|
255
|
+
#{Color.bold("stree write [--plugins=...] [--print-width=NUMBER] FILE")}
|
228
256
|
Read, format, and write back the source of the given files
|
229
257
|
|
230
|
-
[OPTIONS]
|
231
|
-
|
232
258
|
--plugins=...
|
233
259
|
A comma-separated list of plugins to load.
|
260
|
+
|
261
|
+
--print-width=NUMBER
|
262
|
+
The maximum line width to use when formatting.
|
234
263
|
HELP
|
235
264
|
|
236
265
|
class << self
|
@@ -238,19 +267,31 @@ module SyntaxTree
|
|
238
267
|
# passed to the invocation.
|
239
268
|
def run(argv)
|
240
269
|
name, *arguments = argv
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
270
|
+
print_width = DEFAULT_PRINT_WIDTH
|
271
|
+
|
272
|
+
while arguments.first&.start_with?("--")
|
273
|
+
case (argument = arguments.shift)
|
274
|
+
when /^--plugins=(.+)$/
|
275
|
+
# If there are any plugins specified on the command line, then load
|
276
|
+
# them by requiring them here. We do this by transforming something
|
277
|
+
# like
|
278
|
+
#
|
279
|
+
# stree format --plugins=haml template.haml
|
280
|
+
#
|
281
|
+
# into
|
282
|
+
#
|
283
|
+
# require "syntax_tree/haml"
|
284
|
+
#
|
285
|
+
$1.split(",").each { |plugin| require "syntax_tree/#{plugin}" }
|
286
|
+
when /^--print-width=(\d+)$/
|
287
|
+
# If there is a print width specified on the command line, then
|
288
|
+
# parse that out here and use it when formatting.
|
289
|
+
print_width = Integer($1)
|
290
|
+
else
|
291
|
+
warn("Unknown CLI option: #{argument}")
|
292
|
+
warn(HELP)
|
293
|
+
return 1
|
294
|
+
end
|
254
295
|
end
|
255
296
|
|
256
297
|
case name
|
@@ -271,9 +312,9 @@ module SyntaxTree
|
|
271
312
|
when "a", "ast"
|
272
313
|
AST.new
|
273
314
|
when "c", "check"
|
274
|
-
Check.new
|
315
|
+
Check.new(print_width: print_width)
|
275
316
|
when "debug"
|
276
|
-
Debug.new
|
317
|
+
Debug.new(print_width: print_width)
|
277
318
|
when "doc"
|
278
319
|
Doc.new
|
279
320
|
when "j", "json"
|
@@ -281,9 +322,9 @@ module SyntaxTree
|
|
281
322
|
when "m", "match"
|
282
323
|
Match.new
|
283
324
|
when "f", "format"
|
284
|
-
Format.new
|
325
|
+
Format.new(print_width: print_width)
|
285
326
|
when "w", "write"
|
286
|
-
Write.new
|
327
|
+
Write.new(print_width: print_width)
|
287
328
|
else
|
288
329
|
warn(HELP)
|
289
330
|
return 1
|
@@ -315,23 +356,7 @@ module SyntaxTree
|
|
315
356
|
|
316
357
|
# At the end, we're going to return whether or not this worker ever
|
317
358
|
# encountered an error.
|
318
|
-
|
319
|
-
with_workers(queue) do |item|
|
320
|
-
action.run(item)
|
321
|
-
false
|
322
|
-
rescue Parser::ParseError => error
|
323
|
-
warn("Error: #{error.message}")
|
324
|
-
highlight_error(error, item.source)
|
325
|
-
true
|
326
|
-
rescue Check::UnformattedError, Debug::NonIdempotentFormatError
|
327
|
-
true
|
328
|
-
rescue StandardError => error
|
329
|
-
warn(error.message)
|
330
|
-
warn(error.backtrace)
|
331
|
-
true
|
332
|
-
end
|
333
|
-
|
334
|
-
if errored
|
359
|
+
if process_queue(queue, action)
|
335
360
|
action.failure
|
336
361
|
1
|
337
362
|
else
|
@@ -342,13 +367,11 @@ module SyntaxTree
|
|
342
367
|
|
343
368
|
private
|
344
369
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
return yield queue.shift if queue.size == 1
|
349
|
-
|
370
|
+
# Processes each item in the queue with the given action. Returns whether
|
371
|
+
# or not any errors were encountered.
|
372
|
+
def process_queue(queue, action)
|
350
373
|
workers =
|
351
|
-
Etc.nprocessors.times.map do
|
374
|
+
[Etc.nprocessors, queue.size].min.times.map do
|
352
375
|
Thread.new do
|
353
376
|
# Propagate errors in the worker threads up to the parent thread.
|
354
377
|
Thread.current.abort_on_exception = true
|
@@ -360,7 +383,25 @@ module SyntaxTree
|
|
360
383
|
|
361
384
|
# While there is still work left to do, shift off the queue and
|
362
385
|
# process the item.
|
363
|
-
|
386
|
+
until queue.empty?
|
387
|
+
item = queue.shift
|
388
|
+
errored |=
|
389
|
+
begin
|
390
|
+
action.run(item)
|
391
|
+
false
|
392
|
+
rescue Parser::ParseError => error
|
393
|
+
warn("Error: #{error.message}")
|
394
|
+
highlight_error(error, item.source)
|
395
|
+
true
|
396
|
+
rescue Check::UnformattedError,
|
397
|
+
Debug::NonIdempotentFormatError
|
398
|
+
true
|
399
|
+
rescue StandardError => error
|
400
|
+
warn(error.message)
|
401
|
+
warn(error.backtrace)
|
402
|
+
true
|
403
|
+
end
|
404
|
+
end
|
364
405
|
|
365
406
|
# At the end, we're going to return whether or not this worker
|
366
407
|
# ever encountered an error.
|
@@ -368,7 +409,7 @@ module SyntaxTree
|
|
368
409
|
end
|
369
410
|
end
|
370
411
|
|
371
|
-
workers.inject(
|
412
|
+
workers.map(&:value).inject(:|)
|
372
413
|
end
|
373
414
|
|
374
415
|
# Highlights a snippet from a source and parse error.
|
@@ -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
data/lib/syntax_tree.rb
CHANGED
@@ -29,6 +29,11 @@ module SyntaxTree
|
|
29
29
|
HANDLERS = {}
|
30
30
|
HANDLERS.default = SyntaxTree
|
31
31
|
|
32
|
+
# This is the default print width when formatting. It can be overridden in the
|
33
|
+
# CLI by passing the --print-width option or here in the API by passing the
|
34
|
+
# optional second argument to ::format.
|
35
|
+
DEFAULT_PRINT_WIDTH = 80
|
36
|
+
|
32
37
|
# This is a hook provided so that plugins can register themselves as the
|
33
38
|
# handler for a particular file type.
|
34
39
|
def self.register_handler(extension, handler)
|
@@ -43,7 +48,7 @@ module SyntaxTree
|
|
43
48
|
end
|
44
49
|
|
45
50
|
# Parses the given source and returns the formatted source.
|
46
|
-
def self.format(source, maxwidth =
|
51
|
+
def self.format(source, maxwidth = DEFAULT_PRINT_WIDTH)
|
47
52
|
formatter = Formatter.new(source, [], maxwidth)
|
48
53
|
parse(source).format(formatter)
|
49
54
|
|
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.1.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-19 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
|