Skip to main content

cargo/diagnostics/
report.rs

1use 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
11/// Display path, generally relative to the workspace
12///
13/// Mirrors [`crate::util::path_args`]
14pub fn workspace_rel_path(ws: &Workspace<'_>, path: &Path) -> String {
15    // Determine which path we make this relative to: usually it's the workspace root,
16    // but this can be overwritten with a `-Z` flag.
17    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
30/// Display path, generally relative to cwd
31///
32/// Prefer [`workspace_rel_path`].
33/// This is for when there is no workspace available.
34pub 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}