mirror of
https://github.com/nushell/nushell
synced 2024-12-29 06:23:11 +00:00
2fd4a36c0d
# Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> this PR makes nushell use mimalloc as the default allocator, this has the benefit of reducing startup time on my machine. `17%` on linux and `22%` on windows, when testing using hyperfine. the overhead to compile seem to be quite small, aswell as the increase of binary size quite small on linux the binary went from `33.1mb` to `33.2mb` linux ![image](https://github.com/nushell/nushell/assets/17986183/ba5379b4-2c08-483a-a9ff-a9d8524d2943) windows ![image](https://github.com/nushell/nushell/assets/17986183/fda5090f-96a9-48d1-ada4-617694b9d880) # 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. -->
295 lines
8.8 KiB
Rust
295 lines
8.8 KiB
Rust
mod command;
|
|
mod config_files;
|
|
mod ide;
|
|
mod logger;
|
|
mod run;
|
|
mod signals;
|
|
mod terminal;
|
|
mod test_bins;
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
#[cfg(feature = "mimalloc")]
|
|
#[global_allocator]
|
|
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
|
|
|
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::get_init_cwd;
|
|
use nu_protocol::{engine::EngineState, 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 get_engine_state() -> EngineState {
|
|
let engine_state = nu_cmd_lang::create_default_context();
|
|
let engine_state = nu_command::add_shell_command_context(engine_state);
|
|
#[cfg(feature = "extra")]
|
|
let engine_state = nu_cmd_extra::add_extra_command_context(engine_state);
|
|
#[cfg(feature = "dataframe")]
|
|
let engine_state = nu_cmd_dataframe::add_dataframe_context(engine_state);
|
|
let engine_state = nu_cli::add_cli_context(engine_state);
|
|
nu_explore::add_explore_context(engine_state)
|
|
}
|
|
|
|
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 = get_engine_state();
|
|
|
|
// 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 });
|
|
}
|
|
|
|
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 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,
|
|
);
|
|
|
|
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)
|
|
}
|
|
}
|