mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 16:08:05 +00:00
oxfmt ran only below an oxfmt configuration and reused the Prettier settings. It now has its own settings group and page (path, enabled languages, formatting provider, run on save) next to Prettier. For a language with an external formatter, oxfmt formats it when enabled for that language and either an oxfmt configuration is found above the file or oxfmt is the selected provider; otherwise Prettier, when enabled. Turning Prettier off for a language still leaves it to the language server. New Reformat with Prettier / Reformat with oxfmt commands run that tool regardless of the settings and report languages it cannot format. Co-authored-by: d0whc3r <1378986+d0whc3r@users.noreply.github.com>
182 lines
7.9 KiB
Rust
182 lines
7.9 KiB
Rust
//! LightEdit: a window editing loose files without a project.
|
|
|
|
use ide_core::{ChangeSet, NullSink, TextChange};
|
|
use ide_host::{Host, HostConfig, ops};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
|
|
fn host(base: &std::path::Path) -> Arc<Host> {
|
|
Arc::new(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,
|
|
}))
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn edits_loose_files_without_project_services() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let tmp_root = dunce::canonicalize(tmp.path()).unwrap();
|
|
let (a_dir, b_dir) = (tmp_root.join("a"), tmp_root.join("b"));
|
|
std::fs::create_dir_all(a_dir.join(".git")).unwrap();
|
|
std::fs::create_dir_all(&b_dir).unwrap();
|
|
std::fs::write(a_dir.join("one.py"), "print(1)\n").unwrap();
|
|
std::fs::write(b_dir.join("two.rs"), "fn main() {}\n").unwrap();
|
|
let host = host(&tmp_root.join("app"));
|
|
|
|
let light = host.open_light("main", &a_dir.join("one.py")).unwrap();
|
|
assert!(light.light);
|
|
assert_eq!(light.root, a_dir);
|
|
assert!(host.open_light("main", &b_dir).is_err(), "a folder is not opened for LightEdit");
|
|
|
|
let doc = ops::doc::open(&host, "main", a_dir.join("one.py")).await.unwrap();
|
|
assert!(doc.text.starts_with("print"));
|
|
let changes = ChangeSet { changes: vec![TextChange { from: 0, to: 0, insert: "#\n".into() }] };
|
|
let version = ops::doc::edit(&host, "main", doc.id, doc.version, changes).unwrap();
|
|
assert!(version > doc.version);
|
|
ops::doc::save(&host, "main", doc.id).await.unwrap();
|
|
assert_eq!(std::fs::read_to_string(a_dir.join("one.py")).unwrap(), "#\nprint(1)\n");
|
|
|
|
// More files join the same session, wherever they are.
|
|
let again = host.open_light("main", &b_dir.join("two.rs")).unwrap();
|
|
assert!(Arc::ptr_eq(&light, &again));
|
|
ops::doc::open(&host, "main", b_dir.join("two.rs")).await.unwrap();
|
|
|
|
assert!(light.index.wait_idle(Duration::from_secs(10)));
|
|
assert_eq!(light.index.status().files, 0, "nothing is indexed");
|
|
assert!(light.lsp.servers().is_empty(), "no language servers");
|
|
assert!(light.repos().is_empty(), "no repositories");
|
|
|
|
// Opening the folder as a project replaces the LightEdit session.
|
|
let project = host.open_project("main", &a_dir).unwrap();
|
|
assert!(!project.light);
|
|
assert!(!Arc::ptr_eq(&project, &light));
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn light_windows_ignore_project_scoped_settings() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let dir = dunce::canonicalize(tmp.path()).unwrap().join("loose");
|
|
std::fs::create_dir_all(&dir).unwrap();
|
|
std::fs::write(dir.join("notes.txt"), "x\n").unwrap();
|
|
let host = host(&tmp.path().join("app"));
|
|
host.open_light("main", &dir.join("notes.txt")).unwrap();
|
|
let applied = ops::project::set_settings(
|
|
&host,
|
|
"main",
|
|
ide_workspace::settings::SettingsScope::Project,
|
|
"general.projectName",
|
|
"\"loose\"",
|
|
)
|
|
.unwrap();
|
|
assert!(!applied.project_scope);
|
|
assert!(!dir.join(".openidea").exists(), "no project settings next to the file");
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn light_windows_stay_restricted_when_folder_trust_changes() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path().join("loose");
|
|
let other = tmp.path().join("other");
|
|
std::fs::create_dir_all(&root).unwrap();
|
|
std::fs::create_dir_all(&other).unwrap();
|
|
std::fs::write(root.join("one.py"), "print(1)\n").unwrap();
|
|
std::fs::write(other.join("two.js"), "const value = 1;\n").unwrap();
|
|
let host = host(&tmp.path().join("app"));
|
|
host.global_settings
|
|
.set(ide_workspace::SettingsScope::Global, "languages.prettier.prefer", serde_json::json!(true))
|
|
.unwrap();
|
|
let light = host.open_light("main", &root.join("one.py")).unwrap();
|
|
assert!(!light.is_trusted());
|
|
assert!(light.require_trust().is_err());
|
|
|
|
host.set_project_trust(&root, true, false).await.unwrap();
|
|
assert!(!light.is_trusted());
|
|
let trusted_folder = host.open_light("second", &root.join("one.py")).unwrap();
|
|
assert!(!trusted_folder.is_trusted());
|
|
let again = host.open_light("main", &other.join("two.js")).unwrap();
|
|
assert!(Arc::ptr_eq(&light, &again));
|
|
assert!(!again.is_trusted());
|
|
host.set_project_trust(&root, true, true).await.unwrap();
|
|
assert!(!light.is_trusted());
|
|
assert!(!trusted_folder.is_trusted());
|
|
for command in ["sdk_detect", "sdk_locate_tools", "notebook_execute", "notebook_restart", "run_start"] {
|
|
assert!(host.authorize_command("main", command).is_err(), "{command}");
|
|
}
|
|
|
|
let doc = ops::doc::open(&host, "main", other.join("two.js")).await.unwrap();
|
|
let error = ops::lsp::lsp_format(
|
|
&host,
|
|
"main",
|
|
doc.id,
|
|
None,
|
|
ide_lsp::types::FormatOptions { tab_size: 2, insert_spaces: true, on_save: false, tool: None },
|
|
)
|
|
.await
|
|
.unwrap_err();
|
|
assert_eq!(error.kind, ide_core::error::ErrorKind::Unavailable);
|
|
assert!(error.message.contains("Restricted Mode"));
|
|
|
|
host.set_project_trust(&root, false, false).await.unwrap();
|
|
assert!(!light.is_trusted());
|
|
assert!(!trusted_folder.is_trusted());
|
|
host.set_project_trust(&root, true, false).await.unwrap();
|
|
let project = host.open_project("main", &root).unwrap();
|
|
assert!(!project.light);
|
|
assert!(project.is_trusted());
|
|
assert!(project.require_trust().is_ok());
|
|
host.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn light_notebooks_open_without_interpreter_detection_or_execution() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path().join("loose");
|
|
let bin = root.join(".venv").join(if cfg!(windows) { "Scripts" } else { "bin" });
|
|
std::fs::create_dir_all(&bin).unwrap();
|
|
std::fs::write(root.join(".venv/pyvenv.cfg"), "home = python\n").unwrap();
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
let python = bin.join("python");
|
|
std::fs::write(&python, "#!/bin/sh\nprintf probed > \"$0.probed\"\nprintf 'Python 3.12.0\\n'\n").unwrap();
|
|
std::fs::set_permissions(&python, std::fs::Permissions::from_mode(0o755)).unwrap();
|
|
}
|
|
let file = root.join("analysis.ipynb");
|
|
std::fs::write(
|
|
&file,
|
|
r#"{"cells":[{"id":"cell","cell_type":"code","source":["print(1)"],"metadata":{},"outputs":[],"execution_count":null}],"metadata":{},"nbformat":4,"nbformat_minor":5}"#,
|
|
)
|
|
.unwrap();
|
|
let host = host(&tmp.path().join("app"));
|
|
host.open_light("main", &file).unwrap();
|
|
let notebook = ops::notebook::open(&host, "main", file.to_string_lossy().into()).await.unwrap();
|
|
assert!(ops::notebook::save(&host, "main", notebook.id.clone()).await.is_ok());
|
|
let error = ops::sdk::sdk_detect(&host, "main", ide_sdk::SdkKind::Python).await.unwrap_err();
|
|
assert!(error.message.contains("Restricted Mode"));
|
|
assert!(ops::sdk::sdk_python_effective(&host, "main").is_err());
|
|
assert!(ops::sdk::sdk_locate_tools(&host, "main", vec!["prettier".into()], Some(root)).await.is_err());
|
|
let error = ops::notebook::restart(&host, "main", notebook.id.clone()).await.unwrap_err();
|
|
assert!(error.message.contains("Restricted Mode"));
|
|
let error = ops::notebook::execute(
|
|
&host,
|
|
"main",
|
|
notebook.id,
|
|
vec![notebook.cells[0].id.clone()],
|
|
None,
|
|
ide_core::RequestId(849),
|
|
ops::Channel::new(|_| {}),
|
|
)
|
|
.await
|
|
.unwrap_err();
|
|
assert!(error.message.contains("Restricted Mode"));
|
|
assert!(!bin.join("python.probed").exists());
|
|
host.shutdown().await;
|
|
}
|