@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.
Files changed (97) hide show
  1. package/README.md +8 -0
  2. package/dist-lib/assets/qt-resources/index.d.ts +16 -0
  3. package/dist-lib/branding.d.ts +1 -1
  4. package/dist-lib/hooks/useMudSession.d.ts +1 -1
  5. package/dist-lib/hooks/useOutput.d.ts +3 -1
  6. package/dist-lib/import/defaultPackages.d.ts +35 -2
  7. package/dist-lib/import/defaults/generic_mapper/generic_mapper.mpackage +0 -0
  8. package/dist-lib/import/defaults/gui-drop/gui-drop.mpackage +0 -0
  9. package/dist-lib/import/defaults/{run-lua-code.mpackage → mudlet-base-ui/mudlet-base-ui.mpackage} +0 -0
  10. package/dist-lib/import/defaults/run-lua-code/run-lua-code.mpackage +0 -0
  11. package/dist-lib/import/packageExport.d.ts +71 -0
  12. package/dist-lib/import/packageInstaller.d.ts +4 -1
  13. package/dist-lib/index.js +45935 -40688
  14. package/dist-lib/logging/SessionLogger.d.ts +66 -1
  15. package/dist-lib/map/MapStore.d.ts +32 -4
  16. package/dist-lib/map/mapImageExport.d.ts +1 -1
  17. package/dist-lib/map/mapZoom.d.ts +71 -0
  18. package/dist-lib/mud/ItemIdSequence.d.ts +23 -0
  19. package/dist-lib/mud/MudSession.d.ts +113 -11
  20. package/dist-lib/mud/PatternEngine.d.ts +6 -1
  21. package/dist-lib/mud/commandSplit.d.ts +16 -0
  22. package/dist-lib/mud/connection/LineAssembler.d.ts +56 -0
  23. package/dist-lib/mud/connection/MudClient.d.ts +120 -16
  24. package/dist-lib/mud/connection/TelnetNegotiator.d.ts +39 -0
  25. package/dist-lib/mud/connection/telnetByteTags.d.ts +35 -0
  26. package/dist-lib/mud/events.d.ts +19 -4
  27. package/dist-lib/mud/games/bundledGames.d.ts +29 -0
  28. package/dist-lib/mud/games/gameIcons.d.ts +5 -0
  29. package/dist-lib/mud/keybindings/KeyEngine.d.ts +9 -2
  30. package/dist-lib/mud/keybindings/browserReservedKeys.d.ts +5 -1
  31. package/dist-lib/mud/keybindings/keyEventTarget.d.ts +17 -0
  32. package/dist-lib/mud/keybindings/qtKeys.d.ts +2 -0
  33. package/dist-lib/mud/protocol/charLoginFlow.d.ts +68 -0
  34. package/dist-lib/mud/protocol/charset.d.ts +27 -5
  35. package/dist-lib/mud/protocol/constants.d.ts +1 -0
  36. package/dist-lib/mud/protocol/gmcp.d.ts +19 -3
  37. package/dist-lib/mud/protocol/index.d.ts +1 -1
  38. package/dist-lib/mud/protocol/mxp.d.ts +28 -5
  39. package/dist-lib/mud/replay/ReplayPlayer.d.ts +17 -0
  40. package/dist-lib/mud/text/Console.d.ts +64 -0
  41. package/dist-lib/mud/text/FormatState.d.ts +66 -3
  42. package/dist-lib/mud/text/hyperlinkVisibility.d.ts +35 -0
  43. package/dist-lib/mud/text/osc8Docs.d.ts +23 -0
  44. package/dist-lib/mud/text/serverWrap.d.ts +191 -0
  45. package/dist-lib/mud/timers/TimerEngine.d.ts +43 -12
  46. package/dist-lib/mud/triggers/TriggerEngine.d.ts +112 -3
  47. package/dist-lib/scripting/EngineHost.d.ts +56 -3
  48. package/dist-lib/scripting/IScriptingRuntime.d.ts +16 -0
  49. package/dist-lib/scripting/MxpFrameManager.d.ts +118 -0
  50. package/dist-lib/scripting/ScriptingAPI.d.ts +323 -54
  51. package/dist-lib/scripting/ScriptingEngine.d.ts +180 -23
  52. package/dist-lib/scripting/http/HttpService.d.ts +51 -1
  53. package/dist-lib/scripting/lua/LuaRuntime.d.ts +151 -2
  54. package/dist-lib/scripting/lua/bindings/map.d.ts +0 -12
  55. package/dist-lib/scripting/lua/utf8Patterns.d.ts +59 -0
  56. package/dist-lib/storage/index.d.ts +1 -1
  57. package/dist-lib/storage/persistentStorage.d.ts +10 -0
  58. package/dist-lib/storage/schema.d.ts +116 -0
  59. package/dist-lib/styles.css +1 -1
  60. package/dist-lib/ui/BundledGameGrid.d.ts +21 -0
  61. package/dist-lib/ui/CommandBar.d.ts +7 -1
  62. package/dist-lib/ui/ConnectionGrid.d.ts +4 -1
  63. package/dist-lib/ui/FilePickerModal.d.ts +3 -3
  64. package/dist-lib/ui/HelpModal.d.ts +11 -0
  65. package/dist-lib/ui/LogBrowserModal.d.ts +4 -1
  66. package/dist-lib/ui/PlayerMarkerPreview.d.ts +20 -0
  67. package/dist-lib/ui/Toolbar.d.ts +2 -1
  68. package/dist-lib/ui/VfsPickerModal.d.ts +26 -0
  69. package/dist-lib/ui/components/FileSourceButton.d.ts +47 -0
  70. package/dist-lib/ui/components/index.d.ts +1 -0
  71. package/dist-lib/ui/helpTopics.d.ts +19 -0
  72. package/dist-lib/ui/labels/LabelManager.d.ts +7 -0
  73. package/dist-lib/ui/layout/ScriptWindow.d.ts +11 -2
  74. package/dist-lib/ui/markdown.d.ts +10 -1
  75. package/dist-lib/ui/output/OutputArea.d.ts +11 -1
  76. package/dist-lib/ui/output/OutputContextMenu.d.ts +3 -1
  77. package/dist-lib/ui/output/OutputRenderer.d.ts +7 -1
  78. package/dist-lib/ui/output/OutputSearchBar.d.ts +25 -0
  79. package/dist-lib/ui/output/StickyOutputPanel.d.ts +5 -1
  80. package/dist-lib/ui/output/outputSearch.d.ts +130 -0
  81. package/dist-lib/ui/search/matcher.d.ts +15 -0
  82. package/dist-lib/ui/search/useDebounced.d.ts +3 -0
  83. package/dist-lib/ui/tts/TtsManager.d.ts +3 -0
  84. package/dist-lib/ui/useCommandHistory.d.ts +4 -2
  85. package/dist-lib/ui/useOpenProfiles.d.ts +26 -0
  86. package/dist-lib/ui/video/VideoManager.d.ts +17 -0
  87. package/dist-lib/ui/windows/WindowManager.d.ts +132 -2
  88. package/dist-lib/ui/windows/panels/MapPanel.d.ts +4 -1
  89. package/dist-lib/ui/windows/panels/PackageExportModal.d.ts +18 -0
  90. package/dist-lib/ui/windows/panels/TextPanel.d.ts +3 -1
  91. package/dist-lib/ui/windows/types.d.ts +35 -0
  92. package/dist-lib/utils/describeThrown.d.ts +22 -0
  93. package/dist-lib/utils/fontLoader.d.ts +5 -0
  94. package/dist-lib/vite.js +22 -0
  95. package/package.json +10 -6
  96. package/dist-lib/scripting/lua/mudlet-lua/generic-mapper/generic_mapper.mpackage +0 -0
  97. package/dist-lib/ui/windows/panels/VfsModulePickerModal.d.ts +0 -8
@@ -8,10 +8,12 @@ import type { LabelManager, LabelCreateOptions, LabelMouseEvent, LabelWheelEvent
8
8
  import type { CommandLineManager } from '../ui/cmdline/CommandLineManager';
9
9
  import type { ScrollBoxManager } from '../ui/scrollbox/ScrollBoxManager';
10
10
  import { TextEditManager } from '../ui/textedit/TextEditManager';
11
+ import type { LogFormat } from '../logging/SessionLogger';
11
12
  import { AnsiAwareBuffer, type FormatStateSnapshot, type FormatHyperlink } from '../mud/text/FormatState';
13
+ import { type UnderlineStyle } from '../mud/text/hyperlinkConfig';
12
14
  import { StopwatchManager } from './StopwatchManager';
13
15
  import { MapStore } from '../map/MapStore';
14
- import { type EngineHost } from './EngineHost';
16
+ import { type EngineHost, type TempComplexTriggerSpec } from './EngineHost';
15
17
  declare class ScriptingWindowsAPI {
16
18
  private readonly session;
17
19
  constructor(session: MudSession);
@@ -19,6 +21,17 @@ declare class ScriptingWindowsAPI {
19
21
  write(id: string, text: string): void;
20
22
  clear(id: string): void;
21
23
  setTitle(id: string, title?: string): boolean;
24
+ /** Mudlet getUserWindowTitle / getMapWindowTitle — null when no such window. */
25
+ getTitle(id: string): string | null;
26
+ /** Mudlet getScrollBarVisible — the enable/disableScrollBar intent. */
27
+ scrollBarVisible(id: string): boolean;
28
+ /** Mudlet getMapWidgetGeometry / getWindowGeometry — null when no such window. */
29
+ getGeometry(id: string): {
30
+ x: number;
31
+ y: number;
32
+ width: number;
33
+ height: number;
34
+ } | null;
22
35
  focus(id: string): void;
23
36
  hide(id: string): void;
24
37
  show(id: string): boolean;
@@ -71,6 +84,9 @@ declare class ScriptingLabelsAPI {
71
84
  htmlRewriter: () => (html: string) => string);
72
85
  create(name: string, opts: LabelCreateOptions): boolean;
73
86
  has(name: string): boolean;
87
+ /** Whether a movie is installed on this label — the movie functions report
88
+ * "no movie here" separately from "no such label". */
89
+ hasMovie(name: string): boolean;
74
90
  /** Read-only state for the geometry/visibility/text getters. */
75
91
  get(name: string): Readonly<import("../ui/labels/LabelManager").LabelState> | undefined;
76
92
  destroy(name: string): boolean;
@@ -89,6 +105,8 @@ declare class ScriptingLabelsAPI {
89
105
  } | null;
90
106
  setStyleSheet(name: string, css: string): boolean;
91
107
  getStyleSheet(name: string): string | undefined;
108
+ /** Pre-rewrite CSS per label, keyed by name — see {@link setStyleSheet}. */
109
+ private readonly authoredCss;
92
110
  setLinkStyle(name: string, color: string, visitedColor: string, underline: boolean): boolean;
93
111
  resetLinkStyle(name: string): boolean;
94
112
  getSizeHint(name: string): {
@@ -158,6 +176,10 @@ export declare class ScriptingAPI {
158
176
  private inTriggerProcessing;
159
177
  private echoDeferred;
160
178
  private isDeferringEcho;
179
+ /** Flip echo deferral, mirroring it onto the session so echoCommand knows
180
+ * the in-flight console partial belongs to flushDeferredEcho and must not
181
+ * be closed out from under it. */
182
+ private setDeferringEcho;
161
183
  private echoOnMatchedLine;
162
184
  /** Mudlet `startLogging(state)`. Forwarded to ProfileSession, which owns
163
185
  * the SessionLogger instance (created/torn-down on this hook). */
@@ -173,6 +195,10 @@ export declare class ScriptingAPI {
173
195
  private clipboardText;
174
196
  private buffers;
175
197
  constructor(session: MudSession, aliasEngine: AliasEngine, triggerEngine: TriggerEngine, timerEngine: TimerEngine, keyEngine: KeyEngine, connectionId: string);
198
+ /** Push the persisted `muteMediaAPI` / `muteMediaGame` gates onto the live
199
+ * sound and video managers. Both setters no-op when already in the wanted
200
+ * state, so this is cheap to call on every config-bag change. */
201
+ private syncMediaMuteFromConfig;
176
202
  /** Bind the engine backing this API. Called once by ScriptingEngine during
177
203
  * its own construction; pass null on teardown to revert to the inert host,
178
204
  * so anything that outlives the engine (a rendered line's link handler,
@@ -186,7 +212,20 @@ export declare class ScriptingAPI {
186
212
  * during initial load); the default host connects the session directly. */
187
213
  private dialConnect;
188
214
  disconnect(): void;
215
+ /**
216
+ * Mudlet's Lua `send()`, which is C++ `sendRaw` → `Host::send(text,
217
+ * wantPrint, dontExpandAliases = true)`: the whole text is echoed once under
218
+ * the showSentText mode, then split on the profile's command separator, and
219
+ * each part goes to the game **without** passing through the aliases. Item
220
+ * `command` fields take the alias-expanding path instead —
221
+ * {@link ScriptingEngine.hostSend}.
222
+ */
189
223
  send(text: string, echo?: boolean): void;
224
+ /** The tail of `Host::send`: one already-echoed, already-split command onto
225
+ * the wire. Same `sysDataSendRequest` veto as {@link send}, no echo. With
226
+ * no engine wired yet (early init) the no-op host reports "not denied", so
227
+ * this sends straight through. */
228
+ sendData(text: string): void;
190
229
  sendGmcp(message: string): void;
191
230
  /** Mudlet `sendMSDP(variable, ...values)`. Frames an MSDP subnegotiation
192
231
  * (`IAC SB MSDP MSDP_VAR <var> [MSDP_VAL <val>]... IAC SE`) and sends it. */
@@ -206,6 +245,17 @@ export declare class ScriptingAPI {
206
245
  * replay (.dat). The LuaRuntime binding reads the bytes from the VFS
207
246
  * before calling here. Returns null on success or the failure reason. */
208
247
  loadReplay(bytes: Uint8Array): string | null;
248
+ /** Deliver any replay chunk that has come due. Only the busted pump calls
249
+ * this — see MudSession.pumpReplay. */
250
+ pumpReplay(): number;
251
+ /** Commit a line held for a server-wrap continuation whose flush delay has
252
+ * elapsed. Same reason as {@link pumpReplay}: the busted runner blocks the
253
+ * event loop the timer would have fired on. */
254
+ pumpServerWrap(): boolean;
255
+ /** Put back the text of an OSC 8 link written concealed whose reveal delay
256
+ * has elapsed. Same reason again: the runner blocks the event loop the
257
+ * reveal timer would have fired on. */
258
+ pumpHyperlinkReveals(): boolean;
209
259
  /** Mudlet `receiveMSP(text)`. Parses an MSP payload (`!!SOUND(...)` /
210
260
  * `!!MUSIC(...)` tags) as if the server had sent it and dispatches the
211
261
  * resulting sound/music commands through the normal `msp` event path
@@ -256,9 +306,9 @@ export declare class ScriptingAPI {
256
306
  */
257
307
  getProfiles(): Record<string, {
258
308
  host: string;
259
- port: number;
309
+ port: string;
260
310
  loaded: boolean;
261
- connected: boolean;
311
+ connected?: boolean;
262
312
  description: string;
263
313
  }>;
264
314
  /** Mudlet `getMudletInfo()`. Echoes a short diagnostic block to the main
@@ -318,23 +368,35 @@ export declare class ScriptingAPI {
318
368
  * of the two applies before it calls through, and only the type is knowable
319
369
  * ahead of the call.
320
370
  *
321
- * `'readonly'` keys exist for `getConfig` but refuse every write.
371
+ * `'readonly'` keys exist for `getConfig` but refuse every write; `'any'`
372
+ * keys take more than one value type and vet the value themselves.
322
373
  */
323
- configKeyKind(key: string): 'bool' | 'num' | 'str' | 'readonly' | null;
374
+ configKeyKind(key: string): 'bool' | 'num' | 'str' | 'any' | 'readonly' | null;
324
375
  /** Mudlet `setConfig(key, value)`. Returns true when the key is known and
325
376
  * writable, false for unknown or read-only keys. */
326
377
  setConfig(key: string, value: unknown): boolean;
327
- /** Mudlet `getProfileInformation()`. Returns the profile's free-text
328
- * description, or "" when unset. (mudix is single-profile, so the optional
329
- * profile-name argument is ignored.) */
330
- getProfileInformation(): string;
331
- /** Mudlet `setProfileInformation(text)`. Stores the profile's free-text
378
+ /**
379
+ * The connection a profile-name argument refers to, or null when no profile
380
+ * has that name. Matching ignores case, as Mudlet's does: it looks the name
381
+ * up as a folder, and the platforms it runs on mostly have case-insensitive
382
+ * ones — so `setProfileInformation(name:upper(), …)` has to find the profile
383
+ * it already has rather than start a second one beside it.
384
+ */
385
+ private connectionByName;
386
+ /** Mudlet `getProfileInformation([profileName])`. The profile's free-text
387
+ * description ("" when unset), defaulting to this profile. Returns null for
388
+ * a name no profile has. */
389
+ getProfileInformation(profileName?: string): string | null;
390
+ /** Mudlet `setProfileInformation([profileName,] text)`. Stores the free-text
332
391
  * description on the connection record (also editable from the connection
333
- * screen). Always succeeds for the active profile. */
334
- setProfileInformation(text: string): boolean;
335
- /** Mudlet `clearProfileInformation()`. Resets the profile description to
336
- * an empty string. */
337
- clearProfileInformation(): boolean;
392
+ * screen). False for a name no profile has — deliberately a refusal rather
393
+ * than a create, since in Mudlet the write goes through a call that makes
394
+ * whatever folder it is handed, and a folder there is a profile. */
395
+ setProfileInformation(text: string, profileName?: string): boolean;
396
+ /** Mudlet `clearProfileInformation([profileName])`. Puts the description
397
+ * back to what the profile started with: the blurb its game ships with in
398
+ * the bundled catalogue, or empty for a profile someone made up. */
399
+ clearProfileInformation(profileName?: string): boolean;
338
400
  /** Mudlet `getProfileIcon()`. Returns the stored icon as a `data:` URI, or
339
401
  * "" when the profile has no custom icon (the connection screen then shows
340
402
  * the auto-generated name tile). */
@@ -356,6 +418,9 @@ export declare class ScriptingAPI {
356
418
  installModule(path: string): InstallOutcome;
357
419
  uninstallModule(name: string): boolean;
358
420
  syncModule(name: string): Promise<void>;
421
+ /** Write every module flagged to sync back out to its own file. Called by
422
+ * saveProfile — see the note there. */
423
+ saveSyncedModules(): void;
359
424
  reloadModule(name: string): boolean;
360
425
  enableModuleSync(name: string): void;
361
426
  disableModuleSync(name: string): void;
@@ -386,10 +451,26 @@ export declare class ScriptingAPI {
386
451
  /** Hook for ProfileSession to start/stop the per-connection SessionLogger.
387
452
  * Mudlet `startLogging(true|false)` toggles whether new output lines are
388
453
  * recorded; the on/off transition is synchronous. */
389
- setLoggingToggler(fn: ((enabled: boolean) => boolean) | null): void;
454
+ setLoggingToggler(fn: ((enabled: boolean, format: LogFormat) => boolean) | null): void;
390
455
  /** Mudlet `startLogging(state)`. Returns true on success, false when
391
456
  * the toggle isn't wired up yet (e.g. before ProfileSession mounts). */
392
- startLogging(enabled: boolean): boolean;
457
+ /**
458
+ * Mudlet `startLogging(state)` → (ok, message, path, state). The state code
459
+ * distinguishes a change from a no-op: 1 started, 0 stopped, -1 already on,
460
+ * -2 already off; the two "already" cases answer nil rather than true, so a
461
+ * caller can tell "I turned it on" from "it was on".
462
+ */
463
+ startLogging(enabled: boolean): {
464
+ ok: boolean;
465
+ message: string;
466
+ path: string | null;
467
+ state: number;
468
+ };
469
+ /** Where the live logger is writing its text log, or null when logging is
470
+ * off. Wired by ProfileSession alongside the toggler. */
471
+ private loggingPathProvider;
472
+ setLoggingPathProvider(fn: (() => string | null) | null): void;
473
+ private loggingPath;
393
474
  /** Hook for ProfileSession to forward appendLog text to the live logger. */
394
475
  setLogAppender(fn: ((text: string) => void) | null): void;
395
476
  /** Mudlet `appendLog(text)`. Appends a line to the current session log.
@@ -483,11 +564,19 @@ export declare class ScriptingAPI {
483
564
  isActive: boolean;
484
565
  }> | null;
485
566
  /** Mudlet `findItems(name, type [, exact [, caseSensitive]])`. Numeric ids of
486
- * matching items/groups. Empty when none match or the type is unknown. */
487
- findItems(name: string, type: string, exact?: boolean, caseSensitive?: boolean): number[];
567
+ * matching items/groups empty when none match, null when there is no such
568
+ * item family (which the Lua wrapper reports as a bad item type). */
569
+ findItems(name: string, type: string, exact?: boolean, caseSensitive?: boolean): number[] | null;
488
570
  /** Mudlet `isAncestorsActive(id, type)`. True when every ancestor group is
489
571
  * enabled; null when no item of that type has the id. */
490
572
  isAncestorsActive(id: number, type: string): boolean | null;
573
+ /** Next id from the profile's single item-id sequence — see
574
+ * ItemIdSequence. Backs the Lua runtime's temporary items. */
575
+ allocateItemId(): number;
576
+ /** Whether `type` names an item family at all — the tree-walking APIs
577
+ * (findItems, ancestors, isAncestorsActive) all refuse an unknown one, and
578
+ * refuse it differently from "nothing matched". */
579
+ isKnownItemType(type: string): boolean;
491
580
  /** Mudlet `getProfileStats()`. Per-family total/active counts (+ trigger
492
581
  * patterns). See ScriptingEngine.getProfileStats for mudix's caveats. */
493
582
  getProfileStats(): Record<string, unknown>;
@@ -499,6 +588,11 @@ export declare class ScriptingAPI {
499
588
  * empty patterns array creates a trigger group. Returns the new id, or
500
589
  * -1 if `parent` is given but no trigger group of that name exists. */
501
590
  permSubstringTrigger(name: string, parent: string, patterns: string[], code: string): number;
591
+ /** Mudlet `tempComplexRegexTrigger(...)`. See
592
+ * ScriptingEngine.createTempComplexTrigger. */
593
+ tempComplexTrigger(spec: TempComplexTriggerSpec): number;
594
+ /** Remove a temporary trigger by the id its creator returned. */
595
+ removeTemporaryTrigger(id: number): boolean;
502
596
  /** Mudlet `permBeginOfLineStringTrigger(name, parent, patterns, luaCode)`.
503
597
  * Same shape as permSubstringTrigger but each pattern matches only when it
504
598
  * appears at the start of the line (`String.prototype.startsWith`, like the
@@ -561,6 +655,9 @@ export declare class ScriptingAPI {
561
655
  /** Mudlet `getButtonState(name)`. Reads the pressed state of a two-state
562
656
  * button. Returns nil when not found. */
563
657
  getButtonState(name: string): boolean | null;
658
+ /** Which of Mudlet's button refusals applies to `name` — see
659
+ * ScriptingEngine.buttonKindByName. */
660
+ buttonKind(name: string): 'missing' | 'plain' | 'pushdown';
564
661
  /** Mudlet `setButtonStyleSheet(name, css)`. Stores a CSS string on the
565
662
  * ButtonNode; the renderer applies it inline. Returns false when not
566
663
  * found. */
@@ -568,16 +665,34 @@ export declare class ScriptingAPI {
568
665
  /** Mudlet `showToolBar(name)` / `hideToolBar(name)`. Toggles the toolbar's
569
666
  * effective enabled flag — the existing button bar already gates render
570
667
  * on `isEffectivelyEnabled`, so flipping the group's `enabled` field is
571
- * the show/hide hook. Returns true on success, false when not found. */
572
- setToolBarVisibility(name: string, show: boolean): boolean;
668
+ * the show/hide hook. Returns null on success, or why nothing moved. */
669
+ setToolBarVisibility(name: string, show: boolean): string | null;
573
670
  setScript(name: string, code: string, pos: number): number;
574
- /** Mudlet `getScript(name [, pos]) code, count`. Returns the source of the
575
- * pos-th (1-indexed) script named `name` and how many scripts share that
576
- * name. Returns null when none exist (Bridge.lua surfaces "", 0). */
671
+ /** Removes the script with this numeric id. Backs permScript's rollback
672
+ * when the new body raises as it is run. True when one was removed. */
673
+ removeScriptById(id: number): boolean;
674
+ /** Mudlet `getScript(name [, pos]) → code, id`. Returns the source of the
675
+ * pos-th (1-indexed) script named `name` together with that script's own
676
+ * numeric id. Null when no script sits at that position, which Bridge.lua
677
+ * surfaces as Mudlet's `(-1, "script ... at position ... not found")`. */
577
678
  getScript(name: string, pos: number): {
578
679
  code: string;
579
- count: number;
680
+ id: number;
580
681
  } | null;
682
+ /** When the `!osc8-docs` banner last went out — see {@link injectOsc8Docs}. */
683
+ private osc8DocsInjectedAt;
684
+ /**
685
+ * Mudlet's `!osc8-docs` easter egg (`TBuffer::appendLine`): text printed
686
+ * through the echo family that carries the phrase is swallowed whole — not
687
+ * just the phrase, the whole call — and a banner of worked OSC 8 examples
688
+ * goes into the MAIN console instead, whichever window the echo named.
689
+ *
690
+ * Returns true when the caller must print nothing. That happens even while
691
+ * the once-a-second debounce is suppressing the banner itself: an echo and
692
+ * the server response repeating it are two sightings of one phrase, and the
693
+ * phrase never belongs on screen either way.
694
+ */
695
+ private injectOsc8Docs;
581
696
  echo(text: string): void;
582
697
  echoToWindow(win: string, text: string): void;
583
698
  /**
@@ -766,6 +881,17 @@ export declare class ScriptingAPI {
766
881
  isAnsiFgColor(ansiColor: number): boolean;
767
882
  isAnsiBgColor(ansiColor: number): boolean;
768
883
  private matchesAnsiColor;
884
+ /**
885
+ * The colour one of `isAnsiFgColor`/`isAnsiBgColor`'s 0..16 codes names.
886
+ *
887
+ * This is Mudlet's own numbering (`TLuaInterpreterUI.cpp`), and it is not
888
+ * the ANSI one: 0 is the profile's default, then the eight colours follow in
889
+ * *light-first* pairs — 1 light black, 2 black, 3 light red, 4 red, and so
890
+ * on to 15 light white, 16 white. Anything outside 0..16 names no colour;
891
+ * the Bridge wrapper already refuses those with Mudlet's message, so this
892
+ * only has to decline to answer.
893
+ */
894
+ private ansiColorCodeToRgb;
769
895
  private readSelectionColor;
770
896
  /**
771
897
  * Resolve the rgb of `channel` for the character at `pos` in `buf`, falling
@@ -774,6 +900,13 @@ export declare class ScriptingAPI {
774
900
  * (selection or cursor).
775
901
  */
776
902
  private readColorAt;
903
+ /** The blue a link gets in `windowName` when the caller did not pass a
904
+ * format of its own — whichever of Mudlet's two link blues reads better
905
+ * against that console's background. */
906
+ private linkColor;
907
+ /** The profile's own foreground/background — what a cell carrying no colour
908
+ * of its own is drawn in, and what `isAnsi*Color(0)` asks about. */
909
+ private defaultColorRgb;
777
910
  /**
778
911
  * Mudlet `getTextFormat([windowName]) → table | nil, errMsg`. Reads the full
779
912
  * set of display attributes of the character at the current selection's start
@@ -791,6 +924,7 @@ export declare class ScriptingAPI {
791
924
  bold: boolean;
792
925
  italic: boolean;
793
926
  underline: boolean;
927
+ underlineStyle: UnderlineStyle | 'none';
794
928
  strikeout: boolean;
795
929
  reverse: boolean;
796
930
  overline: boolean;
@@ -834,7 +968,10 @@ export declare class ScriptingAPI {
834
968
  * (RGB) segments never match a positive index, matching Mudlet's
835
969
  * palette-only semantics.
836
970
  */
837
- currentLineMatchesColor(wantFg: number, wantBg: number): boolean;
971
+ currentLineMatchesColor(wantFg: number, wantBg: number, window?: {
972
+ start: number;
973
+ length: number;
974
+ } | null): boolean;
838
975
  /**
839
976
  * The text of the first run on the current line carrying the wanted ANSI
840
977
  * colours, or null when none does. A colour trigger reports that run as
@@ -845,12 +982,32 @@ export declare class ScriptingAPI {
845
982
  * may already have recoloured the line, and Mudlet still matches against the
846
983
  * colours the server sent.
847
984
  */
848
- currentLineColorMatch(wantFg: number, wantBg: number): string | null;
985
+ currentLineColorMatch(wantFg: number, wantBg: number, window?: {
986
+ start: number;
987
+ length: number;
988
+ } | null): string | null;
849
989
  /** Per-segment ANSI palette indices (and text) of each line currently being
850
- * processed, as it arrived — see {@link beginLine}. -2 marks a segment with
851
- * no palette colour (RGB or default), which never matches a requested
852
- * index. A stack, because a trigger can feedTriggers another line. */
990
+ * processed, as it arrived — see {@link beginLine}. {@link COLOR_DEFAULT}
991
+ * marks a segment left on the console's default colour, which is what a
992
+ * trigger asking for `-2` matches; {@link COLOR_UNPALETTED} marks an RGB
993
+ * colour outside the palette, which matches nothing. A stack, because a
994
+ * trigger can feedTriggers another line. */
853
995
  private lineColorSnapshots;
996
+ /** Whether each line currently being processed arrived as a prompt — the
997
+ * fallback isPrompt() reads once a trigger has gagged the line itself. A
998
+ * stack for the same reason {@link lineColorSnapshots} is one. */
999
+ private triggerLinePrompts;
1000
+ /** How many lines are being processed at once — more than one whenever a
1001
+ * trigger calls feedTriggers. See beginLine/endLine. */
1002
+ private triggerLineDepth;
1003
+ /** Per nested line, the line the outer pass was on. See beginLine. */
1004
+ private outerTriggerLines;
1005
+ /** Told when text is inserted into the line a trigger is matching, so the
1006
+ * runtime can move the capture positions it recorded at match time —
1007
+ * otherwise `selectCaptureGroup` after an `insertText` selects the text
1008
+ * that has since slid to where the capture used to be. */
1009
+ private captureShiftHook;
1010
+ setCaptureShiftHook(fn: ((at: number, delta: number) => void) | null): void;
854
1011
  /**
855
1012
  * Flush echo output collected during the just-processed line's trigger run.
856
1013
  * Called once per line (right after that line is rendered) so a trigger's
@@ -890,6 +1047,16 @@ export declare class ScriptingAPI {
890
1047
  enableHorizontalScrollBar(windowName?: string): void;
891
1048
  disableScrolling(windowName?: string): boolean;
892
1049
  enableScrolling(windowName?: string): boolean;
1050
+ /** Mudlet `timeStampsEnabled(window)` — whether the console shows its
1051
+ * timestamp column. Null when no such window exists. */
1052
+ timeStampsEnabled(windowName: string): boolean | null;
1053
+ /** Mudlet `enableTimeStamps(window)` / `disableTimeStamps(window)`. False
1054
+ * when no such window exists. */
1055
+ setTimeStamps(windowName: string, visible: boolean): boolean;
1056
+ /** Mudlet `scrollingActive([window])` — whether the user can scroll back in
1057
+ * this console. True unless disableScrolling was called on it; the main
1058
+ * window is always scrollable. */
1059
+ scrollingActive(windowName?: string): boolean;
893
1060
  /** Mudlet getScroll — 0-indexed buffer line at the top of the viewport. In
894
1061
  * tail mode reports the last line (Mudlet's mCursorY behaviour at end). */
895
1062
  getScroll(windowName?: string): number;
@@ -923,7 +1090,7 @@ export declare class ScriptingAPI {
923
1090
  * Sets the scrollback cap (and the round-tripped batch-deletion size).
924
1091
  * Returns false when the named console doesn't exist.
925
1092
  */
926
- setConsoleBufferSize(windowName: string | undefined, linesLimit: number, batchSize?: number): boolean;
1093
+ setConsoleBufferSize(windowName: string | undefined, linesLimit: number, batchSize?: number, useMaximum?: boolean): boolean;
927
1094
  getColumnNumber(windowName?: string): number;
928
1095
  /** Mudlet `isPrompt()` — reports the per-line prompt flag at the current
929
1096
  * cursor position. Lines pushed via beginLine carry the flag, so
@@ -964,6 +1131,10 @@ export declare class ScriptingAPI {
964
1131
  * succeeds (persisted on the active profile).
965
1132
  */
966
1133
  setWindowWrap(name: string, wrapAt: number): boolean;
1134
+ /** Tell the console the width to break stored lines at, so what `getLines`
1135
+ * reports matches what the window shows. Called whenever the wrap width or
1136
+ * either indent moves. */
1137
+ private applyStoredWrap;
967
1138
  /**
968
1139
  * Mudlet `getWindowWrap(name) → cols`. Reports the visual wrap width set by
969
1140
  * setWindowWrap (0 when unset). For "main" reads the profile's stored
@@ -1043,25 +1214,29 @@ export declare class ScriptingAPI {
1043
1214
  */
1044
1215
  deleteMiniConsole(name: string): boolean;
1045
1216
  /**
1046
- * MXP `<FRAME>` (Mudlet 4.21). Maps an MXP frame onto a mini-console — the
1047
- * browser has no OS-level child/floating windows, so internal, external and
1048
- * floating frames all become overlay mini-consoles. `attrs` keys are
1049
- * upper-cased (see `MxpFrameCommand`). `ACTION=close` deletes the frame;
1050
- * anything else opens it (or repositions it if it already exists). Geometry
1051
- * (`LEFT`/`TOP`/`WIDTH`/`HEIGHT`) accepts pixels, `N%` of the main window, or
1052
- * `Nc` character cells.
1217
+ * MXP `<FRAME>` (Mudlet 4.21). All the layout thinking lives in
1218
+ * {@link MxpFrameManager}, a port of Mudlet's TMxpFrameManager edge tiling
1219
+ * with accumulating borders, `<DEST>`-nested sub-frames, `TITLE` tab headers
1220
+ * and `DOCK` tab groups. This just owns the manager and satisfies its host
1221
+ * interface below. `dest` is the `<DEST>` frame open when the tag was parsed.
1053
1222
  */
1054
- mxpFrame(name: string, attrs: Record<string, string>): void;
1223
+ mxpFrame(name: string, attrs: Record<string, string>, dest?: string): void;
1224
+ /** Tear every MXP frame down. MXP frames are per-connection state in Mudlet
1225
+ * (TMxpFrameManager::resetAllFrames), so a reconnect starts from a clean
1226
+ * main window rather than inheriting the last session's layout. */
1227
+ mxpResetFrames(): void;
1055
1228
  /**
1056
- * Write an MXP `<DEST>` redirected line into a frame's mini-console. Returns
1057
- * false when no mini-console of that name exists (the caller then renders the
1058
- * text inline in the main window, matching Mudlet). `eof` clears the frame
1059
- * first — the status-frame "replace contents" idiom.
1229
+ * Write an MXP `<DEST>` redirected line into a frame's console. Returns
1230
+ * false when no such frame exists (the caller then renders the text inline
1231
+ * in the main window, matching Mudlet). `eof` clears the frame first — the
1232
+ * status-frame "replace contents" idiom.
1060
1233
  */
1061
1234
  mxpWriteToFrame(name: string, buffer: AnsiAwareBuffer, eof: boolean): boolean;
1062
- /** Parse an MXP geometry dimension: `N%` fraction of `ref`, `Nc` N
1063
- * character cells (approximate), bare number → pixels. null when absent. */
1064
- private parseMxpDim;
1235
+ /** Frames that have been written with `<DEST EOF>` at least once, i.e. the
1236
+ * server treats them as replace-contents panes. Learned rather than
1237
+ * declared: MXP has no attribute for it. */
1238
+ private readonly mxpReplacedFrames;
1239
+ private readonly mxpFrames;
1065
1240
  /**
1066
1241
  * Mudlet `createBuffer(name)`. Registers a named off-screen console for
1067
1242
  * formatting and storing rich text — like a miniconsole, but never shown
@@ -1080,6 +1255,13 @@ export declare class ScriptingAPI {
1080
1255
  * but doesn't own the active selection.
1081
1256
  */
1082
1257
  copy(windowName?: string): void;
1258
+ /**
1259
+ * Mudlet `cut()`. `copy()` and then delete what was copied, so the clipboard
1260
+ * holds exactly the text the line lost (TConsole::cut → TBuffer::cut). Takes
1261
+ * no window argument in Mudlet — it always acts on the main console — and is
1262
+ * a no-op without a selection there.
1263
+ */
1264
+ cut(): void;
1083
1265
  /**
1084
1266
  * Mudlet `appendBuffer([window])`. Appends the clipboard's rich text (from
1085
1267
  * the last `copy()`) as a new line at the end of the named console's buffer.
@@ -1097,9 +1279,10 @@ export declare class ScriptingAPI {
1097
1279
  * Mudlet `createMapper([parent,] x, y, width, height)`. Creates a positioned
1098
1280
  * mapper widget inside the given parent (defaults to `main`), or repositions
1099
1281
  * it if it already exists. Singleton: Mudlet allows only one in-console
1100
- * mapper at a time, so we reuse a fixed id (`mapper`) — distinct from the
1101
- * dockable map widget opened by `openMapWidget` (id `map`). Both render the
1102
- * same MapStore and stay in sync. Returns true on success.
1282
+ * mapper at a time, so we reuse a fixed id — distinct from the dockable map
1283
+ * widget opened by `openMapWidget`. Both are client-owned ids (see
1284
+ * MAPPER_WIDGET_ID) so a script or a MUD cannot name a window over them.
1285
+ * Both render the same MapStore and stay in sync. Returns true on success.
1103
1286
  */
1104
1287
  createMapper(x: number, y: number, width: number, height: number, parent?: string): boolean;
1105
1288
  /**
@@ -1193,6 +1376,35 @@ export declare class ScriptingAPI {
1193
1376
  clearCmdLineSuggestions(): void;
1194
1377
  getCmdLineSuggestions(): string[];
1195
1378
  private emitCmdLineSuggestions;
1379
+ private cmdLineBlacklist;
1380
+ addCmdLineBlacklist(word: string): void;
1381
+ removeCmdLineBlacklist(word: string): void;
1382
+ clearCmdLineBlacklist(): void;
1383
+ getCmdLineBlacklist(): string[];
1384
+ private emitCmdLineBlacklist;
1385
+ private saveCommandHistoryFlags;
1386
+ saveCommandHistoryFor(cmdLineName: string): boolean;
1387
+ setSaveCommandHistoryFor(cmdLineName: string, save: boolean): void;
1388
+ /**
1389
+ * The command-line history files an end-of-session save should write, as
1390
+ * `{ name, content }` pairs relative to the profile directory. Empty when
1391
+ * nothing is to be written.
1392
+ *
1393
+ * Mudlet does this from `Host::saveProfile()`, which emits
1394
+ * `signal_saveCommandLinesHistory` and lets every TCommandLine write its own
1395
+ * `command_history_<name>` — newest command first, one per line, capped at
1396
+ * the profile-wide save size. Both switches have to be on: the size, and the
1397
+ * command line's own flag.
1398
+ *
1399
+ * Only the main bar has a history to write. mudix's Geyser command lines
1400
+ * keep none, so unlike Mudlet there are no numbered files beside it — the
1401
+ * shape is here rather than a bare `saveMainHistory()` so that one gaining a
1402
+ * history is a change in this function alone.
1403
+ */
1404
+ commandLineHistoryFiles(): {
1405
+ name: string;
1406
+ content: string;
1407
+ }[];
1196
1408
  /**
1197
1409
  * Mudlet `openUrl(url) → bool`. Opens a URL in a new browser tab. Special
1198
1410
  * case: a `file:` prefix (as in `openUrl("file:" .. getMudletHomeDir())`)
@@ -1234,13 +1446,26 @@ export declare class ScriptingAPI {
1234
1446
  private removeOwnedStyleTags;
1235
1447
  setAppStyleSheet(css: string, tag?: string): boolean;
1236
1448
  setUserWindowStyleSheet(name: string, css: string): boolean;
1449
+ /** Mudlet `getUserWindowStyleSheet(name)` — the QSS as it was set. */
1450
+ getUserWindowStyleSheet(name: string): string;
1451
+ private readonly userWindowCss;
1452
+ /** Mudlet `getCmdLineStyleSheet([name])`. Same story as above: the command
1453
+ * line's authored QSS, not the CSS the overlay ends up with. "main" is the
1454
+ * default and has no widget of its own to read back from. */
1455
+ getCmdLineStyleSheet(name: string): string;
1456
+ noteCmdLineStyleSheet(name: string, css: string): void;
1457
+ private readonly cmdLineCss;
1237
1458
  /**
1238
1459
  * Mudlet `setProfileStyleSheet(stylesheet)`. Installs (or replaces) a
1239
1460
  * profile-wide CSS block. In Mudlet this themes the whole profile's
1240
1461
  * widgets; the browser analogue is a single `<style>` tag in document.head,
1241
1462
  * keyed separately from setAppStyleSheet's blocks so the two don't clobber
1242
- * each other. Raises sysAppStyleSheetChange (tag "profile") for parity with
1243
- * the app-level setter. Always returns true.
1463
+ * each other. Always returns true.
1464
+ *
1465
+ * Deliberately raises NO sysAppStyleSheetChange: that event announces an
1466
+ * *application*-level change, and a profile sheet is not one. Raising it
1467
+ * here (as mudix used to) told every profile-agnostic theme handler to
1468
+ * re-apply itself over a change that was never theirs.
1244
1469
  */
1245
1470
  setProfileStyleSheet(css: string): boolean;
1246
1471
  /**
@@ -1304,9 +1529,30 @@ export declare class ScriptingAPI {
1304
1529
  get mouseEvents(): import("../ui/MouseEventRegistry").MouseEventRegistry;
1305
1530
  get sounds(): import("../ui/sound/SoundManager").SoundManager;
1306
1531
  get videos(): import("../ui/video/VideoManager").VideoManager;
1307
- /** Mudlet `setMapBackgroundColor(r, g, b)`. Persists into the profile
1308
- * mapper settings so MapPanel picks it up on its next render pass. */
1309
- setMapBackgroundColor(r: number, g: number, b: number): boolean;
1532
+ /**
1533
+ * Mudlet `setMapBackgroundColor(r, g, b [, a])`. Persists into the profile
1534
+ * mapper settings so MapPanel picks it up on its next render pass.
1535
+ *
1536
+ * Returns the refusal message for a component outside 0-255 and `null` on
1537
+ * success — Bridge.lua turns the former into Mudlet's `(nil, errMsg)` pair.
1538
+ * The alpha is optional and defaults to opaque; it is stored only when it is
1539
+ * not, so an ordinary colour stays the plain `#rrggbb` the renderer and the
1540
+ * Mapper tab have always written.
1541
+ */
1542
+ setMapBackgroundColor(r: number, g: number, b: number, a?: number): string | null;
1543
+ /** Mudlet `getMapBackgroundColor()` — the four components of the colour
1544
+ * {@link setMapBackgroundColor} stored, alpha included. */
1545
+ getMapBackgroundColor(): [number, number, number, number];
1546
+ /** Mudlet `setMapRoomExitsColor(r, g, b)`. The exit pen carries no alpha
1547
+ * either way, so this is the renderer's `lineColor` and nothing else. */
1548
+ setMapRoomExitsColor(r: number, g: number, b: number): string | null;
1549
+ /** Mudlet `getMapRoomExitsColor()` — three components, no alpha. */
1550
+ getMapRoomExitsColor(): [number, number, number];
1551
+ /** Mudlet `setDefaultAreaVisible(visible)`. Mudlet's `TMap::mShowDefaultArea`
1552
+ * decides whether the unnamed catch-all area rooms land in before they are
1553
+ * filed anywhere shows up in the area list; here that list is MapPanel's
1554
+ * area dropdown, which reads the same flag. */
1555
+ setDefaultAreaVisible(visible: boolean): boolean;
1310
1556
  /** Mudlet `setMapRoomSize(size)`. Maps to renderer.settings.roomSize via
1311
1557
  * the profile mapper field. Returns false for non-positive values. */
1312
1558
  setMapRoomSize(size: number): boolean;
@@ -1351,6 +1597,24 @@ export declare class ScriptingAPI {
1351
1597
  * Returns true on success, false when no connectionId is bound.
1352
1598
  */
1353
1599
  saveWindowLayout(): boolean;
1600
+ /** Where Mudlet keeps the window layout: beside the profiles folder, not
1601
+ * inside one, because the layout is the application's rather than any one
1602
+ * profile's. Null when there is no VFS to write into. */
1603
+ private windowLayoutPath;
1604
+ /**
1605
+ * Mirror the snapshot to `windowLayout.dat`.
1606
+ *
1607
+ * The store is still where a layout survives a reload — this file is the
1608
+ * Mudlet-shaped copy, so a script (or a person poking at the profile
1609
+ * filesystem) finds the layout where Mudlet puts it and can read it. It is
1610
+ * JSON rather than Mudlet's `QMainWindow::saveState` blob: nothing outside
1611
+ * mudix reads it, and those bytes describe Qt dock widgets that have no
1612
+ * counterpart here.
1613
+ */
1614
+ private writeWindowLayoutFile;
1615
+ /** The snapshot in `windowLayout.dat`, or null when there is no readable,
1616
+ * parsable file — in which case the caller falls back to the store. */
1617
+ private readWindowLayoutFile;
1354
1618
  /**
1355
1619
  * Mudlet `loadWindowLayout()` — restore the most recently saved snapshot
1356
1620
  * for this connection. Re-applies geometry, dock state, font/colour, and
@@ -1678,6 +1942,11 @@ export declare class ScriptingAPI {
1678
1942
  flushOutput(): void;
1679
1943
  /** @deprecated use echo() */
1680
1944
  print(text: string): void;
1945
+ /** Mudlet `Host::postMessage`. Writes a client message onto the main
1946
+ * console whatever the profile's error-echo preference — this is the
1947
+ * client telling the player something about the line in front of them,
1948
+ * not a script's error. */
1949
+ postSystemMessage(text: string): void;
1681
1950
  printError(text: string, source?: ScriptLogSource): void;
1682
1951
  destroy(): void;
1683
1952
  private getConsole;