Skip to content

feat: add Windows support#158

Open
kogasura wants to merge 1 commit intoarto-app:mainfrom
kogasura:feat/windows-support
Open

feat: add Windows support#158
kogasura wants to merge 1 commit intoarto-app:mainfrom
kogasura:feat/windows-support

Conversation

@kogasura
Copy link
Copy Markdown

Summary

Adds initial Windows support for Arto. The application builds and runs on Windows with these changes:

  • Shortcut key mapping: Cmd/Meta is mapped to Ctrl on non-macOS platforms, so preset keybindings like Cmd+n work as Ctrl+n on Windows
  • Platform-specific shortcut hints: macOS uses symbols (⌘⇧⌥⌃), Windows/Linux uses text labels (Ctrl+, Shift+, Alt+)
  • JS initialization timeout: Increased from 2.5s to 10s for keyboard interceptor and search API, as WebView2 on Windows takes longer to parse the 5MB JS bundle

Test plan

  • cargo check passes on Windows (0 errors, 2 pre-existing warnings)
  • dx bundle --release produces a working Windows executable
  • Application launches and renders Markdown correctly
  • Dark theme detection works
  • File watching works
  • IPC server starts (Windows Named Pipes)
  • Keyboard shortcuts display as Ctrl+ instead of
  • JS keyboard interceptor initializes successfully (no timeout warning)
  • JS search API initializes successfully (no timeout warning)

Notes

  • Windows icon (.ico) is not yet created, so dx bundle shows a non-fatal icon error
  • DPI awareness could be improved in a follow-up
  • Tested on Windows 11 with Rust 1.89.0 and Dioxus CLI 0.7.3

- Map Cmd/Meta to Ctrl on non-macOS platforms in shortcut parsing
- Use platform-specific shortcut hint formatting (macOS symbols vs Windows text)
- Increase JS API initialization timeout from 2.5s to 10s for WebView2
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial cross-platform (Windows) support for Arto by adapting shortcut parsing/formatting and increasing WebView JS-bridge initialization timeouts to accommodate slower WebView2 startup.

Changes:

  • Map Cmd/Meta/Command modifiers to Ctrl on non-macOS during shortcut parsing.
  • Render shortcut hints with macOS symbols on macOS and text labels (e.g., Ctrl+) on Windows/Linux.
  • Increase JS readiness retry windows from 2.5s to 10s for keyboard interceptor and search API.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
desktop/src/shortcut.rs Changes shortcut parsing so Cmd-style presets work as Ctrl on non-macOS.
desktop/src/keybindings/hint.rs Makes shortcut hint rendering platform-specific (symbols on macOS, text on others).
desktop/src/components/search_bar.rs Extends JS search API readiness polling timeout to 10s.
desktop/src/components/app/keybinding_engine.rs Extends JS keyboard interceptor readiness polling timeout to 10s.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +257 to +262
// On non-macOS platforms, map Cmd/Command/Meta to CONTROL
// so that preset keybindings like "Cmd+n" work as "Ctrl+n" on Windows/Linux
#[cfg(target_os = "macos")]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::META),
#[cfg(not(target_os = "macos"))]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::CONTROL),
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_chord now maps "Cmd/Command/Meta" to Modifiers::CONTROL on non-macOS, which will make the existing unit tests that assert Modifiers::META for "Cmd+…" fail on Windows/Linux (e.g., parse_cmd_key, parse_symbol_alias). Update those tests to be OS-aware (e.g., #[cfg(target_os = "macos")] expect META, otherwise expect CONTROL).

Copilot uses AI. Check for mistakes.
Comment on lines 75 to 103
@@ -83,10 +85,46 @@ fn format_chord_hint(chord: &str) -> String {
}
}
}

#[cfg(not(target_os = "macos"))]
for modifier in &parts {
match modifier.to_ascii_lowercase().as_str() {
"cmd" | "command" | "meta" => out.push_str("Ctrl+"),
"ctrl" | "control" => out.push_str("Ctrl+"),
"shift" => out.push_str("Shift+"),
"alt" | "option" => out.push_str("Alt+"),
other => {
out.push_str(other);
out.push('+');
}
}
}

out.push_str(&format_key_name_hint(key_part));
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On non-macOS this now formats modifier hints as text (e.g., "Ctrl+") instead of symbols, but the existing tests in this module still assert macOS symbol output (e.g., expecting "⌘⇧O" / "⌃W H"). This will fail when running cargo test on Windows/Linux; make the assertions conditional on target_os (or split into per-platform tests).

Copilot uses AI. Check for mistakes.
Comment on lines +257 to +262
// On non-macOS platforms, map Cmd/Command/Meta to CONTROL
// so that preset keybindings like "Cmd+n" work as "Ctrl+n" on Windows/Linux
#[cfg(target_os = "macos")]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::META),
#[cfg(not(target_os = "macos"))]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::CONTROL),
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mapping "Cmd/Command/Meta" to Modifiers::CONTROL on non-macOS will create duplicate shortcuts in presets/configs that intentionally include both Cmd- and Ctrl-based bindings. Concretely, the Emacs preset global context includes both "Cmd+n" and "Ctrl+n"; after this change both normalize to "Ctrl+n", causing validate_preset_bindings() to panic on Windows/Linux. Consider keeping Cmd as META in config parsing and translating the physical key at runtime, or introduce platform-specific presets / a distinct token (e.g., "Primary") so Cmd-based and Ctrl-based bindings can coexist without collisions.

Suggested change
// On non-macOS platforms, map Cmd/Command/Meta to CONTROL
// so that preset keybindings like "Cmd+n" work as "Ctrl+n" on Windows/Linux
#[cfg(target_os = "macos")]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::META),
#[cfg(not(target_os = "macos"))]
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::CONTROL),
// Keep Cmd/Command/Meta as META in the parsed representation on all platforms.
// Platform-specific translation of META (e.g., treating it like Ctrl on non-macOS)
// should be handled at runtime, so that Cmd- and Ctrl-based bindings can coexist
// in presets/configs without colliding.
"meta" | "cmd" | "command" => modifiers.insert(Modifiers::META),

Copilot uses AI. Check for mistakes.
@lambdalisue
Copy link
Copy Markdown
Member

lambdalisue commented Mar 28, 2026

I’m unable to test this since I don’t have a Windows environment, but does this PR alone fully provide Windows support? Please provide screenshots and screencasts.

Also, it appears that multiple independent concepts are bundled into a single commit. Please split them into appropriate, logically separated commits.

@kassyi
Copy link
Copy Markdown

kassyi commented Apr 4, 2026

Got it. I’ve broken the changes down into nine atomic, minimal branches. Since I’ve broken them down into atomic, minimal changes, attempting to build each individual PR will result in a build error. However, by merging them all using this command, you can test the functionality without encountering any build errors.

# 1. Create a temporary branch for testing
git checkout main
git branch -D test-all-features # Delete if one already exists
git checkout -b test-all-features

# 2. Merge all 9 created branches
git merge fix/windows-ui-shortcuts --no-edit
git merge feat/safe-asset-loading --no-edit
git merge fix/renderer-footnotes --no-edit
git merge fix/context-menu-async --no-edit
git merge fix/renderer-mermaid --no-edit
git merge fix/sidebar-explorer --no-edit
git merge fix/markdown-clipboard --no-edit
git merge fix/renderer-overscroll --no-edit
git merge fix/context-menu-overflow --no-edit

# 3. Run
cd p:\Projects\Active\Arto\desktop
cargo run

@lambdalisue
Copy link
Copy Markdown
Member

I'm sorry but it's not what I want. Each individual branches should be independent and meaningful.

@kassyi
Copy link
Copy Markdown

kassyi commented Apr 5, 2026

Thank you for pointing that out. So, am I correct in understanding that each PR must be atomic, meaningful, and independent, and must pass compilation and CI checks on its own?

To put it another way, are you saying that because a single PR labeled “Windows support” contains countless bug fixes unrelated to Windows (such as footnotes and sidebars), and because all of that has been compressed into a single massive commit, you’d like the commits to be split up appropriately?

@kogasura
Copy link
Copy Markdown
Author

kogasura commented Apr 6, 2026

I've split this PR into three independent, atomic PRs that each pass compilation and CI on their own:

  1. fix: map Cmd/Meta to Ctrl on non-macOS platforms #171fix/windows-shortcut-mapping: Map Cmd/Meta to Ctrl on non-macOS platforms (shortcut.rs)
  2. feat: platform-specific shortcut hint labels #172feat/platform-shortcut-hints: Platform-specific shortcut hint labels (hint.rs)
  3. fix: increase JS bridge initialization timeout for WebView2 #173fix/webview-init-timeout: Increase JS bridge initialization timeout for WebView2 (keybinding_engine.rs, search_bar.rs)

Each PR includes screenshots showing before/after behavior on Windows 11.

@lambdalisue
Copy link
Copy Markdown
Member

lambdalisue commented Apr 11, 2026

It seems all PRs are closed with

Closing in favor of addressing the root cause first (asset loading on Windows).

So, which one is a PR for addressing that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants