mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-14 00:47:18 +00:00
Provide navigations to parent modules
This commit is contained in:
parent
aaa0771719
commit
59c755227d
4 changed files with 58 additions and 19 deletions
|
@ -1,6 +1,6 @@
|
|||
//! See [`CargoWorkspace`].
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::iter;
|
||||
use std::path::PathBuf;
|
||||
use std::{ops, process::Command};
|
||||
|
@ -400,6 +400,39 @@ impl CargoWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option<Vec<ManifestPath>> {
|
||||
let mut found = false;
|
||||
let parent_manifests = self
|
||||
.packages()
|
||||
.filter_map(|pkg| {
|
||||
if !found && &self[pkg].manifest == manifest_path {
|
||||
found = true
|
||||
}
|
||||
self[pkg].dependencies.iter().find_map(|dep| {
|
||||
if &self[dep.pkg].manifest == manifest_path {
|
||||
return Some(self[pkg].manifest.clone());
|
||||
}
|
||||
None
|
||||
})
|
||||
})
|
||||
.collect::<Vec<ManifestPath>>();
|
||||
|
||||
// some packages has this pkg as dep. return their manifests
|
||||
if parent_manifests.len() > 0 {
|
||||
return Some(parent_manifests);
|
||||
}
|
||||
|
||||
// this pkg is inside this cargo workspace, fallback to workspace root
|
||||
if found {
|
||||
return Some(vec![
|
||||
ManifestPath::try_from(self.workspace_root().join("Cargo.toml")).ok()?
|
||||
]);
|
||||
}
|
||||
|
||||
// not in this workspace
|
||||
None
|
||||
}
|
||||
|
||||
fn is_unique(&self, name: &str) -> bool {
|
||||
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//! `ide` crate.
|
||||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
io::Write as _,
|
||||
process::{self, Stdio},
|
||||
};
|
||||
|
@ -26,10 +27,11 @@ use lsp_types::{
|
|||
SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag,
|
||||
TextDocumentIdentifier, Url, WorkspaceEdit,
|
||||
};
|
||||
use project_model::{ProjectWorkspace, TargetKind};
|
||||
use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
|
||||
use serde_json::json;
|
||||
use stdx::{format_to, never};
|
||||
use syntax::{algo, ast, AstNode, TextRange, TextSize, T};
|
||||
use vfs::AbsPathBuf;
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec,
|
||||
|
@ -606,28 +608,30 @@ pub(crate) fn handle_parent_module(
|
|||
let _p = profile::span("handle_parent_module");
|
||||
if let Ok(file_path) = ¶ms.text_document.uri.to_file_path() {
|
||||
if file_path.file_name().unwrap_or_default() == "Cargo.toml" {
|
||||
// search parent workspace and collect a list of `LocationLink`path,
|
||||
// since cargo.toml doesn't have file_id
|
||||
// search workspaces for parent packages or fallback to workspace root
|
||||
let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() {
|
||||
Some(abs_path_buf) => abs_path_buf,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() {
|
||||
Some(manifest_path) => manifest_path,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let links: Vec<LocationLink> = snap
|
||||
.workspaces
|
||||
.iter()
|
||||
.filter_map(|ws| match ws {
|
||||
ProjectWorkspace::Cargo { cargo, .. } => cargo
|
||||
.packages()
|
||||
.find(|&pkg| cargo[pkg].manifest.as_ref() == file_path)
|
||||
.and_then(|_| Some(cargo)),
|
||||
ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
|
||||
_ => None,
|
||||
})
|
||||
.map(|ws| {
|
||||
let target_cargo_toml_path = ws.workspace_root().join("Cargo.toml");
|
||||
let target_cargo_toml_url =
|
||||
to_proto::url_from_abs_path(&target_cargo_toml_path);
|
||||
LocationLink {
|
||||
origin_selection_range: None,
|
||||
target_uri: target_cargo_toml_url,
|
||||
target_range: Range::default(),
|
||||
target_selection_range: Range::default(),
|
||||
}
|
||||
.flatten()
|
||||
.map(|parent_manifest_path| LocationLink {
|
||||
origin_selection_range: None,
|
||||
target_uri: to_proto::url_from_abs_path(&parent_manifest_path),
|
||||
target_range: Range::default(),
|
||||
target_selection_range: Range::default(),
|
||||
})
|
||||
.collect::<_>();
|
||||
return Ok(Some(links.into()));
|
||||
|
|
|
@ -189,12 +189,14 @@ export function parentModule(ctx: Ctx): Cmd {
|
|||
const client = ctx.client;
|
||||
if (!editor || !client) return;
|
||||
if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
|
||||
|
||||
const locations = await client.sendRequest(ra.parentModule, {
|
||||
textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
||||
position: client.code2ProtocolConverter.asPosition(
|
||||
editor.selection.active,
|
||||
),
|
||||
});
|
||||
if (!locations) return;
|
||||
|
||||
if (locations.length === 1) {
|
||||
const loc = locations[0];
|
||||
|
|
|
@ -62,7 +62,7 @@ export interface MatchingBraceParams {
|
|||
}
|
||||
export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace");
|
||||
|
||||
export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule");
|
||||
export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[] | null, void>("experimental/parentModule");
|
||||
|
||||
export interface JoinLinesParams {
|
||||
textDocument: lc.TextDocumentIdentifier;
|
||||
|
|
Loading…
Reference in a new issue