@juanibiapina/pi-extension-settings 0.5.1 → 0.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ordered-multi-select.d.ts","sourceRoot":"","sources":["../../src/components/ordered-multi-select.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAqD,MAAM,sBAAsB,CAAC;AACzG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAS5D,qBAAa,kBAAmB,YAAW,SAAS;IACnD,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,IAAI,CAAmC;gBAG9C,OAAO,EAAE,iBAAiB,EAAE,EAC5B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI;IAWvC,UAAU,IAAI,IAAI;IAElB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAkC/B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA2B/B,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,QAAQ;CAYhB"}
1
+ {"version":3,"file":"ordered-multi-select.d.ts","sourceRoot":"","sources":["../../src/components/ordered-multi-select.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,SAAS,EAA+C,MAAM,sBAAsB,CAAC;AACnG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAS5D,qBAAa,kBAAmB,YAAW,SAAS;IACnD,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,IAAI,CAAmC;gBAG9C,OAAO,EAAE,iBAAiB,EAAE,EAC5B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI;IAWvC,UAAU,IAAI,IAAI;IAElB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAkC/B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA2B/B,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,QAAQ;CAYhB"}
@@ -5,7 +5,7 @@
5
5
  * Selected items appear at the top with their position number.
6
6
  * Value is stored as a comma-separated string of selected IDs in order.
7
7
  */
8
- import { getEditorKeybindings, matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
8
+ import { getKeybindings, matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
9
9
  export class OrderedMultiSelect {
10
10
  options;
11
11
  selected;
@@ -51,18 +51,18 @@ export class OrderedMultiSelect {
51
51
  return lines;
52
52
  }
53
53
  handleInput(data) {
54
- const kb = getEditorKeybindings();
54
+ const kb = getKeybindings();
55
55
  const items = this.buildDisplayItems();
56
56
  if (items.length === 0) {
57
- if (kb.matches(data, "selectCancel")) {
57
+ if (kb.matches(data, "tui.select.cancel")) {
58
58
  this.done(undefined);
59
59
  }
60
60
  return;
61
61
  }
62
- if (kb.matches(data, "selectUp") || matchesKey(data, "up")) {
62
+ if (kb.matches(data, "tui.select.up") || matchesKey(data, "up")) {
63
63
  this.cursorIndex = this.cursorIndex === 0 ? items.length - 1 : this.cursorIndex - 1;
64
64
  }
65
- else if (kb.matches(data, "selectDown") || matchesKey(data, "down")) {
65
+ else if (kb.matches(data, "tui.select.down") || matchesKey(data, "down")) {
66
66
  this.cursorIndex = this.cursorIndex === items.length - 1 ? 0 : this.cursorIndex + 1;
67
67
  }
68
68
  else if (data === " " || matchesKey(data, "space")) {
@@ -74,10 +74,10 @@ export class OrderedMultiSelect {
74
74
  else if (matchesKey(data, "shift+down")) {
75
75
  this.moveDown(items);
76
76
  }
77
- else if (kb.matches(data, "selectConfirm")) {
77
+ else if (kb.matches(data, "tui.select.confirm")) {
78
78
  this.done(this.selected.join(","));
79
79
  }
80
- else if (kb.matches(data, "selectCancel")) {
80
+ else if (kb.matches(data, "tui.select.cancel")) {
81
81
  this.done(undefined);
82
82
  }
83
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ordered-multi-select.js","sourceRoot":"","sources":["../../src/components/ordered-multi-select.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Ordered multi-select component.\n *\n * Displays a list of options that can be toggled on/off and reordered.\n * Selected items appear at the top with their position number.\n * Value is stored as a comma-separated string of selected IDs in order.\n */\n\nimport { type Component, getEditorKeybindings, matchesKey, truncateToWidth } from \"@mariozechner/pi-tui\";\nimport type { OrderedListOption } from \"../settings/types.js\";\nimport type { SettingsListTheme } from \"./settings-list.js\";\n\ninterface DisplayItem {\n\toption: OrderedListOption;\n\tselected: boolean;\n\t/** 1-based position within selected items, or 0 if not selected */\n\tposition: number;\n}\n\nexport class OrderedMultiSelect implements Component {\n\tprivate options: OrderedListOption[];\n\tprivate selected: string[];\n\tprivate cursorIndex = 0;\n\tprivate theme: SettingsListTheme;\n\tprivate done: (selectedValue?: string) => void;\n\n\tconstructor(\n\t\toptions: OrderedListOption[],\n\t\tcurrentValue: string,\n\t\ttheme: SettingsListTheme,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tthis.options = options;\n\t\tthis.selected = currentValue\n\t\t\t.split(\",\")\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\t\tthis.theme = theme;\n\t\tthis.done = done;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst items = this.buildDisplayItems();\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst item = items[i];\n\t\t\tconst isCursor = i === this.cursorIndex;\n\t\t\tconst prefix = isCursor ? this.theme.cursor : \" \";\n\n\t\t\tlet marker: string;\n\t\t\tif (item.selected) {\n\t\t\t\tmarker = this.theme.value(`✓ ${String(item.position).padStart(2)}`, isCursor);\n\t\t\t} else {\n\t\t\t\tmarker = this.theme.label(\" \", isCursor);\n\t\t\t}\n\n\t\t\tconst label = this.theme.label(item.option.label, isCursor);\n\t\t\tconst line = `${prefix}${marker} ${label}`;\n\t\t\tlines.push(truncateToWidth(line, width, \"…\"));\n\t\t}\n\n\t\t// Scroll indicator\n\t\tif (items.length > 0) {\n\t\t\tconst scrollText = ` (${this.cursorIndex + 1}/${items.length})`;\n\t\t\tlines.push(this.theme.hint(scrollText));\n\t\t}\n\n\t\t// Hint line\n\t\tlines.push(\"\");\n\t\tlines.push(this.theme.hint(\" Space toggle · Shift+↑/↓ reorder · Enter confirm · Esc cancel\"));\n\n\t\treturn lines;\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getEditorKeybindings();\n\t\tconst items = this.buildDisplayItems();\n\t\tif (items.length === 0) {\n\t\t\tif (kb.matches(data, \"selectCancel\")) {\n\t\t\t\tthis.done(undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"selectUp\") || matchesKey(data, \"up\")) {\n\t\t\tthis.cursorIndex = this.cursorIndex === 0 ? items.length - 1 : this.cursorIndex - 1;\n\t\t} else if (kb.matches(data, \"selectDown\") || matchesKey(data, \"down\")) {\n\t\t\tthis.cursorIndex = this.cursorIndex === items.length - 1 ? 0 : this.cursorIndex + 1;\n\t\t} else if (data === \" \" || matchesKey(data, \"space\")) {\n\t\t\tthis.toggleCurrent(items);\n\t\t} else if (matchesKey(data, \"shift+up\")) {\n\t\t\tthis.moveUp(items);\n\t\t} else if (matchesKey(data, \"shift+down\")) {\n\t\t\tthis.moveDown(items);\n\t\t} else if (kb.matches(data, \"selectConfirm\")) {\n\t\t\tthis.done(this.selected.join(\",\"));\n\t\t} else if (kb.matches(data, \"selectCancel\")) {\n\t\t\tthis.done(undefined);\n\t\t}\n\t}\n\n\tprivate buildDisplayItems(): DisplayItem[] {\n\t\tconst items: DisplayItem[] = [];\n\n\t\t// Selected items first, in order\n\t\tfor (let i = 0; i < this.selected.length; i++) {\n\t\t\tconst id = this.selected[i];\n\t\t\tconst option = this.options.find((o) => o.id === id);\n\t\t\tif (option) {\n\t\t\t\titems.push({ option, selected: true, position: i + 1 });\n\t\t\t}\n\t\t}\n\n\t\t// Unselected items, in original options order\n\t\tfor (const option of this.options) {\n\t\t\tif (!this.selected.includes(option.id)) {\n\t\t\t\titems.push({ option, selected: false, position: 0 });\n\t\t\t}\n\t\t}\n\n\t\treturn items;\n\t}\n\n\tprivate toggleCurrent(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item) return;\n\n\t\tconst id = item.option.id;\n\t\tif (item.selected) {\n\t\t\t// Remove from selected\n\t\t\tthis.selected = this.selected.filter((s) => s !== id);\n\t\t} else {\n\t\t\t// Add to end of selected\n\t\t\tthis.selected.push(id);\n\t\t}\n\t}\n\n\tprivate moveUp(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item?.selected) return;\n\n\t\tconst idx = this.selected.indexOf(item.option.id);\n\t\tif (idx <= 0) return;\n\n\t\t// Swap with previous in selected array\n\t\t[this.selected[idx - 1], this.selected[idx]] = [this.selected[idx], this.selected[idx - 1]];\n\t\t// Move cursor up to follow the item\n\t\tthis.cursorIndex--;\n\t}\n\n\tprivate moveDown(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item?.selected) return;\n\n\t\tconst idx = this.selected.indexOf(item.option.id);\n\t\tif (idx < 0 || idx >= this.selected.length - 1) return;\n\n\t\t// Swap with next in selected array\n\t\t[this.selected[idx], this.selected[idx + 1]] = [this.selected[idx + 1], this.selected[idx]];\n\t\t// Move cursor down to follow the item\n\t\tthis.cursorIndex++;\n\t}\n}\n"]}
1
+ {"version":3,"file":"ordered-multi-select.js","sourceRoot":"","sources":["../../src/components/ordered-multi-select.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAkB,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAWnG,MAAM,OAAO,kBAAkB;IACtB,OAAO,CAAsB;IAC7B,QAAQ,CAAW;IACnB,WAAW,GAAG,CAAC,CAAC;IAChB,KAAK,CAAoB;IACzB,IAAI,CAAmC;IAE/C,YACC,OAA4B,EAC5B,YAAoB,EACpB,KAAwB,EACxB,IAAsC;QAEtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,YAAY;aAC1B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,UAAU,KAAU,CAAC;IAErB,MAAM,CAAC,KAAa;QACnB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,QAAQ,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC;YACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAEnD,IAAI,MAAc,CAAC;YACnB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC/E,CAAC;iBAAM,CAAC;gBACP,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC9C,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,GAAG,MAAM,GAAG,MAAM,KAAK,KAAK,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,mBAAmB;QACnB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,YAAY;QACZ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC,CAAC;QAE/F,OAAO,KAAK,CAAC;IACd,CAAC;IAED,WAAW,CAAC,IAAY;QACvB,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;YACD,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrF,CAAC;aAAM,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YAC5E,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrF,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;aAAM,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAEO,iBAAiB;QACxB,MAAM,KAAK,GAAkB,EAAE,CAAC;QAEhC,iCAAiC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACrD,IAAI,MAAM,EAAE,CAAC;gBACZ,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACzD,CAAC;QACF,CAAC;QAED,8CAA8C;QAC9C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBACxC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;YACtD,CAAC;QACF,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,aAAa,CAAC,KAAoB;QACzC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,uBAAuB;YACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACP,yBAAyB;YACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;IACF,CAAC;IAEO,MAAM,CAAC,KAAoB;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,QAAQ;YAAE,OAAO;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO;QAErB,uCAAuC;QACvC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5F,oCAAoC;QACpC,IAAI,CAAC,WAAW,EAAE,CAAC;IACpB,CAAC;IAEO,QAAQ,CAAC,KAAoB;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,QAAQ;YAAE,OAAO;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO;QAEvD,mCAAmC;QACnC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5F,sCAAsC;QACtC,IAAI,CAAC,WAAW,EAAE,CAAC;IACpB,CAAC;CACD","sourcesContent":["/**\n * Ordered multi-select component.\n *\n * Displays a list of options that can be toggled on/off and reordered.\n * Selected items appear at the top with their position number.\n * Value is stored as a comma-separated string of selected IDs in order.\n */\n\nimport { type Component, getKeybindings, matchesKey, truncateToWidth } from \"@mariozechner/pi-tui\";\nimport type { OrderedListOption } from \"../settings/types.js\";\nimport type { SettingsListTheme } from \"./settings-list.js\";\n\ninterface DisplayItem {\n\toption: OrderedListOption;\n\tselected: boolean;\n\t/** 1-based position within selected items, or 0 if not selected */\n\tposition: number;\n}\n\nexport class OrderedMultiSelect implements Component {\n\tprivate options: OrderedListOption[];\n\tprivate selected: string[];\n\tprivate cursorIndex = 0;\n\tprivate theme: SettingsListTheme;\n\tprivate done: (selectedValue?: string) => void;\n\n\tconstructor(\n\t\toptions: OrderedListOption[],\n\t\tcurrentValue: string,\n\t\ttheme: SettingsListTheme,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tthis.options = options;\n\t\tthis.selected = currentValue\n\t\t\t.split(\",\")\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\t\tthis.theme = theme;\n\t\tthis.done = done;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst items = this.buildDisplayItems();\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst item = items[i];\n\t\t\tconst isCursor = i === this.cursorIndex;\n\t\t\tconst prefix = isCursor ? this.theme.cursor : \" \";\n\n\t\t\tlet marker: string;\n\t\t\tif (item.selected) {\n\t\t\t\tmarker = this.theme.value(`✓ ${String(item.position).padStart(2)}`, isCursor);\n\t\t\t} else {\n\t\t\t\tmarker = this.theme.label(\" \", isCursor);\n\t\t\t}\n\n\t\t\tconst label = this.theme.label(item.option.label, isCursor);\n\t\t\tconst line = `${prefix}${marker} ${label}`;\n\t\t\tlines.push(truncateToWidth(line, width, \"…\"));\n\t\t}\n\n\t\t// Scroll indicator\n\t\tif (items.length > 0) {\n\t\t\tconst scrollText = ` (${this.cursorIndex + 1}/${items.length})`;\n\t\t\tlines.push(this.theme.hint(scrollText));\n\t\t}\n\n\t\t// Hint line\n\t\tlines.push(\"\");\n\t\tlines.push(this.theme.hint(\" Space toggle · Shift+↑/↓ reorder · Enter confirm · Esc cancel\"));\n\n\t\treturn lines;\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tconst items = this.buildDisplayItems();\n\t\tif (items.length === 0) {\n\t\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\t\tthis.done(undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.select.up\") || matchesKey(data, \"up\")) {\n\t\t\tthis.cursorIndex = this.cursorIndex === 0 ? items.length - 1 : this.cursorIndex - 1;\n\t\t} else if (kb.matches(data, \"tui.select.down\") || matchesKey(data, \"down\")) {\n\t\t\tthis.cursorIndex = this.cursorIndex === items.length - 1 ? 0 : this.cursorIndex + 1;\n\t\t} else if (data === \" \" || matchesKey(data, \"space\")) {\n\t\t\tthis.toggleCurrent(items);\n\t\t} else if (matchesKey(data, \"shift+up\")) {\n\t\t\tthis.moveUp(items);\n\t\t} else if (matchesKey(data, \"shift+down\")) {\n\t\t\tthis.moveDown(items);\n\t\t} else if (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tthis.done(this.selected.join(\",\"));\n\t\t} else if (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.done(undefined);\n\t\t}\n\t}\n\n\tprivate buildDisplayItems(): DisplayItem[] {\n\t\tconst items: DisplayItem[] = [];\n\n\t\t// Selected items first, in order\n\t\tfor (let i = 0; i < this.selected.length; i++) {\n\t\t\tconst id = this.selected[i];\n\t\t\tconst option = this.options.find((o) => o.id === id);\n\t\t\tif (option) {\n\t\t\t\titems.push({ option, selected: true, position: i + 1 });\n\t\t\t}\n\t\t}\n\n\t\t// Unselected items, in original options order\n\t\tfor (const option of this.options) {\n\t\t\tif (!this.selected.includes(option.id)) {\n\t\t\t\titems.push({ option, selected: false, position: 0 });\n\t\t\t}\n\t\t}\n\n\t\treturn items;\n\t}\n\n\tprivate toggleCurrent(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item) return;\n\n\t\tconst id = item.option.id;\n\t\tif (item.selected) {\n\t\t\t// Remove from selected\n\t\t\tthis.selected = this.selected.filter((s) => s !== id);\n\t\t} else {\n\t\t\t// Add to end of selected\n\t\t\tthis.selected.push(id);\n\t\t}\n\t}\n\n\tprivate moveUp(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item?.selected) return;\n\n\t\tconst idx = this.selected.indexOf(item.option.id);\n\t\tif (idx <= 0) return;\n\n\t\t// Swap with previous in selected array\n\t\t[this.selected[idx - 1], this.selected[idx]] = [this.selected[idx], this.selected[idx - 1]];\n\t\t// Move cursor up to follow the item\n\t\tthis.cursorIndex--;\n\t}\n\n\tprivate moveDown(items: DisplayItem[]): void {\n\t\tconst item = items[this.cursorIndex];\n\t\tif (!item?.selected) return;\n\n\t\tconst idx = this.selected.indexOf(item.option.id);\n\t\tif (idx < 0 || idx >= this.selected.length - 1) return;\n\n\t\t// Swap with next in selected array\n\t\t[this.selected[idx], this.selected[idx + 1]] = [this.selected[idx + 1], this.selected[idx]];\n\t\t// Move cursor down to follow the item\n\t\tthis.cursorIndex++;\n\t}\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Settings list component with support for cycling values and string input.
3
3
  * Based on @mariozechner/pi-tui SettingsList, extended with string editing.
4
4
  */
5
- import { fuzzyFilter, getEditorKeybindings, Input, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@mariozechner/pi-tui";
5
+ import { fuzzyFilter, getKeybindings, Input, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@mariozechner/pi-tui";
6
6
  export class SettingsList {
7
7
  items;
8
8
  filteredItems;
@@ -129,22 +129,22 @@ export class SettingsList {
129
129
  return;
130
130
  }
131
131
  // Main list input handling
132
- const kb = getEditorKeybindings();
132
+ const kb = getKeybindings();
133
133
  const displayItems = this.searchEnabled ? this.filteredItems : this.items;
134
- if (kb.matches(data, "selectUp")) {
134
+ if (kb.matches(data, "tui.select.up")) {
135
135
  if (displayItems.length === 0)
136
136
  return;
137
137
  this.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;
138
138
  }
139
- else if (kb.matches(data, "selectDown")) {
139
+ else if (kb.matches(data, "tui.select.down")) {
140
140
  if (displayItems.length === 0)
141
141
  return;
142
142
  this.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;
143
143
  }
144
- else if (kb.matches(data, "selectConfirm") || data === " ") {
144
+ else if (kb.matches(data, "tui.select.confirm") || data === " ") {
145
145
  this.activateItem();
146
146
  }
147
- else if (kb.matches(data, "selectCancel")) {
147
+ else if (kb.matches(data, "tui.select.cancel")) {
148
148
  this.onCancel();
149
149
  }
150
150
  else if (this.searchEnabled && this.searchInput) {
@@ -1 +1 @@
1
- {"version":3,"file":"settings-list.js","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Settings list component with support for cycling values and string input.\n * Based on @mariozechner/pi-tui SettingsList, extended with string editing.\n */\n\nimport {\n\ttype Component,\n\tfuzzyFilter,\n\tgetEditorKeybindings,\n\tInput,\n\tmatchesKey,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"@mariozechner/pi-tui\";\n\nexport interface SettingItem {\n\t/** Unique identifier for this setting */\n\tid: string;\n\t/** Display label (left side) */\n\tlabel: string;\n\t/** Optional description shown when selected */\n\tdescription?: string;\n\t/** Current value to display (right side) */\n\tcurrentValue: string;\n\t/**\n\t * If provided, Enter/Space cycles through these values.\n\t * If undefined/empty, the setting is treated as a string input.\n\t */\n\tvalues?: string[];\n\t/** If provided, Enter opens this submenu. Receives current value and done callback. */\n\tsubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;\n\t/** If false, item is selectable but cannot be edited or changed. */\n\teditable?: boolean;\n}\n\nexport interface SettingsListTheme {\n\tlabel: (text: string, selected: boolean) => string;\n\tvalue: (text: string, selected: boolean) => string;\n\tdescription: (text: string) => string;\n\tcursor: string;\n\thint: (text: string) => string;\n}\n\nexport interface SettingsListOptions {\n\tenableSearch?: boolean;\n}\n\nexport class SettingsList implements Component {\n\tprivate items: SettingItem[];\n\tprivate filteredItems: SettingItem[];\n\tprivate theme: SettingsListTheme;\n\tprivate selectedIndex = 0;\n\tprivate maxVisible: number;\n\tprivate onChange: (id: string, newValue: string) => void;\n\tprivate onCancel: () => void;\n\tprivate searchInput?: Input;\n\tprivate searchEnabled: boolean;\n\n\t// Submenu state\n\tprivate submenuComponent: Component | null = null;\n\tprivate submenuItemIndex: number | null = null;\n\n\t// String editing state\n\tprivate editingInput: Input | null = null;\n\tprivate editingItemIndex: number | null = null;\n\n\tconstructor(\n\t\titems: SettingItem[],\n\t\tmaxVisible: number,\n\t\ttheme: SettingsListTheme,\n\t\tonChange: (id: string, newValue: string) => void,\n\t\tonCancel: () => void,\n\t\toptions: SettingsListOptions = {},\n\t) {\n\t\tthis.items = items;\n\t\tthis.filteredItems = items;\n\t\tthis.maxVisible = maxVisible;\n\t\tthis.theme = theme;\n\t\tthis.onChange = onChange;\n\t\tthis.onCancel = onCancel;\n\t\tthis.searchEnabled = options.enableSearch ?? false;\n\t\tif (this.searchEnabled) {\n\t\t\tthis.searchInput = new Input();\n\t\t}\n\t}\n\n\t/** Update an item's currentValue */\n\tupdateValue(id: string, newValue: string): void {\n\t\tconst item = this.items.find((i) => i.id === id);\n\t\tif (item) {\n\t\t\titem.currentValue = newValue;\n\t\t}\n\t}\n\n\tinvalidate(): void {\n\t\tthis.submenuComponent?.invalidate?.();\n\t}\n\n\trender(width: number): string[] {\n\t\t// If submenu is active, render it instead\n\t\tif (this.submenuComponent) {\n\t\t\treturn this.submenuComponent.render(width);\n\t\t}\n\n\t\treturn this.renderMainList(width);\n\t}\n\n\tprivate renderMainList(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.searchEnabled && this.searchInput && !this.editingInput) {\n\t\t\tlines.push(...this.searchInput.render(width));\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\tif (this.items.length === 0) {\n\t\t\tlines.push(this.theme.hint(\" No settings available\"));\n\t\t\tif (this.searchEnabled) {\n\t\t\t\tthis.addHintLine(lines);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tif (displayItems.length === 0) {\n\t\t\tlines.push(this.theme.hint(\" No matching settings\"));\n\t\t\tthis.addHintLine(lines);\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), displayItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, displayItems.length);\n\n\t\t// Calculate max label width for alignment\n\t\tconst maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));\n\n\t\t// Render visible items\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = displayItems[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst isEditing = this.editingInput && this.editingItemIndex === i;\n\t\t\tconst prefix = isSelected ? this.theme.cursor : \" \";\n\t\t\tconst prefixWidth = visibleWidth(prefix);\n\n\t\t\t// Pad label to align values\n\t\t\tconst labelPadded = item.label + \" \".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));\n\t\t\tconst labelText = this.theme.label(labelPadded, isSelected);\n\n\t\t\t// Calculate space for value\n\t\t\tconst separator = \" \";\n\t\t\tconst usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);\n\t\t\tconst valueMaxWidth = width - usedWidth - 2;\n\n\t\t\tif (isEditing && this.editingInput) {\n\t\t\t\t// Render inline input for string editing\n\t\t\t\tconst inputLines = this.editingInput.render(valueMaxWidth);\n\t\t\t\tconst inputLine = inputLines[0] ?? \"\";\n\t\t\t\tlines.push(prefix + labelText + separator + inputLine);\n\t\t\t} else {\n\t\t\t\tconst valueText = this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, \"\"), isSelected);\n\t\t\t\tlines.push(prefix + labelText + separator + valueText);\n\t\t\t}\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < displayItems.length) {\n\t\t\tconst scrollText = ` (${this.selectedIndex + 1}/${displayItems.length})`;\n\t\t\tlines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, \"\")));\n\t\t}\n\n\t\t// Add description for selected item\n\t\tconst selectedItem = displayItems[this.selectedIndex];\n\t\tif (selectedItem?.description && !this.editingInput) {\n\t\t\tlines.push(\"\");\n\t\t\tconst wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);\n\t\t\tfor (const line of wrappedDesc) {\n\t\t\t\tlines.push(this.theme.description(` ${line}`));\n\t\t\t}\n\t\t}\n\n\t\t// Add hint\n\t\tthis.addHintLine(lines);\n\n\t\treturn lines;\n\t}\n\n\thandleInput(data: string): void {\n\t\t// If editing a string value, handle input for the editor\n\t\tif (this.editingInput) {\n\t\t\tthis.handleEditingInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// If submenu is active, delegate all input to it\n\t\tif (this.submenuComponent) {\n\t\t\tthis.submenuComponent.handleInput?.(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Main list input handling\n\t\tconst kb = getEditorKeybindings();\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\n\t\tif (kb.matches(data, \"selectUp\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;\n\t\t} else if (kb.matches(data, \"selectDown\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t} else if (kb.matches(data, \"selectConfirm\") || data === \" \") {\n\t\t\tthis.activateItem();\n\t\t} else if (kb.matches(data, \"selectCancel\")) {\n\t\t\tthis.onCancel();\n\t\t} else if (this.searchEnabled && this.searchInput) {\n\t\t\tconst sanitized = data.replace(/ /g, \"\");\n\t\t\tif (!sanitized) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.searchInput.handleInput(sanitized);\n\t\t\tthis.applyFilter(this.searchInput.getValue());\n\t\t}\n\t}\n\n\tprivate handleEditingInput(data: string): void {\n\t\tif (!this.editingInput) return;\n\n\t\t// Enter: confirm edit\n\t\tif (matchesKey(data, \"enter\")) {\n\t\t\tthis.confirmEdit();\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape: cancel edit\n\t\tif (matchesKey(data, \"escape\")) {\n\t\t\tthis.cancelEdit();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass other input to the editor\n\t\tthis.editingInput.handleInput(data);\n\t}\n\n\tprivate confirmEdit(): void {\n\t\tif (!this.editingInput || this.editingItemIndex === null) return;\n\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tconst item = displayItems[this.editingItemIndex];\n\t\tif (item) {\n\t\t\tconst newValue = this.editingInput.getValue();\n\t\t\titem.currentValue = newValue;\n\t\t\tthis.onChange(item.id, newValue);\n\t\t}\n\n\t\tthis.editingInput = null;\n\t\tthis.editingItemIndex = null;\n\t}\n\n\tprivate cancelEdit(): void {\n\t\tthis.editingInput = null;\n\t\tthis.editingItemIndex = null;\n\t}\n\n\tprivate activateItem(): void {\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tconst item = displayItems[this.selectedIndex];\n\t\tif (!item) return;\n\n\t\tif (item.editable === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (item.submenu) {\n\t\t\t// Open submenu, passing current value so it can pre-select correctly\n\t\t\tthis.submenuItemIndex = this.selectedIndex;\n\t\t\tthis.submenuComponent = item.submenu(item.currentValue, (selectedValue?: string) => {\n\t\t\t\tif (selectedValue !== undefined) {\n\t\t\t\t\titem.currentValue = selectedValue;\n\t\t\t\t\tthis.onChange(item.id, selectedValue);\n\t\t\t\t}\n\t\t\t\tthis.closeSubmenu();\n\t\t\t});\n\t\t} else if (item.values && item.values.length > 0) {\n\t\t\t// Cycle through values\n\t\t\tconst currentIndex = item.values.indexOf(item.currentValue);\n\t\t\tconst nextIndex = (currentIndex + 1) % item.values.length;\n\t\t\tconst newValue = item.values[nextIndex];\n\t\t\titem.currentValue = newValue;\n\t\t\tthis.onChange(item.id, newValue);\n\t\t} else {\n\t\t\t// String input - start editing\n\t\t\tthis.editingItemIndex = this.selectedIndex;\n\t\t\tthis.editingInput = new Input();\n\t\t\tthis.editingInput.setValue(item.currentValue);\n\t\t}\n\t}\n\n\tprivate closeSubmenu(): void {\n\t\tthis.submenuComponent = null;\n\t\t// Restore selection to the item that opened the submenu\n\t\tif (this.submenuItemIndex !== null) {\n\t\t\tthis.selectedIndex = this.submenuItemIndex;\n\t\t\tthis.submenuItemIndex = null;\n\t\t}\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tthis.filteredItems = fuzzyFilter(this.items, query, (item) => item.label);\n\t\tthis.selectedIndex = 0;\n\t}\n\n\tprivate addHintLine(lines: string[]): void {\n\t\tlines.push(\"\");\n\t\tif (this.editingInput) {\n\t\t\tlines.push(this.theme.hint(\" Enter to confirm · Esc to cancel\"));\n\t\t} else if (this.searchEnabled) {\n\t\t\tlines.push(this.theme.hint(\" Type to search · Enter/Space to change · Esc to cancel\"));\n\t\t} else {\n\t\t\tlines.push(this.theme.hint(\" Enter/Space to change · Esc to cancel\"));\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"settings-list.js","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Settings list component with support for cycling values and string input.\n * Based on @mariozechner/pi-tui SettingsList, extended with string editing.\n */\n\nimport {\n\ttype Component,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tmatchesKey,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"@mariozechner/pi-tui\";\n\nexport interface SettingItem {\n\t/** Unique identifier for this setting */\n\tid: string;\n\t/** Display label (left side) */\n\tlabel: string;\n\t/** Optional description shown when selected */\n\tdescription?: string;\n\t/** Current value to display (right side) */\n\tcurrentValue: string;\n\t/**\n\t * If provided, Enter/Space cycles through these values.\n\t * If undefined/empty, the setting is treated as a string input.\n\t */\n\tvalues?: string[];\n\t/** If provided, Enter opens this submenu. Receives current value and done callback. */\n\tsubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;\n\t/** If false, item is selectable but cannot be edited or changed. */\n\teditable?: boolean;\n}\n\nexport interface SettingsListTheme {\n\tlabel: (text: string, selected: boolean) => string;\n\tvalue: (text: string, selected: boolean) => string;\n\tdescription: (text: string) => string;\n\tcursor: string;\n\thint: (text: string) => string;\n}\n\nexport interface SettingsListOptions {\n\tenableSearch?: boolean;\n}\n\nexport class SettingsList implements Component {\n\tprivate items: SettingItem[];\n\tprivate filteredItems: SettingItem[];\n\tprivate theme: SettingsListTheme;\n\tprivate selectedIndex = 0;\n\tprivate maxVisible: number;\n\tprivate onChange: (id: string, newValue: string) => void;\n\tprivate onCancel: () => void;\n\tprivate searchInput?: Input;\n\tprivate searchEnabled: boolean;\n\n\t// Submenu state\n\tprivate submenuComponent: Component | null = null;\n\tprivate submenuItemIndex: number | null = null;\n\n\t// String editing state\n\tprivate editingInput: Input | null = null;\n\tprivate editingItemIndex: number | null = null;\n\n\tconstructor(\n\t\titems: SettingItem[],\n\t\tmaxVisible: number,\n\t\ttheme: SettingsListTheme,\n\t\tonChange: (id: string, newValue: string) => void,\n\t\tonCancel: () => void,\n\t\toptions: SettingsListOptions = {},\n\t) {\n\t\tthis.items = items;\n\t\tthis.filteredItems = items;\n\t\tthis.maxVisible = maxVisible;\n\t\tthis.theme = theme;\n\t\tthis.onChange = onChange;\n\t\tthis.onCancel = onCancel;\n\t\tthis.searchEnabled = options.enableSearch ?? false;\n\t\tif (this.searchEnabled) {\n\t\t\tthis.searchInput = new Input();\n\t\t}\n\t}\n\n\t/** Update an item's currentValue */\n\tupdateValue(id: string, newValue: string): void {\n\t\tconst item = this.items.find((i) => i.id === id);\n\t\tif (item) {\n\t\t\titem.currentValue = newValue;\n\t\t}\n\t}\n\n\tinvalidate(): void {\n\t\tthis.submenuComponent?.invalidate?.();\n\t}\n\n\trender(width: number): string[] {\n\t\t// If submenu is active, render it instead\n\t\tif (this.submenuComponent) {\n\t\t\treturn this.submenuComponent.render(width);\n\t\t}\n\n\t\treturn this.renderMainList(width);\n\t}\n\n\tprivate renderMainList(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.searchEnabled && this.searchInput && !this.editingInput) {\n\t\t\tlines.push(...this.searchInput.render(width));\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\tif (this.items.length === 0) {\n\t\t\tlines.push(this.theme.hint(\" No settings available\"));\n\t\t\tif (this.searchEnabled) {\n\t\t\t\tthis.addHintLine(lines);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tif (displayItems.length === 0) {\n\t\t\tlines.push(this.theme.hint(\" No matching settings\"));\n\t\t\tthis.addHintLine(lines);\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), displayItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, displayItems.length);\n\n\t\t// Calculate max label width for alignment\n\t\tconst maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));\n\n\t\t// Render visible items\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = displayItems[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst isEditing = this.editingInput && this.editingItemIndex === i;\n\t\t\tconst prefix = isSelected ? this.theme.cursor : \" \";\n\t\t\tconst prefixWidth = visibleWidth(prefix);\n\n\t\t\t// Pad label to align values\n\t\t\tconst labelPadded = item.label + \" \".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));\n\t\t\tconst labelText = this.theme.label(labelPadded, isSelected);\n\n\t\t\t// Calculate space for value\n\t\t\tconst separator = \" \";\n\t\t\tconst usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);\n\t\t\tconst valueMaxWidth = width - usedWidth - 2;\n\n\t\t\tif (isEditing && this.editingInput) {\n\t\t\t\t// Render inline input for string editing\n\t\t\t\tconst inputLines = this.editingInput.render(valueMaxWidth);\n\t\t\t\tconst inputLine = inputLines[0] ?? \"\";\n\t\t\t\tlines.push(prefix + labelText + separator + inputLine);\n\t\t\t} else {\n\t\t\t\tconst valueText = this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, \"\"), isSelected);\n\t\t\t\tlines.push(prefix + labelText + separator + valueText);\n\t\t\t}\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < displayItems.length) {\n\t\t\tconst scrollText = ` (${this.selectedIndex + 1}/${displayItems.length})`;\n\t\t\tlines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, \"\")));\n\t\t}\n\n\t\t// Add description for selected item\n\t\tconst selectedItem = displayItems[this.selectedIndex];\n\t\tif (selectedItem?.description && !this.editingInput) {\n\t\t\tlines.push(\"\");\n\t\t\tconst wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);\n\t\t\tfor (const line of wrappedDesc) {\n\t\t\t\tlines.push(this.theme.description(` ${line}`));\n\t\t\t}\n\t\t}\n\n\t\t// Add hint\n\t\tthis.addHintLine(lines);\n\n\t\treturn lines;\n\t}\n\n\thandleInput(data: string): void {\n\t\t// If editing a string value, handle input for the editor\n\t\tif (this.editingInput) {\n\t\t\tthis.handleEditingInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// If submenu is active, delegate all input to it\n\t\tif (this.submenuComponent) {\n\t\t\tthis.submenuComponent.handleInput?.(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Main list input handling\n\t\tconst kb = getKeybindings();\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;\n\t\t} else if (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t} else if (kb.matches(data, \"tui.select.confirm\") || data === \" \") {\n\t\t\tthis.activateItem();\n\t\t} else if (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onCancel();\n\t\t} else if (this.searchEnabled && this.searchInput) {\n\t\t\tconst sanitized = data.replace(/ /g, \"\");\n\t\t\tif (!sanitized) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.searchInput.handleInput(sanitized);\n\t\t\tthis.applyFilter(this.searchInput.getValue());\n\t\t}\n\t}\n\n\tprivate handleEditingInput(data: string): void {\n\t\tif (!this.editingInput) return;\n\n\t\t// Enter: confirm edit\n\t\tif (matchesKey(data, \"enter\")) {\n\t\t\tthis.confirmEdit();\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape: cancel edit\n\t\tif (matchesKey(data, \"escape\")) {\n\t\t\tthis.cancelEdit();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass other input to the editor\n\t\tthis.editingInput.handleInput(data);\n\t}\n\n\tprivate confirmEdit(): void {\n\t\tif (!this.editingInput || this.editingItemIndex === null) return;\n\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tconst item = displayItems[this.editingItemIndex];\n\t\tif (item) {\n\t\t\tconst newValue = this.editingInput.getValue();\n\t\t\titem.currentValue = newValue;\n\t\t\tthis.onChange(item.id, newValue);\n\t\t}\n\n\t\tthis.editingInput = null;\n\t\tthis.editingItemIndex = null;\n\t}\n\n\tprivate cancelEdit(): void {\n\t\tthis.editingInput = null;\n\t\tthis.editingItemIndex = null;\n\t}\n\n\tprivate activateItem(): void {\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tconst item = displayItems[this.selectedIndex];\n\t\tif (!item) return;\n\n\t\tif (item.editable === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (item.submenu) {\n\t\t\t// Open submenu, passing current value so it can pre-select correctly\n\t\t\tthis.submenuItemIndex = this.selectedIndex;\n\t\t\tthis.submenuComponent = item.submenu(item.currentValue, (selectedValue?: string) => {\n\t\t\t\tif (selectedValue !== undefined) {\n\t\t\t\t\titem.currentValue = selectedValue;\n\t\t\t\t\tthis.onChange(item.id, selectedValue);\n\t\t\t\t}\n\t\t\t\tthis.closeSubmenu();\n\t\t\t});\n\t\t} else if (item.values && item.values.length > 0) {\n\t\t\t// Cycle through values\n\t\t\tconst currentIndex = item.values.indexOf(item.currentValue);\n\t\t\tconst nextIndex = (currentIndex + 1) % item.values.length;\n\t\t\tconst newValue = item.values[nextIndex];\n\t\t\titem.currentValue = newValue;\n\t\t\tthis.onChange(item.id, newValue);\n\t\t} else {\n\t\t\t// String input - start editing\n\t\t\tthis.editingItemIndex = this.selectedIndex;\n\t\t\tthis.editingInput = new Input();\n\t\t\tthis.editingInput.setValue(item.currentValue);\n\t\t}\n\t}\n\n\tprivate closeSubmenu(): void {\n\t\tthis.submenuComponent = null;\n\t\t// Restore selection to the item that opened the submenu\n\t\tif (this.submenuItemIndex !== null) {\n\t\t\tthis.selectedIndex = this.submenuItemIndex;\n\t\t\tthis.submenuItemIndex = null;\n\t\t}\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tthis.filteredItems = fuzzyFilter(this.items, query, (item) => item.label);\n\t\tthis.selectedIndex = 0;\n\t}\n\n\tprivate addHintLine(lines: string[]): void {\n\t\tlines.push(\"\");\n\t\tif (this.editingInput) {\n\t\t\tlines.push(this.theme.hint(\" Enter to confirm · Esc to cancel\"));\n\t\t} else if (this.searchEnabled) {\n\t\t\tlines.push(this.theme.hint(\" Type to search · Enter/Space to change · Esc to cancel\"));\n\t\t} else {\n\t\t\tlines.push(this.theme.hint(\" Enter/Space to change · Esc to cancel\"));\n\t\t}\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,52 +1,52 @@
1
1
  {
2
- "name": "@juanibiapina/pi-extension-settings",
3
- "version": "0.5.1",
4
- "description": "Pi extension for centralized settings management across extensions",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "scripts": {
9
- "clean": "rm -rf dist",
10
- "build": "tsc -p tsconfig.build.json",
11
- "dev": "tsc -p tsconfig.build.json --watch",
12
- "check": "biome check --write --error-on-warnings . && tsc --noEmit",
13
- "test": "node --test --import tsx test/*.test.ts",
14
- "prepublishOnly": "npm run clean && npm run build && npm run check"
15
- },
16
- "files": [
17
- "dist/**/*",
18
- "README.md"
19
- ],
20
- "keywords": [
21
- "pi",
22
- "pi-package",
23
- "extension",
24
- "config",
25
- "utilities"
26
- ],
27
- "pi": {
28
- "extensions": [
29
- "./dist/index.js"
30
- ]
31
- },
32
- "author": "Juan Ibiapina",
33
- "license": "MIT",
34
- "repository": {
35
- "type": "git",
36
- "url": "https://github.com/juanibiapina/pi-extension-settings"
37
- },
38
- "engines": {
39
- "node": ">=20.0.0"
40
- },
41
- "peerDependencies": {
42
- "@mariozechner/pi-coding-agent": "*",
43
- "@mariozechner/pi-tui": "*"
44
- },
45
- "devDependencies": {
46
- "@biomejs/biome": "2.3.5",
47
- "@mariozechner/pi-coding-agent": "^0.51.1",
48
- "@types/node": "^22.10.5",
49
- "tsx": "^4.20.3",
50
- "typescript": "^5.9.2"
51
- }
2
+ "name": "@juanibiapina/pi-extension-settings",
3
+ "version": "0.6.1",
4
+ "description": "Pi extension for centralized settings management across extensions",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "scripts": {
9
+ "clean": "rm -rf dist",
10
+ "build": "tsc -p tsconfig.build.json",
11
+ "dev": "tsc -p tsconfig.build.json --watch",
12
+ "check": "biome check --write --error-on-warnings . && tsc --noEmit",
13
+ "test": "node --test --import tsx test/*.test.ts",
14
+ "prepublishOnly": "npm run clean && npm run build && npm run check"
15
+ },
16
+ "files": [
17
+ "dist/**/*",
18
+ "README.md"
19
+ ],
20
+ "keywords": [
21
+ "pi",
22
+ "pi-package",
23
+ "extension",
24
+ "config",
25
+ "utilities"
26
+ ],
27
+ "pi": {
28
+ "extensions": [
29
+ "./dist/index.js"
30
+ ]
31
+ },
32
+ "author": "Juan Ibiapina",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/juanibiapina/pi-extension-settings"
37
+ },
38
+ "engines": {
39
+ "node": ">=20.0.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@mariozechner/pi-coding-agent": "*",
43
+ "@mariozechner/pi-tui": "*"
44
+ },
45
+ "devDependencies": {
46
+ "@biomejs/biome": "2.4.9",
47
+ "@mariozechner/pi-coding-agent": "^0.64.0",
48
+ "@types/node": "^25.5.0",
49
+ "tsx": "^4.20.3",
50
+ "typescript": "^6.0.2"
51
+ }
52
52
  }