cargo/diagnostics/
report.rs1use std::borrow::Cow;
2use std::ops::Range;
3use std::path::Path;
4
5use cargo_util::paths::normalize_path;
6use pathdiff::diff_paths;
7
8use crate::GlobalContext;
9use crate::core::Workspace;
10
11pub fn workspace_rel_path(ws: &Workspace<'_>, path: &Path) -> String {
15 let root = match &ws.gctx().cli_unstable().root_dir {
18 None => ws.root().to_owned(),
19 Some(root_dir) => normalize_path(&ws.gctx().cwd().join(root_dir)),
20 };
21 if let Ok(path) = path.strip_prefix(&root) {
22 path
23 } else {
24 path
25 }
26 .display()
27 .to_string()
28}
29
30pub fn cwd_rel_path(path: &Path, gctx: &GlobalContext) -> String {
35 diff_paths(path, gctx.cwd())
36 .unwrap_or_else(|| path.to_path_buf())
37 .display()
38 .to_string()
39}
40
41pub fn get_key_value<'doc, 'i>(
42 document: &'doc toml::Spanned<toml::de::DeTable<'static>>,
43 path: &[impl AsIndex],
44) -> Option<(
45 &'doc toml::Spanned<Cow<'doc, str>>,
46 &'doc toml::Spanned<toml::de::DeValue<'static>>,
47)> {
48 let table = document.get_ref();
49 let mut iter = path.into_iter();
50 let index0 = iter.next()?.as_index();
51 let key0 = index0.as_key()?;
52 let (mut current_key, mut current_item) = table.get_key_value(key0)?;
53
54 while let Some(index) = iter.next() {
55 match index.as_index() {
56 TomlIndex::Key(key) => {
57 if let Some(table) = current_item.get_ref().as_table() {
58 (current_key, current_item) = table.get_key_value(key)?;
59 } else if let Some(array) = current_item.get_ref().as_array() {
60 current_item = array.iter().find(|item| match item.get_ref() {
61 toml::de::DeValue::String(s) => s == key,
62 _ => false,
63 })?;
64 } else {
65 return None;
66 }
67 }
68 TomlIndex::Offset(offset) => {
69 let array = current_item.get_ref().as_array()?;
70 current_item = array.get(offset)?;
71 }
72 }
73 }
74 Some((current_key, current_item))
75}
76
77pub fn get_key_value_span<'i>(
78 document: &toml::Spanned<toml::de::DeTable<'static>>,
79 path: &[impl AsIndex],
80) -> Option<TomlSpan> {
81 get_key_value(document, path).map(|(k, v)| TomlSpan {
82 key: k.span(),
83 value: v.span(),
84 })
85}
86
87#[derive(Clone)]
88pub struct TomlSpan {
89 pub key: Range<usize>,
90 pub value: Range<usize>,
91}
92
93#[derive(Copy, Clone)]
94pub enum TomlIndex<'i> {
95 Key(&'i str),
96 Offset(usize),
97}
98
99impl<'i> TomlIndex<'i> {
100 fn as_key(&self) -> Option<&'i str> {
101 match self {
102 TomlIndex::Key(key) => Some(key),
103 TomlIndex::Offset(_) => None,
104 }
105 }
106}
107
108pub trait AsIndex {
109 fn as_index<'i>(&'i self) -> TomlIndex<'i>;
110}
111
112impl AsIndex for TomlIndex<'_> {
113 fn as_index<'i>(&'i self) -> TomlIndex<'i> {
114 match self {
115 TomlIndex::Key(key) => TomlIndex::Key(key),
116 TomlIndex::Offset(offset) => TomlIndex::Offset(*offset),
117 }
118 }
119}
120
121impl AsIndex for &str {
122 fn as_index<'i>(&'i self) -> TomlIndex<'i> {
123 TomlIndex::Key(self)
124 }
125}
126
127impl AsIndex for String {
128 fn as_index<'i>(&'i self) -> TomlIndex<'i> {
129 TomlIndex::Key(self.as_str())
130 }
131}
132
133impl AsIndex for usize {
134 fn as_index<'i>(&'i self) -> TomlIndex<'i> {
135 TomlIndex::Offset(*self)
136 }
137}