Skip to content

Commit 5feb6d0

Browse files
authored
Merge pull request #224 from KubaO/staging
Help add-in documentation page and screenshots, settings and references-only packages, and a VFS root Parent crash
2 parents a8f860f + 2f889a9 commit 5feb6d0

48 files changed

Lines changed: 3348 additions & 84 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎BUGS-TO-REPORT.md‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ The implementation is accepted, as it is without the attribute. If `[PreserveSig
310310
**Additional context**
311311
BETA 983 gives the second message as TB5000 instead of TB65535 (the reproducer, checked there, does not report TB65535). Severity: an interface the language lets you declare cannot be implemented at all, and the diagnostic asks for the signature that is already written.
312312

313-
<!-- Reproducer: bugs/preservesig-implements/ (mode compile, expects TB5004 and TB65535); verified on 995, and on 983 it differs only in the second code. Found by scripts/check_examples.mjs over Reference/Core/Interface.md, whose example declared IFoo with a [PreserveSig] member and then showed a class implementing it; the example no longer puts [PreserveSig] on a member it implements, and its description of the attribute says why. -->
313+
<!-- Reproducer: bugs/preservesig-implements/ (mode compile, expects TB5004 and TB65535); verified on 995, and on 983 it differs only in the second code. Found by scripts/check_examples.mjs over Reference/Core/Interface.md, whose example declared IFoo with a [PreserveSig] member and then showed a class implementing it; the example no longer puts [PreserveSig] on a member it implements, and its description of the attribute says why. Also stated in docs/Reference/COM-Interfaces/IEnumVARIANT.md (the Err.ReturnHResult paragraph) and in a NOTE in docs/Features/Advanced/API-Declarations.md, "ThisCall in interfaces", whose Sub + Err.ReturnHResult workaround goes with it when fixed. -->
314314

315315
---
316316

@@ -977,3 +977,40 @@ What did not reproduce it: nothing in the project is needed. The console project
977977
Severity: low. No difference in a running program was looked for. Builds are not reproducible: two builds of one project cannot be compared, cached or signed by hash, and now and then the code itself differs.
978978

979979
<!-- Reproducer: bugs/build-writes-compiler-addresses/ (mode probe: scripts/probe_build_twice.mjs builds it twice, each build in an IDE of its own, and prints what differs; --arch win64 for the win64 target, and --vb6 builds its vb6/ project twice with VB6). On BETA 997 the decompressed blocks differed in 7 of 7 win32 pairs and 2 of 2 win64 pairs; on BETA 995, in 2 of 2 and 2 of 2. The memory-map query is not scripted: a read-only VirtualQueryEx walk of the IDE's child processes after a tbbuild --keep build, 2026-10-06, with the IDE then ended by its pid. Not part of this entry: the random 16-byte identifiers that a form or a used class adds to the exe, since VB6 writes such identifiers too; and the type library's id, which the build generates anew unless Use Project ID for type library ID is on (docs/IDE/Project Settings.md). No page of the documentation mentions the defect, so when it is fixed there is nothing to update besides this entry and its reproducer. -->
980+
981+
---
982+
983+
## Reading `Parent` of the file system's root folder crashes the compiler
984+
985+
**Describe the bug**
986+
In an IDE add-in, reading `Parent` of the virtual file system's root folder, `Host.FileSystem.RootFolder.Parent`, crashes the compiler, and the add-in with it. The read itself crashes, before the value is used: `Dim o As Object = Host.FileSystem.RootFolder.Parent`, `Dim f As Folder = Host.FileSystem.RootFolder.Parent`, `Host.FileSystem.RootFolder.Parent Is Nothing` and `TypeName(Host.FileSystem.RootFolder.Parent)` all crash, and the line the add-in printed just before the read is the last one printed. The IDE restarts the compiler, which loads the add-in and crashes again, 3 or 4 times in a run.
987+
988+
**To Reproduce**
989+
Steps to reproduce the behavior:
990+
1. Open `rootfolder-parent-crash.twinproj` (attached as `rootfolder-parent-crash.zip`). It is an add-in whose `Host_OnProjectLoaded` is:
991+
```
992+
Private Sub Host_OnProjectLoaded()
993+
Host.DebugConsole.PrintText "before Parent"
994+
Dim o As Object = Host.FileSystem.RootFolder.Parent
995+
Host.DebugConsole.PrintText "after Parent"
996+
End Sub
997+
```
998+
2. Build it (win32). The add-in crashes the compiler every time it loads, so use an IDE whose add-ins you can restore. Copy `Build\RootfolderParentCrash_win32.dll` into `%APPDATA%\twinBASIC\addins\win32\` and restart the IDE.
999+
3. Open any project. The DEBUG CONSOLE prints `before Parent`, and the compiler crashes. `after Parent` is never printed.
1000+
4. To get the IDE working again, close it and delete `RootfolderParentCrash_win32.dll` from `%APPDATA%\twinBASIC\addins\win32\`.
1001+
1002+
**Expected behavior**
1003+
`Parent` of the root is `Nothing`, as for the root of any object model, so step 3 prints `before Parent` and `after Parent`. At worst the read raises an error that the add-in can handle, and does not take the compiler down.
1004+
1005+
**Desktop:**
1006+
- OS: Windows 10 Pro 22H2 (build 19045)
1007+
- twinBASIC compiler version: BETA 997
1008+
1009+
**Additional context**
1010+
Also on BETA 983 and 995, identically.
1011+
1012+
What did not reproduce it: `Host.CurrentProject.RootFolder.Parent`, the parent of the project's folder, reads fine, and its `Path` is `twinbasic:/`, the file system's root. An add-in that reads neither does not crash.
1013+
1014+
Severity: crash. The crash is in the read, so no `On Error` handler helps, and an add-in that walks up the tree with `Parent` until `Is Nothing` crashes the compiler on every start, until its DLL is removed. The workaround is to stop at the folder whose `Path` is `twinbasic:/` without reading its `Parent`.
1015+
1016+
<!-- Reproducer: bugs/rootfolder-parent-crash/ (mode lane: an add-in has to be built into an IDE's add-in folder, which nothing here may do outside a lane, so `verify` runs the lane). Asserted by `addin-test.bat --only parent` (test/addin/parent.test.mjs, cases a to e; case f is the control that does not crash; the ParentProbe add-in is test/addin/probes/parent), which passes on BETA 983, 995 and 997 while the bug is there. The reproducer is a cut-down copy of that add-in, compiled clean on 997 by `bug_repro.mjs compile`, and not itself run in a lane. Stated in docs/Reference/Built-In/tbIDE/FileSystemItem.md, the WARNING under "Parent" (names BETA 997), and in WIP.HelpAddin.md (P21): when fixed, the WARNING goes and the page states what Parent of the root is, with no mention of the defect; update the lane's tests (parent.test.mjs, which then assert the fixed behaviour) and P21. -->

‎WIP.HelpAddin.md‎

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ add-in that shows the documentation for the symbol under the cursor, and the har
55
tests IDE add-ins by machine, which the add-in is developed against.
66

77
**Status.** Stages 1 to 3 stand. Stage 4, the add-in itself in [add-in/](add-in/), has
8-
increments 1 to 7 built and tested: F1 to a page, the help pane, the compiler's hover to tell
8+
increments 1 to 9 built and tested: F1 to a page, the help pane, the compiler's hover to tell
99
which `Add`, a name with no page shown by its declaration and `[Description]`, offline
10-
help served from an archive in the DLL, hover help, and a detached window.
10+
help served from an archive in the DLL, hover help, a detached window, a settings panel,
11+
and only the packages the project references.
1112

1213
- `addin-test.bat` operates Samples 10 and 15 end to end and leaves the registry as it found it.
13-
- All of Stage 2's questions, P1 to P19, are answered. Most are held by probe lanes that
14+
- All of Stage 2's questions, P1 to P21, are answered. Most are held by probe lanes that
1415
fail when a later IDE build behaves differently.
1516
- Every build publishes `tB/symbols.json`, 5,536 names at 4,086 URLs, under a drift guard that
1617
fails the build when one of its URLs goes.
@@ -25,7 +26,7 @@ one of three kinds:
2526

2627
- stated plainly: read in the IDE's code or registry;
2728
- marked *(reported)*: from a static reading or a harvested finding, not re-checked;
28-
- marked with a probe number (**P1** to **P19**): only running the IDE can settle it.
29+
- marked with a probe number (**P1** to **P21**): only running the IDE can settle it.
2930
[Stage 2](#stage-2-probes-that-decide-the-design) lists them.
3031

3132
## Goals
@@ -613,7 +614,7 @@ registry, `IDESettings` included through hashes, is identical around the run.
613614
Most probes are a small add-in plus a scenario. P5, P11 and P13 need only CDP and the file
614615
system. Record every answer in this file with the build number it was measured on.
615616

616-
All nineteen questions are answered.
617+
All twenty-one questions are answered.
617618

618619
**A probe whose answer something else rests on becomes a lane**: its add-in in
619620
`test/addin/probes/<name>/`, its scenario beside the others, listed in `lanes.mjs`, with each
@@ -639,6 +640,10 @@ run, and the failure says what to update. The lanes and what rests on each:
639640
nothing, which reads `TB_ADDIN_TEST`.
640641
- [widgets.test.mjs](test/addin/widgets.test.mjs) (P16, P17): the two routes to hover help
641642
increment 6 weighed; the mouse route is the one built. It prints the P16 timings with the tests.
643+
- [references.test.mjs](test/addin/references.test.mjs) (P20): increment 9's route to the
644+
packages a project references.
645+
- [parent.test.mjs](test/addin/parent.test.mjs) (P21): the WARNING on the FileSystemItem
646+
page's **Parent**, and the reproducer of its entry in BUGS-TO-REPORT.md.
642647

643648
A probe that settles a question once stays in scratch. So do the two P3 checks that need the
644649
network or a changed WebView2: the live site in the frame, and the colour scheme with
@@ -667,6 +672,8 @@ The table gives each answer in brief; the sections above have the detail.
667672
| P17 | Can the page's Monaco take a second hover provider for `twinbasic`, as the add-in would register it through the page? **Answered, BETA 997: yes.** Its text is shown in the IDE's own hover, above the compiler's, from a synchronous answer and from a promise answered 500 ms later, and goes once the provider is disposed. Registered for `"*"`, which matches less closely than the IDE's `"twinbasic"`, its text is shown below the compiler's. A link in it is drawn as `<a data-href="<url>" href="">`, and a click listener on the window in the capture phase receives the click, and with `preventDefault` and `stopPropagation` nothing is opened. The IDE's hover shows after 1,000 ms (`hover:{delay:1e3}`) and is off when the user turns off *showExtraInformationWhenHovering* | Stage 4, increment 6: the mouse route, the owner's second exception to page internals |
668673
| P18 | What hides a hover once the mouse slides down it past the code editor's bottom? **Answered, BETA 997: the IDE's dock.** Its resizer along the editor's edge (`z-index: 1000`) and its drop targets lie over the hover, transparent, and take the mouse; Monaco's `_onEditorMouseLeave` then hides the hover. Monaco alone keeps a hover the mouse is over: its DOM stays inside the editor's, and the hover is sticky. CDP's mouse reproduces it only in steps small enough to land on the 6 px resizer; the owner's own mouse found it, under a watcher on the IDE's DevTools port that recorded `_hideWidgets`'s stack | Stage 4, increment 6: the add-in draws every hover above the dock, hover help on or off |
669674
| P19 | Can an add-in show a window of its own, a Form holding the WebView2 package's control? **Answered, BETA 997: yes** ([detach.test.mjs](test/addin/detach.test.mjs), `probes/detach`). A minimal hand-written `.tbform` builds, given `_className` and `_clsid` on the form and the control. `Show vbModeless` gives a visible top-level window, owned by the compiler's process (`twinBASIC_win32_noDEP.exe`, a child of `twinBASIC.exe`), with no message loop of the add-in's own; the control is ready about 250 ms after the first Show, 60--80 ms for a later form. A page loaded with `NavigateToString` posts to the add-in and receives what it posts, and an iframe in it loads an `http://localhost` page. Hide and Show keep the page; Unload and a new form work; the IDE ending leaves no `msedgewebview2.exe` of the window's behind. **The harness gives the IDE `WEBVIEW2_USER_DATA_FOLDER` and `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS`, the compiler inherits them, and they override the control's own options: with them left in place the control fails, error `8007139F`** (which of the two, not isolated). With no user data folder set, the control uses `bin\twinBASIC_win32_noDEP.exe.WebView2`, which the IDE has made already | Stage 4, increment 7: the detached window, and the variables it removes under the test switch |
675+
| P20 | Can an add-in learn, through the public API, which packages its project references? **Answered, BETA 995 and 997: yes** ([references.test.mjs](test/addin/references.test.mjs), `probes/references` and its three hosts `probes/references-*`). `<Project>/Packages`, reached with `For Each` from `Host.FileSystem.RootFolder` (`twinbasic:/`), holds a folder for each package the project references, newest first, then VBRUN and VBA, which are always there; a package's own references are folders inside its own `Packages`. A folder is named for the package's project, which is the key the symbol index's `packages` map uses (`VB`, not the reference's symbol `WindowsControlsPackage`; `Assert`, not `TwinBasicAssertions`); `VBComDlg`, which only WinNativeCommonCtls references, is the one name the map lacks. `IsPackagesFolder` is true for every `Packages` folder and false for a package's. A package is one folder shared by every list it is in, and its `Path` and `Parent` name the first one it was found in, so only `Name` identifies it. The list is complete when `Host_OnProjectLoaded` runs. Applying a reference added or removed on the References page restarts the compiler with no question asked, and the new add-in instance's list shows the change. A type library is a file in `References`, not a package. | Stage 4, increment 9: the packages the add-in offers |
676+
| P21 | What does reading `Parent` of the file system's root do? **Answered, BETA 983, 995 and 997: it crashes the compiler** ([parent.test.mjs](test/addin/parent.test.mjs), `probes/parent`, one IDE per case, the case passed in `TB_P21_CASE`). The read itself crashes, before the value is used: into an `Object` or a `Folder`, in `Is Nothing`, in `TypeName`. Each compiler the IDE restarts loads the add-in and crashes again. The project folder's `Parent` reads, and is the root (`twinbasic:/`). | no add-in here reads the root's `Parent` (P20's tells the root by its path); the WARNING on FileSystemItem's **Parent**; a BUGS entry |
670677

671678
### Stage 3: the symbol index, generated by the docs build
672679

@@ -1002,7 +1009,7 @@ harness about a second against opening a new IDE.
10021009
byte for byte, a folder's 301, a 404 and `HEAD`.
10031010
6. **Hover help. Built**, tested by the `help` and `help-offline` lanes on BETA 997, with
10041011
the owner's choices (2026-10-06): links in the IDE's hover under the mouse, behind one
1005-
*Hover help* checkbox in the pane's bar, off by default and kept with `SaveSetting`
1012+
*Hover help* checkbox in the settings panel (increment 8), off by default and kept with `SaveSetting`
10061013
(`Hover`, `On`). It shows a link per page the name has, at most five, labelled with the
10071014
name, its kind and where it is, as in *Help: MsgBox function (VBA.Interaction)* (the
10081015
owner's wording, 2026-10-07; `SymbolIndex.Place`); a click shows that page in the pane,
@@ -1157,8 +1164,30 @@ harness about a second against opening a new IDE.
11571164
caption (no read-back of the DWM attribute), Alt+F4, the registry read, maximizing on
11581165
a monitor other than the primary one (the lab machine has one), and the move
11591166
itself, whose loop needs the real mouse, which the harness's desktop has none of.
1160-
8. **Later:** offering only the packages the project references; how a user gets an add-in
1161-
with the archive.
1167+
8. **Settings. Built**, tested by the `help` and `help-offline` lanes on BETA 997, at the
1168+
owner's choice (2026-10-07): a gear at the right end of the pane's bar, and on the detached
1169+
window's title bar (in its bar under the Windows caption), opens a drop-down panel of
1170+
settings, one label row each. A click outside it, Esc, or the gear closes it; changing a
1171+
setting leaves it open. Each view has its own panel; the settings themselves go through
1172+
the window's messages as before. In the pane a transparent shade under the panel takes a
1173+
click outside it. In the window a press over the page's frame never reaches the page,
1174+
because the frame is cross-site there and runs in a process of its own, so the window's
1175+
`blur` closes the panel as well. The lanes' pane frame is on the IDE page's site, so one
1176+
case points it at `127.0.0.1` to check the shade with a cross-site frame.
1177+
9. **Only the packages the project references. Built**, tested by the `help` and
1178+
`help-offline` lanes on BETA 997, at the owner's choice (2026-10-07): F1, the hover links
1179+
and the search offer the language's own entries and the packages the project references;
1180+
an *All packages* row in the settings panel, off by default and kept with `SaveSetting`
1181+
(`Packages`, `All`), offers every package. `LoadPackages` reads the references at
1182+
`Host_OnProjectLoaded` from the virtual file system (P20): the folders of the project's
1183+
`Packages` folder and, through each, of its own, keyed on `Name`; a reference change
1184+
restarts the compiler, so that is enough. If the list cannot be read, every package is
1185+
offered, and the loaded line says so. `SymbolIndex.Restrict` limits `Find` and `Search`;
1186+
`FindDeclared` is not limited, since the compiler's hover names the declaring package.
1187+
F1 on a name only an unreferenced package documents says *No help for 'X' in the packages
1188+
this project references*.
1189+
10. **Later:** how a user gets an add-in with the archive: the owner's plan (2026-10-07) is to
1190+
build it in CI with everything else, once the compiler runs on Linux there.
11621191

11631192
**Lookup:**
11641193

@@ -1218,8 +1247,11 @@ The add-in's code skeletons are written in Stage 4 against the compiler, with te
12181247

12191248
### Stage 5: shipping
12201249

1221-
- Build both bitnesses, which `buildAddin` does (P7). Add a documentation page under
1222-
[docs/IDE/AddIns/](docs/IDE/AddIns/).
1250+
- Build both bitnesses, which `buildAddin` does (P7). The documentation page is
1251+
[docs/IDE/AddIns/Help.md](docs/IDE/AddIns/Help.md); its pictures are taken by
1252+
`scripts/shoot_help_addin.mjs` from `test/addin/helpdemo`, so retake them after a change the
1253+
pictures show, and update the page's *Getting the add-in* once increment 10 settles how users
1254+
get it.
12231255
- Distribution is upstream's decision: the community add-ins list, or bundled with the IDE.
12241256
- Take to upstream, with the probe results as evidence: the shortcut bug; a call to open a
12251257
URL; a way to ask the compiler about the symbol at a position, whose answer hover already

0 commit comments

Comments
 (0)