Document rust-project.json

This commit is contained in:
Aleksey Kladov 2020-06-03 14:48:38 +02:00
parent 2e7d12d2f3
commit fa019c8f56
5 changed files with 118 additions and 20 deletions

View file

@ -32,6 +32,12 @@ pub enum ProjectWorkspace {
Json { project: JsonProject },
}
impl From<JsonProject> for ProjectWorkspace {
fn from(project: JsonProject) -> ProjectWorkspace {
ProjectWorkspace::Json { project }
}
}
/// `PackageRoot` describes a package root folder.
/// Which may be an external dependency, or a member of
/// the current workspace.
@ -144,11 +150,11 @@ impl ProjectManifest {
impl ProjectWorkspace {
pub fn load(
root: ProjectManifest,
manifest: ProjectManifest,
cargo_features: &CargoConfig,
with_sysroot: bool,
) -> Result<ProjectWorkspace> {
let res = match root {
let res = match manifest {
ProjectManifest::ProjectJson(project_json) => {
let file = File::open(&project_json).with_context(|| {
format!("Failed to open json file {}", project_json.display())

View file

@ -261,6 +261,22 @@ impl Config {
self.lens = LensConfig::NO_LENS;
}
if let Some(linked_projects) = get::<Vec<ManifestOrJsonProject>>(value, "/linkedProjects") {
if !linked_projects.is_empty() {
self.linked_projects.clear();
for linked_project in linked_projects {
let linked_project = match linked_project {
ManifestOrJsonProject::Manifest(it) => match ProjectManifest::from_manifest_file(it) {
Ok(it) => it.into(),
Err(_) => continue,
}
ManifestOrJsonProject::JsonProject(it) => it.into(),
};
self.linked_projects.push(linked_project);
}
}
}
log::info!("Config::update() = {:#?}", self);
fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
@ -324,3 +340,10 @@ impl Config {
}
}
}
#[derive(Deserialize)]
#[serde(untagged)]
enum ManifestOrJsonProject {
Manifest(PathBuf),
JsonProject(JsonProject),
}

View file

@ -105,24 +105,23 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
.linked_projects
.iter()
.filter_map(|project| match project {
LinkedProject::ProjectManifest(it) => Some(it),
LinkedProject::JsonProject(_) => None,
})
.filter_map(|root| {
ra_project_model::ProjectWorkspace::load(
root.clone(),
&config.cargo,
config.with_sysroot,
)
.map_err(|err| {
log::error!("failed to load workspace: {:#}", err);
show_message(
lsp_types::MessageType::Error,
format!("rust-analyzer failed to load workspace: {:#}", err),
&connection.sender,
);
})
.ok()
LinkedProject::ProjectManifest(manifest) => {
ra_project_model::ProjectWorkspace::load(
manifest.clone(),
&config.cargo,
config.with_sysroot,
)
.map_err(|err| {
log::error!("failed to load workspace: {:#}", err);
show_message(
lsp_types::MessageType::Error,
format!("rust-analyzer failed to load workspace: {:#}", err),
&connection.sender,
);
})
.ok()
}
LinkedProject::JsonProject(it) => Some(it.clone().into()),
})
.collect::<Vec<_>>()
};

View file

@ -269,6 +269,57 @@ Gnome Builder currently has support for RLS, and there's no way to configure the
1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`).
2. Enable the Rust Builder plugin.
== Non-Cargo Based Projects
rust-analyzer does not require Cargo.
However, if you use some other build system, you'll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format:
[source,TypeScript]
----
interface JsonProject {
/// The set of paths containing the crates for this project.
/// Any `Crate` must be nested inside some `root`.
roots: string[];
/// The set of crates comprising the current project.
/// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such).
crates: Crate[];
}
interface Crate {
/// Path to the root module of the crate.
root_module: string;
/// Edition of the crate.
edition: "2015" | "2018";
/// Dependencies
deps: Dep[];
/// The set of cfgs activated for a given crate, like `["unix", "feature=foo", "feature=bar"]`.
cfg: string[];
/// value of the OUT_DIR env variable.
out_dir?: string;
/// For proc-macro crates, path to compiles proc-macro (.so file).
proc_macro_dylib_path?: string;
}
interface Dep {
/// Index of a crate in the `crates` array.
crate: number,
/// Name as should appear in the (implicit) `extern crate name` declaration.
name: string,
}
----
This format is provisional and subject to change.
Specifically, the `roots` setup will be different eventually.
There are tree ways to feed `rust-project.json` to rust-analyzer:
* Place `rust-project.json` file at the root of the project, and rust-anlayzer will discover it.
* Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request).
* Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline.
See https://github.com/rust-analyzer/rust-project.json-example for a small example.
== Features
include::./generated_features.adoc[]

View file

@ -475,6 +475,25 @@
"markdownDescription": "Whether to show Implementations lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
"type": "boolean",
"default": true
},
"rust-analyzer.linkedProjects": {
"markdownDescription": [
"Disable project auto-discovery in favor of explicitly specified set of projects.",
"Elements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format"
],
"type": "array",
"items": {
"type": [
"string",
"object"
]
},
"default": null
},
"rust-analyzer.withSysroot": {
"markdownDescription": "Internal config for debugging, disables loading of sysroot crates",
"type": "boolean",
"default": true
}
}
},