@f5-sales-demo/pi-tui 21.13.2 → 21.14.1
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/CHANGELOG.md +9 -3
- package/package.json +3 -3
- package/src/autocomplete.ts +9 -3
- package/src/components/editor.ts +18 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Kept `@` directory completion open after Tab or Enter without inserting a trailing space ([#3724](https://github.com/f5-sales-demo/xcsh/issues/3724)).
|
|
10
|
+
|
|
5
11
|
## [20.3.0] - 2026-08-04
|
|
6
12
|
|
|
7
13
|
<!-- textlint-disable terminology -->
|
|
@@ -274,7 +280,7 @@
|
|
|
274
280
|
|
|
275
281
|
### Fixed
|
|
276
282
|
|
|
277
|
-
- Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of
|
|
283
|
+
- Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of empty lines from being output
|
|
278
284
|
|
|
279
285
|
## [11.3.0] - 2026-02-06
|
|
280
286
|
|
|
@@ -307,7 +313,7 @@
|
|
|
307
313
|
|
|
308
314
|
### Fixed
|
|
309
315
|
|
|
310
|
-
- Fixed rendering of extra
|
|
316
|
+
- Fixed rendering of extra empty lines when content shrinks by improving cursor positioning logic during line deletion
|
|
311
317
|
- Fixed cursor display position in Input component when scrolling horizontally through long text
|
|
312
318
|
- Fixed Kitty keyboard protocol disable sequence to use safe write method, preventing potential output buffering issues
|
|
313
319
|
- Fixed unnecessary full-screen redraws when changes occur in out-of-view components (e.g., spinners), reducing terminal scroll events and improving performance on slower connections
|
|
@@ -430,7 +436,7 @@
|
|
|
430
436
|
- Improved blockquote rendering with text wrapping in Markdown component
|
|
431
437
|
- Restructured terminal capabilities from interface-based to class-based model
|
|
432
438
|
- Improved table column width calculation with word-aware wrapping
|
|
433
|
-
- Refactored text utilities to use native
|
|
439
|
+
- Refactored text utilities to use native Wasm implementations for strings >256 chars with JS fast path
|
|
434
440
|
|
|
435
441
|
### Fixed
|
|
436
442
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-tui",
|
|
4
|
-
"version": "21.
|
|
4
|
+
"version": "21.14.1",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"fmt": "biome format --write ."
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@f5-sales-demo/pi-natives": "21.
|
|
41
|
-
"@f5-sales-demo/pi-utils": "21.
|
|
40
|
+
"@f5-sales-demo/pi-natives": "21.14.1",
|
|
41
|
+
"@f5-sales-demo/pi-utils": "21.14.1",
|
|
42
42
|
"marked": "^18.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
package/src/autocomplete.ts
CHANGED
|
@@ -89,6 +89,11 @@ function parsePathPrefix(prefix: string): { rawPrefix: string; isAtPrefix: boole
|
|
|
89
89
|
return { rawPrefix: prefix, isAtPrefix: false, isQuotedPrefix: false };
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/** Whether a completion value represents a directory, including quoted and Windows paths. */
|
|
93
|
+
export function isDirectoryCompletionValue(value: string): boolean {
|
|
94
|
+
return /[\\/]["']?$/.test(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
function buildCompletionValue(
|
|
93
98
|
path: string,
|
|
94
99
|
options: { isDirectory: boolean; isAtPrefix: boolean; isQuotedPrefix: boolean },
|
|
@@ -363,15 +368,16 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
|
|
|
363
368
|
|
|
364
369
|
// Check if we're completing a file attachment (prefix starts with "@")
|
|
365
370
|
if (prefix.startsWith("@")) {
|
|
366
|
-
// This is a file attachment completion
|
|
367
|
-
const
|
|
371
|
+
// This is a file attachment completion. Keep directory paths open for traversal.
|
|
372
|
+
const suffix = isDirectoryCompletionValue(item.value) ? "" : " ";
|
|
373
|
+
const newLine = `${beforePrefix + item.value}${suffix}${afterCursor}`;
|
|
368
374
|
const newLines = [...lines];
|
|
369
375
|
newLines[cursorLine] = newLine;
|
|
370
376
|
|
|
371
377
|
return {
|
|
372
378
|
lines: newLines,
|
|
373
379
|
cursorLine,
|
|
374
|
-
cursorCol: beforePrefix.length + item.value.length +
|
|
380
|
+
cursorCol: beforePrefix.length + item.value.length + suffix.length,
|
|
375
381
|
};
|
|
376
382
|
}
|
|
377
383
|
|
package/src/components/editor.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { $flag, getProjectDir, logger } from "@f5-sales-demo/pi-utils";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
type AutocompleteProvider,
|
|
4
|
+
type CombinedAutocompleteProvider,
|
|
5
|
+
isDirectoryCompletionValue,
|
|
6
|
+
} from "../autocomplete";
|
|
3
7
|
import { BracketedPasteHandler } from "../bracketed-paste";
|
|
4
8
|
import { getKeybindings, type KeybindingsManager } from "../keybindings";
|
|
5
9
|
import { extractPrintableText, matchesKey } from "../keys";
|
|
@@ -1020,7 +1024,8 @@ export class Editor implements Component, Focusable {
|
|
|
1020
1024
|
if (kb.matches(data, "tui.input.tab")) {
|
|
1021
1025
|
const selected = this.#autocompleteList.getSelectedItem();
|
|
1022
1026
|
if (selected && this.#autocompleteProvider) {
|
|
1023
|
-
const
|
|
1027
|
+
const shouldChainAutocomplete =
|
|
1028
|
+
this.#isSlashCommandNameAutocompleteSelection() || isDirectoryCompletionValue(selected.value);
|
|
1024
1029
|
const result = this.#autocompleteProvider.applyCompletion(
|
|
1025
1030
|
this.#state.lines,
|
|
1026
1031
|
this.#state.cursorLine,
|
|
@@ -1041,8 +1046,8 @@ export class Editor implements Component, Focusable {
|
|
|
1041
1046
|
|
|
1042
1047
|
result.onApplied?.();
|
|
1043
1048
|
|
|
1044
|
-
if (
|
|
1045
|
-
void this.#tryTriggerAutocomplete();
|
|
1049
|
+
if (shouldChainAutocomplete) {
|
|
1050
|
+
queueMicrotask(() => void this.#tryTriggerAutocomplete());
|
|
1046
1051
|
}
|
|
1047
1052
|
}
|
|
1048
1053
|
return;
|
|
@@ -1080,6 +1085,7 @@ export class Editor implements Component, Focusable {
|
|
|
1080
1085
|
else if (kb.matches(data, "tui.input.submit") || data === "\n") {
|
|
1081
1086
|
const selected = this.#autocompleteList.getSelectedItem();
|
|
1082
1087
|
if (selected && this.#autocompleteProvider) {
|
|
1088
|
+
const shouldChainDirectoryCompletion = isDirectoryCompletionValue(selected.value);
|
|
1083
1089
|
const result = this.#autocompleteProvider.applyCompletion(
|
|
1084
1090
|
this.#state.lines,
|
|
1085
1091
|
this.#state.cursorLine,
|
|
@@ -1099,6 +1105,10 @@ export class Editor implements Component, Focusable {
|
|
|
1099
1105
|
}
|
|
1100
1106
|
|
|
1101
1107
|
result.onApplied?.();
|
|
1108
|
+
|
|
1109
|
+
if (shouldChainDirectoryCompletion) {
|
|
1110
|
+
queueMicrotask(() => void this.#tryTriggerAutocomplete());
|
|
1111
|
+
}
|
|
1102
1112
|
}
|
|
1103
1113
|
return;
|
|
1104
1114
|
}
|
|
@@ -2395,16 +2405,6 @@ export class Editor implements Component, Focusable {
|
|
|
2395
2405
|
return textBeforeCursor.startsWith("/") && !textBeforeCursor.includes(" ");
|
|
2396
2406
|
}
|
|
2397
2407
|
|
|
2398
|
-
#isCompletedSlashCommandAtCursor(): boolean {
|
|
2399
|
-
const currentLine = this.#state.lines[this.#state.cursorLine] || "";
|
|
2400
|
-
if (this.#state.cursorCol !== currentLine.length) {
|
|
2401
|
-
return false;
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
const textBeforeCursor = currentLine.slice(0, this.#state.cursorCol).trimStart();
|
|
2405
|
-
return /^\/\S+ $/.test(textBeforeCursor);
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
2408
|
// Autocomplete methods
|
|
2409
2409
|
async #tryTriggerAutocomplete(explicitTab: boolean = false): Promise<void> {
|
|
2410
2410
|
if (!this.#autocompleteProvider) return;
|
|
@@ -2493,6 +2493,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
2493
2493
|
// If there's exactly one suggestion and this was an explicit Tab press, apply it immediately
|
|
2494
2494
|
if (explicitTab && suggestions.items.length === 1) {
|
|
2495
2495
|
const item = suggestions.items[0]!;
|
|
2496
|
+
const shouldChainDirectoryCompletion = isDirectoryCompletionValue(item.value);
|
|
2496
2497
|
const result = this.#autocompleteProvider.applyCompletion(
|
|
2497
2498
|
this.#state.lines,
|
|
2498
2499
|
this.#state.cursorLine,
|
|
@@ -2508,6 +2509,9 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
2508
2509
|
if (this.onChange) {
|
|
2509
2510
|
this.onChange(this.getText());
|
|
2510
2511
|
}
|
|
2512
|
+
if (shouldChainDirectoryCompletion) {
|
|
2513
|
+
queueMicrotask(() => void this.#tryTriggerAutocomplete());
|
|
2514
|
+
}
|
|
2511
2515
|
return;
|
|
2512
2516
|
}
|
|
2513
2517
|
|