Documentation
¶
Overview ¶
Package fynerisor provides Risor v2 language bindings for the Fyne GUI framework.
Fynerisor enables building cross-platform desktop applications using Risor v2 scripts with full access to Fyne's widget and container system. Create interactive GUIs with buttons, forms, tables, charts, and more through simple factory functions.
Package Structure ¶
Fynerisor is split into two packages:
- core: Headless Risor execution with no GUI dependencies (enables static compilation)
- gui: Full GUI capabilities with Fyne (requires dynamic linking for OpenGL/X11)
Always import the specific package you need: core for headless, gui for desktop applications.
Version ¶
Current Version: 0.4.1 Risor Compatibility: v2.1+ (arrow functions required) Fyne Compatibility: v2.7+
Features ¶
- 34 widget bindings (60% coverage - all high/medium priority complete)
- Button importance levels and validation
- Entry validation with visual feedback
- SQL module for MySQL, PostgreSQL, SQLite, SQL Server
- HTTP module for REST API calls
- Layout containers (VBox, HBox, Border, Split, Scroll)
- Canvas objects and charts
- Thread-safe callback handling
- Property access and modification from scripts
- Constants global for Fyne enums
Quick Start ¶
Create a simple GUI application:
package main
import "github.com/uidbz/fynerisor/gui"
func main() {
fw := gui.NewApp("Hello",
gui.WithHTTP(),
gui.WithSQL(),
)
script := `
require(["v0.5", "@gui", "@http"])
let btn = widget.NewButton("Click Me", () => {
window.SetStatus("Button clicked!")
})
btn.Importance = constants.ImportanceHigh
window.SetContent(btn)
`
fw.LoadScript(script)
fw.Execute()
fw.ShowAndRun()
}
Headless Mode ¶
Use the core package for headless execution without GUI dependencies. This enables static compilation and is useful for CLI tools, batch processing, or server-side scripting:
package main
import "github.com/uidbz/fynerisor/core"
func main() {
ctx := core.NewContext(
core.WithHTTP(),
core.WithSQL(),
)
script := `
require(["v0.4", "@http", "@sql"])
let response = http.get("https://api.example.com/data")
print(response.json())
`
ctx.LoadScript(script)
ctx.Eval()
}
The core package excludes all GUI code, allowing your binary to be statically linked without OpenGL, X11, or other GUI dependencies.
Requirements ¶
Scripts can declare version and module requirements:
require(["v0.2", "@sql", "@http"]) // Multiple requirements
require("v0.2.0") // Minimum version
require("@sql") // Module must be enabled
Global Objects ¶
Risor scripts have access to the following global objects:
- window: Main window control (SetContent, SetStatus, Title property)
- widget: Factory for all widgets
- container: Factory for layouts
- canvas: Factory for canvas objects
- chart: Factory for charts
- constants: Fyne constants (button importance, etc.)
- app: Application metadata (app.name)
Options ¶
Enable additional modules using options:
fw := gui.NewApp("My App",
gui.WithHTTP(), // HTTP client
gui.WithSQL(), // Database connectivity
gui.WithOS(), // OS utilities
gui.WithIO(), // File I/O (cp, etc.)
gui.WithStrings(), // String manipulation
gui.WithFilepath(), // Path utilities
gui.WithTime(), // Time operations
gui.WithStatusCallback(func(status string) {
log.Println("Status:", status)
}),
gui.WithAppName("myapp"),
)
Risor v2 Syntax ¶
Fynerisor requires Risor v2 with arrow function syntax:
// Correct
let onClick = () => { print("clicked") }
let process = (x) => x * 2
// Wrong - func keyword not supported
func onClick() { print("clicked") }
No for/while loops - use functional methods:
// Correct
let doubled = [1, 2, 3].map(x => x * 2)
list.each(item => print(item))
// Wrong - no loop keywords
for i in list { }
while (condition) { }
Thread Safety ¶
The Risor VM is single-threaded and NOT thread-safe. All widget callbacks execute synchronously in the UI thread. Never spawn goroutines or use async patterns inside callbacks.
See CONCURRENCY.md for detailed information about the race condition bug that was fixed in v0.2.0.
SQL Module ¶
The SQL module supports MySQL, PostgreSQL, SQLite, and SQL Server:
let conn = sql.connect("sqlite3::memory:")
conn.exec("CREATE TABLE users (id INT, name TEXT)")
conn.exec("INSERT INTO users VALUES (?, ?)", 1, "Alice")
// Query returns streaming iterator with .map() and .each()
let names = conn.query("SELECT * FROM users").map(row => row["name"])
// Or use .each() for side effects
conn.query("SELECT * FROM users").each(row => print(row["name"]))
// Or .collect() to load all into memory first
let rows = conn.query("SELECT * FROM users").collect()
conn.close()
HTTP Module ¶
Make HTTP requests from Risor scripts:
let response = http.get("https://api.example.com/data")
let data = response.json() // parse JSON response
print(data["items"])
Examples ¶
See the examples/ directory for 21 complete working examples:
- 01-hello-world: Simple label display
- 02-button-callback: Interactive button with state
- 03-form-input: Form with validation
- 04-table-display: Paginated table
- 05-progress-widgets: Progress bars and sliders
- 11-list: Virtualized scrolling list
- 12-tree: Hierarchical tree widget
- 13-http-fetch: HTTP requests and JSON
- 15-sql-test: Database connectivity
- 17-gridwrap: Grid layout
- 18-textgrid: Code display
- 19-richtext: Markdown formatting
- 20-button-importance: Button styling
- 21-form-validation: Entry validation
CLI Tool ¶
The fynerisor command-line tool runs Risor GUI scripts:
fynerisor app.risor fynerisor --watch app.risor # auto-reload on changes fynerisor --width 1024 --height 768 app.risor fynerisor --headless app.risor # for testing fynerisor --globals data.json app.risor # custom globals
Custom Globals ¶
Inject custom data or functions into scripts:
import (
"github.com/deepnoodle-ai/risor/v2"
"github.com/uidbz/fynerisor/gui"
)
customData := risor.WithEnv(map[string]any{
"api": myAPIObject,
"config": configData,
})
fw := gui.NewApp("My App",
gui.WithGlobals(customData),
)
Scripts can then access: api.someMethod() and config.someProperty
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
fynerisor
command
|
|
|
Package core provides headless Risor execution without GUI dependencies.
|
Package core provides headless Risor execution without GUI dependencies. |
|
examples
|
|
|
01-hello-world
command
|
|
|
02-button-callback
command
|
|
|
03-form-input
command
|
|
|
04-table-display
command
|
|
|
05-progress-widgets
command
|
|
|
06-icon-hyperlink-card
command
|
|
|
07-radiogroup
command
|
|
|
08-accordion
command
|
|
|
09-toolbar
command
|
|
|
10-calendar
command
|
|
|
11-list
command
|
|
|
12-tree
command
|
|
|
13-http-fetch
command
|
|
|
14-imports
command
|
|
|
15-sql-test
command
|
|
|
16-context-builder
command
|
|
|
17-gridwrap
command
|
|
|
18-textgrid
command
|
|
|
19-richtext
command
|
|
|
20-button-importance
command
|
|
|
21-form-validation
command
|
|
|
22-popup
command
|
|
|
23-menu
command
|
|
|
24-constants
command
|
|
|
25-data-binding
command
|
|
|
26-data-binding-types
command
|
|
|
27-app-versioning
command
|
|
|
28-custom-struct
command
|
|
|
30-dialogs
command
|
|
|
31-apptabs
command
|
|
|
32-table-widgets
command
|
|
|
33-image-gallery
command
|
|
|
widget
Package widget provides Risor bindings for Fyne GUI widgets.
|
Package widget provides Risor bindings for Fyne GUI widgets. |
|
modules
|
|
|
filepath
Package filepath provides file path manipulation functions for Risor scripts.
|
Package filepath provides file path manipulation functions for Risor scripts. |
|
http
Package http provides HTTP client functionality for Risor scripts.
|
Package http provides HTTP client functionality for Risor scripts. |
|
os
Package os provides basic OS functionality for Risor scripts.
|
Package os provides basic OS functionality for Risor scripts. |
|
strings
Package strings provides string manipulation functions for Risor scripts.
|
Package strings provides string manipulation functions for Risor scripts. |
|
time
Package time provides time and date functions for Risor scripts.
|
Package time provides time and date functions for Risor scripts. |