Skip to content

Commit e25f451

Browse files
author
AENERV7
committed
feat: auto-detect 7z from system PATH with override option
- Add find_seven_zip_in_path() to search PATH for 7z/7zz - Add detect_seven_zip_in_path command for frontend - Skip first-run setup when 7z found in PATH - Show detected PATH in readonly input with Override checkbox - Override checkbox lets user specify custom 7z path - Persist override state across restarts - Bump version to 0.3.0
1 parent 8419bcf commit e25f451

6 files changed

Lines changed: 136 additions & 13 deletions

File tree

dist/index.html

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,12 @@ <h2 data-i18n="pw_title"></h2>
196196
<p id="pwStatus" class="status-text"></p>
197197
</div>
198198
<div class="settings-col right">
199-
<h2 data-i18n="sz_title"></h2>
199+
<div style="display:flex; align-items:center; gap:0.5rem;">
200+
<h2 data-i18n="sz_title" style="flex:1;"></h2>
201+
<label id="szOverrideLabel" style="display:none; font-size:0.8rem; color:var(--fg2); cursor:pointer; white-space:nowrap;">
202+
<input type="checkbox" id="szOverride" style="cursor:pointer; vertical-align:middle;" /> <span data-i18n="sz_override"></span>
203+
</label>
204+
</div>
200205
<input class="path-input" id="szDir" autocomplete="off" />
201206
<p id="szStatus" class="status-text"></p>
202207
<h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
@@ -252,6 +257,8 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
252257
sz_placeholder: "例如: C:\\Program Files\\7-Zip 或 /opt/homebrew/bin",
253258
sz_invalid: "路径无效:未找到 7-Zip 或 7-Zip ZS 可执行文件",
254259
sz_version: (v) => `7-Zip 版本: ${v}`,
260+
sz_from_path: (dir) => `已从系统环境变量检测到 7-Zip: ${dir}`,
261+
sz_override: "手动指定",
255262
saving: "保存中...",
256263
save_btn: "保存设置",
257264
saved_all: "设置已保存",
@@ -290,6 +297,8 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
290297
sz_placeholder: "例如: C:\\Program Files\\7-Zip 或 /opt/homebrew/bin",
291298
sz_invalid: "路徑無效:未找到 7-Zip 或 7-Zip ZS 可執行檔",
292299
sz_version: (v) => `7-Zip 版本: ${v}`,
300+
sz_from_path: (dir) => `已從系統環境變數偵測到 7-Zip: ${dir}`,
301+
sz_override: "手動指定",
293302
saving: "儲存中...",
294303
save_btn: "儲存設定",
295304
saved_all: "設定已儲存",
@@ -328,6 +337,8 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
328337
sz_placeholder: "e.g. C:\\Program Files\\7-Zip or /opt/homebrew/bin",
329338
sz_invalid: "Invalid path: 7-Zip or 7-Zip ZS executable not found",
330339
sz_version: (v) => `7-Zip version: ${v}`,
340+
sz_from_path: (dir) => `7-Zip detected in system PATH: ${dir}`,
341+
sz_override: "Override",
331342
saving: "Saving...",
332343
save_btn: "Save Settings",
333344
saved_all: "Settings saved",
@@ -479,6 +490,15 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
479490
// ── 7-Zip 路径 ──
480491
const szDir = document.getElementById("szDir");
481492
const szStatus = document.getElementById("szStatus");
493+
const szOverrideLabel = document.getElementById("szOverrideLabel");
494+
const szOverride = document.getElementById("szOverride");
495+
let szFromPath = ""; // non-empty if 7z detected in system PATH
496+
497+
function setSzReadOnly(readonly) {
498+
szDir.readOnly = readonly;
499+
szDir.style.opacity = readonly ? "0.7" : "";
500+
szDir.style.cursor = readonly ? "default" : "";
501+
}
482502

483503
async function updateSzVersion(dir) {
484504
const ver = await invoke("get_seven_zip_version", { dir });
@@ -487,9 +507,56 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
487507
}
488508

489509
async function loadSzDir() {
490-
try { szDir.value = await invoke("get_seven_zip_dir"); await validateSzDir(); }
510+
try {
511+
// Check system PATH first
512+
szFromPath = await invoke("detect_seven_zip_in_path");
513+
if (szFromPath) {
514+
szOverrideLabel.style.display = "";
515+
const savedDir = await invoke("get_seven_zip_dir");
516+
if (savedDir) {
517+
// User previously overrode — restore override state
518+
szOverride.checked = true;
519+
szDir.value = savedDir;
520+
setSzReadOnly(false);
521+
await validateSzDir();
522+
} else {
523+
szOverride.checked = false;
524+
szDir.value = szFromPath;
525+
setSzReadOnly(true);
526+
szValid = true;
527+
szStatus.textContent = t.sz_from_path(szFromPath);
528+
szStatus.style.color = "var(--success)";
529+
await updateSzVersion("");
530+
}
531+
return;
532+
}
533+
szDir.value = await invoke("get_seven_zip_dir");
534+
await validateSzDir();
535+
}
491536
catch (e) { szStatus.textContent = t.load_fail(e); szStatus.style.color = "var(--error)"; }
492537
}
538+
539+
szOverride.addEventListener("change", async () => {
540+
if (szOverride.checked) {
541+
szDir.value = "";
542+
setSzReadOnly(false);
543+
szDir.focus();
544+
szValid = false;
545+
szStatus.textContent = "";
546+
szDir.style.borderColor = "";
547+
} else {
548+
szDir.value = szFromPath;
549+
setSzReadOnly(true);
550+
szValid = true;
551+
szStatus.textContent = t.sz_from_path(szFromPath);
552+
szStatus.style.color = "var(--success)";
553+
szDir.style.borderColor = "";
554+
// Clear saved override path
555+
await invoke("save_seven_zip_dir", { dir: "" });
556+
await updateSzVersion("");
557+
}
558+
checkDirty();
559+
});
493560
async function validateSzDir() {
494561
const dir = szDir.value.trim();
495562
const valid = await invoke("check_seven_zip_dir", { dir });
@@ -537,7 +604,12 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
537604
// ── 手动保存 ──
538605
document.getElementById("saveSettingsBtn").addEventListener("click", async () => {
539606
await savePasswords();
540-
if (szValid) { await saveSzDir(); }
607+
if (szFromPath && !szOverride.checked) {
608+
// Using PATH-detected 7z, clear saved dir
609+
await invoke("save_seven_zip_dir", { dir: "" });
610+
} else if (szValid) {
611+
await saveSzDir();
612+
}
541613
const langVal = langSelect.value;
542614
savedLangPref = langVal;
543615
lang = (langVal === "auto") ? detectLang() : langVal;
@@ -546,7 +618,7 @@ <h2 data-i18n="lang_title" style="margin-top:1.5rem;"></h2>
546618
try { await invoke("save_language", { language: langVal }); } catch (e) { /* ignore */ }
547619
savedSnapshot.pw = textarea.value;
548620
savedSnapshot.lang = langVal;
549-
if (szValid) { savedSnapshot.sz = szDir.value; }
621+
if (!szFromPath || szOverride.checked) { if (szValid) savedSnapshot.sz = szDir.value; }
550622
checkDirty();
551623
showToast(t.saved_all);
552624
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "yauz",
3-
"version": "0.2.9",
3+
"version": "0.3.0",
44
"private": true,
55
"scripts": {
66
"tauri": "tauri",

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "yauz"
3-
version = "0.2.9"
3+
version = "0.3.0"
44
edition = "2021"
55

66
[lib]

src-tauri/src/lib.rs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ fn resolve_seven_zip_exe(dir: &str) -> PathBuf {
8585
}
8686
}
8787

88+
/// Search for 7z/7zz in system PATH. Returns the full path if found.
89+
fn find_seven_zip_in_path() -> Option<PathBuf> {
90+
#[cfg(target_os = "windows")]
91+
let names = ["7z.exe", "7zz.exe"];
92+
#[cfg(not(target_os = "windows"))]
93+
let names = ["7z", "7zz"];
94+
95+
if let Some(path_var) = std::env::var_os("PATH") {
96+
for dir in std::env::split_paths(&path_var) {
97+
for name in &names {
98+
let candidate = dir.join(name);
99+
if candidate.exists() {
100+
return Some(candidate);
101+
}
102+
}
103+
}
104+
}
105+
None
106+
}
107+
88108
// ── INI 读写 ──
89109

90110
fn load_config() -> (Vec<String>, String, String, bool) {
@@ -199,10 +219,30 @@ fn check_seven_zip_dir(dir: String) -> bool {
199219
exe.exists()
200220
}
201221

222+
/// Check if 7z is available in system PATH.
223+
/// Returns the directory containing the executable, or empty string if not found.
224+
#[tauri::command]
225+
fn detect_seven_zip_in_path() -> String {
226+
match find_seven_zip_in_path() {
227+
Some(exe_path) => exe_path.parent()
228+
.map(|p| p.to_string_lossy().to_string())
229+
.unwrap_or_default(),
230+
None => String::new(),
231+
}
232+
}
233+
202234
#[tauri::command]
203235
fn get_seven_zip_version(dir: String) -> String {
204-
let exe = resolve_seven_zip_exe(&dir);
205-
if !exe.exists() { return "?".to_string(); }
236+
let exe = if dir.is_empty() {
237+
match find_seven_zip_in_path() {
238+
Some(p) => p,
239+
None => return "?".to_string(),
240+
}
241+
} else {
242+
let e = resolve_seven_zip_exe(&dir);
243+
if !e.exists() { return "?".to_string(); }
244+
e
245+
};
206246
let mut cmd = Command::new(&exe);
207247
cmd.args(["i"]);
208248
#[cfg(target_os = "windows")]
@@ -411,7 +451,12 @@ fn try_extract(sz: &PathBuf, archive: &str, out_dir: &str, password: Option<&str
411451
fn extract_files(app: AppHandle, state: State<AppState>, files: Vec<String>, out_dir: String) {
412452
let dir = state.seven_zip_dir.lock().unwrap().clone();
413453
let passwords = state.passwords.lock().unwrap().clone();
414-
let sz = resolve_seven_zip_exe(&dir);
454+
let sz = if dir.is_empty() {
455+
// No configured dir — try system PATH
456+
find_seven_zip_in_path().unwrap_or_default()
457+
} else {
458+
resolve_seven_zip_exe(&dir)
459+
};
415460

416461
std::thread::spawn(move || {
417462
if !sz.exists() {
@@ -479,7 +524,13 @@ fn extract_files(app: AppHandle, state: State<AppState>, files: Vec<String>, out
479524
}
480525

481526
pub fn run() {
482-
let (passwords, seven_zip_dir, language, needs_setup) = load_config();
527+
let (passwords, seven_zip_dir, language, mut needs_setup) = load_config();
528+
529+
// If 7z is found in system PATH, skip setup (user can still override in settings)
530+
if find_seven_zip_in_path().is_some() {
531+
needs_setup = false;
532+
}
533+
483534
tauri::Builder::default()
484535
.plugin(tauri_plugin_dialog::init())
485536
.plugin(tauri_plugin_shell::init())
@@ -493,7 +544,7 @@ pub fn run() {
493544
get_passwords, save_passwords,
494545
get_seven_zip_dir, save_seven_zip_dir, check_seven_zip_dir, get_seven_zip_version,
495546
get_language, save_language,
496-
check_needs_setup,
547+
check_needs_setup, detect_seven_zip_in_path,
497548
extract_files
498549
])
499550
.run(tauri::generate_context!())

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"productName": "YAUZ",
3-
"version": "0.2.9",
3+
"version": "0.3.0",
44
"identifier": "com.yauz.dev",
55
"build": {
66
"frontendDist": "../dist"

0 commit comments

Comments
 (0)