Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
116 linesCodeBlameRaw
1//! The web inspector, for the site's page in the window: off unless
2//! someone turns on Developer tools in settings, for when a page goes
3//! wrong and they want its console. With it on, View › Developer tools
4//! (Ctrl+Shift+I, or ⌥⌘I on macOS), F12 on the page (bridge.js), and the
5//! site's own `g1tDesktop.devtools.open()` open it; with it off, none of
6//! them do anything.
7//!
8//! Release builds have the inspector only through Tauri's `devtools`
9//! feature (Cargo.toml). Whether a web view has it at all is decided when
10//! the web view is made. On Windows, WebView2 lets it change while running,
11//! its own F12, Ctrl+Shift+I and Inspect with it, so the setting takes
12//! effect at once. WebKit, on macOS and Linux, keeps what it was made with,
13//! and its Inspect Element with it, until g1t restarts; the settings then
14//! offer the restart, as they do for the title bar.
15
16use std::sync::Mutex;
17
18use tauri::menu::MenuItem;
19use tauri::{AppHandle, Webview, Wry};
20
21use crate::config;
22
23/// Whether the setting is on now.
24pub fn on(app: &AppHandle) -> bool {
25 config::settings(app).developer_tools
26}
27
28/// Whether the site's web view was made with the inspector, which WebKit
29/// keeps until g1t restarts: decided once, as it is made.
30static STARTED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
31
32/// Whether this run's site web view has the inspector.
33pub fn started(app: &AppHandle) -> bool {
34 *STARTED.get_or_init(|| on(app))
35}
36
37/// The setting differs from what the site's web view was made with, and
38/// only a restart changes that: never on Windows, where it changes at once.
39pub fn changed(app: &AppHandle) -> bool {
40 !cfg!(windows) && started(app) != on(app)
41}
42
43/// The menu's Developer tools rows, kept so a change of the setting can
44/// turn them on or off; a row that is off has no shortcut either.
45static ITEMS: Mutex<Vec<MenuItem<Wry>>> = Mutex::new(Vec::new());
46
47/// The menu row, with its shortcut: Ctrl+Shift+I, or ⌥⌘I on macOS.
48pub fn item(app: &AppHandle) -> tauri::Result<MenuItem<Wry>> {
49 let shortcut = if cfg!(target_os = "macos") { "Cmd+Alt+I" } else { "Ctrl+Shift+I" };
50 let item = MenuItem::with_id(app, "devtools", "Developer tools", on(app), Some(shortcut))?;
51 ITEMS.lock().unwrap().push(item.clone());
52 Ok(item)
53}
54
55/// Whether the inspector opens now: the setting is on, and the site's web
56/// view was made with it, or is WebView2's, which takes it at once.
57pub fn usable(app: &AppHandle) -> bool {
58 on(app) && !changed(app)
59}
60
61/// The setting changed: the menu rows follow it, and so does WebView2's
62/// own way in. Turned off, an inspector that is open closes where the
63/// system can close it (not on Windows, whose WebView2 has no way to).
64pub fn setting_changed(app: &AppHandle) {
65 let on = on(app);
66 for item in ITEMS.lock().unwrap().iter() {
67 let _ = item.set_enabled(usable(app));
68 }
69 allow(app, on);
70 if !on && let Some(site) = crate::frame::site(app) {
71 site.close_devtools();
72 }
73}
74
75/// Lets WebView2 open the inspector, from its own F12, Ctrl+Shift+I and
76/// Inspect as well as when g1t asks, or not. WebKit keeps what its web
77/// view was made with.
78#[cfg(windows)]
79pub fn allow(app: &AppHandle, on: bool) {
80 let Some(site) = crate::frame::site(app) else { return };
81 let _ = site.with_webview(move |webview| {
82 // SAFETY: the controller is the site's, alive while the web view is,
83 // and this runs on the thread that owns it.
84 let _ = unsafe { webview.controller().CoreWebView2().and_then(|core| core.Settings()).and_then(|settings| settings.SetAreDevToolsEnabled(on)) };
85 });
86}
87
88#[cfg(not(windows))]
89pub fn allow(_app: &AppHandle, _on: bool) {}
90
91/// The site's web view, while the inspector opens: an error otherwise,
92/// which the site's `devtools.open()` sees.
93fn site_if_on(app: &AppHandle) -> Result<Webview, String> {
94 if !on(app) {
95 return Err("Developer tools are off. Turn them on in the app's settings, under Window.".into());
96 }
97 if changed(app) {
98 return Err("Developer tools turn on when g1t restarts.".into());
99 }
100 crate::frame::site(app).ok_or_else(|| "g1t's page is not open".into())
101}
102
103/// Opens the inspector for the site's page.
104pub fn open(app: &AppHandle) -> Result<(), String> {
105 site_if_on(app)?.open_devtools();
106 Ok(())
107}
108
109/// The menu row and the shortcuts: opens the inspector, or closes it if it
110/// is open. WebView2 can't tell whether it is, nor close it, so on
111/// Windows it only opens, and the inspector's own window closes it.
112pub fn toggle(app: &AppHandle) -> Result<(), String> {
113 let site = site_if_on(app)?;
114 if site.is_devtools_open() { site.close_devtools() } else { site.open_devtools() }
115 Ok(())
116}