@code-yeongyu/senpi-tui 2026.10.8 → 2026.10.9

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.
@@ -69,6 +69,7 @@ export declare class Editor implements Component, Focusable {
69
69
  private autocompleteList?;
70
70
  private autocompleteState;
71
71
  private autocompletePrefix;
72
+ private autocompleteListSnapshot?;
72
73
  /** The provider items behind `autocompleteList`, which only carries the display fields. */
73
74
  private autocompleteItems;
74
75
  private autocompleteMaxVisible;
@@ -358,6 +359,9 @@ export declare class Editor implements Component, Focusable {
358
359
  private applyAutocompleteSuggestions;
359
360
  private cancelAutocompleteRequest;
360
361
  private clearAutocompleteUi;
362
+ private isAutocompleteListStale;
363
+ /** Accept on a list that predates the text: re-query for the current token, then accept its best match. */
364
+ private acceptRefreshedAutocomplete;
361
365
  private cancelAutocomplete;
362
366
  isShowingAutocomplete(): boolean;
363
367
  private updateAutocomplete;
@@ -688,6 +688,10 @@ export class Editor {
688
688
  return;
689
689
  }
690
690
  if (kb.matches(data, "tui.input.tab")) {
691
+ if (this.isAutocompleteListStale()) {
692
+ this.acceptRefreshedAutocomplete();
693
+ return;
694
+ }
691
695
  const selected = this.autocompleteList.getSelectedItem();
692
696
  if (selected && this.autocompleteProvider) {
693
697
  const drillsIntoNamespace = this.isSlashNamespaceSelection(selected.value);
@@ -706,6 +710,10 @@ export class Editor {
706
710
  return;
707
711
  }
708
712
  if (kb.matches(data, "tui.select.confirm")) {
713
+ if (!this.autocompletePrefix.startsWith("/") && this.isAutocompleteListStale()) {
714
+ this.acceptRefreshedAutocomplete();
715
+ return;
716
+ }
709
717
  const selected = this.autocompleteList.getSelectedItem();
710
718
  if (selected && this.autocompleteProvider) {
711
719
  const drillsIntoNamespace = this.isSlashNamespaceSelection(selected.value);
@@ -2191,6 +2199,24 @@ export class Editor {
2191
2199
  this.tui.requestRender();
2192
2200
  return;
2193
2201
  }
2202
+ if (options.acceptSelection) {
2203
+ const bestMatchIndex = this.getBestAutocompleteMatchIndex(suggestions.items, suggestions.prefix);
2204
+ const item = suggestions.items[Math.max(bestMatchIndex, 0)];
2205
+ const drillsIntoNamespace = suggestions.prefix.startsWith("/") && isSlashNamespaceItem(item.value);
2206
+ this.pushUndoSnapshot();
2207
+ this.lastAction = null;
2208
+ const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, item, suggestions.prefix);
2209
+ this.state.lines = result.lines;
2210
+ this.state.cursorLine = result.cursorLine;
2211
+ this.setCursorCol(result.cursorCol);
2212
+ this.clearAutocompleteUi();
2213
+ if (this.onChange)
2214
+ this.onChange(this.getText());
2215
+ if (drillsIntoNamespace)
2216
+ this.tryTriggerAutocomplete();
2217
+ this.tui.requestRender();
2218
+ return;
2219
+ }
2194
2220
  if (options.force && options.explicitTab && suggestions.items.length === 1) {
2195
2221
  const item = suggestions.items[0];
2196
2222
  this.pushUndoSnapshot();
@@ -2216,6 +2242,11 @@ export class Editor {
2216
2242
  }
2217
2243
  applyAutocompleteSuggestions(suggestions, state) {
2218
2244
  this.autocompletePrefix = suggestions.prefix;
2245
+ this.autocompleteListSnapshot = {
2246
+ text: this.getText(),
2247
+ line: this.state.cursorLine,
2248
+ col: this.state.cursorCol,
2249
+ };
2219
2250
  this.autocompleteItems = suggestions.items;
2220
2251
  this.autocompleteList = this.createAutocompleteList(suggestions.prefix, suggestions.items);
2221
2252
  const bestMatchIndex = this.getBestAutocompleteMatchIndex(suggestions.items, suggestions.prefix);
@@ -2238,6 +2269,22 @@ export class Editor {
2238
2269
  this.autocompleteList = undefined;
2239
2270
  this.autocompleteItems = [];
2240
2271
  this.autocompletePrefix = "";
2272
+ this.autocompleteListSnapshot = undefined;
2273
+ }
2274
+ isAutocompleteListStale() {
2275
+ const snapshot = this.autocompleteListSnapshot;
2276
+ return (snapshot !== undefined &&
2277
+ (snapshot.text !== this.getText() ||
2278
+ snapshot.line !== this.state.cursorLine ||
2279
+ snapshot.col !== this.state.cursorCol));
2280
+ }
2281
+ /** Accept on a list that predates the text: re-query for the current token, then accept its best match. */
2282
+ acceptRefreshedAutocomplete() {
2283
+ this.requestAutocomplete({
2284
+ force: this.autocompleteState === "force",
2285
+ explicitTab: true,
2286
+ acceptSelection: true,
2287
+ });
2241
2288
  }
2242
2289
  cancelAutocomplete() {
2243
2290
  this.cancelAutocompleteRequest();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-tui",
3
- "version": "2026.10.8",
3
+ "version": "2026.10.9",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",