unidecompiler-gui-sdk 0.1.0__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.
- unidecompiler_gui_sdk-0.1.0/PKG-INFO +79 -0
- unidecompiler_gui_sdk-0.1.0/README.md +67 -0
- unidecompiler_gui_sdk-0.1.0/pyproject.toml +20 -0
- unidecompiler_gui_sdk-0.1.0/setup.cfg +4 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk/__init__.py +29 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk/api.py +202 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk.egg-info/PKG-INFO +79 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk.egg-info/SOURCES.txt +8 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk.egg-info/dependency_links.txt +1 -0
- unidecompiler_gui_sdk-0.1.0/src/unidecompiler_gui_sdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unidecompiler-gui-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Stable read-only plugin API for unidecompiler-gui
|
|
5
|
+
Author-email: Wker <1670133844@qq.com>
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/Wker666/unidecompiler
|
|
8
|
+
Project-URL: Repository, https://github.com/Wker666/unidecompiler
|
|
9
|
+
Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# unidecompiler-gui-sdk
|
|
14
|
+
|
|
15
|
+
Stable, read-only API for trusted `unidecompiler-gui` Python plugins. The SDK
|
|
16
|
+
does not depend on Qt, core internals, frontends, or the simulator implementation.
|
|
17
|
+
|
|
18
|
+
Install it directly when developing a plugin:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
python -m pip install unidecompiler-gui-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
End users do not need to install it separately: `unidecompiler-gui` depends on
|
|
25
|
+
the matching SDK API.
|
|
26
|
+
|
|
27
|
+
## Minimal Plugin
|
|
28
|
+
|
|
29
|
+
Place `plugin.toml` and the declared entry module in one directory:
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[plugin]
|
|
33
|
+
id = "example.workspace-inspector"
|
|
34
|
+
name = "Workspace Inspector"
|
|
35
|
+
version = "1.0.0"
|
|
36
|
+
api = "1"
|
|
37
|
+
entry = "workspace_inspector:register"
|
|
38
|
+
|
|
39
|
+
[python]
|
|
40
|
+
requires = []
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from unidecompiler_gui_sdk import Command, Panel, PanelState
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def register(context):
|
|
48
|
+
context.panels.register(Panel("summary", "Summary"))
|
|
49
|
+
|
|
50
|
+
def refresh(plugin_context):
|
|
51
|
+
document = plugin_context.active_document
|
|
52
|
+
text = "No active document" if document is None else document.display_name
|
|
53
|
+
plugin_context.set_panel_state("summary", PanelState.text_view(text))
|
|
54
|
+
|
|
55
|
+
context.commands.register(Command("refresh", "Refresh summary", refresh))
|
|
56
|
+
context.subscribe("document_selected", lambda _document: refresh(context))
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The plugin entry function receives a plugin-scoped context. Plugins are trusted
|
|
60
|
+
in-process code, are not sandboxed, and must not import Qt or private
|
|
61
|
+
decompiler/simulator modules. See the repository's
|
|
62
|
+
`docs/GUI_PLUGIN_DEVELOPMENT.md` for the complete contract.
|
|
63
|
+
|
|
64
|
+
The GUI calls the manifest entry function with a plugin-scoped `PluginContext`.
|
|
65
|
+
Context snapshots are frozen data and navigation/simulation are host requests.
|
|
66
|
+
Register extensions through `context.commands.register(Command(...))` and
|
|
67
|
+
`context.panels.register(Panel(...))`; panels use `PanelState` data rather than
|
|
68
|
+
Qt widgets. The SDK exposes no generic IR, decoded artifacts, frontends, Qt
|
|
69
|
+
objects, or simulator execution internals.
|
|
70
|
+
|
|
71
|
+
For simulation, request frontend-owned targets with
|
|
72
|
+
`request_simulation_targets(document_id)`. The asynchronous target job returns
|
|
73
|
+
`SimulationTargetSnapshot` values containing a display label, parameter names,
|
|
74
|
+
and an opaque query. Pass that query unchanged to `submit_simulation`. Finished
|
|
75
|
+
jobs contain SDK-owned `SimulationResultSnapshot` and
|
|
76
|
+
`SimulationEventSnapshot` data, never simulator implementation objects.
|
|
77
|
+
|
|
78
|
+
`context.settings` stores JSON-compatible values under the current plugin ID;
|
|
79
|
+
one plugin cannot address another plugin's settings namespace.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# unidecompiler-gui-sdk
|
|
2
|
+
|
|
3
|
+
Stable, read-only API for trusted `unidecompiler-gui` Python plugins. The SDK
|
|
4
|
+
does not depend on Qt, core internals, frontends, or the simulator implementation.
|
|
5
|
+
|
|
6
|
+
Install it directly when developing a plugin:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
python -m pip install unidecompiler-gui-sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
End users do not need to install it separately: `unidecompiler-gui` depends on
|
|
13
|
+
the matching SDK API.
|
|
14
|
+
|
|
15
|
+
## Minimal Plugin
|
|
16
|
+
|
|
17
|
+
Place `plugin.toml` and the declared entry module in one directory:
|
|
18
|
+
|
|
19
|
+
```toml
|
|
20
|
+
[plugin]
|
|
21
|
+
id = "example.workspace-inspector"
|
|
22
|
+
name = "Workspace Inspector"
|
|
23
|
+
version = "1.0.0"
|
|
24
|
+
api = "1"
|
|
25
|
+
entry = "workspace_inspector:register"
|
|
26
|
+
|
|
27
|
+
[python]
|
|
28
|
+
requires = []
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from unidecompiler_gui_sdk import Command, Panel, PanelState
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def register(context):
|
|
36
|
+
context.panels.register(Panel("summary", "Summary"))
|
|
37
|
+
|
|
38
|
+
def refresh(plugin_context):
|
|
39
|
+
document = plugin_context.active_document
|
|
40
|
+
text = "No active document" if document is None else document.display_name
|
|
41
|
+
plugin_context.set_panel_state("summary", PanelState.text_view(text))
|
|
42
|
+
|
|
43
|
+
context.commands.register(Command("refresh", "Refresh summary", refresh))
|
|
44
|
+
context.subscribe("document_selected", lambda _document: refresh(context))
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The plugin entry function receives a plugin-scoped context. Plugins are trusted
|
|
48
|
+
in-process code, are not sandboxed, and must not import Qt or private
|
|
49
|
+
decompiler/simulator modules. See the repository's
|
|
50
|
+
`docs/GUI_PLUGIN_DEVELOPMENT.md` for the complete contract.
|
|
51
|
+
|
|
52
|
+
The GUI calls the manifest entry function with a plugin-scoped `PluginContext`.
|
|
53
|
+
Context snapshots are frozen data and navigation/simulation are host requests.
|
|
54
|
+
Register extensions through `context.commands.register(Command(...))` and
|
|
55
|
+
`context.panels.register(Panel(...))`; panels use `PanelState` data rather than
|
|
56
|
+
Qt widgets. The SDK exposes no generic IR, decoded artifacts, frontends, Qt
|
|
57
|
+
objects, or simulator execution internals.
|
|
58
|
+
|
|
59
|
+
For simulation, request frontend-owned targets with
|
|
60
|
+
`request_simulation_targets(document_id)`. The asynchronous target job returns
|
|
61
|
+
`SimulationTargetSnapshot` values containing a display label, parameter names,
|
|
62
|
+
and an opaque query. Pass that query unchanged to `submit_simulation`. Finished
|
|
63
|
+
jobs contain SDK-owned `SimulationResultSnapshot` and
|
|
64
|
+
`SimulationEventSnapshot` data, never simulator implementation objects.
|
|
65
|
+
|
|
66
|
+
`context.settings` stores JSON-compatible values under the current plugin ID;
|
|
67
|
+
one plugin cannot address another plugin's settings namespace.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "unidecompiler-gui-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Stable read-only plugin API for unidecompiler-gui"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "AGPL-3.0-or-later"
|
|
11
|
+
authors = [{ name = "Wker", email = "1670133844@qq.com" }]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Homepage = "https://github.com/Wker666/unidecompiler"
|
|
16
|
+
Repository = "https://github.com/Wker666/unidecompiler"
|
|
17
|
+
Issues = "https://github.com/Wker666/unidecompiler/issues"
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
where = ["src"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Public, GUI-neutral SDK for trusted unidecompiler GUI plugins."""
|
|
2
|
+
|
|
3
|
+
from .api import (
|
|
4
|
+
AstNodeSnapshot,
|
|
5
|
+
CommandRegistrar,
|
|
6
|
+
Command,
|
|
7
|
+
DocumentSnapshot,
|
|
8
|
+
FunctionSnapshot,
|
|
9
|
+
Panel,
|
|
10
|
+
PanelRegistrar,
|
|
11
|
+
PanelState,
|
|
12
|
+
PluginContext,
|
|
13
|
+
PluginSettings,
|
|
14
|
+
ReferenceSnapshot,
|
|
15
|
+
SelectionSnapshot,
|
|
16
|
+
SimulationJobSnapshot,
|
|
17
|
+
SimulationEventSnapshot,
|
|
18
|
+
SimulationResultSnapshot,
|
|
19
|
+
SimulationTargetJobSnapshot,
|
|
20
|
+
SimulationTargetSnapshot,
|
|
21
|
+
SourceLocation,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"AstNodeSnapshot", "Command", "CommandRegistrar", "DocumentSnapshot", "FunctionSnapshot",
|
|
26
|
+
"Panel", "PanelRegistrar", "PanelState", "PluginContext", "PluginSettings", "ReferenceSnapshot",
|
|
27
|
+
"SelectionSnapshot", "SimulationEventSnapshot", "SimulationJobSnapshot", "SimulationResultSnapshot",
|
|
28
|
+
"SimulationTargetJobSnapshot", "SimulationTargetSnapshot", "SourceLocation",
|
|
29
|
+
]
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Versioned data contracts shared by GUI plugins and the GUI host."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any, Callable, Protocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
API_VERSION = "1"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class SourceLocation:
|
|
13
|
+
frontend: str
|
|
14
|
+
offset: int | None
|
|
15
|
+
line: int | None = None
|
|
16
|
+
detail: str | None = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class FunctionSnapshot:
|
|
21
|
+
id: str
|
|
22
|
+
name: str
|
|
23
|
+
status: str
|
|
24
|
+
params: tuple[str, ...] = ()
|
|
25
|
+
source: SourceLocation | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class AstNodeSnapshot:
|
|
30
|
+
id: str
|
|
31
|
+
kind: str
|
|
32
|
+
source: SourceLocation | None = None
|
|
33
|
+
children: tuple["AstNodeSnapshot", ...] = ()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class ReferenceSnapshot:
|
|
38
|
+
kind: str
|
|
39
|
+
name: str
|
|
40
|
+
function_id: str | None
|
|
41
|
+
source: SourceLocation | None = None
|
|
42
|
+
target_ids: tuple[str, ...] = ()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class DocumentSnapshot:
|
|
47
|
+
id: str
|
|
48
|
+
display_name: str
|
|
49
|
+
status: str
|
|
50
|
+
frontend_id: str | None
|
|
51
|
+
revision: int
|
|
52
|
+
functions: tuple[FunctionSnapshot, ...] = ()
|
|
53
|
+
pseudocode: str = ""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class SelectionSnapshot:
|
|
58
|
+
document_id: str | None = None
|
|
59
|
+
function_id: str | None = None
|
|
60
|
+
source: SourceLocation | None = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class SimulationEventSnapshot:
|
|
65
|
+
kind: str
|
|
66
|
+
function: str
|
|
67
|
+
block: str | None = None
|
|
68
|
+
detail: str = ""
|
|
69
|
+
source: SourceLocation | None = None
|
|
70
|
+
args: tuple[Any, ...] = ()
|
|
71
|
+
values: tuple[Any, ...] = ()
|
|
72
|
+
exception: str | None = None
|
|
73
|
+
stdout: str = ""
|
|
74
|
+
stderr: str = ""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(frozen=True)
|
|
78
|
+
class SimulationResultSnapshot:
|
|
79
|
+
status: str
|
|
80
|
+
values: tuple[Any, ...] = ()
|
|
81
|
+
exception: str | None = None
|
|
82
|
+
cause: str | None = None
|
|
83
|
+
locals: tuple[tuple[str, Any], ...] = ()
|
|
84
|
+
steps: int = 0
|
|
85
|
+
diagnostic: str | None = None
|
|
86
|
+
events: tuple[SimulationEventSnapshot, ...] = ()
|
|
87
|
+
trace_truncated: bool = False
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass(frozen=True)
|
|
91
|
+
class SimulationTargetSnapshot:
|
|
92
|
+
"""Presentation-safe simulator target with a frontend-owned opaque query."""
|
|
93
|
+
|
|
94
|
+
label: str
|
|
95
|
+
query: object
|
|
96
|
+
params: tuple[str, ...] = ()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass(frozen=True)
|
|
100
|
+
class SimulationTargetJobSnapshot:
|
|
101
|
+
id: str
|
|
102
|
+
document_id: str
|
|
103
|
+
revision: int
|
|
104
|
+
status: str
|
|
105
|
+
targets: tuple[SimulationTargetSnapshot, ...] = ()
|
|
106
|
+
diagnostic: str | None = None
|
|
107
|
+
stale: bool = False
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass(frozen=True)
|
|
111
|
+
class SimulationJobSnapshot:
|
|
112
|
+
id: str
|
|
113
|
+
document_id: str
|
|
114
|
+
revision: int
|
|
115
|
+
status: str
|
|
116
|
+
result: SimulationResultSnapshot | None = None
|
|
117
|
+
diagnostic: str | None = None
|
|
118
|
+
stale: bool = False
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass(frozen=True)
|
|
122
|
+
class PanelState:
|
|
123
|
+
kind: str
|
|
124
|
+
columns: tuple[str, ...] = ()
|
|
125
|
+
rows: tuple[tuple[str, ...], ...] = ()
|
|
126
|
+
text: str = ""
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def text_view(cls, text: str) -> "PanelState":
|
|
130
|
+
return cls("text", text=text)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def table(cls, columns: tuple[str, ...], rows: tuple[tuple[object, ...], ...]) -> "PanelState":
|
|
134
|
+
return cls("table", columns=columns, rows=tuple(tuple(str(value) for value in row) for row in rows))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
CommandCallback = Callable[["PluginContext"], None]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@dataclass(frozen=True)
|
|
141
|
+
class Command:
|
|
142
|
+
id: str
|
|
143
|
+
title: str
|
|
144
|
+
callback: CommandCallback
|
|
145
|
+
shortcut: str | None = None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclass(frozen=True)
|
|
149
|
+
class Panel:
|
|
150
|
+
id: str
|
|
151
|
+
title: str
|
|
152
|
+
state: PanelState = field(default_factory=lambda: PanelState.text_view(""))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class CommandRegistrar(Protocol):
|
|
156
|
+
def register(self, command: Command) -> None: ...
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class PanelRegistrar(Protocol):
|
|
160
|
+
def register(self, panel: Panel) -> None: ...
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class PluginSettings(Protocol):
|
|
164
|
+
"""JSON-compatible settings isolated to the current plugin ID."""
|
|
165
|
+
|
|
166
|
+
def get(self, key: str, default: Any = None) -> Any: ...
|
|
167
|
+
def set(self, key: str, value: Any) -> None: ...
|
|
168
|
+
def delete(self, key: str) -> None: ...
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class PluginContext(Protocol):
|
|
172
|
+
@property
|
|
173
|
+
def documents(self) -> tuple[DocumentSnapshot, ...]: ...
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def active_document(self) -> DocumentSnapshot | None: ...
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def selection(self) -> SelectionSnapshot: ...
|
|
180
|
+
|
|
181
|
+
def get_document(self, document_id: str) -> DocumentSnapshot | None: ...
|
|
182
|
+
def get_function(self, document_id: str, function_id: str) -> FunctionSnapshot | None: ...
|
|
183
|
+
def get_ast(self, document_id: str, function_id: str | None = None) -> AstNodeSnapshot | None: ...
|
|
184
|
+
def get_references(self, document_id: str, function_id: str | None = None) -> tuple[ReferenceSnapshot, ...]: ...
|
|
185
|
+
def focus_source(self, document_id: str, source: SourceLocation) -> bool: ...
|
|
186
|
+
def focus_function(self, document_id: str, function_id: str) -> bool: ...
|
|
187
|
+
def request_simulation_targets(self, document_id: str) -> SimulationTargetJobSnapshot: ...
|
|
188
|
+
def get_target_job(self, job_id: str) -> SimulationTargetJobSnapshot | None: ...
|
|
189
|
+
def submit_simulation(self, document_id: str, query: object, args: tuple[object, ...] = (), runtime_path: str | None = None) -> SimulationJobSnapshot: ...
|
|
190
|
+
def get_job(self, job_id: str) -> SimulationJobSnapshot | None: ...
|
|
191
|
+
def cancel_job(self, job_id: str) -> bool: ...
|
|
192
|
+
def set_panel_state(self, panel_id: str, state: PanelState) -> None: ...
|
|
193
|
+
def subscribe(self, event: str, callback: Callable[[object], None]) -> Callable[[], None]: ...
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def commands(self) -> CommandRegistrar: ...
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def panels(self) -> PanelRegistrar: ...
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def settings(self) -> PluginSettings: ...
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unidecompiler-gui-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Stable read-only plugin API for unidecompiler-gui
|
|
5
|
+
Author-email: Wker <1670133844@qq.com>
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/Wker666/unidecompiler
|
|
8
|
+
Project-URL: Repository, https://github.com/Wker666/unidecompiler
|
|
9
|
+
Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# unidecompiler-gui-sdk
|
|
14
|
+
|
|
15
|
+
Stable, read-only API for trusted `unidecompiler-gui` Python plugins. The SDK
|
|
16
|
+
does not depend on Qt, core internals, frontends, or the simulator implementation.
|
|
17
|
+
|
|
18
|
+
Install it directly when developing a plugin:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
python -m pip install unidecompiler-gui-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
End users do not need to install it separately: `unidecompiler-gui` depends on
|
|
25
|
+
the matching SDK API.
|
|
26
|
+
|
|
27
|
+
## Minimal Plugin
|
|
28
|
+
|
|
29
|
+
Place `plugin.toml` and the declared entry module in one directory:
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[plugin]
|
|
33
|
+
id = "example.workspace-inspector"
|
|
34
|
+
name = "Workspace Inspector"
|
|
35
|
+
version = "1.0.0"
|
|
36
|
+
api = "1"
|
|
37
|
+
entry = "workspace_inspector:register"
|
|
38
|
+
|
|
39
|
+
[python]
|
|
40
|
+
requires = []
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from unidecompiler_gui_sdk import Command, Panel, PanelState
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def register(context):
|
|
48
|
+
context.panels.register(Panel("summary", "Summary"))
|
|
49
|
+
|
|
50
|
+
def refresh(plugin_context):
|
|
51
|
+
document = plugin_context.active_document
|
|
52
|
+
text = "No active document" if document is None else document.display_name
|
|
53
|
+
plugin_context.set_panel_state("summary", PanelState.text_view(text))
|
|
54
|
+
|
|
55
|
+
context.commands.register(Command("refresh", "Refresh summary", refresh))
|
|
56
|
+
context.subscribe("document_selected", lambda _document: refresh(context))
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The plugin entry function receives a plugin-scoped context. Plugins are trusted
|
|
60
|
+
in-process code, are not sandboxed, and must not import Qt or private
|
|
61
|
+
decompiler/simulator modules. See the repository's
|
|
62
|
+
`docs/GUI_PLUGIN_DEVELOPMENT.md` for the complete contract.
|
|
63
|
+
|
|
64
|
+
The GUI calls the manifest entry function with a plugin-scoped `PluginContext`.
|
|
65
|
+
Context snapshots are frozen data and navigation/simulation are host requests.
|
|
66
|
+
Register extensions through `context.commands.register(Command(...))` and
|
|
67
|
+
`context.panels.register(Panel(...))`; panels use `PanelState` data rather than
|
|
68
|
+
Qt widgets. The SDK exposes no generic IR, decoded artifacts, frontends, Qt
|
|
69
|
+
objects, or simulator execution internals.
|
|
70
|
+
|
|
71
|
+
For simulation, request frontend-owned targets with
|
|
72
|
+
`request_simulation_targets(document_id)`. The asynchronous target job returns
|
|
73
|
+
`SimulationTargetSnapshot` values containing a display label, parameter names,
|
|
74
|
+
and an opaque query. Pass that query unchanged to `submit_simulation`. Finished
|
|
75
|
+
jobs contain SDK-owned `SimulationResultSnapshot` and
|
|
76
|
+
`SimulationEventSnapshot` data, never simulator implementation objects.
|
|
77
|
+
|
|
78
|
+
`context.settings` stores JSON-compatible values under the current plugin ID;
|
|
79
|
+
one plugin cannot address another plugin's settings namespace.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/unidecompiler_gui_sdk/__init__.py
|
|
4
|
+
src/unidecompiler_gui_sdk/api.py
|
|
5
|
+
src/unidecompiler_gui_sdk.egg-info/PKG-INFO
|
|
6
|
+
src/unidecompiler_gui_sdk.egg-info/SOURCES.txt
|
|
7
|
+
src/unidecompiler_gui_sdk.egg-info/dependency_links.txt
|
|
8
|
+
src/unidecompiler_gui_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
unidecompiler_gui_sdk
|