From eaa78452bcd80808afaffe2edbc5c6d647af6f5c Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Mon, 17 Aug 2026 18:04:13 -0400 Subject: [PATCH] =?UTF-8?q?Enter=20asks,=20Ctrl+Enter=20breaks=20the=20lin?= =?UTF-8?q?e=20=E2=80=94=20in=20both=20chat=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Almost every message here is one line, so the common action takes the bare key. Shift+Enter also breaks a line, because that is the reflex people arrive with. --- Plugin/unraid/include/ai_chat.php | 17 +++++++++++++++-- Plugin/unraid/include/node_chat.php | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Plugin/unraid/include/ai_chat.php b/Plugin/unraid/include/ai_chat.php index cc25b04..6b53b98 100644 --- a/Plugin/unraid/include/ai_chat.php +++ b/Plugin/unraid/include/ai_chat.php @@ -2028,7 +2028,19 @@ vv_ai_profiles_script(); wrapEl.addEventListener('keydown', e => { const inp = $('input'); - if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); send(); return; } + // Enter asks; Ctrl/Cmd+Enter breaks the line. The reverse of the usual editor convention, + // and right for this box: almost every message here is one line, so the common action + // gets the bare key and the rare one gets the modifier. Shift+Enter also breaks a line, + // because that is the reflex people arrive with from every other chat box. + if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { + e.preventDefault(); + const t = e.target; + const s = t.selectionStart ?? t.value.length, n = t.selectionEnd ?? s; + t.value = t.value.slice(0, s) + '\n' + t.value.slice(n); + t.selectionStart = t.selectionEnd = s + 1; + return; + } + if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); return; } // Terminal habit: an empty box and Up gets back what you just asked, to edit rather than // retype. Only when empty, or it would eat cursor movement in a question being written. @@ -2360,7 +2372,8 @@ vv_ai_profiles_script(); // broke the tab it lives on. function vv_ai_chat_keys(): array { return [ - ['keys' => ['Ctrl', 'Enter'], 'what' => 'Ask', 'id' => 'send'], + ['keys' => ['Enter'], 'what' => 'Ask', 'id' => 'send'], + ['keys' => ['Ctrl', 'Enter'], 'what' => 'New line', 'id' => 'nl'], ['keys' => ['↑'], 'what' => 'Your last question, to edit', 'id' => 'recall'], ['keys' => ['/'], 'what' => 'Command — /help lists them', 'id' => 'slash'], ['keys' => ['Esc'], 'what' => 'Close a menu, or clear the box', 'id' => 'esc'], diff --git a/Plugin/unraid/include/node_chat.php b/Plugin/unraid/include/node_chat.php index 03d79c7..77b0d0f 100644 --- a/Plugin/unraid/include/node_chat.php +++ b/Plugin/unraid/include/node_chat.php @@ -272,7 +272,7 @@ function vv_nc_pane_markup(string $prefix, bool $meshDefault = false,
@@ -555,6 +555,21 @@ function vvNcGrow(fromAi) { } } +// Same bargain as the assistant's box, because they are two halves of one card and a key that +// sends in one and breaks a line in the other is the kind of difference that costs a message. +function vvNcKey(e) { + if (e.key !== 'Enter') return; + if (e.ctrlKey || e.metaKey) { + e.preventDefault(); + const t = e.target; + const s = t.selectionStart ?? t.value.length, n = t.selectionEnd ?? s; + t.value = t.value.slice(0, s) + '\n' + t.value.slice(n); + t.selectionStart = t.selectionEnd = s + 1; + return; + } + if (!e.shiftKey) { e.preventDefault(); vvNcSend(); } +} + function vvNcEmoji(sel) { const t = document.getElementById('vv-nc-text'); if (t && sel.value) { t.value += sel.value; t.focus(); }