mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-22 00:00:27 +00:00
refactor(tui): Move examples from README to test directory
- Move chat application example to test/chat-app.ts - Move multi-component layout example to test/multi-layout.ts - Update README to reference example files instead of inline code - Add proper exit handlers (Ctrl+C) to all examples - Simplify README by reducing inline code examples
This commit is contained in:
parent
12dfcfad23
commit
838fde47ba
3 changed files with 181 additions and 186 deletions
|
|
@ -310,200 +310,30 @@ console.log(`Average per render: ${ui.getAverageLinesRedrawn()}`);
|
||||||
|
|
||||||
Typical performance: 1-2 lines redrawn for animations, 0 for static content.
|
Typical performance: 1-2 lines redrawn for animations, 0 for static content.
|
||||||
|
|
||||||
## Advanced Examples
|
## Examples
|
||||||
|
|
||||||
### Chat Application with Autocomplete
|
Run the example applications in the `test/` directory:
|
||||||
|
|
||||||
```typescript
|
```bash
|
||||||
import { TUI, Container, TextEditor, MarkdownComponent, CombinedAutocompleteProvider } from "@mariozechner/pi-tui";
|
# Chat application with slash commands and autocomplete
|
||||||
|
npx tsx test/chat-app.ts
|
||||||
|
|
||||||
const ui = new TUI();
|
# File browser with navigation
|
||||||
const chatHistory = new Container();
|
npx tsx test/file-browser.ts
|
||||||
const editor = new TextEditor();
|
|
||||||
|
|
||||||
// Set up autocomplete with slash commands
|
# Multi-component layout demo
|
||||||
const autocompleteProvider = new CombinedAutocompleteProvider([
|
npx tsx test/multi-layout.ts
|
||||||
{ name: "clear", description: "Clear chat history" },
|
|
||||||
{ name: "help", description: "Show help information" },
|
|
||||||
{
|
|
||||||
name: "attach",
|
|
||||||
description: "Attach a file",
|
|
||||||
getArgumentCompletions: (prefix) => {
|
|
||||||
// Return file suggestions for attach command
|
|
||||||
return null; // Use default file completion
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
editor.setAutocompleteProvider(autocompleteProvider);
|
# Performance benchmark with animation
|
||||||
|
npx tsx test/bench.ts
|
||||||
editor.onSubmit = (text) => {
|
|
||||||
// Handle slash commands
|
|
||||||
if (text.startsWith("/")) {
|
|
||||||
const [command, ...args] = text.slice(1).split(" ");
|
|
||||||
if (command === "clear") {
|
|
||||||
chatHistory.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (command === "help") {
|
|
||||||
const help = new MarkdownComponent(`
|
|
||||||
## Available Commands
|
|
||||||
- \`/clear\` - Clear chat history
|
|
||||||
- \`/help\` - Show this help
|
|
||||||
- \`/attach <file>\` - Attach a file
|
|
||||||
`);
|
|
||||||
chatHistory.addChild(help);
|
|
||||||
ui.requestRender();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular message
|
|
||||||
const message = new MarkdownComponent(`**You:** ${text}`);
|
|
||||||
chatHistory.addChild(message);
|
|
||||||
|
|
||||||
// Add AI response (simulated)
|
|
||||||
setTimeout(() => {
|
|
||||||
const response = new MarkdownComponent(`**AI:** Response to "${text}"`);
|
|
||||||
chatHistory.addChild(response);
|
|
||||||
ui.requestRender();
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
ui.addChild(chatHistory);
|
|
||||||
ui.addChild(editor);
|
|
||||||
ui.setFocus(editor);
|
|
||||||
ui.start();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### File Browser
|
### Example Descriptions
|
||||||
|
|
||||||
```typescript
|
- **chat-app.ts** - Chat interface with slash commands (/clear, /help, /attach) and autocomplete
|
||||||
import { TUI, SelectList } from "@mariozechner/pi-tui";
|
- **file-browser.ts** - Interactive file browser with directory navigation
|
||||||
import { readdirSync, statSync } from "fs";
|
- **multi-layout.ts** - Complex layout with header, sidebar, main content, and footer
|
||||||
import { join } from "path";
|
- **bench.ts** - Performance test with animation showing surgical rendering efficiency
|
||||||
|
|
||||||
const ui = new TUI();
|
|
||||||
let currentPath = process.cwd();
|
|
||||||
|
|
||||||
function createFileList(path: string) {
|
|
||||||
const entries = readdirSync(path).map((entry) => {
|
|
||||||
const fullPath = join(path, entry);
|
|
||||||
const isDir = statSync(fullPath).isDirectory();
|
|
||||||
return {
|
|
||||||
value: entry,
|
|
||||||
label: entry,
|
|
||||||
description: isDir ? "directory" : "file",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add parent directory option
|
|
||||||
if (path !== "/") {
|
|
||||||
entries.unshift({
|
|
||||||
value: "..",
|
|
||||||
label: "..",
|
|
||||||
description: "parent directory",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showDirectory(path: string) {
|
|
||||||
ui.clear();
|
|
||||||
|
|
||||||
const entries = createFileList(path);
|
|
||||||
const fileList = new SelectList(entries, 10);
|
|
||||||
|
|
||||||
fileList.onSelect = (item) => {
|
|
||||||
if (item.value === "..") {
|
|
||||||
currentPath = join(currentPath, "..");
|
|
||||||
showDirectory(currentPath);
|
|
||||||
} else if (item.description === "directory") {
|
|
||||||
currentPath = join(currentPath, item.value);
|
|
||||||
showDirectory(currentPath);
|
|
||||||
} else {
|
|
||||||
console.log(`Selected file: ${join(currentPath, item.value)}`);
|
|
||||||
ui.stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ui.addChild(fileList);
|
|
||||||
ui.setFocus(fileList);
|
|
||||||
}
|
|
||||||
|
|
||||||
showDirectory(currentPath);
|
|
||||||
ui.start();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multi-Component Layout
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { TUI, Container, TextComponent, TextEditor, MarkdownComponent } from "@mariozechner/pi-tui";
|
|
||||||
|
|
||||||
const ui = new TUI();
|
|
||||||
|
|
||||||
// Create layout containers
|
|
||||||
const header = new TextComponent("📝 Advanced TUI Demo", { bottom: 1 });
|
|
||||||
const mainContent = new Container();
|
|
||||||
const sidebar = new Container();
|
|
||||||
const footer = new TextComponent("Press Ctrl+C to exit", { top: 1 });
|
|
||||||
|
|
||||||
// Sidebar content
|
|
||||||
sidebar.addChild(new TextComponent("📁 Files:", { bottom: 1 }));
|
|
||||||
sidebar.addChild(new TextComponent("- config.json"));
|
|
||||||
sidebar.addChild(new TextComponent("- README.md"));
|
|
||||||
sidebar.addChild(new TextComponent("- package.json"));
|
|
||||||
|
|
||||||
// Main content area
|
|
||||||
const chatArea = new Container();
|
|
||||||
const inputArea = new TextEditor();
|
|
||||||
|
|
||||||
// Add welcome message
|
|
||||||
chatArea.addChild(
|
|
||||||
new MarkdownComponent(`
|
|
||||||
# Welcome to the TUI Demo
|
|
||||||
|
|
||||||
This demonstrates multiple components working together:
|
|
||||||
|
|
||||||
- **Header**: Static title with padding
|
|
||||||
- **Sidebar**: File list (simulated)
|
|
||||||
- **Chat Area**: Scrollable message history
|
|
||||||
- **Input**: Interactive text editor
|
|
||||||
- **Footer**: Status information
|
|
||||||
|
|
||||||
Try typing a message and pressing Enter!
|
|
||||||
`),
|
|
||||||
);
|
|
||||||
|
|
||||||
inputArea.onSubmit = (text) => {
|
|
||||||
if (text.trim()) {
|
|
||||||
const message = new MarkdownComponent(`
|
|
||||||
**${new Date().toLocaleTimeString()}:** ${text}
|
|
||||||
`);
|
|
||||||
chatArea.addChild(message);
|
|
||||||
ui.requestRender();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build layout
|
|
||||||
mainContent.addChild(chatArea);
|
|
||||||
mainContent.addChild(inputArea);
|
|
||||||
|
|
||||||
ui.addChild(header);
|
|
||||||
ui.addChild(mainContent);
|
|
||||||
ui.addChild(footer);
|
|
||||||
ui.setFocus(inputArea);
|
|
||||||
|
|
||||||
// Configure debug logging
|
|
||||||
ui.configureLogging({
|
|
||||||
enabled: true,
|
|
||||||
level: "info",
|
|
||||||
logFile: "tui-debug.log",
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.start();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Interfaces and Types
|
## Interfaces and Types
|
||||||
|
|
||||||
|
|
|
||||||
80
packages/tui/test/chat-app.ts
Normal file
80
packages/tui/test/chat-app.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/env npx tsx
|
||||||
|
import { TUI, Container, TextEditor, MarkdownComponent, CombinedAutocompleteProvider } from "../src/index.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat Application with Autocomplete
|
||||||
|
*
|
||||||
|
* Demonstrates:
|
||||||
|
* - Slash command system with autocomplete
|
||||||
|
* - Dynamic message history
|
||||||
|
* - Markdown rendering for messages
|
||||||
|
* - Container-based layout
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ui = new TUI();
|
||||||
|
const chatHistory = new Container();
|
||||||
|
const editor = new TextEditor();
|
||||||
|
|
||||||
|
// Set up autocomplete with slash commands
|
||||||
|
const autocompleteProvider = new CombinedAutocompleteProvider([
|
||||||
|
{ name: "clear", description: "Clear chat history" },
|
||||||
|
{ name: "help", description: "Show help information" },
|
||||||
|
{
|
||||||
|
name: "attach",
|
||||||
|
description: "Attach a file",
|
||||||
|
getArgumentCompletions: (prefix) => {
|
||||||
|
// Return file suggestions for attach command
|
||||||
|
return null; // Use default file completion
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
editor.setAutocompleteProvider(autocompleteProvider);
|
||||||
|
|
||||||
|
editor.onSubmit = (text) => {
|
||||||
|
// Handle slash commands
|
||||||
|
if (text.startsWith("/")) {
|
||||||
|
const [command, ...args] = text.slice(1).split(" ");
|
||||||
|
if (command === "clear") {
|
||||||
|
chatHistory.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (command === "help") {
|
||||||
|
const help = new MarkdownComponent(`
|
||||||
|
## Available Commands
|
||||||
|
- \`/clear\` - Clear chat history
|
||||||
|
- \`/help\` - Show this help
|
||||||
|
- \`/attach <file>\` - Attach a file
|
||||||
|
`);
|
||||||
|
chatHistory.addChild(help);
|
||||||
|
ui.requestRender();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular message
|
||||||
|
const message = new MarkdownComponent(`**You:** ${text}`);
|
||||||
|
chatHistory.addChild(message);
|
||||||
|
|
||||||
|
// Add AI response (simulated)
|
||||||
|
setTimeout(() => {
|
||||||
|
const response = new MarkdownComponent(`**AI:** Response to "${text}"`);
|
||||||
|
chatHistory.addChild(response);
|
||||||
|
ui.requestRender();
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle Ctrl+C to exit
|
||||||
|
ui.onGlobalKeyPress = (data: string) => {
|
||||||
|
if (data === "\x03") {
|
||||||
|
ui.stop();
|
||||||
|
console.log("\nChat application exited");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.addChild(chatHistory);
|
||||||
|
ui.addChild(editor);
|
||||||
|
ui.setFocus(editor);
|
||||||
|
ui.start();
|
||||||
85
packages/tui/test/multi-layout.ts
Normal file
85
packages/tui/test/multi-layout.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
#!/usr/bin/env npx tsx
|
||||||
|
import { TUI, Container, TextComponent, TextEditor, MarkdownComponent } from "../src/index.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-Component Layout Demo
|
||||||
|
*
|
||||||
|
* Demonstrates:
|
||||||
|
* - Complex layout with multiple containers
|
||||||
|
* - Header, sidebar, main content, and footer areas
|
||||||
|
* - Mixing static and dynamic components
|
||||||
|
* - Debug logging configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ui = new TUI();
|
||||||
|
|
||||||
|
// Create layout containers
|
||||||
|
const header = new TextComponent("📝 Advanced TUI Demo", { bottom: 1 });
|
||||||
|
const mainContent = new Container();
|
||||||
|
const sidebar = new Container();
|
||||||
|
const footer = new TextComponent("Press Ctrl+C to exit", { top: 1 });
|
||||||
|
|
||||||
|
// Sidebar content
|
||||||
|
sidebar.addChild(new TextComponent("📁 Files:", { bottom: 1 }));
|
||||||
|
sidebar.addChild(new TextComponent("- config.json"));
|
||||||
|
sidebar.addChild(new TextComponent("- README.md"));
|
||||||
|
sidebar.addChild(new TextComponent("- package.json"));
|
||||||
|
|
||||||
|
// Main content area
|
||||||
|
const chatArea = new Container();
|
||||||
|
const inputArea = new TextEditor();
|
||||||
|
|
||||||
|
// Add welcome message
|
||||||
|
chatArea.addChild(
|
||||||
|
new MarkdownComponent(`
|
||||||
|
# Welcome to the TUI Demo
|
||||||
|
|
||||||
|
This demonstrates multiple components working together:
|
||||||
|
|
||||||
|
- **Header**: Static title with padding
|
||||||
|
- **Sidebar**: File list (simulated)
|
||||||
|
- **Chat Area**: Scrollable message history
|
||||||
|
- **Input**: Interactive text editor
|
||||||
|
- **Footer**: Status information
|
||||||
|
|
||||||
|
Try typing a message and pressing Enter!
|
||||||
|
`),
|
||||||
|
);
|
||||||
|
|
||||||
|
inputArea.onSubmit = (text) => {
|
||||||
|
if (text.trim()) {
|
||||||
|
const message = new MarkdownComponent(`
|
||||||
|
**${new Date().toLocaleTimeString()}:** ${text}
|
||||||
|
`);
|
||||||
|
chatArea.addChild(message);
|
||||||
|
ui.requestRender();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build layout
|
||||||
|
mainContent.addChild(chatArea);
|
||||||
|
mainContent.addChild(inputArea);
|
||||||
|
|
||||||
|
ui.addChild(header);
|
||||||
|
ui.addChild(mainContent);
|
||||||
|
ui.addChild(footer);
|
||||||
|
ui.setFocus(inputArea);
|
||||||
|
|
||||||
|
// Configure debug logging
|
||||||
|
ui.configureLogging({
|
||||||
|
enabled: true,
|
||||||
|
level: "info",
|
||||||
|
logFile: "tui-debug.log",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Ctrl+C to exit
|
||||||
|
ui.onGlobalKeyPress = (data: string) => {
|
||||||
|
if (data === "\x03") {
|
||||||
|
ui.stop();
|
||||||
|
console.log("\nMulti-layout demo exited");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.start();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue