basic wsl impl

This commit is contained in:
Brendan Allan
2026-02-10 10:56:39 +08:00
parent b0ceec9b19
commit 563f193f3c
25 changed files with 364 additions and 24 deletions

View File

@@ -1,4 +1,4 @@
import { Component, createMemo, type JSX } from "solid-js"
import { Component, createEffect, createMemo, type JSX, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { Button } from "@opencode-ai/ui/button"
import { Select } from "@opencode-ai/ui/select"
@@ -36,8 +36,12 @@ export const SettingsGeneral: Component = () => {
const platform = usePlatform()
const settings = useSettings()
type BackendMode = "native" | "wsl"
const [store, setStore] = createStore({
checking: false,
backend: "native" as BackendMode,
backendReady: false,
})
const check = () => {
@@ -111,6 +115,34 @@ export const SettingsGeneral: Component = () => {
})),
)
const backendOptions = createMemo(() => [
{ value: "native" as const, label: language.t("settings.desktop.backend.option.native") },
{ value: "wsl" as const, label: language.t("settings.desktop.backend.option.wsl") },
])
const showBackend = () =>
platform.platform === "desktop" &&
platform.os === "windows" &&
!!platform.getBackendConfig &&
!!platform.setBackendConfig
createEffect(() => {
if (!showBackend()) return
if (store.backendReady) return
const get = platform.getBackendConfig
if (!get) {
setStore("backendReady", true)
return
}
void Promise.resolve(get())
.then((config) => {
const mode = config?.mode === "wsl" ? "wsl" : "native"
setStore({ backend: mode, backendReady: true })
})
.catch(() => setStore("backendReady", true))
})
const fontOptions = [
{ value: "ibm-plex-mono", label: "font.option.ibmPlexMono" },
{ value: "cascadia-code", label: "font.option.cascadiaCode" },
@@ -363,6 +395,38 @@ export const SettingsGeneral: Component = () => {
</div>
</div>
<Show when={showBackend()}>
<div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.desktop.section.backend")}</h3>
<div class="bg-surface-raised-base px-4 rounded-lg">
<SettingsRow
title={language.t("settings.desktop.backend.title")}
description={language.t("settings.desktop.backend.description")}
>
<Select
data-action="settings-backend"
options={backendOptions()}
current={backendOptions().find((o) => o.value === store.backend)}
value={(option) => option.value}
label={(option) => option.label}
onSelect={(option) => {
if (!option) return
const setBackend = platform.setBackendConfig
if (!setBackend) return
setStore("backend", option.value)
void Promise.resolve(setBackend({ mode: option.value }))
}}
variant="secondary"
size="small"
triggerVariant="settings"
disabled={!store.backendReady}
/>
</SettingsRow>
</div>
</div>
</Show>
{/* Updates Section */}
<div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.updates")}</h3>

View File

@@ -33,6 +33,9 @@ export type Platform = {
/** Open directory picker dialog (native on Tauri, server-backed on web) */
openDirectoryPickerDialog?(opts?: { title?: string; multiple?: boolean }): Promise<string | string[] | null>
/** Whether native pickers should be used (desktop only) */
supportsNativePickers?(): boolean
/** Open native file picker dialog (Tauri only) */
openFilePickerDialog?(opts?: { title?: string; multiple?: boolean }): Promise<string | string[] | null>
@@ -57,6 +60,12 @@ export type Platform = {
/** Set the default server URL to use on app startup (platform-specific) */
setDefaultServerUrl?(url: string | null): Promise<void> | void
/** Get the configured backend mode (desktop only) */
getBackendConfig?(): Promise<{ mode: "native" | "wsl" } | null> | { mode: "native" | "wsl" } | null
/** Set the configured backend mode (desktop only) */
setBackendConfig?(config: { mode: "native" | "wsl" }): Promise<void> | void
/** Parse markdown to HTML using native parser (desktop only, returns unprocessed code blocks) */
parseMarkdown?(markdown: string): Promise<string>

View File

@@ -508,6 +508,11 @@ export const dict = {
"settings.section.server": "الخادم",
"settings.tab.general": "عام",
"settings.tab.shortcuts": "اختصارات",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "المظهر",
"settings.general.section.notifications": "إشعارات النظام",

View File

@@ -512,6 +512,11 @@ export const dict = {
"settings.section.server": "Servidor",
"settings.tab.general": "Geral",
"settings.tab.shortcuts": "Atalhos",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Aparência",
"settings.general.section.notifications": "Notificações do sistema",

View File

@@ -539,6 +539,11 @@ export const dict = {
"settings.section.server": "Server",
"settings.tab.general": "Opšte",
"settings.tab.shortcuts": "Prečice",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Izgled",
"settings.general.section.notifications": "Sistemske obavijesti",

View File

@@ -512,6 +512,11 @@ export const dict = {
"settings.section.server": "Server",
"settings.tab.general": "Generelt",
"settings.tab.shortcuts": "Genveje",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Udseende",
"settings.general.section.notifications": "Systemmeddelelser",

View File

@@ -556,6 +556,11 @@ export const dict = {
"settings.section.server": "Server",
"settings.tab.general": "Allgemein",
"settings.tab.shortcuts": "Tastenkombinationen",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Erscheinungsbild",
"settings.general.section.notifications": "Systembenachrichtigungen",

View File

@@ -583,6 +583,11 @@ export const dict = {
"settings.section.server": "Server",
"settings.tab.general": "General",
"settings.tab.shortcuts": "Shortcuts",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Appearance",
"settings.general.section.notifications": "System notifications",

View File

@@ -515,6 +515,11 @@ export const dict = {
"settings.section.server": "Servidor",
"settings.tab.general": "General",
"settings.tab.shortcuts": "Atajos",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Apariencia",
"settings.general.section.notifications": "Notificaciones del sistema",

View File

@@ -522,6 +522,11 @@ export const dict = {
"settings.section.server": "Serveur",
"settings.tab.general": "Général",
"settings.tab.shortcuts": "Raccourcis",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Apparence",
"settings.general.section.notifications": "Notifications système",

View File

@@ -507,6 +507,11 @@ export const dict = {
"settings.section.server": "サーバー",
"settings.tab.general": "一般",
"settings.tab.shortcuts": "ショートカット",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "外観",
"settings.general.section.notifications": "システム通知",

View File

@@ -513,6 +513,11 @@ export const dict = {
"settings.section.server": "서버",
"settings.tab.general": "일반",
"settings.tab.shortcuts": "단축키",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "모양",
"settings.general.section.notifications": "시스템 알림",

View File

@@ -515,6 +515,11 @@ export const dict = {
"settings.section.server": "Server",
"settings.tab.general": "Generelt",
"settings.tab.shortcuts": "Snarveier",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Utseende",
"settings.general.section.notifications": "Systemvarsler",

View File

@@ -514,6 +514,11 @@ export const dict = {
"settings.section.server": "Serwer",
"settings.tab.general": "Ogólne",
"settings.tab.shortcuts": "Skróty",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Wygląd",
"settings.general.section.notifications": "Powiadomienia systemowe",

View File

@@ -517,6 +517,11 @@ export const dict = {
"settings.section.server": "Сервер",
"settings.tab.general": "Основные",
"settings.tab.shortcuts": "Горячие клавиши",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "Внешний вид",
"settings.general.section.notifications": "Системные уведомления",

View File

@@ -516,6 +516,11 @@ export const dict = {
"settings.section.server": "เซิร์ฟเวอร์",
"settings.tab.general": "ทั่วไป",
"settings.tab.shortcuts": "ทางลัด",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "รูปลักษณ์",
"settings.general.section.notifications": "การแจ้งเตือนระบบ",

View File

@@ -548,6 +548,11 @@ export const dict = {
"settings.section.server": "服务器",
"settings.tab.general": "通用",
"settings.tab.shortcuts": "快捷键",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "外观",
"settings.general.section.notifications": "系统通知",

View File

@@ -545,6 +545,11 @@ export const dict = {
"settings.section.server": "伺服器",
"settings.tab.general": "一般",
"settings.tab.shortcuts": "快速鍵",
"settings.desktop.section.backend": "Backend",
"settings.desktop.backend.title": "Server backend",
"settings.desktop.backend.description": "Choose where the OpenCode server runs.",
"settings.desktop.backend.option.native": "Native (Windows)",
"settings.desktop.backend.option.wsl": "WSL (Linux)",
"settings.general.section.appearance": "外觀",
"settings.general.section.notifications": "系統通知",

View File

@@ -46,7 +46,8 @@ export default function Home() {
}
}
if (platform.openDirectoryPickerDialog && server.isLocal()) {
const allowNative = platform.supportsNativePickers?.() !== false
if (platform.openDirectoryPickerDialog && server.isLocal() && allowNative) {
const result = await platform.openDirectoryPickerDialog?.({
title: language.t("command.project.open"),
multiple: true,

View File

@@ -1182,7 +1182,8 @@ export default function Layout(props: ParentProps) {
}
}
if (platform.openDirectoryPickerDialog && server.isLocal()) {
const allowNative = platform.supportsNativePickers?.() !== false
if (platform.openDirectoryPickerDialog && server.isLocal() && allowNative) {
const result = await platform.openDirectoryPickerDialog?.({
title: language.t("command.project.open"),
multiple: true,

View File

@@ -3,8 +3,9 @@ use tauri_plugin_shell::{
ShellExt,
process::{Command, CommandChild, CommandEvent},
};
use tauri_plugin_store::StoreExt;
use crate::{LogState, constants::MAX_LOG_ENTRIES};
use crate::{LogState, constants::{BACKEND_MODE_KEY, MAX_LOG_ENTRIES, SETTINGS_STORE}};
const CLI_INSTALL_DIR: &str = ".opencode/bin";
const CLI_BINARY_NAME: &str = "opencode";
@@ -21,7 +22,7 @@ pub struct Config {
}
pub async fn get_config(app: &AppHandle) -> Option<Config> {
create_command(app, "debug config")
create_command(app, "debug config", &[])
.output()
.await
.inspect_err(|e| eprintln!("Failed to read OC config: {e}"))
@@ -150,22 +151,95 @@ fn get_user_shell() -> String {
std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string())
}
pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
fn is_wsl_backend(app: &tauri::AppHandle) -> bool {
let Ok(store) = app.store(SETTINGS_STORE) else {
return false;
};
store
.get(BACKEND_MODE_KEY)
.and_then(|value| value.as_str())
.is_some_and(|value| value == "wsl")
}
fn shell_escape(input: &str) -> String {
if input.is_empty() {
return "''".to_string();
}
let mut escaped = String::from("'");
escaped.push_str(&input.replace("'", "'\"'\"'"));
escaped.push('\'');
escaped
}
pub fn create_command(app: &tauri::AppHandle, args: &str, extra_env: &[(&str, String)]) -> Command {
let state_dir = app
.path()
.resolve("", BaseDirectory::AppLocalData)
.expect("Failed to resolve app local data dir");
let mut envs = vec![
("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY".to_string(), "true".to_string()),
("OPENCODE_EXPERIMENTAL_FILEWATCHER".to_string(), "true".to_string()),
("OPENCODE_CLIENT".to_string(), "desktop".to_string()),
("XDG_STATE_HOME".to_string(), state_dir.to_string_lossy().to_string()),
];
envs.extend(extra_env.iter().map(|(key, value)| (key.to_string(), value.clone())));
#[cfg(target_os = "windows")]
return app
if is_wsl_backend(app) {
let version = app.package_info().version.to_string();
let mut script = vec![
"set -e".to_string(),
"BIN=\"$HOME/.opencode/bin/opencode\"".to_string(),
"if [ ! -x \"$BIN\" ]; then".to_string(),
format!(
" curl -fsSL https://opencode.ai/install | bash -s -- --version {} --no-modify-path",
shell_escape(&version)
),
"fi".to_string(),
];
let mut env_prefix = vec![
"OPENCODE_EXPERIMENTAL_ICON_DISCOVERY=true".to_string(),
"OPENCODE_EXPERIMENTAL_FILEWATCHER=true".to_string(),
"OPENCODE_CLIENT=desktop".to_string(),
"XDG_STATE_HOME=\"$HOME/.local/state\"".to_string(),
];
env_prefix.extend(
envs
.iter()
.filter(|(key, _)| key != "OPENCODE_EXPERIMENTAL_ICON_DISCOVERY")
.filter(|(key, _)| key != "OPENCODE_EXPERIMENTAL_FILEWATCHER")
.filter(|(key, _)| key != "OPENCODE_CLIENT")
.filter(|(key, _)| key != "XDG_STATE_HOME")
.map(|(key, value)| format!("{}={}", key, shell_escape(value))),
);
script.push(format!(
"{} exec \"$BIN\" {}",
env_prefix.join(" "),
args
));
return app
.shell()
.command("wsl")
.args(["-e", "bash", "-lc", &script.join("\n")]);
}
let mut cmd = app
.shell()
.sidecar("opencode-cli")
.unwrap()
.args(args.split_whitespace())
.env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true")
.env("OPENCODE_EXPERIMENTAL_FILEWATCHER", "true")
.env("OPENCODE_CLIENT", "desktop")
.env("XDG_STATE_HOME", &state_dir);
.args(args.split_whitespace());
for (key, value) in envs {
cmd = cmd.env(key, value);
}
return cmd;
#[cfg(not(target_os = "windows"))]
return {
@@ -178,13 +252,15 @@ pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
format!("\"{}\" {}", sidecar.display(), args)
};
app.shell()
let mut cmd = app.shell()
.command(&shell)
.env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true")
.env("OPENCODE_EXPERIMENTAL_FILEWATCHER", "true")
.env("OPENCODE_CLIENT", "desktop")
.env("XDG_STATE_HOME", &state_dir)
.args(["-il", "-c", &cmd])
.args(["-il", "-c", &cmd]);
for (key, value) in envs {
cmd = cmd.env(key, value);
}
cmd
};
}
@@ -194,12 +270,16 @@ pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> Comm
println!("spawning sidecar on port {port}");
let envs = [
("OPENCODE_SERVER_USERNAME", "opencode".to_string()),
("OPENCODE_SERVER_PASSWORD", password.to_string()),
];
let (mut rx, child) = create_command(
app,
format!("serve --hostname {hostname} --port {port}").as_str(),
&envs,
)
.env("OPENCODE_SERVER_USERNAME", "opencode")
.env("OPENCODE_SERVER_PASSWORD", password)
.spawn()
.expect("Failed to spawn opencode");

View File

@@ -2,6 +2,7 @@ use tauri_plugin_window_state::StateFlags;
pub const SETTINGS_STORE: &str = "opencode.settings.dat";
pub const DEFAULT_SERVER_URL_KEY: &str = "defaultServerUrl";
pub const BACKEND_MODE_KEY: &str = "serverBackendMode";
pub const UPDATER_ENABLED: bool = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some();
pub const MAX_LOG_ENTRIES: usize = 200;

View File

@@ -209,6 +209,8 @@ pub fn run() {
await_initialization,
server::get_default_server_url,
server::set_default_server_url,
server::get_backend_config,
server::set_backend_config,
markdown::parse_markdown_command,
check_app_exists
])

View File

@@ -8,9 +8,38 @@ use tokio::task::JoinHandle;
use crate::{
cli,
constants::{DEFAULT_SERVER_URL_KEY, SETTINGS_STORE},
constants::{BACKEND_MODE_KEY, DEFAULT_SERVER_URL_KEY, SETTINGS_STORE},
};
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type, Debug)]
#[serde(rename_all = "snake_case")]
pub enum BackendMode {
Native,
Wsl,
}
impl BackendMode {
fn as_str(&self) -> &'static str {
match self {
BackendMode::Native => "native",
BackendMode::Wsl => "wsl",
}
}
}
#[derive(Clone, serde::Serialize, serde::Deserialize, specta::Type, Debug)]
pub struct BackendConfig {
pub mode: BackendMode,
}
impl Default for BackendConfig {
fn default() -> Self {
Self {
mode: BackendMode::Native,
}
}
}
#[tauri::command]
#[specta::specta]
pub fn get_default_server_url(app: AppHandle) -> Result<Option<String>, String> {
@@ -48,6 +77,44 @@ pub async fn set_default_server_url(app: AppHandle, url: Option<String>) -> Resu
Ok(())
}
#[tauri::command]
#[specta::specta]
pub fn get_backend_config(app: AppHandle) -> Result<BackendConfig, String> {
let store = app
.store(SETTINGS_STORE)
.map_err(|e| format!("Failed to open settings store: {}", e))?;
let mode = store
.get(BACKEND_MODE_KEY)
.and_then(|v| v.as_str())
.map(|v| match v {
"wsl" => BackendMode::Wsl,
_ => BackendMode::Native,
})
.unwrap_or(BackendMode::Native);
Ok(BackendConfig { mode })
}
#[tauri::command]
#[specta::specta]
pub fn set_backend_config(app: AppHandle, config: BackendConfig) -> Result<(), String> {
let store = app
.store(SETTINGS_STORE)
.map_err(|e| format!("Failed to open settings store: {}", e))?;
store.set(
BACKEND_MODE_KEY,
serde_json::Value::String(config.mode.as_str().to_string()),
);
store
.save()
.map_err(|e| format!("Failed to save settings: {}", e))?;
Ok(())
}
pub async fn get_saved_server_url(app: &tauri::AppHandle) -> Option<String> {
if let Some(url) = get_default_server_url(app.clone()).ok().flatten() {
println!("Using desktop-specific custom URL: {url}");

View File

@@ -23,7 +23,7 @@ import { initI18n, t } from "./i18n"
import pkg from "../package.json"
import "./styles.css"
import { commands, InitStep } from "./bindings"
import { Channel } from "@tauri-apps/api/core"
import { Channel, invoke } from "@tauri-apps/api/core"
import { createMenu } from "./menu"
const root = document.getElementById("root")
@@ -51,7 +51,18 @@ const listenForDeepLinks = async () => {
await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined)
}
const createPlatform = (password: Accessor<string | null>): Platform => ({
type BackendConfig = {
mode: "native" | "wsl"
}
const defaultBackend: BackendConfig = { mode: "native" }
const createPlatform = (
password: Accessor<string | null>,
backend: Accessor<BackendConfig>,
setBackend: (next: BackendConfig) => void,
fetchBackend: () => Promise<BackendConfig | null>,
): Platform => ({
platform: "desktop",
os: (() => {
const type = ostype()
@@ -61,6 +72,7 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
version: pkg.version,
async openDirectoryPickerDialog(opts) {
if (backend().mode === "wsl") return null
const result = await open({
directory: true,
multiple: opts?.multiple ?? false,
@@ -338,6 +350,19 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
await commands.setDefaultServerUrl(url)
},
getBackendConfig: async () => {
const next = await fetchBackend()
if (next) return next
return backend()
},
setBackendConfig: async (config: BackendConfig) => {
setBackend(config)
await invoke("set_backend_config", { config }).catch(() => undefined)
},
supportsNativePickers: () => backend().mode !== "wsl",
parseMarkdown: (markdown: string) => commands.parseMarkdownCommand(markdown),
webviewZoom,
@@ -378,7 +403,16 @@ void listenForDeepLinks()
render(() => {
const [serverPassword, setServerPassword] = createSignal<string | null>(null)
const platform = createPlatform(() => serverPassword())
const [backend, setBackend] = createSignal<BackendConfig>(defaultBackend)
const fetchBackend = async () => {
const next = await invoke<BackendConfig>("get_backend_config").catch(() => null)
if (!next) return null
setBackend(next)
return next
}
const platform = createPlatform(() => serverPassword(), backend, setBackend, fetchBackend)
function handleClick(e: MouseEvent) {
const link = (e.target as HTMLElement).closest("a.external-link") as HTMLAnchorElement | null
@@ -390,6 +424,7 @@ render(() => {
onMount(() => {
document.addEventListener("click", handleClick)
void fetchBackend()
onCleanup(() => {
document.removeEventListener("click", handleClick)
})