Files
five/hbrtl/display.go
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

157 lines
3.5 KiB
Go

// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
// All rights reserved.
// Display functions: DISPBEGIN, DISPEND, SAVESCREEN, RESTSCREEN, ALERT
package hbrtl
import (
"five/hbrt"
"fmt"
"strings"
)
var dispCount int // nesting count for DISPBEGIN/DISPEND
// DISPBEGIN() — begins display buffering
func DispBegin(t *hbrt.Thread) {
t.Frame(0, 0)
defer t.EndProc()
dispCount++
// In a real terminal this would hold screen updates;
// for now just track the count.
t.RetNil()
}
// DISPEND() — ends display buffering, flushes
func DispEnd(t *hbrt.Thread) {
t.Frame(0, 0)
defer t.EndProc()
if dispCount > 0 {
dispCount--
}
t.RetNil()
}
// DISPCOUNT() → nNesting
func DispCount(t *hbrt.Thread) {
t.Frame(0, 0)
defer t.EndProc()
t.RetInt(int64(dispCount))
}
// SAVESCREEN([nTop, nLeft, nBottom, nRight]) → cBuffer
// Saves screen content as ANSI escape save sequence.
// Full implementation requires terminal screen buffer; this is a simplified version.
func SaveScreen(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
// Save cursor position and screen via ANSI
fmt.Print("\033[?47h") // save screen (alt buffer)
fmt.Print("\033[s") // save cursor
t.RetString("\033[SAVED]")
}
// RESTSCREEN([nTop, nLeft, nBottom, nRight,] cBuffer)
// Restores previously saved screen.
func RestScreen(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
fmt.Print("\033[u") // restore cursor
fmt.Print("\033[?47l") // restore screen (alt buffer)
t.RetNil()
}
// ALERT(cMessage [, aOptions [, cColor [, nDelay]]]) → nChoice
// Displays a modal alert dialog in the terminal.
func Alert(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
msg := t.Local(1).AsString()
// Parse options array
options := []string{"Ok"}
if nParams >= 2 && !t.Local(2).IsNil() {
arr := t.Local(2).AsArray()
if arr != nil && len(arr.Items) > 0 {
options = make([]string, len(arr.Items))
for i, v := range arr.Items {
options[i] = v.AsString()
}
}
}
// Calculate box dimensions
lines := strings.Split(msg, ";")
maxW := 0
for _, l := range lines {
if len(l) > maxW {
maxW = len(l)
}
}
optLine := strings.Join(options, " ")
if len(optLine) > maxW {
maxW = len(optLine)
}
maxW += 4 // padding
// Draw centered box
row := 8
col := (80 - maxW) / 2
if col < 0 {
col = 0
}
// Top border
fmt.Printf("\033[%d;%dH\033[7m%s\033[0m", row, col+1, strings.Repeat(" ", maxW))
row++
// Message lines
for _, l := range lines {
padded := fmt.Sprintf(" %-*s", maxW-2, l)
if len(padded) > maxW {
padded = padded[:maxW]
}
fmt.Printf("\033[%d;%dH\033[7m%s\033[0m", row, col+1, padded)
row++
}
// Blank line
fmt.Printf("\033[%d;%dH\033[7m%s\033[0m", row, col+1, strings.Repeat(" ", maxW))
row++
// Options line centered
optPad := (maxW - len(optLine)) / 2
optDisplay := fmt.Sprintf("%s%s%s", strings.Repeat(" ", optPad), optLine, strings.Repeat(" ", maxW-optPad-len(optLine)))
fmt.Printf("\033[%d;%dH\033[7m%s\033[0m", row, col+1, optDisplay)
row++
// Bottom border
fmt.Printf("\033[%d;%dH\033[7m%s\033[0m", row, col+1, strings.Repeat(" ", maxW))
// Wait for selection
selected := 1
for {
nKey := ReadKey()
SetLastKey(nKey)
switch nKey {
case 4, 9: // Right, Tab
selected++
if selected > len(options) {
selected = 1
}
case 19: // Left
selected--
if selected < 1 {
selected = len(options)
}
case 13: // Enter
t.RetInt(int64(selected))
return
case 27: // ESC
t.RetInt(0)
return
}
}
}