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
119 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 // Out of the lock first, as in tray::runner_changed: off the main thread
67 // set_enabled waits for the main thread.
68 let items = ITEMS.lock().unwrap().clone();
69 for item in &items {
70 let _ = item.set_enabled(usable(app));
71 }
72 allow(app, on);
73 if !on && let Some(site) = crate::frame::site(app) {
74 site.close_devtools();
75 }
76}
77
78/// Lets WebView2 open the inspector, from its own F12, Ctrl+Shift+I and
79/// Inspect as well as when g1t asks, or not. WebKit keeps what its web
80/// view was made with.
81#[cfg(windows)]
82pub fn allow(app: &AppHandle, on: bool) {
83 let Some(site) = crate::frame::site(app) else { return };
84 let _ = site.with_webview(move |webview| {
85 // SAFETY: the controller is the site's, alive while the web view is,
86 // and this runs on the thread that owns it.
87 let _ = unsafe { webview.controller().CoreWebView2().and_then(|core| core.Settings()).and_then(|settings| settings.SetAreDevToolsEnabled(on)) };
88 });
89}
90
91#[cfg(not(windows))]
92pub fn allow(_app: &AppHandle, _on: bool) {}
93
94/// The site's web view, while the inspector opens: an error otherwise,
95/// which the site's `devtools.open()` sees.
96fn site_if_on(app: &AppHandle) -> Result<Webview, String> {
97 if !on(app) {
98 return Err("Developer tools are off. Turn them on in the app's settings, under Window.".into());
99 }
100 if changed(app) {
101 return Err("Developer tools turn on when g1t restarts.".into());
102 }
103 crate::frame::site(app).ok_or_else(|| "g1t's page is not open".into())
104}
105
106/// Opens the inspector for the site's page.
107pub fn open(app: &AppHandle) -> Result<(), String> {
108 site_if_on(app)?.open_devtools();
109 Ok(())
110}
111
112/// The menu row and the shortcuts: opens the inspector, or closes it if it
113/// is open. WebView2 can't tell whether it is, nor close it, so on
114/// Windows it only opens, and the inspector's own window closes it.
115pub fn toggle(app: &AppHandle) -> Result<(), String> {
116 let site = site_if_on(app)?;
117 if site.is_devtools_open() { site.close_devtools() } else { site.open_devtools() }
118 Ok(())
119}