Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
23d4cb5
DetoursLib 1.0.0.0: a Contributed section (Detours and DetoursMod, se…
KubaO Oct 18, 2026
0ede277
Export Verbose: each DONE line shows \ for every backslash (BETA …
KubaO Oct 18, 2026
52efccf
IDE: the last three pictures on BETA 1010 (Designer_Zoom50 with the g…
KubaO Oct 18, 2026
360cae1
WIP.Screenshots: why the export shot removes its folder (a second exp…
KubaO Oct 18, 2026
3c34d16
BUGS-TO-REPORT: nine Build, Clean, ActiveX and Package Publishing def…
KubaO Oct 18, 2026
0fe2038
IDE: the Building chapter (seven pages under /tB/IDE/Building/, Packa…
KubaO Oct 18, 2026
1fee6dd
tbbuild/tbrun: the default build path opens no Save dialog (BETA 1010…
KubaO Oct 18, 2026
920aad1
tbdocs: strip HTML comments from the rendered pages (stripHtmlComment…
KubaO Oct 18, 2026
7800cf9
ide_js: read, name and patch the IDE's minified main.js (a name map t…
KubaO Oct 18, 2026
bfdbf69
harness.json: every limit but compilerRunQuiet is 10 s (owner, with t…
KubaO Oct 18, 2026
521d126
Data types: a section per type on the summary page, indexed as kind t…
KubaO Oct 18, 2026
04f6cf3
BUGS-TO-REPORT: Dim x As Any compiles (locals, Static, module and cla…
KubaO Oct 18, 2026
cf73c0b
Data types: a page for each of the other thirteen intrinsic types (Da…
KubaO Oct 18, 2026
fed2886
BUGS-TO-REPORT: five data type defects (Date out of range, CLngLng of…
KubaO Oct 18, 2026
791b107
page-baseline: 1502 pages with the data type pages
KubaO Oct 18, 2026
816c1a0
BUGS-TO-REPORT: in a 32-bit build a constant Double expression raises…
KubaO Oct 18, 2026
2a93989
BUGS-TO-REPORT: the 32-bit constant-expression entry cites #2497, lik…
KubaO Oct 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/actions/run-gates/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ runs:
- name: Unit-test the package indexer (test/indexer.test.mjs)
shell: bash
run: node --test test/indexer.test.mjs
# Unit tests for scripts/ide_js.mjs, which reads, names and patches the
# twinBASIC IDE's minified main.js: the byte-exact round trip, how a name
# carries to another build, and a fix patched in as the smallest token edit,
# on a few lines written in the test. No install, no browser, no built tree,
# about 1 s.
- name: Unit-test the IDE's main.js tool (test/ide-js.test.mjs)
shell: bash
run: node --test test/ide-js.test.mjs
# A regex that backtracks exponentially does not fail a build, it stops
# one: the corpus passes until a page happens to contain the trigger, and
# then a render worker sits inside String.replace forever. Nothing else
Expand Down
997 changes: 997 additions & 0 deletions BUGS-TO-REPORT.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions WIP.Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,20 @@ an inline `<code>`, welds the code to the word next to it --- `a <code>x</code>
would come out as `ax b`. Trimming is conditional on which element bounds the
segment, so `<pre>` boundaries trim as they always did.

### HTML comments never reach the output

`stripHtmlCommentsPlugin` (a core rule in `builder/render.mjs`, owner's request) drops every
`<!-- ... -->` the markdown holds from all three trees: the SHOT markers, the `<!-- test: ... -->`
region markers and notes. It edits `html_block` and `html_inline` tokens only, which is why a
comment shown in a fence or a code span is untouched: those are `fence` and `code_inline` tokens,
escaped by their own renderers. It is registered after `tightLooseListPlugin` and must stay
there, because that rule sees a comment block as a block of its own when it decides a list item's
tightness. **Nothing downstream reads a comment from rendered HTML**: `check_package_tests.mjs` and
`package-test-cases.mjs` read the markdown source, and what the build needs from a comment is
written by the templates, not by markdown, so it stays: the `Begin/End Jekyll SEO tag` pair
(`offline-rewrite.mjs` finds the block by it) and the two icon licences in `template.mjs`. A rule
that needs a marker in a page's output uses an element or an attribute, never a comment.

### The book refuses a stale source tree

Testing only that `docs\_site-pdf\book.html` **exists** is not enough: edit a
Expand Down
84 changes: 73 additions & 11 deletions WIP.Harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Read it before changing `scripts/tbbuild.mjs`, `scripts/tbrun.mjs`,
`scripts/lib/tb-launch.ps1`, `scripts/lib/tb-registry.mjs`,
`scripts/lib/tb-ide-copy.mjs`, `scripts/lib/tb-project.mjs`,
`scripts/lib/tb-addin.mjs`, `scripts/lib/tb-click.mjs`, `scripts/lib/tb-operate.mjs`,
`scripts/lib/tb-lane.mjs`,
`scripts/lib/tb-lane.mjs`, `scripts/ide_js.mjs`, `scripts/ide-js/lib.mjs`,
anything under `test/addin/`, or `scripts/census_attributes.mjs`, and before
concluding anything about twinBASIC syntax from a sweep of exported sources.

Expand Down Expand Up @@ -586,13 +586,11 @@ The probe is a module with a `[RunAfterBuild]` Sub, which the IDE runs once the
linked. Reader-facing documentation is the [`tbrun.mjs` entry in
Tools-Compiler.md](docs/Documentation/Tools-Compiler.md#tbrun).

**The script owns the tree because of a silent trap.** A project whose `project.buildPath`
is still the default `${SourcePath}\Build\...` template opens a native *Save* dialog when
you build it. On the private desktop that dialog is invisible and unreachable, so the build
simply never happens --- and **the WebView2 renderer stays responsive throughout**, so
`Runtime.evaluate` answers normally and every health check says the IDE is fine. `tbrun`
pins the path in its staged copy, which is why it insists on a source tree it can edit
rather than a packed project it cannot.
**The script owns the tree** so that it can pin `project.buildPath` in its staged copy and
know where the built file is, which is why it insists on a source tree it can edit rather than
a packed project it cannot. The default `${SourcePath}\Build\...` path opens no dialog: a
project opened from a `.twinproj` with it builds, and the compiler makes `Build\` itself
(BETA 1010 and 1007, packed by `impexp` or from the template, in a new folder, built twice).

Rules it follows:

Expand Down Expand Up @@ -935,11 +933,10 @@ built it, not in the binary:
The first three are decided when compiling; the last three can only come from the running
process, and they agree.

**The build path's folder has to be explicit; its file name need not be.** `tbrun` builds
**The build path's file name need not be explicit.** `tbrun` builds
into its own `out` folder under the IDE's own name,
`${ProjectName}_${Architecture}.${FileExtension}`, giving `ArchProbe_win32.exe` and
`ArchProbe_win64.exe` with no Save dialog --- so the trap above comes from the default
`${SourcePath}\Build\...`, not from the variables. The name is looked for after the build
`ArchProbe_win64.exe`. The name is looked for after the build
rather than assumed, because `${FileExtension}` follows the build type.

**A switch of target is not saved.** The IDE saves the target it last built a project for
Expand Down Expand Up @@ -1673,3 +1670,68 @@ target) and reload (47 s: two builds and two restarts).
- An `--only` that matches nothing is refused with exit code 2. `--timeout 8` ends lanes
mid-build and leaves the registry as found and nothing running.
- Exporting the samples leaves the install's `projects` folder as it was, mtimes included.

## Reading and patching the IDE's main.js

`scripts/ide_js.mjs` and its library `scripts/ide-js/lib.mjs` (the rules are in
[WIP.md](WIP.md#driving-the-twinbasic-compiler), *Fixing the IDE itself*; the usage is on
[Tools-Defects](docs/Documentation/Tools-Defects.md#ide_jsmjs)). It came out of a study on
2026-10-18, whose prototype it replaces.

**What the file is.** BETA 1010's `ide/main.js` is one line of 1,263,324 bytes: 314,309
tokens, no comment, no source map. Its top level is 979 function declarations, 46 classes
and 793 `var`/`const` declarations, so 1,295 units (functions and class methods). It has
9,346 locals, 9,245 of them one letter long. The minifier removed whitespace and renamed
locals and parameters, and nothing else: every top-level name, property and global
survives, which is why a unit's name is the anchor of the map.

**Why edits are splices, never a print.** Any printer (prettier, recast, astring) rewrites
the whole file --- quotes, parentheses, spacing --- so a patched copy would differ from the
install in every byte, and a lane result could not be put down to the fix. acorn's tokens with
their ranges, the comments and the whitespace between them make up every byte of the file
(`survey`'s `coverage`, exact on 1007 and 1010), and an edit replaces a range of the original
text, so a patched `main.js` differs from the install only inside its edits. The view is
prettier's, for reading and for writing a fix, and nothing goes back from it character by
character: a fix comes back as the token diff of the unit.

**Why a local is keyed by where it is declared.** The minifier gives the same local another
letter in another build, so a minified name keys nothing. A scope path and a place in the
scope's declarations do not change while the code does not, and a unit's shape (its syntax
tree with every local replaced by its key, hashed) says whether it did. From 1007 to 1010,
1,294 of the 1,295 units have the same shape; the one that changed is `designer_PropertyPage`.
The committed map's 13 names, named on 1007, check on 1010 as 9 exact, 1 carried and 3 for
review, all three in `designer_PropertyPage`.

**Why a `review` name is not applied.** A local used more or less often in a changed unit is
probably the same variable, but may not be, and a wrong name in a view misleads more than a
minified one does. `seal` after a look applies it again.

**Why the patch checks shapes twice.** First, the fix in our names and the fix turned back into
the build's names must have the same shape: a new variable the fix names like one of the
build's minified names would otherwise take over that name's references. Second, each patched
unit must have the shape of the fix, so the patched file runs what the fix shows, whatever the
token diff and the spaces it glues in did.

**Why tokens compare strings by value.** prettier writes `"x"` for `'x'` and `0.5` for `.5`, so
a fix copied from the view would otherwise rewrite every literal it touches. Parentheses are
not normalised: prettier adds them around mixed `&&` and `||`, and such a fix comes back with
edits that add them. They change no shape, so the patch is right, just not the smallest.

**A fix is a diff against one build.** `patch` turns every difference between a fix's unit
and the build's into an edit, so a fix written on one BETA and patched into a later one whose
unit changed takes the later build's change back out. Before patching a build other than the
one a fix was written on, run `shape` on it: its diff is exactly what the patch changes.

**The IDE does not check `main.js`.** A copy of BETA 1010 with the two edits of
`export-verbose-done-escaped`'s fix ran the export lane: the defect's test reported that it
no longer reproduced, its two controls and the lane's six other tests passed, and
`bug_repro.mjs verify debug-print-escaped-twice` said NO LONGER REPRODUCES (it reproduces on an
unpatched, byte-identical copy). That was the study's prototype; the tool's patch of the
same fix is byte for byte the same.

**The packages.** eslint-scope does the scope analysis, which decides which identifiers are
one variable: hoisting, block and class scopes and `catch` all have to be right for a rename
to be, and it is ESLint's own. prettier prints the view and the fix shape only, and is loaded
on first use. Both are in `package.json` (owner, 2026-10-18), prettier at an exact version:
another version may print a unit otherwise, and a fix shape's diff and line numbers are what
it prints.
10 changes: 6 additions & 4 deletions WIP.HelpAddin.md
Original file line number Diff line number Diff line change
Expand Up @@ -799,10 +799,12 @@ has the complete list):
`ByVal`, `ByRef`, `Optional`, `As` --- are in the index only where a page's title gives
them. Adding one is a `symbols:` line on the page that explains it, which is a content
decision per keyword. Deferred.
- **Data types** --- `Long`, `String`, `LongPtr` --- have their page at
`/Reference/Data-Types`, outside `/tB/`, so the index cannot carry them without breaking
its own rule. Giving that page a `/tB/` permalink, with the old one in `redirect_from:`,
would. Deferred.
- **Data types are done** (owner, 2026-10-18), as the one exception to the `/tB/` rule:
each type the summary page's `symbols:` names is a language entry of kind `type` at its
`##` section of `/Reference/Data-Types` (`#long`), which links to the type's own page,
`/tB/Core/Long`. With `package` null, `Find` gives a bare `String` the type before the
VBA function, and a hover that names `VBA.Strings` (F1 on `String(5, "x")`) still picks
the function; the help lane has a case for each.
- **The offline tree has no copy of the index.** The add-in embeds its own, and the help
archive (increment 5) is the offline tree as built, less `HELP_ARCHIVE_SKIP` in
`builder/help-archive-step.mjs` (the Documentation Development section, Videos,
Expand Down
35 changes: 25 additions & 10 deletions WIP.Screenshots.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,13 @@ whose project does not refer to the VB package.
- **The zoom box is set by a `change` event on `#zoomSelect`**, never by the arrow keys, which
also move the selected controls. Designer_Zoom shows the box and its list only, four rows of
it: the Light theme's list has a smaller font, and the whole list makes the light picture 100
pixels shorter than the dark one. The form at 50 % is not in it: its scaled dots differ in
every capture, even with the ground left out.
pixels shorter than the dark one. The form at 50 % is a picture of its own, Designer_Zoom50,
taken `once` (dark only, owner): the grid is turned off for it first with the command
`tbFormDesigner_TurnGridIndicatorsOff` (what the toolbar's grid button toggles; settled by the
form's style changing), because the scaled dots differ in every capture even with the ground
left out. The change is the form's (its tab shows it changed, so the clip is formStateShot's,
without the tab row), and `formsReset` discards it: the shots after it keep their dots. Its
SVG is 4 % off the PNG (the scaled text), so the page shows the PNG.
- **The Toolbox is scrolled with the mouse wheel**: a capture never holds more than the real
window's height, so a taller page does not show more of it. Show Control Names is set from the
panel's `...` menu and put back afterwards (saved nowhere). The search of Toolbox_Search is
Expand All @@ -350,8 +355,14 @@ whose project does not refer to the VB package.
- **A report's PAGE WIDTH, LEFT MARGIN and RIGHT MARGIN bars show only under the pointer**
(opacity 0, 1 on hover): Report_Controls rests the pointer on PAGE WIDTH.
- **Preview_Window** is a running program's window, taken once with `captureWindow` from the
IDE's desktop. The File menu is not open in it: a native menu is a window
of its own (`#32768`), which the tool cannot yet capture and lay over the form's window.
IDE's desktop, with its File menu open. A key pressed on a private desktop reaches no window,
so the menu is opened as Alt+F opens it: `postWindowMessage` (`tb-ide.mjs`, the `post` mode
of `tb-launch.ps1`) posts `WM_SYSCOMMAND` `SC_KEYMENU` `'f'` to the form's window. The menu is
then a top-level window of class `#32768` of the same process (`openMenuWindow`); both windows
are captured (`windowPicture`, whose user-name check covers the menu's window texts too) and
`withMenu` lays the menu's picture over the form's where it is on the desktop, the ground
beyond the form transparent. The menu is drawn with its mnemonics underlined, as the keyboard
opens it. `WM_CANCELMODE` posted to the form closes it before the run is stopped.
- PROPERTIES shows no description line: in BETA 1005 its text is set in a footer of the
designer's own properties box, which is 0 pixels wide, so nothing is drawn.

Expand All @@ -364,7 +375,7 @@ project file the lane opens is `project.twinproj`, the name the title shows. `pr
the same project with Microsoft Scripting Runtime's symbol overridden as `SR` and a type library
that is not on the machine (`MISSING_LIBRARY`) put in the staged `Settings`; the IDE opens
Project Settings by itself a second after loading it, and the setup's prepare closes it.
`projects-start` is the IDE with no project. Its 15 pictures are under `docs/IDE/Projects/Images/`;
`projects-start` is the IDE with no project. Its 16 pictures are under `docs/IDE/Projects/Images/`;
`Menu_File_Project` is the File menu with the project open (the Menu pages keep `Menu_File`, with
none, which `New Project.md` also shows).

Expand Down Expand Up @@ -396,11 +407,15 @@ none, which `New Project.md` also shows).
which `PAGE_DEFAULTS` blocks anyway).
- Settings_Close types into the description box with real keys, after `templateBuildPath`, and
closes the question with Yes, close, which keeps nothing.
- **Not taken: the export console** (marker `projects-export-console` left). It was reached (Export
Path set in the staged copy to a folder under `PACKAGE_ROOT`, so that the first line holds no
user name; the console floated before Clear, which the docked console is too narrow to show; the
list scrolled with the wheel to its top and its end, as two parts of a composite), but with
Export Verbose every `DONE` line shows `&#92;` for each backslash, a defect not yet decided on.
- **Export_Console** is File > Export Project with Export Verbose off (owner: the verbose `DONE`
lines show `&#92;` for each backslash). `stageProjects` sets `project.exportPath` in the
staged `Settings` of both projects setups to `PACKAGE_ROOT\Export` (`PJ_EXPORT`), so that the
first line names no user; the shot removes that folder before the export and after it, because
a second export without Export Verbose into the folder the first one filled wrote no `COMPLETED`
line within 60 s (BETA 1010; not narrowed, not queued: owner, record only). The
console is floated (docked, it is too narrow for the first line) and emptied with its Clear
button before the export, and emptied again afterwards; the shot is the setup's last. The
times are set in the page (`fixConsoleTimes`). Both lines fit with no scrolling.

## Special IDE states

Expand Down
Loading
Loading