mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 16:08:05 +00:00
project.find-files walked the whole tree on every call; MyBatis Navigator calls it from editor providers interrupted after 500 ms, so on a large project each call timed out, counted as a crash, and the plugin was stopped after three. The host now answers from the project index (VCS-ignored and hidden files left out, as in the walk) and only walks the disk when no index covers the root yet.
103 lines
5.0 KiB
Rust
103 lines
5.0 KiB
Rust
use ide_core::{NullSink, RequestId};
|
|
use ide_host::{Host, HostConfig, ops};
|
|
use std::{sync::Arc, time::Duration};
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn opens_unity_without_generated_solutions_and_excludes_caches_from_the_index() {
|
|
let temp = tempfile::tempdir().unwrap();
|
|
let base = dunce::canonicalize(temp.path()).unwrap();
|
|
let root = base.join("Game");
|
|
for name in ["Assets/Scripts", "Packages", "ProjectSettings", "Library/PackageCache", "Temp", "Logs"] {
|
|
std::fs::create_dir_all(root.join(name)).unwrap();
|
|
}
|
|
std::fs::write(root.join("ProjectSettings/ProjectVersion.txt"), "m_EditorVersion: 6000.0.62f1\n").unwrap();
|
|
std::fs::write(root.join("Assets/Scripts/Player.cs"), "class Player {}\n").unwrap();
|
|
std::fs::write(root.join("Packages/manifest.json"), "{}\n").unwrap();
|
|
std::fs::write(root.join("Library/PackageCache/Cached.cs"), "class Cached {}\n").unwrap();
|
|
std::fs::write(root.join("Temp/Temporary.cs"), "class Temporary {}\n").unwrap();
|
|
std::fs::write(root.join("Logs/Editor.log"), "log\n").unwrap();
|
|
let host = Host::new(HostConfig {
|
|
config_dir: base.join("config"),
|
|
data_dir: base.join("data"),
|
|
local_data_dir: base.join("data"),
|
|
languages: Arc::new(ide_language::LanguageRegistry::load(None).unwrap()),
|
|
syntax: Arc::default(),
|
|
sink_for: Box::new(|_| Arc::new(NullSink)),
|
|
owner: |w| w,
|
|
runtime: tokio::runtime::Handle::current(),
|
|
project_environment: false,
|
|
});
|
|
let project = host.open_project("main", &root).unwrap();
|
|
let info = ops::project::info(&project);
|
|
assert_eq!(info.name, "Game");
|
|
let unity = info.unity.unwrap();
|
|
assert_eq!(unity.editor_version.as_deref(), Some("6000.0.62f1"));
|
|
assert!(unity.projects.is_empty() && unity.solutions.is_empty());
|
|
assert!(project.index.wait_idle(Duration::from_secs(20)));
|
|
assert_eq!(project.index.find_files("Player.cs", 100).len(), 1);
|
|
let listed = project.index.files_matching(&project.root, |rel| rel.ends_with("Player.cs"), 10).unwrap();
|
|
assert_eq!(listed.len(), 1);
|
|
for name in ["Cached.cs", "Temporary.cs", "Editor.log"] {
|
|
assert!(project.index.find_files(name, 100).is_empty(), "indexed generated file {name}");
|
|
}
|
|
let hits = Arc::new(std::sync::Mutex::new(Vec::new()));
|
|
let out = hits.clone();
|
|
let query = serde_json::from_value(serde_json::json!({
|
|
"pattern": "class", "isRegex": false, "caseSensitive": false, "wholeWord": false,
|
|
"include": [], "exclude": [], "scope": { "kind": "project" }, "maxMatches": 100,
|
|
}))
|
|
.unwrap();
|
|
ops::search::start(
|
|
&host,
|
|
"main",
|
|
RequestId::next(),
|
|
query,
|
|
Arc::new(move |event| {
|
|
if let ops::search::SearchEvent::File { file } = event {
|
|
out.lock().unwrap().push(file.rel_path);
|
|
}
|
|
}),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(*hits.lock().unwrap(), ["Assets/Scripts/Player.cs"]);
|
|
let listing = ops::fs::read_dir(&host, "main", root.clone()).await.unwrap();
|
|
assert!(listing.iter().any(|e| e.name == "Library" && e.excluded));
|
|
assert!(project.exclude_globs().contains(&"/Obj".to_owned()));
|
|
|
|
// Project metadata refreshes without reopening when Unity generates its solution.
|
|
std::fs::write(root.join("Game.sln"), "").unwrap();
|
|
std::fs::write(root.join("Assembly-CSharp.csproj"), "").unwrap();
|
|
let unity = ops::project::info(&project).unity.unwrap();
|
|
assert_eq!(unity.solutions, ["Game.sln"]);
|
|
assert_eq!(unity.projects, ["Assembly-CSharp.csproj"]);
|
|
|
|
// Desktop commands and remote RPC share these host operations.
|
|
let original = root.join("Assets/Scripts/Player.cs");
|
|
let renamed = root.join("Assets/Scripts/Hero.cs");
|
|
let copied = root.join("Assets/Scripts/HeroCopy.cs");
|
|
let meta = |path: &std::path::Path| -> std::path::PathBuf {
|
|
let mut name = path.as_os_str().to_os_string();
|
|
name.push(".meta");
|
|
name.into()
|
|
};
|
|
let original_metadata = "fileFormatVersion: 2\nguid: 11111111111111111111111111111111\n";
|
|
std::fs::write(meta(&original), original_metadata).unwrap();
|
|
ops::fs::rename(&host, original.clone(), renamed.clone()).await.unwrap();
|
|
assert!(!original.exists() && !meta(&original).exists());
|
|
assert_eq!(std::fs::read_to_string(meta(&renamed)).unwrap(), original_metadata);
|
|
ops::fs::copy(&host, renamed.clone(), copied.clone()).await.unwrap();
|
|
assert!(copied.exists());
|
|
assert_ne!(std::fs::read_to_string(meta(&copied)).unwrap(), original_metadata);
|
|
assert_eq!(std::fs::read_to_string(meta(&renamed)).unwrap(), original_metadata);
|
|
host.close_project("main");
|
|
|
|
let ordinary = base.join("ConsoleApp");
|
|
std::fs::create_dir(&ordinary).unwrap();
|
|
std::fs::write(ordinary.join("App.csproj"), "").unwrap();
|
|
let project = host.open_project("main", &ordinary).unwrap();
|
|
assert!(ops::project::info(&project).unity.is_none());
|
|
assert!(!project.exclude_globs().contains(&"/Library".to_owned()));
|
|
host.close_project("main");
|
|
}
|