indusagi 0.12.13 → 0.12.16
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/dist/agent/agent-session.d.ts +352 -0
- package/dist/agent/agent-session.d.ts.map +1 -0
- package/dist/agent/agent-session.js +870 -0
- package/dist/agent/agent-session.js.map +1 -0
- package/dist/agent/agent-session.test.d.ts +5 -0
- package/dist/agent/agent-session.test.d.ts.map +1 -0
- package/dist/agent/agent-session.test.js +129 -0
- package/dist/agent/agent-session.test.js.map +1 -0
- package/dist/agent/agent.d.ts +108 -2
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +210 -17
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/bash-executor.d.ts +33 -0
- package/dist/agent/bash-executor.d.ts.map +1 -0
- package/dist/agent/bash-executor.js +197 -0
- package/dist/agent/bash-executor.js.map +1 -0
- package/dist/agent/compaction/compaction.d.ts +87 -0
- package/dist/agent/compaction/compaction.d.ts.map +1 -0
- package/dist/agent/compaction/compaction.js +598 -0
- package/dist/agent/compaction/compaction.js.map +1 -0
- package/dist/agent/compaction/index.d.ts +6 -0
- package/dist/agent/compaction/index.d.ts.map +1 -0
- package/dist/agent/compaction/index.js +6 -0
- package/dist/agent/compaction/index.js.map +1 -0
- package/dist/agent/compaction/utils.d.ts +41 -0
- package/dist/agent/compaction/utils.d.ts.map +1 -0
- package/dist/agent/compaction/utils.js +240 -0
- package/dist/agent/compaction/utils.js.map +1 -0
- package/dist/agent/event-bus.js +1 -3
- package/dist/agent/event-bus.js.map +1 -1
- package/dist/agent/index.d.ts +11 -5
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +19 -8
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/messages.d.ts +2 -48
- package/dist/agent/messages.d.ts.map +1 -1
- package/dist/agent/messages.js.map +1 -1
- package/dist/agent/proxy.js.map +1 -1
- package/dist/agent/session-manager.d.ts +2 -3
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +10 -6
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/agent/settings-manager.d.ts +204 -0
- package/dist/agent/settings-manager.d.ts.map +1 -0
- package/dist/agent/settings-manager.js +594 -0
- package/dist/agent/settings-manager.js.map +1 -0
- package/dist/agent/state-manager.js +1 -0
- package/dist/agent/state-manager.js.map +1 -1
- package/dist/agent/telemetry.js +1 -3
- package/dist/agent/telemetry.js.map +1 -1
- package/dist/agent/tools/bash.js +1 -0
- package/dist/agent/tools/bash.js.map +1 -1
- package/dist/agent/tools/edit.test.d.ts +6 -0
- package/dist/agent/tools/edit.test.d.ts.map +1 -0
- package/dist/agent/tools/edit.test.js +196 -0
- package/dist/agent/tools/edit.test.js.map +1 -0
- package/dist/agent/tools/index.d.ts +26 -26
- package/dist/agent/tools/registry.d.ts +1 -1
- package/dist/agent/tools/registry.d.ts.map +1 -1
- package/dist/agent/tools/registry.js +2 -4
- package/dist/agent/tools/registry.js.map +1 -1
- package/dist/agent/tools/todo-store.js +2 -1
- package/dist/agent/tools/todo-store.js.map +1 -1
- package/dist/agent/tools/utils/hook-runner.js +1 -3
- package/dist/agent/tools/utils/hook-runner.js.map +1 -1
- package/dist/agent/types.d.ts +139 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/ai/api-registry.js +1 -3
- package/dist/ai/api-registry.js.map +1 -1
- package/dist/ai/models.generated.d.ts +621 -53
- package/dist/ai/models.generated.d.ts.map +1 -1
- package/dist/ai/models.generated.js +548 -0
- package/dist/ai/models.generated.js.map +1 -1
- package/dist/ai/models.js +1 -0
- package/dist/ai/models.js.map +1 -1
- package/dist/ai/providers/amazon-bedrock.d.ts +6 -0
- package/dist/ai/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/ai/providers/amazon-bedrock.js +47 -9
- package/dist/ai/providers/amazon-bedrock.js.map +1 -1
- package/dist/ai/providers/anthropic.d.ts +8 -0
- package/dist/ai/providers/anthropic.d.ts.map +1 -1
- package/dist/ai/providers/anthropic.js +28 -12
- package/dist/ai/providers/anthropic.js.map +1 -1
- package/dist/ai/providers/azure-openai-responses.js +1 -0
- package/dist/ai/providers/azure-openai-responses.js.map +1 -1
- package/dist/ai/providers/github-copilot-headers.d.ts +33 -0
- package/dist/ai/providers/github-copilot-headers.d.ts.map +1 -0
- package/dist/ai/providers/github-copilot-headers.js +51 -0
- package/dist/ai/providers/github-copilot-headers.js.map +1 -0
- package/dist/ai/providers/google-shared.d.ts.map +1 -1
- package/dist/ai/providers/google-shared.js +16 -22
- package/dist/ai/providers/google-shared.js.map +1 -1
- package/dist/ai/providers/google-vertex.d.ts.map +1 -1
- package/dist/ai/providers/google-vertex.js +28 -5
- package/dist/ai/providers/google-vertex.js.map +1 -1
- package/dist/ai/providers/google.js +1 -0
- package/dist/ai/providers/google.js.map +1 -1
- package/dist/ai/providers/kimi.js +1 -0
- package/dist/ai/providers/kimi.js.map +1 -1
- package/dist/ai/providers/mistral.d.ts +22 -0
- package/dist/ai/providers/mistral.d.ts.map +1 -0
- package/dist/ai/providers/mistral.js +497 -0
- package/dist/ai/providers/mistral.js.map +1 -0
- package/dist/ai/providers/openai-codex-responses.js +1 -0
- package/dist/ai/providers/openai-codex-responses.js.map +1 -1
- package/dist/ai/providers/openai-completions.js +2 -0
- package/dist/ai/providers/openai-completions.js.map +1 -1
- package/dist/ai/providers/openai-responses.d.ts.map +1 -1
- package/dist/ai/providers/openai-responses.js +30 -0
- package/dist/ai/providers/openai-responses.js.map +1 -1
- package/dist/ai/providers/register-builtins.d.ts.map +1 -1
- package/dist/ai/providers/register-builtins.js +6 -0
- package/dist/ai/providers/register-builtins.js.map +1 -1
- package/dist/ai/providers/simple-options.js +2 -0
- package/dist/ai/providers/simple-options.js.map +1 -1
- package/dist/ai/providers/transform-messages.js +3 -9
- package/dist/ai/providers/transform-messages.js.map +1 -1
- package/dist/ai/stream.js +1 -3
- package/dist/ai/stream.js.map +1 -1
- package/dist/ai/types.d.ts +34 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/ai/utils/base-stream-handler.js +1 -0
- package/dist/ai/utils/base-stream-handler.js.map +1 -1
- package/dist/ai/utils/event-stream.js +9 -4
- package/dist/ai/utils/event-stream.js.map +1 -1
- package/dist/ai/utils/hash.d.ts +6 -0
- package/dist/ai/utils/hash.d.ts.map +1 -0
- package/dist/ai/utils/hash.js +17 -0
- package/dist/ai/utils/hash.js.map +1 -0
- package/dist/ai/utils/index.d.ts +1 -0
- package/dist/ai/utils/index.d.ts.map +1 -1
- package/dist/ai/utils/index.js +1 -0
- package/dist/ai/utils/index.js.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.js +19 -8
- package/dist/ai/utils/oauth/github-copilot.js.map +1 -1
- package/dist/ai/utils/overflow.d.ts.map +1 -1
- package/dist/ai/utils/overflow.js +4 -0
- package/dist/ai/utils/overflow.js.map +1 -1
- package/dist/ai/utils/provider-adapter.js +9 -0
- package/dist/ai/utils/provider-adapter.js.map +1 -1
- package/dist/ai/utils/provider-client-builder.js +1 -1
- package/dist/ai/utils/provider-client-builder.js.map +1 -1
- package/dist/ai/utils/provider-errors.js +2 -0
- package/dist/ai/utils/provider-errors.js.map +1 -1
- package/dist/ai/utils/stream-event-helper.js +3 -0
- package/dist/ai/utils/stream-event-helper.js.map +1 -1
- package/dist/ai/utils/stream-handler-types.js +5 -0
- package/dist/ai/utils/stream-handler-types.js.map +1 -1
- package/dist/ai/utils/streaming-state-manager.js +4 -2
- package/dist/ai/utils/streaming-state-manager.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/client-pool.d.ts +106 -0
- package/dist/mcp/client-pool.d.ts.map +1 -0
- package/dist/mcp/client-pool.js +234 -0
- package/dist/mcp/client-pool.js.map +1 -0
- package/dist/mcp/client.d.ts +158 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +599 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/config.d.ts +61 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +250 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/errors.d.ts +104 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +146 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/index.d.ts +56 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +83 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/schema-converter.d.ts +68 -0
- package/dist/mcp/schema-converter.d.ts.map +1 -0
- package/dist/mcp/schema-converter.js +230 -0
- package/dist/mcp/schema-converter.js.map +1 -0
- package/dist/mcp/server.d.ts +111 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +305 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tool-factory.d.ts +63 -0
- package/dist/mcp/tool-factory.d.ts.map +1 -0
- package/dist/mcp/tool-factory.js +228 -0
- package/dist/mcp/tool-factory.js.map +1 -0
- package/dist/mcp/types.d.ts +289 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +8 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp.d.ts +6 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +6 -0
- package/dist/mcp.js.map +1 -0
- package/dist/memory/embedder/base.d.ts +41 -0
- package/dist/memory/embedder/base.d.ts.map +1 -0
- package/dist/memory/embedder/base.js +10 -0
- package/dist/memory/embedder/base.js.map +1 -0
- package/dist/memory/embedder/index.d.ts +8 -0
- package/dist/memory/embedder/index.d.ts.map +1 -0
- package/dist/memory/embedder/index.js +6 -0
- package/dist/memory/embedder/index.js.map +1 -0
- package/dist/memory/embedder/openai.d.ts +35 -0
- package/dist/memory/embedder/openai.d.ts.map +1 -0
- package/dist/memory/embedder/openai.js +109 -0
- package/dist/memory/embedder/openai.js.map +1 -0
- package/dist/memory/index.d.ts +33 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +31 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memory.d.ts +126 -0
- package/dist/memory/memory.d.ts.map +1 -0
- package/dist/memory/memory.js +285 -0
- package/dist/memory/memory.js.map +1 -0
- package/dist/memory/processors/base.d.ts +42 -0
- package/dist/memory/processors/base.d.ts.map +1 -0
- package/dist/memory/processors/base.js +6 -0
- package/dist/memory/processors/base.js.map +1 -0
- package/dist/memory/processors/index.d.ts +16 -0
- package/dist/memory/processors/index.d.ts.map +1 -0
- package/dist/memory/processors/index.js +18 -0
- package/dist/memory/processors/index.js.map +1 -0
- package/dist/memory/processors/message-history.d.ts +35 -0
- package/dist/memory/processors/message-history.d.ts.map +1 -0
- package/dist/memory/processors/message-history.js +53 -0
- package/dist/memory/processors/message-history.js.map +1 -0
- package/dist/memory/processors/observational-memory/index.d.ts +82 -0
- package/dist/memory/processors/observational-memory/index.d.ts.map +1 -0
- package/dist/memory/processors/observational-memory/index.js +239 -0
- package/dist/memory/processors/observational-memory/index.js.map +1 -0
- package/dist/memory/processors/observational-memory/observer-agent.d.ts +64 -0
- package/dist/memory/processors/observational-memory/observer-agent.d.ts.map +1 -0
- package/dist/memory/processors/observational-memory/observer-agent.js +362 -0
- package/dist/memory/processors/observational-memory/observer-agent.js.map +1 -0
- package/dist/memory/processors/observational-memory/reflector-agent.d.ts +38 -0
- package/dist/memory/processors/observational-memory/reflector-agent.d.ts.map +1 -0
- package/dist/memory/processors/observational-memory/reflector-agent.js +213 -0
- package/dist/memory/processors/observational-memory/reflector-agent.js.map +1 -0
- package/dist/memory/processors/observational-memory/token-counter.d.ts +35 -0
- package/dist/memory/processors/observational-memory/token-counter.d.ts.map +1 -0
- package/dist/memory/processors/observational-memory/token-counter.js +90 -0
- package/dist/memory/processors/observational-memory/token-counter.js.map +1 -0
- package/dist/memory/processors/semantic-recall.d.ts +55 -0
- package/dist/memory/processors/semantic-recall.d.ts.map +1 -0
- package/dist/memory/processors/semantic-recall.js +152 -0
- package/dist/memory/processors/semantic-recall.js.map +1 -0
- package/dist/memory/processors/working-memory.d.ts +41 -0
- package/dist/memory/processors/working-memory.d.ts.map +1 -0
- package/dist/memory/processors/working-memory.js +87 -0
- package/dist/memory/processors/working-memory.js.map +1 -0
- package/dist/memory/storage/base.d.ts +288 -0
- package/dist/memory/storage/base.d.ts.map +1 -0
- package/dist/memory/storage/base.js +209 -0
- package/dist/memory/storage/base.js.map +1 -0
- package/dist/memory/storage/index.d.ts +9 -0
- package/dist/memory/storage/index.d.ts.map +1 -0
- package/dist/memory/storage/index.js +7 -0
- package/dist/memory/storage/index.js.map +1 -0
- package/dist/memory/storage/inmemory.d.ts +93 -0
- package/dist/memory/storage/inmemory.d.ts.map +1 -0
- package/dist/memory/storage/inmemory.js +647 -0
- package/dist/memory/storage/inmemory.js.map +1 -0
- package/dist/memory/tools/working-memory.d.ts +100 -0
- package/dist/memory/tools/working-memory.d.ts.map +1 -0
- package/dist/memory/tools/working-memory.js +237 -0
- package/dist/memory/tools/working-memory.js.map +1 -0
- package/dist/memory/types.d.ts +386 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +58 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/vector/base.d.ts +145 -0
- package/dist/memory/vector/base.d.ts.map +1 -0
- package/dist/memory/vector/base.js +81 -0
- package/dist/memory/vector/base.js.map +1 -0
- package/dist/memory/vector/index.d.ts +8 -0
- package/dist/memory/vector/index.d.ts.map +1 -0
- package/dist/memory/vector/index.js +7 -0
- package/dist/memory/vector/index.js.map +1 -0
- package/dist/memory/vector/inmemory.d.ts +47 -0
- package/dist/memory/vector/inmemory.d.ts.map +1 -0
- package/dist/memory/vector/inmemory.js +231 -0
- package/dist/memory/vector/inmemory.js.map +1 -0
- package/dist/tui/autocomplete.js +5 -1
- package/dist/tui/autocomplete.js.map +1 -1
- package/dist/tui/components/box.js +9 -1
- package/dist/tui/components/box.js.map +1 -1
- package/dist/tui/components/cancellable-loader.js +3 -4
- package/dist/tui/components/cancellable-loader.js.map +1 -1
- package/dist/tui/components/editor.d.ts +39 -3
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +162 -133
- package/dist/tui/components/editor.js.map +1 -1
- package/dist/tui/components/image.js +8 -0
- package/dist/tui/components/image.js.map +1 -1
- package/dist/tui/components/input.js +10 -11
- package/dist/tui/components/input.js.map +1 -1
- package/dist/tui/components/loader.js +7 -4
- package/dist/tui/components/loader.js.map +1 -1
- package/dist/tui/components/markdown.js +10 -0
- package/dist/tui/components/markdown.js.map +1 -1
- package/dist/tui/components/select-list.js +8 -4
- package/dist/tui/components/select-list.js.map +1 -1
- package/dist/tui/components/settings-list.js +12 -4
- package/dist/tui/components/settings-list.js.map +1 -1
- package/dist/tui/components/spacer.js +1 -0
- package/dist/tui/components/spacer.js.map +1 -1
- package/dist/tui/components/text.js +5 -0
- package/dist/tui/components/text.js.map +1 -1
- package/dist/tui/components/truncated-text.js +3 -0
- package/dist/tui/components/truncated-text.js.map +1 -1
- package/dist/tui/fuzzy.js +4 -1
- package/dist/tui/fuzzy.js.map +1 -1
- package/dist/tui/keybindings.js +3 -2
- package/dist/tui/keybindings.js.map +1 -1
- package/dist/tui/keys.d.ts +17 -1
- package/dist/tui/keys.d.ts.map +1 -1
- package/dist/tui/keys.js +56 -0
- package/dist/tui/keys.js.map +1 -1
- package/dist/tui/kill-ring.d.ts +28 -0
- package/dist/tui/kill-ring.d.ts.map +1 -0
- package/dist/tui/kill-ring.js +44 -0
- package/dist/tui/kill-ring.js.map +1 -0
- package/dist/tui/stdin-buffer.js +6 -5
- package/dist/tui/stdin-buffer.js.map +1 -1
- package/dist/tui/terminal-image.js +1 -3
- package/dist/tui/terminal-image.js.map +1 -1
- package/dist/tui/terminal.d.ts +13 -0
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +70 -7
- package/dist/tui/terminal.js.map +1 -1
- package/dist/tui/tui.d.ts +36 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +101 -29
- package/dist/tui/tui.js.map +1 -1
- package/dist/tui/undo-stack.d.ts +17 -0
- package/dist/tui/undo-stack.d.ts.map +1 -0
- package/dist/tui/undo-stack.js +25 -0
- package/dist/tui/undo-stack.js.map +1 -0
- package/dist/tui/utils.js +12 -16
- package/dist/tui/utils.js.map +1 -1
- package/package.json +32 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getEditorKeybindings } from "../keybindings.js";
|
|
2
|
-
import { matchesKey } from "../keys.js";
|
|
2
|
+
import { decodeKittyPrintable, matchesKey } from "../keys.js";
|
|
3
|
+
import { KillRing } from "../kill-ring.js";
|
|
3
4
|
import { ComponentBase, CURSOR_MARKER } from "../tui.js";
|
|
5
|
+
import { UndoStack } from "../undo-stack.js";
|
|
4
6
|
import { getSegmenter, isPunctuationChar, isWhitespaceChar, visibleWidth } from "../utils.js";
|
|
5
7
|
import { SelectList } from "./select-list.js";
|
|
6
8
|
const segmenter = getSegmenter();
|
|
@@ -66,81 +68,60 @@ export function wordWrapLine(line, maxWidth) {
|
|
|
66
68
|
chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });
|
|
67
69
|
return chunks;
|
|
68
70
|
}
|
|
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
71
|
export class Editor extends ComponentBase {
|
|
72
|
+
state = {
|
|
73
|
+
lines: [""],
|
|
74
|
+
cursorLine: 0,
|
|
75
|
+
cursorCol: 0,
|
|
76
|
+
};
|
|
77
|
+
/** Focusable interface - set by TUI when focus changes */
|
|
78
|
+
focused = false;
|
|
79
|
+
tui;
|
|
80
|
+
theme;
|
|
81
|
+
paddingX = 0;
|
|
82
|
+
// Store last render width for cursor navigation
|
|
83
|
+
lastWidth = 80;
|
|
84
|
+
// Vertical scrolling support
|
|
85
|
+
scrollOffset = 0;
|
|
86
|
+
// Border color (can be changed dynamically)
|
|
87
|
+
borderColor;
|
|
88
|
+
// Autocomplete support
|
|
89
|
+
autocompleteProvider;
|
|
90
|
+
autocompleteList;
|
|
91
|
+
isAutocompleting = false;
|
|
92
|
+
autocompletePrefix = "";
|
|
93
|
+
autocompleteMaxVisible = 5;
|
|
94
|
+
// Paste tracking for large pastes
|
|
95
|
+
pastes = new Map();
|
|
96
|
+
pasteCounter = 0;
|
|
97
|
+
// Bracketed paste mode buffering
|
|
98
|
+
pasteBuffer = "";
|
|
99
|
+
isInPaste = false;
|
|
100
|
+
pendingShiftEnter = false;
|
|
101
|
+
// Prompt history for up/down navigation
|
|
102
|
+
history = [];
|
|
103
|
+
historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.
|
|
104
|
+
// Kill ring for Emacs-style kill/yank operations
|
|
105
|
+
// Also tracks undo coalescing: "type-word" means we're mid-word (coalescing)
|
|
106
|
+
killRing = new KillRing();
|
|
107
|
+
lastAction = null;
|
|
108
|
+
// Undo support
|
|
109
|
+
undoStack = new UndoStack();
|
|
110
|
+
// Sticky column navigation for wrapped lines
|
|
111
|
+
// Maintains cursor column when moving up/down through lines of different lengths
|
|
112
|
+
preferredVisualCol = null;
|
|
113
|
+
onSubmit;
|
|
114
|
+
onChange;
|
|
115
|
+
disableSubmit = false;
|
|
106
116
|
constructor(tui, theme, options = {}) {
|
|
107
117
|
super();
|
|
108
|
-
this.state = {
|
|
109
|
-
lines: [""],
|
|
110
|
-
cursorLine: 0,
|
|
111
|
-
cursorCol: 0,
|
|
112
|
-
};
|
|
113
|
-
/** Focusable interface - set by TUI when focus changes */
|
|
114
|
-
this.focused = false;
|
|
115
|
-
this.paddingX = 0;
|
|
116
|
-
// Store last render width for cursor navigation
|
|
117
|
-
this.lastWidth = 80;
|
|
118
|
-
// Vertical scrolling support
|
|
119
|
-
this.scrollOffset = 0;
|
|
120
|
-
this.isAutocompleting = false;
|
|
121
|
-
this.autocompletePrefix = "";
|
|
122
|
-
// Paste tracking for large pastes
|
|
123
|
-
this.pastes = new Map();
|
|
124
|
-
this.pasteCounter = 0;
|
|
125
|
-
// Bracketed paste mode buffering
|
|
126
|
-
this.pasteBuffer = "";
|
|
127
|
-
this.isInPaste = false;
|
|
128
|
-
this.pendingShiftEnter = false;
|
|
129
|
-
// Prompt history for up/down navigation
|
|
130
|
-
this.history = [];
|
|
131
|
-
this.historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.
|
|
132
|
-
// Kill ring for Emacs-style kill/yank operations
|
|
133
|
-
// Also tracks undo coalescing: "type-word" means we're mid-word (coalescing)
|
|
134
|
-
this.killRing = [];
|
|
135
|
-
this.lastAction = null;
|
|
136
|
-
// Undo support
|
|
137
|
-
this.undoStack = [];
|
|
138
|
-
this.disableSubmit = false;
|
|
139
118
|
this.tui = tui;
|
|
140
119
|
this.theme = theme;
|
|
141
120
|
this.borderColor = theme.borderColor;
|
|
142
121
|
const paddingX = options.paddingX ?? 0;
|
|
143
122
|
this.paddingX = Number.isFinite(paddingX) ? Math.max(0, Math.floor(paddingX)) : 0;
|
|
123
|
+
const maxVisible = options.autocompleteMaxVisible ?? 5;
|
|
124
|
+
this.autocompleteMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;
|
|
144
125
|
}
|
|
145
126
|
getPaddingX() {
|
|
146
127
|
return this.paddingX;
|
|
@@ -152,6 +133,16 @@ export class Editor extends ComponentBase {
|
|
|
152
133
|
this.tui.requestRender();
|
|
153
134
|
}
|
|
154
135
|
}
|
|
136
|
+
getAutocompleteMaxVisible() {
|
|
137
|
+
return this.autocompleteMaxVisible;
|
|
138
|
+
}
|
|
139
|
+
setAutocompleteMaxVisible(maxVisible) {
|
|
140
|
+
const newMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;
|
|
141
|
+
if (this.autocompleteMaxVisible !== newMaxVisible) {
|
|
142
|
+
this.autocompleteMaxVisible = newMaxVisible;
|
|
143
|
+
this.tui.requestRender();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
155
146
|
setAutocompleteProvider(provider) {
|
|
156
147
|
this.autocompleteProvider = provider;
|
|
157
148
|
this.invalidate();
|
|
@@ -502,7 +493,7 @@ export class Editor extends ComponentBase {
|
|
|
502
493
|
this.pasteCounter = 0;
|
|
503
494
|
this.historyIndex = -1;
|
|
504
495
|
this.scrollOffset = 0;
|
|
505
|
-
this.undoStack.
|
|
496
|
+
this.undoStack.clear();
|
|
506
497
|
this.lastAction = null;
|
|
507
498
|
if (this.onChange)
|
|
508
499
|
this.onChange("");
|
|
@@ -899,14 +890,93 @@ export class Editor extends ComponentBase {
|
|
|
899
890
|
}
|
|
900
891
|
}
|
|
901
892
|
}
|
|
893
|
+
/**
|
|
894
|
+
* Set cursor column and clear sticky column preference.
|
|
895
|
+
* Call this for any direct column positioning or horizontal movement.
|
|
896
|
+
*/
|
|
897
|
+
setCursorCol(col) {
|
|
898
|
+
this.state.cursorCol = col;
|
|
899
|
+
this.preferredVisualCol = null;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Move cursor to a target visual line, applying sticky column logic.
|
|
903
|
+
* Preserves the cursor column when moving between wrapped lines of different widths.
|
|
904
|
+
*/
|
|
905
|
+
moveToVisualLine(visualLines, currentVisualLine, targetVisualLine) {
|
|
906
|
+
const currentVL = visualLines[currentVisualLine];
|
|
907
|
+
const targetVL = visualLines[targetVisualLine];
|
|
908
|
+
if (currentVL && targetVL) {
|
|
909
|
+
const currentVisualCol = this.state.cursorCol - currentVL.startCol;
|
|
910
|
+
// For non-last segments, clamp to length-1 to stay within the segment
|
|
911
|
+
const isLastSourceSegment = currentVisualLine === visualLines.length - 1 ||
|
|
912
|
+
visualLines[currentVisualLine + 1]?.logicalLine !== currentVL.logicalLine;
|
|
913
|
+
const sourceMaxVisualCol = isLastSourceSegment ? currentVL.length : Math.max(0, currentVL.length - 1);
|
|
914
|
+
const isLastTargetSegment = targetVisualLine === visualLines.length - 1 ||
|
|
915
|
+
visualLines[targetVisualLine + 1]?.logicalLine !== targetVL.logicalLine;
|
|
916
|
+
const targetMaxVisualCol = isLastTargetSegment ? targetVL.length : Math.max(0, targetVL.length - 1);
|
|
917
|
+
const moveToVisualCol = this.computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol);
|
|
918
|
+
// Set cursor position
|
|
919
|
+
this.state.cursorLine = targetVL.logicalLine;
|
|
920
|
+
const targetCol = targetVL.startCol + moveToVisualCol;
|
|
921
|
+
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
922
|
+
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Compute the target visual column for vertical cursor movement.
|
|
927
|
+
* Implements sticky column logic: maintains the cursor column when moving between
|
|
928
|
+
* wrapped lines of different lengths.
|
|
929
|
+
*
|
|
930
|
+
* Decision table:
|
|
931
|
+
* | P | S | T | U | Scenario | Set Preferred | Move To |
|
|
932
|
+
* |---|---|---|---| ---------------------------------------------------- |---------------|-------------|
|
|
933
|
+
* | 0 | * | 0 | - | Start nav, target fits | null | current |
|
|
934
|
+
* | 0 | * | 1 | - | Start nav, target shorter | current | target end |
|
|
935
|
+
* | 1 | 0 | 0 | 0 | Clamped, target fits preferred | null | preferred |
|
|
936
|
+
* | 1 | 0 | 0 | 1 | Clamped, target longer but still can't fit preferred | keep | target end |
|
|
937
|
+
* | 1 | 0 | 1 | - | Clamped, target even shorter | keep | target end |
|
|
938
|
+
* | 1 | 1 | 0 | - | Rewrapped, target fits current | null | current |
|
|
939
|
+
* | 1 | 1 | 1 | - | Rewrapped, target shorter than current | current | target end |
|
|
940
|
+
*
|
|
941
|
+
* Where:
|
|
942
|
+
* - P = preferred col is set
|
|
943
|
+
* - S = cursor in middle of source line (not clamped to end)
|
|
944
|
+
* - T = target line shorter than current visual col
|
|
945
|
+
* - U = target line shorter than preferred col
|
|
946
|
+
*/
|
|
947
|
+
computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol) {
|
|
948
|
+
const hasPreferred = this.preferredVisualCol !== null; // P
|
|
949
|
+
const cursorInMiddle = currentVisualCol < sourceMaxVisualCol; // S
|
|
950
|
+
const targetTooShort = targetMaxVisualCol < currentVisualCol; // T
|
|
951
|
+
if (!hasPreferred || cursorInMiddle) {
|
|
952
|
+
if (targetTooShort) {
|
|
953
|
+
// Cases 2 and 7: Start of navigation with target shorter than current
|
|
954
|
+
// Save current column as preferred for later restoration
|
|
955
|
+
this.preferredVisualCol = currentVisualCol;
|
|
956
|
+
return targetMaxVisualCol;
|
|
957
|
+
}
|
|
958
|
+
// Cases 1 and 6: Target fits current column
|
|
959
|
+
this.preferredVisualCol = null;
|
|
960
|
+
return currentVisualCol;
|
|
961
|
+
}
|
|
962
|
+
const targetCantFitPreferred = targetMaxVisualCol < this.preferredVisualCol; // U
|
|
963
|
+
if (targetTooShort || targetCantFitPreferred) {
|
|
964
|
+
// Cases 4 and 5: Target can't fit preferred, clamp to target end
|
|
965
|
+
return targetMaxVisualCol;
|
|
966
|
+
}
|
|
967
|
+
// Case 3: Target can fit preferred, restore it and clear preference
|
|
968
|
+
const result = this.preferredVisualCol;
|
|
969
|
+
this.preferredVisualCol = null;
|
|
970
|
+
return result;
|
|
971
|
+
}
|
|
902
972
|
moveToLineStart() {
|
|
903
973
|
this.lastAction = null;
|
|
904
|
-
this.
|
|
974
|
+
this.setCursorCol(0);
|
|
905
975
|
}
|
|
906
976
|
moveToLineEnd() {
|
|
907
977
|
this.lastAction = null;
|
|
908
978
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
909
|
-
this.
|
|
979
|
+
this.setCursorCol(currentLine.length);
|
|
910
980
|
}
|
|
911
981
|
deleteToStartOfLine() {
|
|
912
982
|
this.historyIndex = -1; // Exit history browsing mode
|
|
@@ -1138,20 +1208,10 @@ export class Editor extends ComponentBase {
|
|
|
1138
1208
|
// Build visual line map for navigation
|
|
1139
1209
|
const visualLines = this.buildVisualLineMap(width);
|
|
1140
1210
|
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1141
|
-
//
|
|
1142
|
-
const currentVL = visualLines[currentVisualLine];
|
|
1143
|
-
const visualCol = currentVL ? this.state.cursorCol - currentVL.startCol : 0;
|
|
1144
|
-
// Move to target visual line
|
|
1211
|
+
// Move to target visual line with sticky column logic
|
|
1145
1212
|
const targetVisualLine = currentVisualLine + deltaLine;
|
|
1146
1213
|
if (targetVisualLine >= 0 && targetVisualLine < visualLines.length) {
|
|
1147
|
-
|
|
1148
|
-
if (targetVL) {
|
|
1149
|
-
this.state.cursorLine = targetVL.logicalLine;
|
|
1150
|
-
// Try to maintain visual column position, clamped to line length
|
|
1151
|
-
const targetCol = targetVL.startCol + Math.min(visualCol, targetVL.length);
|
|
1152
|
-
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
1153
|
-
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
1154
|
-
}
|
|
1214
|
+
this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);
|
|
1155
1215
|
}
|
|
1156
1216
|
}
|
|
1157
1217
|
if (deltaCol !== 0) {
|
|
@@ -1162,12 +1222,12 @@ export class Editor extends ComponentBase {
|
|
|
1162
1222
|
const afterCursor = currentLine.slice(this.state.cursorCol);
|
|
1163
1223
|
const graphemes = [...segmenter.segment(afterCursor)];
|
|
1164
1224
|
const firstGrapheme = graphemes[0];
|
|
1165
|
-
this.state.cursorCol
|
|
1225
|
+
this.setCursorCol(this.state.cursorCol + (firstGrapheme ? firstGrapheme.segment.length : 1));
|
|
1166
1226
|
}
|
|
1167
1227
|
else if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1168
1228
|
// Wrap to start of next logical line
|
|
1169
1229
|
this.state.cursorLine++;
|
|
1170
|
-
this.
|
|
1230
|
+
this.setCursorCol(0);
|
|
1171
1231
|
}
|
|
1172
1232
|
}
|
|
1173
1233
|
else {
|
|
@@ -1176,13 +1236,13 @@ export class Editor extends ComponentBase {
|
|
|
1176
1236
|
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1177
1237
|
const graphemes = [...segmenter.segment(beforeCursor)];
|
|
1178
1238
|
const lastGrapheme = graphemes[graphemes.length - 1];
|
|
1179
|
-
this.state.cursorCol
|
|
1239
|
+
this.setCursorCol(this.state.cursorCol - (lastGrapheme ? lastGrapheme.segment.length : 1));
|
|
1180
1240
|
}
|
|
1181
1241
|
else if (this.state.cursorLine > 0) {
|
|
1182
1242
|
// Wrap to end of previous logical line
|
|
1183
1243
|
this.state.cursorLine--;
|
|
1184
1244
|
const prevLine = this.state.lines[this.state.cursorLine] || "";
|
|
1185
|
-
this.
|
|
1245
|
+
this.setCursorCol(prevLine.length);
|
|
1186
1246
|
}
|
|
1187
1247
|
}
|
|
1188
1248
|
}
|
|
@@ -1201,17 +1261,8 @@ export class Editor extends ComponentBase {
|
|
|
1201
1261
|
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1202
1262
|
// Calculate target visual line
|
|
1203
1263
|
const targetVisualLine = Math.max(0, Math.min(visualLines.length - 1, currentVisualLine + direction * pageSize));
|
|
1204
|
-
// Move cursor to target visual line
|
|
1205
|
-
|
|
1206
|
-
if (targetVL) {
|
|
1207
|
-
// Preserve column position within the line
|
|
1208
|
-
const currentVL = visualLines[currentVisualLine];
|
|
1209
|
-
const visualCol = currentVL ? this.state.cursorCol - currentVL.startCol : 0;
|
|
1210
|
-
this.state.cursorLine = targetVL.logicalLine;
|
|
1211
|
-
const targetCol = targetVL.startCol + Math.min(visualCol, targetVL.length);
|
|
1212
|
-
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
1213
|
-
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
1214
|
-
}
|
|
1264
|
+
// Move cursor to target visual line with sticky column logic
|
|
1265
|
+
this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);
|
|
1215
1266
|
}
|
|
1216
1267
|
moveWordBackwards() {
|
|
1217
1268
|
this.lastAction = null;
|
|
@@ -1258,7 +1309,7 @@ export class Editor extends ComponentBase {
|
|
|
1258
1309
|
if (this.killRing.length === 0)
|
|
1259
1310
|
return;
|
|
1260
1311
|
this.pushUndoSnapshot();
|
|
1261
|
-
const text = this.killRing
|
|
1312
|
+
const text = this.killRing.peek();
|
|
1262
1313
|
this.insertYankedText(text);
|
|
1263
1314
|
this.lastAction = "yank";
|
|
1264
1315
|
}
|
|
@@ -1274,10 +1325,9 @@ export class Editor extends ComponentBase {
|
|
|
1274
1325
|
// Delete the previously yanked text (still at end of ring before rotation)
|
|
1275
1326
|
this.deleteYankedText();
|
|
1276
1327
|
// Rotate the ring: move end to front
|
|
1277
|
-
|
|
1278
|
-
this.killRing.unshift(lastEntry);
|
|
1328
|
+
this.killRing.rotate();
|
|
1279
1329
|
// Insert the new most recent entry (now at end after rotation)
|
|
1280
|
-
const text = this.killRing
|
|
1330
|
+
const text = this.killRing.peek();
|
|
1281
1331
|
this.insertYankedText(text);
|
|
1282
1332
|
this.lastAction = "yank";
|
|
1283
1333
|
}
|
|
@@ -1319,10 +1369,10 @@ export class Editor extends ComponentBase {
|
|
|
1319
1369
|
}
|
|
1320
1370
|
/**
|
|
1321
1371
|
* Delete the previously yanked text (used by yank-pop).
|
|
1322
|
-
* The yanked text is derived from killRing
|
|
1372
|
+
* The yanked text is derived from killRing.peek() since it hasn't been rotated yet.
|
|
1323
1373
|
*/
|
|
1324
1374
|
deleteYankedText() {
|
|
1325
|
-
const yankedText = this.killRing
|
|
1375
|
+
const yankedText = this.killRing.peek();
|
|
1326
1376
|
if (!yankedText)
|
|
1327
1377
|
return;
|
|
1328
1378
|
const yankLines = yankedText.split("\n");
|
|
@@ -1360,38 +1410,17 @@ export class Editor extends ComponentBase {
|
|
|
1360
1410
|
* @param prepend - If accumulating, prepend (true) or append (false) to existing entry
|
|
1361
1411
|
*/
|
|
1362
1412
|
addToKillRing(text, prepend) {
|
|
1363
|
-
|
|
1364
|
-
return;
|
|
1365
|
-
if (this.lastAction === "kill" && this.killRing.length > 0) {
|
|
1366
|
-
// Accumulate with the most recent entry (at end of array)
|
|
1367
|
-
const lastEntry = this.killRing.pop();
|
|
1368
|
-
if (prepend) {
|
|
1369
|
-
this.killRing.push(text + lastEntry);
|
|
1370
|
-
}
|
|
1371
|
-
else {
|
|
1372
|
-
this.killRing.push(lastEntry + text);
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
else {
|
|
1376
|
-
// Add new entry to end of ring
|
|
1377
|
-
this.killRing.push(text);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
captureUndoSnapshot() {
|
|
1381
|
-
return structuredClone(this.state);
|
|
1382
|
-
}
|
|
1383
|
-
restoreUndoSnapshot(snapshot) {
|
|
1384
|
-
Object.assign(this.state, structuredClone(snapshot));
|
|
1413
|
+
this.killRing.push(text, { prepend, accumulate: this.lastAction === "kill" });
|
|
1385
1414
|
}
|
|
1386
1415
|
pushUndoSnapshot() {
|
|
1387
|
-
this.undoStack.push(this.
|
|
1416
|
+
this.undoStack.push(this.state);
|
|
1388
1417
|
}
|
|
1389
1418
|
undo() {
|
|
1390
1419
|
this.historyIndex = -1; // Exit history browsing mode
|
|
1391
|
-
if (this.undoStack.length === 0)
|
|
1392
|
-
return;
|
|
1393
1420
|
const snapshot = this.undoStack.pop();
|
|
1394
|
-
|
|
1421
|
+
if (!snapshot)
|
|
1422
|
+
return;
|
|
1423
|
+
Object.assign(this.state, snapshot);
|
|
1395
1424
|
this.lastAction = null;
|
|
1396
1425
|
if (this.onChange) {
|
|
1397
1426
|
this.onChange(this.getText());
|
|
@@ -1472,7 +1501,7 @@ export class Editor extends ComponentBase {
|
|
|
1472
1501
|
const suggestions = this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1473
1502
|
if (suggestions && suggestions.items.length > 0) {
|
|
1474
1503
|
this.autocompletePrefix = suggestions.prefix;
|
|
1475
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1504
|
+
this.autocompleteList = new SelectList(suggestions.items, this.autocompleteMaxVisible, this.theme.selectList);
|
|
1476
1505
|
this.isAutocompleting = true;
|
|
1477
1506
|
}
|
|
1478
1507
|
else {
|
|
@@ -1512,7 +1541,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
1512
1541
|
const suggestions = provider.getForceFileSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1513
1542
|
if (suggestions && suggestions.items.length > 0) {
|
|
1514
1543
|
this.autocompletePrefix = suggestions.prefix;
|
|
1515
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1544
|
+
this.autocompleteList = new SelectList(suggestions.items, this.autocompleteMaxVisible, this.theme.selectList);
|
|
1516
1545
|
this.isAutocompleting = true;
|
|
1517
1546
|
}
|
|
1518
1547
|
else {
|
|
@@ -1534,7 +1563,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
1534
1563
|
if (suggestions && suggestions.items.length > 0) {
|
|
1535
1564
|
this.autocompletePrefix = suggestions.prefix;
|
|
1536
1565
|
// Always create new SelectList to ensure update
|
|
1537
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1566
|
+
this.autocompleteList = new SelectList(suggestions.items, this.autocompleteMaxVisible, this.theme.selectList);
|
|
1538
1567
|
}
|
|
1539
1568
|
else {
|
|
1540
1569
|
this.cancelAutocomplete();
|