@pi-unipi/image 2.2.3 → 2.2.4
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 +1 -1
- package/src/tui/model-selector.ts +47 -35
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Component } from "@earendil-works/pi-tui";
|
|
9
|
-
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
9
|
+
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
10
10
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import { boxInnerWidth, safeRepeat } from "@pi-unipi/core";
|
|
12
12
|
|
|
@@ -61,7 +61,7 @@ export class ImageModelSelectorOverlay implements Component {
|
|
|
61
61
|
handleInput(data: string): void {
|
|
62
62
|
// Ctrl+C must always escape, even mid-filter. Without this the overlay traps
|
|
63
63
|
// the user with no way out.
|
|
64
|
-
if (data
|
|
64
|
+
if (matchesKey(data, "ctrl+c")) {
|
|
65
65
|
this.onClose?.();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -76,49 +76,61 @@ export class ImageModelSelectorOverlay implements Component {
|
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
79
|
+
// Escape is checked via matchesKey, not `data === "\x1b"`: under the kitty
|
|
80
|
+
// keyboard protocol it arrives as "\x1b[27u" (and as "\x1b[27;1;27~" with
|
|
81
|
+
// modifyOtherKeys), so a bare comparison silently fails to close.
|
|
82
|
+
if (matchesKey(data, "escape")) {
|
|
83
|
+
this.onClose?.();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (matchesKey(data, "up") || data === "k") {
|
|
87
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (matchesKey(data, "down") || data === "j") {
|
|
91
|
+
this.selectedIndex = Math.min(this.filtered.length - 1, this.selectedIndex + 1);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (matchesKey(data, "enter")) {
|
|
95
|
+
this.commit();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (data === "/") {
|
|
99
|
+
this.filterMode = true;
|
|
100
|
+
this.filter = "";
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (data === "c" || data === "C") {
|
|
104
|
+
// Escape hatch: generator detection is heuristic, so a provider may
|
|
105
|
+
// expose a model the catalog cannot recognise. Let the user name it.
|
|
106
|
+
this.customMode = true;
|
|
107
|
+
this.custom = "";
|
|
108
|
+
this.error = null;
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
private handleFilterInput(data: string): void {
|
|
110
|
-
if (data
|
|
113
|
+
if (matchesKey(data, "enter")) {
|
|
111
114
|
this.filterMode = false;
|
|
112
115
|
return;
|
|
113
116
|
}
|
|
114
|
-
if (data
|
|
117
|
+
if (matchesKey(data, "escape")) {
|
|
115
118
|
this.filter = "";
|
|
116
119
|
this.filterMode = false;
|
|
117
120
|
this.applyFilter();
|
|
118
121
|
this.selectedIndex = 0;
|
|
119
122
|
return;
|
|
120
123
|
}
|
|
121
|
-
|
|
124
|
+
// Let the list be navigated without leaving the filter.
|
|
125
|
+
if (matchesKey(data, "up")) {
|
|
126
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (matchesKey(data, "down")) {
|
|
130
|
+
this.selectedIndex = Math.min(this.filtered.length - 1, this.selectedIndex + 1);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (matchesKey(data, "backspace") || data === "\x7f" || data === "\b") {
|
|
122
134
|
this.filter = this.filter.slice(0, -1);
|
|
123
135
|
this.applyFilter();
|
|
124
136
|
this.clampSelection();
|
|
@@ -133,17 +145,17 @@ export class ImageModelSelectorOverlay implements Component {
|
|
|
133
145
|
|
|
134
146
|
/** Free-text "provider/model-id" entry. */
|
|
135
147
|
private handleCustomInput(data: string): void {
|
|
136
|
-
if (data
|
|
148
|
+
if (matchesKey(data, "enter")) {
|
|
137
149
|
this.commitCustom();
|
|
138
150
|
return;
|
|
139
151
|
}
|
|
140
|
-
if (data
|
|
152
|
+
if (matchesKey(data, "escape")) {
|
|
141
153
|
this.customMode = false;
|
|
142
154
|
this.custom = "";
|
|
143
155
|
this.error = null;
|
|
144
156
|
return;
|
|
145
157
|
}
|
|
146
|
-
if (data === "\x7f" || data === "\b") {
|
|
158
|
+
if (matchesKey(data, "backspace") || data === "\x7f" || data === "\b") {
|
|
147
159
|
this.custom = this.custom.slice(0, -1);
|
|
148
160
|
this.error = null;
|
|
149
161
|
return;
|