Skip to content

Commit 59c7552

Browse files
committed
Provide navigations to parent modules
1 parent aaa0771 commit 59c7552

File tree

4 files changed

+58
-19
lines changed

4 files changed

+58
-19
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! See [`CargoWorkspace`].
22
3-
use std::convert::TryInto;
3+
use std::convert::{TryFrom, TryInto};
44
use std::iter;
55
use std::path::PathBuf;
66
use std::{ops, process::Command};
@@ -400,6 +400,39 @@ impl CargoWorkspace {
400400
}
401401
}
402402

403+
pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option<Vec<ManifestPath>> {
404+
let mut found = false;
405+
let parent_manifests = self
406+
.packages()
407+
.filter_map(|pkg| {
408+
if !found && &self[pkg].manifest == manifest_path {
409+
found = true
410+
}
411+
self[pkg].dependencies.iter().find_map(|dep| {
412+
if &self[dep.pkg].manifest == manifest_path {
413+
return Some(self[pkg].manifest.clone());
414+
}
415+
None
416+
})
417+
})
418+
.collect::<Vec<ManifestPath>>();
419+
420+
// some packages has this pkg as dep. return their manifests
421+
if parent_manifests.len() > 0 {
422+
return Some(parent_manifests);
423+
}
424+
425+
// this pkg is inside this cargo workspace, fallback to workspace root
426+
if found {
427+
return Some(vec![
428+
ManifestPath::try_from(self.workspace_root().join("Cargo.toml")).ok()?
429+
]);
430+
}
431+
432+
// not in this workspace
433+
None
434+
}
435+
403436
fn is_unique(&self, name: &str) -> bool {
404437
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
405438
}

crates/rust-analyzer/src/handlers.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! `ide` crate.
44
55
use std::{
6+
convert::TryFrom,
67
io::Write as _,
78
process::{self, Stdio},
89
};
@@ -26,10 +27,11 @@ use lsp_types::{
2627
SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag,
2728
TextDocumentIdentifier, Url, WorkspaceEdit,
2829
};
29-
use project_model::{ProjectWorkspace, TargetKind};
30+
use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
3031
use serde_json::json;
3132
use stdx::{format_to, never};
3233
use syntax::{algo, ast, AstNode, TextRange, TextSize, T};
34+
use vfs::AbsPathBuf;
3335

3436
use crate::{
3537
cargo_target_spec::CargoTargetSpec,
@@ -606,28 +608,30 @@ pub(crate) fn handle_parent_module(
606608
let _p = profile::span("handle_parent_module");
607609
if let Ok(file_path) = &params.text_document.uri.to_file_path() {
608610
if file_path.file_name().unwrap_or_default() == "Cargo.toml" {
609-
// search parent workspace and collect a list of `LocationLink`path,
610-
// since cargo.toml doesn't have file_id
611+
// search workspaces for parent packages or fallback to workspace root
612+
let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() {
613+
Some(abs_path_buf) => abs_path_buf,
614+
None => return Ok(None),
615+
};
616+
617+
let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() {
618+
Some(manifest_path) => manifest_path,
619+
None => return Ok(None),
620+
};
621+
611622
let links: Vec<LocationLink> = snap
612623
.workspaces
613624
.iter()
614625
.filter_map(|ws| match ws {
615-
ProjectWorkspace::Cargo { cargo, .. } => cargo
616-
.packages()
617-
.find(|&pkg| cargo[pkg].manifest.as_ref() == file_path)
618-
.and_then(|_| Some(cargo)),
626+
ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
619627
_ => None,
620628
})
621-
.map(|ws| {
622-
let target_cargo_toml_path = ws.workspace_root().join("Cargo.toml");
623-
let target_cargo_toml_url =
624-
to_proto::url_from_abs_path(&target_cargo_toml_path);
625-
LocationLink {
626-
origin_selection_range: None,
627-
target_uri: target_cargo_toml_url,
628-
target_range: Range::default(),
629-
target_selection_range: Range::default(),
630-
}
629+
.flatten()
630+
.map(|parent_manifest_path| LocationLink {
631+
origin_selection_range: None,
632+
target_uri: to_proto::url_from_abs_path(&parent_manifest_path),
633+
target_range: Range::default(),
634+
target_selection_range: Range::default(),
631635
})
632636
.collect::<_>();
633637
return Ok(Some(links.into()));

editors/code/src/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,14 @@ export function parentModule(ctx: Ctx): Cmd {
189189
const client = ctx.client;
190190
if (!editor || !client) return;
191191
if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
192+
192193
const locations = await client.sendRequest(ra.parentModule, {
193194
textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
194195
position: client.code2ProtocolConverter.asPosition(
195196
editor.selection.active,
196197
),
197198
});
199+
if (!locations) return;
198200

199201
if (locations.length === 1) {
200202
const loc = locations[0];

editors/code/src/lsp_ext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export interface MatchingBraceParams {
6262
}
6363
export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace");
6464

65-
export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule");
65+
export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[] | null, void>("experimental/parentModule");
6666

6767
export interface JoinLinesParams {
6868
textDocument: lc.TextDocumentIdentifier;

0 commit comments

Comments
 (0)