nushell/src/main.rs
Darren Schroeder fe60fb8679
resolve standard library before ide commands (#9126)
# Description

This PR moves loading the standard library before the ide commands are
executed in hopes that the standard library will no longer give check
errors. I'm not sure if this will be a big performance impact or not.
We'll have to try it and see.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-05-07 07:29:15 -05:00

281 lines
8.3 KiB
Rust

mod command;
mod config_files;
mod ide;
mod logger;
mod run;
mod signals;
mod terminal;
mod test_bins;
#[cfg(test)]
mod tests;
use crate::{
command::parse_commandline_args,
config_files::set_config_path,
logger::{configure, logger},
terminal::acquire_terminal,
};
use command::gather_commandline_args;
use log::Level;
use miette::Result;
use nu_cli::gather_parent_env_vars;
use nu_command::{create_default_context, get_init_cwd};
use nu_protocol::{report_error_new, Value};
use nu_protocol::{util::BufferedReader, PipelineData, RawStream};
use nu_std::load_standard_library;
use nu_utils::utils::perf;
use run::{run_commands, run_file, run_repl};
use signals::{ctrlc_protection, sigquit_protection};
use std::{
io::BufReader,
str::FromStr,
sync::{atomic::AtomicBool, Arc},
};
fn main() -> Result<()> {
let entire_start_time = std::time::Instant::now();
let mut start_time = std::time::Instant::now();
let miette_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |x| {
crossterm::terminal::disable_raw_mode().expect("unable to disable raw mode");
miette_hook(x);
}));
// Get initial current working directory.
let init_cwd = get_init_cwd();
let mut engine_state = nu_cli::add_cli_context(create_default_context());
// Custom additions
let delta = {
let mut working_set = nu_protocol::engine::StateWorkingSet::new(&engine_state);
working_set.add_decl(Box::new(nu_cli::NuHighlight));
working_set.add_decl(Box::new(nu_cli::Print));
working_set.render()
};
if let Err(err) = engine_state.merge_delta(delta) {
report_error_new(&engine_state, &err);
}
let ctrlc = Arc::new(AtomicBool::new(false));
// TODO: make this conditional in the future
ctrlc_protection(&mut engine_state, &ctrlc);
sigquit_protection(&mut engine_state);
let (args_to_nushell, script_name, args_to_script) = gather_commandline_args();
let parsed_nu_cli_args = parse_commandline_args(&args_to_nushell.join(" "), &mut engine_state)
.unwrap_or_else(|_| std::process::exit(1));
engine_state.is_interactive = parsed_nu_cli_args.interactive_shell.is_some();
engine_state.is_login = parsed_nu_cli_args.login_shell.is_some();
let use_color = engine_state.get_config().use_ansi_coloring;
if let Some(level) = parsed_nu_cli_args
.log_level
.as_ref()
.map(|level| level.item.clone())
{
let level = if Level::from_str(&level).is_ok() {
level
} else {
eprintln!(
"ERROR: log library did not recognize log level '{level}', using default 'info'"
);
"info".to_string()
};
let target = parsed_nu_cli_args
.log_target
.as_ref()
.map(|target| target.item.clone())
.unwrap_or_else(|| "stderr".to_string());
logger(|builder| configure(&level, &target, builder))?;
// info!("start logging {}:{}:{}", file!(), line!(), column!());
perf(
"start logging",
start_time,
file!(),
line!(),
column!(),
use_color,
);
}
start_time = std::time::Instant::now();
set_config_path(
&mut engine_state,
&init_cwd,
"config.nu",
"config-path",
&parsed_nu_cli_args.config_file,
);
set_config_path(
&mut engine_state,
&init_cwd,
"env.nu",
"env-path",
&parsed_nu_cli_args.env_file,
);
perf(
"set_config_path",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
// keep this condition in sync with the branches below
acquire_terminal(parsed_nu_cli_args.commands.is_none() && script_name.is_empty());
perf(
"acquire_terminal",
start_time,
file!(),
line!(),
column!(),
use_color,
);
if let Some(include_path) = &parsed_nu_cli_args.include_path {
let span = include_path.span;
let vals: Vec<_> = include_path
.item
.split('\x1e') // \x1e is the record separator character (a character that is unlikely to appear in a path)
.map(|x| Value::String {
val: x.trim().to_string(),
span,
})
.collect();
engine_state.add_env_var("NU_LIB_DIRS".into(), Value::List { vals, span });
}
if parsed_nu_cli_args.no_std_lib.is_none() {
load_standard_library(&mut engine_state)?;
}
// IDE commands
if let Some(ide_goto_def) = parsed_nu_cli_args.ide_goto_def {
ide::goto_def(&mut engine_state, &script_name, &ide_goto_def);
return Ok(());
} else if let Some(ide_hover) = parsed_nu_cli_args.ide_hover {
ide::hover(&mut engine_state, &script_name, &ide_hover);
return Ok(());
} else if let Some(ide_complete) = parsed_nu_cli_args.ide_complete {
let cwd = std::env::current_dir().expect("Could not get current working directory.");
engine_state.add_env_var("PWD".into(), Value::test_string(cwd.to_string_lossy()));
ide::complete(Arc::new(engine_state), &script_name, &ide_complete);
return Ok(());
} else if let Some(max_errors) = parsed_nu_cli_args.ide_check {
ide::check(&mut engine_state, &script_name, &max_errors);
return Ok(());
} else if parsed_nu_cli_args.ide_ast.is_some() {
ide::ast(&mut engine_state, &script_name);
return Ok(());
}
start_time = std::time::Instant::now();
if let Some(testbin) = &parsed_nu_cli_args.testbin {
// Call out to the correct testbin
match testbin.item.as_str() {
"echo_env" => test_bins::echo_env(true),
"echo_env_stderr" => test_bins::echo_env(false),
"cococo" => test_bins::cococo(),
"meow" => test_bins::meow(),
"meowb" => test_bins::meowb(),
"relay" => test_bins::relay(),
"iecho" => test_bins::iecho(),
"fail" => test_bins::fail(),
"nonu" => test_bins::nonu(),
"chop" => test_bins::chop(),
"repeater" => test_bins::repeater(),
"repeat_bytes" => test_bins::repeat_bytes(),
"nu_repl" => test_bins::nu_repl(),
"input_bytes_length" => test_bins::input_bytes_length(),
_ => std::process::exit(1),
}
std::process::exit(0)
}
perf(
"run test_bins",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
let input = if let Some(redirect_stdin) = &parsed_nu_cli_args.redirect_stdin {
let stdin = std::io::stdin();
let buf_reader = BufReader::new(stdin);
PipelineData::ExternalStream {
stdout: Some(RawStream::new(
Box::new(BufferedReader::new(buf_reader)),
Some(ctrlc),
redirect_stdin.span,
None,
)),
stderr: None,
exit_code: None,
span: redirect_stdin.span,
metadata: None,
trim_end_newline: false,
}
} else {
PipelineData::empty()
};
perf(
"redirect stdin",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
// First, set up env vars as strings only
gather_parent_env_vars(&mut engine_state, &init_cwd);
perf(
"gather env vars",
start_time,
file!(),
line!(),
column!(),
use_color,
);
if let Some(commands) = parsed_nu_cli_args.commands.clone() {
run_commands(
&mut engine_state,
parsed_nu_cli_args,
use_color,
&commands,
input,
entire_start_time,
)
} else if !script_name.is_empty() {
run_file(
&mut engine_state,
parsed_nu_cli_args,
use_color,
script_name,
args_to_script,
input,
)
} else {
engine_state.is_interactive = true;
run_repl(&mut engine_state, parsed_nu_cli_args, entire_start_time)
}
}