Skip to content

Commit 246feda

Browse files
authored
Add option to append trailing space after pasted text (cjpais#405)
1 parent 244a99e commit 246feda

File tree

8 files changed

+61
-1
lines changed

8 files changed

+61
-1
lines changed

src-tauri/src/clipboard.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ pub fn paste(text: String, app_handle: AppHandle) -> Result<(), String> {
234234
let settings = get_settings(&app_handle);
235235
let paste_method = settings.paste_method;
236236

237+
// Append trailing space if setting is enabled
238+
let text = if settings.append_trailing_space {
239+
format!("{} ", text)
240+
} else {
241+
text
242+
};
243+
237244
info!("Using paste method: {:?}", paste_method);
238245

239246
// Perform the paste operation

src-tauri/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ pub fn run() {
253253
shortcut::suspend_binding,
254254
shortcut::resume_binding,
255255
shortcut::change_mute_while_recording_setting,
256+
shortcut::change_append_trailing_space_setting,
256257
shortcut::change_update_checks_setting,
257258
trigger_update_check,
258259
commands::cancel_operation,

src-tauri/src/settings.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ pub struct AppSettings {
285285
pub post_process_selected_prompt_id: Option<String>,
286286
#[serde(default)]
287287
pub mute_while_recording: bool,
288+
#[serde(default)]
289+
pub append_trailing_space: bool,
288290
}
289291

290292
fn default_model() -> String {
@@ -483,6 +485,7 @@ pub fn get_default_settings() -> AppSettings {
483485
post_process_prompts: default_post_process_prompts(),
484486
post_process_selected_prompt_id: None,
485487
mute_while_recording: false,
488+
append_trailing_space: false,
486489
}
487490
}
488491

src-tauri/src/shortcut.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,16 @@ pub fn change_mute_while_recording_setting(app: AppHandle, enabled: bool) -> Res
693693
Ok(())
694694
}
695695

696+
#[tauri::command]
697+
#[specta::specta]
698+
pub fn change_append_trailing_space_setting(app: AppHandle, enabled: bool) -> Result<(), String> {
699+
let mut settings = settings::get_settings(&app);
700+
settings.append_trailing_space = enabled;
701+
settings::write_settings(&app, settings);
702+
703+
Ok(())
704+
}
705+
696706
/// Determine whether a shortcut string contains at least one non-modifier key.
697707
/// We allow single non-modifier keys (e.g. "f5" or "space") but disallow
698708
/// modifier-only combos (e.g. "ctrl" or "ctrl+shift").

src/bindings.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ async changeMuteWhileRecordingSetting(enabled: boolean) : Promise<Result<null, s
244244
else return { status: "error", error: e as any };
245245
}
246246
},
247+
async changeAppendTrailingSpaceSetting(enabled: boolean) : Promise<Result<null, string>> {
248+
try {
249+
return { status: "ok", data: await TAURI_INVOKE("change_append_trailing_space_setting", { enabled }) };
250+
} catch (e) {
251+
if(e instanceof Error) throw e;
252+
else return { status: "error", error: e as any };
253+
}
254+
},
247255
async changeUpdateChecksSetting(enabled: boolean) : Promise<Result<null, string>> {
248256
try {
249257
return { status: "ok", data: await TAURI_INVOKE("change_update_checks_setting", { enabled }) };
@@ -602,7 +610,7 @@ async isLaptop() : Promise<Result<boolean, string>> {
602610

603611
/** user-defined types **/
604612

605-
export type AppSettings = { bindings: Partial<{ [key in string]: ShortcutBinding }>; push_to_talk: boolean; audio_feedback: boolean; audio_feedback_volume?: number; sound_theme?: SoundTheme; start_hidden?: boolean; autostart_enabled?: boolean; update_checks_enabled?: boolean; selected_model?: string; always_on_microphone?: boolean; selected_microphone?: string | null; clamshell_microphone?: string | null; selected_output_device?: string | null; translate_to_english?: boolean; selected_language?: string; overlay_position?: OverlayPosition; debug_mode?: boolean; log_level?: LogLevel; custom_words?: string[]; model_unload_timeout?: ModelUnloadTimeout; word_correction_threshold?: number; history_limit?: string; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; post_process_enabled?: boolean; post_process_provider_id?: string; post_process_providers?: PostProcessProvider[]; post_process_api_keys?: Partial<{ [key in string]: string }>; post_process_models?: Partial<{ [key in string]: string }>; post_process_prompts?: LLMPrompt[]; post_process_selected_prompt_id?: string | null; mute_while_recording?: boolean }
613+
export type AppSettings = { bindings: Partial<{ [key in string]: ShortcutBinding }>; push_to_talk: boolean; audio_feedback: boolean; audio_feedback_volume?: number; sound_theme?: SoundTheme; start_hidden?: boolean; autostart_enabled?: boolean; update_checks_enabled?: boolean; selected_model?: string; always_on_microphone?: boolean; selected_microphone?: string | null; clamshell_microphone?: string | null; selected_output_device?: string | null; translate_to_english?: boolean; selected_language?: string; overlay_position?: OverlayPosition; debug_mode?: boolean; log_level?: LogLevel; custom_words?: string[]; model_unload_timeout?: ModelUnloadTimeout; word_correction_threshold?: number; history_limit?: string; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; post_process_enabled?: boolean; post_process_provider_id?: string; post_process_providers?: PostProcessProvider[]; post_process_api_keys?: Partial<{ [key in string]: string }>; post_process_models?: Partial<{ [key in string]: string }>; post_process_prompts?: LLMPrompt[]; post_process_selected_prompt_id?: string | null; mute_while_recording?: boolean; append_trailing_space?: boolean }
606614
export type AudioDevice = { index: string; name: string; is_default: boolean }
607615
export type BindingResponse = { success: boolean; binding: ShortcutBinding | null; error: string | null }
608616
export type ClipboardHandling = "dont_modify" | "copy_to_clipboard"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react";
2+
import { ToggleSwitch } from "../ui/ToggleSwitch";
3+
import { useSettings } from "../../hooks/useSettings";
4+
5+
interface AppendTrailingSpaceProps {
6+
descriptionMode?: "inline" | "tooltip";
7+
grouped?: boolean;
8+
}
9+
10+
export const AppendTrailingSpace: React.FC<AppendTrailingSpaceProps> =
11+
React.memo(({ descriptionMode = "tooltip", grouped = false }) => {
12+
const { getSetting, updateSetting, isUpdating } = useSettings();
13+
14+
const enabled = getSetting("append_trailing_space") ?? false;
15+
16+
return (
17+
<ToggleSwitch
18+
checked={enabled}
19+
onChange={(enabled) => updateSetting("append_trailing_space", enabled)}
20+
isUpdating={isUpdating("append_trailing_space")}
21+
label="Append Trailing Space"
22+
description="Automatically add a space at the end of transcribed text, making it easier to dictate multiple sentences in a row."
23+
descriptionMode={descriptionMode}
24+
grouped={grouped}
25+
/>
26+
);
27+
});

src/components/settings/debug/DebugSettings.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { AlwaysOnMicrophone } from "../AlwaysOnMicrophone";
99
import { SoundPicker } from "../SoundPicker";
1010
import { PostProcessingToggle } from "../PostProcessingToggle";
1111
import { MuteWhileRecording } from "../MuteWhileRecording";
12+
import { AppendTrailingSpace } from "../AppendTrailingSpace";
1213
import { RecordingRetentionPeriodSelector } from "../RecordingRetentionPeriod";
1314
import { ClamshellMicrophoneSelector } from "../ClamshellMicrophoneSelector";
1415
import { HandyShortcut } from "../HandyShortcut";
@@ -40,6 +41,7 @@ export const DebugSettings: React.FC = () => {
4041
<ClamshellMicrophoneSelector descriptionMode="tooltip" grouped={true} />
4142
<PostProcessingToggle descriptionMode="tooltip" grouped={true} />
4243
<MuteWhileRecording descriptionMode="tooltip" grouped={true} />
44+
<AppendTrailingSpace descriptionMode="tooltip" grouped={true} />
4345
{/* Cancel shortcut is disabled on Linux due to instability with dynamic shortcut registration */}
4446
{!isLinux && (
4547
<HandyShortcut

src/stores/settingsStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ const settingUpdaters: {
121121
commands.setPostProcessSelectedPrompt(value as string),
122122
mute_while_recording: (value) =>
123123
commands.changeMuteWhileRecordingSetting(value as boolean),
124+
append_trailing_space: (value) =>
125+
commands.changeAppendTrailingSpaceSetting(value as boolean),
124126
log_level: (value) => commands.setLogLevel(value as any),
125127
};
126128

0 commit comments

Comments
 (0)