feat(m175): Java 设置页接真运行时(扫描 / 手动路径 / 默认 JDK / 内存 / JVM 参数)

用户实测四条抱怨逐条对应:
- 「没有自动检测本机 Java」:首屏自动扫一次盘(托管根 + JAVA_HOME + PATH + 标准安装位置 +
  注册表),之后由「立即扫描」手动触发;扫描在后台线程里跑,带 done/total 进度与取消
- 「显示 Temurin 21.0.4 不知道是不是硬编码」:演示行与绊线测试一起删掉,列表来自真读盘
- 「没一个能改」:默认内存(MB,512~65536,范围与 schema 同源)与 JVM 参数可真改、真落盘、读回
- 「不能手动指定 Java 路径 / 不能改默认版本」:手动添加走严格校验(真跑 java -version),
  设为默认写 java.selected_path 并给出「为什么选它」(当前实例的版本门槛 + 每行满足与否)

core:java::manual(严格探测 + 厂商识别 + 名单持久化)、java::staged(候选收集 + 带进度与
取消的扫描)、java::proc(带超时且可打断的子进程执行:卡住的 java -version 会被 kill)。
i18n:catalog/settings/java.rs 55 条中英 + 金表按装配顺序插入。

复审 r1(p2-5items)全修:
- P2-1 「设为默认」不再清脏:只写 java.selected_path,内存/JVM 草稿一个字节都不动
- P2-2 错误文案全部走 i18n(三档「写不进去」/「路径太长」/「名单写不进去」各自一个 key),
  不再把 Rust 枚举名当人话
- P2-3 手动名单落盘有正面断言(加一条 → 从盘上新读一份 → 在)
- P2-4 版本号显示到小版本(17.0.13 / 17.0.9 可区分),解析不出来时给原始版本串
- P2-5 每候选 8 秒超时并 kill、取消打断正在跑的探测、扫描槽挂在 State 上、线程活着期间
  不许起第二个(界面显示「正在取消…」)

复审 r2(p2-2items)全修:
- P2-1 空态不再指向不存在的「Java 页」,改成真实存在的 `ull java install 21` 命令行入口
- P2-2 `auto_scan_due` 增加 `!report.cancelled`:取消过一次之后本进程不再自动扫,
  配置文件再变(存内存 / 改主题)也不会把取消无声撤销;手动「立即扫描」不受影响
- 顺带:proc 的 kill+wait 补「子进程真死了」的回归守卫(标记文件从未出现)、
  core 的 Schema 错误改成页面自己的 key(不再把中文 Display 直出给英文界面)、
  默认态 chip 用新的 `Chip::badge`(不再挂一条永远收不到的消息)
This commit is contained in:
AskaEth committed 2026-11-08 19:52:04 +08:00
1 parent 30b61e2684
commit df331f6a60
26 files changed
+4030 -85

No files matched your search

@@ -0,0 +1,75 @@
//! 「Java」分组的截图种子(M175,`ULL_JAVA_STATE`):**只给 `--screenshot` 用**。
//!
//! 三档对应任务书要的三张图:未安装 Java 的空态 / 检测到两个 JDK 并选中其一 / 内存与 JVM 参数
//! 的编辑态。编辑态只让**内存**越界(`validate()` 一次只报第一个错,所以图上看到的是「内存超出
//! 允许范围」+ 内存框标红;引号那条另有单测,不靠这张图证明)。
//!
//! 与 `ULL_AI_STATE` / `ULL_UPDATE_STATE` / `ULL_FONT_STATUS` 同一族取证开关:只影响这一次进程,
//! 产品路径不设它。种子里的路径是**写死的示例路径**(真实机器上没有),所以它只在出图通道里出现;
//! 产品路径的真值一律来自 `core::game::java::staged` 的真扫盘。
use super::state::{Context, Layer, Notice, Refusal, Requirement, RuntimeRow, State};
/// 取证开关 `ULL_JAVA_STATE`(只给 `--screenshot` 用)。
///
/// 三档对应三张图:`empty`(未检测到)/ `two`(两个 JDK 并选中其一)/ `editing`(改了内存与
/// JVM 参数、还没保存)。与 `ULL_AI_STATE` / `ULL_UPDATE_STATE` 同一族,只影响这一次进程。
#[must_use]
pub fn build(raw: &str) -> Option<State> {
let mut state = State {
storage: true,
scanned: true,
..State::default()
};
match raw.trim() {
"empty" => {
state.memory = "2048".to_string();
state.saved_memory = 2048;
}
"two" => {
state.runtimes = vec![
RuntimeRow {
binary: "C:/Program Files/Eclipse Adoptium/jdk-17.0.13/bin/java.exe"
.to_string(),
version: "openjdk version \"17.0.13\" 2024-10-15".to_string(),
major: Some(17),
vendor: Some("Temurin".to_string()),
source: "system",
},
RuntimeRow {
binary: "C:/Program Files/Microsoft/jdk-21.0.4/bin/java.exe".to_string(),
version: "openjdk version \"21.0.4\" 2024-07-16 LTS".to_string(),
major: Some(21),
vendor: Some("Microsoft".to_string()),
source: "system",
},
];
state.selected = state.runtimes[1].binary.clone();
state.manual = vec!["D:/jdk/zulu-21".to_string()];
state.memory = "4096".to_string();
state.saved_memory = 4096;
state.jvm = "-XX:+UseG1GC".to_string();
state.saved_jvm = "-XX:+UseG1GC".to_string();
state.context = Context {
required: Some(Requirement {
instance: "生存服".to_string(),
version: "1.20.1".to_string(),
minimum: 17,
maximum: None,
}),
layer: Some(Layer::Global),
effective_memory_mb: Some(4096),
};
}
"editing" => {
let mut seeded = build("two")?;
seeded.memory = "128".to_string();
seeded.jvm = "-XX:+UseG1GC -Xss\"512k".to_string();
seeded.dirty = true;
seeded.notice = Some(Notice::Refused(Refusal::MemoryRange));
return Some(seeded);
}
_ => return None,
}
Some(state)
}