diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx index 836be2b6a0..21cb1a221b 100644 --- a/docs/docs/config.mdx +++ b/docs/docs/config.mdx @@ -58,6 +58,7 @@ wsh editconfig | term:theme | string | preset name of terminal theme to apply by default (default is "default-dark") | | term:transparency | float64 | set the background transparency of terminal theme (default 0.5, 0 = not transparent, 1.0 = fully transparent) | | term:allowbracketedpaste | bool | allow bracketed paste mode in terminal (default false) | +| term:shiftenternewline | bool | when enabled, Shift+Enter sends escape sequence + newline (\u001b\n) instead of carriage return, useful for claude code and similar AI coding tools (default false) | | editor:minimapenabled | bool | set to false to disable editor minimap | | editor:stickyscrollenabled | bool | enables monaco editor's stickyScroll feature (pinning headers of current context, e.g. class names, method names, etc.), defaults to false | | editor:wordwrap | bool | set to true to enable word wrapping in the editor (defaults to false) | diff --git a/docs/docs/faq.mdx b/docs/docs/faq.mdx index 37f51385b2..559944c4e4 100644 --- a/docs/docs/faq.mdx +++ b/docs/docs/faq.mdx @@ -12,6 +12,25 @@ Wave supports various AI providers including local LLMs (via Ollama), Azure Open See our [AI Presets documentation](/ai-presets) for detailed setup instructions for each provider. +### How do I enable Claude Code support with Shift+Enter? + +Wave supports Claude Code and similar AI coding tools that expect Shift+Enter to send an escape sequence + newline (`\u001b\n`) instead of a regular carriage return. This can be enabled using the `term:shiftenternewline` configuration setting. + +To enable this globally for all terminals: +```bash +wsh setconfig term:shiftenternewline=true +``` + +To enable this for just a specific terminal block: +```bash +wsh setmeta term:shiftenternewline=true +``` + +You can also set this in your [settings.json](./config) file: +```json +"term:shiftenternewline": true +``` + ### How can I see the block numbers? The block numbers will appear when you hold down Ctrl-Shift (and disappear once you release the key combo). diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index 4d30aa5c74..9e71285815 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -457,6 +457,18 @@ class TermViewModel implements ViewModel { return false; } // deal with terminal specific keybindings + if (keyutil.checkKeyPressed(waveEvent, "Shift:Enter")) { + // Check if shift+enter newline is enabled via config + const shiftEnterNewlineAtom = getOverrideConfigAtom(this.blockId, "term:shiftenternewline"); + const shiftEnterNewlineEnabled = globalStore.get(shiftEnterNewlineAtom) ?? false; + if (shiftEnterNewlineEnabled) { + // Support for claude code - send escape sequence + newline instead of carriage return + this.sendDataToController("\u001b\n"); + event.preventDefault(); + event.stopPropagation(); + return false; + } + } if (keyutil.checkKeyPressed(waveEvent, "Ctrl:Shift:v")) { const p = navigator.clipboard.readText(); p.then((text) => { diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 13868f341b..3b9c29b2fd 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -581,6 +581,7 @@ declare global { "term:vdomtoolbarblockid"?: string; "term:transparency"?: number; "term:allowbracketedpaste"?: boolean; + "term:shiftenternewline"?: boolean; "term:conndebug"?: string; "web:zoom"?: number; "web:hidenav"?: boolean; @@ -706,6 +707,7 @@ declare global { "term:copyonselect"?: boolean; "term:transparency"?: number; "term:allowbracketedpaste"?: boolean; + "term:shiftenternewline"?: boolean; "editor:minimapenabled"?: boolean; "editor:stickyscrollenabled"?: boolean; "editor:wordwrap"?: boolean; diff --git a/frontend/util/util.ts b/frontend/util/util.ts index 43a1e02408..4a081ad64d 100644 --- a/frontend/util/util.ts +++ b/frontend/util/util.ts @@ -378,6 +378,22 @@ function mergeMeta(meta: MetaType, metaUpdate: MetaType, prefix?: string): MetaT return rtn; } +function escapeBytes(str: string): string { + return str.replace(/[\s\S]/g, ch => { + const code = ch.charCodeAt(0); + switch (ch) { + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case "\b": return "\\b"; + case "\f": return "\\f"; + } + if (code === 0x1b) return "\\x1b"; // escape + if (code < 0x20 || code === 0x7f) return `\\x${code.toString(16).padStart(2,"0")}`; + return ch; + }); +} + function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } @@ -391,6 +407,7 @@ export { cn, countGraphemes, deepCompareReturnPrev, + escapeBytes, fireAndForget, getPrefixedSettings, getPromiseState, diff --git a/pkg/waveobj/metaconsts.go b/pkg/waveobj/metaconsts.go index a3365eb8b1..68caa25f7b 100644 --- a/pkg/waveobj/metaconsts.go +++ b/pkg/waveobj/metaconsts.go @@ -102,6 +102,7 @@ const ( MetaKey_TermVDomToolbarBlockId = "term:vdomtoolbarblockid" MetaKey_TermTransparency = "term:transparency" MetaKey_TermAllowBracketedPaste = "term:allowbracketedpaste" + MetaKey_TermShiftEnterNewline = "term:shiftenternewline" MetaKey_TermConnDebug = "term:conndebug" MetaKey_WebZoom = "web:zoom" diff --git a/pkg/waveobj/wtypemeta.go b/pkg/waveobj/wtypemeta.go index d583cc90c9..b272e17d4f 100644 --- a/pkg/waveobj/wtypemeta.go +++ b/pkg/waveobj/wtypemeta.go @@ -105,6 +105,7 @@ type MetaTSType struct { TermVDomToolbarBlockId string `json:"term:vdomtoolbarblockid,omitempty"` TermTransparency *float64 `json:"term:transparency,omitempty"` // default 0.5 TermAllowBracketedPaste *bool `json:"term:allowbracketedpaste,omitempty"` + TermShiftEnterNewline *bool `json:"term:shiftenternewline,omitempty"` TermConnDebug string `json:"term:conndebug,omitempty"` // null, info, debug WebZoom float64 `json:"web:zoom,omitempty"` diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go index 1057b9c82f..fa672d5791 100644 --- a/pkg/wconfig/metaconsts.go +++ b/pkg/wconfig/metaconsts.go @@ -37,6 +37,7 @@ const ( ConfigKey_TermCopyOnSelect = "term:copyonselect" ConfigKey_TermTransparency = "term:transparency" ConfigKey_TermAllowBracketedPaste = "term:allowbracketedpaste" + ConfigKey_TermShiftEnterNewline = "term:shiftenternewline" ConfigKey_EditorMinimapEnabled = "editor:minimapenabled" ConfigKey_EditorStickyScrollEnabled = "editor:stickyscrollenabled" diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index b041233324..d5516cbff7 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -83,6 +83,7 @@ type SettingsType struct { TermCopyOnSelect *bool `json:"term:copyonselect,omitempty"` TermTransparency *float64 `json:"term:transparency,omitempty"` TermAllowBracketedPaste *bool `json:"term:allowbracketedpaste,omitempty"` + TermShiftEnterNewline *bool `json:"term:shiftenternewline,omitempty"` EditorMinimapEnabled bool `json:"editor:minimapenabled,omitempty"` EditorStickyScrollEnabled bool `json:"editor:stickyscrollenabled,omitempty"` diff --git a/schema/settings.json b/schema/settings.json index c885204a09..c38d46c315 100644 --- a/schema/settings.json +++ b/schema/settings.json @@ -95,6 +95,9 @@ "term:allowbracketedpaste": { "type": "boolean" }, + "term:shiftenternewline": { + "type": "boolean" + }, "editor:minimapenabled": { "type": "boolean" },