mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 09:28:19 +02:00
Stream support (#812)
* Moves off of draining between filters. Instead, the sink will pull on the stream, and will drain element-wise. This moves the whole stream to being lazy. * Adds ctrl-c support and connects it into some of the key points where we pull on the stream. If a ctrl-c is detect, we immediately halt pulling on the stream and return to the prompt. * Moves away from having a SourceMap where anchor locations are stored. Now AnchorLocation is kept directly in the Tag. * To make this possible, split tag and span. Span is largely used in the parser and is copyable. Tag is now no longer copyable.
This commit is contained in:
@ -22,7 +22,7 @@ impl Add {
|
||||
let value_tag = value.tag();
|
||||
match (value.item, self.value.clone()) {
|
||||
(obj @ Value::Row(_), Some(v)) => match &self.field {
|
||||
Some(f) => match obj.insert_data_at_column_path(value_tag, &f, v) {
|
||||
Some(f) => match obj.insert_data_at_column_path(value_tag.clone(), &f, v) {
|
||||
Some(v) => return Ok(v),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
@ -32,7 +32,7 @@ impl Add {
|
||||
f.iter().map(|i| &i.item).join(".")
|
||||
),
|
||||
"column name",
|
||||
value_tag,
|
||||
&value_tag,
|
||||
))
|
||||
}
|
||||
},
|
||||
|
@ -24,8 +24,7 @@ impl Plugin for BinaryView {
|
||||
let value_anchor = v.anchor();
|
||||
match v.item {
|
||||
Value::Primitive(Primitive::Binary(b)) => {
|
||||
let source = call_info.source_map.get(&value_anchor);
|
||||
let _ = view_binary(&b, source, call_info.args.has("lores"));
|
||||
let _ = view_binary(&b, value_anchor.as_ref(), call_info.args.has("lores"));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ impl Edit {
|
||||
return Err(ShellError::labeled_error(
|
||||
"edit could not find place to insert column",
|
||||
"column name",
|
||||
f.tag,
|
||||
&f.tag,
|
||||
))
|
||||
}
|
||||
},
|
||||
|
@ -28,7 +28,7 @@ impl Embed {
|
||||
None => Err(ShellError::labeled_error(
|
||||
"embed needs a field when embedding a value",
|
||||
"original value",
|
||||
value.tag,
|
||||
&tag,
|
||||
)),
|
||||
},
|
||||
}
|
||||
|
@ -82,9 +82,7 @@ impl Inc {
|
||||
Value::Primitive(Primitive::Bytes(b)) => {
|
||||
Ok(Value::bytes(b + 1 as u64).tagged(value.tag()))
|
||||
}
|
||||
Value::Primitive(Primitive::String(ref s)) => {
|
||||
Ok(Tagged::from_item(self.apply(&s)?, value.tag()))
|
||||
}
|
||||
Value::Primitive(Primitive::String(ref s)) => Ok(self.apply(&s)?.tagged(value.tag())),
|
||||
Value::Row(_) => match self.field {
|
||||
Some(ref f) => {
|
||||
let replacement = match value.item.get_data_by_column_path(value.tag(), f) {
|
||||
@ -93,7 +91,7 @@ impl Inc {
|
||||
return Err(ShellError::labeled_error(
|
||||
"inc could not find field to replace",
|
||||
"column name",
|
||||
f.tag,
|
||||
&f.tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
@ -107,7 +105,7 @@ impl Inc {
|
||||
return Err(ShellError::labeled_error(
|
||||
"inc could not find field to replace",
|
||||
"column name",
|
||||
f.tag,
|
||||
&f.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -191,20 +189,18 @@ mod tests {
|
||||
use super::{Inc, SemVerAction};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
CallInfo, EvaluatedArgs, Plugin, ReturnSuccess, SourceMap, Tag, Tagged, TaggedDictBuilder,
|
||||
TaggedItem, Value,
|
||||
CallInfo, EvaluatedArgs, Plugin, ReturnSuccess, Tag, Tagged, TaggedDictBuilder, TaggedItem,
|
||||
Value,
|
||||
};
|
||||
|
||||
struct CallStub {
|
||||
anchor: uuid::Uuid,
|
||||
positionals: Vec<Tagged<Value>>,
|
||||
flags: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl CallStub {
|
||||
fn new(anchor: uuid::Uuid) -> CallStub {
|
||||
fn new() -> CallStub {
|
||||
CallStub {
|
||||
anchor,
|
||||
positionals: vec![],
|
||||
flags: indexmap::IndexMap::new(),
|
||||
}
|
||||
@ -221,19 +217,18 @@ mod tests {
|
||||
fn with_parameter(&mut self, name: &str) -> &mut Self {
|
||||
let fields: Vec<Tagged<Value>> = name
|
||||
.split(".")
|
||||
.map(|s| Value::string(s.to_string()).tagged(Tag::unknown_span(self.anchor)))
|
||||
.map(|s| Value::string(s.to_string()).tagged(Tag::unknown()))
|
||||
.collect();
|
||||
|
||||
self.positionals
|
||||
.push(Value::Table(fields).tagged(Tag::unknown_span(self.anchor)));
|
||||
.push(Value::Table(fields).tagged(Tag::unknown()));
|
||||
self
|
||||
}
|
||||
|
||||
fn create(&self) -> CallInfo {
|
||||
CallInfo {
|
||||
args: EvaluatedArgs::new(Some(self.positionals.clone()), Some(self.flags.clone())),
|
||||
source_map: SourceMap::new(),
|
||||
name_tag: Tag::unknown_span(self.anchor),
|
||||
name_tag: Tag::unknown(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,7 +255,7 @@ mod tests {
|
||||
let mut plugin = Inc::new();
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(CallStub::new(test_uuid()).with_long_flag("major").create())
|
||||
.begin_filter(CallStub::new().with_long_flag("major").create())
|
||||
.is_ok());
|
||||
assert!(plugin.action.is_some());
|
||||
}
|
||||
@ -270,7 +265,7 @@ mod tests {
|
||||
let mut plugin = Inc::new();
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(CallStub::new(test_uuid()).with_long_flag("minor").create())
|
||||
.begin_filter(CallStub::new().with_long_flag("minor").create())
|
||||
.is_ok());
|
||||
assert!(plugin.action.is_some());
|
||||
}
|
||||
@ -280,7 +275,7 @@ mod tests {
|
||||
let mut plugin = Inc::new();
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(CallStub::new(test_uuid()).with_long_flag("patch").create())
|
||||
.begin_filter(CallStub::new().with_long_flag("patch").create())
|
||||
.is_ok());
|
||||
assert!(plugin.action.is_some());
|
||||
}
|
||||
@ -291,7 +286,7 @@ mod tests {
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(
|
||||
CallStub::new(test_uuid())
|
||||
CallStub::new()
|
||||
.with_long_flag("major")
|
||||
.with_long_flag("minor")
|
||||
.create(),
|
||||
@ -305,11 +300,7 @@ mod tests {
|
||||
let mut plugin = Inc::new();
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(
|
||||
CallStub::new(test_uuid())
|
||||
.with_parameter("package.version")
|
||||
.create()
|
||||
)
|
||||
.begin_filter(CallStub::new().with_parameter("package.version").create())
|
||||
.is_ok());
|
||||
|
||||
assert_eq!(
|
||||
@ -347,7 +338,7 @@ mod tests {
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(
|
||||
CallStub::new(test_uuid())
|
||||
CallStub::new()
|
||||
.with_long_flag("major")
|
||||
.with_parameter("version")
|
||||
.create()
|
||||
@ -375,7 +366,7 @@ mod tests {
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(
|
||||
CallStub::new(test_uuid())
|
||||
CallStub::new()
|
||||
.with_long_flag("minor")
|
||||
.with_parameter("version")
|
||||
.create()
|
||||
@ -404,7 +395,7 @@ mod tests {
|
||||
|
||||
assert!(plugin
|
||||
.begin_filter(
|
||||
CallStub::new(test_uuid())
|
||||
CallStub::new()
|
||||
.with_long_flag("patch")
|
||||
.with_parameter(&field)
|
||||
.create()
|
||||
@ -425,8 +416,4 @@ mod tests {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_uuid() -> uuid::Uuid {
|
||||
uuid::Uuid::nil()
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ async fn ps(tag: Tag) -> Vec<Tagged<Value>> {
|
||||
let mut output = vec![];
|
||||
while let Some(res) = processes.next().await {
|
||||
if let Ok((process, usage)) = res {
|
||||
let mut dict = TaggedDictBuilder::new(tag);
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
dict.insert("pid", Value::int(process.pid()));
|
||||
if let Ok(name) = process.name().await {
|
||||
dict.insert("name", Value::string(name));
|
||||
|
@ -89,14 +89,12 @@ impl Str {
|
||||
impl Str {
|
||||
fn strutils(&self, value: Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||
match value.item {
|
||||
Value::Primitive(Primitive::String(ref s)) => {
|
||||
Ok(Tagged::from_item(self.apply(&s)?, value.tag()))
|
||||
}
|
||||
Value::Primitive(Primitive::String(ref s)) => Ok(self.apply(&s)?.tagged(value.tag())),
|
||||
Value::Row(_) => match self.field {
|
||||
Some(ref f) => {
|
||||
let replacement = match value.item.get_data_by_column_path(value.tag(), f) {
|
||||
Some(result) => self.strutils(result.map(|x| x.clone()))?,
|
||||
None => return Ok(Tagged::from_item(Value::nothing(), value.tag)),
|
||||
None => return Ok(Value::nothing().tagged(value.tag)),
|
||||
};
|
||||
match value.item.replace_data_at_column_path(
|
||||
value.tag(),
|
||||
@ -174,7 +172,7 @@ impl Plugin for Str {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in params",
|
||||
possible_field.type_name(),
|
||||
possible_field.tag,
|
||||
&possible_field.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -216,13 +214,12 @@ mod tests {
|
||||
use super::{Action, Str};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
CallInfo, EvaluatedArgs, Plugin, Primitive, ReturnSuccess, SourceMap, Tag, Tagged,
|
||||
TaggedDictBuilder, TaggedItem, Value,
|
||||
CallInfo, EvaluatedArgs, Plugin, Primitive, ReturnSuccess, Tag, Tagged, TaggedDictBuilder,
|
||||
TaggedItem, Value,
|
||||
};
|
||||
use num_bigint::BigInt;
|
||||
|
||||
struct CallStub {
|
||||
anchor: uuid::Uuid,
|
||||
positionals: Vec<Tagged<Value>>,
|
||||
flags: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
@ -230,7 +227,6 @@ mod tests {
|
||||
impl CallStub {
|
||||
fn new() -> CallStub {
|
||||
CallStub {
|
||||
anchor: uuid::Uuid::nil(),
|
||||
positionals: vec![],
|
||||
flags: indexmap::IndexMap::new(),
|
||||
}
|
||||
@ -247,19 +243,18 @@ mod tests {
|
||||
fn with_parameter(&mut self, name: &str) -> &mut Self {
|
||||
let fields: Vec<Tagged<Value>> = name
|
||||
.split(".")
|
||||
.map(|s| Value::string(s.to_string()).tagged(Tag::unknown_span(self.anchor)))
|
||||
.map(|s| Value::string(s.to_string()).tagged(Tag::unknown()))
|
||||
.collect();
|
||||
|
||||
self.positionals
|
||||
.push(Value::Table(fields).tagged(Tag::unknown_span(self.anchor)));
|
||||
.push(Value::Table(fields).tagged(Tag::unknown()));
|
||||
self
|
||||
}
|
||||
|
||||
fn create(&self) -> CallInfo {
|
||||
CallInfo {
|
||||
args: EvaluatedArgs::new(Some(self.positionals.clone()), Some(self.flags.clone())),
|
||||
source_map: SourceMap::new(),
|
||||
name_tag: Tag::unknown_span(self.anchor),
|
||||
name_tag: Tag::unknown(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -271,7 +266,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn unstructured_sample_record(value: &str) -> Tagged<Value> {
|
||||
Tagged::from_item(Value::string(value), Tag::unknown())
|
||||
Value::string(value).tagged(Tag::unknown())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -21,7 +21,7 @@ impl Sum {
|
||||
tag,
|
||||
}) => {
|
||||
//TODO: handle overflow
|
||||
self.total = Some(Value::int(i + j).tagged(*tag));
|
||||
self.total = Some(Value::int(i + j).tagged(tag));
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
@ -36,7 +36,7 @@ impl Sum {
|
||||
}
|
||||
}
|
||||
Value::Primitive(Primitive::Bytes(b)) => {
|
||||
match self.total {
|
||||
match &self.total {
|
||||
Some(Tagged {
|
||||
item: Value::Primitive(Primitive::Bytes(j)),
|
||||
tag,
|
||||
|
@ -80,7 +80,7 @@ async fn mem(tag: Tag) -> Tagged<Value> {
|
||||
}
|
||||
|
||||
async fn host(tag: Tag) -> Tagged<Value> {
|
||||
let mut dict = TaggedDictBuilder::with_capacity(tag, 6);
|
||||
let mut dict = TaggedDictBuilder::with_capacity(&tag, 6);
|
||||
|
||||
let (platform_result, uptime_result) =
|
||||
futures::future::join(host::platform(), host::uptime()).await;
|
||||
@ -95,7 +95,7 @@ async fn host(tag: Tag) -> Tagged<Value> {
|
||||
|
||||
// Uptime
|
||||
if let Ok(uptime) = uptime_result {
|
||||
let mut uptime_dict = TaggedDictBuilder::with_capacity(tag, 4);
|
||||
let mut uptime_dict = TaggedDictBuilder::with_capacity(&tag, 4);
|
||||
|
||||
let uptime = uptime.get::<time::second>().round() as i64;
|
||||
let days = uptime / (60 * 60 * 24);
|
||||
@ -116,7 +116,10 @@ async fn host(tag: Tag) -> Tagged<Value> {
|
||||
let mut user_vec = vec![];
|
||||
while let Some(user) = users.next().await {
|
||||
if let Ok(user) = user {
|
||||
user_vec.push(Tagged::from_item(Value::string(user.username()), tag));
|
||||
user_vec.push(Tagged {
|
||||
item: Value::string(user.username()),
|
||||
tag: tag.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
let user_list = Value::Table(user_vec);
|
||||
@ -130,7 +133,7 @@ async fn disks(tag: Tag) -> Option<Value> {
|
||||
let mut partitions = disk::partitions_physical();
|
||||
while let Some(part) = partitions.next().await {
|
||||
if let Ok(part) = part {
|
||||
let mut dict = TaggedDictBuilder::with_capacity(tag, 6);
|
||||
let mut dict = TaggedDictBuilder::with_capacity(&tag, 6);
|
||||
dict.insert(
|
||||
"device",
|
||||
Value::string(
|
||||
@ -176,7 +179,7 @@ async fn battery(tag: Tag) -> Option<Value> {
|
||||
if let Ok(batteries) = manager.batteries() {
|
||||
for battery in batteries {
|
||||
if let Ok(battery) = battery {
|
||||
let mut dict = TaggedDictBuilder::new(tag);
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
if let Some(vendor) = battery.vendor() {
|
||||
dict.insert("vendor", Value::string(vendor));
|
||||
}
|
||||
@ -217,7 +220,7 @@ async fn temp(tag: Tag) -> Option<Value> {
|
||||
let mut sensors = sensors::temperatures();
|
||||
while let Some(sensor) = sensors.next().await {
|
||||
if let Ok(sensor) = sensor {
|
||||
let mut dict = TaggedDictBuilder::new(tag);
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
dict.insert("unit", Value::string(sensor.unit()));
|
||||
if let Some(label) = sensor.label() {
|
||||
dict.insert("label", Value::string(label));
|
||||
@ -259,7 +262,7 @@ async fn net(tag: Tag) -> Option<Value> {
|
||||
let mut io_counters = net::io_counters();
|
||||
while let Some(nic) = io_counters.next().await {
|
||||
if let Ok(nic) = nic {
|
||||
let mut network_idx = TaggedDictBuilder::with_capacity(tag, 3);
|
||||
let mut network_idx = TaggedDictBuilder::with_capacity(&tag, 3);
|
||||
network_idx.insert("name", Value::string(nic.interface()));
|
||||
network_idx.insert(
|
||||
"sent",
|
||||
@ -280,11 +283,17 @@ async fn net(tag: Tag) -> Option<Value> {
|
||||
}
|
||||
|
||||
async fn sysinfo(tag: Tag) -> Vec<Tagged<Value>> {
|
||||
let mut sysinfo = TaggedDictBuilder::with_capacity(tag, 7);
|
||||
let mut sysinfo = TaggedDictBuilder::with_capacity(&tag, 7);
|
||||
|
||||
let (host, cpu, disks, memory, temp) =
|
||||
futures::future::join5(host(tag), cpu(tag), disks(tag), mem(tag), temp(tag)).await;
|
||||
let (net, battery) = futures::future::join(net(tag), battery(tag)).await;
|
||||
let (host, cpu, disks, memory, temp) = futures::future::join5(
|
||||
host(tag.clone()),
|
||||
cpu(tag.clone()),
|
||||
disks(tag.clone()),
|
||||
mem(tag.clone()),
|
||||
temp(tag.clone()),
|
||||
)
|
||||
.await;
|
||||
let (net, battery) = futures::future::join(net(tag.clone()), battery(tag.clone())).await;
|
||||
|
||||
sysinfo.insert_tagged("host", host);
|
||||
if let Some(cpu) = cpu {
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crossterm::{cursor, terminal, RawScreen};
|
||||
use crossterm::{InputEvent, KeyEvent};
|
||||
use nu::{
|
||||
serve_plugin, AnchorLocation, CallInfo, Plugin, Primitive, ShellError, Signature, SourceMap,
|
||||
Tagged, Value,
|
||||
serve_plugin, AnchorLocation, CallInfo, Plugin, Primitive, ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
use syntect::easy::HighlightLines;
|
||||
@ -29,8 +28,8 @@ impl Plugin for TextView {
|
||||
Ok(Signature::build("textview").desc("Autoview of text data."))
|
||||
}
|
||||
|
||||
fn sink(&mut self, call_info: CallInfo, input: Vec<Tagged<Value>>) {
|
||||
view_text_value(&input[0], &call_info.source_map);
|
||||
fn sink(&mut self, _call_info: CallInfo, input: Vec<Tagged<Value>>) {
|
||||
view_text_value(&input[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,20 +214,18 @@ fn scroll_view(s: &str) {
|
||||
scroll_view_lines_if_needed(v, false);
|
||||
}
|
||||
|
||||
fn view_text_value(value: &Tagged<Value>, source_map: &SourceMap) {
|
||||
fn view_text_value(value: &Tagged<Value>) {
|
||||
let value_anchor = value.anchor();
|
||||
match value.item {
|
||||
Value::Primitive(Primitive::String(ref s)) => {
|
||||
let source = source_map.get(&value_anchor);
|
||||
|
||||
if let Some(source) = source {
|
||||
if let Some(source) = value_anchor {
|
||||
let extension: Option<String> = match source {
|
||||
AnchorLocation::File(file) => {
|
||||
let path = Path::new(file);
|
||||
let path = Path::new(&file);
|
||||
path.extension().map(|x| x.to_string_lossy().to_string())
|
||||
}
|
||||
AnchorLocation::Url(url) => {
|
||||
let url = url::Url::parse(url);
|
||||
let url = url::Url::parse(&url);
|
||||
if let Ok(url) = url {
|
||||
let url = url.clone();
|
||||
if let Some(mut segments) = url.path_segments() {
|
||||
|
Reference in New Issue
Block a user