mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Add minimal support for cargo scripts
This commit is contained in:
parent
50bdeaad07
commit
2f828073aa
8 changed files with 238 additions and 16 deletions
|
@ -305,6 +305,10 @@ impl CargoWorkspace {
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if cargo_toml.extension().is_some_and(|x| x == "rs") {
|
||||||
|
// TODO: enable `+nightly` for cargo scripts
|
||||||
|
other_options.push("-Zscript".to_owned());
|
||||||
|
}
|
||||||
meta.other_options(other_options);
|
meta.other_options(other_options);
|
||||||
|
|
||||||
// FIXME: Fetching metadata is a slow process, as it might require
|
// FIXME: Fetching metadata is a slow process, as it might require
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
||||||
//! database -- `CrateGraph`.
|
//! database -- `CrateGraph`.
|
||||||
|
|
||||||
use std::{collections::VecDeque, fmt, fs, iter, sync};
|
use std::{collections::VecDeque, fmt, fs, io::BufRead, iter, sync};
|
||||||
|
|
||||||
use anyhow::{format_err, Context};
|
use anyhow::{format_err, Context};
|
||||||
use base_db::{
|
use base_db::{
|
||||||
|
@ -115,9 +115,55 @@ pub enum ProjectWorkspace {
|
||||||
target_layout: TargetLayoutLoadResult,
|
target_layout: TargetLayoutLoadResult,
|
||||||
/// A set of cfg overrides for the files.
|
/// A set of cfg overrides for the files.
|
||||||
cfg_overrides: CfgOverrides,
|
cfg_overrides: CfgOverrides,
|
||||||
|
/// Is this file a cargo script file?
|
||||||
|
cargo_script: Option<CargoWorkspace>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks the cargo toml parts in cargo scripts, to detect if they
|
||||||
|
/// changed and reload workspace in that case.
|
||||||
|
pub struct CargoScriptTomls(pub FxHashMap<AbsPathBuf, String>);
|
||||||
|
|
||||||
|
impl CargoScriptTomls {
|
||||||
|
fn extract_toml_part(p: &AbsPath) -> Option<String> {
|
||||||
|
let mut r = String::new();
|
||||||
|
let f = std::fs::File::open(p).ok()?;
|
||||||
|
let f = std::io::BufReader::new(f);
|
||||||
|
let mut started = false;
|
||||||
|
for line in f.lines() {
|
||||||
|
let line = line.ok()?;
|
||||||
|
if started {
|
||||||
|
if line.trim() == "//! ```" {
|
||||||
|
return Some(r);
|
||||||
|
}
|
||||||
|
r += &line;
|
||||||
|
} else {
|
||||||
|
if line.trim() == "//! ```cargo" {
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track_file(&mut self, p: AbsPathBuf) {
|
||||||
|
let toml = CargoScriptTomls::extract_toml_part(&p).unwrap_or_default();
|
||||||
|
self.0.insert(p, toml);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn need_reload(&mut self, p: &AbsPath) -> bool {
|
||||||
|
let Some(prev) = self.0.get_mut(p) else {
|
||||||
|
return false; // File is not tracked
|
||||||
|
};
|
||||||
|
let next = CargoScriptTomls::extract_toml_part(p).unwrap_or_default();
|
||||||
|
if *prev == next {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*prev = next;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ProjectWorkspace {
|
impl fmt::Debug for ProjectWorkspace {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// Make sure this isn't too verbose.
|
// Make sure this isn't too verbose.
|
||||||
|
@ -174,10 +220,12 @@ impl fmt::Debug for ProjectWorkspace {
|
||||||
toolchain,
|
toolchain,
|
||||||
target_layout,
|
target_layout,
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
|
cargo_script,
|
||||||
} => f
|
} => f
|
||||||
.debug_struct("DetachedFiles")
|
.debug_struct("DetachedFiles")
|
||||||
.field("n_files", &files.len())
|
.field("n_files", &files.len())
|
||||||
.field("sysroot", &sysroot.is_ok())
|
.field("sysroot", &sysroot.is_ok())
|
||||||
|
.field("cargo_script", &cargo_script.is_some())
|
||||||
.field("n_rustc_cfg", &rustc_cfg.len())
|
.field("n_rustc_cfg", &rustc_cfg.len())
|
||||||
.field("toolchain", &toolchain)
|
.field("toolchain", &toolchain)
|
||||||
.field("data_layout", &target_layout)
|
.field("data_layout", &target_layout)
|
||||||
|
@ -431,6 +479,7 @@ impl ProjectWorkspace {
|
||||||
pub fn load_detached_files(
|
pub fn load_detached_files(
|
||||||
detached_files: Vec<AbsPathBuf>,
|
detached_files: Vec<AbsPathBuf>,
|
||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
|
cargo_script_tomls: &mut CargoScriptTomls,
|
||||||
) -> anyhow::Result<ProjectWorkspace> {
|
) -> anyhow::Result<ProjectWorkspace> {
|
||||||
let dir = detached_files
|
let dir = detached_files
|
||||||
.first()
|
.first()
|
||||||
|
@ -469,6 +518,23 @@ impl ProjectWorkspace {
|
||||||
None,
|
None,
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
);
|
);
|
||||||
|
let cargo_toml = ManifestPath::try_from(detached_files[0].clone()).unwrap();
|
||||||
|
let meta = CargoWorkspace::fetch_metadata(
|
||||||
|
&cargo_toml,
|
||||||
|
cargo_toml.parent(),
|
||||||
|
config,
|
||||||
|
sysroot_ref,
|
||||||
|
&|_| (),
|
||||||
|
)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("Failed to read Cargo metadata from Cargo.toml file {cargo_toml}")
|
||||||
|
})?;
|
||||||
|
let cargo = CargoWorkspace::new(meta);
|
||||||
|
|
||||||
|
for file in &detached_files {
|
||||||
|
cargo_script_tomls.track_file(file.clone());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ProjectWorkspace::DetachedFiles {
|
Ok(ProjectWorkspace::DetachedFiles {
|
||||||
files: detached_files,
|
files: detached_files,
|
||||||
sysroot,
|
sysroot,
|
||||||
|
@ -476,6 +542,7 @@ impl ProjectWorkspace {
|
||||||
toolchain,
|
toolchain,
|
||||||
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
|
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
|
||||||
cfg_overrides: config.cfg_overrides.clone(),
|
cfg_overrides: config.cfg_overrides.clone(),
|
||||||
|
cargo_script: Some(cargo),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,14 +855,27 @@ impl ProjectWorkspace {
|
||||||
toolchain: _,
|
toolchain: _,
|
||||||
target_layout: _,
|
target_layout: _,
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
|
cargo_script,
|
||||||
} => (
|
} => (
|
||||||
|
if let Some(cargo) = cargo_script {
|
||||||
|
cargo_to_crate_graph(
|
||||||
|
load,
|
||||||
|
None,
|
||||||
|
cargo,
|
||||||
|
sysroot.as_ref().ok(),
|
||||||
|
rustc_cfg.clone(),
|
||||||
|
cfg_overrides,
|
||||||
|
&WorkspaceBuildScripts::default(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
detached_files_to_crate_graph(
|
detached_files_to_crate_graph(
|
||||||
rustc_cfg.clone(),
|
rustc_cfg.clone(),
|
||||||
load,
|
load,
|
||||||
files,
|
files,
|
||||||
sysroot.as_ref().ok(),
|
sysroot.as_ref().ok(),
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
),
|
)
|
||||||
|
},
|
||||||
sysroot,
|
sysroot,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -873,6 +953,7 @@ impl ProjectWorkspace {
|
||||||
files,
|
files,
|
||||||
sysroot,
|
sysroot,
|
||||||
rustc_cfg,
|
rustc_cfg,
|
||||||
|
cargo_script,
|
||||||
toolchain,
|
toolchain,
|
||||||
target_layout,
|
target_layout,
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
|
@ -881,6 +962,7 @@ impl ProjectWorkspace {
|
||||||
files: o_files,
|
files: o_files,
|
||||||
sysroot: o_sysroot,
|
sysroot: o_sysroot,
|
||||||
rustc_cfg: o_rustc_cfg,
|
rustc_cfg: o_rustc_cfg,
|
||||||
|
cargo_script: o_cargo_script,
|
||||||
toolchain: o_toolchain,
|
toolchain: o_toolchain,
|
||||||
target_layout: o_target_layout,
|
target_layout: o_target_layout,
|
||||||
cfg_overrides: o_cfg_overrides,
|
cfg_overrides: o_cfg_overrides,
|
||||||
|
@ -892,6 +974,7 @@ impl ProjectWorkspace {
|
||||||
&& toolchain == o_toolchain
|
&& toolchain == o_toolchain
|
||||||
&& target_layout == o_target_layout
|
&& target_layout == o_target_layout
|
||||||
&& cfg_overrides == o_cfg_overrides
|
&& cfg_overrides == o_cfg_overrides
|
||||||
|
&& cargo_script == o_cargo_script
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ impl Tester {
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
|
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
|
||||||
cfg_overrides: Default::default(),
|
cfg_overrides: Default::default(),
|
||||||
|
cargo_script: None,
|
||||||
};
|
};
|
||||||
let load_cargo_config = LoadCargoConfig {
|
let load_cargo_config = LoadCargoConfig {
|
||||||
load_out_dirs_from_check: false,
|
load_out_dirs_from_check: false,
|
||||||
|
|
|
@ -18,7 +18,9 @@ use parking_lot::{
|
||||||
RwLockWriteGuard,
|
RwLockWriteGuard,
|
||||||
};
|
};
|
||||||
use proc_macro_api::ProcMacroServer;
|
use proc_macro_api::ProcMacroServer;
|
||||||
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
|
use project_model::{
|
||||||
|
CargoScriptTomls, CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts,
|
||||||
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
|
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
|
||||||
|
@ -144,6 +146,7 @@ pub(crate) struct GlobalState {
|
||||||
/// this queue should run only *after* [`GlobalState::process_changes`] has
|
/// this queue should run only *after* [`GlobalState::process_changes`] has
|
||||||
/// been called.
|
/// been called.
|
||||||
pub(crate) deferred_task_queue: TaskQueue,
|
pub(crate) deferred_task_queue: TaskQueue,
|
||||||
|
pub(crate) cargo_script_tomls: Arc<Mutex<CargoScriptTomls>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An immutable snapshot of the world's state at a point in time.
|
/// An immutable snapshot of the world's state at a point in time.
|
||||||
|
@ -240,6 +243,7 @@ impl GlobalState {
|
||||||
prime_caches_queue: OpQueue::default(),
|
prime_caches_queue: OpQueue::default(),
|
||||||
|
|
||||||
deferred_task_queue: task_queue,
|
deferred_task_queue: task_queue,
|
||||||
|
cargo_script_tomls: Arc::new(Mutex::new(CargoScriptTomls(FxHashMap::default()))),
|
||||||
};
|
};
|
||||||
// Apply any required database inputs from the config.
|
// Apply any required database inputs from the config.
|
||||||
this.update_configuration(config);
|
this.update_configuration(config);
|
||||||
|
@ -322,7 +326,11 @@ impl GlobalState {
|
||||||
if file.is_created_or_deleted() {
|
if file.is_created_or_deleted() {
|
||||||
workspace_structure_change.get_or_insert((path, false)).1 |=
|
workspace_structure_change.get_or_insert((path, false)).1 |=
|
||||||
self.crate_graph_file_dependencies.contains(vfs_path);
|
self.crate_graph_file_dependencies.contains(vfs_path);
|
||||||
} else if reload::should_refresh_for_change(&path, file.kind()) {
|
} else if reload::should_refresh_for_change(
|
||||||
|
&path,
|
||||||
|
file.kind(),
|
||||||
|
&mut self.cargo_script_tomls.lock(),
|
||||||
|
) {
|
||||||
workspace_structure_change.get_or_insert((path.clone(), false));
|
workspace_structure_change.get_or_insert((path.clone(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,11 @@ pub(crate) fn handle_did_save_text_document(
|
||||||
if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
||||||
// Re-fetch workspaces if a workspace related file has changed
|
// Re-fetch workspaces if a workspace related file has changed
|
||||||
if let Some(abs_path) = vfs_path.as_path() {
|
if let Some(abs_path) = vfs_path.as_path() {
|
||||||
if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) {
|
if reload::should_refresh_for_change(
|
||||||
|
abs_path,
|
||||||
|
ChangeKind::Modify,
|
||||||
|
&mut state.cargo_script_tomls.lock(),
|
||||||
|
) {
|
||||||
state
|
state
|
||||||
.fetch_workspaces_queue
|
.fetch_workspaces_queue
|
||||||
.request_op(format!("workspace vfs file change saved {abs_path}"), false);
|
.request_op(format!("workspace vfs file change saved {abs_path}"), false);
|
||||||
|
|
|
@ -25,7 +25,7 @@ use ide_db::{
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use load_cargo::{load_proc_macro, ProjectFolders};
|
use load_cargo::{load_proc_macro, ProjectFolders};
|
||||||
use proc_macro_api::ProcMacroServer;
|
use proc_macro_api::ProcMacroServer;
|
||||||
use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
|
use project_model::{CargoScriptTomls, ProjectWorkspace, WorkspaceBuildScripts};
|
||||||
use stdx::{format_to, thread::ThreadIntent};
|
use stdx::{format_to, thread::ThreadIntent};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
use vfs::{AbsPath, AbsPathBuf, ChangeKind};
|
use vfs::{AbsPath, AbsPathBuf, ChangeKind};
|
||||||
|
@ -206,6 +206,7 @@ impl GlobalState {
|
||||||
let linked_projects = self.config.linked_or_discovered_projects();
|
let linked_projects = self.config.linked_or_discovered_projects();
|
||||||
let detached_files = self.config.detached_files().to_vec();
|
let detached_files = self.config.detached_files().to_vec();
|
||||||
let cargo_config = self.config.cargo();
|
let cargo_config = self.config.cargo();
|
||||||
|
let cargo_script_tomls = self.cargo_script_tomls.clone();
|
||||||
|
|
||||||
move |sender| {
|
move |sender| {
|
||||||
let progress = {
|
let progress = {
|
||||||
|
@ -258,6 +259,7 @@ impl GlobalState {
|
||||||
workspaces.push(project_model::ProjectWorkspace::load_detached_files(
|
workspaces.push(project_model::ProjectWorkspace::load_detached_files(
|
||||||
detached_files,
|
detached_files,
|
||||||
&cargo_config,
|
&cargo_config,
|
||||||
|
&mut cargo_script_tomls.lock(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,7 +760,15 @@ pub fn ws_to_crate_graph(
|
||||||
(crate_graph, proc_macro_paths, layouts, toolchains)
|
(crate_graph, proc_macro_paths, layouts, toolchains)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
|
pub(crate) fn should_refresh_for_change(
|
||||||
|
path: &AbsPath,
|
||||||
|
change_kind: ChangeKind,
|
||||||
|
cargo_script_tomls: &mut CargoScriptTomls,
|
||||||
|
) -> bool {
|
||||||
|
if cargo_script_tomls.need_reload(path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
|
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
|
||||||
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
|
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,104 @@ fn f() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_items_from_standard_library_in_cargo_script() {
|
||||||
|
if skip_slow_tests() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let server = Project::with_fixture(
|
||||||
|
r#"
|
||||||
|
//- /dependency/Cargo.toml
|
||||||
|
[package]
|
||||||
|
name = "dependency"
|
||||||
|
version = "0.1.0"
|
||||||
|
//- /dependency/src/lib.rs
|
||||||
|
pub struct SpecialHashMap;
|
||||||
|
//- /dependency2/Cargo.toml
|
||||||
|
[package]
|
||||||
|
name = "dependency2"
|
||||||
|
version = "0.1.0"
|
||||||
|
//- /dependency2/src/lib.rs
|
||||||
|
pub struct SpecialHashMap2;
|
||||||
|
//- /src/lib.rs
|
||||||
|
#!/usr/bin/env -S cargo +nightly -Zscript
|
||||||
|
//! ```cargo
|
||||||
|
//! [dependencies]
|
||||||
|
//! dependency = { path = "../dependency" }
|
||||||
|
//! ```
|
||||||
|
use dependency::Spam;
|
||||||
|
use dependency2::Spam;
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.with_config(serde_json::json!({
|
||||||
|
"cargo": { "sysroot": "discover" },
|
||||||
|
}))
|
||||||
|
.server()
|
||||||
|
.wait_until_workspace_is_loaded();
|
||||||
|
|
||||||
|
let res = server.send_request::<Completion>(CompletionParams {
|
||||||
|
text_document_position: TextDocumentPositionParams::new(
|
||||||
|
server.doc_id("src/lib.rs"),
|
||||||
|
Position::new(7, 18),
|
||||||
|
),
|
||||||
|
context: None,
|
||||||
|
partial_result_params: PartialResultParams::default(),
|
||||||
|
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||||
|
});
|
||||||
|
assert!(res.to_string().contains("SpecialHashMap"));
|
||||||
|
|
||||||
|
let res = server.send_request::<Completion>(CompletionParams {
|
||||||
|
text_document_position: TextDocumentPositionParams::new(
|
||||||
|
server.doc_id("src/lib.rs"),
|
||||||
|
Position::new(8, 18),
|
||||||
|
),
|
||||||
|
context: None,
|
||||||
|
partial_result_params: PartialResultParams::default(),
|
||||||
|
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||||
|
});
|
||||||
|
assert!(!res.to_string().contains("SpecialHashMap"));
|
||||||
|
|
||||||
|
server.write_file_and_save(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"#!/usr/bin/env -S cargo +nightly -Zscript
|
||||||
|
//! ```cargo
|
||||||
|
//! [dependencies]
|
||||||
|
//! dependency2 = { path = "../dependency2" }
|
||||||
|
//! ```
|
||||||
|
use dependency::Spam;
|
||||||
|
use dependency2::Spam;
|
||||||
|
"#
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let server = server.wait_until_workspace_is_loaded();
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(3));
|
||||||
|
|
||||||
|
let res = server.send_request::<Completion>(CompletionParams {
|
||||||
|
text_document_position: TextDocumentPositionParams::new(
|
||||||
|
server.doc_id("src/lib.rs"),
|
||||||
|
Position::new(7, 18),
|
||||||
|
),
|
||||||
|
context: None,
|
||||||
|
partial_result_params: PartialResultParams::default(),
|
||||||
|
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||||
|
});
|
||||||
|
assert!(!res.to_string().contains("SpecialHashMap"));
|
||||||
|
|
||||||
|
let res = server.send_request::<Completion>(CompletionParams {
|
||||||
|
text_document_position: TextDocumentPositionParams::new(
|
||||||
|
server.doc_id("src/lib.rs"),
|
||||||
|
Position::new(8, 18),
|
||||||
|
),
|
||||||
|
context: None,
|
||||||
|
partial_result_params: PartialResultParams::default(),
|
||||||
|
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||||
|
});
|
||||||
|
assert!(res.to_string().contains("SpecialHashMap"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_runnables_project() {
|
fn test_runnables_project() {
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl Project<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut config = Config::new(
|
let mut config = Config::new(
|
||||||
tmp_dir_path,
|
tmp_dir_path.clone(),
|
||||||
lsp_types::ClientCapabilities {
|
lsp_types::ClientCapabilities {
|
||||||
workspace: Some(lsp_types::WorkspaceClientCapabilities {
|
workspace: Some(lsp_types::WorkspaceClientCapabilities {
|
||||||
did_change_watched_files: Some(
|
did_change_watched_files: Some(
|
||||||
|
@ -185,10 +185,14 @@ impl Project<'_> {
|
||||||
roots,
|
roots,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
config.update(self.config).expect("invalid config");
|
// TODO: don't hardcode src/lib.rs as detached file
|
||||||
|
let mut c = self.config;
|
||||||
|
let p = tmp_dir_path.join("src/lib.rs").to_string();
|
||||||
|
c["detachedFiles"] = serde_json::json!([p]);
|
||||||
|
config.update(c).expect("invalid config");
|
||||||
config.rediscover_workspaces();
|
config.rediscover_workspaces();
|
||||||
|
|
||||||
Server::new(tmp_dir, config)
|
Server::new(tmp_dir.keep(), config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +378,16 @@ impl Server {
|
||||||
pub(crate) fn path(&self) -> &Utf8Path {
|
pub(crate) fn path(&self) -> &Utf8Path {
|
||||||
self.dir.path()
|
self.dir.path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_file_and_save(&self, path: &str, text: String) {
|
||||||
|
fs::write(self.dir.path().join(path), &text).unwrap();
|
||||||
|
self.notification::<lsp_types::notification::DidSaveTextDocument>(
|
||||||
|
lsp_types::DidSaveTextDocumentParams {
|
||||||
|
text_document: self.doc_id(path),
|
||||||
|
text: Some(text),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Server {
|
impl Drop for Server {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue