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:
Jonathan Turner
2019-10-13 17:12:43 +13:00
committed by GitHub
parent 8ca678440a
commit 193b00764b
110 changed files with 1988 additions and 1892 deletions

View File

@ -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,
))
}
},

View File

@ -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"));
}
_ => {}
}

View File

@ -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,
))
}
},

View File

@ -28,7 +28,7 @@ impl Embed {
None => Err(ShellError::labeled_error(
"embed needs a field when embedding a value",
"original value",
value.tag,
&tag,
)),
},
}

View File

@ -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()
}
}

View File

@ -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));

View File

@ -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]

View File

@ -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,

View File

@ -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 {

View File

@ -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() {