mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 16:33:37 +01:00
Add tags command and fix source_map transfer
This commit is contained in:
parent
462f783fac
commit
db3ff52973
@ -144,6 +144,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
|
|||||||
| skip amount | Skip a number of rows |
|
| skip amount | Skip a number of rows |
|
||||||
| first amount | Show only the first number of rows |
|
| first amount | Show only the first number of rows |
|
||||||
| str (field) | Apply string function. Optional use the field of a table |
|
| str (field) | Apply string function. Optional use the field of a table |
|
||||||
|
| tags | Read the tags (metadata) for values |
|
||||||
| to-array | Collapse rows into a single list |
|
| to-array | Collapse rows into a single list |
|
||||||
| to-json | Convert table into .json text |
|
| to-json | Convert table into .json text |
|
||||||
| to-toml | Convert table into .toml text |
|
| to-toml | Convert table into .toml text |
|
||||||
|
@ -175,6 +175,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
command("to-toml", Box::new(to_toml::to_toml)),
|
command("to-toml", Box::new(to_toml::to_toml)),
|
||||||
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
||||||
command("sort-by", Box::new(sort_by::sort_by)),
|
command("sort-by", Box::new(sort_by::sort_by)),
|
||||||
|
command("tags", Box::new(tags::tags)),
|
||||||
Arc::new(Remove),
|
Arc::new(Remove),
|
||||||
Arc::new(Copycp),
|
Arc::new(Copycp),
|
||||||
Arc::new(Open),
|
Arc::new(Open),
|
||||||
@ -496,7 +497,6 @@ fn classify_command(
|
|||||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||||
command,
|
command,
|
||||||
name_span: Some(head.span().clone()),
|
name_span: Some(head.span().clone()),
|
||||||
source_map: context.source_map.clone(),
|
|
||||||
args,
|
args,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ crate mod sort_by;
|
|||||||
crate mod split_column;
|
crate mod split_column;
|
||||||
crate mod split_row;
|
crate mod split_row;
|
||||||
crate mod table;
|
crate mod table;
|
||||||
|
crate mod tags;
|
||||||
crate mod to_array;
|
crate mod to_array;
|
||||||
crate mod to_csv;
|
crate mod to_csv;
|
||||||
crate mod to_json;
|
crate mod to_json;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::commands::command::Sink;
|
use crate::commands::command::Sink;
|
||||||
use crate::context::SourceMap;
|
|
||||||
use crate::parser::{registry::Args, TokenNode};
|
use crate::parser::{registry::Args, TokenNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
@ -113,7 +112,6 @@ impl SinkCommand {
|
|||||||
crate struct InternalCommand {
|
crate struct InternalCommand {
|
||||||
crate command: Arc<dyn Command>,
|
crate command: Arc<dyn Command>,
|
||||||
crate name_span: Option<Span>,
|
crate name_span: Option<Span>,
|
||||||
crate source_map: SourceMap,
|
|
||||||
crate args: Args,
|
crate args: Args,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +133,7 @@ impl InternalCommand {
|
|||||||
let result = context.run_command(
|
let result = context.run_command(
|
||||||
self.command,
|
self.command,
|
||||||
self.name_span.clone(),
|
self.name_span.clone(),
|
||||||
self.source_map,
|
context.source_map.clone(),
|
||||||
self.args,
|
self.args,
|
||||||
objects,
|
objects,
|
||||||
)?;
|
)?;
|
||||||
|
32
src/commands/tags.rs
Normal file
32
src/commands/tags.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::{TaggedDictBuilder, Value};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn tags(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let source_map = args.call_info.source_map.clone();
|
||||||
|
Ok(args
|
||||||
|
.input
|
||||||
|
.values
|
||||||
|
.map(move |v| {
|
||||||
|
let mut tags = TaggedDictBuilder::new(v.span());
|
||||||
|
{
|
||||||
|
let span = v.span();
|
||||||
|
let mut dict = TaggedDictBuilder::new(v.span());
|
||||||
|
dict.insert("start", Value::int(span.start as i64));
|
||||||
|
dict.insert("end", Value::int(span.end as i64));
|
||||||
|
match span.source.map(|x| source_map.get(&x)).flatten() {
|
||||||
|
Some(SpanSource::File(source)) => {
|
||||||
|
dict.insert("source", Value::string(source));
|
||||||
|
}
|
||||||
|
Some(SpanSource::Url(source)) => {
|
||||||
|
dict.insert("source", Value::string(source));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
tags.insert_tagged("span", dict.into_tagged_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.into_tagged_value()
|
||||||
|
})
|
||||||
|
.to_output_stream())
|
||||||
|
}
|
203
src/object/meta.rs
Normal file
203
src/object/meta.rs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
use crate::Text;
|
||||||
|
use derive_new::new;
|
||||||
|
use getset::Getters;
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
||||||
|
)]
|
||||||
|
#[get = "crate"]
|
||||||
|
pub struct Tagged<T> {
|
||||||
|
pub tag: Tag,
|
||||||
|
pub item: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TaggedItem: Sized {
|
||||||
|
fn tagged(self, span: impl Into<Span>) -> Tagged<Self> {
|
||||||
|
Tagged::from_item(self, span.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, this is a temporary facility. In many cases, there are other useful spans that we
|
||||||
|
// could be using, such as the original source spans of JSON or Toml files, but we don't yet
|
||||||
|
// have the infrastructure to make that work.
|
||||||
|
fn tagged_unknown(self) -> Tagged<Self> {
|
||||||
|
Tagged::from_item(self, (0, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TaggedItem for T {}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for Tagged<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Tagged<T> {
|
||||||
|
pub fn tagged(self, span: impl Into<Span>) -> Tagged<T> {
|
||||||
|
Tagged::from_item(self.item, span.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_item(item: T, span: impl Into<Span>) -> Tagged<T> {
|
||||||
|
Tagged {
|
||||||
|
item,
|
||||||
|
tag: Tag { span: span.into() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Tagged<U> {
|
||||||
|
let span = self.span();
|
||||||
|
|
||||||
|
let mapped = input(self.item);
|
||||||
|
Tagged::from_item(mapped, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn copy_span<U>(&self, output: U) -> Tagged<U> {
|
||||||
|
let span = self.span();
|
||||||
|
|
||||||
|
Tagged::from_item(output, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source(&self, source: &Text) -> Text {
|
||||||
|
Text::from(self.span().slice(source))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
self.tag.span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<&Tagged<T>> for Span {
|
||||||
|
fn from(input: &Tagged<T>) -> Span {
|
||||||
|
input.span()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Span> for Span {
|
||||||
|
fn from(input: &Span) -> Span {
|
||||||
|
*input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<nom5_locate::LocatedSpan<&str>> for Span {
|
||||||
|
fn from(input: nom5_locate::LocatedSpan<&str>) -> Span {
|
||||||
|
Span {
|
||||||
|
start: input.offset,
|
||||||
|
end: input.offset + input.fragment.len(),
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<(nom5_locate::LocatedSpan<T>, nom5_locate::LocatedSpan<T>)> for Span {
|
||||||
|
fn from(input: (nom5_locate::LocatedSpan<T>, nom5_locate::LocatedSpan<T>)) -> Span {
|
||||||
|
Span {
|
||||||
|
start: input.0.offset,
|
||||||
|
end: input.1.offset,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(usize, usize)> for Span {
|
||||||
|
fn from(input: (usize, usize)) -> Span {
|
||||||
|
Span {
|
||||||
|
start: input.0,
|
||||||
|
end: input.1,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&std::ops::Range<usize>> for Span {
|
||||||
|
fn from(input: &std::ops::Range<usize>) -> Span {
|
||||||
|
Span {
|
||||||
|
start: input.start,
|
||||||
|
end: input.end,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
||||||
|
)]
|
||||||
|
pub struct Tag {
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
|
pub struct Span {
|
||||||
|
crate start: usize,
|
||||||
|
crate end: usize,
|
||||||
|
pub source: Option<Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<Span>> for Span {
|
||||||
|
fn from(input: Option<Span>) -> Span {
|
||||||
|
match input {
|
||||||
|
None => Span {
|
||||||
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
source: None,
|
||||||
|
},
|
||||||
|
Some(span) => span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Span {
|
||||||
|
pub fn unknown() -> Span {
|
||||||
|
Span {
|
||||||
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unknown_with_uuid(uuid: Uuid) -> Span {
|
||||||
|
Span {
|
||||||
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
source: Some(uuid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_unknown(&self) -> bool {
|
||||||
|
self.start == 0 && self.end == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slice(&self, source: &'a str) -> &'a str {
|
||||||
|
&source[self.start..self.end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl language_reporting::ReportingSpan for Span {
|
||||||
|
fn with_start(&self, start: usize) -> Self {
|
||||||
|
Span {
|
||||||
|
start,
|
||||||
|
end: self.end,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_end(&self, end: usize) -> Self {
|
||||||
|
Span {
|
||||||
|
start: self.start,
|
||||||
|
end,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&self) -> usize {
|
||||||
|
self.start
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&self) -> usize {
|
||||||
|
self.end
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@ crate use crate::cli::MaybeOwned;
|
|||||||
crate use crate::commands::command::{
|
crate use crate::commands::command::{
|
||||||
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs,
|
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs,
|
||||||
};
|
};
|
||||||
crate use crate::context::Context;
|
crate use crate::context::{Context, SpanSource};
|
||||||
crate use crate::env::host::handle_unexpected;
|
crate use crate::env::host::handle_unexpected;
|
||||||
crate use crate::env::{Environment, Host};
|
crate use crate::env::{Environment, Host};
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
|
Loading…
Reference in New Issue
Block a user