diff --git a/.gitattributes b/.gitattributes index 9da6f3746..e4b529669 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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. diff --git a/.gitignore b/.gitignore index ea9960691..539d0ae1c 100644 --- a/.gitignore +++ b/.gitignore @@ -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. diff --git a/BUGS-TO-REPORT.md b/BUGS-TO-REPORT.md index df26d8071..0d74c2986 100644 --- a/BUGS-TO-REPORT.md +++ b/BUGS-TO-REPORT.md @@ -208,7 +208,7 @@ The slots that held nothing stay empty, as they do when the key does not exist a **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: cosmetic, but it shows on a new installation, which is exactly when the list has empty slots. @@ -223,7 +223,7 @@ What does not reproduce it: So it takes at least one existing entry and at least one slot with nothing in it, which looks like each slot being read with the previous slot's value as its default. Once a duplicate is there, the next opened project keeps it: 18 copies of one project became 20 after one more open, with the new project on top. Both variants of step 2 (deleted slots, empty strings) were measured on BETA 995, ending with 21 values and 3 distinct projects. - + --- @@ -260,7 +260,7 @@ A build switch for unattended use should report the diagnostics on stdout or std **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: it makes the switch unusable for the one job it exists for, because it is silent, falsely green and hangs on the case worth catching. @@ -271,7 +271,7 @@ So exit 0 on a project with errors happens only for an error in code nothing cal Silence on stdout and stderr: measured on BETA 983 first, and on BETA 995 by redirecting the standard handles of the process to a file. The same redirection captures the compiler executable's own output (`twinBASIC_win32.exe settings ` wrote the whole `Settings` file), so the capture works. - + --- @@ -315,7 +315,7 @@ The implementation is accepted, as it is without the attribute. If `[PreserveSig **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** 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. @@ -343,7 +343,7 @@ Every file and folder is written, however long its path, as `export` already rea **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: an `export` to a deep folder writes part of the tree and exits 0, and the errors it prints blame permissions and storage space. `LongPathsEnabled` is 1 on the machine this was measured on, so the Windows setting does not rescue it. @@ -386,7 +386,7 @@ No window opens from a command-line verb. The command prints the problem (`ERROR **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: an unattended `export`, `settings` or `readme` never finishes, and once the box is closed every one of them exits 0 and `export` reports success, so a script that tests the exit code or `... DONE` is fooled as well. @@ -425,7 +425,7 @@ The files that would be overwritten are found first, as `import` does, and a ref **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: a refused export leaves the folder a mixture of the old tree and the project. @@ -461,7 +461,7 @@ Relative paths and paths with forward slashes work for `export` and for the outp **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: ordinary relative and forward-slashed paths fail, with messages that say the file or folder does not exist. @@ -511,7 +511,7 @@ Either the export deletes nothing when it cannot empty the whole folder, or it r **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: a partly emptied folder, with the only record in the Debug Console. On a Git working copy it breaks the repository, because Git makes its object files read-only. @@ -554,7 +554,7 @@ Steps to reproduce the behavior: **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 983, identically. Moving past the failing line with **Set Next Statement** (Ctrl+F9) instead, each F5 then advances one line. An earlier run by hand, followed to the end, saw the pending step last until the procedure returned; what differed there is not known, and in the lane the step is used up by the one stop, as above. @@ -583,7 +583,7 @@ The imported package is ticked, as after the online import, so that **Apply** is **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 983, by hand. Severity: the package is imported but not referenced, and nothing says so. @@ -621,7 +621,7 @@ After the **Apply**, builds and runs use v2, as they do when the same replacemen **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: the project builds and runs the old package after the user has replaced it. @@ -668,7 +668,7 @@ A diagnostic that names the type argument and the call that supplied it. The `>` **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 983, with the same TB5092. Severity: a diagnostic that points at correct code. `Max` uses `>` on a type parameter with nothing to say which types it accepts, which is how the problem arises. @@ -703,7 +703,7 @@ The run ends, as it does without the attribute, with no restart of the compiler. **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: low; the IDE recovers, but the project is compiled again, and LLVM-compiled code run in the IDE is not recommended anyway. Without the attribute the run ends with no restart. In a built exe, with or without LLVM, `End` ends the program with exit code 0 (this project run with `tbrun --exe` on 995 exits 0). BETA 983 ignored the `End` and went on (fixed in 985 for built programs); this project's LLVM procedure is refused by 983 ("Unable to compile due to use of datatype that is not yet supported for LLVM compilation"), so that was not re-measured with it. @@ -712,6 +712,57 @@ Severity: low; the IDE recovers, but the project is compiled again, and LLVM-com --- +## With LLVM on for the whole project, a `[CompilerOptions("")]` procedure that `Sub Main` reaches ends the IDE run with an access violation when it calls an LLVM procedure + +**Describe the bug** +With LLVM turned on for the debug run of the whole project (Project Settings, Compiler Options (DEBUG), Enable LLVM Compilation), a procedure marked `[CompilerOptions("")]` that `Sub Main` calls, directly or through other procedures, ends the run in the IDE with `NATIVE EXCEPTION: ACCESS_VIOLATION` at the call it makes to a procedure compiled with LLVM. The DEBUG CONSOLE shows the exception, then the IDE's `auto-activated TRACE-MODE` lines, and nothing after the call is written. A built exe of the same sources, compiled with LLVM as well, runs correctly. + +**To Reproduce** +Steps to reproduce the behavior: +1. Open `llvm-plain-calls-llvm-from-main.twinproj` (attached as `llvm-plain-calls-llvm-from-main.zip`). It needs an LLVM licence (Ultimate): its setting `compiler.debugOptions` is `+llvm`, which is Enable LLVM Compilation under Compiler Options (DEBUG). Its only module is: + ``` + Module Startup + + Public Sub Callee() + Debug.Print "Callee" + End Sub + + [CompilerOptions("")] + Public Sub Plain() + Debug.Print "Plain: before Callee" + Callee + Debug.Print "Plain: after Callee" + End Sub + + Public Sub Main() + Plain + End Sub + + End Module + ``` +2. Run the project in the IDE (F5). +3. See `Plain: before Callee` in the DEBUG CONSOLE and then `NATIVE EXCEPTION: ACCESS_VIOLATION /Startup.twin; Startup.Plain LINE 000013`. `Callee` and `Plain: after Callee` are not written, and the run is over. + +**Expected behavior** +`Plain` calls `Callee` and the run goes on: `Callee`, then `Plain: after Callee`. A procedure compiled without LLVM can call one compiled with it, as it does when `Plain` is not reached from `Sub Main` (see below), and as it does in a built exe. + +**Desktop:** + - OS: Windows 10 Pro 22H2 (build 19045) + - twinBASIC compiler version: BETA 1005 + +**Additional context** +Severity: medium. It applies to a debug run compiled with LLVM, which Project Settings itself does not recommend, and it ends the run; nothing wrong is computed. Turning LLVM off for the debug run avoids it. + +What it needs, each checked by removing or changing one thing at a time: LLVM on for the whole project's debug run; a procedure marked `[CompilerOptions("")]`; a call in that procedure to a procedure compiled with LLVM (`Callee` can have an empty body); and `Sub Main` reaching the marked procedure: `Main` calling it directly, through an LLVM procedure (`Main` calls `Helper`, which calls `Plain`) or when `Plain` and `Callee` are in another module all end the run, and so does `Main` calling `Plain` when the run itself calls `Plain` from another procedure, so `Main` need not run it. It happens in a 32-bit and a 64-bit run. + +What does not reproduce it: `Main` empty, with `Plain` reached from another procedure (a `Helper` or the run's own entry procedure) and not from `Main`; `Main` calling `Callee` itself, not through `Plain`; LLVM on for no procedure but `Main` and `Callee`, by their `[CompilerOptions("+llvm")]` attributes, with `Plain` unmarked; `Plain` without the attribute, so that everything is compiled with LLVM; the exe built from the same sources with LLVM on for the build as well (`tbrun --llvm --exe`, 32-bit), which exits with code 0 and no fault. The startup object has to be `Sub Main`: the IDE refuses a project whose startup object is another procedure ("unable to locate form 'Sub Entry'"). + +The crash is a race that one IDE on its own always loses: run on its own, the project ends in the exception every time (8 of 8 runs of a reduced copy, 3 of 3 of this one), and with eight IDEs started at once about four of them do. The address in the exception varies (`ntdll.dll`, `twinBASIC_win32.dll`), and so does where the exception is reported: always the line of the call in `Plain`. + + + +--- + ## An `Interface` declared with the identifier of `IUnknown` compiles, and calling its method ends in an access violation **Describe the bug** @@ -750,7 +801,7 @@ The compiler refuses the declaration, because an interface cannot have the ident **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Severity: low; it takes a deliberate copy of `IUnknown`'s identifier, but the compiler accepts it silently and the failure is a crash. @@ -910,7 +961,7 @@ Steps to reproduce the behavior: **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 987, identically. @@ -953,7 +1004,7 @@ Steps to reproduce the behavior: **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 987, identically. @@ -998,7 +1049,7 @@ Each line stays as it is typed, as it does in the code editor. The code editor's **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 987, identically. @@ -1039,7 +1090,7 @@ Nothing from the compiler's own memory ends up in the exe, and the padding after **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 997 + - twinBASIC compiler version: BETA 1005 **Additional context** The values are addresses in the compiler process. After a build with the IDE left open, a read-only query of the memory map of the IDE's child processes (`VirtualQueryEx`; nothing was read from their memory) found both values of that build's exe in committed, private, read-write memory of the compiler process: `twinBASIC_win64_noDEP.exe` for a win64 build, and `twinBASIC_win32_noDEP.exe` for a win32 build. In the IDE's other child processes, both values fell in free address space. For win64 this is conclusive: only 3 of 200,000 random values below 2^47 fell in that process's committed memory. For win32 it is weaker, since 20,497 of 200,000 random 32-bit values did too. @@ -1082,7 +1133,7 @@ Steps to reproduce the behavior: **Desktop:** - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 997 + - twinBASIC compiler version: BETA 1005 **Additional context** Also on BETA 983 and 995, identically. diff --git a/WIP.Authoring.md b/WIP.Authoring.md index 66e54343f..b3aec258a 100644 --- a/WIP.Authoring.md +++ b/WIP.Authoring.md @@ -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`. | diff --git a/WIP.Build.md b/WIP.Build.md index 4d0d7ebc4..f5fc3236a 100644 --- a/WIP.Build.md +++ b/WIP.Build.md @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/WIP.ExamplesBuild.md b/WIP.ExamplesBuild.md index 50a3a4172..5d91cb814 100644 --- a/WIP.ExamplesBuild.md +++ b/WIP.ExamplesBuild.md @@ -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)). @@ -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 | --- | @@ -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 @@ -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 - '..'...` (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` - 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` 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 @@ -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 @@ -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`). @@ -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 @@ -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.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 @@ -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-`, 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`.** @@ -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 @@ -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. diff --git a/WIP.Harness.md b/WIP.Harness.md index 08608065c..6a782d35c 100644 --- a/WIP.Harness.md +++ b/WIP.Harness.md @@ -26,7 +26,7 @@ in this repository. They are inside the `.twinproj` files an IDE install ships, node scripts/impexp.mjs export .twinproj ``` -On BETA 983 and 995 alike that yields **820 `.twin` files**: 661 from the sixteen +On BETA 1005 that yields **820 `.twin` files**: 661 from the sixteen packages under `packages/`, and 159 from the thirty-two sample and template projects under `projects/` (`addins/` holds no `.twinproj`). The compiler accepts all of this code, which makes it the strongest available evidence for what is legal syntax. @@ -35,7 +35,7 @@ The tooling unpacks and packs in process, through `unpackProject` and `packTree` [scripts/lib/tb-project.mjs](scripts/lib/tb-project.mjs), which call impexp's `exportProject` and `importProject`: the census, `tbbuild --build`, `tbrun`, `check_examples`, `sweep_attributes`, `bug_repro`'s `pack`, and the add-in and IDE -lanes. The compiler executable's `export` verb writes the same tree: on BETA 995 the two +lanes. The compiler executable's `export` verb writes the same tree: the two unpack the install's sixteen packages and thirty-two samples to identical trees, 1,633 files byte for byte. @@ -59,7 +59,7 @@ because: Anything that runs the executable follows two rules. **Use backslashes.** A folder named with forward slashes fails with `output folder does not exist and could not be created` whether it exists or not, creates nothing, and still exits 0. Given backslashes, `export` creates every missing level (tested -three deep, BETA 983 and 995). The project path must be a full one, because `export` +three deep). The project path must be a full one, because `export` prefixes it with `\\?\`. And **redirect stdin** when looping (`` and presses its OK button: `bug_repro`'s `cli` mode uses all four for a compiler that opens a modal box on a damaged project. +`TBBUILD_CWD` is the program's working folder (`launchOnDesktop`'s `cwd`), the program's own +folder when it is unset; `check_impexp_parity.mjs` sets it so that the built impexp exe runs in +the scratch folder of its commands. A launch that fails prints no pid, and its cause as one line on stderr, which `launchIde` reports. Two rules keep the cause readable. With its streams redirected, PowerShell writes @@ -433,7 +436,7 @@ Seven rules about the harness, each a comment in the file: TRACE-MODE writes the thread dump that names the file, and the IDE switches that on in answer to the first `NATIVE EXCEPTION` and passes it to a compiler as it starts, so the restarted compiler's crash is the first to name one. A single re-read of the console after - the crash misses the name 31% of the time (BETA 983: the second crash comes 1.6 to 1.9 s + the crash misses the name 31% of the time (measured: the second crash comes 1.6 to 1.9 s after the first on an idle machine, 1.8 to 3.0 s with four IDEs compiling at once). `awaitCrashName` polls instead, every 250 ms for up to 5 s: it misses none and needs at most 3.25 s; the add-in lanes' `closeProject` uses it too. If a run ever has a second @@ -449,8 +452,7 @@ Seven rules about the harness, each a comment in the file: helper the IDE is not a descendant of anything the harness spawned, so the helper reports the pid on stdout and the harness kills that. -**A crashing probe is a real risk**: `Debug.ExecuteHostCommand` argument-shape probes take the -compiler down repeatedly. Keep a question that might crash the compiler +**A crashing probe is a real risk.** Keep a question that might crash the compiler in a project of its own, so the answer is attributable and one bad probe cannot cost the other thirty their run. @@ -472,7 +474,7 @@ their counts included. **The compiler chooses its own address and key, and tells the process that started it.** So a program that starts a compiler itself can connect to it, and `--compiler=` need not name a -real window for a compile or a build (BETA 995). +real window for a compile or a build. What stands in the way is the work the page does over those connections. It loads the project, gives the compiler every package the project needs, answers what the compiler asks, @@ -570,19 +572,16 @@ Rules it follows: yours. - **A failed build is not output.** A build that fails after a clean compile never runs the probe, and the IDE's own log stays in the console: `[BUILD] Starting...`, - `[TYPELIB] failed to finalize typelibrary. Disk error?`, `[LINKER] FAILED to create type - library`, `[BUILD] failed`. `tbrun` exits 2 on any line `buildProject`'s `BUILD_FAILED` + `[LINKER] FAILED`, `[BUILD] failed`. `tbrun` exits 2 on any line `buildProject`'s `BUILD_FAILED` matches: `[BUILD] failed`, `[LINKER] FAILED`, `[BUILD] ERROR` and `[LINKER] compilation (codegen) error`. The codegen case builds with `[LINKER] SUCCESS`: a `[RunAfterBuild]` Sub that shifts a `Single` (BUGS-TO-REPORT.md) adds `[BUILD] Executing 'DocSamples.Probe.Run'...` - and the codegen line to the console, and nothing in the Sub runs. The type-library failure - comes from IDEs sharing one temp folder; `launchIde` gives each its own (see - WIP.ExamplesBuild.md). + and the codegen line to the console, and nothing in the Sub runs. - **A callee's code-generation failure is erased by the probe's own `Debug.Cls`.** When the failing shift is in a procedure the probe calls, the codegen line naming that procedure comes straight after the `[BUILD] Executing` line, before the probe's first statement runs. The probe's `Debug.Cls` erases it, and the probe prints what comes before the call and stops - there. (BETA 983 and 995: with `Debug.Cls` the probe prints exactly its lines; without it + there. (BETA 1005: with `Debug.Cls` the probe prints exactly its lines; without it `tbrun` warns and the build log lines precede them; exit 0 either way, without the guard below.) So `tbrun` wraps the page's global `clearDebugConsole()` before it presses Build, and keeps what each clear erases (`keepClears` in `tb-ide-console.mjs`). A `BUILD_FAILED` @@ -599,15 +598,15 @@ Rules it follows: `tbbuild`'s 4. `tbrun` exits 3 for no output at all, and 2 for a compile that never settled, which `tbbuild` reports as 3. - **`tbrun` exits 5 when the probe ended before it returned.** The quiet period cannot see - it: on BETA 995, `Err.Raise` with no handler in a `+llvm` procedure ends the run with + it: on BETA 1005, `Err.Raise` with no handler in a `+llvm` procedure ends the run with nothing in the console. `End` does the same, and so does an unhandled error in plain code, - in the same time as a probe that returns (20.7-21.9 s over three runs on BETA 995, against - 18.6-20.4 s). `lib/tb-probe.mjs`'s `wrapProbe` moves the attribute, blanked to spaces so + in about the time of a probe that returns (12.8 s against 10.4 s, one run each on BETA + 1005, other IDEs running). `lib/tb-probe.mjs`'s `wrapProbe` moves the attribute, blanked to spaces so diagnostics keep their positions, to a Sub appended to the same module, so a Private probe Sub can still be called; that Sub prints a sentinel after the call. A probe that leaves a form loaded returns too: the IDE then prints `[DEBUGGER] Waiting for remaining forms to - close...` after the sentinel, which `sentinelIndex` allows and `tbrun` prints (BETA 983 - and 995). `check_twin_parsers` has fixtures for both. + close...` after the sentinel, which `sentinelIndex` allows and `tbrun` prints (BETA + 1005). `check_twin_parsers` has fixtures for both. - **`tbrun --exe` exits 6 when the exe exited with a code other than 0**, when the event log records that it faulted, when it opened a box, or when it was still running at `--timeout` and was ended. A run that would exit 5 exits 5 first, since the @@ -693,16 +692,18 @@ cannot predict. A project with compile errors runs none of its `[TestCase]`s. ### Measuring LLVM `tbrun --llvm` sets `compiler.debugOptions` and `compiler.buildOptions` to `+llvm` in the -staged Settings; `--compiler-options` sets any other string. Measured on BETA 995 with no +staged Settings; `--compiler-options` sets any other string. Measured on BETA 1005 with no per-procedure attributes, one probe in four variants of Settings: **`debugOptions` is what the `[RunAfterBuild]` run is compiled with.** With `+llvm` there, `Debug.Assert`'s condition -was evaluated 0 times and a 200-million-step loop took 516 ms; with it only in -`buildOptions`, 1 time and 672 ms, as with neither. (`+llvm` alone is not -`+llvm +optimize`, which took the same loop to 62 ms as a procedure attribute.) +was evaluated 0 times; with it only in `buildOptions`, 1 time, as with neither. A +200-million-step loop took 465 ms with neither, 387 ms with `buildOptions` only, 430 ms with +`debugOptions` only and 398 ms with both, so on this build the speed of a plain loop does not +tell the variants apart. (`+llvm` alone is not `+llvm +optimize`, which took the same loop to +0 ms.) **The licence is in the status bar's `compilerLicence`:** one of `COMMUNITY EDITION`, `PERSONAL EDITION`, `PROFESSIONAL EDITION`, `ULTIMATE EDITION`, and `tB Licence: ...` -until the IDE knows (`ide/main.js`, BETA 995). The licence key is in HKCU, so a lane IDE +until the IDE knows (`ide/main.js`, BETA 1005). The licence key is in HKCU, so a lane IDE sees the user's. `tbrun` refuses an LLVM run on the first two, which compile no user code with LLVM; it cannot be tested with a real Community licence here, only through a fault. @@ -710,26 +711,27 @@ with LLVM; it cannot be tested with a real Community licence here, only through `launchIde` that calls `tb-launch.ps1`, which reports the program's exit code on a second line (`exit `) once it ends. Nothing reaches the exe's standard output: the launcher creates it with no inherited handles. So `TbRun.Out` writes UTF-8 to the file -`TBRUN_OUT` names, and to standard output only when there is none. Measured on BETA 995: +`TBRUN_OUT` names, and to standard output only when there is none. Measured on BETA 1005: the exit code from `ExitProcess 7` comes back as 7, a hung exe is ended at `--timeout` with nothing left running, and **the exe never evaluates `Debug.Assert`, with or without LLVM**, as VB6 drops `Debug` statements from a compiled program. **An unhandled error in the exe opens a box and waits for it**, so `--exe` passes `dialogs: "close"`: the launcher records each box and presses OK. Without that the exe -sat until `--timeout`. The box is the only sign of the error. In BETA 997 a plain exe -shows *shutdown*, `Run-time error '5' `, and exits with code 0 once the box -is closed; an LLVM-compiled one shows *_TB_ERROR_HANDLER*, `unhandled error in -Probe.Main`, with no number or description, and then dies of an access violation at -address 0 (`0xC0000005`). `tbrun` also reads the Application log for a fault the exe +sat until `--timeout`. The box is the only sign of the error. In BETA 1005 a plain exe +shows a box titled with the project's application title, `Run-time error '11' `, +and exits with code 0 once the box is closed; an LLVM-compiled one shows *_TB_ERROR_HANDLER*, +`unhandled error in ProbeMod.Oops` (the module and procedure), with no number or +description, and then dies of an access violation at address 0 (`0xC0000005`). `tbrun` also reads the Application log for a fault the exe ended on (`lib/win-fault.mjs`), since an exit code need not say it; the record is written because the launcher, not Node, starts the exe. **`TbRun.Out` knows it is in the IDE because the wrapper says so.** The wrapper sets `TbRun.tbrun_InIDE` before it calls the probe; the exe runs `Sub Main`, never the wrapper. `App.IsInIDE` would say the same, but `App` exists only in a project that references the -VB package: in any other, `TbRun` fails to compile (TB5079, `Unrecognized symbol 'App'`) -and `tbrun` exits 1 on a probe that is fine (BETA 995, the install's Samples 6 and 8). +VB package or the AppGlobalClassObject package: in any other, `TbRun` fails to compile +(TB5079, `Unrecognized symbol 'App'`) and `tbrun` exits 1 on a probe that is fine (BETA 1005; +either package alone is enough, and the install's Samples 6 and 8 had neither). Adding that reference to the staged copy would change what the probe's own names resolve to, and the VB6 idiom, a `Debug.Assert` whose condition sets a variable, fails under `--llvm`, because LLVM-compiled code skips `Debug.Assert` in the IDE too. A tree with a @@ -756,7 +758,7 @@ target's own compiler, `twinBASIC_win64_noDEP.exe` for win64, and the project co again. A project opening with a remembered target goes through the same switch before it loads. -**Wait for the restart by the compiler's pid, not by the clock.** Measured on BETA 983, at +**Wait for the restart by the compiler's pid, not by the clock.** Measured at 50 ms: the status bar stays OPERATIONAL for about 250 ms after the switch, reads UNAVAILABLE until the new compiler's pid appears in `g_CurrentCompilerProcessId` at about 510 ms, and LIMITED until OPERATIONAL at 1.4 s. A `waitForCompile` started straight after the switch can @@ -951,12 +953,14 @@ exactly what the lane puts there. The compiler loads the DLLs in `%APPDATA%\twinBASIC\addins\` as well (P6), and the `APPDATA` each lane gives its IDEs keeps the user's out ([The add-in test runner](#the-add-in-test-runner)). -**Measured, against BETA 983 (and 995 where stated):** +**Measured:** - **An IDE session writes nothing into its install.** A compile, a compiler crash and a - `tbrun` build-and-run each left all 233 files byte-identical, down to the mtimes; on - BETA 995 the install (235 files) was byte-identical after exports, a `tbbuild` and two - `tbrun` runs. A compile also left the per-user `%APPDATA%\twinBASIC` unchanged; that folder + `tbrun` build-and-run each left every file byte-identical, down to the mtimes; on + BETA 1005 the install's 232 files outside the default WebView2 profile folder + (`bin\twinBASIC_win32_noDEP.exe.WebView2`, which the user's own IDE writes and the harness's + IDEs, started with their own `WEBVIEW2_USER_DATA_FOLDER`, do not) were byte-identical + after a `tbbuild` and a `tbrun`. A compile also left the per-user `%APPDATA%\twinBASIC` unchanged; that folder holds the user's downloaded packages and empty `addins`, `locale` and `themes` folders, and is shared by every install. So a compile's whole footprint outside its temp folders is the registry, which [the tidy](#what-a-run-leaves-in-the-registry-and-putting-it-back) @@ -968,9 +972,10 @@ IDEs keeps the user's out ([The add-in test runner](#the-add-in-test-runner)). - **Starting the copy re-points the `.twinproj` association at it.** The real install's IDE leaves the keys alone. The tidy restores them with three writes. -**A copy, not hardlinks.** The install is 233 files and 87 MB; leaving out `projects\` (the -samples and New Project templates, 29 MB, which a test that opens its project on the command -line never shows) and `addins\` (recreated), it copies in **380 ms**. Hardlinks would save +**A copy, not hardlinks.** The install is 232 files and 106 MB (BETA 1005, leaving out the +default WebView2 profile folder); leaving out `projects\` (the +samples and New Project templates, 30 MB, which a test that opens its project on the command +line never shows) and `addins\` (recreated), it copies in **348 ms**, that folder included. Hardlinks would save that at the price of sharing every file with the user's install, so that any write the IDE made into its own folder would land in the real one. A copy makes the question irrelevant instead of merely answered. @@ -1078,7 +1083,7 @@ output file ''` or one of about twenty failure lines --- `[LINKER] FAILED error ...`. An output file another process holds open gives `[LINKER] FAILED to create output file '...' (error code 32)`, then `LOCKED BY:` and a line naming the process, then `[BUILD] failed`. A package writes `[BUILD] Creating TWINPACK file ''` and then `[BUILD] -successful.` (BETA 995), and its failures are `[BUILD] FAILED ...` and `[BUILD] failed` lines +successful.` (BETA 1005), and its failures are `[BUILD] FAILED ...` and `[BUILD] failed` lines like a binary's. `buildProject` matches the success line whole, because `[BUILD] successfully built Fusion server file` is another line, and only after the TWINPACK line. Two details: @@ -1249,7 +1254,7 @@ anybody watches. A caller can still set the variable otherwise, or leave it out `undefined` as its value: Node leaves such a variable out of a child's environment even when its own environment has it (measured). -**Measured on BETA 983 and 995 (P10 in WIP.HelpAddin.md), and held by +**Measured (P10 in WIP.HelpAddin.md), and held by [test/addin/env.test.mjs](test/addin/env.test.mjs):** the EnvProbe add-in ([probes/env](test/addin/probes/env)) prints the variable from `Host_OnProjectLoaded`. Through `launchIde` it reads `1`, from `Environ$` and from @@ -1436,7 +1441,7 @@ probe lanes: lane need no change to the runner, and the second takes the same port once the first has been ended. -**Timing, BETA 995:** the thirteen lanes other than widgets (24 s alone on BETA 997) take about two minutes at the default two at a time +**Timing:** the thirteen lanes other than widgets (24 s alone) take about two minutes at the default two at a time (the env lane is 16 s alone, the help lane 15 to 18 s, of which its sixteen cases are about 6 s). Typical lane costs: an add-in build about 10 s, a host IDE about 9 s, a scenario 2 s; the slowest lanes are arch (56 s: two builds and two switches of target) and reload (47 s: two builds and two restarts). diff --git a/WIP.HelpAddin.md b/WIP.HelpAddin.md index f196abb0b..e7f3c0796 100644 --- a/WIP.HelpAddin.md +++ b/WIP.HelpAddin.md @@ -18,10 +18,9 @@ a detached window, a settings panel, and only the packages the project reference a `pane` parameter, with which a page shows without the site's navigation and header (Stage 4, increment 2). -Facts about the IDE are from **BETA 983**, and were re-checked on BETA 995 where the text says -so. An offset like `main.js@611152` is a byte offset into the one-line `ide/main.js`. Offsets -move with every build, so in any other build search for the quoted text instead. Each fact is -one of three kinds: +A fact about the IDE that a probe lane tests is stated for **BETA 1005**, the build the lanes +run on. A name or a quoted text can be searched for in the one-line `ide/main.js`; no byte +offset is given, because offsets move with every build. Each fact is one of three kinds: - stated plainly: read in the IDE's code or registry; - marked *(reported)*: from a static reading or a harvested finding, not re-checked; @@ -67,11 +66,11 @@ the compiler what a symbol is.** Each of those gaps shapes a stage below. `GlobalSearchAddIn AddIn`, the copy reports none). The other is the user's, in the next item. - **The compiler also loads the add-ins in `%APPDATA%\twinBASIC\addins\` (P6).** The page makes that folder at startup. It gives the host's `CreateCommonFolders` - (`main.js@961019`) the text `%APPDATA%\twinBASIC`, which the host expands in the IDE's + the text `%APPDATA%\twinBASIC`, which the host expands in the IDE's own environment, creates `packages`, `themes`, `locale`, `addins\win32` and `addins\win64` in, and returns. The page keeps the path as `commonFolderRootPath` and - passes it to the compiler when it starts it and when it asks it to load the add-ins - (`main.js@1047705` and `@1048667`). Measured on BETA 983 and 995 by + passes it to the compiler when it starts it and when it asks it to load the add-ins. + Measured on BETA 1005 by [test/addin/appdata.test.mjs](test/addin/appdata.test.mjs), with a probe add-in that prints the file it was loaded from: an IDE started with `APPDATA` naming a folder of the lane's own loaded the probe from `\twinBASIC\addins\win32`, and not a second @@ -102,15 +101,14 @@ the compiler what a symbol is.** Each of those gaps shapes a stage below. Addin`, so a test looks for the name it expects rather than counting. - **Holding Shift while a project opens skips the add-ins.** The page asks the compiler to load them only when `shiftKeyDown` is false, and otherwise writes `[IDE] SHIFT - KEY DETECTED: DISABLED LOADING OF ADDINS` to the DEBUG CONSOLE (`main.js@1048443`). + KEY DETECTED: DISABLED LOADING OF ADDINS` to the DEBUG CONSOLE. `shiftKeyDown` follows the keymap's `tbMisc_ShiftKeyStateDown` and `...Up` actions, so a test that presses Shift must not do it while a project is opening. - **The linker exports `tbCreateCompilerAddin` as `tbCreateCompilerAddin_v3`, and the - loader takes three names (P14).** Read in the compiler's code and measured on BETA 983 and - 995 by [test/addin/entry.test.mjs](test/addin/entry.test.mjs). The loader --- in BETA 983 - the code at `0x1EAB6275` in `twinBASIC_win32.dll`, and in another build the code that - pushes the address of the string `tbCreateCompilerAddin_v2`, found with `dumpbin /disasm`; - the same in `twinBASIC_win64.dll` --- asks `GetProcAddress` for + loader takes three names (P14).** Read in the compiler's code and measured on BETA 1005 by + [test/addin/entry.test.mjs](test/addin/entry.test.mjs). The loader --- the code that + pushes the address of the string `tbCreateCompilerAddin_v2` in `twinBASIC_win32.dll`, + found with `dumpbin /disasm`; the same in `twinBASIC_win64.dll` --- asks `GetProcAddress` for `tbCreateCompilerAddin`, then `tbCreateCompilerAddin_v2`, then `tbCreateCompilerAddin_v3`, and calls the first it finds **the same way whichever it is**: one argument, the `Host`, `stdcall` on win32. It asks what that returns for `IAddInV1` --- @@ -122,20 +120,20 @@ the compiler what a symbol is.** Each of those gaps shapes a stage below. patched in four copies, the plain name, `_v2` and `_v3` all loaded, and `_v4` did not, with `[EntryV4.dll] Failed to load addin. Entry point not found. Addin may have been compiled for a newer version of the twinBASIC IDE.` in the DEBUG CONSOLE and an `Unknown Addin` in - the compiler's list. Both of P7's builds, win32 and win64, exported `_v3` alone. Every - install on this machine, BETA 947 to 995, has the same three names in its loader, and each - one's shipped Global Search add-in exports `_v3` alone, so both stamps are older than BETA - 947. + the compiler's list. Both of P7's builds, win32 and win64, exported `_v3` alone. The BETA + 1005 install has the three names in the loader of `twinBASIC_win32.dll` and of + `twinBASIC_win64.dll`, and its shipped Global Search add-in exports `_v3` alone, in both + folders. - **Add-ins cannot be switched off.** The Add-Ins menu lists the loaded add-ins with ticks, and every item calls `notSupportedMenuOption()` *(reported)*. - **A compiler restart loads every add-in again, from the file in its folder then (P9).** - Measured on BETA 983 and 995 by [test/addin/reload.test.mjs](test/addin/reload.test.mjs). A + Measured on BETA 1005 by [test/addin/reload.test.mjs](test/addin/reload.test.mjs). A restart is the toolbar's restart button, every switch of the build target (below), and the - IDE's own restart after a compiler crash. The page's `restartCompiler` (`main.js@153451`) + IDE's own restart after a compiler crash. The page's `restartCompiler` first takes away what every add-in added: `removeAddinAlterations` removes their toolbar buttons and shortcuts, and hides each tool window's body behind the text `(currently unavailable)`, leaving the window where it was. It ends the old compiler with `taskkill - /F` (`forceTerminate`, `main.js@1050553`), so **no add-in's `Class_Terminate` runs**: the + /F` (`forceTerminate`), so **no add-in's `Class_Terminate` runs**: the probe wrote a line to a file from it, which it did for an object it dropped as it loaded and never for itself. The new compiler then loads the add-ins as it starts, and each runs `OnProjectLoaded` again, in a new process, so **an add-in keeps no state across a @@ -160,7 +158,7 @@ the compiler what a symbol is.** Each of those gaps shapes a stage below. `addins\win64` alone. **Switching the target of an open project (Ctrl+F1 / Ctrl+F2) restarts the compiler in the other bitness, and the new one loads the other folders.** `changedActiveBuildConfig` in `ide/main2.js` records the new target and kills the - compiler. Measured on BETA 983 and 995 by [test/addin/arch.test.mjs](test/addin/arch.test.mjs), + compiler. Measured on BETA 1005 by [test/addin/arch.test.mjs](test/addin/arch.test.mjs), with a 32-bit and a 64-bit build of a probe in both folders of their bitness, the install's and `%APPDATA%`'s: the project opened in win32, whose compiler loaded the two 32-bit copies alone; a switch to win64 started `twinBASIC_win64_noDEP.exe`, which loaded the two 64-bit @@ -171,7 +169,7 @@ the compiler what a symbol is.** Each of those gaps shapes a stage below. ### Keyboard shortcuts -Read at `main.js@608242`, `@610953` and `@611152`, and measured on BETA 983 and 995 by P1 and P2, +Read in `ide/main.js`, and measured on BETA 1005 by P1 and P2, whose lane is [test/addin/keys.test.mjs](test/addin/keys.test.mjs). - `KeyboardShortcuts.Add` lowercases the key string, deletes its whitespace and stores it @@ -213,8 +211,7 @@ whose lane is [test/addin/keys.test.mjs](test/addin/keys.test.mjs). ### Tool windows -Read at `main.js@1002292` (`toolWindowElementAddChild`) and `@1005960` -(`toolWindowElementSetProperty`), and measured on BETA 983 and 995 by P3, P4 and P12, whose lane is +Read in `toolWindowElementAddChild` and `toolWindowElementSetProperty`, and measured on BETA 1005 by P3, P4 and P12, whose lane is [test/addin/panes.test.mjs](test/addin/panes.test.mjs). - **A tool window is part of the main document**, inside an open shadow root, not an iframe. @@ -226,7 +223,7 @@ Read at `main.js@1002292` (`toolWindowElementAddChild`) and `@1005960` a place, but its place was under the window's bottom edge, where a click lands on the resize handle. - **A window's id is its identity, and a window given none shares the id `""`.** - `createToolWindow` (`main.js@992211`) files a window under the second argument of + `createToolWindow` files a window under the second argument of `ToolWindows.Add`, and `createToolWindowById` returns the window the page already has under that id, with its body emptied, rather than a new one; the add-in's new `ToolWindow` is then bound to it, since the page answers with its number. P9's window given no id was @@ -292,7 +289,7 @@ Read at `main.js@1002292` (`toolWindowElementAddChild`) and `@1005960` 1. **The external browser.** `ShellExecuteW` from the add-in DLL. Certain to work; it leaves the IDE. The IDE itself opens links with `hostAppObject.Shell('cmd.exe /c start "link" "'+url+'"',1)` *(reported)* --- a host object that only page script can reach. -2. **An `iframe` in a tool window --- it works (P3, BETA 983 and 995).** Nothing refuses the tag. No +2. **An `iframe` in a tool window --- it works (P3, BETA 1005).** Nothing refuses the tag. No file under `ide\` sets a Content-Security-Policy --- there is no `Content-Security-Policy`, `http-equiv` or `frame-ancestors` in any `ide\*.htm` --- and neither does the compiler's HTTP header template *(reported)*. The host DLL, @@ -338,7 +335,7 @@ Read at `main.js@1002292` (`toolWindowElementAddChild`) and `@1005960` **Offline** is harder. `_site-offline/` works over `file://`, and a page served from `http://localhost` cannot frame a `file://` URL. The options are `srcdoc` with rewritten links, or files under the IDE's `ide\` folder. **The IDE serves any file placed there (P13, -BETA 983 and 995)**, measured by [test/addin/ideserver.test.mjs](test/addin/ideserver.test.mjs) +BETA 1005)**, measured by [test/addin/ideserver.test.mjs](test/addin/ideserver.test.mjs) with files put in a lane's copy of the install: - The server is the page server, `bin\twinBASIC_win32.exe --ide=`, not the compiler: @@ -370,8 +367,8 @@ offline site itself instead (Stage 4, increment 5), so this route is not taken. 4](#stage-4-the-add-in-in-increments)) and, for context, the compiler's hover asked through the page (increment 3), with its own parser of the project's source deferred. - **The compiler knows, and names the package, the container and the kind (P5).** Measured - on BETA 983 and 995 by [test/addin/symbols.test.mjs](test/addin/symbols.test.mjs), which puts each - question the way the IDE's own code does. Hover (`main.js@842393`) + on BETA 1005 by [test/addin/symbols.test.mjs](test/addin/symbols.test.mjs), which puts each + question the way the IDE's own code does. Hover returns markdown: for a procedure, its declaration, then a heading naming where it is declared, then its `[Description]` text, which for a VBA function is several paragraphs: @@ -392,8 +389,8 @@ offline site itself instead (Stage 4, increment 5), so this route is not taken. `*enum-value* **vbOKOnly** = 0 ... \`in VBA.Constants.VbMsgBoxStyle\``, a constant `*constant* **vbCrLf As String** = ...` then `` `in VBA.Constants` ``. A VB control's member is named by its control's interface, `cb.Value` `in VB._CheckBox`, which the - `interfaces` map lacks, and a `PropertyBag`'s `ReadProperty` by an interface its default - one inherits, `in VBRUN.PropertyBag_VB5`. Some members name **another procedure**, the + `interfaces` map lacks, and a `PropertyBag`'s `ReadProperty` `in VBRUN._PropertyBag`, its + default interface. Some members name **another procedure**, the one behind them: `Err.Number` is `GetErrNumber` `in VBA._HiddenModule`, `App.Path` `GetAppPath` and `Screen.Width` `ScreenGetWidth`, both `in VB.HiddenModule2`. A member inside `With` is named as it would be written in full, and a function called as a @@ -402,12 +399,11 @@ offline site itself instead (Stage 4, increment 5), so this route is not taken. does with the VB and tbIDE ones. A variable gives its declaration, `*local variable* Dim c As Collection`. `Debug`, `Debug.Print` and a statement such as `Dim` give nothing, and a type such as `Long` a line - about it. For those three a build gives no hover (BETA 983) or a hover whose text is empty - (BETA 987 and 995), so the add-in treats both as nothing. Over a procedure's name in its own declaration, hover gives a debug block + about it. For those three the hover's text is empty, and the add-in treats an empty text + as nothing. Over a procedure's name in its own declaration, hover gives a debug block instead, `TB-DEBUG CODEGEN SIZE: [NOT-READY]`; over a `ByVal` parameter of a class, - `String`, `Variant` or `Object` it adds a wrong note about `Option Explicit` - ([BUGS-TO-REPORT.md](BUGS-TO-REPORT.md)). -- **Go To Definition names the package's own source.** Definition (`@846297`) returns one + `String`, `Variant` or `Object` it says nothing about `Option Explicit`. +- **Go To Definition names the package's own source.** Definition returns one file and range. For `MsgBox` the file is `twinbasic:/SymbolsProbe/Packages/tbIDE/Packages/VBA/Sources/Interaction.twin` and the range the declaration's lines, and the IDE's file system opens the file. Each package's @@ -651,27 +647,27 @@ The table gives each answer in brief; the sections above have the detail. | # | Question | What it decides | |---|---|---| -| P1 | Do `{ctrl}` and `{alt}` add-in shortcuts ever fire? **Answered, BETA 983 and 995: no.** `d`, `{shift}d`, `f1` and `{shift}f1` fire; `{ctrl}{shift}d`, `{ctrl}d` and `{alt}f` fire only when the same key was pressed on its own less than 500 ms before. Queued in BUGS-TO-REPORT.md; the KeyboardShortcuts page has a NOTE. | the bug report; which key the add-in uses; the NOTE on the KeyboardShortcuts page | -| P2 | Does the add-in's `f1` fire with focus in the code editor, and what happens with signature help showing? **Answered, BETA 983 and 995: yes.** It fires with the focus in the code editor, in the DEBUG CONSOLE and on nothing, and types nothing. With signature help showing, the IDE expands or collapses it as well. | F1 or another key --- F1 | -| P3 | Does an `iframe` of a documentation page load and navigate inside a tool window? **Answered, BETA 983 and 995: yes.** It loads, follows its own links, moves when the add-in sets `src`, scrolls, and fills the window under a wrapper's flex layout; the live site works too. Keys in the frame never reach the add-in, and the page's colour scheme is Windows', not the IDE's. | how pages are shown --- in the pane | -| P4 | Does `innerHTML` render, and do inline handlers in it run page script? **Answered, BETA 983 and 995: yes, and yes.** Inline handlers run as the IDE page's own script, with its globals in reach. A property whose name starts with `on` is dropped, and the add-in hears no error. | how summaries are drawn; whether the page-internals route exists --- it does | -| P5 | What does hover return for `MsgBox`, `Collection.Add`, `ToolWindows.Add` and a symbol declared in the project? What does definition return for a package symbol? **Answered, BETA 983 and 995:** hover gives the declaration, then a heading naming where it is declared: `in VBA.Interaction`, `in VBA._Collection`, `in tbIDE.IToolWindowsV1`, `in SymbolsProbe.Symbols` --- a class's members by its default interface, not by the class's name. Definition gives the declaration in the package's own source, which the IDE opens. Nothing for `Debug.Print` or a statement. Only page script can ask. | compiler-assisted context is possible; which route is [Stage 4](#stage-4-the-add-in-in-increments), increment 3 | -| P6 | Does the compiler also load add-ins from `%APPDATA%\twinBASIC\addins\`? Needs a DLL placed there, which the user's own IDE would load too --- **ask before running it against the real `%APPDATA%`.** **Answered, BETA 983 and 995: yes**, from `addins\win32` there and not from `addins` itself. The compiler loads from the folder the page sends it. The lane points `APPDATA` at a folder of its own, so no DLL goes in the user's. | harness isolation --- every lane IDE gets an `APPDATA` of its own | -| P7 | Which bitness does the compiler start in, and does switching the build target restart it in the other one and load the other `addins` folder? **Answered, BETA 983 and 995: yes, and yes.** The target a project opens in picks the compiler, and each compiler loads the folders of its own bitness alone, the install's and `%APPDATA%`'s. | building and testing both bitnesses --- `buildAddin` builds either, and a shipped add-in needs both | -| P8 | Is a loaded add-in DLL locked against being overwritten? **Answered, BETA 983 and 995: yes.** While its IDE runs, overwriting fails (`EBUSY`) and deleting fails (`EPERM`), though renaming works; the hold outlasts the compiler's exit by a few tens of milliseconds. The P9 lane checks all three again. | the rebuild loop --- the DLL is built outside `addins`, and copied in once the IDE has ended, or renamed aside first (P9) | -| P9 | Does a compiler restart reload add-ins from disk? **Answered, BETA 983 and 995: yes.** The restart removes every add-in's buttons and shortcuts, leaves its windows showing `(currently unavailable)`, kills the old compiler so that no `Class_Terminate` runs, and starts a compiler that loads whatever file is in the folders then. A window comes back by its id. | a rebuild loop without restarting the IDE --- it works: rename aside, copy in, restart | -| P10 | Does an environment variable set by the harness reach the add-in (`Environ$`)? **Answered, BETA 983 and 995: yes**, through the launcher, the IDE and the compiler the IDE starts, and again in a compiler a restart starts. With `TB_ADDIN_TEST=1` in `launchIde`'s environment, `Environ$` and `GetEnvironmentVariableW` both return `1`; left out, `Environ$` is empty and the Win32 call says unset. `WEBVIEW2_USER_DATA_FOLDER`, which `launchIde` always sets, arrives with the lane's port in it. | the side-effect switch | -| P11 | Does the IDE write into its own install folder during a session? **Answered, BETA 983 and 995: no.** A compile, a compiler crash, exports, a `tbbuild` and `tbrun` runs leave every file of the install byte-identical, mtimes included (233 files on 983, 235 on 995); `%APPDATA%` was not re-checked on 995. | hardlinks or copies --- copies, for safety, at 380 ms | -| P12 | Does `raiseEvent` from plain tool-window HTML throw? **Answered, BETA 983 and 995: yes** --- `TypeError: Cannot read properties of null (reading 'rootEventHandler')`, and the listener is not called. An inline handler that calls the listener `AddEventListener` stored on its parent, `this.parentNode.(event)`, reaches the add-in. | how the pane's events are written | -| P13 | Does the compiler's HTTP server serve any file placed under `ide\`? **Answered, BETA 983 and 995: yes**, and it is the page server, `twinBASIC_win32.exe --ide=`, not the compiler. A frame with a relative `src` shows the file on the IDE page's own origin. A query string makes a 404, and `.html` has no `Content-Type`. | an offline route --- it exists ([Offline](#ways-to-show-a-page)) | -| P14 | What do `tbCreateCompilerAddin_v2` and `_v3` expect? **Answered, BETA 983 and 995: what `tbCreateCompilerAddin` does.** The names are version stamps: the linker exports a function named `tbCreateCompilerAddin` as `tbCreateCompilerAddin_v3` alone, and an IDE that knows none of a DLL's names refuses it as `compiled for a newer version of the twinBASIC IDE`, as a patched `_v4` was. | nothing in the design --- the add-in declares `tbCreateCompilerAddin` as the package says; the tbIDE page has a NOTE | -| P15 | Does the compiler say anything about a name's `[Description]`, or a COM type library's help string? **Answered, BETA 995: hover gives it**, after the line naming where the name is declared, for a procedure, a member, a constant, a module variable, an enumeration, a `Type`, a class and a module, and a type library's member (`Scripting.IDictionary.Add`: "Add a new key and item to the dictionary."). Classes and modules, the project's and a type library's, are `in library `. A procedure with none gets the IDE's tip, `*no further info available. Tip: use [Description("")] ...*`. On a procedure's name where it is declared, hover gives a block of code-generation details (`TB-DEBUG CODEGEN SIZE: [NOT-READY]`) instead. Signature help gives the same text. A member of an enumeration has none: a `[Description(...)]` line inside an `Enum` is not an attribute but a member of its own, named by a bracketed identifier, as VB6 allows (`Debug.Print Shade.[Description("The light one.")]` prints its value), so hover lists it as a member of the enumeration (twinbasic/twinbasic#2465, closed as not a bug). | Stage 4, increment 4: a name with no page shows its declaration and description from the hover; no parser of the project's source is needed | -| P16 | What does hover help through the public API cost, and how long does a widget live? **Answered, BETA 997:** `GetSelectionInfo` takes 0.5 ms a call, reading `Text` of a 152-character file 0.3 ms, `AddMonacoWidget` 2.8 ms and `Remove` 0.6 ms; a 100 ms `AddinTimer` ticks every 110 ms. A widget with a column is drawn above its line (below when there is no room), stays when the cursor moves, and is removed by the IDE when another file is shown; `Remove` on it after that raises no error. An add-in has no cursor or mouse event (only `OnProjectLoaded`, `OnChangedActiveEditor`, `OnChangedTheme`, a tool window's `OnClose` and a button's `OnClick`), so it can only poll the cursor, and cannot see the mouse | Stage 4, increment 6: polling every 250 ms costs nothing worth counting | -| 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 ``, 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 | +| P1 | Do `{ctrl}` and `{alt}` add-in shortcuts ever fire? **Answered, BETA 1005: no.** `d`, `{shift}d`, `f1` and `{shift}f1` fire; `{ctrl}{shift}d`, `{ctrl}d` and `{alt}f` fire only when the same key was pressed on its own less than 500 ms before. Queued in BUGS-TO-REPORT.md; the KeyboardShortcuts page has a NOTE. | the bug report; which key the add-in uses; the NOTE on the KeyboardShortcuts page | +| P2 | Does the add-in's `f1` fire with focus in the code editor, and what happens with signature help showing? **Answered, BETA 1005: yes.** It fires with the focus in the code editor, in the DEBUG CONSOLE and on nothing, and types nothing. With signature help showing, the IDE expands or collapses it as well. | F1 or another key --- F1 | +| P3 | Does an `iframe` of a documentation page load and navigate inside a tool window? **Answered, BETA 1005: yes.** It loads, follows its own links, moves when the add-in sets `src`, scrolls, and fills the window under a wrapper's flex layout; the live site works too (checked outside the lane). Keys in the frame never reach the add-in, and the page's colour scheme is Windows', not the IDE's. | how pages are shown --- in the pane | +| P4 | Does `innerHTML` render, and do inline handlers in it run page script? **Answered, BETA 1005: yes, and yes.** Inline handlers run as the IDE page's own script, with its globals in reach. A property whose name starts with `on` is dropped, and the add-in hears no error. | how summaries are drawn; whether the page-internals route exists --- it does | +| P5 | What does hover return for `MsgBox`, `Collection.Add`, `ToolWindows.Add` and a symbol declared in the project? What does definition return for a package symbol? **Answered, BETA 1005:** hover gives the declaration, then a heading naming where it is declared: `in VBA.Interaction`, `in VBA._Collection`, `in tbIDE.IToolWindowsV1`, `in SymbolsProbe.Symbols` --- a class's members by its default interface, not by the class's name. Definition gives the declaration in the package's own source, which the IDE opens. Nothing for `Debug.Print` or a statement. Only page script can ask. | compiler-assisted context is possible; which route is [Stage 4](#stage-4-the-add-in-in-increments), increment 3 | +| P6 | Does the compiler also load add-ins from `%APPDATA%\twinBASIC\addins\`? Needs a DLL placed there, which the user's own IDE would load too --- **ask before running it against the real `%APPDATA%`.** **Answered, BETA 1005: yes**, from `addins\win32` there and not from `addins` itself. The compiler loads from the folder the page sends it. The lane points `APPDATA` at a folder of its own, so no DLL goes in the user's. | harness isolation --- every lane IDE gets an `APPDATA` of its own | +| P7 | Which bitness does the compiler start in, and does switching the build target restart it in the other one and load the other `addins` folder? **Answered, BETA 1005: yes, and yes.** The target a project opens in picks the compiler, and each compiler loads the folders of its own bitness alone, the install's and `%APPDATA%`'s. | building and testing both bitnesses --- `buildAddin` builds either, and a shipped add-in needs both | +| P8 | Is a loaded add-in DLL locked against being overwritten? **Answered, BETA 1005: yes.** While its IDE runs, overwriting fails (`EBUSY`) and deleting fails (`EPERM`), though renaming works; the hold outlasts the compiler's exit by a few tens of milliseconds. The P9 lane checks all three again. | the rebuild loop --- the DLL is built outside `addins`, and copied in once the IDE has ended, or renamed aside first (P9) | +| P9 | Does a compiler restart reload add-ins from disk? **Answered, BETA 1005: yes.** The restart removes every add-in's buttons and shortcuts, leaves its windows showing `(currently unavailable)`, kills the old compiler so that no `Class_Terminate` runs, and starts a compiler that loads whatever file is in the folders then. A window comes back by its id. | a rebuild loop without restarting the IDE --- it works: rename aside, copy in, restart | +| P10 | Does an environment variable set by the harness reach the add-in (`Environ$`)? **Answered, BETA 1005: yes**, through the launcher, the IDE and the compiler the IDE starts, and again in a compiler a restart starts. With `TB_ADDIN_TEST=1` in `launchIde`'s environment, `Environ$` and `GetEnvironmentVariableW` both return `1`; left out, `Environ$` is empty and the Win32 call says unset. `WEBVIEW2_USER_DATA_FOLDER`, which `launchIde` always sets, arrives with the lane's port in it. | the side-effect switch | +| P11 | Does the IDE write into its own install folder during a session? **Answered: no.** A compile, a compiler crash, exports, a `tbbuild` and `tbrun` runs leave every file of the install byte-identical, mtimes included; `%APPDATA%` was not re-checked. | hardlinks or copies --- copies, for safety, at 380 ms | +| P12 | Does `raiseEvent` from plain tool-window HTML throw? **Answered, BETA 1005: yes** --- `TypeError: Cannot read properties of null (reading 'rootEventHandler')`, and the listener is not called. An inline handler that calls the listener `AddEventListener` stored on its parent, `this.parentNode.(event)`, reaches the add-in. | how the pane's events are written | +| P13 | Does the compiler's HTTP server serve any file placed under `ide\`? **Answered, BETA 1005: yes**, and it is the page server, `twinBASIC_win32.exe --ide=`, not the compiler. A frame with a relative `src` shows the file on the IDE page's own origin. A query string makes a 404, and `.html` has no `Content-Type`. | an offline route --- it exists ([Offline](#ways-to-show-a-page)) | +| P14 | What do `tbCreateCompilerAddin_v2` and `_v3` expect? **Answered, BETA 1005: what `tbCreateCompilerAddin` does.** The names are version stamps: the linker exports a function named `tbCreateCompilerAddin` as `tbCreateCompilerAddin_v3` alone, and an IDE that knows none of a DLL's names refuses it as `compiled for a newer version of the twinBASIC IDE`, as a patched `_v4` was. | nothing in the design --- the add-in declares `tbCreateCompilerAddin` as the package says; the tbIDE page has a NOTE | +| P15 | Does the compiler say anything about a name's `[Description]`, or a COM type library's help string? **Answered, BETA 1005: hover gives it**, after the line naming where the name is declared, for a procedure, a member, a constant, a module variable, an enumeration, a `Type`, a class and a module, and a type library's member (`Scripting.IDictionary.Add`: "Add a new key and item to the dictionary."). Classes and modules, the project's and a type library's, are `in library `. A procedure with none gets the IDE's tip, `*no further info available. Tip: use [Description("")] ...*`. On a procedure's name where it is declared, hover gives a block of code-generation details (`TB-DEBUG CODEGEN SIZE: [NOT-READY]`) instead. Signature help gives the same text. A member of an enumeration has none: a `[Description(...)]` line inside an `Enum` is not an attribute but a member of its own, named by a bracketed identifier, as VB6 allows (`Debug.Print Shade.[Description("The light one.")]` prints its value), so hover lists it as a member of the enumeration (twinbasic/twinbasic#2465, closed as not a bug). | Stage 4, increment 4: a name with no page shows its declaration and description from the hover; no parser of the project's source is needed | +| P16 | What does hover help through the public API cost, and how long does a widget live? **Answered, BETA 1005:** `GetSelectionInfo` takes 0.3 ms a call, reading `Text` of a 152-character file 0.2 ms, `AddMonacoWidget` 2.2 ms and `Remove` 1.3 ms; a 100 ms `AddinTimer` ticks every 110 ms. A widget with a column is drawn above its line (below when there is no room), stays when the cursor moves, and is removed by the IDE when another file is shown; `Remove` on it after that raises no error. An add-in has no cursor or mouse event (only `OnProjectLoaded`, `OnChangedActiveEditor`, `OnChangedTheme`, a tool window's `OnClose` and a button's `OnClick`), so it can only poll the cursor, and cannot see the mouse | Stage 4, increment 6: polling every 250 ms costs nothing worth counting | +| 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 1005: 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 ``, 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 | | P18 | What keeps a hover shown while the mouse slides down it past the code editor's bottom? **Answered, BETA 1005: the IDE.** It draws `.monaco-hover` at `z-index: 1000 !important`, above its dock resizer along the editor's edge (`.dockElementResizer`, `z-index: 1000`) and its drop targets, so they never take the mouse from the hover (Monaco's `_onEditorMouseLeave` would hide it). Monaco alone keeps a hover the mouse is over: its DOM stays inside the editor's, and the hover is sticky. CDP's mouse reaches the 6 px resizer only in steps small enough to land on it, so the test slides the mouse a pixel at a time | Stage 4, increment 6: nothing in the add-in; the `help` lanes check the IDE's behaviour | -| 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 | -| 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-*`). `/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 | -| 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 | +| P19 | Can an add-in show a window of its own, a Form holding the WebView2 package's control? **Answered, BETA 1005: 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 | +| P20 | Can an add-in learn, through the public API, which packages its project references? **Answered, BETA 1005: yes** ([references.test.mjs](test/addin/references.test.mjs), `probes/references` and its three hosts `probes/references-*`). `/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 | +| P21 | What does reading `Parent` of the file system's root do? **Answered, BETA 1005: 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 | ### Stage 3: the symbol index, generated by the docs build @@ -814,7 +810,7 @@ the new build in its place, and click the compiler's restart button (P9). The la not: a restart saves a harness about a second against opening a new IDE. 1. **F1 to a page**, tested by [help.test.mjs](test/addin/help.test.mjs) on BETA - 995. F1 takes the selection or the name under the cursor (below) and looks it up in the + 1005. F1 takes the selection or the name under the cursor (below) and looks it up in the embedded index. One page is shown in the help pane (increment 2); a miss says `No help for ''` through `ShowNotification`; an empty spot puts the focus in the pane's search box. Several pages fill the pane's results list, labelled @@ -832,7 +828,7 @@ not: a restart saves a harness about a second against opening a new IDE. is on, and every scenario checks that line before it presses anything. An IDE build that stopped passing the variable on to the compiler then fails the run, instead of starting a browser on the private desktop. -2. **The help pane**, tested by the same lane on BETA 995. The tool window +2. **The help pane**, tested by the same lane on BETA 1005. The tool window `tbDocsHelpPane`, titled `TWINBASIC HELP`, holds a search box, an *Open in browser* button, a results list and the page in an iframe (P3), laid out by a flex wrapper inside the root, because showing the window resets the root's `display`. The toolbar's @@ -886,11 +882,11 @@ not: a restart saves a harness about a second against opening a new IDE. followed inside the frame is lost. *Open in browser* passes no theme. The lane works out the IDE's group from its panel colour, not from the API, checks every page's `data-theme`, and switches the theme with the IDE's own commands - (`executeIdeCommand("tbTheme_SwitchToLightMode")`, `...DarkMode`, `main.js` BETA 995), + (`executeIdeCommand("tbTheme_SwitchToLightMode")`, `...DarkMode`), which save it in `twinBASIC_IDE\IDESettings\GENERAL` (`colorTheme`), where the user's own IDE reads it; the registry tidy puts that one entry back (`restoreTheme`). **In the detached window the frame's storage throws** (`SecurityError`, both storages, - BETA 997): the window's page is a `data:` URL (`NavigateToString`), so the docs frame is a + BETA 1005): the window's page is a `data:` URL (`NavigateToString`), so the docs frame is a frame of another site under an opaque top-level origin, with a DevTools target of its own (type `iframe`). So the head script keeps the theme and `pane` in the frame's `window.name` too (`tbdocs::<1>`, written only by a page given either parameter, @@ -930,7 +926,7 @@ not: a restart saves a harness about a second against opening a new IDE. case loads the build's real page, and a 404 fails it. The frame is then same-site, and `Page.getFrameTree` reads its URL. The offline tree cannot be used: a page served over http cannot frame a `file://` URL. So the lane needs `build.bat` first. -3. **Context: which `Add`?** Tested by the same lane on BETA 995. **The route is the +3. **Context: which `Add`?** Tested by the same lane on BETA 1005. **The route is the page's socket** (owner): the add-in's own parser would have to be close to a whole twinBASIC parser, so it waits, and the socket stands until upstream gives the API a call for it. For the name under the cursor, F1 asks the compiler's hover about @@ -967,7 +963,7 @@ not: a restart saves a harness about a second against opening a new IDE. the project's `Beep`. - The socket code is in files of its own, `CompilerHover.twin` and `hover.js`, without comments, so that it can be replaced whole once the API has a call. -4. **A name with no page**, tested by the same lane on BETA 995 (owner): a user who +4. **A name with no page**, tested by the same lane on BETA 1005 (owner): a user who documents their own code with `[Description]` sees it, and is not sent to a page for another name. When the hover names a package the index does not document --- the project, another package, a type library --- F1 shows, in @@ -984,7 +980,7 @@ not: a restart saves a harness about a second against opening a new IDE. `f1Shows` marks the page before pressing F1 and waits for a page without the mark. A page showing again after a summary is waited for too, since its `src` can already be right. -5. **Offline help**, tested by the lane `help-offline` on BETA 995 (owner's choice): the +5. **Offline help**, tested by the lane `help-offline` on BETA 1005 (owner's choice): the add-in's own server, written in twinBASIC, serving one archive embedded in the DLL. The owner's other choices: the archive is a resource; the documentation build makes it; the pane uses it when the DLL has it, and the live site otherwise; the symbol index stays a @@ -1021,7 +1017,7 @@ not: a restart saves a harness about a second against opening a new IDE. (`PerformanceNavigationTiming.responseStatus`), so a 404 fails a case either way. An offline-only case asks the server from Node: a page's gzip body and a stored image byte for byte, a folder's 301, a 404 and `HEAD`. -6. **Hover help**, tested by the `help` and `help-offline` lanes on BETA 997, with +6. **Hover help**, tested by the `help` and `help-offline` lanes on BETA 1005, with the owner's choices: links in the IDE's hover under the mouse, behind one *Hover help* checkbox in the settings panel (increment 8), off by default and kept with `SaveSetting` (`Hover`, `On`). It shows a link per page the name has, at most five, labelled with the @@ -1058,7 +1054,7 @@ not: a restart saves a harness about a second against opening a new IDE. move it against the window's right edge before the mouse rests anywhere; and a hover left open covers the toolbar, so each mouse case moves the mouse away at its end. `test/addin/hover.mjs` holds the helpers both lanes use. -7. **A detached window**, tested by the `help` and `help-offline` lanes on BETA 997 +7. **A detached window**, tested by the `help` and `help-offline` lanes on BETA 1005 (owner's request): the pane can be moved to another monitor. The owner's choices: the add-in shows a window of its own, a twinBASIC Form holding the WebView2 package's control (P19), rather than a `window.open` from the page, which would be page internals and which the host most likely sends to the browser (the host DLL @@ -1173,7 +1169,7 @@ not: a restart saves a harness about a second against opening a new IDE. caption (no read-back of the DWM attribute), Alt+F4, the registry read, maximizing on a monitor other than the primary one (the lab machine has one), and the move itself, whose loop needs the real mouse, which the harness's desktop has none of. -8. **Settings**, tested by the `help` and `help-offline` lanes on BETA 997 (owner's +8. **Settings**, tested by the `help` and `help-offline` lanes on BETA 1005 (owner's choice): a gear at the right end of the pane's bar, and on the detached window's title bar (in its bar under the Windows caption), opens a drop-down panel of settings, one label row each. A click outside it, Esc, or the gear closes it; changing a @@ -1184,7 +1180,7 @@ not: a restart saves a harness about a second against opening a new IDE. `blur` closes the panel as well. The lanes' pane frame is on the IDE page's site, so one case points it at `127.0.0.1` to check the shade with a cross-site frame. 9. **Only the packages the project references**, tested by the `help` and - `help-offline` lanes on BETA 997 (owner's choice): F1, the hover links + `help-offline` lanes on BETA 1005 (owner's choice): F1, the hover links and the search offer the language's own entries and the packages the project references; an *All packages* row in the settings panel, off by default and kept with `SaveSetting` (`Packages`, `All`), offers every package. `LoadPackages` reads the references at diff --git a/WIP.Indexer.md b/WIP.Indexer.md index e871cd4d4..21bcb4e1e 100644 --- a/WIP.Indexer.md +++ b/WIP.Indexer.md @@ -131,14 +131,14 @@ which would write the snapshots of another build. ## Decisions of the owner - **Snapshots are committed only for the documented packages**: 14 files, 3.2 MB - (about 350 KB compressed). The contributed packages and the extra CEF builds are indexed into + (about 360 KB compressed). The contributed packages and the extra CEF builds are indexed into the store and left out of the repository. A package joins when its section does; `sync` copies a snapshot for a documented package it indexed in that run, and gives a documented package with none the store's `api.json` when that is of its `indexed_from` version (`adoptSnapshots`): a package is usually synced before its section exists, and a later sync finds its store current and indexes nothing. -- **They are taken from the build the reference was last indexed against, BETA 997** - (`beta-x-0997`), not from a newer one, so that the pages and the baseline agree and +- **They are taken from the build the reference was last indexed against, BETA 1005** + (`beta-x-1005`), not from a newer one, so that the pages and the baseline agree and `analyze` of a newer build shows the real distance. - **The twinBASIC "install" is the release zip unzipped.** Its `packages//package.twinproj` files are the zip's, so either gives the same sources and the same `api.json`, byte for byte. @@ -155,7 +155,7 @@ which would write the snapshots of another build. decides the store folder, the snapshot folder and the folder of the reference. - **CEF is one snapshot, `cefPackage145`.** `cefPackage49`, `cefPackage109` and `cefPackage145` are one source tree compiled against three CEF runtimes, and their `api.json` files differ - only in the `package` key (checked on BETA 997 and 1005). `analyze` compares a package with + only in the `package` key (checked on BETA 1005). `analyze` compares a package with its own snapshot, so naming all three would triple every CEF task and keep two copies of 460 KB. If a build ever declares an API of its own, it needs its name in `package_name:` and a snapshot. @@ -190,7 +190,7 @@ cache. packages to derive it from. `derive --check` is outside every gate for the same reason. - **A scanner change can change it**, as it can the snapshots. The `[ ]` Enum member (a bracket group alone on a line is a member) gives VB's `ReportBaseCtl.ReportSizeConstants` - its 17 values at BETA 997, the first named `" "`. + its 17 values at BETA 1005, the first named `" "`. ## `draft` and the doc-draft workflow @@ -204,8 +204,8 @@ cache. section exactly. Every rule in `draft-plan.mjs` is a majority over the section's own pages. - **How well it places, checked by leaving each symbol out** of every section with a store - package (the thirteen built-in and default ones at BETA 997, and the nine contributed ones of - the `contributed-packages` branch) and planning it again: 994 of 998 members land on the file + package (the thirteen built-in and default ones, and the nine contributed ones of the + `contributed-packages` branch) and planning it again: 994 of 998 members land on the file the section has them on, with its parent and permalink; 138 of 156 types; and the landing page of each contributed section, planned from the other eight, matches in all nine. The 18 types that miss are layout choices no API shows: six that are the only type of their kind @@ -225,7 +225,7 @@ cache. section that has one, of the same shape: a folder's `index.md` for a class that gets a folder, never a one-page class. - **A permalink is computed only where the rule holds for every existing page** of the - section (`followsFolders`). On staging at BETA 997 that is every section but VBA's, whose + section (`followsFolders`). At BETA 1005 that is every section but VBA's, whose pages live under `/tB/Modules/`. A section that breaks the rule once gets no computed permalinks at all, rather than a guess that a sibling page would contradict. - **The prep is Node and the workflow is thin**, as Wisdom's extract is @@ -283,5 +283,5 @@ cache. lines of it into this note would bury both. Its one reader is `lib/twinserv-client.mjs`, which calls only `query` and `download`; the rest (login, publish, version check, the IDE-to-compiler commands) is there for whoever writes a publisher tool. It is reverse-engineered from - BETA 983 and keeps no copy of the IDE files it came from. Check it against the - current IDE before relying on anything but those two endpoints. + the IDE's own files, of which it keeps no copy, and describes BETA 1005. Check it against + the current IDE before relying on anything but those two endpoints. diff --git a/WIP.Screenshots.md b/WIP.Screenshots.md index 5dd1c5079..2c568766e 100644 --- a/WIP.Screenshots.md +++ b/WIP.Screenshots.md @@ -41,7 +41,7 @@ Ten images under `docs/`, each for a stated reason: ## The IDE the tool drives -Measured on BETA 997: +Measured: - **Fixed device scale.** The IDE page otherwise takes the host's scaling (1.5 on the dev box: `body.scale150`, 22.67 px menu rows). `--force-device-scale-factor=1` in the WebView2 browser @@ -186,8 +186,9 @@ Exit codes: 0 every picture written or unchanged, 1 a picture failed, 2 the tool Every add-in a setup loads has its `SaveSetting` key snapshotted, emptied and restored (`tbDocsHelp`, `GlobalSearchAddIn`). - **Jobs**: `--jobs N` (default 6) runs setups at once, each IDE on its own claimed ports and - private desktop, and splits the big setups into parts, longest first; a full run is about - 200 s in both themes (the jobs add up to about 1,250 s per theme, so six IDEs cannot do much better). + private desktop, and splits the big setups into parts, longest first; a full run with `--svg` is + about 17 minutes in both themes on BETA 1005: the jobs add up to about 5,900 s, and the longest + part, `forms-chapter`, takes about 450 s on its own, so six IDEs cannot do much better. `--jobs 1` runs one IDE per setup in table order. Per-run state lives on the connection (`c.shot`), never in module variables. - **Diffs**: `--diffs ` (never under `docs/`) writes, for each picture that differs from the @@ -242,7 +243,7 @@ Exit codes: 0 every picture written or unchanged, 1 a picture failed, 2 the tool `Features/Images/IDE-FeatureMap.png` (2880x1800, setup `featuremap`, fixture `test/shots/featuremap/` FeatureTour) is a project-made full-IDE feature map. Twelve labels, each -anchored to an element or code span; Problems is labelled Diagnostics, its 997 title. Sticky +anchored to an element or code span; Problems is labelled Diagnostics, the panel's title. Sticky scroll, advanced hover info, inline hints, folding always shown and the debugger's memory figures are switched on in the page only; the memory figures, which change from run to run, are fixed in the page once real ones are shown, as History's times are. @@ -577,8 +578,8 @@ Taken on BETA 1005. ## Project-setup pictures (owner) -Project Settings, the panels, Project Explorer, Sample 6, Sample 15 and Global Search. In -BETA 997 Sample 6's control images are in the CustomControls package's Miscellaneous folder, not +Project Settings, the panels, Project Explorer, Sample 6, Sample 15 and Global Search. +Sample 6's control images are in the CustomControls package's Miscellaneous folder, not the project's, and the tutorial says so. - **History's times are fixed in the page**, as the recent lists are, and its project is a @@ -613,7 +614,7 @@ the project's, and the tutorial says so. package. `MyOwnIcon.ico` is the template's icon copied at run time. 8611d12a's panels are put in place by `restorePanelLayout` in the page and the default layout put back after; the crop stops at History's title bar (its entries carry the real time) and left of the IDE's title. - In 997 PROPERTIES is grouped by category only (Anchors in LAYOUT, WebView2's own properties in + PROPERTIES is grouped by category only (Anchors in LAYOUT, WebView2's own properties in GENERAL), and **a property's description is never shown at the panel's foot**: it goes to the designer's own `.proprtiesBoxFooter` inside the code panel, not the tool window -- a possible IDE defect, not reproduced or queued. The WebView2 tutorial points to the class reference diff --git a/WIP.WinNativeCommonCtls.md b/WIP.WinNativeCommonCtls.md index e75cd4d3d..5d241cd57 100644 --- a/WIP.WinNativeCommonCtls.md +++ b/WIP.WinNativeCommonCtls.md @@ -53,7 +53,7 @@ Points to put on each control's page that are *not* obvious from a flat property - **DTPicker** — the only control where most behaviour is in the calendar drop-down, not the inline display. The `Calendar*` colour properties (`CalendarBackColor`, `CalendarForeColor`, `CalendarTitleBackColor`, `CalendarTitleForeColor`, `CalendarTrailingForeColor`) act on the dropped-down month grid via `DTM_SETMCCOLOR`. `Format` (`DTPickerFormatConstants`) chooses between long-date / short-date / time / custom; when set to `dtpCustom`, the picker pulls `CustomFormat` (a `GetDateFormat`-style picture string). The control exposes `Year` / `Month` / `Week` / `Day` / `Hour` / `Minute` / `Second` accessors that decompose the current `Value`. `Value` is `Variant` — it can be `Null` (no date selected) when `CheckBox = True` and the user unchecks the box. Events `Format`, `FormatSize`, `CallbackKeyDown` fire when `Format = dtpCustom` and the format string contains a callback token. - **ImageList** — purely off-screen; `Visible` does nothing user-meaningful (it's a "store of pictures" control). The `ImageWidth` / `ImageHeight` properties are read/write **only while empty** — once any image is added, the setter raises run-time error 35611 (*"Property is read-only if image list contains images"*). `ColorDepth` is fixed at construction time. `MaskColor` + `UseMaskColor = True` makes the masked pixels transparent when rendered into a control that consumes the image list. `Overlay(Key1, Key2)` composes two list-images into a single `StdPicture`. Bound-count tracking: an `ImageList` cannot be modified (clear / remove) while any control has it bound as `Icons` / `SmallIcons` / `ColumnHeaderIcons` / `ImageList`, throwing error 35617. -- **ListView** — the largest of the eight. `View` switches the visual mode (`lvwIcon` / `lvwSmallIcon` / `lvwList` / `lvwReport`); `Arrange` (`lvwNone` / `lvwAutoLeft` / `lvwAutoTop`) auto-flows the icon mode; `Report` mode is the only one that shows the `ColumnHeaders`. `LabelEdit` defaults to `lvwAutomatic` — F2 / click-and-wait edits a label in place; `lvwManual` requires `StartLabelEdit()` and `lvwDisabled` blocks editing. `TextBackground` (`lvwTransparent` / `lvwOpaque`) acts on the *item* text rendering, not the control's `BackColor`. `MultiSelect = True` enables Ctrl+click / Shift+click range selection. `CheckBoxes = True` adds a leading checkbox per row and fires `ItemCheck`. `AllowColumnReorder` only matters in Report view. `BorderStyle` is `TreeBorderStyleConstants` (`ccNone` / `ccFixedSingle`). The control surfaces `hWnd` and `hWndHeader` (the embedded `SysHeader32` window) separately. `Scroll` is `[Unimplemented]` per the source. `GetFirstVisible() As ListItem`, `SelectedItem` / `SelectedItemIndex` — the latter is read-only (assign through `ListItem.Selected = True` instead). +- **ListView** — the largest of the eight. `View` switches the visual mode (`lvwIcon` / `lvwSmallIcon` / `lvwList` / `lvwReport`); `Arrange` (`lvwNone` / `lvwAutoLeft` / `lvwAutoTop`) auto-flows the icon mode; `Report` mode is the only one that shows the `ColumnHeaders`. `LabelEdit` defaults to `lvwAutomatic` — F2 / click-and-wait edits a label in place; `lvwManual` requires `StartLabelEdit()` and `lvwDisabled` blocks editing. `TextBackground` (`lvwTransparent` / `lvwOpaque`) acts on the *item* text rendering: `lvwOpaque` draws item text on the control's `BackColor` (`LVM_SETTEXTBKCOLOR`), `lvwTransparent` sets it to `CLR_NONE`. Since BETA 1005 `BackColor` and `TextBackground` both go through `ColorsChanged`, and every colour property of `ListView`, `ListItem`, `ProgressBar` and `ImageList` validates its value with `VB.CommonValidateColorOrRevert`: a value `OleTranslateColor` refuses (`-1`) raises 380 and keeps the old colour, so `ListItem.BackColor = -1` (its default, `CLR_NONE`) cannot be assigned back after a colour. `MultiSelect = True` enables Ctrl+click / Shift+click range selection. `CheckBoxes = True` adds a leading checkbox per row and fires `ItemCheck`. `AllowColumnReorder` only matters in Report view. `BorderStyle` is `TreeBorderStyleConstants` (`ccNone` / `ccFixedSingle`). The control surfaces `hWnd` and `hWndHeader` (the embedded `SysHeader32` window) separately. `Scroll` is `[Unimplemented]` per the source. `GetFirstVisible() As ListItem`, `SelectedItem` / `SelectedItemIndex` — the latter is read-only (assign through `ListItem.Selected = True` instead). - **MonthView** — `MonthColumns` / `MonthRows` lay out a grid of side-by-side month panels (`ResizeToFit` auto-sizes the control to fit them). `Day` / `Month` / `Week` / `Year` are the same decomposition pattern as DTPicker. `MaxSelCount` is the upper bound of a multi-day selection (default 7, max ≈ 366 per the Win32 control); `SelStart` and `SelEnd` are the inclusive range. `MinDate` / `MaxDate` bound the navigable range. `Value` is the *current selection's start date* (same as `SelStart` when `MultiSelect = False`). The control fires both `Click` (any click) and `DateClick` (only when a date cell is hit, with the date passed as a parameter); same split for `DblClick` / `DateDblClick`. `GetDayBold` is an event-driven callback — the control fires it for each visible month asking for a `State()` array of which days to render bold; this is the mechanism for highlighting holidays, schedule entries, etc. `DayBold` is an alternative per-date setter. `GetMonthRange(IncludeTrailing, StartDate, EndDate)` returns the visible date span. - **ProgressBar** — three orthogonal axes. `Min` / `Max` / `Value` are the standard range. `Step` + `StepIt()` advances the bar by `Step` units (typical loop pattern: `Min = 0`, `Max = N`, then `StepIt()` per iteration). `Scrolling = PrbScrollingStandard` (default) animates the bar in segments; `PrbScrollingSmooth` is the continuous block; `PrbScrollingMarquee` is the indeterminate animation (drive with `MarqueeAnimation = True` + `MarqueeSpeed`). `State` (`PrbStateNormal` / `Error` / `Paused`) tints the bar red / yellow per the OS theme. `Orientation` is `PrbOrientation` (`Horizontal` / `Vertical`). The control has `Click` / `DblClick` / `Mouse*` events but **no** `Change` despite the declaration — verify with the source if surfaced (`Change` is declared in the events region but not fired by any Win32 progress-bar notification). - **Slider** — `Min` / `Max` / `Value` like a scrollbar; `SmallChange` is the arrow-key step, `LargeChange` is the PgUp / PgDn step. `SelStart` + `SelLength` create a highlighted selection range (visible when `SelectRange = True`). `TickFrequency` controls how often tick marks appear; `TickStyle` (`sldBottomRight` / `sldTopLeft` / `sldBoth` / `sldNoTicks`) chooses which side(s) of the channel they render on. `TextPosition` (`sldAboveLeft` / `sldBelowRight`) is for the optional tip text. `HideThumb = True` removes the draggable indicator. `ShowTip = True` enables the floating tooltip showing the current value during drag. `Orientation` is `OrientationConstants` (the shared horizontal / vertical enum used also by `UpDown`). diff --git a/WIP.md b/WIP.md index 89d4706c3..8614cc609 100644 --- a/WIP.md +++ b/WIP.md @@ -35,7 +35,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages' console claims follow the source, because the samples harness cannot capture a console. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-tests/xCalendar/probe/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-tests/TBMANLIB_Dialog/probe/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. TBMANLIB_Dialog 1.1.0.0 has a page of its own for each class except cDialog, which keeps a page for each member, so `analyze` in audit mode lists the members of those one-page classes as undocumented; its `exclude_from_docs` names its test module, `TestModule`, and the seven COM interface declarations that cDialogEx calls inside (`IOleWindow`, `IModalWindow`, `IShellItem`, `IShellItemArray`, `IFileDialog`, `IFileOpenDialog`, `IFileSaveDialog`), which its landing page describes in a paragraph. cDialogEx 1.1.0.0 returns the name of the chosen file, not its path, ignores `InitialDir` and ignores a `Filter` that has no closing pipe, each documented as a WARNING. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. tbRegExp 1.8.0.0 gives up a search that uses up its step budget (5,000 steps for each character of the string, at least 1,000,000 and at most 50,000,000, for the search of one match; fixed inside the package) and reports it in the read-only `RegExp.SearchAborted`, documented on its own page and in a section of the landing page; `a*` and `^.*$` match 1,000,000 characters whole in about half a second. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner): ArrayListLib and WinReg do not compile on BETA 1005 (each documented from its source and a copy of it that builds, its samples compile-only; in a copy of ArrayListLib 1.6.151.1 with the arguments of its three `VSwap` calls passed `ByVal` and `LSetByVal` taking a `LongPtr`, a For Each over a list with no items fails, ToString of such a list never returns, Reverse keeps the middle pair of an even run in place and a second GetEnumerator over a list ignores its arguments; in a copy of WinReg's source with its four failing calls passed `ByVal`, ReadString, GetRegistryValueType and the first ConvertValueToString give wrong results), xCalendar has a grid that keeps the old month's dates when Value is set to another month, and text colour properties that have no effect, BigNumberLib 1.0.2.0 compiles, but loses the minus sign after `IsNegative = True` and in a negative operand of the greatest common divisor and the least common multiple, makes a zero from `AssignFromLong` negative, and does not return from the modular inverse of zero (all four confirmed by a second agent), TBMANLIB 1.0.0.29 does not compile in a 64-bit build (TB5001 in cSubClass, where the window procedure is passed as a Long) and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a copy of it, the same package at 1.0.0.1, whose types the compiler treats as different; checked in a project made by the IDE's own import, in either order), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary and misplaces List items, TBMANLIB_Dialog 1.1.0.0 has classes that fail at their main task (cDialogFindReplace reports nothing, cDialogPageSetup ignores paper and orientation, cDialogEx returns names without their folder, cDialogPassword shows the password in its confirmation boxes; every defect confirmed by a second agent, owner), TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text (and its XPath engine reads the step `..` and `and` with `or` wrongly). TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph, and the five types of its XPath engine (`XPathTokenType`, `XPathAxisType`, `XPathOperator`, `XPathStep`, `XPathPredicate`), which no public member takes or returns and which the mXPath page mentions in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages' console claims follow the source, because the samples harness cannot capture a console. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-tests/xCalendar/probe/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-tests/TBMANLIB_Dialog/probe/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. TBMANLIB_Dialog 1.1.0.0 has a page of its own for each class except cDialog, which keeps a page for each member, so `analyze` in audit mode lists the members of those one-page classes as undocumented; its `exclude_from_docs` names its test module, `TestModule`, and the seven COM interface declarations that cDialogEx calls inside (`IOleWindow`, `IModalWindow`, `IShellItem`, `IShellItemArray`, `IFileDialog`, `IFileOpenDialog`, `IFileSaveDialog`), which its landing page describes in a paragraph. cDialogEx 1.1.0.0 returns the name of the chosen file, not its path, ignores `InitialDir` and ignores a `Filter` that has no closing pipe, each documented as a WARNING. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. tbRegExp 1.9.0.0 raises `vbObjectError + 3016` from a search that uses up its step budget and returns nothing (1.8.0.0's `SearchAborted` is gone); the budget is 10 steps for each character squared, at least 1,000,000 and at most 100,000,000, for the search of one match, and `RegExp.SearchStepLimit` replaces it with a fixed number, documented on its own page and in a section of the landing page. On the dev box (BETA 1005, win32) `\d+x` costs between 2.0 and 2.2 × n² steps, so it finishes on 7,000 digits (15 s) and raises on 10,000 (16 s); `(a+)+b` raises in 0.2 s on 30 or 300 `a` but takes 16 s on 3,000; `a*` matches 1,000,000 characters whole in about half a second. Its pattern syntax has a page of its own, `PatternSyntax.md`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner): ArrayListLib and WinReg do not compile on BETA 1005 (each documented from its source and a copy of it that builds, its samples compile-only; in a copy of ArrayListLib 1.6.151.1 with the arguments of its three `VSwap` calls passed `ByVal` and `LSetByVal` taking a `LongPtr`, a For Each over a list with no items fails, ToString of such a list never returns, Reverse keeps the middle pair of an even run in place and a second GetEnumerator over a list ignores its arguments; in a copy of WinReg's source with its four failing calls passed `ByVal`, ReadString, GetRegistryValueType and the first ConvertValueToString give wrong results), xCalendar has a grid that keeps the old month's dates when Value is set to another month, and text colour properties that have no effect, BigNumberLib 1.0.2.0 compiles, but loses the minus sign after `IsNegative = True` and in a negative operand of the greatest common divisor and the least common multiple, makes a zero from `AssignFromLong` negative, and does not return from the modular inverse of zero (all four confirmed by a second agent), TBMANLIB 1.0.0.29 does not compile in a 64-bit build (TB5001 in cSubClass, where the window procedure is passed as a Long) and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a copy of it, the same package at 1.0.0.1, whose types the compiler treats as different; checked in a project made by the IDE's own import, in either order), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary and misplaces List items, TBMANLIB_Dialog 1.1.0.0 has classes that fail at their main task (cDialogFindReplace reports nothing, cDialogPageSetup ignores paper and orientation, cDialogEx returns names without their folder, cDialogPassword shows the password in its confirmation boxes; every defect confirmed by a second agent, owner), TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text (and its XPath engine reads the step `..` and `and` with `or` wrongly). TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph, and the five types of its XPath engine (`XPathTokenType`, `XPathAxisType`, `XPathOperator`, `XPathStep`, `XPathPredicate`), which no public member takes or returns and which the mXPath page mentions in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. @@ -83,7 +83,7 @@ The rest of this file is the maintenance guide for updating existing pages or ad - `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. **Every NOTE and WARNING of a section is backed by test cases** in the package's test project, `test/package-tests//` (owner; [its README](test/package-tests/README.md)), and names them in a `` marker on the line above it, which `check_package_tests.mjs` in `test.bat` enforces. **A NOTE or WARNING is only for a real difference or limit** (owner): a statement that describes how the package works stays prose, tied to its cases by a region, the marker on a line of its own above it and `` after it (owner). A difference from the object the package replaces that gives a different result silently (tbRegExp's `\1(a)`, `{,m}`, `$~` against VBScript) is a NOTE, not a WARNING (owner). A case checks what is correct, not what the package does (owner): a defect is a failing case, recorded in the project's `expect.json`, so the project tells the package's author what to fix. A section whose project is not written yet is in that gate's `PENDING` set. `package-tests.bat` runs the cases; a case it reports *fixed* means the callout goes. **The landing page ends, after See Also, with `## Test cases`**: one or two sentences linking to `-tests.twinproj` (owner), which the build publishes beside the section without the package's code in it (owner): it references the package as a linked package, which the reader puts in `%APPDATA%\twinBASIC\packages` ([WIP.PackageTests.md](WIP.PackageTests.md)). Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner); a minor defect that the section documents does not make it Experimental (owner: VBComDlg, whose Replace All raises no event, stays Contributed; owner: nor does a fixed limit that the section states at the top of its landing page). **A package moves from Contributed to Experimental for its defects only after a separate agent has reproduced each defect independently** and ruled out misuse, a wrong expectation, a twinBASIC defect and the harness (owner): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. - `docs/Reference/Statements.md` — alphabetical index of language statements. - `docs/Reference/Procedures and Functions.md` — alphabetical index of procedures/functions. -- `docs/LLVM/` — the LLVM section: compiling with the LLVM back end. A top-level section between Features and Reference Section in the nav, at `nav_order: 6` (Features is 5). `index.md` is the landing page and `Getting-Started.md` the only page so far, with its screenshots under `Images/`. Everything it describes arrived in **BETA 984**. Its language claims are measured on BETA 995 with `tbrun --llvm` and `--exe`: the comma, space and comma-space spellings of `[CompilerOptions]` all turn LLVM and `+optimize` on, `[CompilerOptions("")]` turns it off under project-wide LLVM, the long CPU-flag sample runs, and an error is lost between procedures when either the callee or the caller is LLVM-compiled. Its samples are marked `check_build`, which compiles them; `examples.bat --llvm` also builds them with LLVM. +- `docs/LLVM/` — the LLVM section: compiling with the LLVM back end. A top-level section between Features and Reference Section in the nav, at `nav_order: 6` (Features is 5). `index.md` is the landing page and `Getting-Started.md` the only page so far, with its screenshots under `Images/`. Everything it describes arrived in **BETA 984**. Its language claims are checked on BETA 1005 with `tbrun --llvm` and `--exe`: the comma, space and comma-space spellings of `[CompilerOptions]` all turn LLVM on (`+optimize` alone does not, and an attribute replaces the project's options, so `[CompilerOptions("+optimize")]` is non-LLVM under project-wide LLVM), `[CompilerOptions("")]` turns it off under project-wide LLVM, the long CPU-flag sample runs, an error is lost between procedures when either the callee or the caller is LLVM-compiled, `Err.Raise` is unreadable in an LLVM handler (`-353703423`), a `Double` `*`, `+`, `-` or `^` overflow raises no error (`^` gives 0, the others infinity; `FloatingPointErrorChecks(True)` changes nothing), the conversions round half away from zero, and `Debug.Assert` is skipped and its condition not evaluated. Also on 1005: with LLVM on under Compiler Options (DEBUG) for the whole project, an IDE run of a `[CompilerOptions("")]` procedure that calls an LLVM-compiled one ends in an access violation at the call (a built exe is fine; the page's WARNING). Its samples are marked `check_build`, which compiles them; `examples.bat --llvm` also builds them with LLVM. **A new top-level section needs four things besides its folder**, and nothing checks the first and the third: a `nav_order` between its neighbours; an entry in `docs/_book.yml` for every page, in a part or in `left_out:` with a reason, which the build warns about under its `pdf:` summary when one is missing; a line in *Where content lives* in `docs/Documentation/Authoring.md`; and the page-count rise that `build.bat` writes to `builder/page-baseline.json`, committed with the pages. The Challenges and Videos sections are in `left_out:`, and so are the IDE pages that are still screenshots and labels; the IDE part names its pages one by one, so a new IDE page warns until it goes into the part or into `left_out:`. A link from the book to a left-out page opens the website, and the pass over `book.html` lists it as `OUT OF BOOK`. A section index lists its topics by hand and sets `has_toc: false`, or the template appends a second, automatic list of its children. - Footer rendering — [builder/template.mjs](builder/template.mjs)'s `renderFooterCustom()` renders the copyright line and, when `vba_attribution: true` is set in a page's frontmatter, an additional CC-BY-4.0 attribution line beneath it. @@ -127,11 +127,11 @@ node scripts/tbrun.mjs # what does it print - **Pack and unpack projects with `impexp`, never with the compiler executable's `import` or `export` verbs.** The tooling does both in process, through `packTree` and `unpackProject` in `scripts/lib/tb-project.mjs`; by hand it is `node scripts/impexp.mjs`. The compiler's `import` refuses a project that embeds a package (exit 999, twinbasic/twinbasic#841), and both verbs exit 0 after the failures they report. The reasons, and the path and stdin rules for anything that does run the executable (`bug_repro`'s `cli` mode), are in [WIP.Harness.md](WIP.Harness.md#getting-at-the-twin-sources). - **`tbbuild` exit codes:** 0 clean, 1 the project has errors, 2 the harness failed or the project file cannot be read (empty, cut short, not a project: it is read before an IDE starts), 3 the compile never settled, 4 the project crashes the compiler, 5 the build failed after a clean compile. `--json` returns one object, `--keep` leaves the IDE running. **`--build` and `--llvm` (which implies it) build the project after a clean compile**, because LLVM code generation runs in a build and a compile never asks for it. They first stage a copy with an explicit build path (`%TEMP%\tbbuild\\`), so the given `.twinproj` is untouched. A plain `--build` is the control for an `--llvm` run. `--llvm` refuses a Community or Personal licence. - **It runs the IDE on a private Windows desktop**, so it cannot seize focus. Set `TBBUILD_SHOW=1` while working interactively and leave it unset for unattended runs: a wedged IDE nobody can see is expensive to diagnose. -- **One project per IDE**, 6--8 seconds each and flat in project size. Reusing a live IDE for a second project wedges it, so the cold start is the unit of work, not overhead to optimise away. Run concurrently to go faster: distinct `--port` values give distinct DevTools ports, user-data folders, temp folders (`%TEMP%\tbbuild-tmp-`; IDEs building in one temp folder fail now and then to write the type library) and desktops. `shutdownIde` removes the temp folder and the user-data folder (`%TEMP%\tbbuild-wv2-`, 28 MB) once the IDE has ended, and `launchIde` empties both again at the next launch on the port, for what a killed run left; a kept IDE's stay until the next run. +- **One project per IDE**, 6--8 seconds each and flat in project size. Reusing a live IDE for a second project wedges it, so the cold start is the unit of work, not overhead to optimise away. Run concurrently to go faster: distinct `--port` values give distinct DevTools ports, user-data folders, temp folders (`%TEMP%\tbbuild-tmp-`) and desktops. `shutdownIde` removes the temp folder and the user-data folder (`%TEMP%\tbbuild-wv2-`, 28 MB) once the IDE has ended, and `launchIde` empties both again at the next launch on the port, for what a killed run left; a kept IDE's stay until the next run. - **Keep a probe that might crash the compiler in a project of its own.** twinBASIC runs the compiler in the same process as user code, so one bad probe can take the run down and cost the other probes their answer. -- **`tbrun` takes an exported tree, not a `.twinproj`**, because it has to pin `project.buildPath` in its own staged copy. A project still on the default template opens a native Save dialog that is invisible on the private desktop: the build never happens, while every health check says the IDE is fine. The probe is a module with a `[RunAfterBuild]` Sub, and must start with `Debug.Cls`. Its exit codes: 0 the probe ran and its output was captured, 1 the project has compile errors, 2 the harness failed or the build did after a clean compile, or, on a build before 1005, the probe's module holds a procedure named like the module, which stops the `[RunAfterBuild]` Sub from running there (`--allow-name-clash` runs it anyway), 3 no output, 4 the compiler crashed, as `tbbuild` reports it, 5 the probe ended before it returned (`End`, or an error raised with no handler in LLVM-compiled code, which ends the run silently), 6 with `--exe`, the exe exited with a code other than 0, the event log records that it faulted, it opened a box (an unhandled error opens one, and `tbrun` closes it), or it was still running at `--timeout`, 7 with `--tests`, a case failed. +- **`tbrun` takes an exported tree, not a `.twinproj`**, because it has to pin `project.buildPath` in its own staged copy. A project still on the default template opens a native Save dialog that is invisible on the private desktop: the build never happens, while every health check says the IDE is fine. The probe is a module with a `[RunAfterBuild]` Sub, and must start with `Debug.Cls`. Its exit codes: 0 the probe ran and its output was captured, 1 the project has compile errors, 2 the harness failed or the build did after a clean compile, 3 no output, 4 the compiler crashed, as `tbbuild` reports it, 5 the probe ended before it returned (`End`, or an error raised with no handler in LLVM-compiled code, which ends the run silently), 6 with `--exe`, the exe exited with a code other than 0, the event log records that it faulted, it opened a box (an unhandled error opens one, and `tbrun` closes it), or it was still running at `--timeout`, 7 with `--tests`, a case failed. - **A project's own unit tests: `tbrun --tests`.** It builds nothing: it runs each `[TestCase]` Sub of each `[TestFixture]` Module in the compiler's test mode, the debugger's `evaluate` request with `isTest`, which the IDE itself never sends (BETA 1005 has no test runner a person can use), and prints `PASS` or `FAIL` for each. A failed assertion, an unhandled error and an access violation each end only their case. A defect that is a diagnostic is a compile case instead, a line ending `' CASE : `. A follow-up issue's regression tests are written this way: [WIP.Harness.md](WIP.Harness.md#running-a-projects-test-cases). -- **Measuring LLVM: `tbrun --llvm`** (or `--compiler-options ""`) compiles the whole probe with LLVM, by setting `compiler.debugOptions` --- what a `[RunAfterBuild]` run is compiled with; `compiler.buildOptions` alone does not reach it (BETA 995) --- and `compiler.buildOptions`, for the exe. It refuses a Community or Personal licence. `--exe` also runs the built exe on a private desktop; the exe runs `Sub Main` and prints with `TbRun.Out`, a module `tbrun` adds, because `Debug.Print` writes nothing in an exe. +- **Measuring LLVM: `tbrun --llvm`** (or `--compiler-options ""`) compiles the whole probe with LLVM, by setting `compiler.debugOptions` --- what a `[RunAfterBuild]` run is compiled with; `compiler.buildOptions` alone does not reach it (BETA 1005) --- and `compiler.buildOptions`, for the exe. It refuses a Community or Personal licence. `--exe` also runs the built exe on a private desktop; the exe runs `Sub Main` and prints with `TbRun.Out`, a module `tbrun` adds, because `Debug.Print` writes nothing in an exe. - **A census is evidence, not applicability.** The corpus not using an attribute somewhere does not mean the compiler refuses it there, and the reverse also holds. Only a probe settles that. - **The sweep is the probe for a whole attribute.** Before writing or changing an attribute's `Applicable to:` line, run `sweep_attributes.mjs --names ` (a minute or a few; the once-per-project ones, `RunAfterBuild` and `RunBeforeStartupObject`, take several); it tries every declaration site, not only the ones already claimed. **Always pass `--out` and `--dump-results`**: a run piped through `tail` keeps one line of a report that takes ten minutes. A clean build there means the compiler accepts the attribute, not that it does anything, and an Enum member cannot be tested at all (see [WIP.Harness.md](WIP.Harness.md#sweeping-every-attribute-at-every-site)). - **End an IDE by its pid, never by image name.** `taskkill /IM twinBASIC.exe` ends every other run's IDE, another session's included, and the user's own. `tbbuild --keep` prints the pid for this reason. @@ -393,7 +393,7 @@ must never do: [WIP.Typography.md](WIP.Typography.md). ### Tooling is JavaScript Everything under `scripts/`, `builder/`, `lib/`, `book/`, `eval/`, `wisdom/` and `indexer/` is -Node.js, and a new tool joins them there. Four files and one folder are not, each +Node.js, and a new tool joins them there. Four files and two folders are not, each for a stated reason rather than by oversight: `scripts/impexp.py` is a published download offered to readers rather than tooling, `scripts/build_fonts.py` stays Python because the JavaScript HarfBuzz build produces wrong CFF2 metrics @@ -407,6 +407,15 @@ twinBASIC developers run it in their own build, which has twinBASIC and need not Node. After a change to its `src/`, pack `imagestrip.twinproj` again with `impexp`, run its own `[TestCase]`s with `tbrun --tests`, and run the half of `test/compact-image.test.mjs` that tests it with `IMAGESTRIP_EXE` set to its exe: no gate can build it, so nothing else will. +`scripts/impexp/` is a twinBASIC program too, the third edition of the impexp tool, because +it is a published download (`impexp.twinproj`, which the reader opens in the IDE and builds) +for readers who have twinBASIC and neither Node nor Python. It is laid out as imagestrip +is. After a change to its `src/`, pack `impexp.twinproj` again with `impexp` +(`node scripts/impexp.mjs import scripts/impexp/impexp.twinproj scripts/impexp/src --overwrite`) +and run `node scripts/check_impexp_parity.mjs` with `IMPEXP_EXE` set to its exe, whose +`--self-test` and command sequence are its tests: no gate can build it, so nothing else will. +**A change to what impexp does, or to its self-test, is made in all three editions** in one +commit; CI compares only the Node and Python ones. The full accounting, and what the two ports gained, is in [WIP.Build.md](WIP.Build.md). ### The package indexer @@ -485,7 +494,7 @@ No build gate evaluates a `tb` fence: `check_code_regions.mjs` only protects its the compiler. A sample opts in by carrying `check_build` in its fence info string. The tool works out what to generate around it, packs many samples into one project, builds them through `tbbuild` on concurrent lanes, and reports each diagnostic against the line in the -page it came from. **1,370 samples are marked, and the run takes about 110 seconds.** +page it came from. **2,297 samples are marked, and the run takes about 220 seconds.** It is **never** wired into `build.bat`, `check.bat`, `test.bat` or CI: it needs a twinBASIC install, which `npm install` is not, and Windows with a private desktop and a @@ -526,12 +535,12 @@ Why the report separates the wedged task from the merely blocked ones, and why - `test.bat` — the tests the *toolchain* has to pass: the publish-allowlist self-test (`scripts/check_publish_policy.mjs`), the gate-list check (`scripts/check_gate_lists.mjs`), the CI-workflow roster check (`scripts/check_ci_workflows.mjs`), the lint gate (`scripts/check_lint.mjs`), the site-search unit tests (`node --test test/search.test.mjs`), the markdown-plugin unit tests (`node --test test/render.test.mjs`), the date-formatter unit tests (`node --test test/strftime.test.mjs`), the bug-reproducer picture tests (`node --test test/png.test.mjs`), the embedded-image tests (`node --test test/compact-image.test.mjs`), the SVG screenshots' one-line test (`node --test test/svgshot.test.mjs`), `check_examples.mjs`'s probes (`node --test test/example-batches.test.mjs`), the port-claim unit tests (`node --test test/ports.test.mjs`), the add-in project-file tests (`node --test test/addin-project.test.mjs`), the package-indexer tests (`node --test test/indexer.test.mjs`), the regex-safety gate (`scripts/check_regex_safety.mjs`), the code-region gate (`scripts/check_code_regions.mjs`), the page-count drift-guard probes (`scripts/check_page_baseline.mjs`), the book-coverage probes (`scripts/check_book_coverage.mjs`), the package-test markers and projects (`scripts/check_package_tests.mjs`), the symbol-index probes (`scripts/check_symbol_index.mjs`), the twinBASIC-scanner probes (`scripts/check_twin_parsers.mjs`), the attribute-sweep probes (`scripts/check_attribute_sweep.mjs`), the command-line probes and cases (`scripts/check_cli.mjs`), the pdf-lib shim comparison (`scripts/check_pdf_shims_equiv.mjs`), the impexp parity check (`scripts/check_impexp_parity.mjs`), and the axe source-patch verification (`scripts/check_axe_patch_equiv.mjs`). ~23 s, of which the regex-safety gate is ~10 s and the impexp check ~4 s. See [What belongs in test.bat rather than check.bat](WIP.Build.md#what-belongs-in-testbat-rather-than-checkbat). - `book.bat` — renders the PDF from `docs\_site-pdf\book.html` via `node book\render-book.mjs` into `docs\_pdf\twinBASIC Book.pdf`. Run `build.bat` first to populate `_site-pdf/`; `book.bat` refuses a tree older than its sources rather than rendering the previous book (see [The book refuses a stale source tree](WIP.Build.md#the-book-refuses-a-stale-source-tree)). -- `examples.bat` — compiles the documentation's own twinBASIC code samples, every `tb` fence marked `check_build`, and reports the ones the compiler refuses against the line in the page they came from; a statement sample also marked `check_run` is built and run, and what it prints is checked against the page. Needs a twinBASIC install and Windows, so it is outside every gate and outside CI; ~110 s over the 1,370 samples marked (88 of them `check_run`). `--build` also builds each project that compiles clean, and `--llvm` builds it with LLVM (see [WIP.ExamplesBuild.md](WIP.ExamplesBuild.md)). Two modes need no compiler at all: `--census` classifies every fence and says how many classifiable ones are still unmarked, and `--report ` groups a saved `--propose --json` survey by diagnostic, section and unresolved name. `--propose` itself does compile. See [Compiling the reference's own code samples](#compiling-the-references-own-code-samples) and [WIP.ExamplesBuild.md](WIP.ExamplesBuild.md). +- `examples.bat` — compiles the documentation's own twinBASIC code samples, every `tb` fence marked `check_build`, and reports the ones the compiler refuses against the line in the page they came from; a statement sample also marked `check_run` is built and run, and what it prints is checked against the page. Needs a twinBASIC install and Windows, so it is outside every gate and outside CI; ~220 s over the 2,297 samples marked (776 of them `check_run`). `--build` also builds each project that compiles clean, and `--llvm` builds it with LLVM (see [WIP.ExamplesBuild.md](WIP.ExamplesBuild.md)). Two modes need no compiler at all: `--census` classifies every fence and says how many classifiable ones are still unmarked, and `--report ` groups a saved `--propose --json` survey by diagnostic, section and unresolved name. `--propose` itself does compile. See [Compiling the reference's own code samples](#compiling-the-references-own-code-samples) and [WIP.ExamplesBuild.md](WIP.ExamplesBuild.md). - `package-tests.bat` --- runs the test projects of the contributed packages named (in any case: `tbregexp`), or of every one with `--all-packages`, which is never the default (`scripts/package_tests.mjs`): each project under `test/package-tests/` is staged with its package embedded and run with `tbrun --tests` as 32-bit and 64-bit, and each case is judged against `expect.json` as *documented*, *fixed* (the callout goes) or *changed* (a claim of the page is no longer true). `--update` writes `expect.json` from the run; read every entry it writes, since each is a claim that the package is defective. A case that never returns is caught and run alone. It also rewrites the generated `RunAll.twin`. Outside every gate and CI, as `examples.bat` is. The build publishes each project, referencing the package as a linked package and carrying none of its code, as `tB/Packages/Contributed//-tests.twinproj` in the online tree (the `packageTests` task, `builder/package-tests.mjs`, `_config.yml`'s `package_tests`; the publish allowlist exempts those paths, and the offline tree's links go to the website). -- `addin-test.bat` — tests IDE add-ins by operating an IDE: every lane in `test/addin/lanes.mjs` builds the add-ins it tests into a private copy of the install, opens a project and checks what the add-in does. Outside every gate and outside CI for the same reasons as `examples.bat`; about two minutes for the seventeen lanes today (BETA 997): Samples 10 and 15, the thirteen probe lanes behind Stage 2's answers in [WIP.HelpAddin.md](WIP.HelpAddin.md), and the help add-in in `add-in/` twice, built with its committed copy of the symbol index, `add-in/Resources/SYMBOLS/symbols.json`, which a local build rewrites whenever the index changes. The `help` lane serves the built `docs/_site` on localhost to the add-in's pane; `help-offline` builds the add-in with a help archive of `docs/_site-offline` and the pane's pages come from the add-in's own server. So run `build.bat` first. Exit 0 every lane passed and the registry is as it was found, 1 a lane failed, 2 the harness failed, 3 the registry or a work folder was not put back. See [Driving the twinBASIC compiler](#driving-the-twinbasic-compiler) for its rules. +- `addin-test.bat` — tests IDE add-ins by operating an IDE: every lane in `test/addin/lanes.mjs` builds the add-ins it tests into a private copy of the install, opens a project and checks what the add-in does. Outside every gate and outside CI for the same reasons as `examples.bat`; the seventeen lanes: Samples 10 and 15, the thirteen probe lanes behind Stage 2's answers in [WIP.HelpAddin.md](WIP.HelpAddin.md), and the help add-in in `add-in/` twice, built with its committed copy of the symbol index, `add-in/Resources/SYMBOLS/symbols.json`, which a local build rewrites whenever the index changes. The `help` lane serves the built `docs/_site` on localhost to the add-in's pane; `help-offline` builds the add-in with a help archive of `docs/_site-offline` and the pane's pages come from the add-in's own server. So run `build.bat` first. Exit 0 every lane passed and the registry is as it was found, 1 a lane failed, 2 the harness failed, 3 the registry or a work folder was not put back. See [Driving the twinBASIC compiler](#driving-the-twinbasic-compiler) for its rules. - `ide-test.bat` --- the same runner for scenarios that operate the IDE itself rather than an add-in: every lane in `test/ide/lanes.mjs`, base port 9660. Same exit codes, same standing outside every gate and outside CI, same rules. - `try-help-addin.bat` --- opens one IDE on the user's desktop with the help add-in built and loaded, to try it by hand, and puts the registry back once it is closed (see [Driving the twinBASIC compiler](#driving-the-twinbasic-compiler)). Needs `build.bat` first. Exit 0 closed and put back, 1 the add-in or the project did not compile, 2 the tool could not run, 3 not put back. -- `node scripts/shoot_docs.mjs` --- writes the documentation's IDE screenshots (plan and owner's decisions: [WIP.Screenshots.md](WIP.Screenshots.md)). Each picture is a shot in a table, `out` its path under `docs/` (`--only` matches it), in a setup (the main three below; the full list is in WIP.Screenshots.md), each one IDE on a **private** desktop started only when a shot in it is selected: `help` (builds the add-in as `try-help-addin.bat` does, opens `test/addin/helpdemo`, `TB_DOCS_HELP_REAL_TITLEBAR=0`: the eight `docs/IDE/AddIns/Images/Help_.png`), `no-project` (`Lane.openNoProject` with `includeProjects`: the menus, cut out with alpha, the dialogs that need no project, and the empty panels, each floated on its own, after the dialogs) and `project` (the demo without the add-in: About, which needs the compiler's licence answer, and IDE Options, whose font lists need a project). One setup is not an IDE: `web` starts puppeteer's Chrome through `launchOnDesktop` on a private desktop of its own (never headless, never on the user's desktop; native-window occlusion and occluded-window backgrounding switched off, or a capture waits forever or comes back blank) for the two public pages the FAQ shows, taken once; it needs the network, as do `webpage` (the Webpage pane on `https://docs.twinbasic.com/`, its page captured from the pane's own DevTools target and pasted into the pane's place) and the package-server setups, which never publish. Every IDE gets `--force-device-scale-factor=1` (`Lane`'s `browserArgs`), else the page follows the display's scaling; the page is overridden to 1280x880 at 2x, and `PAGE_DEFAULTS` puts the IDE's options, panel layouts and keyboard groups to their defaults and the recent lists to the tool's own **in the page only**, its save calls replaced first so nothing is written. Each picture is a `Page.captureScreenshot` with a `clip`; a page showing it gives it `{:width height}` of half its pixel size. **Every picture is taken in two themes by one IDE**: dark as `X.png`, then, after `backToPrepared` and `tbTheme_SwitchToLightMode`, Light (not Classic) as `X.light.png` beside it, which the build pairs by name ([WIP.Build.md](WIP.Build.md#pictures-in-two-themes)); a light picture with the dark one's pixels is not kept, and one more than 32 device pixels off the dark one's size fails (a wrong state, not the theme). A label's pill follows the theme unless the shot names a `tone`. A shot's `annotate` list (arrows, rings, badges...) is drawn by `scripts/lib/shot-annotate.mjs` as one SVG layer over the page before the capture and removed after it, the clip growing to hold it. A picture is rewritten only when its bytes differ, and a second run reports every one `unchanged`; a capture is not byte-stable, so `capture` takes up to eight and keeps one equal to the file on disk, and a picture that differs from the file only by a capture's noise (16 grey levels, 0.5% of its pixels) is left as it is. `--jobs N` (default 6) runs the setups at once on their own ports and desktops, a full run in about 200 s (`--jobs 1`: one at a time); `--diffs ` writes the old picture, the new one and an amplified difference map for each that changed, named with its theme. Settle by a condition, never a fixed sleep, and a picture that shows some state sets it itself rather than relying on the shots before it. The page's animations and carets are switched off through a style sheet put into the document and every shadow root; a picture that holds DEBUG CONSOLE lines has their times (and a CodeLens run's time taken) set in the page once the real ones show. **A running program's window** (setup `programs`, fixture `test/shots/programs`) is taken **once** (`once: true`, the dark pass only) with `captureWindow`, cropped to its visible frame, at the display's DPI, shown at its size at 96 DPI. **The Windows user name must never be in a published picture**: the visible text of the page, text boxes included, is searched for it before the first capture and again when a capture is chosen, with the picture's SVG under `--svg` (a page can draw again in between: Project Settings puts a real path back over the one the shot set), and for a program's window the texts of the window and its children, and the run fails when it is there. The tool finds each name it presses F1 on by searching the demo's source, not by line. The add-in is built on a port of its own (`Lane.addAddin`'s `port`): the building IDE's WebView2 process can hold its port after the IDE ends for longer than `launchIde`'s ten seconds. **`--svg`** also draws each picture as SVG from the page as it stands at the capture (`scripts/svgshot/`: a DOM snapshot converted, its text set in per-picture subsets of the fonts the IDE drew it with, cut by `scripts/subset_font.py`, which needs Python with fontTools), compares it with the PNG, and writes `X.svg` or `X.light.svg` beside it only when no more than 0.25% of its pixels are far off; otherwise an older SVG is removed and the page shows the PNG ([WIP.Build.md](WIP.Build.md#pictures-as-svg)). With `--svg` each picture's *bundle*, what its SVG is drawn from, is saved in the gitignored `.svgshot-bundles/` (`--bundles`; never under `docs/`, a bundle holds the user name), and **after a change to the converter, `node scripts/svgshot/replay.mjs` draws every SVG again from the bundles, with no IDE**, in about 20 s for the 370 (an SVG the same as its file is not compared again, `--recheck` compares all; the fonts' cuts are kept in `.svgshot-bundles/subsets/`; one browser per process, GPU off); it lists the pictures whose bundle cannot answer what the converter now asks, with the `--only` command that retakes them ([WIP.Screenshots.md](WIP.Screenshots.md#pictures-as-svg)). `node scripts/svgshot/bench.mjs` tests the converter's replicas of what Chromium draws outside the DOM (scrollbars, drop-down lists) in Edge, with no IDE ([WIP.Screenshots.md](WIP.Screenshots.md#pictures-as-svg)). No wrapper; outside every gate and outside CI, as `try-help-addin.bat` is. Exit 0 every picture written or unchanged, 1 a picture failed, 2 the tool could not run, 3 not put back. Run `build.bat` first. +- `node scripts/shoot_docs.mjs` --- writes the documentation's IDE screenshots (plan and owner's decisions: [WIP.Screenshots.md](WIP.Screenshots.md)). Each picture is a shot in a table, `out` its path under `docs/` (`--only` matches it), in a setup (the main three below; the full list is in WIP.Screenshots.md), each one IDE on a **private** desktop started only when a shot in it is selected: `help` (builds the add-in as `try-help-addin.bat` does, opens `test/addin/helpdemo`, `TB_DOCS_HELP_REAL_TITLEBAR=0`: the eight `docs/IDE/AddIns/Images/Help_.png`), `no-project` (`Lane.openNoProject` with `includeProjects`: the menus, cut out with alpha, the dialogs that need no project, and the empty panels, each floated on its own, after the dialogs) and `project` (the demo without the add-in: About, which needs the compiler's licence answer, and IDE Options, whose font lists need a project). One setup is not an IDE: `web` starts puppeteer's Chrome through `launchOnDesktop` on a private desktop of its own (never headless, never on the user's desktop; native-window occlusion and occluded-window backgrounding switched off, or a capture waits forever or comes back blank) for the two public pages the FAQ shows, taken once; it needs the network, as do `webpage` (the Webpage pane on `https://docs.twinbasic.com/`, its page captured from the pane's own DevTools target and pasted into the pane's place) and the package-server setups, which never publish. Every IDE gets `--force-device-scale-factor=1` (`Lane`'s `browserArgs`), else the page follows the display's scaling; the page is overridden to 1280x880 at 2x, and `PAGE_DEFAULTS` puts the IDE's options, panel layouts and keyboard groups to their defaults and the recent lists to the tool's own **in the page only**, its save calls replaced first so nothing is written. Each picture is a `Page.captureScreenshot` with a `clip`; a page showing it gives it `{:width height}` of half its pixel size. **Every picture is taken in two themes by one IDE**: dark as `X.png`, then, after `backToPrepared` and `tbTheme_SwitchToLightMode`, Light (not Classic) as `X.light.png` beside it, which the build pairs by name ([WIP.Build.md](WIP.Build.md#pictures-in-two-themes)); a light picture with the dark one's pixels is not kept, and one more than 32 device pixels off the dark one's size fails (a wrong state, not the theme). A label's pill follows the theme unless the shot names a `tone`. A shot's `annotate` list (arrows, rings, badges...) is drawn by `scripts/lib/shot-annotate.mjs` as one SVG layer over the page before the capture and removed after it, the clip growing to hold it. A picture is rewritten only when its bytes differ, and a second run reports every one `unchanged`; a capture is not byte-stable, so `capture` takes up to eight and keeps one equal to the file on disk, and a picture that differs from the file only by a capture's noise (16 grey levels, 0.5% of its pixels) is left as it is. `--jobs N` (default 6) runs the setups at once on their own ports and desktops, a full run with `--svg` in about 17 minutes on BETA 1005 (`--jobs 1`: one at a time); `--diffs ` writes the old picture, the new one and an amplified difference map for each that changed, named with its theme. Settle by a condition, never a fixed sleep, and a picture that shows some state sets it itself rather than relying on the shots before it. The page's animations and carets are switched off through a style sheet put into the document and every shadow root; a picture that holds DEBUG CONSOLE lines has their times (and a CodeLens run's time taken) set in the page once the real ones show. **A running program's window** (setup `programs`, fixture `test/shots/programs`) is taken **once** (`once: true`, the dark pass only) with `captureWindow`, cropped to its visible frame, at the display's DPI, shown at its size at 96 DPI. **The Windows user name must never be in a published picture**: the visible text of the page, text boxes included, is searched for it before the first capture and again when a capture is chosen, with the picture's SVG under `--svg` (a page can draw again in between: Project Settings puts a real path back over the one the shot set), and for a program's window the texts of the window and its children, and the run fails when it is there. The tool finds each name it presses F1 on by searching the demo's source, not by line. The add-in is built on a port of its own (`Lane.addAddin`'s `port`): the building IDE's WebView2 process can hold its port after the IDE ends for longer than `launchIde`'s ten seconds. **`--svg`** also draws each picture as SVG from the page as it stands at the capture (`scripts/svgshot/`: a DOM snapshot converted, its text set in per-picture subsets of the fonts the IDE drew it with, cut by `scripts/subset_font.py`, which needs Python with fontTools), compares it with the PNG, and writes `X.svg` or `X.light.svg` beside it only when no more than 0.25% of its pixels are far off; otherwise an older SVG is removed and the page shows the PNG ([WIP.Build.md](WIP.Build.md#pictures-as-svg)). With `--svg` each picture's *bundle*, what its SVG is drawn from, is saved in the gitignored `.svgshot-bundles/` (`--bundles`; never under `docs/`, a bundle holds the user name), and **after a change to the converter, `node scripts/svgshot/replay.mjs` draws every SVG again from the bundles, with no IDE**, in about 20 s for the 370 (an SVG the same as its file is not compared again, `--recheck` compares all; the fonts' cuts are kept in `.svgshot-bundles/subsets/`; one browser per process, GPU off); it lists the pictures whose bundle cannot answer what the converter now asks, with the `--only` command that retakes them ([WIP.Screenshots.md](WIP.Screenshots.md#pictures-as-svg)). `node scripts/svgshot/bench.mjs` tests the converter's replicas of what Chromium draws outside the DOM (scrollbars, drop-down lists) in Edge, with no IDE ([WIP.Screenshots.md](WIP.Screenshots.md#pictures-as-svg)). No wrapper; outside every gate and outside CI, as `try-help-addin.bat` is. Exit 0 every picture written or unchanged, 1 a picture failed, 2 the tool could not run, 3 not put back. Run `build.bat` first. - **The help add-in's project file is written by every build, CI's included.** The `addinProject` task (`builder/addin-project.mjs`) packs `add-in/` into `tB/IDE/AddIns/downloads/tbDocsHelp.twinproj` in the **online tree only**, which the Help Add-In page offers as a download; `_config.yml`'s `addin_project` declares both ends, so a fixture config gets none. It waits for the `helpArchive` task. It packs the files `git ls-files` lists there, read from the working folder, never a `Resources/HELP/` file from the disk, with CRLF made LF outside `Resources/` (so a Windows and a Linux build write the same bytes), the `tB/symbols.json` the same build wrote in place of the committed copy, and **the zip that build's archive task wrote** as `Resources/HELP/site.zip`, passed in memory (a build that wrote none --- `--no-help-archive`, `--serve`, another `--dest`, a fixture --- packs without it, and the summary line says `without the offline archive`). The download is about 28 MB with the archive, 1 MB without. The offline tree holds no copy (the project carries that tree's archive, so a copy there would be circular), and its links to the file are rewritten to the website by the general rule in `offline-rewrite.mjs`: a URL the offline tree lacks but the online tree has becomes `site.url` + path, and is no miss (`computeWebsiteUrl`; the offline link check's `forbidExempt` excuses exactly those links, `isWebsiteOnlyLink`). The pack is `importProject` from `scripts/impexp.mjs`, the one module under `scripts/` that `builder/` may import (`biome.jsonc`); `check_tree_fresh.mjs` watches it and `add-in/` for that reason. The publish allowlist exempts the one path in the trees only (`publishPolicyFor`'s `generated`); a `.twinproj` anywhere else, or in `docs/`, is refused. `--serve` writes it into its one tree; `--dry-run` writes nothing. A failure (no git) fails the build with exit 1 and the index audit names the missing file. **Don't build the DLLs in CI from it**: that needs a twinBASIC install; the download is the project, and the reader builds it. Why each of these: [WIP.Build.md](WIP.Build.md#the-help-add-ins-project-file); `test/addin-project.test.mjs` is the gate. - **The help archive is the `helpArchive` task of the build's graph.** `builder/help-archive-step.mjs` writes `add-in/Resources/HELP/site.zip` from `docs/_site-offline` through `lib/help-archive.mjs`, once every task that writes into the offline tree has finished (`flushJoin`, `scss`, `writeOffline`; the archive task lists exactly those) and **before** the Gantt injection, so the zip holds `BuildInfo.html` without the chart and `assets/images/gantt.svg` as the 105-byte placeholder the sources hold (it is a tracked static file, so the file list already has it). It reads the file back to verify it. A mismatch fails the build (exit 1). After the Gantt injection `recheckHelpArchive` checks that the offline tree on disk lists the same files as the archive and differs from it only in `BuildInfo.html` and `gantt.svg`; a task that wrote into the offline tree late fails the build there. The help add-in embeds the zip as a resource and serves the pages from it with its own server; a build of the add-in without it uses the live site. The file is gitignored (about 26 MB), so a build of the add-in from a clean clone is the online one until `build.bat` has run. The download carries the same zip (previous bullet). **`--no-help-archive` turns the step off, and neither CI workflow may pass it** (`check_ci_workflows.mjs` refuses it, in `ALLOWED.forbiddenBuildFlags`), because CI's published download would then hold no archive. It runs only for the guarded source tree (`docs`) built into the default `docs/_site-offline` (not another `--dest`, so `compare_trees` and `check_links_diff` leave it alone), never under `--serve` or `--dry-run`, never without an offline tree, and not keyed on `$CI`. There is no command-line tool for the archive: the `help-offline` lane makes its own with `writeHelpArchive`. The zip's format is fixed by the add-in's reader, which does no inflating ([WIP.HelpAddin.md](WIP.HelpAddin.md), Stage 4, increment 5). - `node scripts/bug_repro.mjs` --- the reproducer projects under `bugs//` for the entries of [BUGS-TO-REPORT.md](BUGS-TO-REPORT.md): `new`, `pack` (impexp, then the zip, written in Node), `compile`, `build` and `run` through `tbbuild` and `tbrun`, `vb6` (builds the optional `vb6/` VB6 project beside the twinBASIC one in a temp copy, runs its exe on a private desktop, and prints its `out.txt`; a project with a form or a user control is built without Unattended Execution, which VB6 refuses for it; `pack` zips its sources into `-vb6.zip`; VB6 is started only by `scripts/lib/vb6.mjs`, never from a shell; a graphical defect's `images` key makes `run` and `vb6` keep what the `PngDump` modules of `test/repro-templates/png/` draw as `images/-tb.png` and `-vb6.png`, with a `-compare.png` of both, tested by `test/png.test.mjs`), `file` (moves a filed entry and its reproducer to `bugs/filed//`; `file --marked` does every marked entry), and `verify`, which reads each `bugs/*/repro.json` and `bugs/filed/*/repro.json` and says whether the bug still reproduces on the newest beta; a `lane` reproducer names the `ide-test` or `addin-test` lane and tests that assert its bug, which `verify` runs last through that runner, a `probe` one a script under `scripts/`, and a `test` one its own `[TestCase]` Subs and compile cases through `tbrun --tests`, judged by the `PASS` lines of what is fixed and the `FAIL` lines of the bug (`new --template tests` starts one). **No reproducer should need a person at the IDE** (owner): a bug the IDE has to be operated for gets a lane test, and `manual` is left for what cannot be automated at all. It has no wrapper. **`verify` is run by a person only**, never by a gate or CI: it needs a twinBASIC install, like `examples.bat`. Default port 9440, and `--jobs N` takes N ports from there. Its command-line cases are in `scripts/lib/cli-cases.mjs`, and need no IDE. @@ -612,7 +621,7 @@ wrapper: | `test.bat` | `test/addin-project.test.mjs` | `builder/addin-project.mjs` packs the help add-in's project file from exactly the files git tracks in `add-in/`, as the working folder holds them, never `Resources/HELP/`, with the index it is given, the same bytes from a CRLF and an LF checkout, into every tree it is given. Needs git. Run by `node --test` | | `test.bat` | `test/indexer.test.mjs` | the package indexer (`indexer/lib/`) keeps its promise that a snapshot changes only when the API does: VB6 files named by `VB_Name`, else by their file; a package's files in code-unit order with the `Packages` folder left out; `api.json` types sorted by path with `in` for nested ones, members by name, Enum values and Type fields in declaration order, a type character stripped from an unbracketed name only, the same bytes from the same files in any order; `diffApi` and `auditCoverage` on small hand-made inputs. Reads `indexer/sample.twinpack`; no network, git or install. Run by `node --test` | | `test.bat` | `check_pdf_shims_equiv` | the book's pdf-lib shims write what stock pdf-lib writes: one document written by the gate and one built with `PDFDocument.create` are each saved both ways in child processes, and each pair of files is compared object by object with streams inflated and their cross-reference entries checked; every shim must run, and the members of pdf-lib the shims patch must be those its `PATCHES` lists, each run in one document or the other unless marked there as not reached; each of them must also be in the target table its shim passes to `checkTargets`, which `book/lib/shim-targets.mjs` records for the side to ask | -| `test.bat` | `check_impexp_parity` | `impexp.mjs` and `impexp.py` pass the same built-in tests, and one sequence of commands through each gives the exit code each command is there for, the same output and the same files. Without Python it reports itself skipped and passes, but fails when `CI=true` | +| `test.bat` | `check_impexp_parity` | `impexp.mjs` and `impexp.py` pass the same built-in tests, and one sequence of commands through each gives the exit code each command is there for, the same output and the same files. Without Python it reports itself skipped and passes, but fails when `CI=true`. With `IMPEXP_EXE` naming the built exe of the twinBASIC edition (`scripts/impexp/`, Windows only), it compares that too | | `test.bat` | `check_publish_policy`, `check_gate_lists`, `check_page_baseline`, `check_book_coverage`, `check_axe_patch_equiv` | the gates on the gates | **A gate belongs in `test.bat` rather than `check.bat` if it would still mean diff --git a/WIP.tbIDE.md b/WIP.tbIDE.md index a1715c6ae..7d99fd9e5 100644 --- a/WIP.tbIDE.md +++ b/WIP.tbIDE.md @@ -27,7 +27,7 @@ End Module The returned object must implement the [`AddIn`](#public-user-facing-surface) interface (a single read-only `Name` property, declared in `Addin.twin`). Every sample uses this exact `tbCreateCompilerAddin` skeleton. Show it on the index landing as the canonical entry point. -Two facts about loading were measured on BETA 983 and 995 (P9 and P14 in [WIP.HelpAddin.md](WIP.HelpAddin.md)), and the index page states both: +Two facts about loading were measured on BETA 1005 (P9 and P14 in [WIP.HelpAddin.md](WIP.HelpAddin.md)), and the index page states both: - **The linker exports `tbCreateCompilerAddin` as `tbCreateCompilerAddin_v3`**, and under no other name. The IDE's loader accepts `tbCreateCompilerAddin`, `_v2` and `_v3`, calls each the same way, and refuses a DLL with none of them as *compiled for a newer version of the twinBASIC IDE*. The suffix is a version stamp, not a different signature. - **A compiler restart does not release the object; it kills it.** The addin lives in the compiler's process. The page ends that process with `taskkill /F` (`forceTerminate` in `main.js`) on every compiler restart (the restart button, a switch of build target, a crash). So `Class_Terminate` does not run, and a new instance is loaded from the DLL on disk. Closing the project calls `forceTerminate` as well *(read, not measured)*. Never write that the object is released "when the addin is disabled or the IDE shuts down": the Add-Ins menu's items cannot disable an add-in *(reported)*. @@ -73,7 +73,7 @@ Almost every `.twin` declares one or two `Public Interface IV1 Extends stdole **Versioning is conveyed by interface chains.** Two cases visible in the source: - `IFileV1` → `IFileV2 Extends IFileV1` (V2 adds `ReadText(ReadTextFlags)`). The `File` CoClass declares `[Default] Interface IFileV2`. Document the V2 surface as the canonical `File` page; do not split V1 vs V2. (Mention in passing that `ReadText` is V2-only and consequently won't bind against very early IDE builds — though in practice every shipping IDE is V2+.) -- `IHostV1` → `ItbHostEventsV1` → `ItbHostEventsV2 Extends V1` → `ItbHostEventsV3 Extends V2`. The `Host` CoClass declares `[Default, Source] Interface ItbHostEventsV3`. The new members on V2 / V3 (`OnChangedActiveEditor`, `OnChangedTheme`) are each tagged **`[AllowUnpopulatedVtableEntry]`**, which [Attributes](docs/Reference/Attributes.md#allowunpopulatedvtableentry) describes as marking a prototype that a class implementing the interface need not supply. Do not write that the attribute lets a newer addin "still load against an older IDE". Nothing measured it, and the loader works the other way (P14): the linker stamps every addin's entry point `_v3`, and an IDE whose loader does not know a DLL's stamp refuses it. Every install from BETA 947 on knows `_v3`, so the claim cannot be tested either way. +- `IHostV1` → `ItbHostEventsV1` → `ItbHostEventsV2 Extends V1` → `ItbHostEventsV3 Extends V2`. The `Host` CoClass declares `[Default, Source] Interface ItbHostEventsV3`. The new members on V2 / V3 (`OnChangedActiveEditor`, `OnChangedTheme`) are each tagged **`[AllowUnpopulatedVtableEntry]`**, which [Attributes](docs/Reference/Attributes.md#allowunpopulatedvtableentry) describes as marking a prototype that a class implementing the interface need not supply. Do not write that the attribute lets a newer addin "still load against an older IDE". Nothing measured it, and the loader works the other way (P14): the linker stamps every addin's entry point `_v3`, and an IDE whose loader does not know a DLL's stamp refuses it. The BETA 1005 loader knows `_v3`, so the claim cannot be tested either way. Document all `Host` events together on the `Host.md` page (the per-version split is a compatibility detail, not a user-facing concept). @@ -112,7 +112,7 @@ Three things make this surface unusual and have to be surfaced on the docs: 2. **The custom-element tags.** `HtmlElements.Add(id, tagName)` accepts standard HTML tags (`"div"`, `"input"`, `"span"`, `"h1"`, …) AND four IDE-specific widget tags: `"chartjs"` (Chart.js wrapper — surfaces a `.chart` property), `"monaco"` (the Monaco editor — surfaces a `.editor` property), `"listview"` (the IDE's listview widget — surfaces a `.listview` property with `addItem` / `removeItem` / etc.), and `"virtuallistview"` (the same with `setItemCount` + the `onAsyncGetItemHTML` event). All four are demonstrated in samples 11–14. Surface as *"the tag name is forwarded to the IDE's tool-window renderer, which understands the standard HTML tags plus the custom widget tags … see sample 11 / 12 / 13 / 14"*. 3. **`AddEventListener(DomEventName As String, CallbackFunc As LongPtr, Optional Data As Variant)`.** The callback is passed as `AddressOf SomeSub`, and `SomeSub` must have the signature `Sub(ByVal eventInfo As HtmlEventProperties)`. The `eventInfo` parameter is the IDE-marshalled equivalent of the JavaScript `Event` object — `eventInfo.key` / `eventInfo.target.value` / `eventInfo.target.id` are the usual fields, but again the property names are resolved against the *actual* event object at run time, not declared statically. Sample 13 also demonstrates **custom event names raised from inline HTML** via the IDE-side `raiseEvent("name", event, stopPropagation, …customData)` JavaScript helper; the custom-data values become `eventInfo.customData0`, `eventInfo.customData1`, … and are demonstrated in sample 15's `ClickedMatch` handler. Sample 14 demonstrates **async events** via `eventInfo.setAsyncResult("")` (the listener returns the requested HTML asynchronously back into the virtual list view's render cycle). -**`raiseEvent` is narrower than item 3 suggests** (P12 in [WIP.HelpAddin.md](WIP.HelpAddin.md), measured on BETA 983, the `TypeError` on 995 as well): it works only inside a `listview` / `virtuallistview` or an `AddMonacoWidget` widget, and from plain tool-window HTML it throws a `TypeError` in the IDE's page. P4 measured the rest of this surface: `innerHTML`'s inline handlers run as the IDE page's own script, and a property whose name starts with `on` is dropped without an error. The HtmlElement and HtmlElementProperties pages say all three; the ToolWindow page says that showing a window resets its root's `display`. +**`raiseEvent` is narrower than item 3 suggests** (P12 in [WIP.HelpAddin.md](WIP.HelpAddin.md), measured on BETA 1005): it works only inside a `listview` / `virtuallistview` or an `AddMonacoWidget` widget, and from plain tool-window HTML it throws a `TypeError` in the IDE's page. P4 measured the rest of this surface: `innerHTML`'s inline handlers run as the IDE page's own script, and a property whose name starts with `on` is dropped without an error. The HtmlElement and HtmlElementProperties pages say all three; the ToolWindow page says that showing a window resets its root's `display`. Document the four `Html*` classes as the *contract* (`Item` default member, the `Value` accessor, the `Properties` chaining) and use the samples to illustrate the dynamic-resolution mechanism. Do not try to enumerate the resolved property surface — it's open-ended. @@ -211,7 +211,7 @@ Surface as the canonical safe-cast pattern on `CodeEditor.md`. The `keyString` argument is a literal key with optional `{CTRL}` / `{SHIFT}` / `{ALT}` prefixes, e.g. `"{CTRL}{SHIFT}d"` (the source-side `[Description]`'s example). The `Callback` is `AddressOf` an addin function; the function takes no arguments and returns nothing --- a `Private Sub` with no parameters, in the add-in's class, works (measured, BETA 983 and 995). -**The source's own example does not fire.** No sample uses `KeyboardShortcuts.Add`, so the behaviour comes from P1 and P2 in [WIP.HelpAddin.md](WIP.HelpAddin.md), with the lane `test/addin/keys.test.mjs`. In BETA 983 and 995 a shortcut with `{CTRL}` or `{ALT}` never fires when pressed. The prefixes must come in the order `{ctrl}{shift}{alt}`. A shortcut fires on key-up wherever the focus is in the IDE's window, and a key that types fires each time it is typed. The published page says all of that, with an example on Shift+F12; keep it in step with the lane. +**The source's own example does not fire.** No sample uses `KeyboardShortcuts.Add`, so the behaviour comes from P1 and P2 in [WIP.HelpAddin.md](WIP.HelpAddin.md), with the lane `test/addin/keys.test.mjs`. In BETA 1005 a shortcut with `{CTRL}` or `{ALT}` never fires when pressed. The prefixes must come in the order `{ctrl}{shift}{alt}`. A shortcut fires on key-up wherever the focus is in the IDE's window, and a key that types fires each time it is typed. The published page says all of that, with an example on Shift+F12; keep it in step with the lane. **Do not describe callbacks as running "on the IDE's UI thread".** It is unmeasured and probably misleading: an add-in runs inside the compiler's process (P10), not in the IDE's page, which is a WebView2 process of its own. The KeyboardShortcuts page does not say it. **The AddinTimer page still does**, three times, with "long-running work ... will block the UI thread" --- unverified. Which thread runs an add-in's callbacks, and what a slow one holds up, is not known. Fix the AddinTimer page when something measures it. diff --git a/add-in/Resources/SYMBOLS/symbols.json b/add-in/Resources/SYMBOLS/symbols.json index 69e6f3bf1..dbb0eaf2b 100644 --- a/add-in/Resources/SYMBOLS/symbols.json +++ b/add-in/Resources/SYMBOLS/symbols.json @@ -1,6 +1,6 @@ { "format": 1, - "api": 997, + "api": 1005, "packages": {"VBA":"VBA","VBRUN":"VBRUN","VB":"VB","AppGlobalClassProject":"AppGlobalClassObject","cefPackage":"CEF","CustomControls":"CustomControls","CustomControlsPackage":"CustomControls","Assert":"Assert","WebView2Package":"WebView2","WinEventLogLib":"WinEventLogLib","WinNamedPipesLib":"WinNamedPipesLib","WinNativeCommonCtls":"WinNativeCommonCtls","WinServicesLib":"WinServicesLib","tbIDE":"tbIDE"}, "interfaces": {"VBA._Collection":"VBA.Collection","VBA._ErrObject":"VBA.ErrObject","VBA.ITbExpressionService":"VBA.TbExpressionService","VBRUN._PropertyBag":"VBRUN.PropertyBag","VB._App":"VB.App","VB._Clipboard":"VB.Clipboard","VB._Screen":"VB.Screen","VB.VBGlobal":"VB.Global","AppGlobalClassProject._App":"AppGlobalClassProject.App","CustomControls._CustomControlTimer":"CustomControls.CustomControlTimer","CustomControls._CustomControlContext":"CustomControls.CustomControlContext","CustomControls._CustomFormContext":"CustomControls.CustomFormContext","CustomControls._CustomControlsCollection":"CustomControls.CustomControlsCollection","tbIDE.IAddInV1":"tbIDE.AddIn","tbIDE.IButtonV1":"tbIDE.Button","tbIDE.ICodeEditorV1":"tbIDE.CodeEditor","tbIDE.IDebugConsoleV1":"tbIDE.DebugConsole","tbIDE.IEditorV1":"tbIDE.Editor","tbIDE.IEditorsV1":"tbIDE.Editors","tbIDE.IFileV2":"tbIDE.File","tbIDE.IFileSystemV1":"tbIDE.FileSystem","tbIDE.IFileSystemItemV1":"tbIDE.FileSystemItem","tbIDE.IFolderV1":"tbIDE.Folder","tbIDE.IHostV1":"tbIDE.Host","tbIDE.IHtmlElementV1":"tbIDE.HtmlElement","tbIDE.IHtmlElementPropertiesV1":"tbIDE.HtmlElementProperties","tbIDE.IHtmlElementPropertyV1":"tbIDE.HtmlElementProperty","tbIDE.IHtmlElementsV1":"tbIDE.HtmlElements","tbIDE.IHtmlEventPropertiesV1":"tbIDE.HtmlEventProperties","tbIDE.IHtmlEventPropertyV1":"tbIDE.HtmlEventProperty","tbIDE.IKeyboardShortcutsV1":"tbIDE.KeyboardShortcuts","tbIDE.IProjectV1":"tbIDE.Project","tbIDE.IThemesV1":"tbIDE.Themes","tbIDE.IToolWindowV1":"tbIDE.ToolWindow","tbIDE.IToolWindowsV1":"tbIDE.ToolWindows","tbIDE.IToolbarV1":"tbIDE.Toolbar","tbIDE.IToolbarsV1":"tbIDE.Toolbars"}, "symbols": [ diff --git a/add-in/Sources/Declared.twin b/add-in/Sources/Declared.twin index 7c53685b9..df95aef67 100644 --- a/add-in/Sources/Declared.twin +++ b/add-in/Sources/Declared.twin @@ -1,5 +1,5 @@ ' Where the compiler says a name is declared, read from the markdown its hover -' gives (P5 in WIP.HelpAddin.md). The forms, as BETA 995 writes them: +' gives (P5 in WIP.HelpAddin.md). The forms, as BETA 1005 writes them: ' ' a procedure or member: ___ ## **MsgBox** ... `in VBA.Interaction` ' ## **Add** ... `in VBA._Collection` diff --git a/bugs/filed/concurrent-builds-shared-temp/REPORT.md b/bugs/filed/concurrent-builds-shared-temp/REPORT.md deleted file mode 100644 index de478bbb1..000000000 --- a/bugs/filed/concurrent-builds-shared-temp/REPORT.md +++ /dev/null @@ -1,33 +0,0 @@ -Filed as [twinbasic/twinbasic#2505](https://github.com/twinbasic/twinbasic/issues/2505). - -## Builds running at the same time in one TEMP folder sometimes fail to write the type library - -**Describe the bug** -When several twinBASIC IDEs build at the same time, and their `TEMP` is the same folder, which is the default for one user, a build now and then fails while writing the type library, with nothing wrong in the project. The same build passes when repeated, or when it runs alone. With a different `TEMP` folder for each IDE, the failure did not occur. - -**To Reproduce** -Steps to reproduce the behavior: -1. Unzip `concurrent-builds-shared-temp.zip` (it holds `concurrent-builds-shared-temp.twinproj`, an ordinary console project with an empty `Sub Main`) and copy the project into eight folders, one copy each. -2. Open each copy in its own instance of the IDE, all eight running at once, with the default environment, so that every instance has the same `TEMP`. -3. Press **Build** in all eight at about the same time, and repeat. About one build in 24 fails; the DEBUG CONSOLE of the one that failed shows: - ``` - [BUILD] Starting... - [TYPELIB] failed to finalize typelibrary. Disk error? - [LINKER] FAILED to create type library - [BUILD] failed - ``` -4. Control: start each instance with `TEMP` and `TMP` set to a folder of its own (for example from a Command Prompt, `set TEMP=C:\t\1` and `set TMP=C:\t\1`, then start the IDE from it). The failure does not occur. - -Measured with the documentation's build harness, which starts each IDE on its own port and presses Build through it, eight IDEs at once, over 192 builds each way: 8 failed with one `TEMP` for all eight, and 0 failed with a `TEMP` folder for each. With one or two IDEs at once, 0 of 120 failed. Distinct project names and project ids in each copy did not prevent it. The failing build is a different one each time. - -**Expected behavior** -Each build writes its type library and succeeds, however many IDEs share the `TEMP` folder. - -**Desktop:** - - OS: Windows 10 Pro 22H2 (build 19045) - - twinBASIC compiler version: BETA 995 - -**Additional context** -Severity: low; the build passes when repeated, and an IDE run by a person rarely builds at the same moment as another. It affects tools that build several projects at once. The compiler imports `GetTempFileNameW`, and its messages show that it writes the type library to a file and reads it back (`[TYPELIB] failed to read in generated type library file` is the message beside this one). A temporary file name that two processes both use would explain the counts; that is an inference, not observed. The temp folder is empty after the builds, so whatever is written there is deleted. - - diff --git a/bugs/filed/concurrent-builds-shared-temp/repro.json b/bugs/filed/concurrent-builds-shared-temp/repro.json deleted file mode 100644 index 9eefb998b..000000000 --- a/bugs/filed/concurrent-builds-shared-temp/repro.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "mode": "probe", - "probe": [ - "scripts/probe_shared_temp.mjs" - ], - "expect": { - "exit": 1, - "output": [ - "^[1-9]\\d* of \\d+ builds failed to write the type library \\(TEMP shared\\)$" - ] - }, - "steps": "1. Unzip concurrent-builds-shared-temp.zip and copy the project into eight folders.\n2. Open each copy in its own IDE, all eight at once, with the default environment, so that all share one TEMP.\n3. Press Build in all eight at about the same time, and repeat. About one build in 24 fails with [TYPELIB] failed to finalize typelibrary. Disk error? then [LINKER] FAILED to create type library and [BUILD] failed.\n4. Control: give each IDE a TEMP and TMP of its own; no build fails.\nscripts/probe_shared_temp.mjs does this with a TEMP shared by eight IDEs whose builds start together, and --control with a TEMP for each. On BETA 997, 3 of 8 builds failed in the first round shared, and 0 of 48 with a TEMP each.", - "issue": 2505 -} diff --git a/bugs/filed/concurrent-builds-shared-temp/src/Sources/Startup.twin b/bugs/filed/concurrent-builds-shared-temp/src/Sources/Startup.twin deleted file mode 100644 index 20233b3a9..000000000 --- a/bugs/filed/concurrent-builds-shared-temp/src/Sources/Startup.twin +++ /dev/null @@ -1,6 +0,0 @@ -Module Startup - - Public Sub Main() - End Sub - -End Module diff --git a/bugs/llvm-plain-calls-llvm-from-main/llvm-plain-calls-llvm-from-main.twinproj b/bugs/llvm-plain-calls-llvm-from-main/llvm-plain-calls-llvm-from-main.twinproj new file mode 100644 index 000000000..c6c6cefd8 Binary files /dev/null and b/bugs/llvm-plain-calls-llvm-from-main/llvm-plain-calls-llvm-from-main.twinproj differ diff --git a/bugs/llvm-plain-calls-llvm-from-main/repro.json b/bugs/llvm-plain-calls-llvm-from-main/repro.json new file mode 100644 index 000000000..12d0f1dbe --- /dev/null +++ b/bugs/llvm-plain-calls-llvm-from-main/repro.json @@ -0,0 +1,10 @@ +{ + "mode": "run", + "expect": { + "exit": 5, + "output": [ + "^Plain: before Callee$", + "NATIVE EXCEPTION: ACCESS_VIOLATION" + ] + } +} diff --git a/bugs/filed/concurrent-builds-shared-temp/concurrent-builds-shared-temp.twinproj b/bugs/llvm-plain-calls-llvm-from-main/src/Settings similarity index 69% rename from bugs/filed/concurrent-builds-shared-temp/concurrent-builds-shared-temp.twinproj rename to bugs/llvm-plain-calls-llvm-from-main/src/Settings index 7ee685cbe..68e4afc7e 100644 Binary files a/bugs/filed/concurrent-builds-shared-temp/concurrent-builds-shared-temp.twinproj and b/bugs/llvm-plain-calls-llvm-from-main/src/Settings differ diff --git a/bugs/llvm-plain-calls-llvm-from-main/src/Sources/Startup.twin b/bugs/llvm-plain-calls-llvm-from-main/src/Sources/Startup.twin new file mode 100644 index 000000000..adb2c776a --- /dev/null +++ b/bugs/llvm-plain-calls-llvm-from-main/src/Sources/Startup.twin @@ -0,0 +1,21 @@ +' With LLVM turned on for the whole project (Settings: compiler.debugOptions is +llvm), +' a procedure marked [CompilerOptions("")] that Sub Main calls ends the run in the IDE +' with an access violation when it calls a procedure compiled with LLVM. +Module Startup + + Public Sub Callee() + Debug.Print "Callee" + End Sub + + [CompilerOptions("")] + Public Sub Plain() + Debug.Print "Plain: before Callee" + Callee + Debug.Print "Plain: after Callee" + End Sub + + Public Sub Main() + Plain + End Sub + +End Module diff --git a/builder/package-api.json b/builder/package-api.json index d15393116..c2d1ba743 100644 --- a/builder/package-api.json +++ b/builder/package-api.json @@ -1,5 +1,5 @@ { - "build": 997, + "build": 1005, "packages": { "AppGlobalClassProject": { "exports": ["AppGlobalClassObject"], @@ -628,7 +628,7 @@ {"name":"Strings","kind":"module","members":{"Asc":"function","AscW":"function","AscB":"function","Chr$":"function","Chr":"function","ChrW$":"function","ChrW":"function","ChrB$":"function","ChrB":"function","Mid$":"function","Mid":"function","MidB$":"function","MidB":"function","Left$":"function","Left":"function","LeftB$":"function","LeftB":"function","Right$":"function","Right":"function","RightB$":"function","RightB":"function","Space$":"function","Space":"function","String$":"function","String":"function","LTrim$":"function","LTrim":"function","RTrim$":"function","RTrim":"function","Trim$":"function","Trim":"function","MonthName":"function","WeekdayName":"function","StrReverse":"function","LCase$":"function","LCase":"function","UCase$":"function","UCase":"function","Format$":"function","Format":"function","FormatCurrency":"function","FormatNumber":"function","FormatPercent":"function","FormatDateTime":"function","StrComp":"function","StrConv":"function","Join":"function","Replace":"function","InStr$":"function","InStr":"function","InStrB":"function","InStrRev":"function","Filter":"function","Split":"function","Len$":"function","Len":"function","LenB$":"function","LenB":"function"}}, {"name":"TextEncodingConstants","kind":"module","members":{"default_system_ansi":"const","utf_7":"const","utf_7_bom":"const","utf_8":"const","utf_8_bom":"const","utf_16":"const","utf_16_bom":"const","us_ascii":"const","koi8_u":"const","koi8_r":"const","big5":"const","iso_8859_1_latin1":"const","iso_8859_2_latin2":"const","iso_8859_3_latin3":"const","iso_8859_4_latin4":"const","iso_8859_5_cyrillic":"const","iso_8859_6_arabic":"const","iso_8859_7_greek":"const","iso_8859_8_hebrew":"const","iso_8859_9_latin5_turkish":"const","iso_8859_10_latin6_nordic":"const","iso_8859_11_thai":"const","iso_8859_13_latin8_baltic":"const","iso_8859_14_latin8_celtic":"const","iso_8859_15_latin9_euro":"const","iso_8859_16_latin10_balkan":"const","windows_1250_central_europe":"const","windows_1251_cyrillic":"const","windows_1252_western":"const","windows_1253_greek":"const","windows_1254_turkish":"const","windows_1255_hebrew":"const","windows_1256_arabic":"const","windows_1257_baltic":"const","windows_1258_vietnamese":"const","ibm_850_western_europe":"const","ibm_852_central_and_eastern_europe":"const","ibm_855_cyrillic":"const","ibm_856_hebrew":"const","ibm_857_turkish":"const","ibm_858_western_europe":"const","ibm_860_portuguese":"const","ibm_861_icelandic":"const","ibm_862_hebrew":"const","ibm_863_canadian":"const","ibm_865_danish":"const","ibm_866_cyrillic":"const","ibm_869_greek":"const","ibm_932_japanese":"const","ibm_949_korean":"const"},"hiddenMembers":["default_system_ansi","utf_7","utf_7_bom","utf_8","utf_8_bom","utf_16","utf_16_bom","us_ascii","koi8_u","koi8_r","big5","iso_8859_1_latin1","iso_8859_2_latin2","iso_8859_3_latin3","iso_8859_4_latin4","iso_8859_5_cyrillic","iso_8859_6_arabic","iso_8859_7_greek","iso_8859_8_hebrew","iso_8859_9_latin5_turkish","iso_8859_10_latin6_nordic","iso_8859_11_thai","iso_8859_13_latin8_baltic","iso_8859_14_latin8_celtic","iso_8859_15_latin9_euro","iso_8859_16_latin10_balkan","windows_1250_central_europe","windows_1251_cyrillic","windows_1252_western","windows_1253_greek","windows_1254_turkish","windows_1255_hebrew","windows_1256_arabic","windows_1257_baltic","windows_1258_vietnamese","ibm_850_western_europe","ibm_852_central_and_eastern_europe","ibm_855_cyrillic","ibm_856_hebrew","ibm_857_turkish","ibm_858_western_europe","ibm_860_portuguese","ibm_861_icelandic","ibm_862_hebrew","ibm_863_canadian","ibm_865_danish","ibm_866_cyrillic","ibm_869_greek","ibm_932_japanese","ibm_949_korean"]}, {"name":"TestGeneric","kind":"class","members":{"Something":"sub"}}, - {"name":"_HiddenModule","kind":"module","hidden":true,"members":{"PictureToByteArray":"function","CreateGUID":"function","GetMem1":"sub","GetMem2":"sub","GetMem4":"sub","GetMem8":"sub","GetMemPtr":"sub","PutMem1":"sub","PutMem2":"sub","PutMem4":"sub","PutMem8":"sub","PutMemPtr":"sub","vbaObjAddref":"sub","vbaObjRelease":"sub","vbaObjSetAddref":"function","vbaObjSet":"function","vbaRefVarAry":"function","vbaAryMove":"sub","CreateStdPictureFromHandle":"function","RuntimeGetBitmapBits":"sub","RuntimeSetBitmapBits":"sub","RuntimeConvertBitmapToIcon":"sub","RuntimeConvertBitmap32ToIcon":"sub","RuntimeCreateScaledPicture":"function","RuntimeCreatePremultipliedRGBABitmap32bpp":"function","RuntimePrinterGetFonts":"sub","RuntimePatchGetClipBoxForHdc":"sub","RuntimeCreateExpressionService":"function","RuntimeCreateResampledBitmap":"function","Eval":"function","vbaCopyBytes":"function","vbaCopyBytesZero":"function","AllocMem":"function","FreeMem":"sub","SetThreadGlobalErrorTrap":"sub","SuppressRaiseEvents":"sub","DontInitNextCreatedCOMInstance":"sub","ExclusivitySectionEnter":"sub","ExclusivitySectionLeave":"sub","ClipboardGetTextInternal":"function","ClipboardSetTextInternal":"sub","LoadPictureInternal":"function","LoadResDataInternal":"function","CreateClassPropertyBagUCRead2":"function","CreateClassPropertyBagUCWrite2":"function","CreateClassPropertyBagUCRead":"function","CreateClassPropertyBagUCWrite":"function","GetPropertyBagUCWriterContents":"function","HasExclusiveDefaultDispatchValue":"function","ShowPropertyPages":"sub","SynchronizeWindowSizeWithParent":"sub","CreateCoreWebView2Environment":"sub","BringWindowToFront":"sub","CrashDAP":"sub","CrashLSP":"sub","CrashFS":"sub","CrashRoot":"sub","ObjPtr":"function","StrPtr":"function","ConvertIconToBitmap":"function","Input$":"function","Input":"function","InputB$":"function","InputB":"function","Width":"sub","_FileWidth":"sub","_InStrBreak":"function","CreateCollectionObject":"function","Array":"function","Int3Breakpoint":"sub","Emit":"sub","EmitAny":"sub","GetDeclaredTypeProgId":"function","GetDeclaredTypeIid":"function","GetDeclaredTypeEventIid":"function","GetDeclaredTypeClsid":"function","GetDeclaredMinEnumValue":"function","GetDeclaredMaxEnumValue":"function","StackOffset":"function","StackArgsSize":"function","UnprotectedAccess":"function","CheckBadFPUInstruction":"sub","VarPtr":"function","InternalDebugHoverEval":"function","GetErrNumber":"function","LetErrNumber":"sub","GetErrSource":"function","LetErrSource":"sub","GetErrDescription":"function","LetErrDescription":"sub","GetErrHelpFile":"function","LetErrHelpFile":"sub","GetErrHelpContext":"function","LetErrHelpContext":"sub","ErrRaise":"sub","ErrClear":"sub","GetErrLastDllError":"function","LetErrLastDllError":"sub","GetErrLastHresult":"function","GetErrReturnHResult":"function","LetErrReturnHResult":"sub","EnsureContainerIsLoaded":"sub","ResetFirstMethodAccessFlag":"sub","MemZero":"sub","GetClasInstanceAxMiscFlags":"sub","GetClassInstanceSerializer":"function","GetClassInstanceRefCount":"function","RuntimeGetChildControlsList":"function","RuntimeCreateGetMessageHook":"function","vbaCastObj":"function","InterlockedExchangePointer":"function","InterlockedCompareExchangePointer":"function","InterlockedCompareExchange32":"function","InterlockedCompareExchange64":"function","InterlockedIncrement32":"function","InterlockedDecrement32":"function","GetShortcutTextByEnum":"function","RuntimeSetWithEvents":"function","RuntimeReadFileDataBase64":"function","RuntimeRaisePropertyNotifySinkChangedEvent":"sub","RuntimeGetPropertyPageClsidByName":"sub","RuntimeMapDispIdToPropertyPageClsid":"function","RuntimeGetTypeInfoPropertyList":"function","RuntimeCreateRecurseProtectedObjectWrapper":"function","GetInheritedOwner":"function","SetClassOverrideDispatch":"sub","RuntimeSharedMemCreateHost":"function","RuntimeSharedMemCreateClient":"function","RuntimeSharedMemSendMessage":"sub","RuntimeSharedMemReceiveMessage":"function","RuntimeFusionRegisterInterface":"sub","RuntimeFusionRegisterClass":"sub","RuntimeFusionCreateObject":"function","RuntimeFusionCreatePortalHost":"function","RuntimeFusionCreatePortalClient":"function","RuntimeFusionSetChannelNotificationCallback":"sub","RuntimeFusionCreateLinkedChannel":"sub","RuntimeFusionJoinLinkedChannel":"sub","RuntimeFusionProcessMessage":"sub","RuntimeFusionGetThreadID":"function","RuntimeSetActiveXInitializationOverride":"sub","RuntimeShellAutoExit":"function","RuntimeGetFusionActiveXOverrides":"sub","RuntimeShowAxAboutBox":"sub","RuntimeAxGetMiscStatus":"function","RuntimeAxGetSnapshotBits":"function","RuntimePaintBits":"sub","RuntimeFusionGetExePath":"function","RuntimeFusionStartProcess":"sub","InterlockedIncrement64":"function","InterlockedDecrement64":"function","RuntimeOverrideFusionIpcNoWait":"sub","RuntimeFusionCancelLinkedChannel":"sub","RuntimeBase64Encode":"function","RuntimeFusionCreateExplicitLinkedChannelCallback":"sub","RuntimeCreateSharedMemData":"function","RuntimeOpenSharedMemData":"function","RuntimeAccessSharedMemData":"function","RuntimeUnaccessSharedMemData":"sub","RuntimeCloseSharedMemData":"sub","RuntimeFusionInteruptPendingIPC_UIThread":"function","RuntimeFusionSetPortalTimeout":"sub","RuntimeFusionClosePortal":"sub","RuntimeBase64Decode":"function","SetClassOverrideEvents":"sub","RuntimeGetProjectConditionalCompilationArgValue":"function"},"hiddenMembers":["SuppressRaiseEvents","DontInitNextCreatedCOMInstance","ExclusivitySectionEnter","ExclusivitySectionLeave","ClipboardGetTextInternal","ClipboardSetTextInternal","LoadPictureInternal","LoadResDataInternal","CreateClassPropertyBagUCRead2","CreateClassPropertyBagUCWrite2","CreateClassPropertyBagUCRead","CreateClassPropertyBagUCWrite","GetPropertyBagUCWriterContents","HasExclusiveDefaultDispatchValue","ShowPropertyPages","SynchronizeWindowSizeWithParent","CreateCoreWebView2Environment","BringWindowToFront","CrashDAP","CrashLSP","CrashFS","CrashRoot","_FileWidth","_InStrBreak","CreateCollectionObject","Int3Breakpoint","CheckBadFPUInstruction","InternalDebugHoverEval","GetErrNumber","LetErrNumber","GetErrSource","LetErrSource","GetErrDescription","LetErrDescription","GetErrHelpFile","LetErrHelpFile","GetErrHelpContext","LetErrHelpContext","ErrRaise","ErrClear","GetErrLastDllError","LetErrLastDllError","GetErrLastHresult","GetErrReturnHResult","LetErrReturnHResult","EnsureContainerIsLoaded","ResetFirstMethodAccessFlag","MemZero","GetClasInstanceAxMiscFlags","GetClassInstanceSerializer","GetClassInstanceRefCount","SetClassOverrideDispatch","RuntimeSharedMemCreateHost","RuntimeSharedMemCreateClient","RuntimeSharedMemSendMessage","RuntimeSharedMemReceiveMessage","RuntimeFusionRegisterInterface","RuntimeFusionRegisterClass","RuntimeFusionCreateObject","RuntimeFusionCreatePortalHost","RuntimeFusionCreatePortalClient","RuntimeFusionSetChannelNotificationCallback","RuntimeFusionCreateLinkedChannel","RuntimeFusionJoinLinkedChannel","RuntimeFusionProcessMessage","RuntimeFusionGetThreadID","RuntimeShellAutoExit","RuntimeGetFusionActiveXOverrides","RuntimeShowAxAboutBox","RuntimeAxGetMiscStatus","RuntimeAxGetSnapshotBits","RuntimePaintBits","RuntimeFusionGetExePath","RuntimeFusionStartProcess","SetClassOverrideEvents"]}, + {"name":"_HiddenModule","kind":"module","hidden":true,"members":{"PictureToByteArray":"function","CreateGUID":"function","GetMem1":"sub","GetMem2":"sub","GetMem4":"sub","GetMem8":"sub","GetMemPtr":"sub","PutMem1":"sub","PutMem2":"sub","PutMem4":"sub","PutMem8":"sub","PutMemPtr":"sub","vbaObjAddref":"sub","vbaObjRelease":"sub","vbaObjSetAddref":"function","vbaObjSet":"function","vbaRefVarAry":"function","vbaAryMove":"sub","CreateStdPictureFromHandle":"function","RuntimeGetBitmapBits":"sub","RuntimeSetBitmapBits":"sub","RuntimeConvertBitmapToIcon":"sub","RuntimeConvertBitmap32ToIcon":"sub","RuntimeCreateScaledPicture":"function","RuntimeCreatePremultipliedRGBABitmap32bpp":"function","RuntimePrinterGetFonts":"sub","RuntimePatchGetClipBoxForHdc":"sub","RuntimeCreateExpressionService":"function","RuntimeCreateResampledBitmap":"function","Eval":"function","vbaCopyBytes":"function","vbaCopyBytesZero":"function","AllocMem":"function","FreeMem":"sub","SetThreadGlobalErrorTrap":"sub","SuppressRaiseEvents":"sub","DontInitNextCreatedCOMInstance":"sub","ExclusivitySectionEnter":"sub","ExclusivitySectionLeave":"sub","ClipboardGetTextInternal":"function","ClipboardSetTextInternal":"sub","LoadPictureInternal":"function","LoadResDataInternal":"function","CreateClassPropertyBagUCRead2":"function","CreateClassPropertyBagUCWrite2":"function","CreateClassPropertyBagUCRead":"function","CreateClassPropertyBagUCWrite":"function","GetPropertyBagUCWriterContents":"function","HasExclusiveDefaultDispatchValue":"function","ShowPropertyPages":"sub","SynchronizeWindowSizeWithParent":"sub","CreateCoreWebView2Environment":"sub","BringWindowToFront":"sub","CrashDAP":"sub","CrashLSP":"sub","CrashFS":"sub","CrashRoot":"sub","ObjPtr":"function","StrPtr":"function","ConvertIconToBitmap":"function","Input$":"function","Input":"function","InputB$":"function","InputB":"function","Width":"sub","_FileWidth":"sub","_InStrBreak":"function","CreateCollectionObject":"function","Array":"function","Int3Breakpoint":"sub","Emit":"sub","EmitAny":"sub","GetDeclaredTypeProgId":"function","GetDeclaredTypeIid":"function","GetDeclaredTypeEventIid":"function","GetDeclaredTypeClsid":"function","GetDeclaredMinEnumValue":"function","GetDeclaredMaxEnumValue":"function","StackOffset":"function","StackArgsSize":"function","UnprotectedAccess":"function","CheckBadFPUInstruction":"sub","VarPtr":"function","InternalDebugHoverEval":"function","InternalDebugWatchEval":"function","GetErrNumber":"function","LetErrNumber":"sub","GetErrSource":"function","LetErrSource":"sub","GetErrDescription":"function","LetErrDescription":"sub","GetErrHelpFile":"function","LetErrHelpFile":"sub","GetErrHelpContext":"function","LetErrHelpContext":"sub","ErrRaise":"sub","ErrClear":"sub","GetErrLastDllError":"function","LetErrLastDllError":"sub","GetErrLastHresult":"function","GetErrReturnHResult":"function","LetErrReturnHResult":"sub","EnsureContainerIsLoaded":"sub","ResetFirstMethodAccessFlag":"sub","MemZero":"sub","GetClasInstanceAxMiscFlags":"sub","GetClassInstanceSerializer":"function","GetClassInstanceRefCount":"function","RuntimeGetChildControlsList":"function","RuntimeCreateGetMessageHook":"function","vbaCastObj":"function","InterlockedExchangePointer":"function","InterlockedCompareExchangePointer":"function","InterlockedCompareExchange32":"function","InterlockedCompareExchange64":"function","InterlockedIncrement32":"function","InterlockedDecrement32":"function","GetShortcutTextByEnum":"function","RuntimeSetWithEvents":"function","RuntimeReadFileDataBase64":"function","RuntimeRaisePropertyNotifySinkChangedEvent":"sub","RuntimeGetPropertyPageClsidByName":"sub","RuntimeMapDispIdToPropertyPageClsid":"function","RuntimeGetTypeInfoPropertyList":"function","RuntimeCreateRecurseProtectedObjectWrapper":"function","GetInheritedOwner":"function","SetClassOverrideDispatch":"sub","RuntimeSharedMemCreateHost":"function","RuntimeSharedMemCreateClient":"function","RuntimeSharedMemSendMessage":"sub","RuntimeSharedMemReceiveMessage":"function","RuntimeFusionRegisterInterface":"sub","RuntimeFusionRegisterClass":"sub","RuntimeFusionCreateObject":"function","RuntimeFusionCreatePortalHost":"function","RuntimeFusionCreatePortalClient":"function","RuntimeFusionSetChannelNotificationCallback":"sub","RuntimeFusionCreateLinkedChannel":"sub","RuntimeFusionJoinLinkedChannel":"sub","RuntimeFusionProcessMessage":"sub","RuntimeFusionGetThreadID":"function","RuntimeSetActiveXInitializationOverride":"sub","RuntimeShellAutoExit":"function","RuntimeGetFusionActiveXOverrides":"sub","RuntimeShowAxAboutBox":"sub","RuntimeAxGetMiscStatus":"function","RuntimeAxGetSnapshotBits":"function","RuntimePaintBits":"sub","RuntimeFusionGetExePath":"function","RuntimeFusionStartProcess":"sub","InterlockedIncrement64":"function","InterlockedDecrement64":"function","RuntimeOverrideFusionIpcNoWait":"sub","RuntimeFusionCancelLinkedChannel":"sub","RuntimeBase64Encode":"function","RuntimeFusionCreateExplicitLinkedChannelCallback":"sub","RuntimeCreateSharedMemData":"function","RuntimeOpenSharedMemData":"function","RuntimeAccessSharedMemData":"function","RuntimeUnaccessSharedMemData":"sub","RuntimeCloseSharedMemData":"sub","RuntimeFusionInteruptPendingIPC_UIThread":"function","RuntimeFusionSetPortalTimeout":"sub","RuntimeFusionClosePortal":"sub","RuntimeBase64Decode":"function","SetClassOverrideEvents":"sub","RuntimeGetProjectConditionalCompilationArgValue":"function"},"hiddenMembers":["SuppressRaiseEvents","DontInitNextCreatedCOMInstance","ExclusivitySectionEnter","ExclusivitySectionLeave","ClipboardGetTextInternal","ClipboardSetTextInternal","LoadPictureInternal","LoadResDataInternal","CreateClassPropertyBagUCRead2","CreateClassPropertyBagUCWrite2","CreateClassPropertyBagUCRead","CreateClassPropertyBagUCWrite","GetPropertyBagUCWriterContents","HasExclusiveDefaultDispatchValue","ShowPropertyPages","SynchronizeWindowSizeWithParent","CreateCoreWebView2Environment","BringWindowToFront","CrashDAP","CrashLSP","CrashFS","CrashRoot","_FileWidth","_InStrBreak","CreateCollectionObject","Int3Breakpoint","CheckBadFPUInstruction","InternalDebugHoverEval","InternalDebugWatchEval","GetErrNumber","LetErrNumber","GetErrSource","LetErrSource","GetErrDescription","LetErrDescription","GetErrHelpFile","LetErrHelpFile","GetErrHelpContext","LetErrHelpContext","ErrRaise","ErrClear","GetErrLastDllError","LetErrLastDllError","GetErrLastHresult","GetErrReturnHResult","LetErrReturnHResult","EnsureContainerIsLoaded","ResetFirstMethodAccessFlag","MemZero","GetClasInstanceAxMiscFlags","GetClassInstanceSerializer","GetClassInstanceRefCount","SetClassOverrideDispatch","RuntimeSharedMemCreateHost","RuntimeSharedMemCreateClient","RuntimeSharedMemSendMessage","RuntimeSharedMemReceiveMessage","RuntimeFusionRegisterInterface","RuntimeFusionRegisterClass","RuntimeFusionCreateObject","RuntimeFusionCreatePortalHost","RuntimeFusionCreatePortalClient","RuntimeFusionSetChannelNotificationCallback","RuntimeFusionCreateLinkedChannel","RuntimeFusionJoinLinkedChannel","RuntimeFusionProcessMessage","RuntimeFusionGetThreadID","RuntimeShellAutoExit","RuntimeGetFusionActiveXOverrides","RuntimeShowAxAboutBox","RuntimeAxGetMiscStatus","RuntimeAxGetSnapshotBits","RuntimePaintBits","RuntimeFusionGetExePath","RuntimeFusionStartProcess","SetClassOverrideEvents"]}, {"name":"IGetMessageHook","kind":"interface","members":{"RegisterMessage":"sub","Start":"sub","Stop":"sub"}}, {"name":"EnumDescendantsModeFlags","kind":"enum","in":"IGetMessageHook","values":["ExactWindow","AllDescendants","DirectChildren"]}, {"name":"GetMessageHookHelper","kind":"module","members":{"GetMessageHandler":"delegate"}}, @@ -749,8 +749,8 @@ {"name":"Hyperlink","kind":"interface","members":{"GoForward":"sub","GoBack":"sub","NavigateTo":"sub"}}, {"name":"ParentControls","kind":"interface","members":{"Count":"property","Item":"property","_NewEnum":"function","ParentControlsType":"property"}}, {"name":"PropertyBag_VB5","kind":"interface","members":{"ReadProperty":"function","WriteProperty":"sub"}}, - {"name":"_PropertyBag","kind":"interface","extends":"VBRUN.PropertyBag_VB5","members":{"Contents":"property"}}, - {"name":"PropertyBag","kind":"coclass","default":"_PropertyBag"} + {"name":"_PropertyBag","kind":"interface","members":{"ReadProperty":"function","WriteProperty":"sub","Contents":"property"}}, + {"name":"PropertyBag","kind":"coclass","default":"_PropertyBag","interfaces":["PropertyBag_VB5"]} ] }, "WebView2Package": { diff --git a/builder/page-baseline.json b/builder/page-baseline.json index 958e2350a..18891a62c 100644 --- a/builder/page-baseline.json +++ b/builder/page-baseline.json @@ -1,5 +1,5 @@ { "src": "docs", - "pages": 1283, - "staticFiles": 1009 + "pages": 1285, + "staticFiles": 1011 } diff --git a/docs/Documentation/Authoring.md b/docs/Documentation/Authoring.md index 11cd2b951..e884d5815 100644 --- a/docs/Documentation/Authoring.md +++ b/docs/Documentation/Authoring.md @@ -104,9 +104,9 @@ bundle_extra: dest: Features/Packages/downloads/impexp.py ``` -`src` is resolved against `docs/`, so it may point outside the tree --- the two -real entries publish the [Import/Export Tool](../../Features/Packages/Import-Export-Tool) -from `scripts/`, where it is maintained, with no second copy under `docs/`. +`src` is resolved against `docs/`, so it may point outside the tree --- the real +entries publish the three editions of the [Import/Export Tool](../../Features/Packages/Import-Export-Tool) +from `scripts/`, where they are maintained, with no second copy under `docs/`. `dest` is the path in the built site, and the page links to it. A `src` that does not exist aborts the build. @@ -134,7 +134,7 @@ Every page opens with a YAML frontmatter block. The keys that matter: - **`symbols`** --- optional, and rare. The names a page documents, when its title and first heading cannot say; see [Naming what a page documents](#symbols). - **`index`**, **`index_also`** --- optional. Terms a reader searches for that should find this page, as a book's index lists them; see [Index entries for the site search](#index-entries-for-the-site-search). -A package's `index.md` may also carry **`package_name`**, **`indexed_from`**, **`exclude_from_docs`** and **`exclude_kinds`**. They record which packages the section documents, which twinBASIC build the package download was indexed against and what was excluded from the docs, so a later re-index can tell a gap from an exclusion. `package_name` names the packages as the [package indexer](Tools-Build#twin-index) names them, and is needed only where the section's folder is named otherwise. The build uses `exclude_from_docs` only to leave those names out of the [symbol index](Building#the-symbol-index)'s count of undocumented symbols; none of the four reaches the HTML. **Leave them in place**, and bump `indexed_from` in the same commit if you re-index a package against a newer build. +A package's `index.md` may also have **`package_name`**, **`indexed_from`**, **`exclude_from_docs`** and **`exclude_kinds`**. They record which packages the section documents, which twinBASIC build the package download was indexed against and what was excluded from the docs, so a later re-index can tell a gap from an exclusion. `package_name` names the packages as the [package indexer](Tools-Build#twin-index) names them, and is needed only where the section's folder is named otherwise. The build uses `exclude_from_docs` only to leave those names out of the [symbol index](Building#the-symbol-index)'s count of undocumented symbols; none of the four reaches the HTML. **Leave them in place**, and bump `indexed_from` in the same commit if you re-index a package against a newer build. An unrecognised key is inert and never emitted into the page. A key whose *value* is not valid YAML aborts the build with `Failed to parse frontmatter in `, quoting the parser's own line and column. @@ -493,8 +493,10 @@ generated `Sub`. These keys override it when it guesses wrong: A `check_run` sample states what it prints in one of two ways, read from the sample's own text. A trailing comment on a `Debug.Print` line gives that line's -output. A comment line that is exactly `' Output:` gives the whole output, one -line per comment line below it. When a sample states anything, it must print +output. It can go on with a note for the reader after ` -- `, which is not +compared: `' 0 -- nothing left in Err` states `0`. A comment line that is exactly +`' Output:` gives the whole output, one line per comment line below it, each taken +whole; output that itself holds ` -- ` is stated this way. When a sample states anything, it must print exactly as many lines as it states. Each line is compared with the spaces at both ends removed, because twinBASIC prints a space before a positive number. @@ -506,6 +508,7 @@ error with `On Error Resume Next` and print `Err.Number`. ```tb check_run Debug.Print InStr(1, "abc", "b") ' 2 Debug.Print UCase("tb") ' TB +Debug.Print Len("") ' 0 -- an empty string has no characters ``` ```` @@ -911,7 +914,7 @@ A search that backtracks without end gives up instead of hanging. ``` -A region may hold paragraphs, lists, tables and samples, and regions do not nest. The folder's README says how to write a case, and [`check_package_tests.mjs`](Tools-Toolchain-Tests#check-package-tests), in `test.bat`, fails a callout with neither a marker nor a region, a region left open, and a case no marker names. [`package-tests.bat`](Tools#package-testsbat) runs the cases. The section's landing page ends with a short **Test cases** section that links to the project the build publishes, `-tests.twinproj`. +A region may hold paragraphs, lists, tables and samples, and regions do not nest. The folder's README says how to write a case, and [`check_package_tests.mjs`](Tools-Toolchain-Tests#check-package-tests), in `test.bat`, fails a callout with neither a marker nor a region, a region left open, and a case no marker names. [`package-tests.bat`](Tools#package-testsbat) runs the cases. The section's landing page ends with a short **Test cases** section that links to the project the build publishes, `-tests.twinproj`. [Updating a Contributed Package](Contributed-Packages) lists the steps that move a section to a new version of its package. ## Document the product as it is diff --git a/docs/Documentation/Contributed-Packages.md b/docs/Documentation/Contributed-Packages.md new file mode 100644 index 000000000..779dc66e8 --- /dev/null +++ b/docs/Documentation/Contributed-Packages.md @@ -0,0 +1,81 @@ +--- +title: Updating a Contributed Package +parent: Documentation Development +nav_order: 6 +permalink: /Documentation/Development/Contributed-Packages +--- + +# Updating a Contributed Package +{: .no_toc } + +The steps that bring a contributed package's section up to a new version of the package, in the order they are run. + +A contributed package's section, under `docs/Reference/Contributed//`, documents one version of the package. That version is written in five places: the landing page's `indexed_from:` and its **Version:** line, the package's API snapshot, the version its samples compile against, and its test project's `expect.json`. Editing the pages alone leaves the other three behind, and `test.bat` fails. + +The examples below call the package **myPackage**; write your package's name in its place. + +* TOC +{:toc} + +## Before the first update + +1. Install **Node.js 22** or later, and run `npm ci` at the repository root ([Requirements](Building#requirements)). +2. Install the newest twinBASIC BETA. The tools look for the newest `twinBASIC_IDE_BETA_` folder on the Desktop; if yours is elsewhere, set the `TB_IDE` environment variable to the full path of its `twinBASIC.exe`. A contributed package is documented, and its samples compiled, against the newest BETA only. +3. Run `git config core.hooksPath .githooks`, which lints the scripts a commit changes. + +## The steps + +1. **Publish the new version to TWINSERV.** The tools fetch the package from the package server, never from GitHub, so a version that is not published there cannot be documented yet. + +2. **Update the package's API snapshot, and list what changed:** + + ```bash + node indexer/twin-index.mjs sync --package myPackage + node indexer/twin-index.mjs analyze --package myPackage + ``` + + `sync` rewrites `indexer/snapshots/contributed/myPackage/api.json` from the new version. `analyze` lists the public symbols to document, to update and to remove, and every callout labelled with the old version, which is to be checked again. Until the new snapshot is committed, `analyze` says it runs in *audit mode*; that is expected. [twin-index.mjs](Tools-Build#twin-index) has the details. + +3. **Edit the pages.** On the landing page, set `indexed_from:` and the **Version:** line to the new version, all four parts (`1.2.0.0`). Then go through the callouts `analyze` listed: move each label to the new version if it still holds, or remove the callout if it no longer does ([Callouts in a contributed package's section](Authoring#callouts-in-a-contributed-packages-section)). The build refuses a label naming any version but the one `indexed_from:` names. + + A member page that goes away needs the same care as any other removed page ([Removing a page](Authoring#removing-a-page)). When another page takes over its subject, give that page a `redirect_from:` entry with the old URL, so that links to it keep working. + +4. **Set the samples' version** in `test/example-projects/contributed-myPackage/Settings`: the `versionMajor`, `versionMinor`, `versionBuild` and `versionRevision` of the package's reference. The samples and the test project are built against this version. + +5. **Edit the test cases** in `test/package-tests/myPackage/Sources/` ([the folder's README](https://github.com/twinbasic/documentation/tree/main/test/package-tests) says how a case is written). Every NOTE and WARNING in the section names the cases behind it, so a callout added or changed in step 3 has cases to add or change here. + + - Do not copy `Expect.twin` into the project: every project uses the one in `test/package-tests/`. + - Do not edit `RunAll.twin` or `expect.json` by hand. The next step writes them. + - Do not commit a `.twinproj`. The build makes the one it publishes. + +6. **Run the test cases**, on both architectures: + + ```bash + package-tests.bat myPackage + ``` + + The run also writes `RunAll.twin` again. If a case passes or fails differently from what `expect.json` says, the run reports it. Once the cases are right, run it again with `--update`, which writes `expect.json` from the run, and read every entry it writes: each one says the package has a defect. [package-tests.bat](Tools#package-testsbat) has the options. + +7. **Run the section's samples:** + + ```bash + examples.bat --only "^Reference/Contributed/myPackage/" + ``` + + Every sample marked `check_build` has to compile, and every sample marked `check_run` has to print what its page says ([Checking that a sample compiles](Authoring#checking-that-a-sample-compiles)). + +8. **Run the gates:** + + ```bash + build.bat && check.bat && test.bat + ``` + + A page added to the section raises the page count, and the build writes the new count to `builder/page-baseline.json`. A section that has lost a page needs `build.bat --update-page-baseline` ([The page-count drift guard](Building#the-page-count-drift-guard)). + +9. **Commit it all together:** the pages, the snapshot, the samples' `Settings`, the test cases, `RunAll.twin`, `expect.json` and `builder/page-baseline.json` if it changed. In the pull request's description, paste the `examples.bat` command and the line its run ends with. + +## What the tools catch + +`test.bat` fails while the versions disagree, while a copy of `Expect.twin` is in the project, and while `RunAll.twin` is not what `package-tests.bat` would write ([check_package_tests.mjs](Tools-Toolchain-Tests#check-package-tests)). The build fails on a callout labelled with another version. + +Nothing catches a snapshot left at the old version, a test run that was skipped, or samples that were never run: `package-tests.bat` and `examples.bat` need a twinBASIC install, so they run in no CI workflow. The pull request's description is where a reviewer sees that they ran. diff --git a/docs/Documentation/Images/Tools-Groups.dot b/docs/Documentation/Images/Tools-Groups.dot index bad47d4ff..fbadbd797 100644 --- a/docs/Documentation/Images/Tools-Groups.dot +++ b/docs/Documentation/Images/Tools-Groups.dot @@ -108,13 +108,13 @@ digraph tools_groups { margin=12 label="Compiler Harness" c1 [label="tbbuild"] c2 [label="tbrun"] - c3 [label="impexp.mjs, impexp.py"] c4 [label="check_tb_registry"] - c5 [label="probe_shared_temp"] c6 [label="probe_build_twice"] + c3 [label="impexp"] c4 [label="check_tb_registry"] + c6 [label="probe_build_twice"] cp1 [style=invis label=""] cp2 [style=invis label=""] - c1 -> c3 -> c5 -> cp1 -> cp2 + c1 -> c3 -> cp1 -> cp2 c2 -> c4 -> c6 { rank=same; c3 c4 } - { rank=same; c5 c6 } + { rank=same; cp1 c6 } } // ---- row 3 ---- @@ -289,11 +289,9 @@ digraph tools_groups { c2 [URL="Tools-Compiler#tbrun" tooltip="Builds a probe project and captures what it writes to the Debug Console of the IDE, to show what code prints rather than whether it compiles."] c3 [URL="Tools-Compiler#impexp" - tooltip="Unpacks a .twinproj or .twinpack into source files and packs them back, with the same commands as the compiler's own command line. A Node edition and a Python edition behave the same."] + tooltip="Unpacks a .twinproj or .twinpack into source files and packs them back, with the same commands as the compiler's own command line. A Node edition, a Python edition and a twinBASIC edition behave the same."] c4 [URL="Tools-Compiler#check-tb-registry" tooltip="Tests the code that restores the registry entries of the IDE after a harness run, on a scratch copy of the keys."] - c5 [URL="Tools-Compiler#probe-shared-temp" - tooltip="Counts the builds that fail to write the type library when several IDEs build at once in one TEMP folder."] c6 [URL="Tools-Compiler#probe-build-twice" tooltip="Builds one project twice in fresh IDEs and compares the two exes, to show what differs between builds of an unchanged project."] @@ -342,7 +340,7 @@ digraph tools_groups { t22 [URL="Tools-Toolchain-Tests#check-pdf-shims-equiv" tooltip="Verifies that the pdf-lib patches of the book write the same PDF objects as stock pdf-lib does."] t23 [URL="Tools-Toolchain-Tests#check-impexp-parity" - tooltip="Verifies that the Node and Python editions of impexp behave the same: same tests, exit codes, output and files."] + tooltip="Verifies that the Node, Python and (when named) twinBASIC editions of impexp behave the same: same tests, exit codes, output and files."] t24 [URL="Tools-Toolchain-Tests#check-axe-patch-equiv" tooltip="Checks that the patched axe source computes the same colour values as the stock source, for the color-contrast rule."] t25 [URL="Tools-Toolchain-Tests#indexer-test" diff --git a/docs/Documentation/Images/Tools-Groups.svg b/docs/Documentation/Images/Tools-Groups.svg index bf202f84e..e5522443c 100644 --- a/docs/Documentation/Images/Tools-Groups.svg +++ b/docs/Documentation/Images/Tools-Groups.svg @@ -1,39 +1,39 @@ - - + + tools_groups cluster_wrappers - -Batch wrappers + +Batch wrappers cluster_build - -Build and Generation + +Build and Generation cluster_site - -Site Checks + +Site Checks cluster_compiler - -Compiler Harness + +Compiler Harness @@ -73,8 +73,8 @@ w1 - -build.bat + +build.bat @@ -82,8 +82,8 @@ w2 - -serve.bat + +serve.bat @@ -91,8 +91,8 @@ w3 - -check.bat + +check.bat @@ -100,8 +100,8 @@ w4 - -test.bat + +test.bat @@ -109,8 +109,8 @@ w5 - -book.bat + +book.bat @@ -118,8 +118,8 @@ w6 - -examples.bat + +examples.bat @@ -127,8 +127,8 @@ w7 - -addin-test.bat + +addin-test.bat @@ -136,8 +136,8 @@ w8 - -ide-test.bat + +ide-test.bat @@ -145,8 +145,8 @@ w9 - -try-help-addin.bat + +try-help-addin.bat @@ -154,8 +154,8 @@ w10 - -package-tests.bat + +package-tests.bat @@ -163,8 +163,8 @@ b1 - -tbdocs + +tbdocs @@ -172,8 +172,8 @@ b2 - -render-book + +render-book @@ -181,8 +181,8 @@ b3 - -compare_trees + +compare_trees @@ -190,8 +190,8 @@ b4 - -survey_tooling + +survey_tooling @@ -199,8 +199,8 @@ b5 - -convert_em_dash_separators + +convert_em_dash_separators @@ -208,8 +208,8 @@ b6 - -build_fonts.py + +build_fonts.py @@ -217,8 +217,8 @@ b7 - -build_dot_metrics + +build_dot_metrics @@ -226,8 +226,8 @@ b8 - -twin-index + +twin-index @@ -235,8 +235,8 @@ s1 - -check_links + +check_links @@ -244,8 +244,8 @@ s2 - -crawl_check + +crawl_check @@ -253,8 +253,8 @@ s3 - -check_links_diff + +check_links_diff @@ -262,8 +262,8 @@ s4 - -check_tree_fresh + +check_tree_fresh @@ -271,8 +271,8 @@ s5 - -check_dot_fit + +check_dot_fit @@ -280,8 +280,8 @@ s6 - -check_a11y + +check_a11y @@ -289,8 +289,8 @@ s7 - -pick_a11y_sample + +pick_a11y_sample @@ -298,8 +298,8 @@ s8 - -axe-scan + +axe-scan @@ -325,8 +325,8 @@ c1 - -tbbuild + +tbbuild @@ -334,17 +334,17 @@ c2 - -tbrun + +tbrun c3 - - -impexp.mjs, impexp.py + + +impexp @@ -352,395 +352,386 @@ c4 - -check_tb_registry - - - - - -c5 - - -probe_shared_temp + +check_tb_registry - + c6 - - -probe_build_twice + + +probe_build_twice - + t1 - + check_publish_policy - + t2 - + check_regex_safety - + t3 - + check_code_regions - + t4 - + check_gate_lists - + t5 - + check_ci_workflows - + t6 - + check_lint - + t7 - + search.test - + t8 - + render.test - + t9 - + strftime.test - + t10 - + png.test - + t11 - + compact-image.test - + t12 - + svgshot.test - + t13 - + example-batches.test - + t14 - + ports.test - + t15 - + addin-project.test - + t16 - + check_page_baseline - + t17 - + check_book_coverage - + t18 - + check_symbol_index - + t19 - + check_twin_parsers - + t20 - + check_attribute_sweep - + t21 - + check_cli - + t22 - + check_pdf_shims_equiv - + t23 - + check_impexp_parity - + t24 - + check_axe_patch_equiv - + t25 - + indexer.test - + t26 - + check_package_tests - + e1 - + check_examples - + e2 - + gen_attribute_probes - + e3 - + census_attributes - + e4 - + sweep_attributes - + e5 - + package_tests - + i1 - + addin_test - + i2 - + ide_test - + i3 - + try_help_addin - + i4 - + shoot_docs - + i5 - + imagestrip - + i6 - + probe_ide_image_labels - + i7 - + svgshot/replay - + i8 - + probe_theme_semicolon - + d1 - + bug_repro - + d2 - + vb6run @@ -774,9 +765,8 @@ - + - diff --git a/docs/Documentation/Tools-Build.md b/docs/Documentation/Tools-Build.md index c30bd2c44..157b45bd9 100644 --- a/docs/Documentation/Tools-Build.md +++ b/docs/Documentation/Tools-Build.md @@ -206,7 +206,7 @@ A name that matches no package is reported, the other packages are done, and the 1. Run `sync` and `derive` with the new install. `sync` writes the new snapshots into the working tree, and `analyze` still compares with the ones at `HEAD`; `derive` writes the new `builder/package-api.json`. 2. Run `analyze`, then `draft`, and write the pages the plans list, where they say. Check each callout `analyze` lists as labelled with an older build on the new one, and move its label or remove it. -3. Set `indexed_from` on each section to the new build's tag (`beta-x-0997` is BETA 997), and commit the pages, the new `indexed_from`, the new snapshots and `builder/package-api.json` together. A snapshot committed on its own, or an `indexed_from` that is not the snapshot's `version`, sends the next `analyze` into audit mode. +3. Set `indexed_from` on each section to the new build's tag (`beta-x-1005` is BETA 1005), and commit the pages, the new `indexed_from`, the new snapshots and `builder/package-api.json` together. A snapshot committed on its own, or an `indexed_from` that is not the snapshot's `version`, sends the next `analyze` into audit mode. **After a change to the scanner or the model.** The code that writes `api.json` is `scripts/lib/twin-api.mjs`, `scripts/lib/twin-declarations.mjs`, `indexer/lib/api-model.mjs` and `indexer/lib/vb6-preprocess.mjs`. A change to any of them, the `format` number of `api.json` included, can change what the same sources index to. The next `sync` indexes every package again, and the committed snapshots have to be written again from the build they record, with `sync --ide` naming that build's install, in the same commit as the change. Otherwise `analyze` compares the output of the new code with that of the old and reports the difference as changes to the API. `--release` cannot do this: it downloads only the latest release. diff --git a/docs/Documentation/Tools-Compiler.md b/docs/Documentation/Tools-Compiler.md index 0acc5b6dc..1558c5e85 100644 --- a/docs/Documentation/Tools-Compiler.md +++ b/docs/Documentation/Tools-Compiler.md @@ -28,7 +28,7 @@ twinBASIC has no command-line build. None of the compiler executable's verbs --- | Flag | Effect | |---|---| | `--ide ` | Path to `twinBASIC.exe`. Default: `$TB_IDE`, else the newest `twinBASIC_IDE_BETA_` folder on `%USERPROFILE%\Desktop`. **No install path is hardcoded in this tooling**, because one contains a username, so an install kept elsewhere needs one of those two. | -| `--port ` | DevTools port. Default 9333. It also names the WebView2 user-data folder, the IDE's temp folder (`%TEMP%\tbbuild-tmp-`, its `TEMP` and `TMP`) and the private desktop, so runs on distinct ports can go at once; IDEs sharing one temp folder now and then fail to write the type library. Both folders (`%TEMP%\tbbuild-tmp-` and the user-data folder, `%TEMP%\tbbuild-wv2-`, about 28 MB) are emptied when the IDE starts and removed once it has ended. A port another IDE already holds is refused after ten seconds. | +| `--port ` | DevTools port. Default 9333. It also names the WebView2 user-data folder, the IDE's temp folder (`%TEMP%\tbbuild-tmp-`, its `TEMP` and `TMP`) and the private desktop, so runs on distinct ports can go at once. Both folders (`%TEMP%\tbbuild-tmp-` and the user-data folder, `%TEMP%\tbbuild-wv2-`, about 28 MB) are emptied when the IDE starts and removed once it has ended. A port another IDE already holds is refused after ten seconds. | | `--arch ` | `win32` or `win64`. Default `win32`. Diagnostics can differ, because `#If Win64` and the size of `LongPtr` change what compiles. The target is set on every run, whatever the IDE last used for the project; a switch restarts the compiler and adds a few seconds. When the target is not `win32`, or the IDE remembered another, the report starts with a `target:` line. | | `--timeout ` | Give up waiting for the compile to settle. Default 180. | | `--build` | After a compile with no errors, build the project as the toolbar's Build button does, and print `built: ` after the summary line. The given file is never changed (see below). | @@ -71,7 +71,7 @@ Exit codes: **0** the project compiled without errors; **1** the project has err node scripts/tbrun.mjs [--port N] [--arch win32|win64] [--timeout S] [--quiet MS] [--json] [--raw] [--keep] [--no-reap] [--reap-images a,b] [--show|--hide] - [--llvm | --compiler-options S] [--exe | --tests] [--allow-name-clash] + [--llvm | --compiler-options S] [--exe | --tests] Builds a probe project and captures what it writes to the IDE's [Debug Console](../../tB/IDE/Debugging/Debug-Console). Where [`tbbuild.mjs`](#tbbuild) answers @@ -102,8 +102,7 @@ with `[LINKER]` lines. The script warns when a probe omits it, and when there is `[RunAfterBuild]` at all. **A build that fails after a clean compile is a failed run**, with the IDE's build log printed -as the reason: `[BUILD] failed`, often after `[TYPELIB] failed to finalize typelibrary`. The -probe never runs. Run it again: such a failure can pass on a second run. +as the reason: `[BUILD] failed`. The probe never runs. Code generation failures are failed runs too: @@ -129,11 +128,6 @@ file. A probe that leaves a form loaded has returned too, and `tbrun` prints the is one of several marked --- and the check is then off. A probe that stays silent for longer than `--quiet` also ends the wait without the marker, so raise `--quiet` for a slow one. -**On a build before BETA 1005, a probe whose module holds a procedure named like the module is -refused, exit 2**, before an IDE starts. Those builds silently skip the `[RunAfterBuild]` Sub of -such a module, whatever the letter case or modifiers of the procedure. Rename the module or the -procedure, or use BETA 1005 or later. `--allow-name-clash` runs the probe anyway. - **The capture is complete however much a probe prints.** `tbrun` reads the console's backing array, not the pane, which is a virtualised list holding only the rows that fit. `Debug.Cls` is what empties the array, which is the other reason to begin with it. @@ -186,7 +180,6 @@ A defect that is a compile-time diagnostic is a **compile case** instead: a line | `--compiler-options ` | The project's compiler options, for the run and the exe. | | `--exe` | Also run the built exe; print what it writes with `TbRun.Out`, its exit code, the fault the event log records for it, and the boxes it opened, each closed with OK. | | `--tests` | Build nothing: judge the compile cases and run each `[TestCase]` Sub in the compiler's test mode, printing `PASS` or `FAIL` for each. `--timeout` is the limit on each case. Not with `--exe`. | -| `--allow-name-clash` | On a build before BETA 1005, run a probe whose module holds a procedure named like the module. Those builds skip its `[RunAfterBuild]` Sub, so the run exits 5. | | `--raw` | Keep the console's timestamp column, which is otherwise stripped. | | `--json` | One object with the path of the built file, the target, the captured lines, whether the probe returned, the licence an LLVM run checked, the exe's run, the IDE pid and anything reaped. | | `--keep` | Leave the IDE running and print its pid as `ide-pid: ` (with `--json`, `idePid`) and the `taskkill` commands, as for `tbbuild`. Implies `--no-reap`, and leaves the IDE's registry entries for the probe as they are. | @@ -218,32 +211,6 @@ not make later runs on the same port build 64-bit. Exit codes: **0** the probe ran and its output was captured; **1** the project has compile errors (the diagnostics are printed); **2** a refused command line (a source folder that is missing or has no `Settings` file included), no IDE, an IDE that did not start, a compile that never settled, a build that failed after a clean compile, a probe that never ran or stopped at a procedure that failed code generation, an LLVM run on a Community or Personal licence, an `--exe` run with no exe built, `--tests` on a project with no case or with a `[TestCase]` it cannot call (one with parameters, a **Function**, or one outside a `[TestFixture]` module), or a crash; **3** no output: the console held none before the timeout, or the probe printed none after its last `Debug.Cls`; **4** the compiler crashed, or restarted twice, while compiling the project; **5** the probe ended before it returned, its output printed all the same; **6** under `--exe`, the exe exited with a code other than 0, the Application event log records that it faulted, it opened a box (which `tbrun` closed), or it was still running after `--timeout` and was ended, its output, exit code, fault and boxes printed all the same; **7** under `--tests`, a case failed, every case's line printed all the same. A run that would exit 5 exits 5 whatever the exe did. -## probe_shared_temp.mjs -{: #probe-shared-temp } - - node scripts/probe_shared_temp.mjs [--ides N] [--rounds R] [--control] [--all] - [--ide ] [--port N] [--timeout S] - -Counts the builds that fail to write the type library when several IDEs build at once in one `TEMP` folder. It is the measurement behind the entry of `BUGS-TO-REPORT.md` whose reproducer is `bugs/concurrent-builds-shared-temp/`. Such a build ends with `[TYPELIB] failed to finalize typelibrary. Disk error?`, then `[LINKER] FAILED to create type library` and `[BUILD] failed`. Like [`tbbuild.mjs`](#tbbuild), it needs a twinBASIC install and Windows, and it is outside every gate and outside CI. - -Each round starts `--ides` IDEs at once, each on its own port with its own copy of the reproducer's project under `%TEMP%\tbprobe-shared-temp\`. Each compiles, waits for the others, and then builds, so Build is pressed in all of them at about the same moment. A build whose log holds a `[TYPELIB] failed` line or `FAILED to create type library` counts as a failure. Any other failed build ends the probe with exit 2. - -All the IDEs share one `TEMP` folder, made for the run and deleted afterwards, set through the `env` option of `launchIde`; [`tbbuild.mjs`](#tbbuild) gives each IDE its own. With `--control` the probe keeps those per-IDE folders, which is the reproducer's control. - -| Flag | Effect | -|---|---| -| `--ides ` | IDEs at once. Default 8. | -| `--rounds ` | Rounds, one build in each IDE. Default 24. | -| `--control` | Give each IDE a `TEMP` folder of its own. No build is expected to fail. | -| `--all` | Run every round. By default the probe stops after the first round in which a type library fails. | -| `--ide ` | Path to `twinBASIC.exe`, found as for `tbbuild`. | -| `--port ` | The first DevTools port to try. Default 9760. The IDEs take the first free ports from it. | -| `--timeout ` | The wait for a compile to settle, and again for a build. Default 180. | - -The output is one `round : failed` line for each round, the last console lines of every build that failed, and a last line of the form ` of builds failed to write the type library (TEMP shared)`, or `(TEMP per IDE)` under `--control`. Other work on the machine, such as lanes of [`addin_test.mjs`](Tools-IDE#addin-test) or [`ide_test.mjs`](Tools-IDE#ide-test), loads the same processor, so a run on a busy machine is not comparable with one on a quiet machine. - -Exit codes: **0** no build failed to write the type library; **1** at least one did, so the defect is there; **2** a refused command line, no IDE, no free ports, an IDE that did not start, a project that did not compile, a build that failed in some other way, or a crash. - ## probe_build_twice.mjs {: #probe-build-twice } @@ -308,7 +275,7 @@ the CI runners lack. Run it by hand after changing `tb-registry.mjs`. Exit codes: **0** every assertion held, **1** an assertion failed, **2** the test could not run to its end: a refused command line, PowerShell failing, or a crash. -## impexp.mjs and impexp.py +## impexp.mjs, impexp.py and impexp {: #impexp } node scripts/impexp.mjs export [--overwrite] @@ -316,10 +283,23 @@ Exit codes: **0** every assertion held, **1** an assertion failed, **2** the tes node scripts/impexp.mjs settings|licence|changelog|readme node scripts/impexp.mjs --self-test -Standalone `.twinproj` / `.twinpack` unpacker and packer, with the compiler executable's own command line: the same six commands, the project file first, and `--overwrite` required to replace anything. `scripts/impexp.py` is the same tool, run as `python scripts/impexp.py ...`. The two editions print the same output and write byte-identical project files, which [`check_impexp_parity.mjs`](Tools-Toolchain-Tests#check-impexp-parity) checks. Neither has dependencies; the Node edition needs Node 18+, the Python edition Python 3.6+. `--self-test` needs only the script, and adds a round trip of `indexer/sample.twinpack` when run from this repository. +Standalone `.twinproj` / `.twinpack` unpacker and packer, with the compiler executable's own command line: the same six commands, the project file first, and `--overwrite` required to replace anything. `scripts/impexp.py` is the same tool, run as `python scripts/impexp.py ...`, and `scripts/impexp/` is a third edition, a twinBASIC console program that runs as `impexp_win32.exe ...`. The three editions print the same output, give the same exit codes and write byte-identical project files, which [`check_impexp_parity.mjs`](Tools-Toolchain-Tests#check-impexp-parity) checks. The Node edition needs Node 18+ and the Python edition Python 3.6+; the twinBASIC edition needs Windows and nothing else at run time, and reads and writes its paths as Unicode. None has dependencies. `--self-test` needs only the program, runs the same 20 tests in all three, and adds a round trip of `indexer/sample.twinpack` when it can find that file: the Node and Python editions look in `indexer/` beside their own `scripts/` folder, and the twinBASIC edition in each folder above the exe, then in each folder above the current folder. + +The twinBASIC edition exists for readers who have twinBASIC and neither Node nor Python. It is laid out as [`imagestrip`](Tools-IDE#imagestrip) is: `scripts/impexp/src/` is an exported project tree, and `scripts/impexp/impexp.twinproj` is the project file packed from it, which opens in the IDE. Both are checked out byte for byte (`.gitattributes`). After a change to `src/`, pack it again: + + node scripts/impexp.mjs import scripts/impexp/impexp.twinproj scripts/impexp/src --overwrite + +Build it in the IDE, which writes `Build\impexp_win32.exe` beside the project file (git ignores it), or with [`tbbuild.mjs`](#tbbuild), which builds in a private folder and prints the path: + + node scripts/tbbuild.mjs scripts/impexp/impexp.twinproj --build + +No gate can build it, so `check_impexp_parity.mjs` compares it only when `IMPEXP_EXE` names the built exe, and CI never sets that: + + set IMPEXP_EXE= + node scripts/check_impexp_parity.mjs -**Neither is run as a command by the site build.** They are published downloads: `_config.yml`'s `bundle_extra` copies both into `Features/Packages/downloads/` for [Import/Export Tool](../../Features/Packages/Import-Export-Tool). The `bundle_extra` exemption is by exact path, so moving either file breaks the download; see [`check_publish_policy.mjs`](Tools-Toolchain-Tests#check-publish-policy). +**None of them is run as a command by the site build.** They are published downloads: `_config.yml`'s `bundle_extra` copies the Node and Python scripts and the twinBASIC project file into `Features/Packages/downloads/` for [Import/Export Tool](../../Features/Packages/Import-Export-Tool). The `bundle_extra` exemption is by exact path, so moving any of the three files breaks the download; see [`check_publish_policy.mjs`](Tools-Toolchain-Tests#check-publish-policy). The Node edition is also a library. `scripts/lib/tb-project.mjs` imports its `exportProject` and `importProject`, which every tool that unpacks or packs a project calls, among them [`tbbuild.mjs`](#tbbuild), [`tbrun.mjs`](#tbrun), [`check_examples.mjs`](Tools-Samples#check-examples), [`census_attributes.mjs`](Tools-Samples#census-attributes) and [`bug_repro.mjs`](Tools-Defects#bug-repro). The site build imports `importProject` too, to pack the [help add-in's project file](Tools-Build#the-help-add-ins-project-file). `impexp.mjs` is the one module under `scripts/` that `builder/` may import (`biome.jsonc` refuses any other), so [`check_tree_fresh.mjs`](Tools-Site-Checks#check-tree-fresh) watches it. -Exit codes: the table in [Import/Export Tool](../../Features/Packages/Import-Export-Tool#checking-the-result) gives every code. The two editions share these codes, which differ from those of the other tools here. +Exit codes: the table in [Import/Export Tool](../../Features/Packages/Import-Export-Tool#checking-the-result) gives every code. The three editions share these codes, which differ from those of the other tools here. diff --git a/docs/Documentation/Tools-IDE.md b/docs/Documentation/Tools-IDE.md index 1a8b9f265..67ecc4efa 100644 --- a/docs/Documentation/Tools-IDE.md +++ b/docs/Documentation/Tools-IDE.md @@ -189,7 +189,7 @@ Exit codes: **0** every picture was drawn again; **1** a picture needs a retake, imagestrip_win32.exe -A twinBASIC console program, and the one tool under `scripts/` that is not Node. It writes a copy of a CSS file or an SVG file in which every image embedded as a `data:` URI keeps its pixels and any notice of whose it is, and nothing else. An SVG file also loses what only its editor needs, and so does an SVG embedded in either, whose own images are stripped in turn, at any depth. A file whose name ends in `.svg` is read as an SVG, any other as CSS. +A twinBASIC console program, and one of two under `scripts/` that are not Node or Python (the other is the twinBASIC edition of [`impexp`](Tools-Compiler#impexp)). It writes a copy of a CSS file or an SVG file in which every image embedded as a `data:` URI keeps its pixels and any notice of whose it is, and nothing else. An SVG file also loses what only its editor needs, and so does an SVG embedded in either, whose own images are stripped in turn, at any depth. A file whose name ends in `.svg` is read as an SVG, any other as CSS. It is for the twinBASIC IDE's own stylesheets, `styles.css`, `formDesigner.css` and the others in an install's `ide` folder, and for the twinBASIC developers to run in their build, which has twinBASIC and need not have Node. The icons in those stylesheets carry their editors' metadata (GIMP's EXIF, IPTC and XMP profiles, CorelDRAW's and Illustrator's comments) around a few hundred bytes of pixels. One icon, a lock from fileformat.info, has a CC BY-NC-SA attribution that must stay with it. diff --git a/docs/Documentation/Tools-Samples.md b/docs/Documentation/Tools-Samples.md index 1593f5bdd..154b237c9 100644 --- a/docs/Documentation/Tools-Samples.md +++ b/docs/Documentation/Tools-Samples.md @@ -72,7 +72,7 @@ A build refuses three things a compile accepts, so batches are arranged around t - a sample or group that declares its own `Sub Main` gets a project of its own without the template's `Main`, because two make the startup object ambiguous; - two samples that export one `[DllExport]` name are kept in different projects. -**A sample can be run.** A statement sample marked `check_run` is built and run in every mode, and what it prints is compared with what the page says it prints: a trailing comment on a `Debug.Print` line, or the comment lines under an `' Output:` line ([Authoring Pages](Authoring#checking-that-a-sample-compiles) has the markup). A project may have only one `[RunAfterBuild]` Sub (TB5114), so run samples are batched apart from the rest. Each run batch gets one generated `Module tbxRun` whose `[RunAfterBuild]` Sub calls each sample's body in turn. It prints a marker line before and after each call, and an `On Error GoTo` handler around each call keeps one sample's error from ending the rest. +**A sample can be run.** A statement sample marked `check_run` is built and run in every mode, and what it prints is compared with what the page says it prints: a trailing comment on a `Debug.Print` line, up to a ` -- ` that starts a note, or the comment lines under an `' Output:` line ([Authoring Pages](Authoring#checking-that-a-sample-compiles) has the markup). A project may have only one `[RunAfterBuild]` Sub (TB5114), so run samples are batched apart from the rest. Each run batch gets one generated `Module tbxRun` whose `[RunAfterBuild]` Sub calls each sample's body in turn. It prints a marker line before and after each call, and an `On Error GoTo` handler around each call keeps one sample's error from ending the rest. The handler is reached only by an error the sample does not handle itself, so a sample can demonstrate an error under its own `On Error Resume Next` and print `Err.Number`. (Checking `Err.Number` after the call could not tell the two apart: a procedure that handles an error with `On Error Resume Next` returns with `Err` still set, in VB6 and in twinBASIC alike.) @@ -162,7 +162,7 @@ Exit codes: **0** the probe project and the key were written, **2** a refused co Reports, for every attribute the twinBASIC packages use, **which enclosing construct and which kind of declaration it decorates**. It unpacks each package of an IDE install with [`impexp.mjs`](Tools-Compiler#impexp), scans the `.twin` sources, and writes a Markdown or JSON report. No arguments are needed: it finds the newest `twinBASIC_IDE_BETA_*` as [`tbbuild.mjs`](Tools-Compiler#tbbuild) does and caches the export under the build number. It is not part of the site build. -Against BETA 995 that is 661 files, 9,713 attribute sites and 55 distinct attributes. +Against BETA 1005 that is 661 files, 9,744 attribute sites and 55 distinct attributes. **A census is evidence, not applicability.** It says where an attribute *is* used, never where it *may* be used, and the two differ in both directions. The packages contain no use of `[Hidden]` on a whole **Class**, yet the compiler accepts one. They contain many on **Class** and **Interface** members, yet the compiler refuses the same attribute on the **Interface** lines inside a **CoClass**. To find out what the compiler accepts, use [`gen_attribute_probes.mjs`](#gen-attribute-probes) and [`tbbuild.mjs`](Tools-Compiler#tbbuild), which ask it directly. @@ -197,7 +197,7 @@ Asks the compiler where every attribute is legal. It writes each attribute name It exists because the older tools leave a gap. [`census_attributes.mjs`](#census-attributes) says where the shipped packages *use* an attribute, and [`gen_attribute_probes.mjs`](#gen-attribute-probes) probes only the targets the page already *claims*: a line checked against only a Sub and a Const says nothing about an API `Declare`. This tool asks every question, so a missing target shows up as a row of the report. -The names come from every entry in `Attributes.md`, every name in the compiler's own token table (a pipe-separated string in the compiler binary, holding keywords, attributes and object members together), and `--names`. A token-table name is a *candidate*: it is an attribute only if some site accepts it. `Debug` and `ExecuteHostCommand` are in the table and neither is one. +The names come from every entry in `Attributes.md`, every name in the compiler's own token table (a pipe-separated string in the compiler binary, holding keywords, attributes and object members together), and `--names`. A token-table name is a *candidate*: it is an attribute only if some site accepts it. `Debug` is in the table and is not one. **How an answer is made readable.** A clean build is not proof by itself, so the tool guards against the ways one goes wrong: diff --git a/docs/Documentation/Tools-Toolchain-Tests.md b/docs/Documentation/Tools-Toolchain-Tests.md index ba8db5cf8..0d2ca17cd 100644 --- a/docs/Documentation/Tools-Toolchain-Tests.md +++ b/docs/Documentation/Tools-Toolchain-Tests.md @@ -473,13 +473,18 @@ Exit codes: **0** the shims write what stock pdf-lib writes, and every shim and node scripts/check_impexp_parity.mjs -Verifies that the two editions of the [impexp tool](Tools-Compiler#impexp), `scripts/impexp.mjs` and `scripts/impexp.py`, behave the same, as that section promises. Both `--self-test` suites must pass, with the same test names in the same order. Then one sequence of commands runs through each edition, each in a scratch folder of its own holding copies of `indexer/sample.twinpack` and `test/example-projects/console`: export and import, the printing commands, and each refusal, failure and warning the exit codes name. +Verifies that the editions of the [impexp tool](Tools-Compiler#impexp) behave the same, as that section promises: `scripts/impexp.mjs`, `scripts/impexp.py` and, when it is named, the built exe of the twinBASIC edition, `scripts/impexp/`. Every `--self-test` suite must pass, with the same test names in the same order. Then one sequence of commands runs through each edition, each in a scratch folder of its own holding copies of `indexer/sample.twinpack` and `test/example-projects/console`: export and import, the printing commands, and each refusal, failure and warning the exit codes name. -After every command, both editions must give the exit code the command is there for, print the same on each stream, and leave the same files, compared as bytes. On Windows, Python writes CRLF to the console, so a CRLF in the printed output is read as LF on both sides; on Linux, as in CI, the output is compared as written. About four seconds, most of it Python starting once per command. +After every command, every edition must give the exit code the command is there for, print the same on each stream, and leave the same files, compared as bytes. On Windows, Python writes CRLF to the console, so a CRLF in the printed output is read as LF in every edition; on Linux, as in CI, the output is compared as written. About four seconds for the two scripts, most of it Python starting once per command. -Without Python 3.6 or later on the `PATH` (it tries `python3`, then `python`, then `py -3` on Windows), the gate prints `SKIPPED` and exits 0, so `test.bat` passes on a machine without Python. When `CI` is `true`, as GitHub sets it, the same case fails instead: CI must compare the two. +**The twinBASIC edition is compared only when `IMPEXP_EXE` names its built exe**, on Windows, because no gate can build it, as none can build [`imagestrip`](Tools-IDE#imagestrip). The exe runs in the scratch folder of each command, on a private desktop of its own through `launchOnDesktop`, so it cannot open anything on the desktop in use; a message box it opens counts as a difference. CI never sets the variable. With it, a run takes about 30 seconds. -Exit codes: **0** the two editions agree, or the check was skipped because no Python was found; **1** the editions differ, or a built-in test failed; **2** the check could not run: a refused command line, no Python when `CI=true`, or a crash. + set IMPEXP_EXE= + node scripts/check_impexp_parity.mjs + +Without Python 3.6 or later on the `PATH` (it tries `python3`, then `python`, then `py -3` on Windows), the gate prints `SKIPPED` and exits 0, so `test.bat` passes on a machine without Python. When `CI` is `true`, as GitHub sets it, the same case fails instead: CI must compare the two scripts. With `IMPEXP_EXE` set and no Python outside CI, the gate compares `impexp.mjs` with the exe and reports that `impexp.py` was not compared. + +Exit codes: **0** the editions agree, or the check was skipped because no Python was found; **1** the editions differ, or a built-in test failed; **2** the check could not run: a refused command line, no Python when `CI=true`, an `IMPEXP_EXE` that is not a file or is set off Windows, or a crash. ## check_axe_patch_equiv.mjs {: #check-axe-patch-equiv } diff --git a/docs/Documentation/Tools.md b/docs/Documentation/Tools.md index 9ee29b56d..8c90eddcf 100644 --- a/docs/Documentation/Tools.md +++ b/docs/Documentation/Tools.md @@ -10,7 +10,7 @@ permalink: /Documentation/Development/Tools # Tools and Scripts {: .no_toc } -Reference for every executable in the documentation repository. This page covers the nine Windows batch wrappers at the repository root, the conventions every command-line tool shares, and the configuration files the tools read. The tools themselves --- the Node and Python scripts under `scripts/`, the twinBASIC program [`imagestrip`](Tools-IDE#imagestrip), `tbdocs` and its flags, and the PDF render driver --- are on seven pages, grouped by what they work on. For the day-to-day workflow, see [Building and Deployment](Building). To modify the build pipeline, see [tbdocs Internals](Builder). +Reference for every executable in the documentation repository. This page covers the nine Windows batch wrappers at the repository root, the conventions every command-line tool shares, and the configuration files the tools read. The tools themselves --- the Node and Python scripts under `scripts/`, the twinBASIC programs [`imagestrip`](Tools-IDE#imagestrip) and [`impexp`](Tools-Compiler#impexp), `tbdocs` and its flags, and the PDF render driver --- are on seven pages, grouped by what they work on. For the day-to-day workflow, see [Building and Deployment](Building). To modify the build pipeline, see [tbdocs Internals](Builder). * TOC goes here {:toc} @@ -54,6 +54,8 @@ All ten sit at the repository root, beside `package.json`. Each uses `@pushd "%~ - [`census_attributes.mjs`](Tools-Samples#census-attributes) unpacks the packages of a twinBASIC install. It is cross-platform when given an already-exported tree with `--exported`. - [`imagestrip`](Tools-IDE#imagestrip) is a twinBASIC program. +The twinBASIC edition of [`impexp`](Tools-Compiler#impexp) is a Windows program too. Built, it needs no twinBASIC install, Node or Python to run. + `tbdocs` and every gate in both wrappers is a Node script. CI runs all of them on `ubuntu-latest` except [`check_tree_fresh.mjs`](Tools-Site-Checks#check-tree-fresh), which guards against a failure CI cannot have. ### build.bat @@ -136,7 +138,7 @@ The tests the toolchain has to pass. Twenty-six steps, each stopping the run if 22. [`scripts/check_attribute_sweep.mjs`](Tools-Toolchain-Tests#check-attribute-sweep) --- verifies the logic of the attribute sweep: its site skeletons, how it reads a probe's diagnostics, how it batches probes, and how it compares the answers with `Attributes.md`. 23. [`scripts/check_cli.mjs`](Tools-Toolchain-Tests#check-cli) --- verifies `lib/cli.mjs`, the command-line parser, and each tool's recorded command-line errors. 24. [`scripts/check_pdf_shims_equiv.mjs`](Tools-Toolchain-Tests#check-pdf-shims-equiv) --- verifies the book's pdf-lib shims write what stock pdf-lib writes, patch the members of pdf-lib it lists, have each of them in their shim's table of targets, and run. -25. [`scripts/check_impexp_parity.mjs`](Tools-Toolchain-Tests#check-impexp-parity) --- verifies the two editions of the impexp tool pass the same built-in tests, and exit, print and write the same for one sequence of commands. Without Python it reports itself skipped and passes, except in CI. +25. [`scripts/check_impexp_parity.mjs`](Tools-Toolchain-Tests#check-impexp-parity) --- verifies the editions of the impexp tool pass the same built-in tests, and exit, print and write the same for one sequence of commands. Without Python it reports itself skipped and passes, except in CI. It compares the twinBASIC edition too, when `IMPEXP_EXE` names its built exe. 26. [`scripts/check_axe_patch_equiv.mjs`](Tools-Toolchain-Tests#check-axe-patch-equiv) --- verifies the vendored axe source patch still produces identical colour values. POSIX: diff --git a/docs/Documentation/index.md b/docs/Documentation/index.md index 2cbe1e292..4653bbfa3 100644 --- a/docs/Documentation/index.md +++ b/docs/Documentation/index.md @@ -36,6 +36,7 @@ A `build.bat` run executes `tbdocs` against a shared task graph. Workers and the - [Permanent Links](Development/Permanent-Links) --- the stable `/tB/` URL contract under which the IDE help system and external references resolve. - [Authoring Pages](Development/Authoring) --- how to write or edit a page so it matches the rest of the site: frontmatter and permalinks, heading levels, formatting, plain-English prose, attribution, and cross-section links. - [Building and Deployment](Development/Building) --- the day-to-day workflow for editing content: requirements, building, serving locally, link checking, Graphviz diagrams, screenshots, and the GitHub Pages deployment. +- [Updating a Contributed Package](Development/Contributed-Packages) --- the steps that bring a contributed package's section up to a new version of the package: its snapshot, pages, samples and test cases, and the runs that check them. - [Tools and Scripts](Development/Tools) --- reference for every script, batch file, and CLI flag exposed by the documentation toolchain, on a landing page for the batch wrappers and seven pages of tools grouped by what they work on (intended audience: doc contributors). - [tbdocs Builder](Development/Builder) --- detailed technical documentation for the `tbdocs` static site generator that lives under [`builder/`](https://github.com/twinbasic/documentation/tree/main/builder). Read this when modifying the build pipeline itself. Sub-pages: - [Pipeline Stages](Development/Pipeline-Stages) --- complete interface reference: per-task signatures and per-module export tables, plus the scheduler-level concepts (flag bits, task lifecycle, SAB layout). diff --git a/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.light.svg b/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.light.svg index a5c931ec3..543bdb026 100644 --- a/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.light.svg +++ b/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.light.svg @@ -1 +1 @@ -MiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdTB0001    Use of legacy DefType statements is strongly discouragedTB0002    This variable has been auto-declared by the compiler due to Option Explicit being OFFTB0003    Datatype has not been explicitly declared so will default to VariantTB0004    [Exit Sub/Function] inside a Property-Get procedure is only supported for backwards compatibility. Use [Exit Property] instead.TB0005    #Warning directive was encounteredTB0006    Record length is ignored in binary modeTB0007    Mismatched datatype hintTB0008    Suspicious callTB0009    Member is unimplementedTB0010    Duplicate DLL declaration detectedTB0011    Use of legacy date/time property-let assignments are strongly discouragedTB0012    Possible misuse of hexadecimal literal notationTB0013    It is strongly recommended to specify an [ InterfaceId() ] attribute for this classTB0014    The inline ByVal attribute is ignored on User Defined TypesTB0015    Use of legacy DLL {LEGACY.DLL} has been redirected to {MODERN.DLL}TB0016    Implicit creation of variable via ReDimWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGHINTWARNINGWARNING +MiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdTB0001    Use of legacy DefType statements is strongly discouragedTB0002    This variable has been auto-declared by the compiler due to Option Explicit being OFFTB0003    Datatype has not been explicitly declared so will default to VariantTB0004    [Exit Sub/Function] inside a Property-Get procedure is only supported for backwards compatibility. Use [Exit Property] instead.TB0005    #Warning directive was encounteredTB0006    Record length is ignored in binary modeTB0007    Mismatched datatype hintTB0008    Suspicious callTB0009    Member is unimplementedTB0010    Duplicate DLL declaration detectedTB0011    Use of legacy date/time property-let assignments are strongly discouragedTB0012    Possible misuse of hexadecimal literal notationTB0013    It is strongly recommended to specify an [ InterfaceId() ] attribute for this classTB0014    The inline ByVal attribute is ignored on User Defined TypesTB0015    Use of legacy DLL {LEGACY.DLL} has been redirected to {MODERN.DLL}TB0016    Implicit creation of variable via ReDimWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGHINTWARNINGWARNING diff --git a/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.light.png b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.light.png index 05386a151..3d624bf97 100644 Binary files a/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.light.png and b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.light.png differ diff --git a/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png index 38f4944b7..3adeebdf8 100644 Binary files a/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png and b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png differ diff --git a/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.light.png b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.light.png index 8c68d27ab..8021a8277 100644 Binary files a/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.light.png and b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.light.png differ diff --git a/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png index ab81011da..b882c3f3b 100644 Binary files a/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png and b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png differ diff --git a/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.light.png b/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.light.png index 0417f563f..55c6d5ed1 100644 Binary files a/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.light.png and b/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.light.png differ diff --git a/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.light.png b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.light.png index 0027957b2..037617740 100644 Binary files a/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.light.png and b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.light.png differ diff --git a/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png index 4a2913791..4f0a74cf1 100644 Binary files a/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png and b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png differ diff --git a/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.light.png b/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.light.png index f02c9353b..8fba10511 100644 Binary files a/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.light.png and b/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.light.png differ diff --git a/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.png b/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.png index e8aab19f5..53f1d854c 100644 Binary files a/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.png and b/docs/Features/Images/569099635-bc9553a6-fcce-487d-a478-dbee557f33b1.png differ diff --git a/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.png b/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.png index 2cf5512cd..bb7d705d3 100644 Binary files a/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.png and b/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.png differ diff --git a/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.svg b/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.svg index 78996c442..0ca5181d5 100644 --- a/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.svg +++ b/docs/Features/Images/569150839-9ffc87ac-250d-40a4-bb47-669b607ad76f.light.svg @@ -1 +1 @@ -EDITOR 1PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdProject Settingsî©¶Use Project ID for type library IDIf YES, the compiler will use the project ID for the type library ID. If NO, a unique type library ID will be generated during the build process.Build Output PathEnter the full path to the output file that will be created by the compiler. Available variables: ${SourcePath}, ${ProjectName}, ${ProjectID},${FileExtension}, ${Architecture}, ${VersionMajor}, ${VersionMinor}, ${VersionBuild}, ${VersionRevision}${Architecture} == "win32" / "win64"ActiveX Fusion Host EXEOutput PathEnter the full path to the output file that will be created by the compiler for the ActiveX Fusion host companion EXE. Available variables:${SourcePath}, ${ProjectName}, ${ProjectID}, ${FileExtension}, ${Architecture}, ${VersionMajor}, ${VersionMinor}, ${VersionBuild},${VersionRevision}${Architecture} == "win32host" / "win64host"If not specified, the template set for `Build Output Path` will be used when necessary.PLEASE NOTEThe runtime location of this file (for built executables) should be the same folder as the root project EXE, otherwise you must override theexpected folder path by setting App.FusionHostExePath during your startup routine.TB0019    Implicit enumeration conversionTB0020    Suspicious interface conversionTB0021    Implicit enumeration conversion to/from numericTB0022    Suspicious assignment (e.g. array subtype mismatch)TB0023    Unusual use of implicit field generated from an Implements statementTB0024    Unused local variableTB0025    Unused procedure parameterTB0026    Mismatched delegate typesTB0027    Return Without GosubTB0028    Control is overshadowed by base form method or property of the same nameTB0029    Missing PtrSafe syntax on API Declares for VBA7 compatibilityTB0030    Declare Alias is not required as it is identical to the declared nameTB0031    Suspicious use of Erase statementTB0032    Unused line labelTB0032    Duplicate definition, consider changing the name to be uniqueIGNOREIGNOREIGNOREIGNOREWARNINGWARNINGIGNOREIGNOREWARNINGWARNINGWARNINGIGNOREHINTWARNINGWARNINGWARNINGCOMPILER DEFAULT - No${SourcePath}\Build\${ProjectName}_${Architecture}.${FileExtension}Package TWINPACK(enter text to filter) +EDITOR 1PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdProject Settingsî©¶Use Project ID for type library IDIf YES, the compiler will use the project ID for the type library ID. If NO, a unique type library ID will be generated during the build process.Build Output PathEnter the full path to the output file that will be created by the compiler. Available variables: ${SourcePath}, ${ProjectName}, ${ProjectID},${FileExtension}, ${Architecture}, ${VersionMajor}, ${VersionMinor}, ${VersionBuild}, ${VersionRevision}${Architecture} == "win32" / "win64"ActiveX Fusion Host EXEOutput PathEnter the full path to the output file that will be created by the compiler for the ActiveX Fusion host companion EXE. Available variables:${SourcePath}, ${ProjectName}, ${ProjectID}, ${FileExtension}, ${Architecture}, ${VersionMajor}, ${VersionMinor}, ${VersionBuild},${VersionRevision}${Architecture} == "win32host" / "win64host"If not specified, the template set for `Build Output Path` will be used when necessary.PLEASE NOTEThe runtime location of this file (for built executables) should be the same folder as the root project EXE, otherwise you must override theexpected folder path by setting App.FusionHostExePath during your startup routine.TB0019    Implicit enumeration conversionTB0020    Suspicious interface conversionTB0021    Implicit enumeration conversion to/from numericTB0022    Suspicious assignment (e.g. array subtype mismatch)TB0023    Unusual use of implicit field generated from an Implements statementTB0024    Unused local variableTB0025    Unused procedure parameterTB0026    Mismatched delegate typesTB0027    Return Without GosubTB0028    Control is overshadowed by base form method or property of the same nameTB0029    Missing PtrSafe syntax on API Declares for VBA7 compatibilityTB0030    Declare Alias is not required as it is identical to the declared nameTB0031    Suspicious use of Erase statementTB0032    Unused line labelTB0032    Duplicate definition, consider changing the name to be uniqueIGNOREIGNOREIGNOREIGNOREWARNINGWARNINGIGNOREIGNOREWARNINGWARNINGWARNINGIGNOREHINTWARNINGWARNINGWARNINGCOMPILER DEFAULT - No${SourcePath}\Build\${ProjectName}_${Architecture}.${FileExtension}Package TWINPACK(enter text to filter) diff --git a/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png b/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png index 26a301082..7a3c27eb2 100644 Binary files a/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png and b/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png differ diff --git a/docs/Features/Images/IDE-FeatureMap.light.png b/docs/Features/Images/IDE-FeatureMap.light.png index 7e1f0f025..bf5ca3628 100644 Binary files a/docs/Features/Images/IDE-FeatureMap.light.png and b/docs/Features/Images/IDE-FeatureMap.light.png differ diff --git a/docs/Features/Images/IDE-FeatureMap.png b/docs/Features/Images/IDE-FeatureMap.png index 5364d7952..0872d21e8 100644 Binary files a/docs/Features/Images/IDE-FeatureMap.png and b/docs/Features/Images/IDE-FeatureMap.png differ diff --git a/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.light.png b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.light.png index c8ae58f9b..056da57df 100644 Binary files a/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.light.png and b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.light.png differ diff --git a/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png index dd22789de..06e00f4cd 100644 Binary files a/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png and b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png differ diff --git a/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.light.png b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.light.png index a9eac963d..b1a613d59 100644 Binary files a/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.light.png and b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.light.png differ diff --git a/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png index 114065672..5b35075c9 100644 Binary files a/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png and b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png differ diff --git a/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.light.png b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.light.png index 46b880fd2..bcf0bfc9c 100644 Binary files a/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.light.png and b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.light.png differ diff --git a/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png index fffede670..5def0d9e8 100644 Binary files a/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png and b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png differ diff --git a/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.light.png b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.light.png index 9eac2b141..da4e56dd6 100644 Binary files a/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.light.png and b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.light.png differ diff --git a/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png index 52fc416db..99fe2224f 100644 Binary files a/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png and b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png differ diff --git a/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.light.png b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.light.png index 4ea014ee7..8e3b68232 100644 Binary files a/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.light.png and b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.light.png differ diff --git a/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png index 8a772fdcc..ba0cd072a 100644 Binary files a/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png and b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png differ diff --git a/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.light.png b/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.light.png index 9e916fc25..8a4974cda 100644 Binary files a/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.light.png and b/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.light.png differ diff --git a/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png b/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png index e3c390ecd..aa52f5769 100644 Binary files a/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png and b/docs/Features/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png differ diff --git a/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.light.png b/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.light.png index c5b3279b5..de6ece767 100644 Binary files a/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.light.png and b/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.light.png differ diff --git a/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png b/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png index 64693cdbd..b56d6c888 100644 Binary files a/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png and b/docs/Features/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png differ diff --git a/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.light.png b/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.light.png index d8eb10c20..4c14b5534 100644 Binary files a/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.light.png and b/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.light.png differ diff --git a/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.png b/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.png index a5ea7b30b..90f391d7c 100644 Binary files a/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.png and b/docs/Features/Packages/Images/8cf72685-1188-4607-a55a-df16d4280474.png differ diff --git a/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.light.png b/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.light.png index 66a4164a7..d81616245 100644 Binary files a/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.light.png and b/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.light.png differ diff --git a/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png b/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png index f9ee426e9..8d60cd9f6 100644 Binary files a/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png and b/docs/Features/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png differ diff --git a/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.light.png b/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.light.png index 00553982f..d975bb747 100644 Binary files a/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.light.png and b/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.light.png differ diff --git a/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png b/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png index 82fea01de..c44be3254 100644 Binary files a/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png and b/docs/Features/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png differ diff --git a/docs/Features/Packages/Images/LibrarySymbols.light.png b/docs/Features/Packages/Images/LibrarySymbols.light.png index b12222920..581cd76ba 100644 Binary files a/docs/Features/Packages/Images/LibrarySymbols.light.png and b/docs/Features/Packages/Images/LibrarySymbols.light.png differ diff --git a/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.light.png b/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.light.png index 49c424d96..d673ffa38 100644 Binary files a/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.light.png and b/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.light.png differ diff --git a/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png b/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png index e7734b197..3c8ce6729 100644 Binary files a/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png and b/docs/Features/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png differ diff --git a/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.light.png b/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.light.png index fe9615691..e43b4fe33 100644 Binary files a/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.light.png and b/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.light.png differ diff --git a/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png b/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png index 0f24c7e28..a53ef5625 100644 Binary files a/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png and b/docs/Features/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png differ diff --git a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.png b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.png index 5e1d8ab38..2783d0816 100644 Binary files a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.png and b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.png differ diff --git a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.svg b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.svg index 49a23f566..d6beae02a 100644 --- a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.svg +++ b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.light.svg @@ -1 +1 @@ -PROPERTIESSelect references that will be used during compilation of this projectâš  TIP: LOGIN to see any PRIVATE packages you've madeImport from file...WinDevLibWinRegWindows Development Library for twinBASIC v9.5.7449.5.744.0WinReg1.0.1.14 +PROPERTIESSelect references that will be used during compilation of this projectâš  TIP: LOGIN to see any PRIVATE packages you've madeImport from file...WinDevLibWinRegWindows Development Library for twinBASIC v9.5.7459.5.745.0WinReg1.0.1.14 diff --git a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png index 7d2edfcaf..6110ffd89 100644 Binary files a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png and b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png differ diff --git a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.svg b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.svg index 6ac6cf701..dc39de43a 100644 --- a/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.svg +++ b/docs/Features/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.svg @@ -1 +1 @@ -PROPERTIESSelect references that will be used during compilation of this projectâš  TIP: LOGIN to see any PRIVATE packages you've madeImport from file...WinDevLibWinRegWindows Development Library for twinBASIC v9.5.7449.5.744.0WinReg1.0.1.14 +PROPERTIESSelect references that will be used during compilation of this projectâš  TIP: LOGIN to see any PRIVATE packages you've madeImport from file...WinDevLibWinRegWindows Development Library for twinBASIC v9.5.7459.5.745.0WinReg1.0.1.14 diff --git a/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.light.png b/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.light.png index d2c454031..0def49262 100644 Binary files a/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.light.png and b/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.light.png differ diff --git a/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png b/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png index 086414cb9..80e21c7fa 100644 Binary files a/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png and b/docs/Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png differ diff --git a/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.light.png b/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.light.png index 73f17a1ff..9bd5bd3be 100644 Binary files a/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.light.png and b/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.light.png differ diff --git a/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.png b/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.png index 65e94ad64..b68e5d719 100644 Binary files a/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.png and b/docs/Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.png differ diff --git a/docs/Features/Packages/Images/packLicenceFiles.light.png b/docs/Features/Packages/Images/packLicenceFiles.light.png index 164d00c76..884acda44 100644 Binary files a/docs/Features/Packages/Images/packLicenceFiles.light.png and b/docs/Features/Packages/Images/packLicenceFiles.light.png differ diff --git a/docs/Features/Packages/Images/packLicenceFiles.png b/docs/Features/Packages/Images/packLicenceFiles.png index df632c2e6..914509223 100644 Binary files a/docs/Features/Packages/Images/packLicenceFiles.png and b/docs/Features/Packages/Images/packLicenceFiles.png differ diff --git a/docs/Features/Packages/Images/packPublishButton.png b/docs/Features/Packages/Images/packPublishButton.png index 541e4301d..807f0051b 100644 Binary files a/docs/Features/Packages/Images/packPublishButton.png and b/docs/Features/Packages/Images/packPublishButton.png differ diff --git a/docs/Features/Packages/Import-export tool.md b/docs/Features/Packages/Import-export tool.md index 11d315128..cf5ae57b8 100644 --- a/docs/Features/Packages/Import-export tool.md +++ b/docs/Features/Packages/Import-export tool.md @@ -12,20 +12,28 @@ Unpacks a `.twinproj` or `.twinpack` file into a folder of source files, and pac back into a project file. Use it to put a project under version control, to edit source outside the IDE, or to see -what a package contains. Two programs do it, and they take the same commands: +what a package contains. Two kinds of program do it, and they take the same commands: - **The tB executable**, `twinBASIC_win32.exe` or `twinBASIC_win64.exe` in the `bin\` folder of a twinBASIC installation. This is the officially supported way to read or write a project file outside the IDE. -- **The standalone script**, in a Node.js edition and a Python edition, which runs on any - platform and needs no twinBASIC installation. It reads and writes the file format itself, - so an IDE update can break it; in return it removes several of the tB executable's - limitations. - -| Runtime | Download | +- **The standalone tool**, in a Node.js edition, a Python edition and a twinBASIC edition. + The Node.js and Python editions run on any platform and need no twinBASIC installation. + The twinBASIC edition is a project that you build in the IDE into a Windows program, for + a machine that has twinBASIC but neither Node.js nor Python. All three read and write the + file format themselves, so an IDE update can break them; in return they remove several + of the tB executable's limitations. + +| Edition | Download | |---------|----------| | Node.js 18+ | impexp.mjs | | Python 3.6+ | impexp.py | +| twinBASIC | impexp.twinproj: open it in the twinBASIC IDE and build it; the program is `impexp_win32.exe` | + +The twinBASIC edition builds into the `Build` folder beside `impexp.twinproj` (see +[**Build**](../../tB/IDE/Reference/Menu/File#build)). It is a console program, and needs +Windows and nothing else when it runs. Where this page says "the script", it means any of the +three editions. > [!WARNING] > @@ -47,9 +55,10 @@ what a package contains. Two programs do it, and they take the same commands: --help ``` -`` is the tB executable, `node impexp.mjs` or `python impexp.py`. `` is a -`.twinproj` or `.twinpack` file, and it always comes first. The verb says what happens to it: -`export` takes source out of the project, and `import` puts source into it. +`` is the tB executable, `node impexp.mjs`, `python impexp.py` or the twinBASIC +edition's `impexp_win32.exe`. `` is a `.twinproj` or `.twinpack` file, and it always +comes first. The verb says what happens to it: `export` takes source out of the project, and +`import` puts source into it. | Command or option | What it does | tB executable | Script | |-------------------|--------------|---------------|--------| @@ -66,6 +75,7 @@ what a package contains. Two programs do it, and they take the same commands: ```batch twinBASIC_win32.exe export "C:\Projects\MyProject.twinproj" "C:\Projects\MyProject\" node impexp.mjs import MyProject.twinproj MyProject --overwrite +impexp_win32.exe import MyProject.twinproj MyProject --overwrite ``` A package is a project file too: every folder under the installation's `packages\` holds one, @@ -103,7 +113,7 @@ message that names only `export` and `import`; given no arguments at all, it doe | | tB executable | Script | |---|---|---| -| Runs on | Windows, with twinBASIC installed | any system with Node.js or Python | +| Runs on | Windows, with twinBASIC installed | any system with Node.js or Python; the twinBASIC edition, Windows | | A `.twinpack` file for `export` or `import` | not accepted, see below | accepted | | A project that embeds a package | `import` fails, see below | packed | | Paths | folders need backslashes, and `export` needs a full path, with backslashes, to the project | any form | diff --git a/docs/IDE/AddIns/Images/GlobalSearch.light.png b/docs/IDE/AddIns/Images/GlobalSearch.light.png index 98a61242a..b15da9940 100644 Binary files a/docs/IDE/AddIns/Images/GlobalSearch.light.png and b/docs/IDE/AddIns/Images/GlobalSearch.light.png differ diff --git a/docs/IDE/AddIns/Images/GlobalSearch.png b/docs/IDE/AddIns/Images/GlobalSearch.png index 7733ae518..814db06b6 100644 Binary files a/docs/IDE/AddIns/Images/GlobalSearch.png and b/docs/IDE/AddIns/Images/GlobalSearch.png differ diff --git a/docs/IDE/AddIns/Images/GlobalSearch_2.light.png b/docs/IDE/AddIns/Images/GlobalSearch_2.light.png index fa0cfa74a..5e0d00178 100644 Binary files a/docs/IDE/AddIns/Images/GlobalSearch_2.light.png and b/docs/IDE/AddIns/Images/GlobalSearch_2.light.png differ diff --git a/docs/IDE/AddIns/Images/GlobalSearch_2.png b/docs/IDE/AddIns/Images/GlobalSearch_2.png index 5cf332046..60e853519 100644 Binary files a/docs/IDE/AddIns/Images/GlobalSearch_2.png and b/docs/IDE/AddIns/Images/GlobalSearch_2.png differ diff --git a/docs/IDE/AddIns/Images/Help_Choices.light.png b/docs/IDE/AddIns/Images/Help_Choices.light.png index a01f006bd..6a5c691bb 100644 Binary files a/docs/IDE/AddIns/Images/Help_Choices.light.png and b/docs/IDE/AddIns/Images/Help_Choices.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Choices.png b/docs/IDE/AddIns/Images/Help_Choices.png index a0d98f1ae..57e99d24c 100644 Binary files a/docs/IDE/AddIns/Images/Help_Choices.png and b/docs/IDE/AddIns/Images/Help_Choices.png differ diff --git a/docs/IDE/AddIns/Images/Help_Description.light.png b/docs/IDE/AddIns/Images/Help_Description.light.png index c9dc786d7..d6983fce2 100644 Binary files a/docs/IDE/AddIns/Images/Help_Description.light.png and b/docs/IDE/AddIns/Images/Help_Description.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Description.png b/docs/IDE/AddIns/Images/Help_Description.png index 51c55bda2..a67e77da5 100644 Binary files a/docs/IDE/AddIns/Images/Help_Description.png and b/docs/IDE/AddIns/Images/Help_Description.png differ diff --git a/docs/IDE/AddIns/Images/Help_Hover.light.png b/docs/IDE/AddIns/Images/Help_Hover.light.png index 39b692bf5..f998fe897 100644 Binary files a/docs/IDE/AddIns/Images/Help_Hover.light.png and b/docs/IDE/AddIns/Images/Help_Hover.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Hover.png b/docs/IDE/AddIns/Images/Help_Hover.png index ea418ed35..ad25e6041 100644 Binary files a/docs/IDE/AddIns/Images/Help_Hover.png and b/docs/IDE/AddIns/Images/Help_Hover.png differ diff --git a/docs/IDE/AddIns/Images/Help_Pane.light.png b/docs/IDE/AddIns/Images/Help_Pane.light.png index c70172ce6..1c4113338 100644 Binary files a/docs/IDE/AddIns/Images/Help_Pane.light.png and b/docs/IDE/AddIns/Images/Help_Pane.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Pane.png b/docs/IDE/AddIns/Images/Help_Pane.png index cb244d228..2a1dfe60f 100644 Binary files a/docs/IDE/AddIns/Images/Help_Pane.png and b/docs/IDE/AddIns/Images/Help_Pane.png differ diff --git a/docs/IDE/AddIns/Images/Help_Pane.svg b/docs/IDE/AddIns/Images/Help_Pane.svg index eca40e708..b99817657 100644 --- a/docs/IDE/AddIns/Images/Help_Pane.svg +++ b/docs/IDE/AddIns/Images/Help_Pane.svg @@ -1 +1 @@ -î­®Inventory(general)MainInventory.twinî©¶1234567891011121314151617181920212223242526ModuleInventoryPublicSubMain()DimnamesAsNewCollectionnames.Add"Widget"names.Add"Sprocket"names.Add"Gasket"DimpricesAsObjectSetprices=CreateObject("Scripting.Dictionary")prices.Add"Widget",4.5prices.Add"Sprocket",12prices.Add"Gasket",0.75DimitemAsVariantForEachitemInnamesDebug.Printitem,prices(item)NextMsgBox"Total: "&TotalPrice(prices),vbInformationEndSub[Description("Adds up the prices held in a Dictionary.")]PublicFunctionTotalPrice(ByValpricesAsObject)AsDoubleDimkeyAsVariantDimtotalAsDoubleForEachkeyInprices.Keys▶   run Inventory.MainInventoryImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesInventory.twinPROPERTIESî©­î©­î©¶TWINBASIC HELPî©¶Open in browserDetachSearch the documentation/Packages/Default Packages/VBA Package/Interaction ModuleMsgBoxDisplays a message in a modal dialog with a chosen set ofbuttons, waits for the user to click a button, and returns aVbMsgBoxResult value identifying that button.Syntax: MsgBox(prompt [ ,buttons ] [ ,title ] [ ,helpfile,context] ):promptrequired String expression displayed asthe message in the dialog box. Themaximum length of prompt isapproximately 1024 characters, dependingon the width of the characters used. Tobreak prompt across multiple lines,separate the lines with a carriage return(Chr(13)), a linefeed (Chr(10)), or a CR-LF combination (vbCrLf).:buttonsoptional A VbMsgBoxStyle value thatMsgBox +î­®Inventory(general)MainInventory.twinî©¶5678910111213141516171819202122232425261234names.Add"Sprocket"names.Add"Gasket"DimpricesAsObjectSetprices=CreateObject("Scripting.Dictionary")prices.Add"Widget",4.5prices.Add"Sprocket",12prices.Add"Gasket",0.75DimitemAsVariantForEachitemInnamesDebug.Printitem,prices(item)NextMsgBox"Total: "&TotalPrice(prices),vbInformationEndSub[Description("Adds up the prices held in a Dictionary.")]PublicFunctionTotalPrice(ByValpricesAsObject)AsDoubleDimkeyAsVariantDimtotalAsDoubleForEachkeyInprices.KeysModuleInventoryPublicSubMain()DimnamesAsNewCollectionnames.Add"Widget"▶   run Inventory.MainInventoryImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesInventory.twinPROPERTIESî©­î©­î©¶TWINBASIC HELPî©¶Open in browserDetachSearch the documentation/Packages/Default Packages/VBA Package/Interaction ModuleMsgBoxDisplays a message in a modal dialog with a chosen set ofbuttons, waits for the user to click a button, and returns aVbMsgBoxResult value identifying that button.Syntax: MsgBox(prompt [ ,buttons ] [ ,title ] [ ,helpfile,context] ):promptrequired String expression displayed asthe message in the dialog box. Themaximum length of prompt isapproximately 1024 characters, dependingon the width of the characters used. Tobreak prompt across multiple lines,separate the lines with a carriage return(Chr(13)), a linefeed (Chr(10)), or a CR-LF combination (vbCrLf).:buttonsoptional A VbMsgBoxStyle value thatMsgBox diff --git a/docs/IDE/AddIns/Images/Help_Settings.light.png b/docs/IDE/AddIns/Images/Help_Settings.light.png index 816af5bac..45631ecd9 100644 Binary files a/docs/IDE/AddIns/Images/Help_Settings.light.png and b/docs/IDE/AddIns/Images/Help_Settings.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Settings.png b/docs/IDE/AddIns/Images/Help_Settings.png index cdf34650b..c9616a288 100644 Binary files a/docs/IDE/AddIns/Images/Help_Settings.png and b/docs/IDE/AddIns/Images/Help_Settings.png differ diff --git a/docs/IDE/AddIns/Images/Help_Toolbar.light.png b/docs/IDE/AddIns/Images/Help_Toolbar.light.png index 842066f86..2fcdb4b46 100644 Binary files a/docs/IDE/AddIns/Images/Help_Toolbar.light.png and b/docs/IDE/AddIns/Images/Help_Toolbar.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Toolbar.png b/docs/IDE/AddIns/Images/Help_Toolbar.png index 0cc369c4d..3aa22fb8c 100644 Binary files a/docs/IDE/AddIns/Images/Help_Toolbar.png and b/docs/IDE/AddIns/Images/Help_Toolbar.png differ diff --git a/docs/IDE/AddIns/Images/Help_Window.light.png b/docs/IDE/AddIns/Images/Help_Window.light.png index 514625af0..8e94a99ac 100644 Binary files a/docs/IDE/AddIns/Images/Help_Window.light.png and b/docs/IDE/AddIns/Images/Help_Window.light.png differ diff --git a/docs/IDE/AddIns/Images/Help_Window.png b/docs/IDE/AddIns/Images/Help_Window.png index d4feaaac0..de6732965 100644 Binary files a/docs/IDE/AddIns/Images/Help_Window.png and b/docs/IDE/AddIns/Images/Help_Window.png differ diff --git a/docs/IDE/AddIns/Images/Toolbar_GlobalSearch.light.png b/docs/IDE/AddIns/Images/Toolbar_GlobalSearch.light.png index 7e887e046..56d5b3ab1 100644 Binary files a/docs/IDE/AddIns/Images/Toolbar_GlobalSearch.light.png and b/docs/IDE/AddIns/Images/Toolbar_GlobalSearch.light.png differ diff --git a/docs/IDE/Code/Images/Bookmarks.light.png b/docs/IDE/Code/Images/Bookmarks.light.png index 36a7f09fe..343c79e19 100644 Binary files a/docs/IDE/Code/Images/Bookmarks.light.png and b/docs/IDE/Code/Images/Bookmarks.light.png differ diff --git a/docs/IDE/Code/Images/Bookmarks.png b/docs/IDE/Code/Images/Bookmarks.png index 306706a18..01cc976da 100644 Binary files a/docs/IDE/Code/Images/Bookmarks.png and b/docs/IDE/Code/Images/Bookmarks.png differ diff --git a/docs/IDE/Code/Images/Bookmarks.svg b/docs/IDE/Code/Images/Bookmarks.svg index f03323640..9db3c4f42 100644 --- a/docs/IDE/Code/Images/Bookmarks.svg +++ b/docs/IDE/Code/Images/Bookmarks.svg @@ -1 +1 @@ -10111213141516171819202122232425PublicFunctionTwice(ByValnAsLong)AsLongReturnn*2EndFunctionPublicSubWithWarning()ReDimmade(3)Debug.PrintUBound(made)EndSubPublicSubThird()Debug.PrintTwice(5)EndSubEndModuleâ–¶   run Helpers.WithWarningâ–¶   run Helpers.ThirdBookmark +13141516171819202122232425101112EndFunctionPublicSubWithWarning()ReDimmade(3)Debug.PrintUBound(made)EndSubPublicSubThird()Debug.PrintTwice(5)EndSubEndModulePublicFunctionTwice(ByValnAsLong)AsLongReturnn*2â–¶   run Helpers.WithWarningâ–¶   run Helpers.ThirdBookmark diff --git a/docs/IDE/Code/Images/Combo_Lists.png b/docs/IDE/Code/Images/Combo_Lists.png index 9e1f7d217..e6f745a76 100644 Binary files a/docs/IDE/Code/Images/Combo_Lists.png and b/docs/IDE/Code/Images/Combo_Lists.png differ diff --git a/docs/IDE/Code/Images/Combos.light.png b/docs/IDE/Code/Images/Combos.light.png index 4496c48d7..d30eec63a 100644 Binary files a/docs/IDE/Code/Images/Combos.light.png and b/docs/IDE/Code/Images/Combos.light.png differ diff --git a/docs/IDE/Code/Images/Combos.png b/docs/IDE/Code/Images/Combos.png index 98f71e38b..911bb665d 100644 Binary files a/docs/IDE/Code/Images/Combos.png and b/docs/IDE/Code/Images/Combos.png differ diff --git a/docs/IDE/Code/Images/Command_Palette.light.png b/docs/IDE/Code/Images/Command_Palette.light.png index 3665d8ca8..9cc0b86fc 100644 Binary files a/docs/IDE/Code/Images/Command_Palette.light.png and b/docs/IDE/Code/Images/Command_Palette.light.png differ diff --git a/docs/IDE/Code/Images/Command_Palette.png b/docs/IDE/Code/Images/Command_Palette.png index 7e8a0c179..277f5d153 100644 Binary files a/docs/IDE/Code/Images/Command_Palette.png and b/docs/IDE/Code/Images/Command_Palette.png differ diff --git a/docs/IDE/Code/Images/Context_Menu.png b/docs/IDE/Code/Images/Context_Menu.png index aba04d5ce..036009139 100644 Binary files a/docs/IDE/Code/Images/Context_Menu.png and b/docs/IDE/Code/Images/Context_Menu.png differ diff --git a/docs/IDE/Code/Images/Diagnostics_Menu.png b/docs/IDE/Code/Images/Diagnostics_Menu.png index 617e5eb8a..120141b77 100644 Binary files a/docs/IDE/Code/Images/Diagnostics_Menu.png and b/docs/IDE/Code/Images/Diagnostics_Menu.png differ diff --git a/docs/IDE/Code/Images/Diagnostics_Rows.png b/docs/IDE/Code/Images/Diagnostics_Rows.png index 143ef498d..fcaf485bb 100644 Binary files a/docs/IDE/Code/Images/Diagnostics_Rows.png and b/docs/IDE/Code/Images/Diagnostics_Rows.png differ diff --git a/docs/IDE/Code/Images/Editor_Panel.png b/docs/IDE/Code/Images/Editor_Panel.png index 0808b9cac..1a16d8613 100644 Binary files a/docs/IDE/Code/Images/Editor_Panel.png and b/docs/IDE/Code/Images/Editor_Panel.png differ diff --git a/docs/IDE/Code/Images/Find_Project.light.png b/docs/IDE/Code/Images/Find_Project.light.png index 51082f5a9..c3d717aef 100644 Binary files a/docs/IDE/Code/Images/Find_Project.light.png and b/docs/IDE/Code/Images/Find_Project.light.png differ diff --git a/docs/IDE/Code/Images/Find_Project.png b/docs/IDE/Code/Images/Find_Project.png index 73dd65639..cebc72719 100644 Binary files a/docs/IDE/Code/Images/Find_Project.png and b/docs/IDE/Code/Images/Find_Project.png differ diff --git a/docs/IDE/Code/Images/Hints.light.png b/docs/IDE/Code/Images/Hints.light.png index f9cb925cb..604326f7c 100644 Binary files a/docs/IDE/Code/Images/Hints.light.png and b/docs/IDE/Code/Images/Hints.light.png differ diff --git a/docs/IDE/Code/Images/Hints.png b/docs/IDE/Code/Images/Hints.png index ad638271c..34104b0c2 100644 Binary files a/docs/IDE/Code/Images/Hints.png and b/docs/IDE/Code/Images/Hints.png differ diff --git a/docs/IDE/Code/Images/Hover.light.png b/docs/IDE/Code/Images/Hover.light.png index fe0e5200a..b8ad7e017 100644 Binary files a/docs/IDE/Code/Images/Hover.light.png and b/docs/IDE/Code/Images/Hover.light.png differ diff --git a/docs/IDE/Code/Images/Hover.png b/docs/IDE/Code/Images/Hover.png index 8a7957614..1bf0e4b0f 100644 Binary files a/docs/IDE/Code/Images/Hover.png and b/docs/IDE/Code/Images/Hover.png differ diff --git a/docs/IDE/Code/Images/Paste_As_Comment.light.png b/docs/IDE/Code/Images/Paste_As_Comment.light.png index 8b6a33c44..22a5cae96 100644 Binary files a/docs/IDE/Code/Images/Paste_As_Comment.light.png and b/docs/IDE/Code/Images/Paste_As_Comment.light.png differ diff --git a/docs/IDE/Code/Images/Paste_As_Comment.light.svg b/docs/IDE/Code/Images/Paste_As_Comment.light.svg index d85d0f50d..7a7c377b5 100644 --- a/docs/IDE/Code/Images/Paste_As_Comment.light.svg +++ b/docs/IDE/Code/Images/Paste_As_Comment.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXEDITOR 1Helpers(general)Helpers.twinî©¶12ModuleHelpersTwiceReplace +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXEDITOR 1Helpers(general)Helpers.twinî©¶12ModuleHelpersTwiceReplace diff --git a/docs/IDE/Code/Images/Paste_As_Comment.png b/docs/IDE/Code/Images/Paste_As_Comment.png index a101e235a..4209db078 100644 Binary files a/docs/IDE/Code/Images/Paste_As_Comment.png and b/docs/IDE/Code/Images/Paste_As_Comment.png differ diff --git a/docs/IDE/Code/Images/Paste_As_Comment.svg b/docs/IDE/Code/Images/Paste_As_Comment.svg index b2065245e..07bdd6f04 100644 --- a/docs/IDE/Code/Images/Paste_As_Comment.svg +++ b/docs/IDE/Code/Images/Paste_As_Comment.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXEDITOR 1Helpers(general)Helpers.twinî©¶12ModuleHelpers +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXEDITOR 1Helpers(general)Helpers.twinî©¶12ModuleHelpers diff --git a/docs/IDE/Code/Images/Quick_Find.light.png b/docs/IDE/Code/Images/Quick_Find.light.png index 44824752d..453b0e07f 100644 Binary files a/docs/IDE/Code/Images/Quick_Find.light.png and b/docs/IDE/Code/Images/Quick_Find.light.png differ diff --git a/docs/IDE/Code/Images/Quick_Find.png b/docs/IDE/Code/Images/Quick_Find.png index af8702449..08706e645 100644 Binary files a/docs/IDE/Code/Images/Quick_Find.png and b/docs/IDE/Code/Images/Quick_Find.png differ diff --git a/docs/IDE/Code/Images/SignatureHelp.light.png b/docs/IDE/Code/Images/SignatureHelp.light.png index de5447ab7..09199c99e 100644 Binary files a/docs/IDE/Code/Images/SignatureHelp.light.png and b/docs/IDE/Code/Images/SignatureHelp.light.png differ diff --git a/docs/IDE/Code/Images/SignatureHelp.png b/docs/IDE/Code/Images/SignatureHelp.png index 0d98155a9..e41718c32 100644 Binary files a/docs/IDE/Code/Images/SignatureHelp.png and b/docs/IDE/Code/Images/SignatureHelp.png differ diff --git a/docs/IDE/Code/Images/SignatureHelp_Expanded.light.png b/docs/IDE/Code/Images/SignatureHelp_Expanded.light.png index c078f7543..8145f96d6 100644 Binary files a/docs/IDE/Code/Images/SignatureHelp_Expanded.light.png and b/docs/IDE/Code/Images/SignatureHelp_Expanded.light.png differ diff --git a/docs/IDE/Code/Images/SignatureHelp_Expanded.png b/docs/IDE/Code/Images/SignatureHelp_Expanded.png index b2f545e3d..4bf42985e 100644 Binary files a/docs/IDE/Code/Images/SignatureHelp_Expanded.png and b/docs/IDE/Code/Images/SignatureHelp_Expanded.png differ diff --git a/docs/IDE/Code/Images/Tab_Menu.light.png b/docs/IDE/Code/Images/Tab_Menu.light.png index 9d350da4f..3847ce618 100644 Binary files a/docs/IDE/Code/Images/Tab_Menu.light.png and b/docs/IDE/Code/Images/Tab_Menu.light.png differ diff --git a/docs/IDE/Code/Images/Tab_Menu.png b/docs/IDE/Code/Images/Tab_Menu.png index 55456a316..c3ceacddc 100644 Binary files a/docs/IDE/Code/Images/Tab_Menu.png and b/docs/IDE/Code/Images/Tab_Menu.png differ diff --git a/docs/IDE/Code/Images/Tabs_States.light.png b/docs/IDE/Code/Images/Tabs_States.light.png index f379c9c5c..d44dcfb13 100644 Binary files a/docs/IDE/Code/Images/Tabs_States.light.png and b/docs/IDE/Code/Images/Tabs_States.light.png differ diff --git a/docs/IDE/Code/Images/Tabs_States.png b/docs/IDE/Code/Images/Tabs_States.png index 807bd59bc..6cc2adead 100644 Binary files a/docs/IDE/Code/Images/Tabs_States.png and b/docs/IDE/Code/Images/Tabs_States.png differ diff --git a/docs/IDE/Debugging/Images/Breakpoint_Glyphs.light.png b/docs/IDE/Debugging/Images/Breakpoint_Glyphs.light.png index 1114ce30f..0557658d2 100644 Binary files a/docs/IDE/Debugging/Images/Breakpoint_Glyphs.light.png and b/docs/IDE/Debugging/Images/Breakpoint_Glyphs.light.png differ diff --git a/docs/IDE/Debugging/Images/Breakpoint_Glyphs.png b/docs/IDE/Debugging/Images/Breakpoint_Glyphs.png index b782b1742..074bd0321 100644 Binary files a/docs/IDE/Debugging/Images/Breakpoint_Glyphs.png and b/docs/IDE/Debugging/Images/Breakpoint_Glyphs.png differ diff --git a/docs/IDE/Debugging/Images/CallStack_Frames.light.svg b/docs/IDE/Debugging/Images/CallStack_Frames.light.svg index ea8c72954..2b0e3a0d8 100644 --- a/docs/IDE/Debugging/Images/CallStack_Frames.light.svg +++ b/docs/IDE/Debugging/Images/CallStack_Frames.light.svg @@ -1 +1 @@ -EDITOR 1MainModule(general)MainInventory.twinî©¶MainModule.twinî©¶123456789101112131415ModuleMainModulePublicSubMain()DimstockAsNewInventoryDimfirstAsStockItemDimcoststock.Add"Widget",120,2.5stock.Add"Gadget",8,14.75cost=stock.Total(0.2)first=stock.ItemByIndex(stock.Find("Widget"))Debug.Printfirst.Quantity, costEndSubEndModule▶   run MainModule.MainCALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [EXECUTING]24:1TotalInventory.twin9:1MainMainModule.twinVARIABLESî©¶Localsfirst:{user defined type, 16 bytes}StockItemstock:{object: 441954992}Inventorycost:EmptyVariant [Empty] +EDITOR 1MainModule(general)MainInventory.twinî©¶MainModule.twinî©¶123456789101112131415ModuleMainModulePublicSubMain()DimstockAsNewInventoryDimfirstAsStockItemDimcoststock.Add"Widget",120,2.5stock.Add"Gadget",8,14.75cost=stock.Total(0.2)first=stock.ItemByIndex(stock.Find("Widget"))Debug.Printfirst.Quantity, costEndSubEndModule▶   run MainModule.MainCALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [EXECUTING]24:1TotalInventory.twin9:1MainMainModule.twinVARIABLESî©¶Localsfirst:{user defined type, 16 bytes}StockItemstock:{object: 441954992}Inventorycost:EmptyVariant [Empty] diff --git a/docs/IDE/Debugging/Images/CallStack_Frames.png b/docs/IDE/Debugging/Images/CallStack_Frames.png index e981a825d..ad2f18f28 100644 Binary files a/docs/IDE/Debugging/Images/CallStack_Frames.png and b/docs/IDE/Debugging/Images/CallStack_Frames.png differ diff --git a/docs/IDE/Debugging/Images/Console_Menu.light.png b/docs/IDE/Debugging/Images/Console_Menu.light.png index 25ca06462..ece475f83 100644 Binary files a/docs/IDE/Debugging/Images/Console_Menu.light.png and b/docs/IDE/Debugging/Images/Console_Menu.light.png differ diff --git a/docs/IDE/Debugging/Images/Console_Menu.png b/docs/IDE/Debugging/Images/Console_Menu.png index de7e3a597..6cb556d7b 100644 Binary files a/docs/IDE/Debugging/Images/Console_Menu.png and b/docs/IDE/Debugging/Images/Console_Menu.png differ diff --git a/docs/IDE/Debugging/Images/Console_Run.light.png b/docs/IDE/Debugging/Images/Console_Run.light.png index 76848c5c5..96db0d289 100644 Binary files a/docs/IDE/Debugging/Images/Console_Run.light.png and b/docs/IDE/Debugging/Images/Console_Run.light.png differ diff --git a/docs/IDE/Debugging/Images/Console_Run.png b/docs/IDE/Debugging/Images/Console_Run.png index 9fea85aaf..0f9d0f2fd 100644 Binary files a/docs/IDE/Debugging/Images/Console_Run.png and b/docs/IDE/Debugging/Images/Console_Run.png differ diff --git a/docs/IDE/Debugging/Images/Error_Panel.png b/docs/IDE/Debugging/Images/Error_Panel.png index 7b23d937c..c8f2faf7a 100644 Binary files a/docs/IDE/Debugging/Images/Error_Panel.png and b/docs/IDE/Debugging/Images/Error_Panel.png differ diff --git a/docs/IDE/Debugging/Images/Hover_Paused.light.png b/docs/IDE/Debugging/Images/Hover_Paused.light.png index 2b112df64..9be8b6d7a 100644 Binary files a/docs/IDE/Debugging/Images/Hover_Paused.light.png and b/docs/IDE/Debugging/Images/Hover_Paused.light.png differ diff --git a/docs/IDE/Debugging/Images/Hover_Paused.png b/docs/IDE/Debugging/Images/Hover_Paused.png index 0312a3140..a26a9906a 100644 Binary files a/docs/IDE/Debugging/Images/Hover_Paused.png and b/docs/IDE/Debugging/Images/Hover_Paused.png differ diff --git a/docs/IDE/Debugging/Images/Hover_Selection.light.png b/docs/IDE/Debugging/Images/Hover_Selection.light.png index d84aa2a8c..e3c826f31 100644 Binary files a/docs/IDE/Debugging/Images/Hover_Selection.light.png and b/docs/IDE/Debugging/Images/Hover_Selection.light.png differ diff --git a/docs/IDE/Debugging/Images/Hover_Selection.png b/docs/IDE/Debugging/Images/Hover_Selection.png index d5deb11a1..6ba274d40 100644 Binary files a/docs/IDE/Debugging/Images/Hover_Selection.png and b/docs/IDE/Debugging/Images/Hover_Selection.png differ diff --git a/docs/IDE/Debugging/Images/Paused_Line.png b/docs/IDE/Debugging/Images/Paused_Line.png index a826fb0a1..4dab332e0 100644 Binary files a/docs/IDE/Debugging/Images/Paused_Line.png and b/docs/IDE/Debugging/Images/Paused_Line.png differ diff --git a/docs/IDE/Debugging/Images/Paused_Panels.light.png b/docs/IDE/Debugging/Images/Paused_Panels.light.png index cf5bc4231..fe2c81279 100644 Binary files a/docs/IDE/Debugging/Images/Paused_Panels.light.png and b/docs/IDE/Debugging/Images/Paused_Panels.light.png differ diff --git a/docs/IDE/Debugging/Images/Paused_Panels.png b/docs/IDE/Debugging/Images/Paused_Panels.png index db255ef21..7290c1039 100644 Binary files a/docs/IDE/Debugging/Images/Paused_Panels.png and b/docs/IDE/Debugging/Images/Paused_Panels.png differ diff --git a/docs/IDE/Debugging/Images/Toolbar_Paused.light.png b/docs/IDE/Debugging/Images/Toolbar_Paused.light.png index 5faee5e1c..7d93ff04a 100644 Binary files a/docs/IDE/Debugging/Images/Toolbar_Paused.light.png and b/docs/IDE/Debugging/Images/Toolbar_Paused.light.png differ diff --git a/docs/IDE/Debugging/Images/Toolbar_Paused.png b/docs/IDE/Debugging/Images/Toolbar_Paused.png index 355f2405b..06f787501 100644 Binary files a/docs/IDE/Debugging/Images/Toolbar_Paused.png and b/docs/IDE/Debugging/Images/Toolbar_Paused.png differ diff --git a/docs/IDE/Debugging/Images/Variables_Edit.png b/docs/IDE/Debugging/Images/Variables_Edit.png index 9b7d4fd8c..07b00bc10 100644 Binary files a/docs/IDE/Debugging/Images/Variables_Edit.png and b/docs/IDE/Debugging/Images/Variables_Edit.png differ diff --git a/docs/IDE/Debugging/Images/Variables_Expanded.png b/docs/IDE/Debugging/Images/Variables_Expanded.png index 13f5a832a..ffc817be9 100644 Binary files a/docs/IDE/Debugging/Images/Variables_Expanded.png and b/docs/IDE/Debugging/Images/Variables_Expanded.png differ diff --git a/docs/IDE/Debugging/Images/Variables_Tooltip.light.png b/docs/IDE/Debugging/Images/Variables_Tooltip.light.png index a942fc593..6be3ffa0f 100644 Binary files a/docs/IDE/Debugging/Images/Variables_Tooltip.light.png and b/docs/IDE/Debugging/Images/Variables_Tooltip.light.png differ diff --git a/docs/IDE/Debugging/Images/Variables_Tooltip.png b/docs/IDE/Debugging/Images/Variables_Tooltip.png index 6410d9c36..81a21655b 100644 Binary files a/docs/IDE/Debugging/Images/Variables_Tooltip.png and b/docs/IDE/Debugging/Images/Variables_Tooltip.png differ diff --git a/docs/IDE/Debugging/Images/Watches_NotAvailable.png b/docs/IDE/Debugging/Images/Watches_NotAvailable.png index 016818b57..2c2899217 100644 Binary files a/docs/IDE/Debugging/Images/Watches_NotAvailable.png and b/docs/IDE/Debugging/Images/Watches_NotAvailable.png differ diff --git a/docs/IDE/Debugging/Images/Watches_Values.png b/docs/IDE/Debugging/Images/Watches_Values.png index fd22c9ed5..6fb7cda79 100644 Binary files a/docs/IDE/Debugging/Images/Watches_Values.png and b/docs/IDE/Debugging/Images/Watches_Values.png differ diff --git a/docs/IDE/Forms/Images/Controls_Container.light.png b/docs/IDE/Forms/Images/Controls_Container.light.png index 743d29ffd..3d92e4b2f 100644 Binary files a/docs/IDE/Forms/Images/Controls_Container.light.png and b/docs/IDE/Forms/Images/Controls_Container.light.png differ diff --git a/docs/IDE/Forms/Images/Controls_Container.png b/docs/IDE/Forms/Images/Controls_Container.png index 3ca724141..bbf6869e1 100644 Binary files a/docs/IDE/Forms/Images/Controls_Container.png and b/docs/IDE/Forms/Images/Controls_Container.png differ diff --git a/docs/IDE/Forms/Images/Controls_ContextMenu.light.png b/docs/IDE/Forms/Images/Controls_ContextMenu.light.png index bccab8341..9264a1bc3 100644 Binary files a/docs/IDE/Forms/Images/Controls_ContextMenu.light.png and b/docs/IDE/Forms/Images/Controls_ContextMenu.light.png differ diff --git a/docs/IDE/Forms/Images/Controls_ContextMenu.png b/docs/IDE/Forms/Images/Controls_ContextMenu.png index 9cc14efec..dd3e28f23 100644 Binary files a/docs/IDE/Forms/Images/Controls_ContextMenu.png and b/docs/IDE/Forms/Images/Controls_ContextMenu.png differ diff --git a/docs/IDE/Forms/Images/Controls_MultiSelect.light.png b/docs/IDE/Forms/Images/Controls_MultiSelect.light.png index 779aa795f..25328f5d3 100644 Binary files a/docs/IDE/Forms/Images/Controls_MultiSelect.light.png and b/docs/IDE/Forms/Images/Controls_MultiSelect.light.png differ diff --git a/docs/IDE/Forms/Images/Controls_MultiSelect.png b/docs/IDE/Forms/Images/Controls_MultiSelect.png index cd28eecb9..41e2ca014 100644 Binary files a/docs/IDE/Forms/Images/Controls_MultiSelect.png and b/docs/IDE/Forms/Images/Controls_MultiSelect.png differ diff --git a/docs/IDE/Forms/Images/Controls_RubberBand.light.png b/docs/IDE/Forms/Images/Controls_RubberBand.light.png index 819eefd96..264c3fbd1 100644 Binary files a/docs/IDE/Forms/Images/Controls_RubberBand.light.png and b/docs/IDE/Forms/Images/Controls_RubberBand.light.png differ diff --git a/docs/IDE/Forms/Images/Controls_RubberBand.png b/docs/IDE/Forms/Images/Controls_RubberBand.png index 0b5abf954..124666040 100644 Binary files a/docs/IDE/Forms/Images/Controls_RubberBand.png and b/docs/IDE/Forms/Images/Controls_RubberBand.png differ diff --git a/docs/IDE/Forms/Images/Designer_AddName.light.png b/docs/IDE/Forms/Images/Designer_AddName.light.png index ba8a1d939..449e2b144 100644 Binary files a/docs/IDE/Forms/Images/Designer_AddName.light.png and b/docs/IDE/Forms/Images/Designer_AddName.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_AddName.png b/docs/IDE/Forms/Images/Designer_AddName.png index a692c1671..9ee5bd4eb 100644 Binary files a/docs/IDE/Forms/Images/Designer_AddName.png and b/docs/IDE/Forms/Images/Designer_AddName.png differ diff --git a/docs/IDE/Forms/Images/Designer_GridOptions.light.png b/docs/IDE/Forms/Images/Designer_GridOptions.light.png index cce0b9906..553757122 100644 Binary files a/docs/IDE/Forms/Images/Designer_GridOptions.light.png and b/docs/IDE/Forms/Images/Designer_GridOptions.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_GridOptions.png b/docs/IDE/Forms/Images/Designer_GridOptions.png index 42b7e5abd..5ac0a5ccd 100644 Binary files a/docs/IDE/Forms/Images/Designer_GridOptions.png and b/docs/IDE/Forms/Images/Designer_GridOptions.png differ diff --git a/docs/IDE/Forms/Images/Designer_Locked.light.png b/docs/IDE/Forms/Images/Designer_Locked.light.png index 7a868ec5a..927fd7691 100644 Binary files a/docs/IDE/Forms/Images/Designer_Locked.light.png and b/docs/IDE/Forms/Images/Designer_Locked.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_Locked.png b/docs/IDE/Forms/Images/Designer_Locked.png index 557975db5..285a349b0 100644 Binary files a/docs/IDE/Forms/Images/Designer_Locked.png and b/docs/IDE/Forms/Images/Designer_Locked.png differ diff --git a/docs/IDE/Forms/Images/Designer_PackageNeeded.light.png b/docs/IDE/Forms/Images/Designer_PackageNeeded.light.png index 8299dc607..32a7e9c76 100644 Binary files a/docs/IDE/Forms/Images/Designer_PackageNeeded.light.png and b/docs/IDE/Forms/Images/Designer_PackageNeeded.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_PackageNeeded.png b/docs/IDE/Forms/Images/Designer_PackageNeeded.png index 53af2fff5..0e31d794d 100644 Binary files a/docs/IDE/Forms/Images/Designer_PackageNeeded.png and b/docs/IDE/Forms/Images/Designer_PackageNeeded.png differ diff --git a/docs/IDE/Forms/Images/Designer_Selected.light.png b/docs/IDE/Forms/Images/Designer_Selected.light.png index 9570c9f4a..cdcf1da69 100644 Binary files a/docs/IDE/Forms/Images/Designer_Selected.light.png and b/docs/IDE/Forms/Images/Designer_Selected.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_Selected.png b/docs/IDE/Forms/Images/Designer_Selected.png index c0ecb3df7..5faf36951 100644 Binary files a/docs/IDE/Forms/Images/Designer_Selected.png and b/docs/IDE/Forms/Images/Designer_Selected.png differ diff --git a/docs/IDE/Forms/Images/Designer_TabIndex.light.png b/docs/IDE/Forms/Images/Designer_TabIndex.light.png index a9fb4122c..7442ae295 100644 Binary files a/docs/IDE/Forms/Images/Designer_TabIndex.light.png and b/docs/IDE/Forms/Images/Designer_TabIndex.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_TabIndex.light.svg b/docs/IDE/Forms/Images/Designer_TabIndex.light.svg index cd1e3670e..5f8fdb6e9 100644 --- a/docs/IDE/Forms/Images/Designer_TabIndex.light.svg +++ b/docs/IDE/Forms/Images/Designer_TabIndex.light.svg @@ -1 +1 @@ -File+ menu023567x:300 y:245380 x 270 +File+ menu023567x:300 y:245380 x 270 diff --git a/docs/IDE/Forms/Images/Designer_TabIndex.png b/docs/IDE/Forms/Images/Designer_TabIndex.png index d76b375af..5ad3e5591 100644 Binary files a/docs/IDE/Forms/Images/Designer_TabIndex.png and b/docs/IDE/Forms/Images/Designer_TabIndex.png differ diff --git a/docs/IDE/Forms/Images/Designer_Zoom.light.png b/docs/IDE/Forms/Images/Designer_Zoom.light.png index 16196dde9..e7d86e461 100644 Binary files a/docs/IDE/Forms/Images/Designer_Zoom.light.png and b/docs/IDE/Forms/Images/Designer_Zoom.light.png differ diff --git a/docs/IDE/Forms/Images/Designer_Zoom.png b/docs/IDE/Forms/Images/Designer_Zoom.png index 2855f96b9..5a6f848ef 100644 Binary files a/docs/IDE/Forms/Images/Designer_Zoom.png and b/docs/IDE/Forms/Images/Designer_Zoom.png differ diff --git a/docs/IDE/Forms/Images/MenuEditor_Bar.light.png b/docs/IDE/Forms/Images/MenuEditor_Bar.light.png index 0d485ce6c..12477d9e2 100644 Binary files a/docs/IDE/Forms/Images/MenuEditor_Bar.light.png and b/docs/IDE/Forms/Images/MenuEditor_Bar.light.png differ diff --git a/docs/IDE/Forms/Images/MenuEditor_Bar.png b/docs/IDE/Forms/Images/MenuEditor_Bar.png index fb1b2669b..d5262bba6 100644 Binary files a/docs/IDE/Forms/Images/MenuEditor_Bar.png and b/docs/IDE/Forms/Images/MenuEditor_Bar.png differ diff --git a/docs/IDE/Forms/Images/MenuEditor_Open.light.png b/docs/IDE/Forms/Images/MenuEditor_Open.light.png index 36f7ff98c..d2d7b60e2 100644 Binary files a/docs/IDE/Forms/Images/MenuEditor_Open.light.png and b/docs/IDE/Forms/Images/MenuEditor_Open.light.png differ diff --git a/docs/IDE/Forms/Images/MenuEditor_Open.png b/docs/IDE/Forms/Images/MenuEditor_Open.png index 06651d193..d977014d6 100644 Binary files a/docs/IDE/Forms/Images/MenuEditor_Open.png and b/docs/IDE/Forms/Images/MenuEditor_Open.png differ diff --git a/docs/IDE/Forms/Images/Properties_ColourPicker.light.png b/docs/IDE/Forms/Images/Properties_ColourPicker.light.png index fb9f2f77b..5e8c230ce 100644 Binary files a/docs/IDE/Forms/Images/Properties_ColourPicker.light.png and b/docs/IDE/Forms/Images/Properties_ColourPicker.light.png differ diff --git a/docs/IDE/Forms/Images/Properties_ColourPicker.png b/docs/IDE/Forms/Images/Properties_ColourPicker.png index 72654e276..f2f4393df 100644 Binary files a/docs/IDE/Forms/Images/Properties_ColourPicker.png and b/docs/IDE/Forms/Images/Properties_ColourPicker.png differ diff --git a/docs/IDE/Forms/Images/Properties_Control.light.png b/docs/IDE/Forms/Images/Properties_Control.light.png index d8b6071ff..fb6ea4f89 100644 Binary files a/docs/IDE/Forms/Images/Properties_Control.light.png and b/docs/IDE/Forms/Images/Properties_Control.light.png differ diff --git a/docs/IDE/Forms/Images/Properties_Control.png b/docs/IDE/Forms/Images/Properties_Control.png index 2b9c66189..f39b1fb4f 100644 Binary files a/docs/IDE/Forms/Images/Properties_Control.png and b/docs/IDE/Forms/Images/Properties_Control.png differ diff --git a/docs/IDE/Forms/Images/Properties_SystemColours.light.png b/docs/IDE/Forms/Images/Properties_SystemColours.light.png index cc1c545aa..fa9784a9f 100644 Binary files a/docs/IDE/Forms/Images/Properties_SystemColours.light.png and b/docs/IDE/Forms/Images/Properties_SystemColours.light.png differ diff --git a/docs/IDE/Forms/Images/Properties_SystemColours.light.svg b/docs/IDE/Forms/Images/Properties_SystemColours.light.svg new file mode 100644 index 000000000..ce9ec2b2f --- /dev/null +++ b/docs/IDE/Forms/Images/Properties_SystemColours.light.svg @@ -0,0 +1 @@ +PROPERTIESî©­î©¶DESIGNAPPEARANCEDRAWINGBEHAVIOURMOUSEWINDOWNameCommand1IndexCaption...Command1ToolTipText...VisualStylesTrueAppearance1 - vbAppear3dBackColor&H(BGR)8000000FForeColor&H(BGR)80000012Style0 - vbButtonStandardFontNameSegoe UIFontSize8FontBoldFalseFontItalicFalseFontStrikethruFalseFontUnderlineFalsePicture{0 bytes}...PictureDpiScalingFalseDownPicture{0 bytes}...DisabledPicture{0 bytes}...PictureAlignment1 - vbAlignTopî©´MaskColor&H(BGR)C0C0C0î©´UseMaskColorFalseEnabledTrueî©´RightToLeftFalseCausesValidationTrueCancelFalseDefaultFalseMouseIcon{0 bytes}...MousePointer0 - vbDefaultDragMode0 - vbManualDragIcon{0 bytes}...OLEDropMode0 - vbOLEDropNoneCommand1    CommandButtonCopyPasteCopy '-2147483633' To...SYSTEM COLORSvbScrollBarsvbDesktopvbActiveTitleBarvbInactiveTitleBarvbMenuBarvbWindowBackgroundvbWindowFramevbMenuTextvbWindowTextvbActiveTitleBarTextvbActiveBordervbInactiveBordervbApplicationWorkspacevbHighlightvbHighlightTextvbButtonFacevbButtonShadowvbGrayTextvbButtonTextvbInactiveTitleBarTextvb3DHighlightvb3DDKShadowvb3DLightvbInfoTextvbInfoBackgroundvbHotTrackTextvbActiveTitleBarGradientvbInactiveTitleBarGradientvbMenuHighlightvbMenuBarFlat diff --git a/docs/IDE/Forms/Images/Toolbox_Form.light.png b/docs/IDE/Forms/Images/Toolbox_Form.light.png index ada28347f..f787d3e4b 100644 Binary files a/docs/IDE/Forms/Images/Toolbox_Form.light.png and b/docs/IDE/Forms/Images/Toolbox_Form.light.png differ diff --git a/docs/IDE/Forms/Images/Toolbox_Form.png b/docs/IDE/Forms/Images/Toolbox_Form.png index b16a9d19d..85daefdec 100644 Binary files a/docs/IDE/Forms/Images/Toolbox_Form.png and b/docs/IDE/Forms/Images/Toolbox_Form.png differ diff --git a/docs/IDE/Forms/Images/Toolbox_Search.light.png b/docs/IDE/Forms/Images/Toolbox_Search.light.png index 80afec338..07a18c307 100644 Binary files a/docs/IDE/Forms/Images/Toolbox_Search.light.png and b/docs/IDE/Forms/Images/Toolbox_Search.light.png differ diff --git a/docs/IDE/Forms/Images/Toolbox_Search.png b/docs/IDE/Forms/Images/Toolbox_Search.png index c69c8a68d..02e078bef 100644 Binary files a/docs/IDE/Forms/Images/Toolbox_Search.png and b/docs/IDE/Forms/Images/Toolbox_Search.png differ diff --git a/docs/IDE/Images/Add.light.png b/docs/IDE/Images/Add.light.png index 40ac62170..434175ef6 100644 Binary files a/docs/IDE/Images/Add.light.png and b/docs/IDE/Images/Add.light.png differ diff --git a/docs/IDE/Images/Add.png b/docs/IDE/Images/Add.png index f2b08d033..42f076a19 100644 Binary files a/docs/IDE/Images/Add.png and b/docs/IDE/Images/Add.png differ diff --git a/docs/IDE/Images/CallStack.png b/docs/IDE/Images/CallStack.png index 5217396c6..03a0bd811 100644 Binary files a/docs/IDE/Images/CallStack.png and b/docs/IDE/Images/CallStack.png differ diff --git a/docs/IDE/Images/Clear.light.png b/docs/IDE/Images/Clear.light.png index d6b414318..6943b86de 100644 Binary files a/docs/IDE/Images/Clear.light.png and b/docs/IDE/Images/Clear.light.png differ diff --git a/docs/IDE/Images/Clear.png b/docs/IDE/Images/Clear.png index 13c69e446..c1c8cdd6f 100644 Binary files a/docs/IDE/Images/Clear.png and b/docs/IDE/Images/Clear.png differ diff --git a/docs/IDE/Images/Components_Message.png b/docs/IDE/Images/Components_Message.png index fd492bdad..c9f3062ec 100644 Binary files a/docs/IDE/Images/Components_Message.png and b/docs/IDE/Images/Components_Message.png differ diff --git a/docs/IDE/Images/DebugConsole_AutoScroll.light.png b/docs/IDE/Images/DebugConsole_AutoScroll.light.png index 28498fb66..78680cdf2 100644 Binary files a/docs/IDE/Images/DebugConsole_AutoScroll.light.png and b/docs/IDE/Images/DebugConsole_AutoScroll.light.png differ diff --git a/docs/IDE/Images/DebugConsole_AutoScroll.png b/docs/IDE/Images/DebugConsole_AutoScroll.png index 89ea1b518..1310d834a 100644 Binary files a/docs/IDE/Images/DebugConsole_AutoScroll.png and b/docs/IDE/Images/DebugConsole_AutoScroll.png differ diff --git a/docs/IDE/Images/DebugConsole_Clear.light.png b/docs/IDE/Images/DebugConsole_Clear.light.png index 623b793f4..571bdebea 100644 Binary files a/docs/IDE/Images/DebugConsole_Clear.light.png and b/docs/IDE/Images/DebugConsole_Clear.light.png differ diff --git a/docs/IDE/Images/DebugConsole_Clear.png b/docs/IDE/Images/DebugConsole_Clear.png index 07d20f87d..a24519084 100644 Binary files a/docs/IDE/Images/DebugConsole_Clear.png and b/docs/IDE/Images/DebugConsole_Clear.png differ diff --git a/docs/IDE/Images/DebugConsole_Input.png b/docs/IDE/Images/DebugConsole_Input.png index a11b7a5a1..d961c390e 100644 Binary files a/docs/IDE/Images/DebugConsole_Input.png and b/docs/IDE/Images/DebugConsole_Input.png differ diff --git a/docs/IDE/Images/DebugConsole_Options.light.png b/docs/IDE/Images/DebugConsole_Options.light.png index 1518a85d2..e3dbaba47 100644 Binary files a/docs/IDE/Images/DebugConsole_Options.light.png and b/docs/IDE/Images/DebugConsole_Options.light.png differ diff --git a/docs/IDE/Images/DebugConsole_Options.png b/docs/IDE/Images/DebugConsole_Options.png index efdba15ed..5a4b87dbf 100644 Binary files a/docs/IDE/Images/DebugConsole_Options.png and b/docs/IDE/Images/DebugConsole_Options.png differ diff --git a/docs/IDE/Images/Diagnostics.light.png b/docs/IDE/Images/Diagnostics.light.png index bf7657e27..bda6101e2 100644 Binary files a/docs/IDE/Images/Diagnostics.light.png and b/docs/IDE/Images/Diagnostics.light.png differ diff --git a/docs/IDE/Images/Diagnostics.png b/docs/IDE/Images/Diagnostics.png index 77834ab70..ecbb2d1a4 100644 Binary files a/docs/IDE/Images/Diagnostics.png and b/docs/IDE/Images/Diagnostics.png differ diff --git a/docs/IDE/Images/Diagnostics_Toggles.light.png b/docs/IDE/Images/Diagnostics_Toggles.light.png index 1f50919dc..4cc6cf896 100644 Binary files a/docs/IDE/Images/Diagnostics_Toggles.light.png and b/docs/IDE/Images/Diagnostics_Toggles.light.png differ diff --git a/docs/IDE/Images/Diagnostics_Toggles.png b/docs/IDE/Images/Diagnostics_Toggles.png index 994357fb1..2f9ca1b95 100644 Binary files a/docs/IDE/Images/Diagnostics_Toggles.png and b/docs/IDE/Images/Diagnostics_Toggles.png differ diff --git a/docs/IDE/Images/Diagnostics_Totals.light.png b/docs/IDE/Images/Diagnostics_Totals.light.png index 70dad4eed..5201df946 100644 Binary files a/docs/IDE/Images/Diagnostics_Totals.light.png and b/docs/IDE/Images/Diagnostics_Totals.light.png differ diff --git a/docs/IDE/Images/Diagnostics_Totals.png b/docs/IDE/Images/Diagnostics_Totals.png index e0f7854d3..36367d202 100644 Binary files a/docs/IDE/Images/Diagnostics_Totals.png and b/docs/IDE/Images/Diagnostics_Totals.png differ diff --git a/docs/IDE/Images/Editor.light.png b/docs/IDE/Images/Editor.light.png index ad273645f..de158f59a 100644 Binary files a/docs/IDE/Images/Editor.light.png and b/docs/IDE/Images/Editor.light.png differ diff --git a/docs/IDE/Images/Editor.png b/docs/IDE/Images/Editor.png index d3701c32b..f6d6701fa 100644 Binary files a/docs/IDE/Images/Editor.png and b/docs/IDE/Images/Editor.png differ diff --git a/docs/IDE/Images/File-Green.light.png b/docs/IDE/Images/File-Green.light.png index eb1eebb10..539c60137 100644 Binary files a/docs/IDE/Images/File-Green.light.png and b/docs/IDE/Images/File-Green.light.png differ diff --git a/docs/IDE/Images/File-Green.png b/docs/IDE/Images/File-Green.png index 2485cf8b7..28224e9e1 100644 Binary files a/docs/IDE/Images/File-Green.png and b/docs/IDE/Images/File-Green.png differ diff --git a/docs/IDE/Images/FindReplace.png b/docs/IDE/Images/FindReplace.png index 0112df408..cf47aa81d 100644 Binary files a/docs/IDE/Images/FindReplace.png and b/docs/IDE/Images/FindReplace.png differ diff --git a/docs/IDE/Images/FindReplace_Direction.png b/docs/IDE/Images/FindReplace_Direction.png index c9738e5b4..51b41cc88 100644 Binary files a/docs/IDE/Images/FindReplace_Direction.png and b/docs/IDE/Images/FindReplace_Direction.png differ diff --git a/docs/IDE/Images/Folder.light.png b/docs/IDE/Images/Folder.light.png index deef56e08..1bcd55907 100644 Binary files a/docs/IDE/Images/Folder.light.png and b/docs/IDE/Images/Folder.light.png differ diff --git a/docs/IDE/Images/Folder.png b/docs/IDE/Images/Folder.png index 97e547dc5..6fea24a2e 100644 Binary files a/docs/IDE/Images/Folder.png and b/docs/IDE/Images/Folder.png differ diff --git a/docs/IDE/Images/History_1.png b/docs/IDE/Images/History_1.png index 3e4b45d09..8c2268869 100644 Binary files a/docs/IDE/Images/History_1.png and b/docs/IDE/Images/History_1.png differ diff --git a/docs/IDE/Images/History_2.light.png b/docs/IDE/Images/History_2.light.png index c44acdbf8..4ca5400da 100644 Binary files a/docs/IDE/Images/History_2.light.png and b/docs/IDE/Images/History_2.light.png differ diff --git a/docs/IDE/Images/History_2.png b/docs/IDE/Images/History_2.png index 6d1216502..a4df9f176 100644 Binary files a/docs/IDE/Images/History_2.png and b/docs/IDE/Images/History_2.png differ diff --git a/docs/IDE/Images/History_3.light.png b/docs/IDE/Images/History_3.light.png index d36fdd7c9..f5abbc403 100644 Binary files a/docs/IDE/Images/History_3.light.png and b/docs/IDE/Images/History_3.light.png differ diff --git a/docs/IDE/Images/History_3.png b/docs/IDE/Images/History_3.png index cba4ead90..fc14b86d2 100644 Binary files a/docs/IDE/Images/History_3.png and b/docs/IDE/Images/History_3.png differ diff --git a/docs/IDE/Images/IDE.light.png b/docs/IDE/Images/IDE.light.png index 43b5d8712..0f2d138e0 100644 Binary files a/docs/IDE/Images/IDE.light.png and b/docs/IDE/Images/IDE.light.png differ diff --git a/docs/IDE/Images/IDE.png b/docs/IDE/Images/IDE.png index a834b258b..482046638 100644 Binary files a/docs/IDE/Images/IDE.png and b/docs/IDE/Images/IDE.png differ diff --git a/docs/IDE/Images/Memory.png b/docs/IDE/Images/Memory.png index f06df4e8f..ad730e58b 100644 Binary files a/docs/IDE/Images/Memory.png and b/docs/IDE/Images/Memory.png differ diff --git a/docs/IDE/Images/Memory_String.png b/docs/IDE/Images/Memory_String.png index 806539f2c..42aab1198 100644 Binary files a/docs/IDE/Images/Memory_String.png and b/docs/IDE/Images/Memory_String.png differ diff --git a/docs/IDE/Images/New_Project.light.png b/docs/IDE/Images/New_Project.light.png index 892246441..96f4784c8 100644 Binary files a/docs/IDE/Images/New_Project.light.png and b/docs/IDE/Images/New_Project.light.png differ diff --git a/docs/IDE/Images/New_Project.png b/docs/IDE/Images/New_Project.png index c122282c1..325842f44 100644 Binary files a/docs/IDE/Images/New_Project.png and b/docs/IDE/Images/New_Project.png differ diff --git a/docs/IDE/Images/New_Project_Recent_2.light.png b/docs/IDE/Images/New_Project_Recent_2.light.png index 6ab74f684..176a3f13c 100644 Binary files a/docs/IDE/Images/New_Project_Recent_2.light.png and b/docs/IDE/Images/New_Project_Recent_2.light.png differ diff --git a/docs/IDE/Images/New_Project_Recent_2.png b/docs/IDE/Images/New_Project_Recent_2.png index e2e01085e..0440362a3 100644 Binary files a/docs/IDE/Images/New_Project_Recent_2.png and b/docs/IDE/Images/New_Project_Recent_2.png differ diff --git a/docs/IDE/Images/New_Project_Samples.light.png b/docs/IDE/Images/New_Project_Samples.light.png index aaa30fce9..d6764f94b 100644 Binary files a/docs/IDE/Images/New_Project_Samples.light.png and b/docs/IDE/Images/New_Project_Samples.light.png differ diff --git a/docs/IDE/Images/New_Project_Samples.png b/docs/IDE/Images/New_Project_Samples.png index 85009eaf5..d6fe21932 100644 Binary files a/docs/IDE/Images/New_Project_Samples.png and b/docs/IDE/Images/New_Project_Samples.png differ diff --git a/docs/IDE/Images/OpenEditors_1.light.png b/docs/IDE/Images/OpenEditors_1.light.png index a54fafe2b..7f85a0ccd 100644 Binary files a/docs/IDE/Images/OpenEditors_1.light.png and b/docs/IDE/Images/OpenEditors_1.light.png differ diff --git a/docs/IDE/Images/OpenEditors_1.png b/docs/IDE/Images/OpenEditors_1.png index 4e3b350b1..27e2ad184 100644 Binary files a/docs/IDE/Images/OpenEditors_1.png and b/docs/IDE/Images/OpenEditors_1.png differ diff --git a/docs/IDE/Images/Outline_1.png b/docs/IDE/Images/Outline_1.png index 954791332..dbfc1539d 100644 Binary files a/docs/IDE/Images/Outline_1.png and b/docs/IDE/Images/Outline_1.png differ diff --git a/docs/IDE/Images/PackagePublishing.png b/docs/IDE/Images/PackagePublishing.png index 77012a91f..46be9c6cf 100644 Binary files a/docs/IDE/Images/PackagePublishing.png and b/docs/IDE/Images/PackagePublishing.png differ diff --git a/docs/IDE/Images/PackagePublishing_1.light.png b/docs/IDE/Images/PackagePublishing_1.light.png index 85b2f56bb..a3cdde859 100644 Binary files a/docs/IDE/Images/PackagePublishing_1.light.png and b/docs/IDE/Images/PackagePublishing_1.light.png differ diff --git a/docs/IDE/Images/PackagePublishing_1.png b/docs/IDE/Images/PackagePublishing_1.png index dec630318..6dd21a525 100644 Binary files a/docs/IDE/Images/PackagePublishing_1.png and b/docs/IDE/Images/PackagePublishing_1.png differ diff --git a/docs/IDE/Images/ProjectExplorer_Header.light.png b/docs/IDE/Images/ProjectExplorer_Header.light.png index a26cdf374..98eca93b5 100644 Binary files a/docs/IDE/Images/ProjectExplorer_Header.light.png and b/docs/IDE/Images/ProjectExplorer_Header.light.png differ diff --git a/docs/IDE/Images/ProjectExplorer_Header.png b/docs/IDE/Images/ProjectExplorer_Header.png index 6b5cd8dc2..e43d14a30 100644 Binary files a/docs/IDE/Images/ProjectExplorer_Header.png and b/docs/IDE/Images/ProjectExplorer_Header.png differ diff --git a/docs/IDE/Images/ProjectExplorer_Sample.light.png b/docs/IDE/Images/ProjectExplorer_Sample.light.png index 90441b94a..1b7ee4ba8 100644 Binary files a/docs/IDE/Images/ProjectExplorer_Sample.light.png and b/docs/IDE/Images/ProjectExplorer_Sample.light.png differ diff --git a/docs/IDE/Images/ProjectExplorer_Sample.png b/docs/IDE/Images/ProjectExplorer_Sample.png index b35df91b6..55f9544ea 100644 Binary files a/docs/IDE/Images/ProjectExplorer_Sample.png and b/docs/IDE/Images/ProjectExplorer_Sample.png differ diff --git a/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.png b/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.png index 1f5d65824..2125a3621 100644 Binary files a/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.png and b/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.png differ diff --git a/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.svg b/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.svg index 40bf1f62c..e6f6ac67d 100644 --- a/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.svg +++ b/docs/IDE/Images/ProjectSettings_AvailableCOMReferences.light.svg @@ -1 +1 @@ -EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelLibrary ReferencesEnabled LibrariesAvailable COM ReferencesAvailable PackagesSelect references that will be used during compilation of this projectImport from file..................................................................ABBYY FineReader 16 SharePoint Integration Component16.2026AccessibilityCplAdmin 1.0 Type Library1.0Acrobat1.0Acrobat Access 3.0 Type Library3.0AcroBrokerLib1.0Active DS Type Library1.0Active Messaging Object Library1.1ActiveMovie control type library1.0ActiveX DLL to perform Migration of MS Repository V1 to V211.0AddinLoaderLib1.0Adobe Acrobat 1.0 WebView Proxy Type Library1.0Adobe Acrobat 10.0 Type Library1.1Adobe Acrobat Browser Control Type Library 1.01.0Adobe Acrobat File Preview Type Library1.0AFormAut 1.0 Type Library1.0AgentWmiLib1.0AirplaneMode Interfaces1.0AP Client 1.0 HelpPane Type Library1.0AP Client 1.0 Type Library1.0AppIdPolicyEngineApi 1.0 Type Library1.0Apple Bonjour Library 1.01.0Library SymbolVersionPublisherproject.referencesApply Changes +EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelLibrary ReferencesEnabled LibrariesAvailable COM ReferencesAvailable PackagesSelect references that will be used during compilation of this projectImport from file..................................................................ABBYY FineReader 16 SharePoint Integration Component16.2026AccessibilityCplAdmin 1.0 Type Library1.0Acrobat1.0Acrobat Access 3.0 Type Library3.0AcroBrokerLib1.0Active DS Type Library1.0Active Messaging Object Library1.1ActiveMovie control type library1.0ActiveX DLL to perform Migration of MS Repository V1 to V211.0AddinLoaderLib1.0Adobe Acrobat 1.0 WebView Proxy Type Library1.0Adobe Acrobat 10.0 Type Library1.1Adobe Acrobat Browser Control Type Library 1.01.0Adobe Acrobat File Preview Type Library1.0AFormAut 1.0 Type Library1.0AgentWmiLib1.0AirplaneMode Interfaces1.0AP Client 1.0 HelpPane Type Library1.0AP Client 1.0 Type Library1.0AppIdPolicyEngineApi 1.0 Type Library1.0Apple Bonjour Library 1.01.0Library SymbolVersionPublisherproject.referencesApply Changes diff --git a/docs/IDE/Images/ProjectSettings_LibraryReferences.light.png b/docs/IDE/Images/ProjectSettings_LibraryReferences.light.png index b8c40c4c6..d61cfb5ef 100644 Binary files a/docs/IDE/Images/ProjectSettings_LibraryReferences.light.png and b/docs/IDE/Images/ProjectSettings_LibraryReferences.light.png differ diff --git a/docs/IDE/Images/ProjectSettings_LibraryReferences.light.svg b/docs/IDE/Images/ProjectSettings_LibraryReferences.light.svg index dafe50809..56ac47fde 100644 --- a/docs/IDE/Images/ProjectSettings_LibraryReferences.light.svg +++ b/docs/IDE/Images/ProjectSettings_LibraryReferences.light.svg @@ -1 +1 @@ -EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelLibrary ReferencesEnabled LibrariesAvailable COM ReferencesAvailable PackagesSelect references that will be used during compilation of this projectImport from file...VBAVBRUNstdoletbIDEtwinBASIC - VBA Compatibility Package0.0.0.1[BUILT-IN]twinBASIC - VBRUN Compatibility Package0.0.0.1[BUILT-IN]OLE Automation2.0twinBASIC - IDE Extensibility Package0.0.0.1[BUILT-IN]🖉🖉🖉🖉Library SymbolNamein order of priorityVersionPublisherproject.referencesApply Changes +EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelLibrary ReferencesEnabled LibrariesAvailable COM ReferencesAvailable PackagesSelect references that will be used during compilation of this projectImport from file...VBAVBRUNstdoletbIDEtwinBASIC - VBA Compatibility Package0.0.0.1[BUILT-IN]twinBASIC - VBRUN Compatibility Package0.0.0.1[BUILT-IN]OLE Automation2.0twinBASIC - IDE Extensibility Package0.0.0.1[BUILT-IN]🖉🖉🖉🖉Library SymbolNamein order of priorityVersionPublisherproject.referencesApply Changes diff --git a/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.light.png b/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.light.png index cf5e3565c..eb762e9a7 100644 Binary files a/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.light.png and b/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.light.png differ diff --git a/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.png b/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.png index a97c0b3be..0acf09db9 100644 Binary files a/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.png and b/docs/IDE/Images/RightClick-Add-CustomControlsForm-Popup.png differ diff --git a/docs/IDE/Images/Services_Operational.light.png b/docs/IDE/Images/Services_Operational.light.png index 258c489db..7b6510513 100644 Binary files a/docs/IDE/Images/Services_Operational.light.png and b/docs/IDE/Images/Services_Operational.light.png differ diff --git a/docs/IDE/Images/Services_Operational.png b/docs/IDE/Images/Services_Operational.png index bd023ef32..0fef3d7e1 100644 Binary files a/docs/IDE/Images/Services_Operational.png and b/docs/IDE/Images/Services_Operational.png differ diff --git a/docs/IDE/Images/Services_Operational_Tooltip.png b/docs/IDE/Images/Services_Operational_Tooltip.png index 58ec8bf6c..cf529a4a2 100644 Binary files a/docs/IDE/Images/Services_Operational_Tooltip.png and b/docs/IDE/Images/Services_Operational_Tooltip.png differ diff --git a/docs/IDE/Images/Services_Unavailable_Tooltip.png b/docs/IDE/Images/Services_Unavailable_Tooltip.png index a7479df77..23f79dfbc 100644 Binary files a/docs/IDE/Images/Services_Unavailable_Tooltip.png and b/docs/IDE/Images/Services_Unavailable_Tooltip.png differ diff --git a/docs/IDE/Images/Settings.light.png b/docs/IDE/Images/Settings.light.png index d4cadf21e..384ca6d19 100644 Binary files a/docs/IDE/Images/Settings.light.png and b/docs/IDE/Images/Settings.light.png differ diff --git a/docs/IDE/Images/Settings.png b/docs/IDE/Images/Settings.png index a414f0659..1cf170573 100644 Binary files a/docs/IDE/Images/Settings.png and b/docs/IDE/Images/Settings.png differ diff --git a/docs/IDE/Images/Splash_Screen.light.png b/docs/IDE/Images/Splash_Screen.light.png index 5772eb5c4..96f0d6834 100644 Binary files a/docs/IDE/Images/Splash_Screen.light.png and b/docs/IDE/Images/Splash_Screen.light.png differ diff --git a/docs/IDE/Images/Splash_Screen.png b/docs/IDE/Images/Splash_Screen.png index 8b6fbd35d..9fd9eee4c 100644 Binary files a/docs/IDE/Images/Splash_Screen.png and b/docs/IDE/Images/Splash_Screen.png differ diff --git a/docs/IDE/Images/StatusBar.png b/docs/IDE/Images/StatusBar.png index 696dff685..c99f78d0f 100644 Binary files a/docs/IDE/Images/StatusBar.png and b/docs/IDE/Images/StatusBar.png differ diff --git a/docs/IDE/Images/Toggle.light.png b/docs/IDE/Images/Toggle.light.png index 30595a465..d8951cada 100644 Binary files a/docs/IDE/Images/Toggle.light.png and b/docs/IDE/Images/Toggle.light.png differ diff --git a/docs/IDE/Images/Toggle.png b/docs/IDE/Images/Toggle.png index c06922067..7c9799f3c 100644 Binary files a/docs/IDE/Images/Toggle.png and b/docs/IDE/Images/Toggle.png differ diff --git a/docs/IDE/Images/Toolbar_1.light.png b/docs/IDE/Images/Toolbar_1.light.png index 0a048cb68..53f0ca3f4 100644 Binary files a/docs/IDE/Images/Toolbar_1.light.png and b/docs/IDE/Images/Toolbar_1.light.png differ diff --git a/docs/IDE/Images/Toolbar_1.png b/docs/IDE/Images/Toolbar_1.png index a08c7e26e..47c4bf688 100644 Binary files a/docs/IDE/Images/Toolbar_1.png and b/docs/IDE/Images/Toolbar_1.png differ diff --git a/docs/IDE/Images/Toolbar_2.light.png b/docs/IDE/Images/Toolbar_2.light.png index e911a8029..5f7ba4ceb 100644 Binary files a/docs/IDE/Images/Toolbar_2.light.png and b/docs/IDE/Images/Toolbar_2.light.png differ diff --git a/docs/IDE/Images/Toolbar_2.png b/docs/IDE/Images/Toolbar_2.png index f56d70d3a..46a9ed6b0 100644 Binary files a/docs/IDE/Images/Toolbar_2.png and b/docs/IDE/Images/Toolbar_2.png differ diff --git a/docs/IDE/Images/Toolbar_3.light.png b/docs/IDE/Images/Toolbar_3.light.png index f8c870207..70f0e6d68 100644 Binary files a/docs/IDE/Images/Toolbar_3.light.png and b/docs/IDE/Images/Toolbar_3.light.png differ diff --git a/docs/IDE/Images/Toolbar_3.png b/docs/IDE/Images/Toolbar_3.png index 0f06729ac..7d27df43b 100644 Binary files a/docs/IDE/Images/Toolbar_3.png and b/docs/IDE/Images/Toolbar_3.png differ diff --git a/docs/IDE/Images/Toolbar_4.light.png b/docs/IDE/Images/Toolbar_4.light.png index f0f5394b8..702d3c448 100644 Binary files a/docs/IDE/Images/Toolbar_4.light.png and b/docs/IDE/Images/Toolbar_4.light.png differ diff --git a/docs/IDE/Images/Toolbar_4.png b/docs/IDE/Images/Toolbar_4.png index ea1f12b9b..137e43943 100644 Binary files a/docs/IDE/Images/Toolbar_4.png and b/docs/IDE/Images/Toolbar_4.png differ diff --git a/docs/IDE/Images/Toolbox_MoreComponents.light.png b/docs/IDE/Images/Toolbox_MoreComponents.light.png index 4cfe2b997..03e05d05d 100644 Binary files a/docs/IDE/Images/Toolbox_MoreComponents.light.png and b/docs/IDE/Images/Toolbox_MoreComponents.light.png differ diff --git a/docs/IDE/Images/Toolbox_MoreComponents.png b/docs/IDE/Images/Toolbox_MoreComponents.png index f9d652ec7..4b9937d44 100644 Binary files a/docs/IDE/Images/Toolbox_MoreComponents.png and b/docs/IDE/Images/Toolbox_MoreComponents.png differ diff --git a/docs/IDE/Images/Toolbox_Report.light.png b/docs/IDE/Images/Toolbox_Report.light.png index 1185c1129..ba847c7d8 100644 Binary files a/docs/IDE/Images/Toolbox_Report.light.png and b/docs/IDE/Images/Toolbox_Report.light.png differ diff --git a/docs/IDE/Images/Toolbox_Report.png b/docs/IDE/Images/Toolbox_Report.png index c0662b80f..4d9c5701e 100644 Binary files a/docs/IDE/Images/Toolbox_Report.png and b/docs/IDE/Images/Toolbox_Report.png differ diff --git a/docs/IDE/Images/Watches_1.light.png b/docs/IDE/Images/Watches_1.light.png index a28851f63..882508c7b 100644 Binary files a/docs/IDE/Images/Watches_1.light.png and b/docs/IDE/Images/Watches_1.light.png differ diff --git a/docs/IDE/Images/Watches_1.png b/docs/IDE/Images/Watches_1.png index af7f6ecf1..208c0f740 100644 Binary files a/docs/IDE/Images/Watches_1.png and b/docs/IDE/Images/Watches_1.png differ diff --git a/docs/IDE/Images/Watches_2.light.png b/docs/IDE/Images/Watches_2.light.png index 9daff5d47..e6c106247 100644 Binary files a/docs/IDE/Images/Watches_2.light.png and b/docs/IDE/Images/Watches_2.light.png differ diff --git a/docs/IDE/Images/Watches_2.png b/docs/IDE/Images/Watches_2.png index b538f5e69..f6a8c1231 100644 Binary files a/docs/IDE/Images/Watches_2.png and b/docs/IDE/Images/Watches_2.png differ diff --git a/docs/IDE/Images/Webpage.light.png b/docs/IDE/Images/Webpage.light.png index 3b734ac64..721197301 100644 Binary files a/docs/IDE/Images/Webpage.light.png and b/docs/IDE/Images/Webpage.light.png differ diff --git a/docs/IDE/Images/Webpage.png b/docs/IDE/Images/Webpage.png index 8f49f9272..6bec0c763 100644 Binary files a/docs/IDE/Images/Webpage.png and b/docs/IDE/Images/Webpage.png differ diff --git a/docs/IDE/Images/tB-Blue.light.png b/docs/IDE/Images/tB-Blue.light.png index 47aa4d3dc..4f32ef13f 100644 Binary files a/docs/IDE/Images/tB-Blue.light.png and b/docs/IDE/Images/tB-Blue.light.png differ diff --git a/docs/IDE/Images/tB-Blue.png b/docs/IDE/Images/tB-Blue.png index 0d4e102f9..257b1e9bc 100644 Binary files a/docs/IDE/Images/tB-Blue.png and b/docs/IDE/Images/tB-Blue.png differ diff --git a/docs/IDE/Images/tB-Green.light.png b/docs/IDE/Images/tB-Green.light.png index 215fddad6..ff898a226 100644 Binary files a/docs/IDE/Images/tB-Green.light.png and b/docs/IDE/Images/tB-Green.light.png differ diff --git a/docs/IDE/Images/tB-Green.png b/docs/IDE/Images/tB-Green.png index 9ec317d5d..72ba7abbd 100644 Binary files a/docs/IDE/Images/tB-Green.png and b/docs/IDE/Images/tB-Green.png differ diff --git a/docs/IDE/Images/tB-Orange.light.png b/docs/IDE/Images/tB-Orange.light.png index fafb3c431..1eb7fe3aa 100644 Binary files a/docs/IDE/Images/tB-Orange.light.png and b/docs/IDE/Images/tB-Orange.light.png differ diff --git a/docs/IDE/Images/tB-Orange.png b/docs/IDE/Images/tB-Orange.png index cae282013..62e06ca6b 100644 Binary files a/docs/IDE/Images/tB-Orange.png and b/docs/IDE/Images/tB-Orange.png differ diff --git a/docs/IDE/Images/tB-Red.light.png b/docs/IDE/Images/tB-Red.light.png index 8dbfa5c00..9cd30c811 100644 Binary files a/docs/IDE/Images/tB-Red.light.png and b/docs/IDE/Images/tB-Red.light.png differ diff --git a/docs/IDE/Images/tB-Red.png b/docs/IDE/Images/tB-Red.png index f264e3b7b..aa6fa9a0c 100644 Binary files a/docs/IDE/Images/tB-Red.png and b/docs/IDE/Images/tB-Red.png differ diff --git a/docs/IDE/Images/tbForm.light.png b/docs/IDE/Images/tbForm.light.png index 24509e752..5b643f49a 100644 Binary files a/docs/IDE/Images/tbForm.light.png and b/docs/IDE/Images/tbForm.light.png differ diff --git a/docs/IDE/Images/tbForm.png b/docs/IDE/Images/tbForm.png index 01ff199b6..bade96c8d 100644 Binary files a/docs/IDE/Images/tbForm.png and b/docs/IDE/Images/tbForm.png differ diff --git a/docs/IDE/Images/tbReport.light.png b/docs/IDE/Images/tbReport.light.png index 22f545057..a7b598232 100644 Binary files a/docs/IDE/Images/tbReport.light.png and b/docs/IDE/Images/tbReport.light.png differ diff --git a/docs/IDE/Images/tbReport.png b/docs/IDE/Images/tbReport.png index 33690f8a0..736d4dd79 100644 Binary files a/docs/IDE/Images/tbReport.png and b/docs/IDE/Images/tbReport.png differ diff --git a/docs/IDE/Menu/Images/Menu.png b/docs/IDE/Menu/Images/Menu.png index f34c67293..f523f5687 100644 Binary files a/docs/IDE/Menu/Images/Menu.png and b/docs/IDE/Menu/Images/Menu.png differ diff --git a/docs/IDE/Menu/Images/Menu_Add-Ins.light.png b/docs/IDE/Menu/Images/Menu_Add-Ins.light.png index 2520e0246..f27be0657 100644 Binary files a/docs/IDE/Menu/Images/Menu_Add-Ins.light.png and b/docs/IDE/Menu/Images/Menu_Add-Ins.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Add-Ins.png b/docs/IDE/Menu/Images/Menu_Add-Ins.png index 1d05082f4..9898da8ed 100644 Binary files a/docs/IDE/Menu/Images/Menu_Add-Ins.png and b/docs/IDE/Menu/Images/Menu_Add-Ins.png differ diff --git a/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.light.png b/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.light.png index 329e942e6..b7351a31c 100644 Binary files a/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.light.png and b/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.png b/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.png index 6b3007828..992289854 100644 Binary files a/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.png and b/docs/IDE/Menu/Images/Menu_Add-Ins_GlobalSearch.png differ diff --git a/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.light.png b/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.light.png index 32d56a13b..b9d66daeb 100644 Binary files a/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.light.png and b/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.png b/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.png index b3ea8eaac..7f18721a4 100644 Binary files a/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.png and b/docs/IDE/Menu/Images/Menu_Debug_DebuggerOptions.png differ diff --git a/docs/IDE/Menu/Images/Menu_Edit.png b/docs/IDE/Menu/Images/Menu_Edit.png index c4d65ff6b..8ef053ef1 100644 Binary files a/docs/IDE/Menu/Images/Menu_Edit.png and b/docs/IDE/Menu/Images/Menu_Edit.png differ diff --git a/docs/IDE/Menu/Images/Menu_File.light.png b/docs/IDE/Menu/Images/Menu_File.light.png index 9d00146a9..28d4627f0 100644 Binary files a/docs/IDE/Menu/Images/Menu_File.light.png and b/docs/IDE/Menu/Images/Menu_File.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_File.png b/docs/IDE/Menu/Images/Menu_File.png index 5325f2509..d3ccfc081 100644 Binary files a/docs/IDE/Menu/Images/Menu_File.png and b/docs/IDE/Menu/Images/Menu_File.png differ diff --git a/docs/IDE/Menu/Images/Menu_Format.light.png b/docs/IDE/Menu/Images/Menu_Format.light.png index b2c7e63e8..0ff9c5528 100644 Binary files a/docs/IDE/Menu/Images/Menu_Format.light.png and b/docs/IDE/Menu/Images/Menu_Format.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Format.png b/docs/IDE/Menu/Images/Menu_Format.png index d6be785cd..bbc856a97 100644 Binary files a/docs/IDE/Menu/Images/Menu_Format.png and b/docs/IDE/Menu/Images/Menu_Format.png differ diff --git a/docs/IDE/Menu/Images/Menu_Help_About.light.png b/docs/IDE/Menu/Images/Menu_Help_About.light.png index a432be794..d745dd19f 100644 Binary files a/docs/IDE/Menu/Images/Menu_Help_About.light.png and b/docs/IDE/Menu/Images/Menu_Help_About.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Help_About.png b/docs/IDE/Menu/Images/Menu_Help_About.png index ae115f105..e0509c6a9 100644 Binary files a/docs/IDE/Menu/Images/Menu_Help_About.png and b/docs/IDE/Menu/Images/Menu_Help_About.png differ diff --git a/docs/IDE/Menu/Images/Menu_Project.light.png b/docs/IDE/Menu/Images/Menu_Project.light.png index 328fa5eae..f8c16d308 100644 Binary files a/docs/IDE/Menu/Images/Menu_Project.light.png and b/docs/IDE/Menu/Images/Menu_Project.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Project.png b/docs/IDE/Menu/Images/Menu_Project.png index 994e52af0..976254cf4 100644 Binary files a/docs/IDE/Menu/Images/Menu_Project.png and b/docs/IDE/Menu/Images/Menu_Project.png differ diff --git a/docs/IDE/Menu/Images/Menu_Run.light.png b/docs/IDE/Menu/Images/Menu_Run.light.png index 70a3db055..af93c3119 100644 Binary files a/docs/IDE/Menu/Images/Menu_Run.light.png and b/docs/IDE/Menu/Images/Menu_Run.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Run.png b/docs/IDE/Menu/Images/Menu_Run.png index b04d2bbfb..906c9758d 100644 Binary files a/docs/IDE/Menu/Images/Menu_Run.png and b/docs/IDE/Menu/Images/Menu_Run.png differ diff --git a/docs/IDE/Menu/Images/Menu_Tools.light.png b/docs/IDE/Menu/Images/Menu_Tools.light.png index a67a90055..9e26e9a04 100644 Binary files a/docs/IDE/Menu/Images/Menu_Tools.light.png and b/docs/IDE/Menu/Images/Menu_Tools.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Tools.png b/docs/IDE/Menu/Images/Menu_Tools.png index cb95cf39b..16d34d47b 100644 Binary files a/docs/IDE/Menu/Images/Menu_Tools.png and b/docs/IDE/Menu/Images/Menu_Tools.png differ diff --git a/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.light.png b/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.light.png index aa3e872d7..3d5d689c4 100644 Binary files a/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.light.png and b/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.light.png differ diff --git a/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.png b/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.png index ed7d8bb97..e5eb3a17d 100644 Binary files a/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.png and b/docs/IDE/Menu/Images/Menu_Tools_IDEOptions.png differ diff --git a/docs/IDE/Menu/Images/Menu_Window.png b/docs/IDE/Menu/Images/Menu_Window.png index b8f33ffa1..dfffcc09b 100644 Binary files a/docs/IDE/Menu/Images/Menu_Window.png and b/docs/IDE/Menu/Images/Menu_Window.png differ diff --git a/docs/IDE/Reports/Images/Report_Controls.light.png b/docs/IDE/Reports/Images/Report_Controls.light.png index bc1675810..13c0ea5d5 100644 Binary files a/docs/IDE/Reports/Images/Report_Controls.light.png and b/docs/IDE/Reports/Images/Report_Controls.light.png differ diff --git a/docs/IDE/Reports/Images/Report_Controls.png b/docs/IDE/Reports/Images/Report_Controls.png index f7f39470a..d5a876ba4 100644 Binary files a/docs/IDE/Reports/Images/Report_Controls.png and b/docs/IDE/Reports/Images/Report_Controls.png differ diff --git a/docs/LLVM/Getting-Started.md b/docs/LLVM/Getting-Started.md index 84e49dcef..afe060a69 100644 --- a/docs/LLVM/Getting-Started.md +++ b/docs/LLVM/Getting-Started.md @@ -64,7 +64,7 @@ The main feature not yet supported is passing an error up to the calling procedu > An error handler in a procedure compiled with LLVM cannot read an error raised with [**Err.Raise**](../tB/Modules/ErrObject/Raise) in that procedure: **Err.Number** returns -353703423 (`&HEAEAEA01`), **Err.Source** is empty, and **Err.Description** is the generic "Application-defined or object-defined error". An error that a statement causes, such as a division by zero, is read correctly. > [!WARNING] BETA 1005 -> A **Double** addition, subtraction, multiplication or exponentiation (`^`) that overflows raises no error in code compiled with LLVM: the result is infinity (`1.#INF`), where the same code compiled without LLVM raises error 6, *Overflow*, as VB6 does. [**FloatingPointErrorChecks(True)**](../tB/Core/Attributes#floatingpointerrorchecks) does not change this. A **Double** division that overflows, and a division by zero, still raise their errors. After either, under `On Error Resume Next`, the variable that was to receive the result keeps its old value; without LLVM it holds infinity. +> A **Double** addition, subtraction, multiplication or exponentiation (`^`) that overflows raises no error in code compiled with LLVM: the result of the first three is infinity (`1.#INF` or `-1.#INF`) and the result of `^` is 0, where the same code compiled without LLVM raises error 6, *Overflow*, as VB6 does. [**FloatingPointErrorChecks(True)**](../tB/Core/Attributes#floatingpointerrorchecks) does not change this. A **Double** division that overflows, and a division by zero, still raise their errors. After either, under `On Error Resume Next`, the variable that was to receive the result keeps its old value; without LLVM it holds infinity. > [!WARNING] BETA 1005 > Code compiled with LLVM rounds a **Single** or **Double** that is exactly halfway between two integers away from zero when it converts the value to an integer type: in [**CLng**](../tB/Modules/Conversion/CLng), **CInt** and **CLngLng** of a variable, in an assignment to an **Integer** or **Long**, and in the operands of [**\\**](../tB/Core/IntegerDivide). With a **Double** variable holding 2.5, `CLng(x)` is 3, and with -0.5 it is -1. Without LLVM the value is rounded to the even integer, 2 and 0, as VB6 does. A constant expression such as `CLng(2.5)`, a **Variant** argument, and [**Round**](../tB/Modules/Math/Round), **Int** and **Fix** are not affected. @@ -99,6 +99,9 @@ Public Sub DoNotOptimizeMe() End Sub ``` +> [!WARNING] BETA 1005 +> A run in the IDE with LLVM turned on for the whole project under **Compiler Options (DEBUG)** ends with an access violation when a procedure marked `[CompilerOptions("")]` calls a procedure that is compiled with LLVM, and `Sub Main` reaches the marked procedure: it calls it, or calls a procedure that does. A marked procedure that `Sub Main` does not reach is not affected, and neither is a built program. + The same attribute can also turn LLVM on for chosen procedures when it is off in Project Settings. List the flags, separated by commas: `+llvm`, `+optimize` and `+optimizesize`, then `+` and the name of each CPU instruction set to use. Each flag is the direct equivalent of an option in Project Settings: `+llvm` @@ -112,6 +115,8 @@ The same attribute can also turn LLVM on for chosen procedures when it is off in The flags for CPU instruction sets, one for each **LLVM: Target CPUs with** box, are `+aes`, `+avx`, `+avx2`, `+bmi2`, `+fma`, `+fxsr`, `+lzcnt`, `+popcnt`, `+rdseed`, `+sha`, `+sse`, `+sse2`, `+sse3`, `+sse4.1`, `+sse4.2`, `+ssse3`, `+xsave`, `+xsavec`, `+xsaveopt` and `+xsaves`. +The attribute replaces the project's options for that procedure, and the other flags do not turn LLVM on by themselves: `[CompilerOptions("+optimize")]` compiles the procedure without LLVM, whatever the project settings say. Flags may be separated by commas, by spaces or by commas and spaces. + For example: ```tb check_build diff --git a/docs/LLVM/Images/llvmdoc1.light.png b/docs/LLVM/Images/llvmdoc1.light.png index 043a1a12b..3c0306231 100644 Binary files a/docs/LLVM/Images/llvmdoc1.light.png and b/docs/LLVM/Images/llvmdoc1.light.png differ diff --git a/docs/LLVM/Images/llvmdoc1.light.svg b/docs/LLVM/Images/llvmdoc1.light.svg index 9183c1607..94cf21cc3 100644 --- a/docs/LLVM/Images/llvmdoc1.light.svg +++ b/docs/LLVM/Images/llvmdoc1.light.svg @@ -1 +1 @@ -EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelSlider ControlTreeView ControlUpDown ControlCompress Runtime Class Dispatch InfoCompress Runtime Error TablesCompress Misc DataButtons support Graphical styleRuntime PNG support (via Global.LoadPicture)Here you can disable certain project features in order to reduce the compiled build size.Compiler Options (BUILD)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to built executables.NOTE: If you enable targeting for a specific CPU architecture feature, your software will not run on any CPU that does not support that feature.Compiler Options (DEBUG)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to the IDE environment.NOTE: Enabling LLVM compilation in the IDE debug environment is NOT recommended. You will not be able to debug LLVMcompiled code.(enter text to filter)Apply Changes +EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶Apply ChangesCancelSlider ControlTreeView ControlUpDown ControlCompress Runtime Class Dispatch InfoCompress Runtime Error TablesCompress Misc DataButtons support Graphical styleRuntime PNG support (via Global.LoadPicture)Here you can disable certain project features in order to reduce the compiled build size.Compiler Options (BUILD)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to built executables.NOTE: If you enable targeting for a specific CPU architecture feature, your software will not run on any CPU that does not support that feature.Compiler Options (DEBUG)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to the IDE environment.NOTE: Enabling LLVM compilation in the IDE debug environment is NOT recommended. You will not be able to debug LLVMcompiled code.(enter text to filter) diff --git a/docs/LLVM/Images/llvmdoc1.png b/docs/LLVM/Images/llvmdoc1.png index 99ad6f083..b34d24189 100644 Binary files a/docs/LLVM/Images/llvmdoc1.png and b/docs/LLVM/Images/llvmdoc1.png differ diff --git a/docs/LLVM/Images/llvmdoc1.svg b/docs/LLVM/Images/llvmdoc1.svg index a7ae5a801..695af7ad7 100644 --- a/docs/LLVM/Images/llvmdoc1.svg +++ b/docs/LLVM/Images/llvmdoc1.svg @@ -1 +1 @@ -win32100%EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶CancelSlider ControlTreeView ControlUpDown ControlCompress Runtime Class Dispatch InfoCompress Runtime Error TablesCompress Misc DataButtons support Graphical styleRuntime PNG support (via Global.LoadPicture)Here you can disable certain project features in order to reduce the compiled build size.Compiler Options (BUILD)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to built executables.NOTE: If you enable targeting for a specific CPU architecture feature, your software will not run on any CPU that does not support that feature.Compiler Options (DEBUG)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to the IDE environment.NOTE: Enabling LLVM compilation in the IDE debug environment is NOT recommended. You will not be able to debug LLVMcompiled code.(enter text to filter)Apply Changes +win32100%EDITOR 1DEBUG CONSOLEDIAGNOSTICS00î­‚0î©´0î©¶CALL STACKî©¶COMPILER [Win32] v0.15.1005MAIN_THREAD [IDLE]VARIABLESî©¶PROJECT EXPLORERSampleProjectImportedTypeLibrariesMiscellaneousPackagesReferencesResourcesSourcesIShape.twinMainModule.twinTypes.twinCHANGELOG.mdLICENCE.mdPROPERTIESProject Settingsî©¶Apply ChangesCancelSlider ControlTreeView ControlUpDown ControlCompress Runtime Class Dispatch InfoCompress Runtime Error TablesCompress Misc DataButtons support Graphical styleRuntime PNG support (via Global.LoadPicture)Here you can disable certain project features in order to reduce the compiled build size.Compiler Options (BUILD)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to built executables.NOTE: If you enable targeting for a specific CPU architecture feature, your software will not run on any CPU that does not support that feature.Compiler Options (DEBUG)Enable LLVM CompilationLLVM: Generate optimized codeLLVM: Optimize for smaller filesizeLLVM: Target CPUs with AESLLVM: Target CPUs with AVXLLVM: Target CPUs with AVX2LLVM: Target CPUs with BMI2LLVM: Target CPUs with FMALLVM: Target CPUs with FXSRLLVM: Target CPUs with LZCNTLLVM: Target CPUs with POPCNTLLVM: Target CPUs with RDSEEDLLVM: Target CPUs with SHALLVM: Target CPUs with SSELLVM: Target CPUs with SSE2LLVM: Target CPUs with SSE3LLVM: Target CPUs with SSE4.1LLVM: Target CPUs with SSE4.2LLVM: Target CPUs with SSSE3LLVM: Target CPUs with XSAVELLVM: Target CPUs with XSAVECLLVM: Target CPUs with XSAVEOPTLLVM: Target CPUs with XSAVESHere you can enable compiler options via a comma-delimited list of flags that will be applied to the IDE environment.NOTE: Enabling LLVM compilation in the IDE debug environment is NOT recommended. You will not be able to debug LLVMcompiled code.(enter text to filter) diff --git a/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.light.png b/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.light.png index d8a59cebc..513745475 100644 Binary files a/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.light.png and b/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.light.png differ diff --git a/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.light.png b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.light.png index a0cd3440c..7f2a4c675 100644 Binary files a/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.light.png and b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.light.png differ diff --git a/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png index 78666b261..c538ce785 100644 Binary files a/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png and b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png differ diff --git a/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.light.png b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.light.png index c4cb2037e..cc40fcec4 100644 Binary files a/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.light.png and b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.light.png differ diff --git a/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png index 56eeaed3f..022031183 100644 Binary files a/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png and b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png differ diff --git a/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.light.png b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.light.png index 4bfe03a7c..2345d63f4 100644 Binary files a/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.light.png and b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.light.png differ diff --git a/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png index a873bfbc2..7d286409d 100644 Binary files a/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png and b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png differ diff --git a/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.light.png b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.light.png index b0f0bca14..d1fcf4bab 100644 Binary files a/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.light.png and b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.light.png differ diff --git a/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png index 78c3c0fbb..37144d407 100644 Binary files a/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png and b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png differ diff --git a/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png b/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png index 0448840c8..90b6c5a7b 100644 Binary files a/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png and b/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png differ diff --git a/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.light.png b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.light.png index 594a88dee..1f400e35b 100644 Binary files a/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.light.png and b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.light.png differ diff --git a/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png index e5b5c6882..5cd557c23 100644 Binary files a/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png and b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png differ diff --git a/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png index 870920807..00f0f0a99 100644 Binary files a/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png and b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png differ diff --git a/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.svg b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.svg index 06719486f..c5556923a 100644 --- a/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.svg +++ b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.svg @@ -1 +1 @@ -â–¾ Assets3twinBASIC_IDE_BETA_1005.zip39.3 MByesterdaySource code (zip)Jun 29Source code (tar.gz)Jun 29sha256:0339c1f969d4b7d5f8f483767840e7ea24b373c2bfc3292869e827b571fa928d +â–¾ Assets3twinBASIC_IDE_BETA_1005.zip39.3 MB5 days agoSource code (zip)Jun 29Source code (tar.gz)Jun 29sha256:0339c1f969d4b7d5f8f483767840e7ea24b373c2bfc3292869e827b571fa928d diff --git a/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.light.png b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.light.png index 27c2a51a7..483e3e395 100644 Binary files a/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.light.png and b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.light.png differ diff --git a/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png index c81331727..d8fa28437 100644 Binary files a/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png and b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png differ diff --git a/docs/Reference/Attributes.md b/docs/Reference/Attributes.md index dddf1f8d4..4d7f0cf1a 100644 --- a/docs/Reference/Attributes.md +++ b/docs/Reference/Attributes.md @@ -39,8 +39,8 @@ Marks a prototype that a class implementing the interface is not obliged to supp The twinBASIC packages use it to add members to an interface without breaking code written against an earlier revision of it. `ItbHostEventsV2` extends `ItbHostEventsV1` and adds one such prototype; `ItbHostEventsV3` extends that and adds another. An addin that implements only the **V1** members still satisfies **V3**. - ## AppObject (optional Bool) @@ -179,7 +179,7 @@ Public Declare Function GetTickCount Lib "kernel32" () As Long ``` + ## DefaultDesignerEvent {: #defaultdesignerevent } @@ -340,11 +342,12 @@ Syntax: **[DefaultDesignerEvent]** Applicable to: [**Event**](Event) declaration in a [**Class**](Class) -Marks the one event a control nominates as its primary one. Each control that declares it declares exactly one: **Click** for **CheckBox** and **CommandButton**, **Change** for **ComboBox**, **Validate** for **Data**. +Marks the event a control nominates as its primary one. Each control of the VB package that declares it declares exactly one: **Click** for **CheckBox** and **CommandButton**, **Change** for **ComboBox**, **Validate** for **Data**. The **ListView** and **TreeView** controls of WinNativeCommonCtls mark two, **Click** and **BeforeLabelEdit**. - ## DefaultMember (optional Bool) @@ -443,10 +446,10 @@ Indicates that the interface exposes methods via **IDispatch** late-binding. Thi It is usually written combined with the other attributes on the interface rather than alone --- `[Hidden, DispInterface, COMExtensible]`. See [**LibraryId**](#libraryid) for what a generated **Library** module looks like. -## DllExport (optional Bool) +## DllExport (optional String) {: #dllexport } -Syntax: **[DllExport** [ **( True** \| **False )** ] **]** +Syntax: **[DllExport** [ **("** export name **")** ] **]** Applicable to: [procedures](../Gloss#procedure) and constants in a module. @@ -457,6 +460,17 @@ It's possible to export a function or constant from standard modules. The compil Public Const MyExportedSymbol As Long = &H00000001 ``` +Without an argument the DLL exports the procedure or constant under its own name. A **String** argument sets the name the DLL exports it under: + +```tb check_build +[DllExport("Add_Numbers")] +Public Function AddNumbers(ByVal a As Long, ByVal b As Long) As Long + Return a + b +End Function +``` + +The attribute takes no **Boolean**: `[DllExport(True)]` and `[DllExport(False)]` are error **TB5163**, *Expected a single String argument*. + ## DLLStackCheck (optional Bool) {: #dllstackcheck } @@ -481,19 +495,23 @@ Indicates that the interface exposes methods through the OLE VTable binding. The See [**LibraryId**](#libraryid) for what a generated **Library** module looks like. -## EnforceErrors (optional Bool) +## EnforceErrors (Warning code list) {: #enforceerrors } -Syntax: **[EnforceErrors** [ **( True** \| **False )** ] **]** +Syntax: **[EnforceErrors** **(** **TBnnnn** [ **,** **TBmmmm** ]... **)** **]** -Applicable to: [procedures](../Gloss#procedure). +Applicable to: [**Class**](Class), [**Module**](Module), [procedure](../Gloss#procedure) + +Reports the named warnings as errors within the class, module or procedure the attribute is applied to. The codes are written bare, as for [IgnoreWarnings](#ignorewarnings). With `[EnforceErrors(TB0009)]` on a procedure, a call to a procedure marked [Unimplemented](#unimplemented) is an error where it would otherwise be warning TB0009. Written bare it is accepted and has no effect. With **True** or **False** in place of a code it is error TB5169, *Expected an error code in the format of TBxxxx*. -## EnforceWarnings (optional Bool) +## EnforceWarnings (Warning code list) {: #enforcewarnings } -Syntax: **[EnforceWarnings** [ **( True** \| **False )** ] **]** +Syntax: **[EnforceWarnings** **(** **TBnnnn** [ **,** **TBmmmm** ]... **)** **]** + +Applicable to: [**Class**](Class), [**Module**](Module), [procedure](../Gloss#procedure) -Applicable to: [procedures](../Gloss#procedure). +Takes warning codes written bare, as [IgnoreWarnings](#ignorewarnings) does. A warning it names is still reported as a warning. With **True** or **False** in place of a code the attribute is TB5169, *Expected an error code in the format of TBxxxx*. ## Enumerator {: #enumerator } @@ -515,8 +533,9 @@ End Property This replaces VB6's hidden `VB_UserMemId = -4` procedure attribute, which twinBASIC still accepts for compatibility. [Custom Enumerators](../../Features/Language/Custom-Enumerators) describes the member's rules, and how a class can implement the enumerator itself. - ## EventsUseDispInterface (optional Bool) @@ -555,7 +575,7 @@ Applicable to: [**Class**](Class) Makes the event interface generated for the class a dispinterface, so events are raised through **IDispatch** by member id rather than through a vtable. VB6 and VBA event sinks expect a dispinterface, so a control meant to be consumed from either sets this. - @@ -603,9 +623,9 @@ Hides the declaration from certain IntelliSense and other lists. It applies to a > [!NOTE] > A **CoClass** can only be hidden whole. Its body holds nothing but **Interface** lines, and the attribute is refused there with TB5155 --- unlike [**Default**](#default) and [**Source**](#source), which are interface-line attributes. It is likewise refused on an **Enum** or [**Type**](Type) declaration, on a **Type** member, and on a procedure parameter. An **Enum** member cannot be hidden either: written before the member on the same line, the attribute is **TB5182**, and on a line of its own inside the **Enum**, `[Hidden]` declares a member named `Hidden` (see [**Enum**](Enum)). - @@ -680,9 +702,9 @@ Elsewhere in the project, `Honk` is callable on a **CCar** and `Diagnostics` is For an overview of the `Implements ... Via` mechanism itself, see [Implements Via for basic inheritance](../../Features/Language/Inheritance#implements-via-for-basic-inheritance). - + bare, and a Public member is unaffected. With (True) the module's call + draws TB5027 as the bare form does; with (False) it compiles as it does + without the attribute. --> ## IntegerOverflowChecks (optional Bool) {: #integeroverflowchecks } @@ -794,7 +818,7 @@ Public Sub Draw() End Sub ``` -On a class, a member of a class, or an **Enum** in a class, the attribute is error **TB5155**, *This attribute is not supported in this context*. +On a class the attribute is error **TB5155**, *This attribute is not supported in this context*. On a member of a class, or on an **Enum** in a class, it is error **TB5182**, *Syntax error. No handler for this symbol*. ## NonBrowsable (optional Bool) {: #nonbrowsable } @@ -807,9 +831,9 @@ Keeps a member out of the surfaces that list a class's members, while leaving it This is distinct from [Hidden](#hidden), which reaches the same member as well as the whole type, and from [Restricted](#restricted). - ## OleAutomation (optional Bool) @@ -951,11 +975,13 @@ End Interface ``` ## Restricted (optional Bool) @@ -1035,7 +1061,9 @@ Allows an explicitly loaded DLL to load its own dependencies from it's load path Syntax: **[SimplerByVals** [ **( True** \| **False )** ] **]** -Applicable to: [procedure](../Gloss#procedure) +Applicable to: [procedures](../Gloss#procedure) and [**Declare**](Declare) statements in a [**Module**](Module) + +On a procedure in a **Class** or an **Interface**, and on a **Declare** in a class, the attribute is error **TB5182**, *Syntax error. No handler for this symbol*. ## Source {: #source } @@ -1057,10 +1085,10 @@ End CoClass The pairing is a convention rather than a requirement -- `[Source]` on its own compiles, and marks the interface as a source of events without making it the default one. - + ## SpecialCompilerBinding (Integer) {: #specialcompilerbinding } @@ -1077,7 +1105,8 @@ Binds the member to one of the compiler's own internal implementations, selected The numbers the VB package uses, should you meet one while reading its source: `(1)` and `(2)` on the `GlobalLoad` and `GlobalUnload` declares, `(3)` on a generic `Item` property, `(4)` on `IdleMessageLoopBreakpoint`, and `(254)` on **Form**'s `Show`, where a comment in the source says it "prevents ClassBeforeFirstMemberAccessFunc for this member". @@ -1163,8 +1192,9 @@ The VB package supplies that one as `Miscellaneous/ICONS24/Checkbox24.png` and a Compare [CustomControl](#customcontrol), which takes one image path and no size placeholder. @@ -1184,7 +1214,7 @@ The **MyCOMAddin** sample states the consequence directly: the attribute "is nee Implements IRibbonExtensibility ``` - diff --git a/docs/Reference/Built-In/AppGlobalClassObject/index.md b/docs/Reference/Built-In/AppGlobalClassObject/index.md index 6c191c49f..b392b3bfc 100644 --- a/docs/Reference/Built-In/AppGlobalClassObject/index.md +++ b/docs/Reference/Built-In/AppGlobalClassObject/index.md @@ -5,7 +5,7 @@ permalink: /tB/Packages/AppGlobalClassObject/ has_toc: false exclude_from_docs: - InternalStuff -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # AppGlobalClassObject Package diff --git a/docs/Reference/Built-In/CEF/index.md b/docs/Reference/Built-In/CEF/index.md index b0c009b7a..512859bc6 100644 --- a/docs/Reference/Built-In/CEF/index.md +++ b/docs/Reference/Built-In/CEF/index.md @@ -5,7 +5,7 @@ parent: Built-In Packages nav_order: 6 permalink: /tB/Packages/CEF/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # CEF Package diff --git a/docs/Reference/Built-In/CustomControls/index.md b/docs/Reference/Built-In/CustomControls/index.md index 841e165b8..e76324353 100644 --- a/docs/Reference/Built-In/CustomControls/index.md +++ b/docs/Reference/Built-In/CustomControls/index.md @@ -5,7 +5,7 @@ parent: Built-In Packages nav_order: 5 permalink: /tB/Packages/CustomControls/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # CustomControls Package diff --git a/docs/Reference/Built-In/TwinBasicAssertions/index.md b/docs/Reference/Built-In/TwinBasicAssertions/index.md index 94efa96e0..9bef4ba7c 100644 --- a/docs/Reference/Built-In/TwinBasicAssertions/index.md +++ b/docs/Reference/Built-In/TwinBasicAssertions/index.md @@ -4,7 +4,7 @@ parent: Built-In Packages nav_order: 4 permalink: /tB/Packages/Assert/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # Assert Package diff --git a/docs/Reference/Built-In/WebView2/index.md b/docs/Reference/Built-In/WebView2/index.md index 506869de3..ab0c5f52b 100644 --- a/docs/Reference/Built-In/WebView2/index.md +++ b/docs/Reference/Built-In/WebView2/index.md @@ -5,7 +5,7 @@ parent: Built-In Packages nav_order: 7 permalink: /tB/Packages/WebView2/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # WebView2 Package diff --git a/docs/Reference/Built-In/WinEventLogLib/index.md b/docs/Reference/Built-In/WinEventLogLib/index.md index 5e1e62998..0c0af58e4 100644 --- a/docs/Reference/Built-In/WinEventLogLib/index.md +++ b/docs/Reference/Built-In/WinEventLogLib/index.md @@ -9,7 +9,7 @@ exclude_from_docs: - EventLogAPIs exclude_kinds: - Declare -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # WinEventLogLib Package diff --git a/docs/Reference/Built-In/WinNamedPipesLib/index.md b/docs/Reference/Built-In/WinNamedPipesLib/index.md index ebf6e04cc..b2cebee87 100644 --- a/docs/Reference/Built-In/WinNamedPipesLib/index.md +++ b/docs/Reference/Built-In/WinNamedPipesLib/index.md @@ -4,7 +4,7 @@ parent: Built-In Packages nav_order: 9 permalink: /tB/Packages/WinNamedPipesLib/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # WinNamedPipesLib Package diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/Enumerations/ImlDrawConstants.md b/docs/Reference/Built-In/WinNativeCommonCtls/Enumerations/ImlDrawConstants.md index 47c19be4b..aa7bf1927 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/Enumerations/ImlDrawConstants.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/Enumerations/ImlDrawConstants.md @@ -10,7 +10,7 @@ permalink: /tB/Packages/WinNativeCommonCtls/Enumerations/ImlDrawConstants Flag combinations passed to the *Style* parameter of [**ListImage.Draw**](../ImageList/ListImage#draw). Multiple flags can be **Or**-combined to compose render styles. -```tb check_build project=wnc-private +```tb check_build project=packages ' Draw a small icon with the focus rectangle overlaid: ImageList1.ListImages("doc").Draw _ PictureBox1.hDC, 0, 0, _ @@ -18,11 +18,20 @@ ImageList1.ListImages("doc").Draw _ ``` > [!IMPORTANT] -> These members live in a **Private** part of the WinNativeCommonCtls package, so a project that -> references it the ordinary way cannot name them --- `ImlDrawTransparent` on its own is -> *TB5079 Unrecognized symbol*. Set the package's [library symbol](../../../../Features/Packages/Library-Symbols) to -> `*WinNativeCommonCtls` and qualify the member, as the sample does. The asterisk is stripped -> from the name: the library is still written `WinNativeCommonCtls` in code. +> The enumeration lives in a **Private** part of the WinNativeCommonCtls package, so its members +> have no bare names: `ImlDrawTransparent` on its own is *TB5079 Unrecognized symbol*. Qualify +> each member with the library name, as the sample does. To name the enumeration itself as a +> type, set the package's [library symbol](../../../../Features/Packages/Library-Symbols) to +> `*WinNativeCommonCtls`; without it, `As WinNativeCommonCtls.ImlDrawConstants` is TB5079 too. +> The asterisk is stripped from the name: the library is still written `WinNativeCommonCtls` in +> code. + +```tb check_build project=wnc-private +' With the library symbol set to *WinNativeCommonCtls: +Private Sub DrawDoc(ByVal Style As WinNativeCommonCtls.ImlDrawConstants) + ImageList1.ListImages("doc").Draw PictureBox1.hDC, 0, 0, Style +End Sub +``` | Member | Value | Description | diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/ListImage.md b/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/ListImage.md index 51181bca5..836ca5031 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/ListImage.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/ListImage.md @@ -66,7 +66,7 @@ Syntax: *object*.**Draw** *hDC* [, *x* [, *y* [, *Style* ] ] ] *Style* : *optional* A combination of [**ImlDrawConstants**](../Enumerations/ImlDrawConstants) flags controlling the draw mode (normal, transparent, masked, selected, focused). Multiple flags can be **Or**-combined. -```tb check_build project=wnc-private +```tb check_build project=packages Private Sub PictureBox1_Paint() ImageList1.ListImages("doc").Draw _ PictureBox1.hDC, 0, 0, _ @@ -75,11 +75,11 @@ End Sub ``` > [!IMPORTANT] -> These members live in a **Private** part of the WinNativeCommonCtls package, so a project that -> references it the ordinary way cannot name them --- `ImlDrawTransparent` on its own is -> *TB5079 Unrecognized symbol*. Set the package's [library symbol](../../../../Features/Packages/Library-Symbols) to -> `*WinNativeCommonCtls` and qualify the member, as the sample does. The asterisk is stripped -> from the name: the library is still written `WinNativeCommonCtls` in code. +> **ImlDrawConstants** lives in a **Private** part of the WinNativeCommonCtls package, so its +> members have no bare names: `ImlDrawTransparent` on its own is *TB5079 Unrecognized symbol*. +> Qualify each member with the library name, as the sample does. Naming the enumeration itself +> as a type needs the package's [library symbol](../../../../Features/Packages/Library-Symbols) +> set to `*WinNativeCommonCtls`; see [**ImlDrawConstants**](../Enumerations/ImlDrawConstants). ### ExtractIcon diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/index.md b/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/index.md index f3f4425cd..26ee1abd0 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/index.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/ImageList/index.md @@ -53,7 +53,7 @@ Properties ### BackColor {: .no_toc } -The background color used to render the image list into a target DC via [**ListImage.Draw**](ListImage#draw) when [**UseBackColor**](#usebackcolor) is **True**. **OLE_COLOR**. Default: **vbWindowBackground**. +The background color used to render the image list into a target DC via [**ListImage.Draw**](ListImage#draw) when [**UseBackColor**](#usebackcolor) is **True**. **OLE_COLOR**. Default: **vbWindowBackground**. Changing it while [**UseBackColor**](#usebackcolor) is **True** updates the image list at once. A value that is not a color, such as `-1`, raises error 380, *Invalid property value*, and the property keeps its color. ### ColorDepth {: .no_toc } diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/ListView/ListItem.md b/docs/Reference/Built-In/WinNativeCommonCtls/ListView/ListItem.md index b567b8ba8..86da1f247 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/ListView/ListItem.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/ListView/ListItem.md @@ -30,7 +30,10 @@ Properties ### BackColor {: .no_toc } -The background color used to render this row. **OLE_COLOR**. Default: `-1` (transparent --- defer to [**ListView.BackColor**](#backcolor)). +The background color used to render this row. **OLE_COLOR**. Default: `-1` (transparent --- defer to [**ListView.BackColor**](.#backcolor)). A change repaints the list at once. A value that is not a color raises error 380, *Invalid property value*, and the property keeps its color. + +> [!NOTE] BETA 1005 +> Once a color is assigned, assigning the default, `-1`, raises error 380, so the row cannot be made transparent again. ### Bold {: .no_toc } @@ -50,7 +53,7 @@ Scrolls the listview so this row is visible. Available as a method (not a proper ### ForeColor {: .no_toc } -The text color used to render this row. **OLE_COLOR**. Default: **vbWindowText**. +The text color used to render this row. **OLE_COLOR**. Default: **vbWindowText**. A change repaints the list at once. A value that is not a color, such as `-1`, raises error 380, *Invalid property value*, and the property keeps its color. ### Ghosted {: .no_toc } diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/ListView/index.md b/docs/Reference/Built-In/WinNativeCommonCtls/ListView/index.md index 805de6fa1..c1120c082 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/ListView/index.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/ListView/index.md @@ -98,7 +98,7 @@ How items are arranged in icon / small-icon view. A member of [**ListArrangeCons ### BackColor {: .no_toc } -The background color of the list area. **OLE_COLOR**. Default: **vbWindowBackground**. +The background color of the list area. **OLE_COLOR**. Default: **vbWindowBackground**. Takes effect when the control is created and each time the property changes. When [**TextBackground**](#textbackground) is **lvwOpaque**, item text is drawn on this color too. A value that is not a color, such as `-1`, raises error 380, *Invalid property value*, and the property keeps its color. ### BorderStyle {: .no_toc } @@ -203,7 +203,7 @@ The [**ImageList**](../ImageList/) used for small icons in **lvwSmallIcon**, **l ### TextBackground {: .no_toc } -Whether item-label text has an opaque background. A member of [**ListTextBackgroundConstants**](#listtextbackgroundconstants). Default: **lvwTransparent**. +Whether item-label text has an opaque background. A member of [**ListTextBackgroundConstants**](#listtextbackgroundconstants). Default: **lvwTransparent**. Changing it repaints the list at once. ### View {: .no_toc } diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/ProgressBar.md b/docs/Reference/Built-In/WinNativeCommonCtls/ProgressBar.md index 928e54070..26aec4c25 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/ProgressBar.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/ProgressBar.md @@ -84,7 +84,7 @@ Properties ### BackColor {: .no_toc } -The background color drawn behind the progress bar segments. **OLE_COLOR**. Default: **vbButtonFace**. Applied via `PBM_SETBKCOLOR`. +The background color drawn behind the progress bar segments. **OLE_COLOR**. Default: **vbButtonFace**. Applied via `PBM_SETBKCOLOR`, when the control is created and each time the property changes. A value that is not a color, such as `-1`, raises error 380, *Invalid property value*, and the property keeps its color. ### BorderStyle {: .no_toc } @@ -94,7 +94,7 @@ The control's border style. A [**ControlBorderStyleConstants**](../VBRUN/Constan ### ForeColor {: .no_toc } -The color of the progress bar segments themselves. **OLE_COLOR**. Default: **vbHighlight**. Applied via `PBM_SETBARCOLOR`. +The color of the progress bar segments themselves. **OLE_COLOR**. Default: **vbHighlight**. Applied via `PBM_SETBARCOLOR`, when the control is created and each time the property changes. A value that is not a color, such as `-1`, raises error 380, *Invalid property value*, and the property keeps its color. > [!NOTE] > The OS visual styles theme typically overrides this value in standard rendering. To see the assigned **ForeColor** at run time, disable visual styles by setting [**VisualStyles**](../VB/CheckBox#visualstyles) to **False**. diff --git a/docs/Reference/Built-In/WinNativeCommonCtls/index.md b/docs/Reference/Built-In/WinNativeCommonCtls/index.md index 3e0eb1bb2..e98e75195 100644 --- a/docs/Reference/Built-In/WinNativeCommonCtls/index.md +++ b/docs/Reference/Built-In/WinNativeCommonCtls/index.md @@ -4,7 +4,7 @@ parent: Built-In Packages nav_order: 12 permalink: /tB/Packages/WinNativeCommonCtls/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # WinNativeCommonCtls Package diff --git a/docs/Reference/Built-In/WinServicesLib/index.md b/docs/Reference/Built-In/WinServicesLib/index.md index ddb6f6d3f..4999ef6f4 100644 --- a/docs/Reference/Built-In/WinServicesLib/index.md +++ b/docs/Reference/Built-In/WinServicesLib/index.md @@ -4,7 +4,7 @@ parent: Built-In Packages nav_order: 10 permalink: /tB/Packages/WinServicesLib/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 exclude_from_docs: - ServicesConstantsPublic --- diff --git a/docs/Reference/Built-In/tbIDE/index.md b/docs/Reference/Built-In/tbIDE/index.md index cc22847a1..064920cca 100644 --- a/docs/Reference/Built-In/tbIDE/index.md +++ b/docs/Reference/Built-In/tbIDE/index.md @@ -4,7 +4,7 @@ parent: Built-In Packages nav_order: 11 permalink: /tB/Packages/tbIDE/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # tbIDE Package diff --git a/docs/Reference/Contributed/tbRegExp/PatternSyntax.md b/docs/Reference/Contributed/tbRegExp/PatternSyntax.md new file mode 100644 index 000000000..cc80fa806 --- /dev/null +++ b/docs/Reference/Contributed/tbRegExp/PatternSyntax.md @@ -0,0 +1,98 @@ +--- +title: Pattern syntax +parent: tbRegExp Package +permalink: /tB/Packages/Contributed/tbRegExp/PatternSyntax +has_toc: false +--- + +# Pattern syntax +{: .no_toc } + +How a pattern is written for **tbRegExp**, and the few places where that needs saying. + +A pattern written for VBScript's **RegExp** needs no change. What follows either adds to that syntax or spells out a rule VBScript follows without documenting it. + +## What tbRegExp adds + +**tbRegExp** accepts, beyond VBScript's syntax: + +- named groups, `(?...)`: [**SubMatches.Item**](SubMatches/Item) returns one by its name, and [**Replace**](RegExp/Replace) inserts one as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores; a pattern with any other name is not valid; +- lookbehind, `(?<=...)` and `(?\d{4})-(?\d{2})" +Debug.Print re.Execute("2026-10")(0).SubMatches("month") ' 10 +Debug.Print re.Replace("2026-10", "$/$") ' 10/2026 + +re.Pattern = "(?<=\$)\d+" +Debug.Print re.Execute("costs $123")(0).Value ' 123 + +re.Pattern = "(?i:abc)DEF" +Debug.Print re.Test("ABCDEF") ' True +Debug.Print re.Test("ABCdef") ' False +``` + +## Escapes + +The escapes that name a control character or a character code are read as in VBScript: + +- `\c` followed by a letter, in either case, is a control character: `\cJ` and `\CJ` are the line feed. A `\c` followed by anything else makes the pattern invalid; +- `\0` is the character with code 0, `\0` followed by octal digits, such as `\012`, is that code, and `\8` and `\9` are the digits themselves; +- `\1` to `\9` and longer numbers are backreferences when the group they name has already been opened, that is, when its `(` stands earlier in the pattern. Otherwise the digits are read as an octal character code, so `\101` is `A` and `(a)\2` is `a` followed by the character with code 2; [**IsValid**](RegExp/IsValid) returns **True** for both; +- `\f`, `\n`, `\r` and `\t`, inside a character class as well, are the form feed, line feed, carriage return and tab. + + +A backslash before a letter that names no escape stands for the letter itself, as in VBScript. The constructs that other engines spell that way are therefore ordinary text here, not errors: `\k` matches `k`, `\A` matches `A`, and `\p{L}` matches `p{L}`, the braces being text as well. + + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "\101" +Debug.Print re.Test("A") ' True +re.Pattern = "\CJ" +Debug.Print re.Test(vbLf) ' True +re.Pattern = "\k" +Debug.Print re.IsValid ' True +Debug.Print re.Test("k") ' True +re.Pattern = "(a)\2" +Debug.Print re.Test("a" & ChrW(2)) ' True +``` + + +Digits that name a group declared *later* in the pattern are therefore not a backreference at all. `\1(a)` is the character with code 1 followed by `a`, and finds no match in the string `a`, as in VBScript's **RegExp**. A group that is open but has not yet taken part, such as the `\1` in `(\1a)`, is a real backreference and matches no characters. + + +## Character classes + +`\w` matches only the ASCII letters and digits and `_`, as in VBScript, so `\w+` finds `caf` in `café`. + +## Quantifiers and braces + +A `{` starts a quantifier when it is followed by `{n}`, `{n,}` or `{n,m}`. A `{` that starts none, such as the one in `a{`, `a{x}` or `a{,2}`, is an ordinary character, as in VBScript; `\{` for the character is accepted too but not needed. A `]` or `}` that closes nothing is an ordinary character as well. + + +`{,m}` is text and not a quantifier, because a quantifier needs a count before the comma: `a{,2}` finds the text `a{,2}` and not up to two `a`. A `{` that does start a quantifier with counts that cannot be used is still an error, though: `a{2,1}`, whose upper count is below its lower one, makes the pattern invalid. + + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "(?<_part2>\d)" +Debug.Print re.IsValid ' True +re.Pattern = "(?<2part>\d)" +Debug.Print re.IsValid ' False + +re.Pattern = "a{x}" +Debug.Print re.IsValid ' True +Debug.Print re.Execute("a{x}")(0).Value ' a{x} +re.Pattern = "a{2,1}" +Debug.Print re.IsValid ' False +``` + +## See Also + +- [Pattern](RegExp/Pattern) property -- the regular expression +- [IsValid](RegExp/IsValid) property -- whether a pattern compiles +- [LastErrorNumber](RegExp/LastErrorNumber) property -- the faults a pattern can have, with an example of each +- [tbRegExp Package](./) -- overview diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md index 30cfea8d0..e9acb8736 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md @@ -36,8 +36,8 @@ Debug.Print re.Execute("fooBarBaz").Count ' 2 Debug.Print re.Execute("fooBarBaz")(1).FirstIndex ' 6 ``` - -A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging. The collection then holds the matches found before it gave up, and [**SearchAborted**](SearchAborted) returns **True**. + +A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Execute** then raises an error. The matches found before it gave up are not returned: a part of the matches, handed back as though it were all of them, is worse than no answer. See [**SearchStepLimit**](SearchStepLimit). Each **Match** gives the matched text ([**Value**](../Match/Value)), the position where it starts ([**FirstIndex**](../Match/FirstIndex), counted from 0), its length, and the text of each group of the pattern ([**SubMatches**](../Match/SubMatches)). A group written `(?...)` can be read by its name. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md index 8929b93a3..d8992c2a6 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md @@ -24,12 +24,12 @@ The property compiles the pattern if it has not been compiled since [**Pattern** Check **IsValid** before [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) or [**Split**](Split) when the pattern comes from outside the program, because each of those raises the compile error. -> [!NOTE] 1.8.0.0 -> Although nothing is raised, the compile error of an invalid pattern stays in the **Err** object after the call that compiled the pattern returns. A program that tests **Err** for other errors calls **Err.Clear** first. +Nothing is raised and nothing is left behind. The **Err** object is clear when the property returns, even for a pattern that failed to compile, so a program that runs `On Error Resume Next` and tests **Err** for its own errors does not have to call **Err.Clear** first. The number and the message are kept in [**LastErrorNumber**](LastErrorNumber) and [**LastError**](LastError). + -> [!NOTE] 1.8.0.0 -> A quantifier whose lower count is above its upper count, such as `a{2,1}`, is not found when the pattern is compiled, so **IsValid** returns **True** for it and [**LastErrorNumber**](LastErrorNumber) returns 0. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise error 3000 when a search reaches the quantifier, with the description that Windows gives that number, *The specified print monitor is unknown.* +A quantifier whose lower count is above its upper count, such as `a{2,1}`, is found when the pattern is compiled, like any other fault: **IsValid** returns **False**, [**LastErrorNumber**](LastErrorNumber) gives the invalid-quantifier number, and [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise it. A `{` that starts no quantifier at all, such as the one in `a{x}`, is not a fault but an ordinary character. + ## Example @@ -37,9 +37,9 @@ Check **IsValid** before [**Execute**](Execute), [**Test**](Test), [**Replace**] Dim re As RegExp Set re = New RegExp re.Pattern = "(\d+" -Debug.Print re.IsValid ' False -Debug.Print Err.Number = re.LastErrorNumber ' True -Err.Clear +Debug.Print re.IsValid ' False +Debug.Print Err.Number ' 0 -- nothing left in Err +Debug.Print re.LastErrorNumber - vbObjectError ' 3009 re.Pattern = "(\d+)" Debug.Print re.IsValid ' True diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md b/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md index 5935dc1a7..c63e96aad 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md @@ -20,7 +20,7 @@ Returns a **String**: the description of the compile error, or an empty string w ## Remarks -The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastError** raises nothing, but the error stays in the **Err** object (see [**IsValid**](IsValid)). The text is a sentence that names the fault, such as *Unterminated character class: a '[' without a matching ']'.* for the pattern `[abc`. [**LastErrorNumber**](LastErrorNumber) is the number of the error and lists the faults. +The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastError** raises nothing and leaves the **Err** object clear. The text is a sentence that names the fault, such as *Unterminated character class: a '[' without a matching ']'.* for the pattern `[abc`. [**LastErrorNumber**](LastErrorNumber) is the number of the error and lists the faults. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise an error with this description when the pattern is invalid. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md b/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md index 142048169..c07e97df5 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md @@ -22,7 +22,7 @@ Returns a **Long**: the number of the compile error, or 0 when the pattern is va The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastErrorNumber** raises nothing. The value is the `Number` of the error that the compilation raised; [**LastError**](LastError) is its description. -The engine raises its pattern errors with numbers of the form `vbObjectError + 3000 + n`, where *n* identifies the fault, as in the example. The compilation traps the error, so **LastErrorNumber** raises nothing, but the error stays in the **Err** object (see [**IsValid**](IsValid)). +The engine raises its pattern errors with numbers of the form `vbObjectError + 3000 + n`, where *n* identifies the fault, as in the example. The compilation traps the error, so **LastErrorNumber** raises nothing and leaves the **Err** object clear. | *n* | Fault | Example | @@ -32,15 +32,21 @@ The engine raises its pattern errors with numbers of the form `vbObjectError + 3 | 3 | A range in a character class that runs backwards | `[z-a]` | | 4 | A character class without its `]` | `[abc` | | 6 | A group construct `(?<` that is neither a lookbehind nor a valid name | `(?<1a>x)` | -| 8 | A `{` that does not start a quantifier, or a count that is too large | `a{2`, `\p{L}` | +| 8 | A quantifier whose upper count is below its lower count, or a count that is too large | `a{2,1}`, `a{99999999999}` | | 9 | A group without its `)` | `(\d+` | | 11 | A `)` that closes no group | `)` | | 12 | A quantifier with nothing to repeat | `*a` | | 13 | A group name with a character that a name cannot hold | `(?x)` | | 14 | An inline option that is not `i`, `m` or `s`, which includes an atomic group and a conditional | `(?x)`, `(?>a)` | + +An atomic group `(?>...)` and a conditional `(?(`*n*`)`*yes*`|`*no*`)` fall under *n* = 14. VBScript's **RegExp** does not accept either construct, so a pattern that uses one is invalid in both. + + [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise an error with this number when the pattern is invalid. +Those four methods can also raise `vbObjectError + 3016`, which is not a compile error and so never appears here: it means a valid pattern ran out of its step budget before the search finished. See [**SearchStepLimit**](SearchStepLimit). + ## Example ```tb check_build check_run diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md b/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md index b14a12105..a27927f17 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md @@ -34,7 +34,7 @@ Syntax: *object*.**Pattern** **=** *value* Setting a different pattern makes it compile again the next time it is needed. Setting the current pattern does nothing. A pattern that does not compile raises no error when it is set: [**IsValid**](IsValid), [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) report the failure, and [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise it. -A named group is written `(?...)`. Its text is read from the [**SubMatches**](../SubMatches/) of a [**Match**](../Match/) by name, and used in [**Replace**](Replace) as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores. The [overview of the package](../#pattern-syntax) lists the other differences from VBScript's pattern syntax. +A named group is written `(?...)`. Its text is read from the [**SubMatches**](../SubMatches/) of a [**Match**](../Match/) by name, and used in [**Replace**](Replace) as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores. [**Pattern syntax**](../PatternSyntax) covers the rest of the pattern syntax. ## Example diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md b/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md index 0d68f4921..1fa00e031 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md @@ -35,13 +35,12 @@ A `$` in *replaceString* starts a substitution item. Any other text is copied as | `$'` | The part of *sourceString* after the match. | | `$`*n* or `$`*nn* | The text of numbered group *n*, counting from 1. Two digits are read as the number when the pattern has a group with that number, otherwise one. It is an empty string when the group matched nothing. When the pattern has no group *n*, the `$` is copied, and so are the digits: `$0` and `$00` are never items, and `$3` in a pattern of two groups is the text `$3`. | | `$<`*name*`>` | The text of the group written `(?...)`. It is an empty string when the group matched nothing or no group has the name. When the pattern has no named group, or the `>` is missing, or the name is empty, the `$` is copied. | -| `$~` | Nothing. The item is dropped. | A `$` that starts no item raises no error, so a replacement string can hold a literal `$` as it is, at the end or before any other character. Before a character that would make an item, write `$$`: `$$$&` inserts a `$` and then the matched text, as the last example does. -> [!NOTE] 1.8.0.0 -> Items are read as in VBScript's **RegExp**, with two differences: `$<`*name*`>` is an addition of this package, and `$~` is dropped, where VBScript copies `$~` into the result. +> [!NOTE] 1.9.0.0 +> Items are read as in VBScript's **RegExp**, with one difference: `$<`*name*`>` is an addition of this package. A `$~`, which earlier versions dropped, is copied into the result as VBScript copies it. ## Remarks @@ -57,8 +56,8 @@ re.Pattern = "^" Debug.Print Replace(re.Replace("a" & vbLf & "b" & vbLf & "c", "> "), vbLf, "/") ' > a/> b/> c ``` - -A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Replace** then replaces only the matches found before it gave up. [**SearchAborted**](SearchAborted) returns **True** in that case. + +A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Replace** then raises an error. No partly replaced string is returned. See [**SearchStepLimit**](SearchStepLimit). An invalid pattern raises the compile error, with the number in [**LastErrorNumber**](LastErrorNumber) and the description in [**LastError**](LastError). Check [**IsValid**](IsValid) first to avoid it. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/SearchAborted.md b/docs/Reference/Contributed/tbRegExp/RegExp/SearchAborted.md deleted file mode 100644 index b66672fec..000000000 --- a/docs/Reference/Contributed/tbRegExp/RegExp/SearchAborted.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: SearchAborted -parent: RegExp -permalink: /tB/Packages/Contributed/tbRegExp/RegExp/SearchAborted -has_toc: false ---- - -# SearchAborted -{: .no_toc } - -Returns whether the last search of this object gave up before it finished. - -Syntax: *object*.**SearchAborted** - -*object* -: *required* An object expression that evaluates to a **RegExp**. - -Returns a **Boolean**: **True** when the most recent call of [**Test**](Test), [**Execute**](Execute), [**Replace**](Replace) or [**Split**](Split) on *object* stopped because its search ran out of steps, **False** otherwise. The property is read-only. It is **False** for an object that has not searched yet. - -## Remarks - -A search is given a budget of steps, where a step is one operation of the compiled pattern. A pattern that backtracks without end, such as `(a+)+b` on a string of thirty `a`, needs twice as many steps for each `a` it is given, and the budget is what stops it. VBScript's **RegExp** has no such limit and for that string does not return in any reasonable time. - -When the budget runs out, the search stops and nothing is raised. Whatever was found before is returned, and the result can be short or empty: [**Test**](Test) returns **False**, [**Execute**](Execute) returns the matches found before the search stopped, [**Replace**](Replace) returns *sourceString* with only those matches replaced, and [**Split**](Split) splits only at them. A program that cannot tell this from a string without a match reads **SearchAborted** after the call. - -The budget is 5,000 steps for each character of the string, at least 1,000,000 and at most 50,000,000. It is not a property of the object, and a program cannot change it. It applies to the search for one match, so with [**Global**](Global) set to **True** each match has a budget of its own, and the first search that runs out ends the call. A simple pattern needs about three steps for each character it matches, so a long match is not affected: `a*` on a string of 1,000,000 `a` returns all of it in about half a second. - -Each call of **Test**, **Execute**, **Replace** or **Split** sets the value again: a call that finishes its search sets it to **False**, and so does a call that raises an error because the pattern is not valid, because no search was made. The value belongs to the object. A search on another **RegExp** does not change it, and a new object returns **False**. - - -> [!NOTE] 1.8.0.0 -> A pattern that is not catastrophic can also run out of steps, if it tries again from each start position and the string is long. `\d+x` on a string of 5,000 digits and no `x` takes a few seconds and then gives up, with the same result as for a string that has no match, and **SearchAborted** returns **True**. A string of 2,000 digits finishes in a second or two and returns **False**. - -## Example - -This example searches a string of thirty `a` for `(a+)+b`, which cannot match and takes a very long time to prove it. The search gives up after about a fifth of a second, and **SearchAborted** says that the **False** from **Test** is not an answer. A search of a string that has no `b`, where the pattern is not catastrophic, finishes. - -```tb check_build check_run -Dim re As New RegExp -re.Pattern = "(a+)+b" -Debug.Print re.SearchAborted ' False - -Debug.Print re.Test(String(30, "a")) ' False -Debug.Print re.SearchAborted ' True - -Debug.Print re.Test("aaab") ' True -Debug.Print re.SearchAborted ' False - -re.Pattern = "a+b" -Debug.Print re.Test(String(30, "a")) ' False -Debug.Print re.SearchAborted ' False -``` - -This example shows that the value is per object, and that a search which gave up still returns the matches found before it. - -```tb check_build check_run -Dim re As New RegExp -Dim other As New RegExp -re.Pattern = "x|(a+)+b" -re.Global = True -other.Pattern = "a" - -Dim matches As MatchCollection -Set matches = re.Execute("xx" & String(30, "a")) -Debug.Print matches.Count ' 2 -Debug.Print re.SearchAborted ' True - -Debug.Print other.Test("a") ' True -Debug.Print other.SearchAborted ' False -Debug.Print re.SearchAborted ' True -``` - -## See Also - -- [Test](Test) method -- returns whether a string contains a match -- [Execute](Execute) method -- returns the matches -- [Replace](Replace) method -- replaces the matches -- [Split](Split) method -- splits a string at the matches -- [RegExp](./) class -- overview diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/SearchStepLimit.md b/docs/Reference/Contributed/tbRegExp/RegExp/SearchStepLimit.md new file mode 100644 index 000000000..6a8a0d67e --- /dev/null +++ b/docs/Reference/Contributed/tbRegExp/RegExp/SearchStepLimit.md @@ -0,0 +1,91 @@ +--- +title: SearchStepLimit +parent: RegExp +permalink: /tB/Packages/Contributed/tbRegExp/RegExp/SearchStepLimit +has_toc: false +--- + +# SearchStepLimit +{: .no_toc } + +Returns or sets the number of steps a search of this object may take before it gives up. + +Syntax: *object*.**SearchStepLimit** [= *steps*] + +*object* +: *required* An object expression that evaluates to a **RegExp**. + +*steps* +: *optional* A **Long**, the budget for one search, or 0 for the budget the package works out on its own. A negative value raises error 5. + +Returns a **Long**: the value that was set, or 0 when the budget is left to the package. The default is 0. + +## Remarks + +A search is given a budget of steps, where a step is one operation of the compiled pattern. A pattern that backtracks without end, such as `(a+)+b` on a string of thirty `a`, needs twice as many steps for each `a` it is given, and the budget is what stops it. VBScript's **RegExp** has no such limit and for that string does not return in any reasonable time. + +When the budget runs out, [**Test**](Test), [**Execute**](Execute), [**Replace**](Replace) and [**Split**](Split) raise `vbObjectError + 3016` and return nothing at all -- not even the matches found before the search stopped. A search that ran out of steps never established what the rest of the string holds, so a short result is a wrong answer rather than an incomplete one, and the error is the only honest report. The description names the budget that was spent, the length of the string, and what to do about it. + + +With the property left at 0, the budget is ten steps for each character of the string squared, at least 1,000,000 and at most 100,000,000. It is worked out for the search of one match, so with [**Global**](Global) set to **True** each match is given a budget of its own and the first search that runs out ends the call. The square matters: an ordinary pattern that backtracks, such as `\d+x` on a string of digits with no `x`, costs about two and a quarter steps for each character squared, so it finishes at any length a search is likely to be given. A simple pattern needs about three steps for each character it matches, so a long match is never affected: `a*` on a string of 1,000,000 `a` returns all of it in about half a second. + + +Set the property when a pattern of that kind is given a string long enough to reach the cap. The message of the error suggests a value. Nothing covers a pattern whose cost grows faster than the square of the string, and when the budget already exceeded what a pattern of that kind would need, the message says to simplify the pattern instead of naming this property. + +The value that **SearchStepLimit** returns is the one that was set, not the budget a search would be given: with the property at 0 there is no single number to return, because the budget depends on the string. Setting it does not compile the pattern again. + +## The error + +The description of the error says what was spent and what to do about it. The search of a thousand digits in the second example below, given 100,000 steps when it needs about 2,250,000, reports: + +> The regular expression search was abandoned after 100,000 steps on an input of 1,000 characters, so whether it matches is not known. This pattern backtracks heavily at this length. A pattern like this typically needs about 3,000,000 steps at this length - roughly 30 times the work already done. Set **SearchStepLimit** to 3000000 to allow it. If that still fails, the pattern's cost grows faster than the square of the input and no limit will help. + +A pattern that is worse than quadratic is told the opposite, because for it a larger budget is not the answer. `(a+)+b` on thirty `a` is given the floor of 1,000,000 steps, far more than the 2,700 a quadratic pattern of that length would need, so the message does not name this property at all: + +> The regular expression search was abandoned after 1,000,000 steps on an input of 30 characters, so whether it matches is not known. This pattern backtracks heavily at this length. It was already allowed more than a quadratic pattern needs here, so its cost grows faster than the square of the input and no step limit will cover it. Simplify the pattern. + +## Example + +This example searches a string of thirty `a` for `(a+)+b`, which cannot match and takes a very long time to prove it. The search gives up after about a third of a second and raises. The same pattern against a string it can match finishes. + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "(a+)+b" + +On Error Resume Next +re.Test String(30, "a") +Debug.Print Err.Number - vbObjectError ' 3016 +On Error GoTo 0 +Err.Clear + +Debug.Print re.Test("aaab") ' True +``` + + +This example gives a search too few steps on purpose, then raises the limit so that the same search finishes. `\d+x` on a string of 1,000 digits with no `x` costs about 2,250,000 steps. + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "\d+x" +Debug.Print re.SearchStepLimit ' 0 + +re.SearchStepLimit = 100000 +On Error Resume Next +re.Test String(1000, "1") +Debug.Print Err.Number - vbObjectError ' 3016 +On Error GoTo 0 +Err.Clear + +re.SearchStepLimit = 3000000 +Debug.Print re.Test(String(1000, "1")) ' False +Debug.Print re.SearchStepLimit ' 3000000 +``` + + +## See Also + +- [Test](Test) method -- returns whether a string contains a match +- [Execute](Execute) method -- returns the matches +- [Replace](Replace) method -- replaces the matches +- [Split](Split) method -- splits a string at the matches +- [RegExp](./) class -- overview diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Split.md b/docs/Reference/Contributed/tbRegExp/RegExp/Split.md index b1563cfa9..cc45d9f35 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Split.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Split.md @@ -43,8 +43,8 @@ Debug.Print parts.Count ' 3 Debug.Print parts(1) & "|" & parts(2) & "|" & parts(3) ' foo|Bar|Baz ``` - -A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Split** then splits only at the matches found before it gave up. [**SearchAborted**](SearchAborted) returns **True** in that case. + +A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Split** then raises an error. No partly split collection is returned. See [**SearchStepLimit**](SearchStepLimit). When **Pattern** is not a valid regular expression, **Split** raises the compile error. Its number is [**LastErrorNumber**](LastErrorNumber), its description is [**LastError**](LastError), and its source is `RegExp`. Read [**IsValid**](IsValid) first to avoid the error. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Test.md b/docs/Reference/Contributed/tbRegExp/RegExp/Test.md index 49358f946..3cd8cfafa 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Test.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Test.md @@ -26,8 +26,8 @@ Returns **True** if [**Pattern**](Pattern) finds a match in *sourceString*, othe [**IgnoreCase**](IgnoreCase), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) apply to the matching. [**Global**](Global) makes no difference, because one match is enough. - -A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Test** then returns **False**. [**SearchAborted**](SearchAborted) tells that **False** from a string that has no match. + +A search that backtracks without end, such as `(a+)+b` on thirty `a`, gives up instead of hanging, and **Test** then raises an error rather than returning a value: a search that ran out of steps did not establish whether the pattern matches, so there is no answer to return. See [**SearchStepLimit**](SearchStepLimit). When **Pattern** is not a valid regular expression, **Test** raises the compile error. Its number is [**LastErrorNumber**](LastErrorNumber), its description is [**LastError**](LastError), and its source is `RegExp`. Read [**IsValid**](IsValid) first to avoid the error. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/index.md b/docs/Reference/Contributed/tbRegExp/RegExp/index.md index 413728d09..8f6a616f5 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/index.md @@ -47,7 +47,7 @@ All four are **False** in a new instance. The pattern is compiled the first time a method or one of [**IsValid**](IsValid), [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) needs it. It is compiled again after [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) is set to a different value. [**Global**](Global), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) are applied when a match is made and do not cause a new compilation. -A pattern that does not compile does not raise an error at once. [**IsValid**](IsValid) returns **False**, and [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) describe the failure. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise that error, with the number in **LastErrorNumber**, the description in **LastError** and the source `RegExp`. When **IsValid**, **LastError** or **LastErrorNumber** is the call that compiles an invalid pattern, it raises nothing, but the compile error stays in the **Err** object after it returns; [**IsValid**](IsValid) says what to do about it. +A pattern that does not compile does not raise an error at once. [**IsValid**](IsValid) returns **False**, and [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) describe the failure. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise that error, with the number in **LastErrorNumber**, the description in **LastError** and the source `RegExp`. When **IsValid**, **LastError** or **LastErrorNumber** is the call that compiles an invalid pattern, it raises nothing and leaves the **Err** object clear. ## Properties @@ -60,7 +60,7 @@ A pattern that does not compile does not raise an error at once. [**IsValid**](I - [LastErrorNumber](LastErrorNumber) -- returns the number of the compile error - [MultiLine](MultiLine) -- returns or sets whether `^` and `$` match at line boundaries - [Pattern](Pattern) -- returns or sets the regular expression -- [SearchAborted](SearchAborted) -- returns whether the last search gave up before it finished +- [SearchStepLimit](SearchStepLimit) -- returns or sets the step budget that stops a runaway search ## Methods diff --git a/docs/Reference/Contributed/tbRegExp/index.md b/docs/Reference/Contributed/tbRegExp/index.md index 231c26230..18fa0adbf 100644 --- a/docs/Reference/Contributed/tbRegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/index.md @@ -4,109 +4,67 @@ parent: Contributed Packages has_toc: false exclude_from_docs: - StaticRegex -indexed_from: 1.8.0.0 +indexed_from: 1.9.0.0 permalink: /tB/Packages/Contributed/tbRegExp/ --- # tbRegExp Package {: .no_toc } -**Author:** GCuser99. **Version:** 1.8.0.0. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. +**Author:** GCuser99. **Version:** 1.9.0.0. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. The **tbRegExp** contributed package provides regular expressions for twinBASIC projects, as a replacement for the **RegExp** object of VBScript. It follows the same object model. A [**RegExp**](RegExp/) is given a pattern and options, its [**Execute**](RegExp/Execute) method returns a [**MatchCollection**](MatchCollection/) of [**Match**](Match/) objects, and each **Match** holds the text captured by the groups of the pattern as a [**SubMatches**](SubMatches/) object. Positions are zero-based, as in VBScript. The matching is done by the [vba-regex](https://github.com/sihlfall/vba-regex) engine of sihlfall, which the package includes as a private module, **StaticRegex**. -Beyond VBScript's object, **RegExp** has the [**DotAll**](RegExp/DotAll) and [**Flags**](RegExp/Flags) options, the [**Split**](RegExp/Split) method, [**IsValid**](RegExp/IsValid), [**LastError**](RegExp/LastError) and [**LastErrorNumber**](RegExp/LastErrorNumber), which report an invalid pattern before it is used, and [**SearchAborted**](RegExp/SearchAborted), which reports a search that gave up. [**Replace**](RegExp/Replace) reads a `$` in the replacement string as VBScript does, and adds `$` for a named group. - -## Pattern syntax - -A pattern is written as for VBScript's **RegExp**. **tbRegExp** also accepts: - -- named groups, `(?...)`: [**SubMatches.Item**](SubMatches/Item) returns one by its name, and [**Replace**](RegExp/Replace) inserts one as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores; a pattern with any other name is not valid; -- lookbehind, `(?<=...)` and `(?\d{4})-(?\d{2})" -Debug.Print re.Execute("2026-10")(0).SubMatches("month") ' 10 -Debug.Print re.Replace("2026-10", "$/$") ' 10/2026 - -re.Pattern = "(?<=\$)\d+" -Debug.Print re.Execute("costs $123")(0).Value ' 123 - -re.Pattern = "(?i:abc)DEF" -Debug.Print re.Test("ABCDEF") ' True -Debug.Print re.Test("ABCdef") ' False +re.Pattern = "\d+" +re.Global = True +Debug.Print re.Test("a1b22c333") ' True +Debug.Print re.Execute("a1b22c333").Count ' 3 +Debug.Print re.Execute("a1b22c333")(1).Value ' 22 +Debug.Print re.Replace("a1b22c333", "#") ' a#b#c# ``` - -> [!NOTE] 1.8.0.0 -> A pattern that holds an atomic group `(?>...)` or a conditional is not valid: [**IsValid**](RegExp/IsValid) returns **False**. A named backreference `\k`, `\A`, `\Z` and `\p{...}` are not supported either, but they do not make the pattern invalid, because a backslash before a letter that names no escape stands for the letter itself, as in VBScript: `\k` matches the text `k`, and `\A` matches `A`. The pattern `\p{L}` is invalid for another reason: `{L}` does not start a quantifier (see below). +Beyond VBScript's object, **RegExp** has the [**DotAll**](RegExp/DotAll) and [**Flags**](RegExp/Flags) options, the [**Split**](RegExp/Split) method, [**IsValid**](RegExp/IsValid), [**LastError**](RegExp/LastError) and [**LastErrorNumber**](RegExp/LastErrorNumber), which report an invalid pattern before it is used, and [**SearchStepLimit**](RegExp/SearchStepLimit), which bounds a runaway search. [**Replace**](RegExp/Replace) reads a `$` in the replacement string as VBScript does, and adds `$` for a named group. -The escapes that name a control character or a character code are read as in VBScript: +## Pattern syntax -- `\c` followed by a letter, in either case, is a control character: `\cJ` and `\CJ` are the line feed. A `\c` followed by anything else makes the pattern invalid; -- `\0` is the character with code 0, `\0` followed by octal digits, such as `\012`, is that code, and `\8` and `\9` are the digits themselves; -- `\1` to `\9` and longer numbers are backreferences when the pattern has that many groups. Otherwise the digits are read as an octal character code, so `\101` is `A` and `(a)\2` is `a` followed by the character with code 2; [**IsValid**](RegExp/IsValid) returns **True** for both; -- `\f`, `\n`, `\r` and `\t`, inside a character class as well, are the form feed, line feed, carriage return and tab. +A pattern written for VBScript's **RegExp** needs no change. **tbRegExp** also accepts named groups, lookbehind, and the `i`, `m` and `s` options inside the pattern: ```tb check_build check_run Dim re As New RegExp -re.Pattern = "\101" -Debug.Print re.Test("A") ' True -re.Pattern = "\CJ" -Debug.Print re.Test(vbLf) ' True -re.Pattern = "\k" -Debug.Print re.IsValid ' True -Debug.Print re.Test("k") ' True -re.Pattern = "(a)\2" -Debug.Print re.Test("a" & ChrW(2)) ' True +re.Pattern = "(?\d{4})-(?\d{2})" +Debug.Print re.Execute("2026-10")(0).SubMatches("month") ' 10 +Debug.Print re.Replace("2026-10", "$/$") ' 10/2026 ``` - -> [!NOTE] 1.8.0.0 -> A backreference to a group that has not yet taken part in the match, such as `\1(a)`, matches no characters, so the pattern finds `a` in the string `a`. VBScript's **RegExp** finds no match for such a pattern. - -`\w` matches only the ASCII letters and digits and `_`, as in VBScript, so `\w+` finds `caf` in `café`. - -A `{` has to start a quantifier: `{n}`, `{n,}`, `{n,m}` or `{,m}`, which means `{0,m}`. A pattern in which a `{` starts none, such as `a{` or `a{x}`, is not valid; write `\{` for the character. A `]` or `}` that closes nothing is an ordinary character, as in VBScript. - - -> [!NOTE] 1.8.0.0 -> VBScript's **RegExp** reads a `{` that starts no quantifier, and `{,m}`, as ordinary text: `a{x}` is a valid pattern there that finds the text `a{x}`, and `a{,2}` finds the text `a{,2}` and not `aa`. In **tbRegExp** the first is not valid, so a search with it raises the compile error, and `a{,2}` finds up to two `a`. - -```tb check_build check_run -Dim re As New RegExp -re.Pattern = "(?<_part2>\d)" -Debug.Print re.IsValid ' True -re.Pattern = "(?<2part>\d)" -Debug.Print re.IsValid ' False - -re.Pattern = "a{x}" -Debug.Print re.IsValid ' False -re.Pattern = "a\{x}" -Debug.Print re.Execute("a{x}")(0).Value ' a{x} -``` +[**Pattern syntax**](PatternSyntax) covers those in full, along with the escapes, the character classes and the brace rules. ## Searches that give up - -A pattern that backtracks without end, such as `(a+)+b` on a string of thirty `a`, does not hang a search as it does in VBScript's **RegExp**. Every search has a budget of steps, which a program cannot change, and when it runs out the search stops and raises no error. Its result is then short or empty, and a program that has to tell it from a true result reads [**SearchAborted**](RegExp/SearchAborted) after the call. A long match is no problem: `a*` and `^.*$` match a string of 1,000,000 `a` whole. +This is the one place where **tbRegExp** behaves differently from VBScript's **RegExp** rather than adding to it. + + +A pattern that backtracks without end, such as `(a+)+b` on a string of thirty `a`, does not hang a search as it does in VBScript's **RegExp**. Every search is given a budget of steps, and when it runs out the search raises an error rather than returning a result it never established. A long match is no problem: `a*` and `^.*$` match a string of 1,000,000 `a` whole. ```tb check_build check_run Dim re As New RegExp re.Pattern = "(a+)+b" -Debug.Print re.Test(String(30, "a")) ' False -Debug.Print re.SearchAborted ' True +On Error Resume Next +re.Test String(30, "a") +Debug.Print Err.Number - vbObjectError ' 3016 +On Error GoTo 0 +Err.Clear re.Pattern = "^.*$" Debug.Print re.Test(String(100000, "a")) ' True -Debug.Print re.SearchAborted ' False ``` +[**SearchStepLimit**](RegExp/SearchStepLimit) explains the budget, shows the message, and raises the ceiling when a search genuinely needs more. + ## Classes - [Match](Match/) -- holds one match that a RegExp found in a string: the matched text, where it starts, how many characters it has, and the text captured by its groups @@ -130,7 +88,7 @@ Debug.Print re.SearchAborted ' False - [MultiLine](RegExp/MultiLine) -- returns or sets whether `^` and `$` match at line boundaries - [Pattern](RegExp/Pattern) -- returns or sets the regular expression - [Replace](RegExp/Replace) -- replaces the matches in a string - - [SearchAborted](RegExp/SearchAborted) -- returns whether the last search gave up before it finished + - [SearchStepLimit](RegExp/SearchStepLimit) -- returns or sets the step budget that stops a runaway search - [Split](RegExp/Split) -- splits a string at the matches - [Test](RegExp/Test) -- returns whether a string contains a match - [SubMatches](SubMatches/) -- holds the strings that the capture groups of a pattern captured in one Match diff --git a/docs/Reference/Default/VB/index.md b/docs/Reference/Default/VB/index.md index f151d54fe..aff37ed29 100644 --- a/docs/Reference/Default/VB/index.md +++ b/docs/Reference/Default/VB/index.md @@ -4,7 +4,7 @@ parent: Default Packages nav_order: 1 permalink: /tB/Packages/VB/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # VB Package diff --git a/docs/Reference/Default/VBA/Collection/index.md b/docs/Reference/Default/VBA/Collection/index.md index 29fe86385..20da3b76f 100644 --- a/docs/Reference/Default/VBA/Collection/index.md +++ b/docs/Reference/Default/VBA/Collection/index.md @@ -24,8 +24,8 @@ Sub Demo() Cars.Add "Toyota Mirai" ' Add without a key. Debug.Print Cars.Count ' 3 - Debug.Print Cars("EV") ' "Polestar 2" — Item is the default member. - Debug.Print Cars(3) ' "Toyota Mirai" — indexes are 1-based. + Debug.Print Cars("EV") ' "Polestar 2": Item is the default member. + Debug.Print Cars(3) ' "Toyota Mirai": indexes are 1-based. Cars.Remove "ICE" ' Remove the Volvo XC40 by key. Cars.Remove 1 ' Remove the Polestar 2 by index. diff --git a/docs/Reference/Default/VBA/DateTime/index.md b/docs/Reference/Default/VBA/DateTime/index.md index 18c3a944b..84371475e 100644 --- a/docs/Reference/Default/VBA/DateTime/index.md +++ b/docs/Reference/Default/VBA/DateTime/index.md @@ -40,13 +40,13 @@ FirstOfNextMonth = DateSerial(Year(Now), Month(Now) + 1, 1) The single-component accessors each return one part of a **Date** as an **Integer**: [**Year**](Year), [**Month**](Month), [**Day**](Day), [**Weekday**](Weekday), [**Hour**](Hour), [**Minute**](Minute), and [**Second**](Second). [**DatePart**](DatePart) generalises the same idea, taking the chosen part as a string interval code (`"yyyy"`, `"q"`, `"m"`, `"d"`, ...) --- useful when the unit itself is a parameter. -```tb check_build +```tb check_build check_run Dim D As Date D = #2/12/1969# Debug.Print Year(D) ' 1969 Debug.Print Month(D) ' 2 Debug.Print Day(D) ' 12 -Debug.Print Weekday(D) ' 4 — Wednesday +Debug.Print Weekday(D) ' 4 -- Wednesday ``` ## Date arithmetic @@ -54,7 +54,7 @@ Debug.Print Weekday(D) ' 4 — Wednesday [**DateAdd**](DateAdd) shifts a date by a chosen number of intervals --- years, quarters, months, weeks, days, hours, minutes, or seconds --- taking calendar irregularities (varying month lengths, leap years) into account, and clamping to the last day of the target month when a literal day-of-month would be invalid. [**DateDiff**](DateDiff) does the inverse: it returns the count of whole intervals between two dates. Both share the same string interval codes used by **DatePart**. ```tb check_build -Debug.Print DateAdd("m", 1, #1/31/2026#) ' 2/28/2026 — clamped to last day of February +Debug.Print DateAdd("m", 1, #1/31/2026#) ' 2/28/2026 -- clamped to last day of February Debug.Print DateDiff("d", #1/1/2026#, #5/9/2026#) ' 128 ``` diff --git a/docs/Reference/Default/VBA/HiddenModule/GetMem1.md b/docs/Reference/Default/VBA/HiddenModule/GetMem1.md index 22e218a9f..15c004d7a 100644 --- a/docs/Reference/Default/VBA/HiddenModule/GetMem1.md +++ b/docs/Reference/Default/VBA/HiddenModule/GetMem1.md @@ -20,11 +20,11 @@ The address is read directly with no bounds or alignment check. Reading from an ### Example -```tb check_build +```tb check_build check_run Dim s As String = "ABC" Dim b As Byte GetMem1 StrPtr(s), b -Debug.Print b ' 65 — the low byte of the UTF-16 code unit for "A". +Debug.Print b ' 65 -- the low byte of the UTF-16 code unit for "A". ``` ### See Also diff --git a/docs/Reference/Default/VBA/Information/IsArrayInitialized.md b/docs/Reference/Default/VBA/Information/IsArrayInitialized.md index 68a82671b..bc98fd37a 100644 --- a/docs/Reference/Default/VBA/Information/IsArrayInitialized.md +++ b/docs/Reference/Default/VBA/Information/IsArrayInitialized.md @@ -21,13 +21,13 @@ If *varname* is not an array, **IsArrayInitialized** returns **False**. This example tests an array before and after **ReDim**, and again after **Erase** releases its storage. -```tb check_build +```tb check_build check_run Dim a() As Long -Debug.Print IsArrayInitialized(a) ' False — declared but unsized. +Debug.Print IsArrayInitialized(a) ' False -- declared but unsized. ReDim a(0 To 9) -Debug.Print IsArrayInitialized(a) ' True — dimensions allocated. +Debug.Print IsArrayInitialized(a) ' True -- dimensions allocated. Erase a -Debug.Print IsArrayInitialized(a) ' False — Erase released the storage. +Debug.Print IsArrayInitialized(a) ' False -- Erase released the storage. ``` ### See Also diff --git a/docs/Reference/Default/VBA/Information/StrPtr.md b/docs/Reference/Default/VBA/Information/StrPtr.md index 69e9e3f8b..718aa4b9d 100644 --- a/docs/Reference/Default/VBA/Information/StrPtr.md +++ b/docs/Reference/Default/VBA/Information/StrPtr.md @@ -26,7 +26,7 @@ The pointer is valid only as long as the **String** variable stays alive and is ```tb check_build Dim s As String s = "Hello" -Debug.Print StrPtr(s) ' e.g. 1234567890 — varies per run +Debug.Print StrPtr(s) ' e.g. 1234567890 -- varies per run Dim ch As Integer GetMem2 StrPtr(s), ch diff --git a/docs/Reference/Default/VBA/Information/VarPtr.md b/docs/Reference/Default/VBA/Information/VarPtr.md index 7d1c20295..cd87b0ac2 100644 --- a/docs/Reference/Default/VBA/Information/VarPtr.md +++ b/docs/Reference/Default/VBA/Information/VarPtr.md @@ -21,13 +21,13 @@ Pass the result to an API function that needs a raw address, or pass it to one o ### Example -```tb check_build +```tb check_build check_run Dim n As Long n = &H12345678 Dim Bytes(0 To 3) As Byte vbaCopyBytes 4, VarPtr(Bytes(0)), VarPtr(n) -Debug.Print Hex(Bytes(0)) ' "78" — little-endian +Debug.Print Hex(Bytes(0)) ' 78 -- little-endian ``` ### See Also diff --git a/docs/Reference/Default/VBA/Information/index.md b/docs/Reference/Default/VBA/Information/index.md index 08532aeb1..b88dc3bab 100644 --- a/docs/Reference/Default/VBA/Information/index.md +++ b/docs/Reference/Default/VBA/Information/index.md @@ -25,12 +25,12 @@ Debug.Print TypeName(v) ' "String" [**LBound**](LBound) and [**UBound**](UBound) return the smallest and largest valid subscript for a chosen dimension of an array. With a single argument they report on the first dimension; pass an explicit *Dimension* index to query a multidimensional array. -```tb check_build +```tb check_build check_run Dim Grid(1 To 4, 0 To 9) As Long -Debug.Print LBound(Grid) ' 1 — first dimension lower bound -Debug.Print UBound(Grid) ' 4 — first dimension upper bound -Debug.Print LBound(Grid, 2) ' 0 — second dimension lower bound -Debug.Print UBound(Grid, 2) ' 9 — second dimension upper bound +Debug.Print LBound(Grid) ' 1 -- first dimension lower bound +Debug.Print UBound(Grid) ' 4 -- first dimension upper bound +Debug.Print LBound(Grid, 2) ' 0 -- second dimension lower bound +Debug.Print UBound(Grid, 2) ' 9 -- second dimension upper bound ``` ## Building Variant arrays @@ -47,11 +47,11 @@ Array(x, y, z) = a ' destructuring assignment Three functions return raw addresses for use with API calls or unsafe interop: [**ObjPtr**](ObjPtr) for an object's COM identity, [**StrPtr**](StrPtr) for the underlying buffer of a **String**, and [**VarPtr**](VarPtr) for any variable. The result is a **LongPtr** valid only while the underlying object, string, or variable stays alive --- taking a pointer never holds a reference of its own. To read or write the memory at a known address, pair these with the [**GetMem**](../HiddenModule/GetMem4) / [**PutMem**](../HiddenModule/PutMem4) family from the [(Default)](../HiddenModule/) module. -```tb check_build +```tb check_build check_run Dim n As Long = &H12345678 Dim Bytes(0 To 3) As Byte vbaCopyBytes 4, VarPtr(Bytes(0)), VarPtr(n) -Debug.Print Hex(Bytes(0)) ' "78" — little-endian +Debug.Print Hex(Bytes(0)) ' 78 -- little-endian ``` ## Working with colour values diff --git a/docs/Reference/Default/VBA/Math/index.md b/docs/Reference/Default/VBA/Math/index.md index 84d09bb61..c04fd7873 100644 --- a/docs/Reference/Default/VBA/Math/index.md +++ b/docs/Reference/Default/VBA/Math/index.md @@ -22,10 +22,10 @@ Debug.Print Sgn(-7.5) ' -1 [**Sin**](Sin), [**Cos**](Cos), and [**Tan**](Tan) take an angle in radians and return its sine, cosine, and tangent. [**Atn**](Atn) goes the other way --- given a tangent, it returns the angle whose tangent that is, in the range `-pi/2` to `pi/2`. All four work exclusively in radians; multiply degrees by `pi / 180` to convert to radians, or radians by `180 / pi` to convert back. -```tb check_build +```tb check_build check_run Const Pi As Double = 3.14159265358979 Debug.Print Sin(Pi / 2) ' 1 -Debug.Print Atn(1) * 4 ' 3.14159265358979 — pi +Debug.Print Atn(1) * 4 ' 3.14159265358979 -- pi ``` The other inverse trigonometric functions (arcsine, arccosine) and the hyperbolic functions are not provided directly, but each can be derived from **Atn**, **Log**, **Exp**, and **Sqr** in a couple of lines --- see the worked examples on [**Atn**](Atn), [**Log**](Log), and [**Cos**](Cos). @@ -34,9 +34,9 @@ The other inverse trigonometric functions (arcsine, arccosine) and the hyperboli [**Exp**](Exp) raises *e* (≈ 2.71828) to a chosen power, and [**Log**](Log) is its inverse, returning the natural (base-*e*) logarithm. To compute a logarithm in another base, divide by **Log** of that base: `Log(x) / Log(10)` for base 10, `Log(x) / Log(2)` for base 2, and so on. -```tb check_build -Debug.Print Exp(1) ' 2.71828182845905 — e -Debug.Print Log(100) / Log(10) ' 2 — base-10 log of 100 +```tb check_build check_run +Debug.Print Exp(1) ' 2.71828182845905 -- e +Debug.Print Log(100) / Log(10) ' 2 -- base-10 log of 100 ``` ## Square root diff --git a/docs/Reference/Default/VBA/TbExpressionService/AddCustomBinderObject.md b/docs/Reference/Default/VBA/TbExpressionService/AddCustomBinderObject.md index 6fc94bb01..cc3ebb5e6 100644 --- a/docs/Reference/Default/VBA/TbExpressionService/AddCustomBinderObject.md +++ b/docs/Reference/Default/VBA/TbExpressionService/AddCustomBinderObject.md @@ -38,7 +38,7 @@ Service.AddStdLibraryBinder() Service.AddCustomBinderObject "Report", Me, IsAppObject Debug.Print Service.Compile("Report.Title").Evaluate() ' "Sales Q4" -Debug.Print Service.Compile("Title").Evaluate() ' "Sales Q4" — IsAppObject in effect +Debug.Print Service.Compile("Title").Evaluate() ' "Sales Q4" -- IsAppObject in effect ``` ### See Also diff --git a/docs/Reference/Default/VBA/TbExpressionService/index.md b/docs/Reference/Default/VBA/TbExpressionService/index.md index 4d350326d..f0ebc4f5a 100644 --- a/docs/Reference/Default/VBA/TbExpressionService/index.md +++ b/docs/Reference/Default/VBA/TbExpressionService/index.md @@ -45,7 +45,7 @@ Sub UseCustomObject() Service.AddCustomBinderObject "Report", Me, IsAppObject Debug.Print Service.Compile("Report.Title").Evaluate() ' qualified - Debug.Print Service.Compile("Title").Evaluate() ' unqualified — IsAppObject in effect + Debug.Print Service.Compile("Title").Evaluate() ' unqualified -- IsAppObject in effect End Sub ``` diff --git a/docs/Reference/Default/VBA/index.md b/docs/Reference/Default/VBA/index.md index cbe36ffa9..eed6974b7 100644 --- a/docs/Reference/Default/VBA/index.md +++ b/docs/Reference/Default/VBA/index.md @@ -6,7 +6,7 @@ permalink: /tB/Packages/VBA redirect_from: - /tB/Modules has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # VBA Package diff --git a/docs/Reference/Default/VBRUN/index.md b/docs/Reference/Default/VBRUN/index.md index 2655e67b1..802462ed8 100644 --- a/docs/Reference/Default/VBRUN/index.md +++ b/docs/Reference/Default/VBRUN/index.md @@ -4,7 +4,7 @@ parent: Default Packages nav_order: 3 permalink: /tB/Packages/VBRUN/ has_toc: false -indexed_from: beta-x-0997 +indexed_from: beta-x-1005 --- # VBRUN Package diff --git a/docs/Reference/Images/TYizrRW.light.png b/docs/Reference/Images/TYizrRW.light.png index 17c359bc8..0b319ae5e 100644 Binary files a/docs/Reference/Images/TYizrRW.light.png and b/docs/Reference/Images/TYizrRW.light.png differ diff --git a/docs/Reference/Images/TYizrRW.png b/docs/Reference/Images/TYizrRW.png index af2b6ce09..bfc2bab25 100644 Binary files a/docs/Reference/Images/TYizrRW.png and b/docs/Reference/Images/TYizrRW.png differ diff --git a/docs/Reference/Images/flags-attribute.light.png b/docs/Reference/Images/flags-attribute.light.png index 3c81f9b80..3f5e6c738 100644 Binary files a/docs/Reference/Images/flags-attribute.light.png and b/docs/Reference/Images/flags-attribute.light.png differ diff --git a/docs/Reference/Images/flags-attribute.png b/docs/Reference/Images/flags-attribute.png index b81710a15..2cb8a8cf8 100644 Binary files a/docs/Reference/Images/flags-attribute.png and b/docs/Reference/Images/flags-attribute.png differ diff --git a/docs/Reference/Images/oHpCiV1.light.png b/docs/Reference/Images/oHpCiV1.light.png index f67203d32..b9e0c5b4b 100644 Binary files a/docs/Reference/Images/oHpCiV1.light.png and b/docs/Reference/Images/oHpCiV1.light.png differ diff --git a/docs/Reference/Images/oHpCiV1.png b/docs/Reference/Images/oHpCiV1.png index da0c48ad9..ab8b4d2e9 100644 Binary files a/docs/Reference/Images/oHpCiV1.png and b/docs/Reference/Images/oHpCiV1.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccCOMCreatable.light.png b/docs/Tutorials/CustomControls/Images/ccCOMCreatable.light.png index 017108673..4d8d45409 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccCOMCreatable.light.png and b/docs/Tutorials/CustomControls/Images/ccCOMCreatable.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccCOMCreatable.png b/docs/Tutorials/CustomControls/Images/ccCOMCreatable.png index fc2e87232..0d0201ee3 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccCOMCreatable.png and b/docs/Tutorials/CustomControls/Images/ccCOMCreatable.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.light.png b/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.light.png index 6d638dcd6..029d2aaf0 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.light.png and b/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.png b/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.png index 16fb89080..c507ffcc8 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.png and b/docs/Tutorials/CustomControls/Images/ccClassIdAttribute.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccClassIdInsert.light.png b/docs/Tutorials/CustomControls/Images/ccClassIdInsert.light.png index a2c64f761..08f71039e 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccClassIdInsert.light.png and b/docs/Tutorials/CustomControls/Images/ccClassIdInsert.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccClassIdInsert.png b/docs/Tutorials/CustomControls/Images/ccClassIdInsert.png index db60e4663..b7b8d4b07 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccClassIdInsert.png and b/docs/Tutorials/CustomControls/Images/ccClassIdInsert.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.light.png b/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.light.png index 8136ed235..8d8a42fc4 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.light.png and b/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.png b/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.png index efc55b076..7b50010ac 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.png and b/docs/Tutorials/CustomControls/Images/ccCustomControlAttribute.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccEvents.light.svg b/docs/Tutorials/CustomControls/Images/ccEvents.light.svg index b1db399da..d78074804 100644 --- a/docs/Tutorials/CustomControls/Images/ccEvents.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccEvents.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXEDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXEDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccEvents.png b/docs/Tutorials/CustomControls/Images/ccEvents.png index e4822ba0b..92533a339 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccEvents.png and b/docs/Tutorials/CustomControls/Images/ccEvents.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccEvents.svg b/docs/Tutorials/CustomControls/Images/ccEvents.svg index cba3de933..47621bbaf 100644 --- a/docs/Tutorials/CustomControls/Images/ccEvents.svg +++ b/docs/Tutorials/CustomControls/Images/ccEvents.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXEDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXEDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccGridButtonImage.light.png b/docs/Tutorials/CustomControls/Images/ccGridButtonImage.light.png index 3c5400a07..b09a822bc 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccGridButtonImage.light.png and b/docs/Tutorials/CustomControls/Images/ccGridButtonImage.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccGridButtonImage.png b/docs/Tutorials/CustomControls/Images/ccGridButtonImage.png index 2a6f78980..8db8aeffa 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccGridButtonImage.png and b/docs/Tutorials/CustomControls/Images/ccGridButtonImage.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccICustomControl.light.png b/docs/Tutorials/CustomControls/Images/ccICustomControl.light.png index c2d2fe60f..b3ad1549b 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccICustomControl.light.png and b/docs/Tutorials/CustomControls/Images/ccICustomControl.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccICustomControl.png b/docs/Tutorials/CustomControls/Images/ccICustomControl.png index 52b59fb40..27f0279f2 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccICustomControl.png and b/docs/Tutorials/CustomControls/Images/ccICustomControl.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.light.svg b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.light.svg index 5b97bd040..15156eec5 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents.EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents.EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.png b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.png index 8d0d79f9a..d2130fbec 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.png and b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.svg b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.svg index a915ca84b..db58311ac 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyEnumFieldPropertySheet.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.png b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.png index 517ffca6d..c768bfb1b 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.svg index ab9c97ecc..1c89152bc 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.png b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.png index b6a1717ea..e4b19bbcd 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.svg index 882be14bb..e91ef71f1 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldArray.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldArray.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpproject.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶MyGrid.twinî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.png b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.png index 922fa1b69..695a5db38 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.svg index 39557e2fc..f692858df 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32100%TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶480 x 320 +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelp• project.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32100%TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶480 x 320 diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.png b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.png index f186fa1b4..8bcd4c661 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.svg index 2beaae7f5..2cc3f489b 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldClass.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldClass.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpproject.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32100%TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶480 x 320 +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpproject.twinproj - twinBASIC (twinBASIC IDE BETA 1005)win32100%TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyButton.twinî©¶frmCustom.tbformî©¶480 x 320 diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.light.png b/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.light.png index 80f2d0b62..272054b2a 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.light.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.png b/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.png index e2c067513..d85b242bb 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldCustomProperty.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.light.png b/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.light.png index 9acfcf9dd..5da81a1fb 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.light.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.png b/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.png index bf716cddc..5915bc9b2 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.png and b/docs/Tutorials/CustomControls/Images/ccMyFieldJson1a.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.light.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.light.svg index dd91d9214..7b7dc49c4 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.svg index 2cef5d909..e553004ef 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1a.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.light.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.light.svg index 237a102ea..ed7d24240 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.light.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.light.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.svg b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.svg index d8d08de58..29818ce5c 100644 --- a/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.svg +++ b/docs/Tutorials/CustomControls/Images/ccMyFieldPropertySheet1b.svg @@ -1 +1 @@ -FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ +FileEditViewProjectFormatDebugRunToolsAdd-InsWindowHelpwin32TOOLBOXCustomControlsDemoMorecomponents...EDITOR 1MyGrid.twinî©¶frmCustom.tbformî©¶ diff --git a/docs/Tutorials/CustomControls/Images/ccSampleProject.light.png b/docs/Tutorials/CustomControls/Images/ccSampleProject.light.png index 09979fa3a..d50f980d2 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccSampleProject.light.png and b/docs/Tutorials/CustomControls/Images/ccSampleProject.light.png differ diff --git a/docs/Tutorials/CustomControls/Images/ccSampleProject.png b/docs/Tutorials/CustomControls/Images/ccSampleProject.png index 6bd09effa..5d76986ac 100644 Binary files a/docs/Tutorials/CustomControls/Images/ccSampleProject.png and b/docs/Tutorials/CustomControls/Images/ccSampleProject.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.light.png b/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.light.png index 58070e4ca..179b57170 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.light.png and b/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.light.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.png b/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.png index 4cd620e94..52f7c54ac 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.png and b/docs/Tutorials/WebView2/Images/tbWebView2CreateEvent.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2Properties.png b/docs/Tutorials/WebView2/Images/tbWebView2Properties.png index 16cf3fc16..b16b4c175 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2Properties.png and b/docs/Tutorials/WebView2/Images/tbWebView2Properties.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2Sample0.light.png b/docs/Tutorials/WebView2/Images/tbWebView2Sample0.light.png index b9f712cdc..40655cf81 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2Sample0.light.png and b/docs/Tutorials/WebView2/Images/tbWebView2Sample0.light.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2Sample0.png b/docs/Tutorials/WebView2/Images/tbWebView2Sample0.png index f341f389a..5b7f62836 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2Sample0.png and b/docs/Tutorials/WebView2/Images/tbWebView2Sample0.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.light.png b/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.light.png index 9f2b5dcf3..446688295 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.light.png and b/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.light.png differ diff --git a/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.png b/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.png index 82c314c0e..6ce2e39e1 100644 Binary files a/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.png and b/docs/Tutorials/WebView2/Images/tbWebView2Toolbox.png differ diff --git a/docs/_config.yml b/docs/_config.yml index 0b86eb263..f4e0d82a7 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -114,6 +114,8 @@ bundle_extra: dest: Features/Packages/downloads/impexp.mjs - src: ../scripts/impexp.py dest: Features/Packages/downloads/impexp.py + - src: ../scripts/impexp/impexp.twinproj + dest: Features/Packages/downloads/impexp.twinproj # The IDE help add-in's project file, which the build packs from the add-in's # source folder (src, relative to docs/) and writes into the online and offline diff --git a/indexer/README.md b/indexer/README.md index bf8ea0068..123d593da 100644 --- a/indexer/README.md +++ b/indexer/README.md @@ -128,7 +128,7 @@ those files, makes the next `sync` index every package again; the store also keeps each package's `Settings` file for this, beside its `sources/`. `analyze` warns when the fingerprint of a package is not the checkout's. The version in `api.json` is the release tag in both cases: -BETA 983 is `beta-x-0983`, as `indexed_from` in the package pages has it. The +BETA 1005 is `beta-x-1005`, as `indexed_from` in the package pages has it. The BETA number is read from the install's `ide/build.js`, else from the name of its folder. @@ -463,31 +463,31 @@ reads it; the site's builder ignores these keys): | Key | Means | |-----|-------| | `package_name:` | The packages the section documents, by the names the store has, comma-separated: `CustomControls, CustomControlsPackage`. Without it the section documents the package named like its folder. It replaces that name, so the folder's own is listed too when it is a package. | -| `indexed_from:` | The release tag the section was brought up to date with, `beta-x-0997`: the `version` of the committed snapshots. Bump it in the commit that updates the pages, and write the new snapshots in it. | +| `indexed_from:` | The release tag the section was brought up to date with, `beta-x-1005`: the `version` of the committed snapshots. Bump it in the commit that updates the pages, and write the new snapshots in it. | | `exclude_from_docs:`, `exclude_kinds:` | Types, and kinds of symbol, that are deliberately not documented, so `analyze` does not list them. | The group is the folder's: a package in `Built-In/` is a built-in one. -The 13 sections and the 14 snapshots they have, all of BETA 997 (`beta-x-0997`), +The 13 sections and the 14 snapshots they have, all of BETA 1005 (`beta-x-1005`), the build the reference was last indexed against: | Section | Packages (`package_name:`) | Snapshots | Size | |---------|----------------------------|-----------|------| -| `Default/VB` | `VB` (no key) | `default/VB` | 1,424 KB | -| `Default/VBA` | `VBA` (no key) | `default/VBA` | 411 KB | -| `Default/VBRUN` | `VBRUN` (no key) | `default/VBRUN` | 104 KB | +| `Default/VB` | `VB` (no key) | `default/VB` | 1,427 KB | +| `Default/VBA` | `VBA` (no key) | `default/VBA` | 407 KB | +| `Default/VBRUN` | `VBRUN` (no key) | `default/VBRUN` | 106 KB | | `Built-In/AppGlobalClassObject` | `AppGlobalClassObject` (no key) | `built-in/AppGlobalClassObject` | 22 KB | -| `Built-In/CEF` | `cefPackage145` | `built-in/cefPackage145` | 466 KB | +| `Built-In/CEF` | `cefPackage145` | `built-in/cefPackage145` | 468 KB | | `Built-In/CustomControls` | `CustomControls, CustomControlsPackage` | `built-in/CustomControls`, `built-in/CustomControlsPackage` | 20 KB, 87 KB | | `Built-In/TwinBasicAssertions` (the `Assert` package) | `TwinBasicAssertions` (no key) | `built-in/TwinBasicAssertions` | 21 KB | | `Built-In/WebView2` | `WebView2Package` | `built-in/WebView2Package` | 189 KB | | `Built-In/WinEventLogLib` | `WinEventLogLib` (no key) | `built-in/WinEventLogLib` | 7 KB | | `Built-In/WinNamedPipesLib` | `WinNamedPipesLib` (no key) | `built-in/WinNamedPipesLib` | 56 KB | -| `Built-In/WinNativeCommonCtls` | `WinNativeCommonCtls` (no key) | `built-in/WinNativeCommonCtls` | 313 KB | +| `Built-In/WinNativeCommonCtls` | `WinNativeCommonCtls` (no key) | `built-in/WinNativeCommonCtls` | 314 KB | | `Built-In/WinServicesLib` | `WinServicesLib` (no key) | `built-in/WinServicesLib` | 41 KB | | `Built-In/tbIDE` | `tbIDE` (no key) | `built-in/tbIDE` | 48 KB | -That is 3.2 MB as the files are, about 350 KB compressed. The project name inside +That is 3.2 MB as the files are, about 360 KB compressed. The project name inside the files (`project` in `api.json`) is not always the package's: `TwinBasicAssertions` is the project `Assert`, `AppGlobalClassObject` is `AppGlobalClassProject` and the three CEF packages are `cefPackage`. The @@ -497,7 +497,7 @@ project name. **One API, several builds.** The three CEF packages in an install, `cefPackage49`, `cefPackage109` and `cefPackage145`, are one source tree compiled against three CEF runtimes. Their `api.json` files differ only in -the `package` key (checked on BETA 997 and 1005), and the reference has one +the `package` key (checked on BETA 1005), and the reference has one section for them, so the section names one and the repository keeps one snapshot, of the newest, `cefPackage145`. `analyze` compares each package with its own snapshot, so naming all three would triple every CEF task and keep two @@ -601,7 +601,7 @@ so it won't interfere with your global git config. | File | Description | |------|-------------| -| `TWINSERV-protocol.md` | TWINSERV HTTP API specification, reverse-engineered from BETA 983. The indexer calls only `query` and `download`. | +| `TWINSERV-protocol.md` | TWINSERV HTTP API specification, reverse-engineered from the IDE and describing BETA 1005. The indexer calls only `query` and `download`. | | `sample.twinpack` | Sample `.twinpack` binary (CustomControlsPackage v0.0.3.0). | | [`WIP.Indexer.md`](../WIP.Indexer.md) | Why the indexer is built as it is: decisions and open items. | diff --git a/indexer/TWINSERV-protocol.md b/indexer/TWINSERV-protocol.md index bee49faf0..8442b44cb 100644 --- a/indexer/TWINSERV-protocol.md +++ b/indexer/TWINSERV-protocol.md @@ -1,6 +1,8 @@ # TWINSERV Protocol Specification -Reverse-engineered from twinBASIC IDE Beta 983 (June 2026). +Describes twinBASIC IDE BETA 1005 (October 2026): the endpoints, their parameters and +headers, the error codes, the credential rotation and the compiler commands below are the +ones its `ide/main.js` uses. Source material: `ide/main.js`, `ide/toolWindow.js` (the IDE's own files; this repository keeps no copy of them), plus direct API probing. The indexer calls @@ -210,7 +212,7 @@ The server uses custom HTTP status codes beyond the standard range: | 200 | Success | | 551 | Package version already exists (duplicate publish) | | 552 | Authentication required / session expired | -| 553 | Conflict: username already taken (registration), or package owned by another publisher (publish) | +| 553 | Conflict: username already taken (registration), or package owned by another publisher (publish); username not found (login) | | 555 | Incorrect password (login) | ## Other Endpoints diff --git a/indexer/lib/builtin-sync.mjs b/indexer/lib/builtin-sync.mjs index f27f37e0e..033a76cde 100644 --- a/indexer/lib/builtin-sync.mjs +++ b/indexer/lib/builtin-sync.mjs @@ -23,7 +23,7 @@ async function loadManifest(manifestPath) { // What a manifest written before it recorded its source was read from. const sourceOf = (manifest) => manifest.source ?? "release"; -/** The tag a build is released under: BETA 983 is `beta-x-0983`, BETA 999a `beta-x-0999a`. */ +/** The tag a build is released under: BETA 1005 is `beta-x-1005`, BETA 999a `beta-x-0999a`. */ function tagForBeta(beta) { const m = BETA_RE.exec(beta); return m ? `beta-x-${m[1].padStart(4, "0")}${m[2]}` : null; diff --git a/indexer/snapshots/built-in/AppGlobalClassObject/api.json b/indexer/snapshots/built-in/AppGlobalClassObject/api.json index 32a30590d..5f7c07304 100644 --- a/indexer/snapshots/built-in/AppGlobalClassObject/api.json +++ b/indexer/snapshots/built-in/AppGlobalClassObject/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "AppGlobalClassObject", "project": "AppGlobalClassProject", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "App", diff --git a/indexer/snapshots/built-in/CustomControls/api.json b/indexer/snapshots/built-in/CustomControls/api.json index d8ede5bcf..3f3be2047 100644 --- a/indexer/snapshots/built-in/CustomControls/api.json +++ b/indexer/snapshots/built-in/CustomControls/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "CustomControls", "project": "CustomControls", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "Constants", diff --git a/indexer/snapshots/built-in/CustomControlsPackage/api.json b/indexer/snapshots/built-in/CustomControlsPackage/api.json index 8955745b7..3058fedcb 100644 --- a/indexer/snapshots/built-in/CustomControlsPackage/api.json +++ b/indexer/snapshots/built-in/CustomControlsPackage/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "CustomControlsPackage", "project": "CustomControlsPackage", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "Anchors", diff --git a/indexer/snapshots/built-in/TwinBasicAssertions/api.json b/indexer/snapshots/built-in/TwinBasicAssertions/api.json index 203f9c852..33ba04db8 100644 --- a/indexer/snapshots/built-in/TwinBasicAssertions/api.json +++ b/indexer/snapshots/built-in/TwinBasicAssertions/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "TwinBasicAssertions", "project": "Assert", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "Exact", diff --git a/indexer/snapshots/built-in/WebView2Package/api.json b/indexer/snapshots/built-in/WebView2Package/api.json index 197d0e325..df1d60c70 100644 --- a/indexer/snapshots/built-in/WebView2Package/api.json +++ b/indexer/snapshots/built-in/WebView2Package/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WebView2Package", "project": "WebView2Package", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "ControlAlt", diff --git a/indexer/snapshots/built-in/WinEventLogLib/api.json b/indexer/snapshots/built-in/WinEventLogLib/api.json index aee13242d..208cad8c8 100644 --- a/indexer/snapshots/built-in/WinEventLogLib/api.json +++ b/indexer/snapshots/built-in/WinEventLogLib/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WinEventLogLib", "project": "WinEventLogLib", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "EventLog", diff --git a/indexer/snapshots/built-in/WinNamedPipesLib/api.json b/indexer/snapshots/built-in/WinNamedPipesLib/api.json index 81f8bd3f8..943a189c8 100644 --- a/indexer/snapshots/built-in/WinNamedPipesLib/api.json +++ b/indexer/snapshots/built-in/WinNamedPipesLib/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WinNamedPipesLib", "project": "WinNamedPipesLib", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "INamedPipeClientConnectionInternal", diff --git a/indexer/snapshots/built-in/WinNativeCommonCtls/api.json b/indexer/snapshots/built-in/WinNativeCommonCtls/api.json index f593a10be..9e6a27446 100644 --- a/indexer/snapshots/built-in/WinNativeCommonCtls/api.json +++ b/indexer/snapshots/built-in/WinNativeCommonCtls/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WinNativeCommonCtls", "project": "WinNativeCommonCtls", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "ColumnHeader", @@ -469,6 +469,7 @@ "attrs": [{"name":"ClassId","args":"\"3474B17E-2CB0-427C-8E48-A54AFB24A9B4\""},{"name":"InterfaceId","args":"\"5FB4707A-74F6-455A-93CF-48A7991D49F2\""},{"name":"EventInterfaceId","args":"\"7E4E64BD-BA49-4F40-9330-F20E02EA2D2A\""},{"name":"COMCreatable","args":"False"},{"name":"EventsUseDispInterface"}], "members": [ {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}]}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BoundCount","kind":"field","vis":"protected","signature":"Protected BoundCount As Long","hidden":true,"attrs":[{"name":"Serialize","args":"False"},{"name":"Hidden"}]}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"ColorDepth","kind":"field","vis":"public","signature":"Public ColorDepth As ImageListColorDepth = ImageListColorDepth.ColorDepth32Bit"}, @@ -515,7 +516,7 @@ {"name":"Object","kind":"property","vis":"public","signature":"Public Property Get Object() As Object","returnType":"Object","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"Overlay","kind":"function","vis":"public","signature":"Public Function Overlay(Key1 As Variant, Key2 As Variant) As StdPicture","returnType":"StdPicture"}, {"name":"Parent","kind":"property","vis":"public","signature":"Public Property Get Parent() As Object","returnType":"Object","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, - {"name":"SyncListProps","kind":"sub","vis":"protected","signature":"Protected Sub SyncListProps() Handles BackColor.OnPropertyLet, UseBackColor.OnPropertyLet"}, + {"name":"SyncListProps","kind":"sub","vis":"protected","signature":"Protected Sub SyncListProps() Handles UseBackColor.OnPropertyLet"}, {"name":"SyncListProps2","kind":"sub","vis":"protected","signature":"Protected Sub SyncListProps2() Implements TbImageListPrivate.SyncListProps"}, {"name":"UseBackColor","kind":"field","vis":"public","signature":"Public UseBackColor As Boolean = False"}, {"name":"UseMaskColor","kind":"field","vis":"public","signature":"Public UseMaskColor As Boolean = True"}, @@ -735,6 +736,7 @@ "attrs": [{"name":"COMCreatable","args":"False"},{"name":"ClassId","args":"\"90D0C2C1-71A2-4629-B25B-FE97725B0B3C\""},{"name":"InterfaceId","args":"\"4A4A6788-ADB0-4B20-8FD9-69BC7716D491\""}], "members": [ {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = -1","description":"The back color used when rendering this item"}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"Bold","kind":"field","vis":"public","signature":"Public Bold As Boolean = False","description":"Determines if the item is rendered in a bold font"}, {"name":"CachedKey","kind":"field","vis":"private","signature":"Private CachedKey As String"}, {"name":"ChangeIndexInternal","kind":"sub","vis":"friend","signature":"Friend Sub ChangeIndexInternal(Value As Long)"}, @@ -745,12 +747,13 @@ {"name":"CreateDragImage","kind":"function","vis":"public","signature":"Function CreateDragImage() As IPictureDisp","returnType":"IPictureDisp","attrs":[{"name":"Unimplemented"}]}, {"name":"EnsureVisible","kind":"sub","vis":"public","signature":"Public Sub EnsureVisible()","description":"This ensures the item is visible within the listview, by scrolling the listview if necessary"}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = SystemColorConstants.vbWindowText","description":"The fore color (font color) used when rendering this item"}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetItemStateFlag","kind":"function","vis":"private","signature":"Private Function GetItemStateFlag(ByVal StateFlag As Long) As Boolean","returnType":"Boolean"}, {"name":"GetItemStateFlags","kind":"function","vis":"private","signature":"Private Function GetItemStateFlags(ByVal StateFlag As Long) As Long","returnType":"Long"}, {"name":"GetLvItemText","kind":"function","vis":"private","signature":"Private Function GetLvItemText(ByRef Index As Integer) As String","returnType":"String"}, {"name":"Ghosted","kind":"property","vis":"public","signature":"Public Property Get Ghosted() As Boolean","returnType":"Boolean","accessor":"Get","description":"Returns/Sets whether the list item is currently ghosted (cut)"}, {"name":"Ghosted","kind":"property","vis":"public","signature":"Public Property Let Ghosted(ByVal Value As Boolean)","accessor":"Let","description":"Returns/Sets whether the list item is currently ghosted (cut)"}, - {"name":"HandleChanges","kind":"sub","vis":"private","signature":"Private Sub HandleChanges() Handles Bold.OnPropertyLet, BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, + {"name":"HandleChanges","kind":"sub","vis":"private","signature":"Private Sub HandleChanges() Handles Bold.OnPropertyLet"}, {"name":"Height","kind":"property","vis":"public","signature":"Property Get Height() As Single","returnType":"Single","accessor":"Get"}, {"name":"Icon","kind":"property","vis":"public","signature":"Public Property Get Icon() As Variant","returnType":"Variant","accessor":"Get"}, {"name":"Icon","kind":"property","vis":"public","signature":"Public Property Let Icon(Value As Variant)","accessor":"Let"}, @@ -835,7 +838,7 @@ {"name":"AllowColumnReorder","kind":"field","vis":"public","signature":"Public AllowColumnReorder As Boolean = False","attrs":[{"name":"CustomDesigner","args":"\"designer_RestrictedOLEDropMode\""}]}, {"name":"Arrange","kind":"field","vis":"public","signature":"Public Arrange As ListArrangeConstants = ListArrangeConstants.lvwNone","description":""}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":"The back color used when rendering"}, - {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged() Handles BackColor.OnPropertyLet, TextBackground.OnPropertyLet"}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BeforeLabelEdit","kind":"event","vis":"public","signature":"Event BeforeLabelEdit(Cancel As Boolean)","attrs":[{"name":"DefaultDesignerEvent"}],"description":"This event fires before a label-edit operation, providing a change to cancel the operation"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As TreeBorderStyleConstants = TreeBorderStyleConstants.ccFixedSingle","description":"Determines the border style of the listview"}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, @@ -858,6 +861,7 @@ {"name":"CheckBoxes","kind":"field","vis":"public","signature":"Public CheckBoxes As Boolean = False","description":"Determines if each list item of the listview has a checkbox associated with it"}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"}],"description":"This event is fired when the user clicks anywhere within the listview window area"}, + {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged()"}, {"name":"ColumnClick","kind":"event","vis":"public","signature":"Event ColumnClick(ColumnHeader As ColumnHeader)"}, {"name":"ColumnHeaderIcons","kind":"property","vis":"public","signature":"Public Property Get ColumnHeaderIcons() As ImageListBaseCtl","returnType":"ImageListBaseCtl","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ColumnHeaderIcons","kind":"property","vis":"public","signature":"Public Property Let ColumnHeaderIcons(Value As ImageListBaseCtl)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, @@ -955,6 +959,7 @@ {"name":"SyncOLEDropMode","kind":"sub","vis":"protected","signature":"Protected Sub SyncOLEDropMode() Handles OLEDropMode.OnPropertyLet"}, {"name":"SyncOpacity","kind":"sub","vis":"protected","signature":"Protected Sub SyncOpacity() Handles Opacity.OnPropertyLet, TransparencyKey.OnPropertyLet"}, {"name":"TextBackground","kind":"field","vis":"public","signature":"Public TextBackground As ListTextBackgroundConstants = ListTextBackgroundConstants.lvwTransparent","description":""}, + {"name":"TextBackgroundChanged","kind":"sub","vis":"protected","signature":"Protected Sub TextBackgroundChanged(ByVal OldValue As Long) Handles TextBackground.OnPropertyLet"}, {"name":"TransparencyKey","kind":"field","vis":"public","signature":"Public TransparencyKey As OLE_COLOR = -1","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindowsOrClear\""}],"description":"A color, when set, that will appear fully transparent in the window. REQUIRES TARGET OS 6.2+ FOR CHILD CONTROLS."}, {"name":"Validate","kind":"event","vis":"public","signature":"Event Validate(Cancel As Boolean)"}, {"name":"View","kind":"field","vis":"public","signature":"Public View As ListViewConstants = ListViewConstants.lvwIcon","description":"Determines whether the root list items also have visible association lines"}, @@ -2472,6 +2477,7 @@ "attrs": [{"name":"ClassId","args":"\"38268AC5-D63D-441B-8A46-3D4392F0D31A\""},{"name":"InterfaceId","args":"\"0CE28520-4056-4B4F-9F79-A97A3E0EA676\""},{"name":"COMCreatable","args":"False"},{"name":"EventsUseDispInterface"}], "members": [ {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbButtonFace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = ControlBorderStyleConstants.vbNoBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"public","signature":"Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"Change","kind":"event","vis":"public","signature":"Event Change()","description":""}, @@ -2481,6 +2487,7 @@ {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","description":""}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbHighlight","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"HandleCreate","kind":"sub","vis":"protected","signature":"Protected Sub HandleCreate() Implements VB.IWindowElementEventsCommon.Create"}, {"name":"HandleDestroy","kind":"sub","vis":"protected","signature":"Protected Sub HandleDestroy() Implements VB.IWindowsControl.Destroy"}, {"name":"HandleDragOver","kind":"sub","vis":"protected","signature":"Protected Sub HandleDragOver(ByVal Source As Object, ByVal X As Double, ByVal Y As Double, ByVal State As Long) Implements VB.IWindowElementEventsAX.DragOver"}, @@ -2524,8 +2531,6 @@ {"name":"Step","kind":"property","vis":"public","signature":"Public Property Let Step(ByVal Value As Long)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"StepIt","kind":"sub","vis":"public","signature":"Public Sub StepIt()"}, {"name":"Step_INIT","kind":"field","vis":"protected","signature":"Protected Step_INIT As Long = 10","attrs":[{"name":"Serialize","args":"True, \"Step\""}]}, - {"name":"SyncBackColor","kind":"sub","vis":"protected","signature":"Protected Sub SyncBackColor() Handles BackColor.OnPropertyLet"}, - {"name":"SyncForeColor","kind":"sub","vis":"protected","signature":"Protected Sub SyncForeColor() Handles ForeColor.OnPropertyLet"}, {"name":"SyncMarquee","kind":"sub","vis":"protected","signature":"Protected Sub SyncMarquee() Handles MarqueeAnimation.OnPropertyLet, MarqueeSpeed.OnPropertyLet"}, {"name":"SyncOLEDropMode","kind":"sub","vis":"protected","signature":"Protected Sub SyncOLEDropMode() Handles OLEDropMode.OnPropertyLet"}, {"name":"SyncOpacity","kind":"sub","vis":"protected","signature":"Protected Sub SyncOpacity() Handles Opacity.OnPropertyLet, TransparencyKey.OnPropertyLet"}, diff --git a/indexer/snapshots/built-in/WinServicesLib/api.json b/indexer/snapshots/built-in/WinServicesLib/api.json index e151331fb..2cf489720 100644 --- a/indexer/snapshots/built-in/WinServicesLib/api.json +++ b/indexer/snapshots/built-in/WinServicesLib/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WinServicesLib", "project": "WinServicesLib", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "IServiceCreator", diff --git a/indexer/snapshots/built-in/cefPackage145/api.json b/indexer/snapshots/built-in/cefPackage145/api.json index 653163cf6..82a893dd8 100644 --- a/indexer/snapshots/built-in/cefPackage145/api.json +++ b/indexer/snapshots/built-in/cefPackage145/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "cefPackage145", "project": "cefPackage", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "APIs", diff --git a/indexer/snapshots/built-in/tbIDE/api.json b/indexer/snapshots/built-in/tbIDE/api.json index e8c909c12..f1cb231b0 100644 --- a/indexer/snapshots/built-in/tbIDE/api.json +++ b/indexer/snapshots/built-in/tbIDE/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "tbIDE", "project": "tbIDE", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "AddIn", diff --git a/indexer/snapshots/contributed/tbRegExp/api.json b/indexer/snapshots/contributed/tbRegExp/api.json index 3c6b3c1c7..67487eab6 100644 --- a/indexer/snapshots/contributed/tbRegExp/api.json +++ b/indexer/snapshots/contributed/tbRegExp/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "tbRegExp", "project": "tbRegExp", - "version": "1.8.0.0", + "version": "1.9.0.0", "types": [ { "name": "IEnumVARIANT", @@ -93,6 +93,7 @@ "attrs": [{"name":"PredeclaredId","args":"False"},{"name":"Hidden","args":"False"}], "description": "This class exposes a drop-in replacement for VBSript's regular expressions object model.", "members": [ + {"name":"ApplySearchStepLimit","kind":"sub","vis":"private","signature":"Private Sub ApplySearchStepLimit()"}, {"name":"CacheCaptureInfo","kind":"sub","vis":"private","signature":"Private Sub CacheCaptureInfo()"}, {"name":"Class_Initialize","kind":"sub","vis":"private","signature":"Private Sub Class_Initialize()"}, {"name":"DescribeRegexError","kind":"function","vis":"private","signature":"Private Function DescribeRegexError(ByVal errNum As Long) As String","returnType":"String"}, @@ -115,7 +116,8 @@ {"name":"Pattern","kind":"property","vis":"public","signature":"Public Property Let Pattern(ByVal pPattern As String)","accessor":"Let","description":"The regular expression pattern."}, {"name":"Pattern","kind":"property","vis":"public","signature":"Public Property Get Pattern() As String","returnType":"String","accessor":"Get"}, {"name":"Replace","kind":"function","vis":"public","signature":"Public Function Replace(ByVal sourceString As String, ByVal replaceString As String) As String","returnType":"String","description":"Replaces matches with replaceString and returns the String with replacements made."}, - {"name":"SearchAborted","kind":"property","vis":"public","signature":"Public Property Get SearchAborted() As Boolean","returnType":"Boolean","accessor":"Get","description":"True if the most recent Test, Execute, Replace or Split on this object gave up before finishing its search. Results may be truncated or missing, and nothing is raised. In practice only a catastrophically backtracking pattern - nested quantifiers such as '(a+)+b' - can reach this."}, + {"name":"SearchStepLimit","kind":"property","vis":"public","signature":"Public Property Let SearchStepLimit(ByVal pSearchStepLimit As Long)","accessor":"Let","description":"Maximum matcher steps allowed for one Test, Execute, Replace or Split. 0 (the default) scales the budget automatically as min(100000000, max(1000000, 10 * length^2)), which no ordinary pattern reaches. Raise it only if a search was abandoned - the error message suggests a value. 'Steps' are an internal unit and approximate."}, + {"name":"SearchStepLimit","kind":"property","vis":"public","signature":"Public Property Get SearchStepLimit() As Long","returnType":"Long","accessor":"Get"}, {"name":"Split","kind":"function","vis":"public","signature":"Public Function Split(ByVal sourceString As String) As Collection","returnType":"Collection","description":"Splits an input string into an array of substrings at the positions defined by a regular expression match. Needs Global Property set to 'True'."}, {"name":"Test","kind":"function","vis":"public","signature":"Public Function Test(ByVal sourceString As String) As Boolean","returnType":"Boolean","description":"Returns 'True' if Pattern finds a match in sourceString, otherwise returns 'False'."}, {"name":"mCapEntryPoints","kind":"field","vis":"private","signature":"Private mCapEntryPoints() As Long"}, @@ -131,7 +133,7 @@ {"name":"mNamedCount","kind":"field","vis":"private","signature":"Private mNamedCount As Long"}, {"name":"mNumCaptures","kind":"field","vis":"private","signature":"Private mNumCaptures As Long"}, {"name":"mPattern","kind":"field","vis":"private","signature":"Private mPattern As String"}, - {"name":"mSearchAborted","kind":"field","vis":"private","signature":"Private mSearchAborted As Boolean"}, + {"name":"mSearchStepLimit","kind":"field","vis":"private","signature":"Private mSearchStepLimit As Long"}, {"name":"regex","kind":"field","vis":"private","signature":"Private regex As StaticRegex.RegexTy"} ] }, @@ -159,7 +161,6 @@ {"name":"AstTableInitialize","kind":"sub","vis":"private","signature":"Private Sub AstTableInitialize()"}, {"name":"AstToBytecode","kind":"sub","vis":"private","signature":"Private Sub AstToBytecode(ByRef ast() As Long, ByRef identifierTree As IdentifierTreeTy, ByVal caseInsensitive As Boolean, ByRef bytecode() As Long)"}, {"name":"Clear","kind":"sub","vis":"private","signature":"Private Sub Clear(ByRef sb As StaticStringBuilder)"}, - {"name":"ClearStepsLimitHit","kind":"sub","vis":"public","signature":"Public Sub ClearStepsLimitHit()"}, {"name":"CloseGroups","kind":"function","vis":"private","signature":"Private Function CloseGroups( ByRef ast As ArrayBuffer, ByRef parseStack As ArrayBuffer, ByRef pendingDisjunction As Long, ByRef currentDisjunction As Long, ByRef potentialConcat2 As Long, ByRef potentialConcat1 As Long, ByRef modifierMask As Long, ByRef spilloverWriteMask As Long, ByVal whatToHandle As Long ) As Long","returnType":"Long"}, {"name":"Compile","kind":"sub","vis":"private","signature":"Private Sub Compile(ByRef outBytecode() As Long, ByRef s As String, Optional ByVal caseInsensitive As Boolean = False)"}, {"name":"ComputeFirstChar","kind":"function","vis":"private","signature":"Private Function ComputeFirstChar( ByRef bytecode() As Long, ByRef outChar As Long, ByRef outRangesPc As Long, ByRef outIFlag As Long ) As Long","returnType":"Long"}, @@ -196,6 +197,7 @@ {"name":"LexerParseEscapeU","kind":"function","vis":"private","signature":"Private Function LexerParseEscapeU(ByRef lexCtx As LexerContext) As Long","returnType":"Long"}, {"name":"LexerParseEscapeX","kind":"function","vis":"private","signature":"Private Function LexerParseEscapeX(ByRef lexCtx As LexerContext) As Long","returnType":"Long"}, {"name":"LexerParseLegacyOctal","kind":"function","vis":"private","signature":"Private Function LexerParseLegacyOctal(ByRef lexCtx As LexerContext, ByVal x As Long) As Long","returnType":"Long"}, + {"name":"LexerTryParseQuantifier","kind":"function","vis":"private","signature":"Private Function LexerTryParseQuantifier(ByRef lexCtx As LexerContext, ByRef outToken As ReToken) As Boolean","returnType":"Boolean"}, {"name":"Match","kind":"function","vis":"public","signature":"Public Function Match( ByRef matcherState As MatcherStateTy, ByRef regex As RegexTy, ByRef haystack As String, Optional ByVal multiline As Boolean = False, Optional ByVal dotAll As Boolean = False, Optional ByVal matchFrom As Long = 1 ) As Boolean","returnType":"Boolean"}, {"name":"MatchNext","kind":"function","vis":"public","signature":"Public Function MatchNext( ByRef matcherState As MatcherStateTy, ByRef regex As RegexTy, ByRef haystack As String ) As Boolean","returnType":"Boolean"}, {"name":"MatchThenJoin","kind":"function","vis":"public","signature":"Public Function MatchThenJoin( ByRef regex As RegexTy, ByRef haystack As String, Optional ByRef format As String = \"$&\", Optional ByRef delimiter As String = vbNullString, Optional ByVal localMatch As Boolean = False, Optional ByVal multiline As Boolean = False, Optional ByVal dotAll As Boolean = False ) As String","returnType":"String"}, @@ -211,6 +213,7 @@ {"name":"PushMatcherStackFrame","kind":"sub","vis":"private","signature":"Private Sub PushMatcherStackFrame( ByRef context As DfsMatcherContext, ByVal pc As Long, ByVal sp As Long, ByVal pcLandmark As Long, ByVal spDelta As Long, ByVal q As Long )"}, {"name":"QStackPop","kind":"function","vis":"private","signature":"Private Function QStackPop(ByRef context As DfsMatcherContext) As Long","returnType":"Long"}, {"name":"QStackPush","kind":"sub","vis":"private","signature":"Private Sub QStackPush(ByRef context As DfsMatcherContext, ByVal q As Long)"}, + {"name":"RaiseSearchAbandoned","kind":"sub","vis":"private","signature":"Private Sub RaiseSearchAbandoned()"}, {"name":"RangeTablesInitialize","kind":"sub","vis":"private","signature":"Private Sub RangeTablesInitialize()"}, {"name":"RangeTablesInitialized","kind":"field","vis":"private","signature":"Private RangeTablesInitialized As Boolean"}, {"name":"ReCanonicalizeChar","kind":"function","vis":"private","signature":"Private Function ReCanonicalizeChar(ByVal codepoint As Long) As Long","returnType":"Long"}, @@ -229,7 +232,6 @@ {"name":"SetMinimumCapacity","kind":"sub","vis":"private","signature":"Private Sub SetMinimumCapacity(ByRef sb As StaticStringBuilder, ByVal MinimumCapacity As Long)"}, {"name":"SplitByRegex","kind":"function","vis":"public","signature":"Public Function SplitByRegex( ByRef regex As RegexTy, ByRef haystack As String, Optional ByVal localMatch As Boolean = False, Optional ByVal multiline As Boolean = False, Optional ByVal dotAll As Boolean = False ) As Collection","returnType":"Collection"}, {"name":"StaticData","kind":"field","vis":"private","signature":"Private StaticData(0 To STATIC_DATA_LENGTH - 1) As Long"}, - {"name":"StepsLimitHit","kind":"function","vis":"public","signature":"Public Function StepsLimitHit() As Boolean","returnType":"Boolean"}, {"name":"SwitchToLargerBuffer","kind":"sub","vis":"private","signature":"Private Sub SwitchToLargerBuffer(ByRef sb As StaticStringBuilder, ByVal nRequired As Long)"}, {"name":"Test","kind":"function","vis":"public","signature":"Public Function Test( ByRef regex As RegexTy, ByRef str As String, Optional ByVal multiline As Boolean = False, Optional ByVal dotAll As Boolean = False ) As Boolean","returnType":"Boolean"}, {"name":"TryInitializeRegex","kind":"function","vis":"public","signature":"Public Function TryInitializeRegex( ByRef regex As RegexTy, ByRef pattern As String, Optional ByVal caseInsensitive As Boolean = False ) As Boolean","returnType":"Boolean"}, @@ -244,7 +246,7 @@ {"name":"mInputChars","kind":"field","vis":"private","signature":"Private mInputChars() As Integer"}, {"name":"mInputLen","kind":"field","vis":"private","signature":"Private mInputLen As Long"}, {"name":"mStepsBudget","kind":"field","vis":"private","signature":"Private mStepsBudget As Long"}, - {"name":"mStepsLimitHit","kind":"field","vis":"private","signature":"Private mStepsLimitHit As Boolean"}, + {"name":"mStepsInputLen","kind":"field","vis":"private","signature":"Private mStepsInputLen As Long"}, {"name":"mStepsUsed","kind":"field","vis":"private","signature":"Private mStepsUsed As Long"} ] }, @@ -430,9 +432,9 @@ "signature": "Private Enum DfsMatcherSharedConstant", "values": [ {"name":"DEFAULT_STEPS_LIMIT","value":"0"}, - {"name":"STEPS_BUDGET_PER_CHAR","value":"5000"}, + {"name":"STEPS_BUDGET_PER_CHAR_SQ","value":"10"}, {"name":"STEPS_BUDGET_FLOOR","value":"1000000"}, - {"name":"STEPS_BUDGET_CAP","value":"50000000"} + {"name":"STEPS_BUDGET_CAP","value":"100000000"} ] }, { @@ -518,7 +520,8 @@ {"name":"inputStr","vis":"public","signature":"inputStr As String"}, {"name":"currentCharacter","vis":"public","signature":"currentCharacter As Long"}, {"name":"identifierTree","vis":"public","signature":"identifierTree As IdentifierTreeTy"}, - {"name":"nCapturesKnown","vis":"public","signature":"nCapturesKnown As Long"} + {"name":"nCapturesKnown","vis":"public","signature":"nCapturesKnown As Long"}, + {"name":"nCapturesOpened","vis":"public","signature":"nCapturesOpened As Long"} ], "members": [] }, @@ -746,6 +749,7 @@ {"name":"REGEX_ERR_INVALID_IDENTIFIER","value":"REGEX_ERR + 13"}, {"name":"REGEX_ERR_INVALID_MODIFIER","value":"REGEX_ERR + 14"}, {"name":"REGEX_ERR_INVALID_BACKREFERENCE","value":"REGEX_ERR + 15"}, + {"name":"REGEX_ERR_SEARCH_ABANDONED","value":"REGEX_ERR + 16"}, {"name":"REGEX_ERR_INTERNAL_LOGIC_ERR","value":"REGEX_ERR + 20"}, {"name":"REGEX_ERR_INVALID_FLAG_ERR","value":"REGEX_ERR + 30"}, {"name":"REGEX_ERR_INVALID_REPLACEMENT_STRING","value":"REGEX_ERR + 31"}, diff --git a/indexer/snapshots/default/VB/api.json b/indexer/snapshots/default/VB/api.json index 1f28b9489..97a97fd75 100644 --- a/indexer/snapshots/default/VB/api.json +++ b/indexer/snapshots/default/VB/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "VB", "project": "VB", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "ActiveXControlExtender", @@ -1249,8 +1249,8 @@ "attrs": [{"name":"InterfaceId","args":"\"BAE0D7DF-237D-41F0-90C5-4DECC483D956\""},{"name":"COMCreatable","args":"False"}], "members": [ {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vb3DFace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DisabledPicture","kind":"property","vis":"public","signature":"Public Property Get DisabledPicture() As StdPicture","returnType":"StdPicture","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"DisabledPicture","kind":"property","vis":"public","signature":"Public Property Set DisabledPicture(Value As StdPicture)","accessor":"Set","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"DisabledPicture","kind":"property","vis":"public","signature":"Public Property Let DisabledPicture(Value As StdPicture)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, @@ -1261,6 +1261,7 @@ {"name":"DownPictureINIT","kind":"field","vis":"protected","signature":"Protected ReadOnly DownPictureINIT() As Byte","attrs":[{"name":"Serialize","args":"True, \"DownPicture\""},{"name":"CustomDesigner","args":"\"designer_PictureBytes\""}]}, {"name":"FontHandle","kind":"field","vis":"protected","signature":"Protected FontHandle As LongPtr"}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbButtonText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetFontMetrics","kind":"function","vis":"protected","signature":"Protected Function GetFontMetrics() As TEXTMETRIC","returnType":"TEXTMETRIC"}, {"name":"HandleDrawItemBASE","kind":"sub","vis":"protected","signature":"Protected Sub HandleDrawItemBASE(ByRef Info As DRAWITEMSTRUCT, Handled As Boolean, ByVal IsChecked As Boolean, ByVal IsCommandButton As Boolean)"}, {"name":"HandleInitializeButton","kind":"sub","vis":"protected","signature":"Protected Sub HandleInitializeButton()"}, @@ -1583,6 +1584,7 @@ "members": [ {"name":"Appearance","kind":"field","vis":"public","signature":"Public Appearance As VBRUN.AppearanceConstants = VBRUN.AppearanceConstants.vbAppear3d","description":""}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vb3DFace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BackStyle","kind":"field","vis":"public","signature":"Public BackStyle As BackFillStyleConstants"}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"},{"name":"DispId","args":"&HEA0004"}],"description":""}, @@ -1622,7 +1624,7 @@ {"name":"OLEStartDrag","kind":"event","vis":"public","signature":"Event OLEStartDrag(Data As DataObject, AllowedEffects As Long)"}, {"name":"Parent","kind":"property","vis":"public","signature":"Public Property Get Parent() As Object","returnType":"Object","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ShowWhatsThis","kind":"sub","vis":"public","signature":"Public Sub ShowWhatsThis()"}, - {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange() Handles BackColor.OnPropertyLet, BackStyle.OnPropertyLet, Appearance.OnPropertyLet, BackStyle.OnPropertyLet, Value.OnPropertyLet"}, + {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange() Handles BackStyle.OnPropertyLet, Appearance.OnPropertyLet, BackStyle.OnPropertyLet, Value.OnPropertyLet"}, {"name":"TabIndex","kind":"field","vis":"public","signature":"Public TabIndex As Long","attrs":[{"name":"Unimplemented"}],"description":"Adjusts the TAB key order of this control at runtime"}, {"name":"ToolTipText","kind":"property","vis":"public","signature":"Public Property Get ToolTipText() As String","returnType":"String","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ToolTipText","kind":"property","vis":"public","signature":"Public Property Let ToolTipText(ByVal Value As String)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, @@ -1705,6 +1707,7 @@ "members": [ {"name":"AddItem","kind":"sub","vis":"public","signature":"Public Sub AddItem(ByVal Value As String, Optional ByVal Index As Variant)"}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = VBRUN.ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"CachedTopIndex","kind":"field","vis":"protected","signature":"Protected CachedTopIndex As Long"}, @@ -1713,7 +1716,6 @@ {"name":"Clear","kind":"sub","vis":"public","signature":"Public Sub Clear()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DispId","args":"&HEA0004"}],"description":""}, {"name":"CloseUp","kind":"event","vis":"public","signature":"Event CloseUp()","description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DataGetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataGetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.GetLiveValue"}, {"name":"DataGetParent","kind":"sub","vis":"protected","signature":"Protected Sub DataGetParent(out As Control) Overrides DataFieldBinderBase.GetParent"}, {"name":"DataSetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataSetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.SetLiveValue"}, @@ -1724,6 +1726,7 @@ {"name":"DropDown","kind":"event","vis":"public","signature":"Event DropDown()","description":""}, {"name":"EDITSubclasser","kind":"field","vis":"protected","signature":"Protected EDITSubclasser As ComboBoxEDITSubclasser"}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetStyles","kind":"function","vis":"protected","signature":"Protected Function GetStyles() As Long","returnType":"Long"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, {"name":"HandleCommand","kind":"sub","vis":"protected","signature":"Protected Sub HandleCommand(ByVal NotificationCode As ComboBoxNotifications, ByVal Identifier As Integer, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.Command"}, @@ -2923,6 +2926,7 @@ "members": [ {"name":"AddItem","kind":"sub","vis":"public","signature":"Public Sub AddItem(ByVal Value As String, Optional ByVal Index As Variant)","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"CachedPath","kind":"field","vis":"protected","signature":"Protected CachedPath As String"}, @@ -2932,12 +2936,12 @@ {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Clear","kind":"sub","vis":"public","signature":"Public Sub Clear()","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DispId","args":"&HEA0004"}],"description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DirLevel","kind":"field","vis":"protected","signature":"Protected DirLevel As Long"}, {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","attrs":[{"name":"DispId","args":"&HEA000B"}],"description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"DrawItem","kind":"sub","vis":"protected","signature":"Protected Sub DrawItem(ByRef Info As DRAWITEMSTRUCT, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.DrawItem"}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetCustomDrawnHeight","kind":"function","vis":"protected","signature":"Protected Function GetCustomDrawnHeight() As Long","returnType":"Long"}, {"name":"GetStyles","kind":"sub","vis":"protected","signature":"Protected Sub GetStyles(ByRef styles As Long, ByRef extendedStyles As Long)"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, @@ -3046,6 +3050,7 @@ "members": [ {"name":"AddItem","kind":"sub","vis":"public","signature":"Public Sub AddItem(ByVal Value As String, Optional ByVal Index As Variant)","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"CachedSelectedIndex","kind":"field","vis":"protected","signature":"Protected CachedSelectedIndex As Long"}, {"name":"CachedTopIndex","kind":"field","vis":"protected","signature":"Protected CachedTopIndex As Long"}, {"name":"Change","kind":"event","vis":"public","signature":"Event Change()","attrs":[{"name":"DefaultDesignerEvent"}],"description":""}, @@ -3053,7 +3058,6 @@ {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Clear","kind":"sub","vis":"public","signature":"Public Sub Clear()","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"CloseUp","kind":"event","vis":"public","signature":"Event CloseUp()","description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","attrs":[{"name":"DispId","args":"&HEA000B"}],"description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"DrawItem","kind":"sub","vis":"protected","signature":"Protected Sub DrawItem(ByRef Info As DRAWITEMSTRUCT, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.DrawItem"}, @@ -3061,6 +3065,7 @@ {"name":"Drive","kind":"property","vis":"public","signature":"Public Property Let Drive(ByVal Value As String)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"DropDown","kind":"event","vis":"public","signature":"Event DropDown()","description":""}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetCustomDrawnHeight","kind":"function","vis":"protected","signature":"Protected Function GetCustomDrawnHeight() As Long","returnType":"Long"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, {"name":"HandleCommand","kind":"sub","vis":"protected","signature":"Protected Sub HandleCommand(ByVal NotificationCode As ComboBoxNotifications, ByVal Identifier As Integer, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.Command"}, @@ -3222,6 +3227,7 @@ {"name":"AddItem","kind":"sub","vis":"public","signature":"Public Sub AddItem(ByVal Value As String, Optional ByVal Index As Variant)","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"Archive","kind":"field","vis":"public","signature":"Public Archive As Boolean = True","description":""}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"CachedPath","kind":"field","vis":"protected","signature":"Protected CachedPath As String"}, @@ -3231,13 +3237,13 @@ {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Clear","kind":"sub","vis":"public","signature":"Public Sub Clear()","hidden":true,"attrs":[{"name":"Hidden"}]}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"},{"name":"DispId","args":"&HEA0004"}],"description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DblClick","kind":"event","vis":"public","signature":"Event DblClick()","attrs":[{"name":"DispId","args":"&HEA0005"}],"description":""}, {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","attrs":[{"name":"DispId","args":"&HEA000B"}],"description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"FileName","kind":"property","vis":"public","signature":"Public Property Get FileName() As String","returnType":"String","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"FileName","kind":"property","vis":"public","signature":"Public Property Let FileName(ByVal Value As String)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetStyles","kind":"function","vis":"protected","signature":"Protected Function GetStyles() As Long","returnType":"Long"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, {"name":"HandleAttributesChange","kind":"sub","vis":"protected","signature":"Protected Sub HandleAttributesChange() Handles Archive.OnPropertyLet, Hidden.OnPropertyLet, Normal.OnPropertyLet, ReadOnly.OnPropertyLet, System.OnPropertyLet","attrs":[{"name":"Serialize","args":"False"}]}, @@ -3579,6 +3585,7 @@ "attrs": [{"name":"ClassId","args":"\"6A059CC4-5A82-461B-981F-569CA2B865B1\""},{"name":"InterfaceId","args":"\"00352073-61B4-4327-9C8B-722D3B158F5E\""},{"name":"COMCreatable","args":"False"},{"name":"EventsUseDispInterface"},{"name":"ComImport","args":"True"}], "members": [ {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vb3DFace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = VBRUN.ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"Caption","kind":"property","vis":"public","signature":"Public Property Get Caption() As String","returnType":"String","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"Caption","kind":"property","vis":"public","signature":"Public Property Let Caption(ByVal Value As String)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, @@ -3586,11 +3593,11 @@ {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"},{"name":"DispId","args":"&HEA0004"}],"description":""}, {"name":"ClipControls","kind":"field","vis":"public","signature":"Public ClipControls As Boolean = True","description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DblClick","kind":"event","vis":"public","signature":"Event DblClick()","attrs":[{"name":"DispId","args":"&HEA0005"}],"description":""}, {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","attrs":[{"name":"DispId","args":"&HEA000B"}],"description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbButtonText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetStyles","kind":"function","vis":"protected","signature":"Protected Function GetStyles() As Long","returnType":"Long"}, {"name":"HandleCreate","kind":"sub","vis":"protected","signature":"Protected Sub HandleCreate() Implements IWindowElementEventsCommon.Create"}, {"name":"HandleDestroy","kind":"sub","vis":"protected","signature":"Protected Sub HandleDestroy() Implements IWindowsControl.Destroy"}, @@ -4499,8 +4506,9 @@ {"name":"DrawWidth","kind":"field","vis":"public","signature":"Public DrawWidth As Long = 1"}, {"name":"DrawWidthChanged","kind":"sub","vis":"protected","signature":"Protected Sub DrawWidthChanged() Handles DrawWidth.OnPropertyLet"}, {"name":"FillColor","kind":"field","vis":"public","signature":"Public FillColor As OLE_COLOR = 0","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}]}, + {"name":"FillColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub FillColorChanged(ByVal OldValue As OLE_COLOR) Handles FillColor.OnPropertyLet"}, {"name":"FillStyle","kind":"field","vis":"public","signature":"Public FillStyle As FillStyleConstants = FillStyleConstants.vbFSTransparent"}, - {"name":"FillStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub FillStyleChanged() Handles FillStyle.OnPropertyLet, FillColor.OnPropertyLet"}, + {"name":"FillStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub FillStyleChanged() Handles FillStyle.OnPropertyLet"}, {"name":"Font","kind":"field","vis":"public","signature":"Public WithEvents Font As StdFont","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"FontBold","kind":"property","vis":"public","signature":"Public Property Get FontBold() As Boolean","returnType":"Boolean","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"FontBold","kind":"property","vis":"public","signature":"Public Property Let FontBold(ByVal Value As Boolean)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, @@ -4523,7 +4531,7 @@ {"name":"FontUnderline","kind":"property","vis":"public","signature":"Public Property Let FontUnderline(ByVal Value As Boolean)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"FontUnderlineINIT","kind":"field","vis":"protected","signature":"Protected FontUnderlineINIT As Boolean = False","attrs":[{"name":"Serialize","args":"True, \"FontUnderline\""}]}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = SystemColorConstants.vbButtonText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}]}, - {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged() Handles ForeColor.OnPropertyLet"}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As Long) Handles ForeColor.OnPropertyLet"}, {"name":"GetBorderSize","kind":"function","vis":"protected","signature":"Protected Function GetBorderSize(ByVal Owner As Object) As Long","returnType":"Long"}, {"name":"GetColumn","kind":"property","vis":"protected","signature":"Protected Property Get GetColumn() As Long Implements IVBPrint.Column","returnType":"Long","accessor":"Get"}, {"name":"GetFont","kind":"sub","vis":"protected","signature":"Protected Sub GetFont(ByRef fontHandle As LongPtr) Implements IWindowElementEventsGraphics.GetFont"}, @@ -4610,7 +4618,8 @@ {"name":"ScaleYToScaledPixels","kind":"function","vis":"protected","signature":"Protected Function ScaleYToScaledPixels(ByVal Y As Double) As Double","returnType":"Double"}, {"name":"SetDrawingMixMode","kind":"sub","vis":"protected","signature":"Protected Sub SetDrawingMixMode()"}, {"name":"SetFont","kind":"sub","vis":"protected","signature":"Protected Sub SetFont(ByVal fontHandle As LongPtr, ByVal redraw As Boolean) Implements IWindowElementEventsGraphics.SetFont"}, - {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange() Handles BackColor.OnPropertyLet"}, + {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange()"}, + {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"SyncFont","kind":"sub","vis":"protected","signature":"Protected Sub SyncFont() Handles Font.OnPropertySet"}, {"name":"SyncFontProperties","kind":"sub","vis":"protected","signature":"Protected Sub SyncFontProperties()"}, {"name":"SyncScaleMode","kind":"sub","vis":"protected","signature":"Protected Sub SyncScaleMode()"}, @@ -7654,6 +7663,7 @@ {"name":"AutoSize","kind":"field","vis":"public","signature":"Public AutoSize As Boolean = False"}, {"name":"AutoSizeNow","kind":"sub","vis":"protected","signature":"Protected Sub AutoSizeNow()"}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vb3DFace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BackStyle","kind":"field","vis":"public","signature":"Public BackStyle As BackFillStyleConstants = BackFillStyleConstants.vbBFOpaque"}, {"name":"BorderCustomOptions","kind":"property","vis":"public","signature":"Public Property Get BorderCustomOptions() As BorderOptionsClass","returnType":"BorderOptionsClass","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstantsCustom = ControlBorderStyleConstantsCustom.vbNoBorder","description":""}, @@ -7664,7 +7674,7 @@ {"name":"ChangeAffectingAutoSize","kind":"sub","vis":"protected","signature":"Protected Sub ChangeAffectingAutoSize() Handles BorderStyle.OnPropertyLet, WordWrap.OnPropertyLet"}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"},{"name":"DispId","args":"&HEA0004"}],"description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet, BackStyle.OnPropertyLet, UseMnemonic.OnPropertyLet, Alignment.OnPropertyLet, Appearance.OnPropertyLet, BackStyle.OnPropertyLet, Angle.OnPropertyLet"}, + {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackStyle.OnPropertyLet, UseMnemonic.OnPropertyLet, Alignment.OnPropertyLet, Appearance.OnPropertyLet, BackStyle.OnPropertyLet, Angle.OnPropertyLet"}, {"name":"DataFieldAggregate","kind":"field","vis":"public","signature":"Public DataFieldAggregate As AggregateConstants"}, {"name":"DataFieldAggregateValue","kind":"field","vis":"public","signature":"Public DataFieldAggregateValue As Decimal","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"DataGetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataGetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.GetLiveValue"}, @@ -7697,6 +7707,7 @@ {"name":"FontUnderline","kind":"property","vis":"public","signature":"Public Property Let FontUnderline(ByVal Value As Boolean)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"FontUnderlineINIT","kind":"field","vis":"protected","signature":"Protected FontUnderlineINIT As Boolean","attrs":[{"name":"Serialize","args":"True, \"FontUnderline\""}]}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbButtonText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetFont","kind":"function","vis":"protected","signature":"Protected Function GetFont() As StdFont","returnType":"StdFont"}, {"name":"GetFontMetrics","kind":"function","vis":"protected","signature":"Protected Function GetFontMetrics() As TEXTMETRIC","returnType":"TEXTMETRIC"}, {"name":"HandleCreate","kind":"sub","vis":"protected","signature":"Protected Sub HandleCreate() Implements IWindowElementEventsCommon.Create"}, @@ -7850,6 +7861,7 @@ "members": [ {"name":"AddItem","kind":"sub","vis":"public","signature":"Public Sub AddItem(ByVal Value As String, Optional ByVal Index As Variant)"}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"CachedTopIndex","kind":"field","vis":"protected","signature":"Protected CachedTopIndex As Long"}, @@ -7858,7 +7870,6 @@ {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Clear","kind":"sub","vis":"public","signature":"Public Sub Clear()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DefaultDesignerEvent"},{"name":"DispId","args":"&HEA0004"}],"description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"Columns","kind":"field","vis":"public","signature":"Public Columns As Long","description":""}, {"name":"DataGetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataGetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.GetLiveValue"}, {"name":"DataGetParent","kind":"sub","vis":"protected","signature":"Protected Sub DataGetParent(out As Control) Overrides DataFieldBinderBase.GetParent"}, @@ -7869,6 +7880,7 @@ {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"DrawItem","kind":"sub","vis":"protected","signature":"Protected Sub DrawItem(ByRef Info As DRAWITEMSTRUCT, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.DrawItem"}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetCustomDrawnHeight","kind":"function","vis":"protected","signature":"Protected Function GetCustomDrawnHeight() As Long","returnType":"Long"}, {"name":"GetStyles","kind":"function","vis":"protected","signature":"Protected Function GetStyles() As Long","returnType":"Long"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, @@ -8107,9 +8119,10 @@ {"name":"AutoShowChildren","kind":"property","vis":"public","signature":"Property Let AutoShowChildren(ByVal Value As Boolean)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}],"description":""}, {"name":"AutoShowChildrenINIT","kind":"field","vis":"protected","signature":"Protected AutoShowChildrenINIT As Boolean = True","attrs":[{"name":"Serialize","args":"True, \"AutoShowChildren\""}]}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbApplicationWorkspace","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}]}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BuildMenus","kind":"sub","vis":"protected","signature":"Protected Sub BuildMenus(existingMenuHandle As HMENU, windowListMenu As LongPtr, Container As Control, Level As Long, IsPopUp As Boolean, BoldMenuItem As Menu) Implements ITbCommonContainerPrivate.BuildMenus"}, {"name":"CanClose","kind":"sub","vis":"protected","signature":"Protected Sub CanClose(ByRef Cancel As Integer) Implements IWindowElementEventsCommonRoot.CanClose"}, - {"name":"ChangedBackground","kind":"sub","vis":"protected","signature":"Protected Sub ChangedBackground() Handles BackColor.OnPropertyLet, Picture.OnPropertyLet, Picture.OnPropertySet"}, + {"name":"ChangedBackground","kind":"sub","vis":"protected","signature":"Protected Sub ChangedBackground() Handles Picture.OnPropertyLet, Picture.OnPropertySet"}, {"name":"ChangedMDIActiveForm","kind":"sub","vis":"protected","signature":"Protected Sub ChangedMDIActiveForm(ByVal ActiveChildForm As Object, ByVal IsClosing As Boolean) Implements IWindowElementEventsCommonRoot.ChangedMDIActiveForm"}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"ClearSubMenusCachedInfo","kind":"sub","vis":"protected","signature":"Protected Sub ClearSubMenusCachedInfo(Container As Menu)"}, @@ -8828,6 +8841,7 @@ {"name":"CommonRaiseViewChanged","kind":"sub","vis":"public","signature":"Public Sub CommonRaiseViewChanged(Container As Object)"}, {"name":"CommonRebuildMenus","kind":"sub","vis":"public","signature":"Public Sub CommonRebuildMenus(Container As Object, ByVal IsRuntimeChange As Boolean)"}, {"name":"CommonResizeWindowless","kind":"sub","vis":"public","signature":"Public Sub CommonResizeWindowless(ByVal containerHwnd As HWND, ByVal adjustAmount As Long, ByVal oldLeft As Long, ByVal oldTop As Long, ByVal oldWidth As Long, ByVal oldHeight As Long, ByVal newLeft As Long, ByVal newTop As Long, ByVal newWidth As Long, ByVal newHeight As Long)"}, + {"name":"CommonValidateColorOrRevert","kind":"function","vis":"public","signature":"Public Function CommonValidateColorOrRevert(ByRef NewValueInOut As OLE_COLOR, ByVal OldValue As OLE_COLOR) As Boolean","returnType":"Boolean"}, {"name":"ETO_CLIPPED","kind":"const","vis":"private","signature":"Const ETO_CLIPPED As Long = 4"}, {"name":"GA_ROOT","kind":"const","vis":"private","signature":"Private Const GA_ROOT As Long = 2"}, {"name":"GWL_EXSTYLE","kind":"const","vis":"private","signature":"Private Const GWL_EXSTYLE As Long = -20"}, @@ -10299,6 +10313,7 @@ {"name":"Enabled","kind":"property","vis":"public","signature":"Public Property Let Enabled(ByVal Value As Boolean)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"EnabledINIT","kind":"field","vis":"protected","signature":"Protected EnabledINIT As Boolean = True","attrs":[{"name":"Serialize","args":"True, \"Enabled\""}]}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = vbBlack","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}]}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"HandleCreate","kind":"sub","vis":"protected","signature":"Protected Sub HandleCreate() Implements IWindowElementEventsCommon.Create"}, {"name":"HandleDestroy","kind":"sub","vis":"protected","signature":"Protected Sub HandleDestroy() Implements IWindowsControl.Destroy"}, {"name":"HandleGetOpaqueRegion","kind":"sub","vis":"protected","signature":"Protected Sub HandleGetOpaqueRegion(out As LongPtr) Implements IWindowElementEventsCommon.GetOpaqueRegion"}, @@ -10343,7 +10358,7 @@ {"name":"SignificantChange","kind":"sub","vis":"protected","signature":"Protected Sub SignificantChange() Handles Appearance.OnPropertyLet, BorderStyle.OnPropertyLet"}, {"name":"Square","kind":"field","vis":"public","signature":"Public Square As Boolean = True","description":"Determines if the QR code is rendered as a square (1:1 aspect ratio), or stretched to fill the control rectangle"}, {"name":"SquareModules","kind":"field","vis":"public","signature":"Public SquareModules As Boolean = True"}, - {"name":"SyncPicture","kind":"sub","vis":"protected","signature":"Protected Sub SyncPicture() Handles Payload.OnPropertyLet, ForeColor.OnPropertyLet, ModuleSize.OnPropertyLet, SquareModules.OnPropertyLet, EccMode.OnPropertyLet, EccBoost.OnPropertyLet, MinVersion.OnPropertyLet, MaxVersion.OnPropertyLet, MaskType.OnPropertyLet"}, + {"name":"SyncPicture","kind":"sub","vis":"protected","signature":"Protected Sub SyncPicture() Handles Payload.OnPropertyLet, ModuleSize.OnPropertyLet, SquareModules.OnPropertyLet, EccMode.OnPropertyLet, EccBoost.OnPropertyLet, MinVersion.OnPropertyLet, MaxVersion.OnPropertyLet, MaskType.OnPropertyLet"}, {"name":"ToolTipText","kind":"property","vis":"public","signature":"Public Property Get ToolTipText() As String","returnType":"String","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ToolTipText","kind":"property","vis":"public","signature":"Public Property Let ToolTipText(ByVal Value As String)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"ToolTipTextINIT","kind":"field","vis":"protected","signature":"Protected ToolTipTextINIT As String","attrs":[{"name":"CustomDesigner","args":"\"designer_MultiLineText\""},{"name":"Serialize","args":"True, \"ToolTipText\""}]}, @@ -11353,6 +11368,7 @@ {"name":"Angle","kind":"field","vis":"public","signature":"Public Angle As Double","description":"Angle at which the control is rendered. 0 is the natural angle, 90 is a quarter anti-clockwise turn. Control is turned relative to the top-left position."}, {"name":"AngleChanged","kind":"sub","vis":"protected","signature":"Protected Sub AngleChanged() Handles Angle.OnPropertyLet"}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BackStyle","kind":"field","vis":"public","signature":"Public BackStyle As BackFillStyleConstants = BackFillStyleConstants.vbBFTransparent","description":""}, {"name":"BorderColor","kind":"field","vis":"public","signature":"Public BorderColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As BorderStyleConstants = BorderStyleConstants.vbBSSolid","description":""}, @@ -11361,6 +11377,7 @@ {"name":"DrawMode","kind":"field","vis":"public","signature":"Public DrawMode As DrawModeConstants = DrawModeConstants.vbCopyPen","description":""}, {"name":"FillColor","kind":"field","vis":"public","signature":"Public FillColor As OLE_COLOR = VBRUN.SystemColorConstants.vbScrollBars","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, {"name":"FillColorAlt","kind":"field","vis":"public","signature":"Public FillColorAlt As OLE_COLOR = vbWhite","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":"A second fill color, used for gradients"}, + {"name":"FillColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub FillColorChanged(ByVal OldValue As OLE_COLOR) Handles FillColor.OnPropertyLet"}, {"name":"FillStyle","kind":"field","vis":"public","signature":"Public FillStyle As FillStyleConstantsEx = FillStyleConstantsEx.vbFSTransparent","description":""}, {"name":"HandleCreate","kind":"sub","vis":"protected","signature":"Protected Sub HandleCreate() Implements IWindowElementEventsCommon.Create"}, {"name":"HandleDestroy","kind":"sub","vis":"protected","signature":"Protected Sub HandleDestroy() Implements IWindowsControl.Destroy"}, @@ -11373,7 +11390,7 @@ {"name":"IsDesignMode","kind":"field","vis":"protected","signature":"Protected IsDesignMode As Boolean"}, {"name":"IsReportMode","kind":"field","vis":"protected","signature":"Protected IsReportMode As Boolean"}, {"name":"New","kind":"sub","vis":"public","signature":"Sub New()"}, - {"name":"OnChangeProp","kind":"sub","vis":"protected","signature":"Protected Sub OnChangeProp() Handles BackColor.OnPropertyLet, BackStyle.OnPropertyLet, BorderColor.OnPropertyLet, BorderStyle.OnPropertyLet, BorderWidth.OnPropertyLet, DrawMode.OnPropertyLet, FillColor.OnPropertyLet, FillColorAlt.OnPropertyLet, FillStyle.OnPropertyLet, Shape.OnPropertyLet, RoundedCornerSize.OnPropertyLet, VariationA.OnPropertyLet, VariationB.OnPropertyLet, VariationC.OnPropertyLet, Angle.OnPropertyLet"}, + {"name":"OnChangeProp","kind":"sub","vis":"protected","signature":"Protected Sub OnChangeProp() Handles BackStyle.OnPropertyLet, BorderColor.OnPropertyLet, BorderStyle.OnPropertyLet, BorderWidth.OnPropertyLet, DrawMode.OnPropertyLet, FillColorAlt.OnPropertyLet, FillStyle.OnPropertyLet, Shape.OnPropertyLet, RoundedCornerSize.OnPropertyLet, VariationA.OnPropertyLet, VariationB.OnPropertyLet, VariationC.OnPropertyLet, Angle.OnPropertyLet"}, {"name":"Parent","kind":"property","vis":"public","signature":"Public Property Get Parent() As Object","returnType":"Object","accessor":"Get","attrs":[{"name":"Serialize","args":"False"}]}, {"name":"RoundedCornerSize","kind":"field","vis":"public","signature":"Public RoundedCornerSize As Long = 20","description":""}, {"name":"Shape","kind":"field","vis":"public","signature":"Public Shape As ShapeConstants","description":""}, @@ -11764,12 +11781,12 @@ {"name":"Alignment","kind":"property","vis":"public","signature":"Property Let Alignment(Value As VBRUN.AlignmentConstants)","accessor":"Let","attrs":[{"name":"Serialize","args":"False"}],"description":""}, {"name":"AlignmentINIT","kind":"field","vis":"protected","signature":"Protected AlignmentINIT As VBRUN.AlignmentConstants","attrs":[{"name":"Serialize","args":"True, \"Alignment\""}],"description":""}, {"name":"BackColor","kind":"field","vis":"public","signature":"Public BackColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowBackground","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"BackColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub BackColorChanged(ByVal OldValue As OLE_COLOR) Handles BackColor.OnPropertyLet"}, {"name":"BorderStyle","kind":"field","vis":"public","signature":"Public BorderStyle As VBRUN.ControlBorderStyleConstants = VBRUN.ControlBorderStyleConstants.vbFixedSingleBorder","description":""}, {"name":"BorderStyleChanged","kind":"sub","vis":"protected","signature":"Protected Sub BorderStyleChanged() Handles BorderStyle.OnPropertyLet"}, {"name":"Change","kind":"event","vis":"public","signature":"Event Change()","attrs":[{"name":"DefaultDesignerEvent"}],"description":""}, {"name":"Class_Terminate","kind":"sub","vis":"protected","signature":"Protected Sub Class_Terminate()"}, {"name":"Click","kind":"event","vis":"public","signature":"Event Click()","attrs":[{"name":"DispId","args":"&HEA0004"}],"description":""}, - {"name":"ColorsChanged","kind":"sub","vis":"protected","signature":"Protected Sub ColorsChanged() Handles BackColor.OnPropertyLet, ForeColor.OnPropertyLet"}, {"name":"DataGetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataGetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.GetLiveValue"}, {"name":"DataGetParent","kind":"sub","vis":"protected","signature":"Protected Sub DataGetParent(out As Control) Overrides DataFieldBinderBase.GetParent"}, {"name":"DataSetLiveValue","kind":"sub","vis":"protected","signature":"Protected Sub DataSetLiveValue(fieldValue As Variant) Overrides DataFieldBinderBase.SetLiveValue"}, @@ -11777,6 +11794,7 @@ {"name":"DragDrop","kind":"event","vis":"public","signature":"Event DragDrop(Source As Control, X As Single, Y As Single)","attrs":[{"name":"DispId","args":"&HEA000B"}],"description":""}, {"name":"DragOver","kind":"event","vis":"public","signature":"Event DragOver(Source As Control, X As Single, Y As Single, State As Integer)","attrs":[{"name":"DispId","args":"&HEA000C"}],"description":""}, {"name":"ForeColor","kind":"field","vis":"public","signature":"Public ForeColor As OLE_COLOR = VBRUN.SystemColorConstants.vbWindowText","attrs":[{"name":"CustomDesigner","args":"\"designer_SpectrumWindows\""}],"description":""}, + {"name":"ForeColorChanged","kind":"sub","vis":"protected","signature":"Protected Sub ForeColorChanged(ByVal OldValue As OLE_COLOR) Handles ForeColor.OnPropertyLet"}, {"name":"GetStyles","kind":"function","vis":"protected","signature":"Protected Function GetStyles() As Long","returnType":"Long"}, {"name":"GotFocus","kind":"event","vis":"public","signature":"Event GotFocus()","attrs":[{"name":"DispId","args":"&HEA0006"}],"description":""}, {"name":"HandleCommand","kind":"sub","vis":"protected","signature":"Protected Sub HandleCommand(ByVal NotificationCode As EditNotifications, ByVal Identifier As Integer, ByRef Handled As Boolean) Implements IWindowElementEventsCommon.Command"}, diff --git a/indexer/snapshots/default/VBA/api.json b/indexer/snapshots/default/VBA/api.json index 30dc9f7d8..cae4a6f6a 100644 --- a/indexer/snapshots/default/VBA/api.json +++ b/indexer/snapshots/default/VBA/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "VBA", "project": "VBA", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "Collection", @@ -973,6 +973,7 @@ {"name":"InterlockedIncrement32","kind":"function","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Function InterlockedIncrement32 Lib \"\" Alias \"#144\" (ByRef Target As Long) As Long","returnType":"Long","attrs":[{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"}],"description":""}, {"name":"InterlockedIncrement64","kind":"function","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Function InterlockedIncrement64 Lib \"\" Alias \"#188\" (ByRef Target As LongLong) As LongLong","returnType":"LongLong","attrs":[{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"}],"description":""}, {"name":"InternalDebugHoverEval","kind":"function","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Function InternalDebugHoverEval Lib \"\" Alias \"#-14\" (ByVal Expression As Any) As String","returnType":"String","hidden":true,"attrs":[{"name":"PreserveSig","args":"False"},{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"},{"name":"Hidden"},{"name":"Restricted"}],"description":""}, + {"name":"InternalDebugWatchEval","kind":"function","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Function InternalDebugWatchEval Lib \"\" Alias \"#-81\" (ByVal Expression As Any) As String","returnType":"String","hidden":true,"attrs":[{"name":"PreserveSig","args":"False"},{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"},{"name":"Hidden"},{"name":"Restricted"}],"description":""}, {"name":"LetErrDescription","kind":"sub","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Sub LetErrDescription Lib \"\" Alias \"#-44\" (ByVal Value As String)","hidden":true,"attrs":[{"name":"PreserveSig","args":"False"},{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"},{"name":"Hidden"},{"name":"Restricted"}],"description":""}, {"name":"LetErrHelpContext","kind":"sub","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Sub LetErrHelpContext Lib \"\" Alias \"#-48\" (ByVal Value As Long)","hidden":true,"attrs":[{"name":"PreserveSig","args":"False"},{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"},{"name":"Hidden"},{"name":"Restricted"}],"description":""}, {"name":"LetErrHelpFile","kind":"sub","vis":"public","declare":true,"signature":"Public DeclareWide PtrSafe Sub LetErrHelpFile Lib \"\" Alias \"#-46\" (ByVal Value As String)","hidden":true,"attrs":[{"name":"PreserveSig","args":"False"},{"name":"UseGetLastError","args":"False"},{"name":"DLLStackCheck","args":"False"},{"name":"Hidden"},{"name":"Restricted"}],"description":""}, diff --git a/indexer/snapshots/default/VBRUN/api.json b/indexer/snapshots/default/VBRUN/api.json index 3671f7ceb..94a4a92d2 100644 --- a/indexer/snapshots/default/VBRUN/api.json +++ b/indexer/snapshots/default/VBRUN/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "VBRUN", "project": "VBRUN", - "version": "beta-x-0997", + "version": "beta-x-1005", "types": [ { "name": "AmbientProperties", @@ -2005,7 +2005,7 @@ "vis": "public", "file": "PropertyBag.twin", "signature": "Public CoClass PropertyBag", - "interfaces": [{"name":"_PropertyBag","default":true}], + "interfaces": [{"name":"_PropertyBag","default":true},{"name":"PropertyBag_VB5"}], "attrs": [{"name":"CoClassId","args":"\"D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731\""},{"name":"CoClassCustomConstructor","args":"\"CreatePropertyBagObject\""}], "members": [] }, @@ -2027,12 +2027,14 @@ "kind": "interface", "vis": "public", "file": "PropertyBag.twin", - "signature": "Public Interface _PropertyBag Extends PropertyBag_VB5", - "extends": "PropertyBag_VB5", + "signature": "Public Interface _PropertyBag Extends stdole.IDispatch", + "extends": "stdole.IDispatch", "attrs": [{"name":"InterfaceId","args":"\"4495AD01-C993-11D1-A3E4-00A0C90AEA82\""}], "members": [ {"name":"Contents","kind":"property","vis":"public","signature":"Property Get Contents() As Variant","returnType":"Variant","accessor":"Get","attrs":[{"name":"DispId","args":"3"}],"description":"Retrieves or sets the entire state of the contents of a PropertyBag object.\n### Syntax\n`Property Let Contents(ByVal NewValue As Variant)`\n`Property Get Contents() As Variant`\n### Parameters\n- `NewValue`: The new value to assign to the contents of the PropertyBag when using `Let`.\n### Property Value\nA Variant containing the entire state of the PropertyBag when using `Get`. The Variant subtype is a byte-array.\n### Example\n```vb\n' Assume 'propBag' is a previously initialized PropertyBag object.\n' To retrieve the contents:\nDim bagContents As Variant\nbagContents = propBag.Contents\n\n' To set the contents:\n' Assume 'newContents' is a Variant containing the state to load into the PropertyBag\npropBag.Contents = newContents\n```\n### Remarks\nThe `Contents` property is used to retrieve or set the complete state of the PropertyBag. This is useful when you need to load or save the state of the PropertyBag in one operation. When setting the `Contents`, the existing state is replaced by the `NewValue`. When reading the `Contents`, the entire state is retrieved as a Variant, which can then be manipulated as needed."}, - {"name":"Contents","kind":"property","vis":"public","signature":"Property Let Contents(ByVal value As Variant)","accessor":"Let","attrs":[{"name":"DispId","args":"3"}],"description":"Retrieves or sets the entire state of the contents of a PropertyBag object.\n### Syntax\n`Property Let Contents(ByVal NewValue As Variant)`\n`Property Get Contents() As Variant`\n### Parameters\n- `NewValue`: The new value to assign to the contents of the PropertyBag when using `Let`.\n### Property Value\nA Variant containing the entire state of the PropertyBag when using `Get`. The Variant subtype is a byte-array.\n### Example\n```vb\n' Assume 'propBag' is a previously initialized PropertyBag object.\n' To retrieve the contents:\nDim bagContents As Variant\nbagContents = propBag.Contents\n\n' To set the contents:\n' Assume 'newContents' is a Variant containing the state to load into the PropertyBag\npropBag.Contents = newContents\n```\n### Remarks\nThe `Contents` property is used to retrieve or set the complete state of the PropertyBag. This is useful when you need to load or save the state of the PropertyBag in one operation. When setting the `Contents`, the existing state is replaced by the `NewValue`. When reading the `Contents`, the entire state is retrieved as a Variant, which can then be manipulated as needed."} + {"name":"Contents","kind":"property","vis":"public","signature":"Property Let Contents(ByVal value As Variant)","accessor":"Let","attrs":[{"name":"DispId","args":"3"}],"description":"Retrieves or sets the entire state of the contents of a PropertyBag object.\n### Syntax\n`Property Let Contents(ByVal NewValue As Variant)`\n`Property Get Contents() As Variant`\n### Parameters\n- `NewValue`: The new value to assign to the contents of the PropertyBag when using `Let`.\n### Property Value\nA Variant containing the entire state of the PropertyBag when using `Get`. The Variant subtype is a byte-array.\n### Example\n```vb\n' Assume 'propBag' is a previously initialized PropertyBag object.\n' To retrieve the contents:\nDim bagContents As Variant\nbagContents = propBag.Contents\n\n' To set the contents:\n' Assume 'newContents' is a Variant containing the state to load into the PropertyBag\npropBag.Contents = newContents\n```\n### Remarks\nThe `Contents` property is used to retrieve or set the complete state of the PropertyBag. This is useful when you need to load or save the state of the PropertyBag in one operation. When setting the `Contents`, the existing state is replaced by the `NewValue`. When reading the `Contents`, the entire state is retrieved as a Variant, which can then be manipulated as needed."}, + {"name":"ReadProperty","kind":"function","vis":"public","signature":"Function ReadProperty(ByVal Name As String, Optional ByVal DefaultValue As Variant) As Variant","returnType":"Variant","attrs":[{"name":"DispId","args":"1"}],"description":"Reads a property value from a PropertyBag object.\n### Syntax\n`Function ReadProperty(ByVal Name As String, Optional ByVal DefaultValue As Variant) As Variant`\n### Parameters\n- `Name`: The name of the property to read.\n- `DefaultValue`: An optional parameter that specifies the return value if the property is not found. The data type can be any.\n### Return Value\nThe function returns the value of the specified property. If the property is not found, it returns the `DefaultValue` if provided; otherwise, it returns `Null`.\n### Example\n```vb\n' Assume 'propBag' is a previously initialized PropertyBag object with properties set.\nDim myValue As Variant\nmyValue = propBag.ReadProperty(\"MyProperty\", \"DefaultValue\")\n```\n### Remarks\nThe `ReadProperty` function is typically used when an object needs to read its state from a PropertyBag, such as during the `ReadProperties` event when implementing persistence in ActiveX controls (UserControls) or documents."}, + {"name":"WriteProperty","kind":"sub","vis":"public","signature":"Sub WriteProperty(ByVal Name As String, ByVal Value As Variant, Optional ByVal DefaultValue As Variant)","attrs":[{"name":"DispId","args":"2"}],"description":"Writes a property value to a PropertyBag object.\n### Syntax\n`Sub WriteProperty(ByVal Name As String, ByVal Value As Variant, Optional ByVal DefaultValue As Variant)`\n### Parameters\n- `Name`: The name of the property to write.\n- `Value`: The value to write to the property. The data type can be any that is supported by the PropertyBag.\n- `DefaultValue`: An optional parameter that specifies the value the client should assume as default when reading the property.\n### Return Value\nNone. This is a Sub procedure and does not return a value.\n### Example\n```vb\n' Assume 'propBag' is a previously initialized PropertyBag object.\npropBag.WriteProperty(\"MyProperty\", \"SomeValue\", \"DefaultValue\")\n```\n### Remarks\nThe `WriteProperty` procedure is typically used when an object needs to save its state to a PropertyBag, such as during the `WriteProperties` event when implementing persistence in ActiveX controls or documents. The `DefaultValue` parameter is used to optimize storage by not storing the value if it is the same as the default."} ] }, { diff --git a/scripts/bug_repro.mjs b/scripts/bug_repro.mjs index 70c5d2240..eac4b04cd 100644 --- a/scripts/bug_repro.mjs +++ b/scripts/bug_repro.mjs @@ -480,7 +480,7 @@ const STARTUP = crlf(["Module Startup", "", " Public Sub Main()", " End Su // (tb-ide.mjs), so that it can be driven over DevTools, and code run in the IDE // inherits them. WebView2 lets them override what a WebView2 control asks for, // so a reproducer's control would join the IDE's own browser with other options -// and fail to start (8007139F, ERROR_INVALID_STATE; measured, BETA 995). The +// and fail to start (8007139F, ERROR_INVALID_STATE; measured). The // probe clears both for the length of Main, and an IDE started by hand has // neither. const PROBE = crlf([ @@ -953,10 +953,7 @@ async function runProbe(slug, o) { cpSync(p.src, stage, { recursive: true }); mkdirSync(path.join(stage, "Sources"), { recursive: true }); if (!o.exe) writeFileSync(path.join(stage, "Sources", "TbRunProbe.twin"), PROBE); - // Always --allow-name-clash: on a build before 1005 tbrun refuses a probe whose module holds a - // procedure named like the module, because those builds then do not run the [RunAfterBuild] - // Sub, and a reproducer exists to show a defect such as that one, so it must still run. - const flags = [...ideFlags(o), "--allow-name-clash", ...(o.llvm ? ["--llvm"] : []), ...(o.exe ? ["--exe"] : [])]; + const flags = [...ideFlags(o), ...(o.llvm ? ["--llvm"] : []), ...(o.exe ? ["--exe"] : [])]; const env = imagesDir ? { [IMAGES_ENV]: imagesDir } : {}; const r = await runNode([TBRUN, stage, ...flags], limitFor(o.timeout, 120), env); return { ...r, json: null, message: r.stderr.trim(), output: r.stdout, imagesDir }; diff --git a/scripts/check_attribute_sweep.mjs b/scripts/check_attribute_sweep.mjs index a05592285..722a74d25 100644 --- a/scripts/check_attribute_sweep.mjs +++ b/scripts/check_attribute_sweep.mjs @@ -798,6 +798,9 @@ for (const [app, want] of [ ["procedure, Declare (API declaration)", ["DECLARE", "PROC_ANY"]], ["Module", ["MODULE"]], ["an Implements statement in a Class", ["IMPLEMENTS"]], + ["Sub", ["SUB_MODULE"]], + ["procedures and Declare statements in a Module", ["PROC_MODULE", "DECLARE"]], + ["Class, Module, procedure", ["CLASS", "MODULE", "PROC_ANY"]], ]; const wrong = LINES.filter(([app, want]) => !same(targetsOf(app), want)).map( ([app]) => `${app} -> ${show(targetsOf(app))}`, diff --git a/scripts/check_examples.mjs b/scripts/check_examples.mjs index 6f62a447b..c0b3aa566 100644 --- a/scripts/check_examples.mjs +++ b/scripts/check_examples.mjs @@ -50,19 +50,18 @@ // 36.6 s wall including packing. One project per sample would be over three // hours. // -// Three collision rules fall out of putting unrelated samples in one +// Two collision rules fall out of putting unrelated samples in one // compilation unit, and each is a real hazard rather than a precaution: // // * one generated `Module tbx_` per fence, hashed from its id; -// * everything generated is Private -- eleven pages declare a `MyString`; -// * a generated module must not be named like the project, in any letter -// case: up to BETA 997 the IDE then skips the [RunAfterBuild] Sub, even one -// in another module, and reports nothing, so the build is green and nothing -// runs (twinbasic/twinbasic#2494; BETA 1005 runs it). +// * everything generated is Private -- eleven pages declare a `MyString`. +// +// The projects are named `DocSamples` and every generated module `tbx...`, so a +// module is never named like its project; that is only the naming scheme. // // `Sub Main` is not one of them, though it was once listed as one. The template // brings a Main, and a sample may bring its own beside it: two `Public Sub -// Main`s in different modules compile (measured, BETA 983), which is how the +// Main`s in different modules compile (BETA 1005), which is how the // WinServicesLib `Module Startup` samples build as written. That holds for a // compile; a build refuses two Mains, and two [DllExport]s of one name, and a // project with an error at all, so --build and --llvm batch around those three. @@ -189,7 +188,8 @@ Compiles the documentation's own twinBASIC code samples, every tb fence marked \`${MARKER}\`, and reports the ones the compiler refuses. A statement sample (slot=sub) marked \`${RUN_MARKER}\` is also built and run, in every mode, and what it prints is compared with what the page says it prints: the trailing comment on a Debug.Print -line, or the comment lines under a \`' Output:\` line. A sample that raises an error, +line, up to a \` -- \` that starts a note, or the comment lines under a \`' Output:\` +line. A sample that raises an error, does not return, or prints something else is a finding; one that calls MsgBox or InputBox, or contains End, or is not slot=sub, is refused without being built. diff --git a/scripts/check_impexp_parity.mjs b/scripts/check_impexp_parity.mjs index 620a6c6fd..a9437d120 100644 --- a/scripts/check_impexp_parity.mjs +++ b/scripts/check_impexp_parity.mjs @@ -1,29 +1,50 @@ -// Checks that the two editions of the impexp tool behave the same. +// Checks that the editions of the impexp tool behave the same. // // scripts/impexp.mjs and scripts/impexp.py are one tool offered to readers in // two languages, and Tools-Compiler.md promises that they print the same output and // write byte-identical files. Each has the same built-in tests, and nothing ran -// them. This runs both suites, which must pass with the same test names in the +// them. This runs every suite, which must pass with the same test names in the // same order, and then runs one sequence of commands through each edition, each // in a scratch folder of its own holding copies of indexer/sample.twinpack and // test/example-projects/console: export, import, the printing commands, and -// each refusal and failure the exit codes name. After every command the two -// exit codes, the two outputs and the two folders' files must be the same. +// each refusal and failure the exit codes name. After every command the +// exit codes, the outputs and the folders' files must be the same in every +// edition as in the first, impexp.mjs. +// +// A third edition is a twinBASIC console program, scripts/impexp/, built to an +// exe. No gate can build it, as none can build scripts/imagestrip/, so it is +// compared only when IMPEXP_EXE names the built exe (Windows only). It is run +// through launchOnDesktop, on a private desktop of its own, as every program a +// test starts is; a box it opens is a difference. // // Python's text streams write CRLF on Windows, so there a CRLF in the printed -// output is read as LF on both sides; on Linux, as in CI, the output is +// output is read as LF in every edition; on Linux, as in CI, the output is // compared as written. Written files are always compared as bytes. // // Without Python 3.6 or later this reports the gate skipped, loudly, and exits // 0, except in CI (GitHub sets CI=true), where it fails: CI must compare them. +// With IMPEXP_EXE set and no Python outside CI, impexp.mjs and the exe are still +// compared, and the report says impexp.py was not. // // node scripts/check_impexp_parity.mjs +// IMPEXP_EXE=path/to/impexp_win32.exe node scripts/check_impexp_parity.mjs // // Exit codes: 0 the same, or skipped outside CI; 1 a difference or a failed -// built-in test; 2 a refused command line, no Python in CI, or a crash. +// built-in test; 2 a refused command line, an IMPEXP_EXE that cannot be used, +// no Python in CI, or a crash. import { spawn, spawnSync } from "node:child_process"; -import { cpSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -42,11 +63,18 @@ sequence of commands through each, comparing exit codes, printed output and written files. Without Python 3.6 or later it reports the check skipped, or fails when CI=true. +Environment: + IMPEXP_EXE the built exe of scripts/impexp/, the twinBASIC edition (Windows + only). It joins the comparison as impexp.exe, run on a private + desktop. No gate builds it, so without this it is not compared. + With it and no Python outside CI, only impexp.mjs and the exe are + compared, and the report says impexp.py was not. + Exit codes: - 0 the two editions agree, or the check was skipped because no Python was found + 0 the editions agree, or the check was skipped because no Python was found 1 the editions differ, or a built-in test failed - 2 the check could not run: a refused command line, no Python when CI=true, or a - crash`); + 2 the check could not run: a refused command line, an IMPEXP_EXE that is not a + file or is set off Windows, no Python when CI=true, or a crash`); } const TOOL = "check_impexp_parity"; @@ -124,32 +152,84 @@ function findPython() { return null; } +// The twinBASIC edition's exe. It is refused, not skipped, when it cannot be +// used: someone who set the variable meant it to be compared. +const exePath = process.env.IMPEXP_EXE; +if (exePath) { + if (process.platform !== "win32") { + console.error(`${TOOL}: IMPEXP_EXE is set, but the twinBASIC edition runs only on Windows`); + process.exit(2); + } + if (!existsSync(exePath) || !statSync(exePath).isFile()) { + console.error(`${TOOL}: IMPEXP_EXE is "${exePath}", which is not a file`); + process.exit(2); + } +} + const python = findPython(); if (!python) { const tried = process.platform === "win32" ? "python3, python, py -3" : "python3, python"; if (IN_CI) { - console.error(`${TOOL}: no Python 3.6 or later found (tried ${tried}), and CI must compare the two editions`); + console.error(`${TOOL}: no Python 3.6 or later found (tried ${tried}), and CI must compare the editions`); process.exit(2); } + if (!exePath) { + console.error( + `${TOOL}: SKIPPED -- no Python 3.6 or later found (tried ${tried}).\n` + + `${TOOL}: impexp.mjs and impexp.py were NOT compared; CI compares them and fails without Python.`, + ); + process.exit(0); + } console.error( - `${TOOL}: SKIPPED -- no Python 3.6 or later found (tried ${tried}).\n` + - `${TOOL}: impexp.mjs and impexp.py were NOT compared; CI compares them and fails without Python.`, + `${TOOL}: WARNING -- no Python 3.6 or later found (tried ${tried}).\n` + + `${TOOL}: impexp.py was NOT compared; only impexp.mjs and impexp.exe are.`, ); - process.exit(0); } -const editions = [ - { name: "impexp.mjs", cmd: process.execPath, pre: [NODE_EDITION] }, - { name: "impexp.py", cmd: python.cmd, pre: [...python.pre, PYTHON_EDITION] }, -]; +// impexp.mjs comes first: every other edition is compared with it. +const editions = [{ name: "impexp.mjs", cmd: process.execPath, pre: [NODE_EDITION] }]; +if (python) editions.push({ name: "impexp.py", cmd: python.cmd, pre: [...python.pre, PYTHON_EDITION] }); +if (exePath) editions.push({ name: "impexp.exe", exe: exePath }); +const first = editions[0].name; + +// Where the exe's output goes, outside every edition's folder so that it is not +// compared as a written file. Set once the scratch folder exists. +let outputs; +let outputCount = 0; + +// What a stream's text is: latin1, with CRLF read as LF on Windows. +function text(buffer) { + const s = buffer.toString("latin1"); + return process.platform === "win32" ? s.replace(/\r\n/g, "\n") : s; +} -// One command through one edition. The two editions run each command at the +// One command through the exe, on a private desktop. The program's output goes +// to files, one pair for each run, because the editions run at the same time. +async function runExe(edition, args, cwd) { + const { launchOnDesktop } = await import("./lib/tb-ide.mjs"); + const n = ++outputCount; + const stdout = path.join(outputs, `${n}.out`); + const stderr = path.join(outputs, `${n}.err`); + const launched = await launchOnDesktop({ + exe: edition.exe, + args, + cwd, + desktop: "impexp-parity", + env: process.env, + stdout, + stderr, + dialogs: "close", + }); + const { code, dialogs } = await launched.finished; + if (code === null) throw new Error(`${edition.name} ${args.join(" ")}: ended without an exit code`); + const read = (p) => (existsSync(p) ? text(readFileSync(p)) : ""); + return { status: code, stdout: read(stdout), stderr: read(stderr), dialogs }; +} + +// One command through one edition. The editions run each command at the // same time, each in its own folder. function run(edition, args, cwd) { - const text = (chunks) => { - const s = Buffer.concat(chunks).toString("latin1"); - return process.platform === "win32" ? s.replace(/\r\n/g, "\n") : s; - }; + if (edition.exe) return runExe(edition, args, cwd); return new Promise((resolve, reject) => { const child = spawn(edition.cmd, [...edition.pre, ...args], { cwd, timeout: TIMEOUT_MS }); const out = []; @@ -159,11 +239,16 @@ function run(edition, args, cwd) { child.on("error", (e) => reject(new Error(`${edition.name} ${args.join(" ")}: ${e.message}`))); child.on("close", (status, signal) => { if (status === null) reject(new Error(`${edition.name} ${args.join(" ")}: ended by ${signal}`)); - else resolve({ status, stdout: text(out), stderr: text(err) }); + else resolve({ status, stdout: text(Buffer.concat(out)), stderr: text(Buffer.concat(err)), dialogs: [] }); }); }); } +// A box an edition opened is reported against its command. +function dialogProblems(edition, r) { + return r.dialogs.map((d) => `${edition.name} opened a box, "${d.title}": ${d.text}`); +} + // Every file under dir, by path relative to it with forward slashes. function files(dir) { const out = new Map(); @@ -186,44 +271,54 @@ function firstDifference(a, b) { return `line ${i + 1}: ${q(la[i])} and ${q(lb[i])}`; } -// The files that differ between the two folders, each named only the first -// time, so a difference is reported against the command that made it. +// The files that differ between the first edition's folder and another's, each +// named only the first time, so a difference is reported against the command +// that made it. const reported = new Set(); -function compareFolders(a, b) { +function compareFolders(a, b, edition) { const fa = files(a); const fb = files(b); const problems = []; const report = (p, what) => { - if (!reported.has(p)) problems.push(`${p} ${what}`); - reported.add(p); + const key = `${edition.name} ${p}`; + if (!reported.has(key)) problems.push(`${p} ${what}`); + reported.add(key); }; - for (const p of fa.keys()) if (!fb.has(p)) report(p, "written by impexp.mjs only"); - for (const p of fb.keys()) if (!fa.has(p)) report(p, "written by impexp.py only"); + for (const p of fa.keys()) if (!fb.has(p)) report(p, `written by ${first} only`); + for (const p of fb.keys()) if (!fa.has(p)) report(p, `written by ${edition.name} only`); for (const [p, bytes] of fa) { - if (fb.has(p) && !bytes.equals(fb.get(p))) report(p, `differs (${bytes.length} and ${fb.get(p).length} bytes)`); + if (fb.has(p) && !bytes.equals(fb.get(p))) { + report(p, `differs between ${first} and ${edition.name} (${bytes.length} and ${fb.get(p).length} bytes)`); + } } return problems; } const problems = []; - -// The built-in tests: both pass, with the same names in the same order. The -// first line names a temporary folder, which differs. -const selfTestRuns = await Promise.all(editions.map((e) => run(e, ["--self-test"], ROOT))); -const selfTests = editions.map((e, i) => { - const r = selfTestRuns[i]; - const lines = r.stdout.split("\n").filter((l) => !l.startsWith("Self-test workdir:")); - const names = lines.filter((l) => /^\s+\[(PASS|FAIL|SKIP)\] /.test(l)).map((l) => l.trim()); - if (r.status !== 0) problems.push(`${e.name} --self-test exited ${r.status}`); - for (const n of names) if (!n.startsWith("[PASS] ")) problems.push(`${e.name} --self-test: ${n}`); - if (names.length === 0) problems.push(`${e.name} --self-test ran no test`); - return { names, text: `${lines.join("\n")}\n${r.stderr}` }; -}); -const selfTestDifference = firstDifference(selfTests[0].text, selfTests[1].text); -if (selfTestDifference) problems.push(`--self-test prints differently, ${selfTestDifference}`); - const scratch = mkdtempSync(path.join(tmpdir(), "impexp-parity-")); +outputs = path.join(scratch, "outputs"); +mkdirSync(outputs); +let selfTestCount = 0; try { + // The built-in tests: every one passes, with the same names in the same order. + // The first line names a temporary folder, which differs. + const selfTestRuns = await Promise.all(editions.map((e) => run(e, ["--self-test"], ROOT))); + const selfTests = editions.map((e, i) => { + const r = selfTestRuns[i]; + const lines = r.stdout.split("\n").filter((l) => !l.startsWith("Self-test workdir:")); + const names = lines.filter((l) => /^\s+\[(PASS|FAIL|SKIP)\] /.test(l)).map((l) => l.trim()); + problems.push(...dialogProblems(e, r).map((p) => `--self-test: ${p}`)); + if (r.status !== 0) problems.push(`${e.name} --self-test exited ${r.status}`); + for (const n of names) if (!n.startsWith("[PASS] ")) problems.push(`${e.name} --self-test: ${n}`); + if (names.length === 0) problems.push(`${e.name} --self-test ran no test`); + return { names, text: `${lines.join("\n")}\n${r.stderr}` }; + }); + selfTestCount = selfTests[0].names.length; + for (let i = 1; i < editions.length; i++) { + const d = firstDifference(selfTests[0].text, selfTests[i].text); + if (d) problems.push(`--self-test of ${editions[i].name} prints differently from ${first}'s, ${d}`); + } + const dirs = editions.map((e) => { const dir = path.join(scratch, e.name); mkdirSync(dir); @@ -234,26 +329,36 @@ try { for (const c of COMMANDS) { const label = `impexp ${c.args.join(" ")}${c.why ? ` (${c.why})` : ""}`; for (const dir of dirs) c.setup?.(dir); - const [a, b] = await Promise.all(editions.map((e, i) => run(e, c.args, dirs[i]))); - if (a.status !== c.exit || b.status !== c.exit) { - problems.push(`${label}: exit ${a.status} from impexp.mjs and ${b.status} from impexp.py, not ${c.exit}`); + const results = await Promise.all(editions.map((e, i) => run(e, c.args, dirs[i]))); + if (results.some((r) => r.status !== c.exit)) { + const codes = editions.map((e, i) => `${results[i].status} from ${e.name}`); + problems.push(`${label}: exit ${codes.join(", ")}, not ${c.exit}`); + } + for (let i = 0; i < editions.length; i++) { + for (const p of dialogProblems(editions[i], results[i])) problems.push(`${label}: ${p}`); } - for (const stream of ["stdout", "stderr"]) { - const d = firstDifference(a[stream], b[stream]); - if (d) problems.push(`${label}: ${stream} differs, ${d}`); + for (let i = 1; i < editions.length; i++) { + for (const stream of ["stdout", "stderr"]) { + const d = firstDifference(results[0][stream], results[i][stream]); + if (d) problems.push(`${label}: ${stream} of ${editions[i].name} differs from ${first}'s, ${d}`); + } + for (const p of compareFolders(dirs[0], dirs[i], editions[i])) problems.push(`${label}: ${p}`); } - for (const p of compareFolders(dirs[0], dirs[1])) problems.push(`${label}: ${p}`); } } finally { rmSync(scratch, { recursive: true, force: true }); } +// "impexp.mjs, impexp.py (Python 3.12.1) and impexp.exe" +const names = editions.map((e) => (e.name === "impexp.py" ? `${e.name} (Python ${python.version})` : e.name)); +const named = `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`; if (problems.length) { - console.error(`${TOOL}: impexp.mjs and impexp.py (Python ${python.version}) differ:`); + console.error(`${TOOL}: ${named} differ:`); for (const p of problems) console.error(` ${p}`); process.exit(1); } console.log( - `${TOOL}: impexp.mjs and impexp.py (Python ${python.version}) pass the same ${selfTests[0].names.length} ` + + `${TOOL}: ${named} pass the same ${selfTestCount} ` + `built-in tests, and ${COMMANDS.length} commands exit, print and write the same`, ); +if (!python) console.error(`${TOOL}: WARNING -- impexp.py was NOT compared (no Python 3.6 or later found)`); diff --git a/scripts/check_symbol_index.mjs b/scripts/check_symbol_index.mjs index 45546c74c..0dba1c68a 100644 --- a/scripts/check_symbol_index.mjs +++ b/scripts/check_symbol_index.mjs @@ -14,7 +14,7 @@ // ones that stopped working unnoticed. So each rule is asserted here against // the case that made it necessary: // -// - the scanner's traps, each met in the BETA 983 packages -- a Type whose +// - the scanner's traps, each met in the shipped packages -- a Type whose // Subs have bodies, an Interface line inside a CoClass, `[Hidden]` on a // module whose members are global, a `$` name escaped in brackets, an // attribute on the declaration's own line, an attribute run spread over @@ -678,7 +678,7 @@ const show = (x) => JSON.stringify(x); } { - // The compiler (BETA 983, 995 and 1005) reads a line that is only `[Name]` in an + // The compiler (BETA 1005) reads a line that is only `[Name]` in an // Enum body as a value of that name, with the next number, whatever is in the // brackets; the scanner used to take it for the attributes of the next line, and // an Enum made of such lines came out with no values at all. diff --git a/scripts/check_twin_parsers.mjs b/scripts/check_twin_parsers.mjs index 6339613a5..83c084fd2 100644 --- a/scripts/check_twin_parsers.mjs +++ b/scripts/check_twin_parsers.mjs @@ -302,47 +302,6 @@ check( ); } -// A Sub or Function named like the hook's module, in that module: `clash` is its -// name as written, and tbrun refuses the probe (BETA 997: the hook does not run). -const hook = " [RunAfterBuild]\n Sub Go()\n End Sub"; -const named = (text, files = []) => wrapProbe([...files, { name: "Probe.twin", text }]); -for (const [what, text, want, files] of [ - ["a Sub of the module's name", probe(`${hook}\n Sub Probe()\n End Sub`), "Probe"], - [ - "a Private Function of the module's name", - probe(`${hook}\n Private Function Probe() As Long\n End Function`), - "Probe", - ], - ["the name in another letter case", probe(`${hook}\n Public Sub PROBE()\n End Sub`), "PROBE"], - ["a procedure before the hook", probe(` Friend Sub probe()\n End Sub\n${hook}`), "probe"], - ["a Sub that only starts with the module's name", probe(`${hook}\n Sub ProbeHelper()\n End Sub`), undefined], - ["a Sub that ends with the module's name", probe(`${hook}\n Sub MyProbe()\n End Sub`), undefined], - ["a comment line holding Sub Probe", probe(`${hook}\n ' Sub Probe()\n Sub Other()\n End Sub`), undefined], - [ - "the same name in another module of the file", - `${probe(hook)}Module Other\n Sub Probe()\n End Sub\nEnd Module\n`, - undefined, - ], - [ - "the same name in another module before it", - `Module Other\n Sub Probe()\n End Sub\nEnd Module\n${probe(hook)}`, - undefined, - ], - [ - "the same name in another file", - probe(hook), - undefined, - [{ name: "Other.twin", text: "Module Other\n Sub Probe()\n End Sub\nEnd Module\n" }], - ], -]) { - const r = named(text, files); - check( - `wrapProbe: clash, ${what}`, - r.wrapped?.sub === "Go" && r.wrapped.clash === want, - show({ wrapped: r.wrapped, why: r.why }), - ); -} - // ---------------------------------------------------------------- sentinelIndex // What tbrun reads to tell a probe that returned from one that ended first. const WAITING = "[DEBUGGER] Waiting for remaining forms to close..."; diff --git a/scripts/gen_attribute_probes.mjs b/scripts/gen_attribute_probes.mjs index bd3dcadc8..9e54cf1ad 100644 --- a/scripts/gen_attribute_probes.mjs +++ b/scripts/gen_attribute_probes.mjs @@ -114,7 +114,7 @@ const EXTRA_PROBES = []; // Kept in its own project so the "every probe compiles" contract on // AttributeProbes stays true and a red build there stays meaningful. // -// `got` records what BETA 983 answered, so re-running the generator does not +// `got` records what BETA 1005 answers, so re-running the generator does not // lose the result and a later build can be compared against it. A probe whose // `got` is out of date is worse than one with none, so update it in the same // commit as any change to the probe. @@ -130,15 +130,15 @@ const EXTRA_PROBES = []; // And **the token table does not settle existence either**, which an earlier // draft of this comment claimed. The table interns keywords, attributes and // object members together -- `Debug`, `Print` and `Assert` sit in it beside -// `Description` and `DllExport`. `ExecuteHostCommand` is in it and is a member -// of `Debug`, not an attribute, which is why it was rejected in every -// attribute position tried across two rounds. A name in the table is a name -// the compiler knows; what kind of name it is has to be probed. +// `Description` and `DllExport`. `ExecuteHostCommand` was in it and is not an +// attribute, which is why it was rejected in every attribute position tried +// across two rounds. A name in the table is a name the compiler knows; what +// kind of name it is has to be probed. const EXPLORATORY = [ { tag: "X01_ConstantFoldableNumericsOnly_Module", asks: "Is [ConstantFoldableNumericsOnly] accepted on a Function in a Module?", - got: "BETA 983: clean. The documented applicability holds.", + got: "BETA 1005: clean. The documented applicability holds.", clean: "the documented applicability holds", rejected: "`Applicable to: Function` is wrong even for a module function", body: @@ -153,7 +153,7 @@ const EXPLORATORY = [ tag: "X02_ConstantFoldableNumericsOnly_Class", asks: "Is it accepted on a method in a Class? Its sibling [ConstantFoldable] is not.", got: - "BETA 983: TB5182 on the attribute. REJECTED -- `Applicable to: " + + "BETA 1005: TB5182 on the attribute. REJECTED -- `Applicable to: " + "Function` was unqualified and wrong; the entry now carries the `in " + "a Module` qualification its sibling always had.", clean: "the two siblings differ, and the unqualified `Applicable to: Function` is right", @@ -170,7 +170,7 @@ const EXPLORATORY = [ tag: "X03_ConstantFoldable_Class_control", asks: "Control: [ConstantFoldable] on a Class method, already known to be rejected.", got: - "BETA 983: TB5182 on the attribute, as expected -- the same code " + + "BETA 1005: TB5182 on the attribute, as expected -- the same code " + "X02 drew, which is what makes X02's result readable.", clean: "the earlier finding has regressed or was wrong -- re-check it before trusting X02", rejected: "expected; this is what the X02 diagnostic should be compared against", @@ -188,7 +188,7 @@ const EXPLORATORY = [ { tag: "X04_CompilerOptions_Module", asks: 'Is [CompilerOptions("")] accepted on a procedure, and is an empty string a legal option set?', - got: "BETA 983: clean. The documented applicability holds and an empty " + "option string is accepted.", + got: "BETA 1005: clean. The documented applicability holds and an empty " + "option string is accepted.", clean: "the documented applicability holds and the argument may be empty", rejected: "read the diagnostic: a complaint about where the attribute sits " + @@ -207,7 +207,7 @@ const EXPLORATORY = [ asks: "Does [ComExport] exist as an attribute? It sits beside DllExport in the " + "compiler's token table and appears nowhere in docs/ or in any shipped package.", - got: "BETA 983: TB5155 on the attribute. REJECTED on a procedure.", + got: "BETA 1005: TB5155 on the attribute. REJECTED on a procedure.", clean: "it exists and is accepted on a procedure in a Module", rejected: "either it is not an attribute, or not one for a procedure", body: @@ -220,7 +220,7 @@ const EXPLORATORY = [ { tag: "X06_ComExport_Const", asks: "[ComExport] on a Const -- the target [DllExport] turned out to mean.", - got: "BETA 983: clean. [ComExport] mirrors [DllExport] exactly -- " + "constants, not procedures. Now documented.", + got: "BETA 1005: clean. [ComExport] mirrors [DllExport] exactly -- " + "constants, not procedures. Now documented.", clean: "it mirrors DllExport, which documents constants", rejected: "it does not mirror DllExport on this target", body: @@ -236,7 +236,7 @@ const EXPLORATORY = [ "WithDispatchForwarding in the token table, which is used 44 times on an " + "Implements statement.", got: - "BETA 983: TB5155 on the attribute. REJECTED -- it does NOT take " + + "BETA 1005: TB5155 on the attribute. REJECTED -- it does NOT take " + "its neighbour's position. Settled later by X25: it belongs on the " + "`Implements ... Via` form of the statement, not the plain one.", clean: "it exists and takes the same position as its neighbour", @@ -258,9 +258,8 @@ const EXPLORATORY = [ "and the binary also carries a `custom/executeHostCommand` JSON-RPC method, " + "so it is probably an IDE-addin hook rather than a compiler directive.", got: - "BETA 983: TB5182 on the attribute. REJECTED on a procedure in a " + - "Module. Settled later by X19: it is not an attribute at all, but a " + - "member of Debug.", + "BETA 1005: TB5182 on the attribute. REJECTED on a procedure in a " + + "Module. Settled later by X19: it is not an attribute at all.", clean: "it is accepted on a procedure in a Module, like IdeButton", rejected: "it needs an argument, a different target, or is not an attribute", body: @@ -280,7 +279,7 @@ const EXPLORATORY = [ "library:`, which suggests the construct is emitted when a COM type " + "library is imported rather than written by hand.", got: - "BETA 983: TB5182 on lines 10, 11, 12 and 16 -- `[LibraryId(...)]`, " + + "BETA 1005: TB5182 on lines 10, 11, 12 and 16 -- `[LibraryId(...)]`, " + "`Library`, `[DispInterface]` and `End Library`. Lines 13-15, the " + "nested Interface, parsed cleanly, so the failure is the Library " + "scaffolding and not this reconstruction of the Interface. That " + @@ -306,7 +305,7 @@ const EXPLORATORY = [ { tag: "X10_Library_DualInterface", asks: "Same question for [DualInterface].", - got: "BETA 983: TB5182 on lines 6, 7, 8 and 12 -- the same shape as X09.", + got: "BETA 1005: TB5182 on lines 6, 7, 8 and 12 -- the same shape as X09.", clean: "the documented applicability holds", rejected: "as X09 -- distinguish a syntax complaint from an applicability one", body: @@ -324,7 +323,7 @@ const EXPLORATORY = [ "Is [DispInterface] accepted on an ordinary Interface, outside a Library? " + "If it is, the `in a Library` qualification on its line is wrong.", got: - "BETA 983: TB5182 on the attribute. REJECTED, so the `in a Library` " + + "BETA 1005: TB5182 on the attribute. REJECTED, so the `in a Library` " + "qualification is real rather than incidental.", clean: "the qualification is wrong, or at least not required", rejected: "the qualification is real, and X09 is the only way to reach the attribute", @@ -343,7 +342,7 @@ const EXPLORATORY = [ "statement. The name reads as a policy for how a class implements its interfaces, " + "which would be a whole-class setting.", got: - "BETA 983: TB5182 on the attribute. REJECTED on the Class too. " + + "BETA 1005: TB5182 on the attribute. REJECTED on the Class too. " + "Settled later by X25, on the Implements ... Via statement.", clean: "it is a class-level attribute, and X07 tried the wrong target", rejected: "not the class either; try the interface side", @@ -364,7 +363,7 @@ const EXPLORATORY = [ "Same attribute on the Interface being implemented, which would make it the " + "interface author's choice rather than the implementor's.", got: - "BETA 983: TB5182 on the attribute. REJECTED on the Interface too. " + + "BETA 1005: TB5182 on the attribute. REJECTED on the Interface too. " + "Three targets exhausted -- and all three were the wrong question: " + "X25 found it on the Implements ... Via statement.", clean: "it belongs on the Interface", @@ -378,7 +377,7 @@ const EXPLORATORY = [ "[ExecuteHostCommand] on a method in a Class. The binary pairs the name with a " + "`custom/executeHostCommand` JSON-RPC method, so it is likely an addin hook, and an " + "addin's entry points are class methods rather than module procedures.", - got: "BETA 983: TB5182 on the attribute. REJECTED on a class method. " + "Not an attribute anywhere; see X19.", + got: "BETA 1005: TB5182 on the attribute. REJECTED on a class method. " + "Not an attribute anywhere; see X19.", clean: "it is a class-method attribute", rejected: "not a bare attribute on a class method; it may need an argument", body: @@ -395,9 +394,9 @@ const EXPLORATORY = [ "the same target as [IdeButton], whose entry it sits beside in the token table and " + "which takes a caption.", got: - "BETA 983: TB5182 on the attribute, at the same column as the bare " + + "BETA 1005: TB5182 on the attribute, at the same column as the bare " + "form in X08, so the argument is not what X08 was missing. Not an " + - "attribute in any position: X19 shows it is a member of Debug.", + "attribute in any position, and X19 finds no Debug member of the name.", clean: "it takes a String argument, and the bare form in X08 failed for want of one", rejected: "read the diagnostic: complaining about the argument rather than the " + @@ -416,7 +415,7 @@ const EXPLORATORY = [ "uses in the packages is `[Default, Source]`, so the entry written for it cannot " + "say whether the pairing is required or merely universal.", got: - "BETA 983: clean. [Source] works without [Default], so the " + + "BETA 1005: clean. [Source] works without [Default], so the " + "universal pairing in the packages is a convention rather than a " + "requirement. The entry now says so instead of recording it as " + "unknown.", @@ -440,7 +439,7 @@ const EXPLORATORY = [ "Does [ComExport] take the optional Boolean its sibling [DllExport] does? The " + "entry written for it claims no argument, because only the bare form was probed.", got: - "BETA 983: clean. [ComExport] DOES take the optional Boolean, and " + + "BETA 1005: clean. [ComExport] DOES take the optional Boolean, and " + "the entry written from X06 alone was wrong to give it no argument. " + "Corrected.", clean: "the entry should read `[ComExport [ ( True | False ) ]]`, like DllExport's", @@ -457,9 +456,10 @@ const EXPLORATORY = [ // asking a different question rather than trying another target: // // [ExecuteHostCommand] is not an attribute at all. The token table mixes - // keywords, attributes and object members, and this one is a member of - // `Debug` -- X18 to X21 below. The maintainer confirmed it afterwards: a - // leftover from the VS Code IDE, never wired to this one, to be removed. + // keywords, attributes and object members, and this one was a member of + // `Debug` -- X18 to X21 below. The maintainer confirmed it: a leftover + // from the VS Code IDE, never wired to this one, to be removed. It is + // removed: BETA 1005 rejects `Debug.ExecuteHostCommand` (X19, X20). // // [ImplementsViaPrivateFriendlies] belongs on `Implements ... Via`, the // composition-delegation form, not on the plain `Implements` that X07 and @@ -478,7 +478,7 @@ const EXPLORATORY = [ "Does the Debug object have members beyond Print and Assert? The compiler " + "binary carries ANSI identifiers DebugClsCommand and DebugExecuteHostCommand " + "side by side.", - got: "BETA 983: clean. Debug.Cls compiles, so the pairing is real -- which " + "is what makes X19 readable.", + got: "BETA 1005: clean. Debug.Cls compiles, so the pairing is real -- which " + "is what makes X19 readable.", clean: "Debug has a wider member set, and X19's premise is worth testing", rejected: "the DebugXxxCommand identifiers are not Debug members, and X19 is a guess", body: @@ -494,8 +494,9 @@ const EXPLORATORY = [ "Is ExecuteHostCommand a member of Debug rather than an attribute? X08, X14 " + "and X15 rejected it in every attribute position tried.", got: - "BETA 983: clean. It is a Debug member, so the token table entry was " + - "never an attribute and Attributes.md was right not to have one.", + "BETA 1005: TB5182 on the member name. REJECTED: Debug has no such " + + "member, and the name is not an attribute either, so Attributes.md is " + + "right not to have an entry for it.", clean: "it is a Debug member; no attribute entry is owed for the name", rejected: "it is neither an attribute nor a Debug member", body: @@ -511,9 +512,8 @@ const EXPLORATORY = [ "What is the parameter called? The compiler's string pool has " + '"Expected argument: command" immediately after DebugExecuteHostCommand.', got: - "BETA 983: TB5023 `Expected argument: command` -- the string from the " + - "binary, produced by the compiler, naming the parameter. This is the " + - "probe that identifies the binding outright.", + "BETA 1005: TB5182 on the member name, as X19: there is no such Debug " + + "member, so there is no argument to name.", clean: "the argument is optional", rejected: "read the message: naming the parameter identifies the binding", body: @@ -526,7 +526,7 @@ const EXPLORATORY = [ { tag: "X21_ExecuteHostCommand_bare_statement", asks: "Is it also a statement in its own right, without the Debug prefix?", - got: "BETA 983: TB5079 `Unrecognized symbol 'ExecuteHostCommand'`. It must " + "be qualified.", + got: "BETA 1005: TB5079 `Unrecognized symbol 'ExecuteHostCommand'`. It must " + "be qualified.", clean: "it is a statement as well as a Debug member", rejected: "it is reachable only through Debug", body: @@ -543,7 +543,7 @@ const EXPLORATORY = [ "plain Implements the unprefixed private member the attribute's name suggests, " + "instead of the usual IFoo_Ping stub.", got: - "BETA 983: TB5155 on the attribute, plus TB5000 `Missing implementation " + + "BETA 1005: TB5155 on the attribute, plus TB65535 `Missing implementation " + "of member Sub Ping()`. Two answers: the attribute is rejected on a plain " + "Implements whatever the body looks like, and an unprefixed private member " + "does not satisfy an interface on its own.", @@ -563,7 +563,7 @@ const EXPLORATORY = [ tag: "X23_IVPF_with_boolean", asks: "Does it take the optional Boolean many twinBASIC attributes take? Only the " + "bare form had been tried.", got: - "BETA 983: TB5155 on the attribute, at the same place as the bare form " + + "BETA 1005: TB5155 on the attribute, at the same place as the bare form " + "in X07 -- so a missing argument was not what X07 was short of either.", clean: "it takes a Boolean, and the bare form failed for want of one", rejected: "the argument is not what the plain Implements was refusing", @@ -582,7 +582,7 @@ const EXPLORATORY = [ asks: "On an Interface line inside a CoClass -- the target [Default] and [Source] " + "take, and one the earlier rounds did not try.", - got: "BETA 983: TB5182 on the attribute. Not this target either.", + got: "BETA 1005: TB5182 on the attribute. Not this target either.", clean: "it is a CoClass interface-line attribute", rejected: "not a CoClass interface line", body: @@ -600,7 +600,7 @@ const EXPLORATORY = [ "composition-delegation form, which every earlier probe had skipped in favour " + "of the plain Implements.", got: - "BETA 983: CLEAN. This is the answer. The attribute belongs on the " + + "BETA 1005: CLEAN. This is the answer. The attribute belongs on the " + "Via form of the statement, which is what its name says and what five " + "rejections had not suggested. Documented.", clean: "this is its target, and every earlier probe was on the wrong statement", @@ -623,7 +623,7 @@ const EXPLORATORY = [ asks: "The same attribute on the class-to-class form the Inheritance page shows, " + "`Implements Via `.", - got: "BETA 983: clean. Both spellings of the Via statement take it.", + got: "BETA 1005: clean. Both spellings of the Via statement take it.", clean: "both spellings of the Via statement take it", rejected: "only the field-and-constructor spelling takes it", body: @@ -642,7 +642,7 @@ const EXPLORATORY = [ { tag: "X27_IVPF_on_Inherits", asks: "On an Inherits statement -- twinBASIC's other inheritance mechanism.", - got: "BETA 983: TB5155 on the attribute. Delegation only, not Inherits.", + got: "BETA 1005: TB5155 on the attribute. Delegation only, not Inherits.", clean: "it applies to both inheritance mechanisms", rejected: "it is specific to Implements ... Via", body: @@ -660,7 +660,7 @@ const EXPLORATORY = [ "Control for X25. [WithDispatchForwarding] is a known-good " + "Implements-statement attribute. Does the Via form simply accept any attribute?", got: - "BETA 983: TB5155 on the attribute. REJECTED -- so the Via form does " + + "BETA 1005: TB5155 on the attribute. REJECTED -- so the Via form does " + "NOT accept attributes indiscriminately, and X25's clean build is about " + "that attribute rather than about that statement. This control is what " + "makes X25 evidence instead of a coincidence.", @@ -691,7 +691,7 @@ const EXPLORATORY = [ asks: "Baseline. Without the attribute, is a Friend member of the delegate callable " + "on the delegating class from elsewhere in the project?", - got: "BETA 983: clean. A plain Via forwards Friend members as Friend, so " + "they are reachable project-wide.", + got: "BETA 1005: clean. A plain Via forwards Friend members as Friend, so " + "they are reachable project-wide.", clean: "a plain Via re-exposes the delegate's Friend members", rejected: "it does not, and X30 has nothing to remove", body: @@ -715,8 +715,8 @@ const EXPLORATORY = [ tag: "X30_Via_Friend_outside_attr", asks: "The same call with the attribute added, and nothing else changed.", got: - "BETA 983: TB5027 `Unrecognized member 'FriendPing' on type " + - "'_CX30Derived'`. Against X29's clean build this is the effect: the " + + "BETA 1005: TB5027 `Unrecognized member 'FriendPing' on type " + + "'_CX30Derived' [non-extensible object]`. Against X29's clean build this is the effect: the " + "attribute stops the delegate's Friend members being re-exposed.", clean: "the attribute does not affect Friend visibility", rejected: "this is the effect -- read it against X29", @@ -741,7 +741,7 @@ const EXPLORATORY = [ tag: "X31_Via_Friend_inside_attr", asks: "Is that member gone, or merely private? Calling it from inside the class " + "separates the two.", got: - "BETA 983: clean, both through Me and unqualified. The member is still " + + "BETA 1005: clean, both through Me and unqualified. The member is still " + "there and still forwarded -- it is private to the class. `Private " + "friendlies` is literal.", clean: "private rather than absent, which is what the attribute's name claims", @@ -765,7 +765,7 @@ const EXPLORATORY = [ tag: "X32_Via_Public_outside_attr", asks: "Does the attribute touch Public members too, or only Friend ones?", got: - "BETA 983: clean. Public members forward exactly as they do without " + + "BETA 1005: clean. Public members forward exactly as they do without " + "the attribute, so the effect is confined to Friend members.", clean: "the effect is confined to Friend members", rejected: "the attribute makes every forwarded member private", diff --git a/scripts/impexp/impexp.twinproj b/scripts/impexp/impexp.twinproj new file mode 100644 index 000000000..62ee239cc Binary files /dev/null and b/scripts/impexp/impexp.twinproj differ diff --git a/bugs/filed/concurrent-builds-shared-temp/src/Settings b/scripts/impexp/src/Settings similarity index 82% rename from bugs/filed/concurrent-builds-shared-temp/src/Settings rename to scripts/impexp/src/Settings index 4fffbb129..034f0d564 100644 --- a/bugs/filed/concurrent-builds-shared-temp/src/Settings +++ b/scripts/impexp/src/Settings @@ -1,12 +1,13 @@ { "configuration.inherits": "Defaults", - "project.appTitle": "ConcurrentBuildsSharedTemp", + "project.appTitle": "impexp", "project.buildPath": "${SourcePath}\\Build\\${ProjectName}_${Architecture}.${FileExtension}", "project.buildType": "Standard EXE", - "project.description": "Reproduces: Builds running at the same time in one TEMP folder sometimes fail to write the type library", + "project.description": "Unpacks a .twinproj or .twinpack file into a folder, and packs a folder back into a project file: the twinBASIC edition of impexp.mjs and impexp.py.", "project.exportPathIsV2": true, - "project.id": "{F3F2C6A4-A713-4F53-9B49-830560B557F9}", - "project.name": "ConcurrentBuildsSharedTemp", + "project.id": "{312DB30E-7896-4595-8E6F-A633FA7D33E5}", + "project.isConsoleApplication": true, + "project.name": "impexp", "project.optionExplicit": true, "project.references": [ { diff --git a/scripts/impexp/src/Sources/ByteBuilder.twin b/scripts/impexp/src/Sources/ByteBuilder.twin new file mode 100644 index 000000000..5be7c1ba2 --- /dev/null +++ b/scripts/impexp/src/Sources/ByteBuilder.twin @@ -0,0 +1,58 @@ +' A byte array that grows as it is appended to, with the little-endian writes a project file needs. +Class ByteBuilder + Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As LongPtr) + + Private mData() As Byte + Private mLen As Long + Private mCap As Long + + Public Sub AddRange(src() As Byte, ByVal start As Long, ByVal count As Long) + If count <= 0 Then Exit Sub + Reserve count + RtlMoveMemory VarPtr(mData(mLen)), VarPtr(src(start)), count + mLen = mLen + count + End Sub + + Public Sub AddU8(ByVal value As Long) + Reserve 1 + mData(mLen) = value And &HFF + mLen = mLen + 1 + End Sub + + Public Sub AddI16(ByVal value As Integer) + Reserve 2 + RtlMoveMemory VarPtr(mData(mLen)), VarPtr(value), 2 + mLen = mLen + 2 + End Sub + + Public Sub AddU32(ByVal value As Long) + Reserve 4 + RtlMoveMemory VarPtr(mData(mLen)), VarPtr(value), 4 + mLen = mLen + 4 + End Sub + + Public Sub AddU64(ByVal value As LongLong) + Reserve 8 + RtlMoveMemory VarPtr(mData(mLen)), VarPtr(value), 8 + mLen = mLen + 8 + End Sub + + Public Property Get Count() As Long + Count = mLen + End Property + + Public Function ToArray(out() As Byte) As Long + Erase out + If mLen > 0 Then + ReDim out(0 To mLen - 1) + RtlMoveMemory VarPtr(out(0)), VarPtr(mData(0)), mLen + End If + ToArray = mLen + End Function + + Private Sub Reserve(ByVal extra As Long) + If mLen + extra <= mCap Then Exit Sub + mCap = 2 * (mLen + extra) + 64 + ReDim Preserve mData(0 To mCap - 1) + End Sub +End Class diff --git a/scripts/impexp/src/Sources/Entry.twin b/scripts/impexp/src/Sources/Entry.twin new file mode 100644 index 000000000..1e7a63113 --- /dev/null +++ b/scripts/impexp/src/Sources/Entry.twin @@ -0,0 +1,68 @@ +' One entry of a project file's tree: a file with its content, or a folder with its children. +Class Entry + Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As LongPtr) + + Public IsFile As Boolean + Public Name As String + Public Revision As LongLong + Public Flags As Long + Public Category As Long + Public Children As New Collection + + Private mContent() As Byte + Private mContentLength As Long + Private mRevisions() As Long + Private mRevisionCount As Long + + Public Property Get ContentLength() As Long + ContentLength = mContentLength + End Property + + ' The first length bytes of b from start, copied. + Public Sub SetContent(b() As Byte, ByVal start As Long, ByVal length As Long) + Erase mContent + mContentLength = length + If length > 0 Then + ReDim mContent(0 To length - 1) + RtlMoveMemory VarPtr(mContent(0)), VarPtr(b(start)), length + End If + End Sub + + ' The content copied into out, and its length. + Public Function GetContent(out() As Byte) As Long + Erase out + If mContentLength > 0 Then + ReDim out(0 To mContentLength - 1) + RtlMoveMemory VarPtr(out(0)), VarPtr(mContent(0)), mContentLength + End If + GetContent = mContentLength + End Function + + Public Sub SetContentLatin1(ByVal s As String) + Dim b() As Byte, n As Long + n = TextKit.Latin1Encode(s, b) + SetContent b, 0, n + End Sub + + Public Function ContentLatin1() As String + ContentLatin1 = TextKit.Latin1Decode(mContent, mContentLength) + End Function + + Public Property Get RevisionCount() As Long + RevisionCount = mRevisionCount + End Property + + Public Function RevisionAt(ByVal i As Long) As Long + RevisionAt = mRevisions(i) + End Function + + Public Sub AddRevision(ByVal value As Long) + If mRevisionCount = 0 Then + ReDim mRevisions(0 To 3) + ElseIf mRevisionCount > UBound(mRevisions) Then + ReDim Preserve mRevisions(0 To 2 * mRevisionCount - 1) + End If + mRevisions(mRevisionCount) = value + mRevisionCount = mRevisionCount + 1 + End Sub +End Class diff --git a/scripts/impexp/src/Sources/FileSys.twin b/scripts/impexp/src/Sources/FileSys.twin new file mode 100644 index 000000000..b5c167438 --- /dev/null +++ b/scripts/impexp/src/Sources/FileSys.twin @@ -0,0 +1,366 @@ +' The file system, through the wide Win32 calls, so that every path is Unicode. A call that +' fails raises IO_FAILED with the path and the system's own message. +Module FileSys + Private Type FILETIME + Low As Long + High As Long + End Type + + Private Type WIN32_FIND_DATAW + dwFileAttributes As Long + ftCreationTime As FILETIME + ftLastAccessTime As FILETIME + ftLastWriteTime As FILETIME + nFileSizeHigh As Long + nFileSizeLow As Long + dwReserved0 As Long + dwReserved1 As Long + cFileName(0 To 259) As Integer + cAlternateFileName(0 To 13) As Integer + End Type + + Private Declare PtrSafe Function CreateFileW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As LongPtr, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As LongPtr) As LongPtr + Private Declare PtrSafe Function ReadFile Lib "kernel32" (ByVal hFile As LongPtr, ByVal lpBuffer As LongPtr, ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, ByVal lpOverlapped As LongPtr) As Long + Private Declare PtrSafe Function WriteFile Lib "kernel32" (ByVal hFile As LongPtr, ByVal lpBuffer As LongPtr, ByVal nNumberOfBytesToWrite As Long, ByRef lpNumberOfBytesWritten As Long, ByVal lpOverlapped As LongPtr) As Long + Private Declare PtrSafe Function GetFileSizeEx Lib "kernel32" (ByVal hFile As LongPtr, ByRef lpFileSize As LongLong) As Long + Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As LongPtr) As Long + Private Declare PtrSafe Function GetFileAttributesW Lib "kernel32" (ByVal lpFileName As LongPtr) As Long + Private Declare PtrSafe Function SetFileAttributesW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal dwFileAttributes As Long) As Long + Private Declare PtrSafe Function CreateDirectoryW Lib "kernel32" (ByVal lpPathName As LongPtr, ByVal lpSecurityAttributes As LongPtr) As Long + Private Declare PtrSafe Function RemoveDirectoryW Lib "kernel32" (ByVal lpPathName As LongPtr) As Long + Private Declare PtrSafe Function DeleteFileW Lib "kernel32" (ByVal lpFileName As LongPtr) As Long + Private Declare PtrSafe Function MoveFileExW Lib "kernel32" (ByVal lpExistingFileName As LongPtr, ByVal lpNewFileName As LongPtr, ByVal dwFlags As Long) As Long + Private Declare PtrSafe Function FindFirstFileW Lib "kernel32" (ByVal lpFileName As LongPtr, ByRef lpFindFileData As WIN32_FIND_DATAW) As LongPtr + Private Declare PtrSafe Function FindNextFileW Lib "kernel32" (ByVal hFindFile As LongPtr, ByRef lpFindFileData As WIN32_FIND_DATAW) As Long + Private Declare PtrSafe Function FindClose Lib "kernel32" (ByVal hFindFile As LongPtr) As Long + Private Declare PtrSafe Function GetFullPathNameW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal nBufferLength As Long, ByVal lpBuffer As LongPtr, ByVal lpFilePart As LongPtr) As Long + Private Declare PtrSafe Function GetTempPathW Lib "kernel32" (ByVal nBufferLength As Long, ByVal lpBuffer As LongPtr) As Long + Private Declare PtrSafe Function GetCurrentDirectoryW Lib "kernel32" (ByVal nBufferLength As Long, ByVal lpBuffer As LongPtr) As Long + Private Declare PtrSafe Function FormatMessageW Lib "kernel32" (ByVal dwFlags As Long, ByVal lpSource As LongPtr, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As LongPtr, ByVal nSize As Long, ByVal Arguments As LongPtr) As Long + + Public Const IO_FAILED As Long = vbObjectError + &H1101 + + Public Const KIND_NONE As Long = 0 + Public Const KIND_FILE As Long = 1 + Public Const KIND_FOLDER As Long = 2 + + Private Const GENERIC_READ As Long = &H80000000 + Private Const GENERIC_WRITE As Long = &H40000000 + Private Const FILE_SHARE_ALL As Long = 7 + Private Const OPEN_EXISTING As Long = 3 + Private Const CREATE_ALWAYS As Long = 2 + Private Const FILE_ATTRIBUTE_READONLY As Long = 1 + Private Const FILE_ATTRIBUTE_DIRECTORY As Long = &H10 + Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80 + Private Const INVALID_FILE_ATTRIBUTES As Long = -1 + Private Const MOVEFILE_REPLACE_EXISTING As Long = 1 + Private Const CHUNK As Long = &H100000 + + ' KIND_NONE when nothing is there, as Node's statSync throws. + Public Function KindOf(ByVal path As String) As Long + Dim attrs As Long + If Len(path) = 0 Then Exit Function + attrs = GetFileAttributesW(StrPtr(path)) + If attrs = INVALID_FILE_ATTRIBUTES Then Exit Function + If (attrs And FILE_ATTRIBUTE_DIRECTORY) <> 0 Then KindOf = KIND_FOLDER Else KindOf = KIND_FILE + End Function + + ' The whole file into data, and its length. + Public Function ReadAllBytes(ByVal path As String, data() As Byte) As Long + Dim h As LongPtr, size As LongLong, done As Long, n As Long, got As Long + Erase data + h = CreateFileW(StrPtr(path), GENERIC_READ, FILE_SHARE_ALL, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) + If h = -1 Then Fail "cannot read " & path + If GetFileSizeEx(h, size) = 0 Then + CloseHandle h + Fail "cannot read " & path + End If + If size > &H7FFFFFFF Then + CloseHandle h + Err.Raise IO_FAILED, , "cannot read " & path & ": the file is larger than 2 GB" + End If + If size > 0 Then + ReDim data(0 To CLng(size) - 1) + Do While done < size + n = CLng(size) - done + If n > CHUNK Then n = CHUNK + If ReadFile(h, VarPtr(data(done)), n, got, 0) = 0 Then + CloseHandle h + Fail "cannot read " & path + End If + If got = 0 Then Exit Do + done = done + got + Loop + End If + CloseHandle h + ReadAllBytes = done + End Function + + ' Creates or empties the file, and writes the first length bytes of data into it. + Public Sub WriteAllBytes(ByVal path As String, data() As Byte, ByVal length As Long) + Dim h As LongPtr, done As Long, n As Long, wrote As Long + h = CreateFileW(StrPtr(path), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) + If h = -1 Then Fail "cannot write " & path + Do While done < length + n = length - done + If n > CHUNK Then n = CHUNK + If WriteFile(h, VarPtr(data(done)), n, wrote, 0) = 0 Then + CloseHandle h + Fail "cannot write " & path + End If + done = done + wrote + Loop + CloseHandle h + End Sub + + ' The names in a folder, "." and ".." left out, in the order the file system gives them. + Public Function ListNames(ByVal folder As String, names() As String) As Long + Dim d As WIN32_FIND_DATAW, h As LongPtr, name As String, n As Long + Erase names + h = FindFirstFileW(StrPtr(Normalize(folder & "\*")), d) + If h = -1 Then Fail "cannot read the folder " & folder + Do + name = FindName(d) + If name <> "." And name <> ".." Then + If n = 0 Then + ReDim names(0 To 15) + ElseIf n > UBound(names) Then + ReDim Preserve names(0 To 2 * n - 1) + End If + names(n) = name + n = n + 1 + End If + Loop While FindNextFileW(h, d) <> 0 + FindClose h + ListNames = n + End Function + + Private Function FindName(d As WIN32_FIND_DATAW) As String + Dim i As Long, s As String + Do While i <= 259 + If d.cFileName(i) = 0 Then Exit Do + s = s & ChrW$(d.cFileName(i) And &HFFFF&) + i = i + 1 + Loop + FindName = s + End Function + + ' Creates the folder and every folder above it that is missing, as mkdirSync's recursive does. + Public Sub MakeDirs(ByVal path As String) + Dim full As String, parent As String + full = FullPath(path) + If KindOf(full) = KIND_FOLDER Then Exit Sub + parent = ParentOf(full) + If Len(parent) > 0 And parent <> full Then + If KindOf(parent) <> KIND_FOLDER Then MakeDirs parent + End If + If CreateDirectoryW(StrPtr(full), 0) = 0 Then + If KindOf(full) <> KIND_FOLDER Then Fail "cannot create the folder " & path + End If + End Sub + + ' Replaces target with source, as renameSync does. + Public Sub MoveReplacing(ByVal source As String, ByVal target As String) + If MoveFileExW(StrPtr(source), StrPtr(target), MOVEFILE_REPLACE_EXISTING) = 0 Then Fail "cannot write " & target + End Sub + + ' Deletes a file, or a folder and everything in it; nothing there is no error, as rmSync's force. + Public Sub RemovePath(ByVal path As String) + Dim names() As String, n As Long, i As Long + Select Case KindOf(path) + Case KIND_FILE + SetFileAttributesW StrPtr(path), FILE_ATTRIBUTE_NORMAL + If DeleteFileW(StrPtr(path)) = 0 Then Fail "cannot delete " & path + Case KIND_FOLDER + n = ListNames(path, names) + For i = 0 To n - 1 + RemovePath path & "\" & names(i) + Next + If RemoveDirectoryW(StrPtr(path)) = 0 Then Fail "cannot delete " & path + End Select + End Sub + + ' The absolute path, as path.resolve gives it: no trailing separator but a root's. + Public Function FullPath(ByVal path As String) As String + Dim buf As String, n As Long + If Len(path) = 0 Then path = "." + n = GetFullPathNameW(StrPtr(path), 0, 0, 0) + If n = 0 Then + FullPath = path + Exit Function + End If + buf = String$(n, vbNullChar) + n = GetFullPathNameW(StrPtr(path), n, StrPtr(buf), 0) + FullPath = Left$(buf, n) + Do While Len(FullPath) > 3 And Right$(FullPath, 1) = "\" + FullPath = Left$(FullPath, Len(FullPath) - 1) + Loop + End Function + + ' The key two paths to one file share: Windows compares paths without regard to case. + Public Function PathKey(ByVal path As String) As String + PathKey = LCase$(FullPath(path)) + End Function + + Public Function CurrentDirectory() As String + Dim buf As String, n As Long + n = GetCurrentDirectoryW(0, 0) + buf = String$(n, vbNullChar) + n = GetCurrentDirectoryW(n, StrPtr(buf)) + CurrentDirectory = Left$(buf, n) + End Function + + ' The temporary folder, without a trailing separator, as os.tmpdir gives it. + Public Function TempFolder() As String + Dim buf As String, n As Long + buf = String$(1024, vbNullChar) + n = GetTempPathW(1024, StrPtr(buf)) + TempFolder = Left$(buf, n) + Do While Len(TempFolder) > 3 And Right$(TempFolder, 1) = "\" + TempFolder = Left$(TempFolder, Len(TempFolder) - 1) + Loop + End Function + + ' A new, empty folder whose name is prefix and six random characters, as mkdtempSync makes. + Public Function MakeTempFolder(ByVal prefix As String) As String + Const LETTERS As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + Dim attempt As Long, i As Long, candidate As String + Randomize + For attempt = 1 To 100 + candidate = prefix + For i = 1 To 6 + candidate = candidate & Mid$(LETTERS, Int(Rnd * Len(LETTERS)) + 1, 1) + Next + If CreateDirectoryW(StrPtr(candidate), 0) <> 0 Then + MakeTempFolder = candidate + Exit Function + End If + Next + Fail "cannot create a temporary folder " & prefix & "XXXXXX" + End Function + + ' The folder that holds path, or "" for a root. + Public Function ParentOf(ByVal path As String) As String + Dim i As Long + For i = Len(path) To 1 Step -1 + If Mid$(path, i, 1) = "\" Or Mid$(path, i, 1) = "/" Then Exit For + Next + If i <= 0 Then Exit Function + If i = 3 And Mid$(path, 2, 1) = ":" Then + ParentOf = Left$(path, 3) + ElseIf i = 1 Then + ParentOf = "\" + Else + ParentOf = Left$(path, i - 1) + End If + End Function + + ' The last component of a path, as path.basename gives it. + Public Function BaseName(ByVal path As String) As String + Dim i As Long + path = Replace(path, "/", "\") + Do While Len(path) > 1 And Right$(path, 1) = "\" + path = Left$(path, Len(path) - 1) + Loop + i = InStrRev(path, "\") + BaseName = Mid$(path, i + 1) + If Len(BaseName) = 2 And Right$(BaseName, 1) = ":" Then BaseName = "" + If BaseName = "\" Then BaseName = "" + End Function + + ' The extension of a name, from its last dot, as path.extname gives it: none for a name + ' that is only a leading dot and what follows. + Public Function ExtName(ByVal name As String) As String + Dim i As Long + i = InStrRev(name, ".") + If i <= 1 Then Exit Function + ExtName = Mid$(name, i) + End Function + + ' The parts joined with separators and normalised, as path.join does on Windows. + Public Function JoinPath(ParamArray parts() As Variant) As String + Dim i As Long, s As String + For i = LBound(parts) To UBound(parts) + If Len(parts(i)) > 0 Then + If Len(s) > 0 Then s = s & "\" + s = s & CStr(parts(i)) + End If + Next + JoinPath = Normalize(s) + End Function + + ' Forward slashes made backslashes, repeated separators collapsed, and "." and ".." resolved, + ' as path.normalize does on Windows. A trailing separator stays. + Public Function Normalize(ByVal path As String) As String + Dim root As String, rest As String, absolute As Boolean, trailing As Boolean + Dim segs() As String, kept() As String, n As Long, i As Long, s As String + path = Replace(path, "/", "\") + If Len(path) = 0 Then + Normalize = "." + Exit Function + End If + If Left$(path, 2) = "\\" Then + root = "\\" + rest = Mid$(path, 3) + absolute = True + Else + If Len(path) >= 2 And Mid$(path, 2, 1) = ":" Then + root = Left$(path, 2) + path = Mid$(path, 3) + End If + If Left$(path, 1) = "\" Then + root = root & "\" + absolute = True + End If + rest = path + End If + trailing = Right$(rest, 1) = "\" + segs = Split(rest, "\") + ReDim kept(0 To UBound(segs) + 1) + For i = 0 To UBound(segs) + s = segs(i) + If s = "" Or s = "." Then + ' nothing + ElseIf s = ".." Then + If n > 0 And kept(n - 1) <> ".." Then + n = n - 1 + ElseIf Not absolute Then + kept(n) = ".." + n = n + 1 + End If + Else + kept(n) = s + n = n + 1 + End If + Next + s = "" + For i = 0 To n - 1 + If i > 0 Then s = s & "\" + s = s & kept(i) + Next + If Len(s) = 0 And Not absolute Then s = "." + If trailing And n > 0 Then s = s & "\" + Normalize = root & s + End Function + + ' Raises IO_FAILED with the system's message for the last error. + Private Sub Fail(ByVal what As String) + Dim code As Long + code = Err.LastDllError + Err.Raise IO_FAILED, , what & ": " & SystemMessage(code) + End Sub + + Private Function SystemMessage(ByVal code As Long) As String + Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000 + Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200 + Dim buf As String, n As Long + buf = String$(512, vbNullChar) + n = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, 0, code, 0, StrPtr(buf), 512, 0) + buf = Left$(buf, n) + Do While Len(buf) > 0 And (Right$(buf, 1) = vbCr Or Right$(buf, 1) = vbLf Or Right$(buf, 1) = " " Or Right$(buf, 1) = ".") + buf = Left$(buf, Len(buf) - 1) + Loop + If Len(buf) = 0 Then buf = "error " & code + SystemMessage = buf + End Function +End Module diff --git a/scripts/impexp/src/Sources/Impexp.twin b/scripts/impexp/src/Sources/Impexp.twin new file mode 100644 index 000000000..8f68e8e01 --- /dev/null +++ b/scripts/impexp/src/Sources/Impexp.twin @@ -0,0 +1,452 @@ +' Export, import and the printing commands, as exportProject, importProject and readDocument in +' scripts/impexp.mjs do them. A refusal raises REFUSED with its reason, message and details in +' LastReason, LastMessage and LastDetails, and has written nothing. +Module Impexp + Private Declare PtrSafe Function GetCurrentProcessId Lib "kernel32" () As Long + + Public Const REFUSED As Long = vbObjectError + &H1100 + + Public Const EXIT_DONE As Long = 0 + Public Const EXIT_FAILED As Long = 1 + Public Const EXIT_USAGE As Long = 2 + Public Const EXIT_EXISTS As Long = 3 + Public Const EXIT_MISSING As Long = 4 + Public Const EXIT_INVALID As Long = 5 + Public Const EXIT_WARNED As Long = 6 + + Public LastReason As String + Public LastMessage As String + Public LastDetails As New Collection + + ' Extensions of the code files, which the IDE stores with CRLF line endings. + Private Const CRLF_EXTENSIONS As String = "|.twin|.bas|.cls|" + + ' The IDE's editor state, which export leaves out as the compiler's export does. + Private Const META_NAME As String = ".meta" + + ' Git's own folder, never packed and never written. + Private Const GIT_NAME As String = ".git" + + ' The folders the IDE writes into every project and package it exports, even when empty. + Private Const STANDARD_FOLDERS As String = "ImportedTypeLibraries|Miscellaneous|Packages|Resources|Sources" + + ' Export's state while it walks the tree. + Private mFolders As Collection + Private mFileRels As Collection + Private mFileEntries As Collection + Private mInProject As Object + Private mResult As Outcome + + Public Sub Refuse(ByVal reason As String, ByVal message As String, Optional ByVal details As Collection = Nothing) + LastReason = reason + LastMessage = message + If details Is Nothing Then Set LastDetails = New Collection Else Set LastDetails = details + Err.Raise REFUSED, , message + End Sub + + ' The exit code for an error that ended a command. + Public Function ExitCodeForError(ByVal number As Long) As Long + If number <> REFUSED Then + ExitCodeForError = EXIT_FAILED + Exit Function + End If + Select Case LastReason + Case "failed": ExitCodeForError = EXIT_FAILED + Case "usage": ExitCodeForError = EXIT_USAGE + Case "exists": ExitCodeForError = EXIT_EXISTS + Case "missing": ExitCodeForError = EXIT_MISSING + Case "invalid": ExitCodeForError = EXIT_INVALID + Case Else: ExitCodeForError = EXIT_FAILED + End Select + End Function + + ' The exit code for a command that did its work: it warned, or it did not. + Public Function ExitCodeForOutcome(ByVal r As Outcome) As Long + If r.Stale.Count > 0 Or r.Repeated.Count > 0 Then ExitCodeForOutcome = EXIT_WARNED Else ExitCodeForOutcome = EXIT_DONE + End Function + + ' At most ten, so a refusal over a whole tree stays readable. + Public Function Listed(ByVal paths As Collection) As Collection + Dim r As New Collection, i As Long + For i = 1 To paths.Count + If i > 10 Then + r.Add "... and " & (paths.Count - 10) & " more" + Exit For + End If + r.Add paths(i) + Next + Set Listed = r + End Function + + Private Function Lines(ParamArray items() As Variant) As Collection + Dim r As New Collection, i As Long + For i = LBound(items) To UBound(items) + r.Add items(i) + Next + Set Lines = r + End Function + + Private Function HintExport() As Collection + Set HintExport = Lines("export writes the project into the folder.", "To write the folder into the project instead, use import.") + End Function + + Private Function HintImport() As Collection + Set HintImport = Lines("import replaces the project file with the folder.", "To write the project into the folder instead, use export.") + End Function + + ' The project file's tree. Refuses a file that is missing, a folder, or not a project. + Public Function ReadProject(ByVal file As String) As Entry + Dim data() As Byte, n As Long + Select Case FileSys.KindOf(file) + Case FileSys.KIND_NONE: Refuse "missing", "project file does not exist: " & file + Case FileSys.KIND_FOLDER: Refuse "invalid", file & " is a folder, not a project file" + End Select + n = FileSys.ReadAllBytes(file, data) + On Error GoTo Damaged + Set ReadProject = ProjectFormat.Parse(data, n) + Exit Function + Damaged: + Dim why As String + why = Err.Description + On Error GoTo 0 + Refuse "invalid", file & " is damaged or is not a project file: " & why + End Function + + ' Writes the file only once the new one is complete, so a failed write leaves the old one. + Private Sub WriteReplacing(ByVal file As String, data() As Byte, ByVal length As Long) + Dim tmp As String, number As Long, description As String + tmp = file & "." & GetCurrentProcessId() & ".tmp" + On Error GoTo Failed + FileSys.WriteAllBytes tmp, data, length + FileSys.MoveReplacing tmp, file + Exit Sub + Failed: + number = Err.Number + description = Err.Description + On Error Resume Next + FileSys.RemovePath tmp + On Error GoTo 0 + Err.Raise number, , description + End Sub + + ' A name the project holds becomes one component of a path on disk, so it has to be exactly + ' one: "..", "a/b" or "C:x" would put a file outside the folder, and Windows drops a trailing + ' dot or space, which turns ".. " into "..". + Public Function IsSafeName(ByVal name As String) As Boolean + Dim i As Long, c As Long + If Len(name) = 0 Then Exit Function + For i = 1 To Len(name) + c = AscW(Mid$(name, i, 1)) And &HFFFF& + If c < 32 Then Exit Function + If InStr("\/:*?""<>|", ChrW$(c)) > 0 Then Exit Function + Next + If Right$(name, 1) = "." Or Right$(name, 1) = " " Then Exit Function + IsSafeName = True + End Function + + Public Function ExportProject(ByVal projectPath As String, ByVal folder As String, ByVal overwrite As Boolean) As Outcome + Dim root As Entry, i As Long, k As Long, p As String, b() As Byte, n As Long + Set root = ReadProject(projectPath) + + ' Everything is checked before anything is written, so a refusal leaves the folder as it was. + Set mResult = New Outcome + Set mFolders = New Collection + Set mFileRels = New Collection + Set mFileEntries = New Collection + Set mInProject = CreateObject("Scripting.Dictionary") + mInProject.CompareMode = 0 + Collect root, "" + + Dim inTheWay As New Collection, existing As New Collection + If FileSys.KindOf(folder) = FileSys.KIND_FILE Then Refuse "failed", folder & " is a file, not a folder" + For i = 1 To mFolders.Count + p = OnDisk(folder, mFolders(i)) + If FileSys.KindOf(p) = FileSys.KIND_FILE Then inTheWay.Add p + Next + For i = 1 To mFileRels.Count + p = OnDisk(folder, mFileRels(i)) + k = FileSys.KindOf(p) + If k = FileSys.KIND_FOLDER Then + inTheWay.Add p + ElseIf k = FileSys.KIND_FILE Then + existing.Add p + End If + Next + If inTheWay.Count > 0 Then + Refuse "failed", "the folder has a file where the project has a folder, or the reverse:", Listed(inTheWay) + End If + If existing.Count > 0 And Not overwrite Then + Dim details As Collection, line As Variant + Set details = Listed(existing) + For Each line In HintExport() + details.Add line + Next + Refuse "exists", TextKit.Count(existing.Count, "file") & " already " & IIf(existing.Count = 1, "exists", "exist") & _ + ", and --overwrite is not set:", details + End If + + FileSys.MakeDirs folder + For i = 1 To mFolders.Count + FileSys.MakeDirs OnDisk(folder, mFolders(i)) + Next + Dim fe As Entry + For i = 1 To mFileRels.Count + Set fe = mFileEntries(i) + n = fe.GetContent(b) + FileSys.WriteAllBytes OnDisk(folder, mFileRels(i)), b, n + Next + + ' Export never deletes, and the compiler's does not either. A file the project no longer + ' has stays in the folder, and the next import packs it straight back in, so say which. + ScanStale folder, "", FileSys.PathKey(projectPath) + + mResult.Name = root.Name + mResult.Files = mFileRels.Count + mResult.Folders = mFolders.Count + Set ExportProject = mResult + Set mInProject = Nothing + End Function + + Private Function OnDisk(ByVal folder As String, ByVal rel As String) As String + OnDisk = FileSys.JoinPath(folder, Replace(rel, "/", "\")) + End Function + + Private Sub Collect(ByVal dir As Entry, ByVal rel As String) + Dim e As Entry, entryRel As String, key As String, first As Variant + For Each e In dir.Children + If Len(rel) > 0 Then entryRel = rel & "/" & e.Name Else entryRel = e.Name + If Not IsSafeName(e.Name) Then + Refuse "invalid", "the project holds a name that cannot be written safely: " & TextKit.JsonQuote(entryRel) + End If + ' A project can hold one name more than once, and a folder cannot. The first entry + ' wins, as it does with the compiler's export --overwrite, and a repeated folder + ' merges into the first. + key = LCase$(entryRel) + If mInProject.Exists(key) Then + first = mInProject(key) + If first(0) <> e.IsFile Then + Refuse "invalid", "the project holds a file and a folder with the same name: " & entryRel + End If + If Not e.IsFile Then + Collect e, first(1) + ElseIf Not Contains(mResult.Repeated, first(1)) Then + mResult.Repeated.Add first(1) + End If + Else + mInProject.Add key, Array(e.IsFile, entryRel) + If LCase$(e.Name) = GIT_NAME Then + mResult.Skipped.Add Array(entryRel, "Git's own folder") + ElseIf Not e.IsFile Then + mFolders.Add entryRel + Collect e, entryRel + ElseIf e.Name <> META_NAME Then + mFileRels.Add entryRel + mFileEntries.Add e + End If + End If + Next + End Sub + + Private Function Contains(ByVal c As Collection, ByVal s As String) As Boolean + Dim v As Variant + For Each v In c + If v = s Then + Contains = True + Exit Function + End If + Next + End Function + + Private Sub ScanStale(ByVal dir As String, ByVal rel As String, ByVal source As String) + Dim names() As String, n As Long, i As Long, full As String, entryRel As String + n = FileSys.ListNames(dir, names) + TextKit.SortOrdinal names, n + For i = 0 To n - 1 + If LCase$(names(i)) <> GIT_NAME Then + full = FileSys.JoinPath(dir, names(i)) + If Len(rel) > 0 Then entryRel = rel & "/" & names(i) Else entryRel = names(i) + If FileSys.KindOf(full) = FileSys.KIND_FOLDER Then + ScanStale full, entryRel, source + ElseIf Not mInProject.Exists(LCase$(entryRel)) And FileSys.PathKey(full) <> source Then + mResult.Stale.Add full + End If + End If + Next + End Sub + + ' LF made CRLF in a code file; any other file as it is. + Private Function ToCrlf(ByVal name As String, b() As Byte, ByVal length As Long, out() As Byte) As Long + Dim w As ByteBuilder, i As Long + If InStr(CRLF_EXTENSIONS, "|" & LCase$(FileSys.ExtName(name)) & "|") = 0 Or Len(FileSys.ExtName(name)) = 0 Then + Erase out + If length > 0 Then out = b + ToCrlf = length + Exit Function + End If + Set w = New ByteBuilder + For i = 0 To length - 1 + If b(i) = 10 Then + If i = 0 Then + w.AddU8 13 + ElseIf b(i - 1) <> 13 Then + w.AddU8 13 + End If + End If + w.AddU8 b(i) + Next + ToCrlf = w.ToArray(out) + End Function + + ' The project's name in its Settings, or "" when it names none. + Private Function ProjectNameIn(ByVal settingsPath As String) As String + Dim b() As Byte, n As Long, settingsText As String + On Error GoTo Unreadable + n = FileSys.ReadAllBytes(settingsPath, b) + settingsText = TextKit.Utf8Decode(b, 0, n) + If Len(settingsText) > 0 Then + If (AscW(settingsText) And &HFFFF&) = &HFEFF& Then settingsText = Mid$(settingsText, 2) + End If + ProjectNameIn = Json.TopLevelString(settingsText, "project.name") + Unreadable: + End Function + + Private Function BuildTree(ByVal dirPath As String, ByVal rel As String, ByVal self As String, ByVal r As Outcome) As Entry + Dim names() As String, n As Long, i As Long, total As Long + Dim missing As String, have As String, standard As Variant, name As String, entryRel As String + Dim all() As String, subdirs As New Collection, files As New Collection, full As String, kind As Long + n = FileSys.ListNames(dirPath, names) + + ' The standard folders this tree lacks, if it is the project or a package in it. + Dim isPackage As Boolean + If rel <> "" Then + If LCase$(Left$(rel, 9)) = "packages/" And InStr(10, rel, "/") = 0 And Len(rel) > 9 Then + For i = 0 To n - 1 + If names(i) = "Settings" Then isPackage = True + Next + End If + End If + missing = "|" + If rel = "" Or isPackage Then + have = "|" + For i = 0 To n - 1 + have = have & LCase$(names(i)) & "|" + Next + For Each standard In Split(STANDARD_FOLDERS, "|") + If InStr(have, "|" & LCase$(standard) & "|") = 0 Then missing = missing & standard & "|" + Next + End If + + ReDim all(0 To n + 5) + For i = 0 To n - 1 + all(i) = names(i) + Next + total = n + For Each standard In Split(Mid$(missing, 2), "|") + If Len(standard) > 0 Then + all(total) = standard + total = total + 1 + End If + Next + TextKit.SortOrdinal all, total + + For i = 0 To total - 1 + name = all(i) + full = FileSys.JoinPath(dirPath, name) + If Len(rel) > 0 Then entryRel = rel & "/" & name Else entryRel = name + If InStr(missing, "|" & name & "|") > 0 Then + subdirs.Add name + r.Added.Add entryRel + ElseIf LCase$(name) = GIT_NAME Then + r.Skipped.Add Array(entryRel, "Git's own folder") + Else + kind = FileSys.KindOf(full) + If kind = FileSys.KIND_FOLDER Then + subdirs.Add name + ElseIf kind = FileSys.KIND_FILE Then + If FileSys.PathKey(full) = self Then + r.Skipped.Add Array(entryRel, "the project file itself") + Else + files.Add name + End If + End If + End If + Next + + Dim e As Entry, d As Variant, f As Variant, b() As Byte, crlf() As Byte, length As Long + Set e = ProjectFormat.NewFolder(FileSys.BaseName(dirPath)) + For Each d In subdirs + If InStr(missing, "|" & d & "|") > 0 Then + e.Children.Add ProjectFormat.NewFolder(d) + Else + If Len(rel) > 0 Then entryRel = rel & "/" & d Else entryRel = d + e.Children.Add BuildTree(FileSys.JoinPath(dirPath, d), entryRel, self, r) + End If + Next + For Each f In files + length = FileSys.ReadAllBytes(FileSys.JoinPath(dirPath, f), b) + length = ToCrlf(f, b, length, crlf) + e.Children.Add ProjectFormat.NewFile(f, crlf, length) + Next + Set BuildTree = e + End Function + + Public Function ImportProject(ByVal projectPath As String, ByVal folder As String, ByVal overwrite As Boolean) As Outcome + Dim settings As String, existing As Long, r As New Outcome, root As Entry, name As String + Dim b() As Byte, n As Long + ' Everything is checked before the tree is read, so a refusal leaves the project file as it was. + If FileSys.KindOf(folder) <> FileSys.KIND_FOLDER Then Refuse "missing", "input folder does not exist: " & folder, HintImport() + settings = FileSys.JoinPath(folder, "Settings") + If FileSys.KindOf(settings) <> FileSys.KIND_FILE Then + Refuse "invalid", folder & " has no Settings file, so it is not the top folder of a project", HintImport() + End If + existing = FileSys.KindOf(projectPath) + If existing = FileSys.KIND_FOLDER Then Refuse "failed", projectPath & " is a folder, not a project file" + If existing = FileSys.KIND_FILE And Not overwrite Then + Refuse "exists", projectPath & " already exists, and --overwrite is not set", HintImport() + End If + + Set root = BuildTree(FileSys.FullPath(folder), "", FileSys.PathKey(projectPath), r) + ' The IDE names the root after the project; the folder's name is the fallback. + name = ProjectNameIn(settings) + If Len(name) > 0 Then root.Name = name + root.Category = ProjectFormat.CATEGORY_DEFAULT + n = ProjectFormat.Serialize(root, b) + WriteReplacing projectPath, b, n + + r.Name = root.Name + r.Size = n + Tally root, r + Set ImportProject = r + End Function + + Private Sub Tally(ByVal e As Entry, ByVal r As Outcome) + Dim c As Entry + For Each c In e.Children + If c.IsFile Then + r.Files = r.Files + 1 + Else + r.Folders = r.Folders + 1 + Tally c, r + End If + Next + End Sub + + ' The verb's document at the root of the project, matched in any case, into out. + Public Function ReadDocument(ByVal projectPath As String, ByVal verb As String, out() As Byte) As Long + Dim root As Entry, want As String, e As Entry + Set root = ReadProject(projectPath) + Select Case verb + Case "settings": want = "Settings" + Case "licence": want = "LICENCE.md" + Case "changelog": want = "CHANGELOG.md" + Case "readme": want = "README.md" + End Select + For Each e In root.Children + If e.IsFile And LCase$(e.Name) = LCase$(want) Then + ReadDocument = e.GetContent(out) + Exit Function + End If + Next + Refuse "missing", projectPath & " has no " & want + End Function +End Module diff --git a/scripts/impexp/src/Sources/Json.twin b/scripts/impexp/src/Sources/Json.twin new file mode 100644 index 000000000..b5bebe4c0 --- /dev/null +++ b/scripts/impexp/src/Sources/Json.twin @@ -0,0 +1,249 @@ +' Reads one string member of a JSON object's top level, as JSON.parse(text)[key] would find it: +' the text must be JSON as a whole, and the last of two members with one name wins. +Module Json + Private mText As String + Private mPos As Long + Private mBad As Boolean + + ' The string value of the top-level member named key, or "" when the text is not JSON, is not + ' an object, or has no such member, or the member is not a string. + Public Function TopLevelString(ByVal text As String, ByVal key As String) As String + Dim found As String, name As String, value As String, isString As Boolean + mText = text + mPos = 1 + mBad = False + SkipSpace + If Peek() <> "{" Then Exit Function + mPos = mPos + 1 + SkipSpace + If Peek() = "}" Then + mPos = mPos + 1 + Else + Do + SkipSpace + If Peek() <> """" Then Exit Function + name = ReadString() + If mBad Then Exit Function + SkipSpace + If Peek() <> ":" Then Exit Function + mPos = mPos + 1 + SkipSpace + isString = Peek() = """" + If isString Then value = ReadString() Else SkipValue + If mBad Then Exit Function + If name = key Then + If isString Then found = value Else found = "" + End If + SkipSpace + If Peek() = "," Then + mPos = mPos + 1 + ElseIf Peek() = "}" Then + mPos = mPos + 1 + Exit Do + Else + Exit Function + End If + Loop + End If + SkipSpace + If mPos <= Len(mText) Then Exit Function + TopLevelString = found + End Function + + Private Function Peek() As String + If mPos <= Len(mText) Then Peek = Mid$(mText, mPos, 1) + End Function + + Private Sub SkipSpace() + Dim c As String + Do While mPos <= Len(mText) + c = Mid$(mText, mPos, 1) + If c <> " " And c <> vbTab And c <> vbLf And c <> vbCr Then Exit Do + mPos = mPos + 1 + Loop + End Sub + + Private Sub SkipValue() + Dim c As String + If mBad Then Exit Sub + c = Peek() + Select Case c + Case """" + ReadString + Case "{" + mPos = mPos + 1 + SkipSpace + If Peek() = "}" Then + mPos = mPos + 1 + Exit Sub + End If + Do + SkipSpace + If Peek() <> """" Then + mBad = True + Exit Sub + End If + ReadString + SkipSpace + If mBad Or Peek() <> ":" Then + mBad = True + Exit Sub + End If + mPos = mPos + 1 + SkipSpace + SkipValue + If mBad Then Exit Sub + SkipSpace + If Peek() = "," Then + mPos = mPos + 1 + ElseIf Peek() = "}" Then + mPos = mPos + 1 + Exit Sub + Else + mBad = True + Exit Sub + End If + Loop + Case "[" + mPos = mPos + 1 + SkipSpace + If Peek() = "]" Then + mPos = mPos + 1 + Exit Sub + End If + Do + SkipSpace + SkipValue + If mBad Then Exit Sub + SkipSpace + If Peek() = "," Then + mPos = mPos + 1 + ElseIf Peek() = "]" Then + mPos = mPos + 1 + Exit Sub + Else + mBad = True + Exit Sub + End If + Loop + Case "t" + Literal "true" + Case "f" + Literal "false" + Case "n" + Literal "null" + Case Else + SkipNumber + End Select + End Sub + + Private Sub Literal(ByVal word As String) + If Mid$(mText, mPos, Len(word)) = word Then + mPos = mPos + Len(word) + Else + mBad = True + End If + End Sub + + ' -? (0 | [1-9][0-9]*) (. [0-9]+)? ([eE] [+-]? [0-9]+)? + Private Sub SkipNumber() + If Peek() = "-" Then mPos = mPos + 1 + If Peek() = "0" Then + mPos = mPos + 1 + ElseIf IsDigit(Peek()) Then + Do While IsDigit(Peek()) + mPos = mPos + 1 + Loop + Else + mBad = True + Exit Sub + End If + If Peek() = "." Then + mPos = mPos + 1 + If Not IsDigit(Peek()) Then + mBad = True + Exit Sub + End If + Do While IsDigit(Peek()) + mPos = mPos + 1 + Loop + End If + If Peek() = "e" Or Peek() = "E" Then + mPos = mPos + 1 + If Peek() = "+" Or Peek() = "-" Then mPos = mPos + 1 + If Not IsDigit(Peek()) Then + mBad = True + Exit Sub + End If + Do While IsDigit(Peek()) + mPos = mPos + 1 + Loop + End If + End Sub + + Private Function IsDigit(ByVal c As String) As Boolean + If Len(c) = 1 Then IsDigit = c >= "0" And c <= "9" + End Function + + ' The string at mPos, its quotes and escapes undone; sets mBad for one JSON refuses. + Private Function ReadString() As String + Dim r As String, c As String, code As Long, h As String + mPos = mPos + 1 + Do + If mPos > Len(mText) Then + mBad = True + Exit Function + End If + c = Mid$(mText, mPos, 1) + mPos = mPos + 1 + If c = """" Then Exit Do + If (AscW(c) And &HFFFF&) < 32 Then + mBad = True + Exit Function + End If + If c = "\" Then + c = Mid$(mText, mPos, 1) + mPos = mPos + 1 + Select Case c + Case """", "\", "/": r = r & c + Case "b": r = r & ChrW$(8) + Case "f": r = r & ChrW$(12) + Case "n": r = r & vbLf + Case "r": r = r & vbCr + Case "t": r = r & vbTab + Case "u" + h = Mid$(mText, mPos, 4) + If Len(h) <> 4 Or Not IsHex(h) Then + mBad = True + Exit Function + End If + code = HexValue(h) + r = r & ChrW$(code) + mPos = mPos + 4 + Case Else + mBad = True + Exit Function + End Select + Else + r = r & c + End If + Loop + ReadString = r + End Function + + Private Function HexValue(ByVal s As String) As Long + Dim i As Long + For i = 1 To Len(s) + HexValue = HexValue * 16 + InStr("0123456789abcdef", LCase$(Mid$(s, i, 1))) - 1 + Next + End Function + + Private Function IsHex(ByVal s As String) As Boolean + Dim i As Long, c As String + For i = 1 To Len(s) + c = LCase$(Mid$(s, i, 1)) + If Not ((c >= "0" And c <= "9") Or (c >= "a" And c <= "f")) Then Exit Function + Next + IsHex = True + End Function +End Module diff --git a/scripts/impexp/src/Sources/MainModule.twin b/scripts/impexp/src/Sources/MainModule.twin new file mode 100644 index 000000000..b07656c10 --- /dev/null +++ b/scripts/impexp/src/Sources/MainModule.twin @@ -0,0 +1,280 @@ +' impexp -- the twinBASIC edition of scripts/impexp.mjs and scripts/impexp.py: the same commands, +' the same output and the same exit codes, and byte-identical project files. +Module MainModule + Private Declare PtrSafe Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As LongPtr + Private Declare PtrSafe Function GetConsoleMode Lib "kernel32" (ByVal hConsoleHandle As LongPtr, ByRef lpMode As Long) As Long + Private Declare PtrSafe Function WriteConsoleW Lib "kernel32" (ByVal hConsoleOutput As LongPtr, ByVal lpBuffer As LongPtr, ByVal nNumberOfCharsToWrite As Long, ByRef lpNumberOfCharsWritten As Long, ByVal lpReserved As LongPtr) As Long + Private Declare PtrSafe Function WriteFile Lib "kernel32" (ByVal hFile As LongPtr, ByVal lpBuffer As LongPtr, ByVal nNumberOfBytesToWrite As Long, ByRef lpNumberOfBytesWritten As Long, ByVal lpOverlapped As LongPtr) As Long + Private Declare PtrSafe Function GetCommandLineW Lib "kernel32" () As LongPtr + Private Declare PtrSafe Function CommandLineToArgvW Lib "shell32" (ByVal lpCmdLine As LongPtr, ByRef pNumArgs As Long) As LongPtr + Private Declare PtrSafe Function LocalFree Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr + Private Declare PtrSafe Function lstrlenW Lib "kernel32" (ByVal lpString As LongPtr) As Long + Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As LongPtr) + Private Declare PtrSafe Sub ExitProcess Lib "kernel32" (ByVal uExitCode As Long) + + Private Const STD_OUTPUT_HANDLE As Long = -11 + Private Const STD_ERROR_HANDLE As Long = -12 + + Public Sub Main() + Dim code As Long + On Error GoTo Crashed + code = Run(Arguments()) + ExitProcess code + Exit Sub + Crashed: + WriteErr " ERROR: " & Err.Description + ExitProcess Impexp.EXIT_FAILED + End Sub + + Public Function Usage() As String + Usage = Join(Array( _ + "Usage:", _ + " impexp export [--overwrite] unpack the project file into the folder", _ + " impexp import [--overwrite] pack the folder into the project file", _ + " impexp settings print the project's Settings", _ + " impexp licence print the project's LICENCE.md", _ + " impexp changelog print the project's CHANGELOG.md", _ + " impexp readme print the project's README.md", _ + " impexp --self-test run the built-in tests", _ + " impexp --help print this message", _ + "", _ + " is a .twinproj or .twinpack file. It always comes first, and the", _ + "verb says what happens to it: export takes source out, import puts source in.", _ + "The commands and their arguments are those of the tB executable,", _ + "twinBASIC_win32.exe.", _ + "", _ + "The exit code says what happened, so the output need not be read:", _ + " 0 done", _ + " 1 failed for another reason, such as a file that could not be written", _ + " 2 a mistake in the command line", _ + " 3 refused, because a file exists and --overwrite is not set", _ + " 4 the project file, the folder or the file to print does not exist", _ + " 5 the project file is damaged or is not one, or the folder has no Settings", _ + " 6 done, with a warning: the folder holds files the project does not,", _ + " or the project holds one name twice"), vbLf) + End Function + + ' The arguments after the program's name, as the C runtime splits them. + Private Function Arguments() As Collection + Dim r As New Collection, argv As LongPtr, argc As Long, i As Long, p As LongPtr, n As Long, s As String + argv = CommandLineToArgvW(GetCommandLineW(), argc) + For i = 1 To argc - 1 + RtlMoveMemory VarPtr(p), argv + i * LenB(p), LenB(p) + n = lstrlenW(p) + s = String$(n, vbNullChar) + If n > 0 Then RtlMoveMemory StrPtr(s), p, 2 * n + r.Add s + Next + LocalFree argv + Set Arguments = r + End Function + + Private Function IsProjectFile(ByVal name As String) As Boolean + name = LCase$(name) + IsProjectFile = Right$(name, 9) = ".twinproj" Or Right$(name, 9) = ".twinpack" + End Function + + ' What is wrong with the command line, or "". words(1) is the verb, and the rest its + ' arguments. Strict on purpose: the project file has to be named as one and the folder must + ' not be, so arguments given in the wrong order stop here instead of reaching the disk. + Public Function CommandLineError(ByVal words As Collection) As String + Dim verb As String, want As Long, project As String, folder As String, takes As String + If words.Count = 0 Then + CommandLineError = "no command given" + Exit Function + End If + verb = words(1) + Select Case verb + Case "export", "import" + want = 2 + takes = " " + Case "settings", "licence", "changelog", "readme" + want = 1 + takes = "" + Case Else + CommandLineError = "unknown command: " & verb + Exit Function + End Select + If words.Count - 1 <> want Then + CommandLineError = verb & " takes " & takes + Exit Function + End If + project = words(2) + If want = 2 Then folder = words(3) + If Not IsProjectFile(project) Then + CommandLineError = "not a .twinproj or .twinpack file: " & project + If want = 2 Then CommandLineError = CommandLineError & " -- the project file comes first" + Exit Function + End If + If want = 2 Then + Dim bare As String + bare = folder + Do While Len(bare) > 0 And (Right$(bare, 1) = "\" Or Right$(bare, 1) = "/") + bare = Left$(bare, Len(bare) - 1) + Loop + If IsProjectFile(bare) Then CommandLineError = folder & " names a project file, not a folder -- the folder comes second" + End If + End Function + + Private Function UsageError(ByVal message As String) As Long + WriteErr "ERROR: " & message & vbLf & vbLf & Usage() + UsageError = Impexp.EXIT_USAGE + End Function + + Private Sub PrintError(ByVal number As Long, ByVal description As String) + Dim line As Variant + If number = Impexp.REFUSED Then + WriteErr " ERROR: " & Impexp.LastMessage + For Each line In Impexp.LastDetails + WriteErr " " & line + Next + Else + WriteErr " ERROR: " & description + End If + End Sub + + Public Function Run(ByVal argv As Collection) As Long + Dim overwrite As Boolean, help As Boolean, selfTesting As Boolean, words As New Collection, a As Variant + For Each a In argv + If a = "--overwrite" Then + overwrite = True + ElseIf a = "--self-test" Then + selfTesting = True + ElseIf a = "--help" Or a = "-h" Then + help = True + ElseIf Len(a) > 1 And Left$(a, 1) = "-" Then + Run = UsageError("unknown option: " & a) + Exit Function + Else + words.Add a + End If + Next + If help Then + WriteOut Usage() + Exit Function + End If + If selfTesting Then + If words.Count > 0 Then + Run = UsageError("--self-test takes no other arguments") + Else + Run = SelfTest.RunAll() + End If + Exit Function + End If + + Dim problem As String + problem = CommandLineError(words) + If Len(problem) > 0 Then + Run = UsageError(problem) + Exit Function + End If + Dim verb As String, project As String, folder As String + verb = words(1) + project = words(2) + If words.Count > 2 Then folder = words(3) + + If verb = "export" Or verb = "import" Then + ' The progress lines follow the compiler's, down to the last one: a script that + ' tests for "... DONE" works with either. + If verb = "export" Then + WriteOut "exporting from """ & project & """ to """ & folder & """..." + Else + WriteOut "importing into """ & project & """ from """ & folder & """..." + End If + Dim r As Outcome, s As Variant, line As Variant, sizeText As String + On Error GoTo Failed + If verb = "export" Then + Set r = Impexp.ExportProject(project, folder, overwrite) + Else + Set r = Impexp.ImportProject(project, folder, overwrite) + End If + On Error GoTo 0 + For Each s In r.Skipped + WriteOut " skipped " & s(0) & " (" & s(1) & ")" + Next + For Each s In r.Added + WriteOut " added " & s & " (an empty folder the IDE expects)" + Next + If r.Size >= 0 Then sizeText = ", " & Format$(r.Size, "0") & " bytes" + WriteOut " " & TextKit.Count(r.Files, "file") & ", " & TextKit.Count(r.Folders, "folder") & sizeText + If r.Repeated.Count > 0 Then + WriteErr " WARNING: " & TextKit.Count(r.Repeated.Count, "name") & " " & IIf(r.Repeated.Count = 1, "occurs", "occur") & _ + " more than once in the project, and a folder holds one of each, so only the first was written:" + For Each line In Impexp.Listed(r.Repeated) + WriteErr " " & line + Next + End If + If r.Stale.Count > 0 Then + WriteErr " WARNING: " & TextKit.Count(r.Stale.Count, "file") & " in the folder " & IIf(r.Stale.Count = 1, "is", "are") & _ + " not in the project, and import would pack " & IIf(r.Stale.Count = 1, "it", "them") & " back in:" + For Each line In Impexp.Listed(r.Stale) + WriteErr " " & line + Next + End If + WriteOut "... DONE" + Run = Impexp.ExitCodeForOutcome(r) + Exit Function + End If + + Dim b() As Byte, n As Long + On Error GoTo DocumentFailed + n = Impexp.ReadDocument(project, verb, b) + On Error GoTo 0 + WriteBytesOut b, n + Exit Function + + Failed: + Dim number As Long, description As String + number = Err.Number + description = Err.Description + PrintError number, description + WriteOut "... FAILED" + Run = Impexp.ExitCodeForError(number) + Exit Function + + DocumentFailed: + number = Err.Number + description = Err.Description + PrintError number, description + Run = Impexp.ExitCodeForError(number) + End Function + + Public Sub WriteOut(ByVal text As String) + WriteTo STD_OUTPUT_HANDLE, text & vbLf + End Sub + + Public Sub WriteErr(ByVal text As String) + WriteTo STD_ERROR_HANDLE, text & vbLf + End Sub + + ' WriteConsoleW writes nothing to a file or a pipe, so redirected output goes through + ' WriteFile, as UTF-8, as Node writes it. + Private Sub WriteTo(ByVal stream As Long, ByVal text As String) + Dim handle As LongPtr, mode As Long, written As Long, b() As Byte, n As Long + handle = GetStdHandle(stream) + If GetConsoleMode(handle, mode) <> 0 Then + WriteConsoleW handle, StrPtr(text), Len(text), written, 0 + Else + n = TextKit.Utf8Encode(text, b) + If n > 0 Then WriteFile handle, VarPtr(b(0)), n, written, 0 + End If + End Sub + + ' The bytes as they are, to a file or a pipe; read as UTF-8 to the console. + Private Sub WriteBytesOut(b() As Byte, ByVal length As Long) + Dim handle As LongPtr, mode As Long, written As Long, s As String, done As Long, n As Long + If length = 0 Then Exit Sub + handle = GetStdHandle(STD_OUTPUT_HANDLE) + If GetConsoleMode(handle, mode) <> 0 Then + s = TextKit.Utf8Decode(b, 0, length) + WriteConsoleW handle, StrPtr(s), Len(s), written, 0 + Else + Do While done < length + n = length - done + If n > &H100000 Then n = &H100000 + If WriteFile(handle, VarPtr(b(done)), n, written, 0) = 0 Then Exit Do + done = done + written + Loop + End If + End Sub +End Module diff --git a/scripts/impexp/src/Sources/Outcome.twin b/scripts/impexp/src/Sources/Outcome.twin new file mode 100644 index 000000000..9517c5bcc --- /dev/null +++ b/scripts/impexp/src/Sources/Outcome.twin @@ -0,0 +1,20 @@ +' What an export or an import did: the counts, and what it skipped, added and warns about. +Class Outcome + Public Name As String + Public Files As Long + Public Folders As Long + ' The project file's size after an import; -1 after an export, which reports none. + Public Size As Double + ' Each an Array(rel, why). + Public Skipped As New Collection + ' The empty folders an import added, by path in the project. + Public Added As New Collection + ' The paths a project holds more than once. + Public Repeated As New Collection + ' The files in the folder that the project does not hold. + Public Stale As New Collection + + Private Sub Class_Initialize() + Size = -1 + End Sub +End Class diff --git a/scripts/impexp/src/Sources/ProjectFormat.twin b/scripts/impexp/src/Sources/ProjectFormat.twin new file mode 100644 index 000000000..464496469 --- /dev/null +++ b/scripts/impexp/src/Sources/ProjectFormat.twin @@ -0,0 +1,202 @@ +' The project file format: a tree of entries, read from bytes and written to them. +Module ProjectFormat + Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As LongPtr) + + Public Const FORMAT_ERROR As Long = vbObjectError + &H1102 + + Public Const MAGIC As Long = &HEA0BA51C + Public Const FORMAT_VERSION As Integer = 1 + + Public Const FLAG_NONE As Long = 0 + Public Const FLAG_HIDDEN As Long = 1 + Public Const FLAG_SUPER_HIDDEN As Long = 2 + Public Const FLAG_VIRTUAL As Long = 4 + + Public Const CATEGORY_DEFAULT As Long = 0 + Public Const CATEGORY_REFERENCES As Long = 1 ' always virtual; never in a file + Public Const CATEGORY_RESOURCES As Long = 2 + Public Const CATEGORY_SOURCES As Long = 3 + Public Const CATEGORY_SETTINGS As Long = 4 + Public Const CATEGORY_IMPORTED_TYPE_LIBRARIES As Long = 5 + Public Const CATEGORY_MISCELLANEOUS As Long = 6 + Public Const CATEGORY_PACKAGES As Long = 7 + + Private mBuf() As Byte + Private mLen As Long + Private mPos As Long + Private mEntryCount As Long + + ' The category a well-known name gets, at any depth: an embedded package's own Sources and + ' Settings carry them too. References is left out: the IDE makes it, and never stores it. + Public Function CategoryFor(ByVal name As String) As Long + Select Case name + Case "Resources": CategoryFor = CATEGORY_RESOURCES + Case "Sources": CategoryFor = CATEGORY_SOURCES + Case "Settings": CategoryFor = CATEGORY_SETTINGS + Case "ImportedTypeLibraries": CategoryFor = CATEGORY_IMPORTED_TYPE_LIBRARIES + Case "Miscellaneous": CategoryFor = CATEGORY_MISCELLANEOUS + Case "Packages": CategoryFor = CATEGORY_PACKAGES + Case Else: CategoryFor = CATEGORY_DEFAULT + End Select + End Function + + ' The tree in the first length bytes of b; raises FORMAT_ERROR for bytes that are not a project. + Public Function Parse(b() As Byte, ByVal length As Long) As Entry + Dim magicRead As Long + mBuf = b + mLen = length + mPos = 0 + mEntryCount = 0 + magicRead = ReadU32() + If magicRead <> MAGIC Then + Err.Raise FORMAT_ERROR, , "Bad magic: 0x" & Hex8(magicRead) & ", expected 0x" & Hex8(MAGIC) + End If + Set Parse = ReadEntry() + Erase mBuf + End Function + + Private Function ReadEntry() As Entry + Dim e As New Entry, kind As Integer, isRoot As Boolean, n As Long, i As Long, length As Long + ' At the root this field is the format version; everywhere else it is the entry's + ' kind, 1 for a file and 2 for a folder. + kind = ReadI16() + mEntryCount = mEntryCount + 1 + isRoot = mEntryCount = 1 + If isRoot And kind <> FORMAT_VERSION Then + Err.Raise FORMAT_ERROR, , "Unsupported file format version: " & kind & ", expected " & FORMAT_VERSION + End If + e.Name = ReadStr() + e.Revision = ReadU64() + e.Flags = ReadU32() + e.Category = ReadU8() + If kind = 1 And Not isRoot Then + e.IsFile = True + length = ReadU32() + Need length + e.SetContent mBuf, mPos, length + mPos = mPos + length + n = ReadU32() + For i = 1 To n + e.AddRevision ReadU32() + Next + Else + n = ReadU32() + For i = 1 To n + e.Children.Add ReadEntry() + Next + End If + Set ReadEntry = e + End Function + + Private Sub Need(ByVal count As Long) + If count < 0 Or mPos + count > mLen Then Err.Raise FORMAT_ERROR, , "the file ends too soon" + End Sub + + Private Function ReadU8() As Long + Need 1 + ReadU8 = mBuf(mPos) + mPos = mPos + 1 + End Function + + Private Function ReadI16() As Integer + Dim v As Integer + Need 2 + RtlMoveMemory VarPtr(v), VarPtr(mBuf(mPos)), 2 + ReadI16 = v + mPos = mPos + 2 + End Function + + Private Function ReadU32() As Long + Dim v As Long + Need 4 + RtlMoveMemory VarPtr(v), VarPtr(mBuf(mPos)), 4 + ReadU32 = v + mPos = mPos + 4 + End Function + + Private Function ReadU64() As LongLong + Dim v As LongLong + Need 8 + RtlMoveMemory VarPtr(v), VarPtr(mBuf(mPos)), 8 + ReadU64 = v + mPos = mPos + 8 + End Function + + Private Function ReadStr() As String + Dim length As Long + length = ReadU32() + Need length + ReadStr = TextKit.Utf8Decode(mBuf, mPos, length) + mPos = mPos + length + End Function + + Private Function Hex8(ByVal v As Long) As String + Hex8 = Right$("00000000" & Hex$(v), 8) + End Function + + ' The tree as the bytes of a project file, and their length. + Public Function Serialize(ByVal root As Entry, out() As Byte) As Long + Dim w As New ByteBuilder + w.AddU32 MAGIC + WriteEntry w, root, True + Serialize = w.ToArray(out) + End Function + + Private Sub WriteEntry(ByVal w As ByteBuilder, ByVal e As Entry, ByVal isRoot As Boolean) + Dim b() As Byte, n As Long, i As Long, child As Entry + If e.IsFile And Not isRoot Then + w.AddI16 1 + WriteStr w, e.Name + w.AddU64 e.Revision + w.AddU32 e.Flags + w.AddU8 e.Category + n = e.GetContent(b) + w.AddU32 n + w.AddRange b, 0, n + w.AddU32 e.RevisionCount + For i = 0 To e.RevisionCount - 1 + w.AddU32 e.RevisionAt(i) + Next + Else + ' The root writes the format version; any other folder its kind, 2. + If isRoot Then w.AddI16 FORMAT_VERSION Else w.AddI16 2 + WriteStr w, e.Name + w.AddU64 e.Revision + w.AddU32 e.Flags + w.AddU8 e.Category + w.AddU32 e.Children.Count + For Each child In e.Children + WriteEntry w, child, False + Next + End If + End Sub + + Private Sub WriteStr(ByVal w As ByteBuilder, ByVal s As String) + Dim b() As Byte, n As Long + n = TextKit.Utf8Encode(s, b) + w.AddU32 n + w.AddRange b, 0, n + End Sub + + ' A file entry as the IDE writes one: revision 2, no flags, no revision list. + Public Function NewFile(ByVal name As String, b() As Byte, ByVal length As Long) As Entry + Dim e As New Entry + e.IsFile = True + e.Name = name + e.Revision = 2 + e.Flags = FLAG_NONE + e.Category = CategoryFor(name) + e.SetContent b, 0, length + Set NewFile = e + End Function + + ' A folder entry as the IDE writes one: revision 0, no flags. + Public Function NewFolder(ByVal name As String) As Entry + Dim e As New Entry + e.Name = name + e.Revision = 0 + e.Flags = FLAG_NONE + e.Category = CategoryFor(name) + Set NewFolder = e + End Function +End Module diff --git a/scripts/impexp/src/Sources/SelfTest.twin b/scripts/impexp/src/Sources/SelfTest.twin new file mode 100644 index 000000000..83aa574eb --- /dev/null +++ b/scripts/impexp/src/Sources/SelfTest.twin @@ -0,0 +1,728 @@ +' The built-in tests: a port of selfTest in scripts/impexp.mjs, with the same tests in the same +' order, printing the same lines. Each test is a Sub; RunOne runs one, and reports a PASS, or a +' FAIL with the message of the error that ended it. A test leaves no error handler active, so a +' failed check ends it. +Module SelfTest + Private Const CHECK_FAILED As Long = vbObjectError + &H1200 + + Private mWork As String + Private mProj As String + Private mTree As String + Private mSample As String + Private mPassed As Long + Private mFailed As Long + + ' Runs every test, prints each result and the count, and returns 1 if one failed, else 0. + Public Function RunAll() As Long + Dim number As Long, description As String + mWork = FileSys.MakeTempFolder(FileSys.TempFolder() & "\impexp-test-") + MainModule.WriteOut "Self-test workdir: " & mWork + MainModule.WriteOut "" + mPassed = 0 + mFailed = 0 + + On Error Resume Next + RunSuite + number = Err.Number + description = Err.Description + On Error Resume Next + FileSys.RemovePath mWork + On Error GoTo 0 + If number <> 0 Then Err.Raise number, , description + + MainModule.WriteOut "" + MainModule.WriteOut mPassed & "/" & (mPassed + mFailed) & " tests passed." + If mFailed > 0 Then RunAll = 1 Else RunAll = 0 + End Function + + Private Sub RunSuite() + RunOne "Parse and serialize round-trip in memory", 1 + RunOne "Serializing is idempotent", 2 + RunOne "A damaged file is refused", 3 + + mProj = WriteTree(At("Probe.twinproj"), Probe()) + mTree = At("tree") + + RunOne "Export writes every file but .meta", 4 + RunOne "Import packs the folder, naming the root from Settings", 5 + RunOne "Import names the root after the folder when Settings has no name", 6 + RunOne "Import adds the empty folders the IDE expects, to the project and each package in it", 7 + RunOne "Export without --overwrite refuses, and writes nothing", 8 + RunOne "Export --overwrite replaces files and names the ones the project lacks", 9 + RunOne "Import without --overwrite refuses, and leaves the project alone", 10 + RunOne "Import refuses a folder with no Settings file", 11 + RunOne "Import skips .git and the project file itself", 12 + RunOne "Export refuses a name that would leave the folder", 13 + RunOne "Export writes the first of two entries with one name, and says so", 14 + RunOne "Import converts LF to CRLF in code files only", 15 + RunOne "The printing commands read the documents at the root", 16 + RunOne "A command line in the wrong shape is refused before anything is read", 17 + RunOne "The exit code says why a command failed, and that it warned", 18 + + ' The documentation repository's own sample, when run from a checkout. + mSample = FindSample() + If Len(mSample) = 0 Then + MainModule.WriteOut " [SKIP] sample.twinpack -- only in a checkout of the documentation repository" + Else + RunOne "Parse sample.twinpack", 19 + RunOne "sample.twinpack survives export, import and export again", 20 + End If + End Sub + + Private Sub RunOne(ByVal name As String, ByVal index As Long) + Dim message As String + On Error GoTo Failed + Select Case index + Case 1: RoundTripInMemory + Case 2: SerializingIsIdempotent + Case 3: DamagedFileIsRefused + Case 4: ExportWritesEveryFileButMeta + Case 5: ImportPacksTheFolder + Case 6: ImportNamesRootAfterFolder + Case 7: ImportAddsEmptyFolders + Case 8: ExportWithoutOverwriteRefuses + Case 9: ExportOverwriteReplaces + Case 10: ImportWithoutOverwriteRefuses + Case 11: ImportRefusesNoSettings + Case 12: ImportSkipsGitAndSelf + Case 13: ExportRefusesUnsafeNames + Case 14: ExportWritesFirstOfTwo + Case 15: ImportConvertsLineEndings + Case 16: PrintingCommandsReadDocuments + Case 17: CommandLineWrongShape + Case 18: ExitCodes + Case 19: ParseSample + Case 20: SampleSurvivesRoundTrip + End Select + MainModule.WriteOut " [PASS] " & name + mPassed = mPassed + 1 + Exit Sub + Failed: + message = Err.Description + MainModule.WriteOut " [FAIL] " & name + MainModule.WriteOut " " & message + mFailed = mFailed + 1 + End Sub + + ' ---------------------------------------------------------------- the tests + + Private Sub RoundTripInMemory() + Dim tree As Entry, back As Entry, b() As Byte, n As Long, hidden As Entry, backHidden As Entry + Dim i As Long, revs As String + Set tree = Probe() + Set hidden = tree.Children(1) + hidden.Flags = ProjectFormat.FLAG_HIDDEN Or ProjectFormat.FLAG_VIRTUAL + hidden.AddRevision 1 + hidden.AddRevision 2 + hidden.AddRevision 3 + n = ProjectFormat.Serialize(tree, b) + Set back = ProjectFormat.Parse(b, n) + EqS back.Name, "Probe", "root name" + EqS Listing(back), Listing(tree), "contents" + Set backHidden = back.Children(1) + EqN backHidden.Flags, ProjectFormat.FLAG_HIDDEN Or ProjectFormat.FLAG_VIRTUAL, "flags" + For i = 0 To backHidden.RevisionCount - 1 + If i > 0 Then revs = revs & "," + revs = revs & backHidden.RevisionAt(i) + Next + EqS revs, "1,2,3", "revision list" + End Sub + + Private Sub SerializingIsIdempotent() + Dim first() As Byte, second() As Byte, third() As Byte, n1 As Long, n2 As Long, n3 As Long + n1 = ProjectFormat.Serialize(Probe(), first) + n2 = ProjectFormat.Serialize(ProjectFormat.Parse(first, n1), second) + n3 = ProjectFormat.Serialize(ProjectFormat.Parse(second, n2), third) + EqN CompareBytes(second, n2, third, n3), 0, "second pass differs" + End Sub + + Private Sub DamagedFileIsRefused() + Dim good() As Byte, n As Long, junk() As Byte, nj As Long, none() As Byte + n = ProjectFormat.Serialize(Probe(), good) + nj = TextKit.Latin1Encode("not a project file", junk) + CheckDamaged "magic", junk, nj + CheckDamaged "short", good, n - 7 + CheckDamaged "empty", none, 0 + End Sub + + Private Sub CheckDamaged(ByVal name As String, data() As Byte, ByVal length As Long) + Dim p As String, number As Long, description As String + p = At("damaged", name & ".twinproj") + FileSys.MakeDirs FileSys.ParentOf(p) + FileSys.WriteAllBytes p, data, length + Err.Clear + On Error Resume Next + Impexp.ReadProject p + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "damaged or is not a project file", "invalid" + End Sub + + Private Sub ExportWritesEveryFileButMeta() + Dim r As Outcome + Set r = Impexp.ExportProject(mProj, mTree, False) + EqS Text(FileSys.JoinPath(mTree, "Settings")), SettingsText(), "Settings" + EqS Text(FileSys.JoinPath(mTree, "Sources", "Module1.twin")), "Module Module1" & vbCrLf & "End Module" & vbCrLf, "Module1.twin" + EqB Exists(FileSys.JoinPath(mTree, "Packages")), True, "empty folder" + EqB Exists(FileSys.JoinPath(mTree, ".meta")), False, ".meta" + EqS r.Files & " " & r.Folders & " " & r.Stale.Count, "5 6 0", "files, folders, stale" + End Sub + + Private Sub ImportPacksTheFolder() + Dim out As String, back As Entry, expected As Entry + out = At("Repacked.twinproj") + Impexp.ImportProject out, mTree, False + Set back = ParseFile(out) + EqS back.Name, "Probe", "root name" + EqN back.Category, ProjectFormat.CATEGORY_DEFAULT, "root category" + Set expected = Probe() + expected.Children.Remove 1 ' .meta + EqS Listing(back), Listing(expected), "contents" + EqN ChildNamed(back, "Sources").Category, ProjectFormat.CATEGORY_SOURCES, "Sources category" + End Sub + + Private Sub ImportNamesRootAfterFolder() + Dim bare As String, out As String + bare = At("bare", "MyTree") + FileSys.MakeDirs bare + WriteText FileSys.JoinPath(bare, "Settings"), "{}" + out = At("bare", "Bare.twinproj") + Impexp.ImportProject out, bare, False + EqS ParseFile(out).Name, "MyTree", "root name" + End Sub + + Private Sub ImportAddsEmptyFolders() + Dim src As String, d As Variant, r As Outcome, back As Entry, names() As String, n As Long + Dim keys As New Collection, vals As New Collection + src = At("bare", "Git") + For Each d In Array("resources", "Packages/Pkg", "Packages/Pkg/Sources", "Packages/NotPkg") + FileSys.MakeDirs FileSys.JoinPath(src, CStr(d)) + Next + WriteText FileSys.JoinPath(src, "Settings"), "{}" + WriteText FileSys.JoinPath(src, "Packages", "Pkg", "Settings"), "{}" + Set r = Impexp.ImportProject(At("bare", "Git.twinproj"), src, False) + EqS JoinC(r.Added), "ImportedTypeLibraries,Miscellaneous,Sources,Packages/Pkg/ImportedTypeLibraries,Packages/Pkg/Miscellaneous," & _ + "Packages/Pkg/Packages,Packages/Pkg/Resources", "added" + Set back = ParseFile(At("bare", "Git.twinproj")) + Walk back, "", keys, vals + EqS JoinC(keys), "ImportedTypeLibraries/,Miscellaneous/,Packages/,Packages/NotPkg/,Packages/Pkg/," & _ + "Packages/Pkg/ImportedTypeLibraries/,Packages/Pkg/Miscellaneous/,Packages/Pkg/Packages/," & _ + "Packages/Pkg/Resources/,Packages/Pkg/Sources/,Packages/Pkg/Settings,Sources/,resources/,Settings", "contents" + EqN ChildNamed(back, "Miscellaneous").Category, ProjectFormat.CATEGORY_MISCELLANEOUS, "category" + n = FileSys.ListNames(src, names) + TextKit.SortOrdinal names, n + EqS JoinA(names, n), "Packages,Settings,resources", "the tree on disk changed" + End Sub + + Private Sub ExportWithoutOverwriteRefuses() + Dim number As Long, description As String + FileSys.RemovePath FileSys.JoinPath(mTree, "Settings") + WriteText FileSys.JoinPath(mTree, "Sources", "Module1.twin"), "CHANGED" + Err.Clear + On Error Resume Next + Impexp.ExportProject mProj, mTree, False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "already exist", "exists" + EqB Exists(FileSys.JoinPath(mTree, "Settings")), False, "Settings written anyway" + EqS Text(FileSys.JoinPath(mTree, "Sources", "Module1.twin")), "CHANGED", "Module1.twin" + End Sub + + Private Sub ExportOverwriteReplaces() + Dim r As Outcome + WriteText FileSys.JoinPath(mTree, "Sources", "Stale.twin"), "Module Stale" & vbCrLf & "End Module" & vbCrLf + Set r = Impexp.ExportProject(mProj, mTree, True) + EqS Text(FileSys.JoinPath(mTree, "Sources", "Module1.twin")), "Module Module1" & vbCrLf & "End Module" & vbCrLf, "Module1.twin" + EqB Exists(FileSys.JoinPath(mTree, "Settings")), True, "Settings" + EqS JoinC(r.Stale), FileSys.JoinPath(mTree, "Sources", "Stale.twin"), "files the project lacks" + FileSys.RemovePath FileSys.JoinPath(mTree, "Sources", "Stale.twin") + End Sub + + Private Sub ImportWithoutOverwriteRefuses() + Dim before() As Byte, after() As Byte, nb As Long, na As Long, number As Long, description As String + nb = FileSys.ReadAllBytes(mProj, before) + Err.Clear + On Error Resume Next + Impexp.ImportProject mProj, mTree, False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "already exists", "exists" + na = FileSys.ReadAllBytes(mProj, after) + EqN CompareBytes(after, na, before, nb), 0, "project file changed" + End Sub + + Private Sub ImportRefusesNoSettings() + Dim noSettings As String, number As Long, description As String + noSettings = At("nosettings") + FileSys.MakeDirs noSettings + WriteText FileSys.JoinPath(noSettings, "Module1.twin"), "x" + + Err.Clear + On Error Resume Next + Impexp.ImportProject At("NoSettings.twinproj"), noSettings, False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "no Settings file", "invalid" + + Err.Clear + On Error Resume Next + Impexp.ImportProject At("Missing.twinproj"), At("missing"), False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "does not exist", "missing" + + EqB Exists(At("NoSettings.twinproj")), False, "a project file was written" + End Sub + + Private Sub ImportSkipsGitAndSelf() + Dim inside As String, r As Outcome, s As Variant, skipped As String, listed As String + FileSys.MakeDirs FileSys.JoinPath(mTree, ".git") + WriteText FileSys.JoinPath(mTree, ".git", "HEAD"), "ref: refs/heads/main" & vbLf + inside = FileSys.JoinPath(mTree, "Inside.twinproj") + Impexp.ImportProject inside, mTree, False + Set r = Impexp.ImportProject(inside, mTree, True) + listed = Listing(ParseFile(inside)) + EqB InStr(listed, ".git") > 0 Or InStr(listed, "Inside") > 0, False, "packed anyway" + For Each s In r.Skipped + If Len(skipped) > 0 Then skipped = skipped & "," + skipped = skipped & s(0) + Next + EqS skipped, ".git,Inside.twinproj", "skipped" + FileSys.RemovePath inside + FileSys.RemovePath FileSys.JoinPath(mTree, ".git") + End Sub + + Private Sub ExportRefusesUnsafeNames() + Dim bad As Variant, p As String, number As Long, description As String + For Each bad In Array("..", "a/b", "a\b", "C:x", "x.", "x ", "") + p = WriteTree(At("unsafe", "Unsafe.twinproj"), _ + D("Unsafe", F("Settings", "{}"), D("Sources", F(CStr(bad), "x")))) + Err.Clear + On Error Resume Next + Impexp.ExportProject p, At("unsafe", "out"), False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "cannot be written safely", "invalid" + Next + EqB Exists(At("unsafe", "out")), False, "something was written" + End Sub + + Private Sub ExportWritesFirstOfTwo() + Dim p As String, out As String, r As Outcome, clash As String, number As Long, description As String + p = WriteTree(At("twice", "Twice.twinproj"), _ + D("Twice", _ + F("Settings", "{}"), _ + D("Sources", F("A.twin", "first"), F("a.twin", "second"), F("B.twin", "first")), _ + D("Sources", F("B.twin", "second"), F("C.twin", "merged")))) + out = At("twice", "out") + Set r = Impexp.ExportProject(p, out, False) + EqS Text(FileSys.JoinPath(out, "Sources", "A.twin")), "first", "A.twin" + EqS Text(FileSys.JoinPath(out, "Sources", "B.twin")), "first", "B.twin" + EqS Text(FileSys.JoinPath(out, "Sources", "C.twin")), "merged", "C.twin" + EqS JoinC(r.Repeated), "Sources/A.twin,Sources/B.twin", "names reported" + clash = WriteTree(At("twice", "Clash.twinproj"), _ + D("Clash", F("Settings", "{}"), F("Sources", "x"), D("Sources"))) + Err.Clear + On Error Resume Next + Impexp.ExportProject clash, At("twice", "clash"), False + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "a file and a folder with the same name", "invalid" + End Sub + + Private Sub ImportConvertsLineEndings() + Dim rels As Variant, befores As Variant, afters As Variant, i As Long, src As String, p As String + Dim out As String, keys As New Collection, vals As New Collection + rels = Array("Settings", "Sources/Lf.twin", "Sources/Mixed.BAS", "Sources/Crlf.cls", "Sources/Form.tbform", "Resources/RCDATA/data.txt") + befores = Array("{" & vbLf & "}" & vbLf, "A" & vbLf & "B" & vbLf, "A" & vbCrLf & "B" & vbLf & "C", _ + "A" & vbCrLf & "B" & vbCrLf, "{" & vbLf & "}" & vbLf, "A" & vbLf & "B" & vbLf) + afters = Array("{" & vbLf & "}" & vbLf, "A" & vbCrLf & "B" & vbCrLf, "A" & vbCrLf & "B" & vbCrLf & "C", _ + "A" & vbCrLf & "B" & vbCrLf, "{" & vbLf & "}" & vbLf, "A" & vbLf & "B" & vbLf) + src = At("eol", "Eol") + For i = 0 To UBound(rels) + p = FileSys.JoinPath(src, CStr(rels(i))) + FileSys.MakeDirs FileSys.ParentOf(p) + WriteText p, CStr(befores(i)) + Next + out = At("eol", "Eol.twinproj") + Impexp.ImportProject out, src, False + Walk ParseFile(out), "", keys, vals + For i = 0 To UBound(rels) + EqS TextKit.JsonQuote(Lookup(keys, vals, CStr(rels(i)))), TextKit.JsonQuote(CStr(afters(i))), CStr(rels(i)) + Next + End Sub + + Private Sub PrintingCommandsReadDocuments() + Dim b() As Byte, n As Long, lower As String, number As Long, description As String + n = Impexp.ReadDocument(mProj, "readme", b) + EqS TextKit.Latin1Decode(b, n), "# Probe" & vbCrLf, "readme" + n = Impexp.ReadDocument(mProj, "settings", b) + EqS TextKit.Latin1Decode(b, n), SettingsText(), "settings" + + Err.Clear + On Error Resume Next + Impexp.ReadDocument mProj, "licence", b + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "has no LICENCE.md", "missing" + + lower = WriteTree(At("docs", "Lower.twinproj"), _ + D("Lower", F("changelog.MD", "log"), D("Sources", F("README.md", "not at the root")))) + n = Impexp.ReadDocument(lower, "changelog", b) + EqS TextKit.Latin1Decode(b, n), "log", "changelog, lower case" + + Err.Clear + On Error Resume Next + Impexp.ReadDocument lower, "readme", b + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "has no README.md", "missing" + End Sub + + Private Sub CommandLineWrongShape() + ' Each bad line is the verb and its arguments, in one list. + Dim bad As Variant, line As Variant + For Each bad In Array( _ + Array("export", "tree/", "P.twinproj"), _ + Array("import", "P.twinproj", "Q.twinpack"), _ + Array("import", "P.twinproj"), _ + Array("EXPORT", "P.twinproj", "tree"), _ + Array("license", "P.twinproj"), _ + Array("settings", "P.twinproj", "extra"), _ + Array()) + line = bad + EqB Len(MainModule.CommandLineError(WordsOf(line))) = 0, False, JoinV(line) + Next + EqS MainModule.CommandLineError(WordsOf(Array("export", "P.TWINPACK", "tree/"))), "", "export P.TWINPACK tree/" + EqS MainModule.CommandLineError(WordsOf(Array("readme", "P.twinproj"))), "", "readme P.twinproj" + End Sub + + Private Sub ExitCodes() + Dim number As Long, description As String, r As Outcome + EqS Impexp.EXIT_DONE & "," & Impexp.EXIT_FAILED & "," & Impexp.EXIT_USAGE & "," & Impexp.EXIT_EXISTS & "," & _ + Impexp.EXIT_MISSING & "," & Impexp.EXIT_INVALID & "," & Impexp.EXIT_WARNED, "0,1,2,3,4,5,6", "the documented codes" + + Err.Clear + On Error Resume Next + Impexp.ReadProject At("nowhere.twinproj") + number = Err.Number + description = Err.Description + On Error GoTo 0 + ExpectRefused number, description, "does not exist", "missing" + + Impexp.LastReason = "exists" + EqN Impexp.ExitCodeForError(Impexp.REFUSED), Impexp.EXIT_EXISTS, "a refusal" + EqN Impexp.ExitCodeForError(70001), Impexp.EXIT_FAILED, "any other error" + + Set r = New Outcome + r.Stale.Add "Sources/Old.twin" + EqN Impexp.ExitCodeForOutcome(r), Impexp.EXIT_WARNED, "a file the project lacks" + Set r = New Outcome + r.Repeated.Add "Sources/A.twin" + EqN Impexp.ExitCodeForOutcome(r), Impexp.EXIT_WARNED, "a repeated name" + Set r = New Outcome + r.Skipped.Add Array(".git", "Git's own folder") + EqN Impexp.ExitCodeForOutcome(r), Impexp.EXIT_DONE, "a skipped .git" + End Sub + + Private Sub ParseSample() + Dim b() As Byte, n As Long, root As Entry, fc As Long, dc As Long + n = FileSys.ReadAllBytes(mSample, b) + Set root = ProjectFormat.Parse(b, n) + EqS root.Name, "CustomControlsPackage", "root name" + CountTree root, fc, dc + EqN fc, 22, "file count" + EqN dc, 7, "dir count" + End Sub + + Private Sub SampleSurvivesRoundTrip() + Dim a As String, b As String, rt As String + a = At("sample", "a") + b = At("sample", "b") + rt = At("sample", "rt.twinpack") + Impexp.ExportProject mSample, a, False + Impexp.ImportProject rt, a, False + Impexp.ExportProject rt, b, False + EqB DiskListing(b) = DiskListing(a), True, "the two trees differ" + EqS ParseFile(rt).Name, "CustomControlsPackage", "root name" + End Sub + + ' ---------------------------------------------------------------- checks + + Private Sub Fail(ByVal message As String) + Err.Raise CHECK_FAILED, , message + End Sub + + Private Sub EqS(ByVal actual As String, ByVal expected As String, ByVal message As String) + If actual <> expected Then + Fail message & ": expected " & TextKit.JsonQuote(expected) & ", got " & TextKit.JsonQuote(actual) + End If + End Sub + + Private Sub EqN(ByVal actual As Double, ByVal expected As Double, ByVal message As String) + If actual <> expected Then Fail message & ": expected " & CStr(expected) & ", got " & CStr(actual) + End Sub + + Private Sub EqB(ByVal actual As Boolean, ByVal expected As Boolean, ByVal message As String) + If actual <> expected Then Fail message & ": expected " & JsonBool(expected) & ", got " & JsonBool(actual) + End Sub + + Private Function JsonBool(ByVal b As Boolean) As String + If b Then JsonBool = "true" Else JsonBool = "false" + End Function + + ' The call raised a refusal whose message holds the text and whose reason is the one given. + Private Sub ExpectRefused(ByVal number As Long, ByVal description As String, ByVal pattern As String, ByVal reason As String) + If number = 0 Then Fail "was not refused" + If number <> Impexp.REFUSED Then Fail "refused for the wrong reason: " & description + If InStr(description, pattern) = 0 Then Fail "refused for the wrong reason: " & description + If Impexp.LastReason <> reason Then + Fail "refused as " & TextKit.JsonQuote(Impexp.LastReason) & ", expected " & TextKit.JsonQuote(reason) & ": " & description + End If + End Sub + + ' ---------------------------------------------------------------- trees and files + + Private Function SettingsText() As String + SettingsText = "{" & vbCrLf & vbTab & """project.name"": ""Probe""" & vbCrLf & "}" & vbCrLf + End Function + + ' A file entry whose content is the text, one byte for each character. + Private Function F(ByVal name As String, ByVal content As String) As Entry + Dim none(0 To 0) As Byte, e As Entry + Set e = ProjectFormat.NewFile(name, none, 0) + e.SetContentLatin1 content + Set F = e + End Function + + ' A folder entry holding the entries given. + Private Function D(ByVal name As String, ParamArray children() As Variant) As Entry + Dim e As Entry, i As Long + Set e = ProjectFormat.NewFolder(name) + For i = LBound(children) To UBound(children) + e.Children.Add children(i) + Next + Set D = e + End Function + + ' A small project in the shape the IDE writes. + Private Function Probe() As Entry + Set Probe = D("Probe", _ + F(".meta", "{""rootFolder"": ""/Probe""}"), _ + D("ImportedTypeLibraries"), _ + D("Miscellaneous"), _ + D("Packages"), _ + F("README.md", "# Probe" & vbCrLf), _ + D("Resources", D("ICON", F("app.ico", ChrW$(0) & ChrW$(1) & vbCrLf & ChrW$(2) & vbLf))), _ + F("Settings", SettingsText()), _ + D("Sources", F("Form1.tbform", "{" & vbLf & "}" & vbLf), F("Module1.twin", "Module Module1" & vbCrLf & "End Module" & vbCrLf))) + End Function + + ' A path in the work folder. + Private Function At(ByVal a As String, Optional ByVal b As String = "", Optional ByVal c As String = "") As String + At = FileSys.JoinPath(mWork, a, b, c) + End Function + + ' Writes the tree as a project file at p, and returns p. + Private Function WriteTree(ByVal p As String, ByVal tree As Entry) As String + Dim b() As Byte, n As Long + FileSys.MakeDirs FileSys.ParentOf(p) + n = ProjectFormat.Serialize(tree, b) + FileSys.WriteAllBytes p, b, n + WriteTree = p + End Function + + Private Function ParseFile(ByVal p As String) As Entry + Dim b() As Byte, n As Long + n = FileSys.ReadAllBytes(p, b) + Set ParseFile = ProjectFormat.Parse(b, n) + End Function + + Private Function Text(ByVal p As String) As String + Dim b() As Byte, n As Long + n = FileSys.ReadAllBytes(p, b) + Text = TextKit.Latin1Decode(b, n) + End Function + + Private Sub WriteText(ByVal p As String, ByVal s As String) + Dim b() As Byte, n As Long + n = TextKit.Latin1Encode(s, b) + FileSys.WriteAllBytes p, b, n + End Sub + + Private Function Exists(ByVal p As String) As Boolean + Exists = FileSys.KindOf(p) <> FileSys.KIND_NONE + End Function + + Private Function ChildNamed(ByVal e As Entry, ByVal name As String) As Entry + Dim c As Entry + For Each c In e.Children + If c.Name = name Then + Set ChildNamed = c + Exit Function + End If + Next + Fail "no entry named " & name + End Function + + ' 0 when the first na bytes of a are the first nb bytes of b, else -1 or 1. + Private Function CompareBytes(a() As Byte, ByVal na As Long, b() As Byte, ByVal nb As Long) As Long + Dim i As Long, n As Long + n = na + If nb < n Then n = nb + For i = 0 To n - 1 + If a(i) <> b(i) Then + If a(i) < b(i) Then CompareBytes = -1 Else CompareBytes = 1 + Exit Function + End If + Next + If na < nb Then + CompareBytes = -1 + ElseIf na > nb Then + CompareBytes = 1 + End If + End Function + + ' Every entry of the tree by its path, the root's name left out, in walk order: a folder as + ' its path and a slash, with an empty value, and a file with its content as text. + Private Sub Walk(ByVal e As Entry, ByVal rel As String, ByVal keys As Collection, ByVal vals As Collection) + Dim c As Entry, r As String + For Each c In e.Children + If Len(rel) > 0 Then r = rel & "/" & c.Name Else r = c.Name + If c.IsFile Then + keys.Add r + vals.Add c.ContentLatin1() + Else + keys.Add r & "/" + vals.Add "" + Walk c, r, keys, vals + End If + Next + End Sub + + Private Function Lookup(ByVal keys As Collection, ByVal vals As Collection, ByVal key As String) As String + Dim i As Long + For i = 1 To keys.Count + If keys(i) = key Then + Lookup = vals(i) + Exit Function + End If + Next + End Function + + ' The tree's contents as one string that does not depend on the order of the entries. + Private Function Listing(ByVal tree As Entry) As String + Dim keys As New Collection, vals As New Collection, items() As String, i As Long, n As Long + Walk tree, "", keys, vals + n = keys.Count + If n = 0 Then Exit Function + ReDim items(0 To n - 1) + For i = 1 To n + items(i - 1) = TextKit.JsonQuote(keys(i)) & ":" & TextKit.JsonQuote(vals(i)) + Next + TextKit.SortOrdinal items, n + Listing = JoinA(items, n) + End Function + + ' Every folder and file under d in name order, a file with its content. + Private Function DiskListing(ByVal d As String) As String + Dim lines As New Collection + DiskWalk d, "", lines + DiskListing = JoinC(lines, vbLf) + End Function + + Private Sub DiskWalk(ByVal p As String, ByVal rel As String, ByVal lines As Collection) + Dim names() As String, n As Long, i As Long, full As String, r As String + n = FileSys.ListNames(p, names) + TextKit.SortOrdinal names, n + For i = 0 To n - 1 + full = FileSys.JoinPath(p, names(i)) + If Len(rel) > 0 Then r = rel & "/" & names(i) Else r = names(i) + If FileSys.KindOf(full) = FileSys.KIND_FOLDER Then + lines.Add r & "/" + DiskWalk full, r, lines + Else + lines.Add r & "=" & Text(full) + End If + Next + End Sub + + Private Sub CountTree(ByVal e As Entry, ByRef files As Long, ByRef folders As Long) + Dim c As Entry + For Each c In e.Children + If c.IsFile Then + files = files + 1 + Else + folders = folders + 1 + CountTree c, files, folders + End If + Next + End Sub + + ' The first folder up from where the program is, or from where it was started, that holds + ' indexer\sample.twinpack; "" when none does. + Private Function FindSample() As String + FindSample = SearchUp(App.Path) + If Len(FindSample) = 0 Then FindSample = SearchUp(FileSys.CurrentDirectory()) + End Function + + Private Function SearchUp(ByVal start As String) As String + Dim d As String, candidate As String, parent As String + If Len(start) = 0 Then Exit Function + d = FileSys.FullPath(start) + Do While Len(d) > 0 + candidate = FileSys.JoinPath(d, "indexer", "sample.twinpack") + If FileSys.KindOf(candidate) = FileSys.KIND_FILE Then + SearchUp = candidate + Exit Function + End If + parent = FileSys.ParentOf(d) + If Len(parent) = 0 Or parent = d Then Exit Do + d = parent + Loop + End Function + + ' ---------------------------------------------------------------- lists as text + + Private Function JoinC(ByVal c As Collection, Optional ByVal separator As String = ",") As String + Dim i As Long + For i = 1 To c.Count + If i > 1 Then JoinC = JoinC & separator + JoinC = JoinC & c(i) + Next + End Function + + Private Function JoinA(items() As String, ByVal count As Long, Optional ByVal separator As String = ",") As String + Dim i As Long + For i = 0 To count - 1 + If i > 0 Then JoinA = JoinA & separator + JoinA = JoinA & items(i) + Next + End Function + + Private Function JoinV(ByVal items As Variant) As String + Dim i As Long + For i = LBound(items) To UBound(items) + If i > LBound(items) Then JoinV = JoinV & " " + JoinV = JoinV & items(i) + Next + End Function + + ' The command line's words, the verb first, as a Collection. + Private Function WordsOf(ByVal items As Variant) As Collection + Dim r As New Collection, i As Long + For i = LBound(items) To UBound(items) + r.Add CStr(items(i)) + Next + Set WordsOf = r + End Function +End Module diff --git a/scripts/impexp/src/Sources/TextKit.twin b/scripts/impexp/src/Sources/TextKit.twin new file mode 100644 index 000000000..3222155b0 --- /dev/null +++ b/scripts/impexp/src/Sources/TextKit.twin @@ -0,0 +1,124 @@ +' Text helpers: UTF-8, Latin-1, ordinal order and sorting, and JSON's quoting of a string. +Module TextKit + Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As LongPtr, ByVal cbMultiByte As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long) As Long + Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long, ByVal lpMultiByteStr As LongPtr, ByVal cbMultiByte As Long, ByVal lpDefaultChar As LongPtr, ByVal lpUsedDefaultChar As LongPtr) As Long + + Private Const CP_UTF8 As Long = 65001 + + ' b[start, start + length) as UTF-8; an invalid sequence gives U+FFFD, as TextDecoder gives it. + Public Function Utf8Decode(b() As Byte, ByVal start As Long, ByVal length As Long) As String + Dim n As Long, s As String + If length <= 0 Then Exit Function + n = MultiByteToWideChar(CP_UTF8, 0, VarPtr(b(start)), length, 0, 0) + s = String$(n, vbNullChar) + MultiByteToWideChar CP_UTF8, 0, VarPtr(b(start)), length, StrPtr(s), n + Utf8Decode = s + End Function + + ' The text as UTF-8 into out, and its length. + Public Function Utf8Encode(ByVal s As String, out() As Byte) As Long + Dim n As Long + Erase out + If Len(s) = 0 Then Exit Function + n = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0) + ReDim out(0 To n - 1) + WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(out(0)), n, 0, 0 + Utf8Encode = n + End Function + + ' Each byte as the character of that code, as Buffer's toString("latin1") gives it. + Public Function Latin1Decode(b() As Byte, ByVal length As Long) As String + Dim i As Long, s As String + If length <= 0 Then Exit Function + s = String$(length, vbNullChar) + For i = 0 To length - 1 + Mid$(s, i + 1, 1) = ChrW$(b(i)) + Next + Latin1Decode = s + End Function + + ' The low byte of each character, as Buffer.from(s, "latin1") gives it. + Public Function Latin1Encode(ByVal s As String, out() As Byte) As Long + Dim i As Long + Erase out + If Len(s) = 0 Then Exit Function + ReDim out(0 To Len(s) - 1) + For i = 1 To Len(s) + out(i - 1) = AscW(Mid$(s, i, 1)) And &HFF + Next + Latin1Encode = Len(s) + End Function + + ' -1, 0 or 1 by UTF-16 code unit, as JavaScript's < compares two strings. + Public Function CompareOrdinal(ByVal a As String, ByVal b As String) As Long + Dim i As Long, n As Long, ca As Long, cb As Long + n = Len(a) + If Len(b) < n Then n = Len(b) + For i = 1 To n + ca = AscW(Mid$(a, i, 1)) And &HFFFF& + cb = AscW(Mid$(b, i, 1)) And &HFFFF& + If ca <> cb Then + If ca < cb Then CompareOrdinal = -1 Else CompareOrdinal = 1 + Exit Function + End If + Next + If Len(a) < Len(b) Then + CompareOrdinal = -1 + ElseIf Len(a) > Len(b) Then + CompareOrdinal = 1 + End If + End Function + + ' Sorts items(0 To count - 1) by CompareOrdinal; equal items keep their order. + Public Sub SortOrdinal(items() As String, ByVal count As Long) + Dim i As Long, j As Long, v As String + For i = 1 To count - 1 + v = items(i) + j = i - 1 + Do While j >= 0 + If CompareOrdinal(items(j), v) <= 0 Then Exit Do + items(j + 1) = items(j) + j = j - 1 + Loop + items(j + 1) = v + Next + End Sub + + ' The string as JSON.stringify writes it. + Public Function JsonQuote(ByVal s As String) As String + Dim i As Long, c As Long, r As String, nextC As Long, prevC As Long + r = """" + For i = 1 To Len(s) + c = AscW(Mid$(s, i, 1)) And &HFFFF& + Select Case c + Case 34: r = r & "\""" + Case 92: r = r & "\\" + Case 8: r = r & "\b" + Case 9: r = r & "\t" + Case 10: r = r & "\n" + Case 12: r = r & "\f" + Case 13: r = r & "\r" + Case Is < 32: r = r & "\u" & LCase$(Right$("000" & Hex$(c), 4)) + Case &HD800& To &HDBFF& + nextC = 0 + If i < Len(s) Then nextC = AscW(Mid$(s, i + 1, 1)) And &HFFFF& + If nextC >= &HDC00& And nextC <= &HDFFF& Then + r = r & Mid$(s, i, 2) + i = i + 1 + Else + r = r & "\u" & LCase$(Hex$(c)) + End If + Case &HDC00& To &HDFFF& + r = r & "\u" & LCase$(Hex$(c)) + Case Else: r = r & ChrW$(c) + End Select + Next + JsonQuote = r & """" + End Function + + ' n and the noun, plural unless n is 1. + Public Function Count(ByVal n As Long, ByVal noun As String) As String + Count = n & " " & noun + If n <> 1 Then Count = Count & "s" + End Function +End Module diff --git a/scripts/lib/attribute-probe-kit.mjs b/scripts/lib/attribute-probe-kit.mjs index 089bb79a8..5f5a1317e 100644 --- a/scripts/lib/attribute-probe-kit.mjs +++ b/scripts/lib/attribute-probe-kit.mjs @@ -42,7 +42,7 @@ export const FIXED_ARGS = { // // The image and .json those two point at are written into the tree beside the // probes (writeProbeResources), and the factory into `_ProbeFactory.twin`. - // All five probes build clean on BETA 983. + // All five probes build clean on BETA 1005. // // Qualified, because the documented shape is "fully qualified path to factory // method" and that is the claim under test. VBRUN uses the bare form too. diff --git a/scripts/lib/attribute-sites.mjs b/scripts/lib/attribute-sites.mjs index 363cc7f12..7f25a87f1 100644 --- a/scripts/lib/attribute-sites.mjs +++ b/scripts/lib/attribute-sites.mjs @@ -66,7 +66,7 @@ const SITES = [ // its own line, because packages write it either way and both are legal. // // The Enum member is written ONLY on its own line, and that site is voided by - // the sweep. Measured on BETA 987: inline, the compiler refuses every + // the sweep. On BETA 1005: inline, the compiler refuses every // attribute, [Hidden] included (TB5182), though Attributes.md documents // [Hidden] on an Enum member; on its own line it accepts ANY `[...]`, // `[ClassId("guid")]` and `[Hidden(True)]` among them, because an Enum body diff --git a/scripts/lib/attribute-sweep.mjs b/scripts/lib/attribute-sweep.mjs index 7a2666dfd..4d015ea52 100644 --- a/scripts/lib/attribute-sweep.mjs +++ b/scripts/lib/attribute-sweep.mjs @@ -18,7 +18,7 @@ export const CONTROL_NAME = "ZzNoSuchAttributeProbe"; // What each canary MUST draw, fixed here rather than read from a build (see 3 in // sweep_attributes.mjs's header). `unknown` is what an invented name draws; -// recorded from BETA 983 (WIP.Harness.md) and re-checked by the canary-only build +// recorded from BETA 1005 (WIP.Harness.md) and re-checked by the canary-only build // before every run. export const CANARY_SPECS = [ ["clean", "MODULE", '[Description("canary")]'], @@ -33,7 +33,7 @@ export const canaryOk = (c) => Object.keys(EXPECTED_CANARIES).every((k) => c[k] * The compiler's token table: one long pipe-separated string in the compiler * binary, holding keywords, attributes and object members together. A name in it * is a name the compiler KNOWS, not one it accepts as an attribute -- `Debug` - * and `ExecuteHostCommand` are in it, and neither is one -- so these are + * and `PSet` are in it, and neither is one -- so these are * candidates, and a candidate is called an attribute only if some site accepts it. * * @param {string} s the compiler binary read as latin1 text @@ -466,7 +466,7 @@ export function judgePreflight(baselines, controls, outcomeOf) { controlSig.set(p.site.id, signature(o.codes, o.msgs, CONTROL_NAME)); // A site whose control compiles cannot tell an attribute from something else: // an Enum body takes ANY own-line `[...]`, `[ClassId("guid")]` included, as - // measured on BETA 987. It is voided rather than read. + // on BETA 1005. It is voided rather than read. if (!voidSites.has(p.site.id) && (firm(o.state) || inconclusive(o.state))) { voidSites.set( p.site.id, diff --git a/scripts/lib/cli-cases.mjs b/scripts/lib/cli-cases.mjs index 53303b739..134284653 100644 --- a/scripts/lib/cli-cases.mjs +++ b/scripts/lib/cli-cases.mjs @@ -411,7 +411,6 @@ const HELP_TOOLS = { "scripts/pick_a11y_sample.mjs": null, "scripts/probe_build_twice.mjs": null, "scripts/probe_ide_image_labels.mjs": null, - "scripts/probe_shared_temp.mjs": null, "scripts/probe_theme_semicolon.mjs": null, "scripts/survey_tooling.mjs": null, "scripts/sweep_a11y.mjs": null, @@ -495,7 +494,6 @@ const REFUSALS = { "scripts/pick_a11y_sample.mjs": ["sweep"], "scripts/probe_build_twice.mjs": ["ide"], "scripts/probe_ide_image_labels.mjs": ["ide"], - "scripts/probe_shared_temp.mjs": ["ide"], "scripts/probe_theme_semicolon.mjs": ["ide"], "scripts/survey_tooling.mjs": ["root"], "scripts/sweep_a11y.mjs": ["out"], diff --git a/scripts/lib/example-batches.mjs b/scripts/lib/example-batches.mjs index e15ad95ca..32beed510 100644 --- a/scripts/lib/example-batches.mjs +++ b/scripts/lib/example-batches.mjs @@ -352,7 +352,7 @@ export function makeBatches(fences, { batchSize = DEFAULT_BATCH, jobs = DEFAULT_ // diagnostics at all. // // The canary is a #Warning directive, TB0005, on a module that enforces it. -// Measured on BETA 987, it was reported beside samples with an unterminated +// On BETA 1005 it is reported beside samples with an unterminated // Sub, an If with no End If, a stray End Sub and garbage, a class that inherits // itself, and ten undefined names; under Option Explicit off; in a project that // ignores TB0005 or makes it an error, where [EnforceWarnings(TB0005)] keeps it @@ -639,9 +639,7 @@ async function isolateCrash(batch, named, lane, failed = false, detail = "") { * compile. * * A build can fail once and pass when repeated: one that reported nothing for - * 120 s, once in a full --llvm run (BETA 995). Lanes whose IDEs shared a temp - * folder failed with "[LINKER] FAILED to create type library" too, which - * launchIde's folder per IDE prevents. A failure is believed only if the same + * 120 s, once in a full --llvm run. A failure is believed only if the same * batch fails twice running, and so is each part the halving that follows builds. */ async function buildTwiceOnFailure(batch, lane) { @@ -1520,6 +1518,11 @@ export async function runProbes(say) { ["an empty Output block", "Debug.Print 1\n' Output:\n", "true:"], ["no expectations", "Dim x As Long\nx = 1\nDebug.Print x\n", "false:"], ["a comment that says Output but is not a header", "' Output: 5\nDebug.Print 5\n", "false:"], + ["a note after the value", "Debug.Print Err.Number ' 0 -- nothing left in Err\n", "true:11=0"], + ["a note after ---, and only the first dash ends the value", "Debug.Print 4 ' 4 --- a -- b\n", "true:11=4"], + ["a dash with no space after it is part of the value", 'Debug.Print "a --b" \' a --b\n', "true:11=a --b"], + ["a comment that is only a note states nothing", "Debug.Print 1 ' -- the count\n", "false:"], + ["an Output block keeps a dash", "Debug.Print \"a -- b\"\n' Output:\n' a -- b\n", "true:13=a -- b"], ]) { const got = shape(said(content)); expect(got === want, `expected output: ${name} -> ${got}, want ${want}`); @@ -1538,6 +1541,7 @@ export async function runProbes(say) { ["too many lines", "Debug.Print 1 ' 1\n", [" 1", " 2"], "null:prints 2 line(s), the page states 1"], ["nothing stated, anything printed", "Debug.Print 1\n", [" 1", " 2"], ""], ["an Output block that is not met", "Debug.Print 7\n' Output:\n' 8\n", [" 7"], '13:prints "7", the page says "8"'], + ["a note is not compared", "Debug.Print 0 ' 0 -- nothing left\n", [" 0"], ""], ]) { const got = sayOf(content, output).join(";"); expect(got === want, `judged output: ${name} -> ${got}, want ${want}`); diff --git a/scripts/lib/example-run.mjs b/scripts/lib/example-run.mjs index 9ec077f18..2f43365de 100644 --- a/scripts/lib/example-run.mjs +++ b/scripts/lib/example-run.mjs @@ -113,6 +113,9 @@ export function partitionRun(selected) { // --------------------------------------------------------------------- output +/** Where a note starts in a `Debug.Print` line's trailing comment: ` -- ` or ` --- `. */ +const NOTE = /\s---?\s/; + /** The `'` that starts a comment: the first one outside a string literal (`""` escapes). */ function splitComment(line) { let inString = false; @@ -133,6 +136,11 @@ function splitComment(line) { * trailing comment states nothing. When anything is stated, the output has * exactly that many lines. * + * A trailing comment may go on after its value with a note for the reader: + * the value ends at the first ` -- ` or ` --- `, and the note is not compared + * (`' 0 -- nothing left in Err`). The lines of an `' Output:` block are taken + * whole, so output that holds such a dash is stated there. + * * @returns {{stated: boolean, lines: {text: string, line: number}[]}} * `line` is where the expected line is on the page */ @@ -156,7 +164,8 @@ export function expectedOutput(fence) { rows.forEach((row, i) => { const { code, comment } = splitComment(row); if (comment === null || !/^\s*Debug\s*\.\s*Print\b/i.test(code)) return; - if (comment.trim()) lines.push({ text: comment.trim(), line: pageLine(i) }); + const value = comment.split(NOTE)[0].trim(); + if (value) lines.push({ text: value, line: pageLine(i) }); }); return { stated: lines.length > 0, lines }; } @@ -206,7 +215,7 @@ export function judgeOutput(expected, output) { * raised it. The handler is reached only by an error the sample did not handle. * Testing `Err.Number` after the call would not do: a procedure that handles an * error with `On Error Resume Next` returns with `Err` still set, in VB6 and in - * twinBASIC alike (measured, BETA 995), so a sample that demonstrates an error + * twinBASIC alike (BETA 1005), so a sample that demonstrates an error * would be reported as raising it. The first statement is `Debug.Cls`, which * erases the IDE's own build log from the console, so what is left is the * dispatcher's. diff --git a/scripts/lib/tb-ide-addins.mjs b/scripts/lib/tb-ide-addins.mjs index b3a27c51c..f24cf4c88 100644 --- a/scripts/lib/tb-ide-addins.mjs +++ b/scripts/lib/tb-ide-addins.mjs @@ -26,7 +26,7 @@ export const loadedAddins = (c) => * from, besides the install's own: the page's commonFolderRootPath, with its * trailing backslash. Null when the page has none. * - * Measured on BETA 983 (P6 in WIP.HelpAddin.md). The page makes it at startup + * Measured (P6 in WIP.HelpAddin.md). The page makes it at startup * by expanding "%APPDATA%\twinBASIC" in the IDE's own environment, and sends it * with RequestLoadAddins; the compiler loads from what it is sent, not from its * own %APPDATA%. So an IDE started with APPDATA naming another folder loads diff --git a/scripts/lib/tb-ide-console.mjs b/scripts/lib/tb-ide-console.mjs index 260da1123..6fb39ed58 100644 --- a/scripts/lib/tb-ide-console.mjs +++ b/scripts/lib/tb-ide-console.mjs @@ -33,7 +33,7 @@ // costs a comparison and removes a silent-corruption mode. // // An entry's text is stored escaped: an add-in's PrintText of "©=1" -// is stored as "<b>&copy=1" (measured, BETA 983), so decoding gives +// is stored as "<b>&copy=1" (measured), so decoding gives // back exactly what was printed, markup and ampersands included. Except for // the IDE's own bug (twinbasic/twinbasic#2444): text that continues a line left open // by `Debug.Print ...;` is escaped twice, so the console shows "&" for @@ -133,7 +133,7 @@ export async function linesSince(c, mark = null, { prefix } = {}) { } // What each clear erased. The page's global clearDebugConsole() empties the -// console, and BETA 983's main.js calls it by name from the compiler's +// console, and BETA 1005's main.js calls it by name from the compiler's // event_clearDebugConsole, which a program's Debug.Cls raises, from the pane's // Clear command, and on closing the project. So a wrapper assigned to that // global sees each of those clears, and reads the console as readConsole does, diff --git a/scripts/lib/tb-ide.mjs b/scripts/lib/tb-ide.mjs index 087da6dae..8ca6907e3 100644 --- a/scripts/lib/tb-ide.mjs +++ b/scripts/lib/tb-ide.mjs @@ -33,7 +33,7 @@ export const normPath = (p) => p.split("\\").join("/").toLowerCase(); * * launchIde sets it to "1" for every IDE the harness starts, tbbuild's and * tbrun's included: any of them can load an add-in the user has installed, - * and none has anybody watching it. Measured on BETA 983 (P10): it reaches the + * and none has anybody watching it. Measured (P10): it reaches the * compiler, twinBASIC_win32_noDEP.exe, which the IDE starts as its own child, * and every add-in that compiler loads, including after the compiler restarts. */ @@ -146,10 +146,8 @@ export async function launchIde({ exe, project, port, show = false, keep = false } const exeWin = exe.split("/").join("\\"); const target = project ? path.resolve(project).split("/").join("\\") : ""; - // Each IDE has a temp folder of its own, emptied at each launch on its port. - // Builds sharing one fail now and then with `[TYPELIB] failed to finalize - // typelibrary. Disk error?`: 0 in 192 with a folder per IDE, 8 in 192 with - // one for all eight at once (BETA 995). + // Each IDE has a temp folder of its own, emptied at each launch on its port + // and removed when the IDE ends (shutdownIde). const ideTemp = path.join(process.env.TEMP, `tbbuild-tmp-${port}`); // The WebView2 profile, 28 MB once the IDE has run. Emptied here as well, for // what a run that was killed left behind, and removed when the IDE ends @@ -263,6 +261,7 @@ const BOOTSTRAP = "$s = $env:TBBUILD_SCRIPT; Remove-Item Env:TBBUILD_SCRIPT; & ( * @param {object} o.env its whole environment * @param {string[]} [o.args] more arguments, after `arg`, for a program that takes * several; quoted as the C runtime reads them + * @param {string} [o.cwd] its working folder; the program's own folder when left out * @param {string} [o.stdout] a file path: the program's standard output goes there * @param {string} [o.stderr] the same for standard error. With either, the program's * standard input is the null device, and an output left @@ -277,7 +276,7 @@ const BOOTSTRAP = "$s = $env:TBBUILD_SCRIPT; Remove-Item Env:TBBUILD_SCRIPT; & ( * opened (empty without `dialogs`). Throws, with the launcher's error, when * the program did not start. */ -export async function launchOnDesktop({ exe, arg = "", args, desktop, job = true, env, stdout, stderr, dialogs }) { +export async function launchOnDesktop({ exe, arg = "", args, desktop, job = true, env, cwd, stdout, stderr, dialogs }) { const script = readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "tb-launch.ps1"), "utf8"); // -EncodedCommand is UTF-16 in base64, 2.7 characters to each of the script's, // and a command line stops at 32,767: the script outgrew that at about 12,000 @@ -304,6 +303,7 @@ export async function launchOnDesktop({ exe, arg = "", args, desktop, job = true TBBUILD_ARGS: args?.length ? args.map(quoteArg).join(" ") : undefined, TBBUILD_DESKTOP: desktop, TBBUILD_JOB: job ? "1" : "0", + TBBUILD_CWD: cwd || undefined, TBBUILD_STDOUT: stdout || undefined, TBBUILD_STDERR: stderr || undefined, TBBUILD_DIALOGS: dialogs || undefined, @@ -548,7 +548,7 @@ export function waitForExit(pid, timeoutMs) { * * The connection records and dismisses every javascript dialog the page opens, * in `c.dialogs` as `{type, message, at}`. The IDE calls `alert()` from 37 - * places in BETA 983, and never `confirm()` or `prompt()`. An alert blocks the + * places in BETA 1005 (main.js and main2.js), and never `confirm()` or `prompt()`. An alert blocks the * page until it is answered, which on a private desktop nobody can do: every * later call on the connection would time out. An alert is accepted, since it has only the * one button; a confirm or a prompt, which only an add-in could open, is @@ -1056,7 +1056,7 @@ const TARGET_JS = `(() => { * changedActiveBuildConfig, saves the target for the project's path and calls * restartCompilerSafely, which kills the compiler; the new one is the target's * own, twinBASIC_win64_noDEP.exe for win64, and it compiles the project again. - * Measured on BETA 983: the status bar stays OPERATIONAL for about 250 ms + * Measured: the status bar stays OPERATIONAL for about 250 ms * after the switch, and is down for about a second after that until the new * compiler's pid appears. waitForCompile started straight away can count that * as the compiler going down twice and report a crash, so the restart is waited @@ -1121,13 +1121,13 @@ export async function awaitNewCompiler(c, before, { why = "restarting it", timeo } } -// The build log, in the compiler's own words (its strings, BETA 983). A build +// The build log, in the compiler's own words (its strings, BETA 1005). A build // writes "[BUILD] Starting..." to the DEBUG CONSOLE, and a binary ends with // "[LINKER] SUCCESS created output file ''" or with one of some twenty // failure lines: "[LINKER] FAILED ...", "[BUILD] FAILED ...", "[BUILD] ERROR // ...", "[BUILD] failed" and "[LINKER] compilation (codegen) error ...". // A package writes "[BUILD] Creating TWINPACK file ''" and then -// "[BUILD] successful." (BETA 995); it fails with "[BUILD] FAILED to create +// "[BUILD] successful."; it fails with "[BUILD] FAILED to create // output file", "[BUILD] FAILED to write to output file" or "[BUILD] failed". // The success line is matched whole: "[BUILD] successfully built Fusion server // file" is another line. @@ -1137,10 +1137,10 @@ const PACKAGE_FILE = /^\[BUILD\] Creating TWINPACK file '(.+)'$/; const PACKAGE_OK = "[BUILD] successful."; // The last is LLVM's refusal of a procedure, which has no bracketed prefix: // "LLVM compilation error in 'Probe.Stopper': Unable to compile due to use of -// datatype that is not yet supported for LLVM compilation" (BETA 983). +// datatype that is not yet supported for LLVM compilation" (BETA 1005). export const BUILD_FAILED = /^\[(?:LINKER|BUILD)\] (?:FAILED|ERROR|failed)\b|^\[LINKER\] compilation \(codegen\) error|^LLVM compilation error in /; -// A compiler that crashes while building -- measured under LLVM, BETA 995 -- +// A compiler that crashes while building -- as one did under LLVM -- // writes "