nushell/crates/nu-protocol/src/value/value_structure.rs
Andrés N. Robalino 03c9eaf005
Variable completions. (#3666)
In Nu we have variables (E.g. $var-name) and these contain `Value` types.
This means we can bind to variables any structured data and column path syntax
(E.g. `$variable.path.to`) allows flexibility for "querying" said structures.

Here we offer completions for these. For example, in a Nushell session the
variable `$nu` contains environment values among other things. If we wanted to
see in the screen some environment variable (say the var `SHELL`) we do:

```
> echo $nu.env.SHELL
```

with completions we can now do: `echo $nu.env.S[\TAB]` and we get suggestions
that start at the column path `$nu.env` with vars starting with the letter `S`
in this case `SHELL` appears in the suggestions.
2021-06-23 19:21:39 +12:00

84 lines
2.0 KiB
Rust

use crate::{UntaggedValue, Value};
use nu_errors::ShellError;
use std::path::{Component, Path, PathBuf};
fn is_value_tagged_dir(value: &Value) -> bool {
matches!(
&value.value,
UntaggedValue::Row(_) | UntaggedValue::Table(_)
)
}
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct ValueResource {
pub at: usize,
pub loc: PathBuf,
}
impl ValueResource {}
#[derive(Default, Debug)]
pub struct ValueStructure {
pub resources: Vec<ValueResource>,
}
impl ValueStructure {
pub fn new() -> ValueStructure {
ValueStructure {
resources: Vec::<ValueResource>::new(),
}
}
pub fn exists(&self, path: &Path) -> bool {
if path == Path::new("/") {
return true;
}
let path = if path.starts_with("/") {
path.strip_prefix("/").unwrap_or(path)
} else {
path
};
let comps: Vec<_> = path.components().map(Component::as_os_str).collect();
let mut is_there = true;
for (at, fragment) in comps.iter().enumerate() {
is_there = is_there
&& self
.resources
.iter()
.any(|resource| at == resource.at && *fragment == resource.loc.as_os_str());
}
is_there
}
pub fn walk_decorate(&mut self, start: &Value) -> Result<(), ShellError> {
self.resources = Vec::<ValueResource>::new();
self.build(start, 0)?;
self.resources.sort();
Ok(())
}
fn build(&mut self, src: &Value, lvl: usize) -> Result<(), ShellError> {
for entry in src.row_entries() {
let value = entry.1;
let path = entry.0;
self.resources.push(ValueResource {
at: lvl,
loc: PathBuf::from(path),
});
if is_value_tagged_dir(value) {
self.build(value, lvl + 1)?;
}
}
Ok(())
}
}