mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 19:05:11 +00:00
fix(tui): always position cursor for IME
# Conflicts: # packages/coding-agent/CHANGELOG.md
This commit is contained in:
parent
cd43b8a9ca
commit
673916f63c
7 changed files with 87 additions and 11 deletions
|
|
@ -5,6 +5,8 @@
|
|||
### Added
|
||||
|
||||
- Export `keyHint`, `appKeyHint`, `editorKey`, `appKey`, `rawKeyHint` for extensions to format keybinding hints consistently
|
||||
- Added `showHardwareCursor` setting to control cursor visibility while still positioning it for IME support. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
|
||||
- Added `ctx.compact()` and `ctx.getContextUsage()` to extension contexts for programmatic compaction and context usage checks.
|
||||
|
||||
## [0.48.0] - 2026-01-16
|
||||
|
||||
|
|
|
|||
|
|
@ -789,6 +789,7 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|||
"autoResize": true,
|
||||
"blockImages": false
|
||||
},
|
||||
"showHardwareCursor": false,
|
||||
"extensions": ["/path/to/extension.ts"]
|
||||
}
|
||||
```
|
||||
|
|
@ -816,6 +817,7 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|||
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
||||
| `images.autoResize` | Auto-resize images to 2000x2000 max for better model compatibility | `true` |
|
||||
| `images.blockImages` | Prevent images from being sent to LLM providers | `false` |
|
||||
| `showHardwareCursor` | Show terminal cursor while still positioning it for IME support | `false` |
|
||||
| `doubleEscapeAction` | Action for double-escape with empty editor: `tree` or `branch` | `tree` |
|
||||
| `editorPaddingX` | Horizontal padding for input editor (0-3) | `0` |
|
||||
| `extensions` | Additional extension file paths | `[]` |
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export interface Settings {
|
|||
doubleEscapeAction?: "fork" | "tree"; // Action for double-escape with empty editor (default: "tree")
|
||||
thinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels
|
||||
editorPaddingX?: number; // Horizontal padding for input editor (default: 0)
|
||||
showHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME
|
||||
}
|
||||
|
||||
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
||||
|
|
@ -482,6 +483,15 @@ export class SettingsManager {
|
|||
this.save();
|
||||
}
|
||||
|
||||
getShowHardwareCursor(): boolean {
|
||||
return this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === "1";
|
||||
}
|
||||
|
||||
setShowHardwareCursor(enabled: boolean): void {
|
||||
this.globalSettings.showHardwareCursor = enabled;
|
||||
this.save();
|
||||
}
|
||||
|
||||
getEditorPaddingX(): number {
|
||||
return this.settings.editorPaddingX ?? 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ export interface SettingsConfig {
|
|||
hideThinkingBlock: boolean;
|
||||
collapseChangelog: boolean;
|
||||
doubleEscapeAction: "fork" | "tree";
|
||||
showHardwareCursor: boolean;
|
||||
editorPaddingX: number;
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +54,7 @@ export interface SettingsCallbacks {
|
|||
onHideThinkingBlockChange: (hidden: boolean) => void;
|
||||
onCollapseChangelogChange: (collapsed: boolean) => void;
|
||||
onDoubleEscapeActionChange: (action: "fork" | "tree") => void;
|
||||
onShowHardwareCursorChange: (enabled: boolean) => void;
|
||||
onEditorPaddingXChange: (padding: number) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
|
@ -269,9 +271,19 @@ export class SettingsSelectorComponent extends Container {
|
|||
values: ["true", "false"],
|
||||
});
|
||||
|
||||
// Editor padding toggle (insert after skill-commands)
|
||||
// Hardware cursor toggle (insert after skill-commands)
|
||||
const skillCommandsIndex = items.findIndex((item) => item.id === "skill-commands");
|
||||
items.splice(skillCommandsIndex + 1, 0, {
|
||||
id: "show-hardware-cursor",
|
||||
label: "Show hardware cursor",
|
||||
description: "Show the terminal cursor while still positioning it for IME support",
|
||||
currentValue: config.showHardwareCursor ? "true" : "false",
|
||||
values: ["true", "false"],
|
||||
});
|
||||
|
||||
// Editor padding toggle (insert after show-hardware-cursor)
|
||||
const hardwareCursorIndex = items.findIndex((item) => item.id === "show-hardware-cursor");
|
||||
items.splice(hardwareCursorIndex + 1, 0, {
|
||||
id: "editor-padding",
|
||||
label: "Editor padding",
|
||||
description: "Horizontal padding for input editor (0-3)",
|
||||
|
|
@ -318,6 +330,9 @@ export class SettingsSelectorComponent extends Container {
|
|||
case "double-escape-action":
|
||||
callbacks.onDoubleEscapeActionChange(newValue as "fork" | "tree");
|
||||
break;
|
||||
case "show-hardware-cursor":
|
||||
callbacks.onShowHardwareCursorChange(newValue === "true");
|
||||
break;
|
||||
case "editor-padding":
|
||||
callbacks.onEditorPaddingXChange(parseInt(newValue, 10));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ export class InteractiveMode {
|
|||
) {
|
||||
this.session = session;
|
||||
this.version = VERSION;
|
||||
this.ui = new TUI(new ProcessTerminal());
|
||||
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
||||
this.chatContainer = new Container();
|
||||
this.pendingMessagesContainer = new Container();
|
||||
this.statusContainer = new Container();
|
||||
|
|
@ -689,6 +689,18 @@ export class InteractiveMode {
|
|||
shutdown: () => {
|
||||
this.shutdownRequested = true;
|
||||
},
|
||||
getContextUsage: () => this.session.getContextUsage(),
|
||||
compact: (options) => {
|
||||
void (async () => {
|
||||
try {
|
||||
const result = await this.session.compact(options?.customInstructions);
|
||||
options?.onComplete?.(result);
|
||||
} catch (error) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
options?.onError?.(err);
|
||||
}
|
||||
})();
|
||||
},
|
||||
},
|
||||
// ExtensionCommandContextActions - for ctx.* in command handlers
|
||||
{
|
||||
|
|
@ -813,6 +825,18 @@ export class InteractiveMode {
|
|||
shutdown: () => {
|
||||
this.shutdownRequested = true;
|
||||
},
|
||||
getContextUsage: () => this.session.getContextUsage(),
|
||||
compact: (options) => {
|
||||
void (async () => {
|
||||
try {
|
||||
const result = await this.session.compact(options?.customInstructions);
|
||||
options?.onComplete?.(result);
|
||||
} catch (error) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
options?.onError?.(err);
|
||||
}
|
||||
})();
|
||||
},
|
||||
});
|
||||
|
||||
// Set up the extension shortcut handler on the default editor
|
||||
|
|
@ -2521,6 +2545,7 @@ export class InteractiveMode {
|
|||
hideThinkingBlock: this.hideThinkingBlock,
|
||||
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
||||
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
||||
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
||||
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
||||
},
|
||||
{
|
||||
|
|
@ -2589,6 +2614,10 @@ export class InteractiveMode {
|
|||
onDoubleEscapeActionChange: (action) => {
|
||||
this.settingsManager.setDoubleEscapeAction(action);
|
||||
},
|
||||
onShowHardwareCursorChange: (enabled) => {
|
||||
this.settingsManager.setShowHardwareCursor(enabled);
|
||||
this.ui.setShowHardwareCursor(enabled);
|
||||
},
|
||||
onEditorPaddingXChange: (padding) => {
|
||||
this.settingsManager.setEditorPaddingX(padding);
|
||||
this.defaultEditor.setPaddingX(padding);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added `showHardwareCursor` getter and setter to control cursor visibility while keeping IME positioning active. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
|
||||
|
||||
## [0.48.0] - 2026-01-16
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ export class TUI extends Container {
|
|||
private hardwareCursorRow = 0; // Actual terminal cursor row (may differ due to IME positioning)
|
||||
private inputBuffer = ""; // Buffer for parsing terminal responses
|
||||
private cellSizeQueryPending = false;
|
||||
private useHardwareCursor = process.env.PI_HARDWARE_CURSOR === "1";
|
||||
private showHardwareCursor = process.env.PI_HARDWARE_CURSOR === "1";
|
||||
|
||||
// Overlay stack for modal components rendered on top of base content
|
||||
private overlayStack: {
|
||||
|
|
@ -218,9 +218,25 @@ export class TUI extends Container {
|
|||
hidden: boolean;
|
||||
}[] = [];
|
||||
|
||||
constructor(terminal: Terminal) {
|
||||
constructor(terminal: Terminal, showHardwareCursor?: boolean) {
|
||||
super();
|
||||
this.terminal = terminal;
|
||||
if (showHardwareCursor !== undefined) {
|
||||
this.showHardwareCursor = showHardwareCursor;
|
||||
}
|
||||
}
|
||||
|
||||
getShowHardwareCursor(): boolean {
|
||||
return this.showHardwareCursor;
|
||||
}
|
||||
|
||||
setShowHardwareCursor(enabled: boolean): void {
|
||||
if (this.showHardwareCursor === enabled) return;
|
||||
this.showHardwareCursor = enabled;
|
||||
if (!enabled) {
|
||||
this.terminal.hideCursor();
|
||||
}
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
setFocus(component: Component | null): void {
|
||||
|
|
@ -982,12 +998,6 @@ export class TUI extends Container {
|
|||
* @param totalLines Total number of rendered lines
|
||||
*/
|
||||
private positionHardwareCursor(cursorPos: { row: number; col: number } | null, totalLines: number): void {
|
||||
// PI_HARDWARE_CURSOR=1 enables hardware cursor (disabled by default due to terminal compatibility issues)
|
||||
if (!this.useHardwareCursor) {
|
||||
this.terminal.hideCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cursorPos || totalLines <= 0) {
|
||||
this.terminal.hideCursor();
|
||||
return;
|
||||
|
|
@ -1013,6 +1023,10 @@ export class TUI extends Container {
|
|||
}
|
||||
|
||||
this.hardwareCursorRow = targetRow;
|
||||
this.terminal.showCursor();
|
||||
if (this.showHardwareCursor) {
|
||||
this.terminal.showCursor();
|
||||
} else {
|
||||
this.terminal.hideCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue