solargraph-dr_talon 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +13 -0
- data/lib/solargraph/dr_talon/attribute_node.rb +79 -9
- data/lib/solargraph/dr_talon/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0748faad9cf90c06804e66167093ac65dd6f81523d95ead02fd35a0faa462dcd'
|
|
4
|
+
data.tar.gz: 50ace6eb5d6384c7bd15bc12cda516f3c8b6f24f76298a0fc2cd75588d767a6a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8e4fb38812af974a23e7283879ac11de5c73124c48454b5b6167246eb42252f165017195ed78e57babab5dcdf39aed72548b81247eaad8629ccf54b9148dc57
|
|
7
|
+
data.tar.gz: 29e32ead48c70e1552f09368b8a02180078fec57b346724146780b7957950c951e702b96c8aee5607d0c890dae08d44412da73b418d77167564bb704ceb12570
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.0] - 2026-10-11
|
|
4
|
+
|
|
5
|
+
- `prop` and `state` declarations in an `each` loop over a list of symbols (a literal array, or a constant
|
|
6
|
+
assigned one in the same file) define a reader and writer per symbol. `Talon::StateSprite` declares its sprite
|
|
7
|
+
attributes this way, so `x`, `y`, `path`, `angle`, ... now complete on `Talon::GameObject`.
|
|
8
|
+
- Test fixtures synced to Talon c4b670c.
|
|
9
|
+
|
|
3
10
|
## [0.1.0] - 2026-10-11
|
|
4
11
|
|
|
5
12
|
- Initial release: a Solargraph plugin for the [Talon](https://github.com/asimmons91/talon) game framework.
|
|
@@ -13,5 +20,6 @@
|
|
|
13
20
|
any other `on_*`, `set_callback` and `define_callback`) are evaluated on the instance. Their block parameters
|
|
14
21
|
are typed by the hook method's `@yieldparam` tag, which Talon's built-in hooks document as `GTK::Args`.
|
|
15
22
|
|
|
16
|
-
[Unreleased]: https://github.com/asimmons91/solargraph-dr_talon/compare/v0.
|
|
23
|
+
[Unreleased]: https://github.com/asimmons91/solargraph-dr_talon/compare/v0.2.0...HEAD
|
|
24
|
+
[0.2.0]: https://github.com/asimmons91/solargraph-dr_talon/compare/v0.1.0...v0.2.0
|
|
17
25
|
[0.1.0]: https://github.com/asimmons91/solargraph-dr_talon/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -86,6 +86,16 @@ Restart your editor's language server. See solargraph-dragonruby's README for ed
|
|
|
86
86
|
(`2` is an `Integer`, `"a"` a `String`, `true` a `Boolean`, `Vector.new(...)` a `Vector`, ...).
|
|
87
87
|
- The comment becomes the hover docs, and go-to-definition jumps to the declaration.
|
|
88
88
|
- A declaration in a concern's `included` block defines the methods on the concern, so every host gets them.
|
|
89
|
+
- Declarations in a loop over a list of symbols define one reader and writer per symbol. The list can be a
|
|
90
|
+
literal array or a constant assigned one earlier in the same file:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
AXES = %i[dx dy].freeze
|
|
94
|
+
AXES.each { |axis| state axis, default: 0 } # dx, dx=, dy, dy=
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This is how `Talon::StateSprite` declares the sprite attributes of every `Talon::GameObject` (`x`, `y`, `w`,
|
|
98
|
+
`h`, `path`, `angle`, ...), so they complete on game objects (from Talon c4b670c).
|
|
89
99
|
- **Lifecycle hook blocks** in a class body are evaluated on the instance, as Talon runs them.
|
|
90
100
|
- This applies to `on_start`, `on_update`, `on_draw`, `on_destroy`, `on_enter` and `on_exit`, and to `set_callback`
|
|
91
101
|
and `define_callback`.
|
|
@@ -105,6 +115,9 @@ Restart your editor's language server. See solargraph-dragonruby's README for ed
|
|
|
105
115
|
class:
|
|
106
116
|
- `prop :name` and `state :name` called in any class body define accessors.
|
|
107
117
|
- A block passed to any bare `on_*` call in a class body is evaluated on the instance.
|
|
118
|
+
- Only `each` loops are unrolled, with a single block parameter passed straight to `prop` or `state`. A list
|
|
119
|
+
that comes from a method call, another file, or contains anything but symbols isn't known statically, so its
|
|
120
|
+
attributes don't complete.
|
|
108
121
|
- A concern's own class side (`Visible.hidden_by_default`) also completes its `ClassMethods`. This is what makes
|
|
109
122
|
them complete inside `included do ... end`, but calling them on the concern itself fails at runtime.
|
|
110
123
|
- The Talon methods behind a hook block (such as `update` from `on_update`) are generated at runtime and don't
|
|
@@ -10,6 +10,15 @@ module Solargraph
|
|
|
10
10
|
# A `@return` tag in the comment above the call sets the type; otherwise
|
|
11
11
|
# it's inferred from a literal `default:`.
|
|
12
12
|
#
|
|
13
|
+
# It also unrolls declarations made in a loop over a list of symbols, as
|
|
14
|
+
# Talon::StateSprite does for its sprite attributes:
|
|
15
|
+
#
|
|
16
|
+
# ATTRIBUTES = [:x, :y, :w, :h].freeze
|
|
17
|
+
# ATTRIBUTES.each { |name| state name }
|
|
18
|
+
#
|
|
19
|
+
# The list must be a literal array of symbols, or a constant assigned one
|
|
20
|
+
# earlier in the same file.
|
|
21
|
+
#
|
|
13
22
|
# This is a node processor rather than a Convention#local because
|
|
14
23
|
# Solargraph 0.61 doesn't notice when a file's convention pins change, so
|
|
15
24
|
# adding or removing a declaration wouldn't take effect until a restart.
|
|
@@ -44,13 +53,30 @@ module Solargraph
|
|
|
44
53
|
# @return [Boolean] true, so later :send processors still run
|
|
45
54
|
def process
|
|
46
55
|
receiver, dsl, attribute, *options = node.children
|
|
47
|
-
return true unless receiver.nil? && DSLS.key?(dsl)
|
|
56
|
+
return true unless receiver.nil? && DSLS.key?(dsl)
|
|
57
|
+
|
|
58
|
+
if attribute&.type == :sym
|
|
59
|
+
host = Host.namespace(region)
|
|
60
|
+
push_accessors(host, attribute.children[0].to_s, dsl, options, region.code_for(node)) if host
|
|
61
|
+
elsif (names = iterated_names(attribute))
|
|
62
|
+
# The loop's block is the closure; the host is around it.
|
|
63
|
+
host = Host.namespace(region.update(closure: region.closure.closure))
|
|
64
|
+
names.each { |name| push_accessors(host, name.to_s, dsl, options, "#{dsl} :#{name}") } if host
|
|
65
|
+
end
|
|
66
|
+
true
|
|
67
|
+
end
|
|
48
68
|
|
|
49
|
-
|
|
50
|
-
return true unless host
|
|
69
|
+
private
|
|
51
70
|
|
|
52
|
-
|
|
53
|
-
|
|
71
|
+
# @param host [Solargraph::Pin::Namespace]
|
|
72
|
+
# @param name [String]
|
|
73
|
+
# @param dsl [Symbol]
|
|
74
|
+
# @param options [Array<Parser::AST::Node>]
|
|
75
|
+
# @param declaration [String] the declaration's code, for undocumented
|
|
76
|
+
# attributes
|
|
77
|
+
# @return [void]
|
|
78
|
+
def push_accessors(host, name, dsl, options, declaration)
|
|
79
|
+
comments = attribute_comments(dsl, options, declaration)
|
|
54
80
|
reader = method_pin(host, name, comments)
|
|
55
81
|
writer = method_pin(host, "#{name}=", comments)
|
|
56
82
|
writer.parameters.push Solargraph::Pin::Parameter.new(name: "value", decl: :arg, closure: writer, source: :dr_talon)
|
|
@@ -58,10 +84,53 @@ module Solargraph
|
|
|
58
84
|
writer.docstring.add_tag YARD::Tags::Tag.new(:param, "", reader.return_type.items.map(&:rooted_tags), "value")
|
|
59
85
|
end
|
|
60
86
|
pins.push reader, writer
|
|
61
|
-
true
|
|
62
87
|
end
|
|
63
88
|
|
|
64
|
-
|
|
89
|
+
# The names a declaration like `state name` declares when it's directly
|
|
90
|
+
# inside `LIST.each { |name| ... }`.
|
|
91
|
+
#
|
|
92
|
+
# @param attribute [Parser::AST::Node, nil]
|
|
93
|
+
# @return [Array<Symbol>, nil]
|
|
94
|
+
def iterated_names(attribute)
|
|
95
|
+
return unless attribute&.type == :lvar
|
|
96
|
+
|
|
97
|
+
block = region.closure
|
|
98
|
+
return unless block.is_a?(Solargraph::Pin::Block) && block.node
|
|
99
|
+
|
|
100
|
+
call, args = block.node.children
|
|
101
|
+
return unless call.type == :send && call.children[1] == :each && call.children.length == 2
|
|
102
|
+
|
|
103
|
+
params = args.children
|
|
104
|
+
return unless params.length == 1 && params[0].type == :arg && params[0].children[0] == attribute.children[0]
|
|
105
|
+
|
|
106
|
+
symbol_list(call.children[0])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @param list [Parser::AST::Node, nil] a literal array of symbols, or a
|
|
110
|
+
# constant assigned one earlier in this file, optionally frozen
|
|
111
|
+
# @return [Array<Symbol>, nil]
|
|
112
|
+
def symbol_list(list)
|
|
113
|
+
list = unfreeze(list)
|
|
114
|
+
list = unfreeze(constant_value(list)) if list&.type == :const
|
|
115
|
+
return unless list&.type == :array && list.children.all? { |item| item.type == :sym }
|
|
116
|
+
|
|
117
|
+
list.children.map { |item| item.children[0] }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @param node [Parser::AST::Node, nil]
|
|
121
|
+
# @return [Parser::AST::Node, nil] the receiver of `.freeze`, or `node`
|
|
122
|
+
def unfreeze(node)
|
|
123
|
+
frozen = node&.type == :send && node.children[1] == :freeze && node.children.length == 2
|
|
124
|
+
frozen ? node.children[0] : node
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# @param const [Parser::AST::Node]
|
|
128
|
+
# @return [Parser::AST::Node, nil] the value most recently assigned to
|
|
129
|
+
# a constant of that name in this file
|
|
130
|
+
def constant_value(const)
|
|
131
|
+
name = const.children[1].to_s
|
|
132
|
+
pins.reverse_each.find { |pin| pin.is_a?(Solargraph::Pin::Constant) && pin.name == name }&.assignment
|
|
133
|
+
end
|
|
65
134
|
|
|
66
135
|
# @param host [Solargraph::Pin::Namespace]
|
|
67
136
|
# @param name [String]
|
|
@@ -87,10 +156,11 @@ module Solargraph
|
|
|
87
156
|
#
|
|
88
157
|
# @param dsl [Symbol]
|
|
89
158
|
# @param options [Array<Parser::AST::Node>]
|
|
159
|
+
# @param declaration [String]
|
|
90
160
|
# @return [String]
|
|
91
|
-
def attribute_comments(dsl, options)
|
|
161
|
+
def attribute_comments(dsl, options, declaration)
|
|
92
162
|
comments = comments_for(node).to_s
|
|
93
|
-
comments = "#{DSLS[dsl]}: `#{
|
|
163
|
+
comments = "#{DSLS[dsl]}: `#{declaration}`" if comments.strip.empty?
|
|
94
164
|
return comments if comments.match?(/^\s*@return\b/)
|
|
95
165
|
|
|
96
166
|
type = inferred_type(options)
|