Skip to content

Commit be2d8cc

Browse files
committed
Implement ability to choose key combination to send messages
1 parent 09f2a5a commit be2d8cc

File tree

3 files changed

+101
-22
lines changed

3 files changed

+101
-22
lines changed

apps/array/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,24 @@ export function useTiptapEditor(options: UseTiptapEditorOptions) {
9898
editorProps: {
9999
attributes: { class: EDITOR_CLASS },
100100
handleKeyDown: (view, event) => {
101-
if (event.key === "Enter" && !event.shiftKey) {
102-
if (!view.editable) return false;
103-
const suggestionPopup = document.querySelector("[data-tippy-root]");
104-
if (suggestionPopup) return false;
105-
event.preventDefault();
106-
historyActions.reset();
107-
submitRef.current();
108-
return true;
101+
if (event.key === "Enter") {
102+
const sendMessagesWith =
103+
useSettingsStore.getState().sendMessagesWith;
104+
const isCmdEnterMode = sendMessagesWith === "cmd+enter";
105+
const isSubmitKey = isCmdEnterMode
106+
? event.metaKey || event.ctrlKey
107+
: !event.shiftKey;
108+
109+
if (isSubmitKey) {
110+
if (!view.editable) return false;
111+
const suggestionPopup =
112+
document.querySelector("[data-tippy-root]");
113+
if (suggestionPopup) return false;
114+
event.preventDefault();
115+
historyActions.reset();
116+
submitRef.current();
117+
return true;
118+
}
109119
}
110120

111121
if (

apps/array/src/renderer/features/settings/components/SettingsView.tsx

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { useAuthStore } from "@features/auth/stores/authStore";
22
import { FolderPicker } from "@features/folder-picker/components/FolderPicker";
3-
import { useSettingsStore } from "@features/settings/stores/settingsStore";
3+
import {
4+
type SendMessagesWith,
5+
useSettingsStore,
6+
} from "@features/settings/stores/settingsStore";
47
import { useMeQuery } from "@hooks/useMeQuery";
58
import { useProjectQuery } from "@hooks/useProjectQuery";
69
import { useSetHeaderContent } from "@hooks/useSetHeaderContent";
@@ -56,10 +59,14 @@ export function SettingsView() {
5659
createPR,
5760
cursorGlow,
5861
desktopNotifications,
62+
autoConvertLongText,
63+
sendMessagesWith,
5964
setAutoRunTasks,
6065
setCreatePR,
6166
setCursorGlow,
6267
setDesktopNotifications,
68+
setAutoConvertLongText,
69+
setSendMessagesWith,
6370
} = useSettingsStore();
6471
const terminalLayoutMode = useTerminalLayoutStore(
6572
(state) => state.terminalLayoutMode,
@@ -160,6 +167,30 @@ export function SettingsView() {
160167
[terminalLayoutMode, setTerminalLayout],
161168
);
162169

170+
const handleAutoConvertLongTextChange = useCallback(
171+
(checked: boolean) => {
172+
track(ANALYTICS_EVENTS.SETTING_CHANGED, {
173+
setting_name: "auto_convert_long_text",
174+
new_value: checked,
175+
old_value: autoConvertLongText,
176+
});
177+
setAutoConvertLongText(checked);
178+
},
179+
[autoConvertLongText, setAutoConvertLongText],
180+
);
181+
182+
const handleSendMessagesWithChange = useCallback(
183+
(value: SendMessagesWith) => {
184+
track(ANALYTICS_EVENTS.SETTING_CHANGED, {
185+
setting_name: "send_messages_with",
186+
new_value: value,
187+
old_value: sendMessagesWith,
188+
});
189+
setSendMessagesWith(value);
190+
},
191+
[sendMessagesWith, setSendMessagesWith],
192+
);
193+
163194
const handleWorktreeLocationChange = async (newLocation: string) => {
164195
setLocalWorktreeLocation(newLocation);
165196
try {
@@ -341,20 +372,48 @@ export function SettingsView() {
341372
<Flex direction="column" gap="3">
342373
<Heading size="3">Chat</Heading>
343374
<Card>
344-
<Flex align="center" justify="between">
345-
<Flex direction="column" gap="1">
346-
<Text size="1" weight="medium">
347-
Desktop notifications
348-
</Text>
349-
<Text size="1" color="gray">
350-
Show notifications when the agent finishes working on a task
351-
</Text>
375+
<Flex direction="column" gap="4">
376+
<Flex align="center" justify="between">
377+
<Flex direction="column" gap="1">
378+
<Text size="1" weight="medium">
379+
Desktop notifications
380+
</Text>
381+
<Text size="1" color="gray">
382+
Show notifications when the agent finishes working on a
383+
task
384+
</Text>
385+
</Flex>
386+
<Switch
387+
checked={desktopNotifications}
388+
onCheckedChange={setDesktopNotifications}
389+
size="1"
390+
/>
391+
</Flex>
392+
393+
<Flex align="center" justify="between">
394+
<Flex direction="column" gap="1">
395+
<Text size="1" weight="medium">
396+
Send messages with
397+
</Text>
398+
<Text size="1" color="gray">
399+
Choose which key combination sends messages. Use
400+
Shift+Enter for new lines.
401+
</Text>
402+
</Flex>
403+
<Select.Root
404+
value={sendMessagesWith}
405+
onValueChange={(value) =>
406+
handleSendMessagesWithChange(value as SendMessagesWith)
407+
}
408+
size="1"
409+
>
410+
<Select.Trigger />
411+
<Select.Content>
412+
<Select.Item value="enter">Enter</Select.Item>
413+
<Select.Item value="cmd+enter">⌘ Enter</Select.Item>
414+
</Select.Content>
415+
</Select.Root>
352416
</Flex>
353-
<Switch
354-
checked={desktopNotifications}
355-
onCheckedChange={setDesktopNotifications}
356-
size="1"
357-
/>
358417
</Flex>
359418
</Card>
360419
</Flex>

apps/array/src/renderer/features/settings/stores/settingsStore.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { persist } from "zustand/middleware";
55

66
export type DefaultRunMode = "local" | "cloud" | "last_used";
77
export type LocalWorkspaceMode = "worktree" | "root";
8+
export type SendMessagesWith = "enter" | "cmd+enter";
89

910
interface SettingsStore {
1011
autoRunTasks: boolean;
@@ -16,6 +17,8 @@ interface SettingsStore {
1617
defaultModel: string;
1718
desktopNotifications: boolean;
1819
cursorGlow: boolean;
20+
autoConvertLongText: boolean;
21+
sendMessagesWith: SendMessagesWith;
1922

2023
setAutoRunTasks: (autoRun: boolean) => void;
2124
setDefaultRunMode: (mode: DefaultRunMode) => void;
@@ -26,6 +29,8 @@ interface SettingsStore {
2629
setDefaultModel: (model: string) => void;
2730
setDesktopNotifications: (enabled: boolean) => void;
2831
setCursorGlow: (enabled: boolean) => void;
32+
setAutoConvertLongText: (enabled: boolean) => void;
33+
setSendMessagesWith: (mode: SendMessagesWith) => void;
2934
}
3035

3136
export const useSettingsStore = create<SettingsStore>()(
@@ -40,6 +45,8 @@ export const useSettingsStore = create<SettingsStore>()(
4045
defaultModel: DEFAULT_MODEL,
4146
desktopNotifications: true,
4247
cursorGlow: false,
48+
autoConvertLongText: true,
49+
sendMessagesWith: "enter",
4350

4451
setAutoRunTasks: (autoRun) => set({ autoRunTasks: autoRun }),
4552
setDefaultRunMode: (mode) => set({ defaultRunMode: mode }),
@@ -52,6 +59,9 @@ export const useSettingsStore = create<SettingsStore>()(
5259
setDesktopNotifications: (enabled) =>
5360
set({ desktopNotifications: enabled }),
5461
setCursorGlow: (enabled) => set({ cursorGlow: enabled }),
62+
setAutoConvertLongText: (enabled) =>
63+
set({ autoConvertLongText: enabled }),
64+
setSendMessagesWith: (mode) => set({ sendMessagesWith: mode }),
5565
}),
5666
{
5767
name: "settings-storage",

0 commit comments

Comments
 (0)