@slkiser/opencode-quota 5.0.3 → 6.0.0-beta.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/README.md +30 -44
- package/dist/agent-tools.d.ts +24 -0
- package/dist/agent-tools.d.ts.map +1 -0
- package/dist/agent-tools.js +578 -0
- package/dist/agent-tools.js.map +1 -0
- package/dist/bin/opencode-quota.d.ts.map +1 -1
- package/dist/bin/opencode-quota.js +1 -32
- package/dist/bin/opencode-quota.js.map +1 -1
- package/dist/core/errors.d.ts +12 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +141 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/pace.d.ts +13 -0
- package/dist/core/pace.d.ts.map +1 -0
- package/dist/core/pace.js +52 -0
- package/dist/core/pace.js.map +1 -0
- package/dist/core/persist.d.ts +44 -0
- package/dist/core/persist.d.ts.map +1 -0
- package/dist/core/persist.js +210 -0
- package/dist/core/persist.js.map +1 -0
- package/dist/core/provider-source.d.ts +40 -0
- package/dist/core/provider-source.d.ts.map +1 -0
- package/dist/core/provider-source.js +210 -0
- package/dist/core/provider-source.js.map +1 -0
- package/dist/core/redact.d.ts +17 -0
- package/dist/core/redact.d.ts.map +1 -0
- package/dist/core/redact.js +217 -0
- package/dist/core/redact.js.map +1 -0
- package/dist/core/rows.d.ts +20 -0
- package/dist/core/rows.d.ts.map +1 -0
- package/dist/core/rows.js +142 -0
- package/dist/core/rows.js.map +1 -0
- package/dist/core/selection.d.ts +15 -0
- package/dist/core/selection.d.ts.map +1 -0
- package/dist/core/selection.js +43 -0
- package/dist/core/selection.js.map +1 -0
- package/dist/core/snapshot-publisher.d.ts +15 -0
- package/dist/core/snapshot-publisher.d.ts.map +1 -0
- package/dist/core/snapshot-publisher.js +57 -0
- package/dist/core/snapshot-publisher.js.map +1 -0
- package/dist/core/store.d.ts +93 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +563 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/types.d.ts +186 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usage-ranges.d.ts +46 -0
- package/dist/core/usage-ranges.d.ts.map +1 -0
- package/dist/core/usage-ranges.js +72 -0
- package/dist/core/usage-ranges.js.map +1 -0
- package/dist/core/usage.d.ts +100 -0
- package/dist/core/usage.d.ts.map +1 -0
- package/dist/core/usage.js +373 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/core/validate.d.ts +8 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +167 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/core/windows.d.ts +24 -0
- package/dist/core/windows.d.ts.map +1 -0
- package/dist/core/windows.js +43 -0
- package/dist/core/windows.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/accounting-format.d.ts +2 -52
- package/dist/lib/accounting-format.d.ts.map +1 -1
- package/dist/lib/accounting-format.js +6 -255
- package/dist/lib/accounting-format.js.map +1 -1
- package/dist/lib/alibaba-auth.d.ts +14 -21
- package/dist/lib/alibaba-auth.d.ts.map +1 -1
- package/dist/lib/alibaba-auth.js +36 -149
- package/dist/lib/alibaba-auth.js.map +1 -1
- package/dist/lib/alibaba-coding-plan-local-quota.d.ts +1 -6
- package/dist/lib/alibaba-coding-plan-local-quota.d.ts.map +1 -1
- package/dist/lib/alibaba-coding-plan-local-quota.js +1 -1
- package/dist/lib/alibaba-coding-plan-local-quota.js.map +1 -1
- package/dist/lib/alibaba-token-plan.d.ts +18 -27
- package/dist/lib/alibaba-token-plan.d.ts.map +1 -1
- package/dist/lib/alibaba-token-plan.js +121 -285
- package/dist/lib/alibaba-token-plan.js.map +1 -1
- package/dist/lib/anthropic-auth.d.ts +3 -5
- package/dist/lib/anthropic-auth.d.ts.map +1 -1
- package/dist/lib/anthropic-auth.js +6 -9
- package/dist/lib/anthropic-auth.js.map +1 -1
- package/dist/lib/anthropic.d.ts +12 -37
- package/dist/lib/anthropic.d.ts.map +1 -1
- package/dist/lib/anthropic.js +348 -698
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/api-key-resolver.d.ts +165 -192
- package/dist/lib/api-key-resolver.d.ts.map +1 -1
- package/dist/lib/api-key-resolver.js +208 -234
- package/dist/lib/api-key-resolver.js.map +1 -1
- package/dist/lib/atomic-json.d.ts +4 -1
- package/dist/lib/atomic-json.d.ts.map +1 -1
- package/dist/lib/atomic-json.js +2 -3
- package/dist/lib/atomic-json.js.map +1 -1
- package/dist/lib/calendar-date.d.ts +15 -0
- package/dist/lib/calendar-date.d.ts.map +1 -0
- package/dist/lib/calendar-date.js +21 -0
- package/dist/lib/calendar-date.js.map +1 -0
- package/dist/lib/chutes.d.ts +0 -1
- package/dist/lib/chutes.d.ts.map +1 -1
- package/dist/lib/chutes.js +2 -4
- package/dist/lib/chutes.js.map +1 -1
- package/dist/lib/cli-reports.d.ts +15 -11
- package/dist/lib/cli-reports.d.ts.map +1 -1
- package/dist/lib/cli-reports.js +34 -107
- package/dist/lib/cli-reports.js.map +1 -1
- package/dist/lib/cli-show.d.ts +9 -22
- package/dist/lib/cli-show.d.ts.map +1 -1
- package/dist/lib/cli-show.js +104 -75
- package/dist/lib/cli-show.js.map +1 -1
- package/dist/lib/config-file-utils.d.ts +3 -15
- package/dist/lib/config-file-utils.d.ts.map +1 -1
- package/dist/lib/config-file-utils.js +4 -63
- package/dist/lib/config-file-utils.js.map +1 -1
- package/dist/lib/config-write-target.d.ts +4 -7
- package/dist/lib/config-write-target.d.ts.map +1 -1
- package/dist/lib/config-write-target.js +4 -18
- package/dist/lib/config-write-target.js.map +1 -1
- package/dist/lib/copilot.d.ts +29 -20
- package/dist/lib/copilot.d.ts.map +1 -1
- package/dist/lib/copilot.js +392 -649
- package/dist/lib/copilot.js.map +1 -1
- package/dist/lib/cursor-detection.d.ts +3 -3
- package/dist/lib/cursor-detection.d.ts.map +1 -1
- package/dist/lib/cursor-detection.js +44 -88
- package/dist/lib/cursor-detection.js.map +1 -1
- package/dist/lib/cursor-pricing.d.ts +71 -8
- package/dist/lib/cursor-pricing.d.ts.map +1 -1
- package/dist/lib/cursor-pricing.js +33 -125
- package/dist/lib/cursor-pricing.js.map +1 -1
- package/dist/lib/cursor-usage.d.ts +6 -4
- package/dist/lib/cursor-usage.d.ts.map +1 -1
- package/dist/lib/cursor-usage.js +27 -40
- package/dist/lib/cursor-usage.js.map +1 -1
- package/dist/lib/deepseek.d.ts +9 -17
- package/dist/lib/deepseek.d.ts.map +1 -1
- package/dist/lib/deepseek.js +24 -54
- package/dist/lib/deepseek.js.map +1 -1
- package/dist/lib/display-sanitize.d.ts +0 -8
- package/dist/lib/display-sanitize.d.ts.map +1 -1
- package/dist/lib/display-sanitize.js +0 -139
- package/dist/lib/display-sanitize.js.map +1 -1
- package/dist/lib/entries.d.ts +13 -239
- package/dist/lib/entries.d.ts.map +1 -1
- package/dist/lib/entries.js +1 -46
- package/dist/lib/entries.js.map +1 -1
- package/dist/lib/file-lock.d.ts +23 -0
- package/dist/lib/file-lock.d.ts.map +1 -0
- package/dist/lib/file-lock.js +122 -0
- package/dist/lib/file-lock.js.map +1 -0
- package/dist/lib/format-utils.d.ts +2 -82
- package/dist/lib/format-utils.d.ts.map +1 -1
- package/dist/lib/format-utils.js +2 -191
- package/dist/lib/format-utils.js.map +1 -1
- package/dist/lib/glm-coding-plan.d.ts +6 -5
- package/dist/lib/glm-coding-plan.d.ts.map +1 -1
- package/dist/lib/glm-coding-plan.js +19 -1
- package/dist/lib/glm-coding-plan.js.map +1 -1
- package/dist/lib/google-agy.d.ts +8 -40
- package/dist/lib/google-agy.d.ts.map +1 -1
- package/dist/lib/google-agy.js +88 -519
- package/dist/lib/google-agy.js.map +1 -1
- package/dist/lib/google-companion-credentials.d.ts +9 -40
- package/dist/lib/google-companion-credentials.d.ts.map +1 -1
- package/dist/lib/google-companion-credentials.js +167 -224
- package/dist/lib/google-companion-credentials.js.map +1 -1
- package/dist/lib/google-gemini-cli.d.ts +5 -38
- package/dist/lib/google-gemini-cli.d.ts.map +1 -1
- package/dist/lib/google-gemini-cli.js +71 -442
- package/dist/lib/google-gemini-cli.js.map +1 -1
- package/dist/lib/google-oauth-quota.d.ts +76 -0
- package/dist/lib/google-oauth-quota.d.ts.map +1 -0
- package/dist/lib/google-oauth-quota.js +297 -0
- package/dist/lib/google-oauth-quota.js.map +1 -0
- package/dist/lib/google-token-cache.d.ts +3 -5
- package/dist/lib/google-token-cache.d.ts.map +1 -1
- package/dist/lib/google-token-cache.js +2 -14
- package/dist/lib/google-token-cache.js.map +1 -1
- package/dist/lib/home-dir-display.d.ts.map +1 -1
- package/dist/lib/home-dir-display.js +21 -39
- package/dist/lib/home-dir-display.js.map +1 -1
- package/dist/lib/http.d.ts +4 -1
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +2 -1
- package/dist/lib/http.js.map +1 -1
- package/dist/lib/json-guards.d.ts +11 -0
- package/dist/lib/json-guards.d.ts.map +1 -0
- package/dist/lib/json-guards.js +25 -0
- package/dist/lib/json-guards.js.map +1 -0
- package/dist/lib/kilo.d.ts +0 -2
- package/dist/lib/kilo.d.ts.map +1 -1
- package/dist/lib/kilo.js +33 -116
- package/dist/lib/kilo.js.map +1 -1
- package/dist/lib/kimi-endpoints.d.ts +2 -2
- package/dist/lib/kimi-endpoints.d.ts.map +1 -1
- package/dist/lib/kimi-endpoints.js +1 -1
- package/dist/lib/kimi-endpoints.js.map +1 -1
- package/dist/lib/kimi.d.ts.map +1 -1
- package/dist/lib/kimi.js +40 -86
- package/dist/lib/kimi.js.map +1 -1
- package/dist/lib/maintainer-announcements.d.ts +4 -17
- package/dist/lib/maintainer-announcements.d.ts.map +1 -1
- package/dist/lib/maintainer-announcements.js +7 -44
- package/dist/lib/maintainer-announcements.js.map +1 -1
- package/dist/lib/maintainer-home-notice.d.ts +19 -0
- package/dist/lib/maintainer-home-notice.d.ts.map +1 -0
- package/dist/lib/maintainer-home-notice.js +92 -0
- package/dist/lib/maintainer-home-notice.js.map +1 -0
- package/dist/lib/mimo-config.d.ts +6 -9
- package/dist/lib/mimo-config.d.ts.map +1 -1
- package/dist/lib/mimo-config.js +43 -74
- package/dist/lib/mimo-config.js.map +1 -1
- package/dist/lib/mimo.d.ts +2 -5
- package/dist/lib/mimo.d.ts.map +1 -1
- package/dist/lib/mimo.js +57 -109
- package/dist/lib/mimo.js.map +1 -1
- package/dist/lib/minimax-endpoints.d.ts +2 -2
- package/dist/lib/minimax-endpoints.d.ts.map +1 -1
- package/dist/lib/minimax-endpoints.js +1 -1
- package/dist/lib/minimax-endpoints.js.map +1 -1
- package/dist/lib/modelsdev-pricing.d.ts +22 -16
- package/dist/lib/modelsdev-pricing.d.ts.map +1 -1
- package/dist/lib/modelsdev-pricing.js +279 -560
- package/dist/lib/modelsdev-pricing.js.map +1 -1
- package/dist/lib/nanogpt.d.ts +6 -6
- package/dist/lib/nanogpt.d.ts.map +1 -1
- package/dist/lib/nanogpt.js +19 -72
- package/dist/lib/nanogpt.js.map +1 -1
- package/dist/lib/ollama-cloud.d.ts +3 -6
- package/dist/lib/ollama-cloud.d.ts.map +1 -1
- package/dist/lib/ollama-cloud.js +26 -37
- package/dist/lib/ollama-cloud.js.map +1 -1
- package/dist/lib/openai.d.ts +18 -29
- package/dist/lib/openai.d.ts.map +1 -1
- package/dist/lib/openai.js +108 -182
- package/dist/lib/openai.js.map +1 -1
- package/dist/lib/opencode-auth-sqlite.d.ts.map +1 -1
- package/dist/lib/opencode-auth-sqlite.js +22 -23
- package/dist/lib/opencode-auth-sqlite.js.map +1 -1
- package/dist/lib/opencode-auth.d.ts +17 -11
- package/dist/lib/opencode-auth.d.ts.map +1 -1
- package/dist/lib/opencode-auth.js +39 -46
- package/dist/lib/opencode-auth.js.map +1 -1
- package/dist/lib/opencode-config-editor.d.ts +3 -34
- package/dist/lib/opencode-config-editor.d.ts.map +1 -1
- package/dist/lib/opencode-config-editor.js +23 -142
- package/dist/lib/opencode-config-editor.js.map +1 -1
- package/dist/lib/opencode-config-providers.d.ts +4 -3
- package/dist/lib/opencode-config-providers.d.ts.map +1 -1
- package/dist/lib/opencode-config-providers.js +7 -11
- package/dist/lib/opencode-config-providers.js.map +1 -1
- package/dist/lib/opencode-config-read.d.ts +2 -1
- package/dist/lib/opencode-config-read.d.ts.map +1 -1
- package/dist/lib/opencode-config-read.js +3 -2
- package/dist/lib/opencode-config-read.js.map +1 -1
- package/dist/lib/opencode-console-auth.d.ts +2 -3
- package/dist/lib/opencode-console-auth.d.ts.map +1 -1
- package/dist/lib/opencode-console-auth.js +2 -2
- package/dist/lib/opencode-console-auth.js.map +1 -1
- package/dist/lib/opencode-go.d.ts.map +1 -1
- package/dist/lib/opencode-go.js +51 -79
- package/dist/lib/opencode-go.js.map +1 -1
- package/dist/lib/opencode-storage.d.ts +18 -3
- package/dist/lib/opencode-storage.d.ts.map +1 -1
- package/dist/lib/opencode-storage.js +134 -2
- package/dist/lib/opencode-storage.js.map +1 -1
- package/dist/lib/opencode-zen.d.ts +15 -12
- package/dist/lib/opencode-zen.d.ts.map +1 -1
- package/dist/lib/opencode-zen.js +139 -147
- package/dist/lib/opencode-zen.js.map +1 -1
- package/dist/lib/openrouter.d.ts.map +1 -1
- package/dist/lib/openrouter.js +1 -13
- package/dist/lib/openrouter.js.map +1 -1
- package/dist/lib/pricing-key.d.ts +48 -0
- package/dist/lib/pricing-key.d.ts.map +1 -0
- package/dist/lib/pricing-key.js +371 -0
- package/dist/lib/pricing-key.js.map +1 -0
- package/dist/lib/provider-metadata.d.ts +16 -20
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +69 -69
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/provider-model-matching.d.ts +2 -1
- package/dist/lib/provider-model-matching.d.ts.map +1 -1
- package/dist/lib/provider-registration.d.ts +1 -177
- package/dist/lib/provider-registration.d.ts.map +1 -1
- package/dist/lib/provider-registration.js +1 -163
- package/dist/lib/provider-registration.js.map +1 -1
- package/dist/lib/quota-dialog-commands.d.ts +87 -53
- package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
- package/dist/lib/quota-dialog-commands.js +259 -519
- package/dist/lib/quota-dialog-commands.js.map +1 -1
- package/dist/lib/quota-export-types.d.ts +29 -23
- package/dist/lib/quota-export-types.d.ts.map +1 -1
- package/dist/lib/quota-export.d.ts +16 -26
- package/dist/lib/quota-export.d.ts.map +1 -1
- package/dist/lib/quota-export.js +105 -147
- package/dist/lib/quota-export.js.map +1 -1
- package/dist/lib/quota-providers-local.d.ts +12 -8
- package/dist/lib/quota-providers-local.d.ts.map +1 -1
- package/dist/lib/quota-providers-local.js +150 -223
- package/dist/lib/quota-providers-local.js.map +1 -1
- package/dist/lib/quota-providers-remote.d.ts +3 -8
- package/dist/lib/quota-providers-remote.d.ts.map +1 -1
- package/dist/lib/quota-providers-remote.js +309 -449
- package/dist/lib/quota-providers-remote.js.map +1 -1
- package/dist/lib/quota-providers.d.ts +57 -15
- package/dist/lib/quota-providers.d.ts.map +1 -1
- package/dist/lib/quota-providers.js +157 -64
- package/dist/lib/quota-providers.js.map +1 -1
- package/dist/lib/quota-report-message.d.ts +23 -10
- package/dist/lib/quota-report-message.d.ts.map +1 -1
- package/dist/lib/quota-report-message.js +37 -13
- package/dist/lib/quota-report-message.js.map +1 -1
- package/dist/lib/quota-retry-wait.d.ts +14 -6
- package/dist/lib/quota-retry-wait.d.ts.map +1 -1
- package/dist/lib/quota-retry-wait.js +37 -39
- package/dist/lib/quota-retry-wait.js.map +1 -1
- package/dist/lib/quota-status.d.ts +50 -33
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +1113 -773
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/quota-telemetry.d.ts +7 -14
- package/dist/lib/quota-telemetry.d.ts.map +1 -1
- package/dist/lib/quota-telemetry.js +46 -97
- package/dist/lib/quota-telemetry.js.map +1 -1
- package/dist/lib/report-document.d.ts +5 -65
- package/dist/lib/report-document.d.ts.map +1 -1
- package/dist/lib/report-document.js +14 -167
- package/dist/lib/report-document.js.map +1 -1
- package/dist/lib/resolved-auth-identity.d.ts +1 -2
- package/dist/lib/resolved-auth-identity.d.ts.map +1 -1
- package/dist/lib/resolved-auth-identity.js +0 -4
- package/dist/lib/resolved-auth-identity.js.map +1 -1
- package/dist/lib/session-tokens.d.ts +19 -19
- package/dist/lib/session-tokens.d.ts.map +1 -1
- package/dist/lib/session-tokens.js +58 -44
- package/dist/lib/session-tokens.js.map +1 -1
- package/dist/lib/synthetic.d.ts +0 -1
- package/dist/lib/synthetic.d.ts.map +1 -1
- package/dist/lib/synthetic.js +43 -94
- package/dist/lib/synthetic.js.map +1 -1
- package/dist/lib/token-buckets.d.ts +0 -1
- package/dist/lib/token-buckets.d.ts.map +1 -1
- package/dist/lib/token-buckets.js +0 -3
- package/dist/lib/token-buckets.js.map +1 -1
- package/dist/lib/token-cost.d.ts +2 -1
- package/dist/lib/token-cost.d.ts.map +1 -1
- package/dist/lib/types.d.ts +25 -333
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +2 -70
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/xai.d.ts +6 -6
- package/dist/lib/xai.d.ts.map +1 -1
- package/dist/lib/xai.js +51 -90
- package/dist/lib/xai.js.map +1 -1
- package/dist/plugin.d.ts +6 -3
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +315 -90
- package/dist/plugin.js.map +1 -1
- package/dist/providers/alibaba-coding-plan.d.ts +4 -0
- package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
- package/dist/providers/alibaba-coding-plan.js +47 -77
- package/dist/providers/alibaba-coding-plan.js.map +1 -1
- package/dist/providers/alibaba-token-plan.d.ts.map +1 -1
- package/dist/providers/alibaba-token-plan.js +34 -46
- package/dist/providers/alibaba-token-plan.js.map +1 -1
- package/dist/providers/anthropic.d.ts +2 -4
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +80 -162
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/cache-policies.d.ts +0 -2
- package/dist/providers/cache-policies.d.ts.map +1 -1
- package/dist/providers/cache-policies.js +38 -88
- package/dist/providers/cache-policies.js.map +1 -1
- package/dist/providers/chutes.d.ts +0 -3
- package/dist/providers/chutes.d.ts.map +1 -1
- package/dist/providers/chutes.js +16 -28
- package/dist/providers/chutes.js.map +1 -1
- package/dist/providers/contract.d.ts +128 -0
- package/dist/providers/contract.d.ts.map +1 -0
- package/dist/providers/contract.js +101 -0
- package/dist/providers/contract.js.map +1 -0
- package/dist/providers/copilot.d.ts.map +1 -1
- package/dist/providers/copilot.js +171 -175
- package/dist/providers/copilot.js.map +1 -1
- package/dist/providers/cursor.d.ts.map +1 -1
- package/dist/providers/cursor.js +56 -109
- package/dist/providers/cursor.js.map +1 -1
- package/dist/providers/deepseek.d.ts +1 -6
- package/dist/providers/deepseek.d.ts.map +1 -1
- package/dist/providers/deepseek.js +46 -81
- package/dist/providers/deepseek.js.map +1 -1
- package/dist/providers/glm-coding-plan.d.ts +8 -0
- package/dist/providers/glm-coding-plan.d.ts.map +1 -0
- package/dist/providers/glm-coding-plan.js +106 -0
- package/dist/providers/glm-coding-plan.js.map +1 -0
- package/dist/providers/google-agy.d.ts +0 -1
- package/dist/providers/google-agy.d.ts.map +1 -1
- package/dist/providers/google-agy.js +41 -192
- package/dist/providers/google-agy.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/dist/providers/google-gemini-cli.js +51 -151
- package/dist/providers/google-gemini-cli.js.map +1 -1
- package/dist/providers/google-oauth-provider.d.ts +39 -0
- package/dist/providers/google-oauth-provider.d.ts.map +1 -0
- package/dist/providers/google-oauth-provider.js +161 -0
- package/dist/providers/google-oauth-provider.js.map +1 -0
- package/dist/providers/kilo.d.ts +0 -3
- package/dist/providers/kilo.d.ts.map +1 -1
- package/dist/providers/kilo.js +69 -123
- package/dist/providers/kilo.js.map +1 -1
- package/dist/providers/kimi-code.d.ts +5 -0
- package/dist/providers/kimi-code.d.ts.map +1 -1
- package/dist/providers/kimi-code.js +91 -136
- package/dist/providers/kimi-code.js.map +1 -1
- package/dist/providers/mimo.d.ts.map +1 -1
- package/dist/providers/mimo.js +55 -94
- package/dist/providers/mimo.js.map +1 -1
- package/dist/providers/minimax-coding-plan.d.ts +2 -23
- package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
- package/dist/providers/minimax-coding-plan.js +161 -277
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/nanogpt.d.ts +0 -3
- package/dist/providers/nanogpt.d.ts.map +1 -1
- package/dist/providers/nanogpt.js +61 -95
- package/dist/providers/nanogpt.js.map +1 -1
- package/dist/providers/ollama-cloud.d.ts +0 -6
- package/dist/providers/ollama-cloud.d.ts.map +1 -1
- package/dist/providers/ollama-cloud.js +86 -112
- package/dist/providers/ollama-cloud.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +144 -166
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js +157 -199
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/opencode-zen.d.ts.map +1 -1
- package/dist/providers/opencode-zen.js +100 -150
- package/dist/providers/opencode-zen.js.map +1 -1
- package/dist/providers/openrouter.d.ts +0 -3
- package/dist/providers/openrouter.d.ts.map +1 -1
- package/dist/providers/openrouter.js +26 -13
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/quota-providers.d.ts +7 -3
- package/dist/providers/quota-providers.d.ts.map +1 -1
- package/dist/providers/quota-providers.js +111 -217
- package/dist/providers/quota-providers.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +1 -2
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/result-helpers.d.ts +10 -37
- package/dist/providers/result-helpers.d.ts.map +1 -1
- package/dist/providers/result-helpers.js +23 -56
- package/dist/providers/result-helpers.js.map +1 -1
- package/dist/providers/synthetic.d.ts +0 -3
- package/dist/providers/synthetic.d.ts.map +1 -1
- package/dist/providers/synthetic.js +16 -58
- package/dist/providers/synthetic.js.map +1 -1
- package/dist/providers/xai.d.ts +2 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/providers/xai.js +49 -71
- package/dist/providers/xai.js.map +1 -1
- package/dist/rpc.d.ts +110 -38
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +125 -37
- package/dist/rpc.js.map +1 -1
- package/dist/settings/convert.d.ts +60 -0
- package/dist/settings/convert.d.ts.map +1 -0
- package/dist/settings/convert.js +473 -0
- package/dist/settings/convert.js.map +1 -0
- package/dist/settings/file.d.ts +89 -0
- package/dist/settings/file.d.ts.map +1 -0
- package/dist/settings/file.js +452 -0
- package/dist/settings/file.js.map +1 -0
- package/dist/settings/index.d.ts +10 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +3 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/schema.d.ts +607 -0
- package/dist/settings/schema.d.ts.map +1 -0
- package/dist/settings/schema.js +479 -0
- package/dist/settings/schema.js.map +1 -0
- package/dist/tui/client.d.ts +86 -0
- package/dist/tui/client.d.ts.map +1 -0
- package/dist/tui/client.js +229 -0
- package/dist/tui/client.js.map +1 -0
- package/dist/tui/display.d.ts +127 -0
- package/dist/tui/display.d.ts.map +1 -0
- package/dist/tui/display.js +474 -0
- package/dist/tui/display.js.map +1 -0
- package/dist/tui/index.d.ts +21 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +305 -0
- package/dist/tui/server-settings.d.ts +43 -0
- package/dist/tui/server-settings.d.ts.map +1 -0
- package/dist/tui/server-settings.js +233 -0
- package/dist/tui/server-settings.js.map +1 -0
- package/dist/tui/sidebar.d.ts +41 -0
- package/dist/tui/sidebar.d.ts.map +1 -0
- package/dist/tui/sidebar.js +148 -0
- package/dist/tui/status-line.d.ts +14 -0
- package/dist/tui/status-line.d.ts.map +1 -0
- package/dist/tui/status-line.js +225 -0
- package/dist/tui/theme.d.ts +41 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +52 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/toast-colors.d.ts +37 -0
- package/dist/tui/toast-colors.d.ts.map +1 -0
- package/dist/tui/toast-colors.js +77 -0
- package/dist/tui/toasts.d.ts +59 -0
- package/dist/tui/toasts.d.ts.map +1 -0
- package/dist/tui/toasts.js +148 -0
- package/dist/tui/toasts.js.map +1 -0
- package/dist/tui/window/drag.d.ts +26 -0
- package/dist/tui/window/drag.d.ts.map +1 -0
- package/dist/tui/window/drag.js +80 -0
- package/dist/tui/window/drag.js.map +1 -0
- package/dist/tui/window/limits.d.ts +15 -0
- package/dist/tui/window/limits.d.ts.map +1 -0
- package/dist/tui/window/limits.js +227 -0
- package/dist/tui/window/limits.js.map +1 -0
- package/dist/tui/window/rail.d.ts +21 -0
- package/dist/tui/window/rail.d.ts.map +1 -0
- package/dist/tui/window/rail.js +81 -0
- package/dist/tui/window/settings.d.ts +164 -0
- package/dist/tui/window/settings.d.ts.map +1 -0
- package/dist/tui/window/settings.js +1679 -0
- package/dist/tui/window/shell.d.ts +108 -0
- package/dist/tui/window/shell.d.ts.map +1 -0
- package/dist/tui/window/shell.js +1003 -0
- package/dist/tui/window/usage.d.ts +75 -0
- package/dist/tui/window/usage.d.ts.map +1 -0
- package/dist/tui/window/usage.js +928 -0
- package/dist/tui/window/views.d.ts +61 -0
- package/dist/tui/window/views.d.ts.map +1 -0
- package/dist/tui/window/views.js +242 -0
- package/dist/tui.d.ts +1 -5
- package/dist/tui.js +1 -894
- package/dist/view/columns.d.ts +15 -0
- package/dist/view/columns.d.ts.map +1 -0
- package/dist/view/columns.js +48 -0
- package/dist/view/columns.js.map +1 -0
- package/dist/view/format.d.ts +82 -0
- package/dist/view/format.d.ts.map +1 -0
- package/dist/view/format.js +201 -0
- package/dist/view/format.js.map +1 -0
- package/dist/view/quick-look.d.ts +28 -0
- package/dist/view/quick-look.d.ts.map +1 -0
- package/dist/view/quick-look.js +150 -0
- package/dist/view/quick-look.js.map +1 -0
- package/dist/view/select.d.ts +67 -0
- package/dist/view/select.d.ts.map +1 -0
- package/dist/view/select.js +87 -0
- package/dist/view/select.js.map +1 -0
- package/dist/view/text.d.ts +153 -0
- package/dist/view/text.d.ts.map +1 -0
- package/dist/view/text.js +642 -0
- package/dist/view/text.js.map +1 -0
- package/dist/view/usage.d.ts +86 -0
- package/dist/view/usage.d.ts.map +1 -0
- package/dist/view/usage.js +724 -0
- package/dist/view/usage.js.map +1 -0
- package/package.json +4 -6
- package/dist/lib/chutes-config.d.ts +0 -15
- package/dist/lib/chutes-config.d.ts.map +0 -1
- package/dist/lib/chutes-config.js +0 -28
- package/dist/lib/chutes-config.js.map +0 -1
- package/dist/lib/cli-status.d.ts +0 -8
- package/dist/lib/cli-status.d.ts.map +0 -1
- package/dist/lib/cli-status.js +0 -98
- package/dist/lib/cli-status.js.map +0 -1
- package/dist/lib/command-parsing.d.ts +0 -43
- package/dist/lib/command-parsing.d.ts.map +0 -1
- package/dist/lib/command-parsing.js +0 -103
- package/dist/lib/command-parsing.js.map +0 -1
- package/dist/lib/config.d.ts +0 -63
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js +0 -1092
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/deepseek-auth.d.ts +0 -15
- package/dist/lib/deepseek-auth.d.ts.map +0 -1
- package/dist/lib/deepseek-auth.js +0 -28
- package/dist/lib/deepseek-auth.js.map +0 -1
- package/dist/lib/format.d.ts +0 -25
- package/dist/lib/format.d.ts.map +0 -1
- package/dist/lib/format.js +0 -300
- package/dist/lib/format.js.map +0 -1
- package/dist/lib/google-agy-companion.d.ts +0 -8
- package/dist/lib/google-agy-companion.d.ts.map +0 -1
- package/dist/lib/google-agy-companion.js +0 -64
- package/dist/lib/google-agy-companion.js.map +0 -1
- package/dist/lib/google-gemini-cli-companion.d.ts +0 -8
- package/dist/lib/google-gemini-cli-companion.d.ts.map +0 -1
- package/dist/lib/google-gemini-cli-companion.js +0 -64
- package/dist/lib/google-gemini-cli-companion.js.map +0 -1
- package/dist/lib/grouped-entry-normalization.d.ts +0 -12
- package/dist/lib/grouped-entry-normalization.d.ts.map +0 -1
- package/dist/lib/grouped-entry-normalization.js +0 -124
- package/dist/lib/grouped-entry-normalization.js.map +0 -1
- package/dist/lib/grouped-header-format.d.ts +0 -5
- package/dist/lib/grouped-header-format.d.ts.map +0 -1
- package/dist/lib/grouped-header-format.js +0 -16
- package/dist/lib/grouped-header-format.js.map +0 -1
- package/dist/lib/init-installer.d.ts +0 -123
- package/dist/lib/init-installer.d.ts.map +0 -1
- package/dist/lib/init-installer.js +0 -1111
- package/dist/lib/init-installer.js.map +0 -1
- package/dist/lib/jsonc.d.ts +0 -17
- package/dist/lib/jsonc.d.ts.map +0 -1
- package/dist/lib/jsonc.js +0 -23
- package/dist/lib/jsonc.js.map +0 -1
- package/dist/lib/kilo-config.d.ts +0 -15
- package/dist/lib/kilo-config.d.ts.map +0 -1
- package/dist/lib/kilo-config.js +0 -27
- package/dist/lib/kilo-config.js.map +0 -1
- package/dist/lib/kimi-auth.d.ts +0 -49
- package/dist/lib/kimi-auth.d.ts.map +0 -1
- package/dist/lib/kimi-auth.js +0 -82
- package/dist/lib/kimi-auth.js.map +0 -1
- package/dist/lib/markdown-table.d.ts +0 -51
- package/dist/lib/markdown-table.d.ts.map +0 -1
- package/dist/lib/markdown-table.js +0 -179
- package/dist/lib/markdown-table.js.map +0 -1
- package/dist/lib/minimax-auth.d.ts +0 -62
- package/dist/lib/minimax-auth.d.ts.map +0 -1
- package/dist/lib/minimax-auth.js +0 -206
- package/dist/lib/minimax-auth.js.map +0 -1
- package/dist/lib/nanogpt-config.d.ts +0 -15
- package/dist/lib/nanogpt-config.d.ts.map +0 -1
- package/dist/lib/nanogpt-config.js +0 -31
- package/dist/lib/nanogpt-config.js.map +0 -1
- package/dist/lib/ollama-cloud-config.d.ts +0 -15
- package/dist/lib/ollama-cloud-config.d.ts.map +0 -1
- package/dist/lib/ollama-cloud-config.js +0 -27
- package/dist/lib/ollama-cloud-config.js.map +0 -1
- package/dist/lib/opencode-go-auth.d.ts +0 -16
- package/dist/lib/opencode-go-auth.d.ts.map +0 -1
- package/dist/lib/opencode-go-auth.js +0 -42
- package/dist/lib/opencode-go-auth.js.map +0 -1
- package/dist/lib/opencode-version.d.ts +0 -6
- package/dist/lib/opencode-version.d.ts.map +0 -1
- package/dist/lib/opencode-version.js +0 -26
- package/dist/lib/opencode-version.js.map +0 -1
- package/dist/lib/provider-add-command.d.ts +0 -35
- package/dist/lib/provider-add-command.d.ts.map +0 -1
- package/dist/lib/provider-add-command.js +0 -204
- package/dist/lib/provider-add-command.js.map +0 -1
- package/dist/lib/provider-add-json-v1-questionnaire.d.ts +0 -32
- package/dist/lib/provider-add-json-v1-questionnaire.d.ts.map +0 -1
- package/dist/lib/provider-add-json-v1-questionnaire.js +0 -336
- package/dist/lib/provider-add-json-v1-questionnaire.js.map +0 -1
- package/dist/lib/provider-add.d.ts +0 -21
- package/dist/lib/provider-add.d.ts.map +0 -1
- package/dist/lib/provider-add.js +0 -219
- package/dist/lib/provider-add.js.map +0 -1
- package/dist/lib/quota-accounting-projection.d.ts +0 -9
- package/dist/lib/quota-accounting-projection.d.ts.map +0 -1
- package/dist/lib/quota-accounting-projection.js +0 -254
- package/dist/lib/quota-accounting-projection.js.map +0 -1
- package/dist/lib/quota-columns.d.ts +0 -38
- package/dist/lib/quota-columns.d.ts.map +0 -1
- package/dist/lib/quota-columns.js +0 -129
- package/dist/lib/quota-columns.js.map +0 -1
- package/dist/lib/quota-command-format.d.ts +0 -34
- package/dist/lib/quota-command-format.d.ts.map +0 -1
- package/dist/lib/quota-command-format.js +0 -240
- package/dist/lib/quota-command-format.js.map +0 -1
- package/dist/lib/quota-dialog-command-specs.d.ts +0 -63
- package/dist/lib/quota-dialog-command-specs.d.ts.map +0 -1
- package/dist/lib/quota-dialog-command-specs.js +0 -145
- package/dist/lib/quota-dialog-command-specs.js.map +0 -1
- package/dist/lib/quota-entry-display.d.ts +0 -7
- package/dist/lib/quota-entry-display.d.ts.map +0 -1
- package/dist/lib/quota-entry-display.js +0 -59
- package/dist/lib/quota-entry-display.js.map +0 -1
- package/dist/lib/quota-exhaustion-projection.d.ts +0 -11
- package/dist/lib/quota-exhaustion-projection.d.ts.map +0 -1
- package/dist/lib/quota-exhaustion-projection.js +0 -105
- package/dist/lib/quota-exhaustion-projection.js.map +0 -1
- package/dist/lib/quota-format-style.d.ts +0 -21
- package/dist/lib/quota-format-style.d.ts.map +0 -1
- package/dist/lib/quota-format-style.js +0 -38
- package/dist/lib/quota-format-style.js.map +0 -1
- package/dist/lib/quota-render-data.d.ts +0 -102
- package/dist/lib/quota-render-data.d.ts.map +0 -1
- package/dist/lib/quota-render-data.js +0 -419
- package/dist/lib/quota-render-data.js.map +0 -1
- package/dist/lib/quota-reset-notifications.d.ts +0 -20
- package/dist/lib/quota-reset-notifications.d.ts.map +0 -1
- package/dist/lib/quota-reset-notifications.js +0 -331
- package/dist/lib/quota-reset-notifications.js.map +0 -1
- package/dist/lib/quota-runtime-context.d.ts +0 -54
- package/dist/lib/quota-runtime-context.d.ts.map +0 -1
- package/dist/lib/quota-runtime-context.js +0 -110
- package/dist/lib/quota-runtime-context.js.map +0 -1
- package/dist/lib/quota-state-codec.d.ts +0 -16
- package/dist/lib/quota-state-codec.d.ts.map +0 -1
- package/dist/lib/quota-state-codec.js +0 -412
- package/dist/lib/quota-state-codec.js.map +0 -1
- package/dist/lib/quota-state.d.ts +0 -28
- package/dist/lib/quota-state.d.ts.map +0 -1
- package/dist/lib/quota-state.js +0 -473
- package/dist/lib/quota-state.js.map +0 -1
- package/dist/lib/quota-stats-format.d.ts +0 -29
- package/dist/lib/quota-stats-format.d.ts.map +0 -1
- package/dist/lib/quota-stats-format.js +0 -459
- package/dist/lib/quota-stats-format.js.map +0 -1
- package/dist/lib/quota-stats.d.ts +0 -126
- package/dist/lib/quota-stats.d.ts.map +0 -1
- package/dist/lib/quota-stats.js +0 -695
- package/dist/lib/quota-stats.js.map +0 -1
- package/dist/lib/quota-surface-data.d.ts +0 -21
- package/dist/lib/quota-surface-data.d.ts.map +0 -1
- package/dist/lib/quota-surface-data.js +0 -362
- package/dist/lib/quota-surface-data.js.map +0 -1
- package/dist/lib/scoped-update-migration.d.ts +0 -103
- package/dist/lib/scoped-update-migration.d.ts.map +0 -1
- package/dist/lib/scoped-update-migration.js +0 -344
- package/dist/lib/scoped-update-migration.js.map +0 -1
- package/dist/lib/scoped-update.d.ts +0 -77
- package/dist/lib/scoped-update.d.ts.map +0 -1
- package/dist/lib/scoped-update.js +0 -590
- package/dist/lib/scoped-update.js.map +0 -1
- package/dist/lib/session-tokens-format.d.ts +0 -36
- package/dist/lib/session-tokens-format.d.ts.map +0 -1
- package/dist/lib/session-tokens-format.js +0 -111
- package/dist/lib/session-tokens-format.js.map +0 -1
- package/dist/lib/synthetic-config.d.ts +0 -15
- package/dist/lib/synthetic-config.d.ts.map +0 -1
- package/dist/lib/synthetic-config.js +0 -28
- package/dist/lib/synthetic-config.js.map +0 -1
- package/dist/lib/toast-format-grouped.d.ts +0 -25
- package/dist/lib/toast-format-grouped.d.ts.map +0 -1
- package/dist/lib/toast-format-grouped.js +0 -296
- package/dist/lib/toast-format-grouped.js.map +0 -1
- package/dist/lib/tui-compact-format.d.ts +0 -10
- package/dist/lib/tui-compact-format.d.ts.map +0 -1
- package/dist/lib/tui-compact-format.js +0 -460
- package/dist/lib/tui-compact-format.js.map +0 -1
- package/dist/lib/tui-panel-state.d.ts +0 -15
- package/dist/lib/tui-panel-state.d.ts.map +0 -1
- package/dist/lib/tui-panel-state.js +0 -2
- package/dist/lib/tui-panel-state.js.map +0 -1
- package/dist/lib/tui-prompt-bar-format.d.ts +0 -25
- package/dist/lib/tui-prompt-bar-format.d.ts.map +0 -1
- package/dist/lib/tui-prompt-bar-format.js +0 -206
- package/dist/lib/tui-prompt-bar-format.js.map +0 -1
- package/dist/lib/tui-sidebar-format.d.ts +0 -13
- package/dist/lib/tui-sidebar-format.d.ts.map +0 -1
- package/dist/lib/tui-sidebar-format.js +0 -34
- package/dist/lib/tui-sidebar-format.js.map +0 -1
- package/dist/lib/zai-auth.d.ts +0 -15
- package/dist/lib/zai-auth.d.ts.map +0 -1
- package/dist/lib/zai-auth.js +0 -37
- package/dist/lib/zai-auth.js.map +0 -1
- package/dist/lib/zai.d.ts +0 -5
- package/dist/lib/zai.d.ts.map +0 -1
- package/dist/lib/zai.js +0 -14
- package/dist/lib/zai.js.map +0 -1
- package/dist/lib/zhipu-auth.d.ts +0 -15
- package/dist/lib/zhipu-auth.d.ts.map +0 -1
- package/dist/lib/zhipu-auth.js +0 -42
- package/dist/lib/zhipu-auth.js.map +0 -1
- package/dist/lib/zhipu.d.ts +0 -5
- package/dist/lib/zhipu.d.ts.map +0 -1
- package/dist/lib/zhipu.js +0 -13
- package/dist/lib/zhipu.js.map +0 -1
- package/dist/providers/glm-coding-plan-provider.d.ts +0 -56
- package/dist/providers/glm-coding-plan-provider.d.ts.map +0 -1
- package/dist/providers/glm-coding-plan-provider.js +0 -115
- package/dist/providers/glm-coding-plan-provider.js.map +0 -1
- package/dist/providers/google-account-format.d.ts +0 -7
- package/dist/providers/google-account-format.d.ts.map +0 -1
- package/dist/providers/google-account-format.js +0 -52
- package/dist/providers/google-account-format.js.map +0 -1
- package/dist/providers/zai.d.ts +0 -2
- package/dist/providers/zai.d.ts.map +0 -1
- package/dist/providers/zai.js +0 -24
- package/dist/providers/zai.js.map +0 -1
- package/dist/providers/zhipu.d.ts +0 -2
- package/dist/providers/zhipu.d.ts.map +0 -1
- package/dist/providers/zhipu.js +0 -21
- package/dist/providers/zhipu.js.map +0 -1
- package/dist/tui-v2.d.ts +0 -5
- package/dist/tui-v2.d.ts.map +0 -1
- package/dist/tui-v2.jsx +0 -624
- package/dist/tui-v2.jsx.map +0 -1
- package/dist/tui.d.ts.map +0 -1
|
@@ -0,0 +1,1679 @@
|
|
|
1
|
+
import { use as _$use } from "@opentui/solid";
|
|
2
|
+
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
3
|
+
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
4
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
5
|
+
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
6
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
7
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
8
|
+
import { setProp as _$setProp } from "@opentui/solid";
|
|
9
|
+
import { createElement as _$createElement } from "@opentui/solid";
|
|
10
|
+
/** @jsxImportSource @opentui/solid */
|
|
11
|
+
/**
|
|
12
|
+
* The Settings tabs edit settings.jsonc; surfaces preview saved settings with draft changes.
|
|
13
|
+
* Layout's pages are a list left of the body (`Pages`), like Usage's ranges. When a page shows,
|
|
14
|
+
* the list has the keyboard: ↑↓ change the page, → or enter go to the page's first line, and ↑
|
|
15
|
+
* on that line goes back to the list.
|
|
16
|
+
*/
|
|
17
|
+
import { RGBA, TextAttributes } from "@opentui/core";
|
|
18
|
+
import { createEffect, createMemo, createSignal, For, on, Show } from "solid-js";
|
|
19
|
+
import { describeError } from "../../core/errors.js";
|
|
20
|
+
import { ALL_PROVIDERS, WINDOWS } from "../../core/windows.js";
|
|
21
|
+
import { CHANGED_SINCE_REVIEW } from "../../settings/schema.js";
|
|
22
|
+
import { columnsOf } from "../../view/columns.js";
|
|
23
|
+
import { DEFAULT_WORDS, fit, percentText, resetText, rowValueText } from "../../view/format.js";
|
|
24
|
+
import { pickRow, windowFor } from "../../view/select.js";
|
|
25
|
+
import { rpcErrorMessage } from "../client.js";
|
|
26
|
+
import { COLOR_NAMES, FIELDS, isSurfaceTab, PRESETS, presetChoice, presetValues, renameRow, resetTab, setIn, stepIn, typedColor, typedNumber } from "../display.js";
|
|
27
|
+
import { foundProviderIds, isTicked, PROVIDERS_KEY, withTick } from "../server-settings.js";
|
|
28
|
+
import { namedColor, roleColor } from "../theme.js";
|
|
29
|
+
import { plainMessage, quotaToastLines } from "../toasts.js";
|
|
30
|
+
import { draggedTo, movedBy, surfaceTree } from "./drag.js";
|
|
31
|
+
import { Rail, railRoom } from "./rail.js";
|
|
32
|
+
export const SETTINGS_TABS = [{
|
|
33
|
+
tab: "layout",
|
|
34
|
+
title: "All places",
|
|
35
|
+
watchesSidebar: true
|
|
36
|
+
}, {
|
|
37
|
+
tab: "sidebar",
|
|
38
|
+
title: "Sidebar",
|
|
39
|
+
switchTitle: "Show the Quota panel in the session sidebar",
|
|
40
|
+
watchesSidebar: true
|
|
41
|
+
}, {
|
|
42
|
+
tab: "collapsed",
|
|
43
|
+
title: "Collapsed",
|
|
44
|
+
switchTitle: "When the panel is collapsed, show one line per provider",
|
|
45
|
+
watchesSidebar: true
|
|
46
|
+
}, {
|
|
47
|
+
tab: "statusLine",
|
|
48
|
+
title: "Status line",
|
|
49
|
+
switchTitle: "Show the quota line under the message box",
|
|
50
|
+
watchesSidebar: false
|
|
51
|
+
}, {
|
|
52
|
+
tab: "toast",
|
|
53
|
+
title: "Toast",
|
|
54
|
+
switchTitle: "Show quota toasts",
|
|
55
|
+
watchesSidebar: false
|
|
56
|
+
}, {
|
|
57
|
+
tab: "colors",
|
|
58
|
+
title: "Colors",
|
|
59
|
+
watchesSidebar: true
|
|
60
|
+
}, {
|
|
61
|
+
tab: "providers",
|
|
62
|
+
title: "Providers",
|
|
63
|
+
watchesSidebar: true
|
|
64
|
+
}];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The Settings tabs of the window's tab bar, each with its pages: Layout has All places, then one
|
|
68
|
+
* per place; the others are one page each.
|
|
69
|
+
*/
|
|
70
|
+
export const SETTINGS_GROUPS = [{
|
|
71
|
+
title: "Layout",
|
|
72
|
+
pages: ["layout", "sidebar", "collapsed", "statusLine", "toast"]
|
|
73
|
+
}, {
|
|
74
|
+
title: "Colors",
|
|
75
|
+
pages: ["colors"]
|
|
76
|
+
}, {
|
|
77
|
+
title: "Providers",
|
|
78
|
+
pages: ["providers"]
|
|
79
|
+
}];
|
|
80
|
+
export function isSettingsTab(tab) {
|
|
81
|
+
return SETTINGS_TABS.some(item => item.tab === tab);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The pages of `tab`'s Settings tab when it has more than one, for the list left of the body. */
|
|
85
|
+
function pagesOf(tab) {
|
|
86
|
+
const pages = SETTINGS_GROUPS.find(group => group.pages.includes(tab))?.pages ?? [];
|
|
87
|
+
return pages.length > 1 ? pages : undefined;
|
|
88
|
+
}
|
|
89
|
+
function pageTitle(tab) {
|
|
90
|
+
return SETTINGS_TABS.find(item => item.tab === tab)?.title ?? tab;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** What the window keeps left of a Settings tab's body: Layout's page list, else nothing. */
|
|
94
|
+
export function pagesRoom(tab) {
|
|
95
|
+
const pages = isSettingsTab(tab) ? pagesOf(tab) : undefined;
|
|
96
|
+
return pages ? railRoom(PAGE_LIST_GAP) : 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** "Reset page" on Layout's pages, which reset only their own lines; "Reset tab" elsewhere. */
|
|
100
|
+
function resetLabel(tab) {
|
|
101
|
+
return pagesOf(tab) ? "Reset page" : "Reset tab";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** A line ↑↓ select: ‹ value › steps through values, value ▸ runs a button; some take typing. */
|
|
105
|
+
|
|
106
|
+
/** What a line takes when you type into it (e, or a double-click). */
|
|
107
|
+
|
|
108
|
+
/** A line of a surface tab's tree. One object per line, so <For> keeps its view while it moves. */
|
|
109
|
+
|
|
110
|
+
const KEYS = "Quota window";
|
|
111
|
+
const TRANSPARENT = RGBA.fromInts(0, 0, 0, 0);
|
|
112
|
+
/** The id of a surface tab's switch line. */
|
|
113
|
+
const SWITCH_ID = "surface";
|
|
114
|
+
/** The selection id of Layout's page list: the list has the keyboard. */
|
|
115
|
+
const PAGES_ID = "pages";
|
|
116
|
+
/** The body starts right after the page list's line: its lines carry their own indent. */
|
|
117
|
+
const PAGE_LIST_GAP = 0;
|
|
118
|
+
const DOUBLE_CLICK_MS = 400;
|
|
119
|
+
/** A line's columns besides its title and value: the 3 spaces, the title's space, "‹ " and " ›". */
|
|
120
|
+
const LINE_FRAME = 8;
|
|
121
|
+
const TITLE_WIDTH = 26;
|
|
122
|
+
const TITLE_MIN = 12;
|
|
123
|
+
const VALUE_WIDTH = 24;
|
|
124
|
+
const VALUE_MIN = 6;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* A line's title and value widths in `width` columns: 26 and the value's own width when both
|
|
128
|
+
* fit; else the title gives way first (down to 12 columns), then the value (down to 6).
|
|
129
|
+
*/
|
|
130
|
+
export function lineColumns(width, valueWidth = VALUE_WIDTH) {
|
|
131
|
+
if (width === undefined) return {
|
|
132
|
+
title: TITLE_WIDTH,
|
|
133
|
+
value: valueWidth
|
|
134
|
+
};
|
|
135
|
+
const room = width - LINE_FRAME;
|
|
136
|
+
const title = Math.max(TITLE_MIN, Math.min(TITLE_WIDTH, room - valueWidth));
|
|
137
|
+
const value = Math.max(Math.min(VALUE_MIN, valueWidth), Math.min(valueWidth, room - title));
|
|
138
|
+
return {
|
|
139
|
+
title,
|
|
140
|
+
value
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Selection id of a tree line; a row id could equal a setting's path. */
|
|
145
|
+
function lineKey(id) {
|
|
146
|
+
return `line:${id}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Renderable id of a line, so the list can scroll it into view. */
|
|
150
|
+
function boxId(id) {
|
|
151
|
+
return `quota-settings.${id}`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Renderable id of a page in Layout's page list. */
|
|
155
|
+
function pageId(tab) {
|
|
156
|
+
return `quota-layout-page-${tab}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The windows ‹ › steps through: those of the provider's rows not hidden on the page. */
|
|
160
|
+
function windowChoices(provider, hidden) {
|
|
161
|
+
const windows = provider.rows.flatMap(row => row.window && row.percentRemaining !== undefined && !hidden.includes(row.id) ? [row.window] : []);
|
|
162
|
+
const unique = [...new Set(windows)];
|
|
163
|
+
return unique.length > 1 ? ["lowest", ...unique] : [];
|
|
164
|
+
}
|
|
165
|
+
function windowTitle(choice) {
|
|
166
|
+
return choice === "lowest" ? "lowest left" : WINDOWS[choice].short;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* What a provider's ‹ › shows without a pick of its own: the pick for all providers when the
|
|
171
|
+
* provider has that window (one of its `choices`), else lowest.
|
|
172
|
+
*/
|
|
173
|
+
function inheritedWindow(windows, choices) {
|
|
174
|
+
const all = windows[ALL_PROVIDERS];
|
|
175
|
+
return all !== undefined && choices.includes(all) ? all : "lowest";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* One-line text that keeps its width, unless `shrink` lets it give way. With `wrap` (notes,
|
|
180
|
+
* details) it goes on to more lines between words instead of being cut.
|
|
181
|
+
*/
|
|
182
|
+
export function Cell(props) {
|
|
183
|
+
return (() => {
|
|
184
|
+
var _el$ = _$createElement("text");
|
|
185
|
+
_$setProp(_el$, "selectable", false);
|
|
186
|
+
_$insert(_el$, () => props.children);
|
|
187
|
+
_$effect(_p$ => {
|
|
188
|
+
var _v$ = props.fg,
|
|
189
|
+
_v$2 = props.bold ? TextAttributes.BOLD : TextAttributes.NONE,
|
|
190
|
+
_v$3 = props.wrap ? "word" : "none",
|
|
191
|
+
_v$4 = props.shrink ? 1 : 0,
|
|
192
|
+
_v$5 = props.onUp;
|
|
193
|
+
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "fg", _v$, _p$.e));
|
|
194
|
+
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "attributes", _v$2, _p$.t));
|
|
195
|
+
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "wrapMode", _v$3, _p$.a));
|
|
196
|
+
_v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "flexShrink", _v$4, _p$.o));
|
|
197
|
+
_v$5 !== _p$.i && (_p$.i = _$setProp(_el$, "onMouseUp", _v$5, _p$.i));
|
|
198
|
+
return _p$;
|
|
199
|
+
}, {
|
|
200
|
+
e: undefined,
|
|
201
|
+
t: undefined,
|
|
202
|
+
a: undefined,
|
|
203
|
+
o: undefined,
|
|
204
|
+
i: undefined
|
|
205
|
+
});
|
|
206
|
+
return _el$;
|
|
207
|
+
})();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** A window tab's option line: title, ‹ value ›, value ▸ or a tick, color swatches, then a note. */
|
|
211
|
+
export function OptionRow(props) {
|
|
212
|
+
const line = props.line;
|
|
213
|
+
const fg = () => props.active ? props.theme.text.action.primary.focused : props.theme.text.base;
|
|
214
|
+
const arrow = () => props.active ? fg() : props.theme.text.action.primary.selected;
|
|
215
|
+
const note = () => line.note?.() ?? "";
|
|
216
|
+
const columns = () => lineColumns(props.width, props.valueWidth);
|
|
217
|
+
/** Where the value starts: past the 3 spaces, the title, its space and the "‹ ". */
|
|
218
|
+
const valueColumn = () => 3 + columns().title + 1 + 2;
|
|
219
|
+
const noteInline = () => {
|
|
220
|
+
if (props.width === undefined) return true;
|
|
221
|
+
const swatches = 3 * (line.swatches?.() ?? []).length;
|
|
222
|
+
const end = valueColumn() + columns().value + 2 + swatches;
|
|
223
|
+
return end + 3 + columnsOf(note()) <= props.width;
|
|
224
|
+
};
|
|
225
|
+
const indent = " ".repeat(line.depth ?? 0);
|
|
226
|
+
// A tick without a word has the value's room too, so a long name shows whole.
|
|
227
|
+
const titleWidth = () => line.tick && !line.value() ? columns().title + 2 + columns().value : columns().title;
|
|
228
|
+
/** On the selected line's highlight, the highlight's text color; under it, its own color. */
|
|
229
|
+
const noteColor = onHighlight => props.active && onHighlight ? fg() : line.warning ? props.theme.text.feedback.warning.base : props.theme.text.muted;
|
|
230
|
+
return [_$createComponent(Show, {
|
|
231
|
+
get when() {
|
|
232
|
+
return line.group;
|
|
233
|
+
},
|
|
234
|
+
get children() {
|
|
235
|
+
var _el$2 = _$createElement("box");
|
|
236
|
+
_$insert(_el$2, _$createComponent(Cell, {
|
|
237
|
+
get fg() {
|
|
238
|
+
return props.theme.text.action.primary.selected;
|
|
239
|
+
},
|
|
240
|
+
bold: true,
|
|
241
|
+
get children() {
|
|
242
|
+
return ` ${line.group}`;
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
245
|
+
_$effect(_$p => _$setProp(_el$2, "paddingTop", props.first ? 0 : 1, _$p));
|
|
246
|
+
return _el$2;
|
|
247
|
+
}
|
|
248
|
+
}), _$createComponent(Show, {
|
|
249
|
+
get when() {
|
|
250
|
+
return line.gap;
|
|
251
|
+
},
|
|
252
|
+
get children() {
|
|
253
|
+
var _el$3 = _$createElement("box");
|
|
254
|
+
_$setProp(_el$3, "height", 1);
|
|
255
|
+
return _el$3;
|
|
256
|
+
}
|
|
257
|
+
}), (() => {
|
|
258
|
+
var _el$4 = _$createElement("box");
|
|
259
|
+
_$setProp(_el$4, "flexDirection", "row");
|
|
260
|
+
_$insert(_el$4, _$createComponent(Cell, {
|
|
261
|
+
get fg() {
|
|
262
|
+
return fg();
|
|
263
|
+
},
|
|
264
|
+
get onUp() {
|
|
265
|
+
return _$memo(() => !!line.tick)() ? props.click(props.use) : undefined;
|
|
266
|
+
},
|
|
267
|
+
get children() {
|
|
268
|
+
return ` ${indent}${fit(line.title, titleWidth() - indent.length)} `;
|
|
269
|
+
}
|
|
270
|
+
}), null);
|
|
271
|
+
_$insert(_el$4, _$createComponent(Cell, {
|
|
272
|
+
get fg() {
|
|
273
|
+
return arrow();
|
|
274
|
+
},
|
|
275
|
+
get onUp() {
|
|
276
|
+
return props.click(() => line.cycle?.(-1));
|
|
277
|
+
},
|
|
278
|
+
get children() {
|
|
279
|
+
return line.cycle && !line.tick ? "‹ " : " ";
|
|
280
|
+
}
|
|
281
|
+
}), null);
|
|
282
|
+
_$insert(_el$4, _$createComponent(Show, {
|
|
283
|
+
get when() {
|
|
284
|
+
return props.input;
|
|
285
|
+
},
|
|
286
|
+
get fallback() {
|
|
287
|
+
return _$createComponent(Cell, {
|
|
288
|
+
get fg() {
|
|
289
|
+
return _$memo(() => !!line.tick)() ? noteColor(true) : fg();
|
|
290
|
+
},
|
|
291
|
+
get onUp() {
|
|
292
|
+
return props.click(props.use);
|
|
293
|
+
},
|
|
294
|
+
get children() {
|
|
295
|
+
return fit(line.value(), columns().value);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
get children() {
|
|
300
|
+
return props.input?.(columns().value);
|
|
301
|
+
}
|
|
302
|
+
}), null);
|
|
303
|
+
_$insert(_el$4, _$createComponent(Cell, {
|
|
304
|
+
get fg() {
|
|
305
|
+
return arrow();
|
|
306
|
+
},
|
|
307
|
+
get onUp() {
|
|
308
|
+
return props.click(props.use);
|
|
309
|
+
},
|
|
310
|
+
get children() {
|
|
311
|
+
return _$memo(() => !!line.run)() ? " ▸" : line.cycle && !line.tick ? " ›" : " ";
|
|
312
|
+
}
|
|
313
|
+
}), null);
|
|
314
|
+
_$insert(_el$4, _$createComponent(Show, {
|
|
315
|
+
get when() {
|
|
316
|
+
return line.swatches;
|
|
317
|
+
},
|
|
318
|
+
get children() {
|
|
319
|
+
return _$createComponent(Cell, {
|
|
320
|
+
get children() {
|
|
321
|
+
return (line.swatches?.() ?? []).map(color => (() => {
|
|
322
|
+
var _el$8 = _$createElement("span");
|
|
323
|
+
_$insertNode(_el$8, _$createTextNode(` ██`));
|
|
324
|
+
_$setProp(_el$8, "style", {
|
|
325
|
+
fg: color
|
|
326
|
+
});
|
|
327
|
+
return _el$8;
|
|
328
|
+
})());
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}), null);
|
|
333
|
+
_$insert(_el$4, _$createComponent(Show, {
|
|
334
|
+
get when() {
|
|
335
|
+
return _$memo(() => !!note())() && noteInline();
|
|
336
|
+
},
|
|
337
|
+
get children() {
|
|
338
|
+
var _el$5 = _$createElement("box");
|
|
339
|
+
_$setProp(_el$5, "paddingLeft", 3);
|
|
340
|
+
_$setProp(_el$5, "flexShrink", 1);
|
|
341
|
+
_$insert(_el$5, _$createComponent(Cell, {
|
|
342
|
+
get fg() {
|
|
343
|
+
return noteColor(true);
|
|
344
|
+
},
|
|
345
|
+
shrink: true,
|
|
346
|
+
wrap: true,
|
|
347
|
+
get children() {
|
|
348
|
+
return note();
|
|
349
|
+
}
|
|
350
|
+
}));
|
|
351
|
+
return _el$5;
|
|
352
|
+
}
|
|
353
|
+
}), null);
|
|
354
|
+
_$effect(_p$ => {
|
|
355
|
+
var _v$6 = boxId(line.id),
|
|
356
|
+
_v$7 = props.active ? props.theme.background.action.primary.focused : TRANSPARENT,
|
|
357
|
+
_v$8 = props.press;
|
|
358
|
+
_v$6 !== _p$.e && (_p$.e = _$setProp(_el$4, "id", _v$6, _p$.e));
|
|
359
|
+
_v$7 !== _p$.t && (_p$.t = _$setProp(_el$4, "backgroundColor", _v$7, _p$.t));
|
|
360
|
+
_v$8 !== _p$.a && (_p$.a = _$setProp(_el$4, "onMouseDown", _v$8, _p$.a));
|
|
361
|
+
return _p$;
|
|
362
|
+
}, {
|
|
363
|
+
e: undefined,
|
|
364
|
+
t: undefined,
|
|
365
|
+
a: undefined
|
|
366
|
+
});
|
|
367
|
+
return _el$4;
|
|
368
|
+
})(), _$createComponent(Show, {
|
|
369
|
+
get when() {
|
|
370
|
+
return _$memo(() => !!note())() && !noteInline();
|
|
371
|
+
},
|
|
372
|
+
get children() {
|
|
373
|
+
var _el$6 = _$createElement("box");
|
|
374
|
+
_$insert(_el$6, _$createComponent(Cell, {
|
|
375
|
+
get fg() {
|
|
376
|
+
return noteColor(false);
|
|
377
|
+
},
|
|
378
|
+
shrink: true,
|
|
379
|
+
wrap: true,
|
|
380
|
+
get children() {
|
|
381
|
+
return note();
|
|
382
|
+
}
|
|
383
|
+
}));
|
|
384
|
+
_$effect(_p$ => {
|
|
385
|
+
var _v$9 = valueColumn(),
|
|
386
|
+
_v$0 = props.width;
|
|
387
|
+
_v$9 !== _p$.e && (_p$.e = _$setProp(_el$6, "paddingLeft", _v$9, _p$.e));
|
|
388
|
+
_v$0 !== _p$.t && (_p$.t = _$setProp(_el$6, "width", _v$0, _p$.t));
|
|
389
|
+
return _p$;
|
|
390
|
+
}, {
|
|
391
|
+
e: undefined,
|
|
392
|
+
t: undefined
|
|
393
|
+
});
|
|
394
|
+
return _el$6;
|
|
395
|
+
}
|
|
396
|
+
}), _$createComponent(Show, {
|
|
397
|
+
get when() {
|
|
398
|
+
return line.detail;
|
|
399
|
+
},
|
|
400
|
+
get children() {
|
|
401
|
+
var _el$7 = _$createElement("box");
|
|
402
|
+
_$insert(_el$7, _$createComponent(Cell, {
|
|
403
|
+
get fg() {
|
|
404
|
+
return props.theme.text.muted;
|
|
405
|
+
},
|
|
406
|
+
shrink: true,
|
|
407
|
+
wrap: true,
|
|
408
|
+
get children() {
|
|
409
|
+
return line.detail;
|
|
410
|
+
}
|
|
411
|
+
}));
|
|
412
|
+
_$effect(_p$ => {
|
|
413
|
+
var _v$1 = valueColumn(),
|
|
414
|
+
_v$10 = props.width;
|
|
415
|
+
_v$1 !== _p$.e && (_p$.e = _$setProp(_el$7, "paddingLeft", _v$1, _p$.e));
|
|
416
|
+
_v$10 !== _p$.t && (_p$.t = _$setProp(_el$7, "width", _v$10, _p$.t));
|
|
417
|
+
return _p$;
|
|
418
|
+
}, {
|
|
419
|
+
e: undefined,
|
|
420
|
+
t: undefined
|
|
421
|
+
});
|
|
422
|
+
return _el$7;
|
|
423
|
+
}
|
|
424
|
+
})];
|
|
425
|
+
}
|
|
426
|
+
export function createSettingsEditor(api, display, showToast) {
|
|
427
|
+
const [tab, setTabNow] = createSignal();
|
|
428
|
+
const [selected, setSelected] = createSignal("");
|
|
429
|
+
const [typing, setTyping] = createSignal();
|
|
430
|
+
const [confirming, setConfirming] = createSignal(false);
|
|
431
|
+
const [sidebars, setSidebars] = createSignal(0);
|
|
432
|
+
const [dragging, setDragging] = createSignal();
|
|
433
|
+
let draggedSincePress = false;
|
|
434
|
+
let lastPress = {
|
|
435
|
+
id: "",
|
|
436
|
+
atMs: 0
|
|
437
|
+
};
|
|
438
|
+
/** The inline input while a line takes typing; its keys work only while it has the keyboard. */
|
|
439
|
+
let typingInput;
|
|
440
|
+
const treeLines = new Map();
|
|
441
|
+
const theme = () => api.theme;
|
|
442
|
+
const shown = () => display.shown();
|
|
443
|
+
const server = display.server;
|
|
444
|
+
const dirty = server.dirty;
|
|
445
|
+
const discard = server.discard;
|
|
446
|
+
const lineValue = path => server.value(path);
|
|
447
|
+
function setValues(values) {
|
|
448
|
+
for (const [path, value] of Object.entries(values)) server.set(path, value);
|
|
449
|
+
}
|
|
450
|
+
function resetTabLines(settingsTab) {
|
|
451
|
+
display.edit(settings => resetTab(settings, settingsTab));
|
|
452
|
+
if (settingsTab === "providers") server.set(PROVIDERS_KEY, []);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** `run` as a click handler that skips the click OpenCode sends right after a drag. */
|
|
456
|
+
const click = run => () => {
|
|
457
|
+
if (!draggedSincePress) run();
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
/** Two presses on the same line within 400 ms. */
|
|
461
|
+
function isDoubleClick(id) {
|
|
462
|
+
const now = Date.now();
|
|
463
|
+
const double = lastPress.id === id && now - lastPress.atMs < DOUBLE_CLICK_MS;
|
|
464
|
+
lastPress = double ? {
|
|
465
|
+
id: "",
|
|
466
|
+
atMs: 0
|
|
467
|
+
} : {
|
|
468
|
+
id,
|
|
469
|
+
atMs: now
|
|
470
|
+
};
|
|
471
|
+
return double;
|
|
472
|
+
}
|
|
473
|
+
function editSurface(surface, change) {
|
|
474
|
+
const rows = change(shown().surfaces[surface]);
|
|
475
|
+
server.set(`${surface}.show`, rows.enabled);
|
|
476
|
+
server.set(`${surface}.hidden`, rows.hidden);
|
|
477
|
+
server.set(`${surface}.providerOrder`, rows.providerOrder);
|
|
478
|
+
server.set(`${surface}.rowOrder`, rows.rowOrder);
|
|
479
|
+
}
|
|
480
|
+
function toggleSurface(surface) {
|
|
481
|
+
editSurface(surface, rows => ({
|
|
482
|
+
...rows,
|
|
483
|
+
enabled: !rows.enabled
|
|
484
|
+
}));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** What typing into a line does: a color for a color line, a number for a server number. */
|
|
488
|
+
function typedValue(field, role) {
|
|
489
|
+
if (role) {
|
|
490
|
+
return {
|
|
491
|
+
placeholder: "#rrggbb",
|
|
492
|
+
hint: "Type a color like #89b4fa, then enter · enter with nothing typed = the theme's color · esc stop",
|
|
493
|
+
apply: text => display.edit(settings => typedColor(settings, field, text))
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const placeholder = field.placeholder;
|
|
497
|
+
if (!placeholder) return undefined;
|
|
498
|
+
return {
|
|
499
|
+
placeholder,
|
|
500
|
+
hint: `Type ${placeholder}, then enter · enter with nothing typed = ${field.show(null)} · esc stop`,
|
|
501
|
+
apply: text => {
|
|
502
|
+
const value = typedNumber(field, text);
|
|
503
|
+
if (value !== undefined) server.set(field.path, value);
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/** A field's line: ‹ › step through its values, or you type one. */
|
|
509
|
+
function fieldLine(field) {
|
|
510
|
+
const role = field.color ? field.path.slice("colors.".length) : undefined;
|
|
511
|
+
const value = () => lineValue(field.path);
|
|
512
|
+
return {
|
|
513
|
+
id: field.path,
|
|
514
|
+
group: field.group,
|
|
515
|
+
title: field.title,
|
|
516
|
+
depth: field.provider ? 1 : 0,
|
|
517
|
+
value: () => field.show(value()),
|
|
518
|
+
cycle: field.values.length > 0 ? delta => {
|
|
519
|
+
const values = field.choices?.(shown()) ?? field.values;
|
|
520
|
+
setValues({
|
|
521
|
+
[field.path]: stepIn(values, value(), delta)
|
|
522
|
+
});
|
|
523
|
+
} : undefined,
|
|
524
|
+
typed: typedValue(field, role),
|
|
525
|
+
note: () => field.preset && presetChoice(field.preset, lineValue) !== undefined ? "from the preset" : field.note ?? "",
|
|
526
|
+
swatches: role ? () => [roleColor(theme(), shown(), role, 60)] : undefined
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function presetLine(name) {
|
|
530
|
+
const choice = () => presetChoice(name, lineValue);
|
|
531
|
+
return {
|
|
532
|
+
id: `preset.${name}`,
|
|
533
|
+
title: PRESETS[name].title,
|
|
534
|
+
value: () => choice() ?? "your own",
|
|
535
|
+
cycle: delta => setValues(presetValues(name, choice(), delta)),
|
|
536
|
+
note: () => `sets ${PRESETS[name].drives}`
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* OpenCode's own theme list and light/dark switch; quota's colors follow them. `refocus` gives
|
|
542
|
+
* the window the keyboard again.
|
|
543
|
+
*/
|
|
544
|
+
function themeLines(refocus) {
|
|
545
|
+
return [{
|
|
546
|
+
id: "theme",
|
|
547
|
+
group: "OpenCode theme",
|
|
548
|
+
title: "Theme",
|
|
549
|
+
value: () => "open the theme list",
|
|
550
|
+
run: () => api.keymap.dispatch("theme.switch"),
|
|
551
|
+
swatches: () => COLOR_NAMES.map(name => namedColor(theme(), name)),
|
|
552
|
+
note: () => "↑↓ shows each theme live · enter keeps it · esc puts it back"
|
|
553
|
+
}, {
|
|
554
|
+
id: "themeMode",
|
|
555
|
+
title: "Light or dark",
|
|
556
|
+
value: () => api.themeMode ?? "dark",
|
|
557
|
+
cycle: () => {
|
|
558
|
+
api.keymap.dispatch("theme.switch_mode");
|
|
559
|
+
// OpenCode's switch also closes its dialogs, which gives the keyboard to whatever had
|
|
560
|
+
// it before the last dialog opened (the message box); take it back after that.
|
|
561
|
+
setTimeout(refocus, 50);
|
|
562
|
+
},
|
|
563
|
+
note: () => "some themes have only one"
|
|
564
|
+
}];
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* A custom provider's switch, its web address and the key it would send; marked when the server
|
|
569
|
+
* would not switch it on because it changed since the window showed it.
|
|
570
|
+
*/
|
|
571
|
+
function customLine(entry, first) {
|
|
572
|
+
const on = () => server.customOn(entry.id);
|
|
573
|
+
const request = entry.request;
|
|
574
|
+
const changed = server.changedSinceReview(entry.id);
|
|
575
|
+
const where = !request ? "a local estimate: sends nothing" : request.insecure ? `${request.url} plain http: the key travels unencrypted` : request.url;
|
|
576
|
+
return {
|
|
577
|
+
id: `custom.${entry.id}`,
|
|
578
|
+
group: first ? "Custom providers (added in settings.jsonc)" : undefined,
|
|
579
|
+
gap: !first,
|
|
580
|
+
title: entry.label,
|
|
581
|
+
value: () => on() ? "on" : "off",
|
|
582
|
+
cycle: () => server.switchCustom(entry.id, !on()),
|
|
583
|
+
note: () => changed ? `${CHANGED_SINCE_REVIEW} · ${where}` : where,
|
|
584
|
+
warning: changed || request?.insecure,
|
|
585
|
+
detail: request ? `key: ${request.key}` : undefined
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* The custom providers' switches (on top: an agent sends the user here to switch one on), which
|
|
591
|
+
* providers quota checks (ticks, with Cursor's and OpenCode Zen's settings nested; the ones
|
|
592
|
+
* quota found first), then the other groups.
|
|
593
|
+
*/
|
|
594
|
+
function providerLines(snapshot) {
|
|
595
|
+
const loaded = server.saved();
|
|
596
|
+
if (!loaded) return [];
|
|
597
|
+
const found = foundProviderIds(snapshot);
|
|
598
|
+
const off = () => server.value(PROVIDERS_KEY);
|
|
599
|
+
const savedOff = loaded.values[PROVIDERS_KEY];
|
|
600
|
+
const ordered = [...loaded.providers.filter(({
|
|
601
|
+
id
|
|
602
|
+
}) => found.includes(id)), ...loaded.providers.filter(({
|
|
603
|
+
id
|
|
604
|
+
}) => !found.includes(id))];
|
|
605
|
+
const ticks = ordered.flatMap(({
|
|
606
|
+
id,
|
|
607
|
+
label
|
|
608
|
+
}) => {
|
|
609
|
+
const ticked = isTicked(off(), id);
|
|
610
|
+
const tick = {
|
|
611
|
+
id: `provider.${id}`,
|
|
612
|
+
group: id === ordered[0]?.id ? "Which providers" : undefined,
|
|
613
|
+
title: `${ticked ? "[x]" : "[ ]"} ${label}`,
|
|
614
|
+
tick: true,
|
|
615
|
+
warning: true,
|
|
616
|
+
// The tick says on or off; only a saved tick quota can't use says more (a tick not
|
|
617
|
+
// saved yet is not checked yet).
|
|
618
|
+
value: () => ticked && isTicked(savedOff, id) && snapshot && !found.includes(id) ? "not set up" : "",
|
|
619
|
+
cycle: () => server.set(PROVIDERS_KEY, withTick(off(), id, !ticked))
|
|
620
|
+
};
|
|
621
|
+
const nested = ticked ? FIELDS.filter(field => field.provider === id) : [];
|
|
622
|
+
return [tick, ...nested.map(fieldLine)];
|
|
623
|
+
});
|
|
624
|
+
return [...loaded.custom.map((entry, index) => customLine(entry, index === 0)), ...ticks, ...FIELDS.filter(field => field.tab === "providers" && !field.provider).map(fieldLine)];
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Collapsed's and Status line's window for every provider without its own pick in the list
|
|
629
|
+
* below. ‹ › step through lowest and the windows the providers have.
|
|
630
|
+
*/
|
|
631
|
+
function allProvidersLine(surface, snapshot) {
|
|
632
|
+
const current = () => shown()[surface].window[ALL_PROVIDERS] ?? "lowest";
|
|
633
|
+
const choices = () => {
|
|
634
|
+
const found = new Set((snapshot?.providers ?? []).flatMap(provider => provider.rows.flatMap(row => row.window && row.percentRemaining !== undefined ? [row.window] : [])));
|
|
635
|
+
const windows = Object.keys(WINDOWS).filter(window => found.has(window) || window === current());
|
|
636
|
+
return ["lowest", ...windows];
|
|
637
|
+
};
|
|
638
|
+
return {
|
|
639
|
+
id: `${surface}.window.${ALL_PROVIDERS}`,
|
|
640
|
+
group: "Window",
|
|
641
|
+
title: "For all providers",
|
|
642
|
+
value: () => windowTitle(current()),
|
|
643
|
+
cycle: delta => {
|
|
644
|
+
const next = stepIn(choices(), current(), delta);
|
|
645
|
+
display.edit(settings => setIn(settings, [surface, "window", ALL_PROVIDERS], next === "lowest" ? undefined : next));
|
|
646
|
+
},
|
|
647
|
+
note: () => "a pick below wins; a provider without it shows its lowest"
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* A Settings page's lines. A preset sits above the line it names, under that line's heading,
|
|
653
|
+
* or else first, under "Preset". `refocus` gives the window the keyboard again.
|
|
654
|
+
*/
|
|
655
|
+
function optionLines(settingsTab, snapshot, refocus = () => {}) {
|
|
656
|
+
if (settingsTab === "providers") return providerLines(snapshot);
|
|
657
|
+
if (!server.saved()) return [];
|
|
658
|
+
const presets = Object.keys(PRESETS).filter(name => PRESETS[name].tab === settingsTab);
|
|
659
|
+
const fields = FIELDS.filter(field => field.tab === settingsTab).flatMap(field => {
|
|
660
|
+
const line = fieldLine(field);
|
|
661
|
+
const preset = presets.find(name => PRESETS[name].before === field.path);
|
|
662
|
+
return preset ? [{
|
|
663
|
+
...presetLine(preset),
|
|
664
|
+
group: line.group
|
|
665
|
+
}, {
|
|
666
|
+
...line,
|
|
667
|
+
group: undefined
|
|
668
|
+
}] : [line];
|
|
669
|
+
});
|
|
670
|
+
return [...presets.filter(name => PRESETS[name].before === undefined).map(name => ({
|
|
671
|
+
...presetLine(name),
|
|
672
|
+
group: "Preset"
|
|
673
|
+
})), ...(settingsTab === "colors" ? themeLines(refocus) : []), ...fields, ...(settingsTab === "collapsed" || settingsTab === "statusLine" ? [allProvidersLine(settingsTab, snapshot)] : [])];
|
|
674
|
+
}
|
|
675
|
+
function firstLine(settingsTab) {
|
|
676
|
+
if (settingsTab === undefined) return "";
|
|
677
|
+
if (pagesOf(settingsTab)) return PAGES_ID;
|
|
678
|
+
return isSurfaceTab(settingsTab) ? SWITCH_ID : optionLines(settingsTab)[0]?.id ?? "";
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/** Reads the file settings each time a Settings tab shows. */
|
|
682
|
+
async function loadServer(settingsTab) {
|
|
683
|
+
try {
|
|
684
|
+
await server.load();
|
|
685
|
+
} catch (error) {
|
|
686
|
+
api.ui.toast.show({
|
|
687
|
+
variant: "error",
|
|
688
|
+
title: "Quota settings not loaded",
|
|
689
|
+
message: rpcErrorMessage(error)
|
|
690
|
+
});
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (tab() === settingsTab && selected() === "") setSelected(firstLine(settingsTab));
|
|
694
|
+
}
|
|
695
|
+
function Button(props) {
|
|
696
|
+
const {
|
|
697
|
+
text,
|
|
698
|
+
background
|
|
699
|
+
} = theme();
|
|
700
|
+
return (() => {
|
|
701
|
+
var _el$0 = _$createElement("box");
|
|
702
|
+
_$setProp(_el$0, "paddingLeft", 2);
|
|
703
|
+
_$setProp(_el$0, "paddingRight", 2);
|
|
704
|
+
_$setProp(_el$0, "flexShrink", 0);
|
|
705
|
+
_$setProp(_el$0, "alignSelf", "flex-start");
|
|
706
|
+
_$insert(_el$0, _$createComponent(Cell, {
|
|
707
|
+
get fg() {
|
|
708
|
+
return _$memo(() => !!props.primary)() ? text.action.primary.focused : text.base;
|
|
709
|
+
},
|
|
710
|
+
get children() {
|
|
711
|
+
return props.label;
|
|
712
|
+
}
|
|
713
|
+
}));
|
|
714
|
+
_$effect(_p$ => {
|
|
715
|
+
var _v$11 = props.primary ? background.action.primary.focused : background.raised.high,
|
|
716
|
+
_v$12 = click(props.run);
|
|
717
|
+
_v$11 !== _p$.e && (_p$.e = _$setProp(_el$0, "backgroundColor", _v$11, _p$.e));
|
|
718
|
+
_v$12 !== _p$.t && (_p$.t = _$setProp(_el$0, "onMouseUp", _v$12, _p$.t));
|
|
719
|
+
return _p$;
|
|
720
|
+
}, {
|
|
721
|
+
e: undefined,
|
|
722
|
+
t: undefined
|
|
723
|
+
});
|
|
724
|
+
return _el$0;
|
|
725
|
+
})();
|
|
726
|
+
}
|
|
727
|
+
function previewToast(host, sessionID) {
|
|
728
|
+
const settings = shown();
|
|
729
|
+
const snapshot = host.quota.snapshot(sessionID);
|
|
730
|
+
if (!snapshot || !settings.surfaces.toast.enabled) return;
|
|
731
|
+
const lines = quotaToastLines(snapshot, settings, Date.now(), api.renderer.width);
|
|
732
|
+
const message = plainMessage(lines);
|
|
733
|
+
if (!message) return;
|
|
734
|
+
const duration = settings.toast.seconds * 1000;
|
|
735
|
+
showToast({
|
|
736
|
+
variant: "info",
|
|
737
|
+
message,
|
|
738
|
+
duration
|
|
739
|
+
}, lines);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Layout's pages, left of the body (`rail.tsx`). A click shows a page and gives the list the
|
|
744
|
+
* keyboard.
|
|
745
|
+
*/
|
|
746
|
+
function Pages(props) {
|
|
747
|
+
return _$createComponent(Show, {
|
|
748
|
+
get when() {
|
|
749
|
+
return pagesOf(props.tab);
|
|
750
|
+
},
|
|
751
|
+
children: pages => _$createComponent(Rail, {
|
|
752
|
+
get items() {
|
|
753
|
+
return pages().map(page => ({
|
|
754
|
+
key: page,
|
|
755
|
+
label: pageTitle(page),
|
|
756
|
+
id: pageId(page)
|
|
757
|
+
}));
|
|
758
|
+
},
|
|
759
|
+
get chosen() {
|
|
760
|
+
return props.tab;
|
|
761
|
+
},
|
|
762
|
+
get theme() {
|
|
763
|
+
return theme();
|
|
764
|
+
},
|
|
765
|
+
gap: PAGE_LIST_GAP,
|
|
766
|
+
pick: page => click(() => {
|
|
767
|
+
props.showPage(page);
|
|
768
|
+
setSelected(PAGES_ID);
|
|
769
|
+
})()
|
|
770
|
+
})
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Above a Settings tab's scrolling body: the surface switch under its "Enable/disable" heading,
|
|
776
|
+
* and a warning when the sidebar is hidden.
|
|
777
|
+
*/
|
|
778
|
+
function Header(props) {
|
|
779
|
+
const info = () => SETTINGS_TABS.find(item => item.tab === props.tab) ?? SETTINGS_TABS[0];
|
|
780
|
+
const surface = () => isSurfaceTab(props.tab) ? props.tab : undefined;
|
|
781
|
+
const surfaceOn = () => {
|
|
782
|
+
const current = surface();
|
|
783
|
+
return current === undefined || shown().surfaces[current].enabled;
|
|
784
|
+
};
|
|
785
|
+
const sidebarHidden = () => info().watchesSidebar && sidebars() === 0;
|
|
786
|
+
const active = () => selected() === SWITCH_ID;
|
|
787
|
+
return _$createComponent(Show, {
|
|
788
|
+
get when() {
|
|
789
|
+
return surface() || sidebarHidden();
|
|
790
|
+
},
|
|
791
|
+
get children() {
|
|
792
|
+
var _el$1 = _$createElement("box");
|
|
793
|
+
_$setProp(_el$1, "flexDirection", "column");
|
|
794
|
+
_$setProp(_el$1, "flexShrink", 0);
|
|
795
|
+
_$setProp(_el$1, "marginBottom", 1);
|
|
796
|
+
_$insert(_el$1, _$createComponent(Show, {
|
|
797
|
+
get when() {
|
|
798
|
+
return surface();
|
|
799
|
+
},
|
|
800
|
+
get children() {
|
|
801
|
+
return _$createComponent(Cell, {
|
|
802
|
+
get fg() {
|
|
803
|
+
return theme().text.action.primary.selected;
|
|
804
|
+
},
|
|
805
|
+
bold: true,
|
|
806
|
+
children: " Enable/disable"
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
}), null);
|
|
810
|
+
_$insert(_el$1, _$createComponent(Show, {
|
|
811
|
+
get when() {
|
|
812
|
+
return surface();
|
|
813
|
+
},
|
|
814
|
+
children: current => (() => {
|
|
815
|
+
var _el$13 = _$createElement("box");
|
|
816
|
+
_$setProp(_el$13, "flexShrink", 0);
|
|
817
|
+
_$setProp(_el$13, "onMouseDown", () => setSelected(SWITCH_ID));
|
|
818
|
+
_$insert(_el$13, _$createComponent(Cell, {
|
|
819
|
+
get fg() {
|
|
820
|
+
return _$memo(() => !!active())() ? theme().text.action.primary.focused : theme().text.base;
|
|
821
|
+
},
|
|
822
|
+
bold: true,
|
|
823
|
+
get children() {
|
|
824
|
+
return ` ${surfaceOn() ? "[x]" : "[ ]"} ${info().switchTitle}`;
|
|
825
|
+
}
|
|
826
|
+
}));
|
|
827
|
+
_$effect(_p$ => {
|
|
828
|
+
var _v$13 = boxId(SWITCH_ID),
|
|
829
|
+
_v$14 = active() ? theme().background.action.primary.focused : TRANSPARENT,
|
|
830
|
+
_v$15 = click(() => toggleSurface(current()));
|
|
831
|
+
_v$13 !== _p$.e && (_p$.e = _$setProp(_el$13, "id", _v$13, _p$.e));
|
|
832
|
+
_v$14 !== _p$.t && (_p$.t = _$setProp(_el$13, "backgroundColor", _v$14, _p$.t));
|
|
833
|
+
_v$15 !== _p$.a && (_p$.a = _$setProp(_el$13, "onMouseUp", _v$15, _p$.a));
|
|
834
|
+
return _p$;
|
|
835
|
+
}, {
|
|
836
|
+
e: undefined,
|
|
837
|
+
t: undefined,
|
|
838
|
+
a: undefined
|
|
839
|
+
});
|
|
840
|
+
return _el$13;
|
|
841
|
+
})()
|
|
842
|
+
}), null);
|
|
843
|
+
_$insert(_el$1, _$createComponent(Show, {
|
|
844
|
+
get when() {
|
|
845
|
+
return sidebarHidden();
|
|
846
|
+
},
|
|
847
|
+
get children() {
|
|
848
|
+
var _el$10 = _$createElement("box"),
|
|
849
|
+
_el$11 = _$createElement("text");
|
|
850
|
+
_$insertNode(_el$10, _el$11);
|
|
851
|
+
_$setProp(_el$10, "paddingLeft", 3);
|
|
852
|
+
_$setProp(_el$10, "flexDirection", "row");
|
|
853
|
+
_$setProp(_el$10, "gap", 2);
|
|
854
|
+
_$setProp(_el$10, "flexShrink", 0);
|
|
855
|
+
_$insertNode(_el$11, _$createTextNode(`The sidebar is hidden, so there is nothing to watch here.`));
|
|
856
|
+
_$setProp(_el$11, "wrapMode", "word");
|
|
857
|
+
_$setProp(_el$11, "selectable", false);
|
|
858
|
+
_$setProp(_el$11, "flexShrink", 1);
|
|
859
|
+
_$insert(_el$10, _$createComponent(Button, {
|
|
860
|
+
label: "Show sidebar",
|
|
861
|
+
run: () => {
|
|
862
|
+
api.keymap.dispatch("session.sidebar.toggle");
|
|
863
|
+
setTimeout(props.refocus, 50);
|
|
864
|
+
}
|
|
865
|
+
}), null);
|
|
866
|
+
_$effect(_$p => _$setProp(_el$11, "fg", theme().text.feedback.warning.base, _$p));
|
|
867
|
+
return _el$10;
|
|
868
|
+
}
|
|
869
|
+
}), null);
|
|
870
|
+
return _el$1;
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* A Settings tab's lines: its options, then the surface's providers (and rows) as a tree.
|
|
877
|
+
* `showPage` shows another of Layout's pages.
|
|
878
|
+
*/
|
|
879
|
+
function Body(props) {
|
|
880
|
+
/** The box with only the tree lines, so the drag math counts lines from its top. */
|
|
881
|
+
let list;
|
|
882
|
+
let dragId;
|
|
883
|
+
const surface = () => isSurfaceTab(props.tab) ? props.tab : undefined;
|
|
884
|
+
const withRows = () => props.tab === "sidebar" || props.tab === "toast";
|
|
885
|
+
const snapshot = () => props.host.quota.snapshot(props.sessionID);
|
|
886
|
+
const words = () => snapshot()?.words ?? DEFAULT_WORDS;
|
|
887
|
+
/** The picked windows of Collapsed or Status line. */
|
|
888
|
+
const windows = () => shown()[props.tab === "statusLine" ? "statusLine" : "collapsed"].window;
|
|
889
|
+
/** The providers and rows hidden on this page. */
|
|
890
|
+
const hiddenIds = () => {
|
|
891
|
+
const current = surface();
|
|
892
|
+
return current ? shown().surfaces[current].hidden : [];
|
|
893
|
+
};
|
|
894
|
+
const tree = () => {
|
|
895
|
+
const current = surface();
|
|
896
|
+
const loaded = snapshot();
|
|
897
|
+
return current && loaded ? surfaceTree(loaded, shown().surfaces[current]) : [];
|
|
898
|
+
};
|
|
899
|
+
const options = createMemo(() => optionLines(props.tab, snapshot(), () => props.box()?.focus()));
|
|
900
|
+
const lines = createMemo(() => tree().flatMap(({
|
|
901
|
+
provider,
|
|
902
|
+
rowIds
|
|
903
|
+
}) => [treeLine(provider.providerId, provider.providerId, false), ...(withRows() ? rowIds.map(id => treeLine(id, provider.providerId, true)) : [])]));
|
|
904
|
+
const selectedOption = () => options().find(line => line.id === selected());
|
|
905
|
+
const selectedLine = () => lines().find(line => lineKey(line.id) === selected());
|
|
906
|
+
function treeLine(id, providerId, row) {
|
|
907
|
+
const key = `${row ? "row" : "provider"}:${id}`;
|
|
908
|
+
const line = treeLines.get(key) ?? {
|
|
909
|
+
id,
|
|
910
|
+
providerId,
|
|
911
|
+
row
|
|
912
|
+
};
|
|
913
|
+
treeLines.set(key, line);
|
|
914
|
+
return line;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* ↑↓ select the next line; past the first or last one they scroll. In Layout's page list
|
|
919
|
+
* they show the page above or below.
|
|
920
|
+
*/
|
|
921
|
+
function select(delta) {
|
|
922
|
+
if (selected() === PAGES_ID) {
|
|
923
|
+
stepPage(delta);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
const ids = [...(pagesOf(props.tab) ? [PAGES_ID] : []), ...(surface() ? [SWITCH_ID] : []), ...options().map(line => line.id), ...lines().map(line => lineKey(line.id))];
|
|
927
|
+
const next = ids.indexOf(selected()) + delta;
|
|
928
|
+
if (next < 0 || next >= ids.length) props.scroll()?.scrollBy(delta);else setSelected(ids[next]);
|
|
929
|
+
}
|
|
930
|
+
function toggleHidden(id) {
|
|
931
|
+
const current = surface();
|
|
932
|
+
if (!current) return;
|
|
933
|
+
editSurface(current, rows => {
|
|
934
|
+
const hidden = rows.hidden.includes(id);
|
|
935
|
+
return {
|
|
936
|
+
...rows,
|
|
937
|
+
hidden: hidden ? rows.hidden.filter(item => item !== id) : [...rows.hidden, id]
|
|
938
|
+
};
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
function cycleWindow(providerId, delta) {
|
|
942
|
+
const provider = tree().find(item => item.provider.providerId === providerId)?.provider;
|
|
943
|
+
const choices = provider ? windowChoices(provider, hiddenIds()) : [];
|
|
944
|
+
if (choices.length === 0) return;
|
|
945
|
+
const inherited = inheritedWindow(windows(), choices);
|
|
946
|
+
const next = stepIn(choices, windows()[providerId] ?? inherited, delta);
|
|
947
|
+
// The window it would show anyway is no pick of its own, so it follows "For all providers".
|
|
948
|
+
display.edit(settings => setIn(settings, [props.tab === "statusLine" ? "statusLine" : "collapsed", "window", providerId], next === inherited ? undefined : next));
|
|
949
|
+
}
|
|
950
|
+
function move(delta) {
|
|
951
|
+
const current = surface();
|
|
952
|
+
const line = selectedLine();
|
|
953
|
+
if (current && line) editSurface(current, rows => movedBy(tree(), rows, line.id, delta));
|
|
954
|
+
}
|
|
955
|
+
function ownRow(line) {
|
|
956
|
+
return tree().find(item => item.provider.providerId === line.providerId)?.provider.rows.find(row => row.id === line.id);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** e or a double-click: type a color, or rename a row. */
|
|
960
|
+
function startTyping() {
|
|
961
|
+
const option = selectedOption();
|
|
962
|
+
if (option?.typed) {
|
|
963
|
+
setTyping({
|
|
964
|
+
id: option.id,
|
|
965
|
+
value: "",
|
|
966
|
+
...option.typed
|
|
967
|
+
});
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const line = selectedLine();
|
|
971
|
+
const row = line?.row ? ownRow(line) : undefined;
|
|
972
|
+
if (!line || !row) return;
|
|
973
|
+
setTyping({
|
|
974
|
+
id: lineKey(line.id),
|
|
975
|
+
value: "",
|
|
976
|
+
placeholder: shown()[props.tab === "toast" ? "toast" : "sidebar"].names[line.id] ?? row.label,
|
|
977
|
+
hint: `Type a new name, then enter · enter with nothing typed = its own name ("${row.label}") · esc stop`,
|
|
978
|
+
apply: text => display.edit(settings => renameRow(settings, props.tab === "toast" ? "toast" : "sidebar", line.id, text))
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
function stopTyping() {
|
|
982
|
+
setTyping(undefined);
|
|
983
|
+
props.box()?.focus();
|
|
984
|
+
}
|
|
985
|
+
function commitTyping() {
|
|
986
|
+
const current = typing();
|
|
987
|
+
current?.apply(current.value);
|
|
988
|
+
stopTyping();
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/** ↑↓ in Layout's page list: the page above or below this one, shown at once. */
|
|
992
|
+
function stepPage(delta) {
|
|
993
|
+
const pages = pagesOf(props.tab) ?? [];
|
|
994
|
+
const next = pages[pages.indexOf(props.tab) + delta];
|
|
995
|
+
if (next) props.showPage(next);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/** →, enter or space in Layout's page list: the page's first line, its switch or first option. */
|
|
999
|
+
function toFirstLine() {
|
|
1000
|
+
const first = surface() ? SWITCH_ID : options()[0]?.id;
|
|
1001
|
+
if (first) setSelected(first);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Space or enter: to the page's lines from the page list, flip a switch, run a button, next
|
|
1006
|
+
* value, or show/hide a line.
|
|
1007
|
+
*/
|
|
1008
|
+
function activate() {
|
|
1009
|
+
const current = surface();
|
|
1010
|
+
const option = selectedOption();
|
|
1011
|
+
const line = selectedLine();
|
|
1012
|
+
if (selected() === PAGES_ID) toFirstLine();else if (selected() === SWITCH_ID && current) toggleSurface(current);else if (option) useOption(option);else if (line) toggleHidden(line.id);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/** A click on an option's value: run its button, its next value, or start typing. */
|
|
1016
|
+
function useOption(option) {
|
|
1017
|
+
if (option.run) option.run();else if (option.cycle) option.cycle(1);else startTyping();
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/** ←/→ change the selected line's value; → in the page list goes to the page's lines. */
|
|
1021
|
+
function sideways(delta) {
|
|
1022
|
+
const option = selectedOption();
|
|
1023
|
+
const line = selectedLine();
|
|
1024
|
+
if (selected() === PAGES_ID) {
|
|
1025
|
+
if (delta > 0) toFirstLine();
|
|
1026
|
+
} else if (option) option.cycle?.(delta);else if (line && !line.row) cycleWindow(line.providerId, delta);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/** A provider moves with all its rows; a row moves only among its own provider's rows. */
|
|
1030
|
+
function onDrag(event) {
|
|
1031
|
+
const current = surface();
|
|
1032
|
+
const id = dragId;
|
|
1033
|
+
if (!current || !id || !list || typing()) return;
|
|
1034
|
+
draggedSincePress = true;
|
|
1035
|
+
setDragging(id);
|
|
1036
|
+
// Dragging onto the top or bottom line of a list that scrolls moves it one line.
|
|
1037
|
+
const scroll = props.scroll();
|
|
1038
|
+
if (scroll && event.y <= scroll.y) scroll.scrollBy(-1);else if (scroll && event.y >= scroll.y + scroll.height - 1) scroll.scrollBy(1);
|
|
1039
|
+
// list.y already includes the scroll offset, so this counts lines from the first line.
|
|
1040
|
+
const pointer = event.y - list.y;
|
|
1041
|
+
editSurface(current, rows => draggedTo(tree(), rows, id, pointer, withRows()));
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// On the Toast tab the real toast shows again after every change of what it shows.
|
|
1045
|
+
createEffect(on(() => {
|
|
1046
|
+
return props.tab === "toast" && JSON.stringify(shown().toast);
|
|
1047
|
+
}, key => {
|
|
1048
|
+
if (key) previewToast(props.host, props.sessionID);
|
|
1049
|
+
}));
|
|
1050
|
+
// Keep the selected line in view when the list is taller than its room.
|
|
1051
|
+
createEffect(on(selected, id => {
|
|
1052
|
+
queueMicrotask(() => props.scroll()?.scrollChildIntoView(boxId(id)));
|
|
1053
|
+
}));
|
|
1054
|
+
|
|
1055
|
+
// Keys work only while the window has the keyboard; they win over the window's own.
|
|
1056
|
+
api.keymap.layer(() => ({
|
|
1057
|
+
target: props.box,
|
|
1058
|
+
priority: 11,
|
|
1059
|
+
enabled: () => typing() === undefined && !confirming(),
|
|
1060
|
+
commands: [{
|
|
1061
|
+
bind: "up",
|
|
1062
|
+
title: "Previous line",
|
|
1063
|
+
group: KEYS,
|
|
1064
|
+
run: () => select(-1)
|
|
1065
|
+
}, {
|
|
1066
|
+
bind: "down",
|
|
1067
|
+
title: "Next line",
|
|
1068
|
+
group: KEYS,
|
|
1069
|
+
run: () => select(1)
|
|
1070
|
+
}, {
|
|
1071
|
+
bind: "shift+up",
|
|
1072
|
+
title: "Move up",
|
|
1073
|
+
group: KEYS,
|
|
1074
|
+
run: () => move(-1)
|
|
1075
|
+
}, {
|
|
1076
|
+
bind: "shift+down",
|
|
1077
|
+
title: "Move down",
|
|
1078
|
+
group: KEYS,
|
|
1079
|
+
run: () => move(1)
|
|
1080
|
+
}, {
|
|
1081
|
+
bind: "alt+up",
|
|
1082
|
+
title: "Move up",
|
|
1083
|
+
group: KEYS,
|
|
1084
|
+
run: () => move(-1)
|
|
1085
|
+
}, {
|
|
1086
|
+
bind: "alt+down",
|
|
1087
|
+
title: "Move down",
|
|
1088
|
+
group: KEYS,
|
|
1089
|
+
run: () => move(1)
|
|
1090
|
+
}, {
|
|
1091
|
+
bind: "space",
|
|
1092
|
+
title: "Use the line",
|
|
1093
|
+
group: KEYS,
|
|
1094
|
+
run: activate
|
|
1095
|
+
}, {
|
|
1096
|
+
bind: "return",
|
|
1097
|
+
title: "Use the line",
|
|
1098
|
+
group: KEYS,
|
|
1099
|
+
run: activate
|
|
1100
|
+
}, {
|
|
1101
|
+
bind: "e",
|
|
1102
|
+
title: "Type a value or rename a row",
|
|
1103
|
+
group: KEYS,
|
|
1104
|
+
run: startTyping
|
|
1105
|
+
}, {
|
|
1106
|
+
bind: "left",
|
|
1107
|
+
title: "Previous value",
|
|
1108
|
+
group: KEYS,
|
|
1109
|
+
run: () => sideways(-1)
|
|
1110
|
+
}, {
|
|
1111
|
+
bind: "right",
|
|
1112
|
+
title: "Next value",
|
|
1113
|
+
group: KEYS,
|
|
1114
|
+
run: () => sideways(1)
|
|
1115
|
+
}, {
|
|
1116
|
+
bind: "ctrl+r",
|
|
1117
|
+
title: "Reset this tab or page",
|
|
1118
|
+
group: KEYS,
|
|
1119
|
+
run: () => resetTabLines(props.tab)
|
|
1120
|
+
}]
|
|
1121
|
+
}));
|
|
1122
|
+
// While typing, the input has the keyboard: Esc only stops typing, Enter keeps the text.
|
|
1123
|
+
api.keymap.layer(() => ({
|
|
1124
|
+
target: () => typingInput,
|
|
1125
|
+
priority: 20,
|
|
1126
|
+
enabled: () => typing() !== undefined,
|
|
1127
|
+
commands: [{
|
|
1128
|
+
bind: "escape",
|
|
1129
|
+
title: "Stop typing",
|
|
1130
|
+
group: KEYS,
|
|
1131
|
+
run: stopTyping
|
|
1132
|
+
}, {
|
|
1133
|
+
bind: "return",
|
|
1134
|
+
title: "Keep it",
|
|
1135
|
+
group: KEYS,
|
|
1136
|
+
run: commitTyping
|
|
1137
|
+
}]
|
|
1138
|
+
}));
|
|
1139
|
+
function TypingInput(inputProps) {
|
|
1140
|
+
return (() => {
|
|
1141
|
+
var _el$14 = _$createElement("input");
|
|
1142
|
+
_$use(element => {
|
|
1143
|
+
typingInput = element;
|
|
1144
|
+
}, _el$14);
|
|
1145
|
+
_$setProp(_el$14, "flexShrink", 0);
|
|
1146
|
+
_$setProp(_el$14, "value", "");
|
|
1147
|
+
_$setProp(_el$14, "focused", true);
|
|
1148
|
+
_$setProp(_el$14, "onInput", value => {
|
|
1149
|
+
const current = typing();
|
|
1150
|
+
if (current) setTyping({
|
|
1151
|
+
...current,
|
|
1152
|
+
value
|
|
1153
|
+
});
|
|
1154
|
+
});
|
|
1155
|
+
_$setProp(_el$14, "onSubmit", commitTyping);
|
|
1156
|
+
_$effect(_p$ => {
|
|
1157
|
+
var _v$16 = inputProps.width,
|
|
1158
|
+
_v$17 = inputProps.placeholder;
|
|
1159
|
+
_v$16 !== _p$.e && (_p$.e = _$setProp(_el$14, "width", _v$16, _p$.e));
|
|
1160
|
+
_v$17 !== _p$.t && (_p$.t = _$setProp(_el$14, "placeholder", _v$17, _p$.t));
|
|
1161
|
+
return _p$;
|
|
1162
|
+
}, {
|
|
1163
|
+
e: undefined,
|
|
1164
|
+
t: undefined
|
|
1165
|
+
});
|
|
1166
|
+
return _el$14;
|
|
1167
|
+
})();
|
|
1168
|
+
}
|
|
1169
|
+
function TreeRow(rowProps) {
|
|
1170
|
+
const line = rowProps.line;
|
|
1171
|
+
const key = lineKey(line.id);
|
|
1172
|
+
const entry = () => tree().find(item => item.provider.providerId === line.providerId);
|
|
1173
|
+
const rows = () => shown().surfaces[surface()];
|
|
1174
|
+
const active = () => selected() === key;
|
|
1175
|
+
// Dragging a provider carries its rows, so they light up with it.
|
|
1176
|
+
const lit = () => active() || dragging() === line.id || line.row && dragging() === line.providerId;
|
|
1177
|
+
const hidden = () => rows().hidden.includes(line.id);
|
|
1178
|
+
const {
|
|
1179
|
+
text
|
|
1180
|
+
} = theme();
|
|
1181
|
+
const fg = () => lit() ? text.action.primary.focused : !rows().enabled || hidden() || line.row && rows().hidden.includes(line.providerId) ? text.muted : text.base;
|
|
1182
|
+
/** Tree lines show which provider a row belongs to: ├ for a middle row, └ for the last. */
|
|
1183
|
+
const branch = () => {
|
|
1184
|
+
const rowIds = entry()?.rowIds ?? [];
|
|
1185
|
+
return !line.row ? "" : rowIds[rowIds.length - 1] === line.id ? " └ " : " ├ ";
|
|
1186
|
+
};
|
|
1187
|
+
const own = () => line.row ? ownRow(line) : undefined;
|
|
1188
|
+
const label = () => line.row ? shown()[props.tab === "toast" ? "toast" : "sidebar"].names[line.id] ?? own()?.label ?? line.id : entry()?.provider.label ?? line.id;
|
|
1189
|
+
const summary = row => {
|
|
1190
|
+
if (row.percentRemaining === undefined) return rowValueText(row);
|
|
1191
|
+
const reset = resetText(row, Date.now(), words());
|
|
1192
|
+
return `${percentText(words(), row.percentRemaining, true)}${reset ? ` · ${reset}` : ""}`;
|
|
1193
|
+
};
|
|
1194
|
+
const detail = () => {
|
|
1195
|
+
const provider = entry()?.provider;
|
|
1196
|
+
const row = own();
|
|
1197
|
+
if (row && shown()[props.tab === "toast" ? "toast" : "sidebar"].names[line.id] !== undefined) return `was "${row.label}"`;
|
|
1198
|
+
if (row?.prominence === "supplementary" && words().detail !== "detailed") {
|
|
1199
|
+
return "only with all rows";
|
|
1200
|
+
}
|
|
1201
|
+
if (row) return summary(row);
|
|
1202
|
+
if (!provider) return "";
|
|
1203
|
+
if (provider.error && provider.rows.length === 0) {
|
|
1204
|
+
return describeError(provider.error, provider.label, Date.now());
|
|
1205
|
+
}
|
|
1206
|
+
if (withRows()) return "";
|
|
1207
|
+
const rows = provider.rows.filter(item => !hiddenIds().includes(item.id));
|
|
1208
|
+
const picked = pickRow({
|
|
1209
|
+
rows: rows.map(item => ({
|
|
1210
|
+
row: item,
|
|
1211
|
+
label: item.label,
|
|
1212
|
+
named: false
|
|
1213
|
+
}))
|
|
1214
|
+
}, windowFor(windows(), provider.providerId));
|
|
1215
|
+
return picked ? summary(picked.row) : "";
|
|
1216
|
+
};
|
|
1217
|
+
const choices = () => {
|
|
1218
|
+
const provider = entry()?.provider;
|
|
1219
|
+
return !line.row && !withRows() && provider ? windowChoices(provider, hiddenIds()) : [];
|
|
1220
|
+
};
|
|
1221
|
+
/** Rows sit 4 columns further right, so their names get 4 fewer; the details line up. */
|
|
1222
|
+
const labelWidth = line.row ? 24 : 28;
|
|
1223
|
+
return (() => {
|
|
1224
|
+
var _el$15 = _$createElement("box");
|
|
1225
|
+
_$setProp(_el$15, "flexDirection", "row");
|
|
1226
|
+
_$setProp(_el$15, "onMouseDown", event => {
|
|
1227
|
+
if (event.button !== 0 || typing()) return;
|
|
1228
|
+
setSelected(key);
|
|
1229
|
+
dragId = line.id;
|
|
1230
|
+
if (line.row && isDoubleClick(key)) startTyping();
|
|
1231
|
+
});
|
|
1232
|
+
_$insert(_el$15, _$createComponent(Cell, {
|
|
1233
|
+
get fg() {
|
|
1234
|
+
return text.muted;
|
|
1235
|
+
},
|
|
1236
|
+
get children() {
|
|
1237
|
+
return ` ${branch()}`;
|
|
1238
|
+
}
|
|
1239
|
+
}), null);
|
|
1240
|
+
_$insert(_el$15, _$createComponent(Cell, {
|
|
1241
|
+
get fg() {
|
|
1242
|
+
return _$memo(() => !!lit())() ? fg() : text.action.primary.selected;
|
|
1243
|
+
},
|
|
1244
|
+
get children() {
|
|
1245
|
+
return api.renderer.useMouse === false ? "" : "⠿ ";
|
|
1246
|
+
}
|
|
1247
|
+
}), null);
|
|
1248
|
+
_$insert(_el$15, _$createComponent(Cell, {
|
|
1249
|
+
get fg() {
|
|
1250
|
+
return fg();
|
|
1251
|
+
},
|
|
1252
|
+
get onUp() {
|
|
1253
|
+
return click(() => toggleHidden(line.id));
|
|
1254
|
+
},
|
|
1255
|
+
get children() {
|
|
1256
|
+
return hidden() ? "[ ] " : "[x] ";
|
|
1257
|
+
}
|
|
1258
|
+
}), null);
|
|
1259
|
+
_$insert(_el$15, _$createComponent(Show, {
|
|
1260
|
+
get when() {
|
|
1261
|
+
return typing()?.id === key;
|
|
1262
|
+
},
|
|
1263
|
+
get fallback() {
|
|
1264
|
+
return _$createComponent(Cell, {
|
|
1265
|
+
get fg() {
|
|
1266
|
+
return fg();
|
|
1267
|
+
},
|
|
1268
|
+
get bold() {
|
|
1269
|
+
return !line.row;
|
|
1270
|
+
},
|
|
1271
|
+
get children() {
|
|
1272
|
+
return fit(label(), labelWidth);
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
},
|
|
1276
|
+
get children() {
|
|
1277
|
+
return _$createComponent(TypingInput, {
|
|
1278
|
+
width: labelWidth,
|
|
1279
|
+
get placeholder() {
|
|
1280
|
+
return label();
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
}), null);
|
|
1285
|
+
_$insert(_el$15, _$createComponent(Show, {
|
|
1286
|
+
get when() {
|
|
1287
|
+
return choices().length > 0;
|
|
1288
|
+
},
|
|
1289
|
+
get fallback() {
|
|
1290
|
+
return _$createComponent(Cell, {
|
|
1291
|
+
get children() {
|
|
1292
|
+
return _$memo(() => !!withRows())() ? " " : " ".repeat(17);
|
|
1293
|
+
}
|
|
1294
|
+
});
|
|
1295
|
+
},
|
|
1296
|
+
get children() {
|
|
1297
|
+
return _$createComponent(Cell, {
|
|
1298
|
+
get fg() {
|
|
1299
|
+
return _$memo(() => !!active())() ? fg() : text.action.primary.selected;
|
|
1300
|
+
},
|
|
1301
|
+
get onUp() {
|
|
1302
|
+
return click(() => cycleWindow(line.providerId, 1));
|
|
1303
|
+
},
|
|
1304
|
+
get children() {
|
|
1305
|
+
return ` ‹ ${fit(windowTitle(windows()[line.providerId] ?? inheritedWindow(windows(), choices())), 11)} › `;
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
}), null);
|
|
1310
|
+
_$insert(_el$15, _$createComponent(Cell, {
|
|
1311
|
+
get fg() {
|
|
1312
|
+
return _$memo(() => !!lit())() ? fg() : text.muted;
|
|
1313
|
+
},
|
|
1314
|
+
shrink: true,
|
|
1315
|
+
get children() {
|
|
1316
|
+
return fit(detail(), 24);
|
|
1317
|
+
}
|
|
1318
|
+
}), null);
|
|
1319
|
+
_$effect(_p$ => {
|
|
1320
|
+
var _v$18 = boxId(key),
|
|
1321
|
+
_v$19 = lit() ? theme().background.action.primary.focused : TRANSPARENT;
|
|
1322
|
+
_v$18 !== _p$.e && (_p$.e = _$setProp(_el$15, "id", _v$18, _p$.e));
|
|
1323
|
+
_v$19 !== _p$.t && (_p$.t = _$setProp(_el$15, "backgroundColor", _v$19, _p$.t));
|
|
1324
|
+
return _p$;
|
|
1325
|
+
}, {
|
|
1326
|
+
e: undefined,
|
|
1327
|
+
t: undefined
|
|
1328
|
+
});
|
|
1329
|
+
return _el$15;
|
|
1330
|
+
})();
|
|
1331
|
+
}
|
|
1332
|
+
return (() => {
|
|
1333
|
+
var _el$16 = _$createElement("box"),
|
|
1334
|
+
_el$18 = _$createElement("box");
|
|
1335
|
+
_$insertNode(_el$16, _el$18);
|
|
1336
|
+
_$setProp(_el$16, "flexDirection", "column");
|
|
1337
|
+
_$insert(_el$16, _$createComponent(For, {
|
|
1338
|
+
get each() {
|
|
1339
|
+
return options();
|
|
1340
|
+
},
|
|
1341
|
+
children: (line, index) => _$createComponent(OptionRow, {
|
|
1342
|
+
line: line,
|
|
1343
|
+
get theme() {
|
|
1344
|
+
return theme();
|
|
1345
|
+
},
|
|
1346
|
+
get active() {
|
|
1347
|
+
return selected() === line.id;
|
|
1348
|
+
},
|
|
1349
|
+
get first() {
|
|
1350
|
+
return index() === 0;
|
|
1351
|
+
},
|
|
1352
|
+
get width() {
|
|
1353
|
+
return props.width;
|
|
1354
|
+
},
|
|
1355
|
+
click: click,
|
|
1356
|
+
press: event => {
|
|
1357
|
+
if (event.button !== 0 || typing()) return;
|
|
1358
|
+
setSelected(line.id);
|
|
1359
|
+
if (line.typed && isDoubleClick(line.id)) startTyping();
|
|
1360
|
+
},
|
|
1361
|
+
use: () => useOption(line),
|
|
1362
|
+
get input() {
|
|
1363
|
+
return typing()?.id === line.id ? width => _$createComponent(TypingInput, {
|
|
1364
|
+
width: width,
|
|
1365
|
+
get placeholder() {
|
|
1366
|
+
return line.typed?.placeholder ?? "";
|
|
1367
|
+
}
|
|
1368
|
+
}) : undefined;
|
|
1369
|
+
}
|
|
1370
|
+
})
|
|
1371
|
+
}), _el$18);
|
|
1372
|
+
_$insert(_el$16, _$createComponent(Show, {
|
|
1373
|
+
get when() {
|
|
1374
|
+
return _$memo(() => !!surface())() && !snapshot();
|
|
1375
|
+
},
|
|
1376
|
+
get children() {
|
|
1377
|
+
return _$createComponent(Cell, {
|
|
1378
|
+
get fg() {
|
|
1379
|
+
return theme().text.muted;
|
|
1380
|
+
},
|
|
1381
|
+
children: " Loading quota…"
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}), _el$18);
|
|
1385
|
+
_$insert(_el$16, _$createComponent(Show, {
|
|
1386
|
+
get when() {
|
|
1387
|
+
return !server.saved();
|
|
1388
|
+
},
|
|
1389
|
+
get children() {
|
|
1390
|
+
return _$createComponent(Cell, {
|
|
1391
|
+
get fg() {
|
|
1392
|
+
return theme().text.muted;
|
|
1393
|
+
},
|
|
1394
|
+
children: " Loading settings…"
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
}), _el$18);
|
|
1398
|
+
_$insert(_el$16, _$createComponent(Show, {
|
|
1399
|
+
get when() {
|
|
1400
|
+
return _$memo(() => options().length > 0)() && lines().length > 0;
|
|
1401
|
+
},
|
|
1402
|
+
get children() {
|
|
1403
|
+
var _el$17 = _$createElement("box");
|
|
1404
|
+
_$setProp(_el$17, "height", 1);
|
|
1405
|
+
return _el$17;
|
|
1406
|
+
}
|
|
1407
|
+
}), _el$18);
|
|
1408
|
+
_$use(element => {
|
|
1409
|
+
list = element;
|
|
1410
|
+
}, _el$18);
|
|
1411
|
+
_$setProp(_el$18, "flexDirection", "column");
|
|
1412
|
+
_$setProp(_el$18, "onMouseDrag", onDrag);
|
|
1413
|
+
_$setProp(_el$18, "onMouseDragEnd", () => setDragging(undefined));
|
|
1414
|
+
_$setProp(_el$18, "onMouseUp", () => {
|
|
1415
|
+
dragId = undefined;
|
|
1416
|
+
});
|
|
1417
|
+
_$insert(_el$18, _$createComponent(For, {
|
|
1418
|
+
get each() {
|
|
1419
|
+
return lines();
|
|
1420
|
+
},
|
|
1421
|
+
children: line => _$createComponent(TreeRow, {
|
|
1422
|
+
line: line
|
|
1423
|
+
})
|
|
1424
|
+
}));
|
|
1425
|
+
_$effect(_$p => _$setProp(_el$16, "width", props.width, _$p));
|
|
1426
|
+
return _el$16;
|
|
1427
|
+
})();
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* The bottom bar of a Settings tab: Close, or Save and Discard, or the "Keep your changes?"
|
|
1432
|
+
* question, which also shows on the other tabs when closing asks it.
|
|
1433
|
+
*/
|
|
1434
|
+
function Buttons(props) {
|
|
1435
|
+
const settingsTab = () => isSettingsTab(props.tab) ? props.tab : undefined;
|
|
1436
|
+
const warning = () => theme().text.feedback.warning.base;
|
|
1437
|
+
async function save() {
|
|
1438
|
+
try {
|
|
1439
|
+
await server.save();
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
const message = rpcErrorMessage(error);
|
|
1442
|
+
api.ui.toast.show({
|
|
1443
|
+
variant: "error",
|
|
1444
|
+
title: "Quota settings not saved",
|
|
1445
|
+
message
|
|
1446
|
+
});
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
setConfirming(false);
|
|
1450
|
+
props.close();
|
|
1451
|
+
api.ui.toast.show({
|
|
1452
|
+
variant: "success",
|
|
1453
|
+
title: "Quota settings saved",
|
|
1454
|
+
message: "Every open OpenCode window uses them now, and they stay after a restart.",
|
|
1455
|
+
duration: 4_000
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
/** Drops the changes; from the "Keep your changes?" question it also closes the window. */
|
|
1459
|
+
const discardChanges = () => {
|
|
1460
|
+
discard();
|
|
1461
|
+
if (!confirming()) return;
|
|
1462
|
+
setConfirming(false);
|
|
1463
|
+
props.close();
|
|
1464
|
+
};
|
|
1465
|
+
api.keymap.layer(() => ({
|
|
1466
|
+
target: props.box,
|
|
1467
|
+
priority: 12,
|
|
1468
|
+
enabled: () => typing() === undefined && (settingsTab() !== undefined || dirty()),
|
|
1469
|
+
commands: [{
|
|
1470
|
+
bind: "ctrl+s",
|
|
1471
|
+
title: "Save",
|
|
1472
|
+
group: KEYS,
|
|
1473
|
+
run: () => void save()
|
|
1474
|
+
}]
|
|
1475
|
+
}));
|
|
1476
|
+
// While the bottom bar asks about unsaved changes: d drops them, Esc goes back to editing.
|
|
1477
|
+
api.keymap.layer(() => ({
|
|
1478
|
+
target: props.box,
|
|
1479
|
+
priority: 15,
|
|
1480
|
+
enabled: () => confirming() && typing() === undefined,
|
|
1481
|
+
commands: [{
|
|
1482
|
+
bind: "d",
|
|
1483
|
+
title: "Discard the changes",
|
|
1484
|
+
group: KEYS,
|
|
1485
|
+
run: discardChanges
|
|
1486
|
+
}, {
|
|
1487
|
+
bind: "escape",
|
|
1488
|
+
title: "Keep editing",
|
|
1489
|
+
group: KEYS,
|
|
1490
|
+
run: () => setConfirming(false)
|
|
1491
|
+
}]
|
|
1492
|
+
}));
|
|
1493
|
+
return _$createComponent(Show, {
|
|
1494
|
+
get when() {
|
|
1495
|
+
return settingsTab() !== undefined || confirming();
|
|
1496
|
+
},
|
|
1497
|
+
get children() {
|
|
1498
|
+
return _$createComponent(Show, {
|
|
1499
|
+
get when() {
|
|
1500
|
+
return !confirming();
|
|
1501
|
+
},
|
|
1502
|
+
get fallback() {
|
|
1503
|
+
return [_$createComponent(Cell, {
|
|
1504
|
+
get fg() {
|
|
1505
|
+
return warning();
|
|
1506
|
+
},
|
|
1507
|
+
bold: true,
|
|
1508
|
+
children: "Keep your changes?"
|
|
1509
|
+
}), _$createComponent(Button, {
|
|
1510
|
+
label: "Save",
|
|
1511
|
+
primary: true,
|
|
1512
|
+
run: () => void save()
|
|
1513
|
+
}), _$createComponent(Button, {
|
|
1514
|
+
label: "Discard",
|
|
1515
|
+
run: discardChanges
|
|
1516
|
+
}), _$createComponent(Button, {
|
|
1517
|
+
label: "Keep editing",
|
|
1518
|
+
run: () => setConfirming(false)
|
|
1519
|
+
})];
|
|
1520
|
+
},
|
|
1521
|
+
get children() {
|
|
1522
|
+
return [_$createComponent(Show, {
|
|
1523
|
+
get when() {
|
|
1524
|
+
return dirty();
|
|
1525
|
+
},
|
|
1526
|
+
get fallback() {
|
|
1527
|
+
return _$createComponent(Button, {
|
|
1528
|
+
label: "Close",
|
|
1529
|
+
primary: true,
|
|
1530
|
+
get run() {
|
|
1531
|
+
return props.close;
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
},
|
|
1535
|
+
get children() {
|
|
1536
|
+
return [_$createComponent(Button, {
|
|
1537
|
+
label: "Save",
|
|
1538
|
+
primary: true,
|
|
1539
|
+
run: () => void save()
|
|
1540
|
+
}), _$createComponent(Button, {
|
|
1541
|
+
label: "Discard",
|
|
1542
|
+
run: discardChanges
|
|
1543
|
+
})];
|
|
1544
|
+
}
|
|
1545
|
+
}), _$createComponent(Show, {
|
|
1546
|
+
get when() {
|
|
1547
|
+
return settingsTab();
|
|
1548
|
+
},
|
|
1549
|
+
children: current => _$createComponent(Button, {
|
|
1550
|
+
get label() {
|
|
1551
|
+
return resetLabel(current());
|
|
1552
|
+
},
|
|
1553
|
+
run: () => resetTabLines(current())
|
|
1554
|
+
})
|
|
1555
|
+
}), _$createComponent(Show, {
|
|
1556
|
+
get when() {
|
|
1557
|
+
return _$memo(() => settingsTab() === "toast")() && shown().surfaces.toast.enabled;
|
|
1558
|
+
},
|
|
1559
|
+
get children() {
|
|
1560
|
+
return _$createComponent(Button, {
|
|
1561
|
+
label: "Show toast",
|
|
1562
|
+
run: () => previewToast(props.host, props.sessionID)
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
}), _$createComponent(Cell, {
|
|
1566
|
+
get fg() {
|
|
1567
|
+
return warning();
|
|
1568
|
+
},
|
|
1569
|
+
get children() {
|
|
1570
|
+
return dirty() ? " unsaved changes" : "";
|
|
1571
|
+
}
|
|
1572
|
+
})];
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
return {
|
|
1579
|
+
/** The tree line selected on `surface`'s tab, which that surface marks. */
|
|
1580
|
+
marked(surface) {
|
|
1581
|
+
const id = selected();
|
|
1582
|
+
return tab() === surface && id.startsWith("line:") ? id.slice("line:".length) : undefined;
|
|
1583
|
+
},
|
|
1584
|
+
/** Sidebar shows the panel expanded and Collapsed collapsed; undefined = as the user left it. */
|
|
1585
|
+
panelOpen() {
|
|
1586
|
+
if (tab() === "sidebar") return true;
|
|
1587
|
+
return tab() === "collapsed" ? false : undefined;
|
|
1588
|
+
},
|
|
1589
|
+
/** A sidebar panel mounts; the returned function unmounts it. */
|
|
1590
|
+
sidebarShown() {
|
|
1591
|
+
setSidebars(count => count + 1);
|
|
1592
|
+
return () => setSidebars(count => count - 1);
|
|
1593
|
+
},
|
|
1594
|
+
statusLineShown() {
|
|
1595
|
+
const settings = shown();
|
|
1596
|
+
if (!settings.surfaces.statusLine.enabled) return false;
|
|
1597
|
+
const sidebarQuota = sidebars() > 0 && settings.surfaces.sidebar.enabled;
|
|
1598
|
+
return tab() === "statusLine" || settings.statusLine.withSidebar || !sidebarQuota;
|
|
1599
|
+
},
|
|
1600
|
+
/** A line takes typing, so the window's own keys rest. */
|
|
1601
|
+
typing: () => typing() !== undefined,
|
|
1602
|
+
/** A Plugin switch's saved value (`system.exportFile`); undefined until the server answers. */
|
|
1603
|
+
savedSwitch(key) {
|
|
1604
|
+
return server.saved() ? server.value(key) === true : undefined;
|
|
1605
|
+
},
|
|
1606
|
+
/** Saves a Plugin switch straight away; Plugin has no draft and no Save. */
|
|
1607
|
+
saveSwitch: (key, on) => server.saveNow(key, on),
|
|
1608
|
+
/** Reads the saved settings again, for Plugin's switches. */
|
|
1609
|
+
loadSaved: () => server.load(),
|
|
1610
|
+
/** The snapshot with All places' unsaved words, which every surface shows while you edit. */
|
|
1611
|
+
withDraftWords(snapshot) {
|
|
1612
|
+
const words = server.draftWords();
|
|
1613
|
+
if (!snapshot || Object.keys(words).length === 0) return snapshot;
|
|
1614
|
+
return {
|
|
1615
|
+
...snapshot,
|
|
1616
|
+
words: {
|
|
1617
|
+
...(snapshot.words ?? DEFAULT_WORDS),
|
|
1618
|
+
...words
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
},
|
|
1622
|
+
/**
|
|
1623
|
+
* The window shows `next`; undefined when it closed, which drops the changes. Any tab
|
|
1624
|
+
* change stops typing, so the window gets its keys back.
|
|
1625
|
+
*/
|
|
1626
|
+
setTab(next) {
|
|
1627
|
+
setTyping(undefined);
|
|
1628
|
+
typingInput = undefined;
|
|
1629
|
+
if (next === undefined) {
|
|
1630
|
+
discard();
|
|
1631
|
+
setConfirming(false);
|
|
1632
|
+
}
|
|
1633
|
+
const settingsTab = isSettingsTab(next) ? next : undefined;
|
|
1634
|
+
if (settingsTab !== tab()) setSelected(firstLine(settingsTab));
|
|
1635
|
+
setTabNow(settingsTab);
|
|
1636
|
+
if (settingsTab) void loadServer(settingsTab);
|
|
1637
|
+
},
|
|
1638
|
+
/** Esc or Close: true while there are unsaved changes; the bottom bar then asks about them. */
|
|
1639
|
+
askBeforeClose() {
|
|
1640
|
+
if (!dirty()) return false;
|
|
1641
|
+
setConfirming(true);
|
|
1642
|
+
return true;
|
|
1643
|
+
},
|
|
1644
|
+
/** A press anywhere in the window: clicks count again after a drag, and typing goes on. */
|
|
1645
|
+
pressed() {
|
|
1646
|
+
draggedSincePress = false;
|
|
1647
|
+
if (typing()) typingInput?.focus();
|
|
1648
|
+
},
|
|
1649
|
+
click,
|
|
1650
|
+
/** The keyboard hint, or undefined for the window's own. */
|
|
1651
|
+
hint(windowTab, hasKeyboard) {
|
|
1652
|
+
const current = typing();
|
|
1653
|
+
if (current) return current.hint;
|
|
1654
|
+
if (!hasKeyboard) return undefined;
|
|
1655
|
+
if (confirming()) return "ctrl+s save · d discard the changes · esc keep editing";
|
|
1656
|
+
if (!isSettingsTab(windowTab)) return undefined;
|
|
1657
|
+
const reset = `ctrl+r ${resetLabel(windowTab).toLowerCase()}`;
|
|
1658
|
+
const end = `↑↓ select · tab next tab · ctrl+s save · ${reset} · esc close`;
|
|
1659
|
+
if (selected() === PAGES_ID) {
|
|
1660
|
+
return `↑↓ page · → or enter the page's lines · tab next tab · ctrl+s save · ${reset} · esc close`;
|
|
1661
|
+
}
|
|
1662
|
+
if (windowTab === "layout") return `‹ › or ←/→ change · ${end}`;
|
|
1663
|
+
if (windowTab === "providers") {
|
|
1664
|
+
return `‹ › or ←/→ change · space ticks a provider or flips a switch · double-click a number (or e) to type it · ${end}`;
|
|
1665
|
+
}
|
|
1666
|
+
if (!isSurfaceTab(windowTab)) {
|
|
1667
|
+
return `‹ › or ←/→ change · double-click a color (or e) to type your own · ${end}`;
|
|
1668
|
+
}
|
|
1669
|
+
const rowsTab = windowTab === "sidebar" || windowTab === "toast";
|
|
1670
|
+
const moving = api.renderer.useMouse === false ? "shift+↑↓ move" : `drag ⠿ or shift+↑↓ to move${rowsTab ? " (a provider takes its rows along)" : ""}`;
|
|
1671
|
+
const naming = rowsTab ? "double-click a row (or e) to rename it" : "‹ › pick a window";
|
|
1672
|
+
return `${moving} · [x] or space show/hide · ${naming} · ${end}`;
|
|
1673
|
+
},
|
|
1674
|
+
Pages,
|
|
1675
|
+
Header,
|
|
1676
|
+
Body,
|
|
1677
|
+
Buttons
|
|
1678
|
+
};
|
|
1679
|
+
}
|