Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 4 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ add-in/Resources/** -text
bugs/** -text
*.twinproj binary

# The twinBASIC program in scripts/imagestrip/ is laid out as a reproducer is, and is
# checked out byte for byte for the same reason: its .twinproj is packed from its src/.
# The twinBASIC programs in scripts/imagestrip/ and scripts/impexp/ are laid out as a
# reproducer is, and are checked out byte for byte for the same reason: each .twinproj is
# packed from its src/.
scripts/imagestrip/** -text
scripts/impexp/** -text

# The VB6 template `bug_repro.mjs new --with-vb6` copies into a reproducer's vb6/
# is CRLF in every checkout, as the bugs/** files it becomes are, and VB6 needs it.
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ indexer/.packages/
# BUGS-TO-REPORT.md); the .twinproj beside it is committed.
/bugs/**/*.zip

# The IDE builds scripts/imagestrip/imagestrip.twinproj into Build\ beside it.
# The IDE builds scripts/imagestrip/imagestrip.twinproj and scripts/impexp/impexp.twinproj
# into Build\ beside each.
/scripts/imagestrip/Build/
/scripts/impexp/Build/

# shoot_docs.mjs --svg: each picture's bundle (scripts/svgshot/bundle.mjs), what its SVG
# is drawn from, for scripts/svgshot/replay.mjs. Bundles hold the Windows user name.
Expand Down
93 changes: 72 additions & 21 deletions BUGS-TO-REPORT.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion WIP.Authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ four in place.
| Key | Means |
|-----|-------|
| `package_name` | The packages in the indexer's store that the section documents, by their names there, when the folder's name is not theirs: `WebView2Package` for `WebView2`, `CustomControls, CustomControlsPackage` for `CustomControls`, `cefPackage145` for `CEF`. Absent, the folder's name is the package's. `indexer/lib/doc-pages.mjs` reads it. |
| `indexed_from` | The twinBASIC build whose package download the documentation was indexed against, as its release tag. Currently `beta-x-0997` on all thirteen, the build whose `indexer/snapshots/` the pages are compared with. |
| `indexed_from` | The twinBASIC build whose package download the documentation was indexed against, as its release tag. Currently `beta-x-1005` on all thirteen, the build whose `indexer/snapshots/` the pages are compared with. |
| `exclude_from_docs` | Modules or classes in that package deliberately left undocumented --- internals, private helpers, API shims. |
| `exclude_kinds` | Member *kinds* deliberately left undocumented. Only `WinEventLogLib` uses it, for `Declare`. |

Expand Down
27 changes: 22 additions & 5 deletions WIP.Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ Three `.py` files stay, and none is an oversight:
- **`scripts/impexp.py`** is not tooling. It is a published download, declared in
`_config.yml`'s `bundle_extra` beside `impexp.mjs` and offered to readers on
[Import/Export Tool](docs/Features/Packages/Import-export%20tool.md) as the Python edition
of the same standalone tool. Porting it would delete a deliberate offering.
of the same standalone tool. Porting it would delete a deliberate offering. The tool has
a third edition, `scripts/impexp/`, in twinBASIC (see the folder paragraph below).
- **`scripts/build_fonts.py`** stays because the JavaScript build of HarfBuzz it would
use produces wrong CFF2 metrics --- a one-line build-configuration defect in harfbuzzjs,
documented with the evidence in [WIP.Fonts.md](WIP.Fonts.md), which also holds the full
Expand All @@ -128,8 +129,8 @@ without a native FFI addon. Adding one for a few calls would mean
execution policy. See [Compiling a twinBASIC project without the IDE in front of
you](WIP.Harness.md#compiling-a-twinbasic-project-without-the-ide-in-front-of-you).

One folder holds a program written in twinBASIC itself, for a fourth reason.
**`scripts/imagestrip/`** strips the metadata from an SVG file and from the images a CSS or
Two folders hold a program written in twinBASIC itself, each for a reason of its own.
The first, **`scripts/imagestrip/`**, strips the metadata from an SVG file and from the images a CSS or
SVG file embeds as `data:` URIs, at any depth, for the IDE's own stylesheets. Its users are
the twinBASIC developers, who run it in their own build, which has twinBASIC and need not
have Node, so a Node edition of the program would serve nobody. Nothing in this repository
Expand Down Expand Up @@ -180,6 +181,22 @@ PNG encoder in twinBASIC), and an image keeps its encoding --- base64 rewritten
image changed, a text SVG cut in place, escapes and all --- where `compactImage` writes every
SVG as percent-encoded text.

**`scripts/impexp/`** is the third edition of the impexp tool, a twinBASIC console program,
for a reason of its own: it is a published download for readers who have twinBASIC and
neither Node nor Python, offered on [Import/Export
Tool](docs/Features/Packages/Import-export%20tool.md) as `impexp.twinproj`, which the reader
opens in the IDE and builds (`bundle_extra`, `docs/_config.yml`). It is laid out as
`scripts/imagestrip/` is, `src/` and `impexp.twinproj` packed from it, both checked out byte
for byte; nothing checks that they agree, so a change to `src/` is packed again by hand
(`node scripts/impexp.mjs import scripts/impexp/impexp.twinproj scripts/impexp/src
--overwrite`). It has the same command line, output, exit codes and `--self-test` (the same
20 tests) as `impexp.mjs` and `impexp.py`, and writes byte-identical project files. Its tests
are that `--self-test` and the commands of `check_impexp_parity.mjs`, which compares it
when `IMPEXP_EXE` names its built exe, because no gate can build it; CI never sets the
variable. The check runs the exe through `launchOnDesktop` with `cwd` (`TBBUILD_CWD` in
`tb-launch.ps1`) set to each case's scratch folder, so it never runs on the user's desktop.
See [Tools and Scripts](docs/Documentation/Tools-Compiler.md#impexp).

Two `.mjs` files also run a little PowerShell inline, for Windows state Node has no API
for, and neither adds a file: `scripts/tbrun.mjs` takes a process snapshot with
`Get-Process`, and `scripts/lib/tb-registry.mjs` reads and restores the IDE's registry
Expand Down Expand Up @@ -296,8 +313,8 @@ Four details of the policy are essential:
the opening `---` --- a blank line is enough --- so keep the message naming
that and not the BOM.
- **`bundle_extra` is exempt by *path*, not by extension.** `_config.yml`
declares `Features/Packages/downloads/impexp.py` and `impexp.mjs` with both
ends spelled out, which is what makes them shippable. The same extension
declares `Features/Packages/downloads/impexp.py`, `impexp.mjs` and
`impexp.twinproj` with both ends spelled out, which is what makes them shippable. The same extension
anywhere else still fails; otherwise declaring one entry would bless a whole
type.
- **`addin_project` is exempt by path too, and on the tree surface only.** The
Expand Down
49 changes: 20 additions & 29 deletions WIP.ExamplesBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ compiles](docs/Documentation/Authoring.md) in Authoring.md.

## State

Of 1,530 `tb` fences in 749 pages, **1,370 are marked `check_build`** and compile, and 159
are `inert` with a recorded reason (111 of them OLEGuids' method signatures).
**None is undecided**, so the backlog the census measures is empty. No fence is an
`excerpt`. The run takes about 110 s. 88 of the marked samples are also `check_run`.
Of 2,465 `tb` fences in 933 pages, **2,297 are marked `check_build`** and compile (BETA 1005,
a full run with no finding), and 163 are `inert` with a recorded reason (114 of them
signatures, most OLEGuids' methods). 4 are undecided, in three pages under `IDE/`. No fence is an `excerpt`. The run takes about 220 s on four lanes.
776 of the marked samples are also `check_run`.

New marked samples should come from editing pages, not from marking: the unmarked fences
that are left are not programs (see [What cannot be marked](#what-cannot-be-marked)).
Expand Down Expand Up @@ -121,7 +121,7 @@ a fence at all.
| token | meaning | default |
|---|---|---|
| `check_build` | compile this sample | --- |
| `check_run` | compile it, build it and run it, and compare what it prints with what the fence says it prints (a trailing comment on a `Debug.Print` line, or the comment lines under `' Output:`). Statement samples (`slot=sub`) only; `MsgBox`, `InputBox` and `End` are refused. See the dispatcher design below | --- |
| `check_run` | compile it, build it and run it, and compare what it prints with what the fence says it prints (a trailing comment on a `Debug.Print` line, up to a ` -- ` that starts a note, or the comment lines under `' Output:`, taken whole). Statement samples (`slot=sub`) only; `MsgBox`, `InputBox` and `End` are refused. See the dispatcher design below | --- |
| `hidden` | context for the page's samples, compiled with them and rendered to nothing. Implies `check_build` | --- |
| `slot=` | `file`, `module`, `sub`, `class` or `method` --- what to generate around it | inferred |
| `inherits=` | the class the sample is code-behind *of*; forces the Class row | --- |
Expand Down Expand Up @@ -378,8 +378,8 @@ templates each have their own `tbxStageBrowser.twin`, routed by path in `default
`FormDesignerId` attribute) and `Sources/Form1.tbform` (its designer file), and its own
`tbxStage.twin`, which is console's less the line `Public Form1 As Form`. A form made with
`New Form` in code has no designer file and cannot be drawn on (`Load` raises 361, `AutoRedraw`
raises -2147467259), so the form has to be a file of the project. Four facts, all measured on
BETA 995:
raises -2147467259), so the form has to be a file of the project. Four facts, all checked on
BETA 1005:

- **An empty form has no `_children` key.** `"_children": []` in `Form1.tbform` fails the build with
`TB5247 unable to find matching form designer JSON via FormDesignerId`, and `Form1` is then
Expand Down Expand Up @@ -480,14 +480,9 @@ All are forced by putting unrelated samples in one compilation unit:
- **`Sub Main` comes from the template, and a fence may bring its own as well.** Two
`Public Sub Main`s in different modules compile, so the WinServicesLib `Module Startup`
samples build as written. (A *build* adds a rule; see [`--build` and `--llvm`](#--build-and---llvm-what-a-compile-does-not-ask).)
- **No generated module may be named like the project, in any letter case.** With
`project.name = "ProbeWS"`, a `Module ProbeWS` or a `Module probews` stops the
`[RunAfterBuild]` Sub from running, even when it is empty and the Sub is in another module.
Nothing reports it: the build is green, and the DEBUG CONSOLE ends at `[BUILD] Executing
'<project>.<module>.<Sub>'...` (BETA 995 and 997, twinbasic/twinbasic#2494). BETA 1005 runs
the Sub, so the rule matters only to an older build. The tool names each project `DocSamples<n>`
and every module it generates `tbx...`, so the two cannot meet; a sample that declared
`Module DocSamples3` would.
- **A generated module is not named like the project.** On BETA 1005 a module named like its
project, in any letter case, does no harm. The tool names each project `DocSamples<n>` and
every module it generates `tbx...`, so the two never meet; that is only the naming scheme.

**What collides is narrower than it looks, and guessing it wide is expensive.** Two
generated modules may each declare `Public Function Foo`, `Public Type Rec` and `Public Const
Expand Down Expand Up @@ -525,7 +520,7 @@ swallow the rest.
**Each call has an `On Error GoTo` handler of its own, not `On Error Resume Next` and a test
of `Err.Number` after the call.** A procedure that handles an error with `On Error Resume
Next` and returns, by `End Sub` or `Exit Sub`, leaves `Err` set for its caller, in VB6 and in
twinBASIC alike (VB6 against BETA 995, identical; kit `s69/errpersist/`). Only a `Resume`
twinBASIC alike (VB6 against BETA 1005, identical). Only a `Resume`
from an `On Error GoTo` handler, or any `On Error` statement, clears it. With a test after
the call, InStr.md's sample that demonstrates error 5 under its own `On Error Resume Next`
was reported as raising it. The caller's handler is reached only by an error the callee did
Expand Down Expand Up @@ -575,7 +570,7 @@ one that waits on a box. A `projname=` group takes the form when any of its fenc
sample's forms before the end marker, as the twinBASIC dispatcher does, because a loaded form keeps a
VB6 exe running after `Main` returns. `Declare PtrSafe` is not VB6: `declaresForVb6` drops `PtrSafe`
and reads `LongPtr` as `Long` on a Declare statement's lines (and its continuations) and touches
nothing else, which is what lets the documentation's `GetPixel` module build. Checked on BETA 995
nothing else, which is what lets the documentation's `GetPixel` module build. Checked on BETA 1005
and in VB6: both form samples print what the pages say (`Graphics-Methods.md`'s three lines, and
the Form page's `True`).

Expand Down Expand Up @@ -607,7 +602,7 @@ the Form page's `True`).
before anything else reads them.

**It is a warning, and enforced, because that is robust and leaves a clean batch clean**
(BETA 987, `canary-warn.mjs`, ten cases). TB0005 appeared beside an unterminated `Sub`, an
(BETA 1005, in four projects that held every case below at once). TB0005 appeared beside an unterminated `Sub`, an
`If` with no `End If`, a stray `End Sub` with garbage after it, a class inheriting itself
with an unknown type, ten undefined names, under Option Explicit off, and beside a module
with `[IgnoreWarnings(TB0005)]`. A plain `#Warning` vanished in a project that ignores
Expand Down Expand Up @@ -713,7 +708,7 @@ that fails only the second is one LLVM cannot generate code for.
compiler's fault. The lane's `llvm` field chooses the wording.
- **The canary does not stop a build.** `[EnforceWarnings(TB0005)]` keeps its `#Warning` a
warning whatever the project's settings say, and a warning does not stop the IDE building:
a probe with the canary module beside it builds and runs (tbrun, exit 0, BETA 995).
a probe with the canary module beside it builds and runs (tbrun, exit 0, BETA 1005).
- **A project with compile errors is compiled and not built.** `not built: b<n>.twinproj has
errors, the first ...` prints, and the run ends by counting the samples that only ever sat
in such a project: "N sample(s) in batches with errors were compiled but not built". A
Expand All @@ -732,15 +727,11 @@ that fails only the second is one LLVM cannot generate code for.
- **A failed build is believed when it repeats.** `buildTwiceOnFailure` builds a failed
batch again before halving, and every part the halving builds the same way: a build can
fail once and pass when repeated, as one that reported nothing for 120 s did in a full
`--llvm` run (BETA 995).
`--llvm` run.
- **Each IDE has a temp folder of its own**, `%TEMP%\tbbuild-tmp-<port>`, set as its `TEMP`
and `TMP` by `launchIde`. IDEs building at once in one temp folder fail now and then with
`[TYPELIB] failed to finalize typelibrary. Disk error?` and `[LINKER] FAILED to create
type library`, on samples that build clean alone: 8 of 192 builds, eight at once, against
0 of 192 with a folder each (BETA 995). The compiler imports `GetTempFileNameW`, and
writes the type library to a file it then reads back; a name two processes both take fits
the counts, but is not proved.
- **A build adds three collision rules a compile does not have**, each measured on BETA 995:
and `TMP` by `launchIde`, emptied at each launch on the port and removed when the IDE
ends, so that concurrent runs share nothing and a run leaves nothing behind.
- **A build adds three collision rules a compile does not have**, each checked on BETA 1005 (`--build --only` over the pages that hold such samples builds clean):
- **`expect-error` samples are batched apart.** One such sample (Option.md, TB5079) left
the 129 samples beside it unbuilt, since a project with an error is not built.
- **A unit declaring its own `Sub Main` gets a project of its own, without `tbxMain`.**
Expand All @@ -757,7 +748,7 @@ that fails only the second is one LLVM cannot generate code for.
build fails with no startup object, so `select` refuses it before batching. Split it, with
the startup Main in a fence of its own. The class slot may come from `inherits=` or from
the inference: a top-level `WithEvents` field is TB5182 in a module, whether `Private`,
`Dim` or `Public` (BETA 995).
`Dim` or `Public` (BETA 1005).

## Traps

Expand Down Expand Up @@ -953,6 +944,6 @@ a reader writes.
one line each, because its purpose is "the control instances the samples assume". The
invented *classes* go in `hidden` fences, because a class is not a control instance and a
page is where it belongs. The line between the two is a judgement, not a rule.
- Which pages should carry `check_run` (88 samples do)? A sample states its output in its own
- Which pages should carry `check_run` (776 samples do)? A sample states its output in its own
text, as a trailing comment on a `Debug.Print` line or as the comment lines under
`' Output:`; its comparison is only as useful as the pages that state a printed value.
Loading
Loading