A Go port of Free Vision, the Turbo-Vision-derived console UI framework originally from Free Pascal. Based on the modernized Delphi version at oldwired/fv-delphi-modern, not the original Free Pascal sources.
Status: full vertical slice up to and including an embedded VT terminal emulator. macOS / Linux first-class; Windows builds clean (ConPTY-backed terminal, otherwise feature-parity).
- Foundation — types, term backend (hand-rolled VT100/SGR, alt screen, bracketed paste, SGR-1006 mouse, focus events, cell-pixel probe), drivers (FV event queue), screen primitives.
- Views —
View,Group,Window(drag/resize/zoom/close),Frame,ScrollBar,Scroller,ListViewer,Background,SplitGroup. - App —
Program/Application/Desktop, idle loop with dirty-tracking, anim ticker, pre-flush hook for SIXEL z-order, wake-channel so async data (PTY output) doesn't wait for the next keystroke. - Menus —
MenuBar,MenuBox(nested submenus, hotkeys, Alt+letter, Left/Right cycling between top-level menus),StatusLine. - Dialogs —
Dialog,Button,InputLine,Cluster(radio / check),ListBox/StringListBox,Label,StaticText,ParamText,History,CheckListBox,InputLong. - Standard dialogs —
msgbox, classic single-panestddlg.Show(file/save/changeDir), modern split-panestddlg.ShowModernwith lazy-loaded directory tree + file-info pane. - Validators — picture / range / filter / lookup, the full TV set.
- Widget toolkit — 30+ widgets: ProgressBar, Sparkline, BarChart,
VUMeter, ToggleSwitch, LEDDigits, ColorTxt, BlinkIndicator, Marquee,
ToolBar, Tabs, Accordion, Notification, Tooltip, PopupMenu, TimedDlg,
ComboBox, TreeView (lazy-load via
OnExpand), AsciiTab, SpinnerView, TaskProgress, Breadcrumb, Calendar, ColorSel. - Heavy — Editor (with optional
EditorGutterfor line numbers / breakpoints / bookmarks; pluggable syntax highlighting viawidgets/syntax), HexEdit, Grid, MarkdownView, LogViewer, FuzzyFinder. - System gadgets — CPUMeter, CPUCoreView, RAMView, DiskUsageView,
BatteryView, NetworkView, ProcessView, UptimeView. All
bring-your-own-data via a
Samplercallback so the framework stays portable. - Graphics —
pkg/fv/sixelrealtime (216-cube) + quality (median-cut + Floyd-Steinberg) encoders, cell-pixel-size probe viaCSI 16t,ImageView(PNG/JPEG/GIF/BMP/TIFF/WebP) andSixelCanvasView(programmable pixel canvas with line/rect/fill primitives). Half-block fallback on terminals without SIXEL. - Terminal emulator —
widgets/terminal. PTY-backed shell viacreack/ptyon Unix and ConPTY on Windows. VT100 + xterm parser covering plain text + UTF-8, the C0 set, CSI cursor/erase/SGR/scroll, DEC private modes (autowrap, cursor vis, alt screen), OSC 0/1/2 titles. 2000-line scrollback with/-search; drag-to-select + clipboard copy; mouse forwarding when the inner program asks for it.
package main
import (
"github.com/oldwired/fv-go/pkg/fv/app"
"github.com/oldwired/fv-go/pkg/fv/consts"
"github.com/oldwired/fv-go/pkg/fv/dialogs"
"github.com/oldwired/fv-go/pkg/fv/drivers"
"github.com/oldwired/fv-go/pkg/fv/geom"
"github.com/oldwired/fv-go/pkg/fv/menus"
"github.com/oldwired/fv-go/pkg/fv/views"
)
func main() {
a, err := app.NewApplication()
if err != nil {
panic(err)
}
defer a.Done()
cols := a.BaseView().Size.X
a.SetMenuBar(menus.NewMenuBar(geom.NewRect(0, 0, cols, 1),
menus.NewMenu(
&menus.Item{Name: "~F~ile", Sub: menus.NewMenu(
&menus.Item{Name: "~Q~uit", Command: consts.CmQuitApp},
)},
)))
a.OnCommand = func(cmd uint16, ev *drivers.Event) bool {
// Custom commands land here.
return false
}
// Open a window with a button. NewWindow's third arg is the
// number badge in the frame title — 0 means no badge.
win := views.NewWindow(geom.NewRect(5, 3, 40, 10), "Hello", 0)
win.Insert(dialogs.NewButton(geom.NewRect(2, 2, 16, 3), "~C~lick me",
consts.CmOK, dialogs.BfDefault))
a.Desktop.InsertWindow(win)
a.Run()
}See docs/QUICKSTART.md for a deeper tour and cmd/fvdemo/ for a
fully-loaded demo exercising every widget.
go run ./cmd/fvdemoThe demo opens with a menu bar; explore via Test → Widgets /
Test → Apps for the widget showcases. On a SIXEL-capable terminal
(iTerm2, WezTerm, kitty, Windows Terminal ≥ 1.22), Apps → Image View (Open...) and Apps → Sixel Canvas render true pixel graphics.
Application: app.Application / app.Program / app.Desktop (app/)
Widgets: Dialog, Button, InputLine, ListBox, … (dialogs/, widgets/*)
Views: View, Group, Window, Frame, ScrollBar, Scroller (views/)
Drivers: Event queue, keyboard, mouse (drivers/)
Console output, VT/SGR, SIXEL (term/, sixel/)
Foundation: Cell types, geom, unicode width, profile (types/, geom/, unicode/, utf8/, profile/)
The layering matches the Delphi reference: each layer only depends on
the ones below it. The four cross-cutting interfaces from Pascal
(IFVDrawable, IFVEventHandler, IFVDataAware, ISerializable)
become Go interfaces satisfied structurally by views.View.
These are the non-obvious mappings the original PORTING.md won't give
you:
- No inheritance. Pascal's
TGroup : TView,TWindow : TGroup, etc. are rewritten with embedding + interface satisfaction. Virtual dispatch goes through aself Viewback-pointer set bySetSelfduring construction. - In-place initialization.
InitGroup,InitWindow,InitDialogexist alongside theNewXconstructors to avoid the struct-copy bug that orphans childOwnerpointers — initialize via these whenever you embed aGroup/Window/Dialogby value. - Manual ref-counting is gone. Parents own children via slices;
the GC handles cleanup. No
_AddRef/_Releaseplumbing. TFVStream→io.Reader/io.Writerfor streaming; persistence-with-type-tags maps cleanly toencoding/json+ a type registry (pkg/fv/serial).- Unicode width (
FVUnicodeWidth.pas) is data, not logic — ported verbatim intopkg/fv/unicode. Emoji and CJK rendering depends on the wide / zero-width / combining classification. - Windows-only assumptions don't transfer.
FVScreen.pas(Windows Console API) andFVClipboard.pas(Win32 clipboard) are replaced by the hand-rolled VT/SGR writer inpkg/fv/termand OSC 52 clipboard inpkg/fv/clipboard. Cross-platform from day one.
Inherits the Free Vision / Free Pascal license:
LICENSE— GNU Lesser General Public License, version 2.1.FPC-EXCEPTION.txt— Free Pascal library linking exception, which permits linking against modified versions without forcing the linked work to be LGPL.
SPDX-License-Identifier: LGPL-2.1-or-later WITH FPC-modified-LGPL-exception
The practical effect of the FPC exception is that you may distribute
statically linked binaries without needing to make your application's
source available, provided you preserve the fv-go license headers
and provide notice that the library may be replaced or recompiled.
See FPC-EXCEPTION.txt for the exact terms. Original-author
copyright headers are preserved inside each ported unit.
Each tagged GitHub Release ships a CycloneDX SBOM
(fv-go-vX.Y.Z.cdx.json) describing the module's declared dependency
graph and the detected license of every component. Generated by
cyclonedx-gomod in
CI on tag push — see .github/workflows/release.yml.
gh release download vX.Y.Z -p '*.cdx.json'