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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
328 changes: 323 additions & 5 deletions WIP.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/Reference/Packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ These packages are built into twinBASIC and are always available, even offline.
- [WinEventLogLib Package](WinEventLogLib/) -- writes Windows Event Log entries from twinBASIC; the generic **EventLog**(*Of EventIds, Categories*) class handles registration, registry setup, and the per-event `ReportEventW` call, with message-table resources for *EventIds* and *Categories* synthesised into the EXE at compile time
- [WinNamedPipesLib Package](WinNamedPipesLib/) -- Windows named pipes as twinBASIC objects with an asynchronous IOCP-driven I/O model; **NamedPipeServer** + **NamedPipeServerConnection** on the host side, **NamedPipeClientManager** + **NamedPipeClientConnection** on the client side, with message-boundary semantics and a cookie-based correlation pattern across `AsyncRead` / `AsyncWrite` and their matching events
- [WinServicesLib Package](WinServicesLib/) -- runs a twinBASIC EXE as one or more Windows services; the **Services** singleton coordinates configuration, install / uninstall, and the SCM dispatcher loop, while user-implemented [**ITbService**](WinServicesLib/ITbService) classes are surfaced through [**ServiceCreator**](WinServicesLib/ServiceCreator)`(Of T)`
- [tbIDE Package](tbIDE/) -- the **addin SDK** for the twinBASIC IDE: every addin is a Standard DLL that exports `tbCreateCompilerAddin`, returns an object implementing the [**AddIn**](tbIDE/AddIn) contract, and from there reaches the IDE's toolbar, tool-window DOM, virtual file system, debug console, current project (and its `Evaluate` debug-console hook), keyboard shortcuts, and themes — all through the [**Host**](tbIDE/Host) object the IDE passes in
38 changes: 38 additions & 0 deletions docs/Reference/tbIDE/AddIn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: AddIn
parent: tbIDE Package
permalink: /tB/Packages/tbIDE/AddIn
has_toc: false
---

# AddIn class
{: .no_toc }

The contract every addin's main class must implement. One read-only property — [**Name**](#name) — that the IDE reads to label the addin in error messages, log lines, and (eventually) any addin-management UI. The IDE never creates an **AddIn** itself; the addin DLL constructs the object inside [`tbCreateCompilerAddin`](.#building-and-loading-an-addin) and returns it.

```tb
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
End Class
```

The class implementing **AddIn** is also the natural place to hold every other `WithEvents` reference the addin uses ([**Host**](Host), each [**Button**](Button), each [**ToolWindow**](ToolWindow), an optional [**AddinTimer**](AddinTimer), …) — its lifetime is tied to the addin's loaded state.

## Properties

### Name
{: .no_toc }

A short human-readable name for the addin. **String**, read-only. The IDE captures this once when the addin is loaded.

Syntax: *addIn*.**Name** **As String**
59 changes: 59 additions & 0 deletions docs/Reference/tbIDE/AddinTimer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: AddinTimer
parent: tbIDE Package
permalink: /tB/Packages/tbIDE/AddinTimer
has_toc: false
---

# AddinTimer class
{: .no_toc }

A simple periodic-callback helper. **AddinTimer** is the **only user-instantiable class** in the package — every other CoClass is handed to the addin by the IDE; this one the addin creates with `New`. Internally it wraps the Win32 `SetTimer` / `KillTimer` pair against `hwnd = 0` and fires its [**Timer**](#timer) event from the IDE's UI thread.

```tb
Private WithEvents Timer As AddinTimer

Private Sub Button1_OnClick()
Set Timer = New AddinTimer
Timer.Interval = 500 ' milliseconds
Timer.Enabled = True
End Sub

Private Sub Timer_Timer()
' fires every 500 ms on the IDE's UI thread
End Sub
```

Stop the timer by setting [**Enabled**](#enabled) = **False**, or simply by dropping the last reference — `Class_Terminate` cancels the underlying Win32 timer automatically. Both [**Enabled**](#enabled) and [**Interval**](#interval) are live: assigning to either re-arms the underlying Win32 timer using the new values, so changing the interval while the timer is running takes effect immediately.

Nothing in the package *requires* this helper — a direct `SetTimer` / `KillTimer` pair (or any other periodic mechanism) works just as well; sample 15's dwell-time pattern uses raw Win32 calls. Use **AddinTimer** when the convenience of an event-bound class is preferable to managing the Win32 plumbing yourself.

* TOC
{:toc}

## Properties

### Enabled
{: .no_toc }

Controls whether the underlying Win32 timer is running. **Boolean**, default **False**. Assigning to **Enabled** re-arms (or cancels) the timer immediately.

Syntax: *timer*.**Enabled** [ = *value* ]

### Interval
{: .no_toc }

The timer's period, in milliseconds. **Long**, default **0**. With **Interval = 0** the timer is effectively inert; set a positive value and [**Enabled**](#enabled) = **True** to start the periodic callback. Assigning to **Interval** re-arms the timer with the new value, so the next tick fires after the new interval rather than the old one.

Syntax: *timer*.**Interval** [ = *milliseconds* ]

## Events

### Timer
{: .no_toc }

Fires every [**Interval**](#interval) milliseconds while [**Enabled**](#enabled) is **True**. Runs on the IDE's UI thread.

Syntax: *timer*_**Timer**()

Long-running work inside the handler will block the UI thread until it returns — keep the handler short and offload heavy work to a background mechanism if needed.
60 changes: 60 additions & 0 deletions docs/Reference/tbIDE/Button.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Button
parent: tbIDE Package
permalink: /tB/Packages/tbIDE/Button
has_toc: false
---

# Button class
{: .no_toc }

An addin-created toolbar button. Returned by [**Toolbar.AddButton**](Toolbar#addbutton); hold it via `WithEvents` to receive [**OnClick**](#onclick) notifications. The button's [**Caption**](#caption) and [**IconData**](#icondata) are mutable at run time — change the caption to reflect a state, or swap the icon to reflect a toggle.

```tb
Private WithEvents RefreshButton As Button

Private Sub Host_OnProjectLoaded()
Set RefreshButton = Host.Toolbars(0).AddButton("MyAddIn.Refresh", "Refresh project", _
LoadResData("refresh.png", "ICONS"))
End Sub

Private Sub RefreshButton_OnClick()
Host.CurrentProject.Save
End Sub
```

* TOC
{:toc}

## Properties

### Caption
{: .no_toc }

The button's caption. **String**. When [**IconData**](#icondata) is set, the caption is shown as a tooltip on hover. When [**IconData**](#icondata) is empty, the caption is shown inline as the button's text. Read / write.

Syntax: *button*.**Caption** [ = *value* ]

### IconData
{: .no_toc }

The icon graphic as a **Byte()** array — typically the bytes of an embedded PNG / ICO resource. Pass **Empty** to remove the icon and fall back to showing the [**Caption**](#caption) inline. Read / write.

Syntax: *button*.**IconData** [ = *bytes* ]

*bytes*
: A **Byte()** array (or **Empty**). **Variant**.

### ID
{: .no_toc }

The unique ID assigned to the button when it was created via [**Toolbar.AddButton**](Toolbar#addbutton). **String**, read-only.

## Events

### OnClick
{: .no_toc }

Fires when the user clicks the button.

Syntax: *button*_**OnClick**()
136 changes: 136 additions & 0 deletions docs/Reference/tbIDE/CodeEditor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
title: CodeEditor
parent: tbIDE Package
permalink: /tB/Packages/tbIDE/CodeEditor
has_toc: false
---

# CodeEditor class
{: .no_toc }

A code-pane editor — the specific [**Editor**](Editor) kind the IDE returns when the active editor is a source-code pane. Adds selection / text / scrolling control, an inline-widget API, and a raw passthrough into the underlying Monaco editor that powers code panes.

Reach a **CodeEditor** by casting an [**Editor**](Editor) — `Host.ActiveEditors(0)` returns an [**Editor**](Editor) that, for a code pane, is also a **CodeEditor**:

```tb
If TypeOf Host.ActiveEditors(0) Is CodeEditor Then
Dim codeEditor As CodeEditor = Host.ActiveEditors(0)
codeEditor.SelectedText = "' commented out by an addin" & vbCrLf & codeEditor.SelectedText
End If
```

**CodeEditor** inherits every base [**Editor**](Editor) member ([**Path**](Editor#path), [**Type**](Editor#type), [**SetFocus**](Editor#setfocus), [**Close**](Editor#close), [**Save**](Editor#save), [**IsDirty**](Editor#isdirty)) and adds the members listed below.

* TOC
{:toc}

## Properties

### SelectedText
{: .no_toc }

The currently-selected text. Reading returns the selection as a **String** (empty string when nothing is selected). Assigning replaces the current selection with the supplied text. Read / write.

Syntax: *codeEditor*.**SelectedText** [ = *value* ]

### Text
{: .no_toc }

The full text of the code pane. Reading returns the entire document; assigning replaces every line with the supplied text. Read / write.

Syntax: *codeEditor*.**Text** [ = *value* ]

Replacing the entire text is heavyweight — both for the editor (it has to rebuild every Monaco data structure) and for the user (the undo stack collapses to a single step). For surgical edits, prefer [**SelectedText**](#selectedtext) over [**Text**](#text).

## Methods

### AddMonacoWidget
{: .no_toc }

Attaches an inline HTML overlay to a specific position in the editor — Monaco's *content widget* mechanism, surfaced as a familiar [**HtmlElement**](HtmlElement).

Syntax: *codeEditor*.**AddMonacoWidget**( *LineNumber*, *ColumnNumber*, *Html* [, *Css* ] ) **As** [**HtmlElement**](HtmlElement)

*LineNumber*
: *required* One-based line number to attach the widget to. **Long**.

*ColumnNumber*
: *required* One-based column number on that line, **or zero**. **Long**. When the column number is zero, the widget is rendered *below* the line and the editor inserts vertical space so the widget does not overlap the next line. Pass a non-zero column to render the widget inline at that column.

*Html*
: *required* The widget's HTML content. **String**.

*Css*
: *optional* Per-widget CSS as a **String**. Use this for widget-local styles that should not bleed into the rest of the code pane.

The returned [**HtmlElement**](HtmlElement) has the same dynamic-DOM surface as elements inside a tool window — see [Dynamic DOM property resolution](.#dynamic-dom-property-resolution) on the package overview. Use [**HtmlElement.Remove**](HtmlElement#remove) on the returned object to take the widget down.

### ExecuteMonacoCommand
{: .no_toc }

Sends a direct command to the underlying Monaco editor instance. Useful for triggering Monaco's built-in commands (Find, Go-to-Line, Format, Toggle Comment, …) without writing equivalent twinBASIC code.

Syntax: *codeEditor*.**ExecuteMonacoCommand** *Command* [, *Arg1*, *Arg2*, … ]

*Command*
: *required* The Monaco command ID. **String**. Common values include `"actions.find"` (open the Find widget), `"closeFindWidget"` (close it), `"editor.action.formatDocument"`, and `"editor.action.commentLine"`.

*Args*
: *optional* A **ParamArray** of command-specific arguments. **Variant**. Forwarded verbatim to Monaco.

The reference does not enumerate Monaco's command surface — refer to Monaco's documentation for the full list and their per-command argument shapes.

```tb
codeEditor.ExecuteMonacoCommand "actions.find" ' open Find widget
codeEditor.ExecuteMonacoCommand "closeFindWidget" ' close it
```

### GetSelectionInfo
{: .no_toc }

Reports the start and end positions of the current selection. All four output arguments are filled even when nothing is selected — start and end positions then coincide on the caret's current position.

Syntax: *codeEditor*.**GetSelectionInfo** *StartLine*, *StartColumn*, *EndLine*, *EndColumn*

*StartLine*, *StartColumn*, *EndLine*, *EndColumn*
: **ByRef Long** — output parameters, all one-based.

### RevealRange
{: .no_toc }

Scrolls the editor to bring a range into view, optionally animating the scroll and positioning the range at a specific spot in the viewport.

Syntax: *codeEditor*.**RevealRange** *StartLine*, *StartColumn*, *EndLine*, *EndColumn* [, *SmoothScroll* ] [, *Area* ]

*StartLine*, *StartColumn*, *EndLine*, *EndColumn*
: *required* The range to reveal. **Long**, one-based.

*SmoothScroll*
: *optional* **Boolean** — animate the scroll. Default **True**.

*Area*
: *optional* A [**RevealArea**](#revealarea) value controlling where in the viewport the range lands. Default [**Any**](#RevealArea_Any).

### SetSelectionInfo
{: .no_toc }

Sets the start and end positions of the selection. The inverse of [**GetSelectionInfo**](#getselectioninfo).

Syntax: *codeEditor*.**SetSelectionInfo** *StartLine*, *StartColumn*, *EndLine*, *EndColumn*

*StartLine*, *StartColumn*, *EndLine*, *EndColumn*
: *required* One-based line and column positions. **Long**. To position the caret without selecting any text, use the same line / column for both ends.

## RevealArea
{: #revealarea }

Controls where in the viewport [**RevealRange**](#revealrange) places the requested range.

| Constant | Value | Description |
|----------|-------|-------------|
| **Any**{: #RevealArea_Any } | 0 | Scroll vertically or horizontally only as much as necessary to make the range visible. Cheapest scroll. |
| **Top**{: #RevealArea_Top } | 1 | Scroll so the range sits at the top of the viewport. |
| **Center**{: #RevealArea_Center } | 2 | Scroll so the range is vertically centred in the viewport. |
| **CenterIfNotVisible**{: #RevealArea_CenterIfNotVisible } | 3 | Centre vertically, but only if the range currently lies outside the viewport — otherwise do nothing. |
| **NearTop**{: #RevealArea_NearTop } | 4 | Scroll so the range sits close to the top, with some context above — Monaco's "view a code definition" preset. |
| **NearTopIfNotVisible**{: #RevealArea_NearTopIfNotVisible } | 5 | Same as [**NearTop**](#RevealArea_NearTop), but only if the range is currently outside the viewport. |
58 changes: 58 additions & 0 deletions docs/Reference/tbIDE/DebugConsole.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: DebugConsole
parent: tbIDE Package
permalink: /tB/Packages/tbIDE/DebugConsole
has_toc: false
---

# DebugConsole class
{: .no_toc }

The IDE's DEBUG CONSOLE pane — reached through [**Host.DebugConsole**](Host#debugconsole). The canonical place for an addin to write diagnostic and log output.

```tb
With Host.DebugConsole
.PrintText "[MyAddIn] Project: " & Host.CurrentProject.Name
.PrintText "[MyAddIn] Compiler: " & Host.CompilerVersion
.PrintText "[MyAddIn] PID: " & Host.IDEProcessID
End With
```

The pane is shared across the IDE's own output and every addin's output — prefix log lines with an addin tag (e.g. `"[MyAddIn] "`) so users can tell sources apart.

* TOC
{:toc}

## Methods

### Clear
{: .no_toc }

Clears the entire content of the DEBUG CONSOLE pane.

Syntax: *debugConsole*.**Clear**

### PrintText
{: .no_toc }

Prints one line of text to the pane.

Syntax: *debugConsole*.**PrintText** *Prompt* [, *ColorRGB* ]

*Prompt*
: *required* The text to print. **String**.

*ColorRGB*
: *optional* The text colour as an RGB **Long** (use the `RGB(r, g, b)` function to construct one). Default 0 — the IDE's default DEBUG CONSOLE foreground colour.

```tb
Host.DebugConsole.PrintText "Operation completed" ' default colour
Host.DebugConsole.PrintText "Warning: something looks off", RGB(255, 128, 0) ' orange
```

### SetFocus
{: .no_toc }

Gives keyboard focus to the DEBUG CONSOLE's text-entry point — equivalent to the user clicking into the console.

Syntax: *debugConsole*.**SetFocus**
Loading
Loading