diff --git a/TODO.md b/TODO.md index 79ad75928..f16902de6 100644 --- a/TODO.md +++ b/TODO.md @@ -29,6 +29,7 @@ - [x] Value serialization - [x] Handling rows with missing columns during a cell path - [x] finish operator type-checking +- [x] Config file loading - [ ] Input/output types - [ ] Support for `$in` - [ ] ctrl-c support diff --git a/crates/nu-command/src/strings/size.rs b/crates/nu-command/src/strings/size.rs index b1e411cb4..245abdc75 100644 --- a/crates/nu-command/src/strings/size.rs +++ b/crates/nu-command/src/strings/size.rs @@ -1,13 +1,10 @@ extern crate unicode_segmentation; -use std::collections::HashMap; - -// use indexmap::indexmap; use unicode_segmentation::UnicodeSegmentation; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, Span, Spanned, Type, Value}; +use nu_protocol::{Example, ShellError, Signature, Span, Type, Value}; pub struct Size; @@ -33,32 +30,72 @@ impl Command for Size { size(context, call, input) } - // fn examples(&self) -> Vec { - // vec![ - // Example { - // description: "Count the number of words in a string", - // example: r#"echo "There are seven words in this sentence" | size"#, - // result: Some(vec![Value::row(indexmap! { - // "lines".to_string() => UntaggedValue::int(0).into(), - // "words".to_string() => UntaggedValue::int(7).into(), - // "chars".to_string() => UntaggedValue::int(38).into(), - // "bytes".to_string() => UntaggedValue::int(38).into(), - // }) - // .into()]), - // }, - // Example { - // description: "Counts Unicode characters correctly in a string", - // example: r#"echo "Amélie Amelie" | size"#, - // result: Some(vec![UntaggedValue::row(indexmap! { - // "lines".to_string() => UntaggedValue::int(0).into(), - // "words".to_string() => UntaggedValue::int(2).into(), - // "chars".to_string() => UntaggedValue::int(13).into(), - // "bytes".to_string() => UntaggedValue::int(15).into(), - // }) - // .into()]), - // }, - // ] - // } + fn examples(&self) -> Vec { + vec![ + Example { + description: "Count the number of words in a string", + example: r#""There are seven words in this sentence" | size"#, + result: Some(Value::Record { + cols: vec![ + "lines".into(), + "words".into(), + "chars".into(), + "bytes".into(), + ], + vals: vec![ + Value::Int { + val: 0, + span: Span::unknown(), + }, + Value::Int { + val: 7, + span: Span::unknown(), + }, + Value::Int { + val: 38, + span: Span::unknown(), + }, + Value::Int { + val: 38, + span: Span::unknown(), + }, + ], + span: Span::unknown(), + }), + }, + Example { + description: "Counts Unicode characters correctly in a string", + example: r#""Amélie Amelie" | size"#, + result: Some(Value::Record { + cols: vec![ + "lines".into(), + "words".into(), + "chars".into(), + "bytes".into(), + ], + vals: vec![ + Value::Int { + val: 0, + span: Span::unknown(), + }, + Value::Int { + val: 2, + span: Span::unknown(), + }, + Value::Int { + val: 13, + span: Span::unknown(), + }, + Value::Int { + val: 15, + span: Span::unknown(), + }, + ], + span: Span::unknown(), + }), + }, + ] + } } fn size(_context: &EvaluationContext, call: &Call, input: Value) -> Result { @@ -100,24 +137,32 @@ fn count(contents: &str, span: Span) -> Value { } } - let mut item: HashMap = HashMap::new(); - item.insert("lines".to_string(), Value::Int { val: lines, span }); - item.insert("words".to_string(), Value::Int { val: words, span }); - item.insert("chars".to_string(), Value::Int { val: chars, span }); - item.insert("bytes".to_string(), Value::Int { val: bytes, span }); + let mut cols = vec![]; + let mut vals = vec![]; - Value::from(Spanned { item, span }) + cols.push("lines".into()); + vals.push(Value::Int { val: lines, span }); + + cols.push("words".into()); + vals.push(Value::Int { val: words, span }); + + cols.push("chars".into()); + vals.push(Value::Int { val: chars, span }); + + cols.push("bytes".into()); + vals.push(Value::Int { val: bytes, span }); + + Value::Record { cols, vals, span } } -// #[cfg(test)] -// mod tests { -// use super::ShellError; -// use super::Size; +#[cfg(test)] +mod test { + use super::*; -// #[test] -// fn examples_work_as_expected() -> Result<(), ShellError> { -// use crate::examples::test as test_examples; + #[test] + fn test_examples() { + use crate::test_examples; -// test_examples(Size {}) -// } -// } + test_examples(Size {}) + } +} diff --git a/crates/nu-path/src/helpers.rs b/crates/nu-path/src/helpers.rs new file mode 100644 index 000000000..eaab1958c --- /dev/null +++ b/crates/nu-path/src/helpers.rs @@ -0,0 +1,9 @@ +use std::path::PathBuf; + +pub fn home_dir() -> Option { + dirs_next::home_dir() +} + +pub fn config_dir() -> Option { + dirs_next::config_dir() +} diff --git a/crates/nu-path/src/lib.rs b/crates/nu-path/src/lib.rs index 9606bc15c..5cd1edf1c 100644 --- a/crates/nu-path/src/lib.rs +++ b/crates/nu-path/src/lib.rs @@ -1,8 +1,10 @@ mod dots; mod expansions; +mod helpers; mod tilde; mod util; pub use expansions::{canonicalize, canonicalize_with, expand_path, expand_path_with}; +pub use helpers::{config_dir, home_dir}; pub use tilde::expand_tilde; pub use util::trim_trailing_slash; diff --git a/src/main.rs b/src/main.rs index 731c65bf1..0ca6f3b04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -91,6 +91,23 @@ fn main() -> Result<()> { let mut nu_prompt = NushellPrompt::new(); let stack = nu_protocol::engine::Stack::new(); + // Load config startup file + if let Some(mut config_path) = nu_path::config_dir() { + config_path.push("nushell"); + config_path.push("config.nu"); + + // FIXME: remove this message when we're ready + println!("Loading config from: {:?}", config_path); + + if config_path.exists() { + let config_filename = config_path.to_string_lossy().to_owned(); + + if let Ok(contents) = std::fs::read_to_string(&config_path) { + eval_source(engine_state.clone(), &stack, &contents, &config_filename); + } + } + } + loop { let prompt = update_prompt( PROMPT_COMMAND, @@ -124,45 +141,12 @@ fn main() -> Result<()> { continue; } - let (block, delta) = { - let engine_state = engine_state.borrow(); - let mut working_set = StateWorkingSet::new(&*engine_state); - let (output, err) = parse( - &mut working_set, - Some(&format!("entry #{}", entry_num)), - s.as_bytes(), - false, - ); - if let Some(err) = err { - report_error(&working_set, &err); - continue; - } - (output, working_set.render()) - }; - - EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); - - let state = nu_protocol::engine::EvaluationContext { - engine_state: engine_state.clone(), - stack: stack.clone(), - }; - - match eval_block(&state, &block, Value::nothing()) { - Ok(value) => { - if let Err(err) = print_value(value, &state) { - let engine_state = engine_state.borrow(); - let working_set = StateWorkingSet::new(&*engine_state); - - report_error(&working_set, &err); - } - } - Err(err) => { - let engine_state = engine_state.borrow(); - let working_set = StateWorkingSet::new(&*engine_state); - - report_error(&working_set, &err); - } - } + eval_source( + engine_state.clone(), + &stack, + &s, + &format!("entry #{}", entry_num), + ); } Ok(Signal::CtrlC) => { println!("Ctrl-c"); @@ -267,3 +251,54 @@ fn update_prompt<'prompt>( nu_prompt as &dyn Prompt } + +fn eval_source( + engine_state: Rc>, + stack: &Stack, + source: &str, + fname: &str, +) -> bool { + let (block, delta) = { + let engine_state = engine_state.borrow(); + let mut working_set = StateWorkingSet::new(&*engine_state); + let (output, err) = parse( + &mut working_set, + Some(fname), // format!("entry #{}", entry_num) + source.as_bytes(), + false, + ); + if let Some(err) = err { + report_error(&working_set, &err); + return false; + } + (output, working_set.render()) + }; + + EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); + + let state = nu_protocol::engine::EvaluationContext { + engine_state: engine_state.clone(), + stack: stack.clone(), + }; + + match eval_block(&state, &block, Value::nothing()) { + Ok(value) => { + if let Err(err) = print_value(value, &state) { + let engine_state = engine_state.borrow(); + let working_set = StateWorkingSet::new(&*engine_state); + + report_error(&working_set, &err); + return false; + } + } + Err(err) => { + let engine_state = engine_state.borrow(); + let working_set = StateWorkingSet::new(&*engine_state); + + report_error(&working_set, &err); + return false; + } + } + + true +}