2021-01-06 18:47:36 +01:00
|
|
|
use crate::line_editor::configure_ctrl_c;
|
2021-04-09 18:38:56 +02:00
|
|
|
use nu_ansi_term::Color;
|
2021-04-04 07:14:58 +02:00
|
|
|
use nu_engine::{maybe_print_errors, run_block, script::run_script_standalone, EvaluationContext};
|
2020-12-31 00:38:31 +01:00
|
|
|
|
|
|
|
#[allow(unused_imports)]
|
2021-03-12 06:20:54 +01:00
|
|
|
pub(crate) use nu_engine::script::{process_script, LineResult};
|
2020-12-31 00:38:31 +01:00
|
|
|
|
2020-09-17 08:02:30 +02:00
|
|
|
#[cfg(feature = "rustyline-support")]
|
2021-01-06 18:47:36 +01:00
|
|
|
use crate::line_editor::{
|
|
|
|
configure_rustyline_editor, convert_rustyline_result_to_string,
|
|
|
|
default_rustyline_editor_configuration, nu_line_editor_helper,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
use nu_data::config;
|
2021-03-31 07:52:34 +02:00
|
|
|
use nu_source::{Tag, Text};
|
2021-01-06 18:47:36 +01:00
|
|
|
use nu_stream::InputStream;
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
use std::sync::atomic::Ordering;
|
|
|
|
|
|
|
|
#[cfg(feature = "rustyline-support")]
|
|
|
|
use rustyline::{self, error::ReadlineError};
|
|
|
|
|
2020-09-17 01:22:58 +02:00
|
|
|
use nu_errors::ShellError;
|
2020-12-18 08:53:49 +01:00
|
|
|
use nu_parser::ParserScope;
|
2021-04-04 07:14:58 +02:00
|
|
|
use nu_protocol::{hir::ExternalRedirection, ConfigPath, UntaggedValue, Value};
|
2020-12-05 05:12:42 +01:00
|
|
|
|
2021-02-20 14:37:14 +01:00
|
|
|
use log::trace;
|
2021-04-04 07:14:58 +02:00
|
|
|
use std::error::Error;
|
2019-05-24 09:29:16 +02:00
|
|
|
use std::iter::Iterator;
|
2020-12-31 00:38:31 +01:00
|
|
|
use std::path::PathBuf;
|
2019-05-23 06:30:43 +02:00
|
|
|
|
2020-08-27 09:57:40 +02:00
|
|
|
pub fn search_paths() -> Vec<std::path::PathBuf> {
|
2020-03-04 19:58:20 +01:00
|
|
|
use std::env;
|
2019-07-04 05:06:43 +02:00
|
|
|
|
2020-03-04 19:58:20 +01:00
|
|
|
let mut search_paths = Vec::new();
|
2019-09-13 01:49:29 +02:00
|
|
|
|
2020-03-04 19:58:20 +01:00
|
|
|
// Automatically add path `nu` is in as a search path
|
|
|
|
if let Ok(exe_path) = env::current_exe() {
|
|
|
|
if let Some(exe_dir) = exe_path.parent() {
|
|
|
|
search_paths.push(exe_dir.to_path_buf());
|
2019-09-13 01:49:29 +02:00
|
|
|
}
|
2019-08-27 03:46:38 +02:00
|
|
|
}
|
2019-07-03 19:37:09 +02:00
|
|
|
|
2020-08-18 09:00:02 +02:00
|
|
|
if let Ok(config) = nu_data::config::config(Tag::unknown()) {
|
2021-02-12 11:13:14 +01:00
|
|
|
if let Some(Value {
|
|
|
|
value: UntaggedValue::Table(pipelines),
|
|
|
|
..
|
|
|
|
}) = config.get("plugin_dirs")
|
|
|
|
{
|
|
|
|
for pipeline in pipelines {
|
|
|
|
if let Ok(plugin_dir) = pipeline.as_string() {
|
|
|
|
search_paths.push(PathBuf::from(plugin_dir));
|
2020-05-28 21:14:32 +02:00
|
|
|
}
|
2019-11-10 04:44:05 +01:00
|
|
|
}
|
|
|
|
}
|
2019-09-12 05:20:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
search_paths
|
|
|
|
}
|
|
|
|
|
2021-06-16 00:43:25 +02:00
|
|
|
pub fn run_script_file(
|
|
|
|
context: EvaluationContext,
|
|
|
|
options: super::app::CliOptions,
|
|
|
|
) -> Result<(), ShellError> {
|
2021-03-31 07:52:34 +02:00
|
|
|
if let Some(cfg) = options.config {
|
2021-04-06 18:19:43 +02:00
|
|
|
load_cfg_as_global_cfg(&context, PathBuf::from(cfg));
|
2021-03-31 07:52:34 +02:00
|
|
|
} else {
|
2021-04-06 18:19:43 +02:00
|
|
|
load_global_cfg(&context);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2020-09-17 01:22:58 +02:00
|
|
|
|
2021-03-31 07:52:34 +02:00
|
|
|
let _ = register_plugins(&context);
|
|
|
|
let _ = configure_ctrl_c(&context);
|
2020-04-15 19:50:35 +02:00
|
|
|
|
2021-04-04 07:14:58 +02:00
|
|
|
let script = options
|
|
|
|
.scripts
|
|
|
|
.get(0)
|
|
|
|
.ok_or_else(|| ShellError::unexpected("Nu source code not available"))?;
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
run_script_standalone(script.get_code().to_string(), options.stdin, &context, true)?;
|
2020-02-09 03:24:33 +01:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-09-17 08:02:30 +02:00
|
|
|
#[cfg(feature = "rustyline-support")]
|
2021-06-16 00:43:25 +02:00
|
|
|
pub fn cli(
|
|
|
|
context: EvaluationContext,
|
|
|
|
options: super::app::CliOptions,
|
|
|
|
) -> Result<(), Box<dyn Error>> {
|
2021-03-31 07:52:34 +02:00
|
|
|
let _ = configure_ctrl_c(&context);
|
2020-07-22 23:43:52 +02:00
|
|
|
|
2021-03-31 07:52:34 +02:00
|
|
|
// start time for running startup scripts (this metric includes loading of the cfg, but w/e)
|
2021-02-20 14:37:14 +01:00
|
|
|
let startup_commands_start_time = std::time::Instant::now();
|
2021-03-31 07:52:34 +02:00
|
|
|
|
|
|
|
if let Some(cfg) = options.config {
|
2021-04-06 18:19:43 +02:00
|
|
|
load_cfg_as_global_cfg(&context, PathBuf::from(cfg));
|
2021-03-31 07:52:34 +02:00
|
|
|
} else {
|
2021-04-06 18:19:43 +02:00
|
|
|
load_global_cfg(&context);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2021-02-20 14:37:14 +01:00
|
|
|
// Store cmd duration in an env var
|
|
|
|
context.scope.add_env_var(
|
2021-06-08 23:14:38 +02:00
|
|
|
"CMD_DURATION_MS",
|
|
|
|
format!("{}", startup_commands_start_time.elapsed().as_millis()),
|
2021-02-20 14:37:14 +01:00
|
|
|
);
|
|
|
|
trace!(
|
|
|
|
"startup commands took {:?}",
|
|
|
|
startup_commands_start_time.elapsed()
|
|
|
|
);
|
2020-08-27 13:06:25 +02:00
|
|
|
|
2021-03-31 07:52:34 +02:00
|
|
|
//Configure rustyline
|
|
|
|
let mut rl = default_rustyline_editor_configuration();
|
2021-06-14 05:19:12 +02:00
|
|
|
let history_path = if let Some(cfg) = &context.configs().lock().global_config {
|
2021-03-31 07:52:34 +02:00
|
|
|
let _ = configure_rustyline_editor(&mut rl, cfg);
|
|
|
|
let helper = Some(nu_line_editor_helper(&context, cfg));
|
|
|
|
rl.set_helper(helper);
|
2021-04-09 08:03:12 +02:00
|
|
|
nu_data::config::path::history_path_or_default(cfg)
|
2021-03-31 07:52:34 +02:00
|
|
|
} else {
|
|
|
|
nu_data::config::path::default_history_path()
|
|
|
|
};
|
|
|
|
|
|
|
|
// Don't load history if it's not necessary
|
|
|
|
if options.save_history {
|
|
|
|
let _ = rl.load_history(&history_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
//set vars from cfg if present
|
2021-06-14 05:19:12 +02:00
|
|
|
let (skip_welcome_message, prompt) = if let Some(cfg) = &context.configs().lock().global_config
|
|
|
|
{
|
2021-03-31 07:52:34 +02:00
|
|
|
(
|
|
|
|
cfg.var("skip_welcome_message")
|
|
|
|
.map(|x| x.is_true())
|
|
|
|
.unwrap_or(false),
|
|
|
|
cfg.var("prompt"),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(false, None)
|
|
|
|
};
|
|
|
|
|
|
|
|
//Check whether dir we start in contains local cfg file and if so load it.
|
2021-04-06 18:19:43 +02:00
|
|
|
load_local_cfg_if_present(&context);
|
2021-03-31 07:52:34 +02:00
|
|
|
|
2020-12-18 08:53:49 +01:00
|
|
|
// Give ourselves a scope to work in
|
|
|
|
context.scope.enter_scope();
|
|
|
|
|
|
|
|
let mut session_text = String::new();
|
|
|
|
let mut line_start: usize = 0;
|
|
|
|
|
2020-08-09 01:38:21 +02:00
|
|
|
if !skip_welcome_message {
|
|
|
|
println!(
|
|
|
|
"Welcome to Nushell {} (type 'help' for more info)",
|
2021-06-19 02:06:44 +02:00
|
|
|
nu_command::commands::core_version()
|
2020-08-09 01:38:21 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-05-26 08:54:41 +02:00
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
2021-02-22 19:33:34 +01:00
|
|
|
let _ = nu_ansi_term::enable_ansi_support();
|
2019-05-26 08:54:41 +02:00
|
|
|
}
|
|
|
|
|
2019-06-15 20:36:17 +02:00
|
|
|
let mut ctrlcbreak = false;
|
2020-04-15 07:43:23 +02:00
|
|
|
|
2019-05-23 06:30:43 +02:00
|
|
|
loop {
|
2021-06-14 05:19:12 +02:00
|
|
|
if context.ctrl_c().load(Ordering::SeqCst) {
|
|
|
|
context.ctrl_c().store(false, Ordering::SeqCst);
|
2019-06-07 02:31:22 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-06-14 05:19:12 +02:00
|
|
|
let cwd = context.shell_manager().path();
|
2019-08-07 19:49:11 +02:00
|
|
|
|
2019-11-16 21:02:26 +01:00
|
|
|
let colored_prompt = {
|
2021-03-31 07:52:34 +02:00
|
|
|
if let Some(prompt) = &prompt {
|
2020-06-27 00:37:31 +02:00
|
|
|
let prompt_line = prompt.as_string()?;
|
|
|
|
|
2020-12-18 08:53:49 +01:00
|
|
|
context.scope.enter_scope();
|
2021-04-21 22:54:34 +02:00
|
|
|
let (prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
|
2020-11-09 17:27:07 +01:00
|
|
|
|
|
|
|
if err.is_some() {
|
2020-12-18 08:53:49 +01:00
|
|
|
context.scope.exit_scope();
|
|
|
|
|
2021-04-09 18:38:56 +02:00
|
|
|
format!(
|
|
|
|
"{}{}{}{}{}{}> ",
|
|
|
|
Color::Green.bold().prefix().to_string(),
|
|
|
|
cwd,
|
|
|
|
nu_ansi_term::ansi::RESET,
|
|
|
|
Color::Cyan.bold().prefix().to_string(),
|
|
|
|
current_branch(),
|
|
|
|
nu_ansi_term::ansi::RESET
|
|
|
|
)
|
2020-11-09 17:27:07 +01:00
|
|
|
} else {
|
2021-04-21 22:54:34 +02:00
|
|
|
let run_result = run_block(
|
|
|
|
&prompt_block,
|
|
|
|
&context,
|
|
|
|
InputStream::empty(),
|
|
|
|
ExternalRedirection::Stdout,
|
|
|
|
);
|
2020-12-18 08:53:49 +01:00
|
|
|
context.scope.exit_scope();
|
2020-06-28 23:06:05 +02:00
|
|
|
|
2020-12-18 08:53:49 +01:00
|
|
|
match run_result {
|
2021-04-06 18:19:43 +02:00
|
|
|
Ok(result) => match result.collect_string(Tag::unknown()) {
|
2020-11-09 17:27:07 +01:00
|
|
|
Ok(string_result) => {
|
|
|
|
let errors = context.get_errors();
|
2021-03-31 07:52:34 +02:00
|
|
|
maybe_print_errors(&context, Text::from(prompt_line));
|
2020-11-09 17:27:07 +01:00
|
|
|
context.clear_errors();
|
|
|
|
|
|
|
|
if !errors.is_empty() {
|
2020-06-28 23:06:05 +02:00
|
|
|
"> ".to_string()
|
2020-11-09 17:27:07 +01:00
|
|
|
} else {
|
|
|
|
string_result.item
|
2020-06-27 00:37:31 +02:00
|
|
|
}
|
2020-11-09 17:27:07 +01:00
|
|
|
}
|
2020-06-28 23:06:05 +02:00
|
|
|
Err(e) => {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(e, &Text::from(prompt_line));
|
2020-06-28 23:06:05 +02:00
|
|
|
context.clear_errors();
|
|
|
|
|
|
|
|
"> ".to_string()
|
2020-06-27 00:37:31 +02:00
|
|
|
}
|
2020-11-09 17:27:07 +01:00
|
|
|
},
|
|
|
|
Err(e) => {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(e, &Text::from(prompt_line));
|
2020-11-09 17:27:07 +01:00
|
|
|
context.clear_errors();
|
2020-06-27 00:37:31 +02:00
|
|
|
|
2020-11-09 17:27:07 +01:00
|
|
|
"> ".to_string()
|
|
|
|
}
|
2020-06-27 00:37:31 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-25 07:44:55 +02:00
|
|
|
} else {
|
2021-04-09 18:38:56 +02:00
|
|
|
format!(
|
|
|
|
"{}{}{}{}{}{}> ",
|
|
|
|
Color::Green.bold().prefix().to_string(),
|
|
|
|
cwd,
|
|
|
|
nu_ansi_term::ansi::RESET,
|
|
|
|
Color::Cyan.bold().prefix().to_string(),
|
|
|
|
current_branch(),
|
|
|
|
nu_ansi_term::ansi::RESET
|
|
|
|
)
|
2019-10-08 15:47:30 +02:00
|
|
|
}
|
|
|
|
};
|
2019-11-16 21:02:26 +01:00
|
|
|
|
2021-03-04 18:22:14 +01:00
|
|
|
let prompt = {
|
|
|
|
if let Ok(bytes) = strip_ansi_escapes::strip(&colored_prompt) {
|
|
|
|
String::from_utf8_lossy(&bytes).to_string()
|
|
|
|
} else {
|
|
|
|
"> ".to_string()
|
2020-01-01 21:45:32 +01:00
|
|
|
}
|
2019-11-16 21:42:35 +01:00
|
|
|
};
|
|
|
|
|
2021-05-04 05:50:38 +02:00
|
|
|
if let Some(helper) = rl.helper_mut() {
|
|
|
|
helper.colored_prompt = colored_prompt;
|
|
|
|
}
|
2019-09-18 00:21:39 +02:00
|
|
|
let mut initial_command = Some(String::new());
|
|
|
|
let mut readline = Err(ReadlineError::Eof);
|
|
|
|
while let Some(ref cmd) = initial_command {
|
2021-06-09 21:08:12 +02:00
|
|
|
readline = rl.readline_with_initial(&prompt, (cmd, ""));
|
2019-11-22 09:25:09 +01:00
|
|
|
initial_command = None;
|
2019-09-18 00:21:39 +02:00
|
|
|
}
|
2019-05-23 06:30:43 +02:00
|
|
|
|
2020-12-18 08:53:49 +01:00
|
|
|
if let Ok(line) = &readline {
|
|
|
|
line_start = session_text.len();
|
|
|
|
session_text.push_str(line);
|
|
|
|
session_text.push('\n');
|
|
|
|
}
|
|
|
|
|
2021-02-20 14:37:14 +01:00
|
|
|
// start time for command duration
|
|
|
|
let cmd_start_time = std::time::Instant::now();
|
|
|
|
|
2020-09-17 08:02:30 +02:00
|
|
|
let line = match convert_rustyline_result_to_string(readline) {
|
2021-04-06 18:19:43 +02:00
|
|
|
LineResult::Success(_) => process_script(
|
|
|
|
&session_text[line_start..],
|
|
|
|
&context,
|
|
|
|
false,
|
|
|
|
line_start,
|
|
|
|
true,
|
|
|
|
),
|
2020-09-17 08:02:30 +02:00
|
|
|
x => x,
|
|
|
|
};
|
2019-11-04 16:47:03 +01:00
|
|
|
|
2021-02-20 14:37:14 +01:00
|
|
|
// Store cmd duration in an env var
|
2021-06-08 23:14:38 +02:00
|
|
|
context.scope.add_env_var(
|
|
|
|
"CMD_DURATION_MS",
|
|
|
|
format!("{}", cmd_start_time.elapsed().as_millis()),
|
|
|
|
);
|
2021-02-20 14:37:14 +01:00
|
|
|
|
2019-11-04 16:47:03 +01:00
|
|
|
match line {
|
2019-05-23 06:30:43 +02:00
|
|
|
LineResult::Success(line) => {
|
2021-04-09 02:01:31 +02:00
|
|
|
if options.save_history && !line.trim().is_empty() {
|
2021-03-27 06:08:03 +01:00
|
|
|
rl.add_history_entry(&line);
|
2021-04-14 20:20:25 +02:00
|
|
|
let _ = rl.append_history(&history_path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
maybe_print_errors(&context, Text::from(session_text.clone()));
|
2019-11-04 16:47:03 +01:00
|
|
|
}
|
|
|
|
|
2020-11-09 17:23:41 +01:00
|
|
|
LineResult::ClearHistory => {
|
2021-03-31 07:52:34 +02:00
|
|
|
if options.save_history {
|
2021-03-27 06:08:03 +01:00
|
|
|
rl.clear_history();
|
2021-04-14 20:20:25 +02:00
|
|
|
let _ = rl.append_history(&history_path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2020-11-09 17:23:41 +01:00
|
|
|
}
|
|
|
|
|
2021-03-31 07:52:34 +02:00
|
|
|
LineResult::Error(line, err) => {
|
2021-04-09 02:01:31 +02:00
|
|
|
if options.save_history && !line.trim().is_empty() {
|
2021-03-27 06:08:03 +01:00
|
|
|
rl.add_history_entry(&line);
|
2021-04-14 20:20:25 +02:00
|
|
|
let _ = rl.append_history(&history_path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2019-11-04 16:47:03 +01:00
|
|
|
|
2021-03-31 07:52:34 +02:00
|
|
|
context
|
2021-06-14 05:19:12 +02:00
|
|
|
.host()
|
2021-03-31 07:52:34 +02:00
|
|
|
.lock()
|
|
|
|
.print_err(err, &Text::from(session_text.clone()));
|
|
|
|
|
|
|
|
// I am not so sure, we don't need maybe_print_errors here (as we printed an err
|
|
|
|
// above), because maybe_print_errors also clears the errors.
|
|
|
|
// TODO Analyze where above err comes from, and whether we need to clear
|
|
|
|
// context.errors here
|
|
|
|
// Or just be consistent and return errors always in context.errors...
|
|
|
|
maybe_print_errors(&context, Text::from(session_text.clone()));
|
2019-05-23 06:30:43 +02:00
|
|
|
}
|
|
|
|
|
2019-06-15 20:36:17 +02:00
|
|
|
LineResult::CtrlC => {
|
2021-03-31 07:52:34 +02:00
|
|
|
let config_ctrlc_exit = context
|
2021-06-14 05:19:12 +02:00
|
|
|
.configs()
|
2021-03-31 07:52:34 +02:00
|
|
|
.lock()
|
|
|
|
.global_config
|
|
|
|
.as_ref()
|
|
|
|
.map(|cfg| cfg.var("ctrlc_exit"))
|
|
|
|
.flatten()
|
|
|
|
.map(|ctrl_c| ctrl_c.is_true())
|
2019-09-25 03:01:38 +02:00
|
|
|
.unwrap_or(false); // default behavior is to allow CTRL-C spamming similar to other shells
|
|
|
|
|
|
|
|
if !config_ctrlc_exit {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-15 20:36:17 +02:00
|
|
|
if ctrlcbreak {
|
2021-03-31 07:52:34 +02:00
|
|
|
if options.save_history {
|
2021-04-14 20:20:25 +02:00
|
|
|
let _ = rl.append_history(&history_path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2019-06-15 20:36:17 +02:00
|
|
|
std::process::exit(0);
|
|
|
|
} else {
|
Restructure and streamline token expansion (#1123)
Restructure and streamline token expansion
The purpose of this commit is to streamline the token expansion code, by
removing aspects of the code that are no longer relevant, removing
pointless duplication, and eliminating the need to pass the same
arguments to `expand_syntax`.
The first big-picture change in this commit is that instead of a handful
of `expand_` functions, which take a TokensIterator and ExpandContext, a
smaller number of methods on the `TokensIterator` do the same job.
The second big-picture change in this commit is fully eliminating the
coloring traits, making coloring a responsibility of the base expansion
implementations. This also means that the coloring tracer is merged into
the expansion tracer, so you can follow a single expansion and see how
the expansion process produced colored tokens.
One side effect of this change is that the expander itself is marginally
more error-correcting. The error correction works by switching from
structured expansion to `BackoffColoringMode` when an unexpected token
is found, which guarantees that all spans of the source are colored, but
may not be the most optimal error recovery strategy.
That said, because `BackoffColoringMode` only extends as far as a
closing delimiter (`)`, `]`, `}`) or pipe (`|`), it does result in
fairly granular correction strategy.
The current code still produces an `Err` (plus a complete list of
colored shapes) from the parsing process if any errors are encountered,
but this could easily be addressed now that the underlying expansion is
error-correcting.
This commit also colors any spans that are syntax errors in red, and
causes the parser to include some additional information about what
tokens were expected at any given point where an error was encountered,
so that completions and hinting could be more robust in the future.
Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
Co-authored-by: Andrés N. Robalino <andres@androbtech.com>
2020-01-21 23:45:03 +01:00
|
|
|
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"));
|
2019-06-15 20:36:17 +02:00
|
|
|
ctrlcbreak = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-21 09:56:10 +02:00
|
|
|
LineResult::CtrlD => {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.shell_manager().remove_at_current();
|
|
|
|
if context.shell_manager().is_empty() {
|
2020-09-21 09:56:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-23 06:30:43 +02:00
|
|
|
LineResult::Break => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-06-15 20:36:17 +02:00
|
|
|
ctrlcbreak = false;
|
2019-05-23 06:30:43 +02:00
|
|
|
}
|
2019-08-27 00:41:57 +02:00
|
|
|
|
|
|
|
// we are ok if we can not save history
|
2021-03-31 07:52:34 +02:00
|
|
|
if options.save_history {
|
2021-04-14 20:20:25 +02:00
|
|
|
let _ = rl.append_history(&history_path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
2019-05-23 06:30:43 +02:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
pub fn load_local_cfg_if_present(context: &EvaluationContext) {
|
2021-03-31 07:52:34 +02:00
|
|
|
trace!("Loading local cfg if present");
|
2021-06-14 05:19:12 +02:00
|
|
|
match config::loadable_cfg_exists_in_dir(PathBuf::from(context.shell_manager().path())) {
|
2021-03-31 07:52:34 +02:00
|
|
|
Ok(Some(cfg_path)) => {
|
2021-04-06 18:19:43 +02:00
|
|
|
if let Err(err) = context.load_config(&ConfigPath::Local(cfg_path)) {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(err, &Text::from(""))
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
//Report error while checking for local cfg file
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(e, &Text::from(""))
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
Ok(None) => {
|
|
|
|
//No local cfg file present in start dir
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
fn load_cfg_as_global_cfg(context: &EvaluationContext, path: PathBuf) {
|
2021-04-09 08:03:12 +02:00
|
|
|
if let Err(err) = context.load_config(&ConfigPath::Global(path)) {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(err, &Text::from(""));
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
pub fn load_global_cfg(context: &EvaluationContext) {
|
2021-03-31 07:52:34 +02:00
|
|
|
match config::default_path() {
|
|
|
|
Ok(path) => {
|
2021-04-06 18:19:43 +02:00
|
|
|
load_cfg_as_global_cfg(context, path);
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
Err(e) => {
|
2021-06-14 05:19:12 +02:00
|
|
|
context.host().lock().print_err(e, &Text::from(""));
|
2021-03-31 07:52:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register_plugins(context: &EvaluationContext) -> Result<(), ShellError> {
|
2021-01-10 03:50:49 +01:00
|
|
|
if let Ok(plugins) = nu_engine::plugin::build_plugin::scan(search_paths()) {
|
2020-09-17 01:22:58 +02:00
|
|
|
context.add_commands(
|
|
|
|
plugins
|
|
|
|
.into_iter()
|
|
|
|
.filter(|p| !context.is_command_registered(p.name()))
|
|
|
|
.collect(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
pub fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<String, ShellError> {
|
2020-12-18 08:53:49 +01:00
|
|
|
// FIXME: do we still need this?
|
2020-11-22 01:37:16 +01:00
|
|
|
let line = if let Some(s) = line.strip_suffix('\n') {
|
|
|
|
s
|
2020-07-18 03:59:23 +02:00
|
|
|
} else {
|
|
|
|
line
|
|
|
|
};
|
|
|
|
|
2020-12-18 08:53:49 +01:00
|
|
|
// TODO ensure the command whose examples we're testing is actually in the pipeline
|
|
|
|
ctx.scope.enter_scope();
|
2021-06-09 21:08:12 +02:00
|
|
|
let (classified_block, err) = nu_parser::parse(line, 0, &ctx.scope);
|
2020-11-09 17:27:07 +01:00
|
|
|
if let Some(err) = err {
|
2020-12-18 08:53:49 +01:00
|
|
|
ctx.scope.exit_scope();
|
2020-11-09 17:27:07 +01:00
|
|
|
return Err(err.into());
|
|
|
|
}
|
2020-07-18 03:59:23 +02:00
|
|
|
|
|
|
|
let input_stream = InputStream::empty();
|
2020-12-18 08:53:49 +01:00
|
|
|
|
2021-04-21 22:54:34 +02:00
|
|
|
let result = run_block(
|
|
|
|
&classified_block,
|
|
|
|
ctx,
|
|
|
|
input_stream,
|
|
|
|
ExternalRedirection::Stdout,
|
|
|
|
);
|
2020-12-18 08:53:49 +01:00
|
|
|
ctx.scope.exit_scope();
|
2020-07-18 03:59:23 +02:00
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
result?.collect_string(Tag::unknown()).map(|x| x.item)
|
2020-07-18 03:59:23 +02:00
|
|
|
}
|
|
|
|
|
2021-01-15 19:06:29 +01:00
|
|
|
#[allow(dead_code)]
|
|
|
|
fn current_branch() -> String {
|
|
|
|
#[cfg(feature = "shadow-rs")]
|
|
|
|
{
|
|
|
|
Some(shadow_rs::branch())
|
|
|
|
.map(|x| x.trim().to_string())
|
|
|
|
.filter(|x| !x.is_empty())
|
|
|
|
.map(|x| format!("({})", x))
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "shadow-rs"))]
|
|
|
|
{
|
|
|
|
"".to_string()
|
|
|
|
}
|
|
|
|
}
|