@gajae-code/tui 0.12.12 → 0.12.13

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 CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.12.13] - 2026-08-06
6
+
5
7
  ## [0.12.12] - 2026-08-05
6
8
  ### Fixed
7
9
 
10
+ - Applied the compact 12–32-column primary layout to slash-command autocomplete while leaving file and other completion lists on their existing layout.
8
11
  - Restored 60 fps time-dependent loader gradients on direct local terminals while retaining the 80 ms cadence and congestion dropping on SSH and multiplexed terminals.
9
12
  - Bounded loader animation scheduling to 80 ms, stopped OSC 11 polling after DA1 proves the query unsupported while preserving Mode 2031 recovery, and added the default-on `GJC_TUI_SYNCHRONIZED_OUTPUT=0` compatibility opt-out for terminal parsers that mishandle synchronized-output framing. Real iOS-client validation remains pending for #3798.
10
13
  - Decorative animation ticks now pause while stdout has more than 64 KiB buffered, preventing slow SSH terminals and multiplexers from accumulating stale spinner frames.
@@ -8,6 +8,12 @@ export interface AutocompleteItem {
8
8
  /** Dim hint text shown inline after cursor when this item is selected */
9
9
  hint?: string;
10
10
  }
11
+ export type AutocompleteSuggestionKind = "slash-command" | "default";
12
+ export interface AutocompleteSuggestions {
13
+ items: AutocompleteItem[];
14
+ prefix: string;
15
+ kind?: AutocompleteSuggestionKind;
16
+ }
11
17
  type Awaitable<T> = T | Promise<T>;
12
18
  export interface SlashCommand {
13
19
  name: string;
@@ -24,10 +30,7 @@ export interface SlashCommand {
24
30
  }
25
31
  export interface AutocompleteProvider {
26
32
  /** Get autocomplete suggestions for current text/cursor position */
27
- getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<{
28
- items: AutocompleteItem[];
29
- prefix: string;
30
- } | null>;
33
+ getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<AutocompleteSuggestions | null>;
31
34
  /** Apply the selected item and return new text + cursor position */
32
35
  applyCompletion(lines: string[], cursorLine: number, cursorCol: number, item: AutocompleteItem, prefix: string): {
33
36
  lines: string[];
@@ -59,10 +62,7 @@ export interface AutocompleteProvider {
59
62
  export declare class CombinedAutocompleteProvider implements AutocompleteProvider {
60
63
  #private;
61
64
  constructor(commands?: (SlashCommand | AutocompleteItem)[], basePath?: string);
62
- getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<{
63
- items: AutocompleteItem[];
64
- prefix: string;
65
- } | null>;
65
+ getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<AutocompleteSuggestions | null>;
66
66
  applyCompletion(lines: string[], cursorLine: number, cursorCol: number, item: AutocompleteItem, prefix: string): {
67
67
  lines: string[];
68
68
  cursorLine: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/tui",
4
- "version": "0.12.12",
4
+ "version": "0.12.13",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -36,8 +36,8 @@
36
36
  "fmt": "biome format --write ."
37
37
  },
38
38
  "dependencies": {
39
- "@gajae-code/natives": "0.12.12",
40
- "@gajae-code/utils": "0.12.12",
39
+ "@gajae-code/natives": "0.12.13",
40
+ "@gajae-code/utils": "0.12.13",
41
41
  "lru-cache": "11.3.6",
42
42
  "marked": "18.0.6"
43
43
  },
@@ -242,6 +242,13 @@ export interface AutocompleteItem {
242
242
  /** Dim hint text shown inline after cursor when this item is selected */
243
243
  hint?: string;
244
244
  }
245
+ export type AutocompleteSuggestionKind = "slash-command" | "default";
246
+
247
+ export interface AutocompleteSuggestions {
248
+ items: AutocompleteItem[];
249
+ prefix: string;
250
+ kind?: AutocompleteSuggestionKind;
251
+ }
245
252
 
246
253
  type Awaitable<T> = T | Promise<T>;
247
254
 
@@ -263,14 +270,7 @@ export interface SlashCommand {
263
270
 
264
271
  export interface AutocompleteProvider {
265
272
  /** Get autocomplete suggestions for current text/cursor position */
266
- getSuggestions(
267
- lines: string[],
268
- cursorLine: number,
269
- cursorCol: number,
270
- ): Promise<{
271
- items: AutocompleteItem[];
272
- prefix: string; // What we're matching against (e.g., "/" or "src/")
273
- } | null>;
273
+ getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<AutocompleteSuggestions | null>;
274
274
 
275
275
  /** Apply the selected item and return new text + cursor position */
276
276
  applyCompletion(
@@ -381,7 +381,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
381
381
  lines: string[],
382
382
  cursorLine: number,
383
383
  cursorCol: number,
384
- ): Promise<{ items: AutocompleteItem[]; prefix: string } | null> {
384
+ ): Promise<AutocompleteSuggestions | null> {
385
385
  const currentLine = lines[cursorLine] || "";
386
386
  const textBeforeCursor = currentLine.slice(0, cursorCol);
387
387
 
@@ -403,6 +403,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
403
403
  return {
404
404
  items: suggestions,
405
405
  prefix: atPrefix,
406
+ kind: "default",
406
407
  };
407
408
  }
408
409
 
@@ -419,6 +420,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
419
420
 
420
421
  return {
421
422
  items: matches,
423
+ kind: "slash-command",
422
424
  prefix: textBeforeCursor,
423
425
  };
424
426
  }
@@ -439,6 +441,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
439
441
 
440
442
  return {
441
443
  items: argumentSuggestions,
444
+ kind: "default",
442
445
  prefix: argumentText,
443
446
  };
444
447
  }
@@ -452,6 +455,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
452
455
  if (pathSuggestions.length > 0) {
453
456
  return {
454
457
  items: pathSuggestions,
458
+ kind: "default",
455
459
  prefix: pathMatch,
456
460
  };
457
461
  }
@@ -461,6 +465,7 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
461
465
  if (matches.length > 0) {
462
466
  return {
463
467
  items: matches,
468
+ kind: "slash-command",
464
469
  prefix: slashPrefix,
465
470
  };
466
471
  }
@@ -479,12 +484,14 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
479
484
  // We still return it so user can select it and add /
480
485
  return {
481
486
  items: suggestions,
487
+ kind: "default",
482
488
  prefix: pathMatch,
483
489
  };
484
490
  }
485
491
 
486
492
  return {
487
493
  items: suggestions,
494
+ kind: "default",
488
495
  prefix: pathMatch,
489
496
  };
490
497
  }
@@ -1,6 +1,7 @@
1
1
  import { getProjectDir, logger, onDefaultTabWidthChange } from "@gajae-code/utils";
2
2
  import {
3
3
  type AutocompleteProvider,
4
+ type AutocompleteSuggestionKind,
4
5
  type CombinedAutocompleteProvider,
5
6
  extractSlashCommandTokenPrefix,
6
7
  isInsideInlineCodeSpan,
@@ -2838,11 +2839,7 @@ export class Editor implements Component, Focusable {
2838
2839
  );
2839
2840
  }
2840
2841
 
2841
- #isSlashCommandNameAutocompleteSelection(): boolean {
2842
- if (this.#autocompleteState !== "regular") {
2843
- return false;
2844
- }
2845
-
2842
+ #isSlashCommandNameAutocompleteContext(): boolean {
2846
2843
  const currentLine = this.#state.lines[this.#state.cursorLine] || "";
2847
2844
  const textBeforeCursor = currentLine.slice(0, this.#state.cursorCol).trimStart();
2848
2845
  return (
@@ -2850,6 +2847,14 @@ export class Editor implements Component, Focusable {
2850
2847
  );
2851
2848
  }
2852
2849
 
2850
+ #isSlashCommandNameAutocompleteSelection(): boolean {
2851
+ if (this.#autocompleteState !== "regular") {
2852
+ return false;
2853
+ }
2854
+
2855
+ return this.#isSlashCommandNameAutocompleteContext();
2856
+ }
2857
+
2853
2858
  #isCompletedSlashCommandAtCursor(): boolean {
2854
2859
  const currentLine = this.#state.lines[this.#state.cursorLine] || "";
2855
2860
  if (this.#state.cursorCol !== currentLine.length) {
@@ -2890,7 +2895,7 @@ export class Editor implements Component, Focusable {
2890
2895
 
2891
2896
  if (suggestions && Array.isArray(suggestions.items) && suggestions.items.length > 0) {
2892
2897
  this.#autocompletePrefix = suggestions.prefix;
2893
- this.#autocompleteList = this.#createAutocompleteList(suggestions.prefix, suggestions.items);
2898
+ this.#autocompleteList = this.#createAutocompleteList(suggestions.items, suggestions.kind ?? "default");
2894
2899
  this.#autocompleteState = "regular";
2895
2900
  this.#autocompleteOrigin = origin;
2896
2901
  this.onAutocompleteUpdate?.();
@@ -2901,14 +2906,11 @@ export class Editor implements Component, Focusable {
2901
2906
  }
2902
2907
  }
2903
2908
  #createAutocompleteList(
2904
- prefix: string,
2905
2909
  items: Array<{ value: string; label: string; description?: string }>,
2910
+ kind: AutocompleteSuggestionKind,
2906
2911
  ): SelectList {
2907
- // Layout options prepared for future SelectList enhancements (e.g., for slash commands)
2908
- const layout = prefix.startsWith("/") ? SLASH_COMMAND_SELECT_LIST_LAYOUT : undefined;
2909
- // TODO: Pass layout to SelectList when constructor is updated to support it
2910
- void layout; // Use layout variable to avoid lint warnings
2911
- return new SelectList(items, this.#autocompleteMaxVisible, this.#theme.selectList);
2912
+ const layout = kind === "slash-command" ? SLASH_COMMAND_SELECT_LIST_LAYOUT : undefined;
2913
+ return new SelectList(items, this.#autocompleteMaxVisible, this.#theme.selectList, layout);
2912
2914
  }
2913
2915
 
2914
2916
  #handleTabCompletion(): void {
@@ -2985,7 +2987,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
2985
2987
  }
2986
2988
 
2987
2989
  this.#autocompletePrefix = suggestions.prefix;
2988
- this.#autocompleteList = this.#createAutocompleteList(suggestions.prefix, suggestions.items);
2990
+ this.#autocompleteList = this.#createAutocompleteList(suggestions.items, "default");
2989
2991
  this.#autocompleteState = "force";
2990
2992
  this.#autocompleteOrigin = origin;
2991
2993
  this.onAutocompleteUpdate?.();
@@ -3035,7 +3037,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
3035
3037
  if (suggestions && Array.isArray(suggestions.items) && suggestions.items.length > 0) {
3036
3038
  this.#autocompletePrefix = suggestions.prefix;
3037
3039
  // Always create new SelectList to ensure update
3038
- this.#autocompleteList = this.#createAutocompleteList(suggestions.prefix, suggestions.items);
3040
+ this.#autocompleteList = this.#createAutocompleteList(suggestions.items, suggestions.kind ?? "default");
3039
3041
  this.#autocompleteOrigin = origin;
3040
3042
  this.onAutocompleteUpdate?.();
3041
3043
  } else {