rego

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 25, 2025 License: MIT Imports: 10 Imported by: 0

README

Rego

Go Version License Go Report Card

Bringing React Hooks-style development experience to Go CLI/TUI

English | 简体中文


Features

  • Hooks Style - Familiar APIs like Use, UseEffect, UseKey
  • Type Safe - Built on Go generics with compile-time type checking
  • Explicit Keys - Break free from React Hooks' call order constraints, use in if/for blocks
  • Declarative UI - Layout components like VStack, HStack, Box
  • Focus Management - Built-in Tab/Shift+Tab navigation
  • Mouse Support - Click, scroll, and hover events
  • Built-in Components - Button, TextInput, Checkbox, Spinner, Markdown, and more
  • Agent Friendly - Bridge mechanism, perfect for AI Agent streaming scenarios

Quick Start

Installation
go get github.com/erweixin/rego
Hello World
package main

import (
    "fmt"
    "github.com/erweixin/rego"
)

func App(c rego.C) rego.Node {
    count := rego.Use(c, "count", 0)
    
    rego.UseKey(c, func(key rego.Key, r rune) {
        switch r {
        case '+': count.Set(count.Val + 1)
        case '-': count.Set(count.Val - 1)
        case 'q': c.Quit()
        }
    })
    
    return rego.VStack(
        rego.Text("Rego Counter").Bold(),
        rego.Text(fmt.Sprintf("Count: %d", count.Val)),
        rego.Spacer(),
        rego.Text("[+] Increment  [-] Decrement  [q] Quit").Dim(),
    )
}

func main() {
    rego.Run(App)
}

Output:

Rego Counter
Count: 0

[+] Increment  [-] Decrement  [q] Quit

Core Concepts

Hooks
// State management
count := rego.Use(c, "count", 0)        // Declare state
count.Set(10)                            // Set value
count.Update(func(v int) int { return v + 1 }) // Functional update

// Side effects
rego.UseEffect(c, func() func() {
    ticker := time.NewTicker(time.Second)
    go func() {
        for range ticker.C {
            c.Refresh()
        }
    }()
    return ticker.Stop  // Return cleanup function
}, dep1, dep2)  // Dependency list

// Keyboard events
rego.UseKey(c, func(key rego.Key, r rune) {
    if key == rego.KeyEnter { /* ... */ }
    if r == 'q' { c.Quit() }
})

// Mouse events
rego.UseMouse(c, func(ev rego.MouseEvent) {
    if ev.Type == rego.MouseEventClick { /* ... */ }
})

// Focus management
focus := rego.UseFocus(c)
if focus.IsFocused { /* Current component has focus */ }

// Memoization
result := rego.UseMemo(c, func() int {
    return expensiveCalculation()
}, dep1, dep2)

// Refs (solve closure traps)
ref := rego.UseRef(c, &someValue)
Child Components
func App(c rego.C) rego.Node {
    return rego.VStack(
        Header(c.Child("header")),   // Isolated state space
        Content(c.Child("content")),
        Footer(c.Child("footer")),
    )
}

// Use index in lists
rego.For(items, func(item Item, i int) rego.Node {
    return ItemComponent(c.Child("item", i), item)
})
Layout
// Vertical stack
rego.VStack(
    rego.Text("Title").Bold(),
    rego.Divider(),
    rego.Text("Content"),
    rego.Spacer(),  // Flexible space
    rego.Text("Footer").Dim(),
)

// Horizontal stack
rego.HStack(
    rego.Text("Left"),
    rego.Spacer(),
    rego.Text("Right"),
).Gap(2)

// Container with border
rego.Box(
    rego.Text("Boxed Content"),
).Border(rego.BorderRounded).Padding(1, 2)

// Flex layout
rego.VStack(
    rego.Text("Header").Height(1),
    rego.Box(content).Flex(1),  // Take remaining space
    rego.Text("Footer").Height(1),
)
Styling
rego.Text("Styled Text").
    Bold().
    Italic().
    Underline().
    Color(rego.Cyan).
    Background(rego.Black)

rego.Box(child).
    Border(rego.BorderDouble).
    BorderColor(rego.Green).
    Padding(1, 2).
    Width(40).
    Height(10)

Built-in Components

Button
rego.Button(c.Child("btn"), rego.ButtonProps{
    Label:   "Submit",
    Primary: true,
    OnClick: func() { /* ... */ },
})
TextInput
rego.TextInput(c.Child("input"), rego.TextInputProps{
    Value:       value.Val,
    Placeholder: "Enter text...",
    OnChanged:   func(s string) { value.Set(s) },
    OnSubmit:    func(s string) { /* On Enter */ },
})
Checkbox
rego.Checkbox(c.Child("check"), rego.CheckboxProps{
    Label:     "Accept terms",
    Checked:   agreed.Val,
    OnChanged: func(v bool) { agreed.Set(v) },
})
Spinner
rego.Spinner(c.Child("loading"), "Loading...")
ScrollBox / TailBox
// Scrollable container
rego.ScrollBox(c.Child("scroll"), longContent)

// Auto-scroll to bottom (ideal for logs/chat)
rego.TailBox(c.Child("logs"), logContent)
Markdown
rego.Markdown("# Hello\n\nThis is **markdown** content.")

AI Agent Scenarios

Rego is especially suitable for building AI Agent CLIs with built-in Bridge mechanism:

func AgentUI(c rego.C) rego.Node {
    bridge := rego.UseBridge[AgentState, Question, Answer](c, AgentState{})
    
    rego.UseEffect(c, func() func() {
        go agent.Run(bridge.Handle())  // Run Agent in background
        return nil
    })
    
    return rego.VStack(
        // Render streaming output
        rego.Markdown(bridge.State().Response),
        
        // Render interaction requests (e.g., confirmation dialog)
        rego.When(bridge.HasInteraction(),
            ConfirmDialog(c.Child("confirm"), bridge),
        ),
    )
}

For more details, see Agent Bridge Documentation.


Examples

Example Description
hello Simple Hello World
counter Counter, demonstrates state management
todo Todo app, full feature demo
timer Timer, demonstrates UseEffect
focus Focus switching, multi-panel app
form Form, showcases built-in components
dashboard Dashboard, complex layouts
agent AI Agent, streaming output
markdown Markdown rendering
gallery Component gallery, all components

Run examples:

cd examples/counter
go run main.go

Architecture

┌─────────────────────────────────────────────────────────────┐
│                       User Code                             │
│   func App(c rego.C) rego.Node { ... }                      │
└──────────────────────────┬──────────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────────┐
│                     rego (Core Layer)                       │
│                                                             │
│  • C Interface - Component Context                          │
│  • State[T] - Generic State Management                      │
│  • Hooks - Use, UseEffect, UseKey, UseMemo, UseRef, UseFocus│
│  • Node - Declarative View Nodes                            │
│  • Context[T] - Cross-component Context Passing             │
│                                                             │
└──────────────────────────┬──────────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────────┐
│                     tcell (Render Layer)                    │
│                                                             │
│  • Terminal Init/Restore                                    │
│  • Screen Rendering + Built-in Diff                         │
│  • Keyboard/Mouse Events                                    │
│  • Cross-platform Support                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Comparison with Other Solutions

Feature Rego bubbletea tcell
Architecture Hooks Elm (MVU) Imperative
State Management rego.Use() fine-grained Model centralized Manual
Side Effects rego.UseEffect() Cmd Manual
State in Conditionals Yes - -
Type Safety Generics Assertions -
Focus Management rego.UseFocus() Manual Manual
Learning Curve React dev friendly Need to learn Elm Steep

Documentation


Development

# Clone repository
git clone https://github.com/erweixin/rego.git
cd rego

# Run tests
go test ./...

# Run examples
cd examples/gallery
go run .

Roadmap

  • Core Hooks Runtime
  • Basic Layout Components
  • Focus Management System
  • Mouse Support
  • Built-in Component Library
  • Markdown Rendering
  • Agent Bridge
  • Select/Dropdown Component
  • Table Component
  • Modal Component
  • Theme System

Contributing

Contributions are welcome! Please read the Contributing Guide.


License

MIT License - See LICENSE for details.


Acknowledgments


Made with love for the Go community

Documentation

Overview

Package rego 提供 React Hooks 风格的 CLI/TUI 开发体验

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Box

func Box(child Node) *boxNode

Box 创建一个容器节点

func Divider

func Divider() *dividerNode

Divider 创建一个水平分隔线,自动撑满宽度

func Empty

func Empty() *emptyNode

Empty 创建一个空节点

func HStack

func HStack(children ...Node) *hstackNode

HStack 创建一个水平排列布局

func If

func If[T any](cond bool, a, b T) T

If 是一个泛型三元运算符模拟函数

func Markdown

func Markdown(content string) *markdownNode

Markdown 创建一个 Markdown 渲染节点

func Run

func Run(root func(C) Node) error

Run 启动应用

func ScrollBox

func ScrollBox(c C, child Node) *componentNode

ScrollBox 创建一个可滚动的容器

func Spacer

func Spacer() *spacerNode

Spacer 创建一个弹性空白节点(默认 flex=1)

func StringWidth

func StringWidth(s string) int

StringWidth 计算字符串的显示宽度(考虑中文等宽字符)

func TailBox

func TailBox(c C, child Node) *componentNode

TailBox 是一个默认开启自动滚动的 ScrollBox,非常适合日志和聊天界面

func Text

func Text(content string) *textNode

Text 创建一个文本节点

func UseContext

func UseContext[T any](c C, ctx *Context[T]) T

UseContext 获取 Context 的值 从当前组件向上查找,直到找到 Provider 或返回默认值

func UseEffect

func UseEffect(c C, fn func() func(), deps ...any)

UseEffect 声明一个副作用 fn 返回清理函数,如果不需要清理返回 nil

func UseKey

func UseKey(c C, handler func(key Key, r rune))

UseKey 注册键盘事件处理器

func UseMemo

func UseMemo[T any](c C, fn func() T, deps ...any) T

UseMemo 缓存计算结果,只在依赖变化时重新计算

func UseMouse

func UseMouse(c C, handler func(ev MouseEvent))

UseMouse 注册鼠标事件处理器

func VStack

func VStack(children ...Node) *vstackNode

VStack 创建一个垂直堆叠布局

func When

func When(condition bool, node Node) *whenNode

When 条件渲染:当 condition 为 true 时渲染 node

func WhenElse

func WhenElse(condition bool, trueNode, falseNode Node) *whenElseNode

WhenElse 条件渲染:根据 condition 选择渲染哪个节点

Types

type Align

type Align int

Align 对齐方式

const (
	AlignLeft Align = iota
	AlignCenter
	AlignRight
)

type BorderChars

type BorderChars struct {
	TopLeft     rune
	TopRight    rune
	BottomLeft  rune
	BottomRight rune
	Horizontal  rune
	Vertical    rune
}

BorderChars 边框字符

type BorderStyle

type BorderStyle int

BorderStyle 边框样式

const (
	BorderNone BorderStyle = iota
	BorderSingle
	BorderDouble
	BorderRounded
	BorderThick
)

type Bridge

type Bridge[S any, Q any, A any] struct {
	// contains filtered or unexported fields
}

Bridge 是 UI 侧持有的句柄,用于与 Core 通信

func UseBridge

func UseBridge[S any, Q any, A any](c C, initial S) *Bridge[S, Q, A]

UseBridge 创建一个双向通信桥梁 S: 状态类型, Q: 问题类型, A: 回答类型

func (*Bridge[S, Q, A]) Handle

func (b *Bridge[S, Q, A]) Handle() Handle[S, Q, A]

Handle 返回给 Core 使用的句柄

func (*Bridge[S, Q, A]) HasInteraction

func (b *Bridge[S, Q, A]) HasInteraction() bool

HasInteraction 检查是否有挂起的交互请求

func (*Bridge[S, Q, A]) Interaction

func (b *Bridge[S, Q, A]) Interaction() Q

Interaction 返回当前的交互请求内容

func (*Bridge[S, Q, A]) State

func (b *Bridge[S, Q, A]) State() S

State 返回当前从 Core 同步过来的状态

func (*Bridge[S, Q, A]) Submit

func (b *Bridge[S, Q, A]) Submit(answer A)

Submit 提交用户的回答,解除 Core 的阻塞

type ButtonProps

type ButtonProps struct {
	Label   string
	OnClick func()
	Primary bool
}

type C

type C interface {
	// Child 获取子组件上下文
	Child(key string, index ...int) C

	// Refresh 手动触发重渲染
	Refresh()

	// Quit 退出应用
	Quit()

	// SetCursor 设置光标位置(用于 IME 输入定位)
	SetCursor(x, y int)

	// Wrap 包装节点以追踪其位置(用于鼠标点击)
	Wrap(node Node) *componentNode

	// Rect 获取当前组件的屏幕区域
	Rect() Rect
}

C 是组件上下文接口

type CheckboxProps

type CheckboxProps struct {
	Label     string
	Checked   bool
	OnChanged func(bool)
}

type Color

type Color int

Color 表示颜色

const (
	Default Color = iota
	Black
	Red
	Green
	Yellow
	Blue
	Magenta
	Cyan
	White
	Gray
)

基础颜色常量

type Context

type Context[T any] struct {
	// contains filtered or unexported fields
}

Context 表示一个可跨组件共享的上下文

func CreateContext

func CreateContext[T any](defaultValue T) *Context[T]

CreateContext 创建一个新的 Context

func (*Context[T]) Provide

func (ctx *Context[T]) Provide(c C, value T, children ...Node) Node

Provide 提供 Context 值,包装子节点 用法: ThemeContext.Provide(c, "dark", child1, child2, ...)

func (*Context[T]) ProvideH

func (ctx *Context[T]) ProvideH(c C, value T, children ...Node) Node

ProvideH 提供 Context 值,子节点水平排列

type FocusManager

type FocusManager struct {
	// contains filtered or unexported fields
}

FocusManager 管理所有可聚焦组件

func (*FocusManager) Current

func (fm *FocusManager) Current() string

Current 获取当前聚焦的组件 key

func (*FocusManager) CurrentContext

func (fm *FocusManager) CurrentContext() *componentContext

CurrentContext 获取当前聚焦的组件上下文

func (*FocusManager) Focus

func (fm *FocusManager) Focus(key string)

Focus 聚焦到指定组件

func (*FocusManager) IsFocused

func (fm *FocusManager) IsFocused(key string) bool

IsFocused 检查指定组件是否有焦点

func (*FocusManager) Next

func (fm *FocusManager) Next()

Next 切换到下一个可聚焦组件

func (*FocusManager) Prev

func (fm *FocusManager) Prev()

Prev 切换到上一个可聚焦组件

func (*FocusManager) Register

func (fm *FocusManager) Register(key string, ctx *componentContext)

Register 注册可聚焦组件

func (*FocusManager) Reset

func (fm *FocusManager) Reset()

Reset 重置焦点管理器(每次渲染前调用)

func (*FocusManager) Unregister

func (fm *FocusManager) Unregister(key string)

Unregister 注销可聚焦组件

type FocusState

type FocusState struct {
	IsFocused bool   // 当前是否有焦点
	Focus     func() // 获取焦点
	Blur      func() // 失去焦点
	// contains filtered or unexported fields
}

FocusState 表示组件的焦点状态

func UseFocus

func UseFocus(c C) FocusState

UseFocus 声明组件可聚焦,返回焦点状态

type Handle

type Handle[S any, Q any, A any] interface {
	Update(state S)
	Ask(question Q) A
}

Handle 是 Core 侧持有的接口

type Key

type Key int

Key 表示特殊按键

const (
	KeyNone Key = iota
	KeyUp
	KeyDown
	KeyLeft
	KeyRight
	KeyEnter
	KeyEsc
	KeyBackspace
	KeyTab
	KeySpace
	KeyHome
	KeyEnd
	KeyPageUp
	KeyPageDown
	KeyDelete
	KeyInsert
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyCtrlA
	KeyCtrlB
	KeyCtrlC
	KeyCtrlD
	KeyCtrlE
	KeyCtrlF
	KeyCtrlG
	KeyCtrlH
	KeyCtrlI
	KeyCtrlJ
	KeyCtrlK
	KeyCtrlL
	KeyCtrlN
	KeyCtrlO
	KeyCtrlP
	KeyCtrlQ
	KeyCtrlR
	KeyCtrlS
	KeyCtrlT
	KeyCtrlU
	KeyCtrlV
	KeyCtrlW
	KeyCtrlX
	KeyCtrlY
	KeyCtrlZ
)

按键常量

type Modifiers

type Modifiers int

Modifiers 表示修饰键

const (
	ModNone  Modifiers = 0
	ModShift Modifiers = 1 << iota
	ModCtrl
	ModAlt
)

type MouseButton

type MouseButton int

MouseButton 鼠标按钮

const (
	MouseButtonNone MouseButton = iota
	MouseButtonLeft
	MouseButtonMiddle
	MouseButtonRight
)

type MouseEvent

type MouseEvent struct {
	X, Y   int
	Button MouseButton
	Type   MouseEventType
}

MouseEvent 鼠标事件

type MouseEventType

type MouseEventType int

MouseEventType 鼠标事件类型

const (
	MouseEventPress MouseEventType = iota
	MouseEventRelease
	MouseEventClick
	MouseEventMove
	MouseEventScrollUp
	MouseEventScrollDown
)

type Node

type Node interface {
	// contains filtered or unexported methods
}

Node 是所有视图节点的接口

func Button

func Button(c C, props ButtonProps) Node

func Center

func Center(child Node) Node

Center 辅助组件:将内容在可用空间内水平和垂直居中

func Checkbox

func Checkbox(c C, props CheckboxProps) Node

func Cursor

func Cursor(c C) Node

Cursor 创建一个光标标记节点 需要传入 C 来访问 runtime

func For

func For[T any](items []T, render func(item T, index int) Node) Node

For 列表渲染:遍历 items 并用 render 函数渲染每个元素

func Spinner

func Spinner(c C, label string) Node

func Stats

func Stats(c C) Node

Stats 返回一个显示 FPS 和性能信息的组件。 它会自动启动一个后台计时器以确保在界面静止时也能更新 FPS 数值。

func TextInput

func TextInput(c C, props TextInputProps) Node

type Rect

type Rect struct {
	X, Y, W, H int
}

Rect 表示屏幕上的矩形区域

func (Rect) Contains

func (r Rect) Contains(x, y int) bool

Contains 检查点是否在矩形内

type Ref

type Ref[T any] struct {
	Current T
}

Ref 引用类型,用于避免闭包陷阱

func UseRef

func UseRef[T any](c C, initial T) *Ref[T]

UseRef 创建一个引用

type Runtime

type Runtime struct {
	// contains filtered or unexported fields
}

Runtime 是应用运行时

func NewTestRuntime

func NewTestRuntime(root func(C) Node, screen tcell.Screen) *Runtime

NewTestRuntime 创建一个用于测试的运行时

func (*Runtime) DispatchKey

func (r *Runtime) DispatchKey(key tcell.Key, r_rune rune, mod tcell.ModMask)

DispatchKey 分发键盘事件(用于测试)

func (*Runtime) Render

func (r *Runtime) Render()

Render 立即执行一次渲染(用于测试)

func (*Runtime) Run

func (r *Runtime) Run() error

Run 启动运行时

type State

type State[T any] struct {
	Val T
	// contains filtered or unexported fields
}

State 表示一个状态值

func Use

func Use[T any](c C, key string, initial T) *State[T]

Use 声明一个状态

func (*State[T]) Set

func (s *State[T]) Set(value T)

Set 设置状态值并触发重渲染

func (*State[T]) Update

func (s *State[T]) Update(fn func(old T) T)

Update 使用函数更新状态值

type Style

type Style struct {
	// contains filtered or unexported fields
}

Style 表示样式

func NewStyle

func NewStyle() Style

NewStyle 创建一个新的样式对象

func (Style) Align

func (s Style) Align(a Align) Style

func (Style) Background

func (s Style) Background(c Color) Style
func (s Style) Blink() Style

func (Style) Bold

func (s Style) Bold() Style

func (Style) Border

func (s Style) Border(style BorderStyle) Style

func (Style) BorderColor

func (s Style) BorderColor(c Color) Style

func (Style) Dim

func (s Style) Dim() Style

func (Style) Flex

func (s Style) Flex(f int) Style

func (Style) Foreground

func (s Style) Foreground(c Color) Style

func (Style) Height

func (s Style) Height(h int) Style

func (Style) Italic

func (s Style) Italic() Style

func (Style) Padding

func (s Style) Padding(v, h int) Style

func (Style) PaddingAll

func (s Style) PaddingAll(top, right, bottom, left int) Style

func (Style) Underline

func (s Style) Underline() Style

func (Style) Valign

func (s Style) Valign(a Align) Style

func (Style) Width

func (s Style) Width(w int) Style

type TextInputProps

type TextInputProps struct {
	Value       string
	Placeholder string
	Label       string
	Width       int
	Height      int  // 0 表示单行,>1 表示多行
	Multiline   bool // 是否开启多行模式
	OnChanged   func(string)
	OnSubmit    func(string)
	Password    bool // 是否为密码模式
}

Directories

Path Synopsis
examples
agent command
bridge_demo command
counter command
dashboard command
focus command
form command
gallery command
hello command
layout command
markdown command
mouse command
stream command
theme command
timer command
todo command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL