Compare commits

..

No commits in common. "a24f7de7dfccbcfed520cc1b1fe1ddcba79a7775" and "29b15f19c1b51f768c507edf3c121938a9211419" have entirely different histories.

8 changed files with 22 additions and 81 deletions

View file

@ -15,9 +15,7 @@
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.0.0", "@tauri-apps/api": "^2.0.0",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0", "@tauri-apps/plugin-clipboard-manager": "^2.0.0",
"@tauri-apps/plugin-opener": "^2.0.0",
"@xterm/addon-fit": "^0.10.0", "@xterm/addon-fit": "^0.10.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^5.5.0", "@xterm/xterm": "^5.5.0",
"react": "^18.3.0", "react": "^18.3.0",
"react-dom": "^18.3.0" "react-dom": "^18.3.0"

18
pnpm-lock.yaml generated
View file

@ -14,15 +14,9 @@ importers:
'@tauri-apps/plugin-clipboard-manager': '@tauri-apps/plugin-clipboard-manager':
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.3.2 version: 2.3.2
'@tauri-apps/plugin-opener':
specifier: ^2.0.0
version: 2.5.4
'@xterm/addon-fit': '@xterm/addon-fit':
specifier: ^0.10.0 specifier: ^0.10.0
version: 0.10.0(@xterm/xterm@5.5.0) version: 0.10.0(@xterm/xterm@5.5.0)
'@xterm/addon-web-links':
specifier: ^0.12.0
version: 0.12.0
'@xterm/xterm': '@xterm/xterm':
specifier: ^5.5.0 specifier: ^5.5.0
version: 5.5.0 version: 5.5.0
@ -517,9 +511,6 @@ packages:
'@tauri-apps/plugin-clipboard-manager@2.3.2': '@tauri-apps/plugin-clipboard-manager@2.3.2':
resolution: {integrity: sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ==} resolution: {integrity: sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ==}
'@tauri-apps/plugin-opener@2.5.4':
resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==}
'@types/babel__core@7.20.5': '@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@ -589,9 +580,6 @@ packages:
peerDependencies: peerDependencies:
'@xterm/xterm': ^5.0.0 '@xterm/xterm': ^5.0.0
'@xterm/addon-web-links@0.12.0':
resolution: {integrity: sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==}
'@xterm/xterm@5.5.0': '@xterm/xterm@5.5.0':
resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==} resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==}
@ -1194,10 +1182,6 @@ snapshots:
dependencies: dependencies:
'@tauri-apps/api': 2.11.0 '@tauri-apps/api': 2.11.0
'@tauri-apps/plugin-opener@2.5.4':
dependencies:
'@tauri-apps/api': 2.11.0
'@types/babel__core@7.20.5': '@types/babel__core@7.20.5':
dependencies: dependencies:
'@babel/parser': 7.29.3 '@babel/parser': 7.29.3
@ -1290,8 +1274,6 @@ snapshots:
dependencies: dependencies:
'@xterm/xterm': 5.5.0 '@xterm/xterm': 5.5.0
'@xterm/addon-web-links@0.12.0': {}
'@xterm/xterm@5.5.0': {} '@xterm/xterm@5.5.0': {}
assertion-error@2.0.1: {} assertion-error@2.0.1: {}

View file

@ -16,7 +16,6 @@ tauri-build = { version = "2", features = [] }
[dependencies] [dependencies]
tauri = { version = "2", features = [] } tauri = { version = "2", features = [] }
tauri-plugin-clipboard-manager = "2" tauri-plugin-clipboard-manager = "2"
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"

View file

@ -8,7 +8,6 @@
"core:event:default", "core:event:default",
"core:window:default", "core:window:default",
"clipboard-manager:allow-read-text", "clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text", "clipboard-manager:allow-write-text"
"opener:allow-open-url"
] ]
} }

View file

@ -16,7 +16,6 @@ pub fn run() {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_opener::init())
.manage(PtyManager::new()) .manage(PtyManager::new())
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
commands::list_distros, commands::list_distros,

View file

@ -13,10 +13,6 @@ use portable_pty::{CommandBuilder, MasterPty, PtySize, native_pty_system};
use serde::Serialize; use serde::Serialize;
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
/// Sentinel "distro" name used to spawn Windows PowerShell instead of WSL.
/// Frontend appends this to the distro list it shows in the dropdown.
pub const POWERSHELL_DISTRO: &str = "PowerShell";
pub type PaneId = u64; pub type PaneId = u64;
/// What we keep alive for each spawned PTY. /// What we keep alive for each spawned PTY.
@ -66,40 +62,26 @@ impl PtyManager {
}) })
.context("openpty failed")?; .context("openpty failed")?;
let is_powershell = distro.as_deref() == Some(POWERSHELL_DISTRO); let mut cmd = CommandBuilder::new("wsl.exe");
let cmd = if is_powershell {
// cwd from the leaf is ignored — leaves may carry Linux-style
// paths (e.g. `~`, `/mnt/d/...`) from a previously-assigned WSL
// distro that PowerShell wouldn't understand. PowerShell starts
// in its own default cwd; user can `cd` if they want.
let mut c = CommandBuilder::new("powershell.exe");
c.arg("-NoLogo");
c
} else {
let mut c = CommandBuilder::new("wsl.exe");
if let Some(d) = distro.as_deref() { if let Some(d) = distro.as_deref() {
c.arg("-d"); cmd.arg("-d");
c.arg(d); cmd.arg(d);
} }
// Default new panes to the WSL user's home (~) rather than the // Default new panes to the WSL user's home (~) rather than the
// Windows-side cwd we inherit from the launcher (typically // Windows-side cwd we inherit from the launcher (typically
// C:\Users\<you>, which shows up as /mnt/c/Users/<you> inside WSL). // C:\Users\<you>, which shows up as /mnt/c/Users/<you> inside WSL).
// wsl.exe resolves `~` against the distro's default shell. // wsl.exe resolves `~` against the distro's default shell.
let resolved_cwd = cwd.as_deref().unwrap_or("~"); let resolved_cwd = cwd.as_deref().unwrap_or("~");
c.arg("--cd"); cmd.arg("--cd");
c.arg(resolved_cwd); cmd.arg(resolved_cwd);
// Force a login shell so .bashrc etc. run and PATH is populated.
// wsl.exe without an explicit command launches the default shell // wsl.exe without an explicit command launches the default shell
// interactively, which is exactly what we want. // interactively, which is exactly what we want.
c
};
let spawn_err = if is_powershell { let child = pair
"failed to spawn powershell.exe" .slave
} else { .spawn_command(cmd)
"failed to spawn wsl.exe; is WSL installed?" .context("failed to spawn wsl.exe; is WSL installed?")?;
};
let child = pair.slave.spawn_command(cmd).context(spawn_err)?;
// We need to keep the master alive (drop = close the PTY), but we // We need to keep the master alive (drop = close the PTY), but we
// also need the reader and writer split from it. // also need the reader and writer split from it.

View file

@ -49,9 +49,6 @@ import "./lib/layout/Gutter.css";
const LEGACY_STORAGE_KEY = "tiletopia.tree.v1"; const LEGACY_STORAGE_KEY = "tiletopia.tree.v1";
const SAVE_DEBOUNCE_MS = 500; const SAVE_DEBOUNCE_MS = 500;
/** Sentinel "distro" the backend recognises to spawn powershell.exe instead
* of wsl.exe. Must match `POWERSHELL_DISTRO` in `src-tauri/src/pty.rs`. */
const POWERSHELL_DISTRO = "PowerShell";
function isInteractiveDistro(name: string): boolean { function isInteractiveDistro(name: string): boolean {
return !name.toLowerCase().startsWith("docker-desktop"); return !name.toLowerCase().startsWith("docker-desktop");
@ -103,14 +100,11 @@ export default function App() {
let resolvedDefault: string | undefined; let resolvedDefault: string | undefined;
try { try {
resolvedDistros = await listDistros(); resolvedDistros = await listDistros();
resolvedDefault =
resolvedDistros.find(isInteractiveDistro) ?? resolvedDistros[0];
} catch (e) { } catch (e) {
console.warn("list_distros failed:", e); console.warn("list_distros failed:", e);
} }
// Append PowerShell as a pseudo-distro so it appears in the titlebar
// default-picker and the per-pane dropdown.
resolvedDistros = [...resolvedDistros, POWERSHELL_DISTRO];
resolvedDefault =
resolvedDistros.find(isInteractiveDistro) ?? resolvedDistros[0];
if (cancelled) return; if (cancelled) return;
if (loaded) { if (loaded) {

View file

@ -1,13 +1,11 @@
import { useRef, useEffect } from "react"; import { useRef, useEffect } from "react";
import { Terminal } from "@xterm/xterm"; import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit"; import { FitAddon } from "@xterm/addon-fit";
import { WebLinksAddon } from "@xterm/addon-web-links";
import type { UnlistenFn } from "@tauri-apps/api/event"; import type { UnlistenFn } from "@tauri-apps/api/event";
import { import {
readText as clipboardReadText, readText as clipboardReadText,
writeText as clipboardWriteText, writeText as clipboardWriteText,
} from "@tauri-apps/plugin-clipboard-manager"; } from "@tauri-apps/plugin-clipboard-manager";
import { openUrl } from "@tauri-apps/plugin-opener";
import { import {
spawnPane, spawnPane,
writeToPane, writeToPane,
@ -126,16 +124,6 @@ export default function XtermPane({
const fit = new FitAddon(); const fit = new FitAddon();
fitRef.current = fit; fitRef.current = fit;
term.loadAddon(fit); term.loadAddon(fit);
// Underlines http(s) URLs in the terminal output and routes clicks
// through Tauri's opener plugin so they open in the user's default
// browser (WebView2 won't navigate on a plain window.open).
term.loadAddon(
new WebLinksAddon((_event, uri) => {
void openUrl(uri).catch((err) =>
console.warn("openUrl failed:", err),
);
}),
);
term.open(container); term.open(container);
// Initial size — fit before asking the PTY for its dimensions. // Initial size — fit before asking the PTY for its dimensions.