indusagi 0.12.23 → 0.12.26
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 +393 -10
- package/local-dist/bot/actions/composio/accounts.d.ts +23 -0
- package/local-dist/bot/actions/composio/accounts.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/accounts.js +40 -0
- package/local-dist/bot/actions/composio/accounts.js.map +1 -0
- package/local-dist/bot/actions/composio/client.d.ts +40 -0
- package/local-dist/bot/actions/composio/client.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/client.js +361 -0
- package/local-dist/bot/actions/composio/client.js.map +1 -0
- package/local-dist/bot/actions/composio/connect.d.ts +20 -0
- package/local-dist/bot/actions/composio/connect.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/connect.js +41 -0
- package/local-dist/bot/actions/composio/connect.js.map +1 -0
- package/local-dist/bot/actions/composio/enable.d.ts +26 -0
- package/local-dist/bot/actions/composio/enable.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/enable.js +66 -0
- package/local-dist/bot/actions/composio/enable.js.map +1 -0
- package/local-dist/bot/actions/composio/execute.d.ts +27 -0
- package/local-dist/bot/actions/composio/execute.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/execute.js +46 -0
- package/local-dist/bot/actions/composio/execute.js.map +1 -0
- package/local-dist/bot/actions/composio/helpers.d.ts +17 -0
- package/local-dist/bot/actions/composio/helpers.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/helpers.js +533 -0
- package/local-dist/bot/actions/composio/helpers.js.map +1 -0
- package/local-dist/bot/actions/composio/index.d.ts +10 -0
- package/local-dist/bot/actions/composio/index.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/index.js +9 -0
- package/local-dist/bot/actions/composio/index.js.map +1 -0
- package/local-dist/bot/actions/composio/provider.d.ts +9 -0
- package/local-dist/bot/actions/composio/provider.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/provider.js +54 -0
- package/local-dist/bot/actions/composio/provider.js.map +1 -0
- package/local-dist/bot/actions/composio/toolkits.d.ts +23 -0
- package/local-dist/bot/actions/composio/toolkits.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/toolkits.js +40 -0
- package/local-dist/bot/actions/composio/toolkits.js.map +1 -0
- package/local-dist/bot/actions/composio/tools.d.ts +29 -0
- package/local-dist/bot/actions/composio/tools.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/tools.js +72 -0
- package/local-dist/bot/actions/composio/tools.js.map +1 -0
- package/local-dist/bot/actions/composio/types.d.ts +126 -0
- package/local-dist/bot/actions/composio/types.d.ts.map +1 -0
- package/local-dist/bot/actions/composio/types.js +2 -0
- package/local-dist/bot/actions/composio/types.js.map +1 -0
- package/{dist → local-dist}/bot/actions/crew/activity-tracker.js +1 -1
- package/{dist → local-dist}/bot/actions/crew/activity-tracker.js.map +1 -1
- package/{dist → local-dist}/bot/actions/crew/worktree.js +2 -2
- package/local-dist/bot/actions/crew/worktree.js.map +1 -0
- package/{dist → local-dist}/bot/actions/index.d.ts +111 -0
- package/local-dist/bot/actions/index.d.ts.map +1 -0
- package/{dist → local-dist}/bot/actions/index.js +108 -2
- package/local-dist/bot/actions/index.js.map +1 -0
- package/{dist → local-dist}/bot/actions/process-manager.js +1 -1
- package/{dist → local-dist}/bot/actions/process-manager.js.map +1 -1
- package/{dist → local-dist}/index.d.ts +1 -0
- package/{dist → local-dist}/index.d.ts.map +1 -1
- package/{dist → local-dist}/index.js +1 -0
- package/{dist → local-dist}/index.js.map +1 -1
- package/{dist → local-dist}/mcp/client-pool.d.ts +1 -1
- package/{dist → local-dist}/mcp/client-pool.js +1 -1
- package/{dist → local-dist}/mcp/client.d.ts +1 -1
- package/{dist → local-dist}/mcp/client.js +1 -1
- package/{dist → local-dist}/mcp/config.d.ts +1 -1
- package/{dist → local-dist}/mcp/config.js +1 -1
- package/{dist → local-dist}/mcp/errors.d.ts +1 -1
- package/{dist → local-dist}/mcp/errors.js +1 -1
- package/{dist → local-dist}/mcp/schema-converter.d.ts +1 -1
- package/{dist → local-dist}/mcp/schema-converter.js +1 -1
- package/{dist → local-dist}/mcp/server.d.ts +1 -1
- package/{dist → local-dist}/mcp/server.js +1 -1
- package/{dist → local-dist}/mcp/tool-factory.d.ts +1 -1
- package/{dist → local-dist}/mcp/tool-factory.js +1 -1
- package/{dist → local-dist}/mcp/types.d.ts +1 -1
- package/{dist → local-dist}/mcp/types.js +1 -1
- package/{dist → local-dist}/ml/adapters/openai-codex-responses.js +4 -2
- package/{dist → local-dist}/ml/adapters/openai-codex-responses.js.map +1 -1
- package/{dist → local-dist}/ml/kit/auth/openai-codex.d.ts +1 -1
- package/{dist → local-dist}/ml/kit/auth/openai-codex.js +2 -2
- package/{dist → local-dist}/ml/kit/auth/openai-codex.js.map +1 -1
- package/local-dist/react-host/index.d.ts +10 -0
- package/local-dist/react-host/index.d.ts.map +1 -0
- package/local-dist/react-host/index.js +9 -0
- package/local-dist/react-host/index.js.map +1 -0
- package/local-dist/react-host/ink.d.ts +5 -0
- package/local-dist/react-host/ink.d.ts.map +1 -0
- package/local-dist/react-host/ink.js +6 -0
- package/local-dist/react-host/ink.js.map +1 -0
- package/local-dist/react-host/jsx-runtime.d.ts +5 -0
- package/local-dist/react-host/jsx-runtime.d.ts.map +1 -0
- package/local-dist/react-host/jsx-runtime.js +6 -0
- package/local-dist/react-host/jsx-runtime.js.map +1 -0
- package/local-dist/react-host/loader.d.ts +4 -0
- package/local-dist/react-host/loader.d.ts.map +1 -0
- package/local-dist/react-host/loader.js +83 -0
- package/local-dist/react-host/loader.js.map +1 -0
- package/local-dist/react-ink/components/ChangelogBlock.d.ts +9 -0
- package/local-dist/react-ink/components/ChangelogBlock.d.ts.map +1 -0
- package/local-dist/react-ink/components/ChangelogBlock.js +58 -0
- package/local-dist/react-ink/components/ChangelogBlock.js.map +1 -0
- package/local-dist/react-ink/components/DisplayBlockView.d.ts +9 -0
- package/local-dist/react-ink/components/DisplayBlockView.d.ts.map +1 -0
- package/local-dist/react-ink/components/DisplayBlockView.js +11 -0
- package/local-dist/react-ink/components/DisplayBlockView.js.map +1 -0
- package/local-dist/react-ink/components/Footer.d.ts +12 -0
- package/local-dist/react-ink/components/Footer.d.ts.map +1 -0
- package/local-dist/react-ink/components/Footer.js +109 -0
- package/local-dist/react-ink/components/Footer.js.map +1 -0
- package/local-dist/react-ink/components/MessageList.d.ts +15 -0
- package/local-dist/react-ink/components/MessageList.d.ts.map +1 -0
- package/local-dist/react-ink/components/MessageList.js +43 -0
- package/local-dist/react-ink/components/MessageList.js.map +1 -0
- package/local-dist/react-ink/components/MessageRow.d.ts +14 -0
- package/local-dist/react-ink/components/MessageRow.d.ts.map +1 -0
- package/local-dist/react-ink/components/MessageRow.js +35 -0
- package/local-dist/react-ink/components/MessageRow.js.map +1 -0
- package/local-dist/react-ink/components/StatusLine.d.ts +10 -0
- package/local-dist/react-ink/components/StatusLine.d.ts.map +1 -0
- package/local-dist/react-ink/components/StatusLine.js +39 -0
- package/local-dist/react-ink/components/StatusLine.js.map +1 -0
- package/local-dist/react-ink/components/TaskPanel.d.ts +12 -0
- package/local-dist/react-ink/components/TaskPanel.d.ts.map +1 -0
- package/local-dist/react-ink/components/TaskPanel.js +23 -0
- package/local-dist/react-ink/components/TaskPanel.js.map +1 -0
- package/local-dist/react-ink/components/ToolEventBlock.d.ts +18 -0
- package/local-dist/react-ink/components/ToolEventBlock.d.ts.map +1 -0
- package/local-dist/react-ink/components/ToolEventBlock.js +61 -0
- package/local-dist/react-ink/components/ToolEventBlock.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/DialogFrame.d.ts +9 -0
- package/local-dist/react-ink/components/dialogs/DialogFrame.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/DialogFrame.js +6 -0
- package/local-dist/react-ink/components/dialogs/DialogFrame.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/LoginDialog.d.ts +15 -0
- package/local-dist/react-ink/components/dialogs/LoginDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/LoginDialog.js +10 -0
- package/local-dist/react-ink/components/dialogs/LoginDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/ModelDialog.d.ts +10 -0
- package/local-dist/react-ink/components/dialogs/ModelDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/ModelDialog.js +64 -0
- package/local-dist/react-ink/components/dialogs/ModelDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/OAuthDialog.d.ts +10 -0
- package/local-dist/react-ink/components/dialogs/OAuthDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/OAuthDialog.js +24 -0
- package/local-dist/react-ink/components/dialogs/OAuthDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/ScopedModelsDialog.d.ts +10 -0
- package/local-dist/react-ink/components/dialogs/ScopedModelsDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/ScopedModelsDialog.js +95 -0
- package/local-dist/react-ink/components/dialogs/ScopedModelsDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/SelectableDialog.d.ts +17 -0
- package/local-dist/react-ink/components/dialogs/SelectableDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/SelectableDialog.js +66 -0
- package/local-dist/react-ink/components/dialogs/SelectableDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/SessionDialog.d.ts +14 -0
- package/local-dist/react-ink/components/dialogs/SessionDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/SessionDialog.js +201 -0
- package/local-dist/react-ink/components/dialogs/SessionDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/SettingsDialog.d.ts +15 -0
- package/local-dist/react-ink/components/dialogs/SettingsDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/SettingsDialog.js +79 -0
- package/local-dist/react-ink/components/dialogs/SettingsDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/StartupSessionPicker.d.ts +10 -0
- package/local-dist/react-ink/components/dialogs/StartupSessionPicker.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/StartupSessionPicker.js +100 -0
- package/local-dist/react-ink/components/dialogs/StartupSessionPicker.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/ThemeDialog.d.ts +8 -0
- package/local-dist/react-ink/components/dialogs/ThemeDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/ThemeDialog.js +7 -0
- package/local-dist/react-ink/components/dialogs/ThemeDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/TreeDialog.d.ts +9 -0
- package/local-dist/react-ink/components/dialogs/TreeDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/TreeDialog.js +7 -0
- package/local-dist/react-ink/components/dialogs/TreeDialog.js.map +1 -0
- package/local-dist/react-ink/components/dialogs/UserMessageDialog.d.ts +9 -0
- package/local-dist/react-ink/components/dialogs/UserMessageDialog.d.ts.map +1 -0
- package/local-dist/react-ink/components/dialogs/UserMessageDialog.js +7 -0
- package/local-dist/react-ink/components/dialogs/UserMessageDialog.js.map +1 -0
- package/local-dist/react-ink/components/messages/AssistantMessage.d.ts +13 -0
- package/local-dist/react-ink/components/messages/AssistantMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/AssistantMessage.js +20 -0
- package/local-dist/react-ink/components/messages/AssistantMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/BashMessage.d.ts +9 -0
- package/local-dist/react-ink/components/messages/BashMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/BashMessage.js +11 -0
- package/local-dist/react-ink/components/messages/BashMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/BranchSummaryMessage.d.ts +9 -0
- package/local-dist/react-ink/components/messages/BranchSummaryMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/BranchSummaryMessage.js +6 -0
- package/local-dist/react-ink/components/messages/BranchSummaryMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/CompactionMessage.d.ts +9 -0
- package/local-dist/react-ink/components/messages/CompactionMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/CompactionMessage.js +6 -0
- package/local-dist/react-ink/components/messages/CompactionMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/CustomMessage.d.ts +10 -0
- package/local-dist/react-ink/components/messages/CustomMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/CustomMessage.js +9 -0
- package/local-dist/react-ink/components/messages/CustomMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/SkillInvocationMessage.d.ts +8 -0
- package/local-dist/react-ink/components/messages/SkillInvocationMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/SkillInvocationMessage.js +10 -0
- package/local-dist/react-ink/components/messages/SkillInvocationMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/ToolCallMessage.d.ts +9 -0
- package/local-dist/react-ink/components/messages/ToolCallMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/ToolCallMessage.js +8 -0
- package/local-dist/react-ink/components/messages/ToolCallMessage.js.map +1 -0
- package/local-dist/react-ink/components/messages/ToolResultBlock.d.ts +13 -0
- package/local-dist/react-ink/components/messages/ToolResultBlock.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/ToolResultBlock.js +8 -0
- package/local-dist/react-ink/components/messages/ToolResultBlock.js.map +1 -0
- package/local-dist/react-ink/components/messages/UserMessage.d.ts +10 -0
- package/local-dist/react-ink/components/messages/UserMessage.d.ts.map +1 -0
- package/local-dist/react-ink/components/messages/UserMessage.js +9 -0
- package/local-dist/react-ink/components/messages/UserMessage.js.map +1 -0
- package/local-dist/react-ink/index.d.ts +35 -0
- package/local-dist/react-ink/index.d.ts.map +1 -0
- package/local-dist/react-ink/index.js +35 -0
- package/local-dist/react-ink/index.js.map +1 -0
- package/local-dist/react-ink/theme-adapter.d.ts +10 -0
- package/local-dist/react-ink/theme-adapter.d.ts.map +1 -0
- package/local-dist/react-ink/theme-adapter.js +44 -0
- package/local-dist/react-ink/theme-adapter.js.map +1 -0
- package/local-dist/react-ink/types.d.ts +134 -0
- package/local-dist/react-ink/types.d.ts.map +1 -0
- package/local-dist/react-ink/types.js +2 -0
- package/local-dist/react-ink/types.js.map +1 -0
- package/local-dist/react-ink/utils/message-groups.d.ts +26 -0
- package/local-dist/react-ink/utils/message-groups.d.ts.map +1 -0
- package/local-dist/react-ink/utils/message-groups.js +240 -0
- package/local-dist/react-ink/utils/message-groups.js.map +1 -0
- package/local-dist/react-ink/utils/selection-dialog.d.ts +3 -0
- package/local-dist/react-ink/utils/selection-dialog.d.ts.map +1 -0
- package/local-dist/react-ink/utils/selection-dialog.js +18 -0
- package/local-dist/react-ink/utils/selection-dialog.js.map +1 -0
- package/local-dist/react-ink/utils/session-browser.d.ts +28 -0
- package/local-dist/react-ink/utils/session-browser.d.ts.map +1 -0
- package/local-dist/react-ink/utils/session-browser.js +191 -0
- package/local-dist/react-ink/utils/session-browser.js.map +1 -0
- package/local-dist/react-ink/utils/tool-display.d.ts +22 -0
- package/local-dist/react-ink/utils/tool-display.d.ts.map +1 -0
- package/local-dist/react-ink/utils/tool-display.js +349 -0
- package/local-dist/react-ink/utils/tool-display.js.map +1 -0
- package/local-dist/react-ink.d.ts +3 -0
- package/local-dist/react-ink.d.ts.map +1 -0
- package/local-dist/react-ink.js +2 -0
- package/local-dist/react-ink.js.map +1 -0
- package/local-dist/tui.d.ts +9 -0
- package/local-dist/tui.d.ts.map +1 -0
- package/local-dist/tui.js +8 -0
- package/local-dist/tui.js.map +1 -0
- package/local-dist/ui/contracts.d.ts +39 -0
- package/local-dist/ui/contracts.d.ts.map +1 -0
- package/local-dist/ui/contracts.js +2 -0
- package/local-dist/ui/contracts.js.map +1 -0
- package/{dist → local-dist}/ui/editor-component.d.ts +1 -1
- package/local-dist/ui/editor-component.d.ts.map +1 -0
- package/local-dist/ui/index.d.ts +9 -0
- package/local-dist/ui/index.d.ts.map +1 -0
- package/local-dist/ui/index.js +6 -0
- package/local-dist/ui/index.js.map +1 -0
- package/local-dist/ui/theme-types.d.ts +37 -0
- package/local-dist/ui/theme-types.d.ts.map +1 -0
- package/local-dist/ui/theme-types.js +2 -0
- package/local-dist/ui/theme-types.js.map +1 -0
- package/package.json +39 -17
- package/dist/bot/actions/crew/worktree.js.map +0 -1
- package/dist/bot/actions/index.d.ts.map +0 -1
- package/dist/bot/actions/index.js.map +0 -1
- package/dist/tui.d.ts +0 -6
- package/dist/tui.d.ts.map +0 -1
- package/dist/tui.js +0 -6
- package/dist/tui.js.map +0 -1
- package/dist/ui/editor-component.d.ts.map +0 -1
- package/dist/ui/index.d.ts +0 -23
- package/dist/ui/index.d.ts.map +0 -1
- package/dist/ui/index.js +0 -32
- package/dist/ui/index.js.map +0 -1
- package/dist/ui/parts/box.d.ts +0 -19
- package/dist/ui/parts/box.d.ts.map +0 -1
- package/dist/ui/parts/box.js +0 -134
- package/dist/ui/parts/box.js.map +0 -1
- package/dist/ui/parts/cancellable-loader.d.ts +0 -26
- package/dist/ui/parts/cancellable-loader.d.ts.map +0 -1
- package/dist/ui/parts/cancellable-loader.js +0 -39
- package/dist/ui/parts/cancellable-loader.js.map +0 -1
- package/dist/ui/parts/editor.d.ts +0 -189
- package/dist/ui/parts/editor.d.ts.map +0 -1
- package/dist/ui/parts/editor.js +0 -1546
- package/dist/ui/parts/editor.js.map +0 -1
- package/dist/ui/parts/image.d.ts +0 -30
- package/dist/ui/parts/image.d.ts.map +0 -1
- package/dist/ui/parts/image.js +0 -105
- package/dist/ui/parts/image.js.map +0 -1
- package/dist/ui/parts/input.d.ts +0 -21
- package/dist/ui/parts/input.d.ts.map +0 -1
- package/dist/ui/parts/input.js +0 -305
- package/dist/ui/parts/input.js.map +0 -1
- package/dist/ui/parts/loader.d.ts +0 -23
- package/dist/ui/parts/loader.d.ts.map +0 -1
- package/dist/ui/parts/loader.js +0 -57
- package/dist/ui/parts/loader.js.map +0 -1
- package/dist/ui/parts/markdown.d.ts +0 -59
- package/dist/ui/parts/markdown.d.ts.map +0 -1
- package/dist/ui/parts/markdown.js +0 -511
- package/dist/ui/parts/markdown.js.map +0 -1
- package/dist/ui/parts/select-list.d.ts +0 -33
- package/dist/ui/parts/select-list.d.ts.map +0 -1
- package/dist/ui/parts/select-list.js +0 -157
- package/dist/ui/parts/select-list.js.map +0 -1
- package/dist/ui/parts/settings-list.d.ts +0 -50
- package/dist/ui/parts/settings-list.d.ts.map +0 -1
- package/dist/ui/parts/settings-list.js +0 -196
- package/dist/ui/parts/settings-list.js.map +0 -1
- package/dist/ui/parts/spacer.d.ts +0 -13
- package/dist/ui/parts/spacer.d.ts.map +0 -1
- package/dist/ui/parts/spacer.js +0 -42
- package/dist/ui/parts/spacer.js.map +0 -1
- package/dist/ui/parts/text-renderer.d.ts +0 -7
- package/dist/ui/parts/text-renderer.d.ts.map +0 -1
- package/dist/ui/parts/text-renderer.js +0 -25
- package/dist/ui/parts/text-renderer.js.map +0 -1
- package/dist/ui/parts/text.d.ts +0 -17
- package/dist/ui/parts/text.d.ts.map +0 -1
- package/dist/ui/parts/text.js +0 -89
- package/dist/ui/parts/text.js.map +0 -1
- package/dist/ui/parts/truncated-text.d.ts +0 -17
- package/dist/ui/parts/truncated-text.d.ts.map +0 -1
- package/dist/ui/parts/truncated-text.js +0 -54
- package/dist/ui/parts/truncated-text.js.map +0 -1
- package/dist/ui/stdin-buffer.d.ts +0 -53
- package/dist/ui/stdin-buffer.d.ts.map +0 -1
- package/dist/ui/stdin-buffer.js +0 -332
- package/dist/ui/stdin-buffer.js.map +0 -1
- package/dist/ui/terminal-image.d.ts +0 -72
- package/dist/ui/terminal-image.d.ts.map +0 -1
- package/dist/ui/terminal-image.js +0 -291
- package/dist/ui/terminal-image.js.map +0 -1
- package/dist/ui/terminal.d.ts +0 -55
- package/dist/ui/terminal.d.ts.map +0 -1
- package/dist/ui/terminal.js +0 -210
- package/dist/ui/terminal.js.map +0 -1
- package/dist/ui/tui.d.ts +0 -250
- package/dist/ui/tui.d.ts.map +0 -1
- package/dist/ui/tui.js +0 -937
- package/dist/ui/tui.js.map +0 -1
- /package/{dist → local-dist}/agent.d.ts +0 -0
- /package/{dist → local-dist}/agent.d.ts.map +0 -0
- /package/{dist → local-dist}/agent.js +0 -0
- /package/{dist → local-dist}/agent.js.map +0 -0
- /package/{dist → local-dist}/ai.d.ts +0 -0
- /package/{dist → local-dist}/ai.d.ts.map +0 -0
- /package/{dist → local-dist}/ai.js +0 -0
- /package/{dist → local-dist}/ai.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/bash.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/bash.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/bash.js +0 -0
- /package/{dist → local-dist}/bot/actions/bash.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/activity-tracker.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/activity-tracker.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/cleanup.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/cleanup.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/cleanup.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/cleanup.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/fs-lock.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/fs-lock.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/fs-lock.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/fs-lock.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/index.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/index.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/index.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/index.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/mailbox.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/mailbox.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/mailbox.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/mailbox.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/model-policy.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/model-policy.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/model-policy.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/model-policy.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/names.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/names.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/names.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/names.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/protocol.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/protocol.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/protocol.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/protocol.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/task-store.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/task-store.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/task-store.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/task-store.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-attach-claim.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-attach-claim.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-attach-claim.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-attach-claim.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-config.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-config.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-config.js +0 -0
- /package/{dist → local-dist}/bot/actions/crew/team-config.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/crew/worktree.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/crew/worktree.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/edit-diff.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/edit-diff.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/edit-diff.js +0 -0
- /package/{dist → local-dist}/bot/actions/edit-diff.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/edit.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/edit.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/edit.js +0 -0
- /package/{dist → local-dist}/bot/actions/edit.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/find.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/find.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/find.js +0 -0
- /package/{dist → local-dist}/bot/actions/find.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/grep.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/grep.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/grep.js +0 -0
- /package/{dist → local-dist}/bot/actions/grep.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/hook-runner.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/kit/hook-runner.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/hook-runner.js +0 -0
- /package/{dist → local-dist}/bot/actions/kit/hook-runner.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/image-resize.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/kit/image-resize.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/image-resize.js +0 -0
- /package/{dist → local-dist}/bot/actions/kit/image-resize.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/mime.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/kit/mime.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/mime.js +0 -0
- /package/{dist → local-dist}/bot/actions/kit/mime.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/shell.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/kit/shell.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/kit/shell.js +0 -0
- /package/{dist → local-dist}/bot/actions/kit/shell.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/ls.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/ls.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/ls.js +0 -0
- /package/{dist → local-dist}/bot/actions/ls.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/path-utils.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/path-utils.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/path-utils.js +0 -0
- /package/{dist → local-dist}/bot/actions/path-utils.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/process-controller.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/process-controller.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/process-controller.js +0 -0
- /package/{dist → local-dist}/bot/actions/process-controller.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/process-manager.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/process-manager.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/process-types.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/process-types.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/process-types.js +0 -0
- /package/{dist → local-dist}/bot/actions/process-types.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/process.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/process.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/process.js +0 -0
- /package/{dist → local-dist}/bot/actions/process.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/read.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/read.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/read.js +0 -0
- /package/{dist → local-dist}/bot/actions/read.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/registry.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/registry.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/registry.js +0 -0
- /package/{dist → local-dist}/bot/actions/registry.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo-store.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/todo-store.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo-store.js +0 -0
- /package/{dist → local-dist}/bot/actions/todo-store.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo-types.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/todo-types.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo-types.js +0 -0
- /package/{dist → local-dist}/bot/actions/todo-types.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/todo.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/todo.js +0 -0
- /package/{dist → local-dist}/bot/actions/todo.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/truncate.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/truncate.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/truncate.js +0 -0
- /package/{dist → local-dist}/bot/actions/truncate.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/webfetch.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/webfetch.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/webfetch.js +0 -0
- /package/{dist → local-dist}/bot/actions/webfetch.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/websearch.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/websearch.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/websearch.js +0 -0
- /package/{dist → local-dist}/bot/actions/websearch.js.map +0 -0
- /package/{dist → local-dist}/bot/actions/write.d.ts +0 -0
- /package/{dist → local-dist}/bot/actions/write.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/actions/write.js +0 -0
- /package/{dist → local-dist}/bot/actions/write.js.map +0 -0
- /package/{dist → local-dist}/bot/agent-loop.d.ts +0 -0
- /package/{dist → local-dist}/bot/agent-loop.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/agent-loop.js +0 -0
- /package/{dist → local-dist}/bot/agent-loop.js.map +0 -0
- /package/{dist → local-dist}/bot/agent.d.ts +0 -0
- /package/{dist → local-dist}/bot/agent.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/agent.js +0 -0
- /package/{dist → local-dist}/bot/agent.js.map +0 -0
- /package/{dist → local-dist}/bot/error-handler.d.ts +0 -0
- /package/{dist → local-dist}/bot/error-handler.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/error-handler.js +0 -0
- /package/{dist → local-dist}/bot/error-handler.js.map +0 -0
- /package/{dist → local-dist}/bot/event-bus.d.ts +0 -0
- /package/{dist → local-dist}/bot/event-bus.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/event-bus.js +0 -0
- /package/{dist → local-dist}/bot/event-bus.js.map +0 -0
- /package/{dist → local-dist}/bot/index.d.ts +0 -0
- /package/{dist → local-dist}/bot/index.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/index.js +0 -0
- /package/{dist → local-dist}/bot/index.js.map +0 -0
- /package/{dist → local-dist}/bot/messages.d.ts +0 -0
- /package/{dist → local-dist}/bot/messages.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/messages.js +0 -0
- /package/{dist → local-dist}/bot/messages.js.map +0 -0
- /package/{dist → local-dist}/bot/proxy.d.ts +0 -0
- /package/{dist → local-dist}/bot/proxy.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/proxy.js +0 -0
- /package/{dist → local-dist}/bot/proxy.js.map +0 -0
- /package/{dist → local-dist}/bot/session-manager.d.ts +0 -0
- /package/{dist → local-dist}/bot/session-manager.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/session-manager.js +0 -0
- /package/{dist → local-dist}/bot/session-manager.js.map +0 -0
- /package/{dist → local-dist}/bot/state-manager.d.ts +0 -0
- /package/{dist → local-dist}/bot/state-manager.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/state-manager.js +0 -0
- /package/{dist → local-dist}/bot/state-manager.js.map +0 -0
- /package/{dist → local-dist}/bot/telemetry.d.ts +0 -0
- /package/{dist → local-dist}/bot/telemetry.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/telemetry.js +0 -0
- /package/{dist → local-dist}/bot/telemetry.js.map +0 -0
- /package/{dist → local-dist}/bot/types.d.ts +0 -0
- /package/{dist → local-dist}/bot/types.d.ts.map +0 -0
- /package/{dist → local-dist}/bot/types.js +0 -0
- /package/{dist → local-dist}/bot/types.js.map +0 -0
- /package/{dist → local-dist}/cli.d.ts +0 -0
- /package/{dist → local-dist}/cli.d.ts.map +0 -0
- /package/{dist → local-dist}/cli.js +0 -0
- /package/{dist → local-dist}/cli.js.map +0 -0
- /package/{dist → local-dist}/mcp/client-pool.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/client-pool.js.map +0 -0
- /package/{dist → local-dist}/mcp/client.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/client.js.map +0 -0
- /package/{dist → local-dist}/mcp/config.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/config.js.map +0 -0
- /package/{dist → local-dist}/mcp/errors.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/errors.js.map +0 -0
- /package/{dist → local-dist}/mcp/index.d.ts +0 -0
- /package/{dist → local-dist}/mcp/index.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/index.js +0 -0
- /package/{dist → local-dist}/mcp/index.js.map +0 -0
- /package/{dist → local-dist}/mcp/schema-converter.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/schema-converter.js.map +0 -0
- /package/{dist → local-dist}/mcp/server.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/server.js.map +0 -0
- /package/{dist → local-dist}/mcp/tool-factory.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/tool-factory.js.map +0 -0
- /package/{dist → local-dist}/mcp/types.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp/types.js.map +0 -0
- /package/{dist → local-dist}/mcp.d.ts +0 -0
- /package/{dist → local-dist}/mcp.d.ts.map +0 -0
- /package/{dist → local-dist}/mcp.js +0 -0
- /package/{dist → local-dist}/mcp.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/amazon-bedrock.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/amazon-bedrock.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/amazon-bedrock.js +0 -0
- /package/{dist → local-dist}/ml/adapters/amazon-bedrock.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/anthropic.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/anthropic.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/anthropic.js +0 -0
- /package/{dist → local-dist}/ml/adapters/anthropic.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/azure-openai-responses.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/azure-openai-responses.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/azure-openai-responses.js +0 -0
- /package/{dist → local-dist}/ml/adapters/azure-openai-responses.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google-shared.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/google-shared.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google-shared.js +0 -0
- /package/{dist → local-dist}/ml/adapters/google-shared.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google-vertex.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/google-vertex.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google-vertex.js +0 -0
- /package/{dist → local-dist}/ml/adapters/google-vertex.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/google.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/google.js +0 -0
- /package/{dist → local-dist}/ml/adapters/google.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/kimi.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/kimi.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/kimi.js +0 -0
- /package/{dist → local-dist}/ml/adapters/kimi.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/mock.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/mock.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/mock.js +0 -0
- /package/{dist → local-dist}/ml/adapters/mock.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-codex-responses.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-codex-responses.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-completions.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-completions.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-completions.js +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-completions.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses-shared.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses-shared.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses-shared.js +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses-shared.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses.js +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-responses.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-scaffold.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-scaffold.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-scaffold.js +0 -0
- /package/{dist → local-dist}/ml/adapters/openai-scaffold.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/register-builtins.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/register-builtins.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/register-builtins.js +0 -0
- /package/{dist → local-dist}/ml/adapters/register-builtins.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/simple-options.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/simple-options.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/simple-options.js +0 -0
- /package/{dist → local-dist}/ml/adapters/simple-options.js.map +0 -0
- /package/{dist → local-dist}/ml/adapters/transform-messages.d.ts +0 -0
- /package/{dist → local-dist}/ml/adapters/transform-messages.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/adapters/transform-messages.js +0 -0
- /package/{dist → local-dist}/ml/adapters/transform-messages.js.map +0 -0
- /package/{dist → local-dist}/ml/api-registry.d.ts +0 -0
- /package/{dist → local-dist}/ml/api-registry.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/api-registry.js +0 -0
- /package/{dist → local-dist}/ml/api-registry.js.map +0 -0
- /package/{dist → local-dist}/ml/cli.d.ts +0 -0
- /package/{dist → local-dist}/ml/cli.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/cli.js +0 -0
- /package/{dist → local-dist}/ml/cli.js.map +0 -0
- /package/{dist → local-dist}/ml/env-api-keys.d.ts +0 -0
- /package/{dist → local-dist}/ml/env-api-keys.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/env-api-keys.js +0 -0
- /package/{dist → local-dist}/ml/env-api-keys.js.map +0 -0
- /package/{dist → local-dist}/ml/index.d.ts +0 -0
- /package/{dist → local-dist}/ml/index.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/index.js +0 -0
- /package/{dist → local-dist}/ml/index.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/anthropic.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/anthropic.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/anthropic.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/anthropic.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/github-copilot.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/github-copilot.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/github-copilot.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/github-copilot.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/index.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/index.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/index.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/index.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/kimi.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/kimi.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/kimi.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/kimi.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/openai-codex.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/pkce.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/pkce.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/pkce.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/pkce.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/types.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/auth/types.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/auth/types.js +0 -0
- /package/{dist → local-dist}/ml/kit/auth/types.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/base-stream-handler.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/base-stream-handler.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/base-stream-handler.js +0 -0
- /package/{dist → local-dist}/ml/kit/base-stream-handler.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/event-stream.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/event-stream.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/event-stream.js +0 -0
- /package/{dist → local-dist}/ml/kit/event-stream.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/index.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/index.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/index.js +0 -0
- /package/{dist → local-dist}/ml/kit/index.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/json-parse.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/json-parse.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/json-parse.js +0 -0
- /package/{dist → local-dist}/ml/kit/json-parse.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/message-transform.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/message-transform.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/message-transform.js +0 -0
- /package/{dist → local-dist}/ml/kit/message-transform.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/output-factory.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/output-factory.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/output-factory.js +0 -0
- /package/{dist → local-dist}/ml/kit/output-factory.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/overflow.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/overflow.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/overflow.js +0 -0
- /package/{dist → local-dist}/ml/kit/overflow.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-adapter.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/provider-adapter.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-adapter.js +0 -0
- /package/{dist → local-dist}/ml/kit/provider-adapter.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-client-builder.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/provider-client-builder.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-client-builder.js +0 -0
- /package/{dist → local-dist}/ml/kit/provider-client-builder.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-consolidation.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/provider-consolidation.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-consolidation.js +0 -0
- /package/{dist → local-dist}/ml/kit/provider-consolidation.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-constants.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/provider-constants.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-constants.js +0 -0
- /package/{dist → local-dist}/ml/kit/provider-constants.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-errors.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/provider-errors.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/provider-errors.js +0 -0
- /package/{dist → local-dist}/ml/kit/provider-errors.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/sanitize-unicode.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/sanitize-unicode.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/sanitize-unicode.js +0 -0
- /package/{dist → local-dist}/ml/kit/sanitize-unicode.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/stream-event-helper.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/stream-event-helper.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/stream-event-helper.js +0 -0
- /package/{dist → local-dist}/ml/kit/stream-event-helper.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/stream-handler-types.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/stream-handler-types.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/stream-handler-types.js +0 -0
- /package/{dist → local-dist}/ml/kit/stream-handler-types.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/streaming-state-manager.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/streaming-state-manager.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/streaming-state-manager.js +0 -0
- /package/{dist → local-dist}/ml/kit/streaming-state-manager.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/tool-converter.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/tool-converter.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/tool-converter.js +0 -0
- /package/{dist → local-dist}/ml/kit/tool-converter.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/typebox-helpers.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/typebox-helpers.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/typebox-helpers.js +0 -0
- /package/{dist → local-dist}/ml/kit/typebox-helpers.js.map +0 -0
- /package/{dist → local-dist}/ml/kit/validation.d.ts +0 -0
- /package/{dist → local-dist}/ml/kit/validation.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/kit/validation.js +0 -0
- /package/{dist → local-dist}/ml/kit/validation.js.map +0 -0
- /package/{dist → local-dist}/ml/models.d.ts +0 -0
- /package/{dist → local-dist}/ml/models.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/models.generated.d.ts +0 -0
- /package/{dist → local-dist}/ml/models.generated.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/models.generated.js +0 -0
- /package/{dist → local-dist}/ml/models.generated.js.map +0 -0
- /package/{dist → local-dist}/ml/models.js +0 -0
- /package/{dist → local-dist}/ml/models.js.map +0 -0
- /package/{dist → local-dist}/ml/stream.d.ts +0 -0
- /package/{dist → local-dist}/ml/stream.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/stream.js +0 -0
- /package/{dist → local-dist}/ml/stream.js.map +0 -0
- /package/{dist → local-dist}/ml/types.d.ts +0 -0
- /package/{dist → local-dist}/ml/types.d.ts.map +0 -0
- /package/{dist → local-dist}/ml/types.js +0 -0
- /package/{dist → local-dist}/ml/types.js.map +0 -0
- /package/{dist → local-dist}/observability.d.ts +0 -0
- /package/{dist → local-dist}/observability.d.ts.map +0 -0
- /package/{dist → local-dist}/observability.js +0 -0
- /package/{dist → local-dist}/observability.js.map +0 -0
- /package/{dist → local-dist}/ui/autocomplete.d.ts +0 -0
- /package/{dist → local-dist}/ui/autocomplete.d.ts.map +0 -0
- /package/{dist → local-dist}/ui/autocomplete.js +0 -0
- /package/{dist → local-dist}/ui/autocomplete.js.map +0 -0
- /package/{dist → local-dist}/ui/editor-component.js +0 -0
- /package/{dist → local-dist}/ui/editor-component.js.map +0 -0
- /package/{dist → local-dist}/ui/fuzzy.d.ts +0 -0
- /package/{dist → local-dist}/ui/fuzzy.d.ts.map +0 -0
- /package/{dist → local-dist}/ui/fuzzy.js +0 -0
- /package/{dist → local-dist}/ui/fuzzy.js.map +0 -0
- /package/{dist → local-dist}/ui/keybindings.d.ts +0 -0
- /package/{dist → local-dist}/ui/keybindings.d.ts.map +0 -0
- /package/{dist → local-dist}/ui/keybindings.js +0 -0
- /package/{dist → local-dist}/ui/keybindings.js.map +0 -0
- /package/{dist → local-dist}/ui/keys.d.ts +0 -0
- /package/{dist → local-dist}/ui/keys.d.ts.map +0 -0
- /package/{dist → local-dist}/ui/keys.js +0 -0
- /package/{dist → local-dist}/ui/keys.js.map +0 -0
- /package/{dist → local-dist}/ui/utils.d.ts +0 -0
- /package/{dist → local-dist}/ui/utils.d.ts.map +0 -0
- /package/{dist → local-dist}/ui/utils.js +0 -0
- /package/{dist → local-dist}/ui/utils.js.map +0 -0
package/dist/ui/parts/editor.js
DELETED
|
@@ -1,1546 +0,0 @@
|
|
|
1
|
-
import { getEditorKeybindings } from "../keybindings.js";
|
|
2
|
-
import { matchesKey } from "../keys.js";
|
|
3
|
-
import { ComponentBase, CURSOR_MARKER } from "../tui.js";
|
|
4
|
-
import { getSegmenter, isPunctuationChar, isWhitespaceChar, visibleWidth } from "../utils.js";
|
|
5
|
-
import { SelectList } from "./select-list.js";
|
|
6
|
-
const segmenter = getSegmenter();
|
|
7
|
-
/**
|
|
8
|
-
* Split a line into word-wrapped chunks.
|
|
9
|
-
* Wraps at word boundaries when possible, falling back to character-level
|
|
10
|
-
* wrapping for words longer than the available width.
|
|
11
|
-
*
|
|
12
|
-
* @param line - The text line to wrap
|
|
13
|
-
* @param maxWidth - Maximum visible width per chunk
|
|
14
|
-
* @returns Array of chunks with text and position information
|
|
15
|
-
*/
|
|
16
|
-
export function wordWrapLine(line, maxWidth) {
|
|
17
|
-
if (!line || maxWidth <= 0) {
|
|
18
|
-
return [{ text: "", startIndex: 0, endIndex: 0 }];
|
|
19
|
-
}
|
|
20
|
-
const lineWidth = visibleWidth(line);
|
|
21
|
-
if (lineWidth <= maxWidth) {
|
|
22
|
-
return [{ text: line, startIndex: 0, endIndex: line.length }];
|
|
23
|
-
}
|
|
24
|
-
const chunks = [];
|
|
25
|
-
const segments = [...segmenter.segment(line)];
|
|
26
|
-
let currentWidth = 0;
|
|
27
|
-
let chunkStart = 0;
|
|
28
|
-
// Wrap opportunity: the position after the last whitespace before a non-whitespace
|
|
29
|
-
// grapheme, i.e. where a line break is allowed.
|
|
30
|
-
let wrapOppIndex = -1;
|
|
31
|
-
let wrapOppWidth = 0;
|
|
32
|
-
for (let i = 0; i < segments.length; i++) {
|
|
33
|
-
const seg = segments[i];
|
|
34
|
-
const grapheme = seg.segment;
|
|
35
|
-
const gWidth = visibleWidth(grapheme);
|
|
36
|
-
const charIndex = seg.index;
|
|
37
|
-
const isWs = isWhitespaceChar(grapheme);
|
|
38
|
-
// Overflow check before advancing.
|
|
39
|
-
if (currentWidth + gWidth > maxWidth) {
|
|
40
|
-
if (wrapOppIndex >= 0) {
|
|
41
|
-
// Backtrack to last wrap opportunity.
|
|
42
|
-
chunks.push({ text: line.slice(chunkStart, wrapOppIndex), startIndex: chunkStart, endIndex: wrapOppIndex });
|
|
43
|
-
chunkStart = wrapOppIndex;
|
|
44
|
-
currentWidth -= wrapOppWidth;
|
|
45
|
-
}
|
|
46
|
-
else if (chunkStart < charIndex) {
|
|
47
|
-
// No wrap opportunity: force-break at current position.
|
|
48
|
-
chunks.push({ text: line.slice(chunkStart, charIndex), startIndex: chunkStart, endIndex: charIndex });
|
|
49
|
-
chunkStart = charIndex;
|
|
50
|
-
currentWidth = 0;
|
|
51
|
-
}
|
|
52
|
-
wrapOppIndex = -1;
|
|
53
|
-
}
|
|
54
|
-
// Advance.
|
|
55
|
-
currentWidth += gWidth;
|
|
56
|
-
// Record wrap opportunity: whitespace followed by non-whitespace.
|
|
57
|
-
// Multiple spaces join (no break between them); the break point is
|
|
58
|
-
// after the last space before the next word.
|
|
59
|
-
const next = segments[i + 1];
|
|
60
|
-
if (isWs && next && !isWhitespaceChar(next.segment)) {
|
|
61
|
-
wrapOppIndex = next.index;
|
|
62
|
-
wrapOppWidth = currentWidth;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Push final chunk.
|
|
66
|
-
chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });
|
|
67
|
-
return chunks;
|
|
68
|
-
}
|
|
69
|
-
// Kitty CSI-u sequences for printable keys, including optional shifted/base codepoints.
|
|
70
|
-
const KITTY_CSI_U_REGEX = /^\x1b\[(\d+)(?::(\d*))?(?::(\d+))?(?:;(\d+))?(?::(\d+))?u$/;
|
|
71
|
-
const KITTY_MOD_SHIFT = 1;
|
|
72
|
-
const KITTY_MOD_ALT = 2;
|
|
73
|
-
const KITTY_MOD_CTRL = 4;
|
|
74
|
-
// Decode a printable CSI-u sequence, preferring the shifted key when present.
|
|
75
|
-
function decodeKittyPrintable(data) {
|
|
76
|
-
const match = data.match(KITTY_CSI_U_REGEX);
|
|
77
|
-
if (!match)
|
|
78
|
-
return undefined;
|
|
79
|
-
// CSI-u groups: <codepoint>[:<shifted>[:<base>]];<mod>u
|
|
80
|
-
const codepoint = Number.parseInt(match[1] ?? "", 10);
|
|
81
|
-
if (!Number.isFinite(codepoint))
|
|
82
|
-
return undefined;
|
|
83
|
-
const shiftedKey = match[2] && match[2].length > 0 ? Number.parseInt(match[2], 10) : undefined;
|
|
84
|
-
const modValue = match[4] ? Number.parseInt(match[4], 10) : 1;
|
|
85
|
-
// Modifiers are 1-indexed in CSI-u; normalize to our bitmask.
|
|
86
|
-
const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;
|
|
87
|
-
// Ignore CSI-u sequences used for Alt/Ctrl shortcuts.
|
|
88
|
-
if (modifier & (KITTY_MOD_ALT | KITTY_MOD_CTRL))
|
|
89
|
-
return undefined;
|
|
90
|
-
// Prefer the shifted keycode when Shift is held.
|
|
91
|
-
let effectiveCodepoint = codepoint;
|
|
92
|
-
if (modifier & KITTY_MOD_SHIFT && typeof shiftedKey === "number") {
|
|
93
|
-
effectiveCodepoint = shiftedKey;
|
|
94
|
-
}
|
|
95
|
-
// Drop control characters or invalid codepoints.
|
|
96
|
-
if (!Number.isFinite(effectiveCodepoint) || effectiveCodepoint < 32)
|
|
97
|
-
return undefined;
|
|
98
|
-
try {
|
|
99
|
-
return String.fromCodePoint(effectiveCodepoint);
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
class EditorLayoutProjector {
|
|
106
|
-
static buildVisualLineMap(lines, width) {
|
|
107
|
-
const visualLines = [];
|
|
108
|
-
for (let logicalIndex = 0; logicalIndex < lines.length; logicalIndex++) {
|
|
109
|
-
const line = lines[logicalIndex] || "";
|
|
110
|
-
if (line.length === 0) {
|
|
111
|
-
visualLines.push({ logicalLine: logicalIndex, startCol: 0, length: 0 });
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (visibleWidth(line) <= width) {
|
|
115
|
-
visualLines.push({ logicalLine: logicalIndex, startCol: 0, length: line.length });
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
for (const chunk of wordWrapLine(line, width)) {
|
|
119
|
-
visualLines.push({
|
|
120
|
-
logicalLine: logicalIndex,
|
|
121
|
-
startCol: chunk.startIndex,
|
|
122
|
-
length: chunk.endIndex - chunk.startIndex,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return visualLines;
|
|
127
|
-
}
|
|
128
|
-
static findCurrentVisualLine(visualLines, cursorLine, cursorCol) {
|
|
129
|
-
for (let visualIndex = 0; visualIndex < visualLines.length; visualIndex++) {
|
|
130
|
-
const segment = visualLines[visualIndex];
|
|
131
|
-
if (!segment || segment.logicalLine !== cursorLine)
|
|
132
|
-
continue;
|
|
133
|
-
const offset = cursorCol - segment.startCol;
|
|
134
|
-
const lastSegment = visualIndex === visualLines.length - 1 || visualLines[visualIndex + 1]?.logicalLine !== segment.logicalLine;
|
|
135
|
-
if (offset >= 0 && (offset < segment.length || (lastSegment && offset <= segment.length))) {
|
|
136
|
-
return visualIndex;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return visualLines.length - 1;
|
|
140
|
-
}
|
|
141
|
-
static resolveCursorAtVisualLine(visualLines, visualIndex, visualCol, lines) {
|
|
142
|
-
const segment = visualLines[visualIndex];
|
|
143
|
-
if (!segment)
|
|
144
|
-
return null;
|
|
145
|
-
const line = segment.logicalLine;
|
|
146
|
-
const targetCol = segment.startCol + Math.min(visualCol, segment.length);
|
|
147
|
-
return { line, col: Math.min(targetCol, (lines[line] || "").length) };
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
export class Editor extends ComponentBase {
|
|
151
|
-
state = {
|
|
152
|
-
lines: [""],
|
|
153
|
-
cursorLine: 0,
|
|
154
|
-
cursorCol: 0,
|
|
155
|
-
};
|
|
156
|
-
/** Focusable interface - set by TUI when focus changes */
|
|
157
|
-
focused = false;
|
|
158
|
-
tui;
|
|
159
|
-
theme;
|
|
160
|
-
paddingX = 0;
|
|
161
|
-
// Store last render width for cursor navigation
|
|
162
|
-
lastWidth = 80;
|
|
163
|
-
// Vertical scrolling support
|
|
164
|
-
scrollOffset = 0;
|
|
165
|
-
// Border color (can be changed dynamically)
|
|
166
|
-
borderColor;
|
|
167
|
-
// Autocomplete support
|
|
168
|
-
autocompleteProvider;
|
|
169
|
-
autocompleteList;
|
|
170
|
-
isAutocompleting = false;
|
|
171
|
-
autocompletePrefix = "";
|
|
172
|
-
// Paste tracking for large pastes
|
|
173
|
-
pastes = new Map();
|
|
174
|
-
pasteCounter = 0;
|
|
175
|
-
// Bracketed paste mode buffering
|
|
176
|
-
pasteBuffer = "";
|
|
177
|
-
isInPaste = false;
|
|
178
|
-
pendingShiftEnter = false;
|
|
179
|
-
// Prompt history for up/down navigation
|
|
180
|
-
history = [];
|
|
181
|
-
historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.
|
|
182
|
-
// Kill ring for Emacs-style kill/yank operations
|
|
183
|
-
// Also tracks undo coalescing: "type-word" means we're mid-word (coalescing)
|
|
184
|
-
killRing = [];
|
|
185
|
-
lastAction = null;
|
|
186
|
-
// Undo support
|
|
187
|
-
undoStack = [];
|
|
188
|
-
onSubmit;
|
|
189
|
-
onChange;
|
|
190
|
-
disableSubmit = false;
|
|
191
|
-
constructor(tui, theme, options = {}) {
|
|
192
|
-
super();
|
|
193
|
-
this.tui = tui;
|
|
194
|
-
this.theme = theme;
|
|
195
|
-
this.borderColor = theme.borderColor;
|
|
196
|
-
const paddingX = options.paddingX ?? 0;
|
|
197
|
-
this.paddingX = Number.isFinite(paddingX) ? Math.max(0, Math.floor(paddingX)) : 0;
|
|
198
|
-
}
|
|
199
|
-
getPaddingX() {
|
|
200
|
-
return this.paddingX;
|
|
201
|
-
}
|
|
202
|
-
setPaddingX(padding) {
|
|
203
|
-
const newPadding = Number.isFinite(padding) ? Math.max(0, Math.floor(padding)) : 0;
|
|
204
|
-
if (this.paddingX !== newPadding) {
|
|
205
|
-
this.paddingX = newPadding;
|
|
206
|
-
this.tui.requestRender();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
setAutocompleteProvider(provider) {
|
|
210
|
-
this.autocompleteProvider = provider;
|
|
211
|
-
this.invalidate();
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Add a prompt to history for up/down arrow navigation.
|
|
215
|
-
* Called after successful submission.
|
|
216
|
-
*/
|
|
217
|
-
addToHistory(text) {
|
|
218
|
-
const trimmed = text.trim();
|
|
219
|
-
if (!trimmed)
|
|
220
|
-
return;
|
|
221
|
-
// Don't add consecutive duplicates
|
|
222
|
-
if (this.history.length > 0 && this.history[0] === trimmed)
|
|
223
|
-
return;
|
|
224
|
-
this.history.unshift(trimmed);
|
|
225
|
-
// Limit history size
|
|
226
|
-
if (this.history.length > 100) {
|
|
227
|
-
this.history.pop();
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
isEditorEmpty() {
|
|
231
|
-
return this.state.lines.length === 1 && this.state.lines[0] === "";
|
|
232
|
-
}
|
|
233
|
-
isOnFirstVisualLine() {
|
|
234
|
-
const visualLines = this.buildVisualLineMap(this.lastWidth);
|
|
235
|
-
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
236
|
-
return currentVisualLine === 0;
|
|
237
|
-
}
|
|
238
|
-
isOnLastVisualLine() {
|
|
239
|
-
const visualLines = this.buildVisualLineMap(this.lastWidth);
|
|
240
|
-
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
241
|
-
return currentVisualLine === visualLines.length - 1;
|
|
242
|
-
}
|
|
243
|
-
navigateHistory(direction) {
|
|
244
|
-
this.lastAction = null;
|
|
245
|
-
if (this.history.length === 0)
|
|
246
|
-
return;
|
|
247
|
-
const newIndex = this.historyIndex - direction; // Up(-1) increases index, Down(1) decreases
|
|
248
|
-
if (newIndex < -1 || newIndex >= this.history.length)
|
|
249
|
-
return;
|
|
250
|
-
// Capture state when first entering history browsing mode
|
|
251
|
-
if (this.historyIndex === -1 && newIndex >= 0) {
|
|
252
|
-
this.pushUndoSnapshot();
|
|
253
|
-
}
|
|
254
|
-
this.historyIndex = newIndex;
|
|
255
|
-
if (this.historyIndex === -1) {
|
|
256
|
-
// Returned to "current" state - clear editor
|
|
257
|
-
this.setTextInternal("");
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
this.setTextInternal(this.history[this.historyIndex] || "");
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/** Internal setText that doesn't reset history state - used by navigateHistory */
|
|
264
|
-
setTextInternal(text) {
|
|
265
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
266
|
-
this.state.lines = lines.length === 0 ? [""] : lines;
|
|
267
|
-
this.state.cursorLine = this.state.lines.length - 1;
|
|
268
|
-
this.state.cursorCol = this.state.lines[this.state.cursorLine]?.length || 0;
|
|
269
|
-
// Reset scroll - render() will adjust to show cursor
|
|
270
|
-
this.scrollOffset = 0;
|
|
271
|
-
if (this.onChange) {
|
|
272
|
-
this.onChange(this.getText());
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
invalidate() {
|
|
276
|
-
super.invalidate();
|
|
277
|
-
this.autocompleteList?.invalidate?.();
|
|
278
|
-
}
|
|
279
|
-
render(width) {
|
|
280
|
-
const state = this.prepareRenderState(width);
|
|
281
|
-
const out = [];
|
|
282
|
-
out.push(this.renderTopBorder(width, state.horizontal));
|
|
283
|
-
const emitCursorMarker = this.focused && !this.isAutocompleting;
|
|
284
|
-
for (const layoutLine of state.visibleLines) {
|
|
285
|
-
out.push(this.renderVisibleLine(layoutLine, state.contentWidth, state.leftPadding, state.rightPadding, emitCursorMarker));
|
|
286
|
-
}
|
|
287
|
-
const linesBelow = state.layoutLines.length - (this.scrollOffset + state.visibleLines.length);
|
|
288
|
-
out.push(this.renderBottomBorder(width, state.horizontal, linesBelow));
|
|
289
|
-
if (this.isAutocompleting && this.autocompleteList) {
|
|
290
|
-
this.appendAutocompleteLines(out, state.contentWidth, state.leftPadding, state.rightPadding);
|
|
291
|
-
}
|
|
292
|
-
return out;
|
|
293
|
-
}
|
|
294
|
-
prepareRenderState(width) {
|
|
295
|
-
const maxPadding = Math.max(0, Math.floor((width - 1) / 2));
|
|
296
|
-
const paddingX = Math.min(this.paddingX, maxPadding);
|
|
297
|
-
const contentWidth = Math.max(1, width - paddingX * 2);
|
|
298
|
-
const layoutWidth = Math.max(1, contentWidth - (paddingX ? 0 : 1));
|
|
299
|
-
this.lastWidth = layoutWidth;
|
|
300
|
-
const layoutLines = this.layoutText(layoutWidth);
|
|
301
|
-
const maxVisibleLines = Math.max(5, Math.floor(this.tui.terminal.rows * 0.3));
|
|
302
|
-
const cursorLineIndex = Math.max(0, layoutLines.findIndex((line) => line.hasCursor));
|
|
303
|
-
this.syncScrollOffset(cursorLineIndex, maxVisibleLines, layoutLines.length);
|
|
304
|
-
const visibleLines = layoutLines.slice(this.scrollOffset, this.scrollOffset + maxVisibleLines);
|
|
305
|
-
const sidePadding = " ".repeat(paddingX);
|
|
306
|
-
return {
|
|
307
|
-
horizontal: this.borderColor("─"),
|
|
308
|
-
contentWidth,
|
|
309
|
-
leftPadding: sidePadding,
|
|
310
|
-
rightPadding: sidePadding,
|
|
311
|
-
layoutLines,
|
|
312
|
-
visibleLines,
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
syncScrollOffset(cursorLineIndex, maxVisibleLines, totalLayoutLines) {
|
|
316
|
-
if (cursorLineIndex < this.scrollOffset) {
|
|
317
|
-
this.scrollOffset = cursorLineIndex;
|
|
318
|
-
}
|
|
319
|
-
else if (cursorLineIndex >= this.scrollOffset + maxVisibleLines) {
|
|
320
|
-
this.scrollOffset = cursorLineIndex - maxVisibleLines + 1;
|
|
321
|
-
}
|
|
322
|
-
const maxScrollOffset = Math.max(0, totalLayoutLines - maxVisibleLines);
|
|
323
|
-
this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxScrollOffset));
|
|
324
|
-
}
|
|
325
|
-
renderTopBorder(width, horizontal) {
|
|
326
|
-
if (this.scrollOffset <= 0)
|
|
327
|
-
return horizontal.repeat(width);
|
|
328
|
-
const indicator = `─── ↑ ${this.scrollOffset} more `;
|
|
329
|
-
const remaining = width - visibleWidth(indicator);
|
|
330
|
-
return this.borderColor(indicator + "─".repeat(Math.max(0, remaining)));
|
|
331
|
-
}
|
|
332
|
-
renderBottomBorder(width, horizontal, linesBelow) {
|
|
333
|
-
if (linesBelow <= 0)
|
|
334
|
-
return horizontal.repeat(width);
|
|
335
|
-
const indicator = `─── ↓ ${linesBelow} more `;
|
|
336
|
-
const remaining = width - visibleWidth(indicator);
|
|
337
|
-
return this.borderColor(indicator + "─".repeat(Math.max(0, remaining)));
|
|
338
|
-
}
|
|
339
|
-
renderVisibleLine(layoutLine, contentWidth, leftPadding, rightPadding, emitCursorMarker) {
|
|
340
|
-
let displayText = layoutLine.text;
|
|
341
|
-
let measuredWidth = visibleWidth(layoutLine.text);
|
|
342
|
-
let cursorInPadding = false;
|
|
343
|
-
if (layoutLine.hasCursor && layoutLine.cursorPos !== undefined) {
|
|
344
|
-
const before = displayText.slice(0, layoutLine.cursorPos);
|
|
345
|
-
const after = displayText.slice(layoutLine.cursorPos);
|
|
346
|
-
const marker = emitCursorMarker ? CURSOR_MARKER : "";
|
|
347
|
-
if (after.length > 0) {
|
|
348
|
-
const first = [...segmenter.segment(after)][0]?.segment || "";
|
|
349
|
-
const highlighted = `\x1b[7m${first}\x1b[0m`;
|
|
350
|
-
displayText = before + marker + highlighted + after.slice(first.length);
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
displayText = before + marker + "\x1b[7m \x1b[0m";
|
|
354
|
-
measuredWidth += 1;
|
|
355
|
-
cursorInPadding = measuredWidth > contentWidth && rightPadding.length > 0;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
const fill = " ".repeat(Math.max(0, contentWidth - measuredWidth));
|
|
359
|
-
const adjustedRightPadding = cursorInPadding ? rightPadding.slice(1) : rightPadding;
|
|
360
|
-
return `${leftPadding}${displayText}${fill}${adjustedRightPadding}`;
|
|
361
|
-
}
|
|
362
|
-
appendAutocompleteLines(target, contentWidth, leftPadding, rightPadding) {
|
|
363
|
-
const autocompleteResult = this.autocompleteList?.render(contentWidth) ?? [];
|
|
364
|
-
for (const line of autocompleteResult) {
|
|
365
|
-
const linePadding = " ".repeat(Math.max(0, contentWidth - visibleWidth(line)));
|
|
366
|
-
target.push(`${leftPadding}${line}${linePadding}${rightPadding}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
handleInput(data) {
|
|
370
|
-
const kb = getEditorKeybindings();
|
|
371
|
-
const pasteResult = this.consumePasteInput(data);
|
|
372
|
-
if (!pasteResult)
|
|
373
|
-
return;
|
|
374
|
-
data = pasteResult;
|
|
375
|
-
const pendingResult = this.consumePendingShiftEnter(data);
|
|
376
|
-
if (!pendingResult)
|
|
377
|
-
return;
|
|
378
|
-
data = pendingResult;
|
|
379
|
-
if (data === "\\") {
|
|
380
|
-
this.pendingShiftEnter = true;
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
if (this.runEarlyActions(data, kb))
|
|
384
|
-
return;
|
|
385
|
-
const autocompleteResult = this.handleAutocompleteInput(data, kb);
|
|
386
|
-
if (autocompleteResult === "handled")
|
|
387
|
-
return;
|
|
388
|
-
if (!this.isAutocompleting && kb.matches(data, "tab")) {
|
|
389
|
-
this.handleTabCompletion();
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
if (this.runDeleteActions(data, kb))
|
|
393
|
-
return;
|
|
394
|
-
if (this.runKillRingActions(data, kb))
|
|
395
|
-
return;
|
|
396
|
-
if (this.runCursorActions(data, kb))
|
|
397
|
-
return;
|
|
398
|
-
if (this.isNewLineInput(data, kb)) {
|
|
399
|
-
this.addNewLine();
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
if (kb.matches(data, "submit")) {
|
|
403
|
-
this.submitEditor();
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
if (this.runArrowActions(data, kb))
|
|
407
|
-
return;
|
|
408
|
-
if (this.runPagingActions(data, kb))
|
|
409
|
-
return;
|
|
410
|
-
if (matchesKey(data, "shift+space")) {
|
|
411
|
-
this.insertCharacter(" ");
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
const kittyPrintable = decodeKittyPrintable(data);
|
|
415
|
-
if (kittyPrintable !== undefined) {
|
|
416
|
-
this.insertCharacter(kittyPrintable);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
if (data.charCodeAt(0) >= 32) {
|
|
420
|
-
this.insertCharacter(data);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
consumePasteInput(data) {
|
|
424
|
-
if (data.includes("\x1b[200~")) {
|
|
425
|
-
this.isInPaste = true;
|
|
426
|
-
this.pasteBuffer = "";
|
|
427
|
-
data = data.replace("\x1b[200~", "");
|
|
428
|
-
}
|
|
429
|
-
if (!this.isInPaste)
|
|
430
|
-
return data;
|
|
431
|
-
this.pasteBuffer += data;
|
|
432
|
-
const endIndex = this.pasteBuffer.indexOf("\x1b[201~");
|
|
433
|
-
if (endIndex === -1)
|
|
434
|
-
return null;
|
|
435
|
-
const pasteContent = this.pasteBuffer.substring(0, endIndex);
|
|
436
|
-
if (pasteContent.length > 0) {
|
|
437
|
-
this.handlePaste(pasteContent);
|
|
438
|
-
}
|
|
439
|
-
this.isInPaste = false;
|
|
440
|
-
const remaining = this.pasteBuffer.substring(endIndex + 6);
|
|
441
|
-
this.pasteBuffer = "";
|
|
442
|
-
if (remaining.length > 0) {
|
|
443
|
-
this.handleInput(remaining);
|
|
444
|
-
}
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
consumePendingShiftEnter(data) {
|
|
448
|
-
if (!this.pendingShiftEnter)
|
|
449
|
-
return data;
|
|
450
|
-
if (data === "\r") {
|
|
451
|
-
this.pendingShiftEnter = false;
|
|
452
|
-
this.addNewLine();
|
|
453
|
-
return null;
|
|
454
|
-
}
|
|
455
|
-
this.pendingShiftEnter = false;
|
|
456
|
-
this.insertCharacter("\\");
|
|
457
|
-
return data;
|
|
458
|
-
}
|
|
459
|
-
runEarlyActions(data, kb) {
|
|
460
|
-
if (kb.matches(data, "copy")) {
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
|
-
if (kb.matches(data, "undo")) {
|
|
464
|
-
this.undo();
|
|
465
|
-
return true;
|
|
466
|
-
}
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
handleAutocompleteInput(data, kb) {
|
|
470
|
-
if (!this.isAutocompleting || !this.autocompleteList)
|
|
471
|
-
return "none";
|
|
472
|
-
if (kb.matches(data, "selectCancel")) {
|
|
473
|
-
this.cancelAutocomplete();
|
|
474
|
-
return "handled";
|
|
475
|
-
}
|
|
476
|
-
if (kb.matches(data, "selectUp") || kb.matches(data, "selectDown")) {
|
|
477
|
-
this.autocompleteList.handleInput(data);
|
|
478
|
-
return "handled";
|
|
479
|
-
}
|
|
480
|
-
if (kb.matches(data, "tab")) {
|
|
481
|
-
this.applySelectedAutocompleteItem(true);
|
|
482
|
-
return "handled";
|
|
483
|
-
}
|
|
484
|
-
if (kb.matches(data, "selectConfirm")) {
|
|
485
|
-
const applied = this.applySelectedAutocompleteItem(false);
|
|
486
|
-
if (!applied)
|
|
487
|
-
return "handled";
|
|
488
|
-
return this.autocompletePrefix.startsWith("/") ? "continue" : "handled";
|
|
489
|
-
}
|
|
490
|
-
return "none";
|
|
491
|
-
}
|
|
492
|
-
applySelectedAutocompleteItem(notifyOnSlash) {
|
|
493
|
-
const selected = this.autocompleteList?.getSelectedItem();
|
|
494
|
-
if (!selected || !this.autocompleteProvider)
|
|
495
|
-
return false;
|
|
496
|
-
this.pushUndoSnapshot();
|
|
497
|
-
this.lastAction = null;
|
|
498
|
-
const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);
|
|
499
|
-
this.state.lines = result.lines;
|
|
500
|
-
this.state.cursorLine = result.cursorLine;
|
|
501
|
-
this.state.cursorCol = result.cursorCol;
|
|
502
|
-
this.cancelAutocomplete();
|
|
503
|
-
if (this.onChange && (notifyOnSlash || !this.autocompletePrefix.startsWith("/"))) {
|
|
504
|
-
this.onChange(this.getText());
|
|
505
|
-
}
|
|
506
|
-
return true;
|
|
507
|
-
}
|
|
508
|
-
runDeleteActions(data, kb) {
|
|
509
|
-
const actions = [
|
|
510
|
-
{ match: kb.matches(data, "deleteToLineEnd"), run: () => this.deleteToEndOfLine() },
|
|
511
|
-
{ match: kb.matches(data, "deleteToLineStart"), run: () => this.deleteToStartOfLine() },
|
|
512
|
-
{ match: kb.matches(data, "deleteWordBackward"), run: () => this.deleteWordBackwards() },
|
|
513
|
-
{ match: kb.matches(data, "deleteWordForward"), run: () => this.deleteWordForward() },
|
|
514
|
-
{ match: kb.matches(data, "deleteCharBackward") || matchesKey(data, "shift+backspace"), run: () => this.handleBackspace() },
|
|
515
|
-
{ match: kb.matches(data, "deleteCharForward") || matchesKey(data, "shift+delete"), run: () => this.handleForwardDelete() },
|
|
516
|
-
];
|
|
517
|
-
const route = actions.find((entry) => entry.match);
|
|
518
|
-
if (!route)
|
|
519
|
-
return false;
|
|
520
|
-
route.run();
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
runKillRingActions(data, kb) {
|
|
524
|
-
if (kb.matches(data, "yank")) {
|
|
525
|
-
this.yank();
|
|
526
|
-
return true;
|
|
527
|
-
}
|
|
528
|
-
if (kb.matches(data, "yankPop")) {
|
|
529
|
-
this.yankPop();
|
|
530
|
-
return true;
|
|
531
|
-
}
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
534
|
-
runCursorActions(data, kb) {
|
|
535
|
-
const routes = [
|
|
536
|
-
{ match: kb.matches(data, "cursorLineStart"), run: () => this.moveToLineStart() },
|
|
537
|
-
{ match: kb.matches(data, "cursorLineEnd"), run: () => this.moveToLineEnd() },
|
|
538
|
-
{ match: kb.matches(data, "cursorWordLeft"), run: () => this.moveWordBackwards() },
|
|
539
|
-
{ match: kb.matches(data, "cursorWordRight"), run: () => this.moveWordForwards() },
|
|
540
|
-
];
|
|
541
|
-
const route = routes.find((entry) => entry.match);
|
|
542
|
-
if (!route)
|
|
543
|
-
return false;
|
|
544
|
-
route.run();
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
|
-
runArrowActions(data, kb) {
|
|
548
|
-
if (kb.matches(data, "cursorUp")) {
|
|
549
|
-
if (this.isEditorEmpty()) {
|
|
550
|
-
this.navigateHistory(-1);
|
|
551
|
-
}
|
|
552
|
-
else if (this.historyIndex > -1 && this.isOnFirstVisualLine()) {
|
|
553
|
-
this.navigateHistory(-1);
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
this.moveCursor(-1, 0);
|
|
557
|
-
}
|
|
558
|
-
return true;
|
|
559
|
-
}
|
|
560
|
-
if (kb.matches(data, "cursorDown")) {
|
|
561
|
-
if (this.historyIndex > -1 && this.isOnLastVisualLine()) {
|
|
562
|
-
this.navigateHistory(1);
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
this.moveCursor(1, 0);
|
|
566
|
-
}
|
|
567
|
-
return true;
|
|
568
|
-
}
|
|
569
|
-
if (kb.matches(data, "cursorRight")) {
|
|
570
|
-
this.moveCursor(0, 1);
|
|
571
|
-
return true;
|
|
572
|
-
}
|
|
573
|
-
if (kb.matches(data, "cursorLeft")) {
|
|
574
|
-
this.moveCursor(0, -1);
|
|
575
|
-
return true;
|
|
576
|
-
}
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
runPagingActions(data, kb) {
|
|
580
|
-
if (kb.matches(data, "pageUp")) {
|
|
581
|
-
this.pageScroll(-1);
|
|
582
|
-
return true;
|
|
583
|
-
}
|
|
584
|
-
if (kb.matches(data, "pageDown")) {
|
|
585
|
-
this.pageScroll(1);
|
|
586
|
-
return true;
|
|
587
|
-
}
|
|
588
|
-
return false;
|
|
589
|
-
}
|
|
590
|
-
isNewLineInput(data, kb) {
|
|
591
|
-
return (kb.matches(data, "newLine") ||
|
|
592
|
-
(data.charCodeAt(0) === 10 && data.length > 1) ||
|
|
593
|
-
data === "\x1b\r" ||
|
|
594
|
-
data === "\x1b[13;2~" ||
|
|
595
|
-
(data.length > 1 && data.includes("\x1b") && data.includes("\r")) ||
|
|
596
|
-
(data === "\n" && data.length === 1) ||
|
|
597
|
-
data === "\\\r");
|
|
598
|
-
}
|
|
599
|
-
submitEditor() {
|
|
600
|
-
if (this.disableSubmit)
|
|
601
|
-
return;
|
|
602
|
-
let result = this.state.lines.join("\n").trim();
|
|
603
|
-
for (const [pasteId, pasteContent] of this.pastes) {
|
|
604
|
-
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
605
|
-
result = result.replace(markerRegex, pasteContent);
|
|
606
|
-
}
|
|
607
|
-
this.state = { lines: [""], cursorLine: 0, cursorCol: 0 };
|
|
608
|
-
this.pastes.clear();
|
|
609
|
-
this.pasteCounter = 0;
|
|
610
|
-
this.historyIndex = -1;
|
|
611
|
-
this.scrollOffset = 0;
|
|
612
|
-
this.undoStack.length = 0;
|
|
613
|
-
this.lastAction = null;
|
|
614
|
-
if (this.onChange)
|
|
615
|
-
this.onChange("");
|
|
616
|
-
if (this.onSubmit)
|
|
617
|
-
this.onSubmit(result);
|
|
618
|
-
}
|
|
619
|
-
layoutText(contentWidth) {
|
|
620
|
-
const layoutLines = [];
|
|
621
|
-
if (this.state.lines.length === 0 || (this.state.lines.length === 1 && this.state.lines[0] === "")) {
|
|
622
|
-
// Empty editor
|
|
623
|
-
layoutLines.push({
|
|
624
|
-
text: "",
|
|
625
|
-
hasCursor: true,
|
|
626
|
-
cursorPos: 0,
|
|
627
|
-
});
|
|
628
|
-
return layoutLines;
|
|
629
|
-
}
|
|
630
|
-
// Process each logical line
|
|
631
|
-
for (let i = 0; i < this.state.lines.length; i++) {
|
|
632
|
-
const line = this.state.lines[i] || "";
|
|
633
|
-
const isCurrentLine = i === this.state.cursorLine;
|
|
634
|
-
const lineVisibleWidth = visibleWidth(line);
|
|
635
|
-
if (lineVisibleWidth <= contentWidth) {
|
|
636
|
-
// Line fits in one layout line
|
|
637
|
-
if (isCurrentLine) {
|
|
638
|
-
layoutLines.push({
|
|
639
|
-
text: line,
|
|
640
|
-
hasCursor: true,
|
|
641
|
-
cursorPos: this.state.cursorCol,
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
layoutLines.push({
|
|
646
|
-
text: line,
|
|
647
|
-
hasCursor: false,
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
else {
|
|
652
|
-
// Line needs wrapping - use word-aware wrapping
|
|
653
|
-
const chunks = wordWrapLine(line, contentWidth);
|
|
654
|
-
for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
|
|
655
|
-
const chunk = chunks[chunkIndex];
|
|
656
|
-
if (!chunk)
|
|
657
|
-
continue;
|
|
658
|
-
const cursorPos = this.state.cursorCol;
|
|
659
|
-
const isLastChunk = chunkIndex === chunks.length - 1;
|
|
660
|
-
// Determine if cursor is in this chunk
|
|
661
|
-
// For word-wrapped chunks, we need to handle the case where
|
|
662
|
-
// cursor might be in trimmed whitespace at end of chunk
|
|
663
|
-
let hasCursorInChunk = false;
|
|
664
|
-
let adjustedCursorPos = 0;
|
|
665
|
-
if (isCurrentLine) {
|
|
666
|
-
if (isLastChunk) {
|
|
667
|
-
// Last chunk: cursor belongs here if >= startIndex
|
|
668
|
-
hasCursorInChunk = cursorPos >= chunk.startIndex;
|
|
669
|
-
adjustedCursorPos = cursorPos - chunk.startIndex;
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
// Non-last chunk: cursor belongs here if in range [startIndex, endIndex)
|
|
673
|
-
// But we need to handle the visual position in the trimmed text
|
|
674
|
-
hasCursorInChunk = cursorPos >= chunk.startIndex && cursorPos < chunk.endIndex;
|
|
675
|
-
if (hasCursorInChunk) {
|
|
676
|
-
adjustedCursorPos = cursorPos - chunk.startIndex;
|
|
677
|
-
// Clamp to text length (in case cursor was in trimmed whitespace)
|
|
678
|
-
if (adjustedCursorPos > chunk.text.length) {
|
|
679
|
-
adjustedCursorPos = chunk.text.length;
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
if (hasCursorInChunk) {
|
|
685
|
-
layoutLines.push({
|
|
686
|
-
text: chunk.text,
|
|
687
|
-
hasCursor: true,
|
|
688
|
-
cursorPos: adjustedCursorPos,
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
layoutLines.push({
|
|
693
|
-
text: chunk.text,
|
|
694
|
-
hasCursor: false,
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
return layoutLines;
|
|
701
|
-
}
|
|
702
|
-
getText() {
|
|
703
|
-
return this.state.lines.join("\n");
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Get text with paste markers expanded to their actual content.
|
|
707
|
-
* Use this when you need the full content (e.g., for external editor).
|
|
708
|
-
*/
|
|
709
|
-
getExpandedText() {
|
|
710
|
-
let result = this.state.lines.join("\n");
|
|
711
|
-
for (const [pasteId, pasteContent] of this.pastes) {
|
|
712
|
-
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
713
|
-
result = result.replace(markerRegex, pasteContent);
|
|
714
|
-
}
|
|
715
|
-
return result;
|
|
716
|
-
}
|
|
717
|
-
getLines() {
|
|
718
|
-
return [...this.state.lines];
|
|
719
|
-
}
|
|
720
|
-
getCursor() {
|
|
721
|
-
return { line: this.state.cursorLine, col: this.state.cursorCol };
|
|
722
|
-
}
|
|
723
|
-
setText(text) {
|
|
724
|
-
this.lastAction = null;
|
|
725
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
726
|
-
// Push undo snapshot if content differs (makes programmatic changes undoable)
|
|
727
|
-
if (this.getText() !== text) {
|
|
728
|
-
this.pushUndoSnapshot();
|
|
729
|
-
}
|
|
730
|
-
this.setTextInternal(text);
|
|
731
|
-
}
|
|
732
|
-
/**
|
|
733
|
-
* Insert text at the current cursor position.
|
|
734
|
-
* Used for programmatic insertion (e.g., clipboard image markers).
|
|
735
|
-
* This is atomic for undo - single undo restores entire pre-insert state.
|
|
736
|
-
*/
|
|
737
|
-
insertTextAtCursor(text) {
|
|
738
|
-
if (!text)
|
|
739
|
-
return;
|
|
740
|
-
this.pushUndoSnapshot();
|
|
741
|
-
this.lastAction = null;
|
|
742
|
-
this.historyIndex = -1;
|
|
743
|
-
this.insertTextAtCursorInternal(text);
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Internal text insertion at cursor. Handles single and multi-line text.
|
|
747
|
-
* Does not push undo snapshots or trigger autocomplete - caller is responsible.
|
|
748
|
-
* Normalizes line endings and calls onChange once at the end.
|
|
749
|
-
*/
|
|
750
|
-
insertTextAtCursorInternal(text) {
|
|
751
|
-
if (!text)
|
|
752
|
-
return;
|
|
753
|
-
// Normalize line endings
|
|
754
|
-
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
755
|
-
const insertedLines = normalized.split("\n");
|
|
756
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
757
|
-
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
758
|
-
const afterCursor = currentLine.slice(this.state.cursorCol);
|
|
759
|
-
if (insertedLines.length === 1) {
|
|
760
|
-
// Single line - insert at cursor position
|
|
761
|
-
this.state.lines[this.state.cursorLine] = beforeCursor + normalized + afterCursor;
|
|
762
|
-
this.state.cursorCol += normalized.length;
|
|
763
|
-
}
|
|
764
|
-
else {
|
|
765
|
-
// Multi-line insertion
|
|
766
|
-
this.state.lines = [
|
|
767
|
-
// All lines before current line
|
|
768
|
-
...this.state.lines.slice(0, this.state.cursorLine),
|
|
769
|
-
// The first inserted line merged with text before cursor
|
|
770
|
-
beforeCursor + insertedLines[0],
|
|
771
|
-
// All middle inserted lines
|
|
772
|
-
...insertedLines.slice(1, -1),
|
|
773
|
-
// The last inserted line with text after cursor
|
|
774
|
-
insertedLines[insertedLines.length - 1] + afterCursor,
|
|
775
|
-
// All lines after current line
|
|
776
|
-
...this.state.lines.slice(this.state.cursorLine + 1),
|
|
777
|
-
];
|
|
778
|
-
this.state.cursorLine += insertedLines.length - 1;
|
|
779
|
-
this.state.cursorCol = (insertedLines[insertedLines.length - 1] || "").length;
|
|
780
|
-
}
|
|
781
|
-
if (this.onChange) {
|
|
782
|
-
this.onChange(this.getText());
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
// All the editor methods from before...
|
|
786
|
-
insertCharacter(char, skipUndoCoalescing) {
|
|
787
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
788
|
-
// Undo coalescing (fish-style):
|
|
789
|
-
// - Consecutive word chars coalesce into one undo unit
|
|
790
|
-
// - Space captures state before itself (so undo removes space+following word together)
|
|
791
|
-
// - Each space is separately undoable
|
|
792
|
-
// Skip coalescing when called from atomic operations (e.g., handlePaste)
|
|
793
|
-
if (!skipUndoCoalescing) {
|
|
794
|
-
if (isWhitespaceChar(char) || this.lastAction !== "type-word") {
|
|
795
|
-
this.pushUndoSnapshot();
|
|
796
|
-
}
|
|
797
|
-
this.lastAction = "type-word";
|
|
798
|
-
}
|
|
799
|
-
const line = this.state.lines[this.state.cursorLine] || "";
|
|
800
|
-
const before = line.slice(0, this.state.cursorCol);
|
|
801
|
-
const after = line.slice(this.state.cursorCol);
|
|
802
|
-
this.state.lines[this.state.cursorLine] = before + char + after;
|
|
803
|
-
this.state.cursorCol += char.length; // Fix: increment by the length of the inserted string
|
|
804
|
-
if (this.onChange) {
|
|
805
|
-
this.onChange(this.getText());
|
|
806
|
-
}
|
|
807
|
-
// Check if we should trigger or update autocomplete
|
|
808
|
-
if (!this.isAutocompleting) {
|
|
809
|
-
// Auto-trigger for "/" at the start of a line (slash commands)
|
|
810
|
-
if (char === "/" && this.isAtStartOfMessage()) {
|
|
811
|
-
this.tryTriggerAutocomplete();
|
|
812
|
-
}
|
|
813
|
-
// Auto-trigger for "@" file reference (fuzzy search)
|
|
814
|
-
else if (char === "@") {
|
|
815
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
816
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
817
|
-
// Only trigger if @ is after whitespace or at start of line
|
|
818
|
-
const charBeforeAt = textBeforeCursor[textBeforeCursor.length - 2];
|
|
819
|
-
if (textBeforeCursor.length === 1 || charBeforeAt === " " || charBeforeAt === "\t") {
|
|
820
|
-
this.tryTriggerAutocomplete();
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
// Also auto-trigger when typing letters in a slash command context
|
|
824
|
-
else if (/[a-zA-Z0-9.\-_]/.test(char)) {
|
|
825
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
826
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
827
|
-
// Check if we're in a slash command (with or without space for arguments)
|
|
828
|
-
if (this.isInSlashCommandContext(textBeforeCursor)) {
|
|
829
|
-
this.tryTriggerAutocomplete();
|
|
830
|
-
}
|
|
831
|
-
// Check if we're in an @ file reference context
|
|
832
|
-
else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
|
|
833
|
-
this.tryTriggerAutocomplete();
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
else {
|
|
838
|
-
this.updateAutocomplete();
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
handlePaste(pastedText) {
|
|
842
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
843
|
-
this.lastAction = null;
|
|
844
|
-
this.pushUndoSnapshot();
|
|
845
|
-
// Clean the pasted text
|
|
846
|
-
const cleanText = pastedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
847
|
-
// Convert tabs to spaces (4 spaces per tab)
|
|
848
|
-
const tabExpandedText = cleanText.replace(/\t/g, " ");
|
|
849
|
-
// Filter out non-printable characters except newlines
|
|
850
|
-
let filteredText = tabExpandedText
|
|
851
|
-
.split("")
|
|
852
|
-
.filter((char) => char === "\n" || char.charCodeAt(0) >= 32)
|
|
853
|
-
.join("");
|
|
854
|
-
// If pasting a file path (starts with /, ~, or .) and the character before
|
|
855
|
-
// the cursor is a word character, prepend a space for better readability
|
|
856
|
-
if (/^[/~.]/.test(filteredText)) {
|
|
857
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
858
|
-
const charBeforeCursor = this.state.cursorCol > 0 ? currentLine[this.state.cursorCol - 1] : "";
|
|
859
|
-
if (charBeforeCursor && /\w/.test(charBeforeCursor)) {
|
|
860
|
-
filteredText = ` ${filteredText}`;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
// Split into lines to check for large paste
|
|
864
|
-
const pastedLines = filteredText.split("\n");
|
|
865
|
-
// Check if this is a large paste (> 10 lines or > 1000 characters)
|
|
866
|
-
const totalChars = filteredText.length;
|
|
867
|
-
if (pastedLines.length > 10 || totalChars > 1000) {
|
|
868
|
-
// Store the paste and insert a marker
|
|
869
|
-
this.pasteCounter++;
|
|
870
|
-
const pasteId = this.pasteCounter;
|
|
871
|
-
this.pastes.set(pasteId, filteredText);
|
|
872
|
-
// Insert marker like "[paste #1 +123 lines]" or "[paste #1 1234 chars]"
|
|
873
|
-
const marker = pastedLines.length > 10
|
|
874
|
-
? `[paste #${pasteId} +${pastedLines.length} lines]`
|
|
875
|
-
: `[paste #${pasteId} ${totalChars} chars]`;
|
|
876
|
-
this.insertTextAtCursorInternal(marker);
|
|
877
|
-
return;
|
|
878
|
-
}
|
|
879
|
-
if (pastedLines.length === 1) {
|
|
880
|
-
// Single line - insert character by character to trigger autocomplete
|
|
881
|
-
for (const char of filteredText) {
|
|
882
|
-
this.insertCharacter(char, true);
|
|
883
|
-
}
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
// Multi-line paste - use direct state manipulation
|
|
887
|
-
this.insertTextAtCursorInternal(filteredText);
|
|
888
|
-
}
|
|
889
|
-
addNewLine() {
|
|
890
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
891
|
-
this.lastAction = null;
|
|
892
|
-
this.pushUndoSnapshot();
|
|
893
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
894
|
-
const before = currentLine.slice(0, this.state.cursorCol);
|
|
895
|
-
const after = currentLine.slice(this.state.cursorCol);
|
|
896
|
-
// Split current line
|
|
897
|
-
this.state.lines[this.state.cursorLine] = before;
|
|
898
|
-
this.state.lines.splice(this.state.cursorLine + 1, 0, after);
|
|
899
|
-
// Move cursor to start of new line
|
|
900
|
-
this.state.cursorLine++;
|
|
901
|
-
this.state.cursorCol = 0;
|
|
902
|
-
if (this.onChange) {
|
|
903
|
-
this.onChange(this.getText());
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
handleBackspace() {
|
|
907
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
908
|
-
this.lastAction = null;
|
|
909
|
-
if (this.state.cursorCol > 0) {
|
|
910
|
-
this.pushUndoSnapshot();
|
|
911
|
-
// Delete grapheme before cursor (handles emojis, combining characters, etc.)
|
|
912
|
-
const line = this.state.lines[this.state.cursorLine] || "";
|
|
913
|
-
const beforeCursor = line.slice(0, this.state.cursorCol);
|
|
914
|
-
// Find the last grapheme in the text before cursor
|
|
915
|
-
const graphemes = [...segmenter.segment(beforeCursor)];
|
|
916
|
-
const lastGrapheme = graphemes[graphemes.length - 1];
|
|
917
|
-
const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;
|
|
918
|
-
const before = line.slice(0, this.state.cursorCol - graphemeLength);
|
|
919
|
-
const after = line.slice(this.state.cursorCol);
|
|
920
|
-
this.state.lines[this.state.cursorLine] = before + after;
|
|
921
|
-
this.state.cursorCol -= graphemeLength;
|
|
922
|
-
}
|
|
923
|
-
else if (this.state.cursorLine > 0) {
|
|
924
|
-
this.pushUndoSnapshot();
|
|
925
|
-
// Merge with previous line
|
|
926
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
927
|
-
const previousLine = this.state.lines[this.state.cursorLine - 1] || "";
|
|
928
|
-
this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;
|
|
929
|
-
this.state.lines.splice(this.state.cursorLine, 1);
|
|
930
|
-
this.state.cursorLine--;
|
|
931
|
-
this.state.cursorCol = previousLine.length;
|
|
932
|
-
}
|
|
933
|
-
if (this.onChange) {
|
|
934
|
-
this.onChange(this.getText());
|
|
935
|
-
}
|
|
936
|
-
// Update or re-trigger autocomplete after backspace
|
|
937
|
-
if (this.isAutocompleting) {
|
|
938
|
-
this.updateAutocomplete();
|
|
939
|
-
}
|
|
940
|
-
else {
|
|
941
|
-
// If autocomplete was cancelled (no matches), re-trigger if we're in a completable context
|
|
942
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
943
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
944
|
-
// Slash command context
|
|
945
|
-
if (this.isInSlashCommandContext(textBeforeCursor)) {
|
|
946
|
-
this.tryTriggerAutocomplete();
|
|
947
|
-
}
|
|
948
|
-
// @ file reference context
|
|
949
|
-
else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
|
|
950
|
-
this.tryTriggerAutocomplete();
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
moveToLineStart() {
|
|
955
|
-
this.lastAction = null;
|
|
956
|
-
this.state.cursorCol = 0;
|
|
957
|
-
}
|
|
958
|
-
moveToLineEnd() {
|
|
959
|
-
this.lastAction = null;
|
|
960
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
961
|
-
this.state.cursorCol = currentLine.length;
|
|
962
|
-
}
|
|
963
|
-
deleteToStartOfLine() {
|
|
964
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
965
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
966
|
-
if (this.state.cursorCol > 0) {
|
|
967
|
-
this.pushUndoSnapshot();
|
|
968
|
-
// Calculate text to be deleted and save to kill ring (backward deletion = prepend)
|
|
969
|
-
const deletedText = currentLine.slice(0, this.state.cursorCol);
|
|
970
|
-
this.addToKillRing(deletedText, true);
|
|
971
|
-
this.lastAction = "kill";
|
|
972
|
-
// Delete from start of line up to cursor
|
|
973
|
-
this.state.lines[this.state.cursorLine] = currentLine.slice(this.state.cursorCol);
|
|
974
|
-
this.state.cursorCol = 0;
|
|
975
|
-
}
|
|
976
|
-
else if (this.state.cursorLine > 0) {
|
|
977
|
-
this.pushUndoSnapshot();
|
|
978
|
-
// At start of line - merge with previous line, treating newline as deleted text
|
|
979
|
-
this.addToKillRing("\n", true);
|
|
980
|
-
this.lastAction = "kill";
|
|
981
|
-
const previousLine = this.state.lines[this.state.cursorLine - 1] || "";
|
|
982
|
-
this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;
|
|
983
|
-
this.state.lines.splice(this.state.cursorLine, 1);
|
|
984
|
-
this.state.cursorLine--;
|
|
985
|
-
this.state.cursorCol = previousLine.length;
|
|
986
|
-
}
|
|
987
|
-
if (this.onChange) {
|
|
988
|
-
this.onChange(this.getText());
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
deleteToEndOfLine() {
|
|
992
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
993
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
994
|
-
if (this.state.cursorCol < currentLine.length) {
|
|
995
|
-
this.pushUndoSnapshot();
|
|
996
|
-
// Calculate text to be deleted and save to kill ring (forward deletion = append)
|
|
997
|
-
const deletedText = currentLine.slice(this.state.cursorCol);
|
|
998
|
-
this.addToKillRing(deletedText, false);
|
|
999
|
-
this.lastAction = "kill";
|
|
1000
|
-
// Delete from cursor to end of line
|
|
1001
|
-
this.state.lines[this.state.cursorLine] = currentLine.slice(0, this.state.cursorCol);
|
|
1002
|
-
}
|
|
1003
|
-
else if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1004
|
-
this.pushUndoSnapshot();
|
|
1005
|
-
// At end of line - merge with next line, treating newline as deleted text
|
|
1006
|
-
this.addToKillRing("\n", false);
|
|
1007
|
-
this.lastAction = "kill";
|
|
1008
|
-
const nextLine = this.state.lines[this.state.cursorLine + 1] || "";
|
|
1009
|
-
this.state.lines[this.state.cursorLine] = currentLine + nextLine;
|
|
1010
|
-
this.state.lines.splice(this.state.cursorLine + 1, 1);
|
|
1011
|
-
}
|
|
1012
|
-
if (this.onChange) {
|
|
1013
|
-
this.onChange(this.getText());
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
deleteWordBackwards() {
|
|
1017
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
1018
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1019
|
-
// If at start of line, behave like backspace at column 0 (merge with previous line)
|
|
1020
|
-
if (this.state.cursorCol === 0) {
|
|
1021
|
-
if (this.state.cursorLine > 0) {
|
|
1022
|
-
this.pushUndoSnapshot();
|
|
1023
|
-
// Treat newline as deleted text (backward deletion = prepend)
|
|
1024
|
-
this.addToKillRing("\n", true);
|
|
1025
|
-
this.lastAction = "kill";
|
|
1026
|
-
const previousLine = this.state.lines[this.state.cursorLine - 1] || "";
|
|
1027
|
-
this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;
|
|
1028
|
-
this.state.lines.splice(this.state.cursorLine, 1);
|
|
1029
|
-
this.state.cursorLine--;
|
|
1030
|
-
this.state.cursorCol = previousLine.length;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
else {
|
|
1034
|
-
this.pushUndoSnapshot();
|
|
1035
|
-
// Save lastAction before cursor movement (moveWordBackwards resets it)
|
|
1036
|
-
const wasKill = this.lastAction === "kill";
|
|
1037
|
-
const oldCursorCol = this.state.cursorCol;
|
|
1038
|
-
this.moveWordBackwards();
|
|
1039
|
-
const deleteFrom = this.state.cursorCol;
|
|
1040
|
-
this.state.cursorCol = oldCursorCol;
|
|
1041
|
-
// Restore kill state for accumulation check, then save to kill ring
|
|
1042
|
-
this.lastAction = wasKill ? "kill" : null;
|
|
1043
|
-
const deletedText = currentLine.slice(deleteFrom, this.state.cursorCol);
|
|
1044
|
-
this.addToKillRing(deletedText, true);
|
|
1045
|
-
this.lastAction = "kill";
|
|
1046
|
-
this.state.lines[this.state.cursorLine] =
|
|
1047
|
-
currentLine.slice(0, deleteFrom) + currentLine.slice(this.state.cursorCol);
|
|
1048
|
-
this.state.cursorCol = deleteFrom;
|
|
1049
|
-
}
|
|
1050
|
-
if (this.onChange) {
|
|
1051
|
-
this.onChange(this.getText());
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
deleteWordForward() {
|
|
1055
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
1056
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1057
|
-
// If at end of line, merge with next line (delete the newline)
|
|
1058
|
-
if (this.state.cursorCol >= currentLine.length) {
|
|
1059
|
-
if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1060
|
-
this.pushUndoSnapshot();
|
|
1061
|
-
// Treat newline as deleted text (forward deletion = append)
|
|
1062
|
-
this.addToKillRing("\n", false);
|
|
1063
|
-
this.lastAction = "kill";
|
|
1064
|
-
const nextLine = this.state.lines[this.state.cursorLine + 1] || "";
|
|
1065
|
-
this.state.lines[this.state.cursorLine] = currentLine + nextLine;
|
|
1066
|
-
this.state.lines.splice(this.state.cursorLine + 1, 1);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
else {
|
|
1070
|
-
this.pushUndoSnapshot();
|
|
1071
|
-
// Save lastAction before cursor movement (moveWordForwards resets it)
|
|
1072
|
-
const wasKill = this.lastAction === "kill";
|
|
1073
|
-
const oldCursorCol = this.state.cursorCol;
|
|
1074
|
-
this.moveWordForwards();
|
|
1075
|
-
const deleteTo = this.state.cursorCol;
|
|
1076
|
-
this.state.cursorCol = oldCursorCol;
|
|
1077
|
-
// Restore kill state for accumulation check, then save to kill ring
|
|
1078
|
-
this.lastAction = wasKill ? "kill" : null;
|
|
1079
|
-
const deletedText = currentLine.slice(this.state.cursorCol, deleteTo);
|
|
1080
|
-
this.addToKillRing(deletedText, false);
|
|
1081
|
-
this.lastAction = "kill";
|
|
1082
|
-
this.state.lines[this.state.cursorLine] =
|
|
1083
|
-
currentLine.slice(0, this.state.cursorCol) + currentLine.slice(deleteTo);
|
|
1084
|
-
}
|
|
1085
|
-
if (this.onChange) {
|
|
1086
|
-
this.onChange(this.getText());
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
handleForwardDelete() {
|
|
1090
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
1091
|
-
this.lastAction = null;
|
|
1092
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1093
|
-
if (this.state.cursorCol < currentLine.length) {
|
|
1094
|
-
this.pushUndoSnapshot();
|
|
1095
|
-
// Delete grapheme at cursor position (handles emojis, combining characters, etc.)
|
|
1096
|
-
const afterCursor = currentLine.slice(this.state.cursorCol);
|
|
1097
|
-
// Find the first grapheme at cursor
|
|
1098
|
-
const graphemes = [...segmenter.segment(afterCursor)];
|
|
1099
|
-
const firstGrapheme = graphemes[0];
|
|
1100
|
-
const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;
|
|
1101
|
-
const before = currentLine.slice(0, this.state.cursorCol);
|
|
1102
|
-
const after = currentLine.slice(this.state.cursorCol + graphemeLength);
|
|
1103
|
-
this.state.lines[this.state.cursorLine] = before + after;
|
|
1104
|
-
}
|
|
1105
|
-
else if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1106
|
-
this.pushUndoSnapshot();
|
|
1107
|
-
// At end of line - merge with next line
|
|
1108
|
-
const nextLine = this.state.lines[this.state.cursorLine + 1] || "";
|
|
1109
|
-
this.state.lines[this.state.cursorLine] = currentLine + nextLine;
|
|
1110
|
-
this.state.lines.splice(this.state.cursorLine + 1, 1);
|
|
1111
|
-
}
|
|
1112
|
-
if (this.onChange) {
|
|
1113
|
-
this.onChange(this.getText());
|
|
1114
|
-
}
|
|
1115
|
-
// Update or re-trigger autocomplete after forward delete
|
|
1116
|
-
if (this.isAutocompleting) {
|
|
1117
|
-
this.updateAutocomplete();
|
|
1118
|
-
}
|
|
1119
|
-
else {
|
|
1120
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1121
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1122
|
-
// Slash command context
|
|
1123
|
-
if (this.isInSlashCommandContext(textBeforeCursor)) {
|
|
1124
|
-
this.tryTriggerAutocomplete();
|
|
1125
|
-
}
|
|
1126
|
-
// @ file reference context
|
|
1127
|
-
else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
|
|
1128
|
-
this.tryTriggerAutocomplete();
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
/**
|
|
1133
|
-
* Build a mapping from visual lines to logical positions.
|
|
1134
|
-
* Returns an array where each element represents a visual line with:
|
|
1135
|
-
* - logicalLine: index into this.state.lines
|
|
1136
|
-
* - startCol: starting column in the logical line
|
|
1137
|
-
* - length: length of this visual line segment
|
|
1138
|
-
*/
|
|
1139
|
-
buildVisualLineMap(width) {
|
|
1140
|
-
return EditorLayoutProjector.buildVisualLineMap(this.state.lines, width);
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* Find the visual line index for the current cursor position.
|
|
1144
|
-
*/
|
|
1145
|
-
findCurrentVisualLine(visualLines) {
|
|
1146
|
-
return EditorLayoutProjector.findCurrentVisualLine(visualLines, this.state.cursorLine, this.state.cursorCol);
|
|
1147
|
-
}
|
|
1148
|
-
moveCursor(deltaLine, deltaCol) {
|
|
1149
|
-
this.lastAction = null;
|
|
1150
|
-
const width = this.lastWidth;
|
|
1151
|
-
if (deltaLine !== 0) {
|
|
1152
|
-
const visualLines = this.buildVisualLineMap(width);
|
|
1153
|
-
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1154
|
-
const currentSegment = visualLines[currentVisualLine];
|
|
1155
|
-
const visualCol = currentSegment ? this.state.cursorCol - currentSegment.startCol : 0;
|
|
1156
|
-
const targetVisualLine = currentVisualLine + deltaLine;
|
|
1157
|
-
if (targetVisualLine >= 0 && targetVisualLine < visualLines.length) {
|
|
1158
|
-
const target = EditorLayoutProjector.resolveCursorAtVisualLine(visualLines, targetVisualLine, visualCol, this.state.lines);
|
|
1159
|
-
if (target) {
|
|
1160
|
-
this.state.cursorLine = target.line;
|
|
1161
|
-
this.state.cursorCol = target.col;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
if (deltaCol !== 0) {
|
|
1166
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1167
|
-
if (deltaCol > 0) {
|
|
1168
|
-
// Moving right - move by one grapheme (handles emojis, combining characters, etc.)
|
|
1169
|
-
if (this.state.cursorCol < currentLine.length) {
|
|
1170
|
-
const afterCursor = currentLine.slice(this.state.cursorCol);
|
|
1171
|
-
const graphemes = [...segmenter.segment(afterCursor)];
|
|
1172
|
-
const firstGrapheme = graphemes[0];
|
|
1173
|
-
this.state.cursorCol += firstGrapheme ? firstGrapheme.segment.length : 1;
|
|
1174
|
-
}
|
|
1175
|
-
else if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1176
|
-
// Wrap to start of next logical line
|
|
1177
|
-
this.state.cursorLine++;
|
|
1178
|
-
this.state.cursorCol = 0;
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
else {
|
|
1182
|
-
// Moving left - move by one grapheme (handles emojis, combining characters, etc.)
|
|
1183
|
-
if (this.state.cursorCol > 0) {
|
|
1184
|
-
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1185
|
-
const graphemes = [...segmenter.segment(beforeCursor)];
|
|
1186
|
-
const lastGrapheme = graphemes[graphemes.length - 1];
|
|
1187
|
-
this.state.cursorCol -= lastGrapheme ? lastGrapheme.segment.length : 1;
|
|
1188
|
-
}
|
|
1189
|
-
else if (this.state.cursorLine > 0) {
|
|
1190
|
-
// Wrap to end of previous logical line
|
|
1191
|
-
this.state.cursorLine--;
|
|
1192
|
-
const prevLine = this.state.lines[this.state.cursorLine] || "";
|
|
1193
|
-
this.state.cursorCol = prevLine.length;
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Scroll by a page (direction: -1 for up, 1 for down).
|
|
1200
|
-
* Moves cursor by the page size while keeping it in bounds.
|
|
1201
|
-
*/
|
|
1202
|
-
pageScroll(direction) {
|
|
1203
|
-
this.lastAction = null;
|
|
1204
|
-
const width = this.lastWidth;
|
|
1205
|
-
const terminalRows = this.tui.terminal.rows;
|
|
1206
|
-
const pageSize = Math.max(5, Math.floor(terminalRows * 0.3));
|
|
1207
|
-
const visualLines = this.buildVisualLineMap(width);
|
|
1208
|
-
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1209
|
-
const targetVisualLine = Math.max(0, Math.min(visualLines.length - 1, currentVisualLine + direction * pageSize));
|
|
1210
|
-
const currentSegment = visualLines[currentVisualLine];
|
|
1211
|
-
const visualCol = currentSegment ? this.state.cursorCol - currentSegment.startCol : 0;
|
|
1212
|
-
const target = EditorLayoutProjector.resolveCursorAtVisualLine(visualLines, targetVisualLine, visualCol, this.state.lines);
|
|
1213
|
-
if (target) {
|
|
1214
|
-
this.state.cursorLine = target.line;
|
|
1215
|
-
this.state.cursorCol = target.col;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
moveWordBackwards() {
|
|
1219
|
-
this.lastAction = null;
|
|
1220
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1221
|
-
// If at start of line, move to end of previous line
|
|
1222
|
-
if (this.state.cursorCol === 0) {
|
|
1223
|
-
if (this.state.cursorLine > 0) {
|
|
1224
|
-
this.state.cursorLine--;
|
|
1225
|
-
const prevLine = this.state.lines[this.state.cursorLine] || "";
|
|
1226
|
-
this.state.cursorCol = prevLine.length;
|
|
1227
|
-
}
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1231
|
-
const graphemes = [...segmenter.segment(textBeforeCursor)];
|
|
1232
|
-
let newCol = this.state.cursorCol;
|
|
1233
|
-
// Skip trailing whitespace
|
|
1234
|
-
while (graphemes.length > 0 && isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || "")) {
|
|
1235
|
-
newCol -= graphemes.pop()?.segment.length || 0;
|
|
1236
|
-
}
|
|
1237
|
-
if (graphemes.length > 0) {
|
|
1238
|
-
const lastGrapheme = graphemes[graphemes.length - 1]?.segment || "";
|
|
1239
|
-
if (isPunctuationChar(lastGrapheme)) {
|
|
1240
|
-
// Skip punctuation run
|
|
1241
|
-
while (graphemes.length > 0 && isPunctuationChar(graphemes[graphemes.length - 1]?.segment || "")) {
|
|
1242
|
-
newCol -= graphemes.pop()?.segment.length || 0;
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
else {
|
|
1246
|
-
// Skip word run
|
|
1247
|
-
while (graphemes.length > 0 &&
|
|
1248
|
-
!isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || "") &&
|
|
1249
|
-
!isPunctuationChar(graphemes[graphemes.length - 1]?.segment || "")) {
|
|
1250
|
-
newCol -= graphemes.pop()?.segment.length || 0;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
this.state.cursorCol = newCol;
|
|
1255
|
-
}
|
|
1256
|
-
/**
|
|
1257
|
-
* Yank (paste) the most recent kill ring entry at cursor position.
|
|
1258
|
-
*/
|
|
1259
|
-
yank() {
|
|
1260
|
-
if (this.killRing.length === 0)
|
|
1261
|
-
return;
|
|
1262
|
-
this.pushUndoSnapshot();
|
|
1263
|
-
const text = this.killRing[this.killRing.length - 1] || "";
|
|
1264
|
-
this.insertYankedText(text);
|
|
1265
|
-
this.lastAction = "yank";
|
|
1266
|
-
}
|
|
1267
|
-
/**
|
|
1268
|
-
* Cycle through kill ring (only works immediately after yank or yank-pop).
|
|
1269
|
-
* Replaces the last yanked text with the previous entry in the ring.
|
|
1270
|
-
*/
|
|
1271
|
-
yankPop() {
|
|
1272
|
-
// Only works if we just yanked and have more than one entry
|
|
1273
|
-
if (this.lastAction !== "yank" || this.killRing.length <= 1)
|
|
1274
|
-
return;
|
|
1275
|
-
this.pushUndoSnapshot();
|
|
1276
|
-
// Delete the previously yanked text (still at end of ring before rotation)
|
|
1277
|
-
this.deleteYankedText();
|
|
1278
|
-
// Rotate the ring: move end to front
|
|
1279
|
-
const lastEntry = this.killRing.pop();
|
|
1280
|
-
this.killRing.unshift(lastEntry);
|
|
1281
|
-
// Insert the new most recent entry (now at end after rotation)
|
|
1282
|
-
const text = this.killRing[this.killRing.length - 1];
|
|
1283
|
-
this.insertYankedText(text);
|
|
1284
|
-
this.lastAction = "yank";
|
|
1285
|
-
}
|
|
1286
|
-
/**
|
|
1287
|
-
* Insert text at cursor position (used by yank operations).
|
|
1288
|
-
*/
|
|
1289
|
-
insertYankedText(text) {
|
|
1290
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
1291
|
-
const lines = text.split("\n");
|
|
1292
|
-
if (lines.length === 1) {
|
|
1293
|
-
// Single line - insert at cursor
|
|
1294
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1295
|
-
const before = currentLine.slice(0, this.state.cursorCol);
|
|
1296
|
-
const after = currentLine.slice(this.state.cursorCol);
|
|
1297
|
-
this.state.lines[this.state.cursorLine] = before + text + after;
|
|
1298
|
-
this.state.cursorCol += text.length;
|
|
1299
|
-
}
|
|
1300
|
-
else {
|
|
1301
|
-
// Multi-line insert
|
|
1302
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1303
|
-
const before = currentLine.slice(0, this.state.cursorCol);
|
|
1304
|
-
const after = currentLine.slice(this.state.cursorCol);
|
|
1305
|
-
// First line merges with text before cursor
|
|
1306
|
-
this.state.lines[this.state.cursorLine] = before + (lines[0] || "");
|
|
1307
|
-
// Insert middle lines
|
|
1308
|
-
for (let i = 1; i < lines.length - 1; i++) {
|
|
1309
|
-
this.state.lines.splice(this.state.cursorLine + i, 0, lines[i] || "");
|
|
1310
|
-
}
|
|
1311
|
-
// Last line merges with text after cursor
|
|
1312
|
-
const lastLineIndex = this.state.cursorLine + lines.length - 1;
|
|
1313
|
-
this.state.lines.splice(lastLineIndex, 0, (lines[lines.length - 1] || "") + after);
|
|
1314
|
-
// Update cursor position
|
|
1315
|
-
this.state.cursorLine = lastLineIndex;
|
|
1316
|
-
this.state.cursorCol = (lines[lines.length - 1] || "").length;
|
|
1317
|
-
}
|
|
1318
|
-
if (this.onChange) {
|
|
1319
|
-
this.onChange(this.getText());
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
/**
|
|
1323
|
-
* Delete the previously yanked text (used by yank-pop).
|
|
1324
|
-
* The yanked text is derived from killRing[end] since it hasn't been rotated yet.
|
|
1325
|
-
*/
|
|
1326
|
-
deleteYankedText() {
|
|
1327
|
-
const yankedText = this.killRing[this.killRing.length - 1] || "";
|
|
1328
|
-
if (!yankedText)
|
|
1329
|
-
return;
|
|
1330
|
-
const yankLines = yankedText.split("\n");
|
|
1331
|
-
if (yankLines.length === 1) {
|
|
1332
|
-
// Single line - delete backward from cursor
|
|
1333
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1334
|
-
const deleteLen = yankedText.length;
|
|
1335
|
-
const before = currentLine.slice(0, this.state.cursorCol - deleteLen);
|
|
1336
|
-
const after = currentLine.slice(this.state.cursorCol);
|
|
1337
|
-
this.state.lines[this.state.cursorLine] = before + after;
|
|
1338
|
-
this.state.cursorCol -= deleteLen;
|
|
1339
|
-
}
|
|
1340
|
-
else {
|
|
1341
|
-
// Multi-line delete - cursor is at end of last yanked line
|
|
1342
|
-
const startLine = this.state.cursorLine - (yankLines.length - 1);
|
|
1343
|
-
const startCol = (this.state.lines[startLine] || "").length - (yankLines[0] || "").length;
|
|
1344
|
-
// Get text after cursor on current line
|
|
1345
|
-
const afterCursor = (this.state.lines[this.state.cursorLine] || "").slice(this.state.cursorCol);
|
|
1346
|
-
// Get text before yank start position
|
|
1347
|
-
const beforeYank = (this.state.lines[startLine] || "").slice(0, startCol);
|
|
1348
|
-
// Remove all lines from startLine to cursorLine and replace with merged line
|
|
1349
|
-
this.state.lines.splice(startLine, yankLines.length, beforeYank + afterCursor);
|
|
1350
|
-
// Update cursor
|
|
1351
|
-
this.state.cursorLine = startLine;
|
|
1352
|
-
this.state.cursorCol = startCol;
|
|
1353
|
-
}
|
|
1354
|
-
if (this.onChange) {
|
|
1355
|
-
this.onChange(this.getText());
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
/**
|
|
1359
|
-
* Add text to the kill ring.
|
|
1360
|
-
* If lastAction is "kill", accumulates with the previous entry.
|
|
1361
|
-
* @param text - The text to add
|
|
1362
|
-
* @param prepend - If accumulating, prepend (true) or append (false) to existing entry
|
|
1363
|
-
*/
|
|
1364
|
-
addToKillRing(text, prepend) {
|
|
1365
|
-
if (!text)
|
|
1366
|
-
return;
|
|
1367
|
-
if (this.lastAction === "kill" && this.killRing.length > 0) {
|
|
1368
|
-
// Accumulate with the most recent entry (at end of array)
|
|
1369
|
-
const lastEntry = this.killRing.pop();
|
|
1370
|
-
if (prepend) {
|
|
1371
|
-
this.killRing.push(text + lastEntry);
|
|
1372
|
-
}
|
|
1373
|
-
else {
|
|
1374
|
-
this.killRing.push(lastEntry + text);
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
else {
|
|
1378
|
-
// Add new entry to end of ring
|
|
1379
|
-
this.killRing.push(text);
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
captureUndoSnapshot() {
|
|
1383
|
-
return structuredClone(this.state);
|
|
1384
|
-
}
|
|
1385
|
-
restoreUndoSnapshot(snapshot) {
|
|
1386
|
-
Object.assign(this.state, structuredClone(snapshot));
|
|
1387
|
-
}
|
|
1388
|
-
pushUndoSnapshot() {
|
|
1389
|
-
this.undoStack.push(this.captureUndoSnapshot());
|
|
1390
|
-
}
|
|
1391
|
-
undo() {
|
|
1392
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
1393
|
-
if (this.undoStack.length === 0)
|
|
1394
|
-
return;
|
|
1395
|
-
const snapshot = this.undoStack.pop();
|
|
1396
|
-
this.restoreUndoSnapshot(snapshot);
|
|
1397
|
-
this.lastAction = null;
|
|
1398
|
-
if (this.onChange) {
|
|
1399
|
-
this.onChange(this.getText());
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
moveWordForwards() {
|
|
1403
|
-
this.lastAction = null;
|
|
1404
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1405
|
-
// If at end of line, move to start of next line
|
|
1406
|
-
if (this.state.cursorCol >= currentLine.length) {
|
|
1407
|
-
if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1408
|
-
this.state.cursorLine++;
|
|
1409
|
-
this.state.cursorCol = 0;
|
|
1410
|
-
}
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
const textAfterCursor = currentLine.slice(this.state.cursorCol);
|
|
1414
|
-
const segments = segmenter.segment(textAfterCursor);
|
|
1415
|
-
const iterator = segments[Symbol.iterator]();
|
|
1416
|
-
let next = iterator.next();
|
|
1417
|
-
// Skip leading whitespace
|
|
1418
|
-
while (!next.done && isWhitespaceChar(next.value.segment)) {
|
|
1419
|
-
this.state.cursorCol += next.value.segment.length;
|
|
1420
|
-
next = iterator.next();
|
|
1421
|
-
}
|
|
1422
|
-
if (!next.done) {
|
|
1423
|
-
const firstGrapheme = next.value.segment;
|
|
1424
|
-
if (isPunctuationChar(firstGrapheme)) {
|
|
1425
|
-
// Skip punctuation run
|
|
1426
|
-
while (!next.done && isPunctuationChar(next.value.segment)) {
|
|
1427
|
-
this.state.cursorCol += next.value.segment.length;
|
|
1428
|
-
next = iterator.next();
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
else {
|
|
1432
|
-
// Skip word run
|
|
1433
|
-
while (!next.done && !isWhitespaceChar(next.value.segment) && !isPunctuationChar(next.value.segment)) {
|
|
1434
|
-
this.state.cursorCol += next.value.segment.length;
|
|
1435
|
-
next = iterator.next();
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
// Slash menu only allowed when all other lines are empty (no mixed content)
|
|
1441
|
-
isSlashMenuAllowed() {
|
|
1442
|
-
for (let i = 0; i < this.state.lines.length; i++) {
|
|
1443
|
-
if (i === this.state.cursorLine)
|
|
1444
|
-
continue;
|
|
1445
|
-
if (this.state.lines[i].trim() !== "")
|
|
1446
|
-
return false;
|
|
1447
|
-
}
|
|
1448
|
-
return true;
|
|
1449
|
-
}
|
|
1450
|
-
// Helper method to check if cursor is at start of message (for slash command detection)
|
|
1451
|
-
isAtStartOfMessage() {
|
|
1452
|
-
if (!this.isSlashMenuAllowed())
|
|
1453
|
-
return false;
|
|
1454
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1455
|
-
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1456
|
-
return beforeCursor.trim() === "" || beforeCursor.trim() === "/";
|
|
1457
|
-
}
|
|
1458
|
-
isInSlashCommandContext(textBeforeCursor) {
|
|
1459
|
-
return this.isSlashMenuAllowed() && textBeforeCursor.trimStart().startsWith("/");
|
|
1460
|
-
}
|
|
1461
|
-
// Autocomplete methods
|
|
1462
|
-
tryTriggerAutocomplete(explicitTab = false) {
|
|
1463
|
-
if (!this.autocompleteProvider)
|
|
1464
|
-
return;
|
|
1465
|
-
// Check if we should trigger file completion on Tab
|
|
1466
|
-
if (explicitTab) {
|
|
1467
|
-
const provider = this.autocompleteProvider;
|
|
1468
|
-
const shouldTrigger = !provider.shouldTriggerFileCompletion ||
|
|
1469
|
-
provider.shouldTriggerFileCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1470
|
-
if (!shouldTrigger) {
|
|
1471
|
-
return;
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
const suggestions = this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1475
|
-
if (suggestions && suggestions.items.length > 0) {
|
|
1476
|
-
this.autocompletePrefix = suggestions.prefix;
|
|
1477
|
-
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1478
|
-
this.isAutocompleting = true;
|
|
1479
|
-
}
|
|
1480
|
-
else {
|
|
1481
|
-
this.cancelAutocomplete();
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
handleTabCompletion() {
|
|
1485
|
-
if (!this.autocompleteProvider)
|
|
1486
|
-
return;
|
|
1487
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1488
|
-
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1489
|
-
// Check if we're in a slash command context
|
|
1490
|
-
if (this.isInSlashCommandContext(beforeCursor) && !beforeCursor.trimStart().includes(" ")) {
|
|
1491
|
-
this.handleSlashCommandCompletion();
|
|
1492
|
-
}
|
|
1493
|
-
else {
|
|
1494
|
-
this.forceFileAutocomplete();
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
handleSlashCommandCompletion() {
|
|
1498
|
-
this.tryTriggerAutocomplete(true);
|
|
1499
|
-
}
|
|
1500
|
-
/*
|
|
1501
|
-
https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/559322883
|
|
1502
|
-
17 this job fails with https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19
|
|
1503
|
-
536643416/job/55932288317 havea look at .gi
|
|
1504
|
-
*/
|
|
1505
|
-
forceFileAutocomplete() {
|
|
1506
|
-
if (!this.autocompleteProvider)
|
|
1507
|
-
return;
|
|
1508
|
-
// Check if provider supports force file suggestions via runtime check
|
|
1509
|
-
const provider = this.autocompleteProvider;
|
|
1510
|
-
if (typeof provider.getForceFileSuggestions !== "function") {
|
|
1511
|
-
this.tryTriggerAutocomplete(true);
|
|
1512
|
-
return;
|
|
1513
|
-
}
|
|
1514
|
-
const suggestions = provider.getForceFileSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1515
|
-
if (suggestions && suggestions.items.length > 0) {
|
|
1516
|
-
this.autocompletePrefix = suggestions.prefix;
|
|
1517
|
-
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1518
|
-
this.isAutocompleting = true;
|
|
1519
|
-
}
|
|
1520
|
-
else {
|
|
1521
|
-
this.cancelAutocomplete();
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
cancelAutocomplete() {
|
|
1525
|
-
this.isAutocompleting = false;
|
|
1526
|
-
this.autocompleteList = undefined;
|
|
1527
|
-
this.autocompletePrefix = "";
|
|
1528
|
-
}
|
|
1529
|
-
isShowingAutocomplete() {
|
|
1530
|
-
return this.isAutocompleting;
|
|
1531
|
-
}
|
|
1532
|
-
updateAutocomplete() {
|
|
1533
|
-
if (!this.isAutocompleting || !this.autocompleteProvider)
|
|
1534
|
-
return;
|
|
1535
|
-
const suggestions = this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1536
|
-
if (suggestions && suggestions.items.length > 0) {
|
|
1537
|
-
this.autocompletePrefix = suggestions.prefix;
|
|
1538
|
-
// Always create new SelectList to ensure update
|
|
1539
|
-
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1540
|
-
}
|
|
1541
|
-
else {
|
|
1542
|
-
this.cancelAutocomplete();
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
//# sourceMappingURL=editor.js.map
|