aegis-core 1.5.2__tar.gz
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.
- aegis_core-1.5.2/PKG-INFO +20 -0
- aegis_core-1.5.2/README.md +1 -0
- aegis_core-1.5.2/aegis_core/__init__.py +1 -0
- aegis_core-1.5.2/aegis_core/ast/__init__.py +0 -0
- aegis_core-1.5.2/aegis_core/ast/features/__init__.py +39 -0
- aegis_core-1.5.2/aegis_core/ast/features/provider.py +85 -0
- aegis_core-1.5.2/aegis_core/ast/features/resource_location.py +199 -0
- aegis_core-1.5.2/aegis_core/ast/features/variable.py +44 -0
- aegis_core-1.5.2/aegis_core/ast/helpers.py +31 -0
- aegis_core-1.5.2/aegis_core/ast/metadata.py +107 -0
- aegis_core-1.5.2/aegis_core/indexing/__init__.py +1 -0
- aegis_core-1.5.2/aegis_core/indexing/project_index.py +170 -0
- aegis_core-1.5.2/aegis_core/reflection/__init__.py +258 -0
- aegis_core-1.5.2/aegis_core/registry.py +16 -0
- aegis_core-1.5.2/aegis_core/semantics.py +38 -0
- aegis_core-1.5.2/pyproject.toml +25 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: aegis_core
|
|
3
|
+
Version: 1.5.2
|
|
4
|
+
Summary: A library to manipulate Mecha for language server usage
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: TheNuclearNexus
|
|
7
|
+
Author-email: 39636175+TheNuclearNexus@users.noreply.github.com
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: bolt (>=0.49.1,<0.50.0)
|
|
16
|
+
Requires-Dist: lsprotocol (>=2023.0.1,<2024.0.0)
|
|
17
|
+
Requires-Dist: mecha (>=0.96.0,<0.97.0)
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# Aegis Core
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Aegis Core
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.0"
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from beet import Context
|
|
4
|
+
from bolt import AstAttribute, AstIdentifier, AstImportedItem, AstTargetIdentifier
|
|
5
|
+
from mecha import AstNode, AstResourceLocation
|
|
6
|
+
|
|
7
|
+
from .provider import *
|
|
8
|
+
from .resource_location import *
|
|
9
|
+
from .variable import *
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_default_providers() -> dict[type[AstNode], type[BaseFeatureProvider]]:
|
|
13
|
+
return {
|
|
14
|
+
AstIdentifier: VariableFeatureProvider,
|
|
15
|
+
AstAttribute: VariableFeatureProvider,
|
|
16
|
+
AstTargetIdentifier: VariableFeatureProvider,
|
|
17
|
+
AstImportedItem: VariableFeatureProvider,
|
|
18
|
+
AstResourceLocation: ResourceLocationFeatureProvider,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class AegisFeatureProviders:
|
|
24
|
+
ctx: Context
|
|
25
|
+
_providers: dict[type[AstNode], type[BaseFeatureProvider]] = field(
|
|
26
|
+
init=False, default_factory=get_default_providers
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def attach(self, node_type: type[AstNode], provider: type[BaseFeatureProvider]):
|
|
30
|
+
self._providers[node_type] = provider
|
|
31
|
+
|
|
32
|
+
def retrieve(
|
|
33
|
+
self,
|
|
34
|
+
node_type: type[AstNode] | AstNode,
|
|
35
|
+
) -> type[BaseFeatureProvider]:
|
|
36
|
+
if not isinstance(node_type, type):
|
|
37
|
+
node_type = type(node_type)
|
|
38
|
+
|
|
39
|
+
return self._providers.get(node_type, BaseFeatureProvider)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Generic, TypeVar
|
|
3
|
+
|
|
4
|
+
import lsprotocol.types as lsp
|
|
5
|
+
from beet import Context
|
|
6
|
+
from mecha import AstNode
|
|
7
|
+
|
|
8
|
+
from ...semantics import TokenModifier, TokenType
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"BaseFeatureProvider",
|
|
12
|
+
"BaseParams",
|
|
13
|
+
"CompletionParams",
|
|
14
|
+
"HoverParams",
|
|
15
|
+
"DefinitionParams",
|
|
16
|
+
"ReferencesParams",
|
|
17
|
+
"RenameParams",
|
|
18
|
+
"SemanticsParams",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
Node = TypeVar("Node", bound=AstNode)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class BaseParams(Generic[Node]):
|
|
26
|
+
ctx: Context
|
|
27
|
+
node: Node
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class CompletionParams(BaseParams[Node]): ...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class HoverParams(BaseParams[Node]):
|
|
36
|
+
text_range: lsp.Range
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class DefinitionParams(BaseParams[Node]): ...
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class ReferencesParams(BaseParams[Node]): ...
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class RenameParams(BaseParams[Node]): ...
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class SemanticsParams(BaseParams[Node]): ...
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class BaseFeatureProvider(Generic[Node]):
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def completion(
|
|
59
|
+
cls, params: CompletionParams[Node]
|
|
60
|
+
) -> list[lsp.CompletionItem] | None:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def hover(cls, params: HoverParams[Node]) -> lsp.Hover | None:
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def definition(
|
|
69
|
+
cls, params: DefinitionParams[Node]
|
|
70
|
+
) -> list[lsp.Location | lsp.LocationLink] | lsp.Location | lsp.LocationLink | None:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def references(cls, params: ReferencesParams[Node]) -> list[lsp.Location] | None:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def rename(cls, params: RenameParams[Node]) -> lsp.WorkspaceEdit | None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def semantics(
|
|
83
|
+
cls, params: SemanticsParams[Node]
|
|
84
|
+
) -> list[tuple[AstNode, TokenType, TokenModifier]] | None:
|
|
85
|
+
return None
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
__all__ = ["ResourceLocationFeatureProvider"]
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
import lsprotocol.types as lsp
|
|
8
|
+
from beet import File, NamespaceFile
|
|
9
|
+
from mecha import AstResourceLocation
|
|
10
|
+
|
|
11
|
+
from aegis_core.registry import AegisGameRegistries
|
|
12
|
+
|
|
13
|
+
from ...ast.helpers import node_location_to_range
|
|
14
|
+
from ...ast.metadata import ResourceLocationMetadata, retrieve_metadata
|
|
15
|
+
from ...indexing.project_index import AegisProjectIndex
|
|
16
|
+
from .provider import BaseFeatureProvider
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def add_registry_items(
|
|
20
|
+
registries: AegisGameRegistries,
|
|
21
|
+
represents: str,
|
|
22
|
+
prefix: str = "",
|
|
23
|
+
kind: lsp.CompletionItemKind = lsp.CompletionItemKind.Value,
|
|
24
|
+
):
|
|
25
|
+
if represents in registries:
|
|
26
|
+
registry_items = registries[represents]
|
|
27
|
+
|
|
28
|
+
return [
|
|
29
|
+
lsp.CompletionItem(prefix + "minecraft:" + k, kind=kind, sort_text=k)
|
|
30
|
+
for k in registry_items
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
return []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_path(path: str) -> tuple[str | None, Path]:
|
|
37
|
+
segments = path.split(":")
|
|
38
|
+
if len(segments) == 1:
|
|
39
|
+
return (None, Path(segments[0]))
|
|
40
|
+
else:
|
|
41
|
+
return (segments[0], Path(segments[1]))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ResourceLocationFeatureProvider(BaseFeatureProvider[AstResourceLocation]):
|
|
45
|
+
@classmethod
|
|
46
|
+
def hover(cls, params) -> lsp.Hover | None:
|
|
47
|
+
node = params.node
|
|
48
|
+
text_range = params.text_range
|
|
49
|
+
|
|
50
|
+
metadata = retrieve_metadata(node, ResourceLocationMetadata)
|
|
51
|
+
|
|
52
|
+
if metadata is None or metadata.represents is None:
|
|
53
|
+
path_type = None
|
|
54
|
+
elif isinstance(metadata.represents, str):
|
|
55
|
+
path_type = metadata.represents
|
|
56
|
+
elif issubclass(metadata.represents, File):
|
|
57
|
+
path_type = metadata.represents.snake_name
|
|
58
|
+
|
|
59
|
+
type_line = f"**{path_type}**\n" if path_type else ""
|
|
60
|
+
|
|
61
|
+
return lsp.Hover(
|
|
62
|
+
lsp.MarkupContent(
|
|
63
|
+
lsp.MarkupKind.Markdown,
|
|
64
|
+
f"{type_line}```yaml\n{node.get_canonical_value()}\n```",
|
|
65
|
+
),
|
|
66
|
+
text_range,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def definition(cls, params):
|
|
71
|
+
project_index = params.ctx.inject(AegisProjectIndex)
|
|
72
|
+
node = params.node
|
|
73
|
+
|
|
74
|
+
metadata = retrieve_metadata(node, ResourceLocationMetadata)
|
|
75
|
+
|
|
76
|
+
if not metadata or not metadata.represents:
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
if isinstance(metadata.represents, str):
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
path = node.get_canonical_value()
|
|
83
|
+
definitions = project_index[metadata.represents].get_definitions(path)
|
|
84
|
+
|
|
85
|
+
return [
|
|
86
|
+
lsp.LocationLink(
|
|
87
|
+
target_uri=Path(path).as_uri(),
|
|
88
|
+
target_range=node_location_to_range(location),
|
|
89
|
+
target_selection_range=node_location_to_range(location),
|
|
90
|
+
origin_selection_range=node_location_to_range(node),
|
|
91
|
+
)
|
|
92
|
+
for path, *location in definitions
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def references(cls, params) -> list[lsp.Location] | None:
|
|
97
|
+
project_index = params.ctx.inject(AegisProjectIndex)
|
|
98
|
+
node = params.node
|
|
99
|
+
|
|
100
|
+
metadata = retrieve_metadata(node, ResourceLocationMetadata)
|
|
101
|
+
|
|
102
|
+
if not metadata or not metadata.represents:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
if isinstance(metadata.represents, str):
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
path = node.get_canonical_value()
|
|
109
|
+
references = project_index[metadata.represents].get_references(path)
|
|
110
|
+
|
|
111
|
+
return [
|
|
112
|
+
lsp.Location(Path(path).as_uri(), node_location_to_range(location))
|
|
113
|
+
for path, *location in references
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def completion(cls, params):
|
|
118
|
+
node = params.node
|
|
119
|
+
project_index = params.ctx.inject(AegisProjectIndex)
|
|
120
|
+
|
|
121
|
+
metadata = retrieve_metadata(node, ResourceLocationMetadata)
|
|
122
|
+
|
|
123
|
+
if not metadata or metadata.represents is not type[NamespaceFile]:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
represents = metadata.represents
|
|
127
|
+
|
|
128
|
+
if represents is type[NamespaceFile]:
|
|
129
|
+
file_type = cast(type[NamespaceFile], represents)
|
|
130
|
+
|
|
131
|
+
path = node.get_canonical_value()
|
|
132
|
+
|
|
133
|
+
if node.is_tag:
|
|
134
|
+
path = path[1:]
|
|
135
|
+
|
|
136
|
+
resolved = get_path(path)
|
|
137
|
+
|
|
138
|
+
unresolved = get_path(metadata.unresolved_path or path)
|
|
139
|
+
|
|
140
|
+
if unresolved[1].name == "~":
|
|
141
|
+
resolved_parent = resolved[1]
|
|
142
|
+
unresolved_parent = unresolved[1]
|
|
143
|
+
else:
|
|
144
|
+
resolved_parent = resolved[1].parent
|
|
145
|
+
unresolved_parent = unresolved[1].parent
|
|
146
|
+
|
|
147
|
+
items = []
|
|
148
|
+
|
|
149
|
+
for file in project_index[file_type]:
|
|
150
|
+
file_path = get_path(file)
|
|
151
|
+
|
|
152
|
+
if not (
|
|
153
|
+
file_path[0] == resolved[0]
|
|
154
|
+
and file_path[1].is_relative_to(resolved_parent)
|
|
155
|
+
):
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
relative = file_path[1].relative_to(resolved_parent)
|
|
159
|
+
|
|
160
|
+
if unresolved[0] is None and unresolved[1].name == "":
|
|
161
|
+
new_path = "./" + str(relative)
|
|
162
|
+
else:
|
|
163
|
+
new_path = str(unresolved_parent / relative)
|
|
164
|
+
|
|
165
|
+
insert_text = (
|
|
166
|
+
f"{unresolved[0] + ':' if unresolved[0] else ''}{new_path}"
|
|
167
|
+
)
|
|
168
|
+
if node.is_tag:
|
|
169
|
+
insert_text = "#" + insert_text
|
|
170
|
+
|
|
171
|
+
items.append(
|
|
172
|
+
lsp.CompletionItem(
|
|
173
|
+
label=insert_text,
|
|
174
|
+
documentation=file,
|
|
175
|
+
text_edit=lsp.InsertReplaceEdit(
|
|
176
|
+
insert_text,
|
|
177
|
+
node_location_to_range(node),
|
|
178
|
+
node_location_to_range(node),
|
|
179
|
+
),
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return items
|
|
184
|
+
|
|
185
|
+
elif isinstance(represents, str):
|
|
186
|
+
registries = params.ctx.inject(AegisGameRegistries)
|
|
187
|
+
items = []
|
|
188
|
+
|
|
189
|
+
items.extend(add_registry_items(registries, represents))
|
|
190
|
+
items.extend(
|
|
191
|
+
add_registry_items(
|
|
192
|
+
registries,
|
|
193
|
+
"tag/" + represents,
|
|
194
|
+
"#",
|
|
195
|
+
lsp.CompletionItemKind.Constant,
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return items
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import lsprotocol.types as lsp
|
|
2
|
+
from bolt import AstAttribute, AstIdentifier, AstImportedItem, AstTargetIdentifier
|
|
3
|
+
|
|
4
|
+
from ...reflection import get_annotation_description
|
|
5
|
+
from ..metadata import VariableMetadata, retrieve_metadata
|
|
6
|
+
from . import BaseFeatureProvider
|
|
7
|
+
|
|
8
|
+
__all__ = ["VariableFeatureProvider"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class VariableFeatureProvider(
|
|
12
|
+
BaseFeatureProvider[
|
|
13
|
+
AstIdentifier | AstAttribute | AstTargetIdentifier | AstImportedItem
|
|
14
|
+
]
|
|
15
|
+
):
|
|
16
|
+
@classmethod
|
|
17
|
+
def hover(cls, params) -> lsp.Hover | None:
|
|
18
|
+
node = params.node
|
|
19
|
+
text_range = params.text_range
|
|
20
|
+
|
|
21
|
+
metadata = retrieve_metadata(node, VariableMetadata)
|
|
22
|
+
name = (
|
|
23
|
+
node.value
|
|
24
|
+
if not isinstance(node, (AstAttribute, AstImportedItem))
|
|
25
|
+
else node.name
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if metadata and metadata.type_annotation:
|
|
29
|
+
|
|
30
|
+
type_annotation = metadata.type_annotation
|
|
31
|
+
|
|
32
|
+
description = get_annotation_description(name, type_annotation)
|
|
33
|
+
|
|
34
|
+
return lsp.Hover(
|
|
35
|
+
lsp.MarkupContent(lsp.MarkupKind.Markdown, description), text_range
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return lsp.Hover(
|
|
39
|
+
lsp.MarkupContent(
|
|
40
|
+
lsp.MarkupKind.Markdown,
|
|
41
|
+
f"```python\n(variable) {name}\n```",
|
|
42
|
+
),
|
|
43
|
+
text_range,
|
|
44
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
import lsprotocol.types as lsp
|
|
4
|
+
from mecha import AstNode
|
|
5
|
+
from tokenstream import SourceLocation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def node_location_to_range(node: AstNode | Iterable[SourceLocation]):
|
|
9
|
+
if isinstance(node, AstNode):
|
|
10
|
+
location = node.location
|
|
11
|
+
end_location = node.end_location
|
|
12
|
+
else:
|
|
13
|
+
location, end_location = node
|
|
14
|
+
|
|
15
|
+
return lsp.Range(
|
|
16
|
+
start=location_to_position(location), end=location_to_position(end_location)
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def node_start_to_range(node: AstNode):
|
|
21
|
+
start = location_to_position(node.location)
|
|
22
|
+
end = lsp.Position(line=start.line, character=start.character + 1)
|
|
23
|
+
|
|
24
|
+
return lsp.Range(start=start, end=end)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def location_to_position(location: SourceLocation) -> lsp.Position:
|
|
28
|
+
return lsp.Position(
|
|
29
|
+
line=max(location.lineno - 1, 0),
|
|
30
|
+
character=max(location.colno - 1, 0),
|
|
31
|
+
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, TypeVar
|
|
3
|
+
|
|
4
|
+
from beet import NamespaceFile
|
|
5
|
+
from mecha import AstNode
|
|
6
|
+
|
|
7
|
+
from ..reflection import UNKNOWN_TYPE
|
|
8
|
+
|
|
9
|
+
METADATA_KEY = "aegis_metadata"
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"BaseMetadata",
|
|
13
|
+
"VariableMetadata",
|
|
14
|
+
"ResourceLocationMetadata",
|
|
15
|
+
"attach_metadata",
|
|
16
|
+
"retrieve_metadata",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class BaseMetadata:
|
|
22
|
+
"""
|
|
23
|
+
BaseMetadata provides information to aegis_server about the AstNode.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class VariableMetadata(BaseMetadata):
|
|
29
|
+
"""
|
|
30
|
+
VariableMetadata provides information to aegis_server about a node representing a Bolt variable
|
|
31
|
+
|
|
32
|
+
Attributes
|
|
33
|
+
----------
|
|
34
|
+
type_annotation : Any
|
|
35
|
+
The python type that the node represents
|
|
36
|
+
|
|
37
|
+
documentation : str
|
|
38
|
+
The documentation string for the node
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
type_annotation: Any = field(default=UNKNOWN_TYPE)
|
|
42
|
+
|
|
43
|
+
documentation: str | None = field(default=None)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class ResourceLocationMetadata(BaseMetadata):
|
|
48
|
+
"""
|
|
49
|
+
ResourceLocationMetadata provides information to aegis_server about a node representing a resource location node
|
|
50
|
+
|
|
51
|
+
Attributes
|
|
52
|
+
----------
|
|
53
|
+
respresents : str | type[NamespaceFile] | None
|
|
54
|
+
The registry or type of File the resource location represents
|
|
55
|
+
|
|
56
|
+
unresolved_path : str | None
|
|
57
|
+
The unresolved path of the string, ex. ~/foo
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
represents: str | type[NamespaceFile] | None = field(default=None)
|
|
61
|
+
|
|
62
|
+
unresolved_path: str | None = field(default=None)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def attach_metadata(node: AstNode, metadata: BaseMetadata):
|
|
66
|
+
"""
|
|
67
|
+
Attaches the provided metadata instance to the node
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
node : AstNode
|
|
72
|
+
The node to attach the metadata too
|
|
73
|
+
metadata : BaseMetadata
|
|
74
|
+
The metadata to be attached
|
|
75
|
+
"""
|
|
76
|
+
node.__dict__[METADATA_KEY] = metadata
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
T = TypeVar("T")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def retrieve_metadata(
|
|
83
|
+
node: AstNode, type: tuple[type[T]] | type[T] = BaseMetadata
|
|
84
|
+
) -> T | None:
|
|
85
|
+
"""
|
|
86
|
+
Retrieves the metadata attached to a node
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
node : AstNode
|
|
91
|
+
The node to retrieve from
|
|
92
|
+
type : tuple[type] | type
|
|
93
|
+
The type to check the metadata for
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
BaseMetadata
|
|
98
|
+
The metadata attached to the node
|
|
99
|
+
None
|
|
100
|
+
If not metadata is present on the node
|
|
101
|
+
"""
|
|
102
|
+
metadata = node.__dict__.get(METADATA_KEY)
|
|
103
|
+
|
|
104
|
+
if isinstance(metadata, type):
|
|
105
|
+
return metadata
|
|
106
|
+
|
|
107
|
+
return None
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .project_index import *
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from threading import Lock
|
|
6
|
+
from typing import ClassVar
|
|
7
|
+
|
|
8
|
+
from beet import Context, File, NamespaceFile
|
|
9
|
+
from beet.core.utils import extra_field, required_field
|
|
10
|
+
from tokenstream import SourceLocation
|
|
11
|
+
|
|
12
|
+
__all__ = ["FilePointer", "ResourceIndex", "AegisProjectIndex"]
|
|
13
|
+
|
|
14
|
+
FilePointer = tuple[SourceLocation, SourceLocation]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ResourceIndice:
|
|
19
|
+
definitions: dict[str, set[FilePointer]] = extra_field(default_factory=dict)
|
|
20
|
+
references: dict[str, set[FilePointer]] = extra_field(default_factory=dict)
|
|
21
|
+
|
|
22
|
+
def _dump(self) -> str:
|
|
23
|
+
dump = ""
|
|
24
|
+
|
|
25
|
+
dump += "definitions:\n"
|
|
26
|
+
for path, pointers in self.definitions.items():
|
|
27
|
+
for pointer in pointers:
|
|
28
|
+
dump += f"\t- {path} {pointer[0].lineno}:{pointer[0].colno} -> {pointer[1].lineno}:{pointer[1].colno}\n"
|
|
29
|
+
dump += "references:\n"
|
|
30
|
+
for path, pointers in self.references.items():
|
|
31
|
+
for pointer in pointers:
|
|
32
|
+
dump += f"\t- {path} {pointer[0].lineno}:{pointer[0].colno} -> {pointer[1].lineno}:{pointer[1].colno}\n"
|
|
33
|
+
|
|
34
|
+
return dump
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def valid_resource_location(path: str):
|
|
38
|
+
return bool(re.match(r"^[a-z0-9_\.]+:[a-z0-9_\.]+(\/?[a-z0-9_\.]+)*$", path))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ResourceIndex:
|
|
43
|
+
_files: dict[str, ResourceIndice] = extra_field(default_factory=dict)
|
|
44
|
+
_lock: Lock = extra_field(default_factory=Lock)
|
|
45
|
+
|
|
46
|
+
def remove_associated(self, path: str | File):
|
|
47
|
+
self._lock.acquire()
|
|
48
|
+
|
|
49
|
+
if isinstance(path, File):
|
|
50
|
+
path = str(Path(path.ensure_source_path()).absolute())
|
|
51
|
+
|
|
52
|
+
for file, indice in list(self._files.items()):
|
|
53
|
+
if path in indice.definitions:
|
|
54
|
+
del indice.definitions[path]
|
|
55
|
+
if path in indice.references:
|
|
56
|
+
del indice.references[path]
|
|
57
|
+
|
|
58
|
+
if len(indice.definitions) == 0:
|
|
59
|
+
del self._files[file]
|
|
60
|
+
|
|
61
|
+
self._lock.release()
|
|
62
|
+
|
|
63
|
+
def add_definition(
|
|
64
|
+
self,
|
|
65
|
+
resource_path: str,
|
|
66
|
+
source_path: str,
|
|
67
|
+
source_location: FilePointer = (
|
|
68
|
+
SourceLocation(0, 0, 0),
|
|
69
|
+
SourceLocation(0, 0, 0),
|
|
70
|
+
),
|
|
71
|
+
):
|
|
72
|
+
if not valid_resource_location(resource_path):
|
|
73
|
+
raise Exception(f"Invalid resource location {resource_path}")
|
|
74
|
+
|
|
75
|
+
self._lock.acquire()
|
|
76
|
+
|
|
77
|
+
indice = self._files.setdefault(resource_path, ResourceIndice())
|
|
78
|
+
locations = indice.definitions.setdefault(source_path, set())
|
|
79
|
+
locations.add(source_location)
|
|
80
|
+
|
|
81
|
+
self._lock.release()
|
|
82
|
+
|
|
83
|
+
def get_definitions(
|
|
84
|
+
self, resource_path: str
|
|
85
|
+
) -> list[tuple[str, SourceLocation, SourceLocation]]:
|
|
86
|
+
if not (file := self._files.get(resource_path)):
|
|
87
|
+
return []
|
|
88
|
+
|
|
89
|
+
definitions = []
|
|
90
|
+
for path, locations in file.definitions.items():
|
|
91
|
+
for location in locations:
|
|
92
|
+
definitions.append((path, *location))
|
|
93
|
+
|
|
94
|
+
return definitions
|
|
95
|
+
|
|
96
|
+
def get_references(
|
|
97
|
+
self, resource_path: str
|
|
98
|
+
) -> list[tuple[str, SourceLocation, SourceLocation]]:
|
|
99
|
+
if not (file := self._files.get(resource_path)):
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
references = []
|
|
103
|
+
for path, locations in file.references.items():
|
|
104
|
+
for location in locations:
|
|
105
|
+
references.append((path, *location))
|
|
106
|
+
|
|
107
|
+
return references
|
|
108
|
+
|
|
109
|
+
def add_reference(
|
|
110
|
+
self,
|
|
111
|
+
resource_path: str,
|
|
112
|
+
source_path: str,
|
|
113
|
+
source_location: FilePointer = (
|
|
114
|
+
SourceLocation(0, 0, 0),
|
|
115
|
+
SourceLocation(0, 0, 0),
|
|
116
|
+
),
|
|
117
|
+
):
|
|
118
|
+
if not valid_resource_location(resource_path):
|
|
119
|
+
raise Exception(f"Invalid resource location {resource_path}")
|
|
120
|
+
|
|
121
|
+
self._lock.acquire()
|
|
122
|
+
|
|
123
|
+
indice = self._files.setdefault(resource_path, ResourceIndice())
|
|
124
|
+
locations = indice.references.setdefault(source_path, set())
|
|
125
|
+
locations.add(source_location)
|
|
126
|
+
|
|
127
|
+
self._lock.release()
|
|
128
|
+
|
|
129
|
+
def __iter__(self):
|
|
130
|
+
items = self._files.keys()
|
|
131
|
+
|
|
132
|
+
for item in items:
|
|
133
|
+
yield item
|
|
134
|
+
|
|
135
|
+
def _dump(self) -> str:
|
|
136
|
+
dump = ""
|
|
137
|
+
|
|
138
|
+
for file, indice in self._files.items():
|
|
139
|
+
dump += f"\n- '{file}':\n"
|
|
140
|
+
dump += "\t" + "\n\t".join(indice._dump().splitlines())
|
|
141
|
+
|
|
142
|
+
return dump
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class AegisProjectIndex:
|
|
147
|
+
_ctx: Context
|
|
148
|
+
_resources: dict[type[NamespaceFile], ResourceIndex] = field(default_factory=dict)
|
|
149
|
+
|
|
150
|
+
resource_name_to_type: dict[str, type[NamespaceFile]] = field(default_factory=dict)
|
|
151
|
+
|
|
152
|
+
def __post_init__(self):
|
|
153
|
+
self.resource_name_to_type = {
|
|
154
|
+
t.snake_name: t for t in self._ctx.get_file_types()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
def __getitem__(self, key: type[NamespaceFile]):
|
|
158
|
+
return self._resources.setdefault(key, ResourceIndex())
|
|
159
|
+
|
|
160
|
+
def remove_associated(self, path: str):
|
|
161
|
+
for resource in self._resources.values():
|
|
162
|
+
resource.remove_associated(path)
|
|
163
|
+
|
|
164
|
+
def dump(self) -> str:
|
|
165
|
+
dump = ""
|
|
166
|
+
for resource, index in self._resources.items():
|
|
167
|
+
dump += f"\nResource {resource.__name__}:"
|
|
168
|
+
dump += "\t" + "\n\t".join(index._dump().splitlines())
|
|
169
|
+
|
|
170
|
+
return dump
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import types
|
|
3
|
+
import typing
|
|
4
|
+
from copy import copy
|
|
5
|
+
from dataclasses import dataclass, field, fields, is_dataclass
|
|
6
|
+
from typing import Any, get_args, get_origin
|
|
7
|
+
|
|
8
|
+
UNKNOWN_TYPE = object()
|
|
9
|
+
TYPE_TO_INFO: dict[type, "TypeInfo"] = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class ParameterInfo:
|
|
14
|
+
annotation: Any
|
|
15
|
+
default: Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class FunctionInfo:
|
|
20
|
+
parameters: list[tuple[str, ParameterInfo]]
|
|
21
|
+
return_annotation: Any
|
|
22
|
+
doc: str | None
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_signature(
|
|
26
|
+
signature: inspect.Signature, doc: str | None, hints: dict[str, Any]
|
|
27
|
+
) -> "FunctionInfo":
|
|
28
|
+
return FunctionInfo(
|
|
29
|
+
parameters=[
|
|
30
|
+
(
|
|
31
|
+
name,
|
|
32
|
+
ParameterInfo(
|
|
33
|
+
annotation=parameter.annotation, default=parameter.default
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
for name, parameter in signature.parameters.items()
|
|
37
|
+
],
|
|
38
|
+
return_annotation=hints.get("return") or signature.return_annotation,
|
|
39
|
+
doc=doc,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def extract(field_value: Any):
|
|
44
|
+
try:
|
|
45
|
+
hints = typing.get_type_hints(field_value)
|
|
46
|
+
signature = inspect.signature(field_value)
|
|
47
|
+
return FunctionInfo.from_signature(signature, field_value.__doc__, hints)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
return FunctionInfo(
|
|
50
|
+
parameters=[
|
|
51
|
+
(
|
|
52
|
+
"???",
|
|
53
|
+
ParameterInfo(inspect.Parameter.empty, inspect.Parameter.empty),
|
|
54
|
+
)
|
|
55
|
+
],
|
|
56
|
+
return_annotation=UNKNOWN_TYPE,
|
|
57
|
+
doc="Error while extracting signature: " + str(e),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def __hash__(self) -> int:
|
|
61
|
+
return hash(self.__repr__())
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass
|
|
65
|
+
class TypeInfo:
|
|
66
|
+
doc: str | None
|
|
67
|
+
fields: dict[str, Any] = field(default_factory=dict)
|
|
68
|
+
functions: dict[str, FunctionInfo] = field(default_factory=dict)
|
|
69
|
+
|
|
70
|
+
def get_member(self, field_name: str) -> Any | FunctionInfo:
|
|
71
|
+
return self.fields.get(field_name) or self.functions.get(field_name)
|
|
72
|
+
|
|
73
|
+
def add_member(
|
|
74
|
+
self,
|
|
75
|
+
field_annotations: dict[str, Any],
|
|
76
|
+
field_name: str,
|
|
77
|
+
field_value: Any,
|
|
78
|
+
skip_fields=False,
|
|
79
|
+
):
|
|
80
|
+
if (
|
|
81
|
+
inspect.isfunction(field_value)
|
|
82
|
+
or inspect.ismethod(field_value)
|
|
83
|
+
or inspect.ismethoddescriptor(field_value)
|
|
84
|
+
or inspect.isbuiltin(field_value)
|
|
85
|
+
):
|
|
86
|
+
self.functions[field_name] = FunctionInfo.extract(field_value)
|
|
87
|
+
|
|
88
|
+
elif skip_fields:
|
|
89
|
+
return
|
|
90
|
+
elif field_name in field_annotations:
|
|
91
|
+
self.fields[field_name] = field_annotations[field_name]
|
|
92
|
+
elif _ := get_origin(field_value):
|
|
93
|
+
self.fields[field_name] = field_value
|
|
94
|
+
else:
|
|
95
|
+
self.fields[field_name] = type(field_value)
|
|
96
|
+
|
|
97
|
+
def __hash__(self) -> int:
|
|
98
|
+
return hash(self.__repr__())
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_type_info(_type: type) -> TypeInfo:
|
|
102
|
+
|
|
103
|
+
if _type in TYPE_TO_INFO:
|
|
104
|
+
return TYPE_TO_INFO[type]
|
|
105
|
+
|
|
106
|
+
info = TypeInfo(_type.__doc__)
|
|
107
|
+
|
|
108
|
+
# logging.debug("\n\n")
|
|
109
|
+
# logging.debug("-" * 50)
|
|
110
|
+
# logging.debug("Indexing type " + _type.__name__)
|
|
111
|
+
|
|
112
|
+
field_annotations = (
|
|
113
|
+
inspect.get_annotations(_type)
|
|
114
|
+
if inspect.isclass(_type) or callable(_type) or inspect.ismodule(_type)
|
|
115
|
+
else {}
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if is_dataclass(_type):
|
|
119
|
+
handled_fields = set()
|
|
120
|
+
for field in fields(_type):
|
|
121
|
+
info.add_member({}, field.name, field.type)
|
|
122
|
+
handled_fields.add(field.name)
|
|
123
|
+
for field_name, field_value in inspect.getmembers(_type):
|
|
124
|
+
if field_name in handled_fields:
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
# field_value = getattr(_type, field_name)
|
|
128
|
+
info.add_member(field_annotations, field_name, field_value)
|
|
129
|
+
else:
|
|
130
|
+
for field_name, field_value in inspect.getmembers(_type):
|
|
131
|
+
# field_value = getattr(_type, field_name)
|
|
132
|
+
# logging.debug(f"{field_name}, {field_value}")
|
|
133
|
+
info.add_member(field_annotations, field_name, field_value)
|
|
134
|
+
|
|
135
|
+
# logging.debug("-" * 50)
|
|
136
|
+
# logging.debug("\n\n")
|
|
137
|
+
# logging.debug(info)
|
|
138
|
+
return info
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def get_name_of_type(annotation):
|
|
142
|
+
if annotation is inspect.Parameter.empty:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
if annotation is types.NoneType:
|
|
146
|
+
return "None"
|
|
147
|
+
|
|
148
|
+
if annotation is UNKNOWN_TYPE:
|
|
149
|
+
return "???"
|
|
150
|
+
|
|
151
|
+
origin = typing.get_origin(annotation)
|
|
152
|
+
args = list(map(str, map(get_name_of_type, typing.get_args(annotation))))
|
|
153
|
+
|
|
154
|
+
if origin is typing.Union or origin is types.UnionType:
|
|
155
|
+
return " | ".join(args)
|
|
156
|
+
elif origin:
|
|
157
|
+
return f"{origin.__name__}[{', '.join(args)}]"
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
return annotation.__repr__()
|
|
161
|
+
except:
|
|
162
|
+
return annotation.__name__ if hasattr(annotation, "__name__") else annotation
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def format_function_hints(
|
|
166
|
+
name: str,
|
|
167
|
+
signature: FunctionInfo,
|
|
168
|
+
keyword: str = "def",
|
|
169
|
+
show_return_type: bool = True,
|
|
170
|
+
):
|
|
171
|
+
hint = f"{keyword} {name}("
|
|
172
|
+
|
|
173
|
+
return_type = signature.return_annotation
|
|
174
|
+
|
|
175
|
+
parameters = []
|
|
176
|
+
|
|
177
|
+
for name, parameter in signature.parameters:
|
|
178
|
+
annotation = get_name_of_type(parameter.annotation)
|
|
179
|
+
|
|
180
|
+
if annotation is None and parameter.default is not inspect.Parameter.empty:
|
|
181
|
+
annotation = get_name_of_type(type(parameter.default))
|
|
182
|
+
|
|
183
|
+
annotation_string = ": " + str(annotation) if annotation else ""
|
|
184
|
+
default_string = (
|
|
185
|
+
" = " + parameter.default.__repr__() # type: ignore
|
|
186
|
+
if parameter.default is not inspect.Parameter.empty
|
|
187
|
+
else ""
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
parameters.append(f"\n\t{name}{annotation_string}{default_string}")
|
|
191
|
+
|
|
192
|
+
hint += ",".join(parameters)
|
|
193
|
+
|
|
194
|
+
hint += f"\n)"
|
|
195
|
+
|
|
196
|
+
if show_return_type and signature.return_annotation is not types.NoneType:
|
|
197
|
+
hint += f" -> {get_name_of_type(return_type)}"
|
|
198
|
+
|
|
199
|
+
return hint
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def get_doc_string(doc: Any):
|
|
203
|
+
return "\n---\n" + doc if isinstance(doc, str) else ""
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_variable_description(name: str, value: Any):
|
|
207
|
+
if inspect.isclass(value):
|
|
208
|
+
return f"```python\n(variable) {name}: {get_name_of_type(value)}\n```"
|
|
209
|
+
|
|
210
|
+
doc_string = get_doc_string(value.__doc__)
|
|
211
|
+
return f"```python\n(variable) {name}: {get_name_of_type(type(value))}\n```{doc_string}"
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_class_description(name: str, value: type | TypeInfo):
|
|
215
|
+
if not isinstance(value, TypeInfo):
|
|
216
|
+
value = get_type_info(value)
|
|
217
|
+
|
|
218
|
+
doc_string = get_doc_string(value.doc)
|
|
219
|
+
|
|
220
|
+
if not (init := value.functions.get("__init__")):
|
|
221
|
+
return f"```python\nclass {name}()\n```{doc_string}"
|
|
222
|
+
|
|
223
|
+
init = copy(init)
|
|
224
|
+
|
|
225
|
+
if len(init.parameters) > 0:
|
|
226
|
+
init.parameters.pop(0)
|
|
227
|
+
|
|
228
|
+
return f"```python\n{format_function_hints(name, init, keyword='class', show_return_type=False)}\n```{doc_string}"
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def get_function_description(name: str, function: Any):
|
|
232
|
+
function_info = None
|
|
233
|
+
if isinstance(function, FunctionInfo):
|
|
234
|
+
function_info = function
|
|
235
|
+
else:
|
|
236
|
+
function_info = FunctionInfo.extract(function)
|
|
237
|
+
|
|
238
|
+
doc_string = get_doc_string(function_info.doc)
|
|
239
|
+
|
|
240
|
+
return f"```py\n{format_function_hints(name, function_info)}\n```{doc_string}"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def get_annotation_description(name: str, type_annotation: Any):
|
|
244
|
+
if get_origin(type_annotation) is type:
|
|
245
|
+
args = get_args(type_annotation)
|
|
246
|
+
description = get_class_description(name, args[0])
|
|
247
|
+
elif isinstance(type_annotation, TypeInfo):
|
|
248
|
+
description = get_class_description(name, type_annotation)
|
|
249
|
+
elif (
|
|
250
|
+
inspect.isfunction(type_annotation)
|
|
251
|
+
or inspect.isbuiltin(type_annotation)
|
|
252
|
+
or isinstance(type_annotation, FunctionInfo)
|
|
253
|
+
):
|
|
254
|
+
description = get_function_description(name, type_annotation)
|
|
255
|
+
else:
|
|
256
|
+
description = get_variable_description(name, type_annotation)
|
|
257
|
+
|
|
258
|
+
return description
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from beet import Context
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class AegisGameRegistries:
|
|
8
|
+
ctx: Context
|
|
9
|
+
|
|
10
|
+
registries: dict[str, list[str]] = field(init=False, default_factory=dict)
|
|
11
|
+
|
|
12
|
+
def __getitem__(self, registry: str) -> list[str]:
|
|
13
|
+
return self.registries.get(registry) or []
|
|
14
|
+
|
|
15
|
+
def __contains__(self, registry: str) -> bool:
|
|
16
|
+
return registry in self.registries
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Literal, Union
|
|
2
|
+
|
|
3
|
+
TokenModifier = Union[
|
|
4
|
+
Literal["declaration"],
|
|
5
|
+
Literal["definition"],
|
|
6
|
+
Literal["readonly"],
|
|
7
|
+
Literal["static"],
|
|
8
|
+
Literal["deprecated"],
|
|
9
|
+
Literal["abstract"],
|
|
10
|
+
Literal["async"],
|
|
11
|
+
Literal["modification"],
|
|
12
|
+
Literal["documentation"],
|
|
13
|
+
Literal["defaultLibrary"],
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
TokenType = Union[
|
|
17
|
+
Literal["comment"],
|
|
18
|
+
Literal["string"],
|
|
19
|
+
Literal["keyword"],
|
|
20
|
+
Literal["number"],
|
|
21
|
+
Literal["regexp"],
|
|
22
|
+
Literal["operator"],
|
|
23
|
+
Literal["namespace"],
|
|
24
|
+
Literal["type"],
|
|
25
|
+
Literal["struct"],
|
|
26
|
+
Literal["class"],
|
|
27
|
+
Literal["interface"],
|
|
28
|
+
Literal["enum"],
|
|
29
|
+
Literal["typeParameter"],
|
|
30
|
+
Literal["function"],
|
|
31
|
+
Literal["method"],
|
|
32
|
+
Literal["decorator"],
|
|
33
|
+
Literal["macro"],
|
|
34
|
+
Literal["variable"],
|
|
35
|
+
Literal["parameter"],
|
|
36
|
+
Literal["property"],
|
|
37
|
+
Literal["label"],
|
|
38
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "aegis_core"
|
|
3
|
+
version = "1.5.2"
|
|
4
|
+
description = "A library to manipulate Mecha for language server usage"
|
|
5
|
+
authors = ["TheNuclearNexus <39636175+TheNuclearNexus@users.noreply.github.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = "^3.10"
|
|
11
|
+
mecha = "^0.96.0"
|
|
12
|
+
bolt = "^0.49.1"
|
|
13
|
+
lsprotocol = "^2023.0.1"
|
|
14
|
+
|
|
15
|
+
[tool.poetry.group.dev.dependencies]
|
|
16
|
+
isort = "^6.0.0"
|
|
17
|
+
black = "^25.1.0"
|
|
18
|
+
pytest = "^8.1.1"
|
|
19
|
+
|
|
20
|
+
[tool.isort]
|
|
21
|
+
profile = "black"
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["poetry-core"]
|
|
25
|
+
build-backend = "poetry.core.masonry.api"
|