Add line ending autodetect to 'lines' (#589)

This commit is contained in:
JT 2021-12-27 10:11:18 +11:00 committed by GitHub
parent 39f03bf5e4
commit e1c92e90ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 18 deletions

View File

@ -7,8 +7,6 @@ use nu_protocol::{
#[derive(Clone)] #[derive(Clone)]
pub struct Lines; pub struct Lines;
const SPLIT_CHAR: char = '\n';
impl Command for Lines { impl Command for Lines {
fn name(&self) -> &str { fn name(&self) -> &str {
"lines" "lines"
@ -39,8 +37,10 @@ impl Command for Lines {
// the Rc structure to continue using it. If split could take ownership // the Rc structure to continue using it. If split could take ownership
// of the split values, then this wouldn't be needed // of the split values, then this wouldn't be needed
PipelineData::Value(Value::String { val, span }, ..) => { PipelineData::Value(Value::String { val, span }, ..) => {
let split_char = if val.contains("\r\n") { "\r\n" } else { "\n" };
let lines = val let lines = val
.split(SPLIT_CHAR) .split(split_char)
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
@ -55,12 +55,18 @@ impl Command for Lines {
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone())) Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
} }
PipelineData::ListStream(stream, ..) => { PipelineData::ListStream(stream, ..) => {
let mut split_char = "\n";
let iter = stream let iter = stream
.into_iter() .into_iter()
.filter_map(move |value| { .filter_map(move |value| {
if let Value::String { val, span } = value { if let Value::String { val, span } = value {
if split_char != "\r\n" && val.contains("\r\n") {
split_char = "\r\n";
}
let inner = val let inner = val
.split(SPLIT_CHAR) .split(split_char)
.filter_map(|s| { .filter_map(|s| {
if skip_empty && s.is_empty() { if skip_empty && s.is_empty() {
None None
@ -83,22 +89,29 @@ impl Command for Lines {
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone())) Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
} }
PipelineData::StringStream(stream, span, ..) => { PipelineData::StringStream(stream, span, ..) => {
let mut split_char = "\n";
let iter = stream let iter = stream
.into_iter() .into_iter()
.map(move |value| match value { .map(move |value| match value {
Ok(value) => value Ok(value) => {
.split(SPLIT_CHAR) if split_char != "\r\n" && value.contains("\r\n") {
.filter_map(|s| { split_char = "\r\n";
if !s.is_empty() { }
Some(Value::String { value
val: s.into(), .split(split_char)
span, .filter_map(|s| {
}) if !s.is_empty() {
} else { Some(Value::String {
None val: s.into(),
} span,
}) })
.collect::<Vec<Value>>(), } else {
None
}
})
.collect::<Vec<Value>>()
}
Err(err) => vec![Value::Error { error: err }], Err(err) => vec![Value::Error { error: err }],
}) })
.flatten(); .flatten();
@ -116,8 +129,10 @@ impl Command for Lines {
//know to use a different encoding //know to use a different encoding
let s = input.collect_string("", &config)?; let s = input.collect_string("", &config)?;
let split_char = if s.contains("\r\n") { "\r\n" } else { "\n" };
let lines = s let lines = s
.split(SPLIT_CHAR) .split(split_char)
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect::<Vec<String>>(); .collect::<Vec<String>>();

View File

@ -84,3 +84,8 @@ fn string_in_valuestream() -> TestResult {
fn single_tick_interpolation() -> TestResult { fn single_tick_interpolation() -> TestResult {
run_test(r#"$'(3 + 4)'"#, "7") run_test(r#"$'(3 + 4)'"#, "7")
} }
#[test]
fn detect_newlines() -> TestResult {
run_test("'hello\r\nworld' | lines | get 0 | str length", "5")
}