2021-01-06 18:47:36 +01:00
use crate ::line_editor ::configure_ctrl_c ;
2021-01-12 05:59:53 +01:00
use nu_command ::commands ::default_context ::create_default_context ;
#[ allow(unused_imports) ]
use nu_command ::maybe_print_errors ;
2021-01-10 03:50:49 +01:00
use nu_engine ::run_block ;
use nu_engine ::EvaluationContext ;
2020-12-31 00:38:31 +01:00
#[ allow(unused_imports) ]
2021-01-12 05:59:53 +01:00
pub ( crate ) use nu_command ::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 ;
use nu_source ::{ Tag , Text } ;
use nu_stream ::InputStream ;
#[ allow(unused_imports) ]
use std ::sync ::atomic ::Ordering ;
2021-01-12 05:59:53 +01:00
use nu_command ::script ::{ print_err , run_script_standalone } ;
2021-01-06 18:47:36 +01:00
#[ cfg(feature = " rustyline-support " ) ]
use rustyline ::{ self , error ::ReadlineError } ;
2020-05-14 02:35:22 +02:00
use crate ::EnvironmentSyncer ;
2020-09-17 01:22:58 +02:00
use nu_errors ::ShellError ;
2020-12-18 08:53:49 +01:00
use nu_parser ::ParserScope ;
2020-12-31 00:38:31 +01:00
use nu_protocol ::{ UntaggedValue , Value } ;
2020-12-05 05:12:42 +01:00
2019-05-23 06:30:43 +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 ( ) ) {
2020-05-28 21:14:32 +02:00
if let Some ( plugin_dirs ) = config . get ( " plugin_dirs " ) {
if let Value {
value : UntaggedValue ::Table ( pipelines ) ,
..
} = plugin_dirs
{
for pipeline in pipelines {
if let Ok ( plugin_dir ) = pipeline . as_string ( ) {
search_paths . push ( PathBuf ::from ( plugin_dir ) ) ;
}
}
2019-11-10 04:44:05 +01:00
}
}
2019-09-12 05:20:42 +02:00
}
search_paths
}
2020-12-18 08:53:49 +01:00
pub async fn run_script_file (
file_contents : String ,
2020-04-15 19:50:35 +02:00
redirect_stdin : bool ,
) -> Result < ( ) , Box < dyn Error > > {
2020-09-17 01:22:58 +02:00
let mut syncer = EnvironmentSyncer ::new ( ) ;
let mut context = create_default_context ( false ) ? ;
let config = syncer . get_config ( ) ;
2020-04-15 19:50:35 +02:00
2020-09-17 01:22:58 +02:00
context . configure ( & config , | _ , ctx | {
syncer . load_environment ( ) ;
syncer . sync_env_vars ( ctx ) ;
syncer . sync_path_vars ( ctx ) ;
2020-04-15 19:50:35 +02:00
2020-09-17 01:22:58 +02:00
if let Err ( reason ) = syncer . autoenv ( ctx ) {
print_err ( reason , & Text ::from ( " " ) ) ;
2020-07-18 03:59:23 +02:00
}
2020-04-15 19:50:35 +02:00
2020-09-17 01:22:58 +02:00
let _ = register_plugins ( ctx ) ;
let _ = configure_ctrl_c ( ctx ) ;
} ) ;
let _ = run_startup_commands ( & mut context , & config ) . await ;
2020-04-15 19:50:35 +02:00
2020-12-19 08:47:34 +01:00
run_script_standalone ( file_contents , redirect_stdin , & context , true ) . await ? ;
2020-02-09 03:24:33 +01:00
Ok ( ( ) )
}
2020-09-17 01:22:58 +02:00
/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input.
2020-09-17 08:02:30 +02:00
#[ cfg(feature = " rustyline-support " ) ]
2020-09-19 23:29:51 +02:00
pub async fn cli ( mut context : EvaluationContext ) -> Result < ( ) , Box < dyn Error > > {
2020-09-17 01:22:58 +02:00
let mut syncer = EnvironmentSyncer ::new ( ) ;
let configuration = syncer . get_config ( ) ;
2019-12-31 05:06:36 +01:00
2020-09-17 01:22:58 +02:00
let mut rl = default_rustyline_editor_configuration ( ) ;
2020-08-05 23:34:28 +02:00
2020-09-17 01:22:58 +02:00
context . configure ( & configuration , | config , ctx | {
syncer . load_environment ( ) ;
syncer . sync_env_vars ( ctx ) ;
syncer . sync_path_vars ( ctx ) ;
2020-07-15 09:51:59 +02:00
2020-09-17 01:22:58 +02:00
if let Err ( reason ) = syncer . autoenv ( ctx ) {
print_err ( reason , & Text ::from ( " " ) ) ;
2020-07-22 23:43:52 +02:00
}
2020-09-17 01:22:58 +02:00
let _ = configure_ctrl_c ( ctx ) ;
let _ = configure_rustyline_editor ( & mut rl , config ) ;
2020-07-22 23:43:52 +02:00
2020-09-17 01:22:58 +02:00
let helper = Some ( nu_line_editor_helper ( ctx , config ) ) ;
rl . set_helper ( helper ) ;
} ) ;
2020-07-22 23:43:52 +02:00
2020-09-17 01:22:58 +02:00
let _ = run_startup_commands ( & mut context , & configuration ) . await ;
2020-08-27 13:06:25 +02:00
2020-12-18 08:53:49 +01:00
// Give ourselves a scope to work in
context . scope . enter_scope ( ) ;
2021-01-10 03:50:49 +01:00
let history_path = nu_engine ::history_path ( & configuration ) ;
2020-08-27 13:06:25 +02:00
let _ = rl . load_history ( & history_path ) ;
2020-08-09 01:38:21 +02:00
2020-12-18 08:53:49 +01:00
let mut session_text = String ::new ( ) ;
let mut line_start : usize = 0 ;
2020-09-17 01:22:58 +02:00
let skip_welcome_message = configuration
. var ( " skip_welcome_message " )
2020-08-09 01:38:21 +02:00
. map ( | x | x . is_true ( ) )
. unwrap_or ( false ) ;
if ! skip_welcome_message {
println! (
" Welcome to Nushell {} (type 'help' for more info) " ,
clap ::crate_version! ( )
) ;
}
2019-05-26 08:54:41 +02:00
#[ cfg(windows) ]
{
let _ = ansi_term ::enable_ansi_support ( ) ;
}
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 {
2019-10-13 06:12:43 +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 ;
}
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
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 = {
2020-09-17 01:22:58 +02:00
if let Some ( prompt ) = configuration . var ( " 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 ( ) ;
let ( prompt_block , err ) = nu_parser ::parse ( & prompt_line , 0 , & context . scope ) ;
2020-11-09 17:27:07 +01:00
if err . is_some ( ) {
use crate ::git ::current_branch ;
2020-12-18 08:53:49 +01:00
context . scope . exit_scope ( ) ;
2020-11-09 17:27:07 +01:00
format! (
" \x1b [32m{}{} \x1b [m> " ,
cwd ,
match current_branch ( ) {
Some ( s ) = > format! ( " ( {} ) " , s ) ,
None = > " " . to_string ( ) ,
}
)
} else {
2020-12-18 08:53:49 +01:00
// let env = context.get_env();
2020-11-09 17:27:07 +01:00
2020-12-18 08:53:49 +01:00
let run_result = run_block ( & prompt_block , & context , InputStream ::empty ( ) ) . await ;
context . scope . exit_scope ( ) ;
2020-06-28 23:06:05 +02:00
2020-12-18 08:53:49 +01:00
match run_result {
2020-11-09 17:27:07 +01:00
Ok ( result ) = > match result . collect_string ( Tag ::unknown ( ) ) . await {
Ok ( string_result ) = > {
let errors = context . get_errors ( ) ;
2021-01-10 03:50:49 +01: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 ) = > {
crate ::cli ::print_err ( e , & Text ::from ( prompt_line ) ) ;
context . clear_errors ( ) ;
" > " . to_string ( )
2020-06-27 00:37:31 +02:00
}
2020-11-09 17:27:07 +01:00
} ,
Err ( e ) = > {
crate ::cli ::print_err ( e , & Text ::from ( prompt_line ) ) ;
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 {
2020-09-17 08:02:30 +02:00
use crate ::git ::current_branch ;
2019-11-16 21:02:26 +01:00
format! (
2019-11-16 21:42:35 +01:00
" \x1b [32m{}{} \x1b [m> " ,
2019-10-08 15:47:30 +02:00
cwd ,
match current_branch ( ) {
Some ( s ) = > format! ( " ( {} ) " , s ) ,
None = > " " . to_string ( ) ,
}
)
}
} ;
2019-11-16 21:02:26 +01:00
2019-11-16 21:42:35 +01:00
let prompt = {
2020-01-01 21:45:32 +01:00
if let Ok ( bytes ) = strip_ansi_escapes ::strip ( & colored_prompt ) {
String ::from_utf8_lossy ( & bytes ) . to_string ( )
} else {
" > " . to_string ( )
}
2019-11-16 21:42:35 +01:00
} ;
2019-11-16 21:02:26 +01:00
rl . helper_mut ( ) . expect ( " No 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 {
2019-11-16 21:02:26 +01: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' ) ;
}
2020-09-17 08:02:30 +02:00
let line = match convert_rustyline_result_to_string ( readline ) {
2020-12-18 08:53:49 +01:00
LineResult ::Success ( _ ) = > {
process_script (
& session_text [ line_start .. ] ,
2020-12-19 08:47:34 +01:00
& context ,
2020-12-18 08:53:49 +01:00
false ,
line_start ,
true ,
)
. await
}
2020-09-17 08:02:30 +02:00
x = > x ,
} ;
2019-11-04 16:47:03 +01:00
2020-01-28 04:13:22 +01:00
// Check the config to see if we need to update the path
// TODO: make sure config is cached so we don't path this load every call
// FIXME: we probably want to be a bit more graceful if we can't set the environment
2020-09-17 01:22:58 +02:00
context . configure ( & configuration , | config , ctx | {
if syncer . did_config_change ( ) {
syncer . reload ( ) ;
syncer . sync_env_vars ( ctx ) ;
syncer . sync_path_vars ( ctx ) ;
}
if let Err ( reason ) = syncer . autoenv ( ctx ) {
print_err ( reason , & Text ::from ( " " ) ) ;
}
let _ = configure_rustyline_editor ( & mut rl , config ) ;
} ) ;
2020-01-28 04:13:22 +01:00
2019-11-04 16:47:03 +01:00
match line {
2019-05-23 06:30:43 +02:00
LineResult ::Success ( line ) = > {
2020-06-15 19:35:24 +02:00
rl . add_history_entry ( & line ) ;
2020-08-27 13:06:25 +02:00
let _ = rl . save_history ( & history_path ) ;
2021-01-10 03:50:49 +01: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 = > {
rl . clear_history ( ) ;
let _ = rl . save_history ( & history_path ) ;
}
2019-11-04 16:47:03 +01:00
LineResult ::Error ( line , err ) = > {
2020-06-15 19:35:24 +02:00
rl . add_history_entry ( & line ) ;
2020-08-27 13:06:25 +02:00
let _ = rl . save_history ( & history_path ) ;
2019-11-04 16:47:03 +01:00
2020-05-18 20:44:27 +02:00
context . with_host ( | _host | {
2020-12-18 08:53:49 +01:00
print_err ( err , & Text ::from ( session_text . clone ( ) ) ) ;
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
} ) ;
2019-11-04 16:47:03 +01:00
2021-01-10 03:50:49 +01:00
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 = > {
2019-09-25 03:01:38 +02:00
let config_ctrlc_exit = config ::config ( Tag ::unknown ( ) ) ?
. get ( " ctrlc_exit " )
2020-09-15 16:59:51 +02:00
. map ( | s | s . value . 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 {
2020-08-27 13:06:25 +02:00
let _ = rl . save_history ( & history_path ) ;
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 = > {
context . shell_manager . remove_at_current ( ) ;
if context . shell_manager . is_empty ( ) {
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
2020-08-27 13:06:25 +02:00
let _ = rl . save_history ( & history_path ) ;
2019-05-23 06:30:43 +02:00
Ok ( ( ) )
}
2020-09-19 23:29:51 +02:00
pub fn register_plugins ( context : & mut 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 ( ( ) )
}
async fn run_startup_commands (
2020-09-19 23:29:51 +02:00
context : & mut EvaluationContext ,
2020-09-17 01:22:58 +02:00
config : & dyn nu_data ::config ::Conf ,
) -> Result < ( ) , ShellError > {
if let Some ( commands ) = config . var ( " startup " ) {
match commands {
Value {
value : UntaggedValue ::Table ( pipelines ) ,
..
} = > {
2021-01-08 07:36:31 +01:00
let mut script_file = String ::new ( ) ;
2020-09-17 01:22:58 +02:00
for pipeline in pipelines {
2021-01-08 07:36:31 +01:00
script_file . push_str ( & pipeline . as_string ( ) ? ) ;
script_file . push ( '\n' ) ;
2020-09-17 01:22:58 +02:00
}
2021-01-08 07:36:31 +01:00
let _ = run_script_standalone ( script_file , false , context , false ) . await ;
2020-09-17 01:22:58 +02:00
}
_ = > {
return Err ( ShellError ::untagged_runtime_error (
" expected a table of pipeline strings as startup commands " ,
) )
}
}
}
Ok ( ( ) )
}
2020-12-19 08:47:34 +01:00
pub async 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 ( ) ;
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 ( ) ;
let env = ctx . get_env ( ) ;
2020-12-18 08:53:49 +01:00
ctx . scope . add_env ( env ) ;
let result = run_block ( & classified_block , ctx , input_stream ) . await ;
ctx . scope . exit_scope ( ) ;
2020-07-18 03:59:23 +02:00
2020-12-18 08:53:49 +01:00
result ? . collect_string ( Tag ::unknown ( ) ) . await . map ( | x | x . item )
2020-07-18 03:59:23 +02:00
}
2020-04-11 21:05:59 +02:00
#[ cfg(test) ]
mod tests {
2021-01-11 05:58:15 +01:00
use nu_engine ::basic_evaluation_context ;
2020-12-18 08:53:49 +01:00
2020-04-11 21:05:59 +02:00
#[ quickcheck ]
fn quickcheck_parse ( data : String ) -> bool {
2020-12-18 08:53:49 +01:00
let ( tokens , err ) = nu_parser ::lex ( & data , 0 ) ;
2021-01-07 04:03:00 +01:00
let ( lite_block , err2 ) = nu_parser ::block ( tokens ) ;
2020-12-18 08:53:49 +01:00
if err . is_none ( ) & & err2 . is_none ( ) {
2021-01-11 05:58:15 +01:00
let context = basic_evaluation_context ( ) . unwrap ( ) ;
2020-12-18 08:53:49 +01:00
let _ = nu_parser ::classify_block ( & lite_block , & context . scope ) ;
2020-04-11 21:05:59 +02:00
}
2020-04-20 08:41:51 +02:00
true
2020-04-11 21:05:59 +02:00
}
}