Update devcontainer configuration and enhance terminal handling in InkApp. Change base image to 'devpit:latest' and implement a blinking cursor feature in the terminal display, improving user experience and visual feedback during input.

This commit is contained in:
sebseb7
2025-08-12 22:02:01 +00:00
parent 0815d64802
commit 14305859de
3 changed files with 71 additions and 29 deletions

View File

@@ -4,6 +4,26 @@ import TextInput from 'ink-text-input';
import terminalService from '../terminalService.js';
class Pane extends React.Component {
constructor(props) {
super(props);
this.state = {
cursorVisible: true,
};
this._cursorTimer = null;
}
componentDidMount() {
if (this.props.showCursor) {
this._cursorTimer = setInterval(() => {
this.setState((s) => ({ cursorVisible: !s.cursorVisible }));
}, typeof this.props.cursorBlinkMs === 'number' && this.props.cursorBlinkMs > 0 ? this.props.cursorBlinkMs : 500);
}
}
componentWillUnmount() {
if (this._cursorTimer) {
clearInterval(this._cursorTimer);
this._cursorTimer = null;
}
}
// Strip ANSI escape sequences so width measurement/truncation is accurate
stripAnsi(input) {
if (input == null) return '';
@@ -35,6 +55,26 @@ class Pane extends React.Component {
}
return out;
}
// Apply a blinking cursor to the given line according to width constraints
withCursor(line, maxWidth) {
const cursorChar = typeof this.props.cursorChar === 'string' && this.props.cursorChar.length > 0 ? this.props.cursorChar[0] : '█';
const visible = !!this.state.cursorVisible;
if (!visible) {
return line;
}
if (typeof maxWidth === 'number' && maxWidth > 0) {
if (line.length < maxWidth) {
return `${line}${cursorChar}`;
}
if (line.length === maxWidth) {
// Replace last char to avoid overflow
return `${line.slice(0, maxWidth - 1)}${cursorChar}`;
}
// If somehow longer, just ensure width
return `${line.slice(0, maxWidth - 1)}${cursorChar}`;
}
return `${line}${cursorChar}`;
}
render() {
const { title, lines, maxWidth } = this.props;
return (
@@ -42,20 +82,17 @@ class Pane extends React.Component {
<Text color="cyan">{title}</Text>
<Box flexDirection="column" width="100%" flexShrink={1} minWidth={0}>
{(lines && lines.length > 0)
? lines.map((line, index) => (
<Text key={index}>{
(() => {
const clean = this.stripAnsi(line);
const width = typeof maxWidth === 'number' && maxWidth > 0 ? maxWidth : undefined;
// Expand tabs before slicing to visual width
const expanded = this.expandTabs(clean, 8, width);
if (width && expanded.length > width) {
return expanded.slice(0, width);
}
return expanded;
})()
}</Text>
))
? lines.map((line, index) => {
const isLast = index === lines.length - 1;
const width = typeof maxWidth === 'number' && maxWidth > 0 ? maxWidth : undefined;
const clean = this.stripAnsi(line);
const expanded = this.expandTabs(clean, 8, width);
const baseLine = (width && expanded.length > width) ? expanded.slice(0, width) : expanded;
const finalLine = (this.props.showCursor && isLast) ? this.withCursor(baseLine, width) : baseLine;
return (
<Text key={index}>{finalLine}</Text>
);
})
: <Text dimColor></Text>
}
</Box>
@@ -201,7 +238,7 @@ export default class InkApp extends React.Component {
<Pane title="Chain of Thought" lines={chainOfThoughtView} maxWidth={paneContentWidth} />
</Box>
<Box flexGrow={1} flexDirection="column" minWidth={0}>
<Pane title="Terminal" lines={terminalView} maxWidth={paneContentWidth} />
<Pane title="Terminal" lines={terminalView} maxWidth={paneContentWidth} showCursor cursorBlinkMs={600} />
<Pane title="Logging" lines={logsView} maxWidth={paneContentWidth} />
</Box>
</Box>