tbIDE Package
The tbIDE package is the addin SDK for the twinBASIC IDE. An addin is a Standard DLL that the IDE loads at start-up; the DLL exports one factory function, returns one object implementing the AddIn contract, and from there everything happens through the Host object the IDE passes in. The package itself is type-only — every public symbol is an interface or a CoClass; the actual implementations live in the twinBASIC IDE binary, and the addin DLL binds against the type declarations and lets the IDE marshal calls into its implementations at run time.
The package is a built-in compiler package shipped with twinBASIC. It is added to addin projects automatically; you do not need to add it manually through Project → References.
- Building and loading an addin
- The class catalogue
- Dynamic DOM property resolution
- Tool-window DOM tags
- Where the samples live
Building and loading an addin
An addin project has three distinguishing settings:
- Build type: Standard DLL.
- Build path:
${IdePath}\addins\${Architecture}\${ProjectName}.${FileExtension}. The output drops directly into the IDE’saddins\Win32\oraddins\Win64\folder, where the IDE scans for addins on start-up. - Compiler-package reference to tbIDE (added to the project’s references with
isCompilerPackage: true,publisher: TWINBASIC-COMPILER,symbolId: tbIDE). This is the binding between the DLL’s compile-time types and the IDE’s run-time implementations.
The DLL must export one function — the entry point the IDE calls when it discovers and loads the addin:
Module MainModule
[DllExport]
Public Function tbCreateCompilerAddin(ByVal Host As Host) As AddIn
Return New MyAddIn(Host)
End Function
End Module
The returned object must implement AddIn. The IDE releases the object when the addin is disabled or the IDE shuts down, which lets the addin clean up through Class_Terminate.
A minimal addin class:
Private Class MyAddIn
Implements AddIn
Private WithEvents Host As Host
Public Sub New(ByVal Host As Host)
Set Me.Host = Host
End Sub
Private Property Get AddIn_Name() As String
Return "My AddIn"
End Property
Private Sub Host_OnProjectLoaded()
Host.DebugConsole.PrintText "Hello from My AddIn!"
End Sub
End Class
The WithEvents Host As Host pattern is how the addin subscribes to IDE lifecycle events (OnProjectLoaded, OnChangedActiveEditor, OnChangedTheme). Almost every meaningful addin sets up its toolbar buttons and tool windows inside the OnProjectLoaded handler — that is the first moment the IDE is fully ready to accept extensibility commands.
The class catalogue
The package’s twenty-four .twin files declare one interface-and-CoClass pair each (plus one concrete Class), grouped here by role for orientation. Every CoClass except AddinTimer is handed to the addin by the IDE — never instantiated with New.
Entry point and root API
- AddIn — the contract every addin’s main class implements. One read-only Name property.
- Host — the root API object passed to
tbCreateCompilerAddin. Exposes the CurrentProject, the ActiveEditors, the Toolbars, the ToolWindows, the DebugConsole, the FileSystem, the KeyboardShortcuts, the Themes, and a small set of dialog helpers (ShowMessageBox, ShowNotification). - AddinTimer — the package’s only user-instantiable class.
New AddinTimer; set Interval and Enabled; receive a Timer event.
Project, editors, and the virtual file system
- Project — the currently-loaded project. Lifecycle (Save, Close, Build, Clean), introspection (Name, Path, ProjectID, version + architecture + build-output info), the Evaluate hook into the debug-console expression engine, the RootFolder entry into the virtual file system, and the LoadMetaData / SaveMetaData pair for persistent per-addin key/value storage inside the
.twinprojfile. - Editor — the base editor interface (Path, Type, SetFocus, Close, Save, IsDirty). Castable to CodeEditor.
- CodeEditor — a code-pane editor: selection, full text, Monaco passthrough (ExecuteMonacoCommand), inline overlay HTML (AddMonacoWidget).
- Editors — the collection of active editors.
Editors(0)is the current editor; Open jumps to a file (and optional line/column). - FileSystem — the virtual file system. RootFolder, ResolvePath.
- FileSystemItem — the base for File and Folder.
Name,Path,Type,Parent. - Folder — children enumeration (use For Each — see the warning on Count / Item — the IDE is multi-threaded and index-based iteration races), IsPackagesFolder.
- File — virtual-FS file accessors: Data (raw bytes), Text (decoded text), ReadText (text with options like comment-stripping), IsDirty.
IDE UI surface
- Toolbar — the IDE toolbar. AddSplitter, AddButton.
- Toolbars — the toolbar collection. Currently there is only one toolbar, addressable as
Toolbars(0). - Button — a toolbar button created by AddButton. Exposes OnClick.
- ToolWindow — a dockable / floating HTML-rendered tool window. Title, Visible, Resizable, RootDomElement, ApplyCss, OnClose.
- ToolWindows — the tool-window factory: Add creates a new one.
Tool-window DOM and events
The four Html* classes are the addin’s keyhole into the DOM inside a tool window. All four are declared with [COMExtensible(True)] — see Dynamic DOM property resolution.
- HtmlElement — one DOM element. Properties, ChildDomElements, Remove, AddEventListener.
- HtmlElements — the child-element collection. Item and Add — the latter accepts standard HTML tags and the IDE’s custom-widget tags
"chartjs","monaco","listview","virtuallistview". - HtmlElementProperty — one settable property in the bag.
- HtmlElementProperties — the dynamic property bag on a DOM element.
- HtmlEventProperty — one read-only value in an event payload.
- HtmlEventProperties — the dynamic event-payload bag passed to every AddEventListener callback.
Singletons
- DebugConsole — the DEBUG CONSOLE pane. PrintText, Clear, SetFocus.
- KeyboardShortcuts — global IDE keyboard shortcuts. Add.
- Themes — the IDE’s active theme. ActiveThemeName, ActiveThemeNameGroup.
Dynamic DOM property resolution
The four Html* classes that carry the [COMExtensible(True)] attribute — HtmlElementProperties, HtmlElementProperty, HtmlEventProperties, HtmlEventProperty — accept arbitrary property names that are resolved against the underlying DOM element (or event object) at run time. None of style, innerText, chart, editor, listview, value, target, key, index, …, are declared statically on the interfaces — they are all resolved dynamically through the COM-extensible Item(name) default member.
So:
With element.ChildDomElements.Add("mySeparator", "h1").Properties
.style.textAlign = "center"
.style.color = "white"
.innerText = "Section heading"
End With
reads at run time as:
.Item("style").Item("textAlign").Value = "center"
.Item("style").Item("color").Value = "white"
.Item("innerText").Value = "Section heading"
The compiler does not validate the property names; they are forwarded as strings to the IDE’s tool-window renderer. The accepted set is every DOM property of the underlying tag — standard HTML attributes, every CSS-style property under .style.…, plus any custom-widget-specific surface like .chart.data.datasets(0).borderWidth on a "chartjs" element or .editor.setOption(...) on a "monaco" element. The reference does not enumerate them — defer to MDN for standard DOM property names, to Chart.js for chartjs widgets, to Monaco’s documentation for monaco widgets, and to the matching samples below for the IDE-specific listview / virtuallistview surface.
Tool-window DOM tags
HtmlElements.Add takes a TagName string. Standard HTML tags ("div", "span", "input", "h1", "label", "img", …) work as expected; in addition, the IDE provides four custom-widget tags:
"chartjs"— wraps Chart.js. The element surfaces a.chartproperty whose sub-properties mirror Chart.js’sdata/options/confignamespaces. See sample 11."monaco"— embeds an instance of the Monaco editor (the same editor the IDE itself uses for code panes). The element surfaces an.editorproperty withsetOption,setValue,getValue, andAddEventListener(note: event listeners attach to.editor, not to the DOM element). See sample 12."listview"— the IDE’s built-in listview widget. The element surfaces a.listviewproperty withaddItem,removeItem,getItem,setShowScrollbarV/setShowScrollbarH, and the eventsonClickItem/onDblClickItem. See sample 13."virtuallistview"— a virtual variant of the listview suitable for huge data sets (millions of rows). The element surfaces the same.listviewproperty plussetItemCountand the asynchronousonAsyncGetItemHTMLevent (the listener responds viaeventInfo.setAsyncResult("<html>")); call.listview.notifyChangedItem(idx)to invalidate the internal cache for one row when its underlying data changes. See sample 14.
The full per-widget property and method surface is documented by each widget’s home project; this package wraps them through the same [COMExtensible(True)] mechanism described above.
Where the samples live
Six worked addins ship in the twinBASIC samples folder. They are the canonical reference for “how to use the package end-to-end” and are referenced throughout the per-class pages.
| Sample | Project | What it teaches |
|---|---|---|
| 10 | WaynesWorldAddInTest1 | The kitchen-sink walkthrough — toolbar setup, a single big tool window populated with 22 styled div-buttons that each exercise a different Host.* capability. Start here. |
| 11 | WaynesWorldCPUMonitorTest1 | AddinTimer + a "chartjs" custom-widget tool window driving a live line chart. |
| 12 | WaynesWorldMonacoEditorTest1 | A "monaco" custom-widget tool window: an in-window Monaco editor with setValue / getValue and a content-change listener. |
| 13 | WaynesListViewAddIn | A "listview" custom-widget tool window with ApplyCss, double-click-to-remove behaviour, and inline-HTML raiseEvent() for custom event names. |
| 14 | WaynesVirtualListViewAddIn | A "virtuallistview" with 5,000,000 rows backed by onAsyncGetItemHTML / setAsyncResult / notifyChangedItem. |
| 15 | tbGlobalSearchAddIn1 | A full-blown Global Search addin: virtual-FS traversal (For Each over Folder), text reading with comment-stripping (File.ReadText), editor navigation (Editors.Open), persistent options via GetSetting / SaveSetting. |