2023-01-20 22:20:38 +01:00
|
|
|
mod command;
|
2022-01-18 09:48:28 +01:00
|
|
|
mod config_files;
|
2023-04-05 21:34:47 +02:00
|
|
|
mod ide;
|
2022-01-18 09:48:28 +01:00
|
|
|
mod logger;
|
2023-02-05 22:20:35 +01:00
|
|
|
mod run;
|
2023-01-20 19:44:49 +01:00
|
|
|
mod signals;
|
2023-01-20 22:20:38 +01:00
|
|
|
mod terminal;
|
2022-02-09 23:08:16 +01:00
|
|
|
mod test_bins;
|
2021-08-10 20:57:08 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2023-06-15 00:27:12 +02:00
|
|
|
#[cfg(feature = "mimalloc")]
|
|
|
|
#[global_allocator]
|
|
|
|
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
|
|
|
|
2023-01-20 22:20:38 +01:00
|
|
|
use crate::{
|
|
|
|
command::parse_commandline_args,
|
2023-02-05 22:20:35 +01:00
|
|
|
config_files::set_config_path,
|
2023-01-20 22:20:38 +01:00
|
|
|
logger::{configure, logger},
|
|
|
|
terminal::acquire_terminal,
|
|
|
|
};
|
2023-01-27 00:56:55 +01:00
|
|
|
use command::gather_commandline_args;
|
2023-01-24 21:28:59 +01:00
|
|
|
use log::Level;
|
2022-01-18 09:48:28 +01:00
|
|
|
use miette::Result;
|
2023-03-20 05:05:22 +01:00
|
|
|
use nu_cli::gather_parent_env_vars;
|
2023-06-23 21:23:08 +02:00
|
|
|
use nu_cmd_base::util::get_init_cwd;
|
2023-11-02 16:18:57 +01:00
|
|
|
use nu_lsp::LanguageServer;
|
2023-09-01 08:18:55 +02:00
|
|
|
use nu_protocol::{
|
|
|
|
engine::EngineState, eval_const::create_nu_constant, report_error_new, util::BufferedReader,
|
|
|
|
PipelineData, RawStream, Span, Value, NU_VARIABLE_ID,
|
|
|
|
};
|
2023-04-29 12:48:32 +02:00
|
|
|
use nu_std::load_standard_library;
|
2023-01-24 21:28:59 +01:00
|
|
|
use nu_utils::utils::perf;
|
2023-02-05 22:20:35 +01:00
|
|
|
use run::{run_commands, run_file, run_repl};
|
2023-12-21 17:00:38 +01:00
|
|
|
use signals::ctrlc_protection;
|
2022-01-26 15:42:39 +01:00
|
|
|
use std::{
|
2022-05-17 20:28:18 +02:00
|
|
|
io::BufReader,
|
2023-01-23 19:57:40 +01:00
|
|
|
str::FromStr,
|
2023-01-20 19:44:49 +01:00
|
|
|
sync::{atomic::AtomicBool, Arc},
|
2022-01-26 15:42:39 +01:00
|
|
|
};
|
2022-09-29 20:37:48 +02:00
|
|
|
|
2023-06-14 23:12:55 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-09-20 23:37:26 +02:00
|
|
|
fn main() -> Result<()> {
|
2023-01-24 21:28:59 +01:00
|
|
|
let entire_start_time = std::time::Instant::now();
|
|
|
|
let mut start_time = std::time::Instant::now();
|
2021-10-01 18:39:50 +02:00
|
|
|
let miette_hook = std::panic::take_hook();
|
|
|
|
std::panic::set_hook(Box::new(move |x| {
|
2021-12-04 13:38:21 +01:00
|
|
|
crossterm::terminal::disable_raw_mode().expect("unable to disable raw mode");
|
2021-10-01 18:39:50 +02:00
|
|
|
miette_hook(x);
|
|
|
|
}));
|
2021-09-21 21:37:16 +02:00
|
|
|
|
2022-01-04 23:30:34 +01:00
|
|
|
// Get initial current working directory.
|
2022-03-16 19:17:06 +01:00
|
|
|
let init_cwd = get_init_cwd();
|
2023-06-14 23:12:55 +02:00
|
|
|
let mut engine_state = get_engine_state();
|
2021-07-17 08:31:34 +02:00
|
|
|
|
2022-01-24 16:05:19 +01:00
|
|
|
// Custom additions
|
|
|
|
let delta = {
|
|
|
|
let mut working_set = nu_protocol::engine::StateWorkingSet::new(&engine_state);
|
|
|
|
working_set.add_decl(Box::new(nu_cli::NuHighlight));
|
2022-02-18 19:43:34 +01:00
|
|
|
working_set.add_decl(Box::new(nu_cli::Print));
|
2022-01-24 16:05:19 +01:00
|
|
|
working_set.render()
|
|
|
|
};
|
2022-07-14 16:09:27 +02:00
|
|
|
|
|
|
|
if let Err(err) = engine_state.merge_delta(delta) {
|
|
|
|
report_error_new(&engine_state, &err);
|
|
|
|
}
|
2022-01-24 16:05:19 +01:00
|
|
|
|
2021-10-28 06:13:10 +02:00
|
|
|
let ctrlc = Arc::new(AtomicBool::new(false));
|
2023-01-20 19:44:49 +01:00
|
|
|
// TODO: make this conditional in the future
|
|
|
|
ctrlc_protection(&mut engine_state, &ctrlc);
|
2022-06-09 14:08:15 +02:00
|
|
|
|
2023-12-07 15:13:50 +01:00
|
|
|
// Begin: Default NU_LIB_DIRS, NU_PLUGIN_DIRS
|
|
|
|
// Set default NU_LIB_DIRS and NU_PLUGIN_DIRS here before the env.nu is processed. If
|
|
|
|
// the env.nu file exists, these values will be overwritten, if it does not exist, or
|
|
|
|
// there is an error reading it, these values will be used.
|
|
|
|
let nushell_config_path = if let Some(mut path) = nu_path::config_dir() {
|
|
|
|
path.push("nushell");
|
|
|
|
path
|
|
|
|
} else {
|
|
|
|
// Not really sure what to default this to if nu_path::config_dir() returns None
|
|
|
|
std::path::PathBuf::new()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut default_nu_lib_dirs_path = nushell_config_path.clone();
|
|
|
|
default_nu_lib_dirs_path.push("scripts");
|
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_LIB_DIRS".to_string(),
|
|
|
|
Value::test_string(default_nu_lib_dirs_path.to_string_lossy()),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut default_nu_plugin_dirs_path = nushell_config_path;
|
|
|
|
default_nu_plugin_dirs_path.push("plugins");
|
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_PLUGIN_DIRS".to_string(),
|
|
|
|
Value::test_string(default_nu_plugin_dirs_path.to_string_lossy()),
|
|
|
|
);
|
|
|
|
// End: Default NU_LIB_DIRS, NU_PLUGIN_DIRS
|
|
|
|
|
Add `stor` family of commands (#11170)
# Description
This PR adds the `stor` family of commands. These commands are meant to
create, open, insert, update, delete, reset data in an in-memory sqlite
database. This is really an experiment to see how creatively we can use
an in-memory database.
```
Usage:
> stor
Subcommands:
stor create - Create a table in the in-memory sqlite database
stor delete - Delete a table or specified rows in the in-memory sqlite database
stor export - Export the in-memory sqlite database to a sqlite database file
stor import - Import a sqlite database file into the in-memory sqlite database
stor insert - Insert information into a specified table in the in-memory sqlite database
stor open - Opens the in-memory sqlite database
stor reset - Reset the in-memory database by dropping all tables
stor update - Update information in a specified table in the in-memory sqlite database
Flags:
-h, --help - Display the help message for this command
Input/output types:
╭─#─┬──input──┬─output─╮
│ 0 │ nothing │ string │
╰───┴─────────┴────────╯
```
### Examples
## stor create
```nushell
❯ stor create --table-name nudb --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭──────┬────────────────╮
│ nudb │ [list 0 items] │
╰──────┴────────────────╯
```
## stor insert
```nushell
❯ stor insert --table-name nudb --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
```
## stor open
```nushell
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
## stor update
```nushell
❯ stor update --table-name nudb --update-record {str1: toby datetime1: 2021-04-17} --where-clause "bool1 = 1"
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ stor open | table -e
╭──────┬─────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬─str1─┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ toby │ 2021-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴──────┴────────────────────────────╯ │
╰──────┴─────────────────────────────────────────────────────────────────╯
```
## insert another row
```nushell
❯ stor insert --table-name nudb --data-record {bool1: true, int1: 5, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭──────┬────────────────╮
│ nudb │ [table 2 rows] │
╰──────┴────────────────╯
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ toby │ 2021-04-17 00:00:00 +00:00 │ │
│ │ │ 1 │ 2 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
## stor delete (specific row(s))
```nushell
❯ stor delete --table-name nudb --where-clause "int1 == 5"
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
```
## insert multiple tables
```nushell
❯ stor create --table-name nudb1 --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭───────┬────────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [list 0 items] │
╰───────┴────────────────╯
❯ stor insert --table-name nudb1 --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
╰───────┴───────────────╯
❯ stor create --table-name nudb2 --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭───────┬────────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
│ nudb2 │ [list 0 items] │
╰───────┴────────────────╯
❯ stor insert --table-name nudb2 --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
│ nudb2 │ [table 1 row] │
╰───────┴───────────────╯
```
## stor delete (specific table)
```nushell
❯ stor delete --table-name nudb1
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb2 │ [table 1 row] │
╰───────┴───────────────╯
```
## stor reset (all tables are deleted)
```nushell
❯ stor reset
```
## stor export
```nushell
❯ stor export --file-name nudb.sqlite3
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ open nudb.sqlite3 | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
❯ open nudb.sqlite3 | schema | table -e
╭────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │ ╭──────┬──────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ tables │ │ │ ╭───────────────┬──────────────────────────────────────────────────────────────────────────────╮ │ │
│ │ │ nudb │ │ │ ╭─#─┬─cid─┬───name────┬─────type─────┬─notnull─┬───────default────────┬─pk─╮ │ │ │
│ │ │ │ │ columns │ │ 0 │ 0 │ id │ INTEGER │ 1 │ │ 1 │ │ │ │
│ │ │ │ │ │ │ 1 │ 1 │ bool1 │ BOOLEAN │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 2 │ 2 │ int1 │ INTEGER │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 3 │ 3 │ float1 │ REAL │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 4 │ 4 │ str1 │ VARCHAR(255) │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 5 │ 5 │ datetime1 │ DATETIME │ 0 │ STRFTIME('%Y-%m-%d │ 0 │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ %H:%M:%f', 'NOW') │ │ │ │ │
│ │ │ │ │ │ ╰─#─┴─cid─┴───name────┴─────type─────┴─notnull─┴───────default────────┴─pk─╯ │ │ │
│ │ │ │ │ constraints │ [list 0 items] │ │ │
│ │ │ │ │ foreign_keys │ [list 0 items] │ │ │
│ │ │ │ │ indexes │ [list 0 items] │ │ │
│ │ │ │ ╰───────────────┴──────────────────────────────────────────────────────────────────────────────╯ │ │
│ │ ╰──────┴──────────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
## Using with `query db`
```nushell
❯ stor open | query db "select * from nudb"
╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮
│ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │
╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯
```
## stor import
```nushell
❯ stor open
# note, nothing is returned. there is nothing in memory, atm.
❯ stor import --file-name nudb.sqlite3
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
TODO:
- [x] `stor export` - Export a fully formed sqlite db file.
- [x] `stor import` - Imports a specified sqlite db file.
- [x] Perhaps feature-gate it with the sqlite feature
- [x] Update `query db` to work with the in-memory database
- [x] Remove `open --in-memory`
# 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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` 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-11-29 17:02:46 +01:00
|
|
|
// This is the real secret sauce to having an in-memory sqlite db. You must
|
|
|
|
// start a connection to the memory database in main so it will exist for the
|
|
|
|
// lifetime of the program. If it's created with how MEMORY_DB is defined
|
|
|
|
// you'll be able to access this open connection from anywhere in the program
|
|
|
|
// by using the identical connection string.
|
|
|
|
#[cfg(feature = "sqlite")]
|
|
|
|
let db = nu_command::open_connection_in_memory_custom()?;
|
|
|
|
#[cfg(feature = "sqlite")]
|
|
|
|
db.last_insert_rowid();
|
|
|
|
|
2023-01-27 00:56:55 +01:00
|
|
|
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)
|
2023-01-20 19:44:49 +01:00
|
|
|
.unwrap_or_else(|_| std::process::exit(1));
|
|
|
|
|
2023-07-17 23:32:29 +02:00
|
|
|
// keep this condition in sync with the branches at the end
|
2023-08-04 22:43:35 +02:00
|
|
|
engine_state.is_interactive = parsed_nu_cli_args.interactive_shell.is_some()
|
|
|
|
|| (parsed_nu_cli_args.testbin.is_none()
|
|
|
|
&& parsed_nu_cli_args.commands.is_none()
|
|
|
|
&& script_name.is_empty());
|
2023-07-17 23:32:29 +02:00
|
|
|
|
2023-03-09 03:59:33 +01:00
|
|
|
engine_state.is_login = parsed_nu_cli_args.login_shell.is_some();
|
|
|
|
|
2023-02-02 00:03:05 +01:00
|
|
|
let use_color = engine_state.get_config().use_ansi_coloring;
|
2023-02-05 22:20:35 +01:00
|
|
|
if let Some(level) = parsed_nu_cli_args
|
|
|
|
.log_level
|
|
|
|
.as_ref()
|
|
|
|
.map(|level| level.item.clone())
|
|
|
|
{
|
2023-01-24 21:28:59 +01:00
|
|
|
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
|
2023-02-05 22:20:35 +01:00
|
|
|
.as_ref()
|
|
|
|
.map(|target| target.item.clone())
|
2023-01-24 21:28:59 +01:00
|
|
|
.unwrap_or_else(|| "stderr".to_string());
|
|
|
|
|
|
|
|
logger(|builder| configure(&level, &target, builder))?;
|
|
|
|
// info!("start logging {}:{}:{}", file!(), line!(), column!());
|
2023-02-02 00:03:05 +01:00
|
|
|
perf(
|
|
|
|
"start logging",
|
|
|
|
start_time,
|
|
|
|
file!(),
|
|
|
|
line!(),
|
|
|
|
column!(),
|
|
|
|
use_color,
|
|
|
|
);
|
2023-01-24 21:28:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 19:44:49 +01:00
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
|
|
|
&init_cwd,
|
|
|
|
"config.nu",
|
|
|
|
"config-path",
|
2023-09-13 01:00:58 +02:00
|
|
|
parsed_nu_cli_args.config_file.as_ref(),
|
2023-01-20 19:44:49 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
|
|
|
&init_cwd,
|
|
|
|
"env.nu",
|
|
|
|
"env-path",
|
2023-09-13 01:00:58 +02:00
|
|
|
parsed_nu_cli_args.env_file.as_ref(),
|
2023-01-20 19:44:49 +01:00
|
|
|
);
|
2023-02-02 00:03:05 +01:00
|
|
|
perf(
|
|
|
|
"set_config_path",
|
|
|
|
start_time,
|
|
|
|
file!(),
|
|
|
|
line!(),
|
|
|
|
column!(),
|
|
|
|
use_color,
|
|
|
|
);
|
2023-01-20 19:44:49 +01:00
|
|
|
|
2023-01-24 21:28:59 +01:00
|
|
|
start_time = std::time::Instant::now();
|
2023-08-04 22:43:35 +02:00
|
|
|
acquire_terminal(engine_state.is_interactive);
|
2023-02-02 00:03:05 +01:00
|
|
|
perf(
|
|
|
|
"acquire_terminal",
|
|
|
|
start_time,
|
|
|
|
file!(),
|
|
|
|
line!(),
|
|
|
|
column!(),
|
|
|
|
use_color,
|
|
|
|
);
|
2023-01-20 19:44:49 +01:00
|
|
|
|
2023-04-12 19:36:29 +02:00
|
|
|
if let Some(include_path) = &parsed_nu_cli_args.include_path {
|
2023-04-12 20:21:02 +02:00
|
|
|
let span = include_path.span;
|
|
|
|
let vals: Vec<_> = include_path
|
|
|
|
.item
|
2023-04-21 22:30:36 +02:00
|
|
|
.split('\x1e') // \x1e is the record separator character (a character that is unlikely to appear in a path)
|
2023-09-03 16:27:29 +02:00
|
|
|
.map(|x| Value::string(x.trim().to_string(), span))
|
2023-04-12 20:21:02 +02:00
|
|
|
.collect();
|
|
|
|
|
2023-09-03 16:27:29 +02:00
|
|
|
engine_state.add_env_var("NU_LIB_DIRS".into(), Value::list(vals, span));
|
2023-04-12 19:36:29 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 22:48:50 +02:00
|
|
|
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,
|
|
|
|
);
|
|
|
|
|
2023-09-01 08:48:13 +02:00
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_VERSION".to_string(),
|
|
|
|
Value::string(env!("CARGO_PKG_VERSION"), Span::unknown()),
|
|
|
|
);
|
|
|
|
|
2023-05-07 14:29:15 +02:00
|
|
|
if parsed_nu_cli_args.no_std_lib.is_none() {
|
|
|
|
load_standard_library(&mut engine_state)?;
|
|
|
|
}
|
|
|
|
|
2023-11-02 16:18:57 +01:00
|
|
|
if parsed_nu_cli_args.lsp {
|
2023-11-16 00:35:48 +01:00
|
|
|
return LanguageServer::initialize_stdio_connection()?.serve_requests(engine_state, ctrlc);
|
2023-11-02 16:18:57 +01:00
|
|
|
}
|
|
|
|
|
2023-04-05 21:34:47 +02:00
|
|
|
// 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 {
|
2023-04-12 19:36:29 +02:00
|
|
|
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()));
|
|
|
|
|
2023-04-05 21:34:47 +02:00
|
|
|
ide::complete(Arc::new(engine_state), &script_name, &ide_complete);
|
|
|
|
|
|
|
|
return Ok(());
|
2023-04-13 19:53:18 +02:00
|
|
|
} else if let Some(max_errors) = parsed_nu_cli_args.ide_check {
|
|
|
|
ide::check(&mut engine_state, &script_name, &max_errors);
|
2023-04-05 21:34:47 +02:00
|
|
|
|
add `--ide-ast` for a simplistic ast for editors (#8995)
# Description
This is WIP. This generates a simplistic AST so that we can call it from
the vscode side for semantic token highlighting. The output is a
minified version of this screenshot.
![image](https://user-images.githubusercontent.com/343840/234354668-872d6267-9946-4b92-8a13-4fed45b4513a.png)
The script
```
def test [arg] {
print $arg
for i in (seq 1 10) {
echo $i
}
}
```
The simplistic AST
```json
[{"content":"def","index":0,"shape":"shape_internalcall","span":{"end":15,"start":12}},{"content":"test","index":1,"shape":"shape_string","span":{"end":20,"start":16}},{"content":"[arg]","index":2,"shape":"shape_signature","span":{"end":26,"start":21}},{"content":"{\r\n ","index":3,"shape":"shape_closure","span":{"end":32,"start":27}},{"content":"print","index":4,"shape":"shape_internalcall","span":{"end":37,"start":32}},{"content":"$arg","index":5,"shape":"shape_variable","span":{"end":42,"start":38}},{"content":"for","index":6,"shape":"shape_internalcall","span":{"end":49,"start":46}},{"content":"i","index":7,"shape":"shape_vardecl","span":{"end":51,"start":50}},{"content":"in","index":8,"shape":"shape_keyword","span":{"end":54,"start":52}},{"content":"(","index":9,"shape":"shape_block","span":{"end":56,"start":55}},{"content":"seq","index":10,"shape":"shape_internalcall","span":{"end":59,"start":56}},{"content":"1","index":11,"shape":"shape_int","span":{"end":61,"start":60}},{"content":"10","index":12,"shape":"shape_int","span":{"end":64,"start":62}},{"content":")","index":13,"shape":"shape_block","span":{"end":65,"start":64}},{"content":"{\r\n ","index":14,"shape":"shape_block","span":{"end":73,"start":66}},{"content":"echo","index":15,"shape":"shape_internalcall","span":{"end":77,"start":73}},{"content":"$i","index":16,"shape":"shape_variable","span":{"end":80,"start":78}},{"content":"\r\n }","index":17,"shape":"shape_block","span":{"end":85,"start":80}},{"content":"\r\n}","index":18,"shape":"shape_closure","span":{"end":88,"start":85}}]
```
# 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` 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-04-28 15:51:51 +02:00
|
|
|
return Ok(());
|
|
|
|
} else if parsed_nu_cli_args.ide_ast.is_some() {
|
|
|
|
ide::ast(&mut engine_state, &script_name);
|
|
|
|
|
2023-04-05 21:34:47 +02:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2023-01-24 21:28:59 +01:00
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 19:44:49 +01:00
|
|
|
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),
|
2023-11-28 13:42:35 +01:00
|
|
|
"echo_env_mixed" => test_bins::echo_env_mixed(),
|
2023-01-20 19:44:49 +01:00
|
|
|
"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(),
|
special-case ExternalStream in bytes starts-with (#8203)
# Description
`bytes starts-with` converts the input into a `Value` before running
.starts_with to find if the binary matches. This has two side effects:
it makes the code simpler, only dealing in whole values, and simplifying
a lot of input pipeline handling and value transforming it would
otherwise have to do. _Especially_ in the presence of a cell path to
drill into. It also makes buffers the entire input into memory, which
can take up a lot of memory when dealing with large files, especially if
you only want to check the first few bytes (like for a magic number).
This PR adds a special branch on PipelineData::ExternalStream with a
streaming version of starts_with.
# User-Facing Changes
Opening large files and running bytes starts-with on them will not take
a long time.
# 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` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# Drawbacks
Streaming checking is more complicated, and there may be bugs. I tested
it with multiple chunks with string data and binary data and it seems to
work alright up to 8k and over bytes, though.
The existing `operate` method still exists because the way it handles
cell paths and values is complicated. This causes some "code
duplication", or at least some intent duplication, between the value
code and the streaming code. This might be worthwhile considering the
performance gains (approaching infinity on larger inputs).
Another thing to consider is that my ExternalStream branch considers
string data as valid input. The operate branch only parses Binary
values, so it would fail. `open` is kind of unpredictable on whether it
returns string data or binary data, even when passing `--raw`. I think
this can be a problem but not really one I'm trying to tackle in this
PR, so, it's worth considering.
2023-02-26 15:17:44 +01:00
|
|
|
"repeat_bytes" => test_bins::repeat_bytes(),
|
2023-01-20 19:44:49 +01:00
|
|
|
"nu_repl" => test_bins::nu_repl(),
|
2023-02-24 21:39:52 +01:00
|
|
|
"input_bytes_length" => test_bins::input_bytes_length(),
|
2023-01-20 19:44:49 +01:00
|
|
|
_ => std::process::exit(1),
|
|
|
|
}
|
|
|
|
std::process::exit(0)
|
|
|
|
}
|
2023-02-02 00:03:05 +01:00
|
|
|
perf(
|
|
|
|
"run test_bins",
|
|
|
|
start_time,
|
|
|
|
file!(),
|
|
|
|
line!(),
|
|
|
|
column!(),
|
|
|
|
use_color,
|
|
|
|
);
|
2023-01-24 21:28:59 +01:00
|
|
|
|
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 19:44:49 +01:00
|
|
|
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()
|
|
|
|
};
|
2023-02-02 00:03:05 +01:00
|
|
|
perf(
|
|
|
|
"redirect stdin",
|
|
|
|
start_time,
|
|
|
|
file!(),
|
|
|
|
line!(),
|
|
|
|
column!(),
|
|
|
|
use_color,
|
|
|
|
);
|
2022-10-21 17:20:21 +02:00
|
|
|
|
2023-09-01 08:18:55 +02:00
|
|
|
// Set up the $nu constant before evaluating config files (need to have $nu available in them)
|
|
|
|
let nu_const = create_nu_constant(&engine_state, input.span().unwrap_or_else(Span::unknown))?;
|
|
|
|
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
|
|
|
|
|
2023-02-05 22:20:35 +01:00
|
|
|
if let Some(commands) = parsed_nu_cli_args.commands.clone() {
|
|
|
|
run_commands(
|
2023-01-20 19:44:49 +01:00
|
|
|
&mut engine_state,
|
2023-02-05 22:20:35 +01:00
|
|
|
parsed_nu_cli_args,
|
2023-02-02 00:03:05 +01:00
|
|
|
use_color,
|
2023-02-05 22:20:35 +01:00
|
|
|
&commands,
|
2023-01-20 19:44:49 +01:00
|
|
|
input,
|
2023-03-24 16:41:33 +01:00
|
|
|
entire_start_time,
|
2023-02-05 22:20:35 +01:00
|
|
|
)
|
2023-03-09 03:59:33 +01:00
|
|
|
} else if !script_name.is_empty() {
|
2023-02-05 22:20:35 +01:00
|
|
|
run_file(
|
2023-01-20 19:44:49 +01:00
|
|
|
&mut engine_state,
|
2023-02-05 22:20:35 +01:00
|
|
|
parsed_nu_cli_args,
|
2023-02-02 00:03:05 +01:00
|
|
|
use_color,
|
2023-01-20 19:44:49 +01:00
|
|
|
script_name,
|
2023-02-05 22:20:35 +01:00
|
|
|
args_to_script,
|
2023-01-20 19:44:49 +01:00
|
|
|
input,
|
2023-02-05 22:20:35 +01:00
|
|
|
)
|
2023-01-20 19:44:49 +01:00
|
|
|
} else {
|
FEATURE: add the startup time to `$nu` (#8353)
# Description
in https://github.com/nushell/nushell/issues/8311 and the discord
server, the idea of moving the default banner from the `rust` source to
the `nushell` standar library has emerged :yum:
however, in order to do this, one need to have access to all the
variables used in the default banner => all of them are accessible
because known constants, except for the startup time of the shell, which
is not anywhere in the shell...
#### this PR adds exactly this, i.e. the new `startup_time` to the `$nu`
variable, which is computed to have the exact same value as the value
shown in the banner.
## the changes
in order to achieve this, i had to
- add `startup_time` as an `i64` to the `EngineState` => this is, to the
best of my knowledge, the easiest way to pass such an information around
down to where the banner startup time is computed and where the `$nu`
variable is evaluated
- add `startup-time` to the `$nu` variable and use the `EngineState`
getter for `startup_time` to show it as a `Value::Duration`
- pass `engine_state` as a `&mut`able argument from `main.rs` down to
`repl.rs` to allow the setter to change the value of `startup_time` =>
without this, the value would not change and would show `-1ns` as the
default value...
- the value of the startup time is computed in `evaluate_repl` in
`repl.rs`, only once at the beginning, and the same value is used in the
default banner :ok_hand:
# User-Facing Changes
one can now access to the same time as shown in the default banner with
```bash
$nu.startup-time
```
# Tests + Formatting
- :green_circle: `cargo fmt --all`
- :green_circle: `cargo clippy --workspace -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect`
- :green_circle: `cargo test --workspace`
# After Submitting
```
$nothing
```
2023-03-09 21:18:58 +01:00
|
|
|
run_repl(&mut engine_state, parsed_nu_cli_args, entire_start_time)
|
2022-01-26 15:42:39 +01:00
|
|
|
}
|
|
|
|
}
|