@mudlet/mudlet-web 0.3.1 → 0.4.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.
- package/README.md +8 -0
- package/dist-lib/assets/qt-resources/index.d.ts +16 -0
- package/dist-lib/branding.d.ts +1 -1
- package/dist-lib/hooks/useMudSession.d.ts +1 -1
- package/dist-lib/hooks/useOutput.d.ts +3 -1
- package/dist-lib/import/defaultPackages.d.ts +35 -2
- package/dist-lib/import/defaults/generic_mapper/generic_mapper.mpackage +0 -0
- package/dist-lib/import/defaults/gui-drop/gui-drop.mpackage +0 -0
- package/dist-lib/import/defaults/{run-lua-code.mpackage → mudlet-base-ui/mudlet-base-ui.mpackage} +0 -0
- package/dist-lib/import/defaults/run-lua-code/run-lua-code.mpackage +0 -0
- package/dist-lib/import/packageExport.d.ts +71 -0
- package/dist-lib/import/packageInstaller.d.ts +4 -1
- package/dist-lib/index.js +45935 -40688
- package/dist-lib/logging/SessionLogger.d.ts +66 -1
- package/dist-lib/map/MapStore.d.ts +32 -4
- package/dist-lib/map/mapImageExport.d.ts +1 -1
- package/dist-lib/map/mapZoom.d.ts +71 -0
- package/dist-lib/mud/ItemIdSequence.d.ts +23 -0
- package/dist-lib/mud/MudSession.d.ts +113 -11
- package/dist-lib/mud/PatternEngine.d.ts +6 -1
- package/dist-lib/mud/commandSplit.d.ts +16 -0
- package/dist-lib/mud/connection/LineAssembler.d.ts +56 -0
- package/dist-lib/mud/connection/MudClient.d.ts +120 -16
- package/dist-lib/mud/connection/TelnetNegotiator.d.ts +39 -0
- package/dist-lib/mud/connection/telnetByteTags.d.ts +35 -0
- package/dist-lib/mud/events.d.ts +19 -4
- package/dist-lib/mud/games/bundledGames.d.ts +29 -0
- package/dist-lib/mud/games/gameIcons.d.ts +5 -0
- package/dist-lib/mud/keybindings/KeyEngine.d.ts +9 -2
- package/dist-lib/mud/keybindings/browserReservedKeys.d.ts +5 -1
- package/dist-lib/mud/keybindings/keyEventTarget.d.ts +17 -0
- package/dist-lib/mud/keybindings/qtKeys.d.ts +2 -0
- package/dist-lib/mud/protocol/charLoginFlow.d.ts +68 -0
- package/dist-lib/mud/protocol/charset.d.ts +27 -5
- package/dist-lib/mud/protocol/constants.d.ts +1 -0
- package/dist-lib/mud/protocol/gmcp.d.ts +19 -3
- package/dist-lib/mud/protocol/index.d.ts +1 -1
- package/dist-lib/mud/protocol/mxp.d.ts +28 -5
- package/dist-lib/mud/replay/ReplayPlayer.d.ts +17 -0
- package/dist-lib/mud/text/Console.d.ts +64 -0
- package/dist-lib/mud/text/FormatState.d.ts +66 -3
- package/dist-lib/mud/text/hyperlinkVisibility.d.ts +35 -0
- package/dist-lib/mud/text/osc8Docs.d.ts +23 -0
- package/dist-lib/mud/text/serverWrap.d.ts +191 -0
- package/dist-lib/mud/timers/TimerEngine.d.ts +43 -12
- package/dist-lib/mud/triggers/TriggerEngine.d.ts +112 -3
- package/dist-lib/scripting/EngineHost.d.ts +56 -3
- package/dist-lib/scripting/IScriptingRuntime.d.ts +16 -0
- package/dist-lib/scripting/MxpFrameManager.d.ts +118 -0
- package/dist-lib/scripting/ScriptingAPI.d.ts +323 -54
- package/dist-lib/scripting/ScriptingEngine.d.ts +180 -23
- package/dist-lib/scripting/http/HttpService.d.ts +51 -1
- package/dist-lib/scripting/lua/LuaRuntime.d.ts +151 -2
- package/dist-lib/scripting/lua/bindings/map.d.ts +0 -12
- package/dist-lib/scripting/lua/utf8Patterns.d.ts +59 -0
- package/dist-lib/storage/index.d.ts +1 -1
- package/dist-lib/storage/persistentStorage.d.ts +10 -0
- package/dist-lib/storage/schema.d.ts +116 -0
- package/dist-lib/styles.css +1 -1
- package/dist-lib/ui/BundledGameGrid.d.ts +21 -0
- package/dist-lib/ui/CommandBar.d.ts +7 -1
- package/dist-lib/ui/ConnectionGrid.d.ts +4 -1
- package/dist-lib/ui/FilePickerModal.d.ts +3 -3
- package/dist-lib/ui/HelpModal.d.ts +11 -0
- package/dist-lib/ui/LogBrowserModal.d.ts +4 -1
- package/dist-lib/ui/PlayerMarkerPreview.d.ts +20 -0
- package/dist-lib/ui/Toolbar.d.ts +2 -1
- package/dist-lib/ui/VfsPickerModal.d.ts +26 -0
- package/dist-lib/ui/components/FileSourceButton.d.ts +47 -0
- package/dist-lib/ui/components/index.d.ts +1 -0
- package/dist-lib/ui/helpTopics.d.ts +19 -0
- package/dist-lib/ui/labels/LabelManager.d.ts +7 -0
- package/dist-lib/ui/layout/ScriptWindow.d.ts +11 -2
- package/dist-lib/ui/markdown.d.ts +10 -1
- package/dist-lib/ui/output/OutputArea.d.ts +11 -1
- package/dist-lib/ui/output/OutputContextMenu.d.ts +3 -1
- package/dist-lib/ui/output/OutputRenderer.d.ts +7 -1
- package/dist-lib/ui/output/OutputSearchBar.d.ts +25 -0
- package/dist-lib/ui/output/StickyOutputPanel.d.ts +5 -1
- package/dist-lib/ui/output/outputSearch.d.ts +130 -0
- package/dist-lib/ui/search/matcher.d.ts +15 -0
- package/dist-lib/ui/search/useDebounced.d.ts +3 -0
- package/dist-lib/ui/tts/TtsManager.d.ts +3 -0
- package/dist-lib/ui/useCommandHistory.d.ts +4 -2
- package/dist-lib/ui/useOpenProfiles.d.ts +26 -0
- package/dist-lib/ui/video/VideoManager.d.ts +17 -0
- package/dist-lib/ui/windows/WindowManager.d.ts +132 -2
- package/dist-lib/ui/windows/panels/MapPanel.d.ts +4 -1
- package/dist-lib/ui/windows/panels/PackageExportModal.d.ts +18 -0
- package/dist-lib/ui/windows/panels/TextPanel.d.ts +3 -1
- package/dist-lib/ui/windows/types.d.ts +35 -0
- package/dist-lib/utils/describeThrown.d.ts +22 -0
- package/dist-lib/utils/fontLoader.d.ts +5 -0
- package/dist-lib/vite.js +22 -0
- package/package.json +10 -6
- package/dist-lib/scripting/lua/mudlet-lua/generic-mapper/generic_mapper.mpackage +0 -0
- package/dist-lib/ui/windows/panels/VfsModulePickerModal.d.ts +0 -8
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ItemIdSequence } from '../ItemIdSequence';
|
|
1
2
|
import type { TimerNode } from '../../storage/schema';
|
|
2
3
|
export type { TimerNode };
|
|
3
4
|
type TempFn = () => void;
|
|
@@ -8,15 +9,23 @@ export declare class TimerEngine {
|
|
|
8
9
|
* share a name; we keep id as the canonical handle and build a separate
|
|
9
10
|
* name → id index for Mudlet's name-based lookups. */
|
|
10
11
|
private readonly perm;
|
|
11
|
-
/** Name → first matching id, used by remainingTime / kill-by-name.
|
|
12
|
+
/** Name → first matching id, used by remainingTime / kill-by-name. Only
|
|
13
|
+
* holds *armed* timers, since that is what loadPerm builds handles for. */
|
|
12
14
|
private readonly permNameToId;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
/** Every stored permanent timer name, armed or not. remainingTime needs it
|
|
16
|
+
* to tell "exists but inactive" (-1) from "no such timer" (-2): a disabled
|
|
17
|
+
* timer has no handle, so its absence from `perm` proves nothing. */
|
|
18
|
+
private readonly knownPermNames;
|
|
19
|
+
/** Shared with every other engine in the profile — see ItemIdSequence. */
|
|
20
|
+
private idSeq;
|
|
21
|
+
setIdSequence(seq: ItemIdSequence): void;
|
|
22
|
+
/** Number of live session-scoped temp timers (Mudlet `getProfileStats` temp
|
|
23
|
+
* count). Killed-but-unreaped timers are not live and don't count. */
|
|
15
24
|
get tempCount(): number;
|
|
16
25
|
addTemp(seconds: number, fn: TempFn, repeat?: boolean): number;
|
|
17
26
|
/**
|
|
18
|
-
* Fire every
|
|
19
|
-
*
|
|
27
|
+
* Fire every timer that has come due, without waiting for the event loop to
|
|
28
|
+
* deliver its setTimeout.
|
|
20
29
|
*
|
|
21
30
|
* This exists for `waitForEvent`, the busted-only helper Mudlet implements
|
|
22
31
|
* by spinning a nested QEventLoop. A browser can't re-enter its event loop,
|
|
@@ -24,15 +33,33 @@ export declare class TimerEngine {
|
|
|
24
33
|
* deadlock; pumping the due timers by hand is the equivalent of Qt draining
|
|
25
34
|
* its timer queue inside that nested loop.
|
|
26
35
|
*
|
|
27
|
-
* Repeating timers are
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
36
|
+
* Repeating timers are pumped too — Mudlet's own specs wait on a repeat
|
|
37
|
+
* tick, so skipping them made every such wait time out. That works because
|
|
38
|
+
* a repeat is a self-rescheduling setTimeout (see addTemp): the pending
|
|
39
|
+
* tick is cancelled and re-armed rather than left to land a second time.
|
|
31
40
|
*
|
|
32
41
|
* Returns the number of timers fired.
|
|
33
42
|
*/
|
|
34
43
|
pumpDue(now?: number): number;
|
|
44
|
+
/**
|
|
45
|
+
* Whether a temporary timer with this id is still present.
|
|
46
|
+
*
|
|
47
|
+
* Backs `exists(id, "timer")`. Temp timers aren't in the store and — unlike
|
|
48
|
+
* temp triggers and aliases — aren't tracked in LuaRuntime's tempIds either,
|
|
49
|
+
* so this map is the only thing that knows.
|
|
50
|
+
*
|
|
51
|
+
* There is no enable/disable for a temporary timer, so this used to answer
|
|
52
|
+
* `isActive` too. A killed one splits the two apart: it is still present
|
|
53
|
+
* here until the reap, but no longer running — see {@link tempIsActive}.
|
|
54
|
+
*/
|
|
55
|
+
hasTemp(id: number): boolean;
|
|
56
|
+
/** Whether a temporary timer is present *and* still running — `isActive(id,
|
|
57
|
+
* "timer")`. False for one killed since the last reap. */
|
|
58
|
+
tempIsActive(id: number): boolean;
|
|
35
59
|
killTimer(id: number): boolean;
|
|
60
|
+
/** Free every timer killed since the last call. Runs once per processed line
|
|
61
|
+
* batch, mirroring the deferred cleanup Mudlet's TTimerUnit does. */
|
|
62
|
+
reapKilled(): void;
|
|
36
63
|
/**
|
|
37
64
|
* Cached previous load. `nodes` is the TimerNode keyed by id, `desc` is the
|
|
38
65
|
* shape that determines whether the running setTimeout/setInterval is still
|
|
@@ -50,10 +77,14 @@ export declare class TimerEngine {
|
|
|
50
77
|
* Mudlet `remainingTime(idOrName)` — seconds until the next fire. For
|
|
51
78
|
* non-repeating timers, returns the time left before the one and only
|
|
52
79
|
* fire. For repeating timers, returns the time until the next tick.
|
|
53
|
-
*
|
|
80
|
+
* Mirrors Mudlet's two miss sentinels, which the Lua wrapper turns into
|
|
81
|
+
* different messages: **-1** the timer exists but isn't running (a perm
|
|
82
|
+
* timer starts inactive), **-2** nothing of that id or name exists at all.
|
|
54
83
|
* - Numeric arg: looks up tempTimer ids only.
|
|
55
|
-
* - String arg:
|
|
56
|
-
*
|
|
84
|
+
* - String arg: permanent timer names (or a raw uuid), then temp ids —
|
|
85
|
+
* a temporary timer's "name" is the number tempTimer handed back, so
|
|
86
|
+
* remainingTime(tostring(id)) has to resolve the same timer as
|
|
87
|
+
* remainingTime(id).
|
|
57
88
|
*/
|
|
58
89
|
remainingTime(idOrName: number | string): number;
|
|
59
90
|
private stopPerm;
|
|
@@ -35,9 +35,24 @@ export type TriggerMatch = {
|
|
|
35
35
|
namedSpans?: Record<string, CaptureSpan>;
|
|
36
36
|
matchStart?: number;
|
|
37
37
|
};
|
|
38
|
+
/** The lineage a trigger created mid-pass belongs to, and how many generations
|
|
39
|
+
* deep it sits in it. Absent on a trigger that was not created while a line was
|
|
40
|
+
* being processed. See TriggerEngine.addedWhileProcessing. */
|
|
41
|
+
interface SameLineChain {
|
|
42
|
+
chainId: number;
|
|
43
|
+
generation: number;
|
|
44
|
+
}
|
|
45
|
+
/** What a caller can tell the engine about a temp trigger beyond its pattern. */
|
|
46
|
+
export interface TempOptions {
|
|
47
|
+
/** As the runaway report names it. Mudlet uses the trigger's id when the
|
|
48
|
+
* call carried no name of its own. */
|
|
49
|
+
name?: string;
|
|
50
|
+
onStopped?: () => void;
|
|
51
|
+
}
|
|
38
52
|
export declare class TriggerEngine {
|
|
39
53
|
private readonly temp;
|
|
40
|
-
|
|
54
|
+
/** Key for this engine's own temp map — see PatternEngine.nextInternalId. */
|
|
55
|
+
private nextInternalId;
|
|
41
56
|
private inProcessTemp;
|
|
42
57
|
private permCompiled;
|
|
43
58
|
private allById;
|
|
@@ -45,12 +60,32 @@ export declare class TriggerEngine {
|
|
|
45
60
|
private permReg;
|
|
46
61
|
private unified;
|
|
47
62
|
private orderDirty;
|
|
63
|
+
private processingDepth;
|
|
64
|
+
private addedWhileProcessing;
|
|
65
|
+
/** Lineage of each permanent ROOT trigger enrolled for the current line. */
|
|
66
|
+
private permSameLine;
|
|
67
|
+
/** Lineage id → name of the trigger whose script started it, for the report. */
|
|
68
|
+
private sameLineChainStarters;
|
|
69
|
+
private lastSameLineChainId;
|
|
70
|
+
private currentSameLineChainId;
|
|
71
|
+
private currentSameLineGeneration;
|
|
72
|
+
/** The name of the trigger whose script is running, for the abort report. */
|
|
73
|
+
private currentExecutingTriggerName;
|
|
74
|
+
/** When the runaway report was last posted, so a runaway whose creator
|
|
75
|
+
* outlives its line cannot bury the game text. */
|
|
76
|
+
private lastRunawayReportAt;
|
|
48
77
|
private cache;
|
|
49
78
|
private lineCounter;
|
|
50
79
|
private readonly chainOpenUntil;
|
|
51
80
|
private hasChildren;
|
|
52
81
|
private andStates;
|
|
82
|
+
/** Triggers still firing on their own after completing, and the match they
|
|
83
|
+
* re-report while they do. See the fire-length branch in matchPermEntryOnce. */
|
|
84
|
+
private keepFiring;
|
|
53
85
|
private filterActiveText;
|
|
86
|
+
/** Every offering a filter makes to its children this line: one per
|
|
87
|
+
* capture group, or the whole match when it has none. See openChain. */
|
|
88
|
+
private filterCaptures;
|
|
54
89
|
private filterActiveOffset;
|
|
55
90
|
/** Resolves once PCRE wasm is initialized and patterns can be compiled. */
|
|
56
91
|
static ready(): Promise<void>;
|
|
@@ -78,7 +113,7 @@ export declare class TriggerEngine {
|
|
|
78
113
|
* Invalid regex patterns return a no-op disposer so callers don't need
|
|
79
114
|
* to special-case compile failures.
|
|
80
115
|
*/
|
|
81
|
-
addTemp(pattern: string, fn: TempFn, kind?: 'regex' | 'substring' | 'startOfLine' | 'exactMatch' | 'prompt'): () => void;
|
|
116
|
+
addTemp(pattern: string, fn: TempFn, kind?: 'regex' | 'substring' | 'startOfLine' | 'exactMatch' | 'prompt', opts?: TempOptions): () => void;
|
|
82
117
|
/**
|
|
83
118
|
* Mudlet `tempLineTrigger(from, howMany, fn)`. A position-based trigger with
|
|
84
119
|
* no pattern: it fires `fn([lineText])` on `howMany` consecutive lines,
|
|
@@ -95,9 +130,15 @@ export declare class TriggerEngine {
|
|
|
95
130
|
* negative result is cached so we don't retry on every loadPerm. */
|
|
96
131
|
private compileItem;
|
|
97
132
|
processTemp(line: string, isPrompt?: boolean): void;
|
|
133
|
+
/** Leave a processing pass, and once the outermost one is over, forget the
|
|
134
|
+
* lineages it tracked: a trigger that outlives the line it was created on
|
|
135
|
+
* is no longer part of one, so what IT creates later starts counting
|
|
136
|
+
* afresh. */
|
|
137
|
+
private endPass;
|
|
98
138
|
/** Match + fire a single temp trigger against `line`. Self-expiring `line`
|
|
99
139
|
* triggers delete themselves (and dirty the unified order) when spent. */
|
|
100
140
|
private fireTempEntry;
|
|
141
|
+
private fireTempEntryInner;
|
|
101
142
|
matchPerm(line: string, isPrompt?: boolean): TriggerMatch[];
|
|
102
143
|
/**
|
|
103
144
|
* Match one permanent compiled entry against `line`, appending any matches
|
|
@@ -106,6 +147,9 @@ export declare class TriggerEngine {
|
|
|
106
147
|
* shared across all entries processed for that line.
|
|
107
148
|
*/
|
|
108
149
|
private matchPermEntry;
|
|
150
|
+
/** The nearest filter ancestor of `item`, or null when it has none. */
|
|
151
|
+
private innermostFilterId;
|
|
152
|
+
private matchPermEntryOnce;
|
|
109
153
|
/**
|
|
110
154
|
* Mudlet-faithful single pass: walk the one ordered list of permanent and
|
|
111
155
|
* temporary triggers (see the ordering notes on the fields) and, for each
|
|
@@ -122,6 +166,53 @@ export declare class TriggerEngine {
|
|
|
122
166
|
* re-entrancy a handler can cause via `feedTriggers`.
|
|
123
167
|
*/
|
|
124
168
|
process(line: string, isPrompt: boolean, exec: (match: TriggerMatch) => void): void;
|
|
169
|
+
/**
|
|
170
|
+
* Enrol a trigger armed while a line was being processed, so the pass can
|
|
171
|
+
* offer it that line, and put it in a lineage: the one belonging to the
|
|
172
|
+
* trigger whose script armed it, a generation on, or a new one when the
|
|
173
|
+
* script predates the line.
|
|
174
|
+
*/
|
|
175
|
+
private registerSameLineCreation;
|
|
176
|
+
/**
|
|
177
|
+
* The same, for a permanent trigger a script created mid-pass. Only ROOT
|
|
178
|
+
* triggers carry a lineage: one sitting in a folder creates on the folder's
|
|
179
|
+
* behalf, and reading the child's own (always empty) lineage instead would
|
|
180
|
+
* start a fresh one every round — which never deepens and so never trips.
|
|
181
|
+
*/
|
|
182
|
+
notePermCreated(node: TriggerNode, root: TriggerNode): void;
|
|
183
|
+
/** Join the lineage of the trigger whose script is running, a generation on;
|
|
184
|
+
* or start one when that script predates the line. */
|
|
185
|
+
private nextSameLineChain;
|
|
186
|
+
/** The lineage of something enrolled for this line, whichever kind it is. */
|
|
187
|
+
private sameLineOf;
|
|
188
|
+
/** The root ancestor's id — the node a lineage is recorded against. */
|
|
189
|
+
private rootIdOf;
|
|
190
|
+
/** Run a permanent trigger's script inside its lineage, so what it creates
|
|
191
|
+
* is enrolled behind it rather than starting a lineage of its own. */
|
|
192
|
+
private execPerm;
|
|
193
|
+
/**
|
|
194
|
+
* Run `fn` as the script of the trigger named `name`, so anything it arms
|
|
195
|
+
* joins that trigger's lineage rather than starting one of its own.
|
|
196
|
+
*/
|
|
197
|
+
runAsTrigger<T>(name: string, sameLine: SameLineChain | undefined, fn: () => T): T;
|
|
198
|
+
/**
|
|
199
|
+
* End a lineage that keeps arming triggers which match the line being
|
|
200
|
+
* processed. Stopping the pass alone would not do: what it created is still
|
|
201
|
+
* live, so the next line would start with a budget's worth of them and each
|
|
202
|
+
* would spawn a budget's worth again. Only this lineage is disowned — a
|
|
203
|
+
* capture trigger an unrelated script armed on the same line belongs to a
|
|
204
|
+
* lineage of its own and is left alone.
|
|
205
|
+
*/
|
|
206
|
+
private stopSameLineCreationLoop;
|
|
207
|
+
/** Tell the player, at most once every REPORT interval — a runaway whose
|
|
208
|
+
* creator outlives the line trips on every matching line, and an unthrottled
|
|
209
|
+
* report would bury the game text it is trying to explain. */
|
|
210
|
+
private reportRunaway;
|
|
211
|
+
/** Where the runaway report is printed. ScriptingEngine wires this to the
|
|
212
|
+
* main console; unset (tests, teardown) the report is dropped. */
|
|
213
|
+
setRunawayReporter(fn: ((text: string) => void) | null): void;
|
|
214
|
+
/** How the engine switches off a permanent trigger it stopped. */
|
|
215
|
+
setPermDisabler(fn: ((nodeId: string) => void) | null): void;
|
|
125
216
|
/** Rebuild the merged, path-sorted processing list from the current
|
|
126
217
|
* permanent entries and temporary triggers. Called lazily from process()
|
|
127
218
|
* when either source changed. */
|
|
@@ -137,9 +228,27 @@ export declare class TriggerEngine {
|
|
|
137
228
|
* `ScriptingAPI.currentLineMatchesColor`. Passing `null` disables every
|
|
138
229
|
* colour trigger (e.g. during runtime teardown).
|
|
139
230
|
*/
|
|
140
|
-
setColorMatcher(fn: ((fg: number, bg: number
|
|
231
|
+
setColorMatcher(fn: ((fg: number, bg: number, window: {
|
|
232
|
+
start: number;
|
|
233
|
+
length: number;
|
|
234
|
+
} | null) => boolean) | null): void;
|
|
141
235
|
destroy(): void;
|
|
236
|
+
/**
|
|
237
|
+
* Advance every state an AND trigger has in flight against this line, and
|
|
238
|
+
* report the ones that completed on it.
|
|
239
|
+
*
|
|
240
|
+
* States are a LIST, not one: a trigger whose first condition matches twice
|
|
241
|
+
* before its second ever does has two matches part-way through, and both
|
|
242
|
+
* complete when that second condition finally arrives. Keeping a single
|
|
243
|
+
* state let the newer one overwrite the older, so only one ever fired.
|
|
244
|
+
*/
|
|
142
245
|
private processAndTrigger;
|
|
246
|
+
/** Carry one in-flight state as far through the remaining conditions as this
|
|
247
|
+
* line takes it. Several can be satisfied by the same line. */
|
|
248
|
+
private advanceAndState;
|
|
249
|
+
/** The match a completed AND state reports: every line's captures, in order,
|
|
250
|
+
* as `multimatches`. */
|
|
251
|
+
private andMatch;
|
|
143
252
|
/**
|
|
144
253
|
* Record a chain-head match: open the chain for `fireLength` more lines and,
|
|
145
254
|
* if the trigger is also a filter, stash the captured/matched text so
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
import type { TriggerPattern } from '../storage/schema';
|
|
1
2
|
import type { InstallOutcome } from './ScriptingAPI';
|
|
3
|
+
/**
|
|
4
|
+
* The item families the tree-walking APIs accept, lowercased — Mudlet's
|
|
5
|
+
* "'alias', 'button', 'script', 'keybind', 'timer' or 'trigger'", plus the
|
|
6
|
+
* 'key' spelling the engine already treats as 'keybind'. Lives here rather than
|
|
7
|
+
* on the engine so the no-op host below answers the same list: a runtime with no
|
|
8
|
+
* engine wired has no items, but it still knows what an item type IS, and
|
|
9
|
+
* reporting a valid type as invalid would send a caller looking for a typo.
|
|
10
|
+
*/
|
|
11
|
+
export declare const KNOWN_ITEM_TYPES: ReadonlySet<string>;
|
|
2
12
|
/**
|
|
3
13
|
* Everything {@link ScriptingAPI} needs from {@link ScriptingEngine}.
|
|
4
14
|
*
|
|
@@ -15,6 +25,22 @@ import type { InstallOutcome } from './ScriptingAPI';
|
|
|
15
25
|
*
|
|
16
26
|
* Members are grouped the way the engine groups them, not alphabetically.
|
|
17
27
|
*/
|
|
28
|
+
/** What tempComplexRegexTrigger asks for: a session-scoped trigger carrying
|
|
29
|
+
* everything a permanent one can. See ScriptingEngine.createTempComplexTrigger. */
|
|
30
|
+
export interface TempComplexTriggerSpec {
|
|
31
|
+
name: string;
|
|
32
|
+
patterns: TriggerPattern[];
|
|
33
|
+
code: string;
|
|
34
|
+
multiline: boolean;
|
|
35
|
+
isFilter: boolean;
|
|
36
|
+
multipleMatches: boolean;
|
|
37
|
+
fireLength: number;
|
|
38
|
+
delta: number;
|
|
39
|
+
highlight?: {
|
|
40
|
+
fg?: string;
|
|
41
|
+
bg?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
18
44
|
export interface EngineHost {
|
|
19
45
|
/** Run a chunk of Lua on behalf of a clicked hyperlink. Errors are reported
|
|
20
46
|
* through the API's error channel rather than thrown. */
|
|
@@ -34,9 +60,12 @@ export interface EngineHost {
|
|
|
34
60
|
requestReconnect(): boolean;
|
|
35
61
|
/** Run a synthetic batch of lines through the same pipeline as network
|
|
36
62
|
* output, so `feedTriggers` shares ordering semantics with real data. */
|
|
63
|
+
/** `fromServer` distinguishes a batch that came off the socket from one a
|
|
64
|
+
* script synthesised (feedTriggers). Absent means the socket. */
|
|
37
65
|
processFlushBatch(groups: {
|
|
38
66
|
text: string;
|
|
39
67
|
type: string;
|
|
68
|
+
fromServer?: boolean;
|
|
40
69
|
}[]): void;
|
|
41
70
|
/** Apply any coalesced trigger/alias reloads immediately instead of on the
|
|
42
71
|
* scheduled microtask. The Mudlet `perm…`, `enableTrigger` and
|
|
@@ -54,6 +83,8 @@ export interface EngineHost {
|
|
|
54
83
|
installModuleFromPath(path: string): InstallOutcome;
|
|
55
84
|
uninstallModuleByName(name: string): boolean;
|
|
56
85
|
syncModuleToFile(name: string): Promise<void>;
|
|
86
|
+
/** Write every module flagged to sync back out to its own file. */
|
|
87
|
+
saveSyncedModules(): void;
|
|
57
88
|
reloadModuleFromFile(name: string): boolean;
|
|
58
89
|
setModuleSync(name: string, sync: boolean): void;
|
|
59
90
|
getModuleSync(name: string): boolean;
|
|
@@ -75,12 +106,22 @@ export interface EngineHost {
|
|
|
75
106
|
/** Read raw bytes from the profile VFS, or null if missing/unreadable.
|
|
76
107
|
* Backs synchronous binary consumers such as setMovie's GIF decoder. */
|
|
77
108
|
readFileBytes(path: string): Uint8Array | null;
|
|
109
|
+
/** Write raw bytes into the VFS, creating parent directories. False with no
|
|
110
|
+
* VFS or when the write throws. Paths are absolute, so this also reaches
|
|
111
|
+
* outside the profile — the shared window layout lives beside the profiles
|
|
112
|
+
* folder, not inside one. */
|
|
113
|
+
writeFileBytes(path: string, bytes: Uint8Array): boolean;
|
|
114
|
+
/** Absolute VFS path of the directory that holds every profile folder —
|
|
115
|
+
* Mudlet's configuration directory, where files shared between profiles
|
|
116
|
+
* (the window layout) live. Null with no VFS. */
|
|
117
|
+
configDirectory(): string | null;
|
|
78
118
|
toggleScriptByName(name: string, enabled: boolean): boolean;
|
|
79
119
|
toggleTriggerByName(name: string, enabled: boolean): boolean;
|
|
80
120
|
toggleTimerByName(name: string, enabled: boolean): boolean;
|
|
81
121
|
toggleAliasByName(name: string, enabled: boolean): boolean;
|
|
82
122
|
toggleKeyByName(name: string, enabled: boolean): boolean;
|
|
83
|
-
|
|
123
|
+
/** Null when the toolbar moved, otherwise why it did not. */
|
|
124
|
+
toggleToolBarByName(name: string, show: boolean): string | null;
|
|
84
125
|
setTriggerStayOpenByName(name: string, lines: number): boolean;
|
|
85
126
|
/** The saved keybinding carrying this numeric id, or null — getKeyCode
|
|
86
127
|
* resolves a permanent key by the id permKey returned, not only by name. */
|
|
@@ -104,12 +145,19 @@ export interface EngineHost {
|
|
|
104
145
|
node: string;
|
|
105
146
|
isActive: boolean;
|
|
106
147
|
}> | null;
|
|
107
|
-
findItemsByName(name: string, type: string, exact: boolean, caseSensitive: boolean): number[];
|
|
148
|
+
findItemsByName(name: string, type: string, exact: boolean, caseSensitive: boolean): number[] | null;
|
|
149
|
+
/** Whether `type` names an item family at all. */
|
|
150
|
+
isKnownItemType(type: string): boolean;
|
|
151
|
+
/** Next id from the profile's single item-id sequence. Temporary items draw
|
|
152
|
+
* from it too, so a temp and a permanent item can never collide. */
|
|
153
|
+
allocateItemId(): number;
|
|
108
154
|
isAncestorsActiveById(id: number, type: string): boolean | null;
|
|
109
155
|
getProfileStats(): Record<string, unknown>;
|
|
110
156
|
createPermScript(name: string, parent: string, code: string): number;
|
|
111
157
|
createPermRegexTrigger(name: string, parent: string, regexes: string[], code: string): number;
|
|
112
158
|
createPermSubstringTrigger(name: string, parent: string, patterns: string[], code: string): number;
|
|
159
|
+
createTempComplexTrigger(spec: TempComplexTriggerSpec): number;
|
|
160
|
+
removeTemporaryTriggerById(id: number): boolean;
|
|
113
161
|
createPermBeginOfLineStringTrigger(name: string, parent: string, patterns: string[], code: string): number;
|
|
114
162
|
createPermExactMatchTrigger(name: string, parent: string, patterns: string[], code: string): number;
|
|
115
163
|
createPermPromptTrigger(name: string, parent: string, code: string): number;
|
|
@@ -120,14 +168,19 @@ export interface EngineHost {
|
|
|
120
168
|
createPermKey(name: string, parent: string, modifier: number, key: string | number, code: string): number;
|
|
121
169
|
createTempButton(toolbar: string, name: string, code: string, orientation: number): number;
|
|
122
170
|
createTempButtonToolbar(name: string, orientation: number, location: number): number;
|
|
171
|
+
/** True when the state actually changed; false when it already was that. */
|
|
123
172
|
setButtonStateByName(name: string, state: boolean): boolean;
|
|
124
173
|
getButtonStateByName(name: string): boolean | null;
|
|
174
|
+
/** Which of Mudlet's button refusals applies to `name`. */
|
|
175
|
+
buttonKindByName(name: string): 'missing' | 'plain' | 'pushdown';
|
|
125
176
|
setButtonStyleSheetByName(name: string, css: string): boolean;
|
|
126
177
|
setScriptByName(name: string, code: string, pos: number): number;
|
|
127
178
|
getScriptByName(name: string, pos: number): {
|
|
128
179
|
code: string;
|
|
129
|
-
|
|
180
|
+
id: number;
|
|
130
181
|
} | null;
|
|
182
|
+
/** Remove the script with this numeric id; true when one was removed. */
|
|
183
|
+
removeScriptById(id: number): boolean;
|
|
131
184
|
/** Mudlet's killTimer/killAlias/killTrigger/killKey by permanent-item name. */
|
|
132
185
|
killByName(kind: 'timer' | 'alias' | 'trigger' | 'key', name: string): boolean;
|
|
133
186
|
/** Mudlet `resetProfile()` — reload the profile with a fresh Lua VM. */
|
|
@@ -49,7 +49,15 @@ export interface IScriptingRuntime {
|
|
|
49
49
|
setMsspValue(name: string, value: string): void;
|
|
50
50
|
runWithMatches(code: string, name: string, matches: (string | undefined)[], multimatches?: (string | undefined)[][], namedGroups?: Record<string, string>, captureSpans?: CaptureSpan[], namedSpans?: Record<string, CaptureSpan>, fullMatchSpan?: CaptureSpan): void;
|
|
51
51
|
destroy(): void;
|
|
52
|
+
/** Bytes behind a path in the runtime's read-only bundled namespace, or null
|
|
53
|
+
* when it has none / the path is not one of them. Optional because it is a
|
|
54
|
+
* property of how a runtime ships its own library, not of running scripts:
|
|
55
|
+
* the Lua runtime serves `/lua/...` this way. */
|
|
56
|
+
readBuiltinBytes?(path: string): Uint8Array | null;
|
|
52
57
|
setCurrentLine(line: string, isPrompt: boolean): void;
|
|
58
|
+
/** The line {@link setCurrentLine} last recorded. The engine reads it back
|
|
59
|
+
* to restore the outer line after a nested feedTriggers. */
|
|
60
|
+
getCurrentLine(): string;
|
|
53
61
|
/**
|
|
54
62
|
* Mirror the last command-bar input into the Lua `command` global, matching
|
|
55
63
|
* Mudlet's AliasUnit::processDataStream. Read by scripts/keys such as the
|
|
@@ -84,6 +92,9 @@ export interface IScriptingRuntime {
|
|
|
84
92
|
* (unlike permanent items) don't live in the persisted store.
|
|
85
93
|
*/
|
|
86
94
|
tempItemExists(id: number, type: string): boolean;
|
|
95
|
+
/** A live temp item of `type` carrying this script-supplied name (Mudlet's
|
|
96
|
+
* tempComplexRegexTrigger is the one temp API that takes one), or null. */
|
|
97
|
+
tempItemIdByName(name: string, type: string): number | null;
|
|
87
98
|
/** Publish one use of a server-defined MXP element as `mxp.<element>`. */
|
|
88
99
|
setMxpElement(name: string, attrs: Record<string, string>): void;
|
|
89
100
|
/** Whether a live temp item is enabled — backs `isActive(id, type)`. */
|
|
@@ -91,6 +102,11 @@ export interface IScriptingRuntime {
|
|
|
91
102
|
/** enable/disable a live temp item by id — backs enableTrigger/disableTrigger
|
|
92
103
|
* (and the alias pair) when handed the numeric id rather than a name. */
|
|
93
104
|
setTempItemEnabled(id: number, enabled: boolean): boolean;
|
|
105
|
+
/** Free every temp item killed since the last call, or only those of `type`.
|
|
106
|
+
* A killed item stops firing immediately but stays findable until here,
|
|
107
|
+
* which is Mudlet's deferred per-unit cleanup: aliases are reaped when
|
|
108
|
+
* nested alias processing unwinds, triggers when the line batch finishes. */
|
|
109
|
+
reapKilledTempItems(type?: 'alias' | 'trigger'): void;
|
|
94
110
|
/** Rebuild saved Lua globals (a Mudlet `<VariablePackage>` tree) into `_G`. */
|
|
95
111
|
restoreVariables(vars: MudletVariable[]): void;
|
|
96
112
|
/** Snapshot the save-listed globals out of `_G` into a variable tree. */
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MXP `<FRAME>` window layout — a port of Mudlet 4.21's `TMxpFrameManager`
|
|
3
|
+
* (src/TMxpFrameManager.cpp).
|
|
4
|
+
*
|
|
5
|
+
* MXP lets a server carve the client window into named sub-windows and then
|
|
6
|
+
* redirect text into them with `<DEST>`. Mudlet lays those out itself rather
|
|
7
|
+
* than handing them to the OS window manager: internal frames are tiled against
|
|
8
|
+
* the edges of the main console, each one shrinking the console's usable area
|
|
9
|
+
* by adding to a set of "MXP borders", and frames declared inside an open
|
|
10
|
+
* `<DEST>` nest inside that destination frame instead. `TITLE` gives a frame a
|
|
11
|
+
* tab header, and `DOCK`+`ALIGN=CLIENT` (a CMUD extension, not MXP 1.0) adds a
|
|
12
|
+
* frame as another tab of an existing one.
|
|
13
|
+
*
|
|
14
|
+
* This class owns the same bookkeeping — the frame records, the accumulated
|
|
15
|
+
* borders, the parent/child hierarchy and the tab groups — and drives the UI
|
|
16
|
+
* through {@link MxpFrameHost} so the geometry is testable without a DOM.
|
|
17
|
+
* mudix maps a frame's console onto a mini-console (an overlay panel with
|
|
18
|
+
* script-controlled geometry); the tab strip is window chrome rendered by
|
|
19
|
+
* ScriptWindow, and child frames nest by portalling into the parent panel's
|
|
20
|
+
* viewport, so their coordinates are parent-relative.
|
|
21
|
+
*/
|
|
22
|
+
import type { MxpTabPage } from '../ui/windows/types';
|
|
23
|
+
/** Height in px of a frame's tab strip. Must match `.mxp-frame-tabs` in ScriptWindow.css. */
|
|
24
|
+
export declare const MXP_TAB_BAR_HEIGHT = 24;
|
|
25
|
+
/** Pixel insets carved out of the main console by edge-aligned frames. */
|
|
26
|
+
export interface MxpBorders {
|
|
27
|
+
top: number;
|
|
28
|
+
right: number;
|
|
29
|
+
bottom: number;
|
|
30
|
+
left: number;
|
|
31
|
+
}
|
|
32
|
+
/** Rectangle, in main-viewport coordinates, that top-level frames tile inside. */
|
|
33
|
+
export interface MxpArea {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
}
|
|
39
|
+
/** Everything the layout needs from the app. Implemented by ScriptingAPI. */
|
|
40
|
+
export interface MxpFrameHost {
|
|
41
|
+
/** The region top-level frames may tile in: the main window minus whatever
|
|
42
|
+
* `setBorder*` has reserved. A GUI package that docks itself to an edge
|
|
43
|
+
* (Geyser's `Adjustable.Container{attached=…}`) reserves its strip that
|
|
44
|
+
* way, and a server laying out frames must not tile over it. MXP's own
|
|
45
|
+
* borders are excluded — the manager tracks those itself. */
|
|
46
|
+
consoleArea(): MxpArea;
|
|
47
|
+
/** Character cell `[width, height]` in px for the main output font, backing `Nc` sizes. */
|
|
48
|
+
charCellSize(): [number, number];
|
|
49
|
+
/** Create (or reposition) a frame's console. `parent` nests it inside that
|
|
50
|
+
* frame's viewport, making x/y parent-relative. */
|
|
51
|
+
placeFrameConsole(name: string, x: number, y: number, width: number, height: number, parent?: string): void;
|
|
52
|
+
/** Open an `EXTERNAL` frame as a free-floating window with its own titlebar. */
|
|
53
|
+
openExternalFrame(name: string, title: string, width: number, height: number): void;
|
|
54
|
+
destroyFrameConsole(name: string): void;
|
|
55
|
+
showFrameConsole(name: string): void;
|
|
56
|
+
raiseFrameConsole(name: string): void;
|
|
57
|
+
setFrameScrolling(name: string, enabled: boolean): void;
|
|
58
|
+
/** Install/replace a frame's tab strip. An empty `pages` list removes it. */
|
|
59
|
+
setFrameTabs(name: string, pages: MxpTabPage[], active: string): void;
|
|
60
|
+
/** Publish the accumulated borders so the main console shrinks around the frames. */
|
|
61
|
+
setMxpBorders(borders: MxpBorders): void;
|
|
62
|
+
}
|
|
63
|
+
export declare class MxpFrameManager {
|
|
64
|
+
private readonly host;
|
|
65
|
+
private readonly frames;
|
|
66
|
+
private borders;
|
|
67
|
+
constructor(host: MxpFrameHost);
|
|
68
|
+
/**
|
|
69
|
+
* `<FRAME name …>`. `dest` is the `<DEST>` frame open at the time the tag
|
|
70
|
+
* was parsed, which nests this frame inside it. Returns false when the tag
|
|
71
|
+
* could not be honoured (bad name, frame budget exhausted) — Mudlet renders
|
|
72
|
+
* the raw tag text in that case.
|
|
73
|
+
*/
|
|
74
|
+
createFrame(name: string, attrs: Record<string, string>, dest?: string): boolean;
|
|
75
|
+
/** `ACTION=close`. Closing an unknown frame succeeds — it is already closed,
|
|
76
|
+
* and reporting failure would leak the raw tag into the output. */
|
|
77
|
+
closeFrame(name: string): boolean;
|
|
78
|
+
/** `ACTION=focus` — raise an existing frame. False when there is none. */
|
|
79
|
+
focusFrame(name: string): boolean;
|
|
80
|
+
/** `ACTION=open` on a frame that already exists: show and raise, no re-layout. */
|
|
81
|
+
showFrame(name: string): boolean;
|
|
82
|
+
/** MXP frames do not survive a reconnect — Mudlet's `resetAllFrames`. */
|
|
83
|
+
resetAllFrames(): void;
|
|
84
|
+
has(name: string): boolean;
|
|
85
|
+
frameNames(): string[];
|
|
86
|
+
/** Current MXP borders. Exposed for tests and for the initial UI read. */
|
|
87
|
+
getBorders(): MxpBorders;
|
|
88
|
+
/**
|
|
89
|
+
* The common case: a frame tiled against an edge of the main console, or —
|
|
90
|
+
* when declared inside an open `<DEST>` — stacked inside that frame.
|
|
91
|
+
*/
|
|
92
|
+
private layoutInternalFrame;
|
|
93
|
+
/** `EXTERNAL` — a window of its own. The browser has no OS child windows,
|
|
94
|
+
* so this becomes a free-floating panel with a real titlebar. */
|
|
95
|
+
private layoutExternalFrame;
|
|
96
|
+
/** `DOCK=other ALIGN=CLIENT` — join `other`'s tab strip as another page. */
|
|
97
|
+
private layoutTabFrame;
|
|
98
|
+
/** Usable area inside a frame, i.e. its rect minus its own tab strip. */
|
|
99
|
+
private contentSize;
|
|
100
|
+
/** Push a frame's strip to the UI. `active` switches the visible page;
|
|
101
|
+
* omitting it keeps whichever page is showing, so a tab arriving or closing
|
|
102
|
+
* never yanks the reader off the one they were watching. */
|
|
103
|
+
private publishTabs;
|
|
104
|
+
/** Bring `name` to the front of whichever tab strip holds it, if any. */
|
|
105
|
+
private selectTabFor;
|
|
106
|
+
/**
|
|
107
|
+
* `WIDTH`/`HEIGHT`/`LEFT`/`TOP` accept `40c` (character cells), `25%` of the
|
|
108
|
+
* container, or `350px`/`350` (pixels). Anything unparseable is 0, matching
|
|
109
|
+
* Mudlet — the caller's minimums then take over.
|
|
110
|
+
*/
|
|
111
|
+
private calcSize;
|
|
112
|
+
/**
|
|
113
|
+
* Rebuild the borders from the frames that are left. Called after a close so
|
|
114
|
+
* the main console reclaims the space; surviving frames keep the geometry
|
|
115
|
+
* they were given (Mudlet does not re-tile them either).
|
|
116
|
+
*/
|
|
117
|
+
private recalculateBorders;
|
|
118
|
+
}
|