mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 09:05:47 +02:00
input and output types (#5750)
* input and output types * added description * type from stored variable * string in custom value * more tests with non custom
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{ast::Call, BlockId, Example, PipelineData, ShellError, Signature};
|
||||
use crate::{ast::Call, BlockId, Example, PipelineData, ShellError, Signature, Type};
|
||||
|
||||
use super::{EngineState, Stack};
|
||||
|
||||
@ -66,6 +66,20 @@ pub trait Command: Send + Sync + CommandClone {
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
// Command input type. The Type is used during parsing to find the
|
||||
// correct internal command with similar names. The input type is
|
||||
// obtained from the previous expression found in the pipeline
|
||||
fn input_type(&self) -> Type {
|
||||
Type::Any
|
||||
}
|
||||
|
||||
// Command output type. The output type is the value from the command
|
||||
// It is used during parsing to find the next command in case there
|
||||
// are commands with similar names
|
||||
fn output_type(&self) -> Type {
|
||||
Type::Any
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CommandClone {
|
||||
|
@ -464,9 +464,9 @@ impl EngineState {
|
||||
for overlay_frame in self.active_overlays(removed_overlays).iter().rev() {
|
||||
visibility.append(&overlay_frame.visibility);
|
||||
|
||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
||||
if visibility.is_decl_id_visible(decl_id) {
|
||||
return Some(*decl_id);
|
||||
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||
if visibility.is_decl_id_visible(&decl_id) {
|
||||
return Some(decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -533,9 +533,9 @@ impl EngineState {
|
||||
|
||||
for overlay_frame in self.active_overlays(&[]).iter().rev() {
|
||||
for decl in &overlay_frame.decls {
|
||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
|
||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0) {
|
||||
let command = self.get_decl(*decl.1);
|
||||
output.push((decl.0.clone(), Some(command.usage().to_string())));
|
||||
output.push((decl.0 .0.clone(), Some(command.usage().to_string())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -614,7 +614,8 @@ impl EngineState {
|
||||
decls_map.extend(new_decls);
|
||||
}
|
||||
|
||||
let mut decls: Vec<(Vec<u8>, DeclId)> = decls_map.into_iter().collect();
|
||||
let mut decls: Vec<(Vec<u8>, DeclId)> =
|
||||
decls_map.into_iter().map(|(v, k)| (v.0, k)).collect();
|
||||
|
||||
decls.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
decls.into_iter().map(|(_, id)| id)
|
||||
@ -743,6 +744,9 @@ pub struct StateWorkingSet<'a> {
|
||||
pub permanent_state: &'a EngineState,
|
||||
pub delta: StateDelta,
|
||||
pub external_commands: Vec<Vec<u8>>,
|
||||
// Internal commands output that the next expression in the pipe will use to select a declaration
|
||||
// that matches the name in the found output
|
||||
pub found_outputs: Vec<Type>,
|
||||
}
|
||||
|
||||
/// A delta (or change set) between the current global state and a possible future global state. Deltas
|
||||
@ -867,6 +871,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
delta: StateDelta::new(permanent_state),
|
||||
permanent_state,
|
||||
external_commands: vec![],
|
||||
found_outputs: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -918,11 +923,13 @@ impl<'a> StateWorkingSet<'a> {
|
||||
|
||||
pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId {
|
||||
let name = decl.name().as_bytes().to_vec();
|
||||
let input_type = decl.input_type();
|
||||
|
||||
self.delta.decls.push(decl);
|
||||
let decl_id = self.num_decls() - 1;
|
||||
|
||||
self.last_overlay_mut().decls.insert(name, decl_id);
|
||||
self.last_overlay_mut()
|
||||
.insert_decl(name, input_type, decl_id);
|
||||
|
||||
decl_id
|
||||
}
|
||||
@ -931,7 +938,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
let overlay_frame = self.last_overlay_mut();
|
||||
|
||||
for (name, decl_id) in decls {
|
||||
overlay_frame.decls.insert(name, decl_id);
|
||||
overlay_frame.insert_decl(name, Type::Any, decl_id);
|
||||
overlay_frame.visibility.use_decl_id(&decl_id);
|
||||
}
|
||||
}
|
||||
@ -968,7 +975,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
let overlay_frame = self.last_overlay_mut();
|
||||
|
||||
if let Some(decl_id) = overlay_frame.predecls.remove(name) {
|
||||
overlay_frame.decls.insert(name.into(), decl_id);
|
||||
overlay_frame.insert_decl(name.into(), Type::Any, decl_id);
|
||||
|
||||
return Some(decl_id);
|
||||
}
|
||||
@ -998,11 +1005,11 @@ impl<'a> StateWorkingSet<'a> {
|
||||
|
||||
visibility.append(&overlay_frame.visibility);
|
||||
|
||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
||||
if visibility.is_decl_id_visible(decl_id) {
|
||||
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||
if visibility.is_decl_id_visible(&decl_id) {
|
||||
// Hide decl only if it's not already hidden
|
||||
overlay_frame.visibility.hide_decl_id(decl_id);
|
||||
return Some(*decl_id);
|
||||
overlay_frame.visibility.hide_decl_id(&decl_id);
|
||||
return Some(decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1018,11 +1025,11 @@ impl<'a> StateWorkingSet<'a> {
|
||||
{
|
||||
visibility.append(&overlay_frame.visibility);
|
||||
|
||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
||||
if visibility.is_decl_id_visible(decl_id) {
|
||||
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||
if visibility.is_decl_id_visible(&decl_id) {
|
||||
// Hide decl only if it's not already hidden
|
||||
self.last_overlay_mut().visibility.hide_decl_id(decl_id);
|
||||
return Some(*decl_id);
|
||||
self.last_overlay_mut().visibility.hide_decl_id(&decl_id);
|
||||
return Some(decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1254,7 +1261,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
||||
pub fn find_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> {
|
||||
let mut removed_overlays = vec![];
|
||||
|
||||
let mut visibility: Visibility = Visibility::new();
|
||||
@ -1280,9 +1287,9 @@ impl<'a> StateWorkingSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
||||
if visibility.is_decl_id_visible(decl_id) {
|
||||
return Some(*decl_id);
|
||||
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
|
||||
if visibility.is_decl_id_visible(&decl_id) {
|
||||
return Some(decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1297,9 +1304,9 @@ impl<'a> StateWorkingSet<'a> {
|
||||
{
|
||||
visibility.append(&overlay_frame.visibility);
|
||||
|
||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
||||
if visibility.is_decl_id_visible(decl_id) {
|
||||
return Some(*decl_id);
|
||||
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
|
||||
if visibility.is_decl_id_visible(&decl_id) {
|
||||
return Some(decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1384,7 +1391,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
.rev()
|
||||
{
|
||||
for decl in &overlay_frame.decls {
|
||||
if decl.0.starts_with(name) {
|
||||
if decl.0 .0.starts_with(name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1398,7 +1405,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||
.rev()
|
||||
{
|
||||
for decl in &overlay_frame.decls {
|
||||
if decl.0.starts_with(name) {
|
||||
if decl.0 .0.starts_with(name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1562,9 +1569,10 @@ impl<'a> StateWorkingSet<'a> {
|
||||
let overlay_frame = scope_frame.get_overlay(*overlay_id);
|
||||
|
||||
for decl in &overlay_frame.decls {
|
||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
|
||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0)
|
||||
{
|
||||
let command = self.get_decl(*decl.1);
|
||||
output.push((decl.0.clone(), Some(command.usage().to_string())));
|
||||
output.push((decl.0 .0.clone(), Some(command.usage().to_string())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1718,8 +1726,8 @@ impl<'a> StateWorkingSet<'a> {
|
||||
if let Some(overlay_id) = self.permanent_state.find_overlay(name) {
|
||||
let overlay_frame = self.permanent_state.get_overlay(overlay_id);
|
||||
|
||||
for (decl_name, decl_id) in &overlay_frame.decls {
|
||||
result.insert(decl_name.to_owned(), *decl_id);
|
||||
for (decl_key, decl_id) in &overlay_frame.decls {
|
||||
result.insert(decl_key.0.to_owned(), *decl_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,8 +1735,8 @@ impl<'a> StateWorkingSet<'a> {
|
||||
if let Some(overlay_id) = scope_frame.find_overlay(name) {
|
||||
let overlay_frame = scope_frame.get_overlay(overlay_id);
|
||||
|
||||
for (decl_name, decl_id) in &overlay_frame.decls {
|
||||
result.insert(decl_name.to_owned(), *decl_id);
|
||||
for (decl_key, decl_id) in &overlay_frame.decls {
|
||||
result.insert(decl_key.0.to_owned(), *decl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{AliasId, DeclId, ModuleId, OverlayId, Type, VarId};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{AliasId, DeclId, ModuleId, OverlayId, VarId};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
pub static DEFAULT_OVERLAY_NAME: &str = "zero";
|
||||
|
||||
@ -199,7 +200,7 @@ impl ScopeFrame {
|
||||
pub struct OverlayFrame {
|
||||
pub vars: HashMap<Vec<u8>, VarId>,
|
||||
pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
|
||||
pub decls: HashMap<Vec<u8>, DeclId>,
|
||||
pub decls: HashMap<(Vec<u8>, Type), DeclId>,
|
||||
pub aliases: HashMap<Vec<u8>, AliasId>,
|
||||
pub modules: HashMap<Vec<u8>, ModuleId>,
|
||||
pub visibility: Visibility,
|
||||
@ -218,4 +219,58 @@ impl OverlayFrame {
|
||||
origin,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_decl(&mut self, name: Vec<u8>, input: Type, decl_id: DeclId) -> Option<DeclId> {
|
||||
self.decls.insert((name, input), decl_id)
|
||||
}
|
||||
|
||||
pub fn get_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> {
|
||||
self.decls.get(&(name, input) as &dyn DeclKey).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
trait DeclKey {
|
||||
fn name(&self) -> &[u8];
|
||||
fn input(&self) -> &Type;
|
||||
}
|
||||
|
||||
impl Hash for dyn DeclKey + '_ {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.name().hash(state);
|
||||
self.input().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for dyn DeclKey + '_ {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.name() == other.name() && self.input() == other.input()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for dyn DeclKey + '_ {}
|
||||
|
||||
impl<'a> DeclKey for (&'a [u8], &Type) {
|
||||
fn name(&self) -> &[u8] {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn input(&self) -> &Type {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl DeclKey for (Vec<u8>, Type) {
|
||||
fn name(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn input(&self) -> &Type {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Borrow<dyn DeclKey + 'a> for (Vec<u8>, Type) {
|
||||
fn borrow(&self) -> &(dyn DeclKey + 'a) {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::fmt::Display;
|
||||
|
||||
use crate::SyntaxShape;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub enum Type {
|
||||
Int,
|
||||
Float,
|
||||
@ -25,7 +25,7 @@ pub enum Type {
|
||||
Any,
|
||||
Error,
|
||||
Binary,
|
||||
Custom,
|
||||
Custom(String),
|
||||
Signature,
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ impl Type {
|
||||
Type::Any => SyntaxShape::Any,
|
||||
Type::Error => SyntaxShape::Any,
|
||||
Type::Binary => SyntaxShape::Binary,
|
||||
Type::Custom => SyntaxShape::Any,
|
||||
Type::Custom(_) => SyntaxShape::Any,
|
||||
Type::Signature => SyntaxShape::Signature,
|
||||
}
|
||||
}
|
||||
@ -95,7 +95,7 @@ impl Display for Type {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Error => write!(f, "error"),
|
||||
Type::Binary => write!(f, "binary"),
|
||||
Type::Custom => write!(f, "custom"),
|
||||
Type::Custom(custom) => write!(f, "custom<{}>", custom),
|
||||
Type::Signature => write!(f, "signature"),
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ impl Value {
|
||||
Value::Error { .. } => Type::Error,
|
||||
Value::Binary { .. } => Type::Binary,
|
||||
Value::CellPath { .. } => Type::CellPath,
|
||||
Value::CustomValue { .. } => Type::Custom,
|
||||
Value::CustomValue { val, .. } => Type::Custom(val.typetag_name().into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user