@oh-my-pi/pi-tui 11.8.3 → 11.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/autocomplete.ts +34 -4
- package/src/components/editor.ts +45 -3
- package/src/components/select-list.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-tui",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.10.0",
|
|
4
4
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"bun": ">=1.3.7"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@oh-my-pi/pi-natives": "11.
|
|
51
|
-
"@oh-my-pi/pi-utils": "11.
|
|
50
|
+
"@oh-my-pi/pi-natives": "11.10.0",
|
|
51
|
+
"@oh-my-pi/pi-utils": "11.10.0",
|
|
52
52
|
"@types/mime-types": "^3.0.1",
|
|
53
53
|
"chalk": "^5.6.2",
|
|
54
54
|
"marked": "^17.0.1",
|
package/src/autocomplete.ts
CHANGED
|
@@ -130,6 +130,8 @@ export interface AutocompleteItem {
|
|
|
130
130
|
value: string;
|
|
131
131
|
label: string;
|
|
132
132
|
description?: string;
|
|
133
|
+
/** Dim hint text shown inline after cursor when this item is selected */
|
|
134
|
+
hint?: string;
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
export interface SlashCommand {
|
|
@@ -138,11 +140,12 @@ export interface SlashCommand {
|
|
|
138
140
|
// Function to get argument completions for this command
|
|
139
141
|
// Returns null if no argument completion is available
|
|
140
142
|
getArgumentCompletions?(argumentPrefix: string): AutocompleteItem[] | null;
|
|
143
|
+
/** Return inline hint text for the current argument state (shown as dim ghost text after cursor) */
|
|
144
|
+
getInlineHint?(argumentText: string): string | null;
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
export interface AutocompleteProvider {
|
|
144
|
-
|
|
145
|
-
// Returns null if no suggestions available
|
|
148
|
+
/** Get autocomplete suggestions for current text/cursor position */
|
|
146
149
|
getSuggestions(
|
|
147
150
|
lines: string[],
|
|
148
151
|
cursorLine: number,
|
|
@@ -152,8 +155,7 @@ export interface AutocompleteProvider {
|
|
|
152
155
|
prefix: string; // What we're matching against (e.g., "/" or "src/")
|
|
153
156
|
} | null>;
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
// Returns the new text and cursor position
|
|
158
|
+
/** Apply the selected item and return new text + cursor position */
|
|
157
159
|
applyCompletion(
|
|
158
160
|
lines: string[],
|
|
159
161
|
cursorLine: number,
|
|
@@ -165,6 +167,9 @@ export interface AutocompleteProvider {
|
|
|
165
167
|
cursorLine: number;
|
|
166
168
|
cursorCol: number;
|
|
167
169
|
};
|
|
170
|
+
|
|
171
|
+
/** Get inline hint text to show as dim ghost text after the cursor */
|
|
172
|
+
getInlineHint?(lines: string[], cursorLine: number, cursorCol: number): string | null;
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
// Combined provider that handles both slash commands and file paths
|
|
@@ -715,4 +720,29 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
|
|
|
715
720
|
|
|
716
721
|
return true;
|
|
717
722
|
}
|
|
723
|
+
|
|
724
|
+
/** Get inline hint text for slash commands with subcommand hints */
|
|
725
|
+
getInlineHint(lines: string[], cursorLine: number, cursorCol: number): string | null {
|
|
726
|
+
const currentLine = lines[cursorLine] || "";
|
|
727
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
728
|
+
|
|
729
|
+
if (!textBeforeCursor.startsWith("/")) return null;
|
|
730
|
+
|
|
731
|
+
const spaceIndex = textBeforeCursor.indexOf(" ");
|
|
732
|
+
if (spaceIndex === -1) return null;
|
|
733
|
+
|
|
734
|
+
const commandName = textBeforeCursor.slice(1, spaceIndex);
|
|
735
|
+
const argumentText = textBeforeCursor.slice(spaceIndex + 1);
|
|
736
|
+
|
|
737
|
+
const command = this.#commands.find(cmd => {
|
|
738
|
+
const name = "name" in cmd ? cmd.name : cmd.value;
|
|
739
|
+
return name === commandName;
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
if (!command || !("getInlineHint" in command) || !command.getInlineHint) {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return command.getInlineHint(argumentText);
|
|
747
|
+
}
|
|
718
748
|
}
|
package/src/components/editor.ts
CHANGED
|
@@ -263,6 +263,8 @@ export interface EditorTheme {
|
|
|
263
263
|
selectList: SelectListTheme;
|
|
264
264
|
symbols: SymbolTheme;
|
|
265
265
|
editorPaddingX?: number;
|
|
266
|
+
/** Style function for inline hint/ghost text (dim text after cursor) */
|
|
267
|
+
hintStyle?: (text: string) => string;
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
export interface EditorTopBorder {
|
|
@@ -553,6 +555,10 @@ export class Editor implements Component, Focusable {
|
|
|
553
555
|
const emitCursorMarker = this.focused && !this.#autocompleteState;
|
|
554
556
|
const lineContentWidth = contentAreaWidth;
|
|
555
557
|
|
|
558
|
+
// Compute inline hint text (dim ghost text after cursor)
|
|
559
|
+
const inlineHint = this.#getInlineHint();
|
|
560
|
+
const hintStyle = this.#theme.hintStyle ?? ((t: string) => `\x1b[2m${t}\x1b[0m`);
|
|
561
|
+
|
|
556
562
|
for (const layoutLine of visibleLayoutLines) {
|
|
557
563
|
let displayText = layoutLine.text;
|
|
558
564
|
let displayWidth = visibleWidth(layoutLine.text);
|
|
@@ -566,7 +572,13 @@ export class Editor implements Component, Focusable {
|
|
|
566
572
|
if (marker) {
|
|
567
573
|
const before = displayText.slice(0, layoutLine.cursorPos);
|
|
568
574
|
const after = displayText.slice(layoutLine.cursorPos);
|
|
569
|
-
|
|
575
|
+
if (after.length === 0 && inlineHint) {
|
|
576
|
+
const hintText = hintStyle(truncateToWidth(inlineHint, Math.max(0, lineContentWidth - displayWidth)));
|
|
577
|
+
displayText = before + marker + hintText;
|
|
578
|
+
displayWidth += visibleWidth(inlineHint);
|
|
579
|
+
} else {
|
|
580
|
+
displayText = before + marker + after;
|
|
581
|
+
}
|
|
570
582
|
}
|
|
571
583
|
} else if (hasCursor && !this.#useTerminalCursor) {
|
|
572
584
|
const before = displayText.slice(0, layoutLine.cursorPos);
|
|
@@ -585,8 +597,15 @@ export class Editor implements Component, Focusable {
|
|
|
585
597
|
// Cursor is at the end - add thin cursor glyph
|
|
586
598
|
const cursorChar = this.#theme.symbols.inputCursor;
|
|
587
599
|
const cursor = `\x1b[5m${cursorChar}\x1b[0m`;
|
|
588
|
-
|
|
589
|
-
|
|
600
|
+
if (inlineHint) {
|
|
601
|
+
const availWidth = Math.max(0, lineContentWidth - displayWidth - visibleWidth(cursorChar));
|
|
602
|
+
const hintText = hintStyle(truncateToWidth(inlineHint, availWidth));
|
|
603
|
+
displayText = before + marker + cursor + hintText;
|
|
604
|
+
displayWidth += visibleWidth(cursorChar) + Math.min(visibleWidth(inlineHint), availWidth);
|
|
605
|
+
} else {
|
|
606
|
+
displayText = before + marker + cursor;
|
|
607
|
+
displayWidth += visibleWidth(cursorChar);
|
|
608
|
+
}
|
|
590
609
|
if (displayWidth > lineContentWidth && paddingX > 0) {
|
|
591
610
|
cursorInPadding = true;
|
|
592
611
|
}
|
|
@@ -2168,4 +2187,27 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
2168
2187
|
this.#autocompleteTimeout = undefined;
|
|
2169
2188
|
}
|
|
2170
2189
|
}
|
|
2190
|
+
|
|
2191
|
+
/**
|
|
2192
|
+
* Get inline hint text to show as dim ghost text after the cursor.
|
|
2193
|
+
* Checks selected autocomplete item's hint first, then falls back to provider.
|
|
2194
|
+
*/
|
|
2195
|
+
#getInlineHint(): string | null {
|
|
2196
|
+
// Check selected autocomplete item for a hint
|
|
2197
|
+
if (this.#autocompleteState && this.#autocompleteList) {
|
|
2198
|
+
const selected = this.#autocompleteList.getSelectedItem();
|
|
2199
|
+
return selected?.hint ?? null;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
// Fall back to provider's getInlineHint
|
|
2203
|
+
if (this.#autocompleteProvider?.getInlineHint) {
|
|
2204
|
+
return this.#autocompleteProvider.getInlineHint(
|
|
2205
|
+
this.#state.lines,
|
|
2206
|
+
this.#state.cursorLine,
|
|
2207
|
+
this.#state.cursorCol,
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
return null;
|
|
2212
|
+
}
|
|
2171
2213
|
}
|