Merge remote-tracking branch 'origin/main' into feat/maven-dependency-analyzer

# Conflicts:
#	src/platform/locales/text/zh.json
Цей коміт міститься в:
l0ng-ai committed 2026-10-27 18:48:57 +08:00
коміт 8ca6206f18
57 files changed
+2945 -268

No files matched your search

+1
Переглянути файл
@@ -332,6 +332,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
plugin::plugin_run_command,
plugin::plugin_set_active_file,
plugin::plugin_set_theme,
plugin::plugin_set_theme_frame,
perf::app_metrics,
perf::clear_caches,
analysis::inspect_code,
+14
Переглянути файл
@@ -11,9 +11,13 @@ use parking_lot::Mutex;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, LazyLock};
use std::time::Duration;
use tauri::ipc::Channel;
use tauri::{AppHandle, Manager, State, Window};
/// How long `plugin_list` waits for the startup load before answering with what it has.
const INITIAL_LOAD_WAIT: Duration = Duration::from_secs(5);
/// Window label → its event channel.
static SUBSCRIBERS: LazyLock<Mutex<HashMap<String, Channel<PluginEvent>>>> = LazyLock::new(Default::default);
@@ -62,6 +66,8 @@ pub async fn plugin_list(window: Window, state: State<'_, AppState>) -> IdeResul
let host = state.plugins.clone();
let root = state.project(window.label()).ok().map(|p| p.root.clone());
blocking(move || {
// A window opened at startup would otherwise see no plugins and drop the selected theme.
host.wait_initial_load(INITIAL_LOAD_WAIT);
if let Some(root) = &root {
host.sync_project(root);
}
@@ -156,3 +162,11 @@ pub fn plugin_set_theme(
_ => state.plugins.set_theme(None),
}
}
/// The UI reports the selected plugin theme's resolved frame colour (`#rrggbb[aa]`),
/// which new windows open in before their page loads.
#[tauri::command]
#[specta::specta]
pub fn plugin_set_theme_frame(state: State<'_, AppState>, color: Option<String>) -> IdeResult<()> {
state.plugins.set_theme_frame(color.as_deref())
}
+27 -4
Переглянути файл
@@ -230,11 +230,21 @@ pub fn frame_color(appearance: &AppearanceSettings, os_dark: bool) -> Color {
}
}
/// A `#rgb` / `#rrggbb` / `#rrggbbaa` colour sent by the UI (Tauri's own parser).
fn hex_color(hex: &str) -> Option<Color> {
serde_json::from_value(serde_json::Value::String(hex.to_owned())).ok()
}
/// Builds a project window painted in the saved theme's frame colour, so it
/// doesn't flash the light default before its page (and splash) loads.
fn build_project_window(app: &AppHandle, mut config: WindowConfig) -> IdeResult<WebviewWindow> {
let appearance = app.try_state::<AppState>().map(|s| s.global_settings.effective().appearance);
if let Some(a) = &appearance {
let state = app.try_state::<AppState>();
let appearance = state.as_ref().map(|s| s.global_settings.effective().appearance);
// A plugin theme replaces the built-in one in either OS mode; the UI records its resolved frame.
let plugin_frame = state.as_ref().and_then(|s| s.plugins.startup_frame()).and_then(|c| hex_color(&c));
if let Some(color) = plugin_frame {
config.background_color = Some(color);
} else if let Some(a) = &appearance {
config.background_color = Some(frame_color(a, false));
}
let window = WebviewWindowBuilder::from_config(app, &config)
@@ -242,7 +252,7 @@ fn build_project_window(app: &AppHandle, mut config: WindowConfig) -> IdeResult<
.map_err(|e| IdeError::internal(format!("cannot create window: {e}")))?;
apply_zoom(app, &window);
// "Sync with OS" needs the OS mode, known once the window exists.
if let Some(a) = appearance.filter(|a| a.sync_with_os || a.theme == "system")
if let Some(a) = appearance.filter(|a| plugin_frame.is_none() && (a.sync_with_os || a.theme == "system"))
&& window.theme().is_ok_and(|t| t == Theme::Dark)
{
let _ = window.set_background_color(Some(frame_color(&a, true)));
@@ -418,7 +428,7 @@ pub fn open_settings_window(
config.fullscreen = false;
config.drag_drop_enabled = false;
// macOS shows a child window as soon as it is attached, before the page loads: paint the theme's frame colour.
if let Some(color) = background.and_then(|c| serde_json::from_value(serde_json::Value::String(c)).ok()) {
if let Some(color) = background.as_deref().and_then(hex_color) {
config.background_color = Some(color);
}
windows.set_launch(&label, Launch { project: None, settings_page: page, new_projects });
@@ -465,6 +475,19 @@ mod tests {
assert_eq!(frame_color(&a, true), Color(0x26, 0x28, 0x2c, 0xff));
}
#[test]
fn frame_colours_from_the_ui_parse_as_hex() {
for (hex, expected) in [
("#eaeaeb", Color(0xea, 0xea, 0xeb, 0xff)),
("#21252b", Color(0x21, 0x25, 0x2b, 0xff)),
("#8040bfcc", Color(0x80, 0x40, 0xbf, 0xcc)),
("#fff", Color(0xff, 0xff, 0xff, 0xff)),
] {
assert_eq!(hex_color(hex), Some(expected), "{hex}");
}
assert_eq!(hex_color("hsl(220, 13%, 15%)"), None);
}
#[test]
fn labels_sort_main_first_then_numerically() {
assert_eq!(
+1 -1
Переглянути файл
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenIDEA",
"version": "0.1.16",
"version": "0.1.17",
"identifier": "ai.l0ng.openidea",
"build": {
"beforeDevCommand": "pnpm dev",