@travisennis/acai 0.0.8 → 0.0.10
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 +48 -729
- package/bin/acai +52 -0
- package/dist/agent/index.d.ts +12 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +378 -168
- package/dist/agent/sub-agent.d.ts +23 -0
- package/dist/agent/sub-agent.d.ts.map +1 -0
- package/dist/agent/sub-agent.js +109 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +84 -76
- package/dist/cli/stdin.d.ts +9 -0
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/cli/stdin.js +37 -0
- package/dist/commands/copy/index.js +2 -2
- package/dist/commands/copy/utils.d.ts.map +1 -1
- package/dist/commands/copy/utils.js +15 -13
- package/dist/commands/generate-rules/index.d.ts +1 -1
- package/dist/commands/generate-rules/index.d.ts.map +1 -1
- package/dist/commands/generate-rules/index.js +16 -100
- package/dist/commands/generate-rules/service.d.ts +21 -0
- package/dist/commands/generate-rules/service.d.ts.map +1 -0
- package/dist/commands/generate-rules/service.js +103 -0
- package/dist/commands/handoff/index.js +2 -2
- package/dist/commands/health/index.js +1 -1
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/health/utils.js +6 -0
- package/dist/commands/history/index.d.ts +1 -1
- package/dist/commands/history/index.d.ts.map +1 -1
- package/dist/commands/history/index.js +17 -18
- package/dist/commands/history/types.d.ts +38 -0
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/history/utils.d.ts.map +1 -1
- package/dist/commands/history/utils.js +63 -58
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -8
- package/dist/commands/init-project/index.d.ts.map +1 -1
- package/dist/commands/init-project/index.js +3 -3
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +10 -2
- package/dist/commands/list-tools/index.d.ts.map +1 -1
- package/dist/commands/list-tools/index.js +7 -31
- package/dist/commands/manager.d.ts +2 -2
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +57 -33
- package/dist/commands/model/index.d.ts.map +1 -1
- package/dist/commands/model/index.js +20 -151
- package/dist/commands/model/model-panel.d.ts +4 -0
- package/dist/commands/model/model-panel.d.ts.map +1 -0
- package/dist/commands/model/model-panel.js +144 -0
- package/dist/commands/paste/index.d.ts.map +1 -1
- package/dist/commands/paste/index.js +59 -62
- package/dist/commands/paste/utils.d.ts.map +1 -1
- package/dist/commands/paste/utils.js +88 -58
- package/dist/commands/pickup/index.d.ts.map +1 -1
- package/dist/commands/pickup/index.js +6 -3
- package/dist/commands/pickup/utils.js +3 -3
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +33 -50
- package/dist/commands/review/index.d.ts.map +1 -1
- package/dist/commands/review/index.js +3 -117
- package/dist/commands/review/review-panel.d.ts +3 -0
- package/dist/commands/review/review-panel.d.ts.map +1 -0
- package/dist/commands/review/review-panel.js +186 -0
- package/dist/commands/review/utils.d.ts +9 -0
- package/dist/commands/review/utils.d.ts.map +1 -1
- package/dist/commands/review/utils.js +127 -68
- package/dist/commands/session/index.d.ts +1 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +134 -112
- package/dist/commands/session/types.d.ts +7 -0
- package/dist/commands/session/types.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.d.ts +25 -0
- package/dist/commands/share/html-renderer.d.ts.map +1 -0
- package/dist/commands/share/html-renderer.js +384 -0
- package/dist/commands/share/index.d.ts +3 -0
- package/dist/commands/share/index.d.ts.map +1 -0
- package/dist/commands/share/index.js +122 -0
- package/dist/commands/shell/index.d.ts.map +1 -1
- package/dist/commands/shell/index.js +16 -1
- package/dist/commands/types.d.ts +2 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/{config.d.ts → config/index.d.ts} +20 -9
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{config.js → config/index.js} +43 -42
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +75 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +170 -127
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +18 -36
- package/dist/models/ai-config.d.ts +1 -0
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +4 -3
- package/dist/models/anthropic-provider.d.ts +2 -5
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -70
- package/dist/models/deepseek-provider.d.ts +1 -0
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/google-provider.d.ts +2 -3
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -26
- package/dist/models/groq-provider.d.ts +1 -0
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/manager.d.ts +13 -2
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +20 -8
- package/dist/models/openai-provider.d.ts +5 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +27 -40
- package/dist/models/opencode-zen-provider.d.ts +8 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +68 -11
- package/dist/models/openrouter-provider.d.ts +24 -30
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +92 -177
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/xai-provider.d.ts +4 -3
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +18 -18
- package/dist/modes/manager.d.ts +23 -0
- package/dist/modes/manager.d.ts.map +1 -0
- package/dist/modes/manager.js +77 -0
- package/dist/modes/prompts.d.ts +2 -0
- package/dist/modes/prompts.d.ts.map +1 -0
- package/dist/modes/prompts.js +143 -0
- package/dist/prompts/mentions.d.ts +11 -0
- package/dist/prompts/mentions.d.ts.map +1 -0
- package/dist/{mentions.js → prompts/mentions.js} +21 -80
- package/dist/prompts/system-prompt.d.ts +26 -0
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +50 -22
- package/dist/repl/index.d.ts +174 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/{repl-new.js → repl/index.js} +399 -76
- package/dist/repl/project-status.d.ts +1 -0
- package/dist/repl/project-status.d.ts.map +1 -1
- package/dist/repl/project-status.js +4 -1
- package/dist/sessions/manager.d.ts +93 -1
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +264 -9
- package/dist/sessions/summary.d.ts +4 -0
- package/dist/sessions/summary.d.ts.map +1 -0
- package/dist/sessions/summary.js +30 -0
- package/dist/{skills.d.ts → skills/index.d.ts} +14 -2
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +15 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +231 -0
- package/dist/terminal/control.d.ts +1 -1
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +30 -9
- package/dist/terminal/east-asian-width.d.ts.map +1 -1
- package/dist/terminal/east-asian-width.js +404 -351
- package/dist/terminal/keys.d.ts +17 -0
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +37 -0
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +24 -12
- package/dist/terminal/string-width.d.ts.map +1 -1
- package/dist/terminal/string-width.js +25 -27
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/style.js +4 -7
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +41 -27
- package/dist/terminal/table/cell.d.ts +12 -0
- package/dist/terminal/table/cell.d.ts.map +1 -1
- package/dist/terminal/table/cell.js +40 -25
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +100 -68
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +17 -10
- package/dist/terminal/wrap-ansi.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +172 -103
- package/dist/tokens/tracker.d.ts +1 -0
- package/dist/tokens/tracker.d.ts.map +1 -1
- package/dist/tokens/tracker.js +3 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +81 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +343 -121
- package/dist/tools/code-search.d.ts +41 -0
- package/dist/tools/code-search.d.ts.map +1 -0
- package/dist/tools/code-search.js +195 -0
- package/dist/tools/directory-tree.d.ts +3 -3
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +8 -5
- package/dist/tools/dynamic-tool-loader.d.ts +2 -5
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +20 -4
- package/dist/tools/edit-file.d.ts +7 -7
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +164 -66
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +95 -55
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +300 -192
- package/dist/tools/index.d.ts +143 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +39 -24
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +7 -5
- package/dist/tools/read-file.d.ts +3 -3
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +74 -34
- package/dist/tools/save-file.d.ts +3 -3
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +11 -11
- package/dist/tools/skill.d.ts +23 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +65 -0
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +2 -9
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +12 -0
- package/dist/tools/web-fetch.d.ts +62 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +429 -0
- package/dist/tools/web-search.d.ts +62 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +226 -0
- package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
- package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/attachment-provider.js +25 -78
- package/dist/tui/autocomplete/base-provider.d.ts +1 -0
- package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
- package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.js +3 -17
- package/dist/tui/autocomplete/command-provider.d.ts +1 -0
- package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/command-provider.js +3 -0
- package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
- package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +36 -16
- package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
- package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
- package/dist/tui/autocomplete/skill-provider.js +49 -0
- package/dist/tui/autocomplete.d.ts +2 -2
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +3 -5
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.js +0 -4
- package/dist/tui/components/editor.d.ts +21 -2
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +228 -236
- package/dist/tui/components/footer.d.ts +6 -4
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +49 -25
- package/dist/tui/components/markdown.d.ts +8 -5
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +57 -39
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +35 -33
- package/dist/tui/components/notification.d.ts +13 -2
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/notification.js +37 -2
- package/dist/tui/components/progress-bar.js +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +14 -11
- package/dist/tui/components/text.d.ts +16 -0
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +72 -57
- package/dist/tui/components/thinking-block.d.ts +9 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -1
- package/dist/tui/components/thinking-block.js +43 -11
- package/dist/tui/components/tool-execution.d.ts +5 -1
- package/dist/tui/components/tool-execution.d.ts.map +1 -1
- package/dist/tui/components/tool-execution.js +19 -10
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/user-message.js +0 -3
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +13 -0
- package/dist/tui/editor-launcher.d.ts.map +1 -0
- package/dist/tui/editor-launcher.js +39 -0
- package/dist/tui/index.d.ts +3 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +1 -0
- package/dist/tui/terminal.d.ts +27 -0
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +144 -15
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +172 -41
- package/dist/utils/bash/parse.d.ts +19 -0
- package/dist/utils/bash/parse.d.ts.map +1 -0
- package/dist/utils/bash/parse.js +223 -0
- package/dist/utils/bash/quote.d.ts +6 -0
- package/dist/utils/bash/quote.d.ts.map +1 -0
- package/dist/utils/bash/quote.js +23 -0
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +211 -126
- package/dist/utils/command-protection.d.ts +28 -0
- package/dist/utils/command-protection.d.ts.map +1 -0
- package/dist/utils/command-protection.js +324 -0
- package/dist/utils/dedent.d.ts.map +1 -0
- package/dist/utils/env-expand.d.ts +2 -0
- package/dist/utils/env-expand.d.ts.map +1 -0
- package/dist/utils/env-expand.js +8 -0
- package/dist/utils/filesystem/path-display.d.ts +11 -0
- package/dist/utils/filesystem/path-display.d.ts.map +1 -0
- package/dist/utils/filesystem/path-display.js +32 -0
- package/dist/utils/filesystem/security.d.ts +2 -2
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +32 -31
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{formatting.js → utils/formatting.js} +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +30 -0
- package/dist/utils/glob.d.ts +1 -1
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/{logger.js → utils/logger.js} +1 -1
- package/dist/utils/parsing.d.ts.map +1 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +90 -37
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +24 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/{version.js → utils/version.js} +1 -1
- package/package.json +34 -25
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/exit/index.d.ts +0 -10
- package/dist/commands/exit/index.d.ts.map +0 -1
- package/dist/commands/exit/index.js +0 -21
- package/dist/commands/exit/types.d.ts +0 -8
- package/dist/commands/exit/types.d.ts.map +0 -1
- package/dist/commands/exit/types.js +0 -1
- package/dist/commands/exit/utils.d.ts +0 -2
- package/dist/commands/exit/utils.d.ts.map +0 -1
- package/dist/commands/exit/utils.js +0 -13
- package/dist/commands/prompt/index.d.ts +0 -5
- package/dist/commands/prompt/index.d.ts.map +0 -1
- package/dist/commands/prompt/index.js +0 -126
- package/dist/commands/prompt/types.d.ts +0 -15
- package/dist/commands/prompt/types.d.ts.map +0 -1
- package/dist/commands/prompt/types.js +0 -1
- package/dist/commands/prompt/utils.d.ts +0 -12
- package/dist/commands/prompt/utils.d.ts.map +0 -1
- package/dist/commands/prompt/utils.js +0 -107
- package/dist/commands/reset/index.d.ts +0 -3
- package/dist/commands/reset/index.d.ts.map +0 -1
- package/dist/commands/reset/index.js +0 -25
- package/dist/commands/reset/types.d.ts +0 -1
- package/dist/commands/reset/types.d.ts.map +0 -1
- package/dist/commands/reset/types.js +0 -3
- package/dist/commands/save/index.d.ts +0 -3
- package/dist/commands/save/index.d.ts.map +0 -1
- package/dist/commands/save/index.js +0 -19
- package/dist/config.d.ts.map +0 -1
- package/dist/dedent.d.ts.map +0 -1
- package/dist/formatting.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/mentions.d.ts +0 -14
- package/dist/mentions.d.ts.map +0 -1
- package/dist/parsing.d.ts.map +0 -1
- package/dist/prompts.d.ts +0 -10
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -62
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/tui/autocomplete/path-provider.d.ts +0 -21
- package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.js +0 -164
- package/dist/version.d.ts.map +0 -1
- /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
- /package/dist/{dedent.js → utils/dedent.js} +0 -0
- /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
- /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
- /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
- /package/dist/{parsing.js → utils/parsing.js} +0 -0
- /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCtrlC, isEnter, isEscape, isNavigationKey, isTab, } from "../../terminal/keys.js";
|
|
1
|
+
import { isCtrlC, isCtrlG, isEnter, isEscape, isNavigationKey, isTab, } from "../../terminal/keys.js";
|
|
2
2
|
import { getSegmenter } from "../../terminal/segmenter.js";
|
|
3
3
|
import style from "../../terminal/style.js";
|
|
4
4
|
import { visibleWidth } from "../utils.js";
|
|
@@ -174,6 +174,7 @@ export class Editor {
|
|
|
174
174
|
// Custom key handlers for coding-agent
|
|
175
175
|
onEscape;
|
|
176
176
|
onRenderRequested;
|
|
177
|
+
onExternalEditor;
|
|
177
178
|
constructor(theme) {
|
|
178
179
|
// Default theme if none provided (backward compatibility)
|
|
179
180
|
this.theme = theme || {
|
|
@@ -181,6 +182,12 @@ export class Editor {
|
|
|
181
182
|
};
|
|
182
183
|
this.borderColor = this.theme.borderColor;
|
|
183
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Get the current history (for testing purposes).
|
|
187
|
+
*/
|
|
188
|
+
getHistory() {
|
|
189
|
+
return this.history;
|
|
190
|
+
}
|
|
184
191
|
/**
|
|
185
192
|
* Add a prompt to history for up/down arrow navigation.
|
|
186
193
|
* Called after successful submission.
|
|
@@ -201,6 +208,18 @@ export class Editor {
|
|
|
201
208
|
setAutocompleteProvider(provider) {
|
|
202
209
|
this.autocompleteProvider = provider;
|
|
203
210
|
}
|
|
211
|
+
async launchExternalEditor() {
|
|
212
|
+
if (!this.onExternalEditor)
|
|
213
|
+
return;
|
|
214
|
+
const currentContent = this.getText();
|
|
215
|
+
const result = await this.onExternalEditor(currentContent);
|
|
216
|
+
if (!result.aborted) {
|
|
217
|
+
this.setText(result.content);
|
|
218
|
+
if (this.onRenderRequested) {
|
|
219
|
+
this.onRenderRequested();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
204
223
|
isEditorEmpty() {
|
|
205
224
|
return this.state.lines.length === 1 && this.state.lines[0] === "";
|
|
206
225
|
}
|
|
@@ -311,193 +330,247 @@ export class Editor {
|
|
|
311
330
|
return result;
|
|
312
331
|
}
|
|
313
332
|
handleInput(data) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
// If we're in a paste, buffer the data
|
|
328
|
-
if (this.isInPaste) {
|
|
329
|
-
// Append data to buffer first (end marker could be split across chunks)
|
|
330
|
-
this.pasteBuffer += data;
|
|
331
|
-
// Check if the accumulated buffer contains the end marker
|
|
332
|
-
const endIndex = this.pasteBuffer.indexOf("\x1b[201~");
|
|
333
|
-
if (endIndex !== -1) {
|
|
334
|
-
// Extract content before the end marker
|
|
335
|
-
const pasteContent = this.pasteBuffer.substring(0, endIndex);
|
|
336
|
-
// Process the complete paste
|
|
337
|
-
this.handlePaste(pasteContent);
|
|
338
|
-
// Reset paste state
|
|
339
|
-
this.isInPaste = false;
|
|
340
|
-
// Process any remaining data after the end marker
|
|
341
|
-
const remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \x1b[201~
|
|
342
|
-
this.pasteBuffer = "";
|
|
343
|
-
if (remaining.length > 0) {
|
|
344
|
-
this.handleInput(remaining);
|
|
333
|
+
const pasteStart = "\x1b[200~";
|
|
334
|
+
const pasteEnd = "\x1b[201~";
|
|
335
|
+
let input = data;
|
|
336
|
+
while (input.length > 0) {
|
|
337
|
+
if (!this.isInPaste) {
|
|
338
|
+
const startIndex = input.indexOf(pasteStart);
|
|
339
|
+
if (startIndex === -1)
|
|
340
|
+
break;
|
|
341
|
+
const before = input.slice(0, startIndex);
|
|
342
|
+
if (before.length > 0) {
|
|
343
|
+
this.processInputData(before);
|
|
345
344
|
}
|
|
346
|
-
|
|
345
|
+
this.isInPaste = true;
|
|
346
|
+
this.pasteBuffer = "";
|
|
347
|
+
input = input.slice(startIndex + pasteStart.length);
|
|
348
|
+
continue;
|
|
347
349
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
+
this.pasteBuffer += input;
|
|
351
|
+
const endIndex = this.pasteBuffer.indexOf(pasteEnd);
|
|
352
|
+
if (endIndex === -1)
|
|
353
|
+
return;
|
|
354
|
+
const pasteContent = this.pasteBuffer.slice(0, endIndex);
|
|
355
|
+
const remaining = this.pasteBuffer.slice(endIndex + pasteEnd.length);
|
|
356
|
+
this.handlePaste(pasteContent);
|
|
357
|
+
this.isInPaste = false;
|
|
358
|
+
this.pasteBuffer = "";
|
|
359
|
+
input = remaining;
|
|
350
360
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (isEscape(
|
|
361
|
+
if (input.length === 0)
|
|
362
|
+
return;
|
|
363
|
+
if (isEscape(input) && this.onEscape && !this.isShowingAutocomplete()) {
|
|
354
364
|
this.onEscape();
|
|
355
365
|
return;
|
|
356
366
|
}
|
|
357
|
-
|
|
358
|
-
if (isCtrlC(data)) {
|
|
367
|
+
if (isCtrlC(input)) {
|
|
359
368
|
return;
|
|
360
369
|
}
|
|
361
|
-
|
|
362
|
-
this.processInputData(data);
|
|
370
|
+
this.processInputData(input);
|
|
363
371
|
}
|
|
364
372
|
processInputData(data) {
|
|
365
|
-
// Handle special key combinations first
|
|
366
373
|
// Ctrl+C - Exit (let parent handle this)
|
|
367
374
|
if (data.charCodeAt(0) === 3) {
|
|
368
375
|
return;
|
|
369
376
|
}
|
|
370
|
-
//
|
|
371
|
-
if (this.
|
|
372
|
-
|
|
373
|
-
|
|
377
|
+
// Delegate to specialized handlers - return true if input was handled
|
|
378
|
+
if (this.handleAutocompleteInput(data))
|
|
379
|
+
return;
|
|
380
|
+
if (this.handleTabKey(data))
|
|
381
|
+
return;
|
|
382
|
+
if (this.handleExternalEditor(data))
|
|
383
|
+
return;
|
|
384
|
+
if (this.handleControlKey(data))
|
|
385
|
+
return;
|
|
386
|
+
if (this.handlePlainEnter(data))
|
|
387
|
+
return;
|
|
388
|
+
if (this.handleModifiedEnterKey(data))
|
|
389
|
+
return;
|
|
390
|
+
if (this.handleBackspaceKey(data))
|
|
391
|
+
return;
|
|
392
|
+
if (this.handleHomeEndKeys(data))
|
|
393
|
+
return;
|
|
394
|
+
if (this.handleForwardDeleteKey(data))
|
|
395
|
+
return;
|
|
396
|
+
if (this.handleWordNavigation(data))
|
|
397
|
+
return;
|
|
398
|
+
if (this.handleArrowKeys(data))
|
|
399
|
+
return;
|
|
400
|
+
// Default: insert printable character
|
|
401
|
+
if (data.charCodeAt(0) >= 32) {
|
|
402
|
+
this.insertCharacter(data);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
handleAutocompleteInput(data) {
|
|
406
|
+
if (!this.isAutocompleting || !this.autocompleteList) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
// Escape - cancel autocomplete
|
|
410
|
+
if (isEscape(data)) {
|
|
411
|
+
this.cancelAutocomplete();
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
// Enter - apply selection
|
|
415
|
+
if (isEnter(data)) {
|
|
416
|
+
const selected = this.autocompleteList.getSelectedItem();
|
|
417
|
+
if (selected && this.autocompleteProvider) {
|
|
418
|
+
const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);
|
|
419
|
+
this.state.lines = result.lines;
|
|
420
|
+
this.state.cursorLine = result.cursorLine;
|
|
421
|
+
this.state.cursorCol = result.cursorCol;
|
|
374
422
|
this.cancelAutocomplete();
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// Enter - apply selection
|
|
378
|
-
if (isEnter(data)) {
|
|
379
|
-
const selected = this.autocompleteList.getSelectedItem();
|
|
380
|
-
if (selected && this.autocompleteProvider) {
|
|
381
|
-
const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);
|
|
382
|
-
this.state.lines = result.lines;
|
|
383
|
-
this.state.cursorLine = result.cursorLine;
|
|
384
|
-
this.state.cursorCol = result.cursorCol;
|
|
385
|
-
this.cancelAutocomplete();
|
|
386
|
-
if (this.onChange) {
|
|
387
|
-
this.onChange(this.getText());
|
|
388
|
-
}
|
|
423
|
+
if (this.onChange) {
|
|
424
|
+
this.onChange(this.getText());
|
|
389
425
|
}
|
|
390
|
-
return;
|
|
391
426
|
}
|
|
392
|
-
|
|
393
|
-
if (isNavigationKey(data)) {
|
|
394
|
-
this.autocompleteList.handleInput(data);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
// For other keys (like regular typing), DON'T return here
|
|
398
|
-
// Let them fall through to normal character handling
|
|
427
|
+
return true;
|
|
399
428
|
}
|
|
400
|
-
//
|
|
429
|
+
// Navigation keys (arrows, Tab, Shift+Tab) - pass to autocomplete list
|
|
430
|
+
if (isNavigationKey(data)) {
|
|
431
|
+
this.autocompleteList.handleInput(data);
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
handleTabKey(data) {
|
|
401
437
|
if (isTab(data) && !this.isAutocompleting) {
|
|
402
438
|
void this.handleTabCompletion();
|
|
403
|
-
return;
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
handleExternalEditor(data) {
|
|
444
|
+
if (isCtrlG(data) && this.onExternalEditor) {
|
|
445
|
+
void this.launchExternalEditor();
|
|
446
|
+
return true;
|
|
404
447
|
}
|
|
405
|
-
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
handleControlKey(data) {
|
|
451
|
+
const charCode = data.charCodeAt(0);
|
|
406
452
|
// Ctrl+K - Delete to end of line
|
|
407
|
-
if (
|
|
453
|
+
if (charCode === 11) {
|
|
408
454
|
this.deleteToEndOfLine();
|
|
455
|
+
return true;
|
|
409
456
|
}
|
|
410
457
|
// Ctrl+U - Delete to start of line
|
|
411
|
-
|
|
458
|
+
if (charCode === 21) {
|
|
412
459
|
this.deleteToStartOfLine();
|
|
460
|
+
return true;
|
|
413
461
|
}
|
|
414
462
|
// Ctrl+W - Delete word backwards
|
|
415
|
-
|
|
463
|
+
if (charCode === 23) {
|
|
416
464
|
this.deleteWordBackwards();
|
|
465
|
+
return true;
|
|
417
466
|
}
|
|
418
467
|
// Option/Alt+Backspace (e.g. Ghostty sends ESC + DEL)
|
|
419
|
-
|
|
468
|
+
if (data === "\x1b\x7f") {
|
|
420
469
|
this.deleteWordBackwards();
|
|
470
|
+
return true;
|
|
421
471
|
}
|
|
422
472
|
// Ctrl+A - Move to start of line
|
|
423
|
-
|
|
473
|
+
if (charCode === 1) {
|
|
424
474
|
this.moveToLineStart();
|
|
475
|
+
return true;
|
|
425
476
|
}
|
|
426
477
|
// Ctrl+E - Move to end of line
|
|
427
|
-
|
|
478
|
+
if (charCode === 5) {
|
|
428
479
|
this.moveToLineEnd();
|
|
480
|
+
return true;
|
|
429
481
|
}
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
handlePlainEnter(data) {
|
|
430
485
|
// Plain Enter (char code 13 for CR) - create new line
|
|
431
|
-
|
|
486
|
+
if (data.charCodeAt(0) === 13 && data.length === 1) {
|
|
432
487
|
this.addNewLine();
|
|
488
|
+
return true;
|
|
433
489
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
// Get text and substitute paste markers with actual content
|
|
441
|
-
let result = this.state.lines.join("\n").trim();
|
|
442
|
-
// Replace all [paste #N +xxx lines] or [paste #N xxx chars] markers with actual paste content
|
|
443
|
-
for (const [pasteId, pasteContent] of this.pastes) {
|
|
444
|
-
// Match formats: [paste #N], [paste #N +xxx lines], or [paste #N xxx chars]
|
|
445
|
-
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
446
|
-
result = result.replace(markerRegex, pasteContent);
|
|
447
|
-
}
|
|
448
|
-
// Reset editor and clear pastes
|
|
449
|
-
this.state = {
|
|
450
|
-
lines: [""],
|
|
451
|
-
cursorLine: 0,
|
|
452
|
-
cursorCol: 0,
|
|
453
|
-
};
|
|
454
|
-
this.pastes.clear();
|
|
455
|
-
this.pasteCounter = 0;
|
|
456
|
-
this.historyIndex = -1; // Exit history browsing mode
|
|
457
|
-
// Notify that editor is now empty
|
|
458
|
-
if (this.onChange) {
|
|
459
|
-
this.onChange("");
|
|
460
|
-
}
|
|
461
|
-
if (this.onSubmit) {
|
|
462
|
-
this.onSubmit(result);
|
|
463
|
-
}
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
handleModifiedEnterKey(data) {
|
|
493
|
+
if (!this.isModifiedEnter(data)) {
|
|
494
|
+
return false;
|
|
464
495
|
}
|
|
465
|
-
//
|
|
466
|
-
|
|
496
|
+
// If submit is disabled, do nothing
|
|
497
|
+
if (this.disableSubmit) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
// Get text and substitute paste markers with actual content
|
|
501
|
+
let result = this.state.lines.join("\n").trim();
|
|
502
|
+
// Replace all [paste #N +xxx lines] or [paste #N xxx chars] markers with actual paste content
|
|
503
|
+
for (const [pasteId, pasteContent] of this.pastes) {
|
|
504
|
+
// Match formats: [paste #N], [paste #N +xxx lines], or [paste #N xxx chars]
|
|
505
|
+
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
506
|
+
result = result.replace(markerRegex, pasteContent);
|
|
507
|
+
}
|
|
508
|
+
// Reset editor and clear pastes
|
|
509
|
+
this.state = {
|
|
510
|
+
lines: [""],
|
|
511
|
+
cursorLine: 0,
|
|
512
|
+
cursorCol: 0,
|
|
513
|
+
};
|
|
514
|
+
this.pastes.clear();
|
|
515
|
+
this.pasteCounter = 0;
|
|
516
|
+
this.historyIndex = -1; // Exit history browsing mode
|
|
517
|
+
this.addToHistory(result); // Save submitted text to history
|
|
518
|
+
// Notify that editor is now empty
|
|
519
|
+
if (this.onChange) {
|
|
520
|
+
this.onChange("");
|
|
521
|
+
}
|
|
522
|
+
if (this.onSubmit) {
|
|
523
|
+
this.onSubmit(result);
|
|
524
|
+
}
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
handleBackspaceKey(data) {
|
|
528
|
+
if (data.charCodeAt(0) === 127 || data.charCodeAt(0) === 8) {
|
|
467
529
|
this.handleBackspace();
|
|
530
|
+
return true;
|
|
468
531
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
handleHomeEndKeys(data) {
|
|
535
|
+
// Home key: \x1b[H, \x1b[1~, or \x1b[7~
|
|
536
|
+
if (data === "\x1b[H" || data === "\x1b[1~" || data === "\x1b[7~") {
|
|
472
537
|
this.moveToLineStart();
|
|
538
|
+
return true;
|
|
473
539
|
}
|
|
474
|
-
|
|
475
|
-
|
|
540
|
+
// End key: \x1b[F, \x1b[4~, or \x1b[8~
|
|
541
|
+
if (data === "\x1b[F" || data === "\x1b[4~" || data === "\x1b[8~") {
|
|
476
542
|
this.moveToLineEnd();
|
|
543
|
+
return true;
|
|
477
544
|
}
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
handleForwardDeleteKey(data) {
|
|
478
548
|
// Forward delete (Fn+Backspace or Delete key)
|
|
479
|
-
|
|
480
|
-
// Delete key
|
|
549
|
+
if (data === "\x1b[3~") {
|
|
481
550
|
this.handleForwardDelete();
|
|
551
|
+
return true;
|
|
482
552
|
}
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
handleWordNavigation(data) {
|
|
483
556
|
// Word navigation (Option/Alt + Arrow or Ctrl + Arrow)
|
|
484
557
|
// Option+Left: \x1b[1;3D or \x1bb
|
|
485
558
|
// Option+Right: \x1b[1;3C or \x1bf
|
|
486
559
|
// Ctrl+Left: \x1b[1;5D
|
|
487
560
|
// Ctrl+Right: \x1b[1;5C
|
|
488
|
-
|
|
489
|
-
// Word left
|
|
561
|
+
if (data === "\x1b[1;3D" || data === "\x1bb" || data === "\x1b[1;5D") {
|
|
490
562
|
this.moveWordBackwards();
|
|
563
|
+
return true;
|
|
491
564
|
}
|
|
492
|
-
|
|
493
|
-
data === "\x1bf" ||
|
|
494
|
-
data === "\x1b[1;5C") {
|
|
495
|
-
// Word right
|
|
565
|
+
if (data === "\x1b[1;3C" || data === "\x1bf" || data === "\x1b[1;5C") {
|
|
496
566
|
this.moveWordForwards();
|
|
567
|
+
return true;
|
|
497
568
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
handleArrowKeys(data) {
|
|
572
|
+
// Up arrow
|
|
573
|
+
if (data === "\x1b[A") {
|
|
501
574
|
if (this.isEditorEmpty()) {
|
|
502
575
|
this.navigateHistory(-1); // Start browsing history
|
|
503
576
|
}
|
|
@@ -507,28 +580,29 @@ export class Editor {
|
|
|
507
580
|
else {
|
|
508
581
|
this.moveCursor(-1, 0); // Cursor movement (within text or history entry)
|
|
509
582
|
}
|
|
583
|
+
return true;
|
|
510
584
|
}
|
|
511
|
-
|
|
512
|
-
|
|
585
|
+
// Down arrow
|
|
586
|
+
if (data === "\x1b[B") {
|
|
513
587
|
if (this.historyIndex > -1 && this.isOnLastVisualLine()) {
|
|
514
588
|
this.navigateHistory(1); // Navigate to newer history entry or clear
|
|
515
589
|
}
|
|
516
590
|
else {
|
|
517
591
|
this.moveCursor(1, 0); // Cursor movement (within text or history entry)
|
|
518
592
|
}
|
|
593
|
+
return true;
|
|
519
594
|
}
|
|
520
|
-
|
|
521
|
-
|
|
595
|
+
// Right arrow
|
|
596
|
+
if (data === "\x1b[C") {
|
|
522
597
|
this.moveCursor(0, 1);
|
|
598
|
+
return true;
|
|
523
599
|
}
|
|
524
|
-
|
|
525
|
-
|
|
600
|
+
// Left arrow
|
|
601
|
+
if (data === "\x1b[D") {
|
|
526
602
|
this.moveCursor(0, -1);
|
|
603
|
+
return true;
|
|
527
604
|
}
|
|
528
|
-
|
|
529
|
-
else if (data.charCodeAt(0) >= 32) {
|
|
530
|
-
this.insertCharacter(data);
|
|
531
|
-
}
|
|
605
|
+
return false;
|
|
532
606
|
}
|
|
533
607
|
layoutText(contentWidth) {
|
|
534
608
|
const layoutLines = [];
|
|
@@ -610,7 +684,7 @@ export class Editor {
|
|
|
610
684
|
this.setTextInternal(text);
|
|
611
685
|
}
|
|
612
686
|
// All the editor methods from before...
|
|
613
|
-
insertCharacter(char) {
|
|
687
|
+
insertCharacter(char, suppressAutocomplete = false) {
|
|
614
688
|
this.historyIndex = -1; // Exit history browsing mode
|
|
615
689
|
const line = this.state.lines[this.state.cursorLine] || "";
|
|
616
690
|
const before = line.slice(0, this.state.cursorCol);
|
|
@@ -620,50 +694,16 @@ export class Editor {
|
|
|
620
694
|
if (this.onChange) {
|
|
621
695
|
this.onChange(this.getText());
|
|
622
696
|
}
|
|
697
|
+
// Skip autocomplete triggering during paste operations
|
|
698
|
+
if (suppressAutocomplete) {
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
623
701
|
// Check if we should trigger or update autocomplete
|
|
624
702
|
if (!this.isAutocompleting) {
|
|
625
|
-
|
|
626
|
-
if (char === "/" && this.isAtStartOfMessage()) {
|
|
627
|
-
void this.tryTriggerAutocomplete();
|
|
628
|
-
}
|
|
629
|
-
// Auto-trigger for "@" file reference (fuzzy search)
|
|
630
|
-
else if (char === "@") {
|
|
703
|
+
if (this.autocompleteProvider) {
|
|
631
704
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
632
705
|
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
633
|
-
|
|
634
|
-
const charBeforeAt = textBeforeCursor[textBeforeCursor.length - 2];
|
|
635
|
-
if (textBeforeCursor.length === 1 ||
|
|
636
|
-
charBeforeAt === " " ||
|
|
637
|
-
charBeforeAt === "\t") {
|
|
638
|
-
void this.tryTriggerAutocomplete();
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
// Auto-trigger for "#" file search
|
|
642
|
-
else if (char === "#") {
|
|
643
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
644
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
645
|
-
// Only trigger if # is after whitespace or at start of line
|
|
646
|
-
const charBeforeHash = textBeforeCursor[textBeforeCursor.length - 2];
|
|
647
|
-
if (textBeforeCursor.length === 1 ||
|
|
648
|
-
charBeforeHash === " " ||
|
|
649
|
-
charBeforeHash === "\t") {
|
|
650
|
-
void this.tryTriggerAutocomplete();
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
// Also auto-trigger when typing letters in a slash command context
|
|
654
|
-
else if (/[a-zA-Z0-9]/.test(char)) {
|
|
655
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
656
|
-
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
657
|
-
// Check if we're in a slash command (with or without space for arguments)
|
|
658
|
-
if (textBeforeCursor.trimStart().startsWith("/")) {
|
|
659
|
-
void this.tryTriggerAutocomplete();
|
|
660
|
-
}
|
|
661
|
-
// Check if we're in an @ file reference context
|
|
662
|
-
else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
|
|
663
|
-
void this.tryTriggerAutocomplete();
|
|
664
|
-
}
|
|
665
|
-
// Check if we're in a # file search context
|
|
666
|
-
else if (textBeforeCursor.match(/(?:^|[\s])#[^\s]*$/)) {
|
|
706
|
+
if (this.autocompleteProvider.matchesContext(textBeforeCursor)) {
|
|
667
707
|
void this.tryTriggerAutocomplete();
|
|
668
708
|
}
|
|
669
709
|
}
|
|
@@ -696,7 +736,7 @@ export class Editor {
|
|
|
696
736
|
? `[paste #${pasteId} +${pastedLines.length} lines]`
|
|
697
737
|
: `[paste #${pasteId} ${totalChars} chars]`;
|
|
698
738
|
for (const char of marker) {
|
|
699
|
-
this.insertCharacter(char);
|
|
739
|
+
this.insertCharacter(char, true);
|
|
700
740
|
}
|
|
701
741
|
return;
|
|
702
742
|
}
|
|
@@ -704,7 +744,7 @@ export class Editor {
|
|
|
704
744
|
// Single line - just insert each character
|
|
705
745
|
const text = pastedLines[0] || "";
|
|
706
746
|
for (const char of text) {
|
|
707
|
-
this.insertCharacter(char);
|
|
747
|
+
this.insertCharacter(char, true);
|
|
708
748
|
}
|
|
709
749
|
return;
|
|
710
750
|
}
|
|
@@ -779,12 +819,10 @@ export class Editor {
|
|
|
779
819
|
if (this.isAutocompleting) {
|
|
780
820
|
void this.updateAutocomplete();
|
|
781
821
|
}
|
|
782
|
-
else {
|
|
783
|
-
// Check if we should trigger autocomplete after backspace in slash command context
|
|
822
|
+
else if (this.autocompleteProvider) {
|
|
784
823
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
785
824
|
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
786
|
-
|
|
787
|
-
if (textBeforeCursor.startsWith("/") && !textBeforeCursor.includes(" ")) {
|
|
825
|
+
if (this.autocompleteProvider.matchesContext(textBeforeCursor)) {
|
|
788
826
|
void this.tryTriggerAutocomplete();
|
|
789
827
|
}
|
|
790
828
|
}
|
|
@@ -1063,13 +1101,6 @@ export class Editor {
|
|
|
1063
1101
|
}
|
|
1064
1102
|
this.state.cursorCol = newCol;
|
|
1065
1103
|
}
|
|
1066
|
-
// Helper method to check if cursor is at start of message (for slash command detection)
|
|
1067
|
-
isAtStartOfMessage() {
|
|
1068
|
-
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1069
|
-
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1070
|
-
// At start if line is empty, only contains whitespace, or is just "/"
|
|
1071
|
-
return beforeCursor.trim() === "" || beforeCursor.trim() === "/";
|
|
1072
|
-
}
|
|
1073
1104
|
// Autocomplete methods
|
|
1074
1105
|
async tryTriggerAutocomplete(explicitTab = false) {
|
|
1075
1106
|
if (!this.autocompleteProvider)
|
|
@@ -1111,41 +1142,12 @@ export class Editor {
|
|
|
1111
1142
|
if (beforeCursor.trimStart().startsWith("/")) {
|
|
1112
1143
|
await this.handleSlashCommandCompletion();
|
|
1113
1144
|
}
|
|
1114
|
-
else {
|
|
1115
|
-
await this.forceFileAutocomplete();
|
|
1116
|
-
}
|
|
1117
1145
|
}
|
|
1118
1146
|
async handleSlashCommandCompletion() {
|
|
1119
1147
|
// For now, fall back to regular autocomplete (slash commands)
|
|
1120
1148
|
// This can be extended later to handle command-specific argument completion
|
|
1121
1149
|
await this.tryTriggerAutocomplete(true);
|
|
1122
1150
|
}
|
|
1123
|
-
async forceFileAutocomplete() {
|
|
1124
|
-
if (!this.autocompleteProvider)
|
|
1125
|
-
return;
|
|
1126
|
-
// Check if provider has the force method
|
|
1127
|
-
const provider = this.autocompleteProvider;
|
|
1128
|
-
if (!provider.getForceFileSuggestions) {
|
|
1129
|
-
await this.tryTriggerAutocomplete(true);
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
const suggestions = await provider.getForceFileSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1133
|
-
if (suggestions && suggestions.items.length > 0) {
|
|
1134
|
-
this.autocompletePrefix = suggestions.prefix;
|
|
1135
|
-
if (this.autocompleteList) {
|
|
1136
|
-
this.autocompleteList.updateItems(suggestions.items);
|
|
1137
|
-
}
|
|
1138
|
-
else {
|
|
1139
|
-
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1140
|
-
}
|
|
1141
|
-
this.isAutocompleting = true;
|
|
1142
|
-
// Request re-render to show autocomplete list
|
|
1143
|
-
this.onRenderRequested?.();
|
|
1144
|
-
}
|
|
1145
|
-
else {
|
|
1146
|
-
this.cancelAutocomplete();
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
1151
|
cancelAutocomplete() {
|
|
1150
1152
|
this.isAutocompleting = false;
|
|
1151
1153
|
this.autocompleteList = undefined;
|
|
@@ -1158,28 +1160,18 @@ export class Editor {
|
|
|
1158
1160
|
isShowingAutocomplete() {
|
|
1159
1161
|
return this.isAutocompleting;
|
|
1160
1162
|
}
|
|
1163
|
+
wantsNavigationKeys() {
|
|
1164
|
+
return this.isAutocompleting;
|
|
1165
|
+
}
|
|
1161
1166
|
async updateAutocomplete() {
|
|
1162
1167
|
if (!this.isAutocompleting || !this.autocompleteProvider)
|
|
1163
1168
|
return;
|
|
1164
1169
|
// Check if the current text still matches our autocomplete context
|
|
1165
|
-
// This prevents unnecessary updates when typing unrelated text
|
|
1166
1170
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
1167
1171
|
const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (textBeforeCursor.startsWith("/") ||
|
|
1172
|
-
textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/) ||
|
|
1173
|
-
textBeforeCursor.match(/(?:^|[\s])#[^\s]*$/)) {
|
|
1174
|
-
// For slash commands, @ file attachments, and # file search,
|
|
1175
|
-
// continue autocomplete as long as we're in the right context
|
|
1176
|
-
}
|
|
1177
|
-
else {
|
|
1178
|
-
// For other file paths, check if we're still in the same path context
|
|
1179
|
-
if (!textBeforeCursor.endsWith(this.autocompletePrefix)) {
|
|
1180
|
-
this.cancelAutocomplete();
|
|
1181
|
-
return;
|
|
1182
|
-
}
|
|
1172
|
+
if (!this.autocompleteProvider.matchesContext(textBeforeCursor)) {
|
|
1173
|
+
this.cancelAutocomplete();
|
|
1174
|
+
return;
|
|
1183
1175
|
}
|
|
1184
1176
|
// Clear any existing debounce timer
|
|
1185
1177
|
if (this.autocompleteDebounceTimer) {
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import type { LanguageModelUsage } from "ai";
|
|
2
1
|
import type { AgentState } from "../../agent/index.ts";
|
|
3
2
|
import type { ModelManager } from "../../models/manager.ts";
|
|
4
3
|
import type { ProjectStatusData } from "../../repl/project-status.ts";
|
|
4
|
+
import type { TokenTracker } from "../../tokens/tracker.ts";
|
|
5
5
|
import { type Component } from "../tui.ts";
|
|
6
6
|
type State = {
|
|
7
7
|
projectStatus: ProjectStatusData;
|
|
8
8
|
currentContextWindow: number;
|
|
9
9
|
contextWindow: number;
|
|
10
|
-
usage?: LanguageModelUsage;
|
|
11
10
|
agentState?: AgentState;
|
|
11
|
+
currentMode?: string;
|
|
12
12
|
};
|
|
13
13
|
export declare class FooterComponent implements Component {
|
|
14
14
|
private modelManager;
|
|
15
|
+
private tokenTracker?;
|
|
15
16
|
private state;
|
|
16
17
|
private progressBar;
|
|
17
|
-
private usage?;
|
|
18
18
|
private agentState?;
|
|
19
|
-
|
|
19
|
+
private currentMode;
|
|
20
|
+
constructor(modelManager: ModelManager, tokenTracker: TokenTracker | undefined, state: State);
|
|
20
21
|
setState(state: State): void;
|
|
21
22
|
resetState(): void;
|
|
23
|
+
getProjectStatus(): ProjectStatusData;
|
|
22
24
|
render(width: number): string[];
|
|
23
25
|
}
|
|
24
26
|
export {};
|