From 9dfb72f0ea90d0ccaf283ab35646760eb351ee05 Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Wed, 26 Aug 2026 10:21:41 +0500 Subject: [PATCH] feat: add register flow, update to use correct config file --- Cargo.toml | 5 +++++ docs/dev-workflow.md | 35 ++++++++++++++++++++++++++++- src/main.rs | 32 +++++++++++++++++++-------- tools/register.ps1 | 52 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 tools/register.ps1 diff --git a/Cargo.toml b/Cargo.toml index 42c1d8c..fba75d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,8 @@ winreg = "0.56.0" [build-dependencies] slint-build = "1.16.1" + +[profile.release] +lto = true +codegen-units = 1 +strip = true diff --git a/docs/dev-workflow.md b/docs/dev-workflow.md index 4c2ac79..a3b239f 100644 --- a/docs/dev-workflow.md +++ b/docs/dev-workflow.md @@ -129,10 +129,43 @@ HTML-макеты → PNG: **headless Edge** (`--headless --screenshot`), он - [x] env `BP_VIEW=settings` — запуск сразу с окном настроек (без пикера); нюанс: `run()` авто-показывает своё окно, поэтому в этом режиме цикл крутится на settings_window -- [ ] Редактирование браузера (имя/путь/флаги через LineEdit) — следующий шаг +- [ ] Редактирование браузера (имя/путь/флаги через LineEdit) — ОТЛОЖЕНО (решено: + cog в пикере открывает `config.toml` в редакторе — `subl`, fallback `notepad`; + если файла нет — создаётся с автодетектом). Окно SettingsWindow осталось + в коде (недоступно из UI), dev-доступ: env `BP_VIEW=settings` - [ ] Чтение флагов из .lnk ярлыков (крейс `lnk`) — по желанию - [ ] Добавить логотипы Edge/Zen в logos/ (пересоздать набор из alrrr/browser-logos) +### E3 — доведение до ежедневного использования — ГОТОВО + +- [x] cog → открыть конфиг в редакторе (subl → notepad) +- [x] Замер cold start: Instant в main → печать при старте event loop +- [x] `tools/register.ps1` (+ `-Uninstall`): **ставит пакет в + `%LOCALAPPDATA%\bropicker\` (exe + logos + icons)** и регистрирует + ProgId/Capabilities/RegisteredApplications в HKCU на путь из LOCALAPPDATA + (не target\ — переживает cargo clean и перенос репо), открывает + ms-settings:defaultapps +- [x] Иконки резолвятся от папки exe (иначе при запуске обработчиком ссылок + cwd = system32 и иконки бы отвалились); проверено запуском из + LOCALAPPDATA с cwd=System32 +- [x] Release-профиль: lto + codegen-units=1 + strip + +## Этап F — релиз + +- [x] `[profile.release]`: lto, codegen-units=1, strip +- [x] Замер cold start (release, до старта event loop): **183 ms холодный / + 120-122 ms тёплый**; из LOCALAPPDATA первый запуск 153 ms. + Цель <100 ms чуть не достигнута; варианты оптимизации, если захочется: + renderer-femtovg вместо skia (быстрее init GPU), отложенная загрузка + конфига. Пока считаем приемлемым +- [ ] Иконка exe (.ico через build.rs winres) +- [ ] Выбрать лицензию проекта: GPLv3 (опенсорс) или Royalty-free Slint (закрытый десктоп, + атрибуция AboutSlint) — зафиксировать в README и LICENSE +- [ ] Скриншоты в README из tools/out +- [ ] Ручной сценарий приёмки: register → клик ссылки в другом приложении → + пикер → выбор → вкладка открылась; повторный клик того же домена при + always_ask=off → сразу браузер + ## Этап F — релиз - [ ] `[profile.release]`: lto, codegen-units=1, strip diff --git a/src/main.rs b/src/main.rs index 70e5d24..90d1f08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,14 @@ use config::{BrowserEntry, Config}; slint::include_modules!(); fn load_icon(rel: &str) -> slint::Image { + if let Ok(exe) = std::env::current_exe() { + if let Some(dir) = exe.parent() { + let p = dir.join(rel); + if p.exists() { + return slint::Image::load_from_path(&p).unwrap_or_default(); + } + } + } slint::Image::load_from_path(std::path::Path::new(rel)).unwrap_or_default() } @@ -202,16 +210,19 @@ fn init(cfg: Config, url: Option) -> State { }); main_window.on_settings_clicked({ - let settings_window = settings_window.clone_strong(); move || { - settings_window.show().unwrap(); - let weak = settings_window.as_weak(); - let _ = slint::invoke_from_event_loop(move || { - if let Some(sw) = weak.upgrade() { - winit::center_window(sw.window()); - sw.invoke_restore_focus(); - } - }); + let path = config::config_path(); + if !path.exists() { + let mut c = config::load(); + config::ensure_browsers(&mut c); + } + let editor = std::process::Command::new("subl") + .arg(&path) + .spawn() + .or_else(|_| std::process::Command::new("notepad").arg(&path).spawn()); + if let Err(e) = editor { + eprintln!("[bp] cannot open editor: {e}"); + } } }); @@ -307,6 +318,8 @@ pub struct State { } pub fn main() { + let start = std::time::Instant::now(); + let mut cfg = config::load(); config::ensure_browsers(&mut cfg); @@ -347,6 +360,7 @@ pub fn main() { winit::center_window(mw.window()); mw.invoke_restore_focus(); } + eprintln!("[bp] cold start -> event loop: {:?}", start.elapsed()); }); state.main_window.run().unwrap(); diff --git a/tools/register.ps1 b/tools/register.ps1 new file mode 100644 index 0000000..d3ad142 --- /dev/null +++ b/tools/register.ps1 @@ -0,0 +1,52 @@ +param( + [switch]$Uninstall +) + +$ErrorActionPreference = "Stop" + +$installDir = Join-Path $env:LOCALAPPDATA "bropicker" +$classes = "HKCU:\Software\Classes\bropicker" +$caps = "HKCU:\Software\bropicker-Capabilities" +$regApps = "HKCU:\Software\RegisteredApplications" + +if ($Uninstall) { + Remove-Item -Recurse -Force $classes -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force $caps -ErrorAction SilentlyContinue + Remove-ItemProperty -Path $regApps -Name "bropicker" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force $installDir -ErrorAction SilentlyContinue + Write-Host "bropicker unregistered and removed from $installDir" + exit 0 +} + +$src = Join-Path $PSScriptRoot "..\target\release\bropicker.exe" +if (-not (Test-Path $src)) { + Write-Error "target\release\bropicker.exe not found. Build first: cargo build --release" + exit 1 +} + +New-Item -ItemType Directory -Force -Path $installDir | Out-Null +Copy-Item $src (Join-Path $installDir "bropicker.exe") -Force +Copy-Item (Join-Path $PSScriptRoot "..\logos") (Join-Path $installDir "logos") -Recurse -Force +Copy-Item (Join-Path $PSScriptRoot "..\icons") (Join-Path $installDir "icons") -Recurse -Force + +$exe = Join-Path $installDir "bropicker.exe" +Write-Host "Installed to: $exe" + +New-Item -Path "$classes\shell\open\command" -Force | Out-Null +Set-ItemProperty -Path $classes -Name "(default)" -Value "bropicker" +Set-ItemProperty -Path $classes -Name "URL Protocol" -Value "" +Set-ItemProperty -Path "$classes\shell\open\command" -Name "(default)" -Value "`"$exe`" `"%1`"" + +New-Item -Path $caps -Force | Out-Null +Set-ItemProperty -Path $caps -Name "ApplicationName" -Value "bropicker" +Set-ItemProperty -Path $caps -Name "ApplicationDescription" -Value "Lightweight link picker: choose which browser opens the URL" + +New-Item -Path "$caps\URLAssociations" -Force | Out-Null +Set-ItemProperty -Path "$caps\URLAssociations" -Name "https" -Value "bropicker" +Set-ItemProperty -Path "$caps\URLAssociations" -Name "http" -Value "bropicker" + +New-Item -Path $regApps -Force | Out-Null +Set-ItemProperty -Path $regApps -Name "bropicker" -Value "Software\bropicker-Capabilities" + +Write-Host "Registered. Now select bropicker for HTTP/HTTPS in the opened Settings window." +Start-Process "ms-settings:defaultapps"