Add "external script" paste method (#638)
* feat(linux): add "external script" paste method * feat(i18n): external script translation for fr, de, it
This commit is contained in:
parent
f8ee7fce7c
commit
b90077b228
11 changed files with 114 additions and 22 deletions
|
|
@ -4,14 +4,13 @@ use crate::settings::TypingTool;
|
||||||
use crate::settings::{get_settings, AutoSubmitKey, ClipboardHandling, PasteMethod};
|
use crate::settings::{get_settings, AutoSubmitKey, ClipboardHandling, PasteMethod};
|
||||||
use enigo::{Direction, Enigo, Key, Keyboard};
|
use enigo::{Direction, Enigo, Key, Keyboard};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use std::process::Command;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::utils::{is_kde_wayland, is_wayland};
|
use crate::utils::{is_kde_wayland, is_wayland};
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
/// Pastes text using the clipboard: saves current content, writes text, sends paste keystroke, restores clipboard.
|
/// Pastes text using the clipboard: saves current content, writes text, sends paste keystroke, restores clipboard.
|
||||||
fn paste_via_clipboard(
|
fn paste_via_clipboard(
|
||||||
|
|
@ -500,6 +499,31 @@ fn send_key_combo_via_xdotool(paste_method: &PasteMethod) -> Result<(), String>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pastes text by invoking an external script.
|
||||||
|
/// The script receives the text to paste as a single argument.
|
||||||
|
fn paste_via_external_script(text: &str, script_path: &str) -> Result<(), String> {
|
||||||
|
info!("Pasting via external script: {}", script_path);
|
||||||
|
|
||||||
|
let output = Command::new(script_path)
|
||||||
|
.arg(text)
|
||||||
|
.output()
|
||||||
|
.map_err(|e| format!("Failed to execute external script '{}': {}", script_path, e))?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
return Err(format!(
|
||||||
|
"External script '{}' failed with exit code {:?}. stderr: {}, stdout: {}",
|
||||||
|
script_path,
|
||||||
|
output.status.code(),
|
||||||
|
stderr.trim(),
|
||||||
|
stdout.trim()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Types text directly by simulating individual key presses.
|
/// Types text directly by simulating individual key presses.
|
||||||
fn paste_direct(
|
fn paste_direct(
|
||||||
enigo: &mut Enigo,
|
enigo: &mut Enigo,
|
||||||
|
|
@ -612,6 +636,14 @@ pub fn paste(text: String, app_handle: AppHandle) -> Result<(), String> {
|
||||||
paste_delay_ms,
|
paste_delay_ms,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
|
PasteMethod::ExternalScript => {
|
||||||
|
let script_path = settings
|
||||||
|
.external_script_path
|
||||||
|
.as_ref()
|
||||||
|
.filter(|p| !p.is_empty())
|
||||||
|
.ok_or("External script path is not configured")?;
|
||||||
|
paste_via_external_script(&text, script_path)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_send_auto_submit(settings.auto_submit, paste_method) {
|
if should_send_auto_submit(settings.auto_submit, paste_method) {
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,7 @@ pub fn run(cli_args: CliArgs) {
|
||||||
shortcut::change_paste_method_setting,
|
shortcut::change_paste_method_setting,
|
||||||
shortcut::get_available_typing_tools,
|
shortcut::get_available_typing_tools,
|
||||||
shortcut::change_typing_tool_setting,
|
shortcut::change_typing_tool_setting,
|
||||||
|
shortcut::change_external_script_path_setting,
|
||||||
shortcut::change_clipboard_handling_setting,
|
shortcut::change_clipboard_handling_setting,
|
||||||
shortcut::change_auto_submit_setting,
|
shortcut::change_auto_submit_setting,
|
||||||
shortcut::change_auto_submit_key_setting,
|
shortcut::change_auto_submit_key_setting,
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ pub enum PasteMethod {
|
||||||
None,
|
None,
|
||||||
ShiftInsert,
|
ShiftInsert,
|
||||||
CtrlShiftV,
|
CtrlShiftV,
|
||||||
|
ExternalScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Type)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Type)]
|
||||||
|
|
@ -358,6 +359,7 @@ pub struct AppSettings {
|
||||||
pub paste_delay_ms: u64,
|
pub paste_delay_ms: u64,
|
||||||
#[serde(default = "default_typing_tool")]
|
#[serde(default = "default_typing_tool")]
|
||||||
pub typing_tool: TypingTool,
|
pub typing_tool: TypingTool,
|
||||||
|
pub external_script_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_model() -> String {
|
fn default_model() -> String {
|
||||||
|
|
@ -721,6 +723,7 @@ pub fn get_default_settings() -> AppSettings {
|
||||||
show_tray_icon: default_show_tray_icon(),
|
show_tray_icon: default_show_tray_icon(),
|
||||||
paste_delay_ms: default_paste_delay_ms(),
|
paste_delay_ms: default_paste_delay_ms(),
|
||||||
typing_tool: default_typing_tool(),
|
typing_tool: default_typing_tool(),
|
||||||
|
external_script_path: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -668,6 +668,7 @@ pub fn change_paste_method_setting(app: AppHandle, method: String) -> Result<(),
|
||||||
"none" => PasteMethod::None,
|
"none" => PasteMethod::None,
|
||||||
"shift_insert" => PasteMethod::ShiftInsert,
|
"shift_insert" => PasteMethod::ShiftInsert,
|
||||||
"ctrl_shift_v" => PasteMethod::CtrlShiftV,
|
"ctrl_shift_v" => PasteMethod::CtrlShiftV,
|
||||||
|
"external_script" => PasteMethod::ExternalScript,
|
||||||
other => {
|
other => {
|
||||||
warn!("Invalid paste method '{}', defaulting to ctrl_v", other);
|
warn!("Invalid paste method '{}', defaulting to ctrl_v", other);
|
||||||
PasteMethod::CtrlV
|
PasteMethod::CtrlV
|
||||||
|
|
@ -712,6 +713,18 @@ pub fn change_typing_tool_setting(app: AppHandle, tool: String) -> Result<(), St
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub fn change_external_script_path_setting(
|
||||||
|
app: AppHandle,
|
||||||
|
path: Option<String>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let mut settings = settings::get_settings(&app);
|
||||||
|
settings.external_script_path = path;
|
||||||
|
settings::write_settings(&app, settings);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub fn change_clipboard_handling_setting(app: AppHandle, handling: String) -> Result<(), String> {
|
pub fn change_clipboard_handling_setting(app: AppHandle, handling: String) -> Result<(), String> {
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,14 @@ async changeTypingToolSetting(tool: string) : Promise<Result<null, string>> {
|
||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async changeExternalScriptPathSetting(path: string | null) : Promise<Result<null, string>> {
|
||||||
|
try {
|
||||||
|
return { status: "ok", data: await TAURI_INVOKE("change_external_script_path_setting", { path }) };
|
||||||
|
} catch (e) {
|
||||||
|
if(e instanceof Error) throw e;
|
||||||
|
else return { status: "error", error: e as any };
|
||||||
|
}
|
||||||
|
},
|
||||||
async changeClipboardHandlingSetting(handling: string) : Promise<Result<null, string>> {
|
async changeClipboardHandlingSetting(handling: string) : Promise<Result<null, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("change_clipboard_handling_setting", { handling }) };
|
return { status: "ok", data: await TAURI_INVOKE("change_clipboard_handling_setting", { handling }) };
|
||||||
|
|
@ -706,7 +714,7 @@ async updateRecordingRetentionPeriod(period: string) : Promise<Result<null, stri
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Checks if the Mac is a laptop by detecting battery presence
|
* Checks if the Mac is a laptop by detecting battery presence
|
||||||
*
|
*
|
||||||
* This uses pmset to check for battery information.
|
* This uses pmset to check for battery information.
|
||||||
* Returns true if a battery is detected (laptop), false otherwise (desktop)
|
* Returns true if a battery is detected (laptop), false otherwise (desktop)
|
||||||
*/
|
*/
|
||||||
|
|
@ -730,7 +738,7 @@ async isLaptop() : Promise<Result<boolean, string>> {
|
||||||
|
|
||||||
/** user-defined types **/
|
/** user-defined types **/
|
||||||
|
|
||||||
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?: number; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; auto_submit?: boolean; auto_submit_key?: AutoSubmitKey; 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; app_language?: string; experimental_enabled?: boolean; keyboard_implementation?: KeyboardImplementation; show_tray_icon?: boolean; paste_delay_ms?: number; typing_tool?: TypingTool }
|
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?: number; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; auto_submit?: boolean; auto_submit_key?: AutoSubmitKey; 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; app_language?: string; experimental_enabled?: boolean; keyboard_implementation?: KeyboardImplementation; show_tray_icon?: boolean; paste_delay_ms?: number; typing_tool?: TypingTool; external_script_path: string | null }
|
||||||
export type AudioDevice = { index: string; name: string; is_default: boolean }
|
export type AudioDevice = { index: string; name: string; is_default: boolean }
|
||||||
export type AutoSubmitKey = "enter" | "ctrl_enter" | "cmd_enter"
|
export type AutoSubmitKey = "enter" | "ctrl_enter" | "cmd_enter"
|
||||||
export type BindingResponse = { success: boolean; binding: ShortcutBinding | null; error: string | null }
|
export type BindingResponse = { success: boolean; binding: ShortcutBinding | null; error: string | null }
|
||||||
|
|
@ -741,7 +749,7 @@ export type HistoryEntry = { id: number; file_name: string; timestamp: number; s
|
||||||
/**
|
/**
|
||||||
* Result of changing keyboard implementation
|
* Result of changing keyboard implementation
|
||||||
*/
|
*/
|
||||||
export type ImplementationChangeResult = { success: boolean;
|
export type ImplementationChangeResult = { success: boolean;
|
||||||
/**
|
/**
|
||||||
* List of binding IDs that were reset to defaults due to incompatibility
|
* List of binding IDs that were reset to defaults due to incompatibility
|
||||||
*/
|
*/
|
||||||
|
|
@ -753,7 +761,7 @@ export type ModelInfo = { id: string; name: string; description: string; filenam
|
||||||
export type ModelLoadStatus = { is_loaded: boolean; current_model: string | null }
|
export type ModelLoadStatus = { is_loaded: boolean; current_model: string | null }
|
||||||
export type ModelUnloadTimeout = "never" | "immediately" | "min_2" | "min_5" | "min_10" | "min_15" | "hour_1" | "sec_5"
|
export type ModelUnloadTimeout = "never" | "immediately" | "min_2" | "min_5" | "min_10" | "min_15" | "hour_1" | "sec_5"
|
||||||
export type OverlayPosition = "none" | "top" | "bottom"
|
export type OverlayPosition = "none" | "top" | "bottom"
|
||||||
export type PasteMethod = "ctrl_v" | "direct" | "none" | "shift_insert" | "ctrl_shift_v"
|
export type PasteMethod = "ctrl_v" | "direct" | "none" | "shift_insert" | "ctrl_shift_v" | "external_script"
|
||||||
export type PostProcessProvider = { id: string; label: string; base_url: string; allow_base_url_edit?: boolean; models_endpoint?: string | null; supports_structured_output?: boolean }
|
export type PostProcessProvider = { id: string; label: string; base_url: string; allow_base_url_edit?: boolean; models_endpoint?: string | null; supports_structured_output?: boolean }
|
||||||
export type RecordingRetentionPeriod = "never" | "preserve_limit" | "days_3" | "weeks_2" | "months_3"
|
export type RecordingRetentionPeriod = "never" | "preserve_limit" | "days_3" | "weeks_2" | "months_3"
|
||||||
export type ShortcutBinding = { id: string; name: string; description: string; default_binding: string; current_binding: string }
|
export type ShortcutBinding = { id: string; name: string; description: string; default_binding: string; current_binding: string }
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Dropdown } from "../ui/Dropdown";
|
import { Dropdown } from "../ui/Dropdown";
|
||||||
import { SettingContainer } from "../ui/SettingContainer";
|
import { SettingContainer } from "../ui/SettingContainer";
|
||||||
|
import { Input } from "../ui/Input";
|
||||||
import { useSettings } from "../../hooks/useSettings";
|
import { useSettings } from "../../hooks/useSettings";
|
||||||
import { useOsType } from "../../hooks/useOsType";
|
import { useOsType } from "../../hooks/useOsType";
|
||||||
import type { PasteMethod } from "@/bindings";
|
import type { PasteMethod } from "@/bindings";
|
||||||
|
|
@ -55,11 +56,20 @@ export const PasteMethodSetting: React.FC<PasteMethodProps> = React.memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External script is only available on Linux
|
||||||
|
if (osType === "linux") {
|
||||||
|
options.push({
|
||||||
|
value: "external_script",
|
||||||
|
label: t("settings.advanced.pasteMethod.options.externalScript"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedMethod = (getSetting("paste_method") ||
|
const selectedMethod = (getSetting("paste_method") ||
|
||||||
"ctrl_v") as PasteMethod;
|
"ctrl_v") as PasteMethod;
|
||||||
|
const externalScriptPath = getSetting("external_script_path") || "";
|
||||||
|
|
||||||
const pasteMethodOptions = getPasteMethodOptions(osType);
|
const pasteMethodOptions = getPasteMethodOptions(osType);
|
||||||
|
|
||||||
|
|
@ -71,14 +81,29 @@ export const PasteMethodSetting: React.FC<PasteMethodProps> = React.memo(
|
||||||
grouped={grouped}
|
grouped={grouped}
|
||||||
tooltipPosition="bottom"
|
tooltipPosition="bottom"
|
||||||
>
|
>
|
||||||
<Dropdown
|
<div className="flex flex-col gap-2">
|
||||||
options={pasteMethodOptions}
|
<Dropdown
|
||||||
selectedValue={selectedMethod}
|
options={pasteMethodOptions}
|
||||||
onSelect={(value) =>
|
selectedValue={selectedMethod}
|
||||||
updateSetting("paste_method", value as PasteMethod)
|
onSelect={(value) =>
|
||||||
}
|
updateSetting("paste_method", value as PasteMethod)
|
||||||
disabled={isUpdating("paste_method")}
|
}
|
||||||
/>
|
disabled={isUpdating("paste_method")}
|
||||||
|
/>
|
||||||
|
{selectedMethod === "external_script" && (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={externalScriptPath}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateSetting("external_script_path", e.target.value)
|
||||||
|
}
|
||||||
|
placeholder={t(
|
||||||
|
"settings.advanced.pasteMethod.externalScriptPlaceholder",
|
||||||
|
)}
|
||||||
|
disabled={isUpdating("external_script_path")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</SettingContainer>
|
</SettingContainer>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,10 @@
|
||||||
"clipboardCtrlShiftV": "Zwischenablage (Strg+Umschalt+V)",
|
"clipboardCtrlShiftV": "Zwischenablage (Strg+Umschalt+V)",
|
||||||
"clipboardShiftInsert": "Zwischenablage (Umschalt+Einfg)",
|
"clipboardShiftInsert": "Zwischenablage (Umschalt+Einfg)",
|
||||||
"direct": "Direkt",
|
"direct": "Direkt",
|
||||||
"none": "Keine"
|
"none": "Keine",
|
||||||
}
|
"externalScript": "Externes Skript"
|
||||||
|
},
|
||||||
|
"externalScriptPlaceholder": "/pfad/zu/ihrem/skript.sh"
|
||||||
},
|
},
|
||||||
"typingTool": {
|
"typingTool": {
|
||||||
"title": "Eingabetool",
|
"title": "Eingabetool",
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,10 @@
|
||||||
"clipboardCtrlShiftV": "Clipboard (Ctrl+Shift+V)",
|
"clipboardCtrlShiftV": "Clipboard (Ctrl+Shift+V)",
|
||||||
"clipboardShiftInsert": "Clipboard (Shift+Insert)",
|
"clipboardShiftInsert": "Clipboard (Shift+Insert)",
|
||||||
"direct": "Direct",
|
"direct": "Direct",
|
||||||
"none": "None"
|
"none": "None",
|
||||||
}
|
"externalScript": "External Script"
|
||||||
|
},
|
||||||
|
"externalScriptPlaceholder": "/path/to/your/script.sh"
|
||||||
},
|
},
|
||||||
"typingTool": {
|
"typingTool": {
|
||||||
"title": "Typing Tool",
|
"title": "Typing Tool",
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,10 @@
|
||||||
"clipboardCtrlShiftV": "Presse-papiers (Ctrl+Shift+V)",
|
"clipboardCtrlShiftV": "Presse-papiers (Ctrl+Shift+V)",
|
||||||
"clipboardShiftInsert": "Presse-papiers (Shift+Insert)",
|
"clipboardShiftInsert": "Presse-papiers (Shift+Insert)",
|
||||||
"direct": "Direct",
|
"direct": "Direct",
|
||||||
"none": "Aucun"
|
"none": "Aucun",
|
||||||
}
|
"externalScript": "Script externe"
|
||||||
|
},
|
||||||
|
"externalScriptPlaceholder": "/chemin/vers/votre/script.sh"
|
||||||
},
|
},
|
||||||
"typingTool": {
|
"typingTool": {
|
||||||
"title": "Outil de frappe",
|
"title": "Outil de frappe",
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,10 @@
|
||||||
"clipboardCtrlShiftV": "Appunti (Ctrl+Shift+V)",
|
"clipboardCtrlShiftV": "Appunti (Ctrl+Shift+V)",
|
||||||
"clipboardShiftInsert": "Appunti (Shift+Insert)",
|
"clipboardShiftInsert": "Appunti (Shift+Insert)",
|
||||||
"direct": "Diretto",
|
"direct": "Diretto",
|
||||||
"none": "Nessuno"
|
"none": "Nessuno",
|
||||||
}
|
"externalScript": "Script esterno"
|
||||||
|
},
|
||||||
|
"externalScriptPlaceholder": "/percorso/del/tuo/script.sh"
|
||||||
},
|
},
|
||||||
"typingTool": {
|
"typingTool": {
|
||||||
"title": "Strumento di digitazione",
|
"title": "Strumento di digitazione",
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,8 @@ const settingUpdaters: {
|
||||||
commands.changeWordCorrectionThresholdSetting(value as number),
|
commands.changeWordCorrectionThresholdSetting(value as number),
|
||||||
paste_method: (value) => commands.changePasteMethodSetting(value as string),
|
paste_method: (value) => commands.changePasteMethodSetting(value as string),
|
||||||
typing_tool: (value) => commands.changeTypingToolSetting(value as string),
|
typing_tool: (value) => commands.changeTypingToolSetting(value as string),
|
||||||
|
external_script_path: (value) =>
|
||||||
|
commands.changeExternalScriptPathSetting(value as string | null),
|
||||||
clipboard_handling: (value) =>
|
clipboard_handling: (value) =>
|
||||||
commands.changeClipboardHandlingSetting(value as string),
|
commands.changeClipboardHandlingSetting(value as string),
|
||||||
auto_submit: (value) => commands.changeAutoSubmitSetting(value as boolean),
|
auto_submit: (value) => commands.changeAutoSubmitSetting(value as boolean),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue